#include "system.h"
#include <pthread.h>
+#include <stdatomic.h>
#include "adns.h"
+#include "devtools.h"
#include "logger.h"
#include "xalloc.h"
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) {
}
}
-extern void init_adns(meshlink_handle_t *mesh) {
- signal_add(&mesh->loop, &mesh->adns_signal, adns_cb_handler, mesh, 1);
+void init_adns(meshlink_handle_t *mesh) {
meshlink_queue_init(&mesh->adns_queue);
+ meshlink_queue_init(&mesh->adns_done_queue);
+ signal_add(&mesh->loop, &mesh->adns_signal, adns_cb_handler, mesh, 1);
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;
}
abort();
}
- pthread_cond_signal(&mesh->adns_cond);
+ assert(pthread_cond_signal(&mesh->adns_cond) == 0);
pthread_join(mesh->adns_thread, NULL);
meshlink_queue_exit(&mesh->adns_queue);
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;
abort();
}
- pthread_cond_signal(&mesh->adns_cond);
+ assert(pthread_cond_signal(&mesh->adns_cond) == 0);
+}
+
+struct adns_blocking_info {
+ meshlink_handle_t *mesh;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ char *host;
+ char *serv;
+ struct addrinfo *ai;
+ int socktype;
+ bool done;
+};
+
+static 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();
+
+ struct addrinfo hint = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = info->socktype,
+ };
+
+ if(getaddrinfo(info->host, info->serv, &hint, &info->ai)) {
+ info->ai = NULL;
+ }
+
+ assert(pthread_mutex_lock(&info->mutex) == 0);
+
+ bool cleanup = info->done;
+
+ if(!info->done) {
+ info->done = true;
+ assert(pthread_cond_signal(&info->cond) == 0);
+ }
+
+ assert(pthread_mutex_unlock(&info->mutex) == 0);
+
+ 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 socktype, int timeout) {
+ struct adns_blocking_info *info = xzalloc(sizeof(*info));
+
+ info->mesh = mesh;
+ info->host = host;
+ info->serv = serv;
+ info->socktype = socktype;
+ assert(pthread_mutex_init(&info->mutex, NULL) == 0);
+ assert(pthread_cond_init(&info->cond, NULL) == 0);
+
+ 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 {
+ assert(pthread_detach(thread) == 0);
+ }
+
+ assert(pthread_mutex_lock(&info->mutex) == 0);
+ assert(pthread_cond_timedwait(&info->cond, &info->mutex, &deadline) == 0);
+
+ 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;
+ }
+
+ assert(pthread_mutex_unlock(&info->mutex) == 0);
+
+ if(cleanup) {
+ free(info->host);
+ free(info->serv);
+ free(info);
+ }
+
+ return result;
}