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); }
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); }
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_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)); }
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); }
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); }
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; }
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); }
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); } }
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); } }