Maciej Małecki <maciej.malecki@notimplemented.org> <me@mmalecki.com>
Marc Schlaich <marc.schlaich@googlemail.com> <marc.schlaich@gmail.com>
Rasmus Christian Pedersen <ruysch@outlook.com>
+Rasmus Christian Pedersen <zerhacken@yahoo.com> <ruysch@outlook.com>
Rasmus Pedersen <ruysch@outlook.com> <zerhacken@yahoo.com>
Robert Mustacchi <rm@joyent.com> <rm@fingolfin.org>
Ryan Dahl <ryan@joyent.com> <ry@tinyclouds.org>
李港平 <chopdown@gmail.com>
Chernyshev Viacheslav <astellar@ro.ru>
Stephen von Takach <steve@advancedcontrol.com.au>
+JD Ballard <jd@pixelandline.com>
+Luka Perkov <luka.perkov@sartura.hr>
+Ryan Cole <ryan@rycole.com>
+HungMingWu <u9089000@gmail.com>
+Jay Satiro <raysatiro@yahoo.com>
+Leith Bade <leith@leithalweapon.geek.nz>
+Peter Atashian <retep998@gmail.com>
Look at other tests to see how they should be structured (license boilerplate,
the way entry points are declared, etc.).
-```
-$ make test
-```
-
-Make sure that there are no test regressions.
+Check README.md file to find out how to run the test suite and make sure that
+there are no test regressions.
### PUSH
not send out notifications when you add commits.
-### CONTRIBUTOR LICENSE AGREEMENT
-
-The current state of affairs is that, in order to get a patch accepted, you need
-to sign Node.js's [contributor license agreement][]. You only need to do that
-once.
-
-
[issue tracker]: https://github.com/joyent/libuv/issues
[libuv mailing list]: http://groups.google.com/group/libuv
[IRC]: http://webchat.freelibuv.net/?channels=libuv
[Google C/C++ style guide]: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
-[contributor license agreement]: http://nodejs.org/cla.html
-2014.05.02, Version 0.11.25 (Unstable)
+2014.06.28, Version 0.11.26 (Unstable)
+
+Changes since version 0.11.25:
+
+* windows: add VT100 codes ?25l and ?25h (JD Ballard)
+
+* windows: add invert ANSI (7 / 27) emulation (JD Ballard)
+
+* unix: fix handling error on UDP socket creation (Saúl Ibarra Corretgé)
+
+* unix, windows: getnameinfo implementation (Rasmus Pedersen)
+
+* heap: fix `heap_remove()` (Fedor Indutny)
+
+* unix, windows: fix parsing scoped IPv6 addresses (Saúl Ibarra Corretgé)
+
+* windows: fix handling closed socket while poll handle is closing (Saúl Ibarra
+ Corretgé)
+
+* thread: barrier functions (Ben Noordhuis)
+
+* windows: fix PYTHON environment variable usage (Jay Satiro)
+
+* unix, windows: return system error on EAI_SYSTEM (Saúl Ibarra Corretgé)
+
+* windows: fix handling closed socket while poll handle is closing (Saúl Ibarra
+ Corretgé)
+
+* unix: don't run i/o callbacks after prepare callbacks (Saúl Ibarra Corretgé)
+
+* windows: add tty unicode support for input (Peter Atashian)
+
+* header: introduce `uv_loop_size()` (Andrius Bentkus)
+
+* darwin: invoke `mach_timebase_info` only once (Fedor Indutny)
+
+
+2014.05.02, Version 0.11.25 (Unstable), 2acd544cff7142e06aa3b09ec64b4a33dd9ab996
Changes since version 0.11.24:
* inet: allow scopeid in uv_inet_pton (Fedor Indutny)
-* win: always leave crit section in get_proc_title (Fedor Indutny)
-
2014.04.07, Version 0.11.23 (Unstable), e54de537efcacd593f36fcaaf8b4cb9e64313275
* unix: fix setting written size on uv_wd (Saúl Ibarra Corretgé)
-2014.04.07, Version 0.10.26 (Stable), d864907611c25ec986c5e77d4d6d6dee88f26926
-
-Changes since version 0.10.25:
-
-* process: don't close stdio fds during spawn (Tonis Tiigi)
-
-* build, windows: do not fail on Windows SDK Prompt (Marc Schlaich)
-
-* build, windows: fix x64 configuration issue (Marc Schlaich)
-
-* win: fix buffer leak on error in pipe.c (Fedor Indutny)
-
-* kqueue: invalidate fd in uv_fs_event_t (Fedor Indutny)
-
-* linux: always deregister closing fds from epoll (Geoffry Song)
-
-* error: add ENXIO for O_NONBLOCK FIFO open() (Fedor Indutny)
-
-
2014.03.11, Version 0.11.22 (Unstable), cd0c19b1d3c56acf0ade7687006e12e75fbda36d
Changes since version 0.11.21:
* linux: fix C99/C++ comment (Fedor Indutny)
+2014.05.02, Version 0.10.27 (Stable), 6e24ce23b1e7576059f85a608eca13b766458a01
+
+Changes since version 0.10.26:
+
+* windows: fix console signal handler refcount (Saúl Ibarra Corretgé)
+
+* win: always leave crit section in get_proc_title (Fedor Indutny)
+
+
+2014.04.07, Version 0.10.26 (Stable), d864907611c25ec986c5e77d4d6d6dee88f26926
+
+Changes since version 0.10.25:
+
+* process: don't close stdio fds during spawn (Tonis Tiigi)
+
+* build, windows: do not fail on Windows SDK Prompt (Marc Schlaich)
+
+* build, windows: fix x64 configuration issue (Marc Schlaich)
+
+* win: fix buffer leak on error in pipe.c (Fedor Indutny)
+
+* kqueue: invalidate fd in uv_fs_event_t (Fedor Indutny)
+
+* linux: always deregister closing fds from epoll (Geoffry Song)
+
+* error: add ENXIO for O_NONBLOCK FIFO open() (Fedor Indutny)
+
+
2014.02.19, Version 0.10.25 (Stable), d778dc588507588b12b9f9d2905078db542ed751
Changes since version 0.10.24:
src/win/fs-event.c \
src/win/fs.c \
src/win/getaddrinfo.c \
+ src/win/getnameinfo.c \
src/win/handle.c \
src/win/handle-inl.h \
src/win/internal.h \
src/unix/dl.c \
src/unix/fs.c \
src/unix/getaddrinfo.c \
+ src/unix/getnameinfo.c \
src/unix/internal.h \
src/unix/loop-watcher.c \
src/unix/loop.c \
test/test-get-loadavg.c \
test/test-get-memory.c \
test/test-getaddrinfo.c \
+ test/test-getnameinfo.c \
test/test-getsockname.c \
test/test-hrtime.c \
test/test-idle.c \
test/test-pipe-server-close.c \
test/test-platform-output.c \
test/test-poll-close.c \
+ test/test-poll-closesocket.c \
test/test-poll.c \
test/test-process-title.c \
test/test-ref.c \
endif
if ANDROID
-include_HEADERS += include/android-ifaddrs.h
-libuv_la_SOURCES += src/unix/android-ifaddrs.c
+include_HEADERS += include/android-ifaddrs.h \
+ include/pthread-fixes.h
+libuv_la_SOURCES += src/unix/android-ifaddrs.c \
+ src/unix/pthread-fixes.c
endif
if DARWIN
src/win/fs-event.o \
src/win/fs.o \
src/win/getaddrinfo.o \
+ src/win/getnameinfo.o \
src/win/handle.o \
src/win/loop-watcher.o \
src/win/pipe.o \
### Windows
-First, Python 2.6 or 2.7 must be installed as it is required by [GYP][].
-
-Also, the directory for the preferred Python executable must be specified
-by the `PYTHON` or `Path` environment variables.
+First, [Python][] 2.6 or 2.7 must be installed as it is required by [GYP][].
+If python is not in your path set the environment variable `PYTHON` to its
+location. For example: `set PYTHON=C:\Python27\python.exe`
To build with Visual Studio, launch a git shell (e.g. Cmd or PowerShell)
and run vcbuild.bat which will checkout the GYP code into build/gyp and
[node.js]: http://nodejs.org/
[GYP]: http://code.google.com/p/gyp/
+[Python]: https://www.python.org/downloads/
[Visual Studio Express 2010]: http://www.microsoft.com/visualstudio/eng/products/visual-studio-2010-express
[guidelines for contributing]: https://github.com/joyent/libuv/blob/master/CONTRIBUTING.md
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_PREREQ(2.57)
-AC_INIT([libuv], [0.11.25], [https://github.com/joyent/libuv/issues])
+AC_INIT([libuv], [0.11.26], [https://github.com/joyent/libuv/issues])
AC_CONFIG_MACRO_DIR([m4])
m4_include([m4/libuv-extra-automake-flags.m4])
m4_include([m4/as_case.m4])
#define UV_HAVE_KQUEUE 1
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
-
#endif /* UV_BSD_H */
#define UV_HAVE_KQUEUE 1
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
-
#endif /* UV_DARWIN_H */
#define UV__EAI_OVERFLOW (-3009)
#define UV__EAI_SERVICE (-3010)
#define UV__EAI_SOCKTYPE (-3011)
-#define UV__EAI_SYSTEM (-3012) /* TODO(bnoordhuis) Return system error. */
#define UV__EAI_BADHINTS (-3013)
#define UV__EAI_PROTOCOL (-3014)
void* watchers[2]; \
int wd; \
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
-
#endif /* UV_LINUX_H */
#endif /* defined(PORT_SOURCE_FILE) */
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
-
#endif /* UV_SUNOS_H */
# include "uv-bsd.h"
#endif
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
#endif
struct addrinfo* res; \
int retcode;
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
#define UV_PROCESS_PRIVATE_FIELDS \
void* queue[2]; \
int status; \
#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 11
-#define UV_VERSION_PATCH 25
+#define UV_VERSION_PATCH 26
#define UV_VERSION_IS_RELEASE 1
#endif /* UV_VERSION_H */
struct addrinfoW* res; \
int retcode;
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
#define UV_PROCESS_PRIVATE_FIELDS \
struct uv_process_exit_s { \
UV_REQ_FIELDS \
int uv_utf8_to_utf16(const char* utf8Buffer, WCHAR* utf16Buffer,
size_t utf16Size);
-#define UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
XX(EAI_PROTOCOL, "resolved protocol is unknown") \
XX(EAI_SERVICE, "service not available for socket type") \
XX(EAI_SOCKTYPE, "socket type not supported") \
- XX(EAI_SYSTEM, "system error") \
XX(EALREADY, "connection already in progress") \
XX(EBADF, "bad file descriptor") \
XX(EBUSY, "resource busy or locked") \
XX(FS, fs) \
XX(WORK, work) \
XX(GETADDRINFO, getaddrinfo) \
+ XX(GETNAMEINFO, getnameinfo) \
typedef enum {
#define XX(code, _) UV_ ## code = UV__ ## code,
/* Request types. */
typedef struct uv_req_s uv_req_t;
typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
+typedef struct uv_getnameinfo_s uv_getnameinfo_t;
typedef struct uv_shutdown_s uv_shutdown_t;
typedef struct uv_write_s uv_write_t;
typedef struct uv_connect_s uv_connect_t;
UV_EXTERN void uv_loop_delete(uv_loop_t*);
/*
+ * Returns size of the loop struct, useful for dynamic lookup with FFI
+ */
+UV_EXTERN size_t uv_loop_size(void);
+
+/*
* This function runs the event loop. It will act differently depending on the
* specified mode:
* - UV_RUN_DEFAULT: Runs the event loop until the reference count drops to
* or requests left), or non-zero if more events are expected (meaning you
* should run the event loop again sometime in the future).
* - UV_RUN_NOWAIT: Poll for new events once but don't block if there are no
- * pending events.
+ * pending events. Returns zero when done (no active handles
+ * or requests left), or non-zero if more events are expected (meaning you
+ * should run the event loop again sometime in the future).
*/
UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
int status,
struct addrinfo* res);
+typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
+ int status,
+ const char* hostname,
+ const char* service);
typedef struct {
long tv_sec;
UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
+/*
+* uv_getnameinfo_t is a subclass of uv_req_t
+*
+* Request object for uv_getnameinfo.
+*/
+struct uv_getnameinfo_s {
+ UV_REQ_FIELDS
+ /* read-only */
+ uv_loop_t* loop;
+ UV_GETNAMEINFO_PRIVATE_FIELDS
+};
+
+/*
+ * Asynchronous getnameinfo.
+ *
+ * Returns 0 on success or an error code < 0 on failure.
+ *
+ * If successful, your callback gets called sometime in the future with the
+ * lookup result.
+ */
+UV_EXTERN int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags);
+
+
/* uv_spawn() options */
typedef enum {
UV_IGNORE = 0x00,
/*
* Returns the last uv_dlopen() or uv_dlsym() error message.
*/
-UV_EXTERN const char* uv_dlerror(uv_lib_t* lib);
+UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
/*
* The mutex functions return 0 on success or an error code < 0
UV_EXTERN void uv_cond_destroy(uv_cond_t* cond);
UV_EXTERN void uv_cond_signal(uv_cond_t* cond);
UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond);
+
+/*
+ * Same goes for the barrier functions. Note that uv_barrier_wait() returns
+ * a value > 0 to an arbitrarily chosen "serializer" thread to facilitate
+ * cleanup, i.e.:
+ *
+ * if (uv_barrier_wait(&barrier) > 0)
+ * uv_barrier_destroy(&barrier);
+ */
+UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count);
+UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier);
+UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier);
+
/* Waits on a condition variable without a timeout.
*
* Note:
UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex,
uint64_t timeout);
-UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count);
-UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier);
-UV_EXTERN void uv_barrier_wait(uv_barrier_t* barrier);
-
/* Runs a function once and only once. Concurrent calls to uv_once() with the
* same guard will block all callers except one (it's unspecified which one).
* The guard should be initialized statically with the UV_ONCE_INIT macro.
UV_EXTERN void* uv_key_get(uv_key_t* key);
UV_EXTERN void uv_key_set(uv_key_t* key, void* value);
-UV_EXTERN int uv_thread_create(uv_thread_t *tid,
- void (*entry)(void *arg), void *arg);
+/*
+ * Callback that is invoked to initialize thread execution.
+ *
+ * `arg` is the same value that was passed to uv_thread_create().
+ */
+typedef void (*uv_thread_cb)(void* arg);
+
+UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
UV_EXTERN unsigned long uv_thread_self(void);
UV_EXTERN int uv_thread_join(uv_thread_t *tid);
#undef UV_ASYNC_PRIVATE_FIELDS
#undef UV_TIMER_PRIVATE_FIELDS
#undef UV_GETADDRINFO_PRIVATE_FIELDS
+#undef UV_GETNAMEINFO_PRIVATE_FIELDS
#undef UV_FS_REQ_PRIVATE_FIELDS
#undef UV_WORK_PRIVATE_FIELDS
#undef UV_FS_EVENT_PRIVATE_FIELDS
break;
heap_node_swap(heap, child, smallest);
}
+
+ /* Walk up the subtree and check that each parent is less than the node
+ * this is required, because `max` node is not guaranteed to be the
+ * actual maximum in tree
+ */
+ while (child->parent != NULL && less_than(child, child->parent))
+ heap_node_swap(heap, child->parent, child);
}
HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
#include "uv.h"
#include "uv-common.h"
+#define UV__INET_ADDRSTRLEN 16
+#define UV__INET6_ADDRSTRLEN 46
+
static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
static const char fmt[] = "%u.%u.%u.%u";
- char tmp[sizeof "255.255.255.255"];
+ char tmp[UV__INET_ADDRSTRLEN];
int l;
#ifndef _WIN32
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
- char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+ char tmp[UV__INET6_ADDRSTRLEN], *tp;
struct { int base, len; } best, cur;
unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
int i;
int uv_inet_pton(int af, const char* src, void* dst) {
+ if (src == NULL || dst == NULL)
+ return UV_EINVAL;
+
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
- case AF_INET6:
- return (inet_pton6(src, dst));
+ case AF_INET6: {
+ int len;
+ char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
+ s = (char*) src;
+ p = strchr(src, '%');
+ if (p != NULL) {
+ s = tmp;
+ len = p - src;
+ if (len > UV__INET6_ADDRSTRLEN-1)
+ return UV_EINVAL;
+ memcpy(s, src, len);
+ s[len] = '\0';
+ }
+ return inet_pton6(s, dst);
+ }
default:
return UV_EAFNOSUPPORT;
}
curtok = src;
seen_xdigits = 0;
val = 0;
- while ((ch = *src++) != '\0' && ch != '%') {
+ while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
continue;
}
if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
- int err;
-
- /* Scope id present, parse ipv4 addr without it */
- pch = strchr(curtok, '%');
- if (pch != NULL) {
- char tmp[sizeof "255.255.255.255"];
-
- memcpy(tmp, curtok, pch - curtok);
- curtok = tmp;
- src = pch;
- }
-
- err = inet_pton4(curtok, tp);
+ int err = inet_pton4(curtok, tp);
if (err == 0) {
tp += sizeof(struct in_addr);
seen_xdigits = 0;
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
fd = uv__open_cloexec(buf, O_RDWR);
- if (fd != -1) {
+ if (fd >= 0) {
uv__close(pipefd[0]);
uv__close(pipefd[1]);
pipefd[0] = fd;
uv__update_time(loop);
uv__run_timers(loop);
+ uv__run_pending(loop);
uv__run_idle(loop);
uv__run_prepare(loop);
- uv__run_pending(loop);
timeout = 0;
if ((mode & UV_RUN_NOWAIT) == 0)
uint64_t uv__hrtime(uv_clocktype_t type) {
- mach_timebase_info_data_t info;
+ static mach_timebase_info_data_t info;
- if (mach_timebase_info(&info) != KERN_SUCCESS)
+ if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
+ ACCESS_ONCE(uint32_t, info.denom) == 0) &&
+ mach_timebase_info(&info) != KERN_SUCCESS)
abort();
return mach_absolute_time() * info.numer / info.denom;
}
-const char* uv_dlerror(uv_lib_t* lib) {
+const char* uv_dlerror(const uv_lib_t* lib) {
return lib->errmsg ? lib->errmsg : "no error";
}
for (i = 0; i < numcpus; i++) {
cpu_info = &(*cpu_infos)[i];
-
+
cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
--- /dev/null
+/* 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 <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ int err;
+ socklen_t salen;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+
+ if (req->storage.ss_family == AF_INET)
+ salen = sizeof(struct sockaddr_in);
+ else if (req->storage.ss_family == AF_INET6)
+ salen = sizeof(struct sockaddr_in6);
+ else
+ abort();
+
+ err = getnameinfo((struct sockaddr*) &req->storage,
+ salen,
+ req->host,
+ sizeof(req->host),
+ req->service,
+ sizeof(req->service),
+ req->flags);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == -ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || getnameinfo_cb == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+
+ return 0;
+}
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
- return -EINVAL;
+ return 0;
uv__handle_stop(handle);
struct watcher_list* w;
if (!uv__is_active(handle))
- return -EINVAL;
+ return 0;
w = find_watcher(handle->loop, handle->wd);
assert(w != NULL);
}
cpu_info = &(*cpu_infos)[i];
-
+
cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
*/
static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
int err;
+ int emfile_fd;
if (loop->emfile_fd == -1)
return -EMFILE;
uv__close(err);
} while (err >= 0 || err == -EINTR);
- SAVE_ERRNO(loop->emfile_fd = uv__open_cloexec("/", O_RDONLY));
+ emfile_fd = uv__open_cloexec("/", O_RDONLY);
+ if (emfile_fd >= 0)
+ loop->emfile_fd = emfile_fd;
+
return err;
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
- return -EINVAL;
+ return 0;
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
port_dissociate(handle->loop->fs_fd,
}
-void uv_barrier_wait(uv_barrier_t* barrier) {
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
uv_mutex_lock(&barrier->mutex);
if (++barrier->count == barrier->n) {
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile1);
uv_mutex_lock(&barrier->mutex);
- if (--barrier->count == 0) {
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile2);
}
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
}
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
}
-void uv_barrier_wait(uv_barrier_t* barrier) {
+int uv_barrier_wait(uv_barrier_t* barrier) {
int r = pthread_barrier_wait(barrier);
if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
abort();
+ return r == PTHREAD_BARRIER_SERIAL_THREAD;
}
#endif /* defined(__APPLE__) && defined(__MACH__) */
loop = ((uv_getaddrinfo_t*) req)->loop;
wreq = &((uv_getaddrinfo_t*) req)->work_req;
break;
+ case UV_GETNAMEINFO:
+ loop = ((uv_getnameinfo_t*) req)->loop;
+ wreq = &((uv_getnameinfo_t*) req)->work_req;
+ break;
case UV_WORK:
loop = ((uv_work_t*) req)->loop;
wreq = &((uv_work_t*) req)->work_req;
fd = handle->io_watcher.fd;
if (fd == -1) {
- fd = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
- if (fd == -1)
- return -errno;
+ err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (err < 0)
+ return err;
+ fd = err;
handle->io_watcher.fd = fd;
}
}
int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
- int err;
struct sockaddr_storage addr_st;
struct sockaddr_in* addr4;
struct sockaddr_in6* addr6;
}
if (addr_st.ss_family == AF_INET) {
- err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
- if (err)
- return err;
if (setsockopt(handle->io_watcher.fd,
IPPROTO_IP,
IP_MULTICAST_IF,
return -errno;
}
} else if (addr_st.ss_family == AF_INET6) {
- err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
- if (err)
- return err;
if (setsockopt(handle->io_watcher.fd,
IPPROTO_IPV6,
IPV6_MULTICAST_IF,
#include <stdlib.h> /* malloc */
#include <string.h> /* memset */
-#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS) && !defined(_WIN32)
+#if !defined(_WIN32)
# include <net/if.h> /* if_nametoindex */
#endif
#undef XX
+size_t uv_loop_size(void) {
+ return sizeof(uv_loop_t);
+}
+
+
uv_buf_t uv_buf_init(char* base, unsigned int len) {
uv_buf_t buf;
buf.base = base;
int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
-#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS)
char address_part[40];
size_t address_part_size;
const char* zone_index;
-#endif
memset(addr, 0, sizeof(*addr));
addr->sin6_family = AF_INET6;
addr->sin6_port = htons(port);
-#if defined(UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS)
zone_index = strchr(ip, '%');
if (zone_index != NULL) {
address_part_size = zone_index - ip;
addr->sin6_scope_id = if_nametoindex(zone_index);
#endif
}
-#endif
return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
}
case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
#endif
#if defined(EAI_SYSTEM)
- case EAI_SYSTEM: return UV_EAI_SYSTEM;
+ case EAI_SYSTEM: return -errno;
#endif
}
assert(!"unknown EAI_* error code");
static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
return FALSE;
-
+
if (ret_val) {
/* Set ret_val to 0 to continue with normal execution. */
/* Set ret_val to 1 to trigger a breakpoint. */
- if(IsDebuggerPresent())
- *ret_val = 1;
+ if(IsDebuggerPresent())
+ *ret_val = 1;
else
- *ret_val = 0;
+ *ret_val = 0;
}
/* Don't call _CrtDbgReport. */
}
-const char* uv_dlerror(uv_lib_t* lib) {
+const char* uv_dlerror(const uv_lib_t* lib) {
return lib->errmsg ? lib->errmsg : "no error";
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
- return UV_EINVAL;
+ return 0;
if (handle->dir_handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle->dir_handle);
VERIFY_FD(fd, req);
handle = uv__get_osfhandle(fd);
-
+
if (handle == INVALID_HANDLE_VALUE) {
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
return;
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
if (name_len == 0) {
- /* FIXME(bnoordhuis) Retain GetLastError(). */
- err = UV_EAI_SYSTEM;
+ err = uv_translate_sys_error(GetLastError());
goto complete;
}
addrinfo_len += ALIGNED_SIZE(name_len);
--- /dev/null
+/* 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 <assert.h>
+#include <malloc.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+
+/* getnameinfo worker thread implementation */
+static DWORD WINAPI getnameinfo_thread_proc(void* parameter) {
+ uv_getnameinfo_t* req = (uv_getnameinfo_t*)parameter;
+ uv_loop_t* loop = req->loop;
+ WCHAR host[NI_MAXHOST];
+ WCHAR service[NI_MAXSERV];
+ int ret = 0;
+
+ assert(req != NULL);
+
+ ret = GetNameInfoW((struct sockaddr*)&req->storage,
+ sizeof(req->storage),
+ host,
+ sizeof(host),
+ service,
+ sizeof(service),
+ req->flags);
+ req->retcode = uv__getaddrinfo_translate_error(ret);
+
+ /* convert results to UTF-8 */
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ host,
+ -1,
+ req->host,
+ sizeof(req->host),
+ NULL,
+ NULL);
+
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ service,
+ -1,
+ req->service,
+ sizeof(req->service),
+ NULL,
+ NULL);
+
+ /* post getnameinfo completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+/*
+* Called from uv_run when complete.
+*/
+void uv_process_getnameinfo_req(uv_loop_t* loop, uv_getnameinfo_t* req) {
+ char* host;
+ char* service;
+
+ if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ } else {
+ host = NULL;
+ service = NULL;
+ }
+
+ uv__req_unregister(loop, req);
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || getnameinfo_cb == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv_req_init(loop, (uv_req_t*)req);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+
+ /* Ask thread to run. Treat this as a long operation. */
+ if (QueueUserWorkItem(&getnameinfo_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION) == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ uv__req_register(loop, req);
+
+ return 0;
+}
/* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
/* for invalid FDs in release builds (or if you let the assert continue). */
/* So this wrapper function disables asserts when calling _get_osfhandle. */
-
+
HANDLE handle;
UV_BEGIN_DISABLE_CRT_ASSERT();
handle = (HANDLE) _get_osfhandle(fd);
{ \
int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
uv__crt_assert_enabled = FALSE;
-
+
#define UV_END_DISABLE_CRT_ASSERT() \
uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
/*
+* Getnameinfo
+*/
+void uv_process_getnameinfo_req(uv_loop_t* loop, uv_getnameinfo_t* req);
+
+
+/*
* FS
*/
void uv_fs_init();
}
-static HANDLE open_named_pipe(WCHAR* name, DWORD* duplex_flags) {
+static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) {
HANDLE pipeHandle;
/*
if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
/* Stop polling. */
handle->events = 0;
- uv__handle_stop(handle);
+ if (uv__is_active(handle))
+ uv__handle_stop(handle);
}
if (events != 0) {
int quote_hit;
WCHAR* start;
- /*
- * Check if the string must be quoted;
- * if unnecessary, don't do it, it may only confuse older programs.
- */
if (len == 0) {
+ /* Need double quotation for empty argument */
+ *(target++) = L'"';
+ *(target++) = L'"';
return target;
}
/* Spawn succeeded */
/* Beyond this point, failure is reported asynchronously. */
-
+
process->process_handle = info.hProcess;
process->pid = info.dwProcessId;
CloseHandle(info.hThread);
- assert(!err);
-
+ assert(!err);
+
/* Make the handle active. It will remain active until the exit callback */
/* iis made or the handle is closed, whichever happens first. */
uv__handle_start(process);
uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req);
break;
+ case UV_GETNAMEINFO:
+ uv_process_getnameinfo_req(loop, (uv_getnameinfo_t*)req);
+ break;
+
case UV_PROCESS_EXIT:
uv_process_proc_exit(loop, (uv_process_t*) req->data);
break;
if (handle->socket == INVALID_SOCKET) {
SOCKET sock;
-
+
/* Cannot set IPv6-only mode on non-IPv6 socket. */
if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
return ERROR_INVALID_PARAMETER;
req->type = UV_WRITE;
req->handle = (uv_stream_t*) handle;
req->cb = cb;
- memset(&req->overlapped, 0, sizeof(req->overlapped));
/* Prepare the overlapped structure. */
memset(&(req->overlapped), 0, sizeof(req->overlapped));
}
-void uv_barrier_wait(uv_barrier_t* barrier) {
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
uv_mutex_lock(&barrier->mutex);
if (++barrier->count == barrier->n) {
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile1);
uv_mutex_lock(&barrier->mutex);
- if (--barrier->count == 0) {
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile2);
}
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
}
#define ANSI_IN_STRING 0x40
#define ANSI_BACKSLASH_SEEN 0x80
+#define MAX_INPUT_BUFFER_LENGTH 8192
+
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
uv_tty_t* handle;
uv_req_t* req;
DWORD bytes, read_bytes;
+ WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
+ DWORD chars, read_chars;
assert(data);
assert(handle->read_line_buffer.len > 0);
/* ReadConsole can't handle big buffers. */
- if (handle->read_line_buffer.len < 8192) {
+ if (handle->read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
bytes = handle->read_line_buffer.len;
} else {
- bytes = 8192;
+ bytes = MAX_INPUT_BUFFER_LENGTH;
}
- /* Todo: Unicode */
- if (ReadConsoleA(handle->read_line_handle,
- (void*) handle->read_line_buffer.base,
- bytes,
- &read_bytes,
+ /* At last, unicode! */
+ /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
+ chars = bytes / 3;
+
+ if (ReadConsoleW(handle->read_line_handle,
+ (void*) utf16,
+ chars,
+ &read_chars,
NULL)) {
+ read_bytes = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ read_chars,
+ handle->read_line_buffer.base,
+ bytes,
+ NULL,
+ NULL);
SET_REQ_SUCCESS(req);
req->overlapped.InternalHigh = read_bytes;
} else {
return 0;
}
+#define FLIP_FGBG \
+ do { \
+ WORD fg = info.wAttributes & 0xF; \
+ WORD bg = info.wAttributes & 0xF0; \
+ info.wAttributes &= 0xFF00; \
+ info.wAttributes |= fg << 4; \
+ info.wAttributes |= bg >> 4; \
+ } while (0)
static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
unsigned short argc = handle->ansi_csi_argc;
char fg_color = -1, bg_color = -1;
char fg_bright = -1, bg_bright = -1;
+ char inverse = -1;
if (argc == 0) {
/* Reset mode */
bg_color = 0;
fg_bright = 0;
bg_bright = 0;
+ inverse = 0;
}
for (i = 0; i < argc; i++) {
bg_color = 0;
fg_bright = 0;
bg_bright = 0;
+ inverse = 0;
} else if (arg == 1) {
/* Foreground bright on */
/* Background bright on */
bg_bright = 1;
+ } else if (arg == 7) {
+ /* Inverse: on */
+ inverse = 1;
+
} else if (arg == 21 || arg == 22) {
/* Foreground bright off */
fg_bright = 0;
/* Background bright off */
bg_bright = 0;
+ } else if (arg == 27) {
+ /* Inverse: off */
+ inverse = 0;
+
} else if (arg >= 30 && arg <= 37) {
/* Set foreground color */
fg_color = arg - 30;
}
if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
- bg_bright == -1) {
+ bg_bright == -1 && inverse == -1) {
/* Nothing changed */
return 0;
}
return -1;
}
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
if (fg_color != -1) {
info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
}
}
+ if (inverse != -1) {
+ if (inverse) {
+ info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
+ } else {
+ info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
+ }
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
*error = GetLastError();
return -1;
return 0;
}
+static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
+ BOOL visible,
+ DWORD* error) {
+ CONSOLE_CURSOR_INFO cursor_info;
+
+ if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ cursor_info.bVisible = visible;
+
+ if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
static int uv_tty_write_bufs(uv_tty_t* handle,
const uv_buf_t bufs[],
continue;
}
+ } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
+ handle->ansi_csi_argc == 0) {
+ /* Ignores '?' if it is the first character after CSI[ */
+ /* This is an extension character from the VT100 codeset */
+ /* that is supported and used by most ANSI terminals today. */
+ continue;
+
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
(handle->ansi_csi_argc > 0 || utf8_codepoint != '[')) {
int x, y, d;
FLUSH_TEXT();
uv_tty_restore_state(handle, 0, error);
break;
+
+ case 'l':
+ /* Hide the cursor */
+ if (handle->ansi_csi_argc == 1 &&
+ handle->ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 0, error);
+ }
+ break;
+
+ case 'h':
+ /* Show the cursor */
+ if (handle->ansi_csi_argc == 1 &&
+ handle->ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 1, error);
+ }
+ break;
}
/* Sequence ended - go back to normal state. */
int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
- int err;
struct sockaddr_storage addr_st;
struct sockaddr_in* addr4;
struct sockaddr_in6* addr6;
return UV_EINVAL;
}
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
if (addr_st.ss_family == AF_INET) {
- 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);
if (setsockopt(handle->socket,
IPPROTO_IP,
IP_MULTICAST_IF,
return uv_translate_sys_error(WSAGetLastError());
}
} else if (addr_st.ss_family == AF_INET6) {
- 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);
if (setsockopt(handle->socket,
IPPROTO_IPV6,
IPV6_MULTICAST_IF,
int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
BOOL optval = (BOOL) value;
- int err;
- /* 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_),
- 0);
- if (err)
- return uv_translate_sys_error(err);
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
if (setsockopt(handle->socket,
SOL_SOCKET,
#define SOCKOPT_SETTER(name, option4, option6, validate) \
int uv_udp_set_##name(uv_udp_t* handle, int value) { \
DWORD optval = (DWORD) value; \
- int err; \
\
if (!(validate(value))) { \
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_), \
- 0); \
- if (err) \
- return uv_translate_sys_error(err); \
+ if (!(handle->flags & UV_HANDLE_BOUND)) \
+ return UV_EBADF; \
\
if (!(handle->flags & UV_HANDLE_IPV6)) { \
/* Set IPv4 socket option */ \
MEMORYSTATUSEX memory_status;
memory_status.dwLength = sizeof(memory_status);
- if(!GlobalMemoryStatusEx(&memory_status))
- {
+ if (!GlobalMemoryStatusEx(&memory_status)) {
return -1;
}
MEMORYSTATUSEX memory_status;
memory_status.dwLength = sizeof(memory_status);
- if(!GlobalMemoryStatusEx(&memory_status))
- {
+ if (!GlobalMemoryStatusEx(&memory_status)) {
return -1;
}
if (!length) {
err = GetLastError();
goto done;
- };
+ }
/* If the title must be truncated insert a \0 terminator there */
if (length > MAX_TITLE_LENGTH) {
uv_barrier_t barrier;
int delay;
volatile int posted;
+ int main_barrier_wait_rval;
+ int worker_barrier_wait_rval;
} worker_config;
if (c->delay)
uv_sleep(c->delay);
- uv_barrier_wait(&c->barrier);
+ c->worker_barrier_wait_rval = uv_barrier_wait(&c->barrier);
+ if (c->worker_barrier_wait_rval == 1) {
+ uv_barrier_destroy(&c->barrier);
+ ASSERT(c->main_barrier_wait_rval == 0);
+ }
}
worker_config wc;
memset(&wc, 0, sizeof(wc));
+ wc.main_barrier_wait_rval = -1;
+ wc.worker_barrier_wait_rval = -1;
ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
uv_sleep(100);
- uv_barrier_wait(&wc.barrier);
+
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+ if (wc.main_barrier_wait_rval == 1) {
+ uv_barrier_destroy(&wc.barrier);
+ ASSERT(wc.worker_barrier_wait_rval == 0);
+ }
ASSERT(0 == uv_thread_join(&thread));
- uv_barrier_destroy(&wc.barrier);
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0;
}
memset(&wc, 0, sizeof(wc));
wc.delay = 100;
+ wc.main_barrier_wait_rval = -1;
+ wc.worker_barrier_wait_rval = -1;
ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
- uv_barrier_wait(&wc.barrier);
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+ if (wc.main_barrier_wait_rval == 1) {
+ uv_barrier_destroy(&wc.barrier);
+ ASSERT(wc.worker_barrier_wait_rval == 0);
+ }
ASSERT(0 == uv_thread_join(&thread));
- uv_barrier_destroy(&wc.barrier);
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0;
}
worker_config wc;
memset(&wc, 0, sizeof(wc));
+ wc.main_barrier_wait_rval = -1;
+ wc.worker_barrier_wait_rval = -1;
ASSERT(0 == uv_barrier_init(&wc.barrier, 2));
ASSERT(0 == uv_thread_create(&thread, worker, &wc));
- uv_barrier_wait(&wc.barrier);
+ wc.main_barrier_wait_rval = uv_barrier_wait(&wc.barrier);
+ if (wc.main_barrier_wait_rval == 1) {
+ uv_barrier_destroy(&wc.barrier);
+ ASSERT(wc.worker_barrier_wait_rval == 0);
+ }
ASSERT(0 == uv_thread_join(&thread));
- uv_barrier_destroy(&wc.barrier);
+ ASSERT(1 == (wc.main_barrier_wait_rval ^ wc.worker_barrier_wait_rval));
return 0;
}
# include <io.h>
# define unlink _unlink
# define rmdir _rmdir
-# define stat _stati64
# define open _open
# define write _write
-# define lseek _lseek
# define close _close
+# ifndef stat
+# define stat _stati64
+# endif
+# ifndef lseek
+# define lseek _lseek
+# endif
#endif
#define TOO_LONG_NAME_LENGTH 65536
--- /dev/null
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static const char* address_ip4 = "127.0.0.1";
+static const char* address_ip6 = "::1";
+static const int port = 80;
+
+static struct sockaddr_in addr4;
+static struct sockaddr_in6 addr6;
+static uv_getnameinfo_t req;
+
+static void getnameinfo_req(uv_getnameinfo_t* handle,
+ int status,
+ const char* hostname,
+ const char* service) {
+ ASSERT(handle != NULL);
+ ASSERT(status == 0);
+ ASSERT(hostname != NULL);
+ ASSERT(service != NULL);
+}
+
+TEST_IMPL(getnameinfo_basic_ip4) {
+ int r;
+
+ r = uv_ip4_addr(address_ip4, port, &addr4);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(uv_default_loop(),
+ &req,
+ &getnameinfo_req,
+ (const struct sockaddr*)&addr4,
+ 0);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+TEST_IMPL(getnameinfo_basic_ip6) {
+ int r;
+
+ r = uv_ip6_addr(address_ip6, port, &addr6);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(uv_default_loop(),
+ &req,
+ &getnameinfo_req,
+ (const struct sockaddr*)&addr6,
+ 0);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
TEST_IMPL(ip6_addr_link_local) {
-#ifdef UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS
char string_address[INET6_ADDRSTRLEN];
uv_interface_address_t* addresses;
uv_interface_address_t* address;
MAKE_VALGRIND_HAPPY();
return 0;
-#else
- RETURN_SKIP("Qualified link-local addresses are not supported.");
-#endif
}
X("fe80::2acf:daff:fedd:342a") \
X("fe80:0:0:0:2acf:daff:fedd:342a") \
X("fe80:0:0:0:2acf:daff:1.2.3.4") \
+ X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") \
#define BAD_ADDR_LIST(X) \
X(":::1") \
X("fe80:0:0:0:2acf:daff:fedd:342a:5678") \
X("fe80:0:0:0:2acf:daff:abcd:1.2.3.4") \
X("fe80:0:0:2acf:daff:1.2.3.4.5") \
+ X("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255.255") \
#define TEST_GOOD(ADDR) \
ASSERT(0 == uv_inet_pton(AF_INET6, ADDR, &addr)); \
TEST_DECLARE (udp_dual_stack)
TEST_DECLARE (udp_ipv6_only)
TEST_DECLARE (udp_options)
+TEST_DECLARE (udp_no_autobind)
TEST_DECLARE (udp_open)
TEST_DECLARE (pipe_bind_error_addrinuse)
TEST_DECLARE (pipe_bind_error_addrnotavail)
TEST_DECLARE (getaddrinfo_fail)
TEST_DECLARE (getaddrinfo_basic)
TEST_DECLARE (getaddrinfo_concurrent)
+TEST_DECLARE (getnameinfo_basic_ip4)
+TEST_DECLARE (getnameinfo_basic_ip6)
TEST_DECLARE (getsockname_tcp)
TEST_DECLARE (getsockname_udp)
TEST_DECLARE (fail_always)
TEST_DECLARE (threadpool_queue_work_einval)
TEST_DECLARE (threadpool_multiple_event_loops)
TEST_DECLARE (threadpool_cancel_getaddrinfo)
+TEST_DECLARE (threadpool_cancel_getnameinfo)
TEST_DECLARE (threadpool_cancel_work)
TEST_DECLARE (threadpool_cancel_fs)
TEST_DECLARE (threadpool_cancel_single)
TEST_DECLARE (poll_duplex)
TEST_DECLARE (poll_unidirectional)
TEST_DECLARE (poll_close)
+
TEST_DECLARE (ip4_addr)
TEST_DECLARE (ip6_addr_link_local)
+
#ifdef _WIN32
+TEST_DECLARE (poll_closesocket)
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
TEST_DECLARE (argument_escaping)
TEST_DECLARE (environment_creation)
TEST_ENTRY (udp_dual_stack)
TEST_ENTRY (udp_ipv6_only)
TEST_ENTRY (udp_options)
+ TEST_ENTRY (udp_no_autobind)
TEST_ENTRY (udp_multicast_interface)
TEST_ENTRY (udp_multicast_interface6)
TEST_ENTRY (udp_multicast_join)
TEST_ENTRY (getaddrinfo_basic)
TEST_ENTRY (getaddrinfo_concurrent)
+ TEST_ENTRY (getnameinfo_basic_ip4)
+ TEST_ENTRY (getnameinfo_basic_ip6)
+
TEST_ENTRY (getsockname_tcp)
TEST_ENTRY (getsockname_udp)
TEST_ENTRY (kill)
#ifdef _WIN32
+ TEST_ENTRY (poll_closesocket)
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
TEST_ENTRY (argument_escaping)
TEST_ENTRY (environment_creation)
TEST_ENTRY (threadpool_queue_work_einval)
TEST_ENTRY (threadpool_multiple_event_loops)
TEST_ENTRY (threadpool_cancel_getaddrinfo)
+ TEST_ENTRY (threadpool_cancel_getnameinfo)
TEST_ENTRY (threadpool_cancel_work)
TEST_ENTRY (threadpool_cancel_fs)
TEST_ENTRY (threadpool_cancel_single)
--- /dev/null
+/* 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.
+ */
+
+#ifdef _WIN32
+
+#include <errno.h>
+
+#include "uv.h"
+#include "task.h"
+
+uv_os_sock_t sock;
+uv_poll_t handle;
+
+static int close_cb_called = 0;
+
+
+static void close_cb(uv_handle_t* h) {
+ close_cb_called++;
+}
+
+
+static void poll_cb(uv_poll_t* h, int status, int events) {
+ int r;
+
+ ASSERT(status == 0);
+ ASSERT(h == &handle);
+
+ r = uv_poll_start(&handle, UV_READABLE, poll_cb);
+ ASSERT(r == 0);
+
+ closesocket(sock);
+ uv_close((uv_handle_t*) &handle, close_cb);
+
+}
+
+
+TEST_IMPL(poll_closesocket) {
+ struct WSAData wsa_data;
+ int r;
+ unsigned long on;
+ struct sockaddr_in addr;
+
+ r = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ ASSERT(r == 0);
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ ASSERT(sock != INVALID_SOCKET);
+ on = 1;
+ r = ioctlsocket(sock, FIONBIO, &on);
+ ASSERT(r == 0);
+
+ r = uv_ip4_addr("127.0.0.1", TEST_PORT, &addr);
+ ASSERT(r == 0);
+
+ r = connect(sock, (const struct sockaddr*) &addr, sizeof addr);
+ ASSERT(r != 0);
+ ASSERT(WSAGetLastError() == WSAEWOULDBLOCK);
+
+ r = uv_poll_init_socket(uv_default_loop(), &handle, sock);
+ ASSERT(r == 0);
+ r = uv_poll_start(&handle, UV_WRITABLE, poll_cb);
+ ASSERT(r == 0);
+
+ uv_run(uv_default_loop(), UV_RUN_DEFAULT);
+
+ ASSERT(close_cb_called == 1);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+#endif
TEST_IMPL(argument_escaping) {
const WCHAR* test_str[] = {
+ L"",
L"HelloWorld",
L"Hello World",
L"Hello\"World",
static unsigned done_cb_called;
static unsigned done2_cb_called;
static unsigned timer_cb_called;
-static unsigned getaddrinfo_cb_called;
static void work_cb(uv_work_t* req) {
ASSERT(status == UV_EAI_CANCELED);
ASSERT(res == NULL);
uv_freeaddrinfo(res); /* Should not crash. */
- getaddrinfo_cb_called++;
+}
+
+
+static void getnameinfo_cb(uv_getnameinfo_t* handle,
+ int status,
+ const char* hostname,
+ const char* service) {
+ ASSERT(status == UV_EAI_CANCELED);
+ ASSERT(hostname == NULL);
+ ASSERT(service == NULL);
}
}
+TEST_IMPL(threadpool_cancel_getnameinfo) {
+ uv_getnameinfo_t reqs[4];
+ struct sockaddr_in addr4;
+ struct cancel_info ci;
+ uv_loop_t* loop;
+ int r;
+
+ r = uv_ip4_addr("127.0.0.1", 80, &addr4);
+ ASSERT(r == 0);
+
+ INIT_CANCEL_INFO(&ci, reqs);
+ loop = uv_default_loop();
+ saturate_threadpool();
+
+ r = uv_getnameinfo(loop, reqs + 0, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 1, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 2, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ r = uv_getnameinfo(loop, reqs + 3, getnameinfo_cb, (const struct sockaddr*)&addr4, 0);
+ ASSERT(r == 0);
+
+ ASSERT(0 == uv_timer_init(loop, &ci.timer_handle));
+ ASSERT(0 == uv_timer_start(&ci.timer_handle, timer_cb, 10, 0));
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+ ASSERT(1 == timer_cb_called);
+
+ cleanup_threadpool();
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
TEST_IMPL(threadpool_cancel_work) {
struct cancel_info ci;
uv_work_t reqs[16];
MAKE_VALGRIND_HAPPY();
return 0;
}
+
+
+TEST_IMPL(udp_no_autobind) {
+ uv_loop_t* loop;
+ uv_udp_t h;
+
+ loop = uv_default_loop();
+
+ ASSERT(0 == uv_udp_init(loop, &h));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_ttl(&h, 32));
+ ASSERT(UV_EBADF == uv_udp_set_broadcast(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_ttl(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_loop(&h, 1));
+ ASSERT(UV_EBADF == uv_udp_set_multicast_interface(&h, "0.0.0.0"));
+
+ uv_close((uv_handle_t*) &h, NULL);
+
+ ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
'src/win/fs.c',
'src/win/fs-event.c',
'src/win/getaddrinfo.c',
+ 'src/win/getnameinfo.c',
'src/win/handle.c',
'src/win/handle-inl.h',
'src/win/internal.h',
'src/unix/dl.c',
'src/unix/fs.c',
'src/unix/getaddrinfo.c',
+ 'src/unix/getnameinfo.c',
'src/unix/internal.h',
'src/unix/loop.c',
'src/unix/loop-watcher.c',
'test/test-get-currentexe.c',
'test/test-get-memory.c',
'test/test-getaddrinfo.c',
+ 'test/test-getnameinfo.c',
'test/test-getsockname.c',
'test/test-hrtime.c',
'test/test-idle.c',
'test/test-platform-output.c',
'test/test-poll.c',
'test/test-poll-close.c',
+ 'test/test-poll-closesocket.c',
'test/test-process-title.c',
'test/test-ref.c',
'test/test-run-nowait.c',
set GYP_MSVS_VERSION=2013
goto select-target
-@rem Look for Visual Studio 2012
:vc-set-2012
+@rem Look for Visual Studio 2012
if not defined VS110COMNTOOLS goto vc-set-2010
if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010
call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset%
exit /b 1
:have_gyp
-if not defined PYTHON set PYTHON="python"
-%PYTHON% gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library%
+if not defined PYTHON set PYTHON=python
+"%PYTHON%" gyp_uv.py -Dtarget_arch=%target_arch% -Duv_library=%library%
if errorlevel 1 goto create-msvs-files-failed
if not exist uv.sln goto create-msvs-files-failed
echo Project files generated.