Merge branches/quickjs to trunk. This is the way.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3621 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2021-01-02 18:10:00 +00:00
parent d293637741
commit 79022e1e1f
703 changed files with 419987 additions and 30640 deletions

98
deps/libuv/src/win/async.c vendored Normal file
View File

@ -0,0 +1,98 @@
/* 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 "uv.h"
#include "internal.h"
#include "atomicops-inl.h"
#include "handle-inl.h"
#include "req-inl.h"
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING &&
!handle->async_sent) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
uv__handle_close(handle);
}
}
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
uv_req_t* req;
uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
handle->async_sent = 0;
handle->async_cb = async_cb;
req = &handle->async_req;
UV_REQ_INIT(req, UV_WAKEUP);
req->data = handle;
uv__handle_start(handle);
return 0;
}
void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
if (!((uv_async_t*)handle)->async_sent) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
uv__handle_closing(handle);
}
int uv_async_send(uv_async_t* handle) {
uv_loop_t* loop = handle->loop;
if (handle->type != UV_ASYNC) {
/* Can't set errno because that's not thread-safe. */
return -1;
}
/* The user should make sure never to call uv_async_send to a closing or
* closed handle. */
assert(!(handle->flags & UV_HANDLE_CLOSING));
if (!uv__atomic_exchange_set(&handle->async_sent)) {
POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
}
return 0;
}
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req) {
assert(handle->type == UV_ASYNC);
assert(req->type == UV_WAKEUP);
handle->async_sent = 0;
if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*)handle);
} else if (handle->async_cb != NULL) {
handle->async_cb(handle);
}
}

57
deps/libuv/src/win/atomicops-inl.h vendored Normal file
View File

@ -0,0 +1,57 @@
/* 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.
*/
#ifndef UV_WIN_ATOMICOPS_INL_H_
#define UV_WIN_ATOMICOPS_INL_H_
#include "uv.h"
#include "internal.h"
/* Atomic set operation on char */
#ifdef _MSC_VER /* MSVC */
/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less
* efficient than InterlockedExchange, but InterlockedExchange8 does not exist,
* and interlocked operations on larger targets might require the target to be
* aligned. */
#pragma intrinsic(_InterlockedOr8)
static char INLINE uv__atomic_exchange_set(char volatile* target) {
return _InterlockedOr8(target, 1);
}
#else /* GCC */
/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
static inline char uv__atomic_exchange_set(char volatile* target) {
const char one = 1;
char old_value;
__asm__ __volatile__ ("lock xchgb %0, %1\n\t"
: "=r"(old_value), "=m"(*target)
: "0"(one), "m"(*target)
: "memory");
return old_value;
}
#endif
#endif /* UV_WIN_ATOMICOPS_INL_H_ */

748
deps/libuv/src/win/core.c vendored Normal file
View File

@ -0,0 +1,748 @@
/* 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 <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
#include <crtdbg.h>
#endif
#include "uv.h"
#include "internal.h"
#include "queue.h"
#include "handle-inl.h"
#include "heap-inl.h"
#include "req-inl.h"
/* uv_once initialization guards */
static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
/* Our crt debug report handler allows us to temporarily disable asserts
* just for the current thread.
*/
UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
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;
else
*ret_val = 0;
}
/* Don't call _CrtDbgReport. */
return TRUE;
}
#else
UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
#endif
#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
const wchar_t* function, const wchar_t * file, unsigned int line,
uintptr_t reserved) {
/* No-op. */
}
#endif
static uv_loop_t** uv__loops;
static int uv__loops_size;
static int uv__loops_capacity;
#define UV__LOOPS_CHUNK_SIZE 8
static uv_mutex_t uv__loops_lock;
static void uv__loops_init(void) {
uv_mutex_init(&uv__loops_lock);
}
static int uv__loops_add(uv_loop_t* loop) {
uv_loop_t** new_loops;
int new_capacity, i;
uv_mutex_lock(&uv__loops_lock);
if (uv__loops_size == uv__loops_capacity) {
new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
if (!new_loops)
goto failed_loops_realloc;
uv__loops = new_loops;
for (i = uv__loops_capacity; i < new_capacity; ++i)
uv__loops[i] = NULL;
uv__loops_capacity = new_capacity;
}
uv__loops[uv__loops_size] = loop;
++uv__loops_size;
uv_mutex_unlock(&uv__loops_lock);
return 0;
failed_loops_realloc:
uv_mutex_unlock(&uv__loops_lock);
return ERROR_OUTOFMEMORY;
}
static void uv__loops_remove(uv_loop_t* loop) {
int loop_index;
int smaller_capacity;
uv_loop_t** new_loops;
uv_mutex_lock(&uv__loops_lock);
for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
if (uv__loops[loop_index] == loop)
break;
}
/* If loop was not found, ignore */
if (loop_index == uv__loops_size)
goto loop_removed;
uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
uv__loops[uv__loops_size - 1] = NULL;
--uv__loops_size;
if (uv__loops_size == 0) {
uv__loops_capacity = 0;
uv__free(uv__loops);
uv__loops = NULL;
goto loop_removed;
}
/* If we didn't grow to big skip downsizing */
if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
goto loop_removed;
/* Downsize only if more than half of buffer is free */
smaller_capacity = uv__loops_capacity / 2;
if (uv__loops_size >= smaller_capacity)
goto loop_removed;
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
if (!new_loops)
goto loop_removed;
uv__loops = new_loops;
uv__loops_capacity = smaller_capacity;
loop_removed:
uv_mutex_unlock(&uv__loops_lock);
}
void uv__wake_all_loops(void) {
int i;
uv_loop_t* loop;
uv_mutex_lock(&uv__loops_lock);
for (i = 0; i < uv__loops_size; ++i) {
loop = uv__loops[i];
assert(loop);
if (loop->iocp != INVALID_HANDLE_VALUE)
PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
}
uv_mutex_unlock(&uv__loops_lock);
}
static void uv_init(void) {
/* Tell Windows that we will handle critical errors. */
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
/* Tell the CRT to not exit the application when an invalid parameter is
* passed. The main issue is that invalid FDs will trigger this behavior.
*/
#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
#endif
/* We also need to setup our debug report handler because some CRT
* functions (eg _get_osfhandle) raise an assert when called with invalid
* FDs even though they return the proper error code in the release build.
*/
#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
_CrtSetReportHook(uv__crt_dbg_report_handler);
#endif
/* Initialize tracking of all uv loops */
uv__loops_init();
/* Fetch winapi function pointers. This must be done first because other
* initialization code might need these function pointers to be loaded.
*/
uv_winapi_init();
/* Initialize winsock */
uv_winsock_init();
/* Initialize FS */
uv_fs_init();
/* Initialize signal stuff */
uv_signals_init();
/* Initialize console */
uv_console_init();
/* Initialize utilities */
uv__util_init();
/* Initialize system wakeup detection */
uv__init_detect_system_wakeup();
}
int uv_loop_init(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
struct heap* timer_heap;
int err;
/* Initialize libuv itself first */
uv__once_init();
/* Create an I/O completion port */
loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
if (loop->iocp == NULL)
return uv_translate_sys_error(GetLastError());
lfields = (uv__loop_internal_fields_t*) uv__calloc(1, sizeof(*lfields));
if (lfields == NULL)
return UV_ENOMEM;
loop->internal_fields = lfields;
err = uv_mutex_init(&lfields->loop_metrics.lock);
if (err)
goto fail_metrics_mutex_init;
/* To prevent uninitialized memory access, loop->time must be initialized
* to zero before calling uv_update_time for the first time.
*/
loop->time = 0;
uv_update_time(loop);
QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->handle_queue);
loop->active_reqs.count = 0;
loop->active_handles = 0;
loop->pending_reqs_tail = NULL;
loop->endgame_handles = NULL;
loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap));
if (timer_heap == NULL) {
err = UV_ENOMEM;
goto fail_timers_alloc;
}
heap_init(timer_heap);
loop->check_handles = NULL;
loop->prepare_handles = NULL;
loop->idle_handles = NULL;
loop->next_prepare_handle = NULL;
loop->next_check_handle = NULL;
loop->next_idle_handle = NULL;
memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
loop->active_tcp_streams = 0;
loop->active_udp_streams = 0;
loop->timer_counter = 0;
loop->stop_flag = 0;
err = uv_mutex_init(&loop->wq_mutex);
if (err)
goto fail_mutex_init;
err = uv_async_init(loop, &loop->wq_async, uv__work_done);
if (err)
goto fail_async_init;
uv__handle_unref(&loop->wq_async);
loop->wq_async.flags |= UV_HANDLE_INTERNAL;
err = uv__loops_add(loop);
if (err)
goto fail_async_init;
return 0;
fail_async_init:
uv_mutex_destroy(&loop->wq_mutex);
fail_mutex_init:
uv__free(timer_heap);
loop->timer_heap = NULL;
fail_timers_alloc:
uv_mutex_destroy(&lfields->loop_metrics.lock);
fail_metrics_mutex_init:
uv__free(lfields);
loop->internal_fields = NULL;
CloseHandle(loop->iocp);
loop->iocp = INVALID_HANDLE_VALUE;
return err;
}
void uv_update_time(uv_loop_t* loop) {
uint64_t new_time = uv__hrtime(1000);
assert(new_time >= loop->time);
loop->time = new_time;
}
void uv__once_init(void) {
uv_once(&uv_init_guard_, uv_init);
}
void uv__loop_close(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
size_t i;
uv__loops_remove(loop);
/* Close the async handle without needing an extra loop iteration.
* We might have a pending message, but we're just going to destroy the IOCP
* soon, so we can just discard it now without the usual risk of a getting
* another notification from GetQueuedCompletionStatusEx after calling the
* close_cb (which we also skip defining). We'll assert later that queue was
* actually empty and all reqs handled. */
loop->wq_async.async_sent = 0;
loop->wq_async.close_cb = NULL;
uv__handle_closing(&loop->wq_async);
uv__handle_close(&loop->wq_async);
for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
SOCKET sock = loop->poll_peer_sockets[i];
if (sock != 0 && sock != INVALID_SOCKET)
closesocket(sock);
}
uv_mutex_lock(&loop->wq_mutex);
assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
assert(!uv__has_active_reqs(loop));
uv_mutex_unlock(&loop->wq_mutex);
uv_mutex_destroy(&loop->wq_mutex);
uv__free(loop->timer_heap);
loop->timer_heap = NULL;
lfields = uv__get_internal_fields(loop);
uv_mutex_destroy(&lfields->loop_metrics.lock);
uv__free(lfields);
loop->internal_fields = NULL;
CloseHandle(loop->iocp);
}
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
uv__loop_internal_fields_t* lfields;
lfields = uv__get_internal_fields(loop);
if (option == UV_METRICS_IDLE_TIME) {
lfields->flags |= UV_METRICS_IDLE_TIME;
return 0;
}
return UV_ENOSYS;
}
int uv_backend_fd(const uv_loop_t* loop) {
return -1;
}
int uv_loop_fork(uv_loop_t* loop) {
return UV_ENOSYS;
}
int uv_backend_timeout(const uv_loop_t* loop) {
if (loop->stop_flag != 0)
return 0;
if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
return 0;
if (loop->pending_reqs_tail)
return 0;
if (loop->endgame_handles)
return 0;
if (loop->idle_handles)
return 0;
return uv__next_timeout(loop);
}
static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
DWORD bytes;
ULONG_PTR key;
OVERLAPPED* overlapped;
uv_req_t* req;
int repeat;
uint64_t timeout_time;
uint64_t user_timeout;
int reset_timeout;
timeout_time = loop->time + timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (repeat = 0; ; repeat++) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
GetQueuedCompletionStatus(loop->iocp,
&bytes,
&key,
&overlapped,
timeout);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
/* Placed here because on success the loop will break whether there is an
* empty package or not, or if GetQueuedCompletionStatus returned early then
* the timeout will be updated and the loop will run again. In either case
* the idle time will need to be updated.
*/
uv__metrics_update_idle_time(loop);
if (overlapped) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlapped);
uv_insert_pending_req(loop, req);
/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout target time is reached.
*/
uv_update_time(loop);
if (timeout_time > loop->time) {
timeout = (DWORD)(timeout_time - loop->time);
/* The first call to GetQueuedCompletionStatus should return very
* close to the target time and the second should reach it, but
* this is not stated in the documentation. To make sure a busy
* loop cannot happen, the timeout is increased exponentially
* starting on the third round.
*/
timeout += repeat ? (1 << (repeat - 1)) : 0;
continue;
}
}
break;
}
}
static void uv__poll(uv_loop_t* loop, DWORD timeout) {
BOOL success;
uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[128];
ULONG count;
ULONG i;
int repeat;
uint64_t timeout_time;
uint64_t user_timeout;
int reset_timeout;
timeout_time = loop->time + timeout;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1;
user_timeout = timeout;
timeout = 0;
} else {
reset_timeout = 0;
}
for (repeat = 0; ; repeat++) {
/* Only need to set the provider_entry_time if timeout != 0. The function
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
*/
if (timeout != 0)
uv__metrics_set_provider_entry_time(loop);
success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
&count,
timeout,
FALSE);
if (reset_timeout != 0) {
timeout = user_timeout;
reset_timeout = 0;
}
/* Placed here because on success the loop will break whether there is an
* empty package or not, or if GetQueuedCompletionStatus returned early then
* the timeout will be updated and the loop will run again. In either case
* the idle time will need to be updated.
*/
uv__metrics_update_idle_time(loop);
if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued, but see if it is not a empty package
* meant only to wake us up.
*/
if (overlappeds[i].lpOverlapped) {
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
uv_insert_pending_req(loop, req);
}
}
/* Some time might have passed waiting for I/O,
* so update the loop time here.
*/
uv_update_time(loop);
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
} else if (timeout > 0) {
/* GetQueuedCompletionStatus can occasionally return a little early.
* Make sure that the desired timeout target time is reached.
*/
uv_update_time(loop);
if (timeout_time > loop->time) {
timeout = (DWORD)(timeout_time - loop->time);
/* The first call to GetQueuedCompletionStatus should return very
* close to the target time and the second should reach it, but
* this is not stated in the documentation. To make sure a busy
* loop cannot happen, the timeout is increased exponentially
* starting on the third round.
*/
timeout += repeat ? (1 << (repeat - 1)) : 0;
continue;
}
}
break;
}
}
static int uv__loop_alive(const uv_loop_t* loop) {
return uv__has_active_handles(loop) ||
uv__has_active_reqs(loop) ||
loop->endgame_handles != NULL;
}
int uv_loop_alive(const uv_loop_t* loop) {
return uv__loop_alive(loop);
}
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
DWORD timeout;
int r;
int ran_pending;
r = uv__loop_alive(loop);
if (!r)
uv_update_time(loop);
while (r != 0 && loop->stop_flag == 0) {
uv_update_time(loop);
uv__run_timers(loop);
ran_pending = uv_process_reqs(loop);
uv_idle_invoke(loop);
uv_prepare_invoke(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
if (pGetQueuedCompletionStatusEx)
uv__poll(loop, timeout);
else
uv__poll_wine(loop, timeout);
/* Run one final update on the provider_idle_time in case uv__poll*
* returned because the timeout expired, but no events were received. This
* call will be ignored if the provider_entry_time was either never set (if
* the timeout == 0) or was already updated b/c an event was received.
*/
uv__metrics_update_idle_time(loop);
uv_check_invoke(loop);
uv_process_endgames(loop);
if (mode == UV_RUN_ONCE) {
/* UV_RUN_ONCE implies forward progress: at least one callback must have
* been invoked when it returns. uv__io_poll() can return without doing
* I/O (meaning: no callbacks) when its timeout expires - which means we
* have pending timers that satisfy the forward progress constraint.
*
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
* the check.
*/
uv__run_timers(loop);
}
r = uv__loop_alive(loop);
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
break;
}
/* The if statement lets the compiler compile it to a conditional store.
* Avoids dirtying a cache line.
*/
if (loop->stop_flag != 0)
loop->stop_flag = 0;
return r;
}
int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
uv_os_fd_t fd_out;
switch (handle->type) {
case UV_TCP:
fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
break;
case UV_NAMED_PIPE:
fd_out = ((uv_pipe_t*) handle)->handle;
break;
case UV_TTY:
fd_out = ((uv_tty_t*) handle)->handle;
break;
case UV_UDP:
fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
break;
case UV_POLL:
fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
break;
default:
return UV_EINVAL;
}
if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
return UV_EBADF;
*fd = fd_out;
return 0;
}
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
int r;
int len;
SOCKET socket;
if (handle == NULL || value == NULL)
return UV_EINVAL;
if (handle->type == UV_TCP)
socket = ((uv_tcp_t*) handle)->socket;
else if (handle->type == UV_UDP)
socket = ((uv_udp_t*) handle)->socket;
else
return UV_ENOTSUP;
len = sizeof(*value);
if (*value == 0)
r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
else
r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
if (r == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());
return 0;
}
int uv_cpumask_size(void) {
return (int)(sizeof(DWORD_PTR) * 8);
}
int uv__getsockpeername(const uv_handle_t* handle,
uv__peersockfunc func,
struct sockaddr* name,
int* namelen,
int delayed_error) {
int result;
uv_os_fd_t fd;
result = uv_fileno(handle, &fd);
if (result != 0)
return result;
if (delayed_error)
return uv_translate_sys_error(delayed_error);
result = func((SOCKET) fd, name, namelen);
if (result != 0)
return uv_translate_sys_error(WSAGetLastError());
return 0;
}

56
deps/libuv/src/win/detect-wakeup.c vendored Normal file
View File

@ -0,0 +1,56 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include "winapi.h"
static void uv__register_system_resume_callback(void);
void uv__init_detect_system_wakeup(void) {
/* Try registering system power event callback. This is the cleanest
* method, but it will only work on Win8 and above.
*/
uv__register_system_resume_callback();
}
static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
ULONG Type,
PVOID Setting) {
if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
uv__wake_all_loops();
return 0;
}
static void uv__register_system_resume_callback(void) {
_DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
_HPOWERNOTIFY registration_handle;
if (pPowerRegisterSuspendResumeNotification == NULL)
return;
recipient.Callback = uv__system_resume_callback;
recipient.Context = NULL;
(*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
&recipient,
&registration_handle);
}

136
deps/libuv/src/win/dl.c vendored Normal file
View File

@ -0,0 +1,136 @@
/* 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 "internal.h"
static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno);
int uv_dlopen(const char* filename, uv_lib_t* lib) {
WCHAR filename_w[32768];
lib->handle = NULL;
lib->errmsg = NULL;
if (!MultiByteToWideChar(CP_UTF8,
0,
filename,
-1,
filename_w,
ARRAY_SIZE(filename_w))) {
return uv__dlerror(lib, filename, GetLastError());
}
lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (lib->handle == NULL) {
return uv__dlerror(lib, filename, GetLastError());
}
return 0;
}
void uv_dlclose(uv_lib_t* lib) {
if (lib->errmsg) {
LocalFree((void*)lib->errmsg);
lib->errmsg = NULL;
}
if (lib->handle) {
/* Ignore errors. No good way to signal them without leaking memory. */
FreeLibrary(lib->handle);
lib->handle = NULL;
}
}
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
/* Cast though integer to suppress pedantic warning about forbidden cast. */
*ptr = (void*)(uintptr_t) GetProcAddress(lib->handle, name);
return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
}
const char* uv_dlerror(const uv_lib_t* lib) {
return lib->errmsg ? lib->errmsg : "no error";
}
static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
static const CHAR fallback_error[] = "error: %1!d!";
DWORD_PTR args[1];
args[0] = (DWORD_PTR) errorno;
FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_ALLOCATE_BUFFER,
fallback_error, 0, 0,
(LPSTR) &lib->errmsg,
0, (va_list*) args);
}
static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
DWORD_PTR arg;
DWORD res;
char* msg;
if (lib->errmsg) {
LocalFree(lib->errmsg);
lib->errmsg = NULL;
}
if (errorno == 0)
return 0;
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(LPSTR) &lib->errmsg, 0, NULL);
if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND ||
GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) {
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
0, (LPSTR) &lib->errmsg, 0, NULL);
}
if (res && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) {
msg = lib->errmsg;
lib->errmsg = NULL;
arg = (DWORD_PTR) filename;
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY |
FORMAT_MESSAGE_FROM_STRING,
msg,
0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg);
LocalFree(msg);
}
if (!res)
uv__format_fallback_error(lib, errorno);
return -1;
}

173
deps/libuv/src/win/error.c vendored Normal file
View File

@ -0,0 +1,173 @@
/* 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 <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uv.h"
#include "internal.h"
/*
* Display an error message and abort the event loop.
*/
void uv_fatal_error(const int errorno, const char* syscall) {
char* buf = NULL;
const char* errmsg;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
if (buf) {
errmsg = buf;
} else {
errmsg = "Unknown error";
}
/* FormatMessage messages include a newline character already, so don't add
* another. */
if (syscall) {
fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
} else {
fprintf(stderr, "(%d) %s", errorno, errmsg);
}
if (buf) {
LocalFree(buf);
}
DebugBreak();
abort();
}
int uv_translate_sys_error(int sys_errno) {
if (sys_errno <= 0) {
return sys_errno; /* If < 0 then it's already a libuv error. */
}
switch (sys_errno) {
case ERROR_NOACCESS: return UV_EACCES;
case WSAEACCES: return UV_EACCES;
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
case WSAEWOULDBLOCK: return UV_EAGAIN;
case WSAEALREADY: return UV_EALREADY;
case ERROR_INVALID_FLAGS: return UV_EBADF;
case ERROR_INVALID_HANDLE: return UV_EBADF;
case ERROR_LOCK_VIOLATION: return UV_EBUSY;
case ERROR_PIPE_BUSY: return UV_EBUSY;
case ERROR_SHARING_VIOLATION: return UV_EBUSY;
case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
case WSAEINTR: return UV_ECANCELED;
case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
case WSAECONNABORTED: return UV_ECONNABORTED;
case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
case WSAECONNREFUSED: return UV_ECONNREFUSED;
case ERROR_NETNAME_DELETED: return UV_ECONNRESET;
case WSAECONNRESET: return UV_ECONNRESET;
case ERROR_ALREADY_EXISTS: return UV_EEXIST;
case ERROR_FILE_EXISTS: return UV_EEXIST;
case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
case WSAEFAULT: return UV_EFAULT;
case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
case ERROR_INVALID_DATA: return UV_EINVAL;
case ERROR_INVALID_PARAMETER: return UV_EINVAL;
case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
case WSAEINVAL: return UV_EINVAL;
case WSAEPFNOSUPPORT: return UV_EINVAL;
case WSAESOCKTNOSUPPORT: return UV_EINVAL;
case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
case ERROR_BUS_RESET: return UV_EIO;
case ERROR_CRC: return UV_EIO;
case ERROR_DEVICE_DOOR_OPEN: return UV_EIO;
case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO;
case ERROR_DISK_CORRUPT: return UV_EIO;
case ERROR_EOM_OVERFLOW: return UV_EIO;
case ERROR_FILEMARK_DETECTED: return UV_EIO;
case ERROR_GEN_FAILURE: return UV_EIO;
case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO;
case ERROR_IO_DEVICE: return UV_EIO;
case ERROR_NO_DATA_DETECTED: return UV_EIO;
case ERROR_NO_SIGNAL_SENT: return UV_EIO;
case ERROR_OPEN_FAILED: return UV_EIO;
case ERROR_SETMARK_DETECTED: return UV_EIO;
case ERROR_SIGNAL_REFUSED: return UV_EIO;
case WSAEISCONN: return UV_EISCONN;
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;
case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
case WSAENETUNREACH: return UV_ENETUNREACH;
case WSAENOBUFS: return UV_ENOBUFS;
case ERROR_BAD_PATHNAME: return UV_ENOENT;
case ERROR_DIRECTORY: return UV_ENOENT;
case ERROR_ENVVAR_NOT_FOUND: return UV_ENOENT;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
case ERROR_INVALID_NAME: return UV_ENOENT;
case ERROR_INVALID_DRIVE: return UV_ENOENT;
case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
case WSAHOST_NOT_FOUND: return UV_ENOENT;
case WSANO_DATA: return UV_ENOENT;
case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
case ERROR_OUTOFMEMORY: return UV_ENOMEM;
case ERROR_CANNOT_MAKE: return UV_ENOSPC;
case ERROR_DISK_FULL: return UV_ENOSPC;
case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
case ERROR_END_OF_MEDIA: return UV_ENOSPC;
case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
case WSAENOTCONN: return UV_ENOTCONN;
case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
case WSAENOTSOCK: return UV_ENOTSOCK;
case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
case ERROR_BROKEN_PIPE: return UV_EOF;
case ERROR_ACCESS_DENIED: return UV_EPERM;
case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
case ERROR_BAD_PIPE: return UV_EPIPE;
case ERROR_NO_DATA: return UV_EPIPE;
case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
case WSAESHUTDOWN: return UV_EPIPE;
case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
case ERROR_WRITE_PROTECT: return UV_EROFS;
case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
case WSAETIMEDOUT: return UV_ETIMEDOUT;
case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
case ERROR_INVALID_FUNCTION: return UV_EISDIR;
case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
default: return UV_UNKNOWN;
}
}

608
deps/libuv/src/win/fs-event.c vendored Normal file
View File

@ -0,0 +1,608 @@
/* 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 <errno.h>
#include <stdio.h>
#include <string.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
const unsigned int uv_directory_watcher_buffer_size = 4096;
static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
uv_fs_event_t* handle) {
assert(handle->dir_handle != INVALID_HANDLE_VALUE);
assert(!handle->req_pending);
memset(&(handle->req.u.io.overlapped), 0,
sizeof(handle->req.u.io.overlapped));
if (!ReadDirectoryChangesW(handle->dir_handle,
handle->buffer,
uv_directory_watcher_buffer_size,
(handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY,
NULL,
&handle->req.u.io.overlapped,
NULL)) {
/* Make this req pending reporting an error. */
SET_REQ_ERROR(&handle->req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
}
handle->req_pending = 1;
}
static void uv_relative_path(const WCHAR* filename,
const WCHAR* dir,
WCHAR** relpath) {
size_t relpathlen;
size_t filenamelen = wcslen(filename);
size_t dirlen = wcslen(dir);
assert(!_wcsnicmp(filename, dir, dirlen));
if (dirlen > 0 && dir[dirlen - 1] == '\\')
dirlen--;
relpathlen = filenamelen - dirlen - 1;
*relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR));
if (!*relpath)
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
(*relpath)[relpathlen] = L'\0';
}
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
WCHAR** file) {
size_t len, i;
DWORD dir_len;
if (filename == NULL) {
if (dir != NULL)
*dir = NULL;
*file = NULL;
return 0;
}
len = wcslen(filename);
i = len;
while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
if (i == 0) {
if (dir) {
dir_len = GetCurrentDirectoryW(0, NULL);
if (dir_len == 0) {
return -1;
}
*dir = (WCHAR*)uv__malloc(dir_len * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!GetCurrentDirectoryW(dir_len, *dir)) {
uv__free(*dir);
*dir = NULL;
return -1;
}
}
*file = wcsdup(filename);
} else {
if (dir) {
*dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
if (!*dir) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*dir, filename, i + 1);
(*dir)[i + 1] = L'\0';
}
*file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
if (!*file) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
wcsncpy(*file, filename + i + 1, len - i - 1);
(*file)[len - i - 1] = L'\0';
}
return 0;
}
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
handle->dir_handle = INVALID_HANDLE_VALUE;
handle->buffer = NULL;
handle->req_pending = 0;
handle->filew = NULL;
handle->short_filew = NULL;
handle->dirw = NULL;
UV_REQ_INIT(&handle->req, UV_FS_EVENT_REQ);
handle->req.data = handle;
return 0;
}
int uv_fs_event_start(uv_fs_event_t* handle,
uv_fs_event_cb cb,
const char* path,
unsigned int flags) {
int name_size, is_path_dir, size;
DWORD attr, last_error;
WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
DWORD short_path_buffer_len;
WCHAR *short_path_buffer;
WCHAR* short_path, *long_path;
short_path = NULL;
if (uv__is_active(handle))
return UV_EINVAL;
handle->cb = cb;
handle->path = uv__strdup(path);
if (!handle->path) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
uv__handle_start(handle);
/* Convert name to UTF16. */
name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
sizeof(WCHAR);
pathw = (WCHAR*)uv__malloc(name_size);
if (!pathw) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
if (!MultiByteToWideChar(CP_UTF8,
0,
path,
-1,
pathw,
name_size / sizeof(WCHAR))) {
return uv_translate_sys_error(GetLastError());
}
/* Determine whether path is a file or a directory. */
attr = GetFileAttributesW(pathw);
if (attr == INVALID_FILE_ATTRIBUTES) {
last_error = GetLastError();
goto error;
}
is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
if (is_path_dir) {
/* path is a directory, so that's the directory that we will watch. */
/* Convert to long path. */
size = GetLongPathNameW(pathw, NULL, 0);
if (size) {
long_path = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
if (!long_path) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
size = GetLongPathNameW(pathw, long_path, size);
if (size) {
long_path[size] = '\0';
} else {
uv__free(long_path);
long_path = NULL;
}
if (long_path) {
uv__free(pathw);
pathw = long_path;
}
}
dir_to_watch = pathw;
} else {
/*
* path is a file. So we split path into dir & file parts, and
* watch the dir directory.
*/
/* Convert to short path. */
short_path_buffer = NULL;
short_path_buffer_len = GetShortPathNameW(pathw, NULL, 0);
if (short_path_buffer_len == 0) {
goto short_path_done;
}
short_path_buffer = uv__malloc(short_path_buffer_len * sizeof(WCHAR));
if (short_path_buffer == NULL) {
goto short_path_done;
}
if (GetShortPathNameW(pathw,
short_path_buffer,
short_path_buffer_len) == 0) {
uv__free(short_path_buffer);
short_path_buffer = NULL;
}
short_path_done:
short_path = short_path_buffer;
if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
last_error = GetLastError();
goto error;
}
if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
last_error = GetLastError();
goto error;
}
dir_to_watch = dir;
uv__free(pathw);
pathw = NULL;
}
handle->dir_handle = CreateFileW(dir_to_watch,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_DELETE |
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED,
NULL);
if (dir) {
uv__free(dir);
dir = NULL;
}
if (handle->dir_handle == INVALID_HANDLE_VALUE) {
last_error = GetLastError();
goto error;
}
if (CreateIoCompletionPort(handle->dir_handle,
handle->loop->iocp,
(ULONG_PTR)handle,
0) == NULL) {
last_error = GetLastError();
goto error;
}
if (!handle->buffer) {
handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
}
if (!handle->buffer) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
memset(&(handle->req.u.io.overlapped), 0,
sizeof(handle->req.u.io.overlapped));
if (!ReadDirectoryChangesW(handle->dir_handle,
handle->buffer,
uv_directory_watcher_buffer_size,
(flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY,
NULL,
&handle->req.u.io.overlapped,
NULL)) {
last_error = GetLastError();
goto error;
}
assert(is_path_dir ? pathw != NULL : pathw == NULL);
handle->dirw = pathw;
handle->req_pending = 1;
return 0;
error:
if (handle->path) {
uv__free(handle->path);
handle->path = NULL;
}
if (handle->filew) {
uv__free(handle->filew);
handle->filew = NULL;
}
if (handle->short_filew) {
uv__free(handle->short_filew);
handle->short_filew = NULL;
}
uv__free(pathw);
if (handle->dir_handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle->dir_handle);
handle->dir_handle = INVALID_HANDLE_VALUE;
}
if (handle->buffer) {
uv__free(handle->buffer);
handle->buffer = NULL;
}
if (uv__is_active(handle))
uv__handle_stop(handle);
uv__free(short_path);
return uv_translate_sys_error(last_error);
}
int uv_fs_event_stop(uv_fs_event_t* handle) {
if (!uv__is_active(handle))
return 0;
if (handle->dir_handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle->dir_handle);
handle->dir_handle = INVALID_HANDLE_VALUE;
}
uv__handle_stop(handle);
if (handle->filew) {
uv__free(handle->filew);
handle->filew = NULL;
}
if (handle->short_filew) {
uv__free(handle->short_filew);
handle->short_filew = NULL;
}
if (handle->path) {
uv__free(handle->path);
handle->path = NULL;
}
if (handle->dirw) {
uv__free(handle->dirw);
handle->dirw = NULL;
}
return 0;
}
static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
size_t str_len;
if (str == NULL)
return -1;
str_len = wcslen(str);
/*
Since we only care about equality, return early if the strings
aren't the same length
*/
if (str_len != (file_name_len / sizeof(WCHAR)))
return -1;
return _wcsnicmp(str, file_name, str_len);
}
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
uv_fs_event_t* handle) {
FILE_NOTIFY_INFORMATION* file_info;
int err, sizew, size;
char* filename = NULL;
WCHAR* filenamew = NULL;
WCHAR* long_filenamew = NULL;
DWORD offset = 0;
assert(req->type == UV_FS_EVENT_REQ);
assert(handle->req_pending);
handle->req_pending = 0;
/* Don't report any callbacks if:
* - We're closing, just push the handle onto the endgame queue
* - We are not active, just ignore the callback
*/
if (!uv__is_active(handle)) {
if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
return;
}
file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
if (REQ_SUCCESS(req)) {
if (req->u.io.overlapped.InternalHigh > 0) {
do {
file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
assert(!filename);
assert(!filenamew);
assert(!long_filenamew);
/*
* Fire the event only if we were asked to watch a directory,
* or if the filename filter matches.
*/
if (handle->dirw ||
file_info_cmp(handle->filew,
file_info->FileName,
file_info->FileNameLength) == 0 ||
file_info_cmp(handle->short_filew,
file_info->FileName,
file_info->FileNameLength) == 0) {
if (handle->dirw) {
/*
* We attempt to resolve the long form of the file name explicitly.
* We only do this for file names that might still exist on disk.
* If this fails, we use the name given by ReadDirectoryChangesW.
* This may be the long form or the 8.3 short name in some cases.
*/
if (file_info->Action != FILE_ACTION_REMOVED &&
file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
/* Construct a full path to the file. */
size = wcslen(handle->dirw) +
file_info->FileNameLength / sizeof(WCHAR) + 2;
filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
if (!filenamew) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
_snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
file_info->FileNameLength / (DWORD)sizeof(WCHAR),
file_info->FileName);
filenamew[size - 1] = L'\0';
/* Convert to long name. */
size = GetLongPathNameW(filenamew, NULL, 0);
if (size) {
long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
if (!long_filenamew) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
size = GetLongPathNameW(filenamew, long_filenamew, size);
if (size) {
long_filenamew[size] = '\0';
} else {
uv__free(long_filenamew);
long_filenamew = NULL;
}
}
uv__free(filenamew);
if (long_filenamew) {
/* Get the file name out of the long path. */
uv_relative_path(long_filenamew,
handle->dirw,
&filenamew);
uv__free(long_filenamew);
long_filenamew = filenamew;
sizew = -1;
} else {
/* We couldn't get the long filename, use the one reported. */
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(WCHAR);
}
} else {
/*
* Removed or renamed events cannot be resolved to the long form.
* We therefore use the name given by ReadDirectoryChangesW.
* This may be the long form or the 8.3 short name in some cases.
*/
filenamew = file_info->FileName;
sizew = file_info->FileNameLength / sizeof(WCHAR);
}
} else {
/* We already have the long name of the file, so just use it. */
filenamew = handle->filew;
sizew = -1;
}
/* Convert the filename to utf8. */
uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
switch (file_info->Action) {
case FILE_ACTION_ADDED:
case FILE_ACTION_REMOVED:
case FILE_ACTION_RENAMED_OLD_NAME:
case FILE_ACTION_RENAMED_NEW_NAME:
handle->cb(handle, filename, UV_RENAME, 0);
break;
case FILE_ACTION_MODIFIED:
handle->cb(handle, filename, UV_CHANGE, 0);
break;
}
uv__free(filename);
filename = NULL;
uv__free(long_filenamew);
long_filenamew = NULL;
filenamew = NULL;
}
offset = file_info->NextEntryOffset;
} while (offset && !(handle->flags & UV_HANDLE_CLOSING));
} else {
handle->cb(handle, NULL, UV_CHANGE, 0);
}
} else {
err = GET_REQ_ERROR(req);
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
}
if (!(handle->flags & UV_HANDLE_CLOSING)) {
uv_fs_event_queue_readdirchanges(loop, handle);
} else {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
}
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
uv_fs_event_stop(handle);
uv__handle_closing(handle);
if (!handle->req_pending) {
uv_want_endgame(loop, (uv_handle_t*)handle);
}
}
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
if (handle->buffer) {
uv__free(handle->buffer);
handle->buffer = NULL;
}
uv__handle_close(handle);
}
}

200
deps/libuv/src/win/fs-fd-hash-inl.h vendored Normal file
View File

@ -0,0 +1,200 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_FS_FD_HASH_INL_H_
#define UV_WIN_FS_FD_HASH_INL_H_
#include "uv.h"
#include "internal.h"
/* Files are only inserted in uv__fd_hash when the UV_FS_O_FILEMAP flag is
* specified. Thus, when uv__fd_hash_get returns true, the file mapping in the
* info structure should be used for read/write operations.
*
* If the file is empty, the mapping field will be set to
* INVALID_HANDLE_VALUE. This is not an issue since the file mapping needs to
* be created anyway when the file size changes.
*
* Since file descriptors are sequential integers, the modulo operator is used
* as hashing function. For each bucket, a single linked list of arrays is
* kept to minimize allocations. A statically allocated memory buffer is kept
* for the first array in each bucket. */
#define UV__FD_HASH_SIZE 256
#define UV__FD_HASH_GROUP_SIZE 16
struct uv__fd_info_s {
int flags;
BOOLEAN is_directory;
HANDLE mapping;
LARGE_INTEGER size;
LARGE_INTEGER current_pos;
};
struct uv__fd_hash_entry_s {
uv_file fd;
struct uv__fd_info_s info;
};
struct uv__fd_hash_entry_group_s {
struct uv__fd_hash_entry_s entries[UV__FD_HASH_GROUP_SIZE];
struct uv__fd_hash_entry_group_s* next;
};
struct uv__fd_hash_bucket_s {
size_t size;
struct uv__fd_hash_entry_group_s* data;
};
static uv_mutex_t uv__fd_hash_mutex;
static struct uv__fd_hash_entry_group_s
uv__fd_hash_entry_initial[UV__FD_HASH_SIZE * UV__FD_HASH_GROUP_SIZE];
static struct uv__fd_hash_bucket_s uv__fd_hash[UV__FD_HASH_SIZE];
INLINE static void uv__fd_hash_init(void) {
size_t i;
int err;
err = uv_mutex_init(&uv__fd_hash_mutex);
if (err) {
uv_fatal_error(err, "uv_mutex_init");
}
for (i = 0; i < ARRAY_SIZE(uv__fd_hash); ++i) {
uv__fd_hash[i].size = 0;
uv__fd_hash[i].data =
uv__fd_hash_entry_initial + i * UV__FD_HASH_GROUP_SIZE;
}
}
#define FIND_COMMON_VARIABLES \
unsigned i; \
unsigned bucket = fd % ARRAY_SIZE(uv__fd_hash); \
struct uv__fd_hash_entry_s* entry_ptr = NULL; \
struct uv__fd_hash_entry_group_s* group_ptr; \
struct uv__fd_hash_bucket_s* bucket_ptr = &uv__fd_hash[bucket];
#define FIND_IN_GROUP_PTR(group_size) \
do { \
for (i = 0; i < group_size; ++i) { \
if (group_ptr->entries[i].fd == fd) { \
entry_ptr = &group_ptr->entries[i]; \
break; \
} \
} \
} while (0)
#define FIND_IN_BUCKET_PTR() \
do { \
size_t first_group_size = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE; \
if (bucket_ptr->size != 0 && first_group_size == 0) \
first_group_size = UV__FD_HASH_GROUP_SIZE; \
group_ptr = bucket_ptr->data; \
FIND_IN_GROUP_PTR(first_group_size); \
for (group_ptr = group_ptr->next; \
group_ptr != NULL && entry_ptr == NULL; \
group_ptr = group_ptr->next) \
FIND_IN_GROUP_PTR(UV__FD_HASH_GROUP_SIZE); \
} while (0)
INLINE static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) {
FIND_COMMON_VARIABLES
uv_mutex_lock(&uv__fd_hash_mutex);
FIND_IN_BUCKET_PTR();
if (entry_ptr != NULL) {
*info = entry_ptr->info;
}
uv_mutex_unlock(&uv__fd_hash_mutex);
return entry_ptr != NULL;
}
INLINE static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) {
FIND_COMMON_VARIABLES
uv_mutex_lock(&uv__fd_hash_mutex);
FIND_IN_BUCKET_PTR();
if (entry_ptr == NULL) {
i = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE;
if (bucket_ptr->size != 0 && i == 0) {
struct uv__fd_hash_entry_group_s* new_group_ptr =
uv__malloc(sizeof(*new_group_ptr));
if (new_group_ptr == NULL) {
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
}
new_group_ptr->next = bucket_ptr->data;
bucket_ptr->data = new_group_ptr;
}
bucket_ptr->size += 1;
entry_ptr = &bucket_ptr->data->entries[i];
entry_ptr->fd = fd;
}
entry_ptr->info = *info;
uv_mutex_unlock(&uv__fd_hash_mutex);
}
INLINE static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) {
FIND_COMMON_VARIABLES
uv_mutex_lock(&uv__fd_hash_mutex);
FIND_IN_BUCKET_PTR();
if (entry_ptr != NULL) {
*info = entry_ptr->info;
bucket_ptr->size -= 1;
i = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE;
if (entry_ptr != &bucket_ptr->data->entries[i]) {
*entry_ptr = bucket_ptr->data->entries[i];
}
if (bucket_ptr->size != 0 &&
bucket_ptr->size % UV__FD_HASH_GROUP_SIZE == 0) {
struct uv__fd_hash_entry_group_s* old_group_ptr = bucket_ptr->data;
bucket_ptr->data = old_group_ptr->next;
uv__free(old_group_ptr);
}
}
uv_mutex_unlock(&uv__fd_hash_mutex);
return entry_ptr != NULL;
}
#undef FIND_COMMON_VARIABLES
#undef FIND_IN_GROUP_PTR
#undef FIND_IN_BUCKET_PTR
#endif /* UV_WIN_FS_FD_HASH_INL_H_ */

3428
deps/libuv/src/win/fs.c vendored Normal file

File diff suppressed because it is too large Load Diff

463
deps/libuv/src/win/getaddrinfo.c vendored Normal file
View File

@ -0,0 +1,463 @@
/* 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 "uv.h"
#include "internal.h"
#include "req-inl.h"
#include "idna.h"
/* EAI_* constants. */
#include <winsock2.h>
/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
#include <iphlpapi.h>
int uv__getaddrinfo_translate_error(int sys_err) {
switch (sys_err) {
case 0: return 0;
case WSATRY_AGAIN: return UV_EAI_AGAIN;
case WSAEINVAL: return UV_EAI_BADFLAGS;
case WSANO_RECOVERY: return UV_EAI_FAIL;
case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
default: return uv_translate_sys_error(sys_err);
}
}
/*
* MinGW is missing this
*/
#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
typedef struct addrinfoW {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
WCHAR* ai_canonname;
struct sockaddr* ai_addr;
struct addrinfoW* ai_next;
} ADDRINFOW, *PADDRINFOW;
DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
const WCHAR* service,
const ADDRINFOW* hints,
PADDRINFOW* result);
DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
#endif
/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
* Do we need different versions of this for different architectures? */
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
#ifndef NDIS_IF_MAX_STRING_SIZE
#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
#endif
static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req;
struct addrinfoW* hints;
int err;
req = container_of(w, uv_getaddrinfo_t, work_req);
hints = req->addrinfow;
req->addrinfow = NULL;
err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
req->retcode = uv__getaddrinfo_translate_error(err);
}
/*
* Called from uv_run when complete. Call user specified callback
* then free returned addrinfo
* Returned addrinfo strings are converted from UTF-16 to UTF-8.
*
* To minimize allocation we calculate total size required,
* and copy all structs and referenced strings into the one block.
* Each size calculation is adjusted to avoid unaligned pointers.
*/
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req;
int addrinfo_len = 0;
int name_len = 0;
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
struct addrinfoW* addrinfow_ptr;
struct addrinfo* addrinfo_ptr;
char* alloc_ptr = NULL;
char* cur_ptr = NULL;
req = container_of(w, uv_getaddrinfo_t, work_req);
/* release input parameter memory */
uv__free(req->alloc);
req->alloc = NULL;
if (status == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
goto complete;
}
if (req->retcode == 0) {
/* Convert addrinfoW to addrinfo. First calculate required length. */
addrinfow_ptr = req->addrinfow;
while (addrinfow_ptr != NULL) {
addrinfo_len += addrinfo_struct_len +
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
NULL,
0,
NULL,
NULL);
if (name_len == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
goto complete;
}
addrinfo_len += ALIGNED_SIZE(name_len);
}
addrinfow_ptr = addrinfow_ptr->ai_next;
}
/* allocate memory for addrinfo results */
alloc_ptr = (char*)uv__malloc(addrinfo_len);
/* do conversions */
if (alloc_ptr != NULL) {
cur_ptr = alloc_ptr;
addrinfow_ptr = req->addrinfow;
while (addrinfow_ptr != NULL) {
/* copy addrinfo struct data */
assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
addrinfo_ptr = (struct addrinfo*)cur_ptr;
addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
addrinfo_ptr->ai_canonname = NULL;
addrinfo_ptr->ai_addr = NULL;
addrinfo_ptr->ai_next = NULL;
cur_ptr += addrinfo_struct_len;
/* copy sockaddr */
if (addrinfo_ptr->ai_addrlen > 0) {
assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
alloc_ptr + addrinfo_len);
memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
}
/* convert canonical name to UTF-8 */
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
NULL,
0,
NULL,
NULL);
assert(name_len > 0);
assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
name_len = WideCharToMultiByte(CP_UTF8,
0,
addrinfow_ptr->ai_canonname,
-1,
cur_ptr,
name_len,
NULL,
NULL);
assert(name_len > 0);
addrinfo_ptr->ai_canonname = cur_ptr;
cur_ptr += ALIGNED_SIZE(name_len);
}
assert(cur_ptr <= alloc_ptr + addrinfo_len);
/* set next ptr */
addrinfow_ptr = addrinfow_ptr->ai_next;
if (addrinfow_ptr != NULL) {
addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
}
}
req->addrinfo = (struct addrinfo*)alloc_ptr;
} else {
req->retcode = UV_EAI_MEMORY;
}
}
/* return memory to system */
if (req->addrinfow != NULL) {
FreeAddrInfoW(req->addrinfow);
req->addrinfow = NULL;
}
complete:
uv__req_unregister(req->loop, req);
/* finally do callback with converted result */
if (req->getaddrinfo_cb)
req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
}
void uv_freeaddrinfo(struct addrinfo* ai) {
char* alloc_ptr = (char*)ai;
/* release copied result memory */
uv__free(alloc_ptr);
}
/*
* Entry point for getaddrinfo
* we convert the UTF-8 strings to UNICODE
* and save the UNICODE string pointers in the req
* We also copy hints so that caller does not need to keep memory until the
* callback.
* return 0 if a callback will be made
* return error code if validation fails
*
* To minimize allocation we calculate total size required,
* and copy all structs and referenced strings into the one block.
* Each size calculation is adjusted to avoid unaligned pointers.
*/
int uv_getaddrinfo(uv_loop_t* loop,
uv_getaddrinfo_t* req,
uv_getaddrinfo_cb getaddrinfo_cb,
const char* node,
const char* service,
const struct addrinfo* hints) {
char hostname_ascii[256];
int nodesize = 0;
int servicesize = 0;
int hintssize = 0;
char* alloc_ptr = NULL;
int err;
long rc;
if (req == NULL || (node == NULL && service == NULL)) {
return UV_EINVAL;
}
UV_REQ_INIT(req, UV_GETADDRINFO);
req->getaddrinfo_cb = getaddrinfo_cb;
req->addrinfo = NULL;
req->loop = loop;
req->retcode = 0;
/* calculate required memory size for all input values */
if (node != NULL) {
rc = uv__idna_toascii(node,
node + strlen(node),
hostname_ascii,
hostname_ascii + sizeof(hostname_ascii));
if (rc < 0)
return rc;
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
-1, NULL, 0) * sizeof(WCHAR));
if (nodesize == 0) {
err = GetLastError();
goto error;
}
node = hostname_ascii;
}
if (service != NULL) {
servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
0,
service,
-1,
NULL,
0) *
sizeof(WCHAR));
if (servicesize == 0) {
err = GetLastError();
goto error;
}
}
if (hints != NULL) {
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
}
/* allocate memory for inputs, and partition it as needed */
alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
if (!alloc_ptr) {
err = WSAENOBUFS;
goto error;
}
/* save alloc_ptr now so we can free if error */
req->alloc = (void*)alloc_ptr;
/* Convert node string to UTF16 into allocated memory and save pointer in the
* request. */
if (node != NULL) {
req->node = (WCHAR*)alloc_ptr;
if (MultiByteToWideChar(CP_UTF8,
0,
node,
-1,
(WCHAR*) alloc_ptr,
nodesize / sizeof(WCHAR)) == 0) {
err = GetLastError();
goto error;
}
alloc_ptr += nodesize;
} else {
req->node = NULL;
}
/* Convert service string to UTF16 into allocated memory and save pointer in
* the req. */
if (service != NULL) {
req->service = (WCHAR*)alloc_ptr;
if (MultiByteToWideChar(CP_UTF8,
0,
service,
-1,
(WCHAR*) alloc_ptr,
servicesize / sizeof(WCHAR)) == 0) {
err = GetLastError();
goto error;
}
alloc_ptr += servicesize;
} else {
req->service = NULL;
}
/* copy hints to allocated memory and save pointer in req */
if (hints != NULL) {
req->addrinfow = (struct addrinfoW*)alloc_ptr;
req->addrinfow->ai_family = hints->ai_family;
req->addrinfow->ai_socktype = hints->ai_socktype;
req->addrinfow->ai_protocol = hints->ai_protocol;
req->addrinfow->ai_flags = hints->ai_flags;
req->addrinfow->ai_addrlen = 0;
req->addrinfow->ai_canonname = NULL;
req->addrinfow->ai_addr = NULL;
req->addrinfow->ai_next = NULL;
} else {
req->addrinfow = NULL;
}
uv__req_register(loop, req);
if (getaddrinfo_cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getaddrinfo_work,
uv__getaddrinfo_done);
return 0;
} else {
uv__getaddrinfo_work(&req->work_req);
uv__getaddrinfo_done(&req->work_req, 0);
return req->retcode;
}
error:
if (req != NULL) {
uv__free(req->alloc);
req->alloc = NULL;
}
return uv_translate_sys_error(err);
}
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
NET_LUID luid;
wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
DWORD bufsize;
int r;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
r = ConvertInterfaceIndexToLuid(ifindex, &luid);
if (r != 0)
return uv_translate_sys_error(r);
r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
if (r != 0)
return uv_translate_sys_error(r);
/* Check how much space we need */
bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
if (bufsize == 0) {
return uv_translate_sys_error(GetLastError());
} else if (bufsize > *size) {
*size = bufsize;
return UV_ENOBUFS;
}
/* Convert to UTF-8 */
bufsize = WideCharToMultiByte(CP_UTF8,
0,
wname,
-1,
buffer,
*size,
NULL,
NULL);
if (bufsize == 0)
return uv_translate_sys_error(GetLastError());
*size = bufsize - 1;
return 0;
}
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
int r;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
r = snprintf(buffer, *size, "%d", ifindex);
if (r < 0)
return uv_translate_sys_error(r);
if (r >= (int) *size) {
*size = r + 1;
return UV_ENOBUFS;
}
*size = r;
return 0;
}

157
deps/libuv/src/win/getnameinfo.c vendored Normal file
View File

@ -0,0 +1,157 @@
/* 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 <stdio.h>
#include "uv.h"
#include "internal.h"
#include "req-inl.h"
#ifndef GetNameInfo
int WSAAPI GetNameInfoW(
const SOCKADDR *pSockaddr,
socklen_t SockaddrLength,
PWCHAR pNodeBuffer,
DWORD NodeBufferSize,
PWCHAR pServiceBuffer,
DWORD ServiceBufferSize,
INT Flags
);
#endif
static void uv__getnameinfo_work(struct uv__work* w) {
uv_getnameinfo_t* req;
WCHAR host[NI_MAXHOST];
WCHAR service[NI_MAXSERV];
int ret;
req = container_of(w, uv_getnameinfo_t, work_req);
if (GetNameInfoW((struct sockaddr*)&req->storage,
sizeof(req->storage),
host,
ARRAY_SIZE(host),
service,
ARRAY_SIZE(service),
req->flags)) {
ret = WSAGetLastError();
req->retcode = uv__getaddrinfo_translate_error(ret);
return;
}
ret = WideCharToMultiByte(CP_UTF8,
0,
host,
-1,
req->host,
sizeof(req->host),
NULL,
NULL);
if (ret == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
return;
}
ret = WideCharToMultiByte(CP_UTF8,
0,
service,
-1,
req->service,
sizeof(req->service),
NULL,
NULL);
if (ret == 0) {
req->retcode = uv_translate_sys_error(GetLastError());
}
}
/*
* Called from uv_run when complete.
*/
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 == UV_ECANCELED) {
assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED;
} else if (req->retcode == 0) {
host = req->host;
service = req->service;
}
if (req->getnameinfo_cb)
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 || 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(req, UV_GETNAMEINFO);
uv__req_register(loop, req);
req->getnameinfo_cb = getnameinfo_cb;
req->flags = flags;
req->loop = loop;
req->retcode = 0;
if (getnameinfo_cb) {
uv__work_submit(loop,
&req->work_req,
UV__WORK_SLOW_IO,
uv__getnameinfo_work,
uv__getnameinfo_done);
return 0;
} else {
uv__getnameinfo_work(&req->work_req);
uv__getnameinfo_done(&req->work_req, 0);
return req->retcode;
}
}

180
deps/libuv/src/win/handle-inl.h vendored Normal file
View File

@ -0,0 +1,180 @@
/* 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.
*/
#ifndef UV_WIN_HANDLE_INL_H_
#define UV_WIN_HANDLE_INL_H_
#include <assert.h>
#include <io.h>
#include "uv.h"
#include "internal.h"
#define DECREASE_ACTIVE_COUNT(loop, handle) \
do { \
if (--(handle)->activecnt == 0 && \
!((handle)->flags & UV_HANDLE_CLOSING)) { \
uv__handle_stop((handle)); \
} \
assert((handle)->activecnt >= 0); \
} while (0)
#define INCREASE_ACTIVE_COUNT(loop, handle) \
do { \
if ((handle)->activecnt++ == 0) { \
uv__handle_start((handle)); \
} \
assert((handle)->activecnt > 0); \
} while (0)
#define DECREASE_PENDING_REQ_COUNT(handle) \
do { \
assert(handle->reqs_pending > 0); \
handle->reqs_pending--; \
\
if (handle->flags & UV_HANDLE_CLOSING && \
handle->reqs_pending == 0) { \
uv_want_endgame(loop, (uv_handle_t*)handle); \
} \
} while (0)
#define uv__handle_closing(handle) \
do { \
assert(!((handle)->flags & UV_HANDLE_CLOSING)); \
\
if (!(((handle)->flags & UV_HANDLE_ACTIVE) && \
((handle)->flags & UV_HANDLE_REF))) \
uv__active_handle_add((uv_handle_t*) (handle)); \
\
(handle)->flags |= UV_HANDLE_CLOSING; \
(handle)->flags &= ~UV_HANDLE_ACTIVE; \
} while (0)
#define uv__handle_close(handle) \
do { \
QUEUE_REMOVE(&(handle)->handle_queue); \
uv__active_handle_rm((uv_handle_t*) (handle)); \
\
(handle)->flags |= UV_HANDLE_CLOSED; \
\
if ((handle)->close_cb) \
(handle)->close_cb((uv_handle_t*) (handle)); \
} while (0)
INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
handle->endgame_next = loop->endgame_handles;
loop->endgame_handles = handle;
}
}
INLINE static void uv_process_endgames(uv_loop_t* loop) {
uv_handle_t* handle;
while (loop->endgame_handles) {
handle = loop->endgame_handles;
loop->endgame_handles = handle->endgame_next;
handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
switch (handle->type) {
case UV_TCP:
uv_tcp_endgame(loop, (uv_tcp_t*) handle);
break;
case UV_NAMED_PIPE:
uv_pipe_endgame(loop, (uv_pipe_t*) handle);
break;
case UV_TTY:
uv_tty_endgame(loop, (uv_tty_t*) handle);
break;
case UV_UDP:
uv_udp_endgame(loop, (uv_udp_t*) handle);
break;
case UV_POLL:
uv_poll_endgame(loop, (uv_poll_t*) handle);
break;
case UV_TIMER:
uv__timer_close((uv_timer_t*) handle);
uv__handle_close(handle);
break;
case UV_PREPARE:
case UV_CHECK:
case UV_IDLE:
uv_loop_watcher_endgame(loop, handle);
break;
case UV_ASYNC:
uv_async_endgame(loop, (uv_async_t*) handle);
break;
case UV_SIGNAL:
uv_signal_endgame(loop, (uv_signal_t*) handle);
break;
case UV_PROCESS:
uv_process_endgame(loop, (uv_process_t*) handle);
break;
case UV_FS_EVENT:
uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
break;
case UV_FS_POLL:
uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle);
break;
default:
assert(0);
break;
}
}
}
INLINE static HANDLE uv__get_osfhandle(int fd)
{
/* _get_osfhandle() raises an assert in debug builds if the FD is invalid.
* 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);
UV_END_DISABLE_CRT_ASSERT();
return handle;
}
#endif /* UV_WIN_HANDLE_INL_H_ */

162
deps/libuv/src/win/handle.c vendored Normal file
View File

@ -0,0 +1,162 @@
/* 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 <io.h>
#include <stdlib.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
uv_handle_type uv_guess_handle(uv_file file) {
HANDLE handle;
DWORD mode;
if (file < 0) {
return UV_UNKNOWN_HANDLE;
}
handle = uv__get_osfhandle(file);
switch (GetFileType(handle)) {
case FILE_TYPE_CHAR:
if (GetConsoleMode(handle, &mode)) {
return UV_TTY;
} else {
return UV_FILE;
}
case FILE_TYPE_PIPE:
return UV_NAMED_PIPE;
case FILE_TYPE_DISK:
return UV_FILE;
default:
return UV_UNKNOWN_HANDLE;
}
}
int uv_is_active(const uv_handle_t* handle) {
return (handle->flags & UV_HANDLE_ACTIVE) &&
!(handle->flags & UV_HANDLE_CLOSING);
}
void uv_close(uv_handle_t* handle, uv_close_cb cb) {
uv_loop_t* loop = handle->loop;
if (handle->flags & UV_HANDLE_CLOSING) {
assert(0);
return;
}
handle->close_cb = cb;
/* Handle-specific close actions */
switch (handle->type) {
case UV_TCP:
uv_tcp_close(loop, (uv_tcp_t*)handle);
return;
case UV_NAMED_PIPE:
uv_pipe_close(loop, (uv_pipe_t*) handle);
return;
case UV_TTY:
uv_tty_close((uv_tty_t*) handle);
return;
case UV_UDP:
uv_udp_close(loop, (uv_udp_t*) handle);
return;
case UV_POLL:
uv_poll_close(loop, (uv_poll_t*) handle);
return;
case UV_TIMER:
uv_timer_stop((uv_timer_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
case UV_PREPARE:
uv_prepare_stop((uv_prepare_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
case UV_CHECK:
uv_check_stop((uv_check_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
case UV_IDLE:
uv_idle_stop((uv_idle_t*)handle);
uv__handle_closing(handle);
uv_want_endgame(loop, handle);
return;
case UV_ASYNC:
uv_async_close(loop, (uv_async_t*) handle);
return;
case UV_SIGNAL:
uv_signal_close(loop, (uv_signal_t*) handle);
return;
case UV_PROCESS:
uv_process_close(loop, (uv_process_t*) handle);
return;
case UV_FS_EVENT:
uv_fs_event_close(loop, (uv_fs_event_t*) handle);
return;
case UV_FS_POLL:
uv__fs_poll_close((uv_fs_poll_t*) handle);
uv__handle_closing(handle);
return;
default:
/* Not supported */
abort();
}
}
int uv_is_closing(const uv_handle_t* handle) {
return !!(handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED));
}
uv_os_fd_t uv_get_osfhandle(int fd) {
return uv__get_osfhandle(fd);
}
int uv_open_osfhandle(uv_os_fd_t os_fd) {
return _open_osfhandle((intptr_t) os_fd, 0);
}

344
deps/libuv/src/win/internal.h vendored Normal file
View File

@ -0,0 +1,344 @@
/* 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.
*/
#ifndef UV_WIN_INTERNAL_H_
#define UV_WIN_INTERNAL_H_
#include "uv.h"
#include "../uv-common.h"
#include "uv/tree.h"
#include "winapi.h"
#include "winsock.h"
#ifdef _MSC_VER
# define INLINE __inline
# define UV_THREAD_LOCAL __declspec( thread )
#else
# define INLINE inline
# define UV_THREAD_LOCAL __thread
#endif
#ifdef _DEBUG
extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
#define UV_BEGIN_DISABLE_CRT_ASSERT() \
{ \
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; \
}
#else
#define UV_BEGIN_DISABLE_CRT_ASSERT()
#define UV_END_DISABLE_CRT_ASSERT()
#endif
/*
* TCP
*/
typedef enum {
UV__IPC_SOCKET_XFER_NONE = 0,
UV__IPC_SOCKET_XFER_TCP_CONNECTION,
UV__IPC_SOCKET_XFER_TCP_SERVER
} uv__ipc_socket_xfer_type_t;
typedef struct {
WSAPROTOCOL_INFOW socket_info;
uint32_t delayed_error;
} uv__ipc_socket_xfer_info_t;
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
unsigned int nbufs);
void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_write_t* req);
void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_req_t* req);
void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_connect_t* req);
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
int uv__tcp_xfer_export(uv_tcp_t* handle,
int pid,
uv__ipc_socket_xfer_type_t* xfer_type,
uv__ipc_socket_xfer_info_t* xfer_info);
int uv__tcp_xfer_import(uv_tcp_t* tcp,
uv__ipc_socket_xfer_type_t xfer_type,
uv__ipc_socket_xfer_info_t* xfer_info);
/*
* UDP
*/
void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
uv_udp_send_t* req);
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
/*
* Pipes
*/
int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
char* name, size_t nameSize);
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
void uv__pipe_read_stop(uv_pipe_t* handle);
int uv__pipe_write(uv_loop_t* loop,
uv_write_t* req,
uv_pipe_t* handle,
const uv_buf_t bufs[],
size_t nbufs,
uv_stream_t* send_handle,
uv_write_cb cb);
void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* req);
void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_write_t* req);
void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* raw_req);
void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_connect_t* req);
void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_shutdown_t* req);
void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
/*
* TTY
*/
void uv_console_init(void);
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
int uv_tty_read_stop(uv_tty_t* handle);
int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
unsigned int nbufs);
void uv_tty_close(uv_tty_t* handle);
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* req);
void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
uv_write_t* req);
/*
* uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it
*/
void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* raw_req);
/*
* uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it
*/
void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
uv_connect_t* req);
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
/*
* Poll watchers
*/
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
uv_req_t* req);
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
/*
* Loop watchers
*/
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
void uv_prepare_invoke(uv_loop_t* loop);
void uv_check_invoke(uv_loop_t* loop);
void uv_idle_invoke(uv_loop_t* loop);
void uv__once_init(void);
/*
* Async watcher
*/
void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req);
/*
* Signal watcher
*/
void uv_signals_init(void);
int uv__signal_dispatch(int signum);
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req);
/*
* Spawn
*/
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
/*
* Error
*/
int uv_translate_sys_error(int sys_errno);
/*
* FS
*/
void uv_fs_init(void);
/*
* FS Event
*/
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
uv_fs_event_t* handle);
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
/*
* Stat poller.
*/
void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
/*
* Utilities.
*/
void uv__util_init(void);
uint64_t uv__hrtime(unsigned int scale);
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
typedef int (WINAPI *uv__peersockfunc)(SOCKET, struct sockaddr*, int*);
int uv__getsockpeername(const uv_handle_t* handle,
uv__peersockfunc func,
struct sockaddr* name,
int* namelen,
int delayed_error);
int uv__random_rtlgenrandom(void* buf, size_t buflen);
/*
* Process stdio handles.
*/
int uv__stdio_create(uv_loop_t* loop,
const uv_process_options_t* options,
BYTE** buffer_ptr);
void uv__stdio_destroy(BYTE* buffer);
void uv__stdio_noinherit(BYTE* buffer);
int uv__stdio_verify(BYTE* buffer, WORD size);
WORD uv__stdio_size(BYTE* buffer);
HANDLE uv__stdio_handle(BYTE* buffer, int fd);
/*
* Winapi and ntapi utility functions
*/
void uv_winapi_init(void);
/*
* Winsock utility functions
*/
void uv_winsock_init(void);
int uv_ntstatus_to_winsock_error(NTSTATUS status);
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
int* addr_len, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
/* Whether there are any non-IFS LSPs stacked on TCP */
extern int uv_tcp_non_ifs_lsp_ipv4;
extern int uv_tcp_non_ifs_lsp_ipv6;
/* Ip address used to bind to any port at any interface */
extern struct sockaddr_in uv_addr_ip4_any_;
extern struct sockaddr_in6 uv_addr_ip6_any_;
/*
* Wake all loops with fake message
*/
void uv__wake_all_loops(void);
/*
* Init system wake-up detection
*/
void uv__init_detect_system_wakeup(void);
#endif /* UV_WIN_INTERNAL_H_ */

122
deps/libuv/src/win/loop-watcher.c vendored Normal file
View File

@ -0,0 +1,122 @@
/* 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 "uv.h"
#include "internal.h"
#include "handle-inl.h"
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_close(handle);
}
}
#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
\
return 0; \
} \
\
\
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
uv_loop_t* loop = handle->loop; \
uv_##name##_t* old_head; \
\
assert(handle->type == UV_##NAME); \
\
if (uv__is_active(handle)) \
return 0; \
\
if (cb == NULL) \
return UV_EINVAL; \
\
old_head = loop->name##_handles; \
\
handle->name##_next = old_head; \
handle->name##_prev = NULL; \
\
if (old_head) { \
old_head->name##_prev = handle; \
} \
\
loop->name##_handles = handle; \
\
handle->name##_cb = cb; \
uv__handle_start(handle); \
\
return 0; \
} \
\
\
int uv_##name##_stop(uv_##name##_t* handle) { \
uv_loop_t* loop = handle->loop; \
\
assert(handle->type == UV_##NAME); \
\
if (!uv__is_active(handle)) \
return 0; \
\
/* Update loop head if needed */ \
if (loop->name##_handles == handle) { \
loop->name##_handles = handle->name##_next; \
} \
\
/* Update the iterator-next pointer of needed */ \
if (loop->next_##name##_handle == handle) { \
loop->next_##name##_handle = handle->name##_next; \
} \
\
if (handle->name##_prev) { \
handle->name##_prev->name##_next = handle->name##_next; \
} \
if (handle->name##_next) { \
handle->name##_next->name##_prev = handle->name##_prev; \
} \
\
uv__handle_stop(handle); \
\
return 0; \
} \
\
\
void uv_##name##_invoke(uv_loop_t* loop) { \
uv_##name##_t* handle; \
\
(loop)->next_##name##_handle = (loop)->name##_handles; \
\
while ((loop)->next_##name##_handle != NULL) { \
handle = (loop)->next_##name##_handle; \
(loop)->next_##name##_handle = handle->name##_next; \
\
handle->name##_cb(handle); \
} \
}
UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
UV_LOOP_WATCHER_DEFINE(check, CHECK)
UV_LOOP_WATCHER_DEFINE(idle, IDLE)

2393
deps/libuv/src/win/pipe.c vendored Normal file

File diff suppressed because it is too large Load Diff

584
deps/libuv/src/win/poll.c vendored Normal file
View File

@ -0,0 +1,584 @@
/* 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 <io.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
{0xe70f1aa0, 0xab8b, 0x11cf,
{0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
{0xf9eab0c0, 0x26d4, 0x11d0,
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
{0x9fc48064, 0x7298, 0x43e4,
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
};
typedef struct uv_single_fd_set_s {
unsigned int fd_count;
SOCKET fd_array[1];
} uv_single_fd_set_t;
static OVERLAPPED overlapped_dummy_;
static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
static AFD_POLL_INFO afd_poll_info_dummy_;
static void uv__init_overlapped_dummy(void) {
HANDLE event;
event = CreateEvent(NULL, TRUE, TRUE, NULL);
if (event == NULL)
uv_fatal_error(GetLastError(), "CreateEvent");
memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
}
static OVERLAPPED* uv__get_overlapped_dummy(void) {
uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
return &overlapped_dummy_;
}
static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
return &afd_poll_info_dummy_;
}
static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
uv_req_t* req;
AFD_POLL_INFO* afd_poll_info;
int result;
/* Find a yet unsubmitted req to submit. */
if (handle->submitted_events_1 == 0) {
req = &handle->poll_req_1;
afd_poll_info = &handle->afd_poll_info_1;
handle->submitted_events_1 = handle->events;
handle->mask_events_1 = 0;
handle->mask_events_2 = handle->events;
} else if (handle->submitted_events_2 == 0) {
req = &handle->poll_req_2;
afd_poll_info = &handle->afd_poll_info_2;
handle->submitted_events_2 = handle->events;
handle->mask_events_1 = handle->events;
handle->mask_events_2 = 0;
} else {
/* Just wait until there's an unsubmitted req. This will happen almost
* immediately as one of the 2 outstanding requests is about to return.
* When this happens, uv__fast_poll_process_poll_req will be called, and
* the pending events, if needed, will be processed in a subsequent
* request. */
return;
}
/* Setting Exclusive to TRUE makes the other poll request return if there is
* any. */
afd_poll_info->Exclusive = TRUE;
afd_poll_info->NumberOfHandles = 1;
afd_poll_info->Timeout.QuadPart = INT64_MAX;
afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info->Handles[0].Status = 0;
afd_poll_info->Handles[0].Events = 0;
if (handle->events & UV_READABLE) {
afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
} else {
if (handle->events & UV_DISCONNECT) {
afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
}
}
if (handle->events & UV_WRITABLE) {
afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
}
memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
result = uv_msafd_poll((SOCKET) handle->peer_socket,
afd_poll_info,
afd_poll_info,
&req->u.io.overlapped);
if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
/* Queue this req, reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, req);
}
}
static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
uv_req_t* req) {
unsigned char mask_events;
AFD_POLL_INFO* afd_poll_info;
if (req == &handle->poll_req_1) {
afd_poll_info = &handle->afd_poll_info_1;
handle->submitted_events_1 = 0;
mask_events = handle->mask_events_1;
} else if (req == &handle->poll_req_2) {
afd_poll_info = &handle->afd_poll_info_2;
handle->submitted_events_2 = 0;
mask_events = handle->mask_events_2;
} else {
assert(0);
return;
}
/* Report an error unless the select was just interrupted. */
if (!REQ_SUCCESS(req)) {
DWORD error = GET_REQ_SOCK_ERROR(req);
if (error != WSAEINTR && handle->events != 0) {
handle->events = 0; /* Stop the watcher */
handle->poll_cb(handle, uv_translate_sys_error(error), 0);
}
} else if (afd_poll_info->NumberOfHandles >= 1) {
unsigned char events = 0;
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
events |= UV_READABLE;
if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
events |= UV_DISCONNECT;
}
}
if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
AFD_POLL_CONNECT_FAIL)) != 0) {
events |= UV_WRITABLE;
}
events &= handle->events & ~mask_events;
if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
/* Stop polling. */
handle->events = 0;
if (uv__is_active(handle))
uv__handle_stop(handle);
}
if (events != 0) {
handle->poll_cb(handle, 0, events);
}
}
if ((handle->events & ~(handle->submitted_events_1 |
handle->submitted_events_2)) != 0) {
uv__fast_poll_submit_poll_req(loop, handle);
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
WSAPROTOCOL_INFOW* protocol_info) {
SOCKET sock = 0;
sock = WSASocketW(protocol_info->iAddressFamily,
protocol_info->iSocketType,
protocol_info->iProtocol,
protocol_info,
0,
WSA_FLAG_OVERLAPPED);
if (sock == INVALID_SOCKET) {
return INVALID_SOCKET;
}
if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
goto error;
};
if (CreateIoCompletionPort((HANDLE) sock,
iocp,
(ULONG_PTR) sock,
0) == NULL) {
goto error;
}
return sock;
error:
closesocket(sock);
return INVALID_SOCKET;
}
static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
WSAPROTOCOL_INFOW* protocol_info) {
int index, i;
SOCKET peer_socket;
index = -1;
for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
if (memcmp((void*) &protocol_info->ProviderId,
(void*) &uv_msafd_provider_ids[i],
sizeof protocol_info->ProviderId) == 0) {
index = i;
}
}
/* Check if the protocol uses an msafd socket. */
if (index < 0) {
return INVALID_SOCKET;
}
/* If we didn't (try) to create a peer socket yet, try to make one. Don't try
* again if the peer socket creation failed earlier for the same protocol. */
peer_socket = loop->poll_peer_sockets[index];
if (peer_socket == 0) {
peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
loop->poll_peer_sockets[index] = peer_socket;
}
return peer_socket;
}
static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
uv_req_t* req = (uv_req_t*) arg;
uv_poll_t* handle = (uv_poll_t*) req->data;
unsigned char reported_events;
int r;
uv_single_fd_set_t rfds, wfds, efds;
struct timeval timeout;
assert(handle->type == UV_POLL);
assert(req->type == UV_POLL_REQ);
if (handle->events & UV_READABLE) {
rfds.fd_count = 1;
rfds.fd_array[0] = handle->socket;
} else {
rfds.fd_count = 0;
}
if (handle->events & UV_WRITABLE) {
wfds.fd_count = 1;
wfds.fd_array[0] = handle->socket;
efds.fd_count = 1;
efds.fd_array[0] = handle->socket;
} else {
wfds.fd_count = 0;
efds.fd_count = 0;
}
/* Make the select() time out after 3 minutes. If select() hangs because the
* user closed the socket, we will at least not hang indefinitely. */
timeout.tv_sec = 3 * 60;
timeout.tv_usec = 0;
r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
if (r == SOCKET_ERROR) {
/* Queue this req, reporting an error. */
SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
POST_COMPLETION_FOR_REQ(handle->loop, req);
return 0;
}
reported_events = 0;
if (r > 0) {
if (rfds.fd_count > 0) {
assert(rfds.fd_count == 1);
assert(rfds.fd_array[0] == handle->socket);
reported_events |= UV_READABLE;
}
if (wfds.fd_count > 0) {
assert(wfds.fd_count == 1);
assert(wfds.fd_array[0] == handle->socket);
reported_events |= UV_WRITABLE;
} else if (efds.fd_count > 0) {
assert(efds.fd_count == 1);
assert(efds.fd_array[0] == handle->socket);
reported_events |= UV_WRITABLE;
}
}
SET_REQ_SUCCESS(req);
req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
POST_COMPLETION_FOR_REQ(handle->loop, req);
return 0;
}
static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
uv_req_t* req;
/* Find a yet unsubmitted req to submit. */
if (handle->submitted_events_1 == 0) {
req = &handle->poll_req_1;
handle->submitted_events_1 = handle->events;
handle->mask_events_1 = 0;
handle->mask_events_2 = handle->events;
} else if (handle->submitted_events_2 == 0) {
req = &handle->poll_req_2;
handle->submitted_events_2 = handle->events;
handle->mask_events_1 = handle->events;
handle->mask_events_2 = 0;
} else {
assert(0);
return;
}
if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
(void*) req,
WT_EXECUTELONGFUNCTION)) {
/* Make this req pending, reporting an error. */
SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, req);
}
}
static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
uv_req_t* req) {
unsigned char mask_events;
int err;
if (req == &handle->poll_req_1) {
handle->submitted_events_1 = 0;
mask_events = handle->mask_events_1;
} else if (req == &handle->poll_req_2) {
handle->submitted_events_2 = 0;
mask_events = handle->mask_events_2;
} else {
assert(0);
return;
}
if (!REQ_SUCCESS(req)) {
/* Error. */
if (handle->events != 0) {
err = GET_REQ_ERROR(req);
handle->events = 0; /* Stop the watcher */
handle->poll_cb(handle, uv_translate_sys_error(err), 0);
}
} else {
/* Got some events. */
int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
if (events != 0) {
handle->poll_cb(handle, 0, events);
}
}
if ((handle->events & ~(handle->submitted_events_1 |
handle->submitted_events_2)) != 0) {
uv__slow_poll_submit_poll_req(loop, handle);
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
}
int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
uv_os_sock_t socket) {
WSAPROTOCOL_INFOW protocol_info;
int len;
SOCKET peer_socket, base_socket;
DWORD bytes;
DWORD yes = 1;
/* Set the socket to nonblocking mode */
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
return uv_translate_sys_error(WSAGetLastError());
/* Try to obtain a base handle for the socket. This increases this chances that
* we find an AFD handle and are able to use the fast poll mechanism. This will
* always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE
* ioctl. */
#ifndef NDEBUG
base_socket = INVALID_SOCKET;
#endif
if (WSAIoctl(socket,
SIO_BASE_HANDLE,
NULL,
0,
&base_socket,
sizeof base_socket,
&bytes,
NULL,
NULL) == 0) {
assert(base_socket != 0 && base_socket != INVALID_SOCKET);
socket = base_socket;
}
uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
handle->socket = socket;
handle->events = 0;
/* Obtain protocol information about the socket. */
len = sizeof protocol_info;
if (getsockopt(socket,
SOL_SOCKET,
SO_PROTOCOL_INFOW,
(char*) &protocol_info,
&len) != 0) {
return uv_translate_sys_error(WSAGetLastError());
}
/* Get the peer socket that is needed to enable fast poll. If the returned
* value is NULL, the protocol is not implemented by MSAFD and we'll have to
* use slow mode. */
peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
if (peer_socket != INVALID_SOCKET) {
/* Initialize fast poll specific fields. */
handle->peer_socket = peer_socket;
} else {
/* Initialize slow poll specific fields. */
handle->flags |= UV_HANDLE_POLL_SLOW;
}
/* Initialize 2 poll reqs. */
handle->submitted_events_1 = 0;
UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ);
handle->poll_req_1.data = handle;
handle->submitted_events_2 = 0;
UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ);
handle->poll_req_2.data = handle;
return 0;
}
static int uv__poll_set(uv_poll_t* handle, int events, uv_poll_cb cb) {
int submitted_events;
assert(handle->type == UV_POLL);
assert(!(handle->flags & UV_HANDLE_CLOSING));
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
handle->events = events;
handle->poll_cb = cb;
if (handle->events == 0) {
uv__handle_stop(handle);
return 0;
}
uv__handle_start(handle);
submitted_events = handle->submitted_events_1 | handle->submitted_events_2;
if (handle->events & ~submitted_events) {
if (handle->flags & UV_HANDLE_POLL_SLOW) {
uv__slow_poll_submit_poll_req(handle->loop, handle);
} else {
uv__fast_poll_submit_poll_req(handle->loop, handle);
}
}
return 0;
}
int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
return uv__poll_set(handle, events, cb);
}
int uv_poll_stop(uv_poll_t* handle) {
return uv__poll_set(handle, 0, handle->poll_cb);
}
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
uv__fast_poll_process_poll_req(loop, handle, req);
} else {
uv__slow_poll_process_poll_req(loop, handle, req);
}
}
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
AFD_POLL_INFO afd_poll_info;
DWORD error;
int result;
handle->events = 0;
uv__handle_closing(handle);
if (handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
return 0;
}
if (handle->flags & UV_HANDLE_POLL_SLOW)
return 0;
/* Cancel outstanding poll requests by executing another, unique poll
* request that forces the outstanding ones to return. */
afd_poll_info.Exclusive = TRUE;
afd_poll_info.NumberOfHandles = 1;
afd_poll_info.Timeout.QuadPart = INT64_MAX;
afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
afd_poll_info.Handles[0].Status = 0;
afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
result = uv_msafd_poll(handle->socket,
&afd_poll_info,
uv__get_afd_poll_info_dummy(),
uv__get_overlapped_dummy());
if (result == SOCKET_ERROR) {
error = WSAGetLastError();
if (error != WSA_IO_PENDING)
return uv_translate_sys_error(error);
}
return 0;
}
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->submitted_events_1 == 0);
assert(handle->submitted_events_2 == 0);
uv__handle_close(handle);
}

512
deps/libuv/src/win/process-stdio.c vendored Normal file
View File

@ -0,0 +1,512 @@
/* 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 <io.h>
#include <stdio.h>
#include <stdlib.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
/*
* The `child_stdio_buffer` buffer has the following layout:
* int number_of_fds
* unsigned char crt_flags[number_of_fds]
* HANDLE os_handle[number_of_fds]
*/
#define CHILD_STDIO_SIZE(count) \
(sizeof(int) + \
sizeof(unsigned char) * (count) + \
sizeof(uintptr_t) * (count))
#define CHILD_STDIO_COUNT(buffer) \
*((unsigned int*) (buffer))
#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
*((unsigned char*) (buffer) + sizeof(int) + fd)
#define CHILD_STDIO_HANDLE(buffer, fd) \
*((HANDLE*) ((unsigned char*) (buffer) + \
sizeof(int) + \
sizeof(unsigned char) * \
CHILD_STDIO_COUNT((buffer)) + \
sizeof(HANDLE) * (fd)))
/* CRT file descriptor mode flags */
#define FOPEN 0x01
#define FEOFLAG 0x02
#define FCRLF 0x04
#define FPIPE 0x08
#define FNOINHERIT 0x10
#define FAPPEND 0x20
#define FDEV 0x40
#define FTEXT 0x80
/*
* Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
* the parent process. Don't check for errors - the stdio handles may not be
* valid, or may be closed already. There is no guarantee that this function
* does a perfect job.
*/
void uv_disable_stdio_inheritance(void) {
HANDLE handle;
STARTUPINFOW si;
/* Make the windows stdio handles non-inheritable. */
handle = GetStdHandle(STD_INPUT_HANDLE);
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
handle = GetStdHandle(STD_OUTPUT_HANDLE);
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
handle = GetStdHandle(STD_ERROR_HANDLE);
if (handle != NULL && handle != INVALID_HANDLE_VALUE)
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
/* Make inherited CRT FDs non-inheritable. */
GetStartupInfoW(&si);
if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
uv__stdio_noinherit(si.lpReserved2);
}
static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
char pipe_name[64];
SECURITY_ATTRIBUTES sa;
DWORD server_access = 0;
DWORD client_access = 0;
HANDLE child_pipe = INVALID_HANDLE_VALUE;
int err;
int overlap;
if (flags & UV_READABLE_PIPE) {
/* The server needs inbound access too, otherwise CreateNamedPipe() won't
* give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
* state of the write buffer when we're trying to shutdown the pipe. */
server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
}
if (flags & UV_WRITABLE_PIPE) {
server_access |= PIPE_ACCESS_INBOUND;
client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
}
/* Create server pipe handle. */
err = uv_stdio_pipe_server(loop,
server_pipe,
server_access,
pipe_name,
sizeof(pipe_name));
if (err)
goto error;
/* Create child pipe handle. */
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
child_pipe = CreateFileA(pipe_name,
client_access,
0,
&sa,
OPEN_EXISTING,
overlap ? FILE_FLAG_OVERLAPPED : 0,
NULL);
if (child_pipe == INVALID_HANDLE_VALUE) {
err = GetLastError();
goto error;
}
#ifndef NDEBUG
/* Validate that the pipe was opened in the right mode. */
{
DWORD mode;
BOOL r = GetNamedPipeHandleState(child_pipe,
&mode,
NULL,
NULL,
NULL,
NULL,
0);
assert(r == TRUE);
assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
}
#endif
/* Do a blocking ConnectNamedPipe. This should not block because we have both
* ends of the pipe created. */
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
if (GetLastError() != ERROR_PIPE_CONNECTED) {
err = GetLastError();
goto error;
}
}
/* The server end is now readable and/or writable. */
if (flags & UV_READABLE_PIPE)
server_pipe->flags |= UV_HANDLE_WRITABLE;
if (flags & UV_WRITABLE_PIPE)
server_pipe->flags |= UV_HANDLE_READABLE;
*child_pipe_ptr = child_pipe;
return 0;
error:
if (server_pipe->handle != INVALID_HANDLE_VALUE) {
uv_pipe_cleanup(loop, server_pipe);
}
if (child_pipe != INVALID_HANDLE_VALUE) {
CloseHandle(child_pipe);
}
return err;
}
static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
HANDLE current_process;
/* _get_osfhandle will sometimes return -2 in case of an error. This seems to
* happen when fd <= 2 and the process' corresponding stdio handle is set to
* NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
* this situation goes unnoticed until someone tries to use the duplicate.
* Therefore we filter out known-invalid handles here. */
if (handle == INVALID_HANDLE_VALUE ||
handle == NULL ||
handle == (HANDLE) -2) {
*dup = INVALID_HANDLE_VALUE;
return ERROR_INVALID_HANDLE;
}
current_process = GetCurrentProcess();
if (!DuplicateHandle(current_process,
handle,
current_process,
dup,
0,
TRUE,
DUPLICATE_SAME_ACCESS)) {
*dup = INVALID_HANDLE_VALUE;
return GetLastError();
}
return 0;
}
static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
HANDLE handle;
if (fd == -1) {
*dup = INVALID_HANDLE_VALUE;
return ERROR_INVALID_HANDLE;
}
handle = uv__get_osfhandle(fd);
return uv__duplicate_handle(loop, handle, dup);
}
int uv__create_nul_handle(HANDLE* handle_ptr,
DWORD access) {
HANDLE handle;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof sa;
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
handle = CreateFileW(L"NUL",
access,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sa,
OPEN_EXISTING,
0,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
return GetLastError();
}
*handle_ptr = handle;
return 0;
}
int uv__stdio_create(uv_loop_t* loop,
const uv_process_options_t* options,
BYTE** buffer_ptr) {
BYTE* buffer;
int count, i;
int err;
count = options->stdio_count;
if (count < 0 || count > 255) {
/* Only support FDs 0-255 */
return ERROR_NOT_SUPPORTED;
} else if (count < 3) {
/* There should always be at least 3 stdio handles. */
count = 3;
}
/* Allocate the child stdio buffer */
buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
if (buffer == NULL) {
return ERROR_OUTOFMEMORY;
}
/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
* up on failure. */
CHILD_STDIO_COUNT(buffer) = count;
for (i = 0; i < count; i++) {
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
}
for (i = 0; i < count; i++) {
uv_stdio_container_t fdopt;
if (i < options->stdio_count) {
fdopt = options->stdio[i];
} else {
fdopt.flags = UV_IGNORE;
}
switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
UV_INHERIT_STREAM)) {
case UV_IGNORE:
/* Starting a process with no stdin/stout/stderr can confuse it. So no
* matter what the user specified, we make sure the first three FDs are
* always open in their typical modes, e. g. stdin be readable and
* stdout/err should be writable. For FDs > 2, don't do anything - all
* handles in the stdio buffer are initialized with.
* INVALID_HANDLE_VALUE, which should be okay. */
if (i <= 2) {
DWORD access = (i == 0) ? FILE_GENERIC_READ :
FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
access);
if (err)
goto error;
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
}
break;
case UV_CREATE_PIPE: {
/* Create a pair of two connected pipe ends; one end is turned into an
* uv_pipe_t for use by the parent. The other one is given to the
* child. */
uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
HANDLE child_pipe = INVALID_HANDLE_VALUE;
/* Create a new, connected pipe pair. stdio[i]. stream should point to
* an uninitialized, but not connected pipe handle. */
assert(fdopt.data.stream->type == UV_NAMED_PIPE);
assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
err = uv__create_stdio_pipe_pair(loop,
parent_pipe,
&child_pipe,
fdopt.flags);
if (err)
goto error;
CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
break;
}
case UV_INHERIT_FD: {
/* Inherit a raw FD. */
HANDLE child_handle;
/* Make an inheritable duplicate of the handle. */
err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
if (err) {
/* If fdopt. data. fd is not valid and fd <= 2, then ignore the
* error. */
if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
break;
}
goto error;
}
/* Figure out what the type is. */
switch (GetFileType(child_handle)) {
case FILE_TYPE_DISK:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
break;
case FILE_TYPE_PIPE:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
break;
case FILE_TYPE_CHAR:
case FILE_TYPE_REMOTE:
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
break;
case FILE_TYPE_UNKNOWN:
if (GetLastError() != 0) {
err = GetLastError();
CloseHandle(child_handle);
goto error;
}
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
break;
default:
assert(0);
return -1;
}
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
break;
}
case UV_INHERIT_STREAM: {
/* Use an existing stream as the stdio handle for the child. */
HANDLE stream_handle, child_handle;
unsigned char crt_flags;
uv_stream_t* stream = fdopt.data.stream;
/* Leech the handle out of the stream. */
if (stream->type == UV_TTY) {
stream_handle = ((uv_tty_t*) stream)->handle;
crt_flags = FOPEN | FDEV;
} else if (stream->type == UV_NAMED_PIPE &&
stream->flags & UV_HANDLE_CONNECTION) {
stream_handle = ((uv_pipe_t*) stream)->handle;
crt_flags = FOPEN | FPIPE;
} else {
stream_handle = INVALID_HANDLE_VALUE;
crt_flags = 0;
}
if (stream_handle == NULL ||
stream_handle == INVALID_HANDLE_VALUE) {
/* The handle is already closed, or not yet created, or the stream
* type is not supported. */
err = ERROR_NOT_SUPPORTED;
goto error;
}
/* Make an inheritable copy of the handle. */
err = uv__duplicate_handle(loop, stream_handle, &child_handle);
if (err)
goto error;
CHILD_STDIO_HANDLE(buffer, i) = child_handle;
CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
break;
}
default:
assert(0);
return -1;
}
}
*buffer_ptr = buffer;
return 0;
error:
uv__stdio_destroy(buffer);
return err;
}
void uv__stdio_destroy(BYTE* buffer) {
int i, count;
count = CHILD_STDIO_COUNT(buffer);
for (i = 0; i < count; i++) {
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
if (handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
}
}
uv__free(buffer);
}
void uv__stdio_noinherit(BYTE* buffer) {
int i, count;
count = CHILD_STDIO_COUNT(buffer);
for (i = 0; i < count; i++) {
HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
if (handle != INVALID_HANDLE_VALUE) {
SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
}
}
}
int uv__stdio_verify(BYTE* buffer, WORD size) {
unsigned int count;
/* Check the buffer pointer. */
if (buffer == NULL)
return 0;
/* Verify that the buffer is at least big enough to hold the count. */
if (size < CHILD_STDIO_SIZE(0))
return 0;
/* Verify if the count is within range. */
count = CHILD_STDIO_COUNT(buffer);
if (count > 256)
return 0;
/* Verify that the buffer size is big enough to hold info for N FDs. */
if (size < CHILD_STDIO_SIZE(count))
return 0;
return 1;
}
WORD uv__stdio_size(BYTE* buffer) {
return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
}
HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
return CHILD_STDIO_HANDLE(buffer, fd);
}

1281
deps/libuv/src/win/process.c vendored Normal file

File diff suppressed because it is too large Load Diff

221
deps/libuv/src/win/req-inl.h vendored Normal file
View File

@ -0,0 +1,221 @@
/* 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.
*/
#ifndef UV_WIN_REQ_INL_H_
#define UV_WIN_REQ_INL_H_
#include <assert.h>
#include "uv.h"
#include "internal.h"
#define SET_REQ_STATUS(req, status) \
(req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
#define SET_REQ_ERROR(req, error) \
SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency
* between src/uv-common.h and src/win/internal.h.
*/
#define SET_REQ_SUCCESS(req) \
SET_REQ_STATUS((req), STATUS_SUCCESS)
#define GET_REQ_STATUS(req) \
((NTSTATUS) (req)->u.io.overlapped.Internal)
#define REQ_SUCCESS(req) \
(NT_SUCCESS(GET_REQ_STATUS((req))))
#define GET_REQ_ERROR(req) \
(pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
#define GET_REQ_SOCK_ERROR(req) \
(uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
#define REGISTER_HANDLE_REQ(loop, handle, req) \
do { \
INCREASE_ACTIVE_COUNT((loop), (handle)); \
uv__req_register((loop), (req)); \
} while (0)
#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
do { \
DECREASE_ACTIVE_COUNT((loop), (handle)); \
uv__req_unregister((loop), (req)); \
} while (0)
#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
#define UV_SUCCEEDED_WITH_IOCP(result) \
((result) || (GetLastError() == ERROR_IO_PENDING))
#define POST_COMPLETION_FOR_REQ(loop, req) \
if (!PostQueuedCompletionStatus((loop)->iocp, \
0, \
0, \
&((req)->u.io.overlapped))) { \
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
}
INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
}
INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
req->next_req = NULL;
if (loop->pending_reqs_tail) {
#ifdef _DEBUG
/* Ensure the request is not already in the queue, or the queue
* will get corrupted.
*/
uv_req_t* current = loop->pending_reqs_tail;
do {
assert(req != current);
current = current->next_req;
} while(current != loop->pending_reqs_tail);
#endif
req->next_req = loop->pending_reqs_tail->next_req;
loop->pending_reqs_tail->next_req = req;
loop->pending_reqs_tail = req;
} else {
req->next_req = req;
loop->pending_reqs_tail = req;
}
}
#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
do { \
switch (((uv_handle_t*) (req)->handle_at)->type) { \
case UV_TCP: \
uv_process_tcp_##method##_req(loop, \
(uv_tcp_t*) ((req)->handle_at), \
req); \
break; \
\
case UV_NAMED_PIPE: \
uv_process_pipe_##method##_req(loop, \
(uv_pipe_t*) ((req)->handle_at), \
req); \
break; \
\
case UV_TTY: \
uv_process_tty_##method##_req(loop, \
(uv_tty_t*) ((req)->handle_at), \
req); \
break; \
\
default: \
assert(0); \
} \
} while (0)
INLINE static int uv_process_reqs(uv_loop_t* loop) {
uv_req_t* req;
uv_req_t* first;
uv_req_t* next;
if (loop->pending_reqs_tail == NULL)
return 0;
first = loop->pending_reqs_tail->next_req;
next = first;
loop->pending_reqs_tail = NULL;
while (next != NULL) {
req = next;
next = req->next_req != first ? req->next_req : NULL;
switch (req->type) {
case UV_READ:
DELEGATE_STREAM_REQ(loop, req, read, data);
break;
case UV_WRITE:
DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
break;
case UV_ACCEPT:
DELEGATE_STREAM_REQ(loop, req, accept, data);
break;
case UV_CONNECT:
DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
break;
case UV_SHUTDOWN:
/* Tcp shutdown requests don't come here. */
assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
uv_process_pipe_shutdown_req(
loop,
(uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
(uv_shutdown_t*) req);
break;
case UV_UDP_RECV:
uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
break;
case UV_UDP_SEND:
uv_process_udp_send_req(loop,
((uv_udp_send_t*) req)->handle,
(uv_udp_send_t*) req);
break;
case UV_WAKEUP:
uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
break;
case UV_SIGNAL_REQ:
uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
break;
case UV_POLL_REQ:
uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
break;
case UV_PROCESS_EXIT:
uv_process_proc_exit(loop, (uv_process_t*) req->data);
break;
case UV_FS_EVENT_REQ:
uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
break;
default:
assert(0);
}
}
return 1;
}
#endif /* UV_WIN_REQ_INL_H_ */

282
deps/libuv/src/win/signal.c vendored Normal file
View File

@ -0,0 +1,282 @@
/* 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 <signal.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
RB_HEAD(uv_signal_tree_s, uv_signal_s);
static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
static CRITICAL_SECTION uv__signal_lock;
static BOOL WINAPI uv__signal_control_handler(DWORD type);
int uv__signal_start(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum,
int oneshot);
void uv_signals_init(void) {
InitializeCriticalSection(&uv__signal_lock);
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
abort();
}
void uv__signal_cleanup(void) {
/* TODO(bnoordhuis) Undo effects of uv_signal_init()? */
}
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
/* Compare signums first so all watchers with the same signnum end up
* adjacent. */
if (w1->signum < w2->signum) return -1;
if (w1->signum > w2->signum) return 1;
/* Sort by loop pointer, so we can easily look up the first item after
* { .signum = x, .loop = NULL }. */
if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
return 0;
}
RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare)
/*
* Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
* Returns 1 if the signal was dispatched to any watcher, or 0 if there were
* no active signal watchers observing this signal.
*/
int uv__signal_dispatch(int signum) {
uv_signal_t lookup;
uv_signal_t* handle;
int dispatched;
dispatched = 0;
EnterCriticalSection(&uv__signal_lock);
lookup.signum = signum;
lookup.loop = NULL;
for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
handle != NULL && handle->signum == signum;
handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
unsigned long previous = InterlockedExchange(
(volatile LONG*) &handle->pending_signum, signum);
if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED)
continue;
if (!previous) {
POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
}
dispatched = 1;
if (handle->flags & UV_SIGNAL_ONE_SHOT)
handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED;
}
LeaveCriticalSection(&uv__signal_lock);
return dispatched;
}
static BOOL WINAPI uv__signal_control_handler(DWORD type) {
switch (type) {
case CTRL_C_EVENT:
return uv__signal_dispatch(SIGINT);
case CTRL_BREAK_EVENT:
return uv__signal_dispatch(SIGBREAK);
case CTRL_CLOSE_EVENT:
if (uv__signal_dispatch(SIGHUP)) {
/* Windows will terminate the process after the control handler
* returns. After that it will just terminate our process. Therefore
* block the signal handler so the main loop has some time to pick up
* the signal and do something for a few seconds. */
Sleep(INFINITE);
return TRUE;
}
return FALSE;
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
/* These signals are only sent to services. Services have their own
* notification mechanism, so there's no point in handling these. */
default:
/* We don't handle these. */
return FALSE;
}
}
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
handle->pending_signum = 0;
handle->signum = 0;
handle->signal_cb = NULL;
UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ);
handle->signal_req.data = handle;
return 0;
}
int uv_signal_stop(uv_signal_t* handle) {
uv_signal_t* removed_handle;
/* If the watcher wasn't started, this is a no-op. */
if (handle->signum == 0)
return 0;
EnterCriticalSection(&uv__signal_lock);
removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
assert(removed_handle == handle);
LeaveCriticalSection(&uv__signal_lock);
handle->signum = 0;
uv__handle_stop(handle);
return 0;
}
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
return uv__signal_start(handle, signal_cb, signum, 0);
}
int uv_signal_start_oneshot(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum) {
return uv__signal_start(handle, signal_cb, signum, 1);
}
int uv__signal_start(uv_signal_t* handle,
uv_signal_cb signal_cb,
int signum,
int oneshot) {
/* Test for invalid signal values. */
if (signum <= 0 || signum >= NSIG)
return UV_EINVAL;
/* Short circuit: if the signal watcher is already watching {signum} don't go
* through the process of deregistering and registering the handler.
* Additionally, this avoids pending signals getting lost in the (small) time
* frame that handle->signum == 0. */
if (signum == handle->signum) {
handle->signal_cb = signal_cb;
return 0;
}
/* If the signal handler was already active, stop it first. */
if (handle->signum != 0) {
int r = uv_signal_stop(handle);
/* uv_signal_stop is infallible. */
assert(r == 0);
}
EnterCriticalSection(&uv__signal_lock);
handle->signum = signum;
if (oneshot)
handle->flags |= UV_SIGNAL_ONE_SHOT;
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
LeaveCriticalSection(&uv__signal_lock);
handle->signal_cb = signal_cb;
uv__handle_start(handle);
return 0;
}
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req) {
long dispatched_signum;
assert(handle->type == UV_SIGNAL);
assert(req->type == UV_SIGNAL_REQ);
dispatched_signum = InterlockedExchange(
(volatile LONG*) &handle->pending_signum, 0);
assert(dispatched_signum != 0);
/* Check if the pending signal equals the signum that we are watching for.
* These can get out of sync when the handler is stopped and restarted while
* the signal_req is pending. */
if (dispatched_signum == handle->signum)
handle->signal_cb(handle, dispatched_signum);
if (handle->flags & UV_SIGNAL_ONE_SHOT)
uv_signal_stop(handle);
if (handle->flags & UV_HANDLE_CLOSING) {
/* When it is closing, it must be stopped at this point. */
assert(handle->signum == 0);
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
uv_signal_stop(handle);
uv__handle_closing(handle);
if (handle->pending_signum == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
}
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->signum == 0);
assert(handle->pending_signum == 0);
handle->flags |= UV_HANDLE_CLOSED;
uv__handle_close(handle);
}

42
deps/libuv/src/win/snprintf.c vendored Normal file
View File

@ -0,0 +1,42 @@
/* Copyright the libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdio.h>
#include <stdarg.h>
/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
* on overflow...
*/
int snprintf(char* buf, size_t len, const char* fmt, ...) {
int n;
va_list ap;
va_start(ap, fmt);
n = _vscprintf(fmt, ap);
vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
va_end(ap);
return n;
}
#endif

54
deps/libuv/src/win/stream-inl.h vendored Normal file
View File

@ -0,0 +1,54 @@
/* 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.
*/
#ifndef UV_WIN_STREAM_INL_H_
#define UV_WIN_STREAM_INL_H_
#include <assert.h>
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
INLINE static void uv_stream_init(uv_loop_t* loop,
uv_stream_t* handle,
uv_handle_type type) {
uv__handle_init(loop, (uv_handle_t*) handle, type);
handle->write_queue_size = 0;
handle->activecnt = 0;
handle->stream.conn.shutdown_req = NULL;
handle->stream.conn.write_reqs_pending = 0;
UV_REQ_INIT(&handle->read_req, UV_READ);
handle->read_req.event_handle = NULL;
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
handle->read_req.data = handle;
}
INLINE static void uv_connection_init(uv_stream_t* handle) {
handle->flags |= UV_HANDLE_CONNECTION;
}
#endif /* UV_WIN_STREAM_INL_H_ */

243
deps/libuv/src/win/stream.c vendored Normal file
View File

@ -0,0 +1,243 @@
/* 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 "uv.h"
#include "internal.h"
#include "handle-inl.h"
#include "req-inl.h"
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
int err;
err = ERROR_INVALID_PARAMETER;
switch (stream->type) {
case UV_TCP:
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
break;
case UV_NAMED_PIPE:
err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
break;
default:
assert(0);
}
return uv_translate_sys_error(err);
}
int uv_accept(uv_stream_t* server, uv_stream_t* client) {
int err;
err = ERROR_INVALID_PARAMETER;
switch (server->type) {
case UV_TCP:
err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
break;
case UV_NAMED_PIPE:
err = uv_pipe_accept((uv_pipe_t*)server, client);
break;
default:
assert(0);
}
return uv_translate_sys_error(err);
}
int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) {
int err;
if (handle->flags & UV_HANDLE_READING) {
return UV_EALREADY;
}
if (!(handle->flags & UV_HANDLE_READABLE)) {
return UV_ENOTCONN;
}
err = ERROR_INVALID_PARAMETER;
switch (handle->type) {
case UV_TCP:
err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
break;
case UV_NAMED_PIPE:
err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
break;
case UV_TTY:
err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
break;
default:
assert(0);
}
return uv_translate_sys_error(err);
}
int uv_read_stop(uv_stream_t* handle) {
int err;
if (!(handle->flags & UV_HANDLE_READING))
return 0;
err = 0;
if (handle->type == UV_TTY) {
err = uv_tty_read_stop((uv_tty_t*) handle);
} else if (handle->type == UV_NAMED_PIPE) {
uv__pipe_read_stop((uv_pipe_t*) handle);
} else {
handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(handle->loop, handle);
}
return uv_translate_sys_error(err);
}
int uv_write(uv_write_t* req,
uv_stream_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_write_cb cb) {
uv_loop_t* loop = handle->loop;
int err;
if (!(handle->flags & UV_HANDLE_WRITABLE)) {
return UV_EPIPE;
}
err = ERROR_INVALID_PARAMETER;
switch (handle->type) {
case UV_TCP:
err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
break;
case UV_NAMED_PIPE:
err = uv__pipe_write(
loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb);
break;
case UV_TTY:
err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
break;
default:
assert(0);
}
return uv_translate_sys_error(err);
}
int uv_write2(uv_write_t* req,
uv_stream_t* handle,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_stream_t* send_handle,
uv_write_cb cb) {
uv_loop_t* loop = handle->loop;
int err;
if (send_handle == NULL) {
return uv_write(req, handle, bufs, nbufs, cb);
}
if (handle->type != UV_NAMED_PIPE || !((uv_pipe_t*) handle)->ipc) {
return UV_EINVAL;
} else if (!(handle->flags & UV_HANDLE_WRITABLE)) {
return UV_EPIPE;
}
err = uv__pipe_write(
loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb);
return uv_translate_sys_error(err);
}
int uv_try_write(uv_stream_t* stream,
const uv_buf_t bufs[],
unsigned int nbufs) {
if (stream->flags & UV_HANDLE_CLOSING)
return UV_EBADF;
if (!(stream->flags & UV_HANDLE_WRITABLE))
return UV_EPIPE;
switch (stream->type) {
case UV_TCP:
return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
case UV_TTY:
return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
case UV_NAMED_PIPE:
return UV_EAGAIN;
default:
assert(0);
return UV_ENOSYS;
}
}
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
uv_loop_t* loop = handle->loop;
if (!(handle->flags & UV_HANDLE_WRITABLE) ||
handle->flags & UV_HANDLE_SHUTTING ||
uv__is_closing(handle)) {
return UV_ENOTCONN;
}
UV_REQ_INIT(req, UV_SHUTDOWN);
req->handle = handle;
req->cb = cb;
handle->flags &= ~UV_HANDLE_WRITABLE;
handle->flags |= UV_HANDLE_SHUTTING;
handle->stream.conn.shutdown_req = req;
handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
uv_want_endgame(loop, (uv_handle_t*)handle);
return 0;
}
int uv_is_readable(const uv_stream_t* handle) {
return !!(handle->flags & UV_HANDLE_READABLE);
}
int uv_is_writable(const uv_stream_t* handle) {
return !!(handle->flags & UV_HANDLE_WRITABLE);
}
int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
if (handle->type != UV_NAMED_PIPE)
return UV_EINVAL;
if (blocking != 0)
handle->flags |= UV_HANDLE_BLOCKING_WRITES;
else
handle->flags &= ~UV_HANDLE_BLOCKING_WRITES;
return 0;
}

1573
deps/libuv/src/win/tcp.c vendored Normal file

File diff suppressed because it is too large Load Diff

520
deps/libuv/src/win/thread.c vendored Normal file
View File

@ -0,0 +1,520 @@
/* 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 <limits.h>
#include <stdlib.h>
#if defined(__MINGW64_VERSION_MAJOR)
/* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may
* require this header in some versions of mingw64. */
#include <intrin.h>
#endif
#include "uv.h"
#include "internal.h"
static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
DWORD result;
HANDLE existing_event, created_event;
created_event = CreateEvent(NULL, 1, 0, NULL);
if (created_event == 0) {
/* Could fail in a low-memory situation? */
uv_fatal_error(GetLastError(), "CreateEvent");
}
existing_event = InterlockedCompareExchangePointer(&guard->event,
created_event,
NULL);
if (existing_event == NULL) {
/* We won the race */
callback();
result = SetEvent(created_event);
assert(result);
guard->ran = 1;
} else {
/* We lost the race. Destroy the event we created and wait for the existing
* one to become signaled. */
CloseHandle(created_event);
result = WaitForSingleObject(existing_event, INFINITE);
assert(result == WAIT_OBJECT_0);
}
}
void uv_once(uv_once_t* guard, void (*callback)(void)) {
/* Fast case - avoid WaitForSingleObject. */
if (guard->ran) {
return;
}
uv__once_inner(guard, callback);
}
/* Verify that uv_thread_t can be stored in a TLS slot. */
STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
static uv_key_t uv__current_thread_key;
static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
static void uv__init_current_thread_key(void) {
if (uv_key_create(&uv__current_thread_key))
abort();
}
struct thread_ctx {
void (*entry)(void* arg);
void* arg;
uv_thread_t self;
};
static UINT __stdcall uv__thread_start(void* arg) {
struct thread_ctx *ctx_p;
struct thread_ctx ctx;
ctx_p = arg;
ctx = *ctx_p;
uv__free(ctx_p);
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
uv_key_set(&uv__current_thread_key, (void*) ctx.self);
ctx.entry(ctx.arg);
return 0;
}
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
uv_thread_options_t params;
params.flags = UV_THREAD_NO_FLAGS;
return uv_thread_create_ex(tid, &params, entry, arg);
}
int uv_thread_create_ex(uv_thread_t* tid,
const uv_thread_options_t* params,
void (*entry)(void *arg),
void *arg) {
struct thread_ctx* ctx;
int err;
HANDLE thread;
SYSTEM_INFO sysinfo;
size_t stack_size;
size_t pagesize;
stack_size =
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
if (stack_size != 0) {
GetNativeSystemInfo(&sysinfo);
pagesize = (size_t)sysinfo.dwPageSize;
/* Round up to the nearest page boundary. */
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
if ((unsigned)stack_size != stack_size)
return UV_EINVAL;
}
ctx = uv__malloc(sizeof(*ctx));
if (ctx == NULL)
return UV_ENOMEM;
ctx->entry = entry;
ctx->arg = arg;
/* Create the thread in suspended state so we have a chance to pass
* its own creation handle to it */
thread = (HANDLE) _beginthreadex(NULL,
(unsigned)stack_size,
uv__thread_start,
ctx,
CREATE_SUSPENDED,
NULL);
if (thread == NULL) {
err = errno;
uv__free(ctx);
} else {
err = 0;
*tid = thread;
ctx->self = thread;
ResumeThread(thread);
}
switch (err) {
case 0:
return 0;
case EACCES:
return UV_EACCES;
case EAGAIN:
return UV_EAGAIN;
case EINVAL:
return UV_EINVAL;
}
return UV_EIO;
}
uv_thread_t uv_thread_self(void) {
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
return (uv_thread_t) uv_key_get(&uv__current_thread_key);
}
int uv_thread_join(uv_thread_t *tid) {
if (WaitForSingleObject(*tid, INFINITE))
return uv_translate_sys_error(GetLastError());
else {
CloseHandle(*tid);
*tid = 0;
MemoryBarrier(); /* For feature parity with pthread_join(). */
return 0;
}
}
int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
return *t1 == *t2;
}
int uv_mutex_init(uv_mutex_t* mutex) {
InitializeCriticalSection(mutex);
return 0;
}
int uv_mutex_init_recursive(uv_mutex_t* mutex) {
return uv_mutex_init(mutex);
}
void uv_mutex_destroy(uv_mutex_t* mutex) {
DeleteCriticalSection(mutex);
}
void uv_mutex_lock(uv_mutex_t* mutex) {
EnterCriticalSection(mutex);
}
int uv_mutex_trylock(uv_mutex_t* mutex) {
if (TryEnterCriticalSection(mutex))
return 0;
else
return UV_EBUSY;
}
void uv_mutex_unlock(uv_mutex_t* mutex) {
LeaveCriticalSection(mutex);
}
int uv_rwlock_init(uv_rwlock_t* rwlock) {
/* Initialize the semaphore that acts as the write lock. */
HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
if (handle == NULL)
return uv_translate_sys_error(GetLastError());
rwlock->state_.write_semaphore_ = handle;
/* Initialize the critical section protecting the reader count. */
InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
/* Initialize the reader count. */
rwlock->state_.num_readers_ = 0;
return 0;
}
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
CloseHandle(rwlock->state_.write_semaphore_);
}
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
/* Acquire the lock that protects the reader count. */
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
/* Increase the reader count, and lock for write if this is the first
* reader.
*/
if (++rwlock->state_.num_readers_ == 1) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
/* Release the lock that protects the reader count. */
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
}
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
int err;
if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
return UV_EBUSY;
err = 0;
if (rwlock->state_.num_readers_ == 0) {
/* Currently there are no other readers, which means that the write lock
* needs to be acquired.
*/
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
if (r == WAIT_OBJECT_0)
rwlock->state_.num_readers_++;
else if (r == WAIT_TIMEOUT)
err = UV_EBUSY;
else if (r == WAIT_FAILED)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
} else {
/* The write lock has already been acquired because there are other
* active readers.
*/
rwlock->state_.num_readers_++;
}
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
return err;
}
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
if (--rwlock->state_.num_readers_ == 0) {
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
}
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
}
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
if (r == WAIT_OBJECT_0)
return 0;
else if (r == WAIT_TIMEOUT)
return UV_EBUSY;
else
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
}
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
*sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
if (*sem == NULL)
return uv_translate_sys_error(GetLastError());
else
return 0;
}
void uv_sem_destroy(uv_sem_t* sem) {
if (!CloseHandle(*sem))
abort();
}
void uv_sem_post(uv_sem_t* sem) {
if (!ReleaseSemaphore(*sem, 1, NULL))
abort();
}
void uv_sem_wait(uv_sem_t* sem) {
if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
abort();
}
int uv_sem_trywait(uv_sem_t* sem) {
DWORD r = WaitForSingleObject(*sem, 0);
if (r == WAIT_OBJECT_0)
return 0;
if (r == WAIT_TIMEOUT)
return UV_EAGAIN;
abort();
return -1; /* Satisfy the compiler. */
}
int uv_cond_init(uv_cond_t* cond) {
InitializeConditionVariable(&cond->cond_var);
return 0;
}
void uv_cond_destroy(uv_cond_t* cond) {
/* nothing to do */
(void) &cond;
}
void uv_cond_signal(uv_cond_t* cond) {
WakeConditionVariable(&cond->cond_var);
}
void uv_cond_broadcast(uv_cond_t* cond) {
WakeAllConditionVariable(&cond->cond_var);
}
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
abort();
}
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
return 0;
if (GetLastError() != ERROR_TIMEOUT)
abort();
return UV_ETIMEDOUT;
}
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
int err;
barrier->n = count;
barrier->count = 0;
err = uv_mutex_init(&barrier->mutex);
if (err)
return err;
err = uv_sem_init(&barrier->turnstile1, 0);
if (err)
goto error2;
err = uv_sem_init(&barrier->turnstile2, 1);
if (err)
goto error;
return 0;
error:
uv_sem_destroy(&barrier->turnstile1);
error2:
uv_mutex_destroy(&barrier->mutex);
return err;
}
void uv_barrier_destroy(uv_barrier_t* barrier) {
uv_sem_destroy(&barrier->turnstile2);
uv_sem_destroy(&barrier->turnstile1);
uv_mutex_destroy(&barrier->mutex);
}
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_unlock(&barrier->mutex);
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile1);
uv_mutex_lock(&barrier->mutex);
serial_thread = (--barrier->count == 0);
if (serial_thread) {
uv_sem_wait(&barrier->turnstile1);
uv_sem_post(&barrier->turnstile2);
}
uv_mutex_unlock(&barrier->mutex);
uv_sem_wait(&barrier->turnstile2);
uv_sem_post(&barrier->turnstile2);
return serial_thread;
}
int uv_key_create(uv_key_t* key) {
key->tls_index = TlsAlloc();
if (key->tls_index == TLS_OUT_OF_INDEXES)
return UV_ENOMEM;
return 0;
}
void uv_key_delete(uv_key_t* key) {
if (TlsFree(key->tls_index) == FALSE)
abort();
key->tls_index = TLS_OUT_OF_INDEXES;
}
void* uv_key_get(uv_key_t* key) {
void* value;
value = TlsGetValue(key->tls_index);
if (value == NULL)
if (GetLastError() != ERROR_SUCCESS)
abort();
return value;
}
void uv_key_set(uv_key_t* key, void* value) {
if (TlsSetValue(key->tls_index, value) == FALSE)
abort();
}

2452
deps/libuv/src/win/tty.c vendored Normal file

File diff suppressed because it is too large Load Diff

1181
deps/libuv/src/win/udp.c vendored Normal file

File diff suppressed because it is too large Load Diff

1977
deps/libuv/src/win/util.c vendored Normal file

File diff suppressed because it is too large Load Diff

137
deps/libuv/src/win/winapi.c vendored Normal file
View File

@ -0,0 +1,137 @@
/* 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 "uv.h"
#include "internal.h"
/* Ntdll function pointers */
sRtlGetVersion pRtlGetVersion;
sRtlNtStatusToDosError pRtlNtStatusToDosError;
sNtDeviceIoControlFile pNtDeviceIoControlFile;
sNtQueryInformationFile pNtQueryInformationFile;
sNtSetInformationFile pNtSetInformationFile;
sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
sNtQueryDirectoryFile pNtQueryDirectoryFile;
sNtQuerySystemInformation pNtQuerySystemInformation;
sNtQueryInformationProcess pNtQueryInformationProcess;
/* Kernel32 function pointers */
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
/* Powrprof.dll function pointer */
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
/* User32.dll function pointer */
sSetWinEventHook pSetWinEventHook;
void uv_winapi_init(void) {
HMODULE ntdll_module;
HMODULE powrprof_module;
HMODULE user32_module;
HMODULE kernel32_module;
ntdll_module = GetModuleHandleA("ntdll.dll");
if (ntdll_module == NULL) {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
}
pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module,
"RtlGetVersion");
pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
ntdll_module,
"RtlNtStatusToDosError");
if (pRtlNtStatusToDosError == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress(
ntdll_module,
"NtDeviceIoControlFile");
if (pNtDeviceIoControlFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(
ntdll_module,
"NtQueryInformationFile");
if (pNtQueryInformationFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress(
ntdll_module,
"NtSetInformationFile");
if (pNtSetInformationFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile)
GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile");
if (pNtQueryVolumeInformationFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
if (pNtQueryVolumeInformationFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
ntdll_module,
"NtQuerySystemInformation");
if (pNtQuerySystemInformation == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
pNtQueryInformationProcess = (sNtQueryInformationProcess) GetProcAddress(
ntdll_module,
"NtQueryInformationProcess");
if (pNtQueryInformationProcess == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
kernel32_module = GetModuleHandleA("kernel32.dll");
if (kernel32_module == NULL) {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
}
pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
kernel32_module,
"GetQueuedCompletionStatusEx");
powrprof_module = LoadLibraryA("powrprof.dll");
if (powrprof_module != NULL) {
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
}
user32_module = LoadLibraryA("user32.dll");
if (user32_module != NULL) {
pSetWinEventHook = (sSetWinEventHook)
GetProcAddress(user32_module, "SetWinEventHook");
}
}

4762
deps/libuv/src/win/winapi.h vendored Normal file

File diff suppressed because it is too large Load Diff

575
deps/libuv/src/win/winsock.c vendored Normal file
View File

@ -0,0 +1,575 @@
/* 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 "uv.h"
#include "internal.h"
/* Whether there are any non-IFS LSPs stacked on TCP */
int uv_tcp_non_ifs_lsp_ipv4;
int uv_tcp_non_ifs_lsp_ipv6;
/* Ip address used to bind to any port at any interface */
struct sockaddr_in uv_addr_ip4_any_;
struct sockaddr_in6 uv_addr_ip6_any_;
/*
* Retrieves the pointer to a winsock extension function.
*/
static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
void **target) {
int result;
DWORD bytes;
result = WSAIoctl(socket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid,
sizeof(guid),
(void*)target,
sizeof(*target),
&bytes,
NULL,
NULL);
if (result == SOCKET_ERROR) {
*target = NULL;
return FALSE;
} else {
return TRUE;
}
}
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
const GUID wsaid_acceptex = WSAID_ACCEPTEX;
return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
}
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
const GUID wsaid_connectex = WSAID_CONNECTEX;
return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
}
void uv_winsock_init(void) {
WSADATA wsa_data;
int errorno;
SOCKET dummy;
WSAPROTOCOL_INFOW protocol_info;
int opt_len;
/* Set implicit binding address used by connectEx */
if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
abort();
}
if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
abort();
}
/* Skip initialization in safe mode without network support */
if (1 == GetSystemMetrics(SM_CLEANBOOT)) return;
/* Initialize winsock */
errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (errorno != 0) {
uv_fatal_error(errorno, "WSAStartup");
}
/* Try to detect non-IFS LSPs */
uv_tcp_non_ifs_lsp_ipv4 = 1;
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (dummy != INVALID_SOCKET) {
opt_len = (int) sizeof protocol_info;
if (getsockopt(dummy,
SOL_SOCKET,
SO_PROTOCOL_INFOW,
(char*) &protocol_info,
&opt_len) == 0) {
if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
uv_tcp_non_ifs_lsp_ipv4 = 0;
}
closesocket(dummy);
}
/* Try to detect IPV6 support and non-IFS LSPs */
uv_tcp_non_ifs_lsp_ipv6 = 1;
dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
if (dummy != INVALID_SOCKET) {
opt_len = (int) sizeof protocol_info;
if (getsockopt(dummy,
SOL_SOCKET,
SO_PROTOCOL_INFOW,
(char*) &protocol_info,
&opt_len) == 0) {
if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
uv_tcp_non_ifs_lsp_ipv6 = 0;
}
closesocket(dummy);
}
}
int uv_ntstatus_to_winsock_error(NTSTATUS status) {
switch (status) {
case STATUS_SUCCESS:
return ERROR_SUCCESS;
case STATUS_PENDING:
return ERROR_IO_PENDING;
case STATUS_INVALID_HANDLE:
case STATUS_OBJECT_TYPE_MISMATCH:
return WSAENOTSOCK;
case STATUS_INSUFFICIENT_RESOURCES:
case STATUS_PAGEFILE_QUOTA:
case STATUS_COMMITMENT_LIMIT:
case STATUS_WORKING_SET_QUOTA:
case STATUS_NO_MEMORY:
case STATUS_QUOTA_EXCEEDED:
case STATUS_TOO_MANY_PAGING_FILES:
case STATUS_REMOTE_RESOURCES:
return WSAENOBUFS;
case STATUS_TOO_MANY_ADDRESSES:
case STATUS_SHARING_VIOLATION:
case STATUS_ADDRESS_ALREADY_EXISTS:
return WSAEADDRINUSE;
case STATUS_LINK_TIMEOUT:
case STATUS_IO_TIMEOUT:
case STATUS_TIMEOUT:
return WSAETIMEDOUT;
case STATUS_GRACEFUL_DISCONNECT:
return WSAEDISCON;
case STATUS_REMOTE_DISCONNECT:
case STATUS_CONNECTION_RESET:
case STATUS_LINK_FAILED:
case STATUS_CONNECTION_DISCONNECTED:
case STATUS_PORT_UNREACHABLE:
case STATUS_HOPLIMIT_EXCEEDED:
return WSAECONNRESET;
case STATUS_LOCAL_DISCONNECT:
case STATUS_TRANSACTION_ABORTED:
case STATUS_CONNECTION_ABORTED:
return WSAECONNABORTED;
case STATUS_BAD_NETWORK_PATH:
case STATUS_NETWORK_UNREACHABLE:
case STATUS_PROTOCOL_UNREACHABLE:
return WSAENETUNREACH;
case STATUS_HOST_UNREACHABLE:
return WSAEHOSTUNREACH;
case STATUS_CANCELLED:
case STATUS_REQUEST_ABORTED:
return WSAEINTR;
case STATUS_BUFFER_OVERFLOW:
case STATUS_INVALID_BUFFER_SIZE:
return WSAEMSGSIZE;
case STATUS_BUFFER_TOO_SMALL:
case STATUS_ACCESS_VIOLATION:
return WSAEFAULT;
case STATUS_DEVICE_NOT_READY:
case STATUS_REQUEST_NOT_ACCEPTED:
return WSAEWOULDBLOCK;
case STATUS_INVALID_NETWORK_RESPONSE:
case STATUS_NETWORK_BUSY:
case STATUS_NO_SUCH_DEVICE:
case STATUS_NO_SUCH_FILE:
case STATUS_OBJECT_PATH_NOT_FOUND:
case STATUS_OBJECT_NAME_NOT_FOUND:
case STATUS_UNEXPECTED_NETWORK_ERROR:
return WSAENETDOWN;
case STATUS_INVALID_CONNECTION:
return WSAENOTCONN;
case STATUS_REMOTE_NOT_LISTENING:
case STATUS_CONNECTION_REFUSED:
return WSAECONNREFUSED;
case STATUS_PIPE_DISCONNECTED:
return WSAESHUTDOWN;
case STATUS_CONFLICTING_ADDRESSES:
case STATUS_INVALID_ADDRESS:
case STATUS_INVALID_ADDRESS_COMPONENT:
return WSAEADDRNOTAVAIL;
case STATUS_NOT_SUPPORTED:
case STATUS_NOT_IMPLEMENTED:
return WSAEOPNOTSUPP;
case STATUS_ACCESS_DENIED:
return WSAEACCES;
default:
if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
(status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
/* It's a windows error that has been previously mapped to an ntstatus
* code. */
return (DWORD) (status & 0xffff);
} else {
/* The default fallback for unmappable ntstatus codes. */
return WSAEINVAL;
}
}
}
/*
* This function provides a workaround for a bug in the winsock implementation
* of WSARecv. The problem is that when SetFileCompletionNotificationModes is
* used to avoid IOCP notifications of completed reads, WSARecv does not
* reliably indicate whether we can expect a completion package to be posted
* when the receive buffer is smaller than the received datagram.
*
* However it is desirable to use SetFileCompletionNotificationModes because
* it yields a massive performance increase.
*
* This function provides a workaround for that bug, but it only works for the
* specific case that we need it for. E.g. it assumes that the "avoid iocp"
* bit has been set, and supports only overlapped operation. It also requires
* the user to use the default msafd driver, doesn't work when other LSPs are
* stacked on top of it.
*/
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
NTSTATUS status;
void* apc_context;
IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
AFD_RECV_INFO info;
DWORD error;
if (overlapped == NULL || completion_routine != NULL) {
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
info.BufferArray = buffers;
info.BufferCount = buffer_count;
info.AfdFlags = AFD_OVERLAPPED;
info.TdiFlags = TDI_RECEIVE_NORMAL;
if (*flags & MSG_PEEK) {
info.TdiFlags |= TDI_RECEIVE_PEEK;
}
if (*flags & MSG_PARTIAL) {
info.TdiFlags |= TDI_RECEIVE_PARTIAL;
}
if (!((intptr_t) overlapped->hEvent & 1)) {
apc_context = (void*) overlapped;
} else {
apc_context = NULL;
}
iosb->Status = STATUS_PENDING;
iosb->Pointer = 0;
status = pNtDeviceIoControlFile((HANDLE) socket,
overlapped->hEvent,
NULL,
apc_context,
iosb,
IOCTL_AFD_RECEIVE,
&info,
sizeof(info),
NULL,
0);
*flags = 0;
*bytes = (DWORD) iosb->Information;
switch (status) {
case STATUS_SUCCESS:
error = ERROR_SUCCESS;
break;
case STATUS_PENDING:
error = WSA_IO_PENDING;
break;
case STATUS_BUFFER_OVERFLOW:
error = WSAEMSGSIZE;
break;
case STATUS_RECEIVE_EXPEDITED:
error = ERROR_SUCCESS;
*flags = MSG_OOB;
break;
case STATUS_RECEIVE_PARTIAL_EXPEDITED:
error = ERROR_SUCCESS;
*flags = MSG_PARTIAL | MSG_OOB;
break;
case STATUS_RECEIVE_PARTIAL:
error = ERROR_SUCCESS;
*flags = MSG_PARTIAL;
break;
default:
error = uv_ntstatus_to_winsock_error(status);
break;
}
WSASetLastError(error);
if (error == ERROR_SUCCESS) {
return 0;
} else {
return SOCKET_ERROR;
}
}
/* See description of uv_wsarecv_workaround. */
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
int* addr_len, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
NTSTATUS status;
void* apc_context;
IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
AFD_RECV_DATAGRAM_INFO info;
DWORD error;
if (overlapped == NULL || addr == NULL || addr_len == NULL ||
completion_routine != NULL) {
WSASetLastError(WSAEINVAL);
return SOCKET_ERROR;
}
info.BufferArray = buffers;
info.BufferCount = buffer_count;
info.AfdFlags = AFD_OVERLAPPED;
info.TdiFlags = TDI_RECEIVE_NORMAL;
info.Address = addr;
info.AddressLength = addr_len;
if (*flags & MSG_PEEK) {
info.TdiFlags |= TDI_RECEIVE_PEEK;
}
if (*flags & MSG_PARTIAL) {
info.TdiFlags |= TDI_RECEIVE_PARTIAL;
}
if (!((intptr_t) overlapped->hEvent & 1)) {
apc_context = (void*) overlapped;
} else {
apc_context = NULL;
}
iosb->Status = STATUS_PENDING;
iosb->Pointer = 0;
status = pNtDeviceIoControlFile((HANDLE) socket,
overlapped->hEvent,
NULL,
apc_context,
iosb,
IOCTL_AFD_RECEIVE_DATAGRAM,
&info,
sizeof(info),
NULL,
0);
*flags = 0;
*bytes = (DWORD) iosb->Information;
switch (status) {
case STATUS_SUCCESS:
error = ERROR_SUCCESS;
break;
case STATUS_PENDING:
error = WSA_IO_PENDING;
break;
case STATUS_BUFFER_OVERFLOW:
error = WSAEMSGSIZE;
break;
case STATUS_RECEIVE_EXPEDITED:
error = ERROR_SUCCESS;
*flags = MSG_OOB;
break;
case STATUS_RECEIVE_PARTIAL_EXPEDITED:
error = ERROR_SUCCESS;
*flags = MSG_PARTIAL | MSG_OOB;
break;
case STATUS_RECEIVE_PARTIAL:
error = ERROR_SUCCESS;
*flags = MSG_PARTIAL;
break;
default:
error = uv_ntstatus_to_winsock_error(status);
break;
}
WSASetLastError(error);
if (error == ERROR_SUCCESS) {
return 0;
} else {
return SOCKET_ERROR;
}
}
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
IO_STATUS_BLOCK iosb;
IO_STATUS_BLOCK* iosb_ptr;
HANDLE event = NULL;
void* apc_context;
NTSTATUS status;
DWORD error;
if (overlapped != NULL) {
/* Overlapped operation. */
iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
event = overlapped->hEvent;
/* Do not report iocp completion if hEvent is tagged. */
if ((uintptr_t) event & 1) {
event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
apc_context = NULL;
} else {
apc_context = overlapped;
}
} else {
/* Blocking operation. */
iosb_ptr = &iosb;
event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (event == NULL) {
return SOCKET_ERROR;
}
apc_context = NULL;
}
iosb_ptr->Status = STATUS_PENDING;
status = pNtDeviceIoControlFile((HANDLE) socket,
event,
NULL,
apc_context,
iosb_ptr,
IOCTL_AFD_POLL,
info_in,
sizeof *info_in,
info_out,
sizeof *info_out);
if (overlapped == NULL) {
/* If this is a blocking operation, wait for the event to become signaled,
* and then grab the real status from the io status block. */
if (status == STATUS_PENDING) {
DWORD r = WaitForSingleObject(event, INFINITE);
if (r == WAIT_FAILED) {
DWORD saved_error = GetLastError();
CloseHandle(event);
WSASetLastError(saved_error);
return SOCKET_ERROR;
}
status = iosb.Status;
}
CloseHandle(event);
}
switch (status) {
case STATUS_SUCCESS:
error = ERROR_SUCCESS;
break;
case STATUS_PENDING:
error = WSA_IO_PENDING;
break;
default:
error = uv_ntstatus_to_winsock_error(status);
break;
}
WSASetLastError(error);
if (error == ERROR_SUCCESS) {
return 0;
} else {
return SOCKET_ERROR;
}
}
int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
struct sockaddr_storage* storage) {
struct sockaddr_in* dest4;
struct sockaddr_in6* dest6;
if (addr == NULL)
return UV_EINVAL;
switch (addr->sa_family) {
case AF_INET:
dest4 = (struct sockaddr_in*) storage;
memcpy(dest4, addr, sizeof(*dest4));
if (dest4->sin_addr.s_addr == 0)
dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
return 0;
case AF_INET6:
dest6 = (struct sockaddr_in6*) storage;
memcpy(dest6, addr, sizeof(*dest6));
if (memcmp(&dest6->sin6_addr,
&uv_addr_ip6_any_.sin6_addr,
sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) {
struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT;
dest6->sin6_addr = init_sin6_addr;
}
return 0;
default:
return UV_EINVAL;
}
}

201
deps/libuv/src/win/winsock.h vendored Normal file
View File

@ -0,0 +1,201 @@
/* 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.
*/
#ifndef UV_WIN_WINSOCK_H_
#define UV_WIN_WINSOCK_H_
#include <winsock2.h>
#include <iptypes.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <windows.h>
#include "winapi.h"
/*
* MinGW is missing these too
*/
#ifndef SO_UPDATE_CONNECT_CONTEXT
# define SO_UPDATE_CONNECT_CONTEXT 0x7010
#endif
#ifndef TCP_KEEPALIVE
# define TCP_KEEPALIVE 3
#endif
#ifndef IPV6_V6ONLY
# define IPV6_V6ONLY 27
#endif
#ifndef IPV6_HOPLIMIT
# define IPV6_HOPLIMIT 21
#endif
#ifndef SIO_BASE_HANDLE
# define SIO_BASE_HANDLE 0x48000022
#endif
#ifndef MCAST_JOIN_SOURCE_GROUP
# define MCAST_JOIN_SOURCE_GROUP 45
#endif
#ifndef MCAST_LEAVE_SOURCE_GROUP
# define MCAST_LEAVE_SOURCE_GROUP 46
#endif
/*
* TDI defines that are only in the DDK.
* We only need receive flags so far.
*/
#ifndef TDI_RECEIVE_NORMAL
#define TDI_RECEIVE_BROADCAST 0x00000004
#define TDI_RECEIVE_MULTICAST 0x00000008
#define TDI_RECEIVE_PARTIAL 0x00000010
#define TDI_RECEIVE_NORMAL 0x00000020
#define TDI_RECEIVE_EXPEDITED 0x00000040
#define TDI_RECEIVE_PEEK 0x00000080
#define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100
#define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200
#define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400
#define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800
#define TDI_RECEIVE_CONTROL_INFO 0x00001000
#define TDI_RECEIVE_FORCE_INDICATION 0x00002000
#define TDI_RECEIVE_NO_PUSH 0x00004000
#endif
/*
* The "Auxiliary Function Driver" is the windows kernel-mode driver that does
* TCP, UDP etc. Winsock is just a layer that dispatches requests to it.
* Having these definitions allows us to bypass winsock and make an AFD kernel
* call directly, avoiding a bug in winsock's recvfrom implementation.
*/
#define AFD_NO_FAST_IO 0x00000001
#define AFD_OVERLAPPED 0x00000002
#define AFD_IMMEDIATE 0x00000004
#define AFD_POLL_RECEIVE_BIT 0
#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT)
#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1
#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT)
#define AFD_POLL_SEND_BIT 2
#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT)
#define AFD_POLL_DISCONNECT_BIT 3
#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT)
#define AFD_POLL_ABORT_BIT 4
#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT)
#define AFD_POLL_LOCAL_CLOSE_BIT 5
#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT)
#define AFD_POLL_CONNECT_BIT 6
#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT)
#define AFD_POLL_ACCEPT_BIT 7
#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT)
#define AFD_POLL_CONNECT_FAIL_BIT 8
#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT)
#define AFD_POLL_QOS_BIT 9
#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT)
#define AFD_POLL_GROUP_QOS_BIT 10
#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT)
#define AFD_NUM_POLL_EVENTS 11
#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1)
typedef struct _AFD_RECV_DATAGRAM_INFO {
LPWSABUF BufferArray;
ULONG BufferCount;
ULONG AfdFlags;
ULONG TdiFlags;
struct sockaddr* Address;
int* AddressLength;
} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO;
typedef struct _AFD_RECV_INFO {
LPWSABUF BufferArray;
ULONG BufferCount;
ULONG AfdFlags;
ULONG TdiFlags;
} AFD_RECV_INFO, *PAFD_RECV_INFO;
#define _AFD_CONTROL_CODE(operation, method) \
((FSCTL_AFD_BASE) << 12 | (operation << 2) | method)
#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
#define AFD_RECEIVE 5
#define AFD_RECEIVE_DATAGRAM 6
#define AFD_POLL 9
#define IOCTL_AFD_RECEIVE \
_AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER)
#define IOCTL_AFD_RECEIVE_DATAGRAM \
_AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
#define IOCTL_AFD_POLL \
_AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
/* FIXME: __C89_NAMELESS was removed */
/* __C89_NAMELESS */ union {
ULONGLONG Alignment;
/* __C89_NAMELESS */ struct {
ULONG Length;
DWORD Flags;
};
};
struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next;
SOCKET_ADDRESS Address;
IP_PREFIX_ORIGIN PrefixOrigin;
IP_SUFFIX_ORIGIN SuffixOrigin;
IP_DAD_STATE DadState;
ULONG ValidLifetime;
ULONG PreferredLifetime;
ULONG LeaseLifetime;
} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP;
typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
union {
ULONGLONG Alignment;
struct {
ULONG Length;
DWORD Flags;
};
};
struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next;
SOCKET_ADDRESS Address;
IP_PREFIX_ORIGIN PrefixOrigin;
IP_SUFFIX_ORIGIN SuffixOrigin;
IP_DAD_STATE DadState;
ULONG ValidLifetime;
ULONG PreferredLifetime;
ULONG LeaseLifetime;
UINT8 OnLinkPrefixLength;
} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH;
#endif
int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
struct sockaddr_storage* storage);
#endif /* UV_WIN_WINSOCK_H_ */