A Service Provider Interface (SPI) layer for abstracting over logical links (associations) created by a Transport. Handles are responsible for providing an API for sending and receiving from the underlying channel. To register a listener for processing incoming payload data, the listener must be registered by completing the Task returned by AssociationHandle.ReadHandlerSource. Incoming data is not processed until this registration takes place.
 public ThrottledAssociation(IActorRef manager, IAssociationEventListener associationHandler, AssociationHandle originalHandle, bool inbound)
 {
     Manager            = manager;
     AssociationHandler = associationHandler;
     OriginalHandle     = originalHandle;
     Inbound            = inbound;
     InitializeFSM();
 }
Esempio n. 2
0
 public static Props InboundProps(HandshakeInfo handshakeInfo, AssociationHandle wrappedHandle,
                                  IAssociationEventListener associationEventListener, AkkaProtocolSettings settings, AkkaPduCodec codec, FailureDetector failureDetector)
 {
     return
         (Props.Create(
              () =>
              new ProtocolStateActor(handshakeInfo, wrappedHandle, associationEventListener, settings, codec, failureDetector)));
 }
Esempio n. 3
0
 /// <summary>
 /// TBD
 /// </summary>
 /// <param name="originalLocalAddress">TBD</param>
 /// <param name="originalRemoteAddress">TBD</param>
 /// <param name="wrappedHandle">TBD</param>
 /// <param name="addedSchemeIdentifier">TBD</param>
 protected AbstractTransportAdapterHandle(Address originalLocalAddress, Address originalRemoteAddress, AssociationHandle wrappedHandle, string addedSchemeIdentifier) : base(originalLocalAddress, originalRemoteAddress)
 {
     WrappedHandle         = wrappedHandle;
     OriginalRemoteAddress = originalRemoteAddress;
     OriginalLocalAddress  = originalLocalAddress;
     SchemeAugmenter       = new SchemeAugmenter(addedSchemeIdentifier);
     RemoteAddress         = SchemeAugmenter.AugmentScheme(OriginalRemoteAddress);
     LocalAddress          = SchemeAugmenter.AugmentScheme(OriginalLocalAddress);
 }
        private ThrottlerHandle WrapHandle(AssociationHandle originalHandle, IAssociationEventListener listener,
                                           bool inbound)
        {
            var managerRef = Self;

            return(new ThrottlerHandle(originalHandle, Context.ActorOf(
                                           RARP.For(Context.System).ConfigureDispatcher(
                                               Props.Create(() => new ThrottledAssociation(managerRef, listener, originalHandle, inbound)).WithDeploy(Deploy.Local)),
                                           "throttler" + nextId())));
        }
Esempio n. 5
0
 /// <summary>
 /// TBD
 /// </summary>
 /// <param name="wrappedHandle">TBD</param>
 /// <param name="gremlinAdapter">TBD</param>
 public FailureInjectorHandle(AssociationHandle wrappedHandle, FailureInjectorTransportAdapter gremlinAdapter)
     : base(wrappedHandle, FailureInjectorTransportAdapter.FailureInjectorSchemeIdentifier)
 {
     _gremlinAdapter = gremlinAdapter;
     ReadHandlerSource.Task.ContinueWith(tr =>
     {
         _upstreamListener = tr.Result;
         WrappedHandle.ReadHandlerSource.SetResult(this);
     }, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion);
 }
Esempio n. 6
0
 private void SendDisassociate(AssociationHandle wrappedHandle, DisassociateInfo info)
 {
     try
     {
         wrappedHandle.Write(_codec.ConstructDisassociate(info));
     }
     catch (Exception ex)
     {
         throw new AkkaProtocolException("Error writing DISASSOCIATE to transport", ex);
     }
 }
Esempio n. 7
0
 private bool SendAssociate(AssociationHandle wrappedHandle, HandshakeInfo info)
 {
     try
     {
         return(wrappedHandle.Write(_codec.ConstructAssociate(info)));
     }
     catch (Exception ex)
     {
         throw new AkkaProtocolException("Error writing ASSOCIATE to transport", ex);
     }
 }
Esempio n. 8
0
        private Task <IHandleEventListener> NotifyOutboundHandler(AssociationHandle wrappedHandle,
                                                                  HandshakeInfo handshakeInfo, TaskCompletionSource <AssociationHandle> statusPromise)
        {
            var readHandlerPromise = new TaskCompletionSource <IHandleEventListener>();

            ListenForListenerRegistration(readHandlerPromise);

            statusPromise.SetResult(new AkkaProtocolHandle(_localAddress, wrappedHandle.RemoteAddress, readHandlerPromise, wrappedHandle, handshakeInfo, Self, _codec));

            return(readHandlerPromise.Task);
        }
Esempio n. 9
0
 private void SendHeartBeat(AssociationHandle wrappedHandle)
 {
     try
     {
         wrappedHandle.Write(_codec.ConstructHeartbeat());
     }
     catch (Exception ex)
     {
         throw new AkkaProtocolException("Error writing HEARTBEAT to transport", ex);
     }
 }
Esempio n. 10
0
        private Task <IHandleEventListener> NotifyInboundHandler(AssociationHandle wrappedHandle,
                                                                 HandshakeInfo handshakeInfo, IAssociationEventListener associationEventListener)
        {
            var readHandlerPromise = new TaskCompletionSource <IHandleEventListener>();

            ListenForListenerRegistration(readHandlerPromise);

            associationEventListener.Notify(
                new InboundAssociation(
                    new AkkaProtocolHandle(_localAddress, handshakeInfo.Origin, readHandlerPromise, wrappedHandle, handshakeInfo, Self, _codec)));
            return(readHandlerPromise.Task);
        }
Esempio n. 11
0
 private State <AssociationState, ProtocolStateData> HandleTimers(AssociationHandle wrappedHandle)
 {
     if (_failureDetector.IsAvailable)
     {
         SendHeartBeat(wrappedHandle);
         return(Stay());
     }
     else
     {
         SendDisassociate(wrappedHandle, DisassociateInfo.Unknown);
         return(Stop(new Failure(new TimeoutReason())));
     }
 }
Esempio n. 12
0
 private State <AssociationState, ProtocolStateData> HandleTimers(AssociationHandle wrappedHandle)
 {
     if (_failureDetector.IsAvailable)
     {
         SendHeartBeat(wrappedHandle);
         return(Stay());
     }
     else
     {
         //send disassociate just to be sure
         SendDisassociate(wrappedHandle, DisassociateInfo.Unknown);
         return(Stop(new Failure(new TimeoutReason("No response from remote. Handshake timed out or transport failure detector triggered."))));
     }
 }
Esempio n. 13
0
 public OutboundUnderlyingAssociated(TaskCompletionSource <AssociationHandle> statusCompletionSource, AssociationHandle wrappedHandle)
 {
     WrappedHandle          = wrappedHandle;
     StatusCompletionSource = statusCompletionSource;
 }
Esempio n. 14
0
        private void InitializeFSM()
        {
            When(AssociationState.Closed, fsmEvent =>
            {
                State <AssociationState, ProtocolStateData> nextState = null;
                //Transport layer events for outbound associations
                fsmEvent.FsmEvent.Match()
                .With <Status.Failure>(f => fsmEvent.StateData.Match()
                                       .With <OutboundUnassociated>(ou =>
                {
                    ou.StatusCompletionSource.SetException(f.Cause);
                    nextState = Stop();
                }))
                .With <AssociationHandle>(h => fsmEvent.StateData.Match()
                                          .With <OutboundUnassociated>(ou =>
                {
                    var wrappedHandle = h;
                    var statusPromise = ou.StatusCompletionSource;
                    wrappedHandle.ReadHandlerSource.SetResult(new ActorHandleEventListener(Self));
                    if (SendAssociate(wrappedHandle, _localHandshakeInfo))
                    {
                        _failureDetector.HeartBeat();
                        InitTimers();
                        nextState =
                            GoTo(AssociationState.WaitHandshake)
                            .Using(new OutboundUnderlyingAssociated(statusPromise, wrappedHandle));
                    }
                    else
                    {
                        SetTimer("associate-retry", wrappedHandle,
                                 Context.System.Provider.AsInstanceOf <RemoteActorRefProvider>()
                                 .RemoteSettings.BackoffPeriod, repeat: false);
                        nextState = Stay();
                    }
                }))
                .With <DisassociateUnderlying>(d =>
                {
                    nextState = Stop();
                })
                .Default(m => { nextState = Stay(); });

                return(nextState);
            });

            //Transport layer events for outbound associations
            When(AssociationState.WaitHandshake, @event =>
            {
                State <AssociationState, ProtocolStateData> nextState = null;

                @event.FsmEvent.Match()
                .With <UnderlyingTransportError>(e =>
                {
                    PublishError(e);
                    nextState = Stay();
                })
                .With <Disassociated>(d =>
                {
                    nextState = Stop(new Failure(d.Info));
                })
                .With <InboundPayload>(m =>
                {
                    var pdu = DecodePdu(m.Payload);
                    @event.StateData.Match()
                    .With <OutboundUnderlyingAssociated>(ola =>
                    {
                        var wrappedHandle          = ola.WrappedHandle;
                        var statusCompletionSource = ola.StatusCompletionSource;
                        pdu.Match()
                        .With <Associate>(a =>
                        {
                            var handshakeInfo = a.Info;
                            if (_refuseUid.HasValue && _refuseUid == handshakeInfo.Uid)             //refused UID
                            {
                                SendDisassociate(wrappedHandle, DisassociateInfo.Quarantined);
                                nextState = Stop(new Failure(new ForbiddenUidReason()));
                            }
                            else             //accepted UID
                            {
                                _failureDetector.HeartBeat();
                                nextState =
                                    GoTo(AssociationState.Open)
                                    .Using(
                                        new AssociatedWaitHandler(
                                            NotifyOutboundHandler(wrappedHandle, handshakeInfo,
                                                                  statusCompletionSource), wrappedHandle,
                                            new Queue <ByteString>()));
                            }
                        })
                        .With <Disassociate>(d =>
                        {
                            //After receiving Disassociate we MUST NOT send back a Disassociate (loop)
                            nextState = Stop(new Failure(d.Reason));
                        })
                        .Default(d =>
                        {
                            _log.Debug(string.Format("Exepcted message of type Associate; instead received {0}", d));
                            //Expect handshake to be finished, dropping connection
                            SendDisassociate(wrappedHandle, DisassociateInfo.Unknown);
                            nextState = Stop();
                        });
                    })
                    .With <InboundUnassociated>(iu =>
                    {
                        var associationHandler = iu.AssociationEventListener;
                        var wrappedHandle      = iu.WrappedHandle;
                        pdu.Match()
                        .With <Disassociate>(d => nextState = Stop(new Failure(d.Reason)))
                        .With <Associate>(a =>
                        {
                            SendAssociate(wrappedHandle, _localHandshakeInfo);
                            _failureDetector.HeartBeat();
                            InitTimers();
                            nextState =
                                GoTo(AssociationState.Open)
                                .Using(
                                    new AssociatedWaitHandler(
                                        NotifyInboundHandler(wrappedHandle, a.Info, associationHandler),
                                        wrappedHandle, new Queue <ByteString>()));
                        })
                        .Default(d =>
                        {
                            SendDisassociate(wrappedHandle, DisassociateInfo.Unknown);
                            nextState = Stop();
                        });
                    });
                })
                .With <HeartbeatTimer>(h => @event.StateData.Match()
                                       .With <OutboundUnderlyingAssociated>(ou => nextState = HandleTimers(ou.WrappedHandle)));

                return(nextState);
            });

            When(AssociationState.Open, @event =>
            {
                State <AssociationState, ProtocolStateData> nextState = null;
                @event.FsmEvent.Match()
                .With <UnderlyingTransportError>(e =>
                {
                    PublishError(e);
                    nextState = Stay();
                })
                .With <Disassociated>(d =>
                {
                    nextState = Stop(new Failure(d.Info));
                })
                .With <InboundPayload>(ip =>
                {
                    var pdu = DecodePdu(ip.Payload);
                    pdu.Match()
                    .With <Disassociate>(d => nextState = Stop(new Failure(d.Reason)))
                    .With <Heartbeat>(h =>
                    {
                        _failureDetector.HeartBeat();
                        nextState = Stay();
                    })
                    .With <Payload>(p => @event.StateData.Match()
                                    .With <AssociatedWaitHandler>(awh =>
                    {
                        var nQueue = new Queue <ByteString>(awh.Queue);
                        nQueue.Enqueue(p.Bytes);
                        nextState =
                            Stay()
                            .Using(new AssociatedWaitHandler(awh.HandlerListener, awh.WrappedHandle,
                                                             nQueue));
                    })
                                    .With <ListenerReady>(lr =>
                    {
                        lr.Listener.Notify(new InboundPayload(p.Bytes));
                        nextState = Stay();
                    })
                                    .Default(msg =>
                    {
                        throw new AkkaProtocolException(
                            string.Format("Unhandled message in state Open(InboundPayload) with type {0}",
                                          msg));
                    }))
                    .Default(d =>
                    {
                        nextState = Stay();
                    });
                })
                .With <HeartbeatTimer>(hrt => @event.StateData.Match()
                                       .With <AssociatedWaitHandler>(awh => nextState = HandleTimers(awh.WrappedHandle))
                                       .With <ListenerReady>(lr => nextState          = HandleTimers(lr.WrappedHandle)))
                .With <DisassociateUnderlying>(du =>
                {
                    AssociationHandle handle = null;
                    @event.StateData.Match()
                    .With <ListenerReady>(lr => handle          = lr.WrappedHandle)
                    .With <AssociatedWaitHandler>(awh => handle = awh.WrappedHandle)
                    .Default(
                        msg =>
                    {
                        throw new AkkaProtocolException(
                            string.Format(
                                "unhandled message in state Open(DisassociateUnderlying) with type {0}", msg));
                    });
                    SendDisassociate(handle, du.Info);
                    nextState = Stop();
                })
                .With <HandleListenerRegistered>(hlr => @event.StateData.Match()
                                                 .With <AssociatedWaitHandler>(awh =>
                {
                    foreach (var msg in awh.Queue)
                    {
                        hlr.Listener.Notify(new InboundPayload(msg));
                    }
                    nextState = Stay().Using(new ListenerReady(hlr.Listener, awh.WrappedHandle));
                }));

                return(nextState);
            });

            OnTermination(@event => @event.StateData.Match()
                          .With <OutboundUnassociated>(ou => ou.StatusCompletionSource.TrySetException(@event.Reason is Failure
                    ? new AkkaProtocolException(@event.Reason.ToString())
                    : new AkkaProtocolException("Transport disassociated before handshake finished")))
                          .With <OutboundUnderlyingAssociated>(oua =>
            {
                Exception associationFailure = null;
                @event.Reason.Match()
                .With <Failure>(f => f.Cause.Match()
                                .With <TimeoutReason>(
                                    timeout =>
                                    associationFailure =
                                        new AkkaProtocolException("No reponse from remote. Handshake timed out."))
                                .With <ForbiddenUidReason>(
                                    forbidden =>
                                    associationFailure =
                                        new AkkaProtocolException(
                                            "The remote system has a UID that has been quarantined. Association aborted."))
                                .With <DisassociateInfo>(info => associationFailure = DisassociateException(info))
                                .Default(
                                    msg =>
                                    associationFailure =
                                        new AkkaProtocolException(
                                            "Transport disassociated before handshake finished")));

                oua.StatusCompletionSource.TrySetException(associationFailure);
                oua.WrappedHandle.Disassociate();
            })
                          .With <AssociatedWaitHandler>(awh =>
            {
                Disassociated disassociateNotification = null;
                if (@event.Reason is Failure && ((Failure)@event.Reason).Cause is DisassociateInfo)
                {
                    disassociateNotification =
                        new Disassociated(((Failure)@event.Reason).Cause.AsInstanceOf <DisassociateInfo>());
                }
                else
                {
                    disassociateNotification = new Disassociated(DisassociateInfo.Unknown);
                }
                awh.HandlerListener.ContinueWith(result => result.Result.Notify(disassociateNotification),
                                                 TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.AttachedToParent);
            })
                          .With <ListenerReady>(lr =>
            {
                Disassociated disassociateNotification = null;
                if (@event.Reason is Failure && ((Failure)@event.Reason).Cause is DisassociateInfo)
                {
                    disassociateNotification =
                        new Disassociated(((Failure)@event.Reason).Cause.AsInstanceOf <DisassociateInfo>());
                }
                else
                {
                    disassociateNotification = new Disassociated(DisassociateInfo.Unknown);
                }
                lr.Listener.Notify(disassociateNotification);
                lr.WrappedHandle.Disassociate();
            })
                          .With <InboundUnassociated>(iu =>
                                                      iu.WrappedHandle.Disassociate()));

            _initialData.Match()
            .With <OutboundUnassociated>(d =>
            {
                d.Transport.Associate(d.RemoteAddress).PipeTo(Self);
                StartWith(AssociationState.Closed, d);
            })
            .With <InboundUnassociated>(d =>
            {
                d.WrappedHandle.ReadHandlerSource.SetResult(new ActorHandleEventListener(Self));
                StartWith(AssociationState.WaitHandshake, d);
            });
        }
Esempio n. 15
0
 protected bool Equals(AssociationHandle other)
 {
     return Equals(LocalAddress, other.LocalAddress) && Equals(RemoteAddress, other.RemoteAddress);
 }
Esempio n. 16
0
 /// <summary>
 /// TBD
 /// </summary>
 /// <param name="other">TBD</param>
 /// <returns>TBD</returns>
 protected bool Equals(AssociationHandle other)
 {
     return(Equals(LocalAddress, other.LocalAddress) && Equals(RemoteAddress, other.RemoteAddress));
 }
Esempio n. 17
0
 public FailureInjectorHandle(AssociationHandle wrappedHandle, FailureInjectorTransportAdapter gremlinAdapter)
     : base(wrappedHandle, FailureInjectorTransportAdapter.FailureInjectorSchemeIdentifier)
 {
     _gremlinAdapter = gremlinAdapter;
     ReadHandlerSource.Task.ContinueWith(tr =>
     {
         _upstreamListener = tr.Result;
         WrappedHandle.ReadHandlerSource.SetResult(this);
     }, TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion);
 }
Esempio n. 18
0
 public HandleMsg(AssociationHandle handle)
 {
     Handle = handle;
 }
Esempio n. 19
0
 public AkkaProtocolHandle(Address originalLocalAddress, Address originalRemoteAddress,
                           TaskCompletionSource <IHandleEventListener> readHandlerCompletionSource, AssociationHandle wrappedHandle,
                           HandshakeInfo handshakeInfo, ActorRef stateActor, AkkaPduCodec codec)
     : base(originalLocalAddress, originalRemoteAddress, wrappedHandle, RemoteSettings.AkkaScheme)
 {
     HandshakeInfo     = handshakeInfo;
     StateActor        = stateActor;
     ReadHandlerSource = readHandlerCompletionSource;
     Codec             = codec;
 }
 public ThrottlerHandle(AssociationHandle wrappedHandle, IActorRef throttlerActor) : base(wrappedHandle, ThrottleTransportAdapter.Scheme)
 {
     ThrottlerActor = throttlerActor;
 }
Esempio n. 21
0
 /// <summary>
 /// TBD
 /// </summary>
 /// <param name="wrappedHandle">TBD</param>
 /// <param name="addedSchemeIdentifier">TBD</param>
 protected AbstractTransportAdapterHandle(AssociationHandle wrappedHandle, string addedSchemeIdentifier)
     : this(wrappedHandle.LocalAddress, wrappedHandle.RemoteAddress, wrappedHandle, addedSchemeIdentifier)
 {
 }
Esempio n. 22
0
 public InboundUnassociated(IAssociationEventListener associationEventListener, AssociationHandle wrappedHandle)
 {
     WrappedHandle            = wrappedHandle;
     AssociationEventListener = associationEventListener;
 }
Esempio n. 23
0
 public AssociatedWaitHandler(Task <IHandleEventListener> handlerListener, AssociationHandle wrappedHandle, Queue <ByteString> queue)
 {
     Queue           = queue;
     WrappedHandle   = wrappedHandle;
     HandlerListener = handlerListener;
 }
Esempio n. 24
0
 /// <summary>
 /// TBD
 /// </summary>
 /// <param name="association">TBD</param>
 public InboundAssociation(AssociationHandle association)
 {
     Association = association;
 }
Esempio n. 25
0
 public ListenerReady(IHandleEventListener listener, AssociationHandle wrappedHandle)
 {
     WrappedHandle = wrappedHandle;
     Listener      = listener;
 }
Esempio n. 26
0
 public InboundAssociation(AssociationHandle association)
 {
     Association = association;
 }
Esempio n. 27
0
 /// <summary>
 /// Constructor for inbound ProtocolStateActors
 /// </summary>
 public ProtocolStateActor(HandshakeInfo handshakeInfo, AssociationHandle wrappedHandle, IAssociationEventListener associationEventListener, AkkaProtocolSettings settings, AkkaPduCodec codec, FailureDetector failureDetector)
     : this(new InboundUnassociated(associationEventListener, wrappedHandle), handshakeInfo, settings, codec, failureDetector, refuseUid : null)
 {
 }
Esempio n. 28
0
 /// <summary>
 /// TBD
 /// </summary>
 /// <param name="associationHandle">TBD</param>
 /// <param name="statusPromise">TBD</param>
 public AssociateResult(AssociationHandle associationHandle, TaskCompletionSource <AssociationHandle> statusPromise)
 {
     StatusPromise     = statusPromise;
     AssociationHandle = associationHandle;
 }
Esempio n. 29
0
        private void InitializeFSM()
        {
            When(AssociationState.Closed, fsmEvent =>
            {
                State <AssociationState, ProtocolStateData> nextState = null;
                //Transport layer events for outbound associations
                fsmEvent.FsmEvent.Match()
                .With <Status.Failure>(f => fsmEvent.StateData.Match()
                                       .With <OutboundUnassociated>(ou =>
                {
                    ou.StatusCompletionSource.SetException(f.Cause);
                    nextState = Stop();
                }))
                .With <AssociationHandle>(h => fsmEvent.StateData.Match()
                                          .With <OutboundUnassociated>(ou =>
                {
                    /*
                     * Association has been established, but handshake is not yet complete.
                     * This actor, the outbound ProtocolStateActor, can now set itself as
                     * the read handler for the remainder of the handshake process.
                     */
                    AssociationHandle wrappedHandle = h;
                    var statusPromise = ou.StatusCompletionSource;
                    wrappedHandle.ReadHandlerSource.TrySetResult(new ActorHandleEventListener(Self));
                    if (SendAssociate(wrappedHandle, _localHandshakeInfo))
                    {
                        _failureDetector.HeartBeat();
                        InitTimers();
                        // wait for reply from the inbound side of the connection (WaitHandshake)
                        nextState =
                            GoTo(AssociationState.WaitHandshake)
                            .Using(new OutboundUnderlyingAssociated(statusPromise, wrappedHandle));
                    }
                    else
                    {
                        //Otherwise, retry
                        SetTimer("associate-retry", wrappedHandle,
                                 ((RemoteActorRefProvider)((ActorSystemImpl)Context.System).Provider)      //TODO: rewrite using RARP ActorSystem Extension
                                 .RemoteSettings.BackoffPeriod, repeat: false);
                        nextState = Stay();
                    }
                }))
                .With <DisassociateUnderlying>(d =>
                {
                    nextState = Stop();
                })
                .Default(m => { nextState = Stay(); });

                return(nextState);
            });

            //Transport layer events for outbound associations
            When(AssociationState.WaitHandshake, @event =>
            {
                State <AssociationState, ProtocolStateData> nextState = null;

                @event.FsmEvent.Match()
                .With <UnderlyingTransportError>(e =>
                {
                    PublishError(e);
                    nextState = Stay();
                })
                .With <Disassociated>(d =>
                {
                    nextState = Stop(new Failure(d.Info));
                })
                .With <InboundPayload>(m =>
                {
                    var pdu = DecodePdu(m.Payload);
                    @event.StateData.Match()
                    .With <OutboundUnderlyingAssociated>(ola =>
                    {
                        /*
                         * This state is used for OutboundProtocolState actors when they receive
                         * a reply back from the inbound end of the association.
                         */
                        var wrappedHandle          = ola.WrappedHandle;
                        var statusCompletionSource = ola.StatusCompletionSource;
                        pdu.Match()
                        .With <Associate>(a =>
                        {
                            var handshakeInfo = a.Info;
                            if (_refuseUid.HasValue && _refuseUid == handshakeInfo.Uid)             //refused UID
                            {
                                SendDisassociate(wrappedHandle, DisassociateInfo.Quarantined);
                                nextState = Stop(new Failure(new ForbiddenUidReason()));
                            }
                            else             //accepted UID
                            {
                                _failureDetector.HeartBeat();
                                nextState =
                                    GoTo(AssociationState.Open)
                                    .Using(
                                        new AssociatedWaitHandler(
                                            NotifyOutboundHandler(wrappedHandle, handshakeInfo,
                                                                  statusCompletionSource), wrappedHandle,
                                            new Queue <ByteString>()));
                            }
                        })
                        .With <Disassociate>(d =>
                        {
                            //After receiving Disassociate we MUST NOT send back a Disassociate (loop)
                            nextState = Stop(new Failure(d.Reason));
                        })
                        .Default(d =>
                        {
                            _log.Debug(string.Format("Expected message of type Associate; instead received {0}", d));
                            //Expect handshake to be finished, dropping connection
                            SendDisassociate(wrappedHandle, DisassociateInfo.Unknown);
                            nextState = Stop();
                        });
                    })
                    .With <InboundUnassociated>(iu =>
                    {
                        /*
                         * This state is used by inbound protocol state actors
                         * when they receive an association attempt from the
                         * outbound side of the association.
                         */
                        var associationHandler = iu.AssociationEventListener;
                        var wrappedHandle      = iu.WrappedHandle;
                        pdu.Match()
                        .With <Disassociate>(d =>
                        {
                            nextState = Stop(new Failure(d.Reason));
                        })
                        .With <Associate>(a =>
                        {
                            SendAssociate(wrappedHandle, _localHandshakeInfo);
                            _failureDetector.HeartBeat();
                            InitTimers();
                            nextState =
                                GoTo(AssociationState.Open)
                                .Using(
                                    new AssociatedWaitHandler(
                                        NotifyInboundHandler(wrappedHandle, a.Info, associationHandler),
                                        wrappedHandle, new Queue <ByteString>()));
                        })
                        .Default(d =>
                        {
                            SendDisassociate(wrappedHandle, DisassociateInfo.Unknown);
                            nextState = Stop();
                        });
                    });
                })
                .With <HeartbeatTimer>(h => @event.StateData.Match()
                                       .With <OutboundUnderlyingAssociated>(ou => nextState = HandleTimers(ou.WrappedHandle)));

                return(nextState);
            });

            When(AssociationState.Open, @event =>
            {
                State <AssociationState, ProtocolStateData> nextState = null;
                @event.FsmEvent.Match()
                .With <UnderlyingTransportError>(e =>
                {
                    PublishError(e);
                    nextState = Stay();
                })
                .With <Disassociated>(d =>
                {
                    nextState = Stop(new Failure(d.Info));
                })
                .With <InboundPayload>(ip =>
                {
                    var pdu = DecodePdu(ip.Payload);
                    pdu.Match()
                    .With <Disassociate>(d =>
                    {
                        nextState = Stop(new Failure(d.Reason));
                    })
                    .With <Heartbeat>(h =>
                    {
                        _failureDetector.HeartBeat();
                        nextState = Stay();
                    })
                    .With <Payload>(p =>
                    {
                        _failureDetector.HeartBeat();
                        @event.StateData.Match()
                        .With <AssociatedWaitHandler>(awh =>
                        {
                            var nQueue = new Queue <ByteString>(awh.Queue);
                            nQueue.Enqueue(p.Bytes);
                            nextState =
                                Stay()
                                .Using(new AssociatedWaitHandler(awh.HandlerListener, awh.WrappedHandle,
                                                                 nQueue));
                        })
                        .With <ListenerReady>(lr =>
                        {
                            lr.Listener.Notify(new InboundPayload(p.Bytes));
                            nextState = Stay();
                        })
                        .Default(msg =>
                        {
                            throw new AkkaProtocolException(
                                string.Format(
                                    "Unhandled message in state Open(InboundPayload) with type {0}",
                                    msg));
                        });
                    })
                    .Default(d =>
                    {
                        nextState = Stay();
                    });
                })
                .With <HeartbeatTimer>(hrt => @event.StateData.Match()
                                       .With <AssociatedWaitHandler>(awh => nextState = HandleTimers(awh.WrappedHandle))
                                       .With <ListenerReady>(lr => nextState          = HandleTimers(lr.WrappedHandle)))
                .With <DisassociateUnderlying>(du =>
                {
                    AssociationHandle handle = null;
                    @event.StateData.Match()
                    .With <ListenerReady>(lr => handle          = lr.WrappedHandle)
                    .With <AssociatedWaitHandler>(awh => handle = awh.WrappedHandle)
                    .Default(
                        msg =>
                    {
                        throw new AkkaProtocolException(
                            string.Format(
                                "unhandled message in state Open(DisassociateUnderlying) with type {0}", msg));
                    });
                    SendDisassociate(handle, du.Info);
                    nextState = Stop();
                })
                .With <HandleListenerRegistered>(hlr => @event.StateData.Match()
                                                 .With <AssociatedWaitHandler>(awh =>
                {
                    foreach (var msg in awh.Queue)
                    {
                        hlr.Listener.Notify(new InboundPayload(msg));
                    }
                    nextState = Stay().Using(new ListenerReady(hlr.Listener, awh.WrappedHandle));
                }));

                return(nextState);
            });

            OnTermination(@event => @event.StateData.Match()
                          .With <OutboundUnassociated>(ou => ou.StatusCompletionSource.TrySetException(@event.Reason is Failure
                    ? new AkkaProtocolException(@event.Reason.ToString())
                    : new AkkaProtocolException("Transport disassociated before handshake finished")))
                          .With <OutboundUnderlyingAssociated>(oua =>
            {
                Exception associationFailure = null;
                @event.Reason.Match()
                .With <Failure>(f => f.Cause.Match()
                                .With <TimeoutReason>(
                                    timeout =>
                                    associationFailure =
                                        new AkkaProtocolException(timeout.ErrorMessage))
                                .With <ForbiddenUidReason>(
                                    forbidden =>
                                    associationFailure =
                                        new AkkaProtocolException(
                                            "The remote system has a UID that has been quarantined. Association aborted."))
                                .With <DisassociateInfo>(info => associationFailure = DisassociateException(info)))
                .Default(
                    msg =>
                    associationFailure =
                        new AkkaProtocolException(
                            "Transport disassociated before handshake finished"));

                oua.StatusCompletionSource.TrySetException(associationFailure);
                oua.WrappedHandle.Disassociate();
            })
                          .With <AssociatedWaitHandler>(awh =>
            {
                Disassociated disassociateNotification = null;
                if (@event.Reason is Failure && @event.Reason.AsInstanceOf <Failure>().Cause is DisassociateInfo)
                {
                    disassociateNotification =
                        new Disassociated(@event.Reason.AsInstanceOf <Failure>().Cause.AsInstanceOf <DisassociateInfo>());
                }
                else
                {
                    disassociateNotification = new Disassociated(DisassociateInfo.Unknown);
                }
                awh.HandlerListener.ContinueWith(result => result.Result.Notify(disassociateNotification),
                                                 TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.AttachedToParent);
            })
                          .With <ListenerReady>(lr =>
            {
                Disassociated disassociateNotification = null;
                if (@event.Reason is Failure && ((Failure)@event.Reason).Cause is DisassociateInfo)
                {
                    disassociateNotification =
                        new Disassociated(((Failure)@event.Reason).Cause.AsInstanceOf <DisassociateInfo>());
                }
                else
                {
                    disassociateNotification = new Disassociated(DisassociateInfo.Unknown);
                }
                lr.Listener.Notify(disassociateNotification);
                lr.WrappedHandle.Disassociate();
            })
                          .With <InboundUnassociated>(iu =>
                                                      iu.WrappedHandle.Disassociate()));

            /*
             * Set the initial ProtocolStateActor state to CLOSED if OUTBOUND
             * Set the initial ProtocolStateActor state to WAITHANDSHAKE if INBOUND
             * */
            _initialData.Match()
            .With <OutboundUnassociated>(d =>
            {
                // attempt to open underlying transport to the remote address
                // if using Helios, this is where the socket connection is opened.
                d.Transport.Associate(d.RemoteAddress).PipeTo(Self);
                StartWith(AssociationState.Closed, d);
            })
            .With <InboundUnassociated>(d =>
            {
                // inbound transport is opened already inside the ProtocolStateManager
                // therefore we just have to set ourselves as listener and wait for
                // incoming handshake attempts from the client.
                d.WrappedHandle.ReadHandlerSource.SetResult(new ActorHandleEventListener(Self));
                StartWith(AssociationState.WaitHandshake, d);
            });
        }