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); nn_sock_stat_increment (self.socks [s], NN_STAT_MESSAGES_RECEIVED, 1); nn_sock_stat_increment (self.socks [s], NN_STAT_BYTES_RECEIVED, sz); 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; }
void nn_ep_clear_error (struct nn_ep *self) { if (self->last_errno == 0) /* Error is already clear, no need to report it */ return; nn_sock_stat_increment (self->sock, NN_STAT_CURRENT_EP_ERRORS, -1); self->last_errno = 0; nn_sock_report_error (self->sock, self, 0); }
void nn_ep_set_error(struct nn_ep *self, int errnum) { if (self->last_errno == errnum) /* Error is still there, no need to report it again */ return; if (self->last_errno == 0) nn_sock_stat_increment (self->sock, NN_STAT_CURRENT_EP_ERRORS, 1); self->last_errno = errnum; nn_sock_report_error (self->sock, self, errnum); }
int nn_sock_add (struct nn_sock *self, struct nn_pipe *pipe) { int rc; rc = self->sockbase->vfptr->add (self->sockbase, pipe); if (nn_slow (rc >= 0)) { nn_sock_stat_increment (self, NN_STAT_CURRENT_CONNECTIONS, 1); } return rc; }
void nn_ep_stat_increment (struct nn_ep *self, int name, int increment) { nn_sock_stat_increment (self->sock, name, increment); }
void nn_sock_rm (struct nn_sock *self, struct nn_pipe *pipe) { self->sockbase->vfptr->rm (self->sockbase, pipe); nn_sock_stat_increment (self, NN_STAT_CURRENT_CONNECTIONS, -1); }
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_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; int nnmsg; 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) { 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)) { /* 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; }