2014-02-04 23:01:55 -06:00
|
|
|
/**
|
|
|
|
* \file
|
|
|
|
* \brief Public interfaces to getdns, include in your application to use getdns API.
|
|
|
|
*
|
|
|
|
* This source was taken from the original pseudo-implementation by
|
|
|
|
* Paul Hoffman.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
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.
|
|
|
|
* * Neither the name of the <organization> nor the
|
|
|
|
* 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-02-05 20:46:21 -06:00
|
|
|
#include <getdns/getdns_ext_libuv.h>
|
2014-02-04 23:01:55 -06:00
|
|
|
#include <sys/time.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <uv.h>
|
|
|
|
|
|
|
|
#define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
|
|
|
|
|
|
|
|
/* extension info */
|
|
|
|
struct getdns_libuv_data {
|
|
|
|
uv_loop_t* loop;
|
|
|
|
uv_poll_t* poll_handle;
|
2014-02-21 17:42:04 -06:00
|
|
|
uint8_t polling;
|
2014-02-04 23:01:55 -06:00
|
|
|
};
|
|
|
|
|
2014-02-21 17:42:04 -06:00
|
|
|
static void request_count_changed(uint32_t request_count, struct getdns_libuv_data *uv_data);
|
|
|
|
|
2014-02-04 23:01:55 -06:00
|
|
|
/* lib event callbacks */
|
|
|
|
static void
|
|
|
|
getdns_libuv_cb(uv_poll_t* handle, int status, int events) {
|
|
|
|
struct getdns_context* context = (struct getdns_context*) handle->data;
|
|
|
|
getdns_context_process_async(context);
|
2014-02-21 17:42:04 -06:00
|
|
|
uint32_t rc = getdns_context_get_num_pending_requests(context, NULL);
|
|
|
|
struct getdns_libuv_data* uv_data =
|
|
|
|
(struct getdns_libuv_data*) getdns_context_get_extension_data(context);
|
|
|
|
request_count_changed(rc, uv_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
request_count_changed(uint32_t request_count, struct getdns_libuv_data *uv_data) {
|
|
|
|
if (request_count > 0 && uv_data->polling == 0) {
|
|
|
|
uv_poll_start(uv_data->poll_handle, UV_READABLE, getdns_libuv_cb);
|
|
|
|
uv_data->polling = 1;
|
|
|
|
} else if (request_count == 0 && uv_data->polling == 1) {
|
|
|
|
uv_poll_stop(uv_data->poll_handle);
|
|
|
|
uv_data->polling = 0;
|
|
|
|
}
|
2014-02-04 23:01:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
getdns_libuv_timeout_cb(uv_timer_t* handle, int status) {
|
|
|
|
getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) handle->data;
|
|
|
|
timeout_data->callback(timeout_data->userarg);
|
2014-02-21 17:42:04 -06:00
|
|
|
uint32_t rc = getdns_context_get_num_pending_requests(timeout_data->context, NULL);
|
|
|
|
struct getdns_libuv_data* uv_data =
|
|
|
|
(struct getdns_libuv_data*) getdns_context_get_extension_data(timeout_data->context);
|
|
|
|
request_count_changed(rc, uv_data);
|
2014-02-04 23:01:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
getdns_libuv_close_cb(uv_handle_t* handle) {
|
|
|
|
if (handle) {
|
|
|
|
free(handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* getdns extension functions */
|
2014-02-21 17:42:04 -06:00
|
|
|
static getdns_return_t
|
|
|
|
getdns_libuv_request_count_changed(struct getdns_context* context,
|
|
|
|
uint32_t request_count, void* eventloop_data) {
|
|
|
|
struct getdns_libuv_data *edata = (struct getdns_libuv_data*) eventloop_data;
|
|
|
|
request_count_changed(request_count, edata);
|
|
|
|
return GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
|
2014-02-04 23:01:55 -06:00
|
|
|
static getdns_return_t
|
|
|
|
getdns_libuv_cleanup(struct getdns_context* context, void* data) {
|
|
|
|
struct getdns_libuv_data *uv_data = (struct getdns_libuv_data*) data;
|
|
|
|
uv_poll_stop(uv_data->poll_handle);
|
|
|
|
uv_close((uv_handle_t*) uv_data->poll_handle, getdns_libuv_close_cb);
|
|
|
|
/* handle itself gets cleaned up in close_cb */
|
|
|
|
free(uv_data);
|
|
|
|
return GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
static getdns_return_t
|
|
|
|
getdns_libuv_schedule_timeout(struct getdns_context* context,
|
|
|
|
void* eventloop_data, uint16_t timeout,
|
|
|
|
getdns_timeout_data_t* timeout_data,
|
|
|
|
void** eventloop_timer) {
|
|
|
|
|
|
|
|
uv_timer_t *timer;
|
|
|
|
struct getdns_libuv_data* uv_data = (struct getdns_libuv_data*) eventloop_data;
|
|
|
|
|
|
|
|
timer = (uv_timer_t*) malloc(sizeof(uv_timer_t));
|
|
|
|
timer->data = timeout_data;
|
|
|
|
uv_timer_init(uv_data->loop, timer);
|
|
|
|
uv_timer_start(timer, getdns_libuv_timeout_cb, timeout, 0);
|
|
|
|
|
|
|
|
*eventloop_timer = timer;
|
|
|
|
return GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
static getdns_return_t
|
|
|
|
getdns_libuv_clear_timeout(struct getdns_context* context,
|
2014-02-05 23:10:35 -06:00
|
|
|
void* eventloop_data, void* eventloop_timer) {
|
2014-02-04 23:01:55 -06:00
|
|
|
uv_timer_t* timer = (uv_timer_t*) eventloop_timer;
|
|
|
|
uv_timer_stop(timer);
|
|
|
|
uv_close((uv_handle_t*) timer, getdns_libuv_close_cb);
|
|
|
|
return GETDNS_RETURN_GOOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static getdns_eventloop_extension LIBUV_EXT = {
|
|
|
|
getdns_libuv_cleanup,
|
|
|
|
getdns_libuv_schedule_timeout,
|
2014-02-21 17:42:04 -06:00
|
|
|
getdns_libuv_clear_timeout,
|
|
|
|
getdns_libuv_request_count_changed
|
2014-02-04 23:01:55 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* getdns_extension_set_libuv_loop
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
getdns_return_t
|
|
|
|
getdns_extension_set_libuv_loop(struct getdns_context *context,
|
|
|
|
struct uv_loop_s *uv_loop)
|
|
|
|
{
|
|
|
|
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
|
|
|
RETURN_IF_NULL(uv_loop, GETDNS_RETURN_INVALID_PARAMETER);
|
|
|
|
/* TODO: cleanup current extension base */
|
|
|
|
getdns_return_t r = getdns_extension_detach_eventloop(context);
|
|
|
|
if (r != GETDNS_RETURN_GOOD) {
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
struct getdns_libuv_data* uv_data = (struct getdns_libuv_data*) malloc(sizeof(struct getdns_libuv_data));
|
|
|
|
if (!uv_data) {
|
|
|
|
return GETDNS_RETURN_MEMORY_ERROR;
|
|
|
|
}
|
|
|
|
int fd = getdns_context_fd(context);
|
|
|
|
uv_data->poll_handle = (uv_poll_t*) malloc(sizeof(uv_poll_t));
|
|
|
|
uv_poll_init(uv_loop, uv_data->poll_handle, fd);
|
|
|
|
uv_data->poll_handle->data = context;
|
|
|
|
uv_data->loop = uv_loop;
|
2014-02-21 17:42:04 -06:00
|
|
|
uv_data->polling = 0;
|
2014-02-04 23:01:55 -06:00
|
|
|
return getdns_extension_set_eventloop(context, &LIBUV_EXT, uv_data);
|
|
|
|
} /* getdns_extension_set_libuv_loop */
|