int ftw_socket_inbox_construct(struct ftw_socket_inbox **inst, LVUserEventRef *msg_to_lv_event, struct ftw_socket_inbox **sock, const LStrHandleArray **addresses, int linger, int max_recv_size) { char *addr; int rcb; int rcs; int rco; int i; /* Preconditions expected of LabVIEW. */ ftw_assert(inst && *inst && addresses && *addresses && msg_to_lv_event && sock); rcs = nn_socket(AF_SP_RAW, NN_REP); /* Socket creation failure? */ if (rcs < 0) { *sock = NULL; return rcs; } rco = nn_setsockopt(rcs, NN_SOL_SOCKET, NN_LINGER, &linger, sizeof(linger)); if (rco < 0) { *sock = NULL; return rco; } rco = nn_setsockopt(rcs, NN_SOL_SOCKET, NN_RCVMAXSIZE, &max_recv_size, sizeof(max_recv_size)); if (rco < 0) { *sock = NULL; return rco; } for (i = 0; i < (*addresses)->dimsize; i++) { addr = ftw_support_LStrHandle_to_CStr((*addresses)->element[i]); rcb = nn_bind(rcs, addr); ftw_free (addr); if (rcb < 0) { nn_close(rcs); *sock = NULL; return rcb; } } (*inst)->incoming_msg_notifier_event = *msg_to_lv_event; (*inst)->id = rcs; /* Launch thread and wait for it to initialize. */ nn_sem_init(&(*inst)->deinitialized); nn_sem_init(&(*inst)->initialized); nn_sem_init(&(*inst)->msg_acknowledged); nn_thread_init(&(*inst)->async_recv_thread, ftw_socket_inbox_async_recv_worker, *inst); nn_sem_wait(&(*inst)->initialized); *sock = *inst; 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); } }
/* 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; }
int ftw_subscriber_construct(struct ftw_socket_callsite **callsite, LVUserEventRef *lv_event, const char *addr, int linger, int max_recv_size, struct ftw_socket **sock) { struct ftw_socket *inst; int rcc; int rcs; int rco; /* Preconditions expected of LabVIEW. */ ftw_assert(*callsite && addr); nn_mutex_lock(&(*callsite)->sync); rcs = nn_socket(AF_SP, NN_SUB); /* Socket creation failure? */ if (rcs < 0) { *sock = NULL; nn_mutex_unlock(&(*callsite)->sync); return rcs; } rco = nn_setsockopt(rcs, NN_SOL_SOCKET, NN_LINGER, &linger, sizeof(linger)); if (rco < 0) { *sock = NULL; nn_mutex_unlock(&(*callsite)->sync); return rco; } rco = nn_setsockopt(rcs, NN_SOL_SOCKET, NN_RCVMAXSIZE, &max_recv_size, sizeof(max_recv_size)); if (rco < 0) { *sock = NULL; nn_mutex_unlock(&(*callsite)->sync); return rco; } rcc = nn_connect(rcs, addr); /* Endpoint creation failure? */ if (rcc < 0) { nn_close(rcs); *sock = NULL; nn_mutex_unlock(&(*callsite)->sync); return rcc; } rco = nn_setsockopt (rcs, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); if (rco < 0) { nn_close(rcs); *sock = NULL; nn_mutex_unlock(&(*callsite)->sync); return rco; } inst = ftw_malloc(sizeof(struct ftw_socket)); ftw_assert(inst); inst->incoming_msg_notifier_event = *lv_event; inst->id = rcs; inst->callsite = *callsite; nn_list_item_init(&inst->item); nn_list_insert(&(*callsite)->active_sockets, &inst->item, nn_list_end(&(*callsite)->active_sockets)); nn_sem_init(&inst->msg_acknowledged); /* Launch thread and wait for it to initialize. */ nn_sem_init(&inst->async_recv_ready); nn_thread_init(&inst->async_recv_thread, ftw_subscriber_async_recv_thread, inst); nn_sem_wait(&inst->async_recv_ready); *sock = inst; (*callsite)->lifetime_sockets++; nn_mutex_unlock(&(*callsite)->sync); return 0; }