void nn_pipebase_getopt(struct nn_pipebase *self, int level, int option,void *optval, size_t *optvallen) { int rc,intval; if ( level == NN_SOL_SOCKET ) { switch (option) { /* Endpoint options */ case NN_SNDPRIO: intval = self->options.sndprio; break; case NN_RCVPRIO: intval = self->options.rcvprio; break; case NN_IPV4ONLY: intval = self->options.ipv4only; break; /* Fallback to socket options */ default: rc = nn_sock_getopt_inner(self->sock, level,option, optval, optvallen); errnum_assert (rc == 0, -rc); return; } memcpy (optval, &intval,*optvallen < sizeof (int) ? *optvallen : sizeof (int)); *optvallen = sizeof (int); return; } rc = nn_sock_getopt_inner (self->sock, level, option, optval, optvallen); errnum_assert (rc == 0, -rc); }
static int nn_xsub_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xsub *xsub; xsub = nn_cont (self, struct nn_xsub, sockbase); /* Loop while a matching message is found or when there are no more messages to receive. */ while (1) { rc = nn_fq_recv (&xsub->fq, msg, NULL); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc >= 0, -rc); rc = nn_trie_match (&xsub->trie, nn_chunkref_data (&msg->body), nn_chunkref_size (&msg->body)); if (rc == 0) { nn_msg_term (msg); continue; } if (rc == 1) return 0; errnum_assert (0, -rc); } }
static void nn_bipc_start_listening (struct nn_bipc *self) { int rc; struct sockaddr_storage ss; struct sockaddr_un *un; const char *addr; /* First, create the AF_UNIX address. */ 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)); /* Delete the IPC file left over by eventual previous runs of the application. */ rc = unlink (addr); errno_assert (rc == 0 || errno == ENOENT); /* Start listening for incoming connections. */ rc = nn_usock_start (&self->usock, AF_UNIX, SOCK_STREAM, 0); /* TODO: EMFILE error can happen here. We can wait a bit and re-try. */ errnum_assert (rc == 0, -rc); rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, sizeof (struct sockaddr_un)); errnum_assert (rc == 0, -rc); rc = nn_usock_listen (&self->usock, NN_BIPC_BACKLOG); errnum_assert (rc == 0, -rc); }
int nn_sem_wait (struct nn_sem *myself) { int rc; /* With OSX, semaphores are global named objects. They are not useful for our use case. To get a similar object we exploit the implementation detail of pthread_cond_wait() in Darwin kernel: It exits if signal is caught. Note that this behaviour is not mandated by POSIX and may break with future versions of Darwin. */ rc = pthread_mutex_lock (&myself->mutex); errnum_assert (rc == 0, rc); if (nn_fast (myself->signaled)) { rc = pthread_mutex_unlock (&myself->mutex); errnum_assert (rc == 0, rc); return 0; } rc = pthread_cond_wait (&myself->cond, &myself->mutex); errnum_assert (rc == 0, rc); if (nn_slow (!myself->signaled)) { rc = pthread_mutex_unlock (&myself->mutex); errnum_assert (rc == 0, rc); return -EINTR; } myself->signaled = 0; rc = pthread_mutex_unlock (&myself->mutex); errnum_assert (rc == 0, rc); return 0; }
static int nn_ipc_binit (const char *addr, struct nn_usock *usock, struct nn_cp *cp, int backlog) { int rc; struct sockaddr_storage ss; socklen_t sslen; struct sockaddr_un *un; /* Create the AF_UNIX address. */ memset (&ss, 0, sizeof (ss)); un = (struct sockaddr_un*) &ss; if (strlen (addr) >= sizeof (un->sun_path)) return -ENAMETOOLONG; ss.ss_family = AF_UNIX; strncpy (un->sun_path, addr, sizeof (un->sun_path)); sslen = sizeof (struct sockaddr_un); /* Delete the ipc file left over by eventual previous runs of the application. */ rc = unlink (addr); errno_assert (rc == 0 || errno == ENOENT); /* Open the listening socket. */ rc = nn_usock_init (usock, NULL, AF_UNIX, SOCK_STREAM, 0, -1, -1, cp); errnum_assert (rc == 0, -rc); rc = nn_usock_bind (usock, (struct sockaddr*) &ss, sslen); errnum_assert (rc == 0, -rc); rc = nn_usock_listen (usock, backlog); errnum_assert (rc == 0, -rc); return 0; }
void nn_sem_term (struct nn_sem *myself) { int rc; rc = pthread_cond_destroy (&myself->cond); errnum_assert (rc == 0, rc); rc = pthread_mutex_destroy (&myself->mutex); errnum_assert (rc == 0, rc); }
void nn_sem_init (struct nn_sem *myself) { int rc; rc = pthread_mutex_init (&myself->mutex, NULL); errnum_assert (rc == 0, rc); rc = pthread_cond_init (&myself->cond, NULL); errnum_assert (rc == 0, rc); myself->signaled = 0; }
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); /* TODO: EMFILE error can happen here. We can wait a bit and re-try. */ errnum_assert (rc == 0, -rc); rc = nn_usock_bind (&self->usock, (struct sockaddr*) &ss, (size_t) sslen); errnum_assert (rc == 0, -rc); rc = nn_usock_listen (&self->usock, NN_BTCP_BACKLOG); errnum_assert (rc == 0, -rc); }
void xs_sock_term (xs_sock *self) { int rc; xs_tcpout_term (&self->out); rc = pthread_cond_destroy (&self->readable); errnum_assert (rc); rc = pthread_cond_destroy (&self->writeable); errnum_assert (rc); xs_mutex_term (&self->sync); }
int nn_sock_term (struct nn_sock *self) { int rc; int i; /* NOTE: nn_sock_stop must have already been called. */ /* Some endpoints may still be alive. Here we are going to wait till they are all closed. This loop is not interruptible, because making it so would leave a partially cleaned up socket, and we don't have a way to defer resource deallocation. */ for (;;) { rc = nn_sem_wait (&self->termsem); if (nn_slow (rc == -EINTR)) continue; errnum_assert (rc == 0, -rc); break; } /* Also, wait for all holds on the socket to be released. */ for (;;) { rc = nn_sem_wait (&self->relesem); if (nn_slow (rc == -EINTR)) continue; errnum_assert (rc == 0, -rc); break; } /* Threads that posted the semaphore(s) can still have the ctx locked for a short while. By simply entering the context and exiting it immediately we can be sure that any such threads have already exited the context. */ nn_ctx_enter (&self->ctx); nn_ctx_leave (&self->ctx); /* At this point, we can be reasonably certain that no other thread has any references to the socket. */ nn_fsm_stopped_noevent (&self->fsm); nn_fsm_term (&self->fsm); nn_sem_term (&self->termsem); nn_list_term (&self->sdeps); nn_list_term (&self->eps); nn_clock_term (&self->clock); nn_ctx_term (&self->ctx); /* Destroy any optsets associated with the socket. */ for (i = 0; i != NN_MAX_TRANSPORT; ++i) if (self->optsets [i]) self->optsets [i]->vfptr->destroy (self->optsets [i]); return 0; }
void nn_sem_post (struct nn_sem *myself) { int rc; rc = pthread_mutex_lock (&myself->mutex); errnum_assert (rc == 0, rc); nn_assert (myself->signaled == 0); myself->signaled = 1; rc = pthread_cond_signal (&myself->cond); errnum_assert (rc == 0, rc); rc = pthread_mutex_unlock (&myself->mutex); errnum_assert (rc == 0, rc); }
static int nn_tcp_cresolve (const char *addr, struct sockaddr_storage *local, socklen_t *locallen, struct sockaddr_storage *remote, socklen_t *remotelen) { int rc; int port; const char *end; const char *colon; const char *semicolon; int res; res = 0; /* Make sure we're working from a clean slate. Required on Mac OS X. */ memset (remote, 0, sizeof (struct sockaddr_storage)); /* Parse the port. */ end = addr + strlen (addr); colon = strrchr (addr, ':'); port = nn_addr_parse_port (colon + 1, end - colon - 1); if (nn_slow (port == -EINVAL)) return -EINVAL; errnum_assert (port > 0, -port); /* Parse the local address, if any. */ semicolon = strchr (addr, ';'); if (semicolon) { memset (local, 0, sizeof (struct sockaddr_storage)); rc = nn_addr_parse_local (addr, semicolon - addr, NN_ADDR_IPV4ONLY, local, locallen); errnum_assert (rc == 0, -rc); addr = semicolon + 1; res |= NN_CSTREAM_DOBIND; } /* Parse the remote address. */ /* TODO: Get the actual value of the IPV4ONLY socket option. */ rc = nn_addr_parse_remote (addr, colon - addr, NN_ADDR_IPV4ONLY, remote, remotelen); if (nn_slow (rc < 0)) return rc; /* Combine the port and the address. */ 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); return res; }
static int nn_tcp_binit (const char *addr, struct nn_usock *usock, struct nn_cp *cp, int backlog) { int rc; int port; const char *end; const char *pos; struct sockaddr_storage ss; socklen_t sslen; /* Make sure we're working from a clean slate. Required on Mac OS X. */ memset (&ss, 0, sizeof (ss)); /* Parse the port. */ end = addr + strlen (addr); pos = strrchr (addr, ':'); if (!pos) return -EINVAL; ++pos; rc = nn_addr_parse_port (pos, end - pos); if (rc < 0) return rc; port = rc; /* Parse the address. */ /* TODO: Get the actual value of the IPV4ONLY socket option. */ rc = nn_addr_parse_local (addr, pos - addr - 1, NN_ADDR_IPV4ONLY, &ss, &sslen); if (rc < 0) return rc; /* Combine the port and the address. */ if (ss.ss_family == AF_INET) ((struct sockaddr_in*) &ss)->sin_port = htons (port); else if (ss.ss_family == AF_INET6) ((struct sockaddr_in6*) &ss)->sin6_port = htons (port); else nn_assert (0); /* Open the listening socket. */ rc = nn_usock_init (usock, NULL, AF_INET, SOCK_STREAM, IPPROTO_TCP, -1, -1, cp); errnum_assert (rc == 0, -rc); rc = nn_usock_bind (usock, (struct sockaddr*) &ss, sslen); errnum_assert (rc == 0, -rc); rc = nn_usock_listen (usock, NN_TCP_BACKLOG); errnum_assert (rc == 0, -rc); return 0; }
void nn_stream_init (struct nn_stream *self, struct nn_epbase *epbase, struct nn_usock *usock) { int rc; int protocol; size_t sz; struct nn_iobuf iobuf; /* Redirect the underlying socket's events to this state machine. */ self->usock = usock; self->sink = &nn_stream_state_start; self->original_sink = nn_usock_setsink (usock, &self->sink); /* Initialise the pipe to communicate with the user. */ rc = nn_pipebase_init (&self->pipebase, &nn_stream_pipebase_vfptr, epbase); nn_assert (rc == 0); nn_msg_init (&self->inmsg, 0); nn_msg_init (&self->outmsg, 0); /* Start the header timeout timer. */ nn_timer_init (&self->hdr_timeout, &self->sink, usock->cp); nn_timer_start (&self->hdr_timeout, 1000); /* Send the protocol header. */ sz = sizeof (protocol); nn_epbase_getopt (epbase, NN_SOL_SOCKET, NN_PROTOCOL, &protocol, &sz); errnum_assert (rc == 0, -rc); nn_assert (sz == sizeof (protocol)); memcpy (self->protohdr, "\0\0SP\0\0\0\0", 8); nn_puts (self->protohdr + 4, (uint16_t) protocol); iobuf.iov_base = self->protohdr; iobuf.iov_len = 8; nn_usock_send (usock, &iobuf, 1); }
void xs_mutex_init (xs_mutex *self) { int rc; rc = pthread_mutex_init (self, NULL); errnum_assert (rc); }
static int nn_respondent_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_respondent *respondent; respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase); /* If there's no survey going on, report EFSM error. */ if (nn_slow (!(respondent->flags & NN_RESPONDENT_INPROGRESS))) return -EFSM; /* Tag the message with survey ID. */ nn_assert (nn_chunkref_size (&msg->sphdr) == 0); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 4); nn_putl (nn_chunkref_data (&msg->sphdr), respondent->surveyid); /* Try to send the message. If it cannot be sent due to pushback, drop it silently. */ rc = nn_xrespondent_send (&respondent->xrespondent.sockbase, msg); if (nn_slow (rc == -EAGAIN)) { nn_msg_term (msg); return -EAGAIN; } errnum_assert (rc == 0, -rc); /* Remember that no survey is being processed. */ respondent->flags &= ~NN_RESPONDENT_INPROGRESS; return 0; }
static int nn_respondent_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_respondent *respondent; respondent = nn_cont (self, struct nn_respondent, xrespondent.sockbase); /* Cancel current survey, if it exists. */ respondent->flags &= ~NN_RESPONDENT_INPROGRESS; /* Get next survey. */ rc = nn_xrespondent_recv (&respondent->xrespondent.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); /* Remember the survey ID. */ nn_assert (nn_chunkref_size (&msg->sphdr) == sizeof (uint32_t)); respondent->surveyid = nn_getl (nn_chunkref_data (&msg->sphdr)); nn_chunkref_term (&msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); /* Remember that survey is being processed. */ respondent->flags |= NN_RESPONDENT_INPROGRESS; return 0; }
int nn_xrespondent_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_xrespondent *xrespondent; xrespondent = nn_cont (self, struct nn_xrespondent, sockbase); /* Get the survey. */ rc = nn_excl_recv (&xrespondent->excl, msg); if (rc == -EAGAIN) return -EAGAIN; errnum_assert (rc >= 0, -rc); /* Split the survey ID from the body, if needed. */ if (!(rc & NN_PIPE_PARSED)) { if (nn_slow (nn_chunkref_size (&msg->body) < sizeof (uint32_t))) { nn_msg_term (msg); return -EAGAIN; } nn_chunkref_term (&msg->hdr); nn_chunkref_init (&msg->hdr, sizeof (uint32_t)); memcpy (nn_chunkref_data (&msg->hdr), nn_chunkref_data (&msg->body), sizeof (uint32_t)); nn_chunkref_trim (&msg->body, sizeof (uint32_t)); } return 0; }
int nn_condvar_wait (nn_condvar_t *cond, nn_mutex_t *lock, int timeout) { int rc; struct timeval tv; struct timespec ts; if (timeout < 0) { /* This is an infinite sleep. We don't care about return values, as any error we can treat as just a premature wakeup. */ (void) pthread_cond_wait (&cond->cv, &lock->mutex); return (0); } rc = gettimeofday(&tv, NULL); errnum_assert (rc == 0, rc); /* There are extra operations performed here, but they are done to avoid wrap of the tv_usec and ts_nsec members on 32-bit systems. */ tv.tv_sec += timeout / 1000; tv.tv_usec += (timeout % 1000) * 1000; ts.tv_sec = tv.tv_sec + (tv.tv_usec / 1000000); ts.tv_nsec = (tv.tv_usec % 1000000) * 1000; rc = pthread_cond_timedwait (&cond->cv, &lock->mutex, &ts); if (rc == ETIMEDOUT) return (-ETIMEDOUT); /* Treat all other cases (including errors) as normal wakeup. */ return (0); }
int nn_rep_recv (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_rep *rep; rep = nn_cont (self, struct nn_rep, xrep.sockbase); /* If a request is already being processed, cancel it. */ if (nn_slow (rep->flags & NN_REP_INPROGRESS)) { nn_chunkref_term (&rep->backtrace); rep->flags &= ~NN_REP_INPROGRESS; } /* Receive the request. */ rc = nn_xrep_recv (&rep->xrep.sockbase, msg); if (nn_slow (rc == -EAGAIN)) return -EAGAIN; errnum_assert (rc == 0, -rc); /* Store the backtrace. */ nn_chunkref_mv (&rep->backtrace, &msg->sphdr); nn_chunkref_init (&msg->sphdr, 0); rep->flags |= NN_REP_INPROGRESS; return 0; }
int nn_getsockopt (int s, int level, int option, void *optval, size_t *optvallen) { int rc; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (nn_slow (!optval && optvallen)) { rc = -EFAULT; goto fail; } rc = nn_sock_getopt (sock, level, option, optval, optvallen); if (nn_slow (rc < 0)) goto fail; errnum_assert (rc == 0, -rc); nn_global_rele_socket (sock); return 0; fail: nn_global_rele_socket (sock); errno = -rc; return -1; }
void nn_thread_init(struct nn_thread *self,nn_thread_routine *routine, void *arg) { int32_t rc; sigset_t new_sigmask,old_sigmask; // No signals should be processed by this thread. The library doesn't use signals and thus all the signals should be delivered to application threads, not to worker threads. rc = sigfillset(&new_sigmask); errno_assert(rc == 0); rc = pthread_sigmask(SIG_BLOCK, &new_sigmask, &old_sigmask); errnum_assert(rc == 0, rc); self->routine = routine; self->arg = arg; rc = pthread_create(&self->handle,NULL,nn_thread_main_routine,(void *)self); errnum_assert (rc == 0, rc); // Restore signal set to what it was before. rc = pthread_sigmask(SIG_BLOCK, &new_sigmask, &old_sigmask); errnum_assert (rc == 0, rc); }
int grid_xreq_recv (struct grid_sockbase *self, struct grid_msg *msg) { int rc; rc = grid_fq_recv (&grid_cont (self, struct grid_xreq, sockbase)->fq, msg, NULL); if (rc == -EAGAIN) return -EAGAIN; errnum_assert (rc >= 0, -rc); if (!(rc & GRID_PIPE_PARSED)) { /* Ignore malformed replies. */ if (grid_slow (grid_chunkref_size (&msg->body) < sizeof (uint32_t))) { grid_msg_term (msg); return -EAGAIN; } /* Split the message into the header and the body. */ grid_assert (grid_chunkref_size (&msg->sphdr) == 0); grid_chunkref_term (&msg->sphdr); grid_chunkref_init (&msg->sphdr, sizeof (uint32_t)); memcpy (grid_chunkref_data (&msg->sphdr), grid_chunkref_data (&msg->body), sizeof (uint32_t)); grid_chunkref_trim (&msg->body, sizeof (uint32_t)); } return 0; }
void grid_usock_recv (struct grid_usock *self, void *buf, size_t len, int *fd) { int rc; size_t nbytes; /* Make sure that the socket is actually alive. */ grid_assert_state (self, GRID_USOCK_STATE_ACTIVE); /* Try to receive the data immediately. */ nbytes = len; self->in.pfd = fd; rc = grid_usock_recv_raw (self, buf, &nbytes); if (grid_slow (rc < 0)) { errnum_assert (rc == -ECONNRESET, -rc); grid_fsm_action (&self->fsm, GRID_USOCK_ACTION_ERROR); return; } /* Success. */ if (grid_fast (nbytes == len)) { grid_fsm_raise (&self->fsm, &self->event_received, GRID_USOCK_RECEIVED); return; } /* There are still data to receive in the background. */ self->in.buf = ((uint8_t*) buf) + nbytes; self->in.len = len - nbytes; /* Ask the worker thread to receive the remaining data. */ grid_worker_execute (self->worker, &self->task_recv); }
static void nn_cstream_closing_closed (const struct nn_cp_sink **self, struct nn_usock *usock) { int rc; struct nn_cstream *cstream; int sndbuf; int rcvbuf; size_t sz; cstream = nn_cont (self, struct nn_cstream, sink); /* Get the current values of NN_SNDBUF and NN_RCVBUF options. */ sz = sizeof (sndbuf); nn_epbase_getopt (&cstream->epbase, NN_SOL_SOCKET, NN_SNDBUF, &sndbuf, &sz); nn_assert (sz == sizeof (sndbuf)); sz = sizeof (rcvbuf); nn_epbase_getopt (&cstream->epbase, NN_SOL_SOCKET, NN_RCVBUF, &rcvbuf, &sz); nn_assert (sz == sizeof (rcvbuf)); /* Create new socket. */ rc = cstream->initsockfn (&cstream->usock, sndbuf, rcvbuf, nn_epbase_getcp (&cstream->epbase)); errnum_assert (rc == 0, -rc); nn_usock_setsink (&cstream->usock, &cstream->sink); /* Wait for the specified period. */ cstream->sink = &nn_cstream_state_waiting; nn_timer_start (&cstream->retry_timer, nn_cstream_compute_retry_ivl (cstream)); }
void nn_glock_unlock (void) { int rc; rc = pthread_mutex_unlock (&nn_glock_mutex); errnum_assert (rc == 0, rc); }
static void nn_req_action_send (struct nn_req *self) { int rc; struct nn_msg msg; /* Send the request. */ nn_msg_cp (&msg, &self->request); rc = nn_xreq_send (&self->xreq.sockbase, &msg); /* If the request cannot be sent at the moment wait till new outbound pipe arrives. */ if (nn_slow (rc == -EAGAIN)) { nn_msg_term (&msg); self->state = NN_REQ_STATE_DELAYED; return; } /* Request was successfully sent. Set up the re-send timer in case the request gets lost somewhere further out in the topology. */ if (nn_fast (rc == 0)) { nn_timer_start (&self->timer, self->resend_ivl); self->state = NN_REQ_STATE_ACTIVE; return; } /* Unexpected error. */ errnum_assert (0, -rc); }
void xs_mutex_term (xs_mutex *self) { int rc; rc = pthread_mutex_destroy (self); errnum_assert (rc); }
void xs_mutex_unlock (xs_mutex *self) { int rc; rc = pthread_mutex_unlock (self); errnum_assert (rc); }
static int nn_surveyor_send (struct nn_sockbase *self, struct nn_msg *msg) { int rc; struct nn_surveyor *surveyor; surveyor = nn_cont (self, struct nn_surveyor, xsurveyor.sockbase); /* Cancel any ongoing survey. */ if (nn_slow (surveyor->flags & NN_SURVEYOR_INPROGRESS)) { surveyor->flags &= ~NN_SURVEYOR_INPROGRESS; nn_timer_stop (&surveyor->deadline_timer); } /* Generate new survey ID. */ ++surveyor->surveyid; /* Tag the survey body with survey ID. */ nn_assert (nn_chunkref_size (&msg->hdr) == 0); nn_chunkref_term (&msg->hdr); nn_chunkref_init (&msg->hdr, 4); nn_putl (nn_chunkref_data (&msg->hdr), surveyor->surveyid); /* Send the survey. */ rc = nn_xsurveyor_send (&surveyor->xsurveyor.sockbase, msg); errnum_assert (rc == 0, -rc); surveyor->flags |= NN_SURVEYOR_INPROGRESS; /* Set up the re-send timer. */ nn_timer_start (&surveyor->deadline_timer, surveyor->deadline); return 0; }