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; }
static void nn_req_in (struct nn_sockbase *self, struct nn_pipe *pipe) { int rc; struct nn_req *req; uint32_t reqid; req = nn_cont (self, struct nn_req, xreq.sockbase); /* Pass the pipe to the raw REQ socket. */ nn_xreq_in (&req->xreq.sockbase, pipe); while (1) { /* Get new reply. */ rc = nn_xreq_recv (&req->xreq.sockbase, &req->reply); if (nn_slow (rc == -EAGAIN)) return; errnum_assert (rc == 0, -rc); /* No request was sent. Getting a reply doesn't make sense. */ if (nn_slow (req->state != NN_REQ_STATE_SENT)) { nn_msg_term (&req->reply); continue; } /* Ignore malformed replies. */ if (nn_slow (nn_chunkref_size (&req->reply.hdr) != sizeof (uint32_t))) { nn_msg_term (&req->reply); continue; } /* Ignore replies with incorrect request IDs. */ reqid = nn_getl (nn_chunkref_data (&req->reply.hdr)); if (nn_slow (!(reqid & 0x80000000))) { nn_msg_term (&req->reply); continue; } if (nn_slow (reqid != (req->reqid | 0x80000000))) { nn_msg_term (&req->reply); continue; } /* Trim the request ID. */ nn_chunkref_term (&req->reply.hdr); nn_chunkref_init (&req->reply.hdr, 0); /* Swtich to RECEIVED state. */ nn_timer_stop (&req->resend_timer); nn_msg_term (&req->request); req->state = NN_REQ_STATE_RECEIVED; return; } }
static void nn_surveyor_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, fsm); 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; } nn_fsm_bad_state(surveyor->state, src, type); }
void nn_req_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_req *req; req = nn_cont (self, struct nn_req, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_timer_stop (&req->task.timer); req->state = NN_REQ_STATE_STOPPING; } if (nn_slow (req->state == NN_REQ_STATE_STOPPING)) { if (!nn_timer_isidle (&req->task.timer)) return; req->state = NN_REQ_STATE_IDLE; nn_fsm_stopped_noevent (&req->fsm); nn_sockbase_stopped (&req->xreq.sockbase); return; } nn_fsm_bad_state(req->state, src, type); }
static void nn_stream_hdr_received (const struct nn_cp_sink **self, struct nn_usock *usock) { struct nn_stream *stream; int protocol; stream = nn_cont (self, struct nn_stream, sink); stream->sink = &nn_stream_state_active; nn_timer_stop (&stream->hdr_timeout); /* TODO: If it does not conform, drop the connection. */ protocol = nn_gets (stream->protohdr + 4); if (!nn_pipebase_ispeer (&stream->pipebase, protocol)) nn_assert (0); /* Connection is ready for sending. Make outpipe available to the SP socket. */ nn_pipebase_activate (&stream->pipebase); /* Start waiting for incoming messages. First, read the 8-byte size. */ stream->instate = NN_STREAM_INSTATE_HDR; nn_usock_recv (stream->usock, stream->inhdr, 8); }
static void nn_req_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_req *req; req = nn_cont (self, struct nn_req, fsm); /******************************************************************************/ /* STOP procedure. */ /******************************************************************************/ if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_timer_stop (&req->timer); req->state = NN_REQ_STATE_STOPPING; } if (nn_slow (req->state == NN_REQ_STATE_STOPPING)) { if (!nn_timer_isidle (&req->timer)) return; req->state = NN_REQ_STATE_IDLE; nn_fsm_stopped_noevent (&req->fsm); nn_sockbase_stopped (&req->xreq.sockbase); return; } switch (req->state) { /******************************************************************************/ /* IDLE state. */ /* The socket was created recently. Intermediate state. */ /* Pass straight to the PASSIVE state. */ /******************************************************************************/ case NN_REQ_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: req->state = NN_REQ_STATE_PASSIVE; return; default: nn_assert (0); } default: nn_assert (0); } /******************************************************************************/ /* PASSIVE state. */ /* No request is submitted. */ /******************************************************************************/ case NN_REQ_STATE_PASSIVE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: nn_req_action_send (req); return; default: nn_assert (0); } default: nn_assert (0); } /******************************************************************************/ /* DELAYED state. */ /* Request was submitted but it could not be sent to the network because */ /* there was no peer available at the moment. Now we are waiting for the */ /* peer to arrive to send the request to it. */ /******************************************************************************/ case NN_REQ_STATE_DELAYED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_OUT: nn_req_action_send (req); return; case NN_REQ_ACTION_SENT: /* New request was sent while the old one was still being processed. Cancel the old request first. */ nn_timer_stop (&req->timer); req->state = NN_REQ_STATE_CANCELLING; return; default: nn_assert (0); } default: nn_assert (0); } /******************************************************************************/ /* ACTIVE state. */ /* Request was submitted. Waiting for reply. */ /******************************************************************************/ case NN_REQ_STATE_ACTIVE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_IN: /* Reply arrived. */ nn_timer_stop (&req->timer); req->state = NN_REQ_STATE_STOPPING_TIMER; return; case NN_REQ_ACTION_SENT: /* New request was sent while the old one was still being processed. Cancel the old request first. */ nn_timer_stop (&req->timer); req->state = NN_REQ_STATE_CANCELLING; return; default: nn_assert (0); } case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&req->timer); req->state = NN_REQ_STATE_TIMED_OUT; return; default: nn_assert (0); } default: nn_assert (0); } /******************************************************************************/ /* TIMED_OUT state. */ /* Waiting for reply has timer out. Stopping the timer. Afterwards, we'll */ /* re-send the request. */ /******************************************************************************/ case NN_REQ_STATE_TIMED_OUT: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_req_action_send (req); return; default: nn_assert (0); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: req->state = NN_REQ_STATE_CANCELLING; return; default: nn_assert (0); } default: nn_assert (0); } /******************************************************************************/ /* CANCELLING state. */ /* Request was canceled. Waiting till the timer is stopped. */ /******************************************************************************/ case NN_REQ_STATE_CANCELLING: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_req_action_send (req); return; default: nn_assert (0); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: return; default: nn_assert (0); } default: nn_assert (0); } /******************************************************************************/ /* STOPPING_TIMER state. */ /* Reply was delivered. Waiting till the timer is stopped. */ /******************************************************************************/ case NN_REQ_STATE_STOPPING_TIMER: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: req->state = NN_REQ_STATE_DONE; return; default: nn_assert (0); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: req->state = NN_REQ_STATE_CANCELLING; return; default: nn_assert (0); } default: nn_assert (0); } /******************************************************************************/ /* DONE state. */ /* Reply was received but not yet retrieved by the user. */ /******************************************************************************/ case NN_REQ_STATE_DONE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_RECEIVED: req->state = NN_REQ_STATE_PASSIVE; return; case NN_REQ_ACTION_SENT: nn_req_action_send (req); return; default: nn_assert (0); } default: nn_assert (0); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_assert (0); } }
void nn_backoff_stop (struct nn_backoff *self) { nn_timer_stop (&self->timer); }
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); } }
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); } }
void nn_req_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_req *req; req = nn_cont (self, struct nn_req, fsm); switch (req->state) { /******************************************************************************/ /* IDLE state. */ /* The socket was created recently. Intermediate state. */ /* Pass straight to the PASSIVE state. */ /******************************************************************************/ case NN_REQ_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: req->state = NN_REQ_STATE_PASSIVE; return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* PASSIVE state. */ /* No request is submitted. */ /******************************************************************************/ case NN_REQ_STATE_PASSIVE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: nn_req_action_send (req, 1); return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* DELAYED state. */ /* Request was submitted but it could not be sent to the network because */ /* there was no peer available at the moment. Now we are waiting for the */ /* peer to arrive to send the request to it. */ /******************************************************************************/ case NN_REQ_STATE_DELAYED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_OUT: nn_req_action_send (req, 0); return; case NN_REQ_ACTION_SENT: return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Request was submitted. Waiting for reply. */ /******************************************************************************/ case NN_REQ_STATE_ACTIVE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_IN: /* Reply arrived. */ nn_timer_stop (&req->task.timer); req->task.sent_to = NULL; req->state = NN_REQ_STATE_STOPPING_TIMER; return; case NN_REQ_ACTION_SENT: /* New request was sent while the old one was still being processed. Cancel the old request first. */ nn_timer_stop (&req->task.timer); req->task.sent_to = NULL; req->state = NN_REQ_STATE_CANCELLING; return; case NN_REQ_ACTION_PIPE_RM: /* Pipe that we sent request to is removed */ nn_timer_stop (&req->task.timer); req->task.sent_to = NULL; /* Pretend we timed out so request resent immediately */ req->state = NN_REQ_STATE_TIMED_OUT; return; default: nn_fsm_bad_action (req->state, src, type); } case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_TIMEOUT: nn_timer_stop (&req->task.timer); req->task.sent_to = NULL; req->state = NN_REQ_STATE_TIMED_OUT; return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* TIMED_OUT state. */ /* Waiting for reply has timed out. Stopping the timer. Afterwards, we'll */ /* re-send the request. */ /******************************************************************************/ case NN_REQ_STATE_TIMED_OUT: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: nn_req_action_send (req, 1); return; default: nn_fsm_bad_action (req->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: req->state = NN_REQ_STATE_CANCELLING; return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* CANCELLING state. */ /* Request was canceled. Waiting till the timer is stopped. Note that */ /* cancelling is done by sending a new request. Thus there's already */ /* a request waiting to be sent in this state. */ /******************************************************************************/ case NN_REQ_STATE_CANCELLING: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: /* Timer is stopped. Now we can send the delayed request. */ nn_req_action_send (req, 1); return; default: nn_fsm_bad_action (req->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: /* No need to do anything here. Old delayed request is just replaced by the new one that will be sent once the timer is closed. */ return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* STOPPING_TIMER state. */ /* Reply was delivered. Waiting till the timer is stopped. */ /******************************************************************************/ case NN_REQ_STATE_STOPPING_TIMER: switch (src) { case NN_REQ_SRC_RESEND_TIMER: switch (type) { case NN_TIMER_STOPPED: req->state = NN_REQ_STATE_DONE; return; default: nn_fsm_bad_action (req->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: req->state = NN_REQ_STATE_CANCELLING; return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* DONE state. */ /* Reply was received but not yet retrieved by the user. */ /******************************************************************************/ case NN_REQ_STATE_DONE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_RECEIVED: req->state = NN_REQ_STATE_PASSIVE; return; case NN_REQ_ACTION_SENT: nn_req_action_send (req, 1); return; default: nn_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (req->state, src, type); } }
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); } }