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; }
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; }
void *nn_chunkref_data (struct nn_chunkref *self) { return self->ref [0] == 0xff ? nn_chunk_data (((struct nn_chunkref_chunk*) self)->chunk) : &self->ref [1]; }
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; struct nn_chunk *ch; 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) { ch = nn_chunkref_getchunk (&msg.body); *(void**) (msghdr->msg_iov [0].iov_base) = nn_chunk_data (ch); sz = nn_chunk_size (ch); } 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) { ch = nn_chunkref_getchunk (&msg.hdr); *((void**) msghdr->msg_control) = nn_chunk_data (ch); } else { /* TODO: Copy the data to the supplied buffer, prefix them with size. */ nn_assert (0); } } nn_msg_term (&msg); #if defined NN_LATENCY_MONITOR nn_latmon_measure (NN_LATMON_RECV); #endif return (int) sz; }