int nn_sockbase_init (struct nn_sockbase *self, const struct nn_sockbase_vfptr *vfptr) { int rc; /* Make sure that at least one message direction is supported. */ nn_assert (!(vfptr->flags & NN_SOCKBASE_FLAG_NOSEND) || !(vfptr->flags & NN_SOCKBASE_FLAG_NORECV)); /* Open the NN_SNDFD and NN_RCVFD efds. Do so, only if the socket type supports send/recv, as appropriate. */ if (vfptr->flags & NN_SOCKBASE_FLAG_NOSEND) memset (&self->sndfd, 0xcd, sizeof (self->sndfd)); else { rc = nn_efd_init (&self->sndfd); if (nn_slow (rc < 0)) return rc; } if (vfptr->flags & NN_SOCKBASE_FLAG_NORECV) memset (&self->rcvfd, 0xcd, sizeof (self->rcvfd)); else { rc = nn_efd_init (&self->rcvfd); if (nn_slow (rc < 0)) { if (!(vfptr->flags & NN_SOCKBASE_FLAG_NOSEND)) nn_efd_term (&self->sndfd); return rc; } } memset (&self->termsem, 0xcd, sizeof (self->termsem)); rc = nn_cp_init (&self->cp); if (nn_slow (rc < 0)) { if (!(vfptr->flags & NN_SOCKBASE_FLAG_NORECV)) nn_efd_term (&self->rcvfd); if (!(vfptr->flags & NN_SOCKBASE_FLAG_NOSEND)) nn_efd_term (&self->sndfd); return rc; } self->vfptr = vfptr; self->flags = 0; nn_clock_init (&self->clock); nn_list_init (&self->eps); self->eid = 1; /* Default values for NN_SOL_SOCKET options. */ self->domain = -1; self->protocol = -1; self->linger = 1000; self->sndbuf = 128 * 1024; self->rcvbuf = 128 * 1024; self->sndtimeo = -1; self->rcvtimeo = -1; self->reconnect_ivl = 100; self->reconnect_ivl_max = 0; self->sndprio = 8; self->rcvprio = 8; return 0; }
int nn_sock_destroy (struct nn_sock *self) { int rc; struct nn_sockbase *sockbase; struct nn_list_item *it; struct nn_epbase *ep; sockbase = (struct nn_sockbase*) self; nn_cp_lock (&sockbase->cp); /* The call may have been interrupted by a singal and restarted afterwards. In such case don't do the following stuff again. */ if (!(sockbase->flags & NN_SOCK_FLAG_CLOSING)) { /* Mark the socket as being in process of shutting down. */ sockbase->flags |= NN_SOCK_FLAG_CLOSING; /* Close sndfd and rcvfd. This should make any current select/poll using SNDFD and/or RCVFD exit. */ if (!(sockbase->vfptr->flags & NN_SOCKBASE_FLAG_NORECV)) { nn_efd_term (&sockbase->rcvfd); memset (&sockbase->rcvfd, 0xcd, sizeof (sockbase->rcvfd)); } if (!(sockbase->vfptr->flags & NN_SOCKBASE_FLAG_NOSEND)) { nn_efd_term (&sockbase->sndfd); memset (&sockbase->sndfd, 0xcd, sizeof (sockbase->sndfd)); } /* Create a semaphore to wait on for all endpoint to terminate. */ nn_sem_init (&sockbase->termsem); /* Ask all the associated endpoints to terminate. Call to nn_ep_close can actually deallocate the endpoint, so take care to get pointer to the next endpoint before the call. */ it = nn_list_begin (&sockbase->eps); while (it != nn_list_end (&sockbase->eps)) { ep = nn_cont (it, struct nn_epbase, item); it = nn_list_next (&sockbase->eps, it); rc = nn_ep_close ((void*) ep); errnum_assert (rc == 0 || rc == -EINPROGRESS, -rc); } }
static void nn_sock_shutdown (struct nn_fsm *self, int src, int type, void *srcptr) { struct nn_sock *sock; struct nn_list_item *it; struct nn_ep *ep; sock = nn_cont (self, struct nn_sock, fsm); if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) { nn_assert (sock->state == NN_SOCK_STATE_ACTIVE || sock->state == NN_SOCK_STATE_ZOMBIE); /* Close sndfd and rcvfd. This should make any current select/poll using SNDFD and/or RCVFD exit. */ if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) { nn_efd_term (&sock->rcvfd); memset (&sock->rcvfd, 0xcd, sizeof (sock->rcvfd)); } if (!(sock->socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) { nn_efd_term (&sock->sndfd); memset (&sock->sndfd, 0xcd, sizeof (sock->sndfd)); } /* Ask all the associated endpoints to stop. */ it = nn_list_begin (&sock->eps); while (it != nn_list_end (&sock->eps)) { ep = nn_cont (it, struct nn_ep, item); it = nn_list_next (&sock->eps, it); nn_list_erase (&sock->eps, &ep->item); nn_list_insert (&sock->sdeps, &ep->item, nn_list_end (&sock->sdeps)); nn_ep_stop (ep); } sock->state = NN_SOCK_STATE_STOPPING_EPS; goto finish2; }
void nn_worker_term (struct nn_worker *self) { /* Ask worker thread to terminate. */ nn_mutex_lock (&self->sync); nn_queue_push (&self->tasks, &self->stop); nn_efd_signal (&self->efd); nn_mutex_unlock (&self->sync); /* Wait till worker thread terminates. */ nn_thread_term (&self->thread); /* Clean up. */ nn_timerset_term (&self->timerset); nn_poller_term (&self->poller); nn_efd_term (&self->efd); nn_queue_item_term (&self->stop); nn_queue_term (&self->tasks); nn_mutex_term (&self->sync); }
/* Initialize a socket. A hold is placed on the initialized socket for the caller as well. */ int nn_sock_init (struct nn_sock *self, struct nn_socktype *socktype, int fd) { int rc; int i; /* Make sure that at least one message direction is supported. */ nn_assert (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND) || !(socktype->flags & NN_SOCKTYPE_FLAG_NORECV)); /* Create the AIO context for the SP socket. */ nn_ctx_init (&self->ctx, nn_global_getpool (), nn_sock_onleave); /* Initialise the state machine. */ nn_fsm_init_root (&self->fsm, nn_sock_handler, nn_sock_shutdown, &self->ctx); self->state = NN_SOCK_STATE_INIT; /* Open the NN_SNDFD and NN_RCVFD efds. Do so, only if the socket type supports send/recv, as appropriate. */ if (socktype->flags & NN_SOCKTYPE_FLAG_NOSEND) memset (&self->sndfd, 0xcd, sizeof (self->sndfd)); else { rc = nn_efd_init (&self->sndfd); if (nn_slow (rc < 0)) return rc; } if (socktype->flags & NN_SOCKTYPE_FLAG_NORECV) memset (&self->rcvfd, 0xcd, sizeof (self->rcvfd)); else { rc = nn_efd_init (&self->rcvfd); if (nn_slow (rc < 0)) { if (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) nn_efd_term (&self->sndfd); return rc; } } nn_sem_init (&self->termsem); nn_sem_init (&self->relesem); if (nn_slow (rc < 0)) { if (!(socktype->flags & NN_SOCKTYPE_FLAG_NORECV)) nn_efd_term (&self->rcvfd); if (!(socktype->flags & NN_SOCKTYPE_FLAG_NOSEND)) nn_efd_term (&self->sndfd); return rc; } self->holds = 1; /* Callers hold. */ self->flags = 0; nn_clock_init (&self->clock); nn_list_init (&self->eps); nn_list_init (&self->sdeps); self->eid = 1; /* Default values for NN_SOL_SOCKET options. */ self->linger = 1000; self->sndbuf = 128 * 1024; self->rcvbuf = 128 * 1024; self->rcvmaxsize = 1024 * 1024; self->sndtimeo = -1; self->rcvtimeo = -1; self->reconnect_ivl = 100; self->reconnect_ivl_max = 0; self->ep_template.sndprio = 8; self->ep_template.rcvprio = 8; self->ep_template.ipv4only = 1; /* Initialize statistic entries */ self->statistics.established_connections = 0; self->statistics.accepted_connections = 0; self->statistics.dropped_connections = 0; self->statistics.broken_connections = 0; self->statistics.connect_errors = 0; self->statistics.bind_errors = 0; self->statistics.accept_errors = 0; self->statistics.messages_sent = 0; self->statistics.messages_received = 0; self->statistics.bytes_sent = 0; self->statistics.bytes_received = 0; self->statistics.current_connections = 0; self->statistics.inprogress_connections = 0; self->statistics.current_snd_priority = 0; self->statistics.current_ep_errors = 0; /* Should be pretty much enough space for just the number */ sprintf(self->socket_name, "%d", fd); /* The transport-specific options are not initialised immediately, rather, they are allocated later on when needed. */ for (i = 0; i != NN_MAX_TRANSPORT; ++i) self->optsets [i] = NULL; /* Create the specific socket type itself. */ rc = socktype->create ((void*) self, &self->sockbase); errnum_assert (rc == 0, -rc); self->socktype = socktype; /* Launch the state machine. */ nn_ctx_enter (&self->ctx); nn_fsm_start (&self->fsm); nn_ctx_leave (&self->ctx); return 0; }