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); }
static void nn_cipc_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cipc *cipc; cipc = nn_cont (self, struct nn_cipc, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_sipc_isidle (&cipc->sipc)) { nn_epbase_stat_increment (&cipc->epbase, NN_STAT_DROPPED_CONNECTIONS, 1); nn_sipc_stop (&cipc->sipc); } cipc->state = NN_CIPC_STATE_STOPPING_SIPC_FINAL; } if (nn_slow (cipc->state == NN_CIPC_STATE_STOPPING_SIPC_FINAL)) { if (!nn_sipc_isidle (&cipc->sipc)) return; nn_backoff_stop (&cipc->retry); nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING; } if (nn_slow (cipc->state == NN_CIPC_STATE_STOPPING)) { if (!nn_backoff_isidle (&cipc->retry) || !nn_usock_isidle (&cipc->usock)) return; cipc->state = NN_CIPC_STATE_IDLE; nn_fsm_stopped_noevent (&cipc->fsm); nn_epbase_stopped (&cipc->epbase); return; } nn_fsm_bad_state(cipc->state, src, type); }
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); }
static void nn_cinproc_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cinproc *cinproc; cinproc = nn_cont (self, struct nn_cinproc, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { /* First, unregister the endpoint from the global repository of inproc endpoints. This way, new connections cannot be created anymore. */ nn_ins_disconnect (&cinproc->item); /* Stop the existing connection. */ nn_sinproc_stop (&cinproc->sinproc); cinproc->state = NN_CINPROC_STATE_STOPPING; } if (nn_slow (cinproc->state == NN_CINPROC_STATE_STOPPING)) { if (!nn_sinproc_isidle (&cinproc->sinproc)) return; cinproc->state = NN_CINPROC_STATE_IDLE; nn_fsm_stopped_noevent (&cinproc->fsm); nn_epbase_stopped (&cinproc->item.epbase); return; } nn_fsm_bad_state(cinproc->state, src, type); }
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); }
static void nn_cws_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cws *cws; cws = nn_cont (self, struct nn_cws, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_sws_isidle (&cws->sws)) { nn_ep_stat_increment (cws->ep, NN_STAT_DROPPED_CONNECTIONS, 1); nn_sws_stop (&cws->sws); } cws->state = NN_CWS_STATE_STOPPING_SWS_FINAL; } if (nn_slow (cws->state == NN_CWS_STATE_STOPPING_SWS_FINAL)) { if (!nn_sws_isidle (&cws->sws)) return; nn_backoff_stop (&cws->retry); nn_usock_stop (&cws->usock); nn_dns_stop (&cws->dns); cws->state = NN_CWS_STATE_STOPPING; } if (nn_slow (cws->state == NN_CWS_STATE_STOPPING)) { if (!nn_backoff_isidle (&cws->retry) || !nn_usock_isidle (&cws->usock) || !nn_dns_isidle (&cws->dns)) return; cws->state = NN_CWS_STATE_IDLE; nn_fsm_stopped_noevent (&cws->fsm); nn_ep_stopped (cws->ep); return; } nn_fsm_bad_state (cws->state, src, type); }
static void nn_bipc_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_bipc *bipc; struct nn_list_item *it; struct nn_aipc *aipc; bipc = nn_cont (self, struct nn_bipc, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_aipc_stop (bipc->aipc); bipc->state = NN_BIPC_STATE_STOPPING_AIPC; } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_AIPC)) { if (!nn_aipc_isidle (bipc->aipc)) return; nn_aipc_term (bipc->aipc); nn_free (bipc->aipc); bipc->aipc = NULL; nn_usock_stop (&bipc->usock); bipc->state = NN_BIPC_STATE_STOPPING_USOCK; } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_USOCK)) { if (!nn_usock_isidle (&bipc->usock)) return; for (it = nn_list_begin (&bipc->aipcs); it != nn_list_end (&bipc->aipcs); it = nn_list_next (&bipc->aipcs, it)) { aipc = nn_cont (it, struct nn_aipc, item); nn_aipc_stop (aipc); } bipc->state = NN_BIPC_STATE_STOPPING_AIPCS; goto aipcs_stopping; } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_AIPCS)) { nn_assert (src == NN_BIPC_SRC_AIPC && type == NN_AIPC_STOPPED); aipc = (struct nn_aipc *) srcptr; nn_list_erase (&bipc->aipcs, &aipc->item); nn_aipc_term (aipc); nn_free (aipc); /* If there are no more aipc state machines, we can stop the whole bipc object. */ aipcs_stopping: if (nn_list_empty (&bipc->aipcs)) { bipc->state = NN_BIPC_STATE_IDLE; nn_fsm_stopped_noevent (&bipc->fsm); nn_epbase_stopped (&bipc->epbase); return; } return; } nn_fsm_bad_state(bipc->state, src, type); }
static void nn_ep_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ep *ep; ep = nn_cont (self, struct nn_ep, fsm); switch (ep->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_EP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: ep->state = NN_EP_STATE_ACTIVE; return; default: nn_fsm_bad_action (ep->state, src, type); } default: nn_fsm_bad_source (ep->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* We don't expect any events in this state. The only thing that can be done */ /* is closing the endpoint. */ /******************************************************************************/ case NN_EP_STATE_ACTIVE: nn_fsm_bad_source (ep->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (ep->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_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); }
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); }
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); }
static void nn_atcp_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_atcp *atcp; int val; size_t sz; atcp = nn_cont (self, struct nn_atcp, fsm); switch (atcp->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_ATCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_usock_accept (&atcp->usock, atcp->listener); atcp->state = NN_ATCP_STATE_ACCEPTING; return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* ACCEPTING state. */ /* Waiting for incoming connection. */ /******************************************************************************/ case NN_ATCP_STATE_ACCEPTING: switch (src) { case NN_ATCP_SRC_USOCK: switch (type) { case NN_USOCK_ACCEPTED: nn_epbase_clear_error (atcp->epbase); /* Set the relevant socket options. */ sz = sizeof (val); nn_epbase_getopt (atcp->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&atcp->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_epbase_getopt (atcp->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&atcp->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Return ownership of the listening socket to the parent. */ nn_usock_swap_owner (atcp->listener, &atcp->listener_owner); atcp->listener = NULL; atcp->listener_owner.src = -1; atcp->listener_owner.fsm = NULL; nn_fsm_raise (&atcp->fsm, &atcp->accepted, NN_ATCP_ACCEPTED); /* Start the stcp state machine. */ nn_usock_activate (&atcp->usock); nn_stcp_start (&atcp->stcp, &atcp->usock); atcp->state = NN_ATCP_STATE_ACTIVE; nn_epbase_stat_increment (atcp->epbase, NN_STAT_ACCEPTED_CONNECTIONS, 1); return; default: nn_fsm_bad_action (atcp->state, src, type); } case NN_ATCP_SRC_LISTENER: switch (type) { case NN_USOCK_ACCEPT_ERROR: nn_epbase_set_error (atcp->epbase, nn_usock_geterrno(atcp->listener)); nn_epbase_stat_increment (atcp->epbase, NN_STAT_ACCEPT_ERRORS, 1); nn_usock_accept (&atcp->usock, atcp->listener); return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_ATCP_STATE_ACTIVE: switch (src) { case NN_ATCP_SRC_STCP: switch (type) { case NN_STCP_ERROR: nn_stcp_stop (&atcp->stcp); atcp->state = NN_ATCP_STATE_STOPPING_STCP; nn_epbase_stat_increment (atcp->epbase, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* STOPPING_STCP state. */ /******************************************************************************/ case NN_ATCP_STATE_STOPPING_STCP: switch (src) { case NN_ATCP_SRC_STCP: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_STCP_STOPPED: nn_usock_stop (&atcp->usock); atcp->state = NN_ATCP_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /******************************************************************************/ case NN_ATCP_STATE_STOPPING_USOCK: switch (src) { case NN_ATCP_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_fsm_raise (&atcp->fsm, &atcp->done, NN_ATCP_ERROR); atcp->state = NN_ATCP_STATE_DONE; return; default: nn_fsm_bad_action (atcp->state, src, type); } default: nn_fsm_bad_source (atcp->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (atcp->state, src, type); } }
static void nn_cipc_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_cipc *cipc; cipc = nn_cont (self, struct nn_cipc, fsm); /******************************************************************************/ /* STOP procedure. */ /******************************************************************************/ if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_sipc_stop (&cipc->sipc); cipc->state = NN_CIPC_STATE_STOPPING_SIPC_FINAL; } if (nn_slow (cipc->state == NN_CIPC_STATE_STOPPING_SIPC_FINAL)) { if (!nn_sipc_isidle (&cipc->sipc)) return; nn_backoff_stop (&cipc->retry); nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING; } if (nn_slow (cipc->state == NN_CIPC_STATE_STOPPING)) { if (!nn_backoff_isidle (&cipc->retry) || !nn_usock_isidle (&cipc->usock)) return; cipc->state = NN_CIPC_STATE_IDLE; nn_fsm_stopped_noevent (&cipc->fsm); nn_epbase_stopped (&cipc->epbase); return; } switch (cipc->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_CIPC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_cipc_start_connecting (cipc); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Non-blocking connect is under way. */ /******************************************************************************/ case NN_CIPC_STATE_CONNECTING: switch (src) { case NN_CIPC_SRC_USOCK: switch (type) { case NN_USOCK_CONNECTED: nn_sipc_start (&cipc->sipc, &cipc->usock); cipc->state = NN_CIPC_STATE_ACTIVE; return; case NN_USOCK_ERROR: nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Connection is established and handled by the sipc state machine. */ /******************************************************************************/ case NN_CIPC_STATE_ACTIVE: switch (src) { case NN_CIPC_SRC_SIPC: switch (type) { case NN_SIPC_ERROR: nn_sipc_stop (&cipc->sipc); cipc->state = NN_CIPC_STATE_STOPPING_SIPC; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_SIPC state. */ /* sipc object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_SIPC: switch (src) { case NN_CIPC_SRC_SIPC: switch (type) { case NN_SIPC_STOPPED: nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_USOCK: switch (src) { case NN_CIPC_SRC_USOCK: switch (type) { case NN_USOCK_STOPPED: nn_backoff_start (&cipc->retry); cipc->state = NN_CIPC_STATE_WAITING; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* WAITING state. */ /* Waiting before re-connection is attempted. This way we won't overload */ /* the system by continuous re-connection attemps. */ /******************************************************************************/ case NN_CIPC_STATE_WAITING: switch (src) { case NN_CIPC_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&cipc->retry); cipc->state = NN_CIPC_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_BACKOFF: switch (src) { case NN_CIPC_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_cipc_start_connecting (cipc); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (cipc->state, src, type); } }
static void nn_bipc_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_bipc *bipc; struct nn_aipc *aipc; bipc = nn_cont (self, struct nn_bipc, fsm); nn_assert(bipc); switch (bipc->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_BIPC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_bipc_start_listening (bipc); return; default: nn_fsm_bad_action (bipc->state, src, type); } default: nn_fsm_bad_source (bipc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* The execution is yielded to the aipc state machine in this state. */ /******************************************************************************/ case NN_BIPC_STATE_ACTIVE: if (srcptr == bipc->aipc) { switch (type) { case NN_AIPC_ACCEPTED: /* Move the newly created connection to the list of existing connections. */ nn_list_insert (&bipc->aipcs, &bipc->aipc->item, nn_list_end (&bipc->aipcs)); bipc->aipc = NULL; /* Start waiting for a new incoming connection. */ nn_bipc_start_accepting (bipc); return; default: nn_fsm_bad_action (bipc->state, src, type); } } /* For all remaining events we'll assume they are coming from one of remaining child aipc objects. */ nn_assert (src == NN_BIPC_SRC_AIPC); aipc = (struct nn_aipc*) srcptr; switch (type) { case NN_AIPC_ERROR: nn_aipc_stop (aipc); return; case NN_AIPC_STOPPED: nn_list_erase (&bipc->aipcs, &aipc->item); nn_aipc_term (aipc); nn_free (aipc); return; default: nn_fsm_bad_action (bipc->state, src, type); } /******************************************************************************/ /* CLOSING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_BIPC_STATE_CLOSING: switch (src) { case NN_BIPC_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_backoff_start (&bipc->retry); bipc->state = NN_BIPC_STATE_WAITING; return; default: nn_fsm_bad_action (bipc->state, src, type); } default: nn_fsm_bad_source (bipc->state, src, type); } /******************************************************************************/ /* WAITING state. */ /* Waiting before re-bind is attempted. This way we won't overload */ /* the system by continuous re-bind attemps. */ /******************************************************************************/ case NN_BIPC_STATE_WAITING: switch (src) { case NN_BIPC_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&bipc->retry); bipc->state = NN_BIPC_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (bipc->state, src, type); } default: nn_fsm_bad_source (bipc->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_BIPC_STATE_STOPPING_BACKOFF: switch (src) { case NN_BIPC_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_bipc_start_listening (bipc); return; default: nn_fsm_bad_action (bipc->state, src, type); } default: nn_fsm_bad_source (bipc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (bipc->state, src, type); } }
static void nn_ctcp_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ctcp *ctcp; ctcp = nn_cont (self, struct nn_ctcp, fsm); switch (ctcp->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_CTCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_ctcp_start_resolving (ctcp); return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* RESOLVING state. */ /* Name of the host to connect to is being resolved to get an IP address. */ /******************************************************************************/ case NN_CTCP_STATE_RESOLVING: switch (src) { case NN_CTCP_SRC_DNS: switch (type) { case NN_DNS_DONE: nn_dns_stop (&ctcp->dns); ctcp->state = NN_CTCP_STATE_STOPPING_DNS; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* STOPPING_DNS state. */ /* dns object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CTCP_STATE_STOPPING_DNS: switch (src) { case NN_CTCP_SRC_DNS: switch (type) { case NN_DNS_STOPPED: if (ctcp->dns_result.error == 0) { nn_ctcp_start_connecting (ctcp, &ctcp->dns_result.addr, ctcp->dns_result.addrlen); return; } nn_backoff_start (&ctcp->retry); ctcp->state = NN_CTCP_STATE_WAITING; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Non-blocking connect is under way. */ /******************************************************************************/ case NN_CTCP_STATE_CONNECTING: switch (src) { case NN_CTCP_SRC_USOCK: switch (type) { case NN_USOCK_CONNECTED: nn_stcp_start (&ctcp->stcp, &ctcp->usock); ctcp->state = NN_CTCP_STATE_ACTIVE; nn_epbase_stat_increment (&ctcp->epbase, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_epbase_stat_increment (&ctcp->epbase, NN_STAT_ESTABLISHED_CONNECTIONS, 1); nn_epbase_clear_error (&ctcp->epbase); return; case NN_USOCK_ERROR: nn_epbase_set_error (&ctcp->epbase,nn_usock_geterrno(&ctcp->usock),__FILE__,__LINE__); nn_usock_stop (&ctcp->usock); ctcp->state = NN_CTCP_STATE_STOPPING_USOCK; nn_epbase_stat_increment (&ctcp->epbase, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_epbase_stat_increment (&ctcp->epbase, NN_STAT_CONNECT_ERRORS, 1); return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Connection is established and handled by the stcp state machine. */ /******************************************************************************/ case NN_CTCP_STATE_ACTIVE: switch (src) { case NN_CTCP_SRC_STCP: switch (type) { case NN_STCP_ERROR: nn_stcp_stop (&ctcp->stcp); ctcp->state = NN_CTCP_STATE_STOPPING_STCP; nn_epbase_stat_increment (&ctcp->epbase, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* STOPPING_STCP state. */ /* stcp object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CTCP_STATE_STOPPING_STCP: switch (src) { case NN_CTCP_SRC_STCP: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_STCP_STOPPED: nn_usock_stop (&ctcp->usock); ctcp->state = NN_CTCP_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CTCP_STATE_STOPPING_USOCK: switch (src) { case NN_CTCP_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_backoff_start (&ctcp->retry); ctcp->state = NN_CTCP_STATE_WAITING; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* WAITING state. */ /* Waiting before re-connection is attempted. This way we won't overload */ /* the system by continuous re-connection attemps. */ /******************************************************************************/ case NN_CTCP_STATE_WAITING: switch (src) { case NN_CTCP_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&ctcp->retry); ctcp->state = NN_CTCP_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_CTCP_STATE_STOPPING_BACKOFF: switch (src) { case NN_CTCP_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_ctcp_start_resolving (ctcp); return; default: nn_fsm_bad_action (ctcp->state, src, type); } default: nn_fsm_bad_source (ctcp->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (ctcp->state, src, type); } }
static void nn_cipc_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cipc *cipc; cipc = nn_cont (self, struct nn_cipc, fsm); switch (cipc->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_CIPC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_cipc_start_connecting (cipc); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Non-blocking connect is under way. */ /******************************************************************************/ case NN_CIPC_STATE_CONNECTING: switch (src) { case NN_CIPC_SRC_USOCK: switch (type) { case NN_USOCK_CONNECTED: nn_sipc_start (&cipc->sipc, &cipc->usock); cipc->state = NN_CIPC_STATE_ACTIVE; nn_epbase_stat_increment (&cipc->epbase, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_epbase_stat_increment (&cipc->epbase, NN_STAT_ESTABLISHED_CONNECTIONS, 1); nn_epbase_clear_error (&cipc->epbase); return; case NN_USOCK_ERROR: nn_epbase_set_error (&cipc->epbase,nn_usock_geterrno (&cipc->usock),__FILE__,__LINE__); nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING_USOCK; nn_epbase_stat_increment (&cipc->epbase, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_epbase_stat_increment (&cipc->epbase, NN_STAT_CONNECT_ERRORS, 1); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Connection is established and handled by the sipc state machine. */ /******************************************************************************/ case NN_CIPC_STATE_ACTIVE: switch (src) { case NN_CIPC_SRC_SIPC: switch (type) { case NN_SIPC_ERROR: nn_sipc_stop (&cipc->sipc); cipc->state = NN_CIPC_STATE_STOPPING_SIPC; nn_epbase_stat_increment (&cipc->epbase, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_SIPC state. */ /* sipc object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_SIPC: switch (src) { case NN_CIPC_SRC_SIPC: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_SIPC_STOPPED: nn_usock_stop (&cipc->usock); cipc->state = NN_CIPC_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_USOCK: switch (src) { case NN_CIPC_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_backoff_start (&cipc->retry); cipc->state = NN_CIPC_STATE_WAITING; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* WAITING state. */ /* Waiting before re-connection is attempted. This way we won't overload */ /* the system by continuous re-connection attemps. */ /******************************************************************************/ case NN_CIPC_STATE_WAITING: switch (src) { case NN_CIPC_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&cipc->retry); cipc->state = NN_CIPC_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_CIPC_STATE_STOPPING_BACKOFF: switch (src) { case NN_CIPC_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_cipc_start_connecting (cipc); return; default: nn_fsm_bad_action (cipc->state, src, type); } default: nn_fsm_bad_source (cipc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (cipc->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_usock_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { int rc; struct nn_usock *usock; int s; size_t sz; int sockerr; usock = nn_cont (self, struct nn_usock, fsm); if(nn_internal_tasks(usock, src, type)) return; switch (usock->state) { /******************************************************************************/ /* IDLE state. */ /* nn_usock object is initialised, but underlying OS socket is not yet */ /* created. */ /******************************************************************************/ case NN_USOCK_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: usock->state = NN_USOCK_STATE_STARTING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* STARTING state. */ /* Underlying OS socket is created, but it's not yet passed to the worker */ /* thread. In this state we can set socket options, local and remote */ /* address etc. */ /******************************************************************************/ case NN_USOCK_STATE_STARTING: /* Events from the owner of the usock. */ switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_LISTEN: usock->state = NN_USOCK_STATE_LISTENING; return; case NN_USOCK_ACTION_CONNECT: usock->state = NN_USOCK_STATE_CONNECTING; return; case NN_USOCK_ACTION_BEING_ACCEPTED: usock->state = NN_USOCK_STATE_BEING_ACCEPTED; return; case NN_USOCK_ACTION_STARTED: nn_worker_add_fd (usock->worker, usock->s, &usock->wfd); usock->state = NN_USOCK_STATE_ACTIVE; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* BEING_ACCEPTED state. */ /* accept() was called on the usock. Now the socket is waiting for a new */ /* connection to arrive. */ /******************************************************************************/ case NN_USOCK_STATE_BEING_ACCEPTED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_ACCEPTED; nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_ACCEPTED); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* ACCEPTED state. */ /* Connection was accepted, now it can be tuned. Afterwards, it'll move to */ /* the active state. */ /******************************************************************************/ case NN_USOCK_STATE_ACCEPTED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ACTIVATE: nn_worker_add_fd (usock->worker, usock->s, &usock->wfd); usock->state = NN_USOCK_STATE_ACTIVE; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Asynchronous connecting is going on. */ /******************************************************************************/ case NN_USOCK_STATE_CONNECTING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_ACTIVE; nn_worker_execute (usock->worker, &usock->task_connected); nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_CONNECTED); return; case NN_USOCK_ACTION_ERROR: nn_closefd (usock->s); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_FD: switch (type) { case NN_WORKER_FD_OUT: nn_worker_reset_out (usock->worker, &usock->wfd); usock->state = NN_USOCK_STATE_ACTIVE; sockerr = nn_usock_geterr(usock); if (sockerr == 0) { nn_fsm_raise (&usock->fsm, &usock->event_established, NN_USOCK_CONNECTED); } else { usock->errnum = sockerr; nn_worker_rm_fd (usock->worker, &usock->wfd); rc = close (usock->s); errno_assert (rc == 0); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); } return; case NN_WORKER_FD_ERR: nn_worker_rm_fd (usock->worker, &usock->wfd); nn_closefd (usock->s); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Socket is connected. It can be used for sending and receiving data. */ /******************************************************************************/ case NN_USOCK_STATE_ACTIVE: switch (src) { case NN_USOCK_SRC_FD: switch (type) { case NN_WORKER_FD_IN: sz = usock->in.len; rc = nn_usock_recv_raw (usock, usock->in.buf, &sz); if (nn_fast (rc == 0)) { usock->in.len -= sz; usock->in.buf += sz; if (!usock->in.len) { nn_worker_reset_in (usock->worker, &usock->wfd); nn_fsm_raise (&usock->fsm, &usock->event_received, NN_USOCK_RECEIVED); } return; } errnum_assert (rc == -ECONNRESET, -rc); goto error; case NN_WORKER_FD_OUT: rc = nn_usock_send_raw (usock, &usock->out.hdr); if (nn_fast (rc == 0)) { nn_worker_reset_out (usock->worker, &usock->wfd); nn_fsm_raise (&usock->fsm, &usock->event_sent, NN_USOCK_SENT); return; } if (nn_fast (rc == -EAGAIN)) return; errnum_assert (rc == -ECONNRESET, -rc); goto error; case NN_WORKER_FD_ERR: error: nn_worker_rm_fd (usock->worker, &usock->wfd); nn_closefd (usock->s); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ERROR: usock->state = NN_USOCK_STATE_REMOVING_FD; nn_usock_async_stop (usock); return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source(usock->state, src, type); } /******************************************************************************/ /* REMOVING_FD state. */ /******************************************************************************/ case NN_USOCK_STATE_REMOVING_FD: switch (src) { case NN_USOCK_SRC_TASK_STOP: switch (type) { case NN_WORKER_TASK_EXECUTE: nn_worker_rm_fd (usock->worker, &usock->wfd); nn_closefd (usock->s); usock->s = -1; usock->state = NN_USOCK_STATE_DONE; nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ERROR); return; default: nn_fsm_bad_action (usock->state, src, type); } /* Events from the file descriptor are ignored while it is being removed. */ case NN_USOCK_SRC_FD: return; default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* DONE state. */ /* Socket is closed. The only thing that can be done in this state is */ /* stopping the usock. */ /******************************************************************************/ case NN_USOCK_STATE_DONE: nn_fsm_bad_source (usock->state, src, type); /******************************************************************************/ /* LISTENING state. */ /* Socket is listening for new incoming connections, however, user is not */ /* accepting a new connection. */ /******************************************************************************/ case NN_USOCK_STATE_LISTENING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ACCEPT: usock->state = NN_USOCK_STATE_ACCEPTING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* ACCEPTING state. */ /* User is waiting asynchronouslyfor a new inbound connection */ /* to be accepted. */ /******************************************************************************/ case NN_USOCK_STATE_ACCEPTING: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_DONE: usock->state = NN_USOCK_STATE_LISTENING; return; case NN_USOCK_ACTION_CANCEL: usock->state = NN_USOCK_STATE_CANCELLING; nn_worker_execute (usock->worker, &usock->task_stop); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_FD: switch (type) { case NN_WORKER_FD_IN: /* New connection arrived in asynchronous manner. */ #if NN_HAVE_ACCEPT4 s = accept4 (usock->s, NULL, NULL, SOCK_CLOEXEC); #else s = accept (usock->s, NULL, NULL); #endif /* ECONNABORTED is an valid error. New connection was closed by the peer before we were able to accept it. If it happens do nothing and wait for next incoming connection. */ if (nn_slow (s < 0 && errno == ECONNABORTED)) return; /* Resource allocation errors. It's not clear from POSIX specification whether the new connection is closed in this case or whether it remains in the backlog. In the latter case it would be wise to wait here for a while to prevent busy looping. */ if (nn_slow (s < 0 && (errno == ENFILE || errno == EMFILE || errno == ENOBUFS || errno == ENOMEM))) { usock->errnum = errno; usock->state = NN_USOCK_STATE_ACCEPTING_ERROR; /* Wait till the user starts accepting once again. */ nn_worker_rm_fd (usock->worker, &usock->wfd); nn_fsm_raise (&usock->fsm, &usock->event_error, NN_USOCK_ACCEPT_ERROR); return; } /* Any other error is unexpected. */ errno_assert (s >= 0); /* Initialise the new usock object. */ nn_usock_init_from_fd (usock->asock, s); usock->asock->state = NN_USOCK_STATE_ACCEPTED; /* Notify the user that connection was accepted. */ nn_fsm_raise (&usock->asock->fsm, &usock->asock->event_established, NN_USOCK_ACCEPTED); /* Disassociate the listener socket from the accepted socket. */ usock->asock->asock = NULL; usock->asock = NULL; /* Wait till the user starts accepting once again. */ nn_worker_rm_fd (usock->worker, &usock->wfd); usock->state = NN_USOCK_STATE_LISTENING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* ACCEPTING_ERROR state. */ /* Waiting the socket to accept the error and restart */ /******************************************************************************/ case NN_USOCK_STATE_ACCEPTING_ERROR: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_USOCK_ACTION_ACCEPT: usock->state = NN_USOCK_STATE_ACCEPTING; return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* CANCELLING state. */ /******************************************************************************/ case NN_USOCK_STATE_CANCELLING: switch (src) { case NN_USOCK_SRC_TASK_STOP: switch (type) { case NN_WORKER_TASK_EXECUTE: nn_worker_rm_fd (usock->worker, &usock->wfd); usock->state = NN_USOCK_STATE_LISTENING; /* Notify the accepted socket that it was stopped. */ nn_fsm_action (&usock->asock->fsm, NN_USOCK_ACTION_DONE); return; default: nn_fsm_bad_action (usock->state, src, type); } case NN_USOCK_SRC_FD: switch (type) { case NN_WORKER_FD_IN: return; default: nn_fsm_bad_action (usock->state, src, type); } default: nn_fsm_bad_source (usock->state, src, type); } /******************************************************************************/ /* Invalid state */ /******************************************************************************/ default: nn_fsm_bad_state (usock->state, src, type); } }
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); }
static void nn_bipc_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_bipc *bipc; struct nn_list_item *it; struct nn_aipc *aipc; bipc = nn_cont (self, struct nn_bipc, fsm); /******************************************************************************/ /* STOP procedure. */ /******************************************************************************/ if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_aipc_stop (bipc->aipc); bipc->state = NN_BIPC_STATE_STOPPING_AIPC; } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_AIPC)) { if (!nn_aipc_isidle (bipc->aipc)) return; nn_aipc_term (bipc->aipc); nn_free (bipc->aipc); bipc->aipc = NULL; nn_usock_stop (&bipc->usock); bipc->state = NN_BIPC_STATE_STOPPING_USOCK; } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_USOCK)) { if (!nn_usock_isidle (&bipc->usock)) return; for (it = nn_list_begin (&bipc->aipcs); it != nn_list_end (&bipc->aipcs); it = nn_list_next (&bipc->aipcs, it)) { aipc = nn_cont (it, struct nn_aipc, item); nn_aipc_stop (aipc); } bipc->state = NN_BIPC_STATE_STOPPING_AIPCS; goto aipcs_stopping; } if (nn_slow (bipc->state == NN_BIPC_STATE_STOPPING_AIPCS)) { nn_assert (src == NN_BIPC_SRC_AIPC && type == NN_AIPC_STOPPED); aipc = (struct nn_aipc *) srcptr; nn_list_erase (&bipc->aipcs, &aipc->item); nn_aipc_term (aipc); nn_free (aipc); /* If there are no more aipc state machines, we can stop the whole bipc object. */ aipcs_stopping: if (nn_list_empty (&bipc->aipcs)) { bipc->state = NN_BIPC_STATE_IDLE; nn_fsm_stopped_noevent (&bipc->fsm); nn_epbase_stopped (&bipc->epbase); return; } return; } switch (bipc->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_BIPC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_bipc_start_listening (bipc); nn_bipc_start_accepting (bipc); bipc->state = NN_BIPC_STATE_ACTIVE; return; default: nn_fsm_bad_action (bipc->state, src, type); } default: nn_fsm_bad_source (bipc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* The execution is yielded to the aipc state machine in this state. */ /******************************************************************************/ case NN_BIPC_STATE_ACTIVE: if (srcptr == bipc->aipc) { switch (type) { case NN_AIPC_ACCEPTED: /* Move the newly created connection to the list of existing connections. */ nn_list_insert (&bipc->aipcs, &bipc->aipc->item, nn_list_end (&bipc->aipcs)); bipc->aipc = NULL; /* Start waiting for a new incoming connection. */ nn_bipc_start_accepting (bipc); return; default: nn_fsm_bad_action (bipc->state, src, type); } } /* For all remaining events we'll assume they are coming from one of remaining child aipc objects. */ nn_assert (src == NN_BIPC_SRC_AIPC); aipc = (struct nn_aipc*) srcptr; switch (type) { case NN_AIPC_ERROR: nn_aipc_stop (aipc); return; case NN_AIPC_STOPPED: nn_list_erase (&bipc->aipcs, &aipc->item); nn_aipc_term (aipc); nn_free (aipc); return; default: nn_fsm_bad_action (bipc->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (bipc->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_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); 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_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* 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_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* 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_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* 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_fsm_error("Unexpected socket instate", stcp->state, src, type); } case NN_USOCK_SHUTDOWN: nn_pipebase_stop (&stcp->pipebase); stcp->state = NN_STCP_STATE_SHUTTING_DOWN; return; 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_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_STCP_STATE_SHUTTING_DOWN: switch (src) { case NN_STCP_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* 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_fsm_bad_source (stcp->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (stcp->state, src, type); } }
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); } }
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_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); 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); 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_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->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_fsm_bad_action (req->state, src, type); } 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_fsm_bad_action (req->state, src, type); } default: nn_fsm_bad_source (req->state, src, type); } /******************************************************************************/ /* 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_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. */ /******************************************************************************/ 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_fsm_bad_action (req->state, src, type); } case NN_FSM_ACTION: switch (type) { case NN_REQ_ACTION_SENT: 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); 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_timer_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_timer *timer; timer = nn_cont (self, struct nn_timer, fsm); switch (timer->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_TIMER_STATE_IDLE: switch (src) { case NN_FSM_ACTION: 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_fsm_bad_action (timer->state, src, type); } default: nn_fsm_bad_source (timer->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_TIMER_STATE_ACTIVE: if (src == NN_TIMER_SRC_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_fsm_bad_action (timer->state, src, type); } } nn_fsm_bad_source (timer->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (timer->state, src, type); } }
static void nn_btcp_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_btcp *btcp; struct nn_atcp *atcp; btcp = nn_cont (self, struct nn_btcp, fsm); switch (btcp->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_BTCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_btcp_start_listening (btcp); nn_btcp_start_accepting (btcp); btcp->state = NN_BTCP_STATE_ACTIVE; return; default: nn_fsm_bad_action (btcp->state, src, type); } default: nn_fsm_bad_source (btcp->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* The execution is yielded to the atcp state machine in this state. */ /******************************************************************************/ case NN_BTCP_STATE_ACTIVE: if (srcptr == btcp->atcp) { switch (type) { case NN_ATCP_ACCEPTED: /* Move the newly created connection to the list of existing connections. */ nn_list_insert (&btcp->atcps, &btcp->atcp->item, nn_list_end (&btcp->atcps)); btcp->atcp = NULL; /* Start waiting for a new incoming connection. */ nn_btcp_start_accepting (btcp); return; default: nn_fsm_bad_action (btcp->state, src, type); } } /* For all remaining events we'll assume they are coming from one of remaining child atcp objects. */ nn_assert (src == NN_BTCP_SRC_ATCP); atcp = (struct nn_atcp*) srcptr; switch (type) { case NN_ATCP_ERROR: nn_atcp_stop (atcp); return; case NN_ATCP_STOPPED: nn_list_erase (&btcp->atcps, &atcp->item); nn_atcp_term (atcp); nn_free (atcp); return; default: nn_fsm_bad_action (btcp->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (btcp->state, src, type); } }
static void nn_sws_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_sws *sws; int rc; sws = nn_cont (self, struct nn_sws, fsm); switch (sws->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_SWS_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_wshdr_start (&sws->wshdr, sws->usock, &sws->pipebase, sws->mode, sws->remote_host); sws->state = NN_SWS_STATE_HANDSHAKE; return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* HANDSHAKE state. */ /******************************************************************************/ case NN_SWS_STATE_HANDSHAKE: switch (src) { case NN_SWS_SRC_HANDSHAKE: switch (type) { case NN_WSHDR_OK: /* Before moving to the active state stop the handshake state machine. */ nn_wshdr_stop (&sws->wshdr); sws->state = NN_SWS_STATE_STOPPING_HANDSHAKE; return; case NN_WSHDR_ERROR: /* Raise the error and move directly to the DONE state. wshdr object will be stopped later on. */ sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_CLOSE_HANDSHAKE); return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* STOPPING_HANDSHAKE state. */ /******************************************************************************/ case NN_SWS_STATE_STOPPING_HANDSHAKE: switch (src) { case NN_SWS_SRC_HANDSHAKE: switch (type) { case NN_WSHDR_STOPPED: /* Start the pipe. */ rc = nn_pipebase_start (&sws->pipebase); if (nn_slow (rc < 0)) { sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR); return; } /* Start receiving a message in asynchronous manner. */ nn_sws_recv_hdr (sws); /* Mark the pipe as available for sending. */ sws->outstate = NN_SWS_OUTSTATE_IDLE; sws->state = NN_SWS_STATE_ACTIVE; return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_SWS_STATE_ACTIVE: switch (src) { case NN_SWS_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* The message is now fully sent. */ nn_assert (sws->outstate == NN_SWS_OUTSTATE_SENDING); sws->outstate = NN_SWS_OUTSTATE_IDLE; nn_msg_term (&sws->outmsg); nn_msg_init (&sws->outmsg, 0); nn_pipebase_sent (&sws->pipebase); return; case NN_USOCK_RECEIVED: switch (sws->instate) { case NN_SWS_INSTATE_RECV_HDR: /* Require RSV1, RSV2, and RSV3 bits to be unset for as per RFC 6455 section 5.2. */ if (sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV1 || sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV2 || sws->inhdr [0] & NN_SWS_FRAME_BITMASK_RSV3) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "RSV1, RSV2, and RSV3 must be unset."); return; } sws->is_final_frame = sws->inhdr [0] & NN_SWS_FRAME_BITMASK_FIN; /* Communication from client to server must be masked. Communication from server to client must be unmasked. */ if (sws->mode == NN_WS_SERVER) { nn_assert (sws->inhdr [1] & NN_SWS_FRAME_BITMASK_MASKED); sws->ext_hdr_len = 4; } else { nn_assert (!(sws->inhdr [1] & NN_SWS_FRAME_BITMASK_MASKED)); sws->ext_hdr_len = 0; } sws->opcode = sws->inhdr [0] & NN_SWS_FRAME_BITMASK_OPCODE; sws->payload_ctl = sws->inhdr [1] & NN_SWS_FRAME_BITMASK_LENGTH; /* Prevent unexpected continuation frame. */ if (!sws->continuing && sws->opcode == NN_WS_OPCODE_FRAGMENT) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "No message to continue."); return; } /* Preserve initial message opcode and RSV bits in case this is a fragmented message. */ if (!sws->continuing) sws->inmsg_hdr = sws->inhdr [0] | NN_SWS_FRAME_BITMASK_FIN; if (sws->payload_ctl <= 0x7d) { sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_0; } else if (sws->payload_ctl <= 0xffff) { sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_16; } else { sws->ext_hdr_len += NN_SWS_FRAME_SIZE_PAYLOAD_63; } switch (sws->opcode) { case NN_WS_OPCODE_BINARY: sws->is_control_frame = 0; if (sws->continuing) { nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Expected continuation frame opcode."); return; } if (!sws->is_final_frame) sws->continuing = 1; if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) { /* Only a remote server could send a 2-byte msg; sanity-check that this endpoint is a client. */ nn_assert (sws->mode == NN_WS_CLIENT); sws->inmsg_current_chunk_len = 0; if (sws->continuing) { /* This frame was empty, but continue next frame in fragmented sequence. */ nn_sws_recv_hdr (sws); return; } else { /* Special case when there is no payload, mask, or additional frames. */ sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED; nn_pipebase_received (&sws->pipebase); return; } } /* Continue to receive extended header+payload. */ break; case NN_WS_OPCODE_FRAGMENT: sws->is_control_frame = 0; sws->continuing = !sws->is_final_frame; if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) { /* Only a remote server could send a 2-byte msg; sanity-check that this endpoint is a client. */ nn_assert (sws->mode == NN_WS_CLIENT); sws->inmsg_current_chunk_len = 0; if (sws->continuing) { /* This frame was empty, but continue next frame in fragmented sequence. */ nn_sws_recv_hdr (sws); return; } else { /* Special case when there is no payload, mask, or additional frames. */ sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED; nn_pipebase_received (&sws->pipebase); return; } } /* Continue to receive extended header+payload. */ break; case NN_WS_OPCODE_CLOSE: /* RFC 6455 section 5.5.1. */ sws->is_control_frame = 1; if (!sws->is_final_frame) { /* As per RFC 6455 section 5.4, fragmentation of control frames is not allowed; on receipt the endpoint MUST close connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Cannot fragment control message (FIN=0)."); return; } if (sws->payload_ctl > NN_SWS_MAX_SMALL_PAYLOAD) { /* As per RFC 6455 section 5.4, large payloads on control frames is not allowed, and on receipt the endpoint MUST close connection immediately. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Control frame payload exceeds allowable length."); return; } if (sws->payload_ctl == 1) { /* As per RFC 6455 section 5.5.1, if a payload is to accompany a close frame, the first two bytes MUST be the close code. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Expected 2byte close code."); return; } if (sws->ext_hdr_len == 0 && sws->payload_ctl == 0) { /* Special case when there is no payload, mask, or additional frames. */ sws->inmsg_current_chunk_len = 0; sws->instate = NN_SWS_INSTATE_RECVD_CONTROL; nn_pipebase_received (&sws->pipebase); return; } /* Continue to receive extended header+payload. */ break; default: /* Client sent an invalid opcode; as per RFC 6455 section 10.7, close connection with code. */ nn_sws_fail_conn (sws, NN_SWS_CLOSE_ERR_PROTO, "Invalid opcode."); return; } if (sws->ext_hdr_len == 0) { /* Only a remote server could send a 2-byte msg; sanity-check that this endpoint is a client. */ nn_assert (sws->mode == NN_WS_CLIENT); /* In the case of no additional header, the payload is known to not exceed this threshold. */ nn_assert (sws->payload_ctl <= 0x7d); /* In the case of no additional header, the payload is known to not exceed this threshold. */ nn_assert (sws->payload_ctl > 0); sws->instate = NN_SWS_INSTATE_RECV_PAYLOAD; sws->inmsg_current_chunk_len = sws->payload_ctl; /* Use scatter/gather array for application messages, and a fixed-width buffer for control messages. This is convenient since control messages can be interspersed between chunked application msgs. */ if (sws->is_control_frame) { sws->inmsg_current_chunk_buf = sws->inmsg_control; } else { sws->inmsg_chunks++; sws->inmsg_total_size += sws->inmsg_current_chunk_len; sws->inmsg_current_chunk_buf = nn_msg_chunk_new (sws->inmsg_current_chunk_len, &sws->inmsg_array); } nn_usock_recv (sws->usock, sws->inmsg_current_chunk_buf, sws->inmsg_current_chunk_len, NULL); return; } else { /* Continue receiving the rest of the header frame. */ sws->instate = NN_SWS_INSTATE_RECV_HDREXT; nn_usock_recv (sws->usock, sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL, sws->ext_hdr_len, NULL); return; } case NN_SWS_INSTATE_RECV_HDREXT: nn_assert (sws->ext_hdr_len > 0); if (sws->payload_ctl <= 0x7d) { sws->inmsg_current_chunk_len = sws->payload_ctl; if (sws->mode == NN_WS_SERVER) { memcpy (sws->mask, sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL, 4); } } else if (sws->payload_ctl == 0xffff) { sws->inmsg_current_chunk_len = nn_gets (sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL); if (sws->mode == NN_WS_SERVER) { memcpy (sws->mask, sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL + NN_SWS_FRAME_SIZE_PAYLOAD_16, 4); } } else { sws->inmsg_current_chunk_len = (size_t) nn_getll (sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL); if (sws->mode == NN_WS_SERVER) { memcpy (sws->mask, sws->inhdr + NN_SWS_FRAME_SIZE_INITIAL + NN_SWS_FRAME_SIZE_PAYLOAD_63, 4); } } /* Handle zero-length message bodies. */ if (sws->inmsg_current_chunk_len == 0) { if (sws->is_final_frame) { sws->instate = (sws->is_control_frame ? NN_SWS_INSTATE_RECVD_CONTROL : NN_SWS_INSTATE_RECVD_CHUNKED); nn_pipebase_received (&sws->pipebase); return; } else { nn_sws_recv_hdr (sws); return; } } nn_assert (sws->inmsg_current_chunk_len > 0); /* Use scatter/gather array for application messages, and a fixed-width buffer for control messages. This is convenient since control messages can be interspersed between chunked application msgs. */ if (sws->is_control_frame) { sws->inmsg_current_chunk_buf = sws->inmsg_control; } else { sws->inmsg_chunks++; sws->inmsg_total_size += sws->inmsg_current_chunk_len; sws->inmsg_current_chunk_buf = nn_msg_chunk_new (sws->inmsg_current_chunk_len, &sws->inmsg_array); } sws->instate = NN_SWS_INSTATE_RECV_PAYLOAD; nn_usock_recv (sws->usock, sws->inmsg_current_chunk_buf, sws->inmsg_current_chunk_len, NULL); return; case NN_SWS_INSTATE_RECV_PAYLOAD: /* Unmask if necessary. */ if (sws->mode == NN_WS_SERVER) { nn_sws_mask_payload (sws->inmsg_current_chunk_buf, sws->inmsg_current_chunk_len, sws->mask, NULL); } switch (sws->opcode) { case NN_WS_OPCODE_BINARY: case NN_WS_OPCODE_FRAGMENT: if (sws->is_final_frame) { sws->instate = NN_SWS_INSTATE_RECVD_CHUNKED; nn_pipebase_received (&sws->pipebase); } else { nn_sws_recv_hdr (sws); } return; case NN_WS_OPCODE_CLOSE: /* If the payload is not even long enough for the required 2-octet Close Code, the connection should have been failed upstream. */ nn_assert (sws->inmsg_current_chunk_len >= 2); nn_sws_validate_close_handshake (sws); return; default: /* This should have been prevented upstream. */ nn_assert (0); return; } default: nn_fsm_error ("Unexpected socket instate", sws->state, src, type); } case NN_USOCK_SHUTDOWN: nn_pipebase_stop (&sws->pipebase); sws->state = NN_SWS_STATE_BROKEN_CONNECTION; return; case NN_USOCK_ERROR: nn_pipebase_stop (&sws->pipebase); sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR); return; default: nn_fsm_bad_action (sws->state, src, type); } break; default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* CLOSING_CONNECTION state. */ /* Wait for acknowledgement closing handshake was successfully sent. */ /******************************************************************************/ case NN_SWS_STATE_CLOSING_CONNECTION: switch (src) { case NN_SWS_SRC_USOCK: switch (type) { case NN_USOCK_SENT: /* Wait for acknowledgement closing handshake was sent to peer. */ nn_assert (sws->outstate == NN_SWS_OUTSTATE_SENDING); sws->outstate = NN_SWS_OUTSTATE_IDLE; sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_CLOSE_HANDSHAKE); return; case NN_USOCK_SHUTDOWN: return; case NN_USOCK_ERROR: sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR); return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_SWS_STATE_BROKEN_CONNECTION: switch (src) { case NN_SWS_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: sws->state = NN_SWS_STATE_DONE; nn_fsm_raise (&sws->fsm, &sws->done, NN_SWS_RETURN_ERROR); return; default: nn_fsm_bad_action (sws->state, src, type); } default: nn_fsm_bad_source (sws->state, src, type); } /******************************************************************************/ /* DONE state. */ /* The underlying connection is closed. There's nothing that can be done in */ /* this state except stopping the object. */ /******************************************************************************/ case NN_SWS_STATE_DONE: nn_fsm_bad_source (sws->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (sws->state, src, type); } }
static void nn_stcp_handler(struct nn_fsm *self,int32_t src,int32_t type,NN_UNUSED void *srcptr) { int32_t rc,opt; struct nn_stcp *stcp; uint64_t size; size_t opt_sz = sizeof(opt); stcp = nn_cont(self,struct nn_stcp,fsm); switch (stcp->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_STCP_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: //printf("streamhdr start\n"); nn_streamhdr_start(&stcp->streamhdr,stcp->usock,&stcp->pipebase); stcp->state = NN_STCP_STATE_PROTOHDR; return; default: nn_fsm_bad_action (stcp->state,src,type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* 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_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source(stcp->state,src,type); } /******************************************************************************/ /* 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); if ( nn_slow (rc < 0) ) { stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; } // Start receiving a message in asynchronous manner stcp->instate = NN_STCP_INSTATE_HDR; nn_usock_recv(stcp->usock,&stcp->inhdr,sizeof(stcp->inhdr),NULL); //printf("STCP recv.[%d %d %d %d]\n",stcp->inhdr[0],stcp->inhdr[1],stcp->inhdr[2],stcp->inhdr[3]); // Mark the pipe as available for sending stcp->outstate = NN_STCP_OUTSTATE_IDLE; stcp->state = NN_STCP_STATE_ACTIVE; return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* 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. Check that message size is acceptable by comparing with NN_RCVMAXSIZE; if it's too large, drop the connection size = nn_getll(stcp->inhdr); nn_pipebase_getopt(&stcp->pipebase,NN_SOL_SOCKET,NN_RCVMAXSIZE,&opt,&opt_sz); if ( opt != -1 && size > opt ) { stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise(&stcp->fsm,&stcp->done,NN_STCP_ERROR); return; } // Allocate memory for the message 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 ) { printf("STCP: zero size pipebase recv\n"); 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,NULL); 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_fsm_error("Unexpected socket instate",stcp->state,src,type); } case NN_USOCK_SHUTDOWN: nn_pipebase_stop(&stcp->pipebase); stcp->state = NN_STCP_STATE_SHUTTING_DOWN; return; 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_fsm_bad_action(stcp->state,src,type); } default: nn_fsm_bad_source(stcp->state,src,type); } /******************************************************************************/ /* SHUTTING_DOWN state. */ /* The underlying connection is closed. We are just waiting that underlying */ /* usock being closed */ /******************************************************************************/ case NN_STCP_STATE_SHUTTING_DOWN: switch (src) { case NN_STCP_SRC_USOCK: switch (type) { case NN_USOCK_ERROR: stcp->state = NN_STCP_STATE_DONE; nn_fsm_raise (&stcp->fsm, &stcp->done, NN_STCP_ERROR); return; default: nn_fsm_bad_action (stcp->state, src, type); } default: nn_fsm_bad_source (stcp->state, src, type); } /******************************************************************************/ /* 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_fsm_bad_source (stcp->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (stcp->state, src, type); } }
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); } }