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_cipc_start_connecting (struct nn_cipc *self) { int rc; struct sockaddr_storage ss; struct sockaddr_un *un; const char *addr; int val; size_t sz; /* Try to start the underlying socket. */ rc = nn_usock_start (&self->usock, AF_UNIX, SOCK_STREAM, 0); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CIPC_STATE_WAITING; return; } /* Set the relevant socket options. */ sz = sizeof (val); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Create the IPC address from the address string. */ addr = nn_epbase_getaddr (&self->epbase); memset (&ss, 0, sizeof (ss)); un = (struct sockaddr_un*) &ss; nn_assert (strlen (addr) < sizeof (un->sun_path)); ss.ss_family = AF_UNIX; strncpy (un->sun_path, addr, sizeof (un->sun_path)); /* Start connecting. */ nn_usock_connect (&self->usock, (struct sockaddr*) &ss, sizeof (struct sockaddr_un)); self->state = NN_CIPC_STATE_CONNECTING; nn_epbase_stat_increment (&self->epbase, NN_STAT_INPROGRESS_CONNECTIONS, 1); }
static void nn_aws_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_aws *aws; aws = nn_cont (self, struct nn_aws, fsm); nn_assert (aws); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_sws_isidle (&aws->sws)) { nn_epbase_stat_increment (aws->epbase, NN_STAT_DROPPED_CONNECTIONS, 1); nn_sws_stop (&aws->sws); } aws->state = NN_AWS_STATE_STOPPING_SWS_FINAL; } if (nn_slow (aws->state == NN_AWS_STATE_STOPPING_SWS_FINAL)) { if (!nn_sws_isidle (&aws->sws)) return; nn_usock_stop (&aws->usock); aws->state = NN_AWS_STATE_STOPPING; } if (nn_slow (aws->state == NN_AWS_STATE_STOPPING)) { if (!nn_usock_isidle (&aws->usock)) return; if (aws->listener) { nn_assert (aws->listener_owner.fsm); nn_usock_swap_owner (aws->listener, &aws->listener_owner); aws->listener = NULL; aws->listener_owner.src = -1; aws->listener_owner.fsm = NULL; } aws->state = NN_AWS_STATE_IDLE; nn_fsm_stopped (&aws->fsm, NN_AWS_STOPPED); return; } nn_fsm_bad_action (aws->state, src, type); }
static void nn_binproc_connect (struct nn_ins_item *self, struct nn_ins_item *peer) { struct nn_binproc *binproc; struct nn_cinproc *cinproc; struct nn_sinproc *sinproc; binproc = nn_cont (self, struct nn_binproc, item); nn_assert (binproc); cinproc = nn_cont (peer, struct nn_cinproc, item); nn_assert (cinproc); nn_assert_state (binproc, NN_BINPROC_STATE_ACTIVE); sinproc = nn_alloc (sizeof (struct nn_sinproc), "sinproc"); alloc_assert (sinproc); nn_sinproc_init (sinproc, NN_BINPROC_SRC_SINPROC, &binproc->item.epbase, &binproc->fsm); nn_list_insert (&binproc->sinprocs, &sinproc->item, nn_list_end (&binproc->sinprocs)); nn_sinproc_connect (sinproc, &cinproc->fsm); nn_epbase_stat_increment (&binproc->item.epbase, NN_STAT_ACCEPTED_CONNECTIONS, 1); }
static void nn_ctcp_shutdown (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_ctcp *ctcp; ctcp = nn_cont (self, struct nn_ctcp, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { if (!nn_stcp_isidle (&ctcp->stcp)) { nn_epbase_stat_increment (&ctcp->epbase, NN_STAT_DROPPED_CONNECTIONS, 1); nn_stcp_stop (&ctcp->stcp); } ctcp->state = NN_CTCP_STATE_STOPPING_STCP_FINAL; } if (nn_slow (ctcp->state == NN_CTCP_STATE_STOPPING_STCP_FINAL)) { if (!nn_stcp_isidle (&ctcp->stcp)) return; nn_backoff_stop (&ctcp->retry); nn_usock_stop (&ctcp->usock); nn_dns_stop (&ctcp->dns); ctcp->state = NN_CTCP_STATE_STOPPING; } if (nn_slow (ctcp->state == NN_CTCP_STATE_STOPPING)) { if (!nn_backoff_isidle (&ctcp->retry) || !nn_usock_isidle (&ctcp->usock) || !nn_dns_isidle (&ctcp->dns)) return; ctcp->state = NN_CTCP_STATE_IDLE; nn_fsm_stopped_noevent (&ctcp->fsm); nn_epbase_stopped (&ctcp->epbase); return; } nn_fsm_bad_state (ctcp->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_ctcp_start_connecting (struct nn_ctcp *self, struct sockaddr_storage *ss, size_t sslen) { int rc; struct sockaddr_storage remote; size_t remotelen; struct sockaddr_storage local; size_t locallen; const char *addr; const char *end; const char *colon; const char *semicolon; uint16_t port; int ipv4only; size_t ipv4onlylen; int val; size_t sz; /* Create IP address from the address string. */ addr = nn_epbase_getaddr (&self->epbase); memset (&remote, 0, sizeof (remote)); /* Parse the port. */ end = addr + strlen (addr); colon = strrchr (addr, ':'); rc = nn_port_resolve (colon + 1, end - colon - 1); errnum_assert (rc > 0, -rc); port = rc; /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); /* Parse the local address, if any. */ semicolon = strchr (addr, ';'); memset (&local, 0, sizeof (local)); if (semicolon) rc = nn_iface_resolve (addr, semicolon - addr, ipv4only, &local, &locallen); else rc = nn_iface_resolve ("*", 1, ipv4only, &local, &locallen); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Combine the remote address and the port. */ remote = *ss; remotelen = sslen; if (remote.ss_family == AF_INET) ((struct sockaddr_in*) &remote)->sin_port = htons (port); else if (remote.ss_family == AF_INET6) ((struct sockaddr_in6*) &remote)->sin6_port = htons (port); else nn_assert (0); /* Try to start the underlying socket. */ rc = nn_usock_start (&self->usock, remote.ss_family, SOCK_STREAM, 0); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Set the relevant socket options. */ sz = sizeof (val); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Bind the socket to the local network interface. */ rc = nn_usock_bind (&self->usock, (struct sockaddr*) &local, locallen); if (nn_slow (rc != 0)) { nn_backoff_start (&self->retry); self->state = NN_CTCP_STATE_WAITING; return; } /* Start connecting. */ nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen); self->state = NN_CTCP_STATE_CONNECTING; nn_epbase_stat_increment (&self->epbase, NN_STAT_INPROGRESS_CONNECTIONS, 1); }
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_cinproc_handler (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_cinproc *cinproc; struct nn_sinproc *sinproc; cinproc = nn_cont (self, struct nn_cinproc, fsm); switch (cinproc->state) { /******************************************************************************/ /* IDLE state. */ /******************************************************************************/ case NN_CINPROC_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: cinproc->state = NN_CINPROC_STATE_DISCONNECTED; nn_epbase_stat_increment (&cinproc->item.epbase, NN_STAT_INPROGRESS_CONNECTIONS, 1); return; default: nn_fsm_bad_action (cinproc->state, src, type); } default: nn_fsm_bad_source (cinproc->state, src, type); } /******************************************************************************/ /* DISCONNECTED state. */ /******************************************************************************/ case NN_CINPROC_STATE_DISCONNECTED: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_CINPROC_ACTION_CONNECT: cinproc->state = NN_CINPROC_STATE_ACTIVE; nn_epbase_stat_increment (&cinproc->item.epbase, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_epbase_stat_increment (&cinproc->item.epbase, NN_STAT_ESTABLISHED_CONNECTIONS, 1); return; default: nn_fsm_bad_action (cinproc->state, src, type); } case NN_SINPROC_SRC_PEER: sinproc = (struct nn_sinproc*) srcptr; switch (type) { case NN_SINPROC_CONNECT: nn_sinproc_accept (&cinproc->sinproc, sinproc); cinproc->state = NN_CINPROC_STATE_ACTIVE; nn_epbase_stat_increment (&cinproc->item.epbase, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_epbase_stat_increment (&cinproc->item.epbase, NN_STAT_ESTABLISHED_CONNECTIONS, 1); return; default: nn_fsm_bad_action (cinproc->state, src, type); } default: nn_fsm_bad_source (cinproc->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_CINPROC_STATE_ACTIVE: nn_fsm_bad_source (cinproc->state, src, type); /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (cinproc->state, src, type); } }
static void nn_aws_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_aws *aws; int val; size_t sz; aws = nn_cont (self, struct nn_aws, fsm); nn_assert (aws); switch (aws->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_AWS_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_usock_accept (&aws->usock, aws->listener); aws->state = NN_AWS_STATE_ACCEPTING; return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* ACCEPTING state. */ /* Waiting for incoming connection. */ /******************************************************************************/ case NN_AWS_STATE_ACCEPTING: switch (src) { case NN_AWS_SRC_USOCK: switch (type) { case NN_USOCK_ACCEPTED: nn_epbase_clear_error (aws->epbase); /* Set the relevant socket options. */ sz = sizeof (val); nn_epbase_getopt (aws->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_epbase_getopt (aws->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Since the WebSocket handshake must poll, the receive timeout is set to zero. Later, it will be set again to the value specified by the socket option. */ val = 0; sz = sizeof (val); nn_usock_setsockopt (&aws->usock, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof (val)); /* Return ownership of the listening socket to the parent. */ nn_usock_swap_owner (aws->listener, &aws->listener_owner); aws->listener = NULL; aws->listener_owner.src = -1; aws->listener_owner.fsm = NULL; nn_fsm_raise (&aws->fsm, &aws->accepted, NN_AWS_ACCEPTED); /* Start the sws state machine. */ nn_usock_activate (&aws->usock); nn_sws_start (&aws->sws, &aws->usock, NN_WS_SERVER, NULL, NULL); aws->state = NN_AWS_STATE_ACTIVE; nn_epbase_stat_increment (aws->epbase, NN_STAT_ACCEPTED_CONNECTIONS, 1); return; default: nn_fsm_bad_action (aws->state, src, type); } case NN_AWS_SRC_LISTENER: switch (type) { case NN_USOCK_ACCEPT_ERROR: nn_epbase_set_error (aws->epbase, nn_usock_geterrno (aws->listener)); nn_epbase_stat_increment (aws->epbase, NN_STAT_ACCEPT_ERRORS, 1); nn_usock_accept (&aws->usock, aws->listener); return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /******************************************************************************/ case NN_AWS_STATE_ACTIVE: switch (src) { case NN_AWS_SRC_SWS: switch (type) { case NN_SWS_RETURN_CLOSE_HANDSHAKE: /* Peer closed connection without intention to reconnect, or local endpoint failed remote because of invalid data. */ nn_sws_stop (&aws->sws); aws->state = NN_AWS_STATE_STOPPING_SWS; return; case NN_SWS_RETURN_ERROR: nn_sws_stop (&aws->sws); aws->state = NN_AWS_STATE_STOPPING_SWS; nn_epbase_stat_increment (aws->epbase, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* STOPPING_SWS state. */ /******************************************************************************/ case NN_AWS_STATE_STOPPING_SWS: switch (src) { case NN_AWS_SRC_SWS: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_SWS_RETURN_STOPPED: nn_usock_stop (&aws->usock); aws->state = NN_AWS_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /******************************************************************************/ case NN_AWS_STATE_STOPPING_USOCK: switch (src) { case NN_AWS_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: nn_aws_stop (aws); return; default: nn_fsm_bad_action (aws->state, src, type); } default: nn_fsm_bad_source (aws->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (aws->state, src, type); } }
static void nn_cws_start_connecting (struct nn_cws *self, struct sockaddr_storage *ss, size_t sslen) { int rc; struct sockaddr_storage remote; size_t remotelen; struct sockaddr_storage local; size_t locallen; int ipv4only; size_t ipv4onlylen; int val; size_t sz; memset (&remote, 0, sizeof (remote)); memset (&local, 0, sizeof (local)); /* Check whether IPv6 is to be used. */ ipv4onlylen = sizeof (ipv4only); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_IPV4ONLY, &ipv4only, &ipv4onlylen); nn_assert (ipv4onlylen == sizeof (ipv4only)); rc = nn_iface_resolve (nn_chunkref_data (&self->nic), nn_chunkref_size (&self->nic), ipv4only, &local, &locallen); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CWS_STATE_WAITING; return; } /* Combine the remote address and the port. */ remote = *ss; remotelen = sslen; if (remote.ss_family == AF_INET) ((struct sockaddr_in*) &remote)->sin_port = htons (self->remote_port); else if (remote.ss_family == AF_INET6) ((struct sockaddr_in6*) &remote)->sin6_port = htons (self->remote_port); else nn_assert (0); /* Try to start the underlying socket. */ rc = nn_usock_start (&self->usock, remote.ss_family, SOCK_STREAM, 0); if (nn_slow (rc < 0)) { nn_backoff_start (&self->retry); self->state = NN_CWS_STATE_WAITING; return; } /* Set the relevant socket options. */ sz = sizeof (val); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_SNDBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_SNDBUF, &val, sizeof (val)); sz = sizeof (val); nn_epbase_getopt (&self->epbase, NN_SOL_SOCKET, NN_RCVBUF, &val, &sz); nn_assert (sz == sizeof (val)); nn_usock_setsockopt (&self->usock, SOL_SOCKET, SO_RCVBUF, &val, sizeof (val)); /* Bind the socket to the local network interface. */ rc = nn_usock_bind (&self->usock, (struct sockaddr*) &local, locallen); if (nn_slow (rc != 0)) { nn_backoff_start (&self->retry); self->state = NN_CWS_STATE_WAITING; return; } /* Start connecting. */ nn_usock_connect (&self->usock, (struct sockaddr*) &remote, remotelen); self->state = NN_CWS_STATE_CONNECTING; nn_epbase_stat_increment (&self->epbase, NN_STAT_INPROGRESS_CONNECTIONS, 1); }
static void nn_cws_handler (struct nn_fsm *self, int src, int type, NN_UNUSED void *srcptr) { struct nn_cws *cws; cws = nn_cont (self, struct nn_cws, fsm); switch (cws->state) { /******************************************************************************/ /* IDLE state. */ /* The state machine wasn't yet started. */ /******************************************************************************/ case NN_CWS_STATE_IDLE: switch (src) { case NN_FSM_ACTION: switch (type) { case NN_FSM_START: nn_cws_start_resolving (cws); return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* RESOLVING state. */ /* Name of the host to connect to is being resolved to get an IP address. */ /******************************************************************************/ case NN_CWS_STATE_RESOLVING: switch (src) { case NN_CWS_SRC_DNS: switch (type) { case NN_DNS_DONE: nn_dns_stop (&cws->dns); cws->state = NN_CWS_STATE_STOPPING_DNS; return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* STOPPING_DNS state. */ /* dns object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CWS_STATE_STOPPING_DNS: switch (src) { case NN_CWS_SRC_DNS: switch (type) { case NN_DNS_STOPPED: if (cws->dns_result.error == 0) { nn_cws_start_connecting (cws, &cws->dns_result.addr, cws->dns_result.addrlen); return; } nn_backoff_start (&cws->retry); cws->state = NN_CWS_STATE_WAITING; return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* CONNECTING state. */ /* Non-blocking connect is under way. */ /******************************************************************************/ case NN_CWS_STATE_CONNECTING: switch (src) { case NN_CWS_SRC_USOCK: switch (type) { case NN_USOCK_CONNECTED: nn_sws_start (&cws->sws, &cws->usock, NN_WS_CLIENT, nn_chunkref_data (&cws->resource), nn_chunkref_data (&cws->remote_host), cws->msg_type); cws->state = NN_CWS_STATE_ACTIVE; cws->peer_gone = 0; nn_epbase_stat_increment (&cws->epbase, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_epbase_stat_increment (&cws->epbase, NN_STAT_ESTABLISHED_CONNECTIONS, 1); nn_epbase_clear_error (&cws->epbase); return; case NN_USOCK_ERROR: nn_epbase_set_error (&cws->epbase, nn_usock_geterrno (&cws->usock)); nn_usock_stop (&cws->usock); cws->state = NN_CWS_STATE_STOPPING_USOCK; nn_epbase_stat_increment (&cws->epbase, NN_STAT_INPROGRESS_CONNECTIONS, -1); nn_epbase_stat_increment (&cws->epbase, NN_STAT_CONNECT_ERRORS, 1); return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* ACTIVE state. */ /* Connection is established and handled by the sws state machine. */ /******************************************************************************/ case NN_CWS_STATE_ACTIVE: switch (src) { case NN_CWS_SRC_SWS: switch (type) { case NN_SWS_RETURN_CLOSE_HANDSHAKE: /* Peer closed connection without intention to reconnect, or local endpoint failed remote because of invalid data. */ nn_sws_stop (&cws->sws); cws->state = NN_CWS_STATE_STOPPING_SWS; cws->peer_gone = 1; return; case NN_SWS_RETURN_ERROR: nn_sws_stop (&cws->sws); cws->state = NN_CWS_STATE_STOPPING_SWS; nn_epbase_stat_increment (&cws->epbase, NN_STAT_BROKEN_CONNECTIONS, 1); return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* STOPPING_SWS state. */ /* sws object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CWS_STATE_STOPPING_SWS: switch (src) { case NN_CWS_SRC_SWS: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_SWS_RETURN_STOPPED: nn_usock_stop (&cws->usock); cws->state = NN_CWS_STATE_STOPPING_USOCK; return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* STOPPING_USOCK state. */ /* usock object was asked to stop but it haven't stopped yet. */ /******************************************************************************/ case NN_CWS_STATE_STOPPING_USOCK: switch (src) { case NN_CWS_SRC_USOCK: switch (type) { case NN_USOCK_SHUTDOWN: return; case NN_USOCK_STOPPED: /* If the peer has confirmed itself gone with a Closing Handshake, or if the local endpoint failed the remote, don't try to reconnect. */ if (!cws->peer_gone) { nn_backoff_start (&cws->retry); cws->state = NN_CWS_STATE_WAITING; } return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->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_CWS_STATE_WAITING: switch (src) { case NN_CWS_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_TIMEOUT: nn_backoff_stop (&cws->retry); cws->state = NN_CWS_STATE_STOPPING_BACKOFF; return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* STOPPING_BACKOFF state. */ /* backoff object was asked to stop, but it haven't stopped yet. */ /******************************************************************************/ case NN_CWS_STATE_STOPPING_BACKOFF: switch (src) { case NN_CWS_SRC_RECONNECT_TIMER: switch (type) { case NN_BACKOFF_STOPPED: nn_cws_start_resolving (cws); return; default: nn_fsm_bad_action (cws->state, src, type); } default: nn_fsm_bad_source (cws->state, src, type); } /******************************************************************************/ /* Invalid state. */ /******************************************************************************/ default: nn_fsm_bad_state (cws->state, src, type); } }