Exemple #1
0
void nn_stream_init (struct nn_stream *self, struct nn_epbase *epbase,
    struct nn_usock *usock)
{
    int rc;
    int protocol;
    size_t sz;
    struct nn_iobuf iobuf;

    /*  Redirect the underlying socket's events to this state machine. */
    self->usock = usock;
    self->sink = &nn_stream_state_start;
    self->original_sink = nn_usock_setsink (usock, &self->sink);

    /*  Initialise the pipe to communicate with the user. */
    rc = nn_pipebase_init (&self->pipebase, &nn_stream_pipebase_vfptr, epbase);
    nn_assert (rc == 0);

    nn_msg_init (&self->inmsg, 0);
    nn_msg_init (&self->outmsg, 0);

    /*  Start the header timeout timer. */
    nn_timer_init (&self->hdr_timeout, &self->sink, usock->cp);
    nn_timer_start (&self->hdr_timeout, 1000);

    /*  Send the protocol header. */
    sz = sizeof (protocol);
    nn_epbase_getopt (epbase, NN_SOL_SOCKET, NN_PROTOCOL, &protocol, &sz);
    errnum_assert (rc == 0, -rc);
    nn_assert (sz == sizeof (protocol));
    memcpy (self->protohdr, "\0\0SP\0\0\0\0", 8);
    nn_puts (self->protohdr + 4, (uint16_t) protocol);
    iobuf.iov_base = self->protohdr;
    iobuf.iov_len = 8;
    nn_usock_send (usock, &iobuf, 1);
}
Exemple #2
0
static void nn_req_action_send (struct nn_req *self)
{
    int rc;
    struct nn_msg msg;

    /*  Send the request. */
    nn_msg_cp (&msg, &self->request);
    rc = nn_xreq_send (&self->xreq.sockbase, &msg);

    /*  If the request cannot be sent at the moment wait till
        new outbound pipe arrives. */
    if (nn_slow (rc == -EAGAIN)) {
        nn_msg_term (&msg);
        self->state = NN_REQ_STATE_DELAYED;
        return;
    }

    /*  Request was successfully sent. Set up the re-send timer
        in case the request gets lost somewhere further out
        in the topology. */
    if (nn_fast (rc == 0)) {
        nn_timer_start (&self->timer, self->resend_ivl);
        self->state = NN_REQ_STATE_ACTIVE;
        return;
    }

    /*  Unexpected error. */
    errnum_assert (0, -rc);
}
Exemple #3
0
static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg)
{
    int rc;
    struct nn_surveyor *surveyor;

    surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase);

    /*  Cancel any ongoing survey. */
    if (nn_slow (surveyor->flags & NN_SURVEYOR_INPROGRESS)) {
        surveyor->flags &= ~NN_SURVEYOR_INPROGRESS;
        nn_timer_stop (&surveyor->deadline_timer);
    }

    /*  Generate new survey ID. */
    ++surveyor->surveyid;

    /*  Tag the survey body with survey ID. */
    nn_assert (nn_chunkref_size (&msg->hdr) == 0);
    nn_chunkref_term (&msg->hdr);
    nn_chunkref_init (&msg->hdr, 4);
    nn_putl (nn_chunkref_data (&msg->hdr), surveyor->surveyid);

    /*  Send the survey. */
    rc = nn_xsurveyor_send (&surveyor->xsurveyor.sockbase, msg);
    errnum_assert (rc == 0, -rc);

    surveyor->flags |= NN_SURVEYOR_INPROGRESS;

    /*  Set up the re-send timer. */
    nn_timer_start (&surveyor->deadline_timer, surveyor->deadline);

    return 0;
}
Exemple #4
0
static void nn_cstream_closing_closed (const struct nn_cp_sink **self,
    struct nn_usock *usock)
{
    int rc;
    struct nn_cstream *cstream;
    int sndbuf;
    int rcvbuf;
    size_t sz;

    cstream = nn_cont (self, struct nn_cstream, sink);

    /*  Get the current values of NN_SNDBUF and NN_RCVBUF options. */    
    sz = sizeof (sndbuf);
    nn_epbase_getopt (&cstream->epbase, NN_SOL_SOCKET, NN_SNDBUF, &sndbuf, &sz);
    nn_assert (sz == sizeof (sndbuf));
    sz = sizeof (rcvbuf);
    nn_epbase_getopt (&cstream->epbase, NN_SOL_SOCKET, NN_RCVBUF, &rcvbuf, &sz);
    nn_assert (sz == sizeof (rcvbuf));

    /*  Create new socket. */
    rc = cstream->initsockfn (&cstream->usock, sndbuf, rcvbuf,
        nn_epbase_getcp (&cstream->epbase));
    errnum_assert (rc == 0, -rc);
    nn_usock_setsink (&cstream->usock, &cstream->sink);

    /*  Wait for the specified period. */
    cstream->sink = &nn_cstream_state_waiting;
    nn_timer_start (&cstream->retry_timer,
        nn_cstream_compute_retry_ivl (cstream));
}
Exemple #5
0
static void nn_cstream_waiting_timeout (const struct nn_cp_sink **self,
    struct nn_timer *timer)
{
    int rc;
    struct nn_cstream *cstream;
    struct sockaddr_storage ss;
    socklen_t sslen;

    cstream = nn_cont (self, struct nn_cstream, sink);

    /*  Retry timer expired. Now we'll try to resolve the address. */
    rc = cstream->resolvefn (nn_epbase_getaddr (&cstream->epbase), &ss, &sslen);

    /*  If the address resolution have failed, wait and re-try. */
    if (rc < 0) {
        cstream->sink = &nn_cstream_state_waiting;
        nn_timer_start (&cstream->retry_timer,
            nn_cstream_compute_retry_ivl (cstream));
        return;
    }

    /*  Open the socket and start connecting. */
    cstream->sink = &nn_cstream_state_connecting;
    nn_usock_connect (&cstream->usock, (struct sockaddr*) &ss, sslen);
}
Exemple #6
0
void nn_backoff_start (struct nn_backoff *self)
{
     int timeout;

     /*  Start the timer for the actual n value. If the interval haven't yet
         exceeded the maximum, double the next timeout value. */
     timeout = (self->n - 1) * self->minivl;
     if (timeout > self->maxivl)
         timeout = self->maxivl;
     else
         self->n *= 2;
     nn_timer_start (&self->timer, timeout);
}
Exemple #7
0
static int nn_req_send (struct nn_sockbase *self, struct nn_msg *msg)
{
    int rc;
    struct nn_req *req;

    req = nn_cont (self, struct nn_req, xreq.sockbase);

    /*  If there's a request in progress, cancel it. */
    if (nn_slow (req->state != NN_REQ_STATE_IDLE)) {
        if (req->state == NN_REQ_STATE_UNSENT ||
              req->state == NN_REQ_STATE_SENT)
            nn_msg_term (&req->request);
        if (req->state == NN_REQ_STATE_RECEIVED)
            nn_msg_term (&req->reply);
        nn_timer_term (&req->resend_timer);
        req->state = NN_REQ_STATE_IDLE;
    }

    /*  Generate new request ID for the new request and put it into message
        header. The most important bit is set to 1 to indicate that this is
        the bottom of the backtrace stack. */
    ++req->reqid;
    nn_assert (nn_chunkref_size (&msg->hdr) == 0);
    nn_chunkref_term (&msg->hdr);
    nn_chunkref_init (&msg->hdr, 4);
    nn_putl (nn_chunkref_data (&msg->hdr), req->reqid | 0x80000000);

    /*  Store the message so that it can be re-sent if there's no reply. 
        Then make a copy of it and send it. */
    nn_msg_cp (&req->request, msg);
    rc = nn_xreq_send (&req->xreq.sockbase, msg);
    errnum_assert (rc == 0 || rc == -EAGAIN, -rc);

    /*  If the request cannot be sent at the moment switch to UNSENT state.
        It will be sent as soon as a new outbound pipe arrives. */
    if (nn_slow (rc == -EAGAIN)) {
        nn_msg_term (msg);
        req->state = NN_REQ_STATE_UNSENT;
        return 0;
    }

    /*  If the request was successgfully sent set up the re-send timer in case
        it get lost somewhere further out in the topology. */
    nn_timer_start (&req->resend_timer, req->resend_ivl);
    req->state = NN_REQ_STATE_SENT;

    return 0;
}
Exemple #8
0
static void nn_req_timeout (const struct nn_cp_sink **self,
    struct nn_timer *timer)
{
    int rc;
    struct nn_req *req;
    struct nn_msg msg;

    req = nn_cont (self, struct nn_req, sink);
    nn_assert (req->state == NN_REQ_STATE_SENT);

    /*  Re-send the request. If it cannot be sent, just drop it. */
    nn_msg_cp (&msg, &req->request);
    rc = nn_xreq_send (&req->xreq.sockbase, &msg);
    errnum_assert (rc == 0 || rc == -EAGAIN, -rc);
    if (nn_slow (rc == -EAGAIN))
        nn_msg_term (&msg);

    /*  Set up the next re-send timer. */
    nn_timer_start (&req->resend_timer, req->resend_ivl);
}
Exemple #9
0
static void nn_surveyor_handler (struct nn_fsm *self, int src, int type,
    NN_UNUSED void *srcptr)
{
    struct nn_surveyor *surveyor;

    surveyor = nn_cont (self, struct nn_surveyor, fsm);

    switch (surveyor->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/*  The socket was created recently.                                          */
/******************************************************************************/
    case NN_SURVEYOR_STATE_IDLE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_FSM_START:
                surveyor->state = NN_SURVEYOR_STATE_PASSIVE;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

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

/******************************************************************************/
/*  PASSIVE state.                                                            */
/*  There's no survey going on.                                               */
/******************************************************************************/
    case NN_SURVEYOR_STATE_PASSIVE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_SURVEYOR_ACTION_START:
                nn_surveyor_resend (surveyor);
                nn_timer_start (&surveyor->timer, surveyor->deadline);
                surveyor->state = NN_SURVEYOR_STATE_ACTIVE;
                return;

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

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

/******************************************************************************/
/*  ACTIVE state.                                                             */
/*  Survey was sent, waiting for responses.                                   */
/******************************************************************************/
    case NN_SURVEYOR_STATE_ACTIVE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_SURVEYOR_ACTION_CANCEL:
                nn_timer_stop (&surveyor->timer);
                surveyor->state = NN_SURVEYOR_STATE_CANCELLING;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

        case NN_SURVEYOR_SRC_DEADLINE_TIMER:
            switch (type) {
            case NN_TIMER_TIMEOUT:
                nn_timer_stop (&surveyor->timer);
                surveyor->state = NN_SURVEYOR_STATE_STOPPING_TIMER;
                surveyor->timedout = NN_SURVEYOR_TIMEDOUT;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

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

/******************************************************************************/
/*  CANCELLING state.                                                         */
/*  Survey was cancelled, but the old timer haven't stopped yet. The new      */
/*  survey thus haven't been sent and is stored in 'tosend'.                  */
/******************************************************************************/
    case NN_SURVEYOR_STATE_CANCELLING:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_SURVEYOR_ACTION_CANCEL:
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

        case NN_SURVEYOR_SRC_DEADLINE_TIMER:
            switch (type) {
            case NN_TIMER_STOPPED:
                nn_surveyor_resend (surveyor);
                nn_timer_start (&surveyor->timer, surveyor->deadline);
                surveyor->state = NN_SURVEYOR_STATE_ACTIVE;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

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

/******************************************************************************/
/*  STOPPING_TIMER state.                                                     */
/*  Survey timeout expired. Now we are stopping the timer.                    */
/******************************************************************************/
    case NN_SURVEYOR_STATE_STOPPING_TIMER:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_SURVEYOR_ACTION_CANCEL:
                surveyor->state = NN_SURVEYOR_STATE_CANCELLING;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

        case NN_SURVEYOR_SRC_DEADLINE_TIMER:
            switch (type) {
            case NN_TIMER_STOPPED:
                surveyor->state = NN_SURVEYOR_STATE_PASSIVE;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

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

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (surveyor->state, src, type);
    }
}
Exemple #10
0
static void nn_surveyor_handler (struct nn_fsm *self, int src, int type,
    void *srcptr)
{
    int rc;
    struct nn_surveyor *surveyor;

    surveyor = nn_cont (self, struct nn_surveyor, fsm);

/******************************************************************************/
/*  STOP procedure.                                                           */
/******************************************************************************/
    if (nn_slow (src== NN_FSM_ACTION && type == NN_FSM_STOP)) {
        nn_timer_stop (&surveyor->timer);
        surveyor->state = NN_SURVEYOR_STATE_STOPPING;
    }
    if (nn_slow (surveyor->state == NN_SURVEYOR_STATE_STOPPING)) {
        if (!nn_timer_isidle (&surveyor->timer))
            return;
        surveyor->state = NN_SURVEYOR_STATE_IDLE;
        nn_fsm_stopped_noevent (&surveyor->fsm);
        nn_sockbase_stopped (&surveyor->xsurveyor.sockbase);
        return;
    }

    switch (surveyor->state) {

/******************************************************************************/
/*  IDLE state.                                                               */
/*  The socket was created recently.                                          */
/******************************************************************************/
    case NN_SURVEYOR_STATE_IDLE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_FSM_START:
                surveyor->state = NN_SURVEYOR_STATE_PASSIVE;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

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

/******************************************************************************/
/*  PASSIVE state.                                                            */
/*  There's no survey going on.                                               */
/******************************************************************************/
    case NN_SURVEYOR_STATE_PASSIVE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_SURVEYOR_ACTION_START:
                rc = nn_xsurveyor_send (&surveyor->xsurveyor.sockbase,
                    &surveyor->tosend);
                errnum_assert (rc == 0, -rc);
                nn_timer_start (&surveyor->timer, surveyor->deadline);
                surveyor->state = NN_SURVEYOR_STATE_ACTIVE;
                return;

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

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

/******************************************************************************/
/*  ACTIVE state.                                                             */
/*  Survey was sent, waiting for responses.                                   */
/******************************************************************************/
    case NN_SURVEYOR_STATE_ACTIVE:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_SURVEYOR_ACTION_CANCEL:
                nn_timer_stop (&surveyor->timer);
                surveyor->state = NN_SURVEYOR_STATE_CANCELLING;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

        case NN_SURVEYOR_SRC_DEADLINE_TIMER:
            switch (type) {
            case NN_TIMER_TIMEOUT:
                nn_timer_stop (&surveyor->timer);
                surveyor->state = NN_SURVEYOR_STATE_STOPPING_TIMER;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

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

/******************************************************************************/
/*  CANCELLING state.                                                         */
/*  Survey was cancelled, but the old timer haven't stopped yet. The new      */
/*  survey thus haven't been sent and is stored in 'tosend'.                  */
/******************************************************************************/
    case NN_SURVEYOR_STATE_CANCELLING:
        switch (src) {

        case NN_FSM_ACTION:
            switch (type) {
            case NN_SURVEYOR_ACTION_CANCEL:
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

        case NN_SURVEYOR_SRC_DEADLINE_TIMER:
            switch (type) {
            case NN_TIMER_STOPPED:
                rc = nn_xsurveyor_send (&surveyor->xsurveyor.sockbase,
                    &surveyor->tosend);
                errnum_assert (rc == 0, -rc);
                nn_timer_start (&surveyor->timer, surveyor->deadline);
                surveyor->state = NN_SURVEYOR_STATE_ACTIVE;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }
        
        default:
            nn_fsm_bad_source (surveyor->state, src, type);
        }

/******************************************************************************/
/*  STOPPING_TIMER state.                                                     */
/*  Survey timeout expired. Now we are stopping the timer.                    */
/******************************************************************************/
    case NN_SURVEYOR_STATE_STOPPING_TIMER:
        switch (src) {

        case NN_SURVEYOR_SRC_DEADLINE_TIMER:
            switch (type) {
            case NN_TIMER_STOPPED:
                surveyor->state = NN_SURVEYOR_STATE_PASSIVE;
                return;
            default:
                nn_fsm_bad_action (surveyor->state, src, type);
            }

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

/******************************************************************************/
/*  Invalid state.                                                            */
/******************************************************************************/
    default:
        nn_fsm_bad_state (surveyor->state, src, type);
    }
}
Exemple #11
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);
    }
}