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_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); 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); } /******************************************************************************/ /* CLOSING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_BTCP_STATE_CLOSING: switch (src) { case NN_BTCP_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_backoff_start (&btcp->retry); btcp->state = NN_BTCP_STATE_WAITING; return; default: nn_fsm_bad_action (btcp->state, src, type); } default: nn_fsm_bad_source (btcp->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_BTCP_STATE_WAITING: switch (src) { case NN_BTCP_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&btcp->retry); btcp->state = NN_BTCP_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (btcp->state, src, type); } default: nn_fsm_bad_source (btcp->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_BTCP_STATE_STOPPING_BACKOFF: switch (src) { case NN_BTCP_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_btcp_start_listening (btcp); return; default: nn_fsm_bad_action (btcp->state, src, type); } default: nn_fsm_bad_source (btcp->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (btcp->state, src, type); } }
static void nn_btcp_start_listening (struct nn_btcp *self) { int rc; struct sockaddr_storage ss; size_t sslen; int ipv4only; size_t ipv4onlylen; const char *addr; const char *end; const char *pos; uint16_t port; /* First, resolve the IP address. */ addr = nn_epbase_getaddr (&self->epbase); memset (&ss, 0, sizeof (ss)); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); nn_assert (pos); ++pos; rc = nn_port_resolve (pos, end - pos); nn_assert (rc >= 0); port = rc; /* Parse the address. */ ipv4onlylen = sizeof (ipv4only); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); rc = nn_iface_resolve (addr, pos - addr - 1, ipv4only, &ss, &sslen); errnum_assert (rc == 0, -rc); /* Combine the port and the address. */ if (ss.ss_family == AF_INET) { ((struct sockaddr_in*) &ss)->sin_port = htons (port); sslen = sizeof (struct sockaddr_in); } else if (ss.ss_family == AF_INET6) { ((struct sockaddr_in6*) &ss)->sin6_port = htons (port); sslen = sizeof (struct sockaddr_in6); } else nn_assert (0); /* Start listening for incoming connections. */ rc = nn_usock_start (&self->usock, ss.ss_family, SOCK_STREAM, 0); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_BTCP_STATE_WAITING; return; } rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen); if (nn_slow (rc < 0)) { nn_usock_stop (&self->usock); self->state = NN_BTCP_STATE_CLOSING; return; } rc = nn_usock_listen (&self->usock, NN_BTCP_BACKLOG); if (nn_slow (rc < 0)) { nn_usock_stop (&self->usock); self->state = NN_BTCP_STATE_CLOSING; return; } nn_btcp_start_accepting(self); self->state = NN_BTCP_STATE_ACTIVE; }
static void nn_btcp_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_btcp *btcp; struct nn_list_item *it; struct nn_atcp *atcp; btcp = nn_cont (self, struct nn_btcp, fsm); /******************************************************************************/ /* STOP procedure. */ /******************************************************************************/ if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_atcp_stop (btcp->atcp); btcp->state = NN_BTCP_STATE_STOPPING_ATCP; } if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_ATCP)) { if (!nn_atcp_isidle (btcp->atcp)) return; nn_atcp_term (btcp->atcp); nn_free (btcp->atcp); btcp->atcp = NULL; nn_usock_stop (&btcp->usock); btcp->state = NN_BTCP_STATE_STOPPING_USOCK; } if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_USOCK)) { if (!nn_usock_isidle (&btcp->usock)) return; for (it = nn_list_begin (&btcp->atcps); it != nn_list_end (&btcp->atcps); it = nn_list_next (&btcp->atcps, it)) { atcp = nn_cont (it, struct nn_atcp, item); nn_atcp_stop (atcp); } btcp->state = NN_BTCP_STATE_STOPPING_ATCPS; goto atcps_stopping; } if (nn_slow (btcp->state == NN_BTCP_STATE_STOPPING_ATCPS)) { nn_assert (src == NN_BTCP_SRC_ATCP && type == NN_ATCP_STOPPED); atcp = (struct nn_atcp *) srcptr; nn_list_erase (&btcp->atcps, &atcp->item); nn_atcp_term (atcp); nn_free (atcp); /* If there are no more atcp state machines, we can stop the whole btcp object. */ atcps_stopping: if (nn_list_empty (&btcp->atcps)) { btcp->state = NN_BTCP_STATE_IDLE; nn_fsm_stopped_noevent (&btcp->fsm); nn_epbase_stopped (&btcp->epbase); return; } return; } 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); } }