From df0e2e3625d1f72e8b04e05ffa13997a51e9f0d7 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 9 Sep 2019 13:08:37 -0400 Subject: [PATCH] deps: upgrade to libuv 1.32.0 Notable changes: - `uv_tcp_close_reset()` has been added. - `uv_udp_set_source_membership()` has been added. - A double free in `uv_free_cpu_info()` on OpenBSD has been fixed. - Defined, but empty environment variables can now be read on Windows. - Several improvements to the cmake build process. - The `EILSEQ` error code is now mapped by libuv. PR-URL: https://github.com/nodejs/node/pull/29508 Reviewed-By: Trivikram Kamat Reviewed-By: Jiawen Geng Reviewed-By: Ben Noordhuis Reviewed-By: David Carlier Reviewed-By: Anna Henningsen Reviewed-By: Beth Griggs Reviewed-By: James M Snell --- deps/uv/AUTHORS | 7 + deps/uv/CMakeLists.txt | 19 +- deps/uv/ChangeLog | 75 +++++ deps/uv/Makefile.am | 3 + deps/uv/README.md | 2 + deps/uv/configure.ac | 2 +- deps/uv/docs/src/handle.rst | 5 +- deps/uv/docs/src/signal.rst | 11 + deps/uv/docs/src/stream.rst | 4 +- deps/uv/docs/src/tcp.rst | 10 + deps/uv/docs/src/udp.rst | 30 +- deps/uv/include/uv.h | 11 + deps/uv/include/uv/errno.h | 5 + deps/uv/include/uv/unix.h | 16 +- deps/uv/include/uv/version.h | 2 +- deps/uv/src/timer.c | 2 +- deps/uv/src/unix/aix-common.c | 10 - deps/uv/src/unix/atomic-ops.h | 4 - deps/uv/src/unix/core.c | 45 ++- deps/uv/src/unix/cygwin.c | 5 - deps/uv/src/unix/darwin.c | 11 - deps/uv/src/unix/freebsd.c | 11 - deps/uv/src/unix/fs.c | 17 +- deps/uv/src/unix/haiku.c | 9 - deps/uv/src/unix/linux-core.c | 10 - deps/uv/src/unix/netbsd.c | 11 - deps/uv/src/unix/openbsd.c | 29 +- deps/uv/src/unix/os390.c | 7 - deps/uv/src/unix/signal.c | 11 +- deps/uv/src/unix/stream.c | 8 +- deps/uv/src/unix/sunos.c | 10 - deps/uv/src/unix/tcp.c | 17 ++ deps/uv/src/unix/udp.c | 137 +++++++++ deps/uv/src/uv-common.c | 10 + deps/uv/src/win/error.c | 1 + deps/uv/src/win/stream.c | 7 +- deps/uv/src/win/tcp.c | 15 + deps/uv/src/win/tty.c | 44 ++- deps/uv/src/win/udp.c | 150 ++++++++++ deps/uv/src/win/util.c | 21 +- deps/uv/src/win/winapi.h | 2 +- deps/uv/test/test-env-vars.c | 9 + deps/uv/test/test-fs.c | 2 +- deps/uv/test/test-list.h | 12 + deps/uv/test/test-signal-pending-on-close.c | 94 +++++++ deps/uv/test/test-spawn.c | 2 +- deps/uv/test/test-tcp-bind-error.c | 4 - deps/uv/test/test-tcp-close-reset.c | 290 ++++++++++++++++++++ deps/uv/test/test-timer.c | 13 + deps/uv/test/test-udp-multicast-join.c | 74 +++-- deps/uv/test/test-udp-multicast-join6.c | 118 +++++--- deps/uv/test/test.gyp | 2 + deps/uv/uv.gyp | 1 + 53 files changed, 1176 insertions(+), 251 deletions(-) create mode 100644 deps/uv/test/test-signal-pending-on-close.c create mode 100644 deps/uv/test/test-tcp-close-reset.c diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 5d5866d3ff2405..8c3d342d33e6f8 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -396,3 +396,10 @@ Nan Xiao Ben Davies Nhan Khong Crunkle +Tomas Krizek +Konstantin Podsvirov +seny +Vladimir Karnushin +MaYuming +Eneas U de Queiroz +Daniel Hahler diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index bf7990f745fee2..6f18f3397d0129 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -1,5 +1,5 @@ # TODO: determine CMAKE_SYSTEM_NAME on OS/390. Currently assumes "OS/390". -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 2.8.12) project(libuv) if(MSVC) @@ -116,6 +116,7 @@ set(uv_test_sources test/test-shutdown-eof.c test/test-shutdown-twice.c test/test-signal-multiple-loops.c + test/test-signal-pending-on-close.c test/test-signal.c test/test-socket-buffer-size.c test/test-spawn.c @@ -127,6 +128,7 @@ set(uv_test_sources test/test-tcp-close-accept.c test/test-tcp-close-while-connecting.c test/test-tcp-close.c + test/test-tcp-close-reset.c test/test-tcp-connect-error-after-write.c test/test-tcp-connect-error.c test/test-tcp-connect-timeout.c @@ -317,6 +319,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OS/390") list(APPEND uv_defines _OPEN_MSGQ_EXT) list(APPEND uv_defines _OPEN_SYS_FILE_EXT) list(APPEND uv_defines _OPEN_SYS_IF_EXT) + list(APPEND uv_defines _OPEN_SYS_SOCK_EXT3) list(APPEND uv_defines _OPEN_SYS_SOCK_IPV6) list(APPEND uv_defines _UNIX03_SOURCE) list(APPEND uv_defines _UNIX03_THREADS) @@ -340,15 +343,17 @@ if(APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|Linux|NetBSD|OpenBSD") endif() add_library(uv SHARED ${uv_sources}) -target_compile_definitions(uv PRIVATE ${uv_defines} BUILDING_UV_SHARED=1) +target_compile_definitions(uv + INTERFACE USING_UV_SHARED=1 + PRIVATE ${uv_defines} BUILDING_UV_SHARED=1) target_compile_options(uv PRIVATE ${uv_cflags}) -target_include_directories(uv PRIVATE include src) +target_include_directories(uv PUBLIC include PRIVATE src) target_link_libraries(uv ${uv_libraries}) add_library(uv_a STATIC ${uv_sources}) target_compile_definitions(uv_a PRIVATE ${uv_defines}) target_compile_options(uv_a PRIVATE ${uv_cflags}) -target_include_directories(uv_a PRIVATE include src) +target_include_directories(uv_a PUBLIC include PRIVATE src) target_link_libraries(uv_a ${uv_libraries}) option(libuv_buildtests "Build the unit tests when BUILD_TESTING is enabled." ON) @@ -360,7 +365,6 @@ if(BUILD_TESTING AND libuv_buildtests) 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}) add_test(NAME uv_test COMMAND uv_run_tests @@ -368,7 +372,6 @@ if(BUILD_TESTING AND libuv_buildtests) add_executable(uv_run_tests_a ${uv_test_sources}) target_compile_definitions(uv_run_tests_a PRIVATE ${uv_defines}) target_compile_options(uv_run_tests_a PRIVATE ${uv_cflags}) - target_include_directories(uv_run_tests_a PRIVATE include) target_link_libraries(uv_run_tests_a uv_a ${uv_test_libraries}) add_test(NAME uv_test_a COMMAND uv_run_tests_a @@ -383,6 +386,10 @@ if(UNIX) endforeach(x) file(STRINGS configure.ac configure_ac REGEX ^AC_INIT) string(REGEX MATCH [0-9]+[.][0-9]+[.][0-9]+ PACKAGE_VERSION "${configure_ac}") + string(REGEX MATCH ^[0-9]+ UV_VERSION_MAJOR "${PACKAGE_VERSION}") + # The version in the filename is mirroring the behaviour of autotools. + set_target_properties(uv PROPERTIES VERSION ${UV_VERSION_MAJOR}.0.0 + SOVERSION ${UV_VERSION_MAJOR}) set(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}) set(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) set(prefix ${CMAKE_INSTALL_PREFIX}) diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index d440b5507719c5..093579de8e4985 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,78 @@ +2019.09.10, Version 1.32.0 (Stable), 697bea87b3a0b0e9b4e5ff86b39d1dedb70ee46d + +Changes since version 1.31.0: + +* misc: enable stalebot (Saúl Ibarra Corretgé) + +* win: map ERROR_ENVVAR_NOT_FOUND to UV_ENOENT (cjihrig) + +* win: use L'\0' as UTF-16 null terminator (cjihrig) + +* win: support retrieving empty env variables (cjihrig) + +* unix,stream: fix returned error codes (Santiago Gimeno) + +* test: fix typo in DYLD_LIBRARY_PATH (Ben Noordhuis) + +* unix,signal: keep handle active if pending signal (Santiago Gimeno) + +* openbsd: fix uv_cpu_info (Santiago Gimeno) + +* src: move uv_free_cpu_info to uv-common.c (Santiago Gimeno) + +* tcp: add uv_tcp_close_reset method (Santiago Gimeno) + +* test: fix udp-multicast-join tests (Santiago Gimeno) + +* test: remove assertion in fs_statfs test (cjihrig) + +* doc: clarify uv_buf_t usage in uv_alloc_cb (Tomas Krizek) + +* win: fix typo in preprocessor expression (Konstantin Podsvirov) + +* timer: fix uv_timer_start on closing timer (seny) + +* udp: add source-specific multicast support (Vladimir Karnushin) + +* udp: fix error return values (Santiago Gimeno) + +* udp: drop IPV6_SSM_SUPPORT macro (Santiago Gimeno) + +* udp: fix uv__udp_set_source_membership6 (Santiago Gimeno) + +* udp: use sockaddr_storage instead of union (Santiago Gimeno) + +* build,zos: add _OPEN_SYS_SOCK_EXT3 flag (Santiago Gimeno) + +* test: add specific source multicast tests (Santiago Gimeno) + +* include: map EILSEQ error code (cjihrig) + +* win, tty: improve SIGWINCH performance (Bartosz Sosnowski) + +* build: fix ios build error (MaYuming) + +* aix: replace ECONNRESET with EOF if already closed (Milad Farazmand) + +* build: add cmake library VERSION, SOVERSION (Eneas U de Queiroz) + +* build: make include/ public in CMakeLists.txt (Ben Noordhuis) + +* build: export USING_UV_SHARED=1 to cmake deps (Ben Noordhuis) + +* build: cmake_minimum_required(VERSION 2.8.12) (Daniel Hahler) + +* aix: Fix broken cmpxchgi() XL C++ specialization. (Andrew Paprocki) + +* test: fix -Wsign-compare warning (Ben Noordhuis) + +* unix: simplify open(O_CLOEXEC) feature detection (Ben Noordhuis) + +* unix: fix UV_FS_O_DIRECT definition on Linux (Joran Dirk Greef) + +* doc: uv_handle_t documentation suggestion (Daniel Bevenius) + + 2019.08.10, Version 1.31.0 (Stable), 0a6771cee4c15184c924bfe9d397bdd0c3b206ba Changes since version 1.30.1: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index 6b11c9349ce9dc..099b0efb084343 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -248,6 +248,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-shutdown-eof.c \ test/test-shutdown-twice.c \ test/test-signal-multiple-loops.c \ + test/test-signal-pending-on-close.c \ test/test-signal.c \ test/test-socket-buffer-size.c \ test/test-spawn.c \ @@ -259,6 +260,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-tcp-close-accept.c \ test/test-tcp-close-while-connecting.c \ test/test-tcp-close.c \ + test/test-tcp-close-reset.c \ test/test-tcp-create-socket-early.c \ test/test-tcp-connect-error-after-write.c \ test/test-tcp-connect-error.c \ @@ -517,6 +519,7 @@ libuv_la_CFLAGS += -D_UNIX03_THREADS \ -D_XOPEN_SOURCE_EXTENDED \ -D_ALL_SOURCE \ -D_LARGE_TIME_API \ + -D_OPEN_SYS_SOCK_EXT3 \ -D_OPEN_SYS_SOCK_IPV6 \ -D_OPEN_SYS_FILE_EXT \ -DUV_PLATFORM_SEM_T=int \ diff --git a/deps/uv/README.md b/deps/uv/README.md index b55c3a9238a1d1..f9daaa1cea153c 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -401,6 +401,8 @@ Check the [SUPPORTED_PLATFORMS file](SUPPORTED_PLATFORMS.md). ### AIX Notes +AIX compilation using IBM XL C/C++ requires version 12.1 or greater. + AIX support for filesystem events requires the non-default IBM `bos.ahafs` package to be installed. This package provides the AIX Event Infrastructure that is detected by `autoconf`. diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index c5e29fef849e4e..b503e538298dd9 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.31.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.32.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]) diff --git a/deps/uv/docs/src/handle.rst b/deps/uv/docs/src/handle.rst index 544794db06c956..0a25bfa8b27dd1 100644 --- a/deps/uv/docs/src/handle.rst +++ b/deps/uv/docs/src/handle.rst @@ -60,6 +60,9 @@ Data types a ``UV_ENOBUFS`` error will be triggered in the :c:type:`uv_udp_recv_cb` or the :c:type:`uv_read_cb` callback. + Each buffer is used only once and the user is responsible for freeing it in the + :c:type:`uv_udp_recv_cb` or the :c:type:`uv_read_cb` callback. + A suggested size (65536 at the moment in most cases) is provided, but it's just an indication, not related in any way to the pending data to be read. The user is free to allocate the amount of memory they decide. @@ -87,7 +90,7 @@ Public members .. c:member:: uv_loop_t* uv_handle_t.loop - Pointer to the :c:type:`uv_loop_t` where the handle is running on. Readonly. + Pointer to the :c:type:`uv_loop_t` the handle is running on. Readonly. .. c:member:: uv_handle_type uv_handle_t.type diff --git a/deps/uv/docs/src/signal.rst b/deps/uv/docs/src/signal.rst index f5a809ab0bb73d..eeadb95b0a47d4 100644 --- a/deps/uv/docs/src/signal.rst +++ b/deps/uv/docs/src/signal.rst @@ -20,6 +20,15 @@ Reception of some signals is emulated: program is given approximately 10 seconds to perform cleanup. After that Windows will unconditionally terminate it. +* SIGWINCH is raised whenever libuv detects that the console has been + resized. When a libuv app is running under a console emulator, or when a + 32-bit libuv app is running on 64-bit system, SIGWINCH will be emulated. In + such cases SIGWINCH signals may not always be delivered in a timely manner. + For a writable :c:type:`uv_tty_t` handle libuv will only detect size changes + when the cursor is moved. When a readable :c:type:`uv_tty_t` handle is used, + resizing of the console buffer will be detected only if the handle is in raw + mode and is being read. + * Watchers for other signals can be successfully created, but these signals are never received. These signals are: `SIGILL`, `SIGABRT`, `SIGFPE`, `SIGSEGV`, `SIGTERM` and `SIGKILL.` @@ -28,6 +37,8 @@ Reception of some signals is emulated: not detected by libuv; these will not trigger a signal watcher. .. versionchanged:: 1.15.0 SIGWINCH support on Windows was improved. +.. versionchanged:: 1.31.0 32-bit libuv SIGWINCH support on 64-bit Windows was + rolled back to old implementation. Unix notes ---------- diff --git a/deps/uv/docs/src/stream.rst b/deps/uv/docs/src/stream.rst index 6a704367b1b361..2ccb59b51cb432 100644 --- a/deps/uv/docs/src/stream.rst +++ b/deps/uv/docs/src/stream.rst @@ -50,8 +50,8 @@ Data types from the stream again is undefined. The callee is responsible for freeing the buffer, libuv does not reuse it. - The buffer may be a null buffer (where buf->base=NULL and buf->len=0) on - error. + The buffer may be a null buffer (where `buf->base` == NULL and `buf->len` == 0) + on error. .. c:type:: void (*uv_write_cb)(uv_write_t* req, int status) diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst index d20a6362af94d5..bcb163ea0f0356 100644 --- a/deps/uv/docs/src/tcp.rst +++ b/deps/uv/docs/src/tcp.rst @@ -113,3 +113,13 @@ API mapping .. seealso:: The :c:type:`uv_stream_t` API functions also apply. + +.. c:function:: int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) + + Resets a TCP connection by sending a RST packet. This is accomplished by + setting the `SO_LINGER` socket option with a linger interval of zero and + then calling :c:func:`uv_close`. + Due to some platform inconsistencies, mixing of :c:func:`uv_shutdown` and + :c:func:`uv_tcp_close_reset` calls is not allowed. + + .. versionadded:: 1.32.0 diff --git a/deps/uv/docs/src/udp.rst b/deps/uv/docs/src/udp.rst index f3de53fbab0568..53b1fea4933aae 100644 --- a/deps/uv/docs/src/udp.rst +++ b/deps/uv/docs/src/udp.rst @@ -56,16 +56,19 @@ Data types * `handle`: UDP handle * `nread`: Number of bytes that have been received. - 0 if there is no more data to read. You may discard or repurpose - the read buffer. Note that 0 may also mean that an empty datagram - was received (in this case `addr` is not NULL). < 0 if a transmission - error was detected. + 0 if there is no more data to read. Note that 0 may also mean that an + empty datagram was received (in this case `addr` is not NULL). < 0 if + a transmission error was detected. * `buf`: :c:type:`uv_buf_t` with the received data. * `addr`: ``struct sockaddr*`` containing the address of the sender. Can be NULL. Valid for the duration of the callback only. * `flags`: One or more or'ed UV_UDP_* constants. Right now only ``UV_UDP_PARTIAL`` is used. + The callee is responsible for freeing the buffer, libuv does not reuse it. + The buffer may be a null buffer (where `buf->base` == NULL and `buf->len` == 0) + on error. + .. note:: The receive callback will be called with `nread` == 0 and `addr` == NULL when there is nothing to read, and with `nread` == 0 and `addr` != NULL when an empty UDP packet is @@ -219,6 +222,25 @@ API :returns: 0 on success, or an error code < 0 on failure. +.. c:function:: int uv_udp_set_source_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, const char* source_addr, uv_membership membership) + + Set membership for a source-specific multicast group. + + :param handle: UDP handle. Should have been initialized with + :c:func:`uv_udp_init`. + + :param multicast_addr: Multicast address to set membership for. + + :param interface_addr: Interface address. + + :param source_addr: Source address. + + :param membership: Should be ``UV_JOIN_GROUP`` or ``UV_LEAVE_GROUP``. + + :returns: 0 on success, or an error code < 0 on failure. + + .. versionadded:: 1.32.0 + .. c:function:: int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) Set IP multicast loop flag. Makes multicast packets loop back to diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index f71767b6e9fab5..ee45bcaefce1d3 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -27,6 +27,10 @@ extern "C" { #endif +#if defined(BUILDING_UV_SHARED) && defined(USING_UV_SHARED) +#error "Define either BUILDING_UV_SHARED or USING_UV_SHARED, not both." +#endif + #ifdef _WIN32 /* Windows - set up dll import/export decorators. */ # if defined(BUILDING_UV_SHARED) @@ -143,6 +147,7 @@ extern "C" { XX(EREMOTEIO, "remote I/O error") \ XX(ENOTTY, "inappropriate ioctl for device") \ XX(EFTYPE, "inappropriate file type or format") \ + XX(EILSEQ, "illegal byte sequence") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ @@ -559,6 +564,7 @@ UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle, UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle, struct sockaddr* name, int* namelen); +UV_EXTERN int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb); UV_EXTERN int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, const struct sockaddr* addr, @@ -645,6 +651,11 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, uv_membership membership); +UV_EXTERN int uv_udp_set_source_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + const char* source_addr, + uv_membership membership); UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on); UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl); UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle, diff --git a/deps/uv/include/uv/errno.h b/deps/uv/include/uv/errno.h index 8eeb95de31b065..165fd11c376a1c 100644 --- a/deps/uv/include/uv/errno.h +++ b/deps/uv/include/uv/errno.h @@ -439,5 +439,10 @@ # define UV__EFTYPE (-4028) #endif +#if defined(EILSEQ) && !defined(_WIN32) +# define UV__EILSEQ UV__ERR(EILSEQ) +#else +# define UV__EILSEQ (-4027) +#endif #endif /* UV_ERRNO_H_ */ diff --git a/deps/uv/include/uv/unix.h b/deps/uv/include/uv/unix.h index 9080352d31dfc0..3a131638f77606 100644 --- a/deps/uv/include/uv/unix.h +++ b/deps/uv/include/uv/unix.h @@ -405,11 +405,25 @@ typedef struct { #else # define UV_FS_O_CREAT 0 #endif -#if defined(O_DIRECT) + +#if defined(__linux__) && defined(__arm__) +# define UV_FS_O_DIRECT 0x10000 +#elif defined(__linux__) && defined(__m68k__) +# define UV_FS_O_DIRECT 0x10000 +#elif defined(__linux__) && defined(__mips__) +# define UV_FS_O_DIRECT 0x08000 +#elif defined(__linux__) && defined(__powerpc__) +# define UV_FS_O_DIRECT 0x20000 +#elif defined(__linux__) && defined(__s390x__) +# define UV_FS_O_DIRECT 0x04000 +#elif defined(__linux__) && defined(__x86_64__) +# define UV_FS_O_DIRECT 0x04000 +#elif defined(O_DIRECT) # define UV_FS_O_DIRECT O_DIRECT #else # define UV_FS_O_DIRECT 0 #endif + #if defined(O_DIRECTORY) # define UV_FS_O_DIRECTORY O_DIRECTORY #else diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index 37a6a445b8d0da..928647b8200502 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 31 +#define UV_VERSION_MINOR 32 #define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/src/timer.c b/deps/uv/src/timer.c index dd78bcbad9a986..8fce7f6472f9fd 100644 --- a/deps/uv/src/timer.c +++ b/deps/uv/src/timer.c @@ -74,7 +74,7 @@ int uv_timer_start(uv_timer_t* handle, uint64_t repeat) { uint64_t clamped_timeout; - if (cb == NULL) + if (uv__is_closing(handle) || cb == NULL) return UV_EINVAL; if (uv__is_active(handle)) diff --git a/deps/uv/src/unix/aix-common.c b/deps/uv/src/unix/aix-common.c index 63ac16a03431e6..b9d313c0c5d7cb 100644 --- a/deps/uv/src/unix/aix-common.c +++ b/deps/uv/src/unix/aix-common.c @@ -155,16 +155,6 @@ int uv_exepath(char* buffer, size_t* size) { } } -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; ++i) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} - int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; diff --git a/deps/uv/src/unix/atomic-ops.h b/deps/uv/src/unix/atomic-ops.h index 541a6c864882a0..bc37c0d45d159c 100644 --- a/deps/uv/src/unix/atomic-ops.h +++ b/deps/uv/src/unix/atomic-ops.h @@ -36,10 +36,6 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) { : "r" (newval), "0" (oldval) : "memory"); return out; -#elif defined(_AIX) && defined(__xlC__) - const int out = (*(volatile int*) ptr); - __compare_and_swap(ptr, &oldval, newval); - return out; #elif defined(__MVS__) unsigned int op4; if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index f4b94e30cc0049..366c43c2ab0843 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include /* O_CLOEXEC */ #include #include #include @@ -49,17 +49,19 @@ # include #endif -#ifdef __APPLE__ +#if defined(__APPLE__) +# include +# endif /* defined(__APPLE__) */ + + +#if defined(__APPLE__) && !TARGET_OS_IPHONE # include # include /* _NSGetExecutablePath */ -# include -# if defined(O_CLOEXEC) -# define UV__O_CLOEXEC O_CLOEXEC -# endif # define environ (*_NSGetEnviron()) -#else +#else /* defined(__APPLE__) && !TARGET_OS_IPHONE */ extern char** environ; -#endif +#endif /* !(defined(__APPLE__) && !TARGET_OS_IPHONE) */ + #if defined(__DragonFly__) || \ defined(__FreeBSD__) || \ @@ -68,7 +70,6 @@ extern char** environ; # include # include # include -# define UV__O_CLOEXEC O_CLOEXEC # if defined(__FreeBSD__) && __FreeBSD__ >= 10 # define uv__accept4 accept4 # endif @@ -1000,24 +1001,17 @@ int uv_getrusage(uv_rusage_t* rusage) { int uv__open_cloexec(const char* path, int flags) { - int err; +#if defined(O_CLOEXEC) int fd; -#if defined(UV__O_CLOEXEC) - static int no_cloexec; - - if (!no_cloexec) { - fd = open(path, flags | UV__O_CLOEXEC); - if (fd != -1) - return fd; - - if (errno != EINVAL) - return UV__ERR(errno); + fd = open(path, flags | O_CLOEXEC); + if (fd == -1) + return UV__ERR(errno); - /* O_CLOEXEC not supported. */ - no_cloexec = 1; - } -#endif + return fd; +#else /* O_CLOEXEC */ + int err; + int fd; fd = open(path, flags); if (fd == -1) @@ -1030,6 +1024,7 @@ int uv__open_cloexec(const char* path, int flags) { } return fd; +#endif /* O_CLOEXEC */ } @@ -1051,7 +1046,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { static int no_dup3; if (!no_dup3) { do - r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); + r = uv__dup3(oldfd, newfd, O_CLOEXEC); while (r == -1 && errno == EBUSY); if (r != -1) return r; diff --git a/deps/uv/src/unix/cygwin.c b/deps/uv/src/unix/cygwin.c index 6b5cfb7ba5b817..169958d55f2ed0 100644 --- a/deps/uv/src/unix/cygwin.c +++ b/deps/uv/src/unix/cygwin.c @@ -48,11 +48,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { return UV_ENOSYS; } -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - (void)cpu_infos; - (void)count; -} - uint64_t uv_get_constrained_memory(void) { return 0; /* Memory constraints are unknown. */ } diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index e4cd8ff7e0cf99..5cf03aea0b4054 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -223,14 +223,3 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { return 0; } - - -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index 7de88d6a52faf6..d0b7d8e9d11f95 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -288,14 +288,3 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uv__free(cp_times); return 0; } - - -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index fc80d00d5c563e..fd3dd4c287e9ba 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -255,20 +255,10 @@ static ssize_t uv__fs_mkdtemp(uv_fs_t* req) { static ssize_t uv__fs_open(uv_fs_t* req) { - static int no_cloexec_support; - int r; - - /* Try O_CLOEXEC before entering locks */ - if (no_cloexec_support == 0) { #ifdef O_CLOEXEC - r = open(req->path, req->flags | O_CLOEXEC, req->mode); - if (r >= 0) - return r; - if (errno != EINVAL) - return r; - no_cloexec_support = 1; -#endif /* O_CLOEXEC */ - } + return open(req->path, req->flags | O_CLOEXEC, req->mode); +#else /* O_CLOEXEC */ + int r; if (req->cb != NULL) uv_rwlock_rdlock(&req->loop->cloexec_lock); @@ -289,6 +279,7 @@ static ssize_t uv__fs_open(uv_fs_t* req) { uv_rwlock_rdunlock(&req->loop->cloexec_lock); return r; +#endif /* O_CLOEXEC */ } diff --git a/deps/uv/src/unix/haiku.c b/deps/uv/src/unix/haiku.c index 7708851c2a5fa9..cf17d836b4c7e8 100644 --- a/deps/uv/src/unix/haiku.c +++ b/deps/uv/src/unix/haiku.c @@ -165,12 +165,3 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { return 0; } - -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; i++) - uv__free(cpu_infos[i].model); - - uv__free(cpu_infos); -} diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index b539beb86ae576..433e201fe19dbf 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -812,16 +812,6 @@ static uint64_t read_cpufreq(unsigned int cpunum) { } -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} - static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) return 1; diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c index c649bb375f32a1..cfe2c6a49dc3c7 100644 --- a/deps/uv/src/unix/netbsd.c +++ b/deps/uv/src/unix/netbsd.c @@ -234,14 +234,3 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { uv__free(cp_times); return 0; } - - -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index b5cdc80c3e92fe..1f5228dc13fd7a 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -202,14 +202,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { if (!(*cpu_infos)) return UV_ENOMEM; + i = 0; *count = numcpus; which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); - if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { - uv__free(*cpu_infos); - return UV__ERR(errno); - } + if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) + goto error; size = sizeof(info); which[0] = CTL_KERN; @@ -217,10 +216,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { for (i = 0; i < numcpus; i++) { which[2] = i; size = sizeof(info); - if (sysctl(which, 3, &info, &size, NULL, 0)) { - uv__free(*cpu_infos); - return UV__ERR(errno); - } + if (sysctl(which, 3, &info, &size, NULL, 0)) + goto error; cpu_info = &(*cpu_infos)[i]; @@ -235,15 +232,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } return 0; -} +error: + *count = 0; + for (j = 0; j < i; j++) + uv__free((*cpu_infos)[j].model); -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); + uv__free(*cpu_infos); + *cpu_infos = NULL; + return UV__ERR(errno); } diff --git a/deps/uv/src/unix/os390.c b/deps/uv/src/unix/os390.c index 273ded7ca5e81c..a7305006c1756d 100644 --- a/deps/uv/src/unix/os390.c +++ b/deps/uv/src/unix/os390.c @@ -433,13 +433,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - for (int i = 0; i < count; ++i) - uv__free(cpu_infos[i].model); - uv__free(cpu_infos); -} - - static int uv__interface_addresses_v6(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index 5e89ded2d842ce..3a257f04b57807 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -477,9 +477,11 @@ static void uv__signal_event(uv_loop_t* loop, * yet dispatched, the uv__finish_close was deferred. Make close pending * now if this has happened. */ - if ((handle->flags & UV_HANDLE_CLOSING) && - (handle->caught_signals == handle->dispatched_signals)) { - uv__make_close_pending((uv_handle_t*) handle); + if (handle->caught_signals == handle->dispatched_signals) { + if (handle->signum == 0) + uv__handle_stop(handle); + if (handle->flags & UV_HANDLE_CLOSING) + uv__make_close_pending((uv_handle_t*) handle); } } @@ -569,5 +571,6 @@ static void uv__signal_stop(uv_signal_t* handle) { uv__signal_unlock_and_unblock(&saved_sigmask); handle->signum = 0; - uv__handle_stop(handle); + if (handle->caught_signals == handle->dispatched_signals) + uv__handle_stop(handle); } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 9de01e3c78403e..78ce8e84870e8e 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -1180,6 +1180,10 @@ static void uv__read(uv_stream_t* stream) { } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) { uv__stream_eof(stream, &buf); return; +#elif defined(_AIX) + } else if (errno == ECONNRESET && (stream->flags & UV_DISCONNECT)) { + uv__stream_eof(stream, &buf); + return; #endif } else { /* Error. User should call uv_close(). */ @@ -1403,7 +1407,7 @@ int uv_write2(uv_write_t* req, return UV_EBADF; if (!(stream->flags & UV_HANDLE_WRITABLE)) - return -EPIPE; + return UV_EPIPE; if (send_handle) { if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc) @@ -1557,7 +1561,7 @@ int uv_read_start(uv_stream_t* stream, return UV_EINVAL; if (!(stream->flags & UV_HANDLE_READABLE)) - return -ENOTCONN; + return UV_ENOTCONN; /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index f323d1defdef98..180cc84651db37 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -696,16 +696,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} - #ifdef SUNOS_NO_IFADDRS int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { *count = 0; diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 8cedcd6027be52..fa660f1381315e 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -308,6 +308,23 @@ int uv_tcp_getpeername(const uv_tcp_t* handle, } +int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { + int fd; + struct linger l = { 1, 0 }; + + /* Disallow setting SO_LINGER to zero due to some platform inconsistencies */ + if (handle->flags & UV_HANDLE_SHUTTING) + return UV_EINVAL; + + fd = uv__stream_fd(handle); + if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) + return UV__ERR(errno); + + uv_close((uv_handle_t*) handle, close_cb); + return 0; +} + + int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { static int single_accept = -1; unsigned long flags; diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index b578e7bc1037ef..dba8eff8382edd 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -659,6 +659,98 @@ static int uv__udp_set_membership6(uv_udp_t* handle, } +static int uv__udp_set_source_membership4(uv_udp_t* handle, + const struct sockaddr_in* multicast_addr, + const char* interface_addr, + const struct sockaddr_in* source_addr, + uv_membership membership) { + struct ip_mreq_source mreq; + int optname; + int err; + + err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR); + if (err) + return err; + + memset(&mreq, 0, sizeof(mreq)); + + if (interface_addr != NULL) { + err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr); + if (err) + return err; + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr; + mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr; + + if (membership == UV_JOIN_GROUP) + optname = IP_ADD_SOURCE_MEMBERSHIP; + else if (membership == UV_LEAVE_GROUP) + optname = IP_DROP_SOURCE_MEMBERSHIP; + else + return UV_EINVAL; + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IP, + optname, + &mreq, + sizeof(mreq))) { + return UV__ERR(errno); + } + + return 0; +} + + +static int uv__udp_set_source_membership6(uv_udp_t* handle, + const struct sockaddr_in6* multicast_addr, + const char* interface_addr, + const struct sockaddr_in6* source_addr, + uv_membership membership) { + struct group_source_req mreq; + struct sockaddr_in6 addr6; + int optname; + int err; + + err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR); + if (err) + return err; + + memset(&mreq, 0, sizeof(mreq)); + + if (interface_addr != NULL) { + err = uv_ip6_addr(interface_addr, 0, &addr6); + if (err) + return err; + mreq.gsr_interface = addr6.sin6_scope_id; + } else { + mreq.gsr_interface = 0; + } + + memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group)); + memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source)); + + if (membership == UV_JOIN_GROUP) + optname = MCAST_JOIN_SOURCE_GROUP; + else if (membership == UV_LEAVE_GROUP) + optname = MCAST_LEAVE_SOURCE_GROUP; + else + return UV_EINVAL; + + if (setsockopt(handle->io_watcher.fd, + IPPROTO_IPV6, + optname, + &mreq, + sizeof(mreq))) { + return UV__ERR(errno); + } + + return 0; +} + + int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) { int domain; int err; @@ -748,6 +840,51 @@ int uv_udp_set_membership(uv_udp_t* handle, } } + +int uv_udp_set_source_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + const char* source_addr, + uv_membership membership) { + int err; + struct sockaddr_storage mcast_addr; + struct sockaddr_in* mcast_addr4; + struct sockaddr_in6* mcast_addr6; + struct sockaddr_storage src_addr; + struct sockaddr_in* src_addr4; + struct sockaddr_in6* src_addr6; + + mcast_addr4 = (struct sockaddr_in*)&mcast_addr; + mcast_addr6 = (struct sockaddr_in6*)&mcast_addr; + src_addr4 = (struct sockaddr_in*)&src_addr; + src_addr6 = (struct sockaddr_in6*)&src_addr; + + err = uv_ip4_addr(multicast_addr, 0, mcast_addr4); + if (err) { + err = uv_ip6_addr(multicast_addr, 0, mcast_addr6); + if (err) + return err; + err = uv_ip6_addr(source_addr, 0, src_addr6); + if (err) + return err; + return uv__udp_set_source_membership6(handle, + mcast_addr6, + interface_addr, + src_addr6, + membership); + } + + err = uv_ip4_addr(source_addr, 0, src_addr4); + if (err) + return err; + return uv__udp_set_source_membership4(handle, + mcast_addr4, + interface_addr, + src_addr4, + membership); +} + + static int uv__setsockopt(uv_udp_t* handle, int option4, int option6, diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index d1a5e2fbe6b77e..70db53ab04dacf 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -797,3 +797,13 @@ void uv_os_free_environ(uv_env_item_t* envitems, int count) { uv__free(envitems); } + + +void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { + int i; + + for (i = 0; i < count; i++) + uv__free(cpu_infos[i].model); + + uv__free(cpu_infos); +} diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 24924ba81ef3b2..32ac5e596fea82 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -132,6 +132,7 @@ int uv_translate_sys_error(int sys_errno) { case WSAENOBUFS: return UV_ENOBUFS; case ERROR_BAD_PATHNAME: return UV_ENOENT; case ERROR_DIRECTORY: return UV_ENOENT; + case ERROR_ENVVAR_NOT_FOUND: return UV_ENOENT; case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_INVALID_NAME: return UV_ENOENT; case ERROR_INVALID_DRIVE: return UV_ENOENT; diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 7656627e902da0..46a0709a38e3bd 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -198,8 +198,10 @@ int uv_try_write(uv_stream_t* stream, int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { uv_loop_t* loop = handle->loop; - if (!(handle->flags & UV_HANDLE_WRITABLE)) { - return UV_EPIPE; + if (!(handle->flags & UV_HANDLE_WRITABLE) || + handle->flags & UV_HANDLE_SHUTTING || + uv__is_closing(handle)) { + return UV_ENOTCONN; } UV_REQ_INIT(req, UV_SHUTDOWN); @@ -207,6 +209,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { req->cb = cb; handle->flags &= ~UV_HANDLE_WRITABLE; + handle->flags |= UV_HANDLE_SHUTTING; handle->stream.conn.shutdown_req = req; handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index f2cb5271b8d77d..81e48136a3b9ef 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -549,6 +549,21 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { } +int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) { + struct linger l = { 1, 0 }; + + /* Disallow setting SO_LINGER to zero due to some platform inconsistencies */ + if (handle->flags & UV_HANDLE_SHUTTING) + return UV_EINVAL; + + if (0 != setsockopt(handle->socket, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) + return uv_translate_sys_error(WSAGetLastError()); + + uv_close((uv_handle_t*) handle, close_cb); + return 0; +} + + int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { unsigned int i, simultaneous_accepts; uv_tcp_accept_t* req; diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 07436dc804f0f1..8f84bcd0e45544 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -120,6 +120,8 @@ static int uv_tty_virtual_width = -1; static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE; static int uv__tty_console_height = -1; static int uv__tty_console_width = -1; +static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE; +static uv_mutex_t uv__tty_console_resize_mutex; static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param); static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, @@ -129,6 +131,8 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime); +static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param); +static void uv__tty_console_signal_resize(void); /* We use a semaphore rather than a mutex or critical section because in some cases (uv__cancel_read_console) we need take the lock in the main thread and @@ -168,6 +172,7 @@ void uv_console_init(void) { QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, NULL, WT_EXECUTELONGFUNCTION); + uv_mutex_init(&uv__tty_console_resize_mutex); } } @@ -728,6 +733,12 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, } records_left--; + /* We might be not subscribed to EVENT_CONSOLE_LAYOUT or we might be + * running under some TTY emulator that does not send those events. */ + if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) { + uv__tty_console_signal_resize(); + } + /* Ignore other events that are not key events. */ if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) { continue; @@ -2299,15 +2310,24 @@ static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) { sizeof(conhost_pid), NULL); - if (!NT_SUCCESS(status)) + if (!NT_SUCCESS(status)) { /* We couldn't retrieve our console host process, probably because this * is a 32-bit process running on 64-bit Windows. Fall back to receiving - * console events from all processes. */ - conhost_pid = 0; + * console events from the input stream only. */ + return 0; + } /* Ensure the PID is a multiple of 4, which is required by SetWinEventHook */ conhost_pid &= ~(ULONG_PTR)0x3; + uv__tty_console_resized = CreateEvent(NULL, TRUE, FALSE, NULL); + if (uv__tty_console_resized == NULL) + return 0; + if (QueueUserWorkItem(uv__tty_console_resize_watcher_thread, + NULL, + WT_EXECUTELONGFUNCTION) == 0) + return 0; + if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT, EVENT_CONSOLE_LAYOUT, NULL, @@ -2331,6 +2351,20 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) { + SetEvent(uv__tty_console_resized); +} + +static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) { + for (;;) { + /* Make sure to not overwhelm the system with resize events */ + Sleep(33); + WaitForSingleObject(uv__tty_console_resized, INFINITE); + uv__tty_console_signal_resize(); + ResetEvent(uv__tty_console_resized); + } +} + +static void uv__tty_console_signal_resize(void) { CONSOLE_SCREEN_BUFFER_INFO sb_info; int width, height; @@ -2340,9 +2374,13 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook, width = sb_info.dwSize.X; height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1; + uv_mutex_lock(&uv__tty_console_resize_mutex); if (width != uv__tty_console_width || height != uv__tty_console_height) { uv__tty_console_width = width; uv__tty_console_height = height; + uv_mutex_unlock(&uv__tty_console_resize_mutex); uv__signal_dispatch(SIGWINCH); + } else { + uv_mutex_unlock(&uv__tty_console_resize_mutex); } } diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 8aeeab3b4628c3..39fc34d3bfcd94 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -702,6 +702,112 @@ int uv__udp_set_membership6(uv_udp_t* handle, } +static int uv__udp_set_source_membership4(uv_udp_t* handle, + const struct sockaddr_in* multicast_addr, + const char* interface_addr, + const struct sockaddr_in* source_addr, + uv_membership membership) { + struct ip_mreq_source mreq; + int optname; + int err; + + if (handle->flags & UV_HANDLE_IPV6) + return UV_EINVAL; + + /* If the socket is unbound, bind to inaddr_any. */ + err = uv_udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip4_any_, + sizeof(uv_addr_ip4_any_), + UV_UDP_REUSEADDR); + if (err) + return uv_translate_sys_error(err); + + memset(&mreq, 0, sizeof(mreq)); + + if (interface_addr != NULL) { + err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr); + if (err) + return err; + } else { + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + } + + mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr; + mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr; + + if (membership == UV_JOIN_GROUP) + optname = IP_ADD_SOURCE_MEMBERSHIP; + else if (membership == UV_LEAVE_GROUP) + optname = IP_DROP_SOURCE_MEMBERSHIP; + else + return UV_EINVAL; + + if (setsockopt(handle->socket, + IPPROTO_IP, + optname, + (char*) &mreq, + sizeof(mreq)) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + +int uv__udp_set_source_membership6(uv_udp_t* handle, + const struct sockaddr_in6* multicast_addr, + const char* interface_addr, + const struct sockaddr_in6* source_addr, + uv_membership membership) { + struct group_source_req mreq; + struct sockaddr_in6 addr6; + int optname; + int err; + + if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6)) + return UV_EINVAL; + + err = uv_udp_maybe_bind(handle, + (const struct sockaddr*) &uv_addr_ip6_any_, + sizeof(uv_addr_ip6_any_), + UV_UDP_REUSEADDR); + + if (err) + return uv_translate_sys_error(err); + + memset(&mreq, 0, sizeof(mreq)); + + if (interface_addr != NULL) { + err = uv_ip6_addr(interface_addr, 0, &addr6); + if (err) + return err; + mreq.gsr_interface = addr6.sin6_scope_id; + } else { + mreq.gsr_interface = 0; + } + + memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group)); + memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source)); + + if (membership == UV_JOIN_GROUP) + optname = MCAST_JOIN_SOURCE_GROUP; + else if (membership == UV_LEAVE_GROUP) + optname = MCAST_LEAVE_SOURCE_GROUP; + else + return UV_EINVAL; + + if (setsockopt(handle->socket, + IPPROTO_IPV6, + optname, + (char*) &mreq, + sizeof(mreq)) == SOCKET_ERROR) { + return uv_translate_sys_error(WSAGetLastError()); + } + + return 0; +} + + int uv_udp_set_membership(uv_udp_t* handle, const char* multicast_addr, const char* interface_addr, @@ -718,6 +824,50 @@ int uv_udp_set_membership(uv_udp_t* handle, } +int uv_udp_set_source_membership(uv_udp_t* handle, + const char* multicast_addr, + const char* interface_addr, + const char* source_addr, + uv_membership membership) { + int err; + struct sockaddr_storage mcast_addr; + struct sockaddr_in* mcast_addr4; + struct sockaddr_in6* mcast_addr6; + struct sockaddr_storage src_addr; + struct sockaddr_in* src_addr4; + struct sockaddr_in6* src_addr6; + + mcast_addr4 = (struct sockaddr_in*)&mcast_addr; + mcast_addr6 = (struct sockaddr_in6*)&mcast_addr; + src_addr4 = (struct sockaddr_in*)&src_addr; + src_addr6 = (struct sockaddr_in6*)&src_addr; + + err = uv_ip4_addr(multicast_addr, 0, mcast_addr4); + if (err) { + err = uv_ip6_addr(multicast_addr, 0, mcast_addr6); + if (err) + return err; + err = uv_ip6_addr(source_addr, 0, src_addr6); + if (err) + return err; + return uv__udp_set_source_membership6(handle, + mcast_addr6, + interface_addr, + src_addr6, + membership); + } + + err = uv_ip4_addr(source_addr, 0, src_addr4); + if (err) + return err; + return uv__udp_set_source_membership4(handle, + mcast_addr4, + interface_addr, + src_addr4, + membership); +} + + int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) { struct sockaddr_storage addr_st; struct sockaddr_in* addr4; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 359a16aed4bb27..8849d041bf0283 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -721,17 +721,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { } -void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { - int i; - - for (i = 0; i < count; i++) { - uv__free(cpu_infos[i].model); - } - - uv__free(cpu_infos); -} - - static int is_windows_version_or_greater(DWORD os_major, DWORD os_minor, WORD service_pack_major, @@ -1325,7 +1314,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) { return uv_translate_sys_error(GetLastError()); } - (*utf16)[bufsize] = '\0'; + (*utf16)[bufsize] = L'\0'; return 0; } @@ -1481,17 +1470,15 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) { if (r != 0) return r; + SetLastError(ERROR_SUCCESS); len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH); uv__free(name_w); assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */ if (len == 0) { r = GetLastError(); - - if (r == ERROR_ENVVAR_NOT_FOUND) - return UV_ENOENT; - - return uv_translate_sys_error(r); + if (r != ERROR_SUCCESS) + return uv_translate_sys_error(r); } /* Check how much space we need */ diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 203393c2e3af03..322a212dd73c19 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4109,7 +4109,7 @@ #endif /* from winternl.h */ -#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_) +#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32__) #define __UNICODE_STRING_DEFINED #endif typedef struct _UNICODE_STRING { diff --git a/deps/uv/test/test-env-vars.c b/deps/uv/test/test-env-vars.c index d7abb4249561a4..3814699356db55 100644 --- a/deps/uv/test/test-env-vars.c +++ b/deps/uv/test/test-env-vars.c @@ -88,6 +88,15 @@ TEST_IMPL(env_vars) { r = uv_os_unsetenv(name); ASSERT(r == 0); + /* Setting an environment variable to the empty string does not delete it. */ + r = uv_os_setenv(name, ""); + ASSERT(r == 0); + size = BUF_SIZE; + r = uv_os_getenv(name, buf, &size); + ASSERT(r == 0); + ASSERT(size == 0); + ASSERT(strlen(buf) == 0); + /* Check getting all env variables. */ r = uv_os_setenv(name, "123456789"); ASSERT(r == 0); diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 0d92b0d3a0d319..9326c6bc2753f0 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -354,7 +354,7 @@ static void statfs_cb(uv_fs_t* req) { ASSERT(stats->f_files == 0); ASSERT(stats->f_ffree == 0); #else - ASSERT(stats->f_files > 0); + /* There is no assertion for stats->f_files that makes sense, so ignore it. */ ASSERT(stats->f_ffree <= stats->f_files); #endif uv_fs_req_cleanup(req); diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 6eb8ecadc7870f..b6066f27276dc6 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -112,6 +112,10 @@ TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_close_while_connecting) TEST_DECLARE (tcp_close) +TEST_DECLARE (tcp_close_reset_accepted) +TEST_DECLARE (tcp_close_reset_accepted_after_shutdown) +TEST_DECLARE (tcp_close_reset_client) +TEST_DECLARE (tcp_close_reset_client_after_shutdown) TEST_DECLARE (tcp_create_early) TEST_DECLARE (tcp_create_early_bad_bind) TEST_DECLARE (tcp_create_early_bad_domain) @@ -193,6 +197,7 @@ TEST_DECLARE (timer_huge_timeout) TEST_DECLARE (timer_huge_repeat) TEST_DECLARE (timer_run_once) TEST_DECLARE (timer_from_check) +TEST_DECLARE (timer_is_closing) TEST_DECLARE (timer_null_callback) TEST_DECLARE (timer_early_check) TEST_DECLARE (idle_starvation) @@ -445,6 +450,7 @@ TEST_DECLARE (we_get_signals) TEST_DECLARE (we_get_signal_one_shot) TEST_DECLARE (we_get_signals_mixed) TEST_DECLARE (signal_multiple_loops) +TEST_DECLARE (signal_pending_on_close) TEST_DECLARE (closed_fd_events) #endif #ifdef __APPLE__ @@ -623,6 +629,10 @@ TASK_LIST_START TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_close_while_connecting) TEST_ENTRY (tcp_close) + TEST_ENTRY (tcp_close_reset_accepted) + TEST_ENTRY (tcp_close_reset_accepted_after_shutdown) + TEST_ENTRY (tcp_close_reset_client) + TEST_ENTRY (tcp_close_reset_client_after_shutdown) TEST_ENTRY (tcp_create_early) TEST_ENTRY (tcp_create_early_bad_bind) TEST_ENTRY (tcp_create_early_bad_domain) @@ -720,6 +730,7 @@ TASK_LIST_START TEST_ENTRY (timer_huge_repeat) TEST_ENTRY (timer_run_once) TEST_ENTRY (timer_from_check) + TEST_ENTRY (timer_is_closing) TEST_ENTRY (timer_null_callback) TEST_ENTRY (timer_early_check) @@ -886,6 +897,7 @@ TASK_LIST_START TEST_ENTRY (we_get_signal_one_shot) TEST_ENTRY (we_get_signals_mixed) TEST_ENTRY (signal_multiple_loops) + TEST_ENTRY (signal_pending_on_close) TEST_ENTRY (closed_fd_events) #endif diff --git a/deps/uv/test/test-signal-pending-on-close.c b/deps/uv/test/test-signal-pending-on-close.c new file mode 100644 index 00000000000000..bf8d2793d51f01 --- /dev/null +++ b/deps/uv/test/test-signal-pending-on-close.c @@ -0,0 +1,94 @@ +/* Copyright libuv project 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. +*/ +#ifndef _WIN32 + +#include "uv.h" +#include "task.h" + +#include +#include + +static uv_loop_t loop; +static uv_signal_t signal_hdl; +static uv_pipe_t pipe_hdl; +static uv_write_t write_req; +static char* buf; +static int close_cb_called; + + +static void signal_cb(uv_signal_t* signal, int signum) { + ASSERT(0); +} + +static void close_cb(uv_handle_t *handle) { + close_cb_called++; +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == UV_EPIPE); + free(buf); + uv_close((uv_handle_t *) &pipe_hdl, close_cb); + uv_close((uv_handle_t *) &signal_hdl, close_cb); +} + + +TEST_IMPL(signal_pending_on_close) { + int pipefds[2]; + uv_buf_t buffer; + int r; + + ASSERT(0 == uv_loop_init(&loop)); + + ASSERT(0 == uv_signal_init(&loop, &signal_hdl)); + + ASSERT(0 == uv_signal_start(&signal_hdl, signal_cb, SIGPIPE)); + + ASSERT(0 == pipe(pipefds)); + + ASSERT(0 == uv_pipe_init(&loop, &pipe_hdl, 0)); + + ASSERT(0 == uv_pipe_open(&pipe_hdl, pipefds[1])); + + /* Write data large enough so it needs loop iteration */ + buf = malloc(1<<24); + ASSERT(buf != NULL); + memset(buf, '.', 1<<24); + buffer = uv_buf_init(buf, 1<<24); + + r = uv_write(&write_req, (uv_stream_t *) &pipe_hdl, &buffer, 1, write_cb); + ASSERT(0 == r); + + /* cause a SIGPIPE on write in next iteration */ + close(pipefds[0]); + + ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); + + ASSERT(0 == uv_loop_close(&loop)); + + ASSERT(2 == close_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif \ No newline at end of file diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index fec610bfdef97e..be9e2539aa6562 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -240,7 +240,7 @@ TEST_IMPL(spawn_empty_env) { * in the environment, but of course that doesn't work with * the empty environment that we're testing here. */ - if (NULL != getenv("DYLD_LIBARY_PATH") || + if (NULL != getenv("DYLD_LIBRARY_PATH") || NULL != getenv("LD_LIBRARY_PATH")) { RETURN_SKIP("doesn't work with DYLD_LIBRARY_PATH/LD_LIBRARY_PATH"); } diff --git a/deps/uv/test/test-tcp-bind-error.c b/deps/uv/test/test-tcp-bind-error.c index 1456d081ae6374..f95efd9f0c8900 100644 --- a/deps/uv/test/test-tcp-bind-error.c +++ b/deps/uv/test/test-tcp-bind-error.c @@ -239,11 +239,7 @@ TEST_IMPL(tcp_bind_writable_flags) { r = uv_write(&write_req, (uv_stream_t*) &server, &buf, 1, NULL); ASSERT(r == UV_EPIPE); r = uv_shutdown(&shutdown_req, (uv_stream_t*) &server, NULL); -#ifdef _WIN32 - ASSERT(r == UV_EPIPE); -#else ASSERT(r == UV_ENOTCONN); -#endif r = uv_read_start((uv_stream_t*) &server, NULL, NULL); ASSERT(r == UV_ENOTCONN); diff --git a/deps/uv/test/test-tcp-close-reset.c b/deps/uv/test/test-tcp-close-reset.c new file mode 100644 index 00000000000000..7ca55c4c7f984b --- /dev/null +++ b/deps/uv/test/test-tcp-close-reset.c @@ -0,0 +1,290 @@ +/* Copyright libuv project 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 /* memset */ + +static uv_loop_t* loop; +static uv_tcp_t tcp_server; +static uv_tcp_t tcp_client; +static uv_tcp_t tcp_accepted; +static uv_connect_t connect_req; +static uv_shutdown_t shutdown_req; +static uv_write_t write_reqs[4]; + +static int client_close; +static int shutdown_before_close; + +static int write_cb_called; +static int close_cb_called; +static int shutdown_cb_called; + +static void connect_cb(uv_connect_t* req, int status); +static void write_cb(uv_write_t* req, int status); +static void close_cb(uv_handle_t* handle); +static void shutdown_cb(uv_shutdown_t* req, int status); + +static int read_size; + + +static void do_write(uv_tcp_t* handle) { + uv_buf_t buf; + unsigned i; + int r; + + buf = uv_buf_init("PING", 4); + for (i = 0; i < ARRAY_SIZE(write_reqs); i++) { + r = uv_write(&write_reqs[i], (uv_stream_t*) handle, &buf, 1, write_cb); + ASSERT(r == 0); + } +} + + +static void do_close(uv_tcp_t* handle) { + if (shutdown_before_close == 1) { + ASSERT(0 == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb)); + ASSERT(UV_EINVAL == uv_tcp_close_reset(handle, close_cb)); + } else { + ASSERT(0 == uv_tcp_close_reset(handle, close_cb)); + ASSERT(UV_ENOTCONN == uv_shutdown(&shutdown_req, (uv_stream_t*) handle, shutdown_cb)); + } + + uv_close((uv_handle_t*) &tcp_server, NULL); +} + +static void alloc_cb(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + static char slab[1024]; + buf->base = slab; + buf->len = sizeof(slab); +} + +static void read_cb2(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + ASSERT((uv_tcp_t*)stream == &tcp_client); + if (nread == UV_EOF) + uv_close((uv_handle_t*) stream, NULL); +} + + +static void connect_cb(uv_connect_t* conn_req, int status) { + ASSERT(conn_req == &connect_req); + uv_read_start((uv_stream_t*) &tcp_client, alloc_cb, read_cb2); + do_write(&tcp_client); + if (client_close) + do_close(&tcp_client); +} + + +static void write_cb(uv_write_t* req, int status) { + /* write callbacks should run before the close callback */ + ASSERT(close_cb_called == 0); + ASSERT(req->handle == (uv_stream_t*)&tcp_client); + write_cb_called++; +} + + +static void close_cb(uv_handle_t* handle) { + if (client_close) + ASSERT(handle == (uv_handle_t*) &tcp_client); + else + ASSERT(handle == (uv_handle_t*) &tcp_accepted); + + close_cb_called++; +} + +static void shutdown_cb(uv_shutdown_t* req, int status) { + if (client_close) + ASSERT(req->handle == (uv_stream_t*) &tcp_client); + else + ASSERT(req->handle == (uv_stream_t*) &tcp_accepted); + + shutdown_cb_called++; +} + + +static void read_cb(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { + ASSERT((uv_tcp_t*)stream == &tcp_accepted); + if (nread < 0) { + uv_close((uv_handle_t*) stream, NULL); + } else { + read_size += nread; + if (read_size == 16 && client_close == 0) + do_close(&tcp_accepted); + } +} + + +static void connection_cb(uv_stream_t* server, int status) { + ASSERT(status == 0); + + ASSERT(0 == uv_tcp_init(loop, &tcp_accepted)); + ASSERT(0 == uv_accept(server, (uv_stream_t*) &tcp_accepted)); + + uv_read_start((uv_stream_t*) &tcp_accepted, alloc_cb, read_cb); +} + + +static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_init(loop, handle); + ASSERT(r == 0); + + r = uv_tcp_bind(handle, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)handle, 128, connection_cb); + ASSERT(r == 0); +} + + +static void do_connect(uv_loop_t* loop, uv_tcp_t* tcp_client) { + struct sockaddr_in addr; + int r; + + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + + r = uv_tcp_init(loop, tcp_client); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, + tcp_client, + (const struct sockaddr*) &addr, + connect_cb); + ASSERT(r == 0); +} + + +/* Check that pending write requests have their callbacks + * invoked when the handle is closed. + */ +TEST_IMPL(tcp_close_reset_client) { + int r; + + loop = uv_default_loop(); + + start_server(loop, &tcp_server); + + client_close = 1; + shutdown_before_close = 0; + + do_connect(loop, &tcp_client); + + ASSERT(write_cb_called == 0); + ASSERT(close_cb_called == 0); + ASSERT(shutdown_cb_called == 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(write_cb_called == 4); + ASSERT(close_cb_called == 1); + ASSERT(shutdown_cb_called == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tcp_close_reset_client_after_shutdown) { + int r; + + loop = uv_default_loop(); + + start_server(loop, &tcp_server); + + client_close = 1; + shutdown_before_close = 1; + + do_connect(loop, &tcp_client); + + ASSERT(write_cb_called == 0); + ASSERT(close_cb_called == 0); + ASSERT(shutdown_cb_called == 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(write_cb_called == 4); + ASSERT(close_cb_called == 0); + ASSERT(shutdown_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tcp_close_reset_accepted) { + int r; + + loop = uv_default_loop(); + + start_server(loop, &tcp_server); + + client_close = 0; + shutdown_before_close = 0; + + do_connect(loop, &tcp_client); + + ASSERT(write_cb_called == 0); + ASSERT(close_cb_called == 0); + ASSERT(shutdown_cb_called == 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(write_cb_called == 4); + ASSERT(close_cb_called == 1); + ASSERT(shutdown_cb_called == 0); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +TEST_IMPL(tcp_close_reset_accepted_after_shutdown) { + int r; + + loop = uv_default_loop(); + + start_server(loop, &tcp_server); + + client_close = 0; + shutdown_before_close = 1; + + do_connect(loop, &tcp_client); + + ASSERT(write_cb_called == 0); + ASSERT(close_cb_called == 0); + ASSERT(shutdown_cb_called == 0); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(write_cb_called == 4); + ASSERT(close_cb_called == 0); + ASSERT(shutdown_cb_called == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/deps/uv/test/test-timer.c b/deps/uv/test/test-timer.c index 080a73005ee3c2..c667da00ec3af8 100644 --- a/deps/uv/test/test-timer.c +++ b/deps/uv/test/test-timer.c @@ -292,6 +292,19 @@ TEST_IMPL(timer_run_once) { } +TEST_IMPL(timer_is_closing) { + uv_timer_t handle; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); + uv_close((uv_handle_t *)&handle, NULL); + + ASSERT(UV_EINVAL == uv_timer_start(&handle, never_cb, 100, 100)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(timer_null_callback) { uv_timer_t handle; diff --git a/deps/uv/test/test-udp-multicast-join.c b/deps/uv/test/test-udp-multicast-join.c index 053d2f791498f7..9ee80e44e7c24a 100644 --- a/deps/uv/test/test-udp-multicast-join.c +++ b/deps/uv/test/test-udp-multicast-join.c @@ -29,8 +29,12 @@ #define CHECK_HANDLE(handle) \ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) +#define MULTICAST_ADDR "239.255.0.1" + static uv_udp_t server; static uv_udp_t client; +static uv_udp_send_t req; +static uv_udp_send_t req_ss; static int cl_recv_cb_called; @@ -62,7 +66,26 @@ static void sv_send_cb(uv_udp_send_t* req, int status) { sv_send_cb_called++; - uv_close((uv_handle_t*) req->handle, close_cb); + if (sv_send_cb_called == 2) + uv_close((uv_handle_t*) req->handle, close_cb); +} + + +static int do_send(uv_udp_send_t* send_req) { + uv_buf_t buf; + struct sockaddr_in addr; + + buf = uv_buf_init("PING", 4); + + ASSERT(0 == uv_ip4_addr(MULTICAST_ADDR, TEST_PORT, &addr)); + + /* client sends "PING" */ + return uv_udp_send(send_req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + sv_send_cb); } @@ -74,8 +97,6 @@ static void cl_recv_cb(uv_udp_t* handle, CHECK_HANDLE(handle); ASSERT(flags == 0); - cl_recv_cb_called++; - if (nread < 0) { ASSERT(0 && "unexpected error"); } @@ -90,18 +111,35 @@ static void cl_recv_cb(uv_udp_t* handle, ASSERT(nread == 4); ASSERT(!memcmp("PING", buf->base, nread)); - /* we are done with the client handle, we can close it */ - uv_close((uv_handle_t*) &client, close_cb); + cl_recv_cb_called++; + + if (cl_recv_cb_called == 2) { + /* we are done with the server handle, we can close it */ + uv_close((uv_handle_t*) &server, close_cb); + } else { + int r; + char source_addr[64]; + + r = uv_ip4_name((const struct sockaddr_in*)addr, source_addr, sizeof(source_addr)); + ASSERT(r == 0); + + r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_LEAVE_GROUP); + ASSERT(r == 0); + + r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, NULL, source_addr, UV_JOIN_GROUP); + ASSERT(r == 0); + + r = do_send(&req_ss); + ASSERT(r == 0); + } } TEST_IMPL(udp_multicast_join) { int r; - uv_udp_send_t req; - uv_buf_t buf; struct sockaddr_in addr; - ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); + ASSERT(0 == uv_ip4_addr("0.0.0.0", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); ASSERT(r == 0); @@ -110,27 +148,19 @@ TEST_IMPL(udp_multicast_join) { ASSERT(r == 0); /* bind to the desired port */ - r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); /* join the multicast channel */ - r = uv_udp_set_membership(&client, "239.255.0.1", NULL, UV_JOIN_GROUP); + r = uv_udp_set_membership(&server, MULTICAST_ADDR, NULL, UV_JOIN_GROUP); if (r == UV_ENODEV) RETURN_SKIP("No multicast support."); ASSERT(r == 0); - r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb); + r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb); ASSERT(r == 0); - buf = uv_buf_init("PING", 4); - - /* server sends "PING" */ - r = uv_udp_send(&req, - &server, - &buf, - 1, - (const struct sockaddr*) &addr, - sv_send_cb); + r = do_send(&req); ASSERT(r == 0); ASSERT(close_cb_called == 0); @@ -140,8 +170,8 @@ TEST_IMPL(udp_multicast_join) { /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(cl_recv_cb_called == 1); - ASSERT(sv_send_cb_called == 1); + ASSERT(cl_recv_cb_called == 2); + ASSERT(sv_send_cb_called == 2); ASSERT(close_cb_called == 2); MAKE_VALGRIND_HAPPY(); diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c index bda5e20ea70403..edcd371b2c22c0 100644 --- a/deps/uv/test/test-udp-multicast-join6.c +++ b/deps/uv/test/test-udp-multicast-join6.c @@ -30,8 +30,23 @@ #define CHECK_HANDLE(handle) \ ASSERT((uv_udp_t*)(handle) == &server || (uv_udp_t*)(handle) == &client) +#if defined(__APPLE__) || \ + defined(_AIX) || \ + defined(__MVS__) || \ + defined(__FreeBSD_kernel__) || \ + defined(__NetBSD__) || \ + defined(__OpenBSD__) + #define MULTICAST_ADDR "ff02::1%lo0" + #define INTERFACE_ADDR "::1%lo0" +#else + #define MULTICAST_ADDR "ff02::1" + #define INTERFACE_ADDR NULL +#endif + static uv_udp_t server; static uv_udp_t client; +static uv_udp_send_t req; +static uv_udp_send_t req_ss; static int cl_recv_cb_called; @@ -63,7 +78,26 @@ static void sv_send_cb(uv_udp_send_t* req, int status) { sv_send_cb_called++; - uv_close((uv_handle_t*) req->handle, close_cb); + if (sv_send_cb_called == 2) + uv_close((uv_handle_t*) req->handle, close_cb); +} + + +static int do_send(uv_udp_send_t* send_req) { + uv_buf_t buf; + struct sockaddr_in6 addr; + + buf = uv_buf_init("PING", 4); + + ASSERT(0 == uv_ip6_addr(MULTICAST_ADDR, TEST_PORT, &addr)); + + /* client sends "PING" */ + return uv_udp_send(send_req, + &client, + &buf, + 1, + (const struct sockaddr*) &addr, + sv_send_cb); } @@ -75,8 +109,6 @@ static void cl_recv_cb(uv_udp_t* handle, CHECK_HANDLE(handle); ASSERT(flags == 0); - cl_recv_cb_called++; - if (nread < 0) { ASSERT(0 && "unexpected error"); } @@ -91,21 +123,57 @@ static void cl_recv_cb(uv_udp_t* handle, ASSERT(nread == 4); ASSERT(!memcmp("PING", buf->base, nread)); - /* we are done with the client handle, we can close it */ - uv_close((uv_handle_t*) &client, close_cb); + cl_recv_cb_called++; + + if (cl_recv_cb_called == 2) { + /* we are done with the server handle, we can close it */ + uv_close((uv_handle_t*) &server, close_cb); + } else { + int r; + char source_addr[64]; + + r = uv_ip6_name((const struct sockaddr_in6*)addr, source_addr, sizeof(source_addr)); + ASSERT(r == 0); + + r = uv_udp_set_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, UV_LEAVE_GROUP); + ASSERT(r == 0); + + r = uv_udp_set_source_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, source_addr, UV_JOIN_GROUP); + ASSERT(r == 0); + + r = do_send(&req_ss); + ASSERT(r == 0); + } +} + + +static int can_ipv6_external(void) { + uv_interface_address_t* addr; + int supported; + int count; + int i; + + if (uv_interface_addresses(&addr, &count)) + return 0; /* Assume no IPv6 support on failure. */ + + supported = 0; + for (i = 0; supported == 0 && i < count; i += 1) + supported = (AF_INET6 == addr[i].address.address6.sin6_family && + !addr[i].is_internal); + + uv_free_interface_addresses(addr, count); + return supported; } TEST_IMPL(udp_multicast_join6) { int r; - uv_udp_send_t req; - uv_buf_t buf; struct sockaddr_in6 addr; - if (!can_ipv6()) - RETURN_SKIP("IPv6 not supported"); + if (!can_ipv6_external()) + RETURN_SKIP("No external IPv6 interface available"); - ASSERT(0 == uv_ip6_addr("::1", TEST_PORT, &addr)); + ASSERT(0 == uv_ip6_addr("::", TEST_PORT, &addr)); r = uv_udp_init(uv_default_loop(), &server); ASSERT(r == 0); @@ -114,20 +182,10 @@ TEST_IMPL(udp_multicast_join6) { ASSERT(r == 0); /* bind to the desired port */ - r = uv_udp_bind(&client, (const struct sockaddr*) &addr, 0); + r = uv_udp_bind(&server, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); - /* join the multicast channel */ -#if defined(__APPLE__) || \ - defined(_AIX) || \ - defined(__MVS__) || \ - defined(__FreeBSD_kernel__) || \ - defined(__NetBSD__) || \ - defined(__OpenBSD__) - r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); -#else - r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); -#endif + r = uv_udp_set_membership(&server, MULTICAST_ADDR, INTERFACE_ADDR, UV_JOIN_GROUP); if (r == UV_ENODEV) { MAKE_VALGRIND_HAPPY(); RETURN_SKIP("No ipv6 multicast route"); @@ -135,18 +193,10 @@ TEST_IMPL(udp_multicast_join6) { ASSERT(r == 0); - r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb); + r = uv_udp_recv_start(&server, alloc_cb, cl_recv_cb); ASSERT(r == 0); - buf = uv_buf_init("PING", 4); - - /* server sends "PING" */ - r = uv_udp_send(&req, - &server, - &buf, - 1, - (const struct sockaddr*) &addr, - sv_send_cb); + r = do_send(&req); ASSERT(r == 0); ASSERT(close_cb_called == 0); @@ -156,8 +206,8 @@ TEST_IMPL(udp_multicast_join6) { /* run the loop till all events are processed */ uv_run(uv_default_loop(), UV_RUN_DEFAULT); - ASSERT(cl_recv_cb_called == 1); - ASSERT(sv_send_cb_called == 1); + ASSERT(cl_recv_cb_called == 2); + ASSERT(sv_send_cb_called == 2); ASSERT(close_cb_called == 2); MAKE_VALGRIND_HAPPY(); diff --git a/deps/uv/test/test.gyp b/deps/uv/test/test.gyp index 6158a2b8b6601f..60792ad6ebbb57 100644 --- a/deps/uv/test/test.gyp +++ b/deps/uv/test/test.gyp @@ -99,6 +99,7 @@ 'test-shutdown-twice.c', 'test-signal.c', 'test-signal-multiple-loops.c', + 'test-signal-pending-on-close.c', 'test-socket-buffer-size.c', 'test-spawn.c', 'test-strscpy.c', @@ -108,6 +109,7 @@ 'test-tcp-bind6-error.c', 'test-tcp-close.c', 'test-tcp-close-accept.c', + 'test-tcp-close-reset.c', 'test-tcp-close-while-connecting.c', 'test-tcp-create-socket-early.c', 'test-tcp-connect-error-after-write.c', diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 46de9b769e76e4..75a6d9781995ae 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -20,6 +20,7 @@ '_UNIX03_SOURCE', '_UNIX03_WITHDRAWN', '_OPEN_SYS_IF_EXT', + '_OPEN_SYS_SOCK_EXT3', '_OPEN_SYS_SOCK_IPV6', '_OPEN_MSGQ_EXT', '_XOPEN_SOURCE_EXTENDED',