int nn_recv (int s, void *buf, size_t len, int flags) { int rc; struct nn_msg msg; size_t sz; void *chunk; NN_BASIC_CHECKS; if (nn_slow (!buf && len)) { errno = EFAULT; return -1; } rc = nn_sock_recv (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (len == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.body); *(void**) buf = chunk; sz = nn_chunk_size (chunk); } else { sz = nn_chunkref_size (&msg.body); memcpy (buf, nn_chunkref_data (&msg.body), len < sz ? len : sz); } nn_msg_term (&msg); return (int) sz; }
int nn_send (int s, const void *buf, size_t len, int flags) { int rc; struct nn_msg msg; void *chunk; int nnmsg; NN_BASIC_CHECKS; if (nn_slow (!buf && len)) { errno = EFAULT; return -1; } /* Create a message object. */ if (len == NN_MSG) { chunk = *(void**) buf; if (nn_slow (chunk == NULL)) { errno = EFAULT; return -1; } len = nn_chunk_size (chunk); nn_msg_init_chunk (&msg, chunk); nnmsg = 1; } else { nn_msg_init (&msg, len); memcpy (nn_chunkref_data (&msg.body), buf, len); nnmsg = 0; } /* Send it further down the stack. */ rc = nn_sock_send (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { /* If we are dealing with user-supplied buffer, detach it from the message object. */ if (nnmsg) nn_chunkref_init (&msg.body, 0); nn_msg_term (&msg); errno = -rc; return -1; } nn_sock_stat_increment (self.socks [s], NN_STAT_MESSAGES_SENT, 1); nn_sock_stat_increment (self.socks [s], NN_STAT_BYTES_SENT, len); return (int) len; }
struct nn_cmsghdr *nn_cmsg_nxthdr_ (const struct nn_msghdr *mhdr, const struct nn_cmsghdr *cmsg) { char *data; size_t sz; struct nn_cmsghdr *next; size_t headsz; /* Early return if no message is provided. */ if (nn_slow (mhdr == NULL)) return NULL; /* Get the actual data. */ if (mhdr->msg_controllen == NN_MSG) { data = *((void**) mhdr->msg_control); sz = nn_chunk_size (data); } else { data = (char*) mhdr->msg_control; sz = mhdr->msg_controllen; } /* Ancillary data allocation was not even large enough for one element. */ if (nn_slow (sz < NN_CMSG_SPACE (0))) return NULL; /* If cmsg is set to NULL we are going to return first property. Otherwise move to the next property. */ if (!cmsg) next = (struct nn_cmsghdr*) data; else next = (struct nn_cmsghdr*) (((char*) cmsg) + NN_CMSG_ALIGN_ (cmsg->cmsg_len)); /* If there's no space for next property, treat it as the end of the property list. */ headsz = ((char*) next) - data; if (headsz + NN_CMSG_SPACE (0) > sz || headsz + NN_CMSG_ALIGN_ (next->cmsg_len) > sz) return NULL; /* Success. */ return next; }
int nn_send (int s, const void *buf, size_t len, int flags) { int rc; struct nn_msg msg; struct nn_chunk *ch; NN_BASIC_CHECKS; #if defined NN_LATENCY_MONITOR nn_latmon_measure (NN_LATMON_SEND); #endif if (nn_slow (!buf && len)) { errno = EFAULT; return -1; } /* Create a message object. */ if (len == NN_MSG) { ch = nn_chunk_from_data (*(void**) buf); if (nn_slow (ch == NULL)) { errno = EFAULT; return -1; } len = nn_chunk_size (ch); nn_msg_init_chunk (&msg, ch); } else { nn_msg_init (&msg, len); memcpy (nn_chunkref_data (&msg.body), buf, len); } /* Send it further down the stack. */ rc = nn_sock_send (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { nn_msg_term (&msg); errno = -rc; return -1; } return (int) len; }
int nn_send (int s, const void *buf, size_t len, int flags) { int rc; struct nn_msg msg; void *chunk; NN_BASIC_CHECKS; if (nn_slow (!buf && len)) { errno = EFAULT; return -1; } /* Create a message object. */ if (len == NN_MSG) { chunk = *(void**) buf; if (nn_slow (chunk == NULL)) { errno = EFAULT; return -1; } len = nn_chunk_size (chunk); nn_msg_init_chunk (&msg, chunk); } else { nn_msg_init (&msg, len); memcpy (nn_chunkref_data (&msg.body), buf, len); } /* Send it further down the stack. */ rc = nn_sock_send (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { nn_msg_term (&msg); errno = -rc; return -1; } return (int) len; }
int nn_recv (int s, void *buf, size_t len, int flags) { int rc; struct nn_msg msg; size_t sz; struct nn_chunk *ch; NN_BASIC_CHECKS; if (nn_slow (!buf && len)) { errno = EFAULT; return -1; } rc = nn_sock_recv (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (len == NN_MSG) { ch = nn_chunkref_getchunk (&msg.body); *(void**) buf = nn_chunk_data (ch); sz = nn_chunk_size (ch); } else { sz = nn_chunkref_size (&msg.body); memcpy (buf, nn_chunkref_data (&msg.body), len < sz ? len : sz); } nn_msg_term (&msg); #if defined NN_LATENCY_MONITOR nn_latmon_measure (NN_LATMON_RECV); #endif return (int) sz; }
struct nn_cmsghdr *nn_cmsg_nexthdr_ (const struct nn_msghdr *mhdr, const struct nn_cmsghdr *cmsg) { char *data; size_t sz; struct nn_cmsghdr *next; size_t headsz; /* Get the actual data. */ if (mhdr->msg_controllen == NN_MSG) { data = *((void**) mhdr->msg_control); sz = nn_chunk_size (data); } else { data = (char*) mhdr->msg_control; sz = mhdr->msg_controllen; } /* If cmsg is set to NULL we are going to return first property. Otherwise move to the next property. */ if (!cmsg) next = (struct nn_cmsghdr*) data; else next = (struct nn_cmsghdr*) (((char*) cmsg) + NN_CMSG_SPACE (cmsg->cmsg_len)); /* If there's no space for next property, treat it as the end of the property list. */ headsz = ((char*) next) - ((char*) mhdr->msg_control); if (headsz + sizeof (struct nn_cmsghdr) > sz || headsz + NN_CMSG_SPACE (next->cmsg_len) > sz) return NULL; /* Success. */ return next; }
void ftw_socket_inbox_async_recv_worker(void *arg) { /* Opaque pointer into ftw_incoming_request structure using LabVIEW-safe type for PostLVUserEvent. */ int64 opaque; struct ftw_incoming_request *incoming; struct ftw_socket_inbox *self; struct nn_iovec iov; struct nn_msghdr msg; void *msg_ptr; void *hdr_ptr; MgErr lv_err; int socket_err; int rc; /* Notify launching process this thread is constructed. */ ftw_assert(arg); self = (struct ftw_socket_inbox *) arg; nn_sem_post(&self->initialized); lv_err = mgNoErr; socket_err = 0; /* This broker relays messages from the nanomsg socket into the LabVIEW incoming message queue. */ while (!lv_err && !socket_err) { /* Created here, this incoming request should be freed once the response is sent. */ incoming = ftw_malloc(sizeof(struct ftw_incoming_request)); if (incoming == NULL) { lv_err = mFullErr; continue; } iov.iov_base = &msg_ptr; iov.iov_len = NN_MSG; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &hdr_ptr; msg.msg_controllen = NN_MSG; rc = nn_recvmsg(self->id, &msg, 0); if (rc >= 0) { incoming->inbox = self; incoming->msg_ptr = msg_ptr; incoming->msg_len = nn_chunk_size(msg_ptr); incoming->hdr_ptr = hdr_ptr; incoming->hdr_len = nn_chunk_size(hdr_ptr); opaque = (int64)incoming; lv_err = PostLVUserEvent(self->incoming_msg_notifier_event, &opaque); ftw_assert(lv_err == mgNoErr); /* On the LabVIEW side, the handler is a an Event Handler Structure, which applies no backpressure since the event queue cannot be limited for dynamic events. For this reason, a semaphore is introduced to simulate blocking backpressure, where the semaphore is posted once the Inbox Message Router receives the message. */ nn_sem_wait(&self->msg_acknowledged); } else { /* Treat timeouts as non-fatal. Anything else will stop this thread. */ socket_err = ((errno == ETIMEDOUT || errno == EAGAIN) ? 0 : errno); } } /* Posting a NULL pointer signals the LabVIEW Message Router to shutdown. */ opaque = (int64) NULL; lv_err = PostLVUserEvent(self->incoming_msg_notifier_event, &opaque); ftw_assert(lv_err == mgNoErr); /* Wait for the Message Router to unload. */ nn_sem_wait(&self->deinitialized); return; }
int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags) { int rc; struct nn_msg msg; uint8_t *data; size_t sz; int i; struct nn_iovec *iov; void *chunk; NN_BASIC_CHECKS; if (nn_slow (!msghdr)) { errno = EINVAL; return -1; } if (nn_slow (msghdr->msg_iovlen < 0)) { errno = EMSGSIZE; return -1; } /* Get a message. */ rc = nn_sock_recv (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.body); *(void**) (msghdr->msg_iov [0].iov_base) = chunk; sz = nn_chunk_size (chunk); } else { /* Copy the message content into the supplied gather array. */ data = nn_chunkref_data (&msg.body); sz = nn_chunkref_size (&msg.body); for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { nn_msg_term (&msg); errno = EINVAL; return -1; } if (iov->iov_len > sz) { memcpy (iov->iov_base, data, sz); break; } memcpy (iov->iov_base, data, iov->iov_len); data += iov->iov_len; sz -= iov->iov_len; } sz = nn_chunkref_size (&msg.body); } /* Retrieve the ancillary data from the message. */ if (msghdr->msg_control) { if (msghdr->msg_controllen == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.hdr); *((void**) msghdr->msg_control) = chunk; } else { /* TODO: Copy the data to the supplied buffer, prefix them with size. */ nn_assert (0); } } nn_msg_term (&msg); return (int) sz; }
int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags) { int rc; size_t sz; int i; struct nn_iovec *iov; struct nn_msg msg; void *chunk; NN_BASIC_CHECKS; if (nn_slow (!msghdr)) { errno = EINVAL; return -1; } if (nn_slow (msghdr->msg_iovlen < 0)) { errno = EMSGSIZE; return -1; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = *(void**) msghdr->msg_iov [0].iov_base; if (nn_slow (chunk == NULL)) { errno = EFAULT; return -1; } sz = nn_chunk_size (chunk); nn_msg_init_chunk (&msg, chunk); } else { /* Compute the total size of the message. */ sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { errno = EINVAL; return -1; } if (nn_slow (!iov->iov_base && iov->iov_len)) { errno = EFAULT; return -1; } if (nn_slow (sz + iov->iov_len < sz)) { errno = EINVAL; return -1; } sz += iov->iov_len; } /* Create a message object from the supplied scatter array. */ nn_msg_init (&msg, sz); sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; memcpy (((uint8_t*) nn_chunkref_data (&msg.body)) + sz, iov->iov_base, iov->iov_len); sz += iov->iov_len; } } /* Add ancillary data to the message. */ if (msghdr->msg_control) { if (msghdr->msg_controllen == NN_MSG) { chunk = *((void**) msghdr->msg_control); nn_chunkref_term (&msg.hdr); nn_chunkref_init_chunk (&msg.hdr, chunk); } else { /* TODO: Copy the control data to the message. */ nn_assert (0); } } /* Send it further down the stack. */ rc = nn_sock_send (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { nn_msg_term (&msg); errno = -rc; return -1; } return (int) sz; }
size_t nn_chunkref_size (struct nn_chunkref *self) { return self->u.ref [0] == 0xff ? nn_chunk_size (((struct nn_chunkref_chunk*) self)->chunk) : self->u.ref [0]; }
int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags) { int rc; struct nn_msg msg; uint8_t *data; size_t sz; int i; struct nn_iovec *iov; void *chunk; size_t hdrssz; void *ctrl; size_t ctrlsz; size_t spsz; size_t sptotalsz; struct nn_cmsghdr *chdr; NN_BASIC_CHECKS; if (nn_slow (!msghdr)) { errno = EINVAL; return -1; } if (nn_slow (msghdr->msg_iovlen < 0)) { errno = EMSGSIZE; return -1; } /* Get a message. */ rc = nn_sock_recv (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.body); *(void**) (msghdr->msg_iov [0].iov_base) = chunk; sz = nn_chunk_size (chunk); } else { /* Copy the message content into the supplied gather array. */ data = nn_chunkref_data (&msg.body); sz = nn_chunkref_size (&msg.body); for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { nn_msg_term (&msg); errno = EINVAL; return -1; } if (iov->iov_len > sz) { memcpy (iov->iov_base, data, sz); break; } memcpy (iov->iov_base, data, iov->iov_len); data += iov->iov_len; sz -= iov->iov_len; } sz = nn_chunkref_size (&msg.body); } /* Retrieve the ancillary data from the message. */ if (msghdr->msg_control) { spsz = nn_chunkref_size (&msg.sphdr); sptotalsz = NN_CMSG_SPACE (spsz); ctrlsz = sptotalsz + nn_chunkref_size (&msg.hdrs); if (msghdr->msg_controllen == NN_MSG) { /* Allocate the buffer. */ rc = nn_chunk_alloc (ctrlsz, 0, &ctrl); errnum_assert (rc == 0, -rc); /* Set output parameters. */ *((void**) msghdr->msg_control) = ctrl; } else { /* Just use the buffer supplied by the user. */ ctrl = msghdr->msg_control; ctrlsz = msghdr->msg_controllen; } /* If SP header alone won't fit into the buffer, return no ancillary properties. */ if (ctrlsz >= sptotalsz) { /* Fill in SP_HDR ancillary property. */ chdr = (struct nn_cmsghdr*) ctrl; chdr->cmsg_len = sptotalsz; chdr->cmsg_level = PROTO_SP; chdr->cmsg_type = SP_HDR; memcpy (chdr + 1, nn_chunkref_data (&msg.sphdr), spsz); /* Fill in as many remaining properties as possible. Truncate the trailing properties if necessary. */ hdrssz = nn_chunkref_size (&msg.hdrs); if (hdrssz > ctrlsz - sptotalsz) hdrssz = ctrlsz - sptotalsz; memcpy (((char*) ctrl) + sptotalsz, nn_chunkref_data (&msg.hdrs), hdrssz); } } nn_msg_term (&msg); return (int) sz; }
int nn_sendmsg (int s, const struct nn_msghdr *msghdr, int flags) { int rc; size_t sz; size_t spsz; int i; struct nn_iovec *iov; struct nn_msg msg; void *chunk; int nnmsg; struct nn_cmsghdr *cmsg; NN_BASIC_CHECKS; if (nn_slow (!msghdr)) { errno = EINVAL; return -1; } if (nn_slow (msghdr->msg_iovlen < 0)) { errno = EMSGSIZE; return -1; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = *(void**) msghdr->msg_iov [0].iov_base; if (nn_slow (chunk == NULL)) { errno = EFAULT; return -1; } sz = nn_chunk_size (chunk); nn_msg_init_chunk (&msg, chunk); nnmsg = 1; } else { /* Compute the total size of the message. */ sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { errno = EINVAL; return -1; } if (nn_slow (!iov->iov_base && iov->iov_len)) { errno = EFAULT; return -1; } if (nn_slow (sz + iov->iov_len < sz)) { errno = EINVAL; return -1; } sz += iov->iov_len; } /* Create a message object from the supplied scatter array. */ nn_msg_init (&msg, sz); sz = 0; for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; memcpy (((uint8_t*) nn_chunkref_data (&msg.body)) + sz, iov->iov_base, iov->iov_len); sz += iov->iov_len; } nnmsg = 0; } /* Add ancillary data to the message. */ if (msghdr->msg_control) { /* Copy all headers. */ /* TODO: SP_HDR should not be copied here! */ if (msghdr->msg_controllen == NN_MSG) { chunk = *((void**) msghdr->msg_control); nn_chunkref_term (&msg.hdrs); nn_chunkref_init_chunk (&msg.hdrs, chunk); } else { nn_chunkref_term (&msg.hdrs); nn_chunkref_init (&msg.hdrs, msghdr->msg_controllen); memcpy (nn_chunkref_data (&msg.hdrs), msghdr->msg_control, msghdr->msg_controllen); } /* Search for SP_HDR property. */ cmsg = NN_CMSG_FIRSTHDR (msghdr); while (cmsg) { if (cmsg->cmsg_level == PROTO_SP && cmsg->cmsg_type == SP_HDR) { /* Copy body of SP_HDR property into 'sphdr'. */ nn_chunkref_term (&msg.sphdr); spsz = cmsg->cmsg_len - NN_CMSG_SPACE (0); nn_chunkref_init (&msg.sphdr, spsz); memcpy (nn_chunkref_data (&msg.sphdr), NN_CMSG_DATA (cmsg), spsz); break; } cmsg = NN_CMSG_NXTHDR (msghdr, cmsg); } } /* Send it further down the stack. */ rc = nn_sock_send (self.socks [s], &msg, flags); if (nn_slow (rc < 0)) { /* If we are dealing with user-supplied buffer, detach it from the message object. */ if (nnmsg) nn_chunkref_init (&msg.body, 0); nn_msg_term (&msg); errno = -rc; return -1; } /* Adjust the statistics. */ nn_sock_stat_increment (self.socks [s], NN_STAT_MESSAGES_SENT, 1); nn_sock_stat_increment (self.socks [s], NN_STAT_BYTES_SENT, sz); return (int) sz; }
int nn_recvmsg (int s, struct nn_msghdr *msghdr, int flags) { int rc; struct nn_msg msg; uint8_t *data; size_t sz; int i; struct nn_iovec *iov; void *chunk; size_t hdrssz; void *ctrl; size_t ctrlsz; size_t spsz; size_t sptotalsz; struct nn_cmsghdr *chdr; struct nn_sock *sock; rc = nn_global_hold_socket (&sock, s); if (nn_slow (rc < 0)) { errno = -rc; return -1; } if (nn_slow (!msghdr)) { rc = -EINVAL; goto fail; } if (nn_slow (msghdr->msg_iovlen < 0)) { rc = -EMSGSIZE; goto fail; } /* Get a message. */ rc = nn_sock_recv (sock, &msg, flags); if (nn_slow (rc < 0)) { goto fail; } if (msghdr->msg_iovlen == 1 && msghdr->msg_iov [0].iov_len == NN_MSG) { chunk = nn_chunkref_getchunk (&msg.body); *(void**) (msghdr->msg_iov [0].iov_base) = chunk; sz = nn_chunk_size (chunk); } else { /* Copy the message content into the supplied gather array. */ data = nn_chunkref_data (&msg.body); sz = nn_chunkref_size (&msg.body); for (i = 0; i != msghdr->msg_iovlen; ++i) { iov = &msghdr->msg_iov [i]; if (nn_slow (iov->iov_len == NN_MSG)) { nn_msg_term (&msg); rc = -EINVAL; goto fail; } if (iov->iov_len > sz) { memcpy (iov->iov_base, data, sz); break; } memcpy (iov->iov_base, data, iov->iov_len); data += iov->iov_len; sz -= iov->iov_len; } sz = nn_chunkref_size (&msg.body); } /* Retrieve the ancillary data from the message. */ if (msghdr->msg_control) { spsz = nn_chunkref_size (&msg.sphdr); sptotalsz = NN_CMSG_SPACE (spsz+sizeof (size_t)); ctrlsz = sptotalsz + nn_chunkref_size (&msg.hdrs); if (msghdr->msg_controllen == NN_MSG) { /* Allocate the buffer. */ rc = nn_chunk_alloc (ctrlsz, 0, &ctrl); errnum_assert (rc == 0, -rc); /* Set output parameters. */ *((void**) msghdr->msg_control) = ctrl; } else { /* Just use the buffer supplied by the user. */ ctrl = msghdr->msg_control; ctrlsz = msghdr->msg_controllen; } /* If SP header alone won't fit into the buffer, return no ancillary properties. */ if (ctrlsz >= sptotalsz) { char *ptr; /* Fill in SP_HDR ancillary property. */ chdr = (struct nn_cmsghdr*) ctrl; chdr->cmsg_len = sptotalsz; chdr->cmsg_level = PROTO_SP; chdr->cmsg_type = SP_HDR; ptr = (void *)chdr; ptr += sizeof (*chdr); *(size_t *)(void *)ptr = spsz; ptr += sizeof (size_t); memcpy (ptr, nn_chunkref_data (&msg.sphdr), spsz); /* Fill in as many remaining properties as possible. Truncate the trailing properties if necessary. */ hdrssz = nn_chunkref_size (&msg.hdrs); if (hdrssz > ctrlsz - sptotalsz) hdrssz = ctrlsz - sptotalsz; memcpy (((char*) ctrl) + sptotalsz, nn_chunkref_data (&msg.hdrs), hdrssz); } } nn_msg_term (&msg); /* Adjust the statistics. */ nn_sock_stat_increment (sock, NN_STAT_MESSAGES_RECEIVED, 1); nn_sock_stat_increment (sock, NN_STAT_BYTES_RECEIVED, sz); nn_global_rele_socket (sock); return (int) sz; fail: nn_global_rele_socket (sock); errno = -rc; return -1; }