From d6f6d7f8541327b72667d38777c47b9ea675125d Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 16 Mar 2019 14:38:18 -0400 Subject: [PATCH] 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/AUTHORS | 2 + deps/uv/CMakeLists.txt | 6 +- deps/uv/ChangeLog | 59 +++++++++ deps/uv/Makefile.am | 24 +++- deps/uv/README.md | 2 +- deps/uv/configure.ac | 21 ++-- deps/uv/docs/src/loop.rst | 2 + deps/uv/docs/src/signal.rst | 24 +++- deps/uv/docs/src/threading.rst | 4 +- deps/uv/docs/src/udp.rst | 54 ++++++++ deps/uv/include/uv.h | 4 + deps/uv/include/uv/version.h | 2 +- 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 ++- deps/uv/test/run-tests.c | 7 +- deps/uv/test/task.h | 3 +- deps/uv/test/test-fs-copyfile.c | 3 +- deps/uv/test/test-fs-poll.c | 74 +++++++++++ deps/uv/test/test-fs.c | 13 +- deps/uv/test/test-hrtime.c | 8 +- deps/uv/test/test-ipc.c | 2 +- deps/uv/test/test-list.h | 13 ++ deps/uv/test/test-loop-handles.c | 2 +- deps/uv/test/test-poll.c | 12 +- deps/uv/test/test-spawn.c | 10 +- deps/uv/test/test-udp-connect.c | 182 +++++++++++++++++++++++++++ deps/uv/test/test-udp-open.c | 81 ++++++++++++ deps/uv/test/test.gyp | 1 + 49 files changed, 1146 insertions(+), 200 deletions(-) create mode 100644 deps/uv/test/test-udp-connect.c diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 25447eb0e6..2c1d8ae685 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -369,3 +369,5 @@ Kevin Adler Stephen Belanger yeyuanfeng erw7 +Thomas Karl Pietrowski +evgley diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index 5dc61eb825..01a7c47e57 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -153,6 +153,7 @@ set(uv_test_sources test/test-tty.c test/test-udp-alloc-cb-fail.c test/test-udp-bind.c + test/test-udp-connect.c test/test-udp-create-socket-early.c test/test-udp-dgram-too-big.c test/test-udp-ipv6.c @@ -351,7 +352,8 @@ target_link_libraries(uv_a ${uv_libraries}) if(BUILD_TESTING) include(CTest) add_executable(uv_run_tests ${uv_test_sources}) - target_compile_definitions(uv_run_tests PRIVATE ${uv_defines}) + target_compile_definitions(uv_run_tests + PRIVATE ${uv_defines} USING_UV_SHARED=1) target_compile_options(uv_run_tests PRIVATE ${uv_cflags}) target_include_directories(uv_run_tests PRIVATE include) target_link_libraries(uv_run_tests uv ${uv_test_libraries}) @@ -383,7 +385,7 @@ if(UNIX) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR}) - install(FILES LICENSE ${CMAKE_CURRENT_BINARY_DIR}/libuv.pc + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libuv.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(TARGETS uv LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(TARGETS uv_a ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 7f02045e03..62d6073d7d 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,62 @@ +2019.03.17, Version 1.27.0 (Stable), a4fc9a66cc35256dbc4dcd67c910174f05b6daa6 + +Changes since version 1.26.0: + +* doc: describe unix signal handling better (Vladimír Čunát) + +* linux: use statx() to obtain file birth time (Ben Noordhuis) + +* src: fill sockaddr_in6.sin6_len when it's defined (Santiago Gimeno) + +* test: relax uv_hrtime() test assumptions (Ben Noordhuis) + +* build: make cmake install LICENSE only once (Thomas Karl Pietrowski) + +* bsd: plug uv_fs_event_start() error path fd leak (Ben Noordhuis) + +* unix: fix __FreeBSD_kernel__ typo (cjihrig) + +* doc: add note about uv_run() not being reentrant (Ben Noordhuis) + +* unix, win: make fs-poll close wait for resource cleanup (Anna Henningsen) + +* doc: fix typo in uv_thread_options_t definition (Ryan Liptak) + +* win: skip winsock initialization in safe mode (evgley) + +* unix: refactor getsockname/getpeername methods (Santiago Gimeno) + +* win,udp: allow to use uv_udp_open on bound sockets (Santiago Gimeno) + +* udp: add support for UDP connected sockets (Santiago Gimeno) + +* build: fix uv_test shared uv Windows cmake build (ptlomholt) + +* build: add android-configure scripts to EXTRA_DIST (Ben Noordhuis) + +* build: add missing header (cjihrig) + +* sunos: add perror() output prior to abort() (Andrew Paprocki) + +* test,sunos: disable UV_DISCONNECT handling (Andrew Paprocki) + +* sunos: disable __attribute__((unused)) (Andrew Paprocki) + +* test,sunos: use unistd.h code branch (Andrew Paprocki) + +* build,sunos: better handling of non-GCC compiler (Andrew Paprocki) + +* test,sunos: fix statement not reached warnings (Andrew Paprocki) + +* sunos: fix argument/prototype mismatch in atomics (Andrew Paprocki) + +* test,sunos: test-ipc.c lacks newline at EOF (Andrew Paprocki) + +* test: change spawn_stdin_stdout return to void (Andrew Paprocki) + +* test: remove call to floor() in test driver (Andrew Paprocki) + + 2019.02.11, Version 1.26.0 (Stable), 8669d8d3e93cddb62611b267ef62a3ddb5ba3ca0 Changes since version 1.25.0: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 7e49d8ad0b..595a5aea03 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -32,6 +32,7 @@ libuv_la_LDFLAGS = -no-undefined -version-info 1:0:0 libuv_la_SOURCES = src/fs-poll.c \ src/heap-inl.h \ src/idna.c \ + src/idna.h \ src/inet.c \ src/queue.h \ src/strscpy.c \ @@ -44,10 +45,12 @@ libuv_la_SOURCES = src/fs-poll.c \ src/version.c if SUNOS +if GCC # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers # on other platforms complain that the argument is unused during compilation. libuv_la_CFLAGS += -pthreads endif +endif if WINNT @@ -121,11 +124,13 @@ EXTRA_DIST = test/fixtures/empty_file \ docs \ img \ samples \ - android-configure \ + android-configure-arm \ + android-configure-arm64 \ + android-configure-x86 \ + android-configure-x86_64 \ CONTRIBUTING.md \ LICENSE \ README.md \ - checksparse.sh \ vcbuild.bat \ common.gypi \ gyp_uv.py \ @@ -138,14 +143,20 @@ check_PROGRAMS = test/run-tests if OS390 test_run_tests_CFLAGS = else +if GCC test_run_tests_CFLAGS = -Wno-long-long +else +test_run_tests_CFLAGS = +endif endif if SUNOS +if GCC # Can't be turned into a CC_CHECK_CFLAGS in configure.ac, it makes compilers # on other platforms complain that the argument is unused during compilation. test_run_tests_CFLAGS += -pthreads endif +endif test_run_tests_LDFLAGS = test_run_tests_SOURCES = test/blackhole-server.c \ @@ -281,6 +292,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tty.c \ test/test-udp-alloc-cb-fail.c \ test/test-udp-bind.c \ + test/test-udp-connect.c \ test/test-udp-create-socket-early.c \ test/test-udp-dgram-too-big.c \ test/test-udp-ipv6.c \ @@ -320,7 +332,9 @@ test_run_tests_CFLAGS += -D_GNU_SOURCE endif if SUNOS -test_run_tests_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 +test_run_tests_CFLAGS += -D__EXTENSIONS__ \ + -D_XOPEN_SOURCE=500 \ + -D_REENTRANT endif if OS390 @@ -458,7 +472,9 @@ endif if SUNOS uvinclude_HEADERS += include/uv/sunos.h -libuv_la_CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 +libuv_la_CFLAGS += -D__EXTENSIONS__ \ + -D_XOPEN_SOURCE=500 \ + -D_REENTRANT libuv_la_SOURCES += src/unix/no-proctitle.c \ src/unix/sunos.c endif diff --git a/deps/uv/README.md b/deps/uv/README.md index fb5971d3e3..4e92a8174a 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -312,7 +312,7 @@ $ make -C out The default API level is 24, but a different one can be selected as follows: ```bash -$ source ./android-configure ~/android-ndk-r15b gyp 21 +$ source ./android-configure-arm ~/android-ndk-r15b gyp 21 $ make -C out ``` diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 931ac3e361..336e55b15f 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.26.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.27.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) @@ -24,16 +24,18 @@ AC_ENABLE_SHARED AC_ENABLE_STATIC AC_PROG_CC AM_PROG_CC_C_O -AS_IF([AS_CASE([$host_os],[openedition*], [false], [true])], [ - CC_CHECK_CFLAGS_APPEND([-pedantic]) -]) CC_FLAG_VISIBILITY #[-fvisibility=hidden] CC_CHECK_CFLAGS_APPEND([-g]) -CC_CHECK_CFLAGS_APPEND([-std=gnu89]) -CC_CHECK_CFLAGS_APPEND([-Wall]) -CC_CHECK_CFLAGS_APPEND([-Wextra]) -CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) -CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes]) +AS_IF([test "x$GCC" = xyes], [ + AS_IF([AS_CASE([$host_os], [openedition*], [false], [true])], [ + CC_CHECK_CFLAGS_APPEND([-pedantic]) + ]) + CC_CHECK_CFLAGS_APPEND([-std=gnu89]) + CC_CHECK_CFLAGS_APPEND([-Wall]) + CC_CHECK_CFLAGS_APPEND([-Wextra]) + CC_CHECK_CFLAGS_APPEND([-Wno-unused-parameter]) + CC_CHECK_CFLAGS_APPEND([-Wstrict-prototypes]) +]) # AM_PROG_AR is not available in automake v0.11 but it's essential in v0.12. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) # autoconf complains if AC_PROG_LIBTOOL precedes AM_PROG_AR. @@ -50,6 +52,7 @@ AC_CHECK_LIB([rt], [clock_gettime]) AC_CHECK_LIB([sendfile], [sendfile]) AC_CHECK_LIB([socket], [socket]) AC_SYS_LARGEFILE +AM_CONDITIONAL([GCC], [AS_IF([test "x$GCC" = xyes], [true], [false])]) AM_CONDITIONAL([AIX], [AS_CASE([$host_os],[aix*], [true], [false])]) AM_CONDITIONAL([ANDROID], [AS_CASE([$host_os],[linux-android*],[true], [false])]) AM_CONDITIONAL([CYGWIN], [AS_CASE([$host_os],[cygwin*], [true], [false])]) diff --git a/deps/uv/docs/src/loop.rst b/deps/uv/docs/src/loop.rst index 86a99adf5d..d642ac1d2f 100644 --- a/deps/uv/docs/src/loop.rst +++ b/deps/uv/docs/src/loop.rst @@ -107,6 +107,8 @@ API or requests left), or non-zero if more callbacks are expected (meaning you should run the event loop again sometime in the future). + :c:func:`uv_run` is not reentrant. It must not be called from a callback. + .. c:function:: int uv_loop_alive(const uv_loop_t* loop) Returns non-zero if there are referenced active handles, active diff --git a/deps/uv/docs/src/signal.rst b/deps/uv/docs/src/signal.rst index f52b64706a..f5a809ab0b 100644 --- a/deps/uv/docs/src/signal.rst +++ b/deps/uv/docs/src/signal.rst @@ -6,7 +6,10 @@ Signal handles implement Unix style signal handling on a per-event loop bases. -Reception of some signals is emulated on Windows: +Windows notes +------------- + +Reception of some signals is emulated: * SIGINT is normally delivered when the user presses CTRL+C. However, like on Unix, it is not generated when terminal raw mode is enabled. @@ -24,13 +27,22 @@ Reception of some signals is emulated on Windows: * Calls to raise() or abort() to programmatically raise a signal are not detected by libuv; these will not trigger a signal watcher. -.. note:: - On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL pthreads library to - manage threads. Installing watchers for those signals will lead to unpredictable behavior - and is strongly discouraged. Future versions of libuv may simply reject them. - .. versionchanged:: 1.15.0 SIGWINCH support on Windows was improved. +Unix notes +---------- + +* SIGKILL and SIGSTOP are impossible to catch. + +* Handling SIGBUS, SIGFPE, SIGILL or SIGSEGV via libuv results into undefined behavior. + +* SIGABRT will not be caught by libuv if generated by `abort()`, e.g. through `assert()`. + +* On Linux SIGRT0 and SIGRT1 (signals 32 and 33) are used by the NPTL pthreads library to + manage threads. Installing watchers for those signals will lead to unpredictable behavior + and is strongly discouraged. Future versions of libuv may simply reject them. + + Data types ---------- diff --git a/deps/uv/docs/src/threading.rst b/deps/uv/docs/src/threading.rst index a5759a38a6..7ca1d4b7a5 100644 --- a/deps/uv/docs/src/threading.rst +++ b/deps/uv/docs/src/threading.rst @@ -61,13 +61,13 @@ Threads :: - typedef struct uv_process_options_s { + typedef struct uv_thread_options_s { enum { UV_THREAD_NO_FLAGS = 0x00, UV_THREAD_HAS_STACK_SIZE = 0x01 } flags; size_t stack_size; - } uv_process_options_t; + } uv_thread_options_t; More fields may be added to this struct at any time, so its exact layout and size should not be relied upon. diff --git a/deps/uv/docs/src/udp.rst b/deps/uv/docs/src/udp.rst index 8148828522..f3de53fbab 100644 --- a/deps/uv/docs/src/udp.rst +++ b/deps/uv/docs/src/udp.rst @@ -150,6 +150,44 @@ API :returns: 0 on success, or an error code < 0 on failure. +.. c:function:: int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) + + Associate the UDP handle to a remote address and port, so every + message sent by this handle is automatically sent to that destination. + Calling this function with a `NULL` `addr` disconnects the handle. + Trying to call `uv_udp_connect()` on an already connected handle will result + in an `UV_EISCONN` error. Trying to disconnect a handle that is not + connected will return an `UV_ENOTCONN` error. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param addr: `struct sockaddr_in` or `struct sockaddr_in6` + with the address and port to associate to. + + :returns: 0 on success, or an error code < 0 on failure. + + .. versionadded:: 1.27.0 + +.. c:function:: int uv_udp_getpeername(const uv_udp_t* handle, struct sockaddr* name, int* namelen) + + Get the remote IP and port of the UDP handle on connected UDP handles. + On unconnected handles, it returns `UV_ENOTCONN`. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init` and bound. + + :param name: Pointer to the structure to be filled with the address data. + In order to support IPv4 and IPv6 `struct sockaddr_storage` should be + used. + + :param namelen: On input it indicates the data of the `name` field. On + output it indicates how much of it was filled. + + :returns: 0 on success, or an error code < 0 on failure + + .. versionadded:: 1.27.0 + .. c:function:: int uv_udp_getsockname(const uv_udp_t* handle, struct sockaddr* name, int* namelen) Get the local IP and port of the UDP handle. @@ -247,6 +285,12 @@ API (``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``. This is done to match the behavior of Linux systems. + For connected UDP handles, `addr` must be set to `NULL`, otherwise it will + return `UV_EISCONN` error. + + For connectionless UDP handles, `addr` cannot be `NULL`, otherwise it will + return `UV_EDESTADDRREQ` error. + :param req: UDP request handle. Need not be initialized. :param handle: UDP handle. Should have been initialized with @@ -266,15 +310,25 @@ API .. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost`` mapping + .. versionchanged:: 1.27.0 added support for connected sockets + .. c:function:: int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr) Same as :c:func:`uv_udp_send`, but won't queue a send request if it can't be completed immediately. + For connected UDP handles, `addr` must be set to `NULL`, otherwise it will + return `UV_EISCONN` error. + + For connectionless UDP handles, `addr` cannot be `NULL`, otherwise it will + return `UV_EDESTADDRREQ` error. + :returns: >= 0: number of bytes sent (it matches the given buffer size). < 0: negative error code (``UV_EAGAIN`` is returned when the message can't be sent immediately). + .. versionchanged:: 1.27.0 added support for connected sockets + .. c:function:: int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, uv_udp_recv_cb recv_cb) Prepare for receiving data. If the socket has not previously been bound diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 1578bbd568..43895ac80d 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -630,7 +630,11 @@ UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock); UV_EXTERN int uv_udp_bind(uv_udp_t* handle, const struct sockaddr* addr, unsigned int flags); +UV_EXTERN int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr); +UV_EXTERN int uv_udp_getpeername(const uv_udp_t* handle, + struct sockaddr* name, + int* namelen); UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle, struct sockaddr* name, int* namelen); diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index fa7320cf4d..4f65398307 100644 --- a/deps/uv/include/uv/version.h +++ b/deps/uv/include/uv/version.h @@ -31,7 +31,7 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 26 +#define UV_VERSION_MINOR 27 #define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" 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 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, 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 @@ static void poll_cb(uv_fs_t* req) { } -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 @@ int uv_os_uname(uv_utsname_t* buffer) { 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 @@ void uv_pipe_connect(uv_connect_t* req, } -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); diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index eba28ecb9a..55cf412827 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -44,7 +44,7 @@ int ipc_send_recv_helper(void); int ipc_helper_bind_twice(void); int ipc_helper_send_zero(void); int stdio_over_pipes_helper(void); -int spawn_stdin_stdout(void); +void spawn_stdin_stdout(void); int spawn_tcp_server_helper(void); static int maybe_run_test(int argc, char **argv); @@ -67,7 +67,9 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } +#ifndef __SUNPRO_C return EXIT_SUCCESS; +#endif } @@ -209,7 +211,8 @@ static int maybe_run_test(int argc, char **argv) { if (strcmp(argv[1], "spawn_helper9") == 0) { notify_parent_process(); - return spawn_stdin_stdout(); + spawn_stdin_stdout(); + return 1; } #ifndef _WIN32 diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index 282c02d50c..8462e0ddbd 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -174,8 +174,7 @@ extern int snprintf(char*, size_t, const char*, ...); #if defined(__clang__) || \ defined(__GNUC__) || \ - defined(__INTEL_COMPILER) || \ - defined(__SUNPRO_C) + defined(__INTEL_COMPILER) # define UNUSED __attribute__((unused)) #else # define UNUSED diff --git a/deps/uv/test/test-fs-copyfile.c b/deps/uv/test/test-fs-copyfile.c index eadff542bc..7b6511c93c 100644 --- a/deps/uv/test/test-fs-copyfile.c +++ b/deps/uv/test/test-fs-copyfile.c @@ -23,7 +23,8 @@ #include "task.h" #if defined(__unix__) || defined(__POSIX__) || \ - defined(__APPLE__) || defined(_AIX) || defined(__MVS__) + defined(__APPLE__) || defined(__sun) || \ + defined(_AIX) || defined(__MVS__) #include /* unlink, etc. */ #else # include diff --git a/deps/uv/test/test-fs-poll.c b/deps/uv/test/test-fs-poll.c index 737d50dfd2..e19a68780f 100644 --- a/deps/uv/test/test-fs-poll.c +++ b/deps/uv/test/test-fs-poll.c @@ -185,3 +185,77 @@ TEST_IMPL(fs_poll_getpath) { MAKE_VALGRIND_HAPPY(); return 0; } + + +TEST_IMPL(fs_poll_close_request) { + uv_loop_t loop; + uv_fs_poll_t poll_handle; + + remove(FIXTURE); + + ASSERT(0 == uv_loop_init(&loop)); + + ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); + ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); + uv_close((uv_handle_t*) &poll_handle, close_cb); + while (close_cb_called == 0) + uv_run(&loop, UV_RUN_ONCE); + ASSERT(close_cb_called == 1); + + ASSERT(0 == uv_loop_close(&loop)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_poll_close_request_multi_start_stop) { + uv_loop_t loop; + uv_fs_poll_t poll_handle; + int i; + + remove(FIXTURE); + + ASSERT(0 == uv_loop_init(&loop)); + + ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); + + for (i = 0; i < 10; ++i) { + ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); + ASSERT(0 == uv_fs_poll_stop(&poll_handle)); + } + uv_close((uv_handle_t*) &poll_handle, close_cb); + while (close_cb_called == 0) + uv_run(&loop, UV_RUN_ONCE); + ASSERT(close_cb_called == 1); + + ASSERT(0 == uv_loop_close(&loop)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(fs_poll_close_request_multi_stop_start) { + uv_loop_t loop; + uv_fs_poll_t poll_handle; + int i; + + remove(FIXTURE); + + ASSERT(0 == uv_loop_init(&loop)); + + ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); + + for (i = 0; i < 10; ++i) { + ASSERT(0 == uv_fs_poll_stop(&poll_handle)); + ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); + } + uv_close((uv_handle_t*) &poll_handle, close_cb); + while (close_cb_called == 0) + uv_run(&loop, UV_RUN_ONCE); + ASSERT(close_cb_called == 1); + + ASSERT(0 == uv_loop_close(&loop)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 5eed160de2..35f7d0c3f1 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -30,7 +30,8 @@ /* FIXME we shouldn't need to branch in this file */ #if defined(__unix__) || defined(__POSIX__) || \ - defined(__APPLE__) || defined(_AIX) || defined(__MVS__) + defined(__APPLE__) || defined(__sun) || \ + defined(_AIX) || defined(__MVS__) #include /* unlink, rmdir, etc. */ #else # include @@ -1248,6 +1249,16 @@ TEST_IMPL(fs_fstat) { #endif #endif +#if defined(__linux__) + /* If statx() is supported, the birth time should be equal to the change time + * because we just created the file. On older kernels, it's set to zero. + */ + ASSERT(s->st_birthtim.tv_sec == 0 || + s->st_birthtim.tv_sec == t.st_ctim.tv_sec); + ASSERT(s->st_birthtim.tv_nsec == 0 || + s->st_birthtim.tv_nsec == t.st_ctim.tv_nsec); +#endif + uv_fs_req_cleanup(&req); /* Now do the uv_fs_fstat call asynchronously */ diff --git a/deps/uv/test/test-hrtime.c b/deps/uv/test/test-hrtime.c index fbe9a68bfc..9d461d9623 100644 --- a/deps/uv/test/test-hrtime.c +++ b/deps/uv/test/test-hrtime.c @@ -41,13 +41,11 @@ TEST_IMPL(hrtime) { diff = b - a; - /* printf("i= %d diff = %llu\n", i, (unsigned long long int) diff); */ - /* The windows Sleep() function has only a resolution of 10-20 ms. Check - * that the difference between the two hrtime values is somewhat in the - * range we expect it to be. */ + * that the difference between the two hrtime values has a reasonable + * lower bound. + */ ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC); - ASSERT(diff < (uint64_t) 80 * NANOSEC / MILLISEC); --i; } return 0; diff --git a/deps/uv/test/test-ipc.c b/deps/uv/test/test-ipc.c index 88d04ba143..24c067e0a4 100644 --- a/deps/uv/test/test-ipc.c +++ b/deps/uv/test/test-ipc.c @@ -971,4 +971,4 @@ int ipc_helper_send_zero(void) { MAKE_VALGRIND_HAPPY(); return 0; -} \ No newline at end of file +} diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index d81416fad2..f498c7dc81 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -132,6 +132,7 @@ TEST_DECLARE (tcp_write_ready) TEST_DECLARE (udp_alloc_cb_fail) TEST_DECLARE (udp_bind) TEST_DECLARE (udp_bind_reuseaddr) +TEST_DECLARE (udp_connect) TEST_DECLARE (udp_create_early) TEST_DECLARE (udp_create_early_bad_bind) TEST_DECLARE (udp_create_early_bad_domain) @@ -152,6 +153,8 @@ TEST_DECLARE (udp_options6) TEST_DECLARE (udp_no_autobind) TEST_DECLARE (udp_open) TEST_DECLARE (udp_open_twice) +TEST_DECLARE (udp_open_bound) +TEST_DECLARE (udp_open_connect) TEST_DECLARE (udp_try_send) TEST_DECLARE (pipe_bind_error_addrinuse) TEST_DECLARE (pipe_bind_error_addrnotavail) @@ -280,6 +283,9 @@ TEST_DECLARE (spawn_quoted_path) TEST_DECLARE (spawn_tcp_server) TEST_DECLARE (fs_poll) TEST_DECLARE (fs_poll_getpath) +TEST_DECLARE (fs_poll_close_request) +TEST_DECLARE (fs_poll_close_request_multi_start_stop) +TEST_DECLARE (fs_poll_close_request_multi_stop_start) TEST_DECLARE (kill) TEST_DECLARE (kill_invalid_signum) TEST_DECLARE (fs_file_noent) @@ -619,6 +625,7 @@ TASK_LIST_START TEST_ENTRY (udp_alloc_cb_fail) TEST_ENTRY (udp_bind) TEST_ENTRY (udp_bind_reuseaddr) + TEST_ENTRY (udp_connect) TEST_ENTRY (udp_create_early) TEST_ENTRY (udp_create_early_bad_bind) TEST_ENTRY (udp_create_early_bad_domain) @@ -642,6 +649,9 @@ TASK_LIST_START TEST_ENTRY (udp_open) TEST_HELPER (udp_open, udp4_echo_server) TEST_ENTRY (udp_open_twice) + TEST_ENTRY (udp_open_bound) + TEST_ENTRY (udp_open_connect) + TEST_HELPER (udp_open_connect, udp4_echo_server) TEST_ENTRY (pipe_bind_error_addrinuse) TEST_ENTRY (pipe_bind_error_addrnotavail) @@ -817,6 +827,9 @@ TASK_LIST_START TEST_ENTRY (spawn_tcp_server) TEST_ENTRY (fs_poll) TEST_ENTRY (fs_poll_getpath) + TEST_ENTRY (fs_poll_close_request) + TEST_ENTRY (fs_poll_close_request_multi_start_stop) + TEST_ENTRY (fs_poll_close_request_multi_stop_start) TEST_ENTRY (kill) TEST_ENTRY (kill_invalid_signum) diff --git a/deps/uv/test/test-loop-handles.c b/deps/uv/test/test-loop-handles.c index 6471cd08b3..131098801a 100644 --- a/deps/uv/test/test-loop-handles.c +++ b/deps/uv/test/test-loop-handles.c @@ -320,7 +320,7 @@ TEST_IMPL(loop_handles) { ASSERT(prepare_1_cb_called == ITERATIONS); ASSERT(prepare_1_close_cb_called == 1); - ASSERT(prepare_2_cb_called == floor(ITERATIONS / 2.0)); + ASSERT(prepare_2_cb_called == ITERATIONS / 2); ASSERT(prepare_2_close_cb_called == 1); ASSERT(check_cb_called == ITERATIONS); diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index 0d1b1d7ec9..cc2b5fbe59 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -82,9 +82,9 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; -#if !defined(_AIX) && !defined(__MVS__) +#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) static int disconnects = 0; -#endif /* !_AIX && !__MVS__ */ +#endif /* !__sun && !_AIX && !__MVS__ */ static int got_eagain(void) { #ifdef _WIN32 @@ -391,7 +391,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { new_events &= ~UV_WRITABLE; } } -#if !defined(_AIX) && !defined(__MVS__) +#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) if (events & UV_DISCONNECT) { context->got_disconnect = 1; ++disconnects; @@ -399,9 +399,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } if (context->got_fin && context->sent_fin && context->got_disconnect) { -#else /* _AIX && __MVS__ */ +#else /* __sun && _AIX && __MVS__ */ if (context->got_fin && context->sent_fin) { -#endif /* !_AIX && !__MVS__ */ +#endif /* !__sun && !_AIX && !__MVS__ */ /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -569,7 +569,7 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); -#if !defined(_AIX) && !defined(__MVS__) +#if !defined(__sun) && !defined(_AIX) && !defined(__MVS__) ASSERT(disconnects == NUM_CLIENTS * 2); #endif MAKE_VALGRIND_HAPPY(); diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index 05c76f6145..e5fc308a0e 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -1838,7 +1838,7 @@ TEST_IMPL(spawn_quoted_path) { /* Helper for child process of spawn_inherit_streams */ #ifndef _WIN32 -int spawn_stdin_stdout(void) { +void spawn_stdin_stdout(void) { char buf[1024]; char* pbuf; for (;;) { @@ -1847,7 +1847,7 @@ int spawn_stdin_stdout(void) { r = read(0, buf, sizeof buf); } while (r == -1 && errno == EINTR); if (r == 0) { - return 1; + return; } ASSERT(r > 0); c = r; @@ -1861,10 +1861,9 @@ int spawn_stdin_stdout(void) { c = c - w; } } - return 2; } #else -int spawn_stdin_stdout(void) { +void spawn_stdin_stdout(void) { char buf[1024]; char* pbuf; HANDLE h_stdin = GetStdHandle(STD_INPUT_HANDLE); @@ -1877,7 +1876,7 @@ int spawn_stdin_stdout(void) { DWORD to_write; if (!ReadFile(h_stdin, buf, sizeof buf, &n_read, NULL)) { ASSERT(GetLastError() == ERROR_BROKEN_PIPE); - return 1; + return; } to_write = n_read; pbuf = buf; @@ -1887,6 +1886,5 @@ int spawn_stdin_stdout(void) { pbuf += n_written; } } - return 2; } #endif /* !_WIN32 */ diff --git a/deps/uv/test/test-udp-connect.c b/deps/uv/test/test-udp-connect.c new file mode 100644 index 0000000000..f44634248f --- /dev/null +++ b/deps/uv/test/test-udp-connect.c @@ -0,0 +1,182 @@ +/* Copyright libuv project and contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include +#include + +#define CHECK_HANDLE(handle) \ + ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) + +static uv_udp_t server; +static uv_udp_t client; +static uv_buf_t buf; +static struct sockaddr_in lo_addr; + +static int cl_send_cb_called; +static int sv_recv_cb_called; + +static int close_cb_called; + + +static void alloc_cb(uv_handle_t* handle, + size_t suggested_size, + uv_buf_t* buf) { + static char slab[65536]; + CHECK_HANDLE(handle); + ASSERT(suggested_size <= sizeof(slab)); + buf->base = slab; + buf->len = sizeof(slab); +} + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + ASSERT(uv_is_closing(handle)); + close_cb_called++; +} + + +static void cl_send_cb(uv_udp_send_t* req, int status) { + int r; + + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + if (++cl_send_cb_called == 1) { + uv_udp_connect(&client, NULL); + r = uv_udp_send(req, &client, &buf, 1, NULL, cl_send_cb); + ASSERT(r == UV_EDESTADDRREQ); + r = uv_udp_send(req, + &client, + &buf, + 1, + (const struct sockaddr*) &lo_addr, + cl_send_cb); + ASSERT(r == 0); + } + +} + + +static void sv_recv_cb(uv_udp_t* handle, + ssize_t nread, + const uv_buf_t* rcvbuf, + const struct sockaddr* addr, + unsigned flags) { + if (nread > 0) { + ASSERT(nread == 4); + ASSERT(addr != NULL); + ASSERT(memcmp("EXIT", rcvbuf->base, nread) == 0); + if (++sv_recv_cb_called == 4) { + uv_close((uv_handle_t*) &server, close_cb); + uv_close((uv_handle_t*) &client, close_cb); + } + } +} + + +TEST_IMPL(udp_connect) { + uv_udp_send_t req; + struct sockaddr_in ext_addr; + struct sockaddr_in tmp_addr; + int r; + int addrlen; + + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &lo_addr)); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &lo_addr, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&server, alloc_cb, sv_recv_cb); + ASSERT(r == 0); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + buf = uv_buf_init("EXIT", 4); + + ASSERT(0 == uv_ip4_addr("8.8.8.8", TEST_PORT, &ext_addr)); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &lo_addr)); + + r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); + ASSERT(r == 0); + r = uv_udp_connect(&client, (const struct sockaddr*) &ext_addr); + ASSERT(r == UV_EISCONN); + + addrlen = sizeof(tmp_addr); + r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); + ASSERT(r == 0); + + /* To send messages in connected UDP sockets addr must be NULL */ + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); + ASSERT(r == UV_EISCONN); + r = uv_udp_try_send(&client, &buf, 1, NULL); + ASSERT(r == 4); + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &ext_addr); + ASSERT(r == UV_EISCONN); + + r = uv_udp_connect(&client, NULL); + ASSERT(r == 0); + r = uv_udp_connect(&client, NULL); + ASSERT(r == UV_ENOTCONN); + + addrlen = sizeof(tmp_addr); + r = uv_udp_getpeername(&client, (struct sockaddr*) &tmp_addr, &addrlen); + ASSERT(r == UV_ENOTCONN); + + /* To send messages in disconnected UDP sockets addr must be set */ + r = uv_udp_try_send(&client, &buf, 1, (const struct sockaddr*) &lo_addr); + ASSERT(r == 4); + r = uv_udp_try_send(&client, &buf, 1, NULL); + ASSERT(r == UV_EDESTADDRREQ); + + + r = uv_udp_connect(&client, (const struct sockaddr*) &lo_addr); + ASSERT(r == 0); + r = uv_udp_send(&req, + &client, + &buf, + 1, + (const struct sockaddr*) &lo_addr, + cl_send_cb); + ASSERT(r == UV_EISCONN); + r = uv_udp_send(&req, &client, &buf, 1, NULL, cl_send_cb); + ASSERT(r == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 2); + ASSERT(sv_recv_cb_called == 4); + ASSERT(cl_send_cb_called == 2); + + ASSERT(client.send_queue_size == 0); + ASSERT(server.send_queue_size == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-udp-open.c b/deps/uv/test/test-udp-open.c index ee04c99f61..0390bae2e5 100644 --- a/deps/uv/test/test-udp-open.c +++ b/deps/uv/test/test-udp-open.c @@ -129,6 +129,7 @@ static void send_cb(uv_udp_send_t* req, int status) { ASSERT(status == 0); send_cb_called++; + uv_close((uv_handle_t*)req->handle, close_cb); } @@ -215,3 +216,83 @@ TEST_IMPL(udp_open_twice) { MAKE_VALGRIND_HAPPY(); return 0; } + +TEST_IMPL(udp_open_bound) { + struct sockaddr_in addr; + uv_udp_t client; + uv_os_sock_t sock; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + startup(); + sock = create_udp_socket(); + + r = bind(sock, (struct sockaddr*) &addr, sizeof(addr)); + ASSERT(r == 0); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + r = uv_udp_open(&client, sock); + ASSERT(r == 0); + + r = uv_udp_recv_start(&client, alloc_cb, recv_cb); + ASSERT(r == 0); + + uv_close((uv_handle_t*) &client, NULL); + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(udp_open_connect) { + struct sockaddr_in addr; + uv_buf_t buf = uv_buf_init("PING", 4); + uv_udp_t client; + uv_udp_t server; + uv_os_sock_t sock; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + startup(); + sock = create_udp_socket(); + + r = uv_udp_init(uv_default_loop(), &client); + ASSERT(r == 0); + + r = connect(sock, (const struct sockaddr*) &addr, sizeof(addr)); + ASSERT(r == 0); + + r = uv_udp_open(&client, sock); + ASSERT(r == 0); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_udp_recv_start(&server, alloc_cb, recv_cb); + ASSERT(r == 0); + + r = uv_udp_send(&send_req, + &client, + &buf, + 1, + NULL, + send_cb); + ASSERT(r == 0); + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(send_cb_called == 1); + ASSERT(close_cb_called == 2); + + ASSERT(client.send_queue_size == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test.gyp b/deps/uv/test/test.gyp index 8fc6cca140..9c13e25dde 100644 --- a/deps/uv/test/test.gyp +++ b/deps/uv/test/test.gyp @@ -137,6 +137,7 @@ 'test-tty.c', 'test-udp-alloc-cb-fail.c', 'test-udp-bind.c', + 'test-udp-connect.c', 'test-udp-create-socket-early.c', 'test-udp-dgram-too-big.c', 'test-udp-ipv6.c',