1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
3
* Permission is hereby granted, free of charge, to any person obtaining a copy
4
* of this software and associated documentation files (the "Software"), to
5
* deal in the Software without restriction, including without limitation the
6
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
* sell copies of the Software, and to permit persons to whom the Software is
8
* furnished to do so, subject to the following conditions:
10
* The above copyright notice and this permission notice shall be included in
11
* all copies or substantial portions of the Software.
13
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31
* This is called once per second by loop->timer. It is used to
32
* constantly callback into c-ares for possibly processing timeouts.
34
static void uv__ares_timeout(struct ev_loop* ev, struct ev_timer* watcher,
36
uv_loop_t* loop = ev_userdata(ev);
38
assert(ev == loop->ev);
39
assert((uv_loop_t*)watcher->data == loop);
40
assert(watcher == &loop->timer);
41
assert(revents == EV_TIMER);
42
assert(!uv_ares_handles_empty(loop));
44
ares_process_fd(loop->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
48
static void uv__ares_io(struct ev_loop* ev, struct ev_io* watcher,
50
uv_loop_t* loop = ev_userdata(ev);
52
assert(ev == loop->ev);
54
/* Reset the idle timer */
55
ev_timer_again(ev, &loop->timer);
57
/* Process DNS responses */
58
ares_process_fd(loop->channel,
59
revents & EV_READ ? watcher->fd : ARES_SOCKET_BAD,
60
revents & EV_WRITE ? watcher->fd : ARES_SOCKET_BAD);
64
/* Allocates and returns a new uv_ares_task_t */
65
static uv_ares_task_t* uv__ares_task_create(int fd) {
66
uv_ares_task_t* h = malloc(sizeof(uv_ares_task_t));
69
uv_fatal_error(ENOMEM, "malloc");
75
ev_io_init(&h->read_watcher, uv__ares_io, fd, EV_READ);
76
ev_io_init(&h->write_watcher, uv__ares_io, fd, EV_WRITE);
78
h->read_watcher.data = h;
79
h->write_watcher.data = h;
85
/* Callback from ares when socket operation is started */
86
static void uv__ares_sockstate_cb(void* data, ares_socket_t sock,
87
int read, int write) {
88
uv_loop_t* loop = data;
91
assert((uv_loop_t*)loop->timer.data == loop);
93
h = uv_find_ares_handle(loop, sock);
99
/* If this is the first socket then start the timer. */
100
if (!ev_is_active(&loop->timer)) {
101
assert(uv_ares_handles_empty(loop));
102
ev_timer_again(loop->ev, &loop->timer);
105
h = uv__ares_task_create(sock);
106
uv_add_ares_handle(loop, h);
110
ev_io_start(loop->ev, &h->read_watcher);
112
ev_io_stop(loop->ev, &h->read_watcher);
116
ev_io_start(loop->ev, &h->write_watcher);
118
ev_io_stop(loop->ev, &h->write_watcher);
123
* read == 0 and write == 0 this is c-ares's way of notifying us that
124
* the socket is now closed. We must free the data associated with
127
assert(h && "When an ares socket is closed we should have a handle for it");
129
ev_io_stop(loop->ev, &h->read_watcher);
130
ev_io_stop(loop->ev, &h->write_watcher);
132
uv_remove_ares_handle(h);
135
if (uv_ares_handles_empty(loop)) {
136
ev_timer_stop(loop->ev, &loop->timer);
142
/* c-ares integration initialize and terminate */
143
/* TODO: share this with windows? */
144
int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr,
145
struct ares_options *options, int optmask) {
148
/* only allow single init at a time */
149
if (loop->channel != NULL) {
150
uv__set_artificial_error(loop, UV_EALREADY);
154
/* set our callback as an option */
155
options->sock_state_cb = uv__ares_sockstate_cb;
156
options->sock_state_cb_data = loop;
157
optmask |= ARES_OPT_SOCK_STATE_CB;
159
/* We do the call to ares_init_option for caller. */
160
rc = ares_init_options(channelptr, options, optmask);
162
/* if success, save channel */
163
if (rc == ARES_SUCCESS) {
164
loop->channel = *channelptr;
168
* Initialize the timeout timer. The timer won't be started until the
169
* first socket is opened.
171
ev_timer_init(&loop->timer, uv__ares_timeout, 1., 1.);
172
loop->timer.data = loop;
178
/* TODO share this with windows? */
179
void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) {
180
/* only allow destroy if did init */
182
ev_timer_stop(loop->ev, &loop->timer);
183
ares_destroy(channel);
184
loop->channel = NULL;