void *nn_allocmsg (size_t size, int type) { struct nn_chunk *ch; ch = nn_chunk_alloc (size, type); if (nn_slow (!ch)) return NULL; return (void*) (ch + 1); }
void *nn_allocmsg (size_t size, int type) { int rc; void *result; rc = nn_chunk_alloc (size, type, &result); if (rc == 0) return result; errno = -rc; return NULL; }
void nn_chunkref_init (struct nn_chunkref *self, size_t size) { struct nn_chunkref_chunk *ch; if (size < NN_CHUNKREF_MAX) { self->ref [0] = (uint8_t) size; return; } ch = (struct nn_chunkref_chunk*) self; ch->tag = 0xff; ch->chunk = nn_chunk_alloc (size, 0); alloc_assert (ch->chunk); }
void nn_chunkref_init (struct nn_chunkref *self, size_t size) { int rc; struct nn_chunkref_chunk *ch; if (size < NN_CHUNKREF_MAX) { self->u.ref [0] = (uint8_t) size; return; } ch = (struct nn_chunkref_chunk*) self; ch->tag = 0xff; rc = nn_chunk_alloc (size, 0, &ch->chunk); errno_assert (rc == 0); }
struct nn_chunk *nn_chunkref_getchunk (struct nn_chunkref *self) { struct nn_chunkref_chunk *ch; struct nn_chunk *chunk; if (self->ref [0] == 0xff) { ch = (struct nn_chunkref_chunk*) self; self->ref [0] = 0; return ch->chunk; } chunk = nn_chunk_alloc (self->ref [0], 0); alloc_assert (chunk); memcpy (nn_chunk_data (chunk), &self->ref [1], self->ref [0]); self->ref [0] = 0; return chunk; }
void *nn_chunkref_getchunk (struct nn_chunkref *self) { int rc; struct nn_chunkref_chunk *ch; void *chunk; if (self->u.ref [0] == 0xff) { ch = (struct nn_chunkref_chunk*) self; self->u.ref [0] = 0; return ch->chunk; } rc = nn_chunk_alloc (self->u.ref [0], 0, &chunk); errno_assert (rc == 0); memcpy (chunk, &self->u.ref [1], self->u.ref [0]); self->u.ref [0] = 0; return chunk; }
void *nn_allocmsg (size_t size, int type) { return nn_chunk_alloc (size, type); }
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_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; }