windows, unix: share c-ares glue code

This commit is contained in:
Bert Belder 2012-05-22 01:41:59 +02:00
parent 25316a3f92
commit c06edd4c88
16 changed files with 215 additions and 540 deletions

View File

@ -37,15 +37,15 @@ RUNNER_LINKFLAGS=$(LINKFLAGS)
RUNNER_LIBS=-lws2_32 -lpsapi -liphlpapi
RUNNER_SRC=test/runner-win.c
uv.a: $(WIN_OBJS) src/uv-common.o $(CARES_OBJS)
$(AR) rcs uv.a src/win/*.o src/uv-common.o $(CARES_OBJS)
uv.a: $(WIN_OBJS) src/cares.o src/uv-common.o $(CARES_OBJS)
$(AR) rcs uv.a $(WIN_OBJS) src/cares.o src/uv-common.o $(CARES_OBJS)
src/win/%.o: src/win/%.c src/win/internal.h
src/%.o: src/%.c include/uv.h include/uv-private/uv-win.h
$(CC) $(CFLAGS) -c $< -o $@
src/win/%.o: src/win/%.c include/uv.h include/uv-private/uv-win.h src/win/internal.h
$(CC) $(CFLAGS) -o $@ -c $<
src/uv-common.o: src/uv-common.c include/uv.h include/uv-private/uv-win.h
$(CC) $(CFLAGS) -c src/uv-common.c -o src/uv-common.o
EIO_CPPFLAGS += $(CPPFLAGS)
EIO_CPPFLAGS += -DEIO_STACKSIZE=65536
EIO_CPPFLAGS += -D_GNU_SOURCE

View File

@ -21,14 +21,13 @@
E=
CSTDFLAG=--std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter
CFLAGS += -g
CPPFLAGS += -Isrc/unix/ev
CPPFLAGS += -Isrc -Isrc/unix/ev
LINKFLAGS=-lm
CPPFLAGS += -D_LARGEFILE_SOURCE
CPPFLAGS += -D_FILE_OFFSET_BITS=64
OBJS += src/unix/async.o
OBJS += src/unix/cares.o
OBJS += src/unix/core.o
OBJS += src/unix/dl.o
OBJS += src/unix/error.o
@ -129,14 +128,14 @@ endif
RUNNER_LIBS=
RUNNER_SRC=test/runner-unix.c
uv.a: $(OBJS) src/uv-common.o src/unix/ev/ev.o src/unix/uv-eio.o src/unix/eio/eio.o $(CARES_OBJS)
$(AR) rcs uv.a $(OBJS) src/uv-common.o src/unix/uv-eio.o src/unix/ev/ev.o src/unix/eio/eio.o $(CARES_OBJS)
uv.a: $(OBJS) src/cares.o src/uv-common.o src/unix/ev/ev.o src/unix/uv-eio.o src/unix/eio/eio.o $(CARES_OBJS)
$(AR) rcs uv.a $(OBJS) src/cares.o src/uv-common.o src/unix/uv-eio.o src/unix/ev/ev.o src/unix/eio/eio.o $(CARES_OBJS)
src/%.o: src/%.c include/uv.h include/uv-private/uv-unix.h
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
src/unix/%.o: src/unix/%.c include/uv.h include/uv-private/uv-unix.h src/unix/internal.h
$(CC) $(CSTDFLAG) $(CPPFLAGS) -Isrc $(CFLAGS) -c $< -o $@
src/uv-common.o: src/uv-common.c include/uv.h include/uv-private/uv-unix.h
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c src/uv-common.c -o src/uv-common.o
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
src/unix/ev/ev.o: src/unix/ev/ev.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c src/unix/ev/ev.c -o src/unix/ev/ev.o -DEV_CONFIG_H=\"$(EV_CONFIG)\"

View File

@ -90,13 +90,6 @@ typedef struct {
#endif
#define UV_LOOP_PRIVATE_FIELDS \
ares_channel channel; \
/* \
* While the channel is active this timer is called once per second to be \
* sure that we're always calling ares_process. See the warning above the \
* definition of ares_timeout(). \
*/ \
uv_timer_t timer; \
/* Poll result queue */ \
eio_channel uv_eio_channel; \
struct ev_loop* ev; \

View File

@ -231,23 +231,17 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
uv_idle_t* next_idle_handle; \
/* This handle holds the peer sockets for the fast variant of uv_poll_t */ \
SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \
/* State used by uv_ares. */ \
ares_channel ares_chan; \
int ares_active_sockets; \
uv_timer_t ares_polling_timer; \
/* Counter to keep track of active tcp streams */ \
unsigned int active_tcp_streams; \
/* Counter to keep track of active udp streams */ \
unsigned int active_udp_streams;
#define UV_HANDLE_TYPE_PRIVATE \
UV_ARES_EVENT,
/* empty */
#define UV_REQ_TYPE_PRIVATE \
/* TODO: remove the req suffix */ \
UV_ACCEPT, \
UV_ARES_EVENT_REQ, \
UV_ARES_CLEANUP_REQ, \
UV_FS_EVENT_REQ, \
UV_POLL_REQ, \
UV_PROCESS_EXIT, \

View File

@ -1645,8 +1645,13 @@ struct uv_counters_s {
struct uv_loop_s {
UV_LOOP_PRIVATE_FIELDS
ares_channel channel;
/* While the channel is active this timer is called once per second to be */
/* sure that we're always calling ares_process. See the warning above the */
/* definition of ares_timeout(). */
uv_timer_t ares_timer; \
/* RB_HEAD(uv__ares_tasks, uv_ares_task_t) */
struct uv__ares_tasks { uv_ares_task_t* rbh_root; } uv_ares_handles_;
struct uv__ares_tasks { uv_ares_task_t* rbh_root; } ares_handles;
/* Diagnostic counters */
uv_counters_t counters;
/* The last error */

179
src/cares.c Normal file
View File

@ -0,0 +1,179 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "uv-common.h"
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
/* This is called once per second by loop->timer. It is used to constantly */
/* call back into c-ares for possibly processing timeouts. */
static void uv__ares_timeout(uv_timer_t* handle, int status) {
assert(!uv_ares_handles_empty(handle->loop));
ares_process_fd(handle->loop->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
static void uv__ares_poll_cb(uv_poll_t* watcher, int status, int events) {
uv_loop_t* loop = watcher->loop;
uv_ares_task_t* task = container_of(watcher, uv_ares_task_t, poll_watcher);
/* Reset the idle timer */
uv_timer_again(&loop->ares_timer);
if (status < 0) {
/* An error happened. Just pretend that the socket is both readable and */
/* writable. */
ares_process_fd(loop->channel, task->sock, task->sock);
return;
}
/* Process DNS responses */
ares_process_fd(loop->channel,
events & UV_READABLE ? task->sock : ARES_SOCKET_BAD,
events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
}
static void uv__ares_poll_close_cb(uv_handle_t* watcher) {
uv_ares_task_t* task = container_of(watcher, uv_ares_task_t, poll_watcher);
free(task);
}
/* Allocates and returns a new uv_ares_task_t */
static uv_ares_task_t* uv__ares_task_create(uv_loop_t* loop, ares_socket_t sock) {
uv_ares_task_t* task = (uv_ares_task_t*) malloc(sizeof *task);
if (task == NULL) {
/* Out of memory. */
return NULL;
}
task->loop = loop;
task->sock = sock;
if (uv_poll_init_socket(loop, &task->poll_watcher, sock) < 0) {
/* This should never happen. */
free(task);
return NULL;
}
return task;
}
/* Callback from ares when socket operation is started */
static void uv__ares_sockstate_cb(void* data, ares_socket_t sock,
int read, int write) {
uv_loop_t* loop = (uv_loop_t*) data;
uv_ares_task_t* task;
task = uv_find_ares_handle(loop, sock);
if (read || write) {
if (!task) {
/* New socket */
/* If this is the first socket then start the timer. */
if (!uv_is_active((uv_handle_t*) &loop->ares_timer)) {
assert(uv_ares_handles_empty(loop));
uv_timer_start(&loop->ares_timer, uv__ares_timeout, 1000, 1000);
}
task = uv__ares_task_create(loop, sock);
if (task == NULL) {
/* This should never happen unless we're out of memory or something */
/* is seriously wrong. The socket won't be polled, but the the query */
/* will eventually time out. */
return;
}
uv_add_ares_handle(loop, task);
}
/* This should never fail. If it fails anyway, the query will eventually */
/* time out. */
uv_poll_start(&task->poll_watcher,
(read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0),
uv__ares_poll_cb);
} else {
/* read == 0 and write == 0 this is c-ares's way of notifying us that */
/* the socket is now closed. We must free the data associated with */
/* socket. */
assert(task &&
"When an ares socket is closed we should have a handle for it");
uv_remove_ares_handle(task);
uv_close((uv_handle_t*) &task->poll_watcher, uv__ares_poll_close_cb);
if (uv_ares_handles_empty(loop)) {
uv_timer_stop(&loop->ares_timer);
}
}
}
/* C-ares integration initialize and terminate */
int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr,
struct ares_options *options, int optmask) {
int rc;
/* only allow single init at a time */
if (loop->channel != NULL) {
uv__set_artificial_error(loop, UV_EALREADY);
return -1;
}
/* set our callback as an option */
options->sock_state_cb = uv__ares_sockstate_cb;
options->sock_state_cb_data = loop;
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) {
loop->channel = *channelptr;
}
/* Initialize the timeout timer. The timer won't be started until the */
/* first socket is opened. */
uv_timer_init(loop, &loop->ares_timer);
return rc;
}
void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) {
/* Only allow destroy if did init. */
if (loop->channel) {
uv_timer_stop(&loop->ares_timer);
ares_destroy(channel);
loop->channel = NULL;
}
}

View File

@ -1,179 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "internal.h"
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
/*
* This is called once per second by loop->timer. It is used to
* constantly callback into c-ares for possibly processing timeouts.
*/
static void uv__ares_timeout(uv_timer_t* handle, int status) {
assert(!uv_ares_handles_empty(handle->loop));
ares_process_fd(handle->loop->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
static void uv__ares_io(struct ev_loop* ev, struct ev_io* watcher,
int revents) {
uv_loop_t* loop = ev_userdata(ev);
assert(ev == loop->ev);
/* Reset the idle timer */
uv_timer_again(&loop->timer);
/* Process DNS responses */
ares_process_fd(loop->channel,
revents & EV_READ ? watcher->fd : ARES_SOCKET_BAD,
revents & EV_WRITE ? watcher->fd : ARES_SOCKET_BAD);
}
/* Allocates and returns a new uv_ares_task_t */
static uv_ares_task_t* uv__ares_task_create(uv_loop_t* loop, int fd) {
uv_ares_task_t* h = malloc(sizeof(uv_ares_task_t));
if (h == NULL) {
uv_fatal_error(ENOMEM, "malloc");
return NULL;
}
h->loop = loop;
h->sock = fd;
ev_io_init(&h->read_watcher, uv__ares_io, fd, EV_READ);
ev_io_init(&h->write_watcher, uv__ares_io, fd, EV_WRITE);
h->read_watcher.data = h;
h->write_watcher.data = h;
return h;
}
/* Callback from ares when socket operation is started */
static void uv__ares_sockstate_cb(void* data, ares_socket_t sock,
int read, int write) {
uv_loop_t* loop = data;
uv_ares_task_t* h;
assert((uv_loop_t*)loop->timer.data == loop);
h = uv_find_ares_handle(loop, sock);
if (read || write) {
if (!h) {
/* New socket */
/* If this is the first socket then start the timer. */
if (!uv__is_active(&loop->timer)) {
assert(uv_ares_handles_empty(loop));
uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000);
}
h = uv__ares_task_create(loop, sock);
uv_add_ares_handle(loop, h);
}
if (read) {
ev_io_start(loop->ev, &h->read_watcher);
} else {
ev_io_stop(loop->ev, &h->read_watcher);
}
if (write) {
ev_io_start(loop->ev, &h->write_watcher);
} else {
ev_io_stop(loop->ev, &h->write_watcher);
}
} else {
/*
* read == 0 and write == 0 this is c-ares's way of notifying us that
* the socket is now closed. We must free the data associated with
* socket.
*/
assert(h && "When an ares socket is closed we should have a handle for it");
ev_io_stop(loop->ev, &h->read_watcher);
ev_io_stop(loop->ev, &h->write_watcher);
uv_remove_ares_handle(h);
free(h);
if (uv_ares_handles_empty(loop)) {
uv_timer_stop(&loop->timer);
}
}
}
/* c-ares integration initialize and terminate */
/* TODO: share this with windows? */
int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr,
struct ares_options *options, int optmask) {
int rc;
/* only allow single init at a time */
if (loop->channel != NULL) {
uv__set_artificial_error(loop, UV_EALREADY);
return -1;
}
/* set our callback as an option */
options->sock_state_cb = uv__ares_sockstate_cb;
options->sock_state_cb_data = loop;
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) {
loop->channel = *channelptr;
}
/*
* Initialize the timeout timer. The timer won't be started until the
* first socket is opened.
*/
uv_timer_init(loop, &loop->timer);
loop->timer.data = loop;
return rc;
}
/* TODO share this with windows? */
void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) {
/* only allow destroy if did init */
if (loop->channel) {
uv_timer_stop(&loop->timer);
ares_destroy(channel);
loop->channel = NULL;
}
}

View File

@ -27,7 +27,6 @@
#include <assert.h>
#include <stdlib.h> /* abort */
#include <stddef.h> /* offsetof */
#if __STRICT_ANSI__
# define inline __inline
@ -64,9 +63,6 @@
# define HAVE_KQUEUE 1
#endif
#define container_of(ptr, type, member) \
((type *) ((char *) (ptr) - offsetof(type, member)))
#define UNREACHABLE() \
do { \
assert(0 && "unreachable code"); \

View File

@ -41,7 +41,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) {
ngx_queue_init(&loop->active_reqs);
#endif
RB_INIT(&loop->uv_ares_handles_);
RB_INIT(&loop->ares_handles);
ngx_queue_init(&loop->idle_handles);
ngx_queue_init(&loop->check_handles);
ngx_queue_init(&loop->prepare_handles);

View File

@ -212,7 +212,7 @@ RB_GENERATE_STATIC(uv__ares_tasks, uv_ares_task_s, node, cmp_ares_tasks)
/* add ares handle to list */
void uv_add_ares_handle(uv_loop_t* loop, uv_ares_task_t* handle) {
assert(loop == handle->loop);
RB_INSERT(uv__ares_tasks, &loop->uv_ares_handles_, handle);
RB_INSERT(uv__ares_tasks, &loop->ares_handles, handle);
}
@ -220,19 +220,19 @@ void uv_add_ares_handle(uv_loop_t* loop, uv_ares_task_t* handle) {
uv_ares_task_t* uv_find_ares_handle(uv_loop_t* loop, ares_socket_t sock) {
uv_ares_task_t handle;
handle.sock = sock;
return RB_FIND(uv__ares_tasks, &loop->uv_ares_handles_, &handle);
return RB_FIND(uv__ares_tasks, &loop->ares_handles, &handle);
}
/* remove ares handle in list */
void uv_remove_ares_handle(uv_ares_task_t* handle) {
RB_REMOVE(uv__ares_tasks, &handle->loop->uv_ares_handles_, handle);
RB_REMOVE(uv__ares_tasks, &handle->loop->ares_handles, handle);
}
/* Returns 1 if the uv_ares_handles_ list is empty. 0 otherwise. */
/* Returns 1 if the ares_handles list is empty. 0 otherwise. */
int uv_ares_handles_empty(uv_loop_t* loop) {
return RB_EMPTY(&loop->uv_ares_handles_);
return RB_EMPTY(&loop->ares_handles);
}

View File

@ -28,6 +28,8 @@
#define UV_COMMON_H_
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include "uv.h"
#include "tree.h"
@ -35,6 +37,9 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define container_of(ptr, type, member) \
((type *) ((char *) (ptr) - offsetof(type, member)))
#ifdef _MSC_VER
# define UNUSED /* empty */
#else
@ -54,17 +59,8 @@ enum {
struct uv_ares_task_s {
UV_HANDLE_FIELDS
#if _WIN32
struct uv_req_s ares_req;
SOCKET sock;
HANDLE h_wait;
WSAEVENT h_event;
HANDLE h_close_event;
#else
int sock;
ev_io read_watcher;
ev_io write_watcher;
#endif
ares_socket_t sock;
uv_poll_t poll_watcher;
RB_ENTRY(uv_ares_task_s) node;
};

View File

@ -1,288 +0,0 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <assert.h>
#include "uv.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;
};
/* 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;
uv_loop_t* loop;
assert(parameter != NULL);
if (parameter != NULL) {
sockhandle = (uv_ares_task_t*) parameter;
loop = sockhandle->loop;
/* 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 unnecessary 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(loop, uv_ares_req);
uv_ares_req->type = UV_ARES_EVENT_REQ;
uv_ares_req->data = selhandle;
/* post ares needs to called */
POST_COMPLETION_FOR_REQ(loop, uv_ares_req);
}
}
/* periodically call ares to check for timeouts */
static void uv_ares_poll(uv_timer_t* handle, int status) {
uv_loop_t* loop = handle->loop;
if (loop->ares_chan != NULL && loop->ares_active_sockets > 0) {
ares_process_fd(loop->ares_chan, 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_loop_t* loop = (uv_loop_t*) data;
uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(loop, sock);
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 receive 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);
uv__handle_stop(uv_handle_ares);
/* Post request to cleanup the Task */
uv_ares_req = &uv_handle_ares->ares_req;
uv_req_init(loop, 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. */
POST_COMPLETION_FOR_REQ(loop, uv_ares_req);
} 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->loop = loop;
uv_handle_ares->data = loop;
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(loop, uv_handle_ares);
uv__handle_start(uv_handle_ares);
/*
* 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 (loop->ares_active_sockets == 0) {
uv_timer_init(loop, &loop->ares_polling_timer);
uv_timer_start(&loop->ares_polling_timer, uv_ares_poll, 1000L, 1000L);
}
loop->ares_active_sockets++;
/* 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_loop_t* loop, uv_ares_action_t* handle,
uv_req_t* req) {
ares_process_fd(loop->ares_chan,
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_loop_t* loop, 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__handle_stop(loop);
/* 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 (loop->ares_active_sockets > 0) {
loop->ares_active_sockets--;
if (loop->ares_active_sockets == 0) {
uv_close((uv_handle_t*) &loop->ares_polling_timer, NULL);
}
}
} else {
/* still busy - repost and try again */
POST_COMPLETION_FOR_REQ(loop, req);
}
}
/* set ares SOCK_STATE callback to our handler */
int uv_ares_init_options(uv_loop_t* loop,
ares_channel *channelptr,
struct ares_options *options,
int optmask) {
int rc;
/* only allow single init at a time */
if (loop->ares_chan != NULL) {
return UV_EALREADY;
}
/* set our callback as an option */
options->sock_state_cb = uv_ares_sockstate_cb;
options->sock_state_cb_data = loop;
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) {
loop->ares_chan = *channelptr;
}
return rc;
}
/* release memory */
void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) {
/* only allow destroy if did init */
if (loop->ares_chan != NULL) {
ares_destroy(channel);
loop->ares_chan = NULL;
}
}

View File

@ -79,7 +79,6 @@ static void uv_loop_init(uv_loop_t* loop) {
loop->endgame_handles = NULL;
RB_INIT(&loop->timers);
RB_INIT(&loop->uv_ares_handles_);
loop->check_handles = NULL;
loop->prepare_handles = NULL;
@ -91,8 +90,8 @@ static void uv_loop_init(uv_loop_t* loop) {
memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
loop->ares_active_sockets = 0;
loop->ares_chan = NULL;
loop->channel = NULL;
RB_INIT(&loop->ares_handles);
loop->active_tcp_streams = 0;
loop->active_udp_streams = 0;

View File

@ -312,16 +312,6 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
/*
* C-ares integration
*/
typedef struct uv_ares_action_s uv_ares_action_t;
void uv_process_ares_event_req(uv_loop_t* loop, uv_ares_action_t* handle,
uv_req_t* req);
void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle,
uv_req_t* req);
/*
* Getaddrinfo
*/

View File

@ -138,14 +138,6 @@ void uv_process_reqs(uv_loop_t* loop) {
uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
break;
case UV_ARES_EVENT_REQ:
uv_process_ares_event_req(loop, (uv_ares_action_t*) req->data, req);
break;
case UV_ARES_CLEANUP_REQ:
uv_process_ares_cleanup_req(loop, (uv_ares_task_t*) req->data, req);
break;
case UV_GETADDRINFO:
uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req);
break;

3
uv.gyp
View File

@ -49,6 +49,7 @@
'include/uv.h',
'include/uv-private/ngx-queue.h',
'include/uv-private/tree.h',
'src/cares.c',
'src/uv-common.c',
'src/uv-common.h',
'src/ares/ares_cancel.c',
@ -134,7 +135,6 @@
'src/ares/ares_iphlpapi.h',
'src/ares/ares_platform.c',
'src/win/async.c',
'src/win/cares.c',
'src/win/core.c',
'src/win/dl.c',
'src/win/error.c',
@ -182,7 +182,6 @@
'include/uv-private/ev.h',
'include/uv-private/uv-unix.h',
'src/unix/async.c',
'src/unix/cares.c',
'src/unix/core.c',
'src/unix/dl.c',
'src/unix/eio/ecb.h',