diff --git a/src/unix/core.c b/src/unix/core.c index 4e657b63..79813a05 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -542,6 +542,44 @@ int uv__dup(int fd) { } +ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { + struct cmsghdr* cmsg; + ssize_t rc; + int* pfd; + int* end; +#if defined(__linux__) + static int no_msg_cmsg_cloexec; + if (no_msg_cmsg_cloexec == 0) { + rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */ + if (rc != -1) + return rc; + if (errno != EINVAL) + return -errno; + rc = recvmsg(fd, msg, flags); + if (rc == -1) + return -errno; + no_msg_cmsg_cloexec = 1; + } else { + rc = recvmsg(fd, msg, flags); + } +#else + rc = recvmsg(fd, msg, flags); +#endif + if (rc == -1) + return -errno; + if (msg->msg_controllen == 0) + return rc; + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) + if (cmsg->cmsg_type == SCM_RIGHTS) + for (pfd = (int*) CMSG_DATA(cmsg), + end = (int*) ((char*) cmsg + cmsg->cmsg_len); + pfd < end; + pfd += 1) + uv__cloexec(*pfd, 1); + return rc; +} + + int uv_cwd(char* buffer, size_t size) { if (buffer == NULL) return -EINVAL; diff --git a/src/unix/internal.h b/src/unix/internal.h index 7437e514..79e41faa 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -139,6 +139,7 @@ int uv__close(int fd); int uv__cloexec(int fd, int set); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); +ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); void uv__make_close_pending(uv_handle_t* handle); void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd); diff --git a/src/unix/stream.c b/src/unix/stream.c index d910a68b..de330c49 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -1007,7 +1007,7 @@ static void uv__read(uv_stream_t* stream) { msg.msg_control = (void*) cmsg_space; do { - nread = recvmsg(uv__stream_fd(stream), &msg, 0); + nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); } while (nread < 0 && errno == EINTR); }