From 495853ee2b5d25f3848264139ab5214ddfc602bb Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Wed, 1 Feb 2012 12:38:14 -0800 Subject: [PATCH 01/12] windows: map ERROR_ACCESS_DENIED to UV_EPERM --- src/win/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win/error.c b/src/win/error.c index 59c9ea834..779061031 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -69,7 +69,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case ERROR_SUCCESS: return UV_OK; case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_PATH_NOT_FOUND: return UV_ENOENT; - case ERROR_ACCESS_DENIED: return UV_EACCES; + case ERROR_ACCESS_DENIED: return UV_EPERM; case ERROR_NOACCESS: return UV_EACCES; case WSAEACCES: return UV_EACCES; case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; From 267e75dda2b6b7ecf9501764a42416122a4f0ff5 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Thu, 2 Feb 2012 16:23:57 +0100 Subject: [PATCH 02/12] Windows: better stat implementation --- src/win/fs.c | 186 ++++++++----------------------------------------- test/test-fs.c | 13 ++++ 2 files changed, 41 insertions(+), 158 deletions(-) diff --git a/src/win/fs.c b/src/win/fs.c index 5248ac2a9..12ad514c4 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -489,191 +489,61 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) { } -#define IS_SLASH(c) \ - ((wchar_t) c == L'/' || (wchar_t) c == L'\\') -#define IS_COLON(c) \ - ((wchar_t) c == L':') -#define IS_LETTER(c) \ - ((((wchar_t) c >= L'a') && ((wchar_t) c <= L'z')) || \ - (((wchar_t) c >= L'A') && ((wchar_t) c <= L'Z'))) -#define IS_QUESTION(c) \ - ((wchar_t) c == L'?') - - -static int uv__count_slash_separated_words(const wchar_t* pos, - const wchar_t* end, - int limit) { - char last_was_slash = 1, count = 0; - - for (; pos < end; pos++) { - if (IS_SLASH(*pos)) { - /* Don't accept double slashes */ - if (last_was_slash) { - return 0; - } else { - last_was_slash = 1; - } - } else { - if (last_was_slash) { - /* Found a new word */ - count++; - if (count > limit) { - return -1; - } - last_was_slash = 0; - } - } - } - - return count; -} - -/* - * Returns true if the given path is a root directory. The following patterns - * are recognized: - * \ - * c:\ (must have trailing slash) - * \\server\share (trailing slash optional) - * \\?\c: (trailing slash optional) - * \\?\UNC\server\share (trailing slash optional) - */ -static int uv__is_root(const wchar_t* path) { - size_t len = wcslen(path); - - /* Test for \ */ - if (len == 1 && IS_SLASH(path[0])) { - return 1; - } - - if (len < 3) { - return 0; - } - - /* Test for c:\ */ - if (IS_LETTER(path[0]) && IS_COLON(path[1]) && IS_SLASH(path[2])) { - return 1; - } - - if (!IS_SLASH(path[0]) || !IS_SLASH(path[1])) { - return 0; - } - - /* Test for \\server\share */ - if (!IS_QUESTION(path[2])) { - return uv__count_slash_separated_words(path + 2, path + len, 2) == 2; - } - - if (!IS_SLASH(path[3])) { - return 0; - } - - if ((len == 6 || len == 7) && - IS_LETTER(path[4]) && IS_COLON(path[5]) && - (len == 6 || IS_SLASH(path[6]))) { - return 1; - } - - /* Test for \\?\UNC\server\share */ - if (len >= 8 && - (path[4] == L'u' || path[4] == L'U') && - (path[5] == L'n' || path[5] == L'N') && - (path[6] == L'c' || path[6] == L'C') && - IS_SLASH(path[7])) { - return uv__count_slash_separated_words(path + 8, path + len, 2) == 2; - } - - return 0; -} - - -void fs__stat(uv_fs_t* req, const wchar_t* path) { - HANDLE file; - WIN32_FIND_DATAW ent; +static void fs__stat(uv_fs_t* req, const wchar_t* path) { + HANDLE handle; int result; + BY_HANDLE_FILE_INFORMATION info; req->ptr = NULL; - if (uv__is_root(path)) { - /* We can't stat root directories like c:\. _wstati64 can't either, but */ - /* it will make up something reasonable. */ - DWORD drive_type = GetDriveTypeW(path); - if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) { - req->last_error = ERROR_PATH_NOT_FOUND; - req->errorno = UV_ENOENT; - req->result = -1; - return; - } - - memset(&req->stat, 0, sizeof req->stat); - - req->stat.st_nlink = 1; - req->stat.st_mode = ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + - ((_S_IREAD|_S_IWRITE) >> 6)) | S_IFDIR; - - req->last_error = ERROR_SUCCESS; - req->errorno = UV_OK; - req->result = 0; - req->ptr = &req->stat; - return; - } - - file = FindFirstFileExW(path, FindExInfoStandard, &ent, - FindExSearchNameMatch, NULL, 0); - - if (file == INVALID_HANDLE_VALUE) { + handle = CreateFileW(path, + FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) { SET_REQ_RESULT_WIN32_ERROR(req, GetLastError()); return; } - FindClose(file); - - if (ent.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && - ent.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { - fs__open(req, path, _O_RDONLY, 0); - if (req->result != -1) { - result = _fstati64(req->result, &req->stat); - _close(req->result); - - if (result != -1) { - req->ptr = &req->stat; - } - - SET_REQ_RESULT(req, result); - } - + if (!GetFileInformationByHandle(handle, &info)) { + SET_REQ_RESULT_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); return; } - req->stat.st_ino = 0; - req->stat.st_uid = 0; - req->stat.st_gid = 0; - req->stat.st_mode = 0; - req->stat.st_rdev = 0; - req->stat.st_dev = 0; - req->stat.st_nlink = 1; + memset(&req->stat, 0, sizeof req->stat); - if (ent.dwFileAttributes & FILE_ATTRIBUTE_READONLY ) { + /* TODO: set st_dev and st_ino? */ + + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); } else { req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + ((_S_IREAD|_S_IWRITE) >> 6)); } - if (ent.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { req->stat.st_mode |= _S_IFDIR; } else { req->stat.st_mode |= _S_IFREG; } - uv_filetime_to_time_t(&ent.ftLastWriteTime, &(req->stat.st_mtime)); - uv_filetime_to_time_t(&ent.ftLastAccessTime, &(req->stat.st_atime)); - uv_filetime_to_time_t(&ent.ftCreationTime, &(req->stat.st_ctime)); + uv_filetime_to_time_t(&info.ftLastWriteTime, &(req->stat.st_mtime)); + uv_filetime_to_time_t(&info.ftLastAccessTime, &(req->stat.st_atime)); + uv_filetime_to_time_t(&info.ftCreationTime, &(req->stat.st_ctime)); - req->stat.st_size = ((int64_t)ent.nFileSizeHigh << 32) + - (int64_t)ent.nFileSizeLow; + req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) + + (int64_t) info.nFileSizeLow; + + req->stat.st_nlink = info.nNumberOfLinks; req->ptr = &req->stat; req->result = 0; + + CloseHandle(handle); } diff --git a/test/test-fs.c b/test/test-fs.c index dbeb2a19c..109ae014b 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -1309,6 +1309,19 @@ TEST_IMPL(fs_stat_root) { r = uv_fs_stat(loop, &stat_req, "\\", NULL); ASSERT(r == 0); + r = uv_fs_stat(loop, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "..", NULL); + ASSERT(r == 0); + + r = uv_fs_stat(loop, &stat_req, "..\\", NULL); + ASSERT(r == 0); + + /* stats the current directory on c: */ + r = uv_fs_stat(loop, &stat_req, "c:", NULL); + ASSERT(r == 0); + r = uv_fs_stat(loop, &stat_req, "c:\\", NULL); ASSERT(r == 0); From 2f182f445161a823800b94e434c66bedd0b8cac3 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 3 Feb 2012 16:18:50 +0100 Subject: [PATCH 03/12] unix: map ECONNABORTED --- src/unix/error.c | 1 + src/unix/stream.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/unix/error.c b/src/unix/error.c index 1d38623f0..615747b2b 100644 --- a/src/unix/error.c +++ b/src/unix/error.c @@ -74,6 +74,7 @@ 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 ECONNREFUSED: return UV_ECONNREFUSED; case EADDRINUSE: return UV_EADDRINUSE; case EADDRNOTAVAIL: return UV_EADDRNOTAVAIL; diff --git a/src/unix/stream.c b/src/unix/stream.c index e0689fbcd..5a8f6ebe7 100644 --- a/src/unix/stream.c +++ b/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; From 3ff3626e52144d62b685d1ced472fee2cc9e08d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Ma=C5=82ecki?= Date: Wed, 25 Jan 2012 12:10:33 +0100 Subject: [PATCH 04/12] unix: map `ELOOP` to `UV_ELOOP` --- include/uv.h | 3 ++- src/unix/error.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index 23e5e21d1..a3f75d717 100644 --- a/include/uv.h +++ b/include/uv.h @@ -117,7 +117,8 @@ 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") #define UV_ERRNO_GEN(val, name, s) UV_##name = val, diff --git a/src/unix/error.c b/src/unix/error.c index 615747b2b..3524e6645 100644 --- a/src/unix/error.c +++ b/src/unix/error.c @@ -75,6 +75,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { 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; From 0596c59bc3e0d5083c11abd6a558e21e94de3066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Ma=C5=82ecki?= Date: Wed, 25 Jan 2012 12:39:44 +0100 Subject: [PATCH 05/12] test: test if `UV_ELOOP` mapping works --- test/test-fs.c | 35 +++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 2 files changed, 37 insertions(+) diff --git a/test/test-fs.c b/test/test-fs.c index 109ae014b..1d231c0e4 100644 --- a/test/test-fs.c +++ b/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,33 @@ 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"); + symlink("test_symlink", "test_symlink"); + + 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/test/test-list.h b/test/test-list.h index 02fabcb9e..55adf366b 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -105,6 +105,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) @@ -275,6 +276,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) From e2565c332aa5daab090cb436d5255c5e86faeec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Ma=C5=82ecki?= Date: Wed, 25 Jan 2012 12:42:46 +0100 Subject: [PATCH 06/12] win: map `ERROR_CANT_RESOLVE_FILENAME` to `UV_ENAMETOOLONG` --- src/win/error.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/error.c b/src/win/error.c index 779061031..dd0018daa 100644 --- a/src/win/error.c +++ b/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; From 443445a3c61d2ce5020c9e4bc2ee9a10bc7560fc Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Sun, 5 Feb 2012 19:54:04 +0100 Subject: [PATCH 07/12] Windows: reset brightness when reverting to default text color --- src/win/tty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/win/tty.c b/src/win/tty.c index e61fc7e28..556875d43 100644 --- a/src/win/tty.c +++ b/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 */ From 9fa2cf2eacde4a740f8b2b3e9519bcdcf1be6047 Mon Sep 17 00:00:00 2001 From: Roman Shtylman Date: Thu, 19 Jan 2012 11:07:28 -0500 Subject: [PATCH 08/12] test: add multicast TTL test --- test/test-list.h | 2 + test/test-udp-multicast-ttl.c | 89 +++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 3 files changed, 92 insertions(+) create mode 100644 test/test-udp-multicast-ttl.c diff --git a/test/test-list.h b/test/test-list.h index 55adf366b..137137177 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -47,6 +47,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) @@ -191,6 +192,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) diff --git a/test/test-udp-multicast-ttl.c b/test/test-udp-multicast-ttl.c new file mode 100644 index 000000000..e54583c13 --- /dev/null +++ b/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/uv.gyp b/uv.gyp index 1bc9ff9b4..07ea07a81 100644 --- a/uv.gyp +++ b/uv.gyp @@ -321,6 +321,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"', { From dbc046cb7f3705d9f9a386e22f48e7996624909a Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Mon, 6 Feb 2012 00:21:33 -0800 Subject: [PATCH 09/12] Add EXDEV to the errno map. --- include/uv.h | 3 ++- src/unix/error.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uv.h b/include/uv.h index a3f75d717..d8f861e3d 100644 --- a/include/uv.h +++ b/include/uv.h @@ -118,7 +118,8 @@ typedef intptr_t ssize_t; XX( 48, ESRCH, "no such process") \ XX( 49, ENAMETOOLONG, "name too long") \ XX( 50, EPERM, "operation not permitted") \ - XX( 51, ELOOP, "too many symbolic links encountered") + 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, diff --git a/src/unix/error.c b/src/unix/error.c index 3524e6645..93c5ac1f5 100644 --- a/src/unix/error.c +++ b/src/unix/error.c @@ -87,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; } From c800043112a873a0fab1c5df2c76a958a2b012e7 Mon Sep 17 00:00:00 2001 From: Luis Lavena Date: Mon, 6 Feb 2012 19:15:03 -0300 Subject: [PATCH 10/12] Add missing IPV6_HOPLIMIT definition for MinGW Closes GH-307 --- src/win/winsock.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/win/winsock.h b/src/win/winsock.h index 433ce4767..954ad5ce1 100644 --- a/src/win/winsock.h +++ b/src/win/winsock.h @@ -45,6 +45,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. From 53eb9935cbe07efe2823249c59f79103b8b0689f Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Thu, 9 Feb 2012 12:59:41 -0800 Subject: [PATCH 11/12] fix windows build --- test/test-fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test-fs.c b/test/test-fs.c index 1d231c0e4..006968829 100644 --- a/test/test-fs.c +++ b/test/test-fs.c @@ -498,7 +498,8 @@ TEST_IMPL(fs_file_loop) { loop = uv_default_loop(); unlink("test_symlink"); - symlink("test_symlink", "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); From f9be43a564c55a6e28cc2de730cb8d7131d8e558 Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Wed, 8 Feb 2012 12:01:33 -0800 Subject: [PATCH 12/12] support half-duplex pipes --- include/uv.h | 7 ++++ src/unix/stream.c | 8 ++++ src/win/pipe.c | 88 +++++++++++++++++++++++++++++++------------ src/win/stream.c | 10 +++++ test/run-tests.c | 3 ++ test/test-ping-pong.c | 3 ++ 6 files changed, 95 insertions(+), 24 deletions(-) diff --git a/include/uv.h b/include/uv.h index d8f861e3d..b6ce8ec2e 100644 --- a/include/uv.h +++ b/include/uv.h @@ -470,6 +470,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 diff --git a/src/unix/stream.c b/src/unix/stream.c index 5a8f6ebe7..111bbc2de 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -968,3 +968,11 @@ int uv_read_stop(uv_stream_t* stream) { } +int uv_is_readable(uv_stream_t* stream) { + return stream->flags & UV_READABLE; +} + + +int uv_is_writable(uv_stream_t* stream) { + return stream->flags & UV_WRITABLE; +} diff --git a/src/win/pipe.c b/src/win/pipe.c index 5c20fe480..ae769c1d1 100644 --- a/src/win/pipe.c +++ b/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. */ diff --git a/src/win/stream.c b/src/win/stream.c index c2354eecb..ea7363ef0 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -186,3 +186,13 @@ size_t uv_count_bufs(uv_buf_t bufs[], int count) { return bytes; } + + +int uv_is_readable(uv_stream_t* handle) { + return !(handle->flags & UV_HANDLE_EOF); +} + + +int uv_is_writable(uv_stream_t* handle) { + return !(handle->flags & UV_HANDLE_SHUT); +} diff --git a/test/run-tests.c b/test/run-tests.c index 1d8b0bcf5..a3e08fc09 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -129,6 +129,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/test/test-ping-pong.c b/test/test-ping-pong.c index 5c3de3b4f..245a6014e 100644 --- a/test/test-ping-pong.c +++ b/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);