2014-02-04 23:01:55 -06:00
|
|
|
/**
|
2014-10-10 07:48:52 -05:00
|
|
|
* \file libuv.c
|
|
|
|
* \brief Eventloop extension for libuv.
|
2014-02-04 23:01:55 -06:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2014-02-25 07:12:33 -06:00
|
|
|
* Copyright (c) 2013, NLNet Labs, Verisign, Inc.
|
2014-02-04 23:01:55 -06:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2014-02-25 07:23:19 -06:00
|
|
|
* * Neither the names of the copyright holders nor the
|
2014-02-04 23:01:55 -06:00
|
|
|
* names of its contributors may be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
|
|
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2014-10-31 08:17:30 -05:00
|
|
|
#include "config.h"
|
2015-12-18 06:50:17 -06:00
|
|
|
#include "debug.h"
|
|
|
|
#include "types-internal.h"
|
2014-02-04 23:01:55 -06:00
|
|
|
#include <uv.h>
|
2014-05-19 08:50:34 -05:00
|
|
|
#include "getdns/getdns_ext_libuv.h"
|
2014-02-04 23:01:55 -06:00
|
|
|
|
2014-10-15 03:47:36 -05:00
|
|
|
#define UV_DEBUG 0
|
|
|
|
|
|
|
|
#if defined(UV_DEBUG) && UV_DEBUG
|
|
|
|
#include <time.h>
|
|
|
|
#define DEBUG_UV(...) DEBUG_ON(__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define DEBUG_UV(...) DEBUG_OFF(__VA_ARGS__)
|
|
|
|
#endif
|
|
|
|
|
2014-10-10 04:14:01 -05:00
|
|
|
typedef struct getdns_libuv {
|
|
|
|
getdns_eventloop_vmt *vmt;
|
|
|
|
uv_loop_t *loop;
|
|
|
|
struct mem_funcs mf;
|
|
|
|
} getdns_libuv;
|
|
|
|
|
2014-10-10 07:48:52 -05:00
|
|
|
static void
|
|
|
|
getdns_libuv_run(getdns_eventloop *loop)
|
2014-10-10 04:14:01 -05:00
|
|
|
{
|
2014-10-10 07:48:52 -05:00
|
|
|
(void) uv_run(((getdns_libuv *)loop)->loop, UV_RUN_DEFAULT);
|
|
|
|
}
|
2014-10-10 04:14:01 -05:00
|
|
|
|
2014-10-10 07:48:52 -05:00
|
|
|
static void
|
|
|
|
getdns_libuv_run_once(getdns_eventloop *loop, int blocking)
|
|
|
|
{
|
|
|
|
(void) uv_run(((getdns_libuv *)loop)->loop,
|
|
|
|
blocking ? UV_RUN_ONCE : UV_RUN_NOWAIT);
|
2014-02-04 23:01:55 -06:00
|
|
|
}
|
|
|
|
|
2014-10-10 07:48:52 -05:00
|
|
|
static void
|
2014-10-10 04:14:01 -05:00
|
|
|
getdns_libuv_cleanup(getdns_eventloop *loop)
|
|
|
|
{
|
|
|
|
getdns_libuv *ext = (getdns_libuv *)loop;
|
|
|
|
GETDNS_FREE(ext->mf, ext);
|
2014-02-04 23:01:55 -06:00
|
|
|
}
|
|
|
|
|
2014-10-10 04:14:01 -05:00
|
|
|
typedef struct poll_timer {
|
register only a single poll_t with libuv
Most of the time we only need a read _or_ a write callback registered
with libuv - for example, on a UDP request a write callback is
registered, when executed the write callback performs the write,
deregisters itself, and registers a read callback.
However there is one case where getdns registers both read and write
callbacks: when a backlog of TCP requests is going to the same upstream
resolver, we use a single fd and queue the requests. In this instance we
want to listen for both read (to get responses for requests we've
already sent) and write (to continue to send our pending requests).
libuv, like most event libraries, only allows one callback to be
registered per fd. To get notification for both reads and writes, you
should examine the event flags and have appropriate conditional logic
within the single callback. Today getdns incorrectly tries to register
two separate poll_t with libuv, one for read and one for write - this
results in a crash (internal libuv assertion guaranteeing that only a
single poll_t is registered per fd).
Testing was done by using flamethrower
(https://github.com/DNS-OARC/flamethrower) to toss queries at a program
that embeds getdns.
Note that a higher qps trigger a _different_ getdns/libuv crashing bug
that occurs when the TCP backlog grows so large that requests start to
time out. That crash is not addressed in this PR, and will be more
involved to fix.
2020-06-18 16:31:34 -05:00
|
|
|
uv_poll_t poll;
|
2014-10-15 03:47:36 -05:00
|
|
|
uv_timer_t timer;
|
|
|
|
int to_close;
|
|
|
|
struct mem_funcs mf;
|
2014-10-10 04:14:01 -05:00
|
|
|
} poll_timer;
|
|
|
|
|
2014-10-15 03:47:36 -05:00
|
|
|
static void
|
|
|
|
getdns_libuv_close_cb(uv_handle_t *handle)
|
|
|
|
{
|
|
|
|
poll_timer *my_ev = (poll_timer *)handle->data;
|
|
|
|
|
|
|
|
DEBUG_UV("enter libuv_close_cb(el_ev->ev = %p, to_close = %d)\n"
|
|
|
|
, my_ev, my_ev->to_close);
|
|
|
|
if (--my_ev->to_close) {
|
|
|
|
DEBUG_UV(
|
|
|
|
"exit libuv_close_cb(el_ev->ev = %p, to_close = %d)\n"
|
|
|
|
, my_ev, my_ev->to_close);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DEBUG_UV("enter libuv_close_cb to_free: %p\n", my_ev);
|
|
|
|
GETDNS_FREE(my_ev->mf, my_ev);
|
|
|
|
DEBUG_UV("enter libuv_close_cb freed: %p\n", my_ev);
|
|
|
|
}
|
|
|
|
|
2014-10-10 07:48:52 -05:00
|
|
|
static getdns_return_t
|
|
|
|
getdns_libuv_clear(getdns_eventloop *loop, getdns_eventloop_event *el_ev)
|
|
|
|
{
|
2014-10-15 03:47:36 -05:00
|
|
|
poll_timer *my_ev = (poll_timer *)el_ev->ev;
|
|
|
|
uv_poll_t *my_poll;
|
|
|
|
uv_timer_t *my_timer;
|
2021-06-03 13:45:55 -05:00
|
|
|
(void)loop; /* unused parameter */
|
2014-10-10 07:48:52 -05:00
|
|
|
|
|
|
|
assert(my_ev);
|
|
|
|
|
2014-10-15 03:47:36 -05:00
|
|
|
DEBUG_UV("enter libuv_clear(el_ev = %p, my_ev = %p, to_close = %d)\n"
|
|
|
|
, el_ev, my_ev, my_ev->to_close);
|
2014-10-14 18:13:39 -05:00
|
|
|
|
register only a single poll_t with libuv
Most of the time we only need a read _or_ a write callback registered
with libuv - for example, on a UDP request a write callback is
registered, when executed the write callback performs the write,
deregisters itself, and registers a read callback.
However there is one case where getdns registers both read and write
callbacks: when a backlog of TCP requests is going to the same upstream
resolver, we use a single fd and queue the requests. In this instance we
want to listen for both read (to get responses for requests we've
already sent) and write (to continue to send our pending requests).
libuv, like most event libraries, only allows one callback to be
registered per fd. To get notification for both reads and writes, you
should examine the event flags and have appropriate conditional logic
within the single callback. Today getdns incorrectly tries to register
two separate poll_t with libuv, one for read and one for write - this
results in a crash (internal libuv assertion guaranteeing that only a
single poll_t is registered per fd).
Testing was done by using flamethrower
(https://github.com/DNS-OARC/flamethrower) to toss queries at a program
that embeds getdns.
Note that a higher qps trigger a _different_ getdns/libuv crashing bug
that occurs when the TCP backlog grows so large that requests start to
time out. That crash is not addressed in this PR, and will be more
involved to fix.
2020-06-18 16:31:34 -05:00
|
|
|
if (el_ev->read_cb || el_ev->write_cb) {
|
|
|
|
my_poll = &my_ev->poll;
|
2014-10-15 03:47:36 -05:00
|
|
|
uv_poll_stop(my_poll);
|
|
|
|
my_ev->to_close += 1;
|
|
|
|
my_poll->data = my_ev;
|
|
|
|
uv_close((uv_handle_t *)my_poll, getdns_libuv_close_cb);
|
2014-10-10 07:48:52 -05:00
|
|
|
}
|
2014-10-14 18:13:39 -05:00
|
|
|
if (el_ev->timeout_cb) {
|
2014-10-15 03:47:36 -05:00
|
|
|
my_timer = &my_ev->timer;
|
|
|
|
uv_timer_stop(my_timer);
|
|
|
|
my_ev->to_close += 1;
|
|
|
|
my_timer->data = my_ev;
|
|
|
|
uv_close((uv_handle_t *)my_timer, getdns_libuv_close_cb);
|
2014-10-14 18:13:39 -05:00
|
|
|
}
|
2014-10-10 07:48:52 -05:00
|
|
|
el_ev->ev = NULL;
|
2014-10-15 03:47:36 -05:00
|
|
|
DEBUG_UV("exit libuv_clear(el_ev = %p, my_ev = %p, to_close = %d)\n"
|
|
|
|
, el_ev, my_ev, my_ev->to_close);
|
2014-10-10 07:48:52 -05:00
|
|
|
return GETDNS_RETURN_GOOD;
|
|
|
|
}
|
2014-10-10 04:14:01 -05:00
|
|
|
|
2014-02-04 23:01:55 -06:00
|
|
|
static void
|
register only a single poll_t with libuv
Most of the time we only need a read _or_ a write callback registered
with libuv - for example, on a UDP request a write callback is
registered, when executed the write callback performs the write,
deregisters itself, and registers a read callback.
However there is one case where getdns registers both read and write
callbacks: when a backlog of TCP requests is going to the same upstream
resolver, we use a single fd and queue the requests. In this instance we
want to listen for both read (to get responses for requests we've
already sent) and write (to continue to send our pending requests).
libuv, like most event libraries, only allows one callback to be
registered per fd. To get notification for both reads and writes, you
should examine the event flags and have appropriate conditional logic
within the single callback. Today getdns incorrectly tries to register
two separate poll_t with libuv, one for read and one for write - this
results in a crash (internal libuv assertion guaranteeing that only a
single poll_t is registered per fd).
Testing was done by using flamethrower
(https://github.com/DNS-OARC/flamethrower) to toss queries at a program
that embeds getdns.
Note that a higher qps trigger a _different_ getdns/libuv crashing bug
that occurs when the TCP backlog grows so large that requests start to
time out. That crash is not addressed in this PR, and will be more
involved to fix.
2020-06-18 16:31:34 -05:00
|
|
|
getdns_libuv_cb(uv_poll_t *poll, int status, int events)
|
2014-10-10 04:14:01 -05:00
|
|
|
{
|
register only a single poll_t with libuv
Most of the time we only need a read _or_ a write callback registered
with libuv - for example, on a UDP request a write callback is
registered, when executed the write callback performs the write,
deregisters itself, and registers a read callback.
However there is one case where getdns registers both read and write
callbacks: when a backlog of TCP requests is going to the same upstream
resolver, we use a single fd and queue the requests. In this instance we
want to listen for both read (to get responses for requests we've
already sent) and write (to continue to send our pending requests).
libuv, like most event libraries, only allows one callback to be
registered per fd. To get notification for both reads and writes, you
should examine the event flags and have appropriate conditional logic
within the single callback. Today getdns incorrectly tries to register
two separate poll_t with libuv, one for read and one for write - this
results in a crash (internal libuv assertion guaranteeing that only a
single poll_t is registered per fd).
Testing was done by using flamethrower
(https://github.com/DNS-OARC/flamethrower) to toss queries at a program
that embeds getdns.
Note that a higher qps trigger a _different_ getdns/libuv crashing bug
that occurs when the TCP backlog grows so large that requests start to
time out. That crash is not addressed in this PR, and will be more
involved to fix.
2020-06-18 16:31:34 -05:00
|
|
|
getdns_eventloop_event *el_ev = (getdns_eventloop_event *)poll->data;
|
2014-02-04 23:01:55 -06:00
|
|
|
|
2020-09-10 09:59:12 -05:00
|
|
|
if (status == 0) {
|
|
|
|
if (events & UV_READABLE) {
|
|
|
|
assert(el_ev->read_cb);
|
|
|
|
DEBUG_UV("enter libuv_read_cb(el_ev = %p, el_ev->ev = %p)\n"
|
|
|
|
, el_ev, el_ev->ev);
|
|
|
|
el_ev->read_cb(el_ev->userarg);
|
|
|
|
DEBUG_UV("exit libuv_read_cb(el_ev = %p, el_ev->ev = %p)\n"
|
|
|
|
, el_ev, el_ev->ev);
|
|
|
|
} else if (events & UV_WRITABLE) {
|
|
|
|
assert(el_ev->write_cb);
|
|
|
|
DEBUG_UV("enter libuv_write_cb(el_ev = %p, el_ev->ev = %p)\n"
|
|
|
|
, el_ev, el_ev->ev);
|
|
|
|
el_ev->write_cb(el_ev->userarg);
|
|
|
|
DEBUG_UV("exit libuv_write_cb(el_ev = %p, el_ev->ev = %p)\n"
|
|
|
|
, el_ev, el_ev->ev);
|
|
|
|
} else {
|
|
|
|
assert(ASSERT_UNREACHABLE);
|
|
|
|
}
|
register only a single poll_t with libuv
Most of the time we only need a read _or_ a write callback registered
with libuv - for example, on a UDP request a write callback is
registered, when executed the write callback performs the write,
deregisters itself, and registers a read callback.
However there is one case where getdns registers both read and write
callbacks: when a backlog of TCP requests is going to the same upstream
resolver, we use a single fd and queue the requests. In this instance we
want to listen for both read (to get responses for requests we've
already sent) and write (to continue to send our pending requests).
libuv, like most event libraries, only allows one callback to be
registered per fd. To get notification for both reads and writes, you
should examine the event flags and have appropriate conditional logic
within the single callback. Today getdns incorrectly tries to register
two separate poll_t with libuv, one for read and one for write - this
results in a crash (internal libuv assertion guaranteeing that only a
single poll_t is registered per fd).
Testing was done by using flamethrower
(https://github.com/DNS-OARC/flamethrower) to toss queries at a program
that embeds getdns.
Note that a higher qps trigger a _different_ getdns/libuv crashing bug
that occurs when the TCP backlog grows so large that requests start to
time out. That crash is not addressed in this PR, and will be more
involved to fix.
2020-06-18 16:31:34 -05:00
|
|
|
}
|
2014-10-10 07:48:52 -05:00
|
|
|
}
|
|
|
|
|
2014-10-10 04:14:01 -05:00
|
|
|
static void
|
2014-10-31 08:17:30 -05:00
|
|
|
#ifdef HAVE_NEW_UV_TIMER_CB
|
|
|
|
getdns_libuv_timeout_cb(uv_timer_t *timer)
|
|
|
|
#else
|
2014-10-10 04:14:01 -05:00
|
|
|
getdns_libuv_timeout_cb(uv_timer_t *timer, int status)
|
2014-10-31 08:17:30 -05:00
|
|
|
#endif
|
2014-10-10 04:14:01 -05:00
|
|
|
{
|
|
|
|
getdns_eventloop_event *el_ev = (getdns_eventloop_event *)timer->data;
|
2017-09-14 09:43:10 -05:00
|
|
|
#ifndef HAVE_NEW_UV_TIMER_CB
|
2021-06-03 13:45:55 -05:00
|
|
|
(void)status; /* unused parameter */
|
2017-09-14 09:43:10 -05:00
|
|
|
#endif
|
2014-10-10 04:14:01 -05:00
|
|
|
assert(el_ev->timeout_cb);
|
2014-10-15 03:47:36 -05:00
|
|
|
DEBUG_UV("enter libuv_timeout_cb(el_ev = %p, el_ev->ev = %p)\n"
|
|
|
|
, el_ev, el_ev->ev);
|
2014-10-10 04:14:01 -05:00
|
|
|
el_ev->timeout_cb(el_ev->userarg);
|
2014-10-15 03:47:36 -05:00
|
|
|
DEBUG_UV("exit libuv_timeout_cb(el_ev = %p, el_ev->ev = %p)\n"
|
|
|
|
, el_ev, el_ev->ev);
|
2014-02-21 17:42:04 -06:00
|
|
|
}
|
|
|
|
|
2014-02-04 23:01:55 -06:00
|
|
|
static getdns_return_t
|
2014-10-10 07:48:52 -05:00
|
|
|
getdns_libuv_schedule(getdns_eventloop *loop,
|
2014-10-10 04:14:01 -05:00
|
|
|
int fd, uint64_t timeout, getdns_eventloop_event *el_ev)
|
|
|
|
{
|
|
|
|
getdns_libuv *ext = (getdns_libuv *)loop;
|
|
|
|
poll_timer *my_ev;
|
|
|
|
uv_poll_t *my_poll;
|
|
|
|
uv_timer_t *my_timer;
|
|
|
|
|
2014-10-10 07:48:52 -05:00
|
|
|
assert(el_ev);
|
|
|
|
assert(!(el_ev->read_cb || el_ev->write_cb) || fd >= 0);
|
|
|
|
assert( el_ev->read_cb || el_ev->write_cb || el_ev->timeout_cb);
|
2014-10-10 04:14:01 -05:00
|
|
|
|
2014-10-15 03:47:36 -05:00
|
|
|
DEBUG_UV("enter libuv_schedule(el_ev = %p, el_ev->ev = %p)\n"
|
|
|
|
, el_ev, el_ev->ev);
|
2014-10-14 18:13:39 -05:00
|
|
|
|
2014-10-10 04:14:01 -05:00
|
|
|
if (!(my_ev = GETDNS_MALLOC(ext->mf, poll_timer)))
|
|
|
|
return GETDNS_RETURN_MEMORY_ERROR;
|
|
|
|
|
2014-10-15 03:47:36 -05:00
|
|
|
my_ev->to_close = 0;
|
|
|
|
my_ev->mf = ext->mf;
|
2014-10-10 04:14:01 -05:00
|
|
|
el_ev->ev = my_ev;
|
register only a single poll_t with libuv
Most of the time we only need a read _or_ a write callback registered
with libuv - for example, on a UDP request a write callback is
registered, when executed the write callback performs the write,
deregisters itself, and registers a read callback.
However there is one case where getdns registers both read and write
callbacks: when a backlog of TCP requests is going to the same upstream
resolver, we use a single fd and queue the requests. In this instance we
want to listen for both read (to get responses for requests we've
already sent) and write (to continue to send our pending requests).
libuv, like most event libraries, only allows one callback to be
registered per fd. To get notification for both reads and writes, you
should examine the event flags and have appropriate conditional logic
within the single callback. Today getdns incorrectly tries to register
two separate poll_t with libuv, one for read and one for write - this
results in a crash (internal libuv assertion guaranteeing that only a
single poll_t is registered per fd).
Testing was done by using flamethrower
(https://github.com/DNS-OARC/flamethrower) to toss queries at a program
that embeds getdns.
Note that a higher qps trigger a _different_ getdns/libuv crashing bug
that occurs when the TCP backlog grows so large that requests start to
time out. That crash is not addressed in this PR, and will be more
involved to fix.
2020-06-18 16:31:34 -05:00
|
|
|
|
|
|
|
if (el_ev->read_cb || el_ev->write_cb) {
|
|
|
|
my_poll = &my_ev->poll;
|
2014-10-10 07:48:52 -05:00
|
|
|
my_poll->data = el_ev;
|
2014-10-15 03:47:36 -05:00
|
|
|
uv_poll_init(ext->loop, my_poll, fd);
|
register only a single poll_t with libuv
Most of the time we only need a read _or_ a write callback registered
with libuv - for example, on a UDP request a write callback is
registered, when executed the write callback performs the write,
deregisters itself, and registers a read callback.
However there is one case where getdns registers both read and write
callbacks: when a backlog of TCP requests is going to the same upstream
resolver, we use a single fd and queue the requests. In this instance we
want to listen for both read (to get responses for requests we've
already sent) and write (to continue to send our pending requests).
libuv, like most event libraries, only allows one callback to be
registered per fd. To get notification for both reads and writes, you
should examine the event flags and have appropriate conditional logic
within the single callback. Today getdns incorrectly tries to register
two separate poll_t with libuv, one for read and one for write - this
results in a crash (internal libuv assertion guaranteeing that only a
single poll_t is registered per fd).
Testing was done by using flamethrower
(https://github.com/DNS-OARC/flamethrower) to toss queries at a program
that embeds getdns.
Note that a higher qps trigger a _different_ getdns/libuv crashing bug
that occurs when the TCP backlog grows so large that requests start to
time out. That crash is not addressed in this PR, and will be more
involved to fix.
2020-06-18 16:31:34 -05:00
|
|
|
int events =
|
|
|
|
(el_ev->read_cb ? UV_READABLE : 0) |
|
|
|
|
(el_ev->write_cb ? UV_WRITABLE : 0);
|
|
|
|
uv_poll_start(my_poll, events, getdns_libuv_cb);
|
2014-10-10 07:48:52 -05:00
|
|
|
}
|
2014-10-10 04:14:01 -05:00
|
|
|
if (el_ev->timeout_cb) {
|
|
|
|
my_timer = &my_ev->timer;
|
|
|
|
my_timer->data = el_ev;
|
2014-10-15 03:47:36 -05:00
|
|
|
uv_timer_init(ext->loop, my_timer);
|
2014-10-10 04:14:01 -05:00
|
|
|
uv_timer_start(my_timer, getdns_libuv_timeout_cb, timeout, 0);
|
|
|
|
}
|
2014-10-15 03:47:36 -05:00
|
|
|
DEBUG_UV("exit libuv_schedule(el_ev = %p, el_ev->ev = %p)\n"
|
|
|
|
, el_ev, el_ev->ev);
|
2014-10-10 04:14:01 -05:00
|
|
|
return GETDNS_RETURN_GOOD;
|
2014-02-04 23:01:55 -06:00
|
|
|
}
|
|
|
|
|
2014-10-10 07:48:52 -05:00
|
|
|
getdns_return_t
|
|
|
|
getdns_extension_set_libuv_loop(getdns_context *context, uv_loop_t *loop)
|
2014-10-06 13:23:50 -05:00
|
|
|
{
|
2014-10-10 07:48:52 -05:00
|
|
|
static getdns_eventloop_vmt getdns_libuv_vmt = {
|
|
|
|
getdns_libuv_cleanup,
|
|
|
|
getdns_libuv_schedule,
|
|
|
|
getdns_libuv_clear,
|
|
|
|
getdns_libuv_run,
|
|
|
|
getdns_libuv_run_once
|
|
|
|
};
|
|
|
|
getdns_libuv *ext;
|
2014-02-04 23:01:55 -06:00
|
|
|
|
2014-10-10 07:48:52 -05:00
|
|
|
if (!context)
|
|
|
|
return GETDNS_RETURN_BAD_CONTEXT;
|
|
|
|
if (!loop)
|
|
|
|
return GETDNS_RETURN_INVALID_PARAMETER;
|
2014-10-10 04:14:01 -05:00
|
|
|
|
2014-10-10 07:48:52 -05:00
|
|
|
ext = GETDNS_MALLOC(*priv_getdns_context_mf(context), getdns_libuv);
|
2014-10-14 18:13:39 -05:00
|
|
|
if (!ext)
|
|
|
|
return GETDNS_RETURN_MEMORY_ERROR;
|
2014-10-10 07:48:52 -05:00
|
|
|
ext->vmt = &getdns_libuv_vmt;
|
|
|
|
ext->loop = loop;
|
|
|
|
ext->mf = *priv_getdns_context_mf(context);
|
2014-02-04 23:01:55 -06:00
|
|
|
|
2014-10-14 18:13:39 -05:00
|
|
|
return getdns_context_set_eventloop(context, (getdns_eventloop *)ext);
|
2014-10-10 07:48:52 -05:00
|
|
|
}
|