From d6f6d7f8541327b72667d38777c47b9ea675125d Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 16 Mar 2019 14:38:18 -0400 Subject: deps: upgrade to libuv 1.27.0 Notable changes: - `statx()` is used to retrieve file birth times on supported platforms. - Improved support of running under Windows safe mode. - Add support for UDP connected sockets. Several functions can now return `UV_EBADF` instead of `UV_EINVAL`. - SunOS support is improved. PR-URL: https://github.com/nodejs/node/pull/26707 Reviewed-By: Santiago Gimeno Reviewed-By: Anna Henningsen Reviewed-By: Richard Lau Reviewed-By: Refael Ackermann Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell --- deps/uv/src/fs-poll.c | 63 ++++++++++++++----- deps/uv/src/unix/atomic-ops.h | 4 +- deps/uv/src/unix/core.c | 26 +++++++- deps/uv/src/unix/fs.c | 82 ++++++++++++++++++++++++- deps/uv/src/unix/getaddrinfo.c | 2 + deps/uv/src/unix/internal.h | 10 ++- deps/uv/src/unix/kqueue.c | 5 +- deps/uv/src/unix/linux-syscalls.c | 28 +++++++++ deps/uv/src/unix/linux-syscalls.h | 35 +++++++++++ deps/uv/src/unix/pipe.c | 10 +-- deps/uv/src/unix/sunos.c | 18 ++++-- deps/uv/src/unix/tcp.c | 34 +++-------- deps/uv/src/unix/thread.c | 2 + deps/uv/src/unix/udp.c | 115 +++++++++++++++++++++++++++-------- deps/uv/src/uv-common.c | 92 +++++++++++++++++++++++----- deps/uv/src/uv-common.h | 9 +++ deps/uv/src/uv-data-getter-setters.c | 2 +- deps/uv/src/win/core.c | 27 ++++++++ deps/uv/src/win/handle.c | 1 - deps/uv/src/win/internal.h | 8 +++ deps/uv/src/win/tcp.c | 40 +++--------- deps/uv/src/win/udp.c | 103 ++++++++++++++++++++++++++----- deps/uv/src/win/winsock.c | 15 +++-- 23 files changed, 581 insertions(+), 150 deletions(-) (limited to 'deps/uv/src') diff --git a/deps/uv/src/fs-poll.c b/deps/uv/src/fs-poll.c index 6c82dfc1d7..40cb147e8d 100644 --- a/deps/uv/src/fs-poll.c +++ b/deps/uv/src/fs-poll.c @@ -22,12 +22,20 @@ #include "uv.h" #include "uv-common.h" +#ifdef _WIN32 +#include "win/internal.h" +#include "win/handle-inl.h" +#define uv__make_close_pending(h) uv_want_endgame((h)->loop, (h)) +#else +#include "unix/internal.h" +#endif + #include #include #include struct poll_ctx { - uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */ + uv_fs_poll_t* parent_handle; int busy_polling; unsigned int interval; uint64_t start_time; @@ -36,6 +44,7 @@ struct poll_ctx { uv_timer_t timer_handle; uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */ uv_stat_t statbuf; + struct poll_ctx* previous; /* context from previous start()..stop() period */ char path[1]; /* variable length */ }; @@ -49,6 +58,7 @@ static uv_stat_t zero_statbuf; int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) { uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL); + handle->poll_ctx = NULL; return 0; } @@ -62,7 +72,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, size_t len; int err; - if (uv__is_active(handle)) + if (uv_is_active((uv_handle_t*)handle)) return 0; loop = handle->loop; @@ -90,6 +100,8 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, if (err < 0) goto error; + if (handle->poll_ctx != NULL) + ctx->previous = handle->poll_ctx; handle->poll_ctx = ctx; uv__handle_start(handle); @@ -104,19 +116,17 @@ error: int uv_fs_poll_stop(uv_fs_poll_t* handle) { struct poll_ctx* ctx; - if (!uv__is_active(handle)) + if (!uv_is_active((uv_handle_t*)handle)) return 0; ctx = handle->poll_ctx; assert(ctx != NULL); - assert(ctx->parent_handle != NULL); - ctx->parent_handle = NULL; - handle->poll_ctx = NULL; + assert(ctx->parent_handle == handle); /* Close the timer if it's active. If it's inactive, there's a stat request * in progress and poll_cb will take care of the cleanup. */ - if (uv__is_active(&ctx->timer_handle)) + if (uv_is_active((uv_handle_t*)&ctx->timer_handle)) uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); uv__handle_stop(handle); @@ -129,7 +139,7 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { struct poll_ctx* ctx; size_t required_len; - if (!uv__is_active(handle)) { + if (!uv_is_active((uv_handle_t*)handle)) { *size = 0; return UV_EINVAL; } @@ -153,6 +163,9 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) { void uv__fs_poll_close(uv_fs_poll_t* handle) { uv_fs_poll_stop(handle); + + if (handle->poll_ctx == NULL) + uv__make_close_pending((uv_handle_t*)handle); } @@ -173,14 +186,13 @@ static void poll_cb(uv_fs_t* req) { uv_stat_t* statbuf; struct poll_ctx* ctx; uint64_t interval; + uv_fs_poll_t* handle; ctx = container_of(req, struct poll_ctx, fs_req); + handle = ctx->parent_handle; - if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */ - uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); - uv_fs_req_cleanup(req); - return; - } + if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle)) + goto out; if (req->result != 0) { if (ctx->busy_polling != req->result) { @@ -205,7 +217,7 @@ static void poll_cb(uv_fs_t* req) { out: uv_fs_req_cleanup(req); - if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */ + if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle)) { uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb); return; } @@ -219,8 +231,27 @@ out: } -static void timer_close_cb(uv_handle_t* handle) { - uv__free(container_of(handle, struct poll_ctx, timer_handle)); +static void timer_close_cb(uv_handle_t* timer) { + struct poll_ctx* ctx; + struct poll_ctx* it; + struct poll_ctx* last; + uv_fs_poll_t* handle; + + ctx = container_of(timer, struct poll_ctx, timer_handle); + handle = ctx->parent_handle; + if (ctx == handle->poll_ctx) { + handle->poll_ctx = ctx->previous; + if (handle->poll_ctx == NULL) + uv__make_close_pending((uv_handle_t*)handle); + } else { + for (last = handle->poll_ctx, it = last->previous; + it != ctx; + last = it, it = it->previous) { + assert(last->previous != NULL); + } + last->previous = ctx->previous; + } + uv__free(ctx); } diff --git a/deps/uv/src/unix/atomic-ops.h b/deps/uv/src/unix/atomic-ops.h index 7cac1f9889..fb46978859 100644 --- a/deps/uv/src/unix/atomic-ops.h +++ b/deps/uv/src/unix/atomic-ops.h @@ -49,7 +49,7 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { else return op4; #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) - return atomic_cas_uint(ptr, oldval, newval); + return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval); #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif @@ -85,7 +85,7 @@ UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) { else return op4; #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) - return atomic_cas_ulong(ptr, oldval, newval); + return atomic_cas_ulong((ulong_t *)ptr, (ulong_t)oldval, (ulong_t)newval); #else return __sync_val_compare_and_swap(ptr, oldval, newval); #endif diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 7e42337b9a..ca0e345da0 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -161,7 +161,9 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { case UV_FS_POLL: uv__fs_poll_close((uv_fs_poll_t*)handle); - break; + /* Poll handles use file system requests, and one of them may still be + * running. The poll code will call uv__make_close_pending() for us. */ + return; case UV_SIGNAL: uv__signal_close((uv_signal_t*) handle); @@ -1405,3 +1407,25 @@ error: buffer->machine[0] = '\0'; return r; } + +int uv__getsockpeername(const uv_handle_t* handle, + uv__peersockfunc func, + struct sockaddr* name, + int* namelen) { + socklen_t socklen; + uv_os_fd_t fd; + int r; + + r = uv_fileno(handle, &fd); + if (r < 0) + return r; + + /* sizeof(socklen_t) != sizeof(int) on some systems. */ + socklen = (socklen_t) *namelen; + + if (func(fd, name, &socklen)) + return UV__ERR(errno); + + *namelen = (int) socklen; + return 0; +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 91bb82f725..f4b4280ca0 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -47,7 +47,7 @@ #if defined(__DragonFly__) || \ defined(__FreeBSD__) || \ - defined(__FreeBSD_kernel_) || \ + defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) # define HAVE_PREADV 1 @@ -1053,10 +1053,82 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) { } +static int uv__fs_statx(int fd, + const char* path, + int is_fstat, + int is_lstat, + uv_stat_t* buf) { + STATIC_ASSERT(UV_ENOSYS != -1); +#ifdef __linux__ + static int no_statx; + struct uv__statx statxbuf; + int dirfd; + int flags; + int mode; + int rc; + + if (no_statx) + return UV_ENOSYS; + + dirfd = AT_FDCWD; + flags = 0; /* AT_STATX_SYNC_AS_STAT */ + mode = 0xFFF; /* STATX_BASIC_STATS + STATX_BTIME */ + + if (is_fstat) { + dirfd = fd; + flags |= 0x1000; /* AT_EMPTY_PATH */ + } + + if (is_lstat) + flags |= AT_SYMLINK_NOFOLLOW; + + rc = uv__statx(dirfd, path, flags, mode, &statxbuf); + + if (rc == -1) { + /* EPERM happens when a seccomp filter rejects the system call. + * Has been observed with libseccomp < 2.3.3 and docker < 18.04. + */ + if (errno != EINVAL && errno != EPERM && errno != ENOSYS) + return -1; + + no_statx = 1; + return UV_ENOSYS; + } + + buf->st_dev = 256 * statxbuf.stx_dev_major + statxbuf.stx_dev_minor; + buf->st_mode = statxbuf.stx_mode; + buf->st_nlink = statxbuf.stx_nlink; + buf->st_uid = statxbuf.stx_uid; + buf->st_gid = statxbuf.stx_gid; + buf->st_rdev = statxbuf.stx_rdev_major; + buf->st_ino = statxbuf.stx_ino; + buf->st_size = statxbuf.stx_size; + buf->st_blksize = statxbuf.stx_blksize; + buf->st_blocks = statxbuf.stx_blocks; + buf->st_atim.tv_sec = statxbuf.stx_atime.tv_sec; + buf->st_atim.tv_nsec = statxbuf.stx_atime.tv_nsec; + buf->st_mtim.tv_sec = statxbuf.stx_mtime.tv_sec; + buf->st_mtim.tv_nsec = statxbuf.stx_mtime.tv_nsec; + buf->st_ctim.tv_sec = statxbuf.stx_ctime.tv_sec; + buf->st_ctim.tv_nsec = statxbuf.stx_ctime.tv_nsec; + buf->st_birthtim.tv_sec = statxbuf.stx_btime.tv_sec; + buf->st_birthtim.tv_nsec = statxbuf.stx_btime.tv_nsec; + + return 0; +#else + return UV_ENOSYS; +#endif /* __linux__ */ +} + + static int uv__fs_stat(const char *path, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 0, buf); + if (ret != UV_ENOSYS) + return ret; + ret = stat(path, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); @@ -1069,6 +1141,10 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 1, buf); + if (ret != UV_ENOSYS) + return ret; + ret = lstat(path, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); @@ -1081,6 +1157,10 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { struct stat pbuf; int ret; + ret = uv__fs_statx(fd, "", /* is_fstat */ 1, /* is_lstat */ 0, buf); + if (ret != UV_ENOSYS) + return ret; + ret = fstat(fd, &pbuf); if (ret == 0) uv__to_stat(&pbuf, buf); diff --git a/deps/uv/src/unix/getaddrinfo.c b/deps/uv/src/unix/getaddrinfo.c index 6d23fbe02a..d7ca7d1a44 100644 --- a/deps/uv/src/unix/getaddrinfo.c +++ b/deps/uv/src/unix/getaddrinfo.c @@ -92,7 +92,9 @@ int uv__getaddrinfo_translate_error(int sys_err) { } assert(!"unknown EAI_* error code"); abort(); +#ifndef __SUNPRO_C return 0; /* Pacify compiler. */ +#endif } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index c059893a46..a084697032 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -95,8 +95,7 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); */ #if defined(__clang__) || \ defined(__GNUC__) || \ - defined(__INTEL_COMPILER) || \ - defined(__SUNPRO_C) + defined(__INTEL_COMPILER) # define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration # define UV_UNUSED(declaration) __attribute__((unused)) declaration #else @@ -306,4 +305,11 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) { int uv__inotify_fork(uv_loop_t* loop, void* old_watchers); #endif +typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*); + +int uv__getsockpeername(const uv_handle_t* handle, + uv__peersockfunc func, + struct sockaddr* name, + int* namelen); + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 38c88d7da7..092005161f 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -490,8 +490,11 @@ int uv_fs_event_start(uv_fs_event_t* handle, return UV__ERR(errno); handle->path = uv__strdup(path); - if (handle->path == NULL) + if (handle->path == NULL) { + uv__close_nocheckstdio(fd); return UV_ENOMEM; + } + handle->cb = cb; uv__handle_start(handle); uv__io_init(&handle->event_watcher, uv__fs_event, fd); diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index bfd7544879..beaba4ed9a 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -187,6 +187,21 @@ # endif #endif /* __NR_pwritev */ +#ifndef __NR_statx +# if defined(__x86_64__) +# define __NR_statx 332 +# elif defined(__i386__) +# define __NR_statx 383 +# elif defined(__aarch64__) +# define __NR_statx 397 +# elif defined(__arm__) +# define __NR_statx (UV_SYSCALL_BASE + 397) +# elif defined(__ppc__) +# define __NR_statx 383 +# elif defined(__s390__) +# define __NR_statx 379 +# endif +#endif /* __NR_statx */ int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { #if defined(__i386__) @@ -336,3 +351,16 @@ int uv__dup3(int oldfd, int newfd, int flags) { return errno = ENOSYS, -1; #endif } + + +int uv__statx(int dirfd, + const char* path, + int flags, + unsigned int mask, + struct uv__statx* statxbuf) { +#if defined(__NR_statx) + return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 3dfd329d6c..7e58bfa218 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -80,6 +80,36 @@ #define UV__IN_DELETE_SELF 0x400 #define UV__IN_MOVE_SELF 0x800 +struct uv__statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t unused0; +}; + +struct uv__statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t unused0; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct uv__statx_timestamp stx_atime; + struct uv__statx_timestamp stx_btime; + struct uv__statx_timestamp stx_ctime; + struct uv__statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t unused1[14]; +}; + struct uv__inotify_event { int32_t wd; uint32_t mask; @@ -113,5 +143,10 @@ int uv__sendmmsg(int fd, ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); int uv__dup3(int oldfd, int newfd, int flags); +int uv__statx(int dirfd, + const char* path, + int flags, + unsigned int mask, + struct uv__statx* statxbuf); #endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 228d158800..8347668632 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -233,9 +233,6 @@ out: } -typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*); - - static int uv__pipe_getsockpeername(const uv_pipe_t* handle, uv__peersockfunc func, char* buffer, @@ -246,10 +243,13 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle, addrlen = sizeof(sa); memset(&sa, 0, addrlen); - err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen); + err = uv__getsockpeername((const uv_handle_t*) handle, + func, + (struct sockaddr*) &sa, + (int*) &addrlen); if (err < 0) { *size = 0; - return UV__ERR(errno); + return err; } #if defined(__linux__) diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 75501f7a0a..fb6b070fd1 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -135,8 +135,10 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0)) return UV__ERR(errno); - if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) + if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) { + perror("(libuv) port_dissociate()"); abort(); + } return 0; } @@ -174,8 +176,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w = QUEUE_DATA(q, uv__io_t, watcher_queue); assert(w->pevents != 0); - if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0)) + if (port_associate(loop->backend_fd, + PORT_SOURCE_FD, + w->fd, + w->pevents, + 0)) { + perror("(libuv) port_associate()"); abort(); + } w->events = w->pevents; } @@ -219,10 +227,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { /* Work around another kernel bug: port_getn() may return events even * on error. */ - if (errno == EINTR || errno == ETIME) + if (errno == EINTR || errno == ETIME) { saved_errno = errno; - else + } else { + perror("(libuv) port_getn()"); abort(); + } } /* Update loop->time unconditionally. It's tempting to skip the update when diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 900839a99d..8cedcd6027 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -82,7 +82,7 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) { handle->flags |= flags; return 0; } - + /* Query to see if tcp socket is bound. */ slen = sizeof(saddr); memset(&saddr, 0, sizeof(saddr)); @@ -283,44 +283,28 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) { - socklen_t socklen; if (handle->delayed_error) return handle->delayed_error; - if (uv__stream_fd(handle) < 0) - return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; - - if (getsockname(uv__stream_fd(handle), name, &socklen)) - return UV__ERR(errno); - - *namelen = (int) socklen; - return 0; + return uv__getsockpeername((const uv_handle_t*) handle, + getsockname, + name, + namelen); } int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) { - socklen_t socklen; if (handle->delayed_error) return handle->delayed_error; - if (uv__stream_fd(handle) < 0) - return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; - - if (getpeername(uv__stream_fd(handle), name, &socklen)) - return UV__ERR(errno); - - *namelen = (int) socklen; - return 0; + return uv__getsockpeername((const uv_handle_t*) handle, + getpeername, + name, + namelen); } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index c17a51fed2..6088c77f71 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -801,7 +801,9 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { return UV_ETIMEDOUT; abort(); +#ifndef __SUNPRO_C return UV_EINVAL; /* Satisfy the compiler. */ +#endif } diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index ec337ec8b8..15fa5937b3 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -227,9 +227,14 @@ static void uv__udp_sendmsg(uv_udp_t* handle) { assert(req != NULL); memset(&h, 0, sizeof h); - h.msg_name = &req->addr; - h.msg_namelen = (req->addr.ss_family == AF_INET6 ? - sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if (req->addr.ss_family == AF_UNSPEC) { + h.msg_name = NULL; + h.msg_namelen = 0; + } else { + h.msg_name = &req->addr; + h.msg_namelen = req->addr.ss_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); + } h.msg_iov = (struct iovec*) req->bufs; h.msg_iovlen = req->nbufs; @@ -383,6 +388,50 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle, } +int uv__udp_connect(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen) { + int err; + + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + + do { + errno = 0; + err = connect(handle->io_watcher.fd, addr, addrlen); + } while (err == -1 && errno == EINTR); + + if (err) + return UV__ERR(errno); + + handle->flags |= UV_HANDLE_UDP_CONNECTED; + + return 0; +} + + +int uv__udp_disconnect(uv_udp_t* handle) { + int r; + struct sockaddr addr; + + memset(&addr, 0, sizeof(addr)); + + addr.sa_family = AF_UNSPEC; + + do { + errno = 0; + r = connect(handle->io_watcher.fd, &addr, sizeof(addr)); + } while (r == -1 && errno == EINTR); + + if (r == -1 && errno != EAFNOSUPPORT) + return UV__ERR(errno); + + handle->flags &= ~UV_HANDLE_UDP_CONNECTED; + return 0; +} + + int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], @@ -395,9 +444,11 @@ int uv__udp_send(uv_udp_send_t* req, assert(nbufs > 0); - err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); - if (err) - return err; + if (addr) { + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + } /* It's legal for send_queue_count > 0 even when the write_queue is empty; * it means there are error-state requests in the write_completed_queue that @@ -407,7 +458,10 @@ int uv__udp_send(uv_udp_send_t* req, uv__req_init(handle->loop, req, UV_UDP_SEND); assert(addrlen <= sizeof(req->addr)); - memcpy(&req->addr, addr, addrlen); + if (addr == NULL) + req->addr.ss_family = AF_UNSPEC; + else + memcpy(&req->addr, addr, addrlen); req->send_cb = send_cb; req->handle = handle; req->nbufs = nbufs; @@ -459,9 +513,13 @@ int uv__udp_try_send(uv_udp_t* handle, if (handle->send_queue_count != 0) return UV_EAGAIN; - err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); - if (err) - return err; + if (addr) { + err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0); + if (err) + return err; + } else { + assert(handle->flags & UV_HANDLE_UDP_CONNECTED); + } memset(&h, 0, sizeof h); h.msg_name = (struct sockaddr*) addr; @@ -608,6 +666,7 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { uv__io_init(&handle->io_watcher, uv__udp_io, fd); QUEUE_INIT(&handle->write_queue); QUEUE_INIT(&handle->write_completed_queue); + return 0; } @@ -636,6 +695,9 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { return err; handle->io_watcher.fd = sock; + if (uv__udp_is_connected(handle)) + handle->flags |= UV_HANDLE_UDP_CONNECTED; + return 0; } @@ -743,13 +805,17 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) { IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || - defined(__MVS__) */ + +#else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__)) */ return uv__setsockopt_maybe_char(handle, IP_TTL, IPV6_UNICAST_HOPS, ttl); + +#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) || + defined(__MVS__) */ } @@ -851,23 +917,24 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) return 0; } - -int uv_udp_getsockname(const uv_udp_t* handle, +int uv_udp_getpeername(const uv_udp_t* handle, struct sockaddr* name, int* namelen) { - socklen_t socklen; - if (handle->io_watcher.fd == -1) - return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */ - - /* sizeof(socklen_t) != sizeof(int) on some systems. */ - socklen = (socklen_t) *namelen; + return uv__getsockpeername((const uv_handle_t*) handle, + getpeername, + name, + namelen); +} - if (getsockname(handle->io_watcher.fd, name, &socklen)) - return UV__ERR(errno); +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { - *namelen = (int) socklen; - return 0; + return uv__getsockpeername((const uv_handle_t*) handle, + getsockname, + name, + namelen); } diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 952bde080c..94dd59fb07 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -222,6 +222,9 @@ int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) { memset(addr, 0, sizeof(*addr)); addr->sin6_family = AF_INET6; addr->sin6_port = htons(port); +#ifdef SIN6_LEN + addr->sin6_len = sizeof(*addr); +#endif zone_index = strchr(ip, '%'); if (zone_index != NULL) { @@ -314,17 +317,20 @@ int uv_tcp_connect(uv_connect_t* req, } -int uv_udp_send(uv_udp_send_t* req, - uv_udp_t* handle, - const uv_buf_t bufs[], - unsigned int nbufs, - const struct sockaddr* addr, - uv_udp_send_cb send_cb) { +int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) { unsigned int addrlen; if (handle->type != UV_UDP) return UV_EINVAL; + /* Disconnect the handle */ + if (addr == NULL) { + if (!(handle->flags & UV_HANDLE_UDP_CONNECTED)) + return UV_ENOTCONN; + + return uv__udp_disconnect(handle); + } + if (addr->sa_family == AF_INET) addrlen = sizeof(struct sockaddr_in); else if (addr->sa_family == AF_INET6) @@ -332,6 +338,66 @@ int uv_udp_send(uv_udp_send_t* req, else return UV_EINVAL; + if (handle->flags & UV_HANDLE_UDP_CONNECTED) + return UV_EISCONN; + + return uv__udp_connect(handle, addr, addrlen); +} + + +int uv__udp_is_connected(uv_udp_t* handle) { + struct sockaddr_storage addr; + int addrlen; + if (handle->type != UV_UDP) + return 0; + + addrlen = sizeof(addr); + if (uv_udp_getpeername(handle, (struct sockaddr*) &addr, &addrlen) != 0) + return 0; + + return addrlen > 0; +} + + +int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) { + unsigned int addrlen; + + if (handle->type != UV_UDP) + return UV_EINVAL; + + if (addr != NULL && (handle->flags & UV_HANDLE_UDP_CONNECTED)) + return UV_EISCONN; + + if (addr == NULL && !(handle->flags & UV_HANDLE_UDP_CONNECTED)) + return UV_EDESTADDRREQ; + + if (addr != NULL) { + if (addr->sa_family == AF_INET) + addrlen = sizeof(struct sockaddr_in); + else if (addr->sa_family == AF_INET6) + addrlen = sizeof(struct sockaddr_in6); + else + return UV_EINVAL; + } else { + addrlen = 0; + } + + return addrlen; +} + + +int uv_udp_send(uv_udp_send_t* req, + uv_udp_t* handle, + const uv_buf_t bufs[], + unsigned int nbufs, + const struct sockaddr* addr, + uv_udp_send_cb send_cb) { + int addrlen; + + addrlen = uv__udp_check_before_send(handle, addr); + if (addrlen < 0) + return addrlen; + return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb); } @@ -340,17 +406,11 @@ int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr) { - unsigned int addrlen; - - if (handle->type != UV_UDP) - return UV_EINVAL; + int addrlen; - if (addr->sa_family == AF_INET) - addrlen = sizeof(struct sockaddr_in); - else if (addr->sa_family == AF_INET6) - addrlen = sizeof(struct sockaddr_in6); - else - return UV_EINVAL; + addrlen = uv__udp_check_before_send(handle, addr); + if (addrlen < 0) + return addrlen; return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen); } diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index 15ac4d02c1..e09a57b2c2 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -103,6 +103,7 @@ enum { /* Only used by uv_udp_t handles. */ UV_HANDLE_UDP_PROCESSING = 0x01000000, + UV_HANDLE_UDP_CONNECTED = 0x02000000, /* Only used by uv_pipe_t handles. */ UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000, @@ -142,6 +143,14 @@ int uv__udp_bind(uv_udp_t* handle, unsigned int addrlen, unsigned int flags); +int uv__udp_connect(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen); + +int uv__udp_disconnect(uv_udp_t* handle); + +int uv__udp_is_connected(uv_udp_t* handle); + int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], diff --git a/deps/uv/src/uv-data-getter-setters.c b/deps/uv/src/uv-data-getter-setters.c index b7fcd4a7fd..c3025662fa 100644 --- a/deps/uv/src/uv-data-getter-setters.c +++ b/deps/uv/src/uv-data-getter-setters.c @@ -36,7 +36,7 @@ const char* uv_req_type_name(uv_req_type type) { case UV_REQ_TYPE_MAX: case UV_UNKNOWN_REQ: default: /* UV_REQ_TYPE_PRIVATE */ - return NULL; + break; } return NULL; } diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index bf80d77e27..e9d0a58153 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -623,3 +623,30 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { return 0; } + +int uv_cpumask_size(void) { + return (int)(sizeof(DWORD_PTR) * 8); +} + +int uv__getsockpeername(const uv_handle_t* handle, + uv__peersockfunc func, + struct sockaddr* name, + int* namelen, + int delayed_error) { + + int result; + uv_os_fd_t fd; + + result = uv_fileno(handle, &fd); + if (result != 0) + return result; + + if (delayed_error) + return uv_translate_sys_error(delayed_error); + + result = func((SOCKET) fd, name, namelen); + if (result != 0) + return uv_translate_sys_error(WSAGetLastError()); + + return 0; +} diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index 9d76c3f542..61e4df61b3 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -139,7 +139,6 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { case UV_FS_POLL: uv__fs_poll_close((uv_fs_poll_t*) handle); uv__handle_closing(handle); - uv_want_endgame(loop, handle); return; default: diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 634b9f776c..70ddaa5332 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -272,6 +272,14 @@ int uv__getpwuid_r(uv_passwd_t* pwd); int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16); +typedef int (WINAPI *uv__peersockfunc)(SOCKET, struct sockaddr*, int*); + +int uv__getsockpeername(const uv_handle_t* handle, + uv__peersockfunc func, + struct sockaddr* name, + int* namelen, + int delayed_error); + /* * Process stdio handles. diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 3ce5548c0a..f2cb5271b8 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -809,44 +809,24 @@ static int uv_tcp_try_connect(uv_connect_t* req, int uv_tcp_getsockname(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) { - int result; - - if (handle->socket == INVALID_SOCKET) { - return UV_EINVAL; - } - - if (handle->delayed_error) { - return uv_translate_sys_error(handle->delayed_error); - } - - result = getsockname(handle->socket, name, namelen); - if (result != 0) { - return uv_translate_sys_error(WSAGetLastError()); - } - return 0; + return uv__getsockpeername((const uv_handle_t*) handle, + getsockname, + name, + namelen, + handle->delayed_error); } int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen) { - int result; - - if (handle->socket == INVALID_SOCKET) { - return UV_EINVAL; - } - - if (handle->delayed_error) { - return uv_translate_sys_error(handle->delayed_error); - } - - result = getpeername(handle->socket, name, namelen); - if (result != 0) { - return uv_translate_sys_error(WSAGetLastError()); - } - return 0; + return uv__getsockpeername((const uv_handle_t*) handle, + getpeername, + name, + namelen, + handle->delayed_error); } diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 37df849f8f..8aeeab3b46 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -36,22 +36,27 @@ const unsigned int uv_active_udp_streams_threshold = 0; /* A zero-size buffer for use by uv_udp_read */ static char uv_zero_[] = ""; - -int uv_udp_getsockname(const uv_udp_t* handle, +int uv_udp_getpeername(const uv_udp_t* handle, struct sockaddr* name, int* namelen) { - int result; - if (handle->socket == INVALID_SOCKET) { - return UV_EINVAL; - } + return uv__getsockpeername((const uv_handle_t*) handle, + getpeername, + name, + namelen, + 0); +} - result = getsockname(handle->socket, name, namelen); - if (result != 0) { - return uv_translate_sys_error(WSAGetLastError()); - } - return 0; +int uv_udp_getsockname(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen) { + + return uv__getsockpeername((const uv_handle_t*) handle, + getsockname, + name, + namelen, + 0); } @@ -784,6 +789,18 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int value) { } +int uv__udp_is_bound(uv_udp_t* handle) { + struct sockaddr_storage addr; + int addrlen; + + addrlen = sizeof(addr); + if (uv_udp_getsockname(handle, (struct sockaddr*) &addr, &addrlen) != 0) + return 0; + + return addrlen > 0; +} + + int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { WSAPROTOCOL_INFOW protocol_info; int opt_len; @@ -803,7 +820,16 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { handle, sock, protocol_info.iAddressFamily); - return uv_translate_sys_error(err); + if (err) + return uv_translate_sys_error(err); + + if (uv__udp_is_bound(handle)) + handle->flags |= UV_HANDLE_BOUND; + + if (uv__udp_is_connected(handle)) + handle->flags |= UV_HANDLE_UDP_CONNECTED; + + return 0; } @@ -880,6 +906,50 @@ int uv__udp_bind(uv_udp_t* handle, } +int uv__udp_connect(uv_udp_t* handle, + const struct sockaddr* addr, + unsigned int addrlen) { + const struct sockaddr* bind_addr; + int err; + + if (!(handle->flags & UV_HANDLE_BOUND)) { + if (addrlen == sizeof(uv_addr_ip4_any_)) + bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_; + else if (addrlen == sizeof(uv_addr_ip6_any_)) + bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; + else + return UV_EINVAL; + + err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); + if (err) + return uv_translate_sys_error(err); + } + + err = connect(handle->socket, addr, addrlen); + if (err) + return uv_translate_sys_error(err); + + handle->flags |= UV_HANDLE_UDP_CONNECTED; + + return 0; +} + + +int uv__udp_disconnect(uv_udp_t* handle) { + int err; + struct sockaddr addr; + + memset(&addr, 0, sizeof(addr)); + + err = connect(handle->socket, &addr, sizeof(addr)); + if (err) + return uv_translate_sys_error(err); + + handle->flags &= ~UV_HANDLE_UDP_CONNECTED; + return 0; +} + + /* This function is an egress point, i.e. it returns libuv errors rather than * system errors. */ @@ -900,6 +970,7 @@ int uv__udp_send(uv_udp_send_t* req, bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; else return UV_EINVAL; + err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); if (err) return uv_translate_sys_error(err); @@ -925,9 +996,11 @@ int uv__udp_try_send(uv_udp_t* handle, assert(nbufs > 0); - err = uv__convert_to_localhost_if_unspecified(addr, &converted); - if (err) - return err; + if (addr != NULL) { + err = uv__convert_to_localhost_if_unspecified(addr, &converted); + if (err) + return err; + } /* Already sending a message.*/ if (handle->send_queue_count != 0) diff --git a/deps/uv/src/win/winsock.c b/deps/uv/src/win/winsock.c index 5e7da2a8f2..5820ba9c66 100644 --- a/deps/uv/src/win/winsock.c +++ b/deps/uv/src/win/winsock.c @@ -87,12 +87,6 @@ void uv_winsock_init(void) { WSAPROTOCOL_INFOW protocol_info; int opt_len; - /* Initialize winsock */ - errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); - if (errorno != 0) { - uv_fatal_error(errorno, "WSAStartup"); - } - /* Set implicit binding address used by connectEx */ if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) { abort(); @@ -102,6 +96,15 @@ void uv_winsock_init(void) { abort(); } + /* Skip initialization in safe mode without network support */ + if (1 == GetSystemMetrics(SM_CLEANBOOT)) return; + + /* Initialize winsock */ + errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (errorno != 0) { + uv_fatal_error(errorno, "WSAStartup"); + } + /* Detect non-IFS LSPs */ dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); -- cgit v1.2.3