eventloop separate from context & libmini_event

This commit is contained in:
Willem Toorop 2014-10-08 15:42:33 +02:00
parent a21895d145
commit 1f203485e2
9 changed files with 537 additions and 398 deletions

View File

@ -78,7 +78,8 @@ EXTENSION_LIBUV_LDFLAGS=@EXTENSION_LIBUV_LDFLAGS@
GETDNS_OBJ=sync.lo context.lo list.lo dict.lo convert.lo general.lo \
hostname.lo service.lo request-internal.lo util-internal.lo \
getdns_error.lo rr-dict.lo dnssec.lo const-info.lo \
ub_timed_resolve.lo stub.lo
ub_timed_resolve.lo stub.lo \
libmini_event.lo
GLDNS_OBJ=keyraw.lo gbuffer.lo wire2str.lo parse.lo parseutil.lo rrdef.lo \
str2wire.lo
@ -97,7 +98,7 @@ UTIL_OBJ=mini_event.lo rbtree.lo
.c.lo:
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@
$(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ):
$(GLDNS_OBJ) $(COMPAT_OBJ) $(UTIL_OBJ) libmini_event.lo:
@:
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $< -o $@
@ -193,10 +194,11 @@ configure.status: configure
depend:
(cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new )
(cd $(srcdir) ; gcc -MM -I. gldns/*.c compat/*.c util/*.c | \
(cd $(srcdir) ; gcc -MM -I. gldns/*.c compat/*.c util/*.c extension/libmini_event.c| \
sed -e 's?gldns/?$$(srcdir)/gldns/?g' \
-e 's?compat/?$$(srcdir)/compat/?g' \
-e 's?util/?$$(srcdir)/util/?g' \
-e 's?extension/?$$(srcdir)/extension/?g' \
-e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' >> Makefile.in.new )
(cd $(srcdir) ; diff Makefile.in.new Makefile.in && rm Makefile.in.new \
|| mv Makefile.in.new Makefile.in )
@ -204,7 +206,7 @@ depend:
.PHONY: clean test example
FORCE:
# Dependencies for gldns and compatibility functions
# Dependencies for gldns, utils, the mini_event extension and compat functions
gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c config.h $(srcdir)/gldns/gbuffer.h
keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c config.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h
parse.lo parse.o: $(srcdir)/gldns/parse.c config.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h \
@ -221,3 +223,6 @@ mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/
$(srcdir)/util/fptr_wlist.h
rbtree.lo rbtree.o: $(srcdir)/util/rbtree.c config.h $(srcdir)/util/log.h $(srcdir)/util/fptr_wlist.h \
$(srcdir)/util/rbtree.h
libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c config.h \
$(srcdir)/extension/libmini_event.h types-internal.h getdns/getdns.h \
getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h

View File

@ -517,129 +517,6 @@ create_ldns_rbtree(getdns_context * context,
return result;
}
/******************************************************************************
******************************************************************************
*****
***** Start of mini_event extension
***** TODO: Move to own source file
*****/
/** call timeouts handlers, and return how long to wait for next one or -1 */
void getdns_handle_timeouts(struct getdns_event_base* base,
struct timeval* now, struct timeval* wait);
/** call select and callbacks for that */
int getdns_handle_select(struct getdns_event_base* base, struct timeval* wait);
int
getdns_mini_event_settime(getdns_mini_event_extension *e)
{
if (gettimeofday(e->base->time_tv, NULL) < 0)
return -1;
*e->base->time_secs = (time_t)e->base->time_tv->tv_sec;
return 0;
}
static void
getdns_mini_event_timeout_cb(int fd, short bits, void *arg)
{
getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*)arg;
timeout_data->callback(timeout_data->userarg);
}
static getdns_return_t
getdns_mini_event_schedule_timeout(getdns_context *context, void *ext,
uint64_t timeout, getdns_timeout_data_t *timeout_data)
{
getdns_mini_event_extension *e = (getdns_mini_event_extension *)ext;
struct timeval tv;
struct getdns_event *ev;
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
ev = GETDNS_MALLOC(context->mf, struct getdns_event);
timeout_data->extension_timer = ev;
getdns_event_set(ev, -1, EV_TIMEOUT, getdns_mini_event_timeout_cb,
timeout_data);
(void) getdns_mini_event_settime(e);
(void) getdns_event_base_set(e->base, ev);
(void) getdns_event_add(ev, &tv);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_mini_event_clear_timeout(getdns_context *context, void *ext, void *timer)
{
/* getdns_mini_event_extension *e = (getdns_mini_event_extension *)ext;
*/
struct getdns_event *ev = (struct getdns_event *)timer;
(void) getdns_event_del(ev);
GETDNS_FREE(context->mf, ev);
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_mini_event_request_count_changed(getdns_context *context,
uint32_t request_count, void *ext)
{
getdns_mini_event_extension *e = (getdns_mini_event_extension *)ext;
if (request_count == 0)
(void) getdns_event_del(&e->ub_event);
return GETDNS_RETURN_GOOD;
}
static void
getdns_mini_event_cb(int fd, short bits, void *arg)
{
getdns_context *context = (getdns_context *)arg;
if (getdns_context_process_async(context))
return;
getdns_mini_event_request_count_changed(context,
getdns_context_get_num_pending_requests(context, NULL),
context->extension_data);
}
static getdns_return_t
getdns_mini_event_cleanup(getdns_context *context, void *ext);
getdns_return_t
getdns_mini_event_extension_init(getdns_mini_event_extension *e)
{
e->base = getdns_event_init(&e->time_secs, &e->time_tv);
if (!e->base)
return GETDNS_RETURN_MEMORY_ERROR;
e->ub_event.ev_fd = -1;
e->ext.cleanup_data = getdns_mini_event_cleanup;
e->ext.schedule_timeout = getdns_mini_event_schedule_timeout;
e->ext.clear_timeout = getdns_mini_event_clear_timeout;
e->ext.request_count_changed = getdns_mini_event_request_count_changed;
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_mini_event_cleanup(getdns_context *context, void *ext)
{
getdns_mini_event_extension *e = (getdns_mini_event_extension *)ext;
if (e->ub_event.ev_fd != -1) {
getdns_event_del(&e->ub_event);
e->ub_event.ev_fd = -1;
}
/* TODO: Cleanup all synchronous events? Maybe not... */
getdns_event_base_free(e->base);
return GETDNS_RETURN_GOOD;
}
/*****
***** End of mini_event extension
*****
*****************************************************************************
*****************************************************************************/
/*
* getdns_context_create
*
@ -655,99 +532,95 @@ getdns_context_create_with_extended_memory_functions(
void (*free)(void *userarg, void *)
)
{
struct getdns_context *result = NULL;
mf_union mf;
getdns_return_t r;
struct getdns_context *result = NULL;
mf_union mf;
if (!context || !malloc || !realloc || !free)
return GETDNS_RETURN_INVALID_PARAMETER;
if (!context || !malloc || !realloc || !free)
return GETDNS_RETURN_INVALID_PARAMETER;
/** default init **/
mf.ext.malloc = malloc;
result = userarg == MF_PLAIN
? (*mf.pln.malloc)( sizeof(struct getdns_context))
: (*mf.ext.malloc)(userarg, sizeof(struct getdns_context));
if (!result) {
return GETDNS_RETURN_GENERIC_ERROR;
}
result->processing = 0;
result->destroying = 0;
result->my_mf.mf_arg = userarg;
result->my_mf.mf.ext.malloc = malloc;
result->my_mf.mf.ext.realloc = realloc;
result->my_mf.mf.ext.free = free;
/** default init **/
mf.ext.malloc = malloc;
result = userarg == MF_PLAIN
? (*mf.pln.malloc)( sizeof(struct getdns_context))
: (*mf.ext.malloc)(userarg, sizeof(struct getdns_context));
result->update_callback = NULL;
if (!result)
return GETDNS_RETURN_MEMORY_ERROR;
result->mf.mf_arg = userarg;
result->mf.mf.ext.malloc = malloc;
result->mf.mf.ext.realloc = realloc;
result->mf.mf.ext.free = free;
result->processing = 0;
result->destroying = 0;
result->my_mf.mf_arg = userarg;
result->my_mf.mf.ext.malloc = malloc;
result->my_mf.mf.ext.realloc = realloc;
result->my_mf.mf.ext.free = free;
result->resolution_type_set = 0;
result->update_callback = NULL;
result->outbound_requests = create_ldns_rbtree(result, transaction_id_cmp);
result->local_hosts = create_ldns_rbtree(result, local_host_cmp);
result->mf.mf_arg = userarg;
result->mf.mf.ext.malloc = malloc;
result->mf.mf.ext.realloc = realloc;
result->mf.mf.ext.free = free;
result->resolution_type_set = 0;
result->resolution_type = GETDNS_RESOLUTION_RECURSING;
if(create_default_namespaces(result) != GETDNS_RETURN_GOOD) {
getdns_context_destroy(result);
return GETDNS_RETURN_GENERIC_ERROR;
}
result->outbound_requests = create_ldns_rbtree(result, transaction_id_cmp);
result->local_hosts = create_ldns_rbtree(result, local_host_cmp);
result->timeout = 5000;
result->follow_redirects = GETDNS_REDIRECTS_FOLLOW;
result->dns_root_servers = create_default_root_servers();
result->append_name = GETDNS_APPEND_NAME_ALWAYS;
result->suffix = NULL;
if (!result->outbound_requests || !result->local_hosts) {
r = GETDNS_RETURN_MEMORY_ERROR;
goto error;
}
result->dnssec_trust_anchors = NULL;
result->resolution_type = GETDNS_RESOLUTION_RECURSING;
if ((r = create_default_namespaces(result)))
goto error;
result->edns_extended_rcode = 0;
result->edns_version = 0;
result->edns_do_bit = 1;
result->timeout = 5000;
result->follow_redirects = GETDNS_REDIRECTS_FOLLOW;
result->dns_root_servers = create_default_root_servers();
result->append_name = GETDNS_APPEND_NAME_ALWAYS;
result->suffix = NULL;
result->extension = &result->mini_event_extension.ext;
result->extension_data = (void *)&result->mini_event_extension;
if (getdns_mini_event_extension_init(&result->mini_event_extension))
return GETDNS_RETURN_GENERIC_ERROR;
result->dnssec_trust_anchors = NULL;
result->edns_extended_rcode = 0;
result->edns_version = 0;
result->edns_do_bit = 1;
result->extension = &result->mini_event.loop;
if ((r = getdns_mini_event_init(result, &result->mini_event)))
goto error;
result->fchg_resolvconf = NULL;
result->fchg_hosts = NULL;
if (set_from_os) {
if (GETDNS_RETURN_GOOD != set_os_defaults(result)) {
getdns_context_destroy(result);
return GETDNS_RETURN_GENERIC_ERROR;
}
}
result->dnssec_allowed_skew = 0;
result->edns_maximum_udp_payload_size = 512;
result->dns_transport = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP;
result->limit_outstanding_queries = 0;
result->has_ta = priv_getdns_parse_ta_file(NULL, NULL);
result->return_dnssec_status = GETDNS_EXTENSION_FALSE;
if (!result->outbound_requests ||
!result->local_hosts) {
getdns_context_destroy(result);
return GETDNS_RETURN_MEMORY_ERROR;
}
/* unbound context is initialized here */
result->unbound_ctx = NULL;
if (GETDNS_RETURN_GOOD != rebuild_ub_ctx(result)) {
getdns_context_destroy(result);
return GETDNS_RETURN_GENERIC_ERROR;
}
/* ldns context is initialised to NULL here and rebuilt later if needed */
result->ldns_res = NULL;
result->fchg_hosts = NULL;
if(create_local_hosts(result) != GETDNS_RETURN_GOOD) {
getdns_context_destroy(result);
return GETDNS_RETURN_GENERIC_ERROR;
}
if (set_from_os && (r = set_os_defaults(result)))
goto error;
*context = result;
result->dnssec_allowed_skew = 0;
result->edns_maximum_udp_payload_size = 512;
result->dns_transport = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP;
result->limit_outstanding_queries = 0;
result->has_ta = priv_getdns_parse_ta_file(NULL, NULL);
result->return_dnssec_status = GETDNS_EXTENSION_FALSE;
return GETDNS_RETURN_GOOD;
/* unbound context is initialized here */
result->unbound_ctx = NULL;
if ((r = rebuild_ub_ctx(result)))
goto error;
/* ldns context is initialised to NULL here and rebuilt later if needed */
result->ldns_res = NULL;
if ((r = create_local_hosts(result)))
goto error;
*context = result;
return GETDNS_RETURN_GOOD;
error:
getdns_context_destroy(result);
return r;
} /* getdns_context_create_with_extended_memory_functions */
/*
@ -805,7 +678,7 @@ getdns_context_destroy(struct getdns_context *context)
}
context->destroying = 1;
cancel_outstanding_requests(context, 1);
getdns_extension_detach_eventloop(context);
getdns_context_detach_eventloop(context);
if (context->namespaces)
GETDNS_FREE(context->my_mf, context->namespaces);
@ -878,6 +751,33 @@ set_ub_number_opt(struct getdns_context *ctx, char *opt, uint16_t value)
set_ub_string_opt(ctx, opt, buffer);
}
static void
getdns_context_request_count_changed(getdns_context *context, uint32_t prev_rc)
{
if ((!prev_rc && !context->outbound_requests->count) ||
( prev_rc && context->outbound_requests->count))
return;
if (context->outbound_requests->count)
context->extension->functions->schedule_read(
context->extension, ub_fd(context->unbound_ctx),
TIMEOUT_FOREVER, &context->ub_event);
else
context->extension->functions->clear_read(
context->extension, &context->ub_event);
}
static void
getdns_context_ub_read_cb(void *userarg)
{
getdns_context *context = (getdns_context *)userarg;
int32_t prev_rc = context->outbound_requests->count;
if (getdns_context_process_async(context)) return;
(void) getdns_context_get_num_pending_requests(context, NULL);
getdns_context_request_count_changed(context, prev_rc);
}
static getdns_return_t
rebuild_ub_ctx(struct getdns_context* context) {
if (context->unbound_ctx != NULL) {
@ -903,14 +803,11 @@ rebuild_ub_ctx(struct getdns_context* context) {
(void) ub_ctx_add_ta_file(
context->unbound_ctx, TRUST_ANCHOR_FILE);
}
if (context->extension == (void *)&context->mini_event_extension.ext) {
getdns_mini_event_extension *e =&context->mini_event_extension;
getdns_event_set(&e->ub_event, getdns_context_fd(context),
EV_READ, getdns_mini_event_cb, context);
(void) getdns_event_base_set(e->base, &e->ub_event);
(void) getdns_event_add(&e->ub_event, NULL);
}
context->ub_event.userarg = context;
context->ub_event.read_cb = getdns_context_ub_read_cb;
context->ub_event.timeout_cb = NULL;
return GETDNS_RETURN_GOOD;
}
@ -1597,25 +1494,6 @@ getdns_context_cancel_request(struct getdns_context *context,
return GETDNS_RETURN_GOOD;
}
/*
* getdns_cancel_callback
*
*/
getdns_return_t
getdns_cancel_callback(struct getdns_context *context,
getdns_transaction_t transaction_id)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
context->processing = 1;
getdns_return_t r = getdns_context_cancel_request(context, transaction_id, 1);
if (context->extension) {
context->extension->request_count_changed(context,
context->outbound_requests->count, context->extension_data);
}
context->processing = 0;
return r;
} /* getdns_cancel_callback */
static getdns_return_t
ub_setup_stub(struct ub_ctx *ctx, getdns_upstreams *upstreams)
{
@ -1815,47 +1693,54 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
getdns_return_t
getdns_context_track_outbound_request(getdns_dns_req * req)
{
if (!req) {
return GETDNS_RETURN_GENERIC_ERROR;
}
struct getdns_context *context = req->context;
ldns_rbnode_t *node = GETDNS_MALLOC(context->my_mf, ldns_rbnode_t);
if (!node) {
return GETDNS_RETURN_GENERIC_ERROR;
}
node->key = &(req->trans_id);
node->data = req;
if (!ldns_rbtree_insert(context->outbound_requests, node)) {
/* free the node */
GETDNS_FREE(context->my_mf, node);
return GETDNS_RETURN_GENERIC_ERROR;
}
if (context->extension) {
context->extension->request_count_changed(context,
context->outbound_requests->count, context->extension_data);
}
return GETDNS_RETURN_GOOD;
uint32_t prev_rc;
ldns_rbnode_t *node;
if (!req)
return GETDNS_RETURN_INVALID_PARAMETER;
prev_rc = req->context->outbound_requests->count;
if (!(node = GETDNS_MALLOC(req->context->my_mf, ldns_rbnode_t)))
return GETDNS_RETURN_MEMORY_ERROR;
node->key = &(req->trans_id);
node->data = req;
if (! ldns_rbtree_insert(req->context->outbound_requests, node)) {
GETDNS_FREE(req->context->my_mf, node);
return GETDNS_RETURN_GENERIC_ERROR;
}
getdns_context_request_count_changed(req->context, prev_rc);
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_context_clear_outbound_request(getdns_dns_req * req)
{
if (!req) {
return GETDNS_RETURN_GENERIC_ERROR;
}
struct getdns_context *context = req->context;
ldns_rbnode_t *node = ldns_rbtree_delete(context->outbound_requests,
&(req->trans_id));
if (node) {
GETDNS_FREE(context->my_mf, node);
}
return GETDNS_RETURN_GOOD;
uint32_t prev_rc;
ldns_rbnode_t *node;
if (!req)
return GETDNS_RETURN_INVALID_PARAMETER;
prev_rc = req->context->outbound_requests->count;
node = ldns_rbtree_delete(
req->context->outbound_requests, &req->trans_id);
if (!node)
return GETDNS_RETURN_GENERIC_ERROR;
GETDNS_FREE(req->context->my_mf, node);
getdns_context_request_count_changed(req->context, prev_rc);
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_context_request_timed_out(struct getdns_dns_req
*req) {
/* Don't use req after callback */
getdns_context* context = req->context;
uint32_t prev_rc = context->outbound_requests->count;
getdns_transaction_t trans_id = req->trans_id;
getdns_callback_t cb = req->user_callback;
void *user_arg = req->user_pointer;
@ -1866,10 +1751,7 @@ getdns_context_request_timed_out(struct getdns_dns_req
context->processing = 1;
cb(context, GETDNS_CALLBACK_TIMEOUT, response, user_arg, trans_id);
context->processing = 0;
if (context->extension) {
context->extension->request_count_changed(context,
context->outbound_requests->count, context->extension_data);
}
getdns_context_request_count_changed(context, prev_rc);
return GETDNS_RETURN_GOOD;
}
@ -1927,17 +1809,13 @@ uint32_t
getdns_context_get_num_pending_requests(struct getdns_context* context,
struct timeval* next_timeout)
{
static struct timeval dummy = { 0, 0 };
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
if (context->outbound_requests->count &&
context->extension == (void *)&context->mini_event_extension.ext &&
getdns_mini_event_settime(&context->mini_event_extension) == 0)
context->extension == &context->mini_event.loop)
getdns_handle_timeouts(
context->mini_event_extension.base,
context->mini_event_extension.base->time_tv,
next_timeout ? next_timeout : &dummy);
getdns_mini_event_handle_timeouts(
&context->mini_event, next_timeout);
return context->outbound_requests->count;
}
@ -1945,7 +1823,6 @@ getdns_context_get_num_pending_requests(struct getdns_context* context,
/* process async reqs */
getdns_return_t getdns_context_process_async(struct getdns_context* context)
{
struct timeval immediately = { 0, 0 };
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
context->processing = 1;
@ -1954,9 +1831,8 @@ getdns_return_t getdns_context_process_async(struct getdns_context* context)
context->processing = 0;
return GETDNS_RETURN_GENERIC_ERROR;
}
if (context->extension == (void *)&context->mini_event_extension.ext
&& getdns_handle_select(context->mini_event_extension.base,
&immediately)) {
if (context->extension == &context->mini_event.loop
&& getdns_mini_event_handle_select(&context->mini_event, NULL)) {
context->processing = 0;
return GETDNS_RETURN_GENERIC_ERROR;
@ -1994,7 +1870,7 @@ cancel_outstanding_requests(struct getdns_context* context, int fire_callback) {
}
getdns_return_t
getdns_extension_detach_eventloop(struct getdns_context* context)
getdns_context_detach_eventloop(struct getdns_context* context)
{
getdns_return_t r = GETDNS_RETURN_GOOD;
@ -2010,73 +1886,64 @@ getdns_extension_detach_eventloop(struct getdns_context* context)
context->processing = 1;
/* cancel all outstanding requests */
cancel_outstanding_requests(context, 1);
r = context->extension->cleanup_data(context,
context->extension_data);
r = context->extension->functions->cleanup(context->extension);
if (r == GETDNS_RETURN_GOOD) {
context->extension = &context->mini_event_extension.ext;
context->extension_data =(void*)&context->mini_event_extension;
r = getdns_mini_event_extension_init(
&context->mini_event_extension);
context->extension = &context->mini_event.loop;
r = getdns_mini_event_init(context, &context->mini_event);
}
context->processing = 0;
return r;
}
getdns_return_t
getdns_extension_set_eventloop(struct getdns_context* context,
getdns_eventloop_extension* extension, void* extension_data)
getdns_context_set_eventloop(struct getdns_context* context, getdns_eventloop* loop)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(extension, GETDNS_RETURN_INVALID_PARAMETER);
getdns_return_t r = getdns_extension_detach_eventloop(context);
if (r != GETDNS_RETURN_GOOD) {
return r;
}
context->extension = extension;
context->extension_data = extension_data;
return GETDNS_RETURN_GOOD;
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(loop , GETDNS_RETURN_INVALID_PARAMETER);
getdns_return_t r = getdns_context_detach_eventloop(context);
if (r != GETDNS_RETURN_GOOD)
return r;
context->extension = loop;
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_context_schedule_timeout(getdns_context* context, uint64_t timeout,
getdns_timeout_callback callback, void* userarg,
getdns_timeout_data_t *timeout_data)
getdns_context_schedule_timeout(getdns_context *context, uint64_t timeout,
getdns_eventloop_callback callback, void *userarg,
getdns_eventloop_event *el_ev)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(context , GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(callback, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(timeout_data, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(el_ev , GETDNS_RETURN_INVALID_PARAMETER);
/* Initialize timeout_data struct */
timeout_data->context = context;
timeout_data->callback = callback;
timeout_data->userarg = userarg;
timeout_data->extension_timer = NULL;
/* Initialize eev_data struct */
el_ev->userarg = userarg;
el_ev->read_cb = NULL;
el_ev->timeout_cb = callback;
el_ev->ev = NULL;
return context->extension->schedule_timeout(context,
context->extension_data, timeout, timeout_data);
return context->extension->functions->schedule_timeout(
context->extension, timeout, el_ev);
}
getdns_return_t
getdns_context_clear_timeout(getdns_context* context,
getdns_timeout_data_t *timeout_data)
getdns_eventloop_event *el_ev)
{
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(timeout_data, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(timeout_data->context, GETDNS_RETURN_GOOD);
RETURN_IF_NULL(el_ev, GETDNS_RETURN_INVALID_PARAMETER);
RETURN_IF_NULL(el_ev->timeout_cb, GETDNS_RETURN_GOOD);
context->extension->clear_timeout(context,
context->extension_data, timeout_data->extension_timer);
timeout_data->context = NULL;
if (el_ev->timeout_cb) {
context->extension->functions->clear_timeout(
context->extension, el_ev);
el_ev->timeout_cb = NULL;
}
return GETDNS_RETURN_GOOD;
}
void*
getdns_context_get_extension_data(struct getdns_context* context) {
RETURN_IF_NULL(context, NULL);
return context->extension_data;
}
static inline getdns_return_t
priv_dict_set_list_if_not_null(getdns_dict* dict,
const char* name, getdns_list* list) {

View File

@ -41,7 +41,7 @@
#include "getdns/getdns_extra.h"
#include "config.h"
#include "types-internal.h"
#include "util/mini_event.h"
#include "extension/libmini_event.h"
struct getdns_dns_req;
struct ldns_rbtree_t;
@ -82,14 +82,6 @@ typedef struct getdns_upstreams {
struct getdns_upstream upstreams[];
} getdns_upstreams;
typedef struct getdns_mini_event_extention {
getdns_eventloop_extension ext;
time_t time_secs;
struct timeval time_tv;
struct getdns_event_base *base;
struct getdns_event ub_event;
} getdns_mini_event_extension;
struct getdns_context {
/* Context values */
getdns_resolution_t resolution_type;
@ -137,20 +129,12 @@ struct getdns_context {
*/
struct ldns_rbtree_t *outbound_requests;
/*
* Event loop extension functions
* These structs are static and should never be freed
* since they are just a collection of function pointers
*/
getdns_eventloop_extension* extension;
/*
* Extension data that will be freed by the functions
* in the extension struct
*/
void* extension_data;
/* Event loop extension. */
getdns_eventloop *extension;
getdns_eventloop_event ub_event;
/* The default extension */
getdns_mini_event_extension mini_event_extension;
getdns_mini_event mini_event;
/*
* state data used to detect changes to the system config files
@ -197,11 +181,11 @@ void getdns_bindata_destroy(
/* timeout scheduling */
getdns_return_t getdns_context_schedule_timeout(getdns_context* context,
uint64_t timeout, getdns_timeout_callback callback, void* userarg,
getdns_timeout_data_t *init_to_track);
uint64_t timeout, getdns_eventloop_callback callback, void* userarg,
getdns_eventloop_event *init_to_track);
getdns_return_t getdns_context_clear_timeout(getdns_context* context,
getdns_timeout_data_t *timeout_data);
getdns_eventloop_event *timeout_data);
/* perform name resolution in /etc/hosts */
getdns_return_t getdns_context_local_namespace_resolve(getdns_dns_req* req,

196
src/extension/libmini_event.c Executable file
View File

@ -0,0 +1,196 @@
/**
*
* \file libmini_event.c
* @brief Build in default eventloop extension that uses select.
*
*/
/*
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
* 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 names of the copyright holders 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.
*/
#include "config.h"
#include "extension/libmini_event.h"
#include "util/mini_event.h"
#include "context.h"
void getdns_handle_timeouts(struct getdns_event_base* base,
struct timeval* now, struct timeval* wait);
int getdns_handle_select(struct getdns_event_base* base, struct timeval* wait);
static getdns_return_t getdns_mini_event_cleanup(getdns_eventloop *loop);
static getdns_return_t getdns_mini_event_schedule_read(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *ev);
static getdns_return_t getdns_mini_event_schedule_timeout
(getdns_eventloop *loop, uint64_t timeout, getdns_eventloop_event *ev);
static getdns_return_t getdns_mini_event_clear_event
(getdns_eventloop *loop, getdns_eventloop_event *ev);
static getdns_eventloop_functions getdns_mini_event_functions = {
getdns_mini_event_cleanup,
getdns_mini_event_schedule_read,
getdns_mini_event_clear_event,
getdns_mini_event_schedule_timeout,
getdns_mini_event_clear_event,
};
getdns_return_t
getdns_mini_event_init(getdns_context *context, getdns_mini_event *ext)
{
if (!context) return GETDNS_RETURN_BAD_CONTEXT;
if (!ext) return GETDNS_RETURN_INVALID_PARAMETER;
ext->loop.functions = &getdns_mini_event_functions;
ext->base = getdns_event_init(&ext->time_secs, &ext->time_tv);
if (!ext->base)
return GETDNS_RETURN_MEMORY_ERROR;
ext->mf = context->mf;
return GETDNS_RETURN_GOOD;
}
getdns_return_t
getdns_mini_event_create(getdns_context *context, getdns_mini_event **ext)
{
if (!context) return GETDNS_RETURN_BAD_CONTEXT;
if (!ext) return GETDNS_RETURN_INVALID_PARAMETER;
*ext = GETDNS_MALLOC(context->mf, getdns_mini_event);
return getdns_mini_event_init(context, *ext);
}
void
getdns_mini_event_destroy(getdns_mini_event *ext)
{
if (ext) {
ext->loop.functions->cleanup(&ext->loop);
GETDNS_FREE(ext->mf, ext);
}
}
static getdns_return_t
getdns_mini_event_cleanup(getdns_eventloop *loop)
{
getdns_mini_event *ext = (getdns_mini_event *)loop;
getdns_event_base_free(ext->base);
return GETDNS_RETURN_GOOD;
}
static int
getdns_mini_event_settime(getdns_mini_event *ext)
{
if (gettimeofday(&ext->time_tv, NULL) < 0)
return -1;
ext->time_secs = (time_t)ext->time_tv.tv_sec;
return 0;
}
/** Call timeouts handlers, and return how long to wait for next one or -1 */
void
getdns_mini_event_handle_timeouts(getdns_mini_event *ext, struct timeval *wait)
{
struct timeval dispose = { 0, 0 };
if (getdns_mini_event_settime(ext) == 0)
getdns_handle_timeouts(
ext->base, &ext->time_tv, wait ? wait : &dispose);
}
/** Call select and callbacks for that */
getdns_return_t
getdns_mini_event_handle_select(getdns_mini_event *ext, struct timeval* wait)
{
static struct timeval immediately = { 0, 0 };
return getdns_handle_select(ext->base, wait ? wait : &immediately)
? GETDNS_RETURN_GENERIC_ERROR : GETDNS_RETURN_GOOD;
}
static void
getdns_mini_event_callback(int fd, short bits, void *arg)
{
getdns_eventloop_event *el_ev = (getdns_eventloop_event *)arg;
if (bits & EV_READ) {
assert(el_ev->read_cb);
el_ev->read_cb(el_ev->userarg);
} else if (bits & EV_TIMEOUT) {
assert(el_ev->timeout_cb);
el_ev->timeout_cb(el_ev->userarg);
} else
assert(ASSERT_UNREACHABLE);
}
static getdns_return_t
getdns_mini_event_schedule_read(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *el_ev)
{
getdns_mini_event *ext = (getdns_mini_event *)loop;
struct getdns_event *my_ev;
struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 };
short bits =
((fd >= 0 && el_ev->read_cb ? EV_READ : 0) |
(timeout!=TIMEOUT_FOREVER && el_ev->timeout_cb ? EV_TIMEOUT : 0));
if (!bits)
return GETDNS_RETURN_GOOD; /* Nothing to schedule */
my_ev = GETDNS_MALLOC(ext->mf, struct getdns_event);
el_ev->ev = my_ev;
getdns_event_set(my_ev, fd, bits, getdns_mini_event_callback, el_ev);
if (getdns_mini_event_settime(ext))
return GETDNS_RETURN_GENERIC_ERROR;
(void) getdns_event_base_set(ext->base, my_ev);
if (getdns_event_add(my_ev, &tv))
return GETDNS_RETURN_GENERIC_ERROR;
return GETDNS_RETURN_GOOD;
}
static getdns_return_t
getdns_mini_event_schedule_timeout(getdns_eventloop *loop,
uint64_t timeout, getdns_eventloop_event *el_ev)
{
return getdns_mini_event_schedule_read(loop, -1, timeout, el_ev);
}
static getdns_return_t
getdns_mini_event_clear_event(getdns_eventloop *loop,
getdns_eventloop_event *el_ev)
{
getdns_mini_event *ext = (getdns_mini_event *)loop;
assert(el_ev->ev);
if (getdns_event_del(el_ev->ev) != 0)
return GETDNS_RETURN_GENERIC_ERROR;
GETDNS_FREE(ext->mf, el_ev->ev);
el_ev->ev = NULL;
return GETDNS_RETURN_GOOD;
}
/* libmini_event.c */

65
src/extension/libmini_event.h Executable file
View File

@ -0,0 +1,65 @@
/**
*
* \file libmini_event.h
* @brief Build in default eventloop extension that uses select.
*
*/
/*
* Copyright (c) 2013, NLnet Labs, Verisign, Inc.
* 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 names of the copyright holders 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.
*/
#ifndef _GETDNS_LIBMINI_EVENT_H_
#define _GETDNS_LIBMINI_EVENT_H_
#include "util/mini_event.h"
#include "types-internal.h"
typedef struct getdns_mini_event {
getdns_eventloop loop;
time_t time_secs;
struct timeval time_tv;
struct getdns_event_base *base;
struct mem_funcs mf;
} getdns_mini_event;
getdns_return_t
getdns_mini_event_init(getdns_context *context, getdns_mini_event *mini_event);
getdns_return_t
getdns_mini_event_create(getdns_context *ctxt, getdns_mini_event **mini_event);
void
getdns_mini_event_destroy(getdns_mini_event *mini_event);
/** Call timeouts handlers, and return how long to wait for next one or -1 */
void
getdns_mini_event_handle_timeouts(getdns_mini_event *ext, struct timeval *wait);
/** Call select and callbacks for that */
getdns_return_t
getdns_mini_event_handle_select(getdns_mini_event *ext, struct timeval* wait);
#endif /* _GETDNS_LIBMINI_EVENT_H_ */

View File

@ -50,7 +50,7 @@
/* declarations */
static void ub_resolve_callback(void* mydata, int err, struct ub_result* result);
static getdns_return_t ub_resolve_timeout(void *arg);
static void ub_resolve_timeout(void *arg);
static void handle_network_request_error(getdns_network_req * netreq, int err);
static void handle_dns_request_complete(getdns_dns_req * dns_req);
@ -64,11 +64,11 @@ typedef struct netreq_cb_data
} netreq_cb_data;
/* cancel, cleanup and send timeout to callback */
static getdns_return_t
static void
ub_resolve_timeout(void *arg)
{
getdns_dns_req *dns_req = (getdns_dns_req *) arg;
return getdns_context_request_timed_out(dns_req);
(void) getdns_context_request_timed_out(dns_req);
}
void priv_getdns_call_user_callback(getdns_dns_req *dns_req,

View File

@ -39,85 +39,105 @@ extern "C" {
value is either GETDNS_EXTENSION_TRUE or GETDNS_EXTENSION_FALSE
returns GETDNS_RETURN_GOOD on success or GETDNS_RETURN_INVALID_PARAMETER
if context or value is invalid */
getdns_return_t getdns_context_set_return_dnssec_status(getdns_context* context, int enabled);
getdns_return_t getdns_context_set_return_dnssec_status(
getdns_context *context, int enabled);
/* dict util */
/* set a string as bindata */
getdns_return_t getdns_dict_util_set_string(struct getdns_dict * dict, char *name,
const char *value);
getdns_return_t getdns_dict_util_set_string(struct getdns_dict * dict,
char *name, const char *value);
/* get a string from a dict. the result must be freed if valid */
getdns_return_t getdns_dict_util_get_string(struct getdns_dict * dict, char *name,
char **result);
/* Async support */
uint32_t getdns_context_get_num_pending_requests(getdns_context* context, struct timeval* next_timeout);
getdns_return_t getdns_dict_util_get_string(struct getdns_dict * dict,
char *name, char **result);
/* get the fd */
int getdns_context_fd(getdns_context* context);
/* tells underlying unbound to use background threads or fork */
getdns_return_t getdns_context_set_use_threads(getdns_context* context,
int use_threads);
/* Async support */
uint32_t getdns_context_get_num_pending_requests(getdns_context* context,
struct timeval* next_timeout);
/* process async reqs */
getdns_return_t getdns_context_process_async(getdns_context* context);
/* tells underlying unbound to use background threads or fork */
getdns_return_t getdns_context_set_use_threads(getdns_context* context, int use_threads);
/***************** functions for eventloop extensions ******************/
/* extensions */
typedef getdns_return_t (*getdns_timeout_callback) (void* userarg);
typedef void (*getdns_eventloop_callback)(void *userarg);
/* context timeout data */
typedef struct getdns_timeout_data {
/* the timeout callback to fire */
getdns_timeout_callback callback;
/* timeout callback user arg */
void* userarg;
/* pointer to the underlying extension pointer that the extension
will create and free */
void* extension_timer;
/* context */
struct getdns_context* context;
} getdns_timeout_data_t;
/* context extension event data */
typedef struct getdns_eventloop_event {
void *userarg;
getdns_eventloop_callback read_cb;
getdns_eventloop_callback timeout_cb;
/* call the extension when the data needs to be cleaned up */
typedef getdns_return_t (*getdns_eventloop_cleanup_t)(struct getdns_context* context, void* eventloop_data);
/* Pointer to the underlying event
* that the eventloop extension will create and free.
*/
void *ev;
} getdns_eventloop_event;
/* call the extension to schedule a timer. Any timer data that needs to be tracked should be
stored in eventloop_timer */
typedef getdns_return_t (*getdns_eventloop_schedule_timeout_t)(struct getdns_context* context,
void* eventloop_data, uint64_t timeout,
getdns_timeout_data_t* timeout_data);
typedef struct getdns_eventloop_functions getdns_eventloop_functions;
typedef struct getdns_eventloop {
getdns_eventloop_functions *functions;
} getdns_eventloop;
/* call the extension to free a timer. The timer passed in is the same as that returned in
the schedule timeout */
typedef getdns_return_t (*getdns_eventloop_clear_timeout_t)(struct getdns_context* context,
void* eventloop_data, void* eventloop_timer);
/* Call the extension to clean up data allocated on initialization. */
typedef getdns_return_t (*getdns_eventloop_cleanup)(getdns_eventloop *loop);
/* call the extension to tell it that the number of outbound requests changed. This is called
when an async request is submitted or canceled by the user */
typedef getdns_return_t (*getdns_eventloop_request_count_changed_t)(struct getdns_context* context,
uint32_t request_count, void* eventloop_data);
/* Call the extension to schedule an event that will trigger when
* file descriptor fd will become readble.
*
* The getdns_eventloop_event must be provided by the caller with the callbacks
* and userarg therein already supplied (by the caller). This function must set
* the ev pointer (in the getdns_eventloop_event) to refer to the underlying
* (extension) event.
*/
typedef getdns_return_t (*getdns_eventloop_schedule_read)(getdns_eventloop *loop,
int fd, uint64_t timeout, getdns_eventloop_event *ev);
typedef struct getdns_eventloop_extension {
getdns_eventloop_cleanup_t cleanup_data;
getdns_eventloop_schedule_timeout_t schedule_timeout;
getdns_eventloop_clear_timeout_t clear_timeout;
getdns_eventloop_request_count_changed_t request_count_changed;
} getdns_eventloop_extension;
/* Call the extension to free a read event. */
typedef getdns_return_t (*getdns_eventloop_clear_read)
(getdns_eventloop *loop, getdns_eventloop_event *ev);
/* Call the extension to schedule a timer.
*
* The getdns_eventloop_event must be provided by the caller with the timeout
* callback and userarg therein already supplied (by the caller).
* This function must set the ev pointer (in the getdns_eventloop_event)
* to refer to the underlying (extension) event.
*/
typedef getdns_return_t (*getdns_eventloop_schedule_timeout)
(getdns_eventloop *loop, uint64_t timeout, getdns_eventloop_event *ev);
/* Call the extension to free a timer. */
typedef getdns_return_t (*getdns_eventloop_clear_timeout)
(getdns_eventloop *loop, getdns_eventloop_event *ev);
struct getdns_eventloop_functions {
getdns_eventloop_cleanup cleanup;
getdns_eventloop_schedule_read schedule_read;
getdns_eventloop_clear_read clear_read;
getdns_eventloop_schedule_timeout schedule_timeout;
getdns_eventloop_clear_timeout clear_timeout;
};
/* set an event loop extension on the context */
getdns_return_t
getdns_extension_set_eventloop(struct getdns_context* context,
getdns_eventloop_extension* extension, void* extension_data);
void*
getdns_context_get_extension_data(struct getdns_context* context);
getdns_context_set_eventloop(getdns_context* context,
getdns_eventloop *eventloop);
/* detach the eventloop from the context */
getdns_return_t
getdns_extension_detach_eventloop(struct getdns_context* context);
getdns_context_detach_eventloop(getdns_context *context);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -130,7 +130,7 @@ dns_req_new(struct getdns_context *context,
/* will be set by caller */
result->user_pointer = NULL;
result->user_callback = NULL;
memset(&result->timeout, 0, sizeof(getdns_timeout_data_t));
memset(&result->timeout, 0, sizeof(result->timeout));
/* check the specify_class extension */
(void) getdns_dict_get_int(extensions, "specify_class", &klass);

View File

@ -93,6 +93,8 @@ struct getdns_context;
#define GETDNS_STR_KEY_NSCOUNT "nscount"
#define GETDNS_STR_KEY_ARCOUNT "arcount"
#define TIMEOUT_FOREVER ((int64_t)-1)
#define ASSERT_UNREACHABLE 0
/** @}
*/
@ -198,7 +200,7 @@ typedef struct getdns_dns_req
/* the transaction id */
getdns_transaction_t trans_id;
getdns_timeout_data_t timeout;
getdns_eventloop_event timeout;
/* dnssec status */
int return_dnssec_status;