diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-06 17:51:14 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-06 17:51:14 +0000 |
commit | 6319ac5225aec738f134f338f68109822581bff1 (patch) | |
tree | 17e827cff6841eaae0de6b0b733ee2e8958cc9e0 /src/libunixonacid/unixmessage_receive.c | |
parent | 5d6810d9eb833f923f1543fbb369823f7cd289df (diff) | |
download | skalibs-6319ac5225aec738f134f338f68109822581bff1.tar.xz |
Rewrite unixmessage_receiver without buffer, only cbuffer
Diffstat (limited to 'src/libunixonacid/unixmessage_receive.c')
-rw-r--r-- | src/libunixonacid/unixmessage_receive.c | 106 |
1 files changed, 87 insertions, 19 deletions
diff --git a/src/libunixonacid/unixmessage_receive.c b/src/libunixonacid/unixmessage_receive.c index dc75263..fed1b03 100644 --- a/src/libunixonacid/unixmessage_receive.c +++ b/src/libunixonacid/unixmessage_receive.c @@ -1,44 +1,112 @@ /* ISC license. */ +#define _XPG4_2 +#include <skalibs/sysdeps.h> +#include <skalibs/nonposix.h> #include <errno.h> -#include <skalibs/allreadwrite.h> -#include <skalibs/buffer.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <skalibs/uint.h> +#include <skalibs/diuint.h> #include <skalibs/cbuffer.h> +#include <skalibs/djbunix.h> #include <skalibs/error.h> +#include <skalibs/allreadwrite.h> #include <skalibs/stralloc.h> -#include <skalibs/uint.h> +#include <skalibs/siovec.h> #include <skalibs/unixmessage.h> +static int unixmessage_receiver_fill (unixmessage_receiver_t *b, diuint *d) +{ + char ancilbuf[CMSG_SPACE(b->auxb.a - 1)] ; + struct iovec iov[2] ; + struct msghdr msghdr = + { + .msg_name = 0, + .msg_namelen = 0, + .msg_iov = iov, + .msg_iovlen = 2, + .msg_flags = 0, + .msg_control = ancilbuf, + .msg_controllen = sizeof(ancilbuf) + } ; + unsigned int auxlen ; + int r ; + if (cbuffer_isfull(&b->mainb) || cbuffer_isfull(&b->auxb)) + return (errno = ENOBUFS, -1) ; + { + siovec_t v[2] ; + cbuffer_wpeek(&b->mainb, v) ; + iovec_from_siovec(iov, v, 2) ; + } +#ifdef SKALIBS_HASCMSGCLOEXEC + r = recvmsg(b->fd, &msghdr, MSG_WAITALL | MSG_CMSG_CLOEXEC) ; +#else + r = recvmsg(b->fd, &msghdr, MSG_WAITALL) ; +#endif + if (r <= 0) return r ; + { + struct cmsghdr *c = CMSG_FIRSTHDR(&msghdr) ; + if (c) + { + if (c->cmsg_level != SOL_SOCKET + || c->cmsg_type != SCM_RIGHTS) return (errno = EPROTO, -1) ; + auxlen = (unsigned int)(c->cmsg_len - (CMSG_DATA(c) - (unsigned char *)c)) ; +#ifndef SKALIBS_HASCMSGCLOEXEC + { + register unsigned int i = 0 ; + for (; i < auxlen/sizeof(int) ; i++) + if (coe(((int *)CMSG_DATA(c))[i]) < 0) return -1 ; + } +#endif + if (msghdr.msg_flags & MSG_CTRUNC) return (errno = EPROTO, -1) ; + if (cbuffer_put(&b->auxb, (char *)CMSG_DATA(c), auxlen) < auxlen) + return (errno = ENOBUFS, -1) ; + d->right = auxlen / sizeof(int) ; + r -= c->cmsg_len ; + } + } + d->left = cbuffer_WSEEK(&b->mainb, r) ; + return 1 ; +} + int unixmessage_receive (unixmessage_receiver_t *b, unixmessage_t *m) { - if (b->data.len == b->mainlen) + if (b->maindata.len == b->mainlen && b->auxdata.len == b->auxlen) { char pack[sizeof(unsigned int) << 1] ; - if (buffer_len(&b->mainb) < sizeof(unsigned int) << 1) + if (cbuffer_len(&b->mainb) < sizeof(unsigned int) << 1) { - register int r = sanitize_read(buffer_fill(&b->mainb)) ; + diuint d ; + register int r = sanitize_read(unixmessage_receiver_fill(b, &d)) ; if (r <= 0) return r ; - if (r < sizeof(unsigned int) << 1) return (errno = EWOULDBLOCK, 0) ; + if (cbuffer_len(&b->mainb) < sizeof(unsigned int) << 1) + return (errno = EWOULDBLOCK, 0) ; } - buffer_getnofill(&b->mainb, pack, sizeof(unsigned int) << 1) ; + cbuffer_get(&b->mainb, pack, sizeof(unsigned int) << 1) ; uint_unpack_big(pack, &b->mainlen) ; uint_unpack_big(pack + sizeof(unsigned int), &b->auxlen) ; - if (b->auxlen > UNIXMESSAGE_MAXFDS) return (errno = EPROTO, -1) ; b->auxlen *= sizeof(int) ; - if (!stralloc_ready(&b->data, b->mainlen)) return -1 ; - b->data.len = 0 ; - b->auxw = cbuffer_get(&b->auxb, (char *)b->fds, b->auxlen) ; + if (!stralloc_ready(&b->maindata, b->mainlen)) return -1 ; + b->maindata.len = 0 ; + if (!stralloc_ready(&b->auxdata, b->auxlen)) return -1 ; + b->auxdata.len = 0 ; } + + for (;;) { - register int r = buffer_getall(&b->mainb, b->data.s, b->mainlen, &b->data.len) ; + diuint d ; + register int r ; + b->maindata.len += cbuffer_get(&b->mainb, b->maindata.s + b->maindata.len, cbuffer_len(&b->mainb)) ; + b->auxdata.len += cbuffer_get(&b->auxb, b->auxdata.s + b->auxdata.len, cbuffer_len(&b->auxb)) ; + if (b->maindata.len == b->mainlen && b->auxdata.len == b->auxlen) break ; + r = sanitize_read(unixmessage_receiver_fill(b, &d)) ; if (r <= 0) return r ; } - if (b->auxw < b->auxlen) - b->auxw += cbuffer_get(&b->auxb, (char *)b->fds, b->auxlen - b->auxw) ; - if (b->auxw < b->auxlen) return (errno = EPROTO, -1) ; - m->s = b->data.s ; - m->len = b->data.len ; - m->fds = b->fds ; + + m->s = b->maindata.s ; + m->len = b->maindata.len ; + m->fds = (int *)b->auxdata.s ; m->nfds = b->auxlen / sizeof(int) ; return 1 ; } |