diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index f1fef1ca2e..37452ac892 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -40,3 +40,6 @@ Maciej MaƂecki Yasuhiro Matsumoto Daisuke Murase Paddy Byers +Dan VerWeire +Brandon Benvie +Brandon Philips diff --git a/deps/uv/include/uv-private/uv-unix.h b/deps/uv/include/uv-private/uv-unix.h index 792ca84a2c..24ef37cb9d 100644 --- a/deps/uv/include/uv-private/uv-unix.h +++ b/deps/uv/include/uv-private/uv-unix.h @@ -192,9 +192,6 @@ typedef void* uv_lib_t; struct termios orig_termios; \ int mode; -#define UV_STREAM_INFO_PRIVATE_FIELDS \ - int fd; - /* UV_FS_EVENT_PRIVATE_FIELDS */ #if defined(__linux__) diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 626eb6db4c..5a6a949e53 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -450,11 +450,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); wchar_t* dirw; \ char* buffer; -#define UV_STREAM_INFO_PRIVATE_FIELDS \ - union { \ - WSAPROTOCOL_INFOW socket_info; \ - }; - int uv_utf16_to_utf8(const wchar_t* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size); int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index ba93e07c78..f4ee49cc28 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -41,8 +41,9 @@ extern "C" { # define UV_EXTERN /* nothing */ # define CARES_STATICLIB 1 # endif +#elif __GNUC__ >= 4 +# define UV_EXTERN __attribute__((visibility("default"))) #else - /* Unix. TODO: symbol hiding */ # define UV_EXTERN /* nothing */ #endif @@ -117,7 +118,9 @@ typedef intptr_t ssize_t; XX( 47, EEXIST, "file already exists") \ XX( 48, ESRCH, "no such process") \ XX( 49, ENAMETOOLONG, "name too long") \ - XX( 50, EPERM, "operation not permitted") + XX( 50, EPERM, "operation not permitted") \ + XX( 51, ELOOP, "too many symbolic links encountered") \ + XX( 52, EXDEV, "cross-device link not permitted") #define UV_ERRNO_GEN(val, name, s) UV_##name = val, @@ -181,7 +184,6 @@ typedef struct uv_process_s uv_process_t; typedef struct uv_counters_s uv_counters_t; typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; -typedef struct uv_stream_info_s uv_stream_info_t; /* Request types */ typedef struct uv_req_s uv_req_t; typedef struct uv_shutdown_s uv_shutdown_t; @@ -237,15 +239,27 @@ UV_EXTERN int64_t uv_now(uv_loop_t*); /* - * The status parameter is 0 if the request completed successfully, - * and should be -1 if the request was cancelled or failed. - * Error details can be obtained by calling uv_last_error(). + * Should return a buffer that libuv can use to read data into. * - * In the case of uv_read_cb the uv_buf_t returned should be freed by the - * user. + * `suggested_size` is a hint. Returning a buffer that is smaller is perfectly + * okay as long as `buf.len > 0`. */ typedef uv_buf_t (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size); + +/* + * `nread` is > 0 if there is data available, 0 if libuv is done reading for now + * or -1 on error. + * + * Error details can be obtained by calling uv_last_error(). UV_EOF indicates + * that the stream has been closed. + * + * The callee is responsible for closing the stream when an error happens. + * Trying to read from the stream again is undefined. + * + * The callee is responsible for freeing the buffer, libuv does not reuse it. + */ typedef void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); + /* * Just like the uv_read_cb except that if the pending parameter is true * then you can use uv_accept() to pull the new handle into the process. @@ -253,6 +267,7 @@ typedef void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); */ typedef void (*uv_read2_cb)(uv_pipe_t* pipe, ssize_t nread, uv_buf_t buf, uv_handle_type pending); + typedef void (*uv_write_cb)(uv_write_t* req, int status); typedef void (*uv_connect_cb)(uv_connect_t* req, int status); typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status); @@ -491,6 +506,13 @@ struct uv_write_s { }; +/* + * Used to determine whether a stream is readable or writable. + * TODO: export in v0.8. + */ +/* UV_EXTERN */ int uv_is_readable(uv_stream_t* handle); +/* UV_EXTERN */ int uv_is_writable(uv_stream_t* handle); + /* * uv_tcp_t is a subclass of uv_stream_t @@ -532,28 +554,6 @@ UV_EXTERN int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, UV_EXTERN int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name, int* namelen); -/* - * uv_stream_info_t is used to store exported stream (using uv_export), - * which can be imported into a different event-loop within the same process - * (using uv_import). - */ -struct uv_stream_info_s { - uv_handle_type type; - UV_STREAM_INFO_PRIVATE_FIELDS -}; - -/* - * Exports uv_stream_t as uv_stream_info_t value, which could - * be used to initialize shared streams within the same process. - */ -UV_EXTERN int uv_export(uv_stream_t* stream, uv_stream_info_t* info); - -/* - * Imports uv_stream_info_t value into uv_stream_t to initialize - * shared stream. - */ -UV_EXTERN int uv_import(uv_stream_t* stream, uv_stream_info_t* info); - /* * uv_tcp_connect, uv_tcp_connect6 * These functions establish IPv4 and IPv6 TCP connections. Provide an diff --git a/deps/uv/src/unix/eio/config_linux.h b/deps/uv/src/unix/eio/config_linux.h index 606301faf2..e7a0d6e7ae 100644 --- a/deps/uv/src/unix/eio/config_linux.h +++ b/deps/uv/src/unix/eio/config_linux.h @@ -13,8 +13,8 @@ /* utimes(2) is available */ #define HAVE_UTIMES 1 -/* futimes(2) is available */ -#define HAVE_FUTIMES 1 +/* futimes(2) is available but we make the syscall directly. */ +#undef HAVE_FUTIMES /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 @@ -56,6 +56,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SYSCALL_H 1 + /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 diff --git a/deps/uv/src/unix/eio/eio.c b/deps/uv/src/unix/eio/eio.c index 58300a65eb..248af9e2f6 100644 --- a/deps/uv/src/unix/eio/eio.c +++ b/deps/uv/src/unix/eio/eio.c @@ -1039,8 +1039,15 @@ eio__utimes (const char *filename, const struct timeval times[2]) static int eio__futimes (int fd, const struct timeval tv[2]) { +#if defined(__linux) && defined(__NR_utimensat) + struct timespec ts[2]; + ts[0].tv_sec = tv[0].tv_sec, ts[0].tv_nsec = tv[0].tv_usec * 1000; + ts[1].tv_sec = tv[1].tv_sec, ts[1].tv_nsec = tv[1].tv_usec * 1000; + return syscall(__NR_utimensat, fd, NULL, ts, 0); +#else errno = ENOSYS; return -1; +#endif } #endif diff --git a/deps/uv/src/unix/error.c b/deps/uv/src/unix/error.c index b4886cf40b..b167f7af1a 100644 --- a/deps/uv/src/unix/error.c +++ b/deps/uv/src/unix/error.c @@ -74,6 +74,8 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case EMSGSIZE: return UV_EMSGSIZE; case ENAMETOOLONG: return UV_ENAMETOOLONG; case EINVAL: return UV_EINVAL; + case ECONNABORTED: return UV_ECONNABORTED; + case ELOOP: return UV_ELOOP; case ECONNREFUSED: return UV_ECONNREFUSED; case EADDRINUSE: return UV_EADDRINUSE; case EADDRNOTAVAIL: return UV_EADDRNOTAVAIL; @@ -85,6 +87,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case EAI_NONAME: return UV_ENOENT; case ESRCH: return UV_ESRCH; case ETIMEDOUT: return UV_ETIMEDOUT; + case EXDEV: return UV_EXDEV; default: return UV_UNKNOWN; } UNREACHABLE(); diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 9e58fc5377..111bbc2dec 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -802,6 +802,8 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr, /* If we get a ECONNREFUSED wait until the next tick to report the * error. Solaris wants to report immediately--other unixes want to * wait. + * + * XXX: do the same for ECONNABORTED? */ case ECONNREFUSED: stream->delayed_error = errno; @@ -966,40 +968,11 @@ int uv_read_stop(uv_stream_t* stream) { } -int uv_export(uv_stream_t* stream, uv_stream_info_t* info) { - int fd; - - if (stream->type != UV_TCP) { - uv__set_artificial_error(stream->loop, UV_EINVAL); - return -1; - } - - fd = uv__dup(stream->fd); - - if (fd == -1) { - uv__set_sys_error(stream->loop, errno); - return -1; - } - - info->type = stream->type; - info->fd = fd; - - return 0; +int uv_is_readable(uv_stream_t* stream) { + return stream->flags & UV_READABLE; } -int uv_import(uv_stream_t* stream, uv_stream_info_t* info) { - if (info->type != UV_TCP) { - uv__set_artificial_error(stream->loop, UV_EINVAL); - return -1; - } - - if (stream->fd != -1) { - uv__set_artificial_error(stream->loop, UV_EALREADY); - return -1; - } - - stream->fd = info->fd; - - return 0; +int uv_is_writable(uv_stream_t* stream) { + return stream->flags & UV_WRITABLE; } diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 779061031f..dd0018daa6 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -89,6 +89,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case WSAEHOSTUNREACH: return UV_EHOSTUNREACH; case ERROR_INVALID_DATA: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL; + case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP; case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; case WSAEMFILE: return UV_EMFILE; case WSAEMSGSIZE: return UV_EMSGSIZE; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 9435bb28bd..0dc551dbaa 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -143,14 +143,11 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); -int uv__tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info); +int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info); int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, LPWSAPROTOCOL_INFOW protocol_info); -int uv_tcp_export(uv_tcp_t* tcp, uv_stream_info_t* info); -int uv_tcp_import(uv_tcp_t* tcp, uv_stream_info_t* info); - /* * UDP diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 60f137e974..ae769c1d1e 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -98,6 +98,62 @@ static void uv_pipe_connection_init(uv_pipe_t* handle) { } +static int open_named_pipe(uv_pipe_t* handle) { + /* + * Assume that we have a duplex pipe first, so attempt to + * connect with GENERIC_READ | GENERIC_WRITE. + */ + handle->handle = CreateFileW(handle->name, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (handle->handle != INVALID_HANDLE_VALUE) { + return 0; + } + + /* + * If the pipe is not duplex CreateFileW fails with + * ERROR_ACCESS_DENIED. In that case try to connect + * as a read-only or write-only. + */ + if (GetLastError() == ERROR_ACCESS_DENIED) { + handle->handle = CreateFileW(handle->name, + GENERIC_READ | FILE_WRITE_ATTRIBUTES, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (handle->handle != INVALID_HANDLE_VALUE) { + handle->flags |= UV_HANDLE_SHUT; + return 0; + } + } + + if (GetLastError() == ERROR_ACCESS_DENIED) { + handle->handle = CreateFileW(handle->name, + GENERIC_WRITE | FILE_READ_ATTRIBUTES, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if (handle->handle != INVALID_HANDLE_VALUE) { + handle->flags |= UV_HANDLE_EOF; + return 0; + } + } + + return -1; +} + + int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, char* name, size_t nameSize) { HANDLE pipeHandle; @@ -437,15 +493,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { /* We wait for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ - pipeHandle = CreateFileW(handle->name, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - NULL); - - if (pipeHandle != INVALID_HANDLE_VALUE) { + if (open_named_pipe(handle) == 0) { break; } @@ -471,7 +519,6 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; int errno, nameSize; - HANDLE pipeHandle; handle->handle = INVALID_HANDLE_VALUE; @@ -492,15 +539,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, goto error; } - pipeHandle = CreateFileW(handle->name, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - NULL); - - if (pipeHandle == INVALID_HANDLE_VALUE) { + if (open_named_pipe(handle) != 0) { if (GetLastError() == ERROR_PIPE_BUSY) { /* Wait for the server to make a pipe instance available. */ if (!QueueUserWorkItem(&pipe_connect_thread_proc, @@ -519,13 +558,13 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, goto error; } - if (uv_set_pipe_handle(loop, (uv_pipe_t*)req->handle, pipeHandle)) { + assert(handle->handle != INVALID_HANDLE_VALUE); + + if (uv_set_pipe_handle(loop, (uv_pipe_t*)req->handle, handle->handle)) { errno = GetLastError(); goto error; } - handle->handle = pipeHandle; - SET_REQ_SUCCESS(req); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; @@ -537,8 +576,9 @@ error: handle->name = NULL; } - if (pipeHandle != INVALID_HANDLE_VALUE) { - CloseHandle(pipeHandle); + if (handle->handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle->handle); + handle->handle = INVALID_HANDLE_VALUE; } /* Make this req pending reporting an error. */ @@ -649,7 +689,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { return -1; } - return uv__tcp_import((uv_tcp_t*)client, server->pending_socket_info); + return uv_tcp_import((uv_tcp_t*)client, server->pending_socket_info); } else { pipe_client = (uv_pipe_t*)client; diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 7faa0a2b61..ea7363ef03 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -188,25 +188,11 @@ size_t uv_count_bufs(uv_buf_t bufs[], int count) { } -int uv_export(uv_stream_t* stream, uv_stream_info_t* info) { - switch (stream->type) { - case UV_TCP: - return uv_tcp_export((uv_tcp_t*)stream, info); - default: - assert(0); - uv__set_sys_error(stream->loop, WSAEINVAL); - return -1; - } +int uv_is_readable(uv_stream_t* handle) { + return !(handle->flags & UV_HANDLE_EOF); } -int uv_import(uv_stream_t* stream, uv_stream_info_t* info) { - switch (stream->type) { - case UV_TCP: - return uv_tcp_import((uv_tcp_t*)stream, info); - default: - assert(0); - uv__set_sys_error(stream->loop, WSAEINVAL); - return -1; - } -} \ No newline at end of file +int uv_is_writable(uv_stream_t* handle) { + return !(handle->flags & UV_HANDLE_SHUT); +} diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 590d0792fb..f810913f30 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -1019,7 +1019,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, } -int uv__tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info) { +int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info) { SOCKET socket = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_IP, @@ -1140,25 +1140,4 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { } return 0; -} - - -int uv_tcp_export(uv_tcp_t* tcp, uv_stream_info_t* info) { - if (uv_tcp_duplicate_socket(tcp, GetCurrentProcessId(), - &info->socket_info) == -1) { - return -1; - } - - info->type = UV_TCP; - return 0; -} - - -int uv_tcp_import(uv_tcp_t* tcp, uv_stream_info_t* info) { - if (info->type != UV_TCP) { - uv__set_sys_error(tcp->loop, WSAEINVAL); - return -1; - } - - return uv__tcp_import(tcp, &info->socket_info); -} +} \ No newline at end of file diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 6a4d39dea0..dd2fdbcabc 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -1096,6 +1096,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { } else if (arg == 39) { /* Default text color */ fg_color = 7; + fg_bright = 0; } else if (arg >= 40 && arg <= 47) { /* Set background color */ diff --git a/deps/uv/src/win/winsock.h b/deps/uv/src/win/winsock.h index 3eb8e43178..79b9e6b2c4 100644 --- a/deps/uv/src/win/winsock.h +++ b/deps/uv/src/win/winsock.h @@ -46,6 +46,10 @@ #define IPV6_V6ONLY 27 #endif +#ifndef IPV6_HOPLIMIT + #define IPV6_HOPLIMIT 21 +#endif + /* * TDI defines that are only in the DDK. * We only need receive flags so far. diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index ebbd16e1aa..a101305bf5 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -131,6 +131,9 @@ static int ipc_helper(int listen_after_write) { uv_pipe_open(&channel, 0); + ASSERT(uv_is_readable(&channel)); + ASSERT(uv_is_writable(&channel)); + r = uv_tcp_init(uv_default_loop(), &tcp_server); ASSERT(r == 0); diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 109ae014b4..006968829d 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -432,6 +432,14 @@ static void open_nametoolong_cb(uv_fs_t* req) { uv_fs_req_cleanup(req); } +static void open_loop_cb(uv_fs_t* req) { + ASSERT(req->fs_type == UV_FS_OPEN); + ASSERT(req->errorno == UV_ELOOP); + ASSERT(req->result == -1); + open_cb_count++; + uv_fs_req_cleanup(req); +} + TEST_IMPL(fs_file_noent) { uv_fs_t req; @@ -483,6 +491,34 @@ TEST_IMPL(fs_file_nametoolong) { return 0; } +TEST_IMPL(fs_file_loop) { + uv_fs_t req; + int r; + + loop = uv_default_loop(); + + unlink("test_symlink"); + uv_fs_symlink(loop, &req, "test_symlink", "test_symlink", 0, NULL); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, NULL); + ASSERT(r == -1); + ASSERT(req.result == -1); + ASSERT(uv_last_error(loop).code == UV_ELOOP); + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, open_loop_cb); + ASSERT(r == 0); + + ASSERT(open_cb_count == 0); + uv_run(loop); + ASSERT(open_cb_count == 1); + + unlink("test_symlink"); + + return 0; +} + static void check_utime(const char* path, double atime, double mtime) { struct stat* s; uv_fs_t req; diff --git a/deps/uv/test/test-ipc-threads.c b/deps/uv/test/test-ipc-threads.c deleted file mode 100644 index 1821f6ab0a..0000000000 --- a/deps/uv/test/test-ipc-threads.c +++ /dev/null @@ -1,235 +0,0 @@ -/* Copyright Joyent, Inc. and other Node 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 "runner.h" -#include "task.h" - -#include -#include - -typedef struct { - uv_loop_t* loop; - uv_thread_t thread; - uv_async_t* recv_channel; - uv_async_t* send_channel; - uv_tcp_t server; - uv_tcp_t conn; - int connection_accepted; - int close_cb_called; -} worker_t; - -static uv_async_t send_channel; -static uv_async_t recv_channel; -static worker_t parent; -static worker_t child; - -static volatile uv_stream_info_t dup_stream; - -typedef struct { - uv_connect_t conn_req; - uv_tcp_t conn; -} tcp_conn; - -#define CONN_COUNT 100 - -static void close_cb(uv_handle_t* handle) { - worker_t* worker = (worker_t*)handle->data; - ASSERT(worker); - worker->close_cb_called++; -} - - -static void on_connection(uv_stream_t* server, int status) { - int r; - worker_t* worker = container_of(server, worker_t, server); - - if (!worker->connection_accepted) { - /* - * Accept the connection and close it. - */ - ASSERT(status == 0); - - r = uv_tcp_init(server->loop, &worker->conn); - ASSERT(r == 0); - - worker->conn.data = worker; - - r = uv_accept(server, (uv_stream_t*)&worker->conn); - ASSERT(r == 0); - - worker->connection_accepted = 1; - - uv_close((uv_handle_t*)worker->recv_channel, close_cb); - uv_close((uv_handle_t*)&worker->conn, close_cb); - uv_close((uv_handle_t*)server, close_cb); - } -} - - -static void close_client_conn_cb(uv_handle_t* handle) { - tcp_conn* p = (tcp_conn*)handle->data; - free(p); -} - - -static void connect_cb(uv_connect_t* req, int status) { - uv_close((uv_handle_t*)req->handle, close_client_conn_cb); -} - - -static void make_many_connections() { - tcp_conn* conn; - struct sockaddr_in addr; - int r, i; - - for (i = 0; i < CONN_COUNT; i++) { - conn = malloc(sizeof(*conn)); - ASSERT(conn); - - r = uv_tcp_init(uv_default_loop(), &conn->conn); - ASSERT(r == 0); - - addr = uv_ip4_addr("127.0.0.1", TEST_PORT); - - r = uv_tcp_connect(&conn->conn_req, (uv_tcp_t*)&conn->conn, addr, connect_cb); - ASSERT(r == 0); - - conn->conn.data = conn; - } -} - - -void on_parent_msg(uv_async_t* handle, int status) { - int r; - - ASSERT(dup_stream.type == UV_TCP); - - /* Import the shared TCP server, and start listening on it. */ - r = uv_tcp_init(parent.loop, &parent.server); - ASSERT(r == 0); - - parent.server.data = &parent; - - r = uv_import((uv_stream_t*)&parent.server, - (uv_stream_info_t*)&dup_stream); - ASSERT(r == 0); - - r = uv_listen((uv_stream_t*)&parent.server, 12, on_connection); - ASSERT(r == 0); - - /* Create a bunch of connections to get both servers to accept. */ - make_many_connections(); -} - - -void on_child_msg(uv_async_t* handle, int status) { - ASSERT(!"no"); -} - - -static void child_thread_entry(void* arg) { - int r; - int listen_after_write = *(int*) arg; - - r = uv_tcp_init(child.loop, &child.server); - ASSERT(r == 0); - - child.server.data = &child; - - r = uv_tcp_bind(&child.server, uv_ip4_addr("0.0.0.0", TEST_PORT)); - ASSERT(r == 0); - - if (!listen_after_write) { - r = uv_listen((uv_stream_t*)&child.server, 12, on_connection); - ASSERT(r == 0); - } - - r = uv_export((uv_stream_t*)&child.server, - (uv_stream_info_t*)&dup_stream); - ASSERT(r == 0); - - r = uv_async_send(child.send_channel); - ASSERT(r == 0); - - if (listen_after_write) { - r = uv_listen((uv_stream_t*)&child.server, 12, on_connection); - ASSERT(r == 0); - } - - r = uv_run(child.loop); - ASSERT(r == 0); - - ASSERT(child.connection_accepted == 1); - ASSERT(child.close_cb_called == 3); -} - - -static void run_ipc_threads_test(int listen_after_write) { - int r; - - parent.send_channel = &send_channel; - parent.recv_channel = &recv_channel; - child.send_channel = &recv_channel; - child.recv_channel = &send_channel; - - parent.loop = uv_default_loop(); - child.loop = uv_loop_new(); - ASSERT(child.loop); - - r = uv_async_init(parent.loop, parent.recv_channel, on_parent_msg); - ASSERT(r == 0); - parent.recv_channel->data = &parent; - - r = uv_async_init(child.loop, child.recv_channel, on_child_msg); - ASSERT(r == 0); - child.recv_channel->data = &child; - - r = uv_thread_create(&child.thread, child_thread_entry, &listen_after_write); - ASSERT(r == 0); - - r = uv_run(parent.loop); - ASSERT(r == 0); - - ASSERT(parent.connection_accepted == 1); - ASSERT(parent.close_cb_called == 3); - - r = uv_thread_join(&child.thread); - ASSERT(r == 0); - - /* Satisfy valgrind. Maybe we should delete the default loop from the - * test runner. - */ - uv_loop_delete(child.loop); - uv_loop_delete(uv_default_loop()); -} - - -TEST_IMPL(ipc_threads_listen_after_write) { - run_ipc_threads_test(1); - return 0; -} - - -TEST_IMPL(ipc_threads_listen_before_write) { - run_ipc_threads_test(0); - return 0; -} diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 63c10000fb..99932da5dc 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -24,8 +24,6 @@ TEST_DECLARE (tty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (ipc_listen_before_write) TEST_DECLARE (ipc_listen_after_write) -TEST_DECLARE (ipc_threads_listen_after_write) -TEST_DECLARE (ipc_threads_listen_before_write) TEST_DECLARE (tcp_ping_pong) TEST_DECLARE (tcp_ping_pong_v6) TEST_DECLARE (pipe_ping_pong) @@ -50,6 +48,7 @@ TEST_DECLARE (tcp_bind6_error_inval) TEST_DECLARE (tcp_bind6_localhost_ok) TEST_DECLARE (udp_send_and_recv) TEST_DECLARE (udp_multicast_join) +TEST_DECLARE (udp_multicast_ttl) TEST_DECLARE (udp_dgram_too_big) TEST_DECLARE (udp_dual_stack) TEST_DECLARE (udp_ipv6_only) @@ -110,6 +109,7 @@ TEST_DECLARE (spawn_and_ping) TEST_DECLARE (kill) TEST_DECLARE (fs_file_noent) TEST_DECLARE (fs_file_nametoolong) +TEST_DECLARE (fs_file_loop) TEST_DECLARE (fs_file_async) TEST_DECLARE (fs_file_sync) TEST_DECLARE (fs_async_dir) @@ -164,8 +164,6 @@ TASK_LIST_START TEST_ENTRY (stdio_over_pipes) TEST_ENTRY (ipc_listen_before_write) TEST_ENTRY (ipc_listen_after_write) - TEST_ENTRY (ipc_threads_listen_after_write) - TEST_ENTRY (ipc_threads_listen_before_write) TEST_ENTRY (tcp_ping_pong) TEST_HELPER (tcp_ping_pong, tcp4_echo_server) @@ -206,6 +204,7 @@ TASK_LIST_START TEST_ENTRY (udp_ipv6_only) TEST_ENTRY (udp_options) TEST_ENTRY (udp_multicast_join) + TEST_ENTRY (udp_multicast_ttl) TEST_ENTRY (pipe_bind_error_addrinuse) TEST_ENTRY (pipe_bind_error_addrnotavail) @@ -294,6 +293,7 @@ TASK_LIST_START TEST_ENTRY (fs_file_noent) TEST_ENTRY (fs_file_nametoolong) + TEST_ENTRY (fs_file_loop) TEST_ENTRY (fs_file_async) TEST_ENTRY (fs_file_sync) TEST_ENTRY (fs_async_dir) diff --git a/deps/uv/test/test-ping-pong.c b/deps/uv/test/test-ping-pong.c index 5c3de3b4f6..245a6014ec 100644 --- a/deps/uv/test/test-ping-pong.c +++ b/deps/uv/test/test-ping-pong.c @@ -138,6 +138,9 @@ static void pinger_on_connect(uv_connect_t *req, int status) { ASSERT(status == 0); + ASSERT(uv_is_readable(req->handle)); + ASSERT(uv_is_writable(req->handle)); + pinger_write_ping(pinger); uv_read_start((uv_stream_t*)(req->handle), alloc_cb, pinger_read_cb); diff --git a/deps/uv/test/test-udp-multicast-ttl.c b/deps/uv/test/test-udp-multicast-ttl.c new file mode 100644 index 0000000000..e54583c13f --- /dev/null +++ b/deps/uv/test/test-udp-multicast-ttl.c @@ -0,0 +1,89 @@ +/* Copyright Joyent, Inc. and other Node 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 int cl_recv_cb_called; + +static int sv_send_cb_called; + +static int close_cb_called; + + +static void close_cb(uv_handle_t* handle) { + CHECK_HANDLE(handle); + close_cb_called++; +} + + +static void sv_send_cb(uv_udp_send_t* req, int status) { + ASSERT(req != NULL); + ASSERT(status == 0); + CHECK_HANDLE(req->handle); + + sv_send_cb_called++; + + uv_close((uv_handle_t*) req->handle, close_cb); +} + + +TEST_IMPL(udp_multicast_ttl) { + int r; + uv_udp_send_t req; + uv_buf_t buf; + struct sockaddr_in addr = uv_ip4_addr("239.255.0.1", TEST_PORT); + + r = uv_udp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_udp_bind(&server, uv_ip4_addr("0.0.0.0", 0), 0); + ASSERT(r == 0); + + r = uv_udp_set_multicast_ttl(&server, 32); + ASSERT(r == 0); + + /* server sends "PING" */ + buf = uv_buf_init("PING", 4); + r = uv_udp_send(&req, &server, &buf, 1, addr, sv_send_cb); + ASSERT(r == 0); + + ASSERT(close_cb_called == 0); + ASSERT(sv_send_cb_called == 0); + + /* run the loop till all events are processed */ + uv_run(uv_default_loop()); + + ASSERT(sv_send_cb_called == 1); + ASSERT(close_cb_called == 1); + + return 0; +} diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 4c8caa4fea..75f3634ef7 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -115,7 +115,7 @@ 'src/ares/config_win32' ], 'defines': [ - '_WIN32_WINNT=0x0502', + '_WIN32_WINNT=0x0600', 'EIO_STACKSIZE=262144', '_GNU_SOURCE', ], @@ -301,7 +301,6 @@ 'test/test-hrtime.c', 'test/test-idle.c', 'test/test-ipc.c', - 'test/test-ipc-threads.c', 'test/test-list.h', 'test/test-loop-handles.c', 'test/test-multiple-listen.c', @@ -336,6 +335,7 @@ 'test/test-udp-send-and-recv.c', 'test/test-udp-multicast-join.c', 'test/test-counters-init.c', + 'test/test-udp-multicast-ttl.c', ], 'conditions': [ [ 'OS=="win"', {