]> git.meshlink.io Git - meshlink/blobdiff - src/adns.c
Add a probe point for async DNS resolving.
[meshlink] / src / adns.c
index 6e988c01f0147a3a0ed270c83fbf2f603534c82a..8181140d15ddb011e3837bff81119b272b9fd9f5 100644 (file)
 #include "system.h"
 
 #include <pthread.h>
+#include <stdatomic.h>
 
 #include "adns.h"
+#include "devtools.h"
 #include "logger.h"
 #include "xalloc.h"
 
@@ -47,6 +49,7 @@ static void *adns_loop(void *data) {
 
                if(time(NULL) < item->deadline) {
                        logger(mesh, MESHLINK_DEBUG, "Resolving %s port %s", item->host, item->serv);
+                       devtool_adns_resolve_probe();
                        int result = getaddrinfo(item->host, item->serv, NULL, &item->ai);
 
                        if(result) {
@@ -81,13 +84,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 +114,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 +130,89 @@ 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);
+       devtool_adns_resolve_probe();
+
+       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;
+}