diff --git a/src/unix/darwin-syscalls.h b/src/unix/darwin-syscalls.h new file mode 100644 index 00000000..dc2d1bd2 --- /dev/null +++ b/src/unix/darwin-syscalls.h @@ -0,0 +1,17 @@ +#ifndef UV_DARWIN_SYSCALLS_H_ +#define UV_DARWIN_SYSCALLS_H_ + +#include +#include + +/* https://github.com/apple/darwin-xnu/blob/master/bsd/sys/socket.h */ + +struct mmsghdr { + struct msghdr msg_hdr; + size_t msg_len; +}; + +ssize_t recvmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags); +ssize_t sendmsg_x(int s, const struct mmsghdr* msgp, u_int cnt, int flags); + +#endif /* UV_DARWIN_SYSCALLS_H_ */ diff --git a/src/unix/internal.h b/src/unix/internal.h index 86c0d18a..529c783e 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -75,8 +75,11 @@ # include #endif /* _AIX */ -#if defined(__APPLE__) && !TARGET_OS_IPHONE -# include +#if defined(__APPLE__) +# include "darwin-syscalls.h" +# if !TARGET_OS_IPHONE +# include +# endif #endif /* diff --git a/src/unix/udp.c b/src/unix/udp.c index aa214db0..f6640fc7 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -148,7 +148,7 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { } static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) struct sockaddr_in6 peers[20]; struct iovec iov[ARRAY_SIZE(peers)]; struct mmsghdr msgs[ARRAY_SIZE(peers)]; @@ -173,11 +173,18 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { msgs[k].msg_hdr.msg_control = NULL; msgs[k].msg_hdr.msg_controllen = 0; msgs[k].msg_hdr.msg_flags = 0; + msgs[k].msg_len = 0; } +#if defined(__APPLE__) + do + nread = recvmsg_x(handle->io_watcher.fd, msgs, chunks, MSG_DONTWAIT); + while (nread == -1 && errno == EINTR); +#else do nread = recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL); while (nread == -1 && errno == EINTR); +#endif if (nread < 1) { if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK) @@ -204,9 +211,9 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) { handle->recv_cb(handle, 0, buf, NULL, UV_UDP_MMSG_FREE); } return nread; -#else /* __linux__ || ____FreeBSD__ */ +#else /* __linux__ || ____FreeBSD__ || __APPLE__ */ return UV_ENOSYS; -#endif /* __linux__ || ____FreeBSD__ */ +#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */ } static void uv__udp_recvmsg(uv_udp_t* handle) { @@ -328,7 +335,7 @@ static void uv__udp_sendmsg_one(uv_udp_t* handle, uv_udp_send_t* req) { } } -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) static void uv__udp_sendmsg_many(uv_udp_t* handle) { uv_udp_send_t* req; struct mmsghdr h[20]; @@ -366,9 +373,15 @@ write_queue_drain: h[pkts].msg_hdr.msg_iovlen = req->nbufs; } +#if defined(__APPLE__) + do + npkts = sendmsg_x(handle->io_watcher.fd, h, pkts, MSG_DONTWAIT); + while (npkts == -1 && errno == EINTR); +#else do npkts = sendmmsg(handle->io_watcher.fd, h, pkts, 0); while (npkts == -1 && errno == EINTR); +#endif if (npkts < 1) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) @@ -409,7 +422,7 @@ write_queue_drain: uv__io_feed(handle->loop, &handle->io_watcher); } -#endif /* __linux__ || ____FreeBSD__ */ +#endif /* __linux__ || ____FreeBSD__ || __APPLE__ */ static void uv__udp_sendmsg(uv_udp_t* handle) { struct uv__queue* q; @@ -421,7 +434,7 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { q = uv__queue_head(&handle->write_queue); req = uv__queue_data(q, uv_udp_send_t, queue); -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) /* Use sendmmsg() if this send request contains more than one datagram OR * there is more than one send request (because that automatically implies * there is more than one datagram.) @@ -1037,7 +1050,7 @@ int uv__udp_init_ex(uv_loop_t* loop, int uv_udp_using_recvmmsg(const uv_udp_t* handle) { -#if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) if (handle->flags & UV_HANDLE_UDP_RECVMMSG) return 1; #endif