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:
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]) ;
+}