complete upgrade
This commit is contained in:
parent
62f7c7961d
commit
87d974bb8f
129
deps/uv/src/win/async.c
vendored
Normal file
129
deps/uv/src/win/async.c
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
/* 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"
|
||||
|
||||
|
||||
/* 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 __declspec(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
|
||||
|
||||
|
||||
void uv_async_endgame(uv_async_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
!handle->async_sent) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
uv_unref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_async_init(uv_async_t* handle, uv_async_cb async_cb) {
|
||||
uv_req_t* req;
|
||||
|
||||
uv_counters()->handle_init++;
|
||||
uv_counters()->async_init++;
|
||||
|
||||
handle->type = UV_ASYNC;
|
||||
handle->flags = 0;
|
||||
handle->async_sent = 0;
|
||||
handle->error = uv_ok_;
|
||||
handle->async_cb = async_cb;
|
||||
|
||||
req = &handle->async_req;
|
||||
uv_req_init(req);
|
||||
req->type = UV_WAKEUP;
|
||||
req->data = handle;
|
||||
|
||||
uv_ref();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_async_send(uv_async_t* handle) {
|
||||
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)) {
|
||||
if (!PostQueuedCompletionStatus(LOOP->iocp,
|
||||
0,
|
||||
0,
|
||||
&handle->async_req.overlapped)) {
|
||||
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_process_async_wakeup_req(uv_async_t* handle, uv_req_t* req) {
|
||||
assert(handle->type == UV_ASYNC);
|
||||
assert(req->type == UV_WAKEUP);
|
||||
|
||||
handle->async_sent = 0;
|
||||
if (handle->async_cb) {
|
||||
handle->async_cb((uv_async_t*) handle, 0);
|
||||
}
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame((uv_handle_t*)handle);
|
||||
}
|
||||
}
|
304
deps/uv/src/win/cares.c
vendored
Normal file
304
deps/uv/src/win/cares.c
vendored
Normal file
@ -0,0 +1,304 @@
|
||||
/* 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 "../uv-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* Subclass of uv_handle_t. Used for integration of c-ares.
|
||||
*/
|
||||
struct uv_ares_action_s {
|
||||
UV_HANDLE_FIELDS
|
||||
struct uv_req_s ares_req;
|
||||
SOCKET sock;
|
||||
int read;
|
||||
int write;
|
||||
};
|
||||
|
||||
|
||||
/* memory used per ares_channel */
|
||||
typedef struct uv_ares_channel_s {
|
||||
ares_channel channel;
|
||||
int activesockets;
|
||||
uv_timer_t pollingtimer;
|
||||
} uv_ares_channel_t;
|
||||
|
||||
|
||||
/* static data to hold single ares_channel */
|
||||
static uv_ares_channel_t uv_ares_data = { NULL, 0 };
|
||||
|
||||
|
||||
/* default timeout per socket request if ares does not specify value */
|
||||
/* use 20 sec */
|
||||
#define ARES_TIMEOUT_MS 20000
|
||||
|
||||
|
||||
/* thread pool callback when socket is signalled */
|
||||
static void CALLBACK uv_ares_socksignal_tp(void* parameter, BOOLEAN timerfired) {
|
||||
WSANETWORKEVENTS network_events;
|
||||
uv_ares_task_t* sockhandle;
|
||||
uv_ares_action_t* selhandle;
|
||||
uv_req_t* uv_ares_req;
|
||||
|
||||
assert(parameter != NULL);
|
||||
|
||||
if (parameter != NULL) {
|
||||
sockhandle = (uv_ares_task_t*)parameter;
|
||||
|
||||
/* clear socket status for this event */
|
||||
/* do not fail if error, thread may run after socket close */
|
||||
/* The code assumes that c-ares will write all pending data in the callback,
|
||||
unless the socket would block. We can clear the state here to avoid unecessary
|
||||
signals. */
|
||||
WSAEnumNetworkEvents(sockhandle->sock, sockhandle->h_event, &network_events);
|
||||
|
||||
/* setup new handle */
|
||||
selhandle = (uv_ares_action_t*)malloc(sizeof(uv_ares_action_t));
|
||||
if (selhandle == NULL) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
||||
}
|
||||
selhandle->type = UV_ARES_EVENT;
|
||||
selhandle->close_cb = NULL;
|
||||
selhandle->data = sockhandle->data;
|
||||
selhandle->sock = sockhandle->sock;
|
||||
selhandle->read = (network_events.lNetworkEvents & (FD_READ | FD_CONNECT)) ? 1 : 0;
|
||||
selhandle->write = (network_events.lNetworkEvents & (FD_WRITE | FD_CONNECT)) ? 1 : 0;
|
||||
|
||||
uv_ares_req = &selhandle->ares_req;
|
||||
uv_req_init(uv_ares_req);
|
||||
uv_ares_req->type = UV_ARES_EVENT_REQ;
|
||||
uv_ares_req->data = selhandle;
|
||||
|
||||
/* post ares needs to called */
|
||||
if (!PostQueuedCompletionStatus(LOOP->iocp,
|
||||
0,
|
||||
0,
|
||||
&uv_ares_req->overlapped)) {
|
||||
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* periodically call ares to check for timeouts */
|
||||
static void uv_ares_poll(uv_timer_t* handle, int status) {
|
||||
if (uv_ares_data.channel != NULL && uv_ares_data.activesockets > 0) {
|
||||
ares_process_fd(uv_ares_data.channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* callback from ares when socket operation is started */
|
||||
static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, int write) {
|
||||
/* look to see if we have a handle for this socket in our list */
|
||||
uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(sock);
|
||||
uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)data;
|
||||
|
||||
int timeoutms = 0;
|
||||
|
||||
if (read == 0 && write == 0) {
|
||||
/* if read and write are 0, cleanup existing data */
|
||||
/* The code assumes that c-ares does a callback with read = 0 and write = 0
|
||||
when the socket is closed. After we recieve this we stop monitoring the socket. */
|
||||
if (uv_handle_ares != NULL) {
|
||||
uv_req_t* uv_ares_req;
|
||||
|
||||
uv_handle_ares->h_close_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
/* remove Wait */
|
||||
if (uv_handle_ares->h_wait) {
|
||||
UnregisterWaitEx(uv_handle_ares->h_wait, uv_handle_ares->h_close_event);
|
||||
uv_handle_ares->h_wait = NULL;
|
||||
}
|
||||
|
||||
/* detach socket from the event */
|
||||
WSAEventSelect(sock, NULL, 0);
|
||||
if (uv_handle_ares->h_event != WSA_INVALID_EVENT) {
|
||||
WSACloseEvent(uv_handle_ares->h_event);
|
||||
uv_handle_ares->h_event = WSA_INVALID_EVENT;
|
||||
}
|
||||
/* remove handle from list */
|
||||
uv_remove_ares_handle(uv_handle_ares);
|
||||
|
||||
/* Post request to cleanup the Task */
|
||||
uv_ares_req = &uv_handle_ares->ares_req;
|
||||
uv_req_init(uv_ares_req);
|
||||
uv_ares_req->type = UV_ARES_CLEANUP_REQ;
|
||||
uv_ares_req->data = uv_handle_ares;
|
||||
|
||||
/* post ares done with socket - finish cleanup when all threads done. */
|
||||
if (!PostQueuedCompletionStatus(LOOP->iocp,
|
||||
0,
|
||||
0,
|
||||
&uv_ares_req->overlapped)) {
|
||||
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
||||
}
|
||||
} else {
|
||||
assert(0);
|
||||
uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB");
|
||||
}
|
||||
} else {
|
||||
if (uv_handle_ares == NULL) {
|
||||
/* setup new handle */
|
||||
/* The code assumes that c-ares will call us when it has an open socket.
|
||||
We need to call into c-ares when there is something to read,
|
||||
or when it becomes writable. */
|
||||
uv_handle_ares = (uv_ares_task_t*)malloc(sizeof(uv_ares_task_t));
|
||||
if (uv_handle_ares == NULL) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
||||
}
|
||||
uv_handle_ares->type = UV_ARES_TASK;
|
||||
uv_handle_ares->close_cb = NULL;
|
||||
uv_handle_ares->data = uv_ares_data_ptr;
|
||||
uv_handle_ares->sock = sock;
|
||||
uv_handle_ares->h_wait = NULL;
|
||||
uv_handle_ares->flags = 0;
|
||||
|
||||
/* create an event to wait on socket signal */
|
||||
uv_handle_ares->h_event = WSACreateEvent();
|
||||
if (uv_handle_ares->h_event == WSA_INVALID_EVENT) {
|
||||
uv_fatal_error(WSAGetLastError(), "WSACreateEvent");
|
||||
}
|
||||
|
||||
/* tie event to socket */
|
||||
if (SOCKET_ERROR == WSAEventSelect(sock, uv_handle_ares->h_event, FD_READ | FD_WRITE | FD_CONNECT)) {
|
||||
uv_fatal_error(WSAGetLastError(), "WSAEventSelect");
|
||||
}
|
||||
|
||||
/* add handle to list */
|
||||
uv_add_ares_handle(uv_handle_ares);
|
||||
uv_ref();
|
||||
|
||||
/*
|
||||
* we have a single polling timer for all ares sockets.
|
||||
* This is preferred to using ares_timeout. See ares_timeout.c warning.
|
||||
* if timer is not running start it, and keep socket count
|
||||
*/
|
||||
if (uv_ares_data_ptr->activesockets == 0) {
|
||||
uv_timer_init(&uv_ares_data_ptr->pollingtimer);
|
||||
uv_timer_start(&uv_ares_data_ptr->pollingtimer, uv_ares_poll, 1000L, 1000L);
|
||||
}
|
||||
uv_ares_data_ptr->activesockets++;
|
||||
|
||||
/* specify thread pool function to call when event is signaled */
|
||||
if (RegisterWaitForSingleObject(&uv_handle_ares->h_wait,
|
||||
uv_handle_ares->h_event,
|
||||
uv_ares_socksignal_tp,
|
||||
(void*)uv_handle_ares,
|
||||
INFINITE,
|
||||
WT_EXECUTEINWAITTHREAD) == 0) {
|
||||
uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
|
||||
}
|
||||
} else {
|
||||
/* found existing handle. */
|
||||
assert(uv_handle_ares->type == UV_ARES_TASK);
|
||||
assert(uv_handle_ares->data != NULL);
|
||||
assert(uv_handle_ares->h_event != WSA_INVALID_EVENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* called via uv_poll when ares completion port signaled */
|
||||
void uv_process_ares_event_req(uv_ares_action_t* handle, uv_req_t* req) {
|
||||
uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)handle->data;
|
||||
|
||||
ares_process_fd(uv_ares_data_ptr->channel,
|
||||
handle->read ? handle->sock : INVALID_SOCKET,
|
||||
handle->write ? handle->sock : INVALID_SOCKET);
|
||||
|
||||
/* release handle for select here */
|
||||
free(handle);
|
||||
}
|
||||
|
||||
|
||||
/* called via uv_poll when ares is finished with socket */
|
||||
void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req) {
|
||||
/* check for event complete without waiting */
|
||||
unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0);
|
||||
|
||||
if (signaled != WAIT_TIMEOUT) {
|
||||
uv_ares_channel_t* uv_ares_data_ptr = (uv_ares_channel_t*)handle->data;
|
||||
|
||||
uv_unref();
|
||||
|
||||
/* close event handle and free uv handle memory */
|
||||
CloseHandle(handle->h_close_event);
|
||||
free(handle);
|
||||
|
||||
/* decrement active count. if it becomes 0 stop polling */
|
||||
if (uv_ares_data_ptr->activesockets > 0) {
|
||||
uv_ares_data_ptr->activesockets--;
|
||||
if (uv_ares_data_ptr->activesockets == 0) {
|
||||
uv_close((uv_handle_t*)&uv_ares_data_ptr->pollingtimer, NULL);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* stil busy - repost and try again */
|
||||
if (!PostQueuedCompletionStatus(LOOP->iocp,
|
||||
0,
|
||||
0,
|
||||
&req->overlapped)) {
|
||||
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* set ares SOCK_STATE callback to our handler */
|
||||
int uv_ares_init_options(ares_channel *channelptr,
|
||||
struct ares_options *options,
|
||||
int optmask) {
|
||||
int rc;
|
||||
|
||||
/* only allow single init at a time */
|
||||
if (uv_ares_data.channel != NULL) {
|
||||
return UV_EALREADY;
|
||||
}
|
||||
|
||||
/* set our callback as an option */
|
||||
options->sock_state_cb = uv_ares_sockstate_cb;
|
||||
options->sock_state_cb_data = &uv_ares_data;
|
||||
optmask |= ARES_OPT_SOCK_STATE_CB;
|
||||
|
||||
/* We do the call to ares_init_option for caller. */
|
||||
rc = ares_init_options(channelptr, options, optmask);
|
||||
|
||||
/* if success, save channel */
|
||||
if (rc == ARES_SUCCESS) {
|
||||
uv_ares_data.channel = *channelptr;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* release memory */
|
||||
void uv_ares_destroy(ares_channel channel) {
|
||||
/* only allow destroy if did init */
|
||||
if (uv_ares_data.channel != NULL) {
|
||||
ares_destroy(channel);
|
||||
uv_ares_data.channel = NULL;
|
||||
}
|
||||
}
|
154
deps/uv/src/win/core.c
vendored
Normal file
154
deps/uv/src/win/core.c
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
/* 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 <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "../uv-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
/* The only event loop we support right now */
|
||||
uv_loop_t uv_main_loop_;
|
||||
|
||||
|
||||
static void uv_loop_init() {
|
||||
/* Create an I/O completion port */
|
||||
LOOP->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
|
||||
if (LOOP->iocp == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
|
||||
}
|
||||
|
||||
LOOP->refs = 0;
|
||||
|
||||
uv_update_time();
|
||||
|
||||
LOOP->pending_reqs_tail = NULL;
|
||||
|
||||
LOOP->endgame_handles = NULL;
|
||||
|
||||
RB_INIT(&LOOP->timers);
|
||||
|
||||
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;
|
||||
|
||||
LOOP->last_error = uv_ok_;
|
||||
|
||||
LOOP->err_str = NULL;
|
||||
}
|
||||
|
||||
|
||||
void uv_init() {
|
||||
/* Initialize winsock */
|
||||
uv_winsock_startup();
|
||||
|
||||
/* Initialize timers */
|
||||
uv_timer_startup();
|
||||
|
||||
/* Intialize event loop */
|
||||
uv_loop_init();
|
||||
}
|
||||
|
||||
|
||||
void uv_ref() {
|
||||
LOOP->refs++;
|
||||
}
|
||||
|
||||
|
||||
void uv_unref() {
|
||||
LOOP->refs--;
|
||||
}
|
||||
|
||||
|
||||
static void uv_poll() {
|
||||
BOOL success;
|
||||
DWORD bytes;
|
||||
ULONG_PTR key;
|
||||
OVERLAPPED* overlapped;
|
||||
uv_req_t* req;
|
||||
|
||||
success = GetQueuedCompletionStatus(LOOP->iocp,
|
||||
&bytes,
|
||||
&key,
|
||||
&overlapped,
|
||||
uv_get_poll_timeout());
|
||||
|
||||
uv_update_time();
|
||||
|
||||
if (overlapped) {
|
||||
/* Package was dequeued */
|
||||
req = uv_overlapped_to_req(overlapped);
|
||||
|
||||
if (!success) {
|
||||
req->error = uv_new_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
uv_insert_pending_req(req);
|
||||
|
||||
} else if (GetLastError() != WAIT_TIMEOUT) {
|
||||
/* Serious error */
|
||||
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_run() {
|
||||
while (1) {
|
||||
uv_update_time();
|
||||
uv_process_timers();
|
||||
|
||||
/* Terrible: please fix me! */
|
||||
while (LOOP->refs > 0 &&
|
||||
(LOOP->idle_handles || LOOP->pending_reqs_tail || LOOP->endgame_handles)) {
|
||||
/* Terrible: please fix me! */
|
||||
while (LOOP->pending_reqs_tail || LOOP->endgame_handles) {
|
||||
uv_process_endgames();
|
||||
uv_process_reqs();
|
||||
}
|
||||
|
||||
/* Call idle callbacks */
|
||||
uv_idle_invoke();
|
||||
}
|
||||
|
||||
if (LOOP->refs <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
uv_prepare_invoke();
|
||||
|
||||
uv_poll();
|
||||
|
||||
uv_check_invoke();
|
||||
}
|
||||
|
||||
assert(LOOP->refs == 0);
|
||||
return 0;
|
||||
}
|
133
deps/uv/src/win/error.c
vendored
Normal file
133
deps/uv/src/win/error.c
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
/* 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 <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "../uv-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
const uv_err_t uv_ok_ = { UV_OK, ERROR_SUCCESS };
|
||||
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
*((char*)NULL) = 0xff; /* Force debug break */
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
uv_err_t uv_last_error() {
|
||||
return LOOP->last_error;
|
||||
}
|
||||
|
||||
|
||||
char* uv_strerror(uv_err_t err) {
|
||||
if (LOOP->err_str != NULL) {
|
||||
LocalFree(LOOP->err_str);
|
||||
}
|
||||
|
||||
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err.sys_errno_,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&LOOP->err_str, 0, NULL);
|
||||
|
||||
if (LOOP->err_str) {
|
||||
return LOOP->err_str;
|
||||
} else {
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uv_err_code uv_translate_sys_error(int sys_errno) {
|
||||
switch (sys_errno) {
|
||||
case ERROR_SUCCESS: return UV_OK;
|
||||
case ERROR_NOACCESS: return UV_EACCESS;
|
||||
case WSAEACCES: return UV_EACCESS;
|
||||
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
|
||||
case WSAEADDRINUSE: return UV_EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
|
||||
case WSAEWOULDBLOCK: return UV_EAGAIN;
|
||||
case WSAEALREADY: return UV_EALREADY;
|
||||
case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
|
||||
case WSAECONNREFUSED: return UV_ECONNREFUSED;
|
||||
case WSAEFAULT: return UV_EFAULT;
|
||||
case ERROR_INVALID_DATA: return UV_EINVAL;
|
||||
case WSAEINVAL: return UV_EINVAL;
|
||||
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
|
||||
case WSAEMFILE: return UV_EMFILE;
|
||||
case ERROR_OUTOFMEMORY: return UV_ENOMEM;
|
||||
case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
|
||||
case ERROR_INVALID_FLAGS: return UV_EBADF;
|
||||
case ERROR_INVALID_PARAMETER: return UV_EINVAL;
|
||||
case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
|
||||
case ERROR_BROKEN_PIPE: return UV_EOF;
|
||||
case ERROR_PIPE_BUSY: return UV_EBUSY;
|
||||
case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
|
||||
default: return UV_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uv_err_t uv_new_sys_error(int sys_errno) {
|
||||
uv_err_t e;
|
||||
e.code = uv_translate_sys_error(sys_errno);
|
||||
e.sys_errno_ = sys_errno;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void uv_set_sys_error(int sys_errno) {
|
||||
LOOP->last_error.code = uv_translate_sys_error(sys_errno);
|
||||
LOOP->last_error.sys_errno_ = sys_errno;
|
||||
}
|
341
deps/uv/src/win/getaddrinfo.c
vendored
Normal file
341
deps/uv/src/win/getaddrinfo.c
vendored
Normal file
@ -0,0 +1,341 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* MinGW is missing this
|
||||
*/
|
||||
#ifndef _MSC_VER
|
||||
typedef struct addrinfoW {
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
size_t ai_addrlen;
|
||||
wchar_t* ai_canonname;
|
||||
struct sockaddr* ai_addr;
|
||||
struct addrinfoW* ai_next;
|
||||
} ADDRINFOW, *PADDRINFOW;
|
||||
|
||||
DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const wchar_t* node,
|
||||
const wchar_t* 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)
|
||||
|
||||
|
||||
/*
|
||||
* getaddrinfo error code mapping
|
||||
* Falls back to uv_translate_sys_error if no match
|
||||
*/
|
||||
static uv_err_code uv_translate_eai_error(int eai_errno) {
|
||||
switch (eai_errno) {
|
||||
case ERROR_SUCCESS: return UV_OK;
|
||||
case EAI_BADFLAGS: return UV_EBADF;
|
||||
case EAI_FAIL: return UV_EFAULT;
|
||||
case EAI_FAMILY: return UV_EAIFAMNOSUPPORT;
|
||||
case EAI_MEMORY: return UV_ENOMEM;
|
||||
case EAI_NONAME: return UV_EAINONAME;
|
||||
case EAI_AGAIN: return UV_EAGAIN;
|
||||
case EAI_SERVICE: return UV_EAISERVICE;
|
||||
case EAI_SOCKTYPE: return UV_EAISOCKTYPE;
|
||||
default: return uv_translate_sys_error(eai_errno);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* getaddrinfo worker thread implementation */
|
||||
static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
|
||||
uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*)parameter;
|
||||
int ret;
|
||||
|
||||
assert(handle != NULL);
|
||||
|
||||
if (handle != NULL) {
|
||||
/* call OS function on this thread */
|
||||
ret = GetAddrInfoW(handle->node, handle->service, handle->hints, &handle->res);
|
||||
handle->retcode = ret;
|
||||
|
||||
/* post getaddrinfo completed */
|
||||
if (!PostQueuedCompletionStatus(LOOP->iocp,
|
||||
0,
|
||||
0,
|
||||
&handle->getadddrinfo_req.overlapped)) {
|
||||
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void uv_process_getaddrinfo_req(uv_getaddrinfo_t* handle, uv_req_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;
|
||||
uv_err_code uv_ret;
|
||||
|
||||
/* release input parameter memory */
|
||||
if (handle->alloc != NULL) {
|
||||
free(handle->alloc);
|
||||
handle->alloc = NULL;
|
||||
}
|
||||
|
||||
uv_ret = uv_translate_eai_error(handle->retcode);
|
||||
if (handle->retcode == 0) {
|
||||
/* convert addrinfoW to addrinfo */
|
||||
/* first calculate required length */
|
||||
addrinfow_ptr = handle->res;
|
||||
while (addrinfow_ptr != NULL) {
|
||||
addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
|
||||
if (addrinfow_ptr->ai_canonname != NULL) {
|
||||
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
|
||||
if (name_len == 0) {
|
||||
uv_ret = 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*)malloc(addrinfo_len);
|
||||
|
||||
/* do conversions */
|
||||
if (alloc_ptr != NULL) {
|
||||
cur_ptr = alloc_ptr;
|
||||
addrinfow_ptr = handle->res;
|
||||
|
||||
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 = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
|
||||
assert(name_len > 0);
|
||||
assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
|
||||
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, cur_ptr, name_len);
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uv_ret = UV_ENOMEM;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* return memory to system */
|
||||
if (handle->res != NULL) {
|
||||
FreeAddrInfoW(handle->res);
|
||||
handle->res = NULL;
|
||||
}
|
||||
|
||||
complete:
|
||||
/* finally do callback with converted result */
|
||||
handle->getaddrinfo_cb(handle, uv_ret, (struct addrinfo*)alloc_ptr);
|
||||
|
||||
/* release copied result memory */
|
||||
if (alloc_ptr != NULL) {
|
||||
free(alloc_ptr);
|
||||
}
|
||||
|
||||
uv_unref();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Entry point for getaddrinfo
|
||||
* we convert the UTF-8 strings to UNICODE
|
||||
* and save the UNICODE string pointers in the handle
|
||||
* We also copy hints so that caller does not need to keep memory until the callback.
|
||||
* return UV_OK 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_getaddrinfo_t* handle,
|
||||
uv_getaddrinfo_cb getaddrinfo_cb,
|
||||
const char* node,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
int nodesize = 0;
|
||||
int servicesize = 0;
|
||||
int hintssize = 0;
|
||||
char* alloc_ptr = NULL;
|
||||
|
||||
if (handle == NULL || getaddrinfo_cb == NULL ||
|
||||
(node == NULL && service == NULL)) {
|
||||
uv_set_sys_error(WSAEINVAL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
handle->getaddrinfo_cb = getaddrinfo_cb;
|
||||
handle->res = NULL;
|
||||
handle->type = UV_GETADDRINFO;
|
||||
|
||||
/* calculate required memory size for all input values */
|
||||
if (node != NULL) {
|
||||
nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(wchar_t));
|
||||
if (nodesize == 0) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (service != NULL) {
|
||||
servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * sizeof(wchar_t));
|
||||
if (servicesize == 0) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (hints != NULL) {
|
||||
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
|
||||
}
|
||||
|
||||
/* allocate memory for inputs, and partition it as needed */
|
||||
alloc_ptr = (char*)malloc(nodesize + servicesize + hintssize);
|
||||
if (!alloc_ptr) {
|
||||
uv_set_sys_error(WSAENOBUFS);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* save alloc_ptr now so we can free if error */
|
||||
handle->alloc = (void*)alloc_ptr;
|
||||
|
||||
/* convert node string to UTF16 into allocated memory and save pointer in handle */
|
||||
if (node != NULL) {
|
||||
handle->node = (wchar_t*)alloc_ptr;
|
||||
if (uv_utf8_to_utf16(node, (wchar_t*)alloc_ptr, nodesize / sizeof(wchar_t)) == 0) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
alloc_ptr += nodesize;
|
||||
} else {
|
||||
handle->node = NULL;
|
||||
}
|
||||
|
||||
/* convert service string to UTF16 into allocated memory and save pointer in handle */
|
||||
if (service != NULL) {
|
||||
handle->service = (wchar_t*)alloc_ptr;
|
||||
if (uv_utf8_to_utf16(service, (wchar_t*)alloc_ptr, servicesize / sizeof(wchar_t)) == 0) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
alloc_ptr += servicesize;
|
||||
} else {
|
||||
handle->service = NULL;
|
||||
}
|
||||
|
||||
/* copy hints to allocated memory and save pointer in handle */
|
||||
if (hints != NULL) {
|
||||
handle->hints = (struct addrinfoW*)alloc_ptr;
|
||||
handle->hints->ai_family = hints->ai_family;
|
||||
handle->hints->ai_socktype = hints->ai_socktype;
|
||||
handle->hints->ai_protocol = hints->ai_protocol;
|
||||
handle->hints->ai_flags = hints->ai_flags;
|
||||
handle->hints->ai_addrlen = 0;
|
||||
handle->hints->ai_canonname = NULL;
|
||||
handle->hints->ai_addr = NULL;
|
||||
handle->hints->ai_next = NULL;
|
||||
} else {
|
||||
handle->hints = NULL;
|
||||
}
|
||||
|
||||
/* init request for Post handling */
|
||||
uv_req_init(&handle->getadddrinfo_req);
|
||||
handle->getadddrinfo_req.data = handle;
|
||||
handle->getadddrinfo_req.type = UV_GETADDRINFO_REQ;
|
||||
|
||||
/* Ask thread to run. Treat this as a long operation */
|
||||
if (QueueUserWorkItem(&getaddrinfo_thread_proc, handle, WT_EXECUTELONGFUNCTION) == 0) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
|
||||
uv_ref();
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (handle != NULL && handle->alloc != NULL) {
|
||||
free(handle->alloc);
|
||||
}
|
||||
return -1;
|
||||
}
|
167
deps/uv/src/win/handle.c
vendored
Normal file
167
deps/uv/src/win/handle.c
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
/* 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"
|
||||
|
||||
|
||||
int uv_is_active(uv_handle_t* handle) {
|
||||
switch (handle->type) {
|
||||
case UV_TIMER:
|
||||
case UV_IDLE:
|
||||
case UV_PREPARE:
|
||||
case UV_CHECK:
|
||||
return (handle->flags & UV_HANDLE_ACTIVE) ? 1 : 0;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TODO: integrate this with uv_close. */
|
||||
static int uv_close_error(uv_handle_t* handle, uv_err_t e) {
|
||||
uv_tcp_t* tcp;
|
||||
uv_pipe_t* pipe;
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle->error = e;
|
||||
handle->flags |= UV_HANDLE_CLOSING;
|
||||
|
||||
/* Handle-specific close actions */
|
||||
switch (handle->type) {
|
||||
case UV_TCP:
|
||||
tcp = (uv_tcp_t*)handle;
|
||||
/* If we don't shutdown before calling closesocket, windows will */
|
||||
/* silently discard the kernel send buffer and reset the connection. */
|
||||
if (!(tcp->flags & UV_HANDLE_SHUT)) {
|
||||
shutdown(tcp->socket, SD_SEND);
|
||||
tcp->flags |= UV_HANDLE_SHUT;
|
||||
}
|
||||
tcp->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING);
|
||||
closesocket(tcp->socket);
|
||||
if (tcp->reqs_pending == 0) {
|
||||
uv_want_endgame(handle);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
pipe = (uv_pipe_t*)handle;
|
||||
pipe->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING);
|
||||
close_pipe(pipe, NULL, NULL);
|
||||
if (pipe->reqs_pending == 0) {
|
||||
uv_want_endgame(handle);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case UV_TIMER:
|
||||
uv_timer_stop((uv_timer_t*)handle);
|
||||
uv_want_endgame(handle);
|
||||
return 0;
|
||||
|
||||
case UV_PREPARE:
|
||||
uv_prepare_stop((uv_prepare_t*)handle);
|
||||
uv_want_endgame(handle);
|
||||
return 0;
|
||||
|
||||
case UV_CHECK:
|
||||
uv_check_stop((uv_check_t*)handle);
|
||||
uv_want_endgame(handle);
|
||||
return 0;
|
||||
|
||||
case UV_IDLE:
|
||||
uv_idle_stop((uv_idle_t*)handle);
|
||||
uv_want_endgame(handle);
|
||||
return 0;
|
||||
|
||||
case UV_ASYNC:
|
||||
if (!((uv_async_t*)handle)->async_sent) {
|
||||
uv_want_endgame(handle);
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
/* Not supported */
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
handle->close_cb = close_cb;
|
||||
return uv_close_error(handle, uv_ok_);
|
||||
}
|
||||
|
||||
|
||||
void uv_want_endgame(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_process_endgames() {
|
||||
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((uv_tcp_t*)handle);
|
||||
break;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
uv_pipe_endgame((uv_pipe_t*)handle);
|
||||
break;
|
||||
|
||||
case UV_TIMER:
|
||||
uv_timer_endgame((uv_timer_t*)handle);
|
||||
break;
|
||||
|
||||
case UV_PREPARE:
|
||||
case UV_CHECK:
|
||||
case UV_IDLE:
|
||||
uv_loop_watcher_endgame(handle);
|
||||
break;
|
||||
|
||||
case UV_ASYNC:
|
||||
uv_async_endgame((uv_async_t*)handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
223
deps/uv/src/win/internal.h
vendored
Normal file
223
deps/uv/src/win/internal.h
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
/* 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 "tree.h"
|
||||
|
||||
|
||||
/*
|
||||
* Timers
|
||||
*/
|
||||
|
||||
RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
|
||||
void uv_timer_startup();
|
||||
|
||||
void uv_timer_endgame(uv_timer_t* handle);
|
||||
|
||||
DWORD uv_get_poll_timeout();
|
||||
void uv_process_timers();
|
||||
|
||||
|
||||
/*
|
||||
* Core
|
||||
*/
|
||||
|
||||
/* Loop state struct. We don't support multiplicity right now, but this */
|
||||
/* should help when we get to that. */
|
||||
typedef struct uv_loop_s {
|
||||
/* The loop's I/O completion port */
|
||||
HANDLE iocp;
|
||||
/* Reference count that keeps the event loop alive */
|
||||
int refs;
|
||||
/* The current time according to the event loop. in msecs. */
|
||||
int64_t time;
|
||||
/* Tail of a single-linked circular queue of pending reqs. If the queue */
|
||||
/* is empty, tail_ is NULL. If there is only one item, */
|
||||
/* tail_->next_req == tail_ */
|
||||
uv_req_t* pending_reqs_tail;
|
||||
/* Head of a single-linked list of closed handles */
|
||||
uv_handle_t* endgame_handles;
|
||||
/* The head of the timers tree */
|
||||
struct uv_timer_tree_s timers;
|
||||
/* Lists of active loop (prepare / check / idle) watchers */
|
||||
uv_prepare_t* prepare_handles;
|
||||
uv_check_t* check_handles;
|
||||
uv_idle_t* idle_handles;
|
||||
/* This pointer will refer to the prepare/check/idle handle whose */
|
||||
/* callback is scheduled to be called next. This is needed to allow */
|
||||
/* safe removal from one of the lists above while that list being */
|
||||
/* iterated over. */
|
||||
uv_prepare_t* next_prepare_handle;
|
||||
uv_check_t* next_check_handle;
|
||||
uv_idle_t* next_idle_handle;
|
||||
/* Last error code */
|
||||
uv_err_t last_error;
|
||||
/* Error string most recently returned by uv_strerror() */
|
||||
char* err_str;
|
||||
} uv_loop_t;
|
||||
|
||||
extern uv_loop_t uv_main_loop_;
|
||||
|
||||
#define LOOP (&uv_main_loop_)
|
||||
|
||||
|
||||
/*
|
||||
* Handles
|
||||
*/
|
||||
|
||||
/* Private uv_handle flags */
|
||||
#define UV_HANDLE_CLOSING 0x0001
|
||||
#define UV_HANDLE_CLOSED 0x0002
|
||||
#define UV_HANDLE_BOUND 0x0004
|
||||
#define UV_HANDLE_LISTENING 0x0008
|
||||
#define UV_HANDLE_CONNECTION 0x0010
|
||||
#define UV_HANDLE_CONNECTED 0x0020
|
||||
#define UV_HANDLE_READING 0x0040
|
||||
#define UV_HANDLE_ACTIVE 0x0040
|
||||
#define UV_HANDLE_EOF 0x0080
|
||||
#define UV_HANDLE_SHUTTING 0x0100
|
||||
#define UV_HANDLE_SHUT 0x0200
|
||||
#define UV_HANDLE_ENDGAME_QUEUED 0x0400
|
||||
#define UV_HANDLE_BIND_ERROR 0x1000
|
||||
#define UV_HANDLE_IPV6 0x2000
|
||||
#define UV_HANDLE_PIPESERVER 0x4000
|
||||
#define UV_HANDLE_READ_PENDING 0x8000
|
||||
|
||||
void uv_want_endgame(uv_handle_t* handle);
|
||||
void uv_process_endgames();
|
||||
|
||||
#define DECREASE_PENDING_REQ_COUNT(handle) \
|
||||
do { \
|
||||
handle->reqs_pending--; \
|
||||
\
|
||||
if (handle->flags & UV_HANDLE_CLOSING && \
|
||||
handle->reqs_pending == 0) { \
|
||||
uv_want_endgame((uv_handle_t*)handle); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* Requests
|
||||
*/
|
||||
void uv_req_init(uv_req_t* req);
|
||||
|
||||
uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped);
|
||||
|
||||
void uv_insert_pending_req(uv_req_t* req);
|
||||
void uv_process_reqs();
|
||||
|
||||
|
||||
/*
|
||||
* Streams
|
||||
*/
|
||||
void uv_stream_init(uv_stream_t* handle);
|
||||
void uv_connection_init(uv_stream_t* handle);
|
||||
|
||||
size_t uv_count_bufs(uv_buf_t bufs[], int count);
|
||||
|
||||
|
||||
/*
|
||||
* TCP
|
||||
*/
|
||||
void uv_winsock_startup();
|
||||
|
||||
void uv_tcp_endgame(uv_tcp_t* handle);
|
||||
|
||||
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_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[],
|
||||
int bufcnt, uv_write_cb cb);
|
||||
|
||||
void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req);
|
||||
void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req);
|
||||
void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req);
|
||||
void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req);
|
||||
|
||||
|
||||
/*
|
||||
* Pipes
|
||||
*/
|
||||
void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err);
|
||||
void uv_pipe_endgame(uv_pipe_t* handle);
|
||||
|
||||
int uv_pipe_accept(uv_pipe_t* server, uv_pipe_t* client);
|
||||
int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb);
|
||||
int uv_pipe_write(uv_write_t* req, uv_pipe_t* handle, uv_buf_t bufs[],
|
||||
int bufcnt, uv_write_cb cb);
|
||||
|
||||
void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req);
|
||||
void uv_process_pipe_write_req(uv_pipe_t* handle, uv_write_t* req);
|
||||
void uv_process_pipe_accept_req(uv_pipe_t* handle, uv_req_t* raw_req);
|
||||
void uv_process_pipe_connect_req(uv_pipe_t* handle, uv_connect_t* req);
|
||||
|
||||
/*
|
||||
* Loop watchers
|
||||
*/
|
||||
void uv_loop_watcher_endgame(uv_handle_t* handle);
|
||||
|
||||
void uv_prepare_invoke();
|
||||
void uv_check_invoke();
|
||||
void uv_idle_invoke();
|
||||
|
||||
|
||||
/*
|
||||
* Async watcher
|
||||
*/
|
||||
void uv_async_endgame(uv_async_t* handle);
|
||||
|
||||
void uv_process_async_wakeup_req(uv_async_t* handle, uv_req_t* req);
|
||||
|
||||
|
||||
/*
|
||||
* C-ares integration
|
||||
*/
|
||||
typedef struct uv_ares_action_s uv_ares_action_t;
|
||||
|
||||
void uv_process_ares_event_req(uv_ares_action_t* handle, uv_req_t* req);
|
||||
void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req);
|
||||
|
||||
/*
|
||||
* Getaddrinfo
|
||||
*/
|
||||
void uv_process_getaddrinfo_req(uv_getaddrinfo_t* handle, uv_req_t* req);
|
||||
|
||||
|
||||
/*
|
||||
* Error handling
|
||||
*/
|
||||
extern const uv_err_t uv_ok_;
|
||||
|
||||
void uv_fatal_error(const int errorno, const char* syscall);
|
||||
|
||||
uv_err_code uv_translate_sys_error(int sys_errno);
|
||||
uv_err_t uv_new_sys_error(int sys_errno);
|
||||
void uv_set_sys_error(int sys_errno);
|
||||
|
||||
|
||||
#endif /* UV_WIN_INTERNAL_H_ */
|
128
deps/uv/src/win/loop-watcher.c
vendored
Normal file
128
deps/uv/src/win/loop-watcher.c
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
/* 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 "../uv-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
void uv_loop_watcher_endgame(uv_handle_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb(handle);
|
||||
}
|
||||
|
||||
uv_unref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
|
||||
int uv_##name##_init(uv_##name##_t* handle) { \
|
||||
handle->type = UV_##NAME; \
|
||||
handle->flags = 0; \
|
||||
handle->error = uv_ok_; \
|
||||
\
|
||||
uv_ref(); \
|
||||
\
|
||||
uv_counters()->handle_init++; \
|
||||
uv_counters()->prepare_init++; \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
|
||||
uv_##name##_t* old_head; \
|
||||
\
|
||||
assert(handle->type == UV_##NAME); \
|
||||
\
|
||||
if (handle->flags & UV_HANDLE_ACTIVE) \
|
||||
return 0; \
|
||||
\
|
||||
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; \
|
||||
handle->flags |= UV_HANDLE_ACTIVE; \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
int uv_##name##_stop(uv_##name##_t* handle) { \
|
||||
assert(handle->type == UV_##NAME); \
|
||||
\
|
||||
if (!(handle->flags & UV_HANDLE_ACTIVE)) \
|
||||
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; \
|
||||
} \
|
||||
\
|
||||
handle->flags &= ~UV_HANDLE_ACTIVE; \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
void uv_##name##_invoke() { \
|
||||
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, 0); \
|
||||
} \
|
||||
}
|
||||
|
||||
UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
|
||||
UV_LOOP_WATCHER_DEFINE(check, CHECK)
|
||||
UV_LOOP_WATCHER_DEFINE(idle, IDLE)
|
648
deps/uv/src/win/pipe.c
vendored
Normal file
648
deps/uv/src/win/pipe.c
vendored
Normal file
@ -0,0 +1,648 @@
|
||||
/* 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 <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "../uv-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
/* A zero-size buffer for use by uv_pipe_read */
|
||||
static char uv_zero_[] = "";
|
||||
|
||||
|
||||
int uv_pipe_init(uv_pipe_t* handle) {
|
||||
uv_stream_init((uv_stream_t*)handle);
|
||||
|
||||
handle->type = UV_NAMED_PIPE;
|
||||
handle->reqs_pending = 0;
|
||||
handle->pending_accepts = NULL;
|
||||
handle->name = NULL;
|
||||
|
||||
uv_counters()->pipe_init++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv_set_pipe_handle(uv_pipe_t* handle, HANDLE pipeHandle) {
|
||||
DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
|
||||
|
||||
if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (CreateIoCompletionPort(pipeHandle,
|
||||
LOOP->iocp,
|
||||
(ULONG_PTR)handle,
|
||||
0) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_pipe_endgame(uv_pipe_t* handle) {
|
||||
uv_err_t err;
|
||||
int status;
|
||||
|
||||
if (handle->flags & UV_HANDLE_SHUTTING &&
|
||||
!(handle->flags & UV_HANDLE_SHUT) &&
|
||||
handle->write_reqs_pending == 0) {
|
||||
close_pipe(handle, &status, &err);
|
||||
|
||||
if (handle->shutdown_req->cb) {
|
||||
if (status == -1) {
|
||||
LOOP->last_error = err;
|
||||
}
|
||||
handle->shutdown_req->cb(handle->shutdown_req, status);
|
||||
}
|
||||
handle->reqs_pending--;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
uv_unref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Creates a pipe server. */
|
||||
/* TODO: make this work with UTF8 name */
|
||||
int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
int i;
|
||||
uv_pipe_accept_t* req;
|
||||
|
||||
if (!name) {
|
||||
uv_set_sys_error(WSAEINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make our own copy of the pipe name */
|
||||
handle->name = strdup(name);
|
||||
if (!handle->name) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
||||
}
|
||||
|
||||
for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
|
||||
req = &handle->accept_reqs[i];
|
||||
uv_req_init((uv_req_t*) req);
|
||||
req->type = UV_ACCEPT;
|
||||
req->data = handle;
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
req->next_pending = NULL;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_PIPESERVER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
|
||||
HANDLE pipeHandle = INVALID_HANDLE_VALUE;
|
||||
int errno;
|
||||
uv_pipe_t* handle;
|
||||
uv_connect_t* req;
|
||||
|
||||
req = (uv_connect_t*)parameter;
|
||||
assert(req);
|
||||
handle = (uv_pipe_t*)req->handle;
|
||||
assert(handle);
|
||||
|
||||
/* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait for the pipe to become available with WaitNamedPipe. */
|
||||
while (WaitNamedPipe(handle->name, 30000)) {
|
||||
/* The pipe is now available, try to connect. */
|
||||
pipeHandle = CreateFile(handle->name,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(handle, pipeHandle)) {
|
||||
handle->handle = pipeHandle;
|
||||
req->error = uv_ok_;
|
||||
} else {
|
||||
req->error = uv_new_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||
|
||||
/* Post completed */
|
||||
if (!PostQueuedCompletionStatus(LOOP->iocp,
|
||||
0,
|
||||
0,
|
||||
&req->overlapped)) {
|
||||
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: make this work with UTF8 name */
|
||||
int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
||||
const char* name, uv_connect_cb cb) {
|
||||
int errno;
|
||||
HANDLE pipeHandle;
|
||||
|
||||
handle->handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
uv_req_init((uv_req_t*) req);
|
||||
req->type = UV_CONNECT;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
|
||||
pipeHandle = CreateFile(name,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
|
||||
if (pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
if (GetLastError() == ERROR_PIPE_BUSY) {
|
||||
/* Wait for the server to make a pipe instance available. */
|
||||
handle->name = strdup(name);
|
||||
if (!handle->name) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
||||
}
|
||||
|
||||
if (!QueueUserWorkItem(&pipe_connect_thread_proc, req, WT_EXECUTELONGFUNCTION)) {
|
||||
errno = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (uv_set_pipe_handle((uv_pipe_t*)req->handle, pipeHandle)) {
|
||||
errno = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
handle->handle = pipeHandle;
|
||||
|
||||
req->error = uv_ok_;
|
||||
uv_insert_pending_req((uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(pipeHandle);
|
||||
}
|
||||
uv_set_sys_error(errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Cleans up uv_pipe_t (server or connection) and all resources associated with it */
|
||||
void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) {
|
||||
int i;
|
||||
HANDLE pipeHandle;
|
||||
|
||||
if (handle->name) {
|
||||
free(handle->name);
|
||||
handle->name;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER) {
|
||||
for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
|
||||
pipeHandle = handle->accept_reqs[i].pipeHandle;
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(pipeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (handle->handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle->handle);
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_SHUT;
|
||||
}
|
||||
|
||||
|
||||
static void uv_pipe_queue_accept(uv_pipe_t* handle, uv_pipe_accept_t* req) {
|
||||
HANDLE pipeHandle;
|
||||
|
||||
assert(handle->flags & UV_HANDLE_LISTENING);
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
|
||||
pipeHandle = CreateNamedPipe(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
65536,
|
||||
65536,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
if (pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
req->error = uv_new_sys_error(GetLastError());
|
||||
uv_insert_pending_req((uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (CreateIoCompletionPort(pipeHandle,
|
||||
LOOP->iocp,
|
||||
(ULONG_PTR)handle,
|
||||
0) == NULL) {
|
||||
req->error = uv_new_sys_error(GetLastError());
|
||||
uv_insert_pending_req((uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->overlapped), 0, sizeof(req->overlapped));
|
||||
|
||||
if (!ConnectNamedPipe(pipeHandle, &req->overlapped) && GetLastError() != ERROR_IO_PENDING) {
|
||||
if (GetLastError() == ERROR_PIPE_CONNECTED) {
|
||||
req->pipeHandle = pipeHandle;
|
||||
req->error = uv_ok_;
|
||||
} else {
|
||||
/* Make this req pending reporting an error. */
|
||||
req->error = uv_new_sys_error(GetLastError());
|
||||
}
|
||||
uv_insert_pending_req((uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
req->pipeHandle = pipeHandle;
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_accept(uv_pipe_t* server, uv_pipe_t* client) {
|
||||
/* Find a connection instance that has been connected, but not yet accepted. */
|
||||
uv_pipe_accept_t* req = server->pending_accepts;
|
||||
|
||||
if (!req) {
|
||||
/* No valid connections found, so we error out. */
|
||||
uv_set_sys_error(WSAEWOULDBLOCK);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize the client handle and copy the pipeHandle to the client */
|
||||
uv_pipe_init(client);
|
||||
uv_connection_init((uv_stream_t*) client);
|
||||
client->handle = req->pipeHandle;
|
||||
|
||||
/* Prepare the req to pick up a new connection */
|
||||
server->pending_accepts = req->next_pending;
|
||||
req->next_pending = NULL;
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_pipe_queue_accept(server, req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Starts listening for connections for the given pipe. */
|
||||
int uv_pipe_listen(uv_pipe_t* handle, uv_connection_cb cb) {
|
||||
int i, errno;
|
||||
|
||||
if (handle->flags & UV_HANDLE_LISTENING ||
|
||||
handle->flags & UV_HANDLE_READING) {
|
||||
uv_set_sys_error(UV_EALREADY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
|
||||
uv_set_sys_error(UV_ENOTSUP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_LISTENING;
|
||||
handle->connection_cb = cb;
|
||||
|
||||
for (i = 0; i < COUNTOF(handle->accept_reqs); i++) {
|
||||
uv_pipe_queue_accept(handle, &handle->accept_reqs[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv_pipe_queue_read(uv_pipe_t* handle) {
|
||||
uv_req_t* req;
|
||||
int result;
|
||||
|
||||
assert(handle->flags & UV_HANDLE_READING);
|
||||
assert(!(handle->flags & UV_HANDLE_READ_PENDING));
|
||||
|
||||
assert(handle->handle != INVALID_HANDLE_VALUE);
|
||||
|
||||
req = &handle->read_req;
|
||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||
|
||||
/* Do 0-read */
|
||||
result = ReadFile(handle->handle,
|
||||
&uv_zero_,
|
||||
0,
|
||||
NULL,
|
||||
&req->overlapped);
|
||||
|
||||
if (!result && GetLastError() != ERROR_IO_PENDING) {
|
||||
/* Make this req pending reporting an error. */
|
||||
req->error = uv_new_sys_error(WSAGetLastError());
|
||||
uv_insert_pending_req(req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION)) {
|
||||
uv_set_sys_error(UV_EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
uv_set_sys_error(UV_EALREADY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EOF) {
|
||||
uv_set_sys_error(UV_EOF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_READING;
|
||||
handle->read_cb = read_cb;
|
||||
handle->alloc_cb = alloc_cb;
|
||||
|
||||
/* If reading was stopped and then started again, there could stell be a */
|
||||
/* read request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
||||
uv_pipe_queue_read(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_pipe_write(uv_write_t* req, uv_pipe_t* handle, uv_buf_t bufs[], int bufcnt,
|
||||
uv_write_cb cb) {
|
||||
int result;
|
||||
|
||||
if (bufcnt != 1) {
|
||||
uv_set_sys_error(UV_ENOTSUP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(handle->handle != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION)) {
|
||||
uv_set_sys_error(UV_EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_SHUTTING) {
|
||||
uv_set_sys_error(UV_EOF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uv_req_init((uv_req_t*) req);
|
||||
req->type = UV_WRITE;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||
|
||||
result = WriteFile(handle->handle,
|
||||
bufs[0].base,
|
||||
bufs[0].len,
|
||||
NULL,
|
||||
&req->overlapped);
|
||||
|
||||
if (!result && GetLastError() != WSA_IO_PENDING) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
/* Request completed immediately. */
|
||||
req->queued_bytes = 0;
|
||||
} else {
|
||||
/* Request queued by the kernel. */
|
||||
req->queued_bytes = uv_count_bufs(bufs, bufcnt);
|
||||
handle->write_queue_size += req->queued_bytes;
|
||||
}
|
||||
|
||||
handle->reqs_pending++;
|
||||
handle->write_reqs_pending++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req) {
|
||||
DWORD bytes, err, mode;
|
||||
uv_buf_t buf;
|
||||
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
handle->flags &= ~UV_HANDLE_READ_PENDING;
|
||||
|
||||
if (req->error.code != UV_OK) {
|
||||
/* An error occurred doing the 0-read. */
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
/* Stop reading and report error. */
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
LOOP->last_error = req->error;
|
||||
buf.base = 0;
|
||||
buf.len = 0;
|
||||
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Temporarily switch to non-blocking mode.
|
||||
* This is so that ReadFile doesn't block if the read buffer is empty.
|
||||
*/
|
||||
mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT;
|
||||
if (!SetNamedPipeHandleState(handle->handle, &mode, NULL, NULL)) {
|
||||
/* We can't continue processing this read. */
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
uv_set_sys_error(GetLastError());
|
||||
buf.base = 0;
|
||||
buf.len = 0;
|
||||
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
||||
}
|
||||
|
||||
/* Do non-blocking reads until the buffer is empty */
|
||||
while (handle->flags & UV_HANDLE_READING) {
|
||||
buf = handle->alloc_cb((uv_stream_t*)handle, 65536);
|
||||
assert(buf.len > 0);
|
||||
|
||||
if (ReadFile(handle->handle,
|
||||
buf.base,
|
||||
buf.len,
|
||||
&bytes,
|
||||
NULL)) {
|
||||
if (bytes > 0) {
|
||||
/* Successful read */
|
||||
handle->read_cb((uv_stream_t*)handle, bytes, buf);
|
||||
/* Read again only if bytes == buf.len */
|
||||
if (bytes < buf.len) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Connection closed */
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
handle->flags |= UV_HANDLE_EOF;
|
||||
LOOP->last_error.code = UV_EOF;
|
||||
LOOP->last_error.sys_errno_ = ERROR_SUCCESS;
|
||||
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
err = GetLastError();
|
||||
if (err == ERROR_NO_DATA) {
|
||||
/* Read buffer was completely empty, report a 0-byte read. */
|
||||
uv_set_sys_error(WSAEWOULDBLOCK);
|
||||
handle->read_cb((uv_stream_t*)handle, 0, buf);
|
||||
} else {
|
||||
/* Ouch! serious error. */
|
||||
uv_set_sys_error(err);
|
||||
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: if the read callback stops reading we can't start reading again
|
||||
because the pipe will still be in nowait mode. */
|
||||
if ((handle->flags & UV_HANDLE_READING) &&
|
||||
!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
/* Switch back to blocking mode so that we can use IOCP for 0-reads */
|
||||
mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
|
||||
if (SetNamedPipeHandleState(handle->handle, &mode, NULL, NULL)) {
|
||||
/* Post another 0-read */
|
||||
uv_pipe_queue_read(handle);
|
||||
} else {
|
||||
/* Report and continue. */
|
||||
/* We can't continue processing this read. */
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
uv_set_sys_error(GetLastError());
|
||||
buf.base = 0;
|
||||
buf.len = 0;
|
||||
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_write_req(uv_pipe_t* handle, uv_write_t* req) {
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
handle->write_queue_size -= req->queued_bytes;
|
||||
|
||||
if (req->cb) {
|
||||
LOOP->last_error = req->error;
|
||||
((uv_write_cb)req->cb)(req, LOOP->last_error.code == UV_OK ? 0 : -1);
|
||||
}
|
||||
|
||||
handle->write_reqs_pending--;
|
||||
if (handle->write_reqs_pending == 0 &&
|
||||
handle->flags & UV_HANDLE_SHUTTING) {
|
||||
uv_want_endgame((uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_accept_req(uv_pipe_t* handle, uv_req_t* raw_req) {
|
||||
uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
|
||||
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
if (req->error.code == UV_OK) {
|
||||
assert(req->pipeHandle != INVALID_HANDLE_VALUE);
|
||||
|
||||
req->next_pending = handle->pending_accepts;
|
||||
handle->pending_accepts = req;
|
||||
|
||||
if (handle->connection_cb) {
|
||||
handle->connection_cb((uv_handle_t*)handle, 0);
|
||||
}
|
||||
} else {
|
||||
if (req->pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(req->pipeHandle);
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (!(handle->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_pipe_queue_accept(handle, req);
|
||||
}
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_pipe_connect_req(uv_pipe_t* handle, uv_connect_t* req) {
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
if (req->cb) {
|
||||
if (req->error.code == UV_OK) {
|
||||
uv_connection_init((uv_stream_t*)handle);
|
||||
((uv_connect_cb)req->cb)(req, 0);
|
||||
} else {
|
||||
LOOP->last_error = req->error;
|
||||
((uv_connect_cb)req->cb)(req, -1);
|
||||
}
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
133
deps/uv/src/win/req.c
vendored
Normal file
133
deps/uv/src/win/req.c
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
/* 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 "../uv-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
void uv_req_init(uv_req_t* req) {
|
||||
uv_counters()->req_init++;
|
||||
req->type = UV_UNKNOWN_REQ;
|
||||
req->error = uv_ok_;
|
||||
}
|
||||
|
||||
|
||||
uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
|
||||
return CONTAINING_RECORD(overlapped, uv_req_t, overlapped);
|
||||
}
|
||||
|
||||
|
||||
void uv_insert_pending_req(uv_req_t* req) {
|
||||
req->next_req = NULL;
|
||||
if (LOOP->pending_reqs_tail) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uv_req_t* uv_remove_pending_req() {
|
||||
uv_req_t* req;
|
||||
|
||||
if (LOOP->pending_reqs_tail) {
|
||||
req = LOOP->pending_reqs_tail->next_req;
|
||||
|
||||
if (req == LOOP->pending_reqs_tail) {
|
||||
LOOP->pending_reqs_tail = NULL;
|
||||
} else {
|
||||
LOOP->pending_reqs_tail->next_req = req->next_req;
|
||||
}
|
||||
|
||||
return req;
|
||||
|
||||
} else {
|
||||
/* queue empty */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define DELEGATE_STREAM_REQ(req, method, handle_at) \
|
||||
do { \
|
||||
switch (((uv_handle_t*) (req)->handle_at)->type) { \
|
||||
case UV_TCP: \
|
||||
uv_process_tcp_##method##_req((uv_tcp_t*) ((req)->handle_at), req); \
|
||||
break; \
|
||||
\
|
||||
case UV_NAMED_PIPE: \
|
||||
uv_process_pipe_##method##_req((uv_pipe_t*) ((req)->handle_at), req); \
|
||||
break; \
|
||||
\
|
||||
default: \
|
||||
assert(0); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
void uv_process_reqs() {
|
||||
uv_req_t* req;
|
||||
|
||||
while (req = uv_remove_pending_req()) {
|
||||
switch (req->type) {
|
||||
case UV_READ:
|
||||
DELEGATE_STREAM_REQ(req, read, data);
|
||||
break;
|
||||
|
||||
case UV_WRITE:
|
||||
DELEGATE_STREAM_REQ((uv_write_t*) req, write, handle);
|
||||
break;
|
||||
|
||||
case UV_ACCEPT:
|
||||
DELEGATE_STREAM_REQ(req, accept, data);
|
||||
break;
|
||||
|
||||
case UV_CONNECT:
|
||||
DELEGATE_STREAM_REQ((uv_connect_t*) req, connect, handle);
|
||||
break;
|
||||
|
||||
case UV_WAKEUP:
|
||||
uv_process_async_wakeup_req((uv_async_t*) req->data, req);
|
||||
break;
|
||||
|
||||
case UV_ARES_EVENT_REQ:
|
||||
uv_process_ares_event_req((uv_ares_action_t*) req->data, req);
|
||||
break;
|
||||
|
||||
case UV_ARES_CLEANUP_REQ:
|
||||
uv_process_ares_cleanup_req((uv_ares_task_t*) req->data, req);
|
||||
break;
|
||||
|
||||
case UV_GETADDRINFO_REQ:
|
||||
uv_process_getaddrinfo_req((uv_getaddrinfo_t*) req->data, req);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
130
deps/uv/src/win/stream.c
vendored
Normal file
130
deps/uv/src/win/stream.c
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
/* 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 "../uv-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
void uv_stream_init(uv_stream_t* handle) {
|
||||
handle->write_queue_size = 0;
|
||||
handle->flags = 0;
|
||||
handle->error = uv_ok_;
|
||||
|
||||
uv_counters()->handle_init++;
|
||||
uv_counters()->stream_init++;
|
||||
|
||||
uv_ref();
|
||||
}
|
||||
|
||||
|
||||
void uv_connection_init(uv_stream_t* handle) {
|
||||
handle->flags |= UV_HANDLE_CONNECTION;
|
||||
handle->write_reqs_pending = 0;
|
||||
|
||||
uv_req_init((uv_req_t*) &(handle->read_req));
|
||||
handle->read_req.type = UV_READ;
|
||||
handle->read_req.data = handle;
|
||||
}
|
||||
|
||||
|
||||
int uv_accept(uv_handle_t* server, uv_stream_t* client) {
|
||||
assert(client->type == server->type);
|
||||
|
||||
if (server->type == UV_TCP) {
|
||||
return uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
|
||||
} else if (server->type == UV_NAMED_PIPE) {
|
||||
return uv_pipe_accept((uv_pipe_t*)server, (uv_pipe_t*)client);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
|
||||
if (handle->type == UV_TCP) {
|
||||
return uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
|
||||
} else if (handle->type == UV_NAMED_PIPE) {
|
||||
return uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int uv_read_stop(uv_stream_t* handle) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
|
||||
uv_write_cb cb) {
|
||||
if (handle->type == UV_TCP) {
|
||||
return uv_tcp_write(req, (uv_tcp_t*) handle, bufs, bufcnt, cb);
|
||||
} else if (handle->type == UV_NAMED_PIPE) {
|
||||
return uv_pipe_write(req, (uv_pipe_t*) handle, bufs, bufcnt, cb);
|
||||
}
|
||||
|
||||
uv_set_sys_error(WSAEINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION)) {
|
||||
uv_set_sys_error(WSAEINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_SHUTTING) {
|
||||
uv_set_sys_error(WSAESHUTDOWN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uv_req_init((uv_req_t*) req);
|
||||
req->type = UV_SHUTDOWN;
|
||||
req->handle = handle;
|
||||
req->cb = cb;
|
||||
|
||||
handle->flags |= UV_HANDLE_SHUTTING;
|
||||
handle->shutdown_req = req;
|
||||
handle->reqs_pending++;
|
||||
|
||||
uv_want_endgame((uv_handle_t*)handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t uv_count_bufs(uv_buf_t bufs[], int count) {
|
||||
size_t bytes = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
bytes += (size_t)bufs[i].len;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
895
deps/uv/src/win/tcp.c
vendored
Normal file
895
deps/uv/src/win/tcp.c
vendored
Normal file
@ -0,0 +1,895 @@
|
||||
/* 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 "../uv-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Guids and typedefs for winsock extension functions
|
||||
* Mingw32 doesn't have these :-(
|
||||
*/
|
||||
#ifndef WSAID_ACCEPTEX
|
||||
# define WSAID_ACCEPTEX \
|
||||
{0xb5367df1, 0xcbac, 0x11cf, \
|
||||
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
|
||||
|
||||
# define WSAID_CONNECTEX \
|
||||
{0x25a207b9, 0xddf3, 0x4660, \
|
||||
{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
|
||||
|
||||
# define WSAID_GETACCEPTEXSOCKADDRS \
|
||||
{0xb5367df2, 0xcbac, 0x11cf, \
|
||||
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
|
||||
|
||||
# define WSAID_DISCONNECTEX \
|
||||
{0x7fda2e11, 0x8630, 0x436f, \
|
||||
{0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
|
||||
|
||||
# define WSAID_TRANSMITFILE \
|
||||
{0xb5367df0, 0xcbac, 0x11cf, \
|
||||
{0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
|
||||
|
||||
typedef BOOL PASCAL (*LPFN_ACCEPTEX)
|
||||
(SOCKET sListenSocket,
|
||||
SOCKET sAcceptSocket,
|
||||
PVOID lpOutputBuffer,
|
||||
DWORD dwReceiveDataLength,
|
||||
DWORD dwLocalAddressLength,
|
||||
DWORD dwRemoteAddressLength,
|
||||
LPDWORD lpdwBytesReceived,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef BOOL PASCAL (*LPFN_CONNECTEX)
|
||||
(SOCKET s,
|
||||
const struct sockaddr* name,
|
||||
int namelen,
|
||||
PVOID lpSendBuffer,
|
||||
DWORD dwSendDataLength,
|
||||
LPDWORD lpdwBytesSent,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS)
|
||||
(PVOID lpOutputBuffer,
|
||||
DWORD dwReceiveDataLength,
|
||||
DWORD dwLocalAddressLength,
|
||||
DWORD dwRemoteAddressLength,
|
||||
LPSOCKADDR* LocalSockaddr,
|
||||
LPINT LocalSockaddrLength,
|
||||
LPSOCKADDR* RemoteSockaddr,
|
||||
LPINT RemoteSockaddrLength);
|
||||
|
||||
typedef BOOL PASCAL (*LPFN_DISCONNECTEX)
|
||||
(SOCKET hSocket,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
DWORD dwFlags,
|
||||
DWORD reserved);
|
||||
|
||||
typedef BOOL PASCAL (*LPFN_TRANSMITFILE)
|
||||
(SOCKET hSocket,
|
||||
HANDLE hFile,
|
||||
DWORD nNumberOfBytesToWrite,
|
||||
DWORD nNumberOfBytesPerSend,
|
||||
LPOVERLAPPED lpOverlapped,
|
||||
LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
|
||||
DWORD dwFlags);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* MinGW is missing this too
|
||||
*/
|
||||
#ifndef SO_UPDATE_CONNECT_CONTEXT
|
||||
# define SO_UPDATE_CONNECT_CONTEXT 0x7010
|
||||
#endif
|
||||
|
||||
|
||||
/* Pointers to winsock extension functions to be retrieved dynamically */
|
||||
static LPFN_CONNECTEX pConnectEx;
|
||||
static LPFN_ACCEPTEX pAcceptEx;
|
||||
static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs;
|
||||
static LPFN_DISCONNECTEX pDisconnectEx;
|
||||
static LPFN_TRANSMITFILE pTransmitFile;
|
||||
|
||||
/* IPv6 version of these extension functions */
|
||||
static LPFN_CONNECTEX pConnectEx6;
|
||||
static LPFN_ACCEPTEX pAcceptEx6;
|
||||
static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6;
|
||||
static LPFN_DISCONNECTEX pDisconnectEx6;
|
||||
static LPFN_TRANSMITFILE pTransmitFile6;
|
||||
|
||||
/* Ip address used to bind to any port at any interface */
|
||||
static struct sockaddr_in uv_addr_ip4_any_;
|
||||
static struct sockaddr_in6 uv_addr_ip6_any_;
|
||||
|
||||
/* A zero-size buffer for use by uv_tcp_read */
|
||||
static char uv_zero_[] = "";
|
||||
|
||||
/* mark if IPv6 sockets are supported */
|
||||
static BOOL uv_allow_ipv6 = FALSE;
|
||||
|
||||
|
||||
/*
|
||||
* Retrieves the pointer to a winsock extension function.
|
||||
*/
|
||||
static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
|
||||
void **target) {
|
||||
DWORD result, 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Setup tcp subsystem
|
||||
*/
|
||||
void uv_winsock_startup() {
|
||||
const GUID wsaid_connectex = WSAID_CONNECTEX;
|
||||
const GUID wsaid_acceptex = WSAID_ACCEPTEX;
|
||||
const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
|
||||
const GUID wsaid_disconnectex = WSAID_DISCONNECTEX;
|
||||
const GUID wsaid_transmitfile = WSAID_TRANSMITFILE;
|
||||
|
||||
WSADATA wsa_data;
|
||||
int errorno;
|
||||
SOCKET dummy;
|
||||
SOCKET dummy6;
|
||||
|
||||
/* Initialize winsock */
|
||||
errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
if (errorno != 0) {
|
||||
uv_fatal_error(errorno, "WSAStartup");
|
||||
}
|
||||
|
||||
/* Set implicit binding address used by connectEx */
|
||||
uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0);
|
||||
uv_addr_ip6_any_ = uv_ip6_addr("::1", 0);
|
||||
|
||||
/* Retrieve the needed winsock extension function pointers. */
|
||||
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (dummy == INVALID_SOCKET) {
|
||||
uv_fatal_error(WSAGetLastError(), "socket");
|
||||
}
|
||||
|
||||
if (!uv_get_extension_function(dummy,
|
||||
wsaid_connectex,
|
||||
(void**)&pConnectEx) ||
|
||||
!uv_get_extension_function(dummy,
|
||||
wsaid_acceptex,
|
||||
(void**)&pAcceptEx) ||
|
||||
!uv_get_extension_function(dummy,
|
||||
wsaid_getacceptexsockaddrs,
|
||||
(void**)&pGetAcceptExSockAddrs) ||
|
||||
!uv_get_extension_function(dummy,
|
||||
wsaid_disconnectex,
|
||||
(void**)&pDisconnectEx) ||
|
||||
!uv_get_extension_function(dummy,
|
||||
wsaid_transmitfile,
|
||||
(void**)&pTransmitFile)) {
|
||||
uv_fatal_error(WSAGetLastError(),
|
||||
"WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)");
|
||||
}
|
||||
|
||||
if (closesocket(dummy) == SOCKET_ERROR) {
|
||||
uv_fatal_error(WSAGetLastError(), "closesocket");
|
||||
}
|
||||
|
||||
/* optional IPv6 versions of winsock extension functions */
|
||||
dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
|
||||
if (dummy6 != INVALID_SOCKET) {
|
||||
uv_allow_ipv6 = TRUE;
|
||||
|
||||
if (!uv_get_extension_function(dummy6,
|
||||
wsaid_connectex,
|
||||
(void**)&pConnectEx6) ||
|
||||
!uv_get_extension_function(dummy6,
|
||||
wsaid_acceptex,
|
||||
(void**)&pAcceptEx6) ||
|
||||
!uv_get_extension_function(dummy6,
|
||||
wsaid_getacceptexsockaddrs,
|
||||
(void**)&pGetAcceptExSockAddrs6) ||
|
||||
!uv_get_extension_function(dummy6,
|
||||
wsaid_disconnectex,
|
||||
(void**)&pDisconnectEx6) ||
|
||||
!uv_get_extension_function(dummy6,
|
||||
wsaid_transmitfile,
|
||||
(void**)&pTransmitFile6)) {
|
||||
uv_allow_ipv6 = FALSE;
|
||||
}
|
||||
|
||||
if (closesocket(dummy6) == SOCKET_ERROR) {
|
||||
uv_fatal_error(WSAGetLastError(), "closesocket");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) {
|
||||
DWORD yes = 1;
|
||||
|
||||
assert(handle->socket == INVALID_SOCKET);
|
||||
|
||||
/* Set the socket to nonblocking mode */
|
||||
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
|
||||
uv_set_sys_error(WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make the socket non-inheritable */
|
||||
if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Associate it with the I/O completion port. */
|
||||
/* Use uv_handle_t pointer as completion key. */
|
||||
if (CreateIoCompletionPort((HANDLE)socket,
|
||||
LOOP->iocp,
|
||||
(ULONG_PTR)socket,
|
||||
0) == NULL) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->socket = socket;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_init(uv_tcp_t* handle) {
|
||||
uv_stream_init((uv_stream_t*)handle);
|
||||
|
||||
handle->socket = INVALID_SOCKET;
|
||||
handle->type = UV_TCP;
|
||||
handle->reqs_pending = 0;
|
||||
handle->accept_socket = INVALID_SOCKET;
|
||||
|
||||
uv_counters()->tcp_init++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_tcp_endgame(uv_tcp_t* handle) {
|
||||
uv_err_t err;
|
||||
int status;
|
||||
|
||||
if (handle->flags & UV_HANDLE_SHUTTING &&
|
||||
!(handle->flags & UV_HANDLE_SHUT) &&
|
||||
handle->write_reqs_pending == 0) {
|
||||
|
||||
if (shutdown(handle->socket, SD_SEND) != SOCKET_ERROR) {
|
||||
status = 0;
|
||||
handle->flags |= UV_HANDLE_SHUT;
|
||||
} else {
|
||||
status = -1;
|
||||
err = uv_new_sys_error(WSAGetLastError());
|
||||
}
|
||||
if (handle->shutdown_req->cb) {
|
||||
if (status == -1) {
|
||||
LOOP->last_error = err;
|
||||
}
|
||||
handle->shutdown_req->cb(handle->shutdown_req, status);
|
||||
}
|
||||
handle->reqs_pending--;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
uv_unref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int uv__bind(uv_tcp_t* handle, int domain, struct sockaddr* addr, int addrsize) {
|
||||
DWORD err;
|
||||
int r;
|
||||
SOCKET sock;
|
||||
|
||||
if (handle->socket == INVALID_SOCKET) {
|
||||
sock = socket(domain, SOCK_STREAM, 0);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
uv_set_sys_error(WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uv_tcp_set_socket(handle, sock) == -1) {
|
||||
closesocket(sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
r = bind(handle->socket, addr, addrsize);
|
||||
|
||||
if (r == SOCKET_ERROR) {
|
||||
err = WSAGetLastError();
|
||||
if (err == WSAEADDRINUSE) {
|
||||
/* Some errors are not to be reported until connect() or listen() */
|
||||
handle->error = uv_new_sys_error(err);
|
||||
handle->flags |= UV_HANDLE_BIND_ERROR;
|
||||
} else {
|
||||
uv_set_sys_error(err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in addr) {
|
||||
if (addr.sin_family != AF_INET) {
|
||||
uv_set_sys_error(WSAEFAULT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return uv__bind(handle, AF_INET, (struct sockaddr*)&addr, sizeof(struct sockaddr_in));
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) {
|
||||
if (addr.sin6_family != AF_INET6) {
|
||||
uv_set_sys_error(WSAEFAULT);
|
||||
return -1;
|
||||
}
|
||||
if (uv_allow_ipv6) {
|
||||
handle->flags |= UV_HANDLE_IPV6;
|
||||
return uv__bind(handle, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6));
|
||||
} else {
|
||||
uv_new_sys_error(UV_EAFNOSUPPORT);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv_tcp_queue_accept(uv_tcp_t* handle) {
|
||||
uv_req_t* req;
|
||||
BOOL success;
|
||||
DWORD bytes;
|
||||
SOCKET accept_socket;
|
||||
short family;
|
||||
LPFN_ACCEPTEX pAcceptExFamily;
|
||||
|
||||
assert(handle->flags & UV_HANDLE_LISTENING);
|
||||
assert(handle->accept_socket == INVALID_SOCKET);
|
||||
|
||||
/* Prepare the uv_req structure. */
|
||||
req = &handle->accept_req;
|
||||
|
||||
/* choose family and extension function */
|
||||
if ((handle->flags & UV_HANDLE_IPV6) != 0) {
|
||||
family = AF_INET6;
|
||||
pAcceptExFamily = pAcceptEx6;
|
||||
} else {
|
||||
family = AF_INET;
|
||||
pAcceptExFamily = pAcceptEx;
|
||||
}
|
||||
|
||||
/* Open a socket for the accepted connection. */
|
||||
accept_socket = socket(family, SOCK_STREAM, 0);
|
||||
if (accept_socket == INVALID_SOCKET) {
|
||||
req->error = uv_new_sys_error(WSAGetLastError());
|
||||
uv_insert_pending_req(req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->overlapped), 0, sizeof(req->overlapped));
|
||||
|
||||
success = pAcceptExFamily(handle->socket,
|
||||
accept_socket,
|
||||
(void*)&handle->accept_buffer,
|
||||
0,
|
||||
sizeof(struct sockaddr_storage),
|
||||
sizeof(struct sockaddr_storage),
|
||||
&bytes,
|
||||
&req->overlapped);
|
||||
|
||||
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
|
||||
/* Make this req pending reporting an error. */
|
||||
req->error = uv_new_sys_error(WSAGetLastError());
|
||||
uv_insert_pending_req(req);
|
||||
handle->reqs_pending++;
|
||||
/* Destroy the preallocated client socket. */
|
||||
closesocket(accept_socket);
|
||||
return;
|
||||
}
|
||||
|
||||
handle->accept_socket = accept_socket;
|
||||
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
|
||||
|
||||
static void uv_tcp_queue_read(uv_tcp_t* handle) {
|
||||
uv_req_t* req;
|
||||
uv_buf_t buf;
|
||||
int result;
|
||||
DWORD bytes, flags;
|
||||
|
||||
assert(handle->flags & UV_HANDLE_READING);
|
||||
assert(!(handle->flags & UV_HANDLE_READ_PENDING));
|
||||
|
||||
req = &handle->read_req;
|
||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||
|
||||
buf.base = (char*) &uv_zero_;
|
||||
buf.len = 0;
|
||||
|
||||
flags = 0;
|
||||
result = WSARecv(handle->socket,
|
||||
(WSABUF*)&buf,
|
||||
1,
|
||||
&bytes,
|
||||
&flags,
|
||||
&req->overlapped,
|
||||
NULL);
|
||||
if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) {
|
||||
/* Make this req pending reporting an error. */
|
||||
req->error = uv_new_sys_error(WSAGetLastError());
|
||||
uv_insert_pending_req(req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
assert(backlog > 0);
|
||||
|
||||
if (handle->flags & UV_HANDLE_BIND_ERROR) {
|
||||
LOOP->last_error = handle->error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_LISTENING ||
|
||||
handle->flags & UV_HANDLE_READING) {
|
||||
/* Already listening. */
|
||||
uv_set_sys_error(WSAEALREADY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND) &&
|
||||
uv_tcp_bind(handle, uv_addr_ip4_any_) < 0)
|
||||
return -1;
|
||||
|
||||
if (listen(handle->socket, backlog) == SOCKET_ERROR) {
|
||||
uv_set_sys_error(WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_LISTENING;
|
||||
handle->connection_cb = cb;
|
||||
|
||||
uv_req_init(&(handle->accept_req));
|
||||
handle->accept_req.type = UV_ACCEPT;
|
||||
handle->accept_req.data = handle;
|
||||
uv_tcp_queue_accept(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
int rv = 0;
|
||||
|
||||
if (server->accept_socket == INVALID_SOCKET) {
|
||||
uv_set_sys_error(WSAENOTCONN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (uv_tcp_set_socket(client, server->accept_socket) == -1) {
|
||||
closesocket(server->accept_socket);
|
||||
rv = -1;
|
||||
} else {
|
||||
uv_connection_init((uv_stream_t*)client);
|
||||
}
|
||||
|
||||
server->accept_socket = INVALID_SOCKET;
|
||||
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_tcp_queue_accept(server);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION)) {
|
||||
uv_set_sys_error(WSAEINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
uv_set_sys_error(WSAEALREADY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EOF) {
|
||||
uv_set_sys_error(WSAESHUTDOWN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_READING;
|
||||
handle->read_cb = read_cb;
|
||||
handle->alloc_cb = alloc_cb;
|
||||
|
||||
/* If reading was stopped and then started again, there could stell be a */
|
||||
/* read request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
||||
uv_tcp_queue_read(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
|
||||
struct sockaddr_in address, uv_connect_cb cb) {
|
||||
int addrsize = sizeof(struct sockaddr_in);
|
||||
BOOL success;
|
||||
DWORD bytes;
|
||||
|
||||
if (handle->flags & UV_HANDLE_BIND_ERROR) {
|
||||
LOOP->last_error = handle->error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (address.sin_family != AF_INET) {
|
||||
uv_set_sys_error(WSAEFAULT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND) &&
|
||||
uv_tcp_bind(handle, uv_addr_ip4_any_) < 0)
|
||||
return -1;
|
||||
|
||||
uv_req_init((uv_req_t*) req);
|
||||
req->type = UV_CONNECT;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||
|
||||
success = pConnectEx(handle->socket,
|
||||
(struct sockaddr*) &address,
|
||||
addrsize,
|
||||
NULL,
|
||||
0,
|
||||
&bytes,
|
||||
&req->overlapped);
|
||||
|
||||
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
|
||||
uv_set_sys_error(WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->reqs_pending++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
|
||||
struct sockaddr_in6 address, uv_connect_cb cb) {
|
||||
int addrsize = sizeof(struct sockaddr_in6);
|
||||
BOOL success;
|
||||
DWORD bytes;
|
||||
|
||||
if (!uv_allow_ipv6) {
|
||||
uv_new_sys_error(UV_EAFNOSUPPORT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_BIND_ERROR) {
|
||||
LOOP->last_error = handle->error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (address.sin6_family != AF_INET6) {
|
||||
uv_set_sys_error(WSAEFAULT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND) &&
|
||||
uv_tcp_bind6(handle, uv_addr_ip6_any_) < 0)
|
||||
return -1;
|
||||
|
||||
uv_req_init((uv_req_t*) req);
|
||||
req->type = UV_CONNECT;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||
|
||||
success = pConnectEx6(handle->socket,
|
||||
(struct sockaddr*) &address,
|
||||
addrsize,
|
||||
NULL,
|
||||
0,
|
||||
&bytes,
|
||||
&req->overlapped);
|
||||
|
||||
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
|
||||
uv_set_sys_error(WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->reqs_pending++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen) {
|
||||
int result;
|
||||
|
||||
if (handle->flags & UV_HANDLE_SHUTTING) {
|
||||
uv_set_sys_error(WSAESHUTDOWN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = getsockname(handle->socket, name, namelen);
|
||||
if (result != 0) {
|
||||
uv_set_sys_error(WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt,
|
||||
uv_write_cb cb) {
|
||||
int result;
|
||||
DWORD bytes, err;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION)) {
|
||||
uv_set_sys_error(WSAEINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_SHUTTING) {
|
||||
uv_set_sys_error(WSAESHUTDOWN);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uv_req_init((uv_req_t*) req);
|
||||
req->type = UV_WRITE;
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||
|
||||
result = WSASend(handle->socket,
|
||||
(WSABUF*)bufs,
|
||||
bufcnt,
|
||||
&bytes,
|
||||
0,
|
||||
&req->overlapped,
|
||||
NULL);
|
||||
if (result != 0) {
|
||||
err = WSAGetLastError();
|
||||
if (err != WSA_IO_PENDING) {
|
||||
/* Send failed due to an error. */
|
||||
uv_set_sys_error(WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
/* Request completed immediately. */
|
||||
req->queued_bytes = 0;
|
||||
} else {
|
||||
/* Request queued by the kernel. */
|
||||
req->queued_bytes = uv_count_bufs(bufs, bufcnt);
|
||||
handle->write_queue_size += req->queued_bytes;
|
||||
}
|
||||
|
||||
handle->reqs_pending++;
|
||||
handle->write_reqs_pending++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) {
|
||||
DWORD bytes, flags, err;
|
||||
uv_buf_t buf;
|
||||
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
handle->flags &= ~UV_HANDLE_READ_PENDING;
|
||||
|
||||
if (req->error.code != UV_OK) {
|
||||
/* An error occurred doing the 0-read. */
|
||||
if ((handle->flags & UV_HANDLE_READING)) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
LOOP->last_error = req->error;
|
||||
buf.base = 0;
|
||||
buf.len = 0;
|
||||
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
||||
}
|
||||
} else {
|
||||
/* Do nonblocking reads until the buffer is empty */
|
||||
while (handle->flags & UV_HANDLE_READING) {
|
||||
buf = handle->alloc_cb((uv_stream_t*)handle, 65536);
|
||||
assert(buf.len > 0);
|
||||
flags = 0;
|
||||
if (WSARecv(handle->socket,
|
||||
(WSABUF*)&buf,
|
||||
1,
|
||||
&bytes,
|
||||
&flags,
|
||||
NULL,
|
||||
NULL) != SOCKET_ERROR) {
|
||||
if (bytes > 0) {
|
||||
/* Successful read */
|
||||
handle->read_cb((uv_stream_t*)handle, bytes, buf);
|
||||
/* Read again only if bytes == buf.len */
|
||||
if (bytes < buf.len) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Connection closed */
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
handle->flags |= UV_HANDLE_EOF;
|
||||
LOOP->last_error.code = UV_EOF;
|
||||
LOOP->last_error.sys_errno_ = ERROR_SUCCESS;
|
||||
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
err = WSAGetLastError();
|
||||
if (err == WSAEWOULDBLOCK) {
|
||||
/* Read buffer was completely empty, report a 0-byte read. */
|
||||
uv_set_sys_error(WSAEWOULDBLOCK);
|
||||
handle->read_cb((uv_stream_t*)handle, 0, buf);
|
||||
} else {
|
||||
/* Ouch! serious error. */
|
||||
uv_set_sys_error(err);
|
||||
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Post another 0-read if still reading and not closing. */
|
||||
if ((handle->flags & UV_HANDLE_READING) &&
|
||||
!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
uv_tcp_queue_read(handle);
|
||||
}
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req) {
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
handle->write_queue_size -= req->queued_bytes;
|
||||
|
||||
if (req->cb) {
|
||||
LOOP->last_error = req->error;
|
||||
((uv_write_cb)req->cb)(req, LOOP->last_error.code == UV_OK ? 0 : -1);
|
||||
}
|
||||
|
||||
handle->write_reqs_pending--;
|
||||
if (handle->flags & UV_HANDLE_SHUTTING &&
|
||||
handle->write_reqs_pending == 0) {
|
||||
uv_want_endgame((uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) {
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
/* If handle->accepted_socket is not a valid socket, then */
|
||||
/* uv_queue_accept must have failed. This is a serious error. We stop */
|
||||
/* accepting connections and report this error to the connection */
|
||||
/* callback. */
|
||||
if (handle->accept_socket == INVALID_SOCKET) {
|
||||
if (handle->flags & UV_HANDLE_LISTENING) {
|
||||
handle->flags &= ~UV_HANDLE_LISTENING;
|
||||
if (handle->connection_cb) {
|
||||
LOOP->last_error = req->error;
|
||||
handle->connection_cb((uv_handle_t*)handle, -1);
|
||||
}
|
||||
}
|
||||
} else if (req->error.code == UV_OK &&
|
||||
setsockopt(handle->accept_socket,
|
||||
SOL_SOCKET,
|
||||
SO_UPDATE_ACCEPT_CONTEXT,
|
||||
(char*)&handle->socket,
|
||||
sizeof(handle->socket)) == 0) {
|
||||
/* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
|
||||
if (handle->connection_cb) {
|
||||
handle->connection_cb((uv_handle_t*)handle, 0);
|
||||
}
|
||||
} else {
|
||||
/* Error related to accepted socket is ignored because the server */
|
||||
/* socket may still be healthy. If the server socket is broken
|
||||
/* uv_queue_accept will detect it. */
|
||||
closesocket(handle->accept_socket);
|
||||
if (handle->flags & UV_HANDLE_LISTENING) {
|
||||
uv_tcp_queue_accept(handle);
|
||||
}
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req) {
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
if (req->cb) {
|
||||
if (req->error.code == UV_OK) {
|
||||
if (setsockopt(handle->socket,
|
||||
SOL_SOCKET,
|
||||
SO_UPDATE_CONNECT_CONTEXT,
|
||||
NULL,
|
||||
0) == 0) {
|
||||
uv_connection_init((uv_stream_t*)handle);
|
||||
((uv_connect_cb)req->cb)(req, 0);
|
||||
} else {
|
||||
uv_set_sys_error(WSAGetLastError());
|
||||
((uv_connect_cb)req->cb)(req, -1);
|
||||
}
|
||||
} else {
|
||||
LOOP->last_error = req->error;
|
||||
((uv_connect_cb)req->cb)(req, -1);
|
||||
}
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
232
deps/uv/src/win/timer.c
vendored
Normal file
232
deps/uv/src/win/timer.c
vendored
Normal file
@ -0,0 +1,232 @@
|
||||
/* 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 "uv.h"
|
||||
#include "internal.h"
|
||||
#include "tree.h"
|
||||
|
||||
|
||||
/* The resolution of the high-resolution clock. */
|
||||
static int64_t uv_ticks_per_msec_ = 0;
|
||||
|
||||
|
||||
|
||||
void uv_update_time() {
|
||||
LARGE_INTEGER counter;
|
||||
|
||||
if (!QueryPerformanceCounter(&counter))
|
||||
uv_fatal_error(GetLastError(), "QueryPerformanceCounter");
|
||||
|
||||
LOOP->time = counter.QuadPart / uv_ticks_per_msec_;
|
||||
}
|
||||
|
||||
|
||||
int64_t uv_now() {
|
||||
return LOOP->time;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_hrtime(void) {
|
||||
assert(0 && "implement me");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_timer_startup() {
|
||||
LARGE_INTEGER timer_frequency;
|
||||
|
||||
/* Initialize the event loop time */
|
||||
if (!QueryPerformanceFrequency(&timer_frequency))
|
||||
uv_fatal_error(GetLastError(), "QueryPerformanceFrequency");
|
||||
uv_ticks_per_msec_ = timer_frequency.QuadPart / 1000;
|
||||
}
|
||||
|
||||
|
||||
static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
|
||||
if (a->due < b->due)
|
||||
return -1;
|
||||
if (a->due > b->due)
|
||||
return 1;
|
||||
if ((intptr_t)a < (intptr_t)b)
|
||||
return -1;
|
||||
if ((intptr_t)a > (intptr_t)b)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
|
||||
|
||||
|
||||
int uv_timer_init(uv_timer_t* handle) {
|
||||
uv_counters()->handle_init++;
|
||||
uv_counters()->timer_init++;
|
||||
|
||||
handle->type = UV_TIMER;
|
||||
handle->flags = 0;
|
||||
handle->error = uv_ok_;
|
||||
handle->timer_cb = NULL;
|
||||
handle->repeat = 0;
|
||||
|
||||
uv_ref();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_timer_endgame(uv_timer_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
|
||||
if (handle->close_cb) {
|
||||
handle->close_cb((uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
uv_unref();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout, int64_t repeat) {
|
||||
if (handle->flags & UV_HANDLE_ACTIVE) {
|
||||
RB_REMOVE(uv_timer_tree_s, &LOOP->timers, handle);
|
||||
}
|
||||
|
||||
handle->timer_cb = timer_cb;
|
||||
handle->due = LOOP->time + timeout;
|
||||
handle->repeat = repeat;
|
||||
handle->flags |= UV_HANDLE_ACTIVE;
|
||||
|
||||
if (RB_INSERT(uv_timer_tree_s, &LOOP->timers, handle) != NULL) {
|
||||
uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_stop(uv_timer_t* handle) {
|
||||
if (!(handle->flags & UV_HANDLE_ACTIVE))
|
||||
return 0;
|
||||
|
||||
RB_REMOVE(uv_timer_tree_s, &LOOP->timers, handle);
|
||||
|
||||
handle->flags &= ~UV_HANDLE_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_again(uv_timer_t* handle) {
|
||||
/* If timer_cb is NULL that means that the timer was never started. */
|
||||
if (!handle->timer_cb) {
|
||||
uv_set_sys_error(ERROR_INVALID_DATA);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_ACTIVE) {
|
||||
RB_REMOVE(uv_timer_tree_s, &LOOP->timers, handle);
|
||||
handle->flags &= ~UV_HANDLE_ACTIVE;
|
||||
}
|
||||
|
||||
if (handle->repeat) {
|
||||
handle->due = LOOP->time + handle->repeat;
|
||||
|
||||
if (RB_INSERT(uv_timer_tree_s, &LOOP->timers, handle) != NULL) {
|
||||
uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_ACTIVE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_timer_set_repeat(uv_timer_t* handle, int64_t repeat) {
|
||||
assert(handle->type == UV_TIMER);
|
||||
handle->repeat = repeat;
|
||||
}
|
||||
|
||||
|
||||
int64_t uv_timer_get_repeat(uv_timer_t* handle) {
|
||||
assert(handle->type == UV_TIMER);
|
||||
return handle->repeat;
|
||||
}
|
||||
|
||||
|
||||
DWORD uv_get_poll_timeout() {
|
||||
uv_timer_t* timer;
|
||||
int64_t delta;
|
||||
|
||||
/* Check if there are any running timers */
|
||||
timer = RB_MIN(uv_timer_tree_s, &LOOP->timers);
|
||||
if (timer) {
|
||||
uv_update_time();
|
||||
|
||||
delta = timer->due - LOOP->time;
|
||||
if (delta >= UINT_MAX) {
|
||||
/* Can't have a timeout greater than UINT_MAX, and a timeout value of */
|
||||
/* UINT_MAX means infinite, so that's no good either. */
|
||||
return UINT_MAX - 1;
|
||||
} else if (delta < 0) {
|
||||
/* Negative timeout values are not allowed */
|
||||
return 0;
|
||||
} else {
|
||||
return (DWORD)delta;
|
||||
}
|
||||
} else {
|
||||
/* No timers */
|
||||
return INFINITE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_process_timers() {
|
||||
uv_timer_t* timer;
|
||||
|
||||
/* Call timer callbacks */
|
||||
for (timer = RB_MIN(uv_timer_tree_s, &LOOP->timers);
|
||||
timer != NULL && timer->due <= LOOP->time;
|
||||
timer = RB_MIN(uv_timer_tree_s, &LOOP->timers)) {
|
||||
RB_REMOVE(uv_timer_tree_s, &LOOP->timers, timer);
|
||||
|
||||
if (timer->repeat != 0) {
|
||||
/* If it is a repeating timer, reschedule with repeat timeout. */
|
||||
timer->due += timer->repeat;
|
||||
if (timer->due < LOOP->time) {
|
||||
timer->due = LOOP->time;
|
||||
}
|
||||
if (RB_INSERT(uv_timer_tree_s, &LOOP->timers, timer) != NULL) {
|
||||
uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
|
||||
}
|
||||
} else {
|
||||
/* If non-repeating, mark the timer as inactive. */
|
||||
timer->flags &= ~UV_HANDLE_ACTIVE;
|
||||
}
|
||||
|
||||
timer->timer_cb((uv_timer_t*) timer, 0);
|
||||
}
|
||||
}
|
82
deps/uv/src/win/util.c
vendored
Normal file
82
deps/uv/src/win/util.c
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
int uv_utf16_to_utf8(wchar_t* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size) {
|
||||
return WideCharToMultiByte(CP_UTF8, 0, utf16Buffer, utf16Size, utf8Buffer, utf8Size, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, size_t utf16Size) {
|
||||
return MultiByteToWideChar(CP_UTF8, 0, utf8Buffer, -1, utf16Buffer, utf16Size);
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
int retVal;
|
||||
size_t utf16Size;
|
||||
wchar_t* utf16Buffer;
|
||||
|
||||
if (!buffer || !size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
utf16Buffer = (wchar_t*)malloc(sizeof(wchar_t) * *size);
|
||||
if (!utf16Buffer) {
|
||||
retVal = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get the path as UTF-16 */
|
||||
utf16Size = GetModuleFileNameW(NULL, utf16Buffer, *size - 1);
|
||||
if (utf16Size <= 0) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
retVal = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
utf16Buffer[utf16Size] = L'\0';
|
||||
|
||||
/* Convert to UTF-8 */
|
||||
*size = uv_utf16_to_utf8(utf16Buffer, utf16Size, buffer, *size);
|
||||
if (!*size) {
|
||||
uv_set_sys_error(GetLastError());
|
||||
retVal = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
buffer[*size] = '\0';
|
||||
retVal = 0;
|
||||
|
||||
done:
|
||||
if (utf16Buffer) {
|
||||
free(utf16Buffer);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user