skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

commit db7f4d2c1ef70334af4cb8c1980f47d8a9f69249
parent 0d82edd9f8bebb396a9154d4e1003340dbf6b967
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Sat, 20 Dec 2014 22:25:08 +0000

 Found the BSD unixmessage bug. recvmsg(..., MSG_WAITALL) blocks
until buffer full or socket shutdown on BSD, *even if the socket is
nonblocking*. So I added an "okwaitall" sysdeps, and won't set
MSG_WAITALL on retarded systems.

Diffstat:
Mconfigure | 8+++++++-
Mpackage/deps.mak | 3+--
Msrc/libunixonacid/unixmessage_receive.c | 21+++++++++++++++------
Asrc/sysdeps/tryokwaitall.c | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 140 insertions(+), 9 deletions(-)

diff --git a/configure b/configure @@ -133,7 +133,12 @@ choose () { fi if $r ; then case "$1" in - *r*) ./try$2 >/dev/null 2>&1 || r=false ;; + *r*) ./try$2 >/dev/null 2>&1 ; r=$? + case "$r" in + 111) echo " ... test crashed, aborting." ; exit 111 ;; + 0) r=true ;; + *) r=false ;; + esac esac fi rm -f try$2.o try$2 @@ -437,6 +442,7 @@ EOF choose cl getpeerucred GETPEERUCRED 'getpeerucred()' choose cl ipv6 IPV6 'IPv6 support' $socket_lib choose clr malloc0 MALLOC0 'non-NULL malloc(0)' + choose clr okwaitall OKWAITALL 'a usable MSG_WAITALL flag' choose cl openat OPENAT 'openat()' choose cl linkat LINKAT 'linkat()' choose clr pipe2 PIPE2 'pipe2()' diff --git a/package/deps.mak b/package/deps.mak @@ -49,7 +49,6 @@ src/include/skalibs/strerr.h: src/include/skalibs/gccattributes.h src/include/skalibs/strerr2.h: src/include/skalibs/strerr.h src/include/skalibs/surf.h: src/include/skalibs/uint32.h src/include/skalibs/tai.h: src/include/skalibs/gccattributes.h src/include/skalibs/uint32.h src/include/skalibs/uint64.h -src/include/skalibs/uint32.h: src/include/skalibs/uint64.h src/include/skalibs/unirandom.h: src/include/skalibs/buffer.h src/include/skalibs/surf.h src/include/skalibs/unirandomdev.h: src/include/skalibs/unirandom.h src/include/skalibs/unirandomegd.h: src/include/skalibs/unirandom.h @@ -150,7 +149,7 @@ src/librandom/rrandom_add.o src/librandom/rrandom_add.lo: src/librandom/rrandom_ src/librandom/rrandom_finish.o src/librandom/rrandom_finish.lo: src/librandom/rrandom_finish.c src/include/skalibs/rrandom.h src/include/skalibs/unirandom.h src/librandom/rrandom_name.o src/librandom/rrandom_name.lo: src/librandom/rrandom_name.c src/include/skalibs/rrandom.h src/include/skalibs/unirandom.h src/librandom/rrandom_read.o src/librandom/rrandom_read.lo: src/librandom/rrandom_read.c src/include/skalibs/allreadwrite.h src/include/skalibs/error.h src/include/skalibs/rrandom.h src/include/skalibs/unirandom.h -src/librandom/rrandom_readint.o src/librandom/rrandom_readint.lo: src/librandom/rrandom_readint.c src/librandom/random-internal.h src/include/skalibs/rrandom.h src/include/skalibs/uint.h src/include/skalibs/unirandom.h +src/librandom/rrandom_readint.o src/librandom/rrandom_readint.lo: src/librandom/rrandom_readint.c src/include/skalibs/bytestr.h src/librandom/random-internal.h src/include/skalibs/rrandom.h src/include/skalibs/uint.h src/include/skalibs/unirandom.h src/librandom/surf.o src/librandom/surf.lo: src/librandom/surf.c src/include/skalibs/bytestr.h src/include/skalibs/surf.h src/include/skalibs/uint32.h src/librandom/surf_autoinit.o src/librandom/surf_autoinit.lo: src/librandom/surf_autoinit.c src/include/skalibs/surf.h src/librandom/surf_here.o src/librandom/surf_here.lo: src/librandom/surf_here.c src/librandom/random-internal.h src/include/skalibs/surf.h diff --git a/src/libunixonacid/unixmessage_receive.c b/src/libunixonacid/unixmessage_receive.c @@ -1,6 +1,5 @@ /* ISC license. */ -#define _XPG4_2 #include <skalibs/sysdeps.h> #include <skalibs/nonposix.h> #include <errno.h> @@ -15,6 +14,20 @@ #include <skalibs/siovec.h> #include <skalibs/unixmessage.h> +#ifdef SKALIBS_HASOKWAITALL +# ifdef SKALIBS_HASCMSGCLOEXEC +# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_WAITALL | MSG_CMSG_CLOEXEC) +# else +# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_WAITALL) +# endif +#else +# ifdef SKALIBS_HASCMSGCLOEXEC +# define RECV(fd, hdr) recvmsg(fd, (hdr), MSG_CMSG_CLOEXEC) +# else +# define RECV(fd, hdr) recvmsg(fd, (hdr), 0) +# endif +#endif + static int unixmessage_receiver_fill (unixmessage_receiver_t *b) { char ancilbuf[CMSG_SPACE(b->auxb.a - 1)] ; @@ -38,11 +51,7 @@ static int unixmessage_receiver_fill (unixmessage_receiver_t *b) 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 + r = RECV(b->fd, &msghdr) ; if (r <= 0) return r ; { struct cmsghdr *c = CMSG_FIRSTHDR(&msghdr) ; diff --git a/src/sysdeps/tryokwaitall.c b/src/sysdeps/tryokwaitall.c @@ -0,0 +1,117 @@ +/* ISC license. */ + +#undef _POSIX_C_SOURCE +#undef _XOPEN_SOURCE + +#ifndef _XPG4_2 +# define _XPG4_2 +#endif + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif + +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/uio.h> +#if defined(__FreeBSD__) +#include <sys/param.h> +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +static int ndelay_on (int fd) +{ + register int got = fcntl(fd, F_GETFL) ; + return (got == -1) ? -1 : fcntl(fd, F_SETFL, got | O_NONBLOCK) ; +} + +static int child (int p, int fd) +{ + char c ; + struct iovec v = { .iov_base = &c, .iov_len = 1 } ; + struct msghdr msg = + { + .msg_name = 0, + .msg_namelen = 0, + .msg_iov = &v, + .msg_iovlen = 1, + .msg_control = 0, + .msg_controllen = 0 + } ; + fd_set rfds ; + if (ndelay_on(fd) < 0) return 111 ; + FD_ZERO(&rfds) ; + FD_SET(fd, &rfds) ; + if (write(p, "", 1) < 1) return 111 ; /* sync with the parent */ + if (select(fd+1, &rfds, 0, 0, 0) < 1) return 111 ; + + /* On buggy systems, the following recvmsg will block, despite + setting the fd non-blocking */ + + if (recvmsg(fd, &msg, MSG_WAITALL) < 1) return 111 ; + if (write(p, "", 1) < 1) return 111 ; + return 0 ; +} + +static int parent (pid_t pid, int p, int fd) +{ + char c ; + struct iovec v = { .iov_base = &c, .iov_len = 1 } ; + struct msghdr msg = + { + .msg_name = 0, + .msg_namelen = 0, + .msg_iov = &v, + .msg_iovlen = 1, + .msg_control = 0, + .msg_controllen = 0 + } ; + struct timeval tv = { .tv_sec = 2, .tv_usec = 0 } ; + fd_set rfds ; + unsigned int n = p > fd ? p : fd ; + int r ; + FD_ZERO(&rfds) ; + FD_SET(p, &rfds) ; + if (read(p, &c, 1) < 1) return 111 ; + if (sendmsg(fd, &msg, MSG_NOSIGNAL) < 1) return 111 ; + for (;;) + { + r = select(n+1, &rfds, 0, 0, &tv) ; + if (r >= 0 || errno != EINTR) break ; + } + if (!r) /* child is still blocking on recvmsg() after 2 seconds */ + { + kill(pid, SIGTERM) ; + return 1 ; + } + if (read(p, &c, 1) < 1) return 111 ; + return 0 ; +} + +int main (void) +{ + pid_t pid ; + int fd[2] ; + int p[2] ; + if (pipe(p) < 0) return 111 ; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) return 111 ; + pid = fork() ; + if (pid < 0) return 111 ; + if (!pid) + { + close(p[0]) ; + close(fd[0]) ; + return child(p[1], fd[1]) ; + } + close(p[1]) ; + close(fd[1]) ; + return parent(pid, p[0], fd[0]) ; +}