diff --git a/configure b/configure index db02242..420a177 100755 --- a/configure +++ b/configure @@ -112,6 +112,7 @@ For better control, use the options below. --disable-pps Disable PPS API support --disable-rtc Don't include RTC even on Linux --disable-linuxcaps Disable Linux capabilities support + --disable-asyncdns Disable asynchronous name resolving --disable-forcednsretry Don't retry on permanent DNS error --with-user=USER Specify default chronyd user [root] --with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail] @@ -191,6 +192,7 @@ try_phc=0 feat_pps=1 try_setsched=0 try_lockmem=0 +feat_asyncdns=1 feat_forcednsretry=1 default_user="root" mail_program="/usr/lib/sendmail" @@ -267,6 +269,9 @@ do --disable-linuxcaps) feat_linuxcaps=0 ;; + --disable-asyncdns) + feat_asyncdns=0 + ;; --disable-forcednsretry) feat_forcednsretry=0 ;; @@ -419,6 +424,15 @@ then add_def HAVE_GETADDRINFO fi +if [ $feat_asyncdns = "1" ] && \ + test_code 'pthread' 'pthread.h' '-pthread' '' \ + 'return pthread_create(NULL, NULL, NULL, NULL);' +then + add_def FEAT_ASYNCDNS + add_def USE_PTHREAD_ASYNCDNS + MYCFLAGS="$MYCFLAGS -pthread" +fi + timepps_h="" if [ $feat_pps = "1" ]; then if test_code '' 'sys/timepps.h' '' '' ''; then diff --git a/logging.h b/logging.h index fcadb7b..9d7cbfb 100644 --- a/logging.h +++ b/logging.h @@ -77,6 +77,7 @@ typedef enum { LOGF_Manual, LOGF_Keys, LOGF_Logging, + LOGF_Nameserv, LOGF_Rtc, LOGF_Regress, LOGF_Sys, diff --git a/nameserv_async.c b/nameserv_async.c index b11da86..3ea187f 100644 --- a/nameserv_async.c +++ b/nameserv_async.c @@ -30,10 +30,103 @@ #include "nameserv_async.h" #include "logging.h" +#include "memory.h" +#include "sched.h" #include "util.h" +#ifdef FEAT_ASYNCDNS + +#ifdef USE_PTHREAD_ASYNCDNS +#include + /* ================================================== */ +struct DNS_Async_Instance { + const char *name; + DNS_Status status; + IPAddr addr; + DNS_NameResolveHandler handler; + void *arg; + + pthread_t thread; + int pipe[2]; +}; + +static int resolving_threads = 0; + +/* ================================================== */ + +static void * +start_resolving(void *anything) +{ + struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything; + + inst->status = DNS_Name2IPAddress(inst->name, &inst->addr); + + /* Notify the main thread that the result is ready */ + if (write(inst->pipe[1], "", 1) < 0) + ; + + return NULL; +} + +/* ================================================== */ + +static void +end_resolving(void *anything) +{ + struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything; + + if (pthread_join(inst->thread, NULL)) { + LOG_FATAL(LOGF_Nameserv, "pthread_join() failed"); + } + + resolving_threads--; + + SCH_RemoveInputFileHandler(inst->pipe[0]); + close(inst->pipe[0]); + close(inst->pipe[1]); + + (inst->handler)(inst->status, &inst->addr, inst->arg); + + Free(inst); +} + +/* ================================================== */ + +void +DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything) +{ + struct DNS_Async_Instance *inst; + + inst = MallocNew(struct DNS_Async_Instance); + inst->name = name; + inst->handler = handler; + inst->arg = anything; + inst->status = DNS_Failure; + + if (pipe(inst->pipe)) { + LOG_FATAL(LOGF_Nameserv, "pipe() failed"); + } + + resolving_threads++; + assert(resolving_threads <= 1); + + if (pthread_create(&inst->thread, NULL, start_resolving, inst)) { + LOG_FATAL(LOGF_Nameserv, "pthread_create() failed"); + } + + SCH_AddInputFileHandler(inst->pipe[0], end_resolving, inst); +} + +/* ================================================== */ + +#else +#error +#endif + +#else + /* This is a blocking implementation used when nothing else is available */ void @@ -47,3 +140,5 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void * } /* ================================================== */ + +#endif