From 5b72f55e11cf44d788a788e7231927bc2a3fbe2d Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Thu, 9 Apr 2020 23:39:19 +0200 Subject: [PATCH] Add "blocking" asynchronous DNS requests. These block for a limited amount of time, preventing lookups from taking too long. Because these requests can be done without the main MeshLink thread running, we don't use the request queue, but instead spawn a thread for each blocking request. --- src/adns.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/adns.h | 1 + 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/adns.c b/src/adns.c index 6e988c01..2776a4c5 100644 --- a/src/adns.c +++ b/src/adns.c @@ -20,6 +20,7 @@ #include "system.h" #include +#include #include "adns.h" #include "logger.h" @@ -81,13 +82,13 @@ static void adns_cb_handler(event_loop_t *loop, void *data) { } } -extern void init_adns(meshlink_handle_t *mesh) { +void init_adns(meshlink_handle_t *mesh) { signal_add(&mesh->loop, &mesh->adns_signal, adns_cb_handler, mesh, 1); meshlink_queue_init(&mesh->adns_queue); pthread_create(&mesh->adns_thread, NULL, adns_loop, mesh); } -extern void exit_adns(meshlink_handle_t *mesh) { +void exit_adns(meshlink_handle_t *mesh) { if(!mesh->adns_signal.cb) { return; } @@ -111,7 +112,7 @@ extern void exit_adns(meshlink_handle_t *mesh) { signal_del(&mesh->loop, &mesh->adns_signal); } -extern void adns_queue(meshlink_handle_t *mesh, char *host, char *serv, adns_cb_t cb, void *data, int timeout) { +void adns_queue(meshlink_handle_t *mesh, char *host, char *serv, adns_cb_t cb, void *data, int timeout) { adns_item_t *item = xmalloc(sizeof(*item)); item->cb = cb; item->data = data; @@ -127,3 +128,88 @@ extern void adns_queue(meshlink_handle_t *mesh, char *host, char *serv, adns_cb_ pthread_cond_signal(&mesh->adns_cond); } + +struct adns_blocking_info { + meshlink_handle_t *mesh; + pthread_mutex_t mutex; + pthread_cond_t cond; + char *host; + char *serv; + struct addrinfo *ai; + bool done; +}; + +void *adns_blocking_handler(void *data) { + struct adns_blocking_info *info = data; + + logger(info->mesh, MESHLINK_DEBUG, "Resolving %s port %s", info->host, info->serv); + + if(getaddrinfo(info->host, info->serv, NULL, &info->ai)) { + info->ai = NULL; + } + + pthread_mutex_lock(&info->mutex); + + bool cleanup = info->done; + + if(!info->done) { + info->done = true; + pthread_cond_signal(&info->cond); + } + + pthread_mutex_unlock(&info->mutex); + + if(cleanup) { + free(info->host); + free(info->serv); + free(info); + } + + return NULL; +} + +struct addrinfo *adns_blocking_request(meshlink_handle_t *mesh, char *host, char *serv, int timeout) { + struct adns_blocking_info *info = xzalloc(sizeof(*info)); + + info->mesh = mesh; + info->host = host; + info->serv = serv; + + struct timespec deadline; + clock_gettime(CLOCK_REALTIME, &deadline); + deadline.tv_sec += timeout; + + pthread_t thread; + + if(pthread_create(&thread, NULL, adns_blocking_handler, info)) { + free(info->host); + free(info->serv); + free(info); + return NULL; + } else { + pthread_detach(thread); + } + + pthread_mutex_lock(&info->mutex); + pthread_cond_timedwait(&info->cond, &info->mutex, &deadline); + + struct addrinfo *result = NULL; + bool cleanup = info->done; + + if(info->done) { + result = info->ai; + } else { + logger(mesh, MESHLINK_WARNING, "Deadline passed for DNS request %s port %s", host, serv); + info->done = true; + } + + pthread_mutex_unlock(&info->mutex); + + if(cleanup) { + free(info->host); + free(info->serv); + free(info); + } + + return result; +} diff --git a/src/adns.h b/src/adns.h index aed15d86..8dc89fe1 100644 --- a/src/adns.h +++ b/src/adns.h @@ -27,5 +27,6 @@ typedef void (*adns_cb_t)(meshlink_handle_t *mesh, char *host, char *serv, void extern void init_adns(meshlink_handle_t *mesh); extern void exit_adns(meshlink_handle_t *mesh); extern void adns_queue(meshlink_handle_t *mesh, char *host, char *serv, adns_cb_t cb, void *data, int timeout); +extern struct addrinfo *adns_blocking_request(meshlink_handle_t *mesh, char *host, char *serv, int timeout); #endif -- 2.39.2