diff --git a/src/Makefile.in b/src/Makefile.in index 39bd6d96..37c94d5a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -98,7 +98,7 @@ install: libgetdns.la uninstall: rm -rf $(DESTDIR)$(includedir)/getdns - $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/libgetdns.la $(EXTENSION_LIBEVENT_LIB) $(EXTENSION_LIBUV_LIB) $(EXTENSION_LIBEV_LIB) + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/libgetdns.la $(DESTDIR)$(libdir)/$(EXTENSION_LIBEVENT_LIB) $(DESTDIR)$(libdir)/$(EXTENSION_LIBUV_LIB) $(DESTDIR)$(libdir)/$(EXTENSION_LIBEV_LIB) libgetdns_ext_event.la: libgetdns.la extension/libevent.lo $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) -o $@ extension/libevent.lo ./.libs/libgetdns.la $(EXTENSION_LDFLAGS) $(EXTENSION_LIBEVENT_EXT_LIBS) -rpath $(libdir) -version-info $(libversion) -no-undefined diff --git a/src/context.c b/src/context.c index 88d98725..648de5b9 100644 --- a/src/context.c +++ b/src/context.c @@ -1183,15 +1183,14 @@ getdns_context_cancel_request(struct getdns_context *context, cb = req->user_callback; user_pointer = req->user_pointer; - /* clean up */ - GETDNS_FREE(context->my_mf, node); - dns_req_free(req); - /* fire callback */ cb(context, GETDNS_CALLBACK_CANCEL, NULL, user_pointer, transaction_id); } + /* clean up */ + GETDNS_FREE(context->my_mf, node); + dns_req_free(req); return GETDNS_RETURN_GOOD; } @@ -1204,7 +1203,12 @@ getdns_cancel_callback(struct getdns_context *context, getdns_transaction_t transaction_id) { RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); - return getdns_context_cancel_request(context, transaction_id, 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); + } + return r; } /* getdns_cancel_callback */ static getdns_return_t @@ -1384,6 +1388,10 @@ getdns_context_track_outbound_request(getdns_dns_req * req) 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; } @@ -1454,11 +1462,11 @@ int getdns_context_fd(struct getdns_context* context) { return ub_fd(context->unbound_ctx); } -int +uint32_t getdns_context_get_num_pending_requests(struct getdns_context* context, struct timeval* next_timeout) { RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); - int r = context->outbound_requests->count; + uint32_t r = context->outbound_requests->count; if (r > 0) { if (!context->extension && next_timeout) { /* default is 1 second */ @@ -1697,6 +1705,12 @@ getdns_context_clear_timeout(struct getdns_context* context, 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) { diff --git a/src/extension/libev.c b/src/extension/libev.c index 6f844629..9bed6aaf 100644 --- a/src/extension/libev.c +++ b/src/extension/libev.c @@ -46,20 +46,45 @@ struct getdns_libev_data { struct ev_io* poll_handle; }; -/* lib event callbacks */ +static void +request_count_changed(uint32_t request_count, struct getdns_libev_data *ev_data) { + if (request_count > 0) { + ev_io_start(ev_data->loop, ev_data->poll_handle); + } else { + ev_io_stop(ev_data->loop, ev_data->poll_handle); + } +} + +/* lib ev callbacks */ static void getdns_libev_cb(struct ev_loop *loop, struct ev_io *handle, int revents) { struct getdns_context* context = (struct getdns_context*) handle->data; getdns_context_process_async(context); + uint32_t rc = getdns_context_get_num_pending_requests(context, NULL); + struct getdns_libev_data* ev_data = + (struct getdns_libev_data*) getdns_context_get_extension_data(context); + request_count_changed(rc, ev_data); } static void getdns_libev_timeout_cb(struct ev_loop *loop, struct ev_timer* handle, int status) { getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) handle->data; timeout_data->callback(timeout_data->userarg); + uint32_t rc = getdns_context_get_num_pending_requests(timeout_data->context, NULL); + struct getdns_libev_data* ev_data = + (struct getdns_libev_data*) getdns_context_get_extension_data(timeout_data->context); + request_count_changed(rc, ev_data); } /* getdns extension functions */ +static getdns_return_t +getdns_libev_request_count_changed(struct getdns_context* context, + uint32_t request_count, void* eventloop_data) { + struct getdns_libev_data *ev_data = (struct getdns_libev_data*) eventloop_data; + request_count_changed(request_count, ev_data); + return GETDNS_RETURN_GOOD; +} + static getdns_return_t getdns_libev_cleanup(struct getdns_context* context, void* data) { struct getdns_libev_data *ev_data = (struct getdns_libev_data*) data; @@ -102,7 +127,8 @@ getdns_libev_clear_timeout(struct getdns_context* context, static getdns_eventloop_extension LIBEV_EXT = { getdns_libev_cleanup, getdns_libev_schedule_timeout, - getdns_libev_clear_timeout + getdns_libev_clear_timeout, + getdns_libev_request_count_changed }; /* @@ -129,7 +155,6 @@ getdns_extension_set_libev_loop(struct getdns_context *context, ev_io_init(ev_data->poll_handle, getdns_libev_cb, fd, EV_READ); ev_data->loop = loop; - ev_io_start(ev_data->loop, ev_data->poll_handle); ev_data->poll_handle->data = context; return getdns_extension_set_eventloop(context, &LIBEV_EXT, ev_data); } /* getdns_extension_set_libev_loop */ diff --git a/src/extension/libevent.c b/src/extension/libevent.c index 41f508c4..f030271e 100644 --- a/src/extension/libevent.c +++ b/src/extension/libevent.c @@ -72,20 +72,45 @@ struct event_data { struct event_base* event_base; }; +static void +request_count_changed(uint32_t request_count, struct event_data *ev_data) { + if (request_count > 0) { + event_add(ev_data->event, NULL); + } else { + event_del(ev_data->event); + } +} + /* lib event callbacks */ static void getdns_libevent_cb(evutil_socket_t fd, short what, void *userarg) { struct getdns_context* context = (struct getdns_context*) userarg; getdns_context_process_async(context); + uint32_t rc = getdns_context_get_num_pending_requests(context, NULL); + struct event_data* ev_data = + (struct event_data*) getdns_context_get_extension_data(context); + request_count_changed(rc, ev_data); } static void getdns_libevent_timeout_cb(evutil_socket_t fd, short what, void* userarg) { getdns_timeout_data_t* timeout_data = (getdns_timeout_data_t*) userarg; timeout_data->callback(timeout_data->userarg); + uint32_t rc = getdns_context_get_num_pending_requests(timeout_data->context, NULL); + struct event_data* ev_data = + (struct event_data*) getdns_context_get_extension_data(timeout_data->context); + request_count_changed(rc, ev_data); } /* getdns extension functions */ +static getdns_return_t +getdns_libevent_request_count_changed(struct getdns_context* context, + uint32_t request_count, void* eventloop_data) { + struct event_data *edata = (struct event_data*) eventloop_data; + request_count_changed(request_count, edata); + return GETDNS_RETURN_GOOD; +} + static getdns_return_t getdns_libevent_cleanup(struct getdns_context* context, void* data) { struct event_data *edata = (struct event_data*) data; @@ -128,7 +153,8 @@ getdns_libevent_clear_timeout(struct getdns_context* context, static getdns_eventloop_extension LIBEVENT_EXT = { getdns_libevent_cleanup, getdns_libevent_schedule_timeout, - getdns_libevent_clear_timeout + getdns_libevent_clear_timeout, + getdns_libevent_request_count_changed }; /* @@ -151,7 +177,6 @@ getdns_extension_set_libevent_base(struct getdns_context *context, if (!getdns_event) { return GETDNS_RETURN_GENERIC_ERROR; } - event_add(getdns_event, NULL); /* TODO: use context functs? */ struct event_data* ev_data = (struct event_data*) malloc(sizeof(struct event_data)); @@ -163,6 +188,5 @@ getdns_extension_set_libevent_base(struct getdns_context *context, } ev_data->event = getdns_event; ev_data->event_base = this_event_base; - return getdns_extension_set_eventloop(context, &LIBEVENT_EXT, ev_data); } /* getdns_extension_set_libevent_base */ diff --git a/src/extension/libuv.c b/src/extension/libuv.c index 8646e7e1..583ba263 100644 --- a/src/extension/libuv.c +++ b/src/extension/libuv.c @@ -44,19 +44,41 @@ struct getdns_libuv_data { uv_loop_t* loop; uv_poll_t* poll_handle; + uint8_t polling; }; +static void request_count_changed(uint32_t request_count, struct getdns_libuv_data *uv_data); + /* 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); + 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; + } } 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); + 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); } static void @@ -67,6 +89,14 @@ getdns_libuv_close_cb(uv_handle_t* handle) { } /* getdns extension functions */ +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; +} + static getdns_return_t getdns_libuv_cleanup(struct getdns_context* context, void* data) { struct getdns_libuv_data *uv_data = (struct getdns_libuv_data*) data; @@ -108,7 +138,8 @@ getdns_libuv_clear_timeout(struct getdns_context* context, static getdns_eventloop_extension LIBUV_EXT = { getdns_libuv_cleanup, getdns_libuv_schedule_timeout, - getdns_libuv_clear_timeout + getdns_libuv_clear_timeout, + getdns_libuv_request_count_changed }; /* @@ -135,7 +166,6 @@ getdns_extension_set_libuv_loop(struct getdns_context *context, uv_poll_init(uv_loop, uv_data->poll_handle, fd); uv_data->poll_handle->data = context; uv_data->loop = uv_loop; - - uv_poll_start(uv_data->poll_handle, UV_READABLE, getdns_libuv_cb); + uv_data->polling = 0; return getdns_extension_set_eventloop(context, &LIBUV_EXT, uv_data); } /* getdns_extension_set_libuv_loop */ diff --git a/src/general.c b/src/general.c index 86f7a380..243106a4 100644 --- a/src/general.c +++ b/src/general.c @@ -74,12 +74,9 @@ ub_resolve_timeout(void *arg) getdns_callback_t cb = dns_req->user_callback; void *user_arg = dns_req->user_pointer; - /* cancel the req - also clears it from outbound */ + /* cancel the req - also clears it from outbound and cleans up*/ getdns_context_cancel_request(context, trans_id, 0); - /* cleanup */ - dns_req_free(dns_req); - cb(context, GETDNS_CALLBACK_TIMEOUT, NULL, user_arg, trans_id); } diff --git a/src/getdns/getdns.h.in b/src/getdns/getdns.h.in index 4c37f750..d8bcb586 100644 --- a/src/getdns/getdns.h.in +++ b/src/getdns/getdns.h.in @@ -1009,16 +1009,6 @@ getdns_context_set_extended_memory_functions(getdns_context *context, getdns_dict* getdns_context_get_api_information(getdns_context* context); -/* Async support */ -struct timeval; -int getdns_context_get_num_pending_requests(getdns_context* context, struct timeval* next_timeout); - -/* get the fd */ -int getdns_context_fd(getdns_context* context); - -/* process async reqs */ -getdns_return_t getdns_context_process_async(getdns_context* context); - /* Get root trust anchor */ getdns_list *getdns_root_trust_anchor(time_t *utc_date_of_anchor); diff --git a/src/getdns/getdns_extra.h b/src/getdns/getdns_extra.h index 12c1ca58..8d8494fd 100644 --- a/src/getdns/getdns_extra.h +++ b/src/getdns/getdns_extra.h @@ -42,12 +42,12 @@ getdns_return_t getdns_context_set_return_dnssec_status(getdns_context* context, getdns_return_t getdns_dict_util_set_string(struct getdns_dict * dict, char *name, const char *value); -/* get a string from a dict. result is valid as long as dict is valid */ +/* 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 */ -int getdns_context_get_num_pending_requests(getdns_context* context, struct timeval* next_timeout); +uint32_t getdns_context_get_num_pending_requests(getdns_context* context, struct timeval* next_timeout); /* get the fd */ int getdns_context_fd(getdns_context* context); @@ -61,33 +61,57 @@ typedef void (*getdns_timeout_callback) (void* userarg); /* context timeout data */ typedef struct getdns_timeout_data { + /* a timeout id */ getdns_transaction_t transaction_id; + /* the absolute time of the timeout */ struct timeval timeout_time; + /* 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; +/* 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); + +/* 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, uint16_t timeout, getdns_timeout_data_t* timeout_data, void** eventloop_timer); + +/* 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 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); 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; -/* extension stuff */ -getdns_return_t getdns_extension_set_eventloop(struct getdns_context* context, +/* 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); + +/* detach the eventloop from the context */ getdns_return_t getdns_extension_detach_eventloop(struct getdns_context* context); diff --git a/src/test/Makefile.in b/src/test/Makefile.in index fe209368..d614471a 100644 --- a/src/test/Makefile.in +++ b/src/test/Makefile.in @@ -82,16 +82,16 @@ check_getdns_common: check_getdns_common.o $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ check_getdns_common.o check_getdns: check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_selectloop.o - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_selectloop.o + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -lpthread -o $@ check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_selectloop.o check_getdns_event: check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libevent.o - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -lgetdns_ext_event $(EXTENSION_LIBEVENT_EXT_LIBS) $(LDLIBS) -o $@ check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libevent.o + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -lpthread -lgetdns_ext_event $(EXTENSION_LIBEVENT_EXT_LIBS) $(LDLIBS) -o $@ check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libevent.o check_getdns_uv: check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libuv.o - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -lgetdns_ext_uv $(EXTENSION_LIBUV_EXT_LIBS) $(LDLIBS) -o $@ check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libuv.o + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -lpthread -lgetdns_ext_uv $(EXTENSION_LIBUV_EXT_LIBS) $(LDLIBS) -o $@ check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libuv.o check_getdns_ev: check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libev.o - $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -lgetdns_ext_ev $(EXTENSION_LIBEV_EXT_LIBS) $(LDLIBS) -o $@ check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libev.o + $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -lpthread -lgetdns_ext_ev $(EXTENSION_LIBEV_EXT_LIBS) $(LDLIBS) -o $@ check_getdns.o check_getdns_common.o check_getdns_context_set_timeout.o check_getdns_libev.o tests_dnssec: tests_dnssec.o testmessages.o $(LIBTOOL) --tag=CC --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -lgetdns_ext_event $(LDLIBS) -o $@ tests_dnssec.o testmessages.o diff --git a/src/test/check_getdns_libev.c b/src/test/check_getdns_libev.c index 6a5b2455..c3dff023 100644 --- a/src/test/check_getdns_libev.c +++ b/src/test/check_getdns_libev.c @@ -42,9 +42,7 @@ void run_event_loop_impl(struct getdns_context* context, void* eventloop) { struct ev_loop* loop = (struct ev_loop*) eventloop; - while (getdns_context_get_num_pending_requests(context, NULL) > 0) { - ev_run(loop, EVRUN_ONCE); - } + ev_run(loop, 0); } void* create_eventloop_impl(struct getdns_context* context) { diff --git a/src/test/check_getdns_libevent.c b/src/test/check_getdns_libevent.c index d2d39c03..a83bd551 100644 --- a/src/test/check_getdns_libevent.c +++ b/src/test/check_getdns_libevent.c @@ -42,9 +42,7 @@ void run_event_loop_impl(struct getdns_context* context, void* eventloop) { struct event_base* base = (struct event_base*) eventloop; - while (getdns_context_get_num_pending_requests(context, NULL) > 0) { - event_base_loop(base, EVLOOP_ONCE); - } + event_base_dispatch(base); } void* create_eventloop_impl(struct getdns_context* context) { diff --git a/src/test/check_getdns_libuv.c b/src/test/check_getdns_libuv.c index c1ffcf77..4994cae7 100644 --- a/src/test/check_getdns_libuv.c +++ b/src/test/check_getdns_libuv.c @@ -42,9 +42,7 @@ void run_event_loop_impl(struct getdns_context* context, void* eventloop) { uv_loop_t* loop = (uv_loop_t*) eventloop; - while (getdns_context_get_num_pending_requests(context, NULL) > 0) { - uv_run(loop, UV_RUN_ONCE); - } + uv_run(loop, UV_RUN_DEFAULT); }