unixmessage_receive.c (4074B)
1 /* ISC license. */ 2 3 #include <skalibs/sysdeps.h> 4 #include <skalibs/nonposix.h> 5 6 #include <errno.h> 7 #include <sys/socket.h> 8 #include <sys/uio.h> 9 10 #include <skalibs/uint16.h> 11 #include <skalibs/uint32.h> 12 #include <skalibs/cbuffer.h> 13 #include <skalibs/djbunix.h> 14 #include <skalibs/allreadwrite.h> 15 #include <skalibs/stralloc.h> 16 #include <skalibs/unixmessage.h> 17 #include <skalibs/posixishard.h> 18 19 union aligner_u 20 { 21 struct cmsghdr cmsghdr ; 22 int i ; 23 } ; 24 25 static int const awesomeflags = 26 #ifdef SKALIBS_HASMSGDONTWAIT 27 MSG_DONTWAIT 28 #else 29 0 30 #endif 31 | 32 #ifdef SKALIBS_HASCMSGCLOEXEC 33 MSG_CMSG_CLOEXEC 34 #else 35 0 36 #endif 37 ; 38 39 static int unixmessage_receiver_fill (unixmessage_receiver *b) 40 { 41 union aligner_u ancilbuf[1 + CMSG_SPACE(b->auxb.a - 1) / sizeof(union aligner_u)] ; 42 struct iovec iov[2] ; 43 struct msghdr msghdr = 44 { 45 .msg_name = 0, 46 .msg_namelen = 0, 47 .msg_iov = iov, 48 .msg_iovlen = 2, 49 .msg_flags = 0, 50 .msg_control = b->fds_ok & 1 ? ancilbuf : 0, 51 .msg_controllen = b->fds_ok & 1 ? CMSG_SPACE(b->auxb.a - 1) : 0 52 } ; 53 ssize_t r = -1 ; 54 if (cbuffer_isfull(&b->mainb) || ((b->fds_ok & 1) && cbuffer_isfull(&b->auxb))) 55 return (errno = ENOBUFS, -1) ; 56 cbuffer_wpeek(&b->mainb, iov) ; 57 while (r < 0) 58 { 59 r = recvmsg(b->fd, &msghdr, awesomeflags) ; 60 if (!r || (r < 0 && errno != EINTR)) return r ; 61 } 62 if (b->fds_ok & 1) 63 { 64 struct cmsghdr *c = CMSG_FIRSTHDR(&msghdr) ; 65 if (c) 66 { 67 size_t auxlen ; 68 if (c->cmsg_level != SOL_SOCKET 69 || c->cmsg_type != SCM_RIGHTS) return (errno = EPROTO, -1) ; 70 auxlen = (size_t)(c->cmsg_len - (CMSG_DATA(c) - (unsigned char *)c)) ; 71 if (auxlen && !(b->fds_ok & 2)) 72 { 73 size_t i = auxlen / sizeof(int) ; 74 while (i--) fd_close(((int *)CMSG_DATA(c))[i]) ; 75 return (errno = EPROTO, -1) ; 76 } 77 #ifndef SKALIBS_HASCMSGCLOEXEC 78 { 79 size_t i = 0 ; 80 for (; i < auxlen / sizeof(int) ; i++) 81 if (coe(((int *)CMSG_DATA(c))[i]) < 0) 82 { 83 i++ ; 84 while (i--) fd_close(((int *)CMSG_DATA(c))[i]) ; 85 return -1 ; 86 } 87 } 88 #endif 89 if ((msghdr.msg_flags & MSG_CTRUNC) || cbuffer_put(&b->auxb, (char *)CMSG_DATA(c), auxlen) < auxlen) 90 { 91 size_t i = auxlen/sizeof(int) ; 92 while (i--) fd_close(((int *)CMSG_DATA(c))[i]) ; 93 return (errno = ENOBUFS, -1) ; 94 } 95 } 96 } 97 cbuffer_WSEEK(&b->mainb, r) ; 98 return 1 ; 99 } 100 101 int unixmessage_receive (unixmessage_receiver *b, unixmessage *m) 102 { 103 if (b->maindata.len == b->mainlen && b->auxdata.len == b->auxlen) 104 { 105 char pack[6] ; 106 if (cbuffer_len(&b->mainb) < 6) 107 { 108 ssize_t r = sanitize_read(unixmessage_receiver_fill(b)) ; 109 if (r <= 0) return r ; 110 if (cbuffer_len(&b->mainb) < 6) return (errno = EWOULDBLOCK, 0) ; 111 } 112 cbuffer_get(&b->mainb, pack, 6) ; 113 uint32_unpack_big(pack, &b->mainlen) ; 114 if (b->fds_ok & 1) uint16_unpack_big(pack + 4, &b->auxlen) ; 115 else b->auxlen = 0 ; 116 b->auxlen *= sizeof(int) ; 117 if (b->mainlen > UNIXMESSAGE_MAXSIZE 118 || b->auxlen > ((b->fds_ok & 2) ? UNIXMESSAGE_MAXFDS * sizeof(int) : 0)) 119 return (errno = EPROTO, -1) ; 120 if (!stralloc_ready(&b->maindata, b->mainlen) 121 || !stralloc_ready(&b->auxdata, b->auxlen)) 122 return -1 ; 123 b->maindata.len = 0 ; 124 b->auxdata.len = 0 ; 125 } 126 127 for (;;) 128 { 129 ssize_t r ; 130 size_t n = cbuffer_len(&b->mainb) ; 131 if (n > b->mainlen - b->maindata.len) n = b->mainlen - b->maindata.len ; 132 b->maindata.len += cbuffer_get(&b->mainb, b->maindata.s + b->maindata.len, n) ; 133 n = cbuffer_len(&b->auxb) ; 134 if (n > b->auxlen - b->auxdata.len) n = b->auxlen - b->auxdata.len ; 135 b->auxdata.len += cbuffer_get(&b->auxb, b->auxdata.s + b->auxdata.len, n) ; 136 if (b->maindata.len == b->mainlen && b->auxdata.len == b->auxlen) break ; 137 r = sanitize_read(unixmessage_receiver_fill(b)) ; 138 if (r <= 0) return r ; 139 } 140 141 m->s = b->maindata.s ; 142 m->len = b->maindata.len ; 143 m->fds = (int *)b->auxdata.s ; 144 m->nfds = b->auxdata.len / sizeof(int) ; 145 return 1 ; 146 }