Example #1
0
File: aipc.c Project: antmd/nanomsg
static void nn_aipc_shutdown (struct nn_fsm *self, int src, int type,
    void *srcptr)
{
    struct nn_aipc *aipc;

    aipc = nn_cont (self, struct nn_aipc, fsm);

    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
        nn_sipc_stop (&aipc->sipc);
        aipc->state = NN_AIPC_STATE_STOPPING_SIPC_FINAL;
    }
    if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING_SIPC_FINAL)) {
        if (!nn_sipc_isidle (&aipc->sipc))
            return;
        nn_usock_stop (&aipc->usock);
        aipc->state = NN_AIPC_STATE_STOPPING;
    }
    if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING)) {
        if (!nn_usock_isidle (&aipc->usock))
            return;
       if (aipc->listener) {
            nn_assert (aipc->listener_owner.fsm);
            nn_usock_swap_owner (aipc->listener, &aipc->listener_owner);
            aipc->listener = NULL;
            aipc->listener_owner.src = 1;
            aipc->listener_owner.fsm = NULL;
        }
        aipc->state = NN_AIPC_STATE_IDLE;
        nn_fsm_stopped (&aipc->fsm, NN_AIPC_STOPPED);
        return;
    }

    nn_fsm_bad_state(aipc->state, src, type);
}
Example #2
0
static void nn_stcp_shutdown(struct nn_fsm *self,int32_t src,int32_t type,NN_UNUSED void *srcptr)
{
    struct nn_stcp *stcp;
    stcp = nn_cont (self, struct nn_stcp, fsm);
    if ( nn_slow(src == NN_FSM_ACTION && type == NN_FSM_STOP) )
    {
        nn_pipebase_stop(&stcp->pipebase);
        nn_streamhdr_stop(&stcp->streamhdr);
        stcp->state = NN_STCP_STATE_STOPPING;
    }
    if ( nn_slow(stcp->state == NN_STCP_STATE_STOPPING) )
    {
        if ( nn_streamhdr_isidle(&stcp->streamhdr) )
        {
            nn_usock_swap_owner(stcp->usock,&stcp->usock_owner);
            stcp->usock = NULL;
            stcp->usock_owner.src = -1;
            stcp->usock_owner.fsm = NULL;
            stcp->state = NN_STCP_STATE_IDLE;
            nn_fsm_stopped (&stcp->fsm,NN_STCP_STOPPED);
            return;
        }
        return;
    }
    nn_fsm_bad_state(stcp->state,src,type);
}
Example #3
0
static void nn_sws_shutdown (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_sws *sws;

    sws = nn_cont (self, struct nn_sws, fsm);

    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
        /*  TODO: Consider sending a close code here? */
        nn_pipebase_stop (&sws->pipebase);
        nn_wshdr_stop (&sws->wshdr);
        sws->state = NN_SWS_STATE_STOPPING;
    }
    if (nn_slow (sws->state == NN_SWS_STATE_STOPPING)) {
        if (nn_wshdr_isidle (&sws->wshdr)) {
            nn_usock_swap_owner (sws->usock, &sws->usock_owner);
            sws->usock = NULL;
            sws->usock_owner.src = -1;
            sws->usock_owner.fsm = NULL;
            sws->state = NN_SWS_STATE_IDLE;
            nn_fsm_stopped (&sws->fsm, NN_SWS_RETURN_STOPPED);
            return;
        }
        return;
    }

    nn_fsm_bad_state (sws->state, src, type);
}
Example #4
0
File: ep.c Project: WongTai/nanomsg
static void nn_ep_shutdown (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_ep *ep;

    ep = nn_cont (self, struct nn_ep, fsm);

    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
        ep->epbase->vfptr->stop (ep->epbase);
        ep->state = NN_EP_STATE_STOPPING;
        return;
    }
    if (nn_slow (ep->state == NN_EP_STATE_STOPPING)) {
        if (src != NN_FSM_ACTION || type != NN_EP_ACTION_STOPPED)
            return;
        ep->state = NN_EP_STATE_IDLE;
        nn_fsm_stopped (&ep->fsm, NN_EP_STOPPED);
        return;
    }

    nn_fsm_bad_state (ep->state, src, type);
}
Example #5
0
static void nn_aws_shutdown (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_aws *aws;

    aws = nn_cont (self, struct nn_aws, fsm);
    nn_assert (aws);

    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
        if (!nn_sws_isidle (&aws->sws)) {
            nn_epbase_stat_increment (aws->epbase,
                NN_STAT_DROPPED_CONNECTIONS, 1);
            nn_sws_stop (&aws->sws);
        }
        aws->state = NN_AWS_STATE_STOPPING_SWS_FINAL;
    }
    if (nn_slow (aws->state == NN_AWS_STATE_STOPPING_SWS_FINAL)) {
        if (!nn_sws_isidle (&aws->sws))
            return;
        nn_usock_stop (&aws->usock);
        aws->state = NN_AWS_STATE_STOPPING;
    }
    if (nn_slow (aws->state == NN_AWS_STATE_STOPPING)) {
        if (!nn_usock_isidle (&aws->usock))
            return;
       if (aws->listener) {
            nn_assert (aws->listener_owner.fsm);
            nn_usock_swap_owner (aws->listener, &aws->listener_owner);
            aws->listener = NULL;
            aws->listener_owner.src = -1;
            aws->listener_owner.fsm = NULL;
        }
        aws->state = NN_AWS_STATE_IDLE;
        nn_fsm_stopped (&aws->fsm, NN_AWS_STOPPED);
        return;
    }

    nn_fsm_bad_action (aws->state, src, type);
}
Example #6
0
static void nn_timer_shutdown (struct nn_fsm *self, int src, int type,
    void *srcptr)
{
    struct nn_timer *timer;

    timer = nn_cont (self, struct nn_timer, fsm);

    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
        nn_worker_execute (timer->worker, &timer->stop_task);
        timer->state = NN_TIMER_STATE_STOPPING;
        return;
    }
    if (nn_slow (timer->state == NN_TIMER_STATE_STOPPING)) {
        if (src != NN_TIMER_SRC_STOP_TASK)
            return;
        nn_assert (type == NN_WORKER_TASK_EXECUTE);
        nn_worker_rm_timer (timer->worker, &timer->wtimer);
        timer->state = NN_TIMER_STATE_IDLE;
        nn_fsm_stopped (&timer->fsm, NN_TIMER_STOPPED);
        return;
    }

    nn_fsm_bad_state(timer->state, src, type);
}
Example #7
0
static void nn_usock_shutdown (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_usock *usock;

    usock = nn_cont (self, struct nn_usock, fsm);

    if (nn_internal_tasks (usock, src, type))
        return;

    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {

        /*  Socket in ACCEPTING or CANCELLING state cannot be closed.
            Stop the socket being accepted first. */
        nn_assert (usock->state != NN_USOCK_STATE_ACCEPTING &&
            usock->state != NN_USOCK_STATE_CANCELLING);

        usock->errnum = 0;

        /*  Synchronous stop. */
        if (usock->state == NN_USOCK_STATE_IDLE)
            goto finish3;
        if (usock->state == NN_USOCK_STATE_DONE)
            goto finish2;
        if (usock->state == NN_USOCK_STATE_STARTING ||
              usock->state == NN_USOCK_STATE_ACCEPTED ||
              usock->state == NN_USOCK_STATE_ACCEPTING_ERROR ||
              usock->state == NN_USOCK_STATE_LISTENING)
            goto finish1;

        /*  When socket that's being accepted is asked to stop, we have to
            ask the listener socket to stop accepting first. */
        if (usock->state == NN_USOCK_STATE_BEING_ACCEPTED) {
            nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_CANCEL);
            usock->state = NN_USOCK_STATE_STOPPING_ACCEPT;
            return;
        }

        /*  Asynchronous stop. */
        if (usock->state != NN_USOCK_STATE_REMOVING_FD)
            nn_usock_async_stop (usock);
        usock->state = NN_USOCK_STATE_STOPPING;
        return;
    }
    if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING_ACCEPT)) {
        nn_assert (src == NN_FSM_ACTION && type == NN_USOCK_ACTION_DONE);
        goto finish2;
    }
    if (nn_slow (usock->state == NN_USOCK_STATE_STOPPING)) {
        if (src != NN_USOCK_SRC_TASK_STOP)
            return;
        nn_assert (type == NN_WORKER_TASK_EXECUTE);
        nn_worker_rm_fd (usock->worker, &usock->wfd);
finish1:
        nn_closefd (usock->s);
        usock->s = -1;
finish2:
        usock->state = NN_USOCK_STATE_IDLE;
        nn_fsm_stopped (&usock->fsm, NN_USOCK_STOPPED);
finish3:
        return;
    }

    nn_fsm_bad_state(usock->state, src, type);
}
Example #8
0
static void nn_aipc_handler (struct nn_fsm *self, int src, int type,
    void *srcptr)
{
    struct nn_aipc *aipc;

    aipc = nn_cont (self, struct nn_aipc, fsm);

/******************************************************************************/
/*  STOP procedure.                                                           */
/******************************************************************************/
    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
        nn_sipc_stop (&aipc->sipc);
        aipc->state = NN_AIPC_STATE_STOPPING_SIPC_FINAL;
    }
    if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING_SIPC_FINAL)) {
        if (!nn_sipc_isidle (&aipc->sipc))
            return;
        nn_usock_stop (&aipc->usock);
        aipc->state = NN_AIPC_STATE_STOPPING;
    }
    if (nn_slow (aipc->state == NN_AIPC_STATE_STOPPING)) {
        if (!nn_usock_isidle (&aipc->usock))
            return;
       if (aipc->listener) {
            nn_assert (aipc->listener_owner.fsm);
            nn_usock_swap_owner (aipc->listener, &aipc->listener_owner);
            aipc->listener = NULL;
            aipc->listener_owner.src = 1;
            aipc->listener_owner.fsm = NULL;
        }
        aipc->state = NN_AIPC_STATE_IDLE;
        nn_fsm_stopped (&aipc->fsm, NN_AIPC_STOPPED);
        return;
    }

    switch (aipc->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/*  The state machine wasn't yet started.                                     */
/******************************************************************************/
    case NN_AIPC_STATE_IDLE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_FSM_START:
                nn_usock_accept (&aipc->usock, aipc->listener);
                aipc->state = NN_AIPC_STATE_ACCEPTING;
                return;
            default:
                nn_fsm_bad_action (aipc->state, src, type);
            }

        default:
            nn_fsm_bad_source (aipc->state, src, type);
        }

/******************************************************************************/
/*  ACCEPTING state.                                                          */
/*  Waiting for incoming connection.                                          */
/******************************************************************************/
    case NN_AIPC_STATE_ACCEPTING:
        switch (src) {

        case NN_AIPC_SRC_USOCK:
            switch (type) {
            case NN_USOCK_ACCEPTED:

                /*  Return ownership of the listening socket to the parent. */
                nn_usock_swap_owner (aipc->listener, &aipc->listener_owner);
                aipc->listener = NULL;
                aipc->listener_owner.src = -1;
                aipc->listener_owner.fsm = NULL;
                nn_fsm_raise (&aipc->fsm, &aipc->accepted, NN_AIPC_ACCEPTED);

                /*  Start the sipc state machine. */
                nn_usock_activate (&aipc->usock);
                nn_sipc_start (&aipc->sipc, &aipc->usock);
                aipc->state = NN_AIPC_STATE_ACTIVE;

                return;

            default:
                nn_fsm_bad_action (aipc->state, src, type);
            }

        default:
            nn_fsm_bad_source (aipc->state, src, type);
        }

/******************************************************************************/
/*  ACTIVE state.                                                             */
/******************************************************************************/
    case NN_AIPC_STATE_ACTIVE:
        switch (src) {

        case NN_AIPC_SRC_SIPC:
            switch (type) {
            case NN_SIPC_ERROR:
                nn_sipc_stop (&aipc->sipc);
                aipc->state = NN_AIPC_STATE_STOPPING_SIPC;
                return;
            default:
                nn_fsm_bad_action (aipc->state, src, type);
            }

        default:
            nn_fsm_bad_source (aipc->state, src, type);
        }

/******************************************************************************/
/*  STOPPING_SIPC state.                                                      */
/******************************************************************************/
    case NN_AIPC_STATE_STOPPING_SIPC:
        switch (src) {

        case NN_AIPC_SRC_SIPC:
            switch (type) {
            case NN_SIPC_STOPPED:
                nn_usock_stop (&aipc->usock);
                aipc->state = NN_AIPC_STATE_STOPPING_USOCK;
                return;
            default:
                nn_fsm_bad_action (aipc->state, src, type);
            }

        default:
            nn_fsm_bad_source (aipc->state, src, type);
        }

/******************************************************************************/
/*  STOPPING_USOCK state.                                                      */
/******************************************************************************/
    case NN_AIPC_STATE_STOPPING_USOCK:
        switch (src) {

        case NN_AIPC_SRC_USOCK:
            switch (type) {
            case NN_USOCK_STOPPED:
                nn_fsm_raise (&aipc->fsm, &aipc->done, NN_AIPC_ERROR);
                aipc->state = NN_AIPC_STATE_DONE;
                return;
            default:
                nn_fsm_bad_action (aipc->state, src, type);
            }

        default:
            nn_fsm_bad_source (aipc->state, src, type);
        }

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (aipc->state, src, type);
    }
}
Example #9
0
static void nn_streamhdr_handler (struct nn_fsm *self, int src, int type,
    void *srcptr)
{
    struct nn_streamhdr *streamhdr;
    struct nn_iovec iovec;
    int protocol;

    streamhdr = nn_cont (self, struct nn_streamhdr, fsm);

/******************************************************************************/
/*  STOP procedure.                                                           */
/******************************************************************************/
    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
        nn_timer_stop (&streamhdr->timer);
        streamhdr->state = NN_STREAMHDR_STATE_STOPPING;
    }
    if (nn_slow (streamhdr->state == NN_STREAMHDR_STATE_STOPPING)) {
        if (!nn_timer_isidle (&streamhdr->timer))
            return;
        streamhdr->state = NN_STREAMHDR_STATE_IDLE;
        nn_fsm_stopped (&streamhdr->fsm, NN_STREAMHDR_STOPPED);
        return;
    }

    switch (streamhdr->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/******************************************************************************/
    case NN_STREAMHDR_STATE_IDLE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_FSM_START:
                nn_timer_start (&streamhdr->timer, 1000);
                iovec.iov_base = streamhdr->protohdr;
                iovec.iov_len = sizeof (streamhdr->protohdr);
                nn_usock_send (streamhdr->usock, &iovec, 1);
                streamhdr->state = NN_STREAMHDR_STATE_SENDING;
                return;
            default:
                nn_fsm_bad_action (streamhdr->state, src, type);
            }

        default:
            nn_fsm_bad_source (streamhdr->state, src, type);
        }

/******************************************************************************/
/*  SENDING state.                                                            */
/******************************************************************************/
    case NN_STREAMHDR_STATE_SENDING:
        switch (src) {

        case NN_STREAMHDR_SRC_USOCK:
            switch (type) {
            case NN_USOCK_SENT:
                nn_usock_recv (streamhdr->usock, streamhdr->protohdr,
                    sizeof (streamhdr->protohdr));
                streamhdr->state = NN_STREAMHDR_STATE_RECEIVING;
                return;
            case NN_USOCK_ERROR:
                nn_timer_stop (&streamhdr->timer);
                streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR;
                return;
            default:
                nn_fsm_bad_action (streamhdr->state, src, type);
            }

        case NN_STREAMHDR_SRC_TIMER:
            switch (type) {
            case NN_TIMER_TIMEOUT:
                nn_timer_stop (&streamhdr->timer);
                streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR;
                return;
            default:
                nn_fsm_bad_action (streamhdr->state, src, type);
            }

        default:
            nn_fsm_bad_source (streamhdr->state, src, type);
        }

/******************************************************************************/
/*  RECEIVING state.                                                          */
/******************************************************************************/
    case NN_STREAMHDR_STATE_RECEIVING:
        switch (src) {

        case NN_STREAMHDR_SRC_USOCK:
            switch (type) {
            case NN_USOCK_RECEIVED:

                /*  Here we are checking whether the peer speaks the same
                    protocol as this socket. */
                if (memcmp (streamhdr->protohdr, "\0SP\0", 4) != 0)
                    goto invalidhdr;
                protocol = nn_gets (streamhdr->protohdr + 4);
                if (!nn_pipebase_ispeer (streamhdr->pipebase, protocol))
                    goto invalidhdr;
                nn_timer_stop (&streamhdr->timer);
                streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_DONE;
                return;
            case NN_USOCK_ERROR:
invalidhdr:
                nn_timer_stop (&streamhdr->timer);
                streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR;
                return;
            default:
                nn_assert (0);
            }

        case NN_STREAMHDR_SRC_TIMER:
            switch (type) {
            case NN_TIMER_TIMEOUT:
                nn_timer_stop (&streamhdr->timer);
                streamhdr->state = NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR;
                return;
            default:
                nn_fsm_bad_action (streamhdr->state, src, type);
            }

        default:
            nn_fsm_bad_source (streamhdr->state, src, type);
        }

/******************************************************************************/
/*  STOPPING_TIMER_ERROR state.                                               */
/******************************************************************************/
    case NN_STREAMHDR_STATE_STOPPING_TIMER_ERROR:
        switch (src) {

        case NN_STREAMHDR_SRC_TIMER:
            switch (type) {
            case NN_TIMER_STOPPED:
                nn_usock_swap_owner (streamhdr->usock, &streamhdr->usock_owner);
                streamhdr->usock = NULL;
                streamhdr->usock_owner.src = -1;
                streamhdr->usock_owner.fsm = NULL;
                streamhdr->state = NN_STREAMHDR_STATE_DONE;
                nn_fsm_raise (&streamhdr->fsm, &streamhdr->done,
                    NN_STREAMHDR_ERROR);
                return;
            default:
                nn_fsm_bad_action (streamhdr->state, src, type);
            }

        default:    
            nn_fsm_bad_source (streamhdr->state, src, type);
        }

/******************************************************************************/
/*  STOPPING_TIMER_DONE state.                                                */
/******************************************************************************/
    case NN_STREAMHDR_STATE_STOPPING_TIMER_DONE:
        switch (src) {

        case NN_STREAMHDR_SRC_TIMER:
            switch (type) {
            case NN_TIMER_STOPPED:
                nn_usock_swap_owner (streamhdr->usock, &streamhdr->usock_owner);
                streamhdr->usock = NULL;
                streamhdr->usock_owner.src = -1;
                streamhdr->usock_owner.fsm = NULL;
                streamhdr->state = NN_STREAMHDR_STATE_DONE;
                nn_fsm_raise (&streamhdr->fsm, &streamhdr->done,
                    NN_STREAMHDR_OK);
                return;
            default:
                nn_fsm_bad_action (streamhdr->state, src, type);
            }

        default:       
            nn_fsm_bad_source (streamhdr->state, src, type);
        }

/******************************************************************************/
/*  DONE state.                                                               */
/*  The header exchange was either done successfully of failed. There's       */
/*  nothing that can be done in this state except stopping the object.        */
/******************************************************************************/
    case NN_STREAMHDR_STATE_DONE:
        nn_fsm_bad_source (streamhdr->state, src, type);

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (streamhdr->state, src, type);
    }
}
Example #10
0
static void nn_timer_handler (struct nn_fsm *self, int src, int type,
    void *srcptr)
{
    struct nn_timer *timer;

    timer = nn_cont (self, struct nn_timer, fsm);

/******************************************************************************/
/*  STOP procedure.                                                           */
/******************************************************************************/
    if (nn_slow (srcptr == NULL && type == NN_FSM_STOP)) {
        nn_worker_execute (timer->worker, &timer->stop_task);
        timer->state = NN_TIMER_STATE_STOPPING;
        return;
    }
    if (nn_slow (timer->state == NN_TIMER_STATE_STOPPING)) {
        if (srcptr != &timer->stop_task)
            return;
        nn_assert (type == NN_WORKER_TASK_EXECUTE);
        nn_worker_rm_timer (timer->worker, &timer->wtimer);
        timer->state = NN_TIMER_STATE_IDLE;
        nn_fsm_stopped (&timer->fsm, NN_TIMER_STOPPED);
        return;
    }

    switch (timer->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/******************************************************************************/
    case NN_TIMER_STATE_IDLE:
        if (srcptr == NULL) {
            switch (type) {
            case NN_FSM_START:

                /*  Send start event to the worker thread. */
                nn_worker_execute (timer->worker, &timer->start_task);
                timer->state = NN_TIMER_STATE_ACTIVE;
                return;
            default:
                nn_assert (0);
            }
        }
        nn_assert (0);

/******************************************************************************/
/*  ACTIVE state.                                                             */
/******************************************************************************/
    case NN_TIMER_STATE_ACTIVE:
        if (srcptr == &timer->start_task) {
            nn_assert (type == NN_WORKER_TASK_EXECUTE);
            nn_assert (timer->timeout >= 0);
            nn_worker_add_timer (timer->worker, timer->timeout,
                &timer->wtimer);
            timer->timeout = -1;
            return;
        }
        if (srcptr == &timer->wtimer) {
            switch (type) {
            case NN_WORKER_TIMER_TIMEOUT:

                /*  Notify the user about the timeout. */
                nn_assert (timer->timeout == -1);
                nn_fsm_raise (&timer->fsm, &timer->done, NN_TIMER_TIMEOUT);
                return;

            default:
                nn_assert (0);
            }
        }
        nn_assert (0);

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_assert (0);
    }
}
Example #11
0
static void nn_stcp_handler (struct nn_fsm *self, int src, int type,
    void *srcptr)
{
    int rc;
    struct nn_stcp *stcp;
    uint64_t size;

    stcp = nn_cont (self, struct nn_stcp, fsm);

/******************************************************************************/
/*  STOP procedure.                                                           */
/******************************************************************************/
    if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
        nn_pipebase_stop (&stcp->pipebase);
        nn_streamhdr_stop (&stcp->streamhdr);
        stcp->state = NN_STCP_STATE_STOPPING;
    }
    if (nn_slow (stcp->state == NN_STCP_STATE_STOPPING)) {
        if (nn_streamhdr_isidle (&stcp->streamhdr)) {
            nn_usock_swap_owner (stcp->usock, &stcp->usock_owner);
            stcp->usock = NULL;
            stcp->usock_owner.src = -1;
            stcp->usock_owner.fsm = NULL;
            stcp->state = NN_STCP_STATE_IDLE;
            nn_fsm_stopped (&stcp->fsm, NN_STCP_STOPPED);
            return;
        }
        return;
    }

    switch (stcp->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/******************************************************************************/
    case NN_STCP_STATE_IDLE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_FSM_START:
                nn_streamhdr_start (&stcp->streamhdr, stcp->usock,
                    &stcp->pipebase);
                stcp->state = NN_STCP_STATE_PROTOHDR;
                return;
            default:
                nn_assert (0);
            }

        default:
            nn_assert (0);
        }

/******************************************************************************/
/*  PROTOHDR state.                                                           */
/******************************************************************************/
    case NN_STCP_STATE_PROTOHDR:
        switch (src) {

        case NN_STCP_SRC_STREAMHDR:
            switch (type) {
            case NN_STREAMHDR_OK:

                /*  Before moving to the active state stop the streamhdr
                    state machine. */
                nn_streamhdr_stop (&stcp->streamhdr);
                stcp->state = NN_STCP_STATE_STOPPING_STREAMHDR;
                return;

            case NN_STREAMHDR_ERROR:

                /* Raise the error and move directly to the DONE state.
                   streamhdr object will be stopped later on. */
                stcp->state = NN_STCP_STATE_DONE;
                nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR);
                return;

            default:
                nn_assert (0);
            }

        default:
            nn_assert (0);
        }

/******************************************************************************/
/*  STOPPING_STREAMHDR state.                                                 */
/******************************************************************************/
    case NN_STCP_STATE_STOPPING_STREAMHDR:
        switch (src) {

        case NN_STCP_SRC_STREAMHDR:
            switch (type) {
            case NN_STREAMHDR_STOPPED:

                 /*  Start the pipe. */
                 rc = nn_pipebase_start (&stcp->pipebase);
                 errnum_assert (rc == 0, -rc);
                 
                 /*  Start receiving a message in asynchronous manner. */
                 stcp->instate = NN_STCP_INSTATE_HDR;
                 nn_usock_recv (stcp->usock, &stcp->inhdr,
                     sizeof (stcp->inhdr));

                 /*  Mark the pipe as available for sending. */
                 stcp->outstate = NN_STCP_OUTSTATE_IDLE;

                 stcp->state = NN_STCP_STATE_ACTIVE;
                 return;

            default:
                nn_assert (0);
            }

        default:
            nn_assert (0);
        }

/******************************************************************************/
/*  ACTIVE state.                                                             */
/******************************************************************************/
    case NN_STCP_STATE_ACTIVE:
        switch (src) {

        case NN_STCP_SRC_USOCK:
            switch (type) {
            case NN_USOCK_SENT:

                /*  The message is now fully sent. */
                nn_assert (stcp->outstate == NN_STCP_OUTSTATE_SENDING);
                stcp->outstate = NN_STCP_OUTSTATE_IDLE;
                nn_msg_term (&stcp->outmsg);
                nn_msg_init (&stcp->outmsg, 0);
                nn_pipebase_sent (&stcp->pipebase);
                return;

            case NN_USOCK_RECEIVED:

                switch (stcp->instate) {
                case NN_STCP_INSTATE_HDR:

                    /*  Message header was received. Allocate memory for the
                        message. */
                    size = nn_getll (stcp->inhdr);
                    nn_msg_term (&stcp->inmsg);
                    nn_msg_init (&stcp->inmsg, (size_t) size);

                    /*  Special case when size of the message body is 0. */
                    if (!size) {
                        stcp->instate = NN_STCP_INSTATE_HASMSG;
                        nn_pipebase_received (&stcp->pipebase);
                        return;
                    }

                    /*  Start receiving the message body. */
                    stcp->instate = NN_STCP_INSTATE_BODY;
                    nn_usock_recv (stcp->usock,
                        nn_chunkref_data (&stcp->inmsg.body), (size_t) size);

                    return;

                case NN_STCP_INSTATE_BODY:

                    /*  Message body was received. Notify the owner that it
                        can receive it. */
                    stcp->instate = NN_STCP_INSTATE_HASMSG;
                    nn_pipebase_received (&stcp->pipebase);

                    return;

                default:
                    nn_assert (0);
                }

            case NN_USOCK_ERROR:
                nn_pipebase_stop (&stcp->pipebase);
                stcp->state = NN_STCP_STATE_DONE;
                nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR);
                return;

            default:
                nn_assert (0);
            }

        default:
            nn_assert (0);
        }

/******************************************************************************/
/*  DONE state.                                                               */
/*  The underlying connection is closed. There's nothing that can be done in  */
/*  this state except stopping the object.                                    */
/******************************************************************************/
    case NN_STCP_STATE_DONE:
        nn_assert (0);

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_assert (0);
    }
}