I am trying to look up domain asynchronously in c++. The reason is I want to be able to effectively add a time out period in case the system can't look up the domain. I came across the getaddrinfo_a() command so I decided to give it a try. However cancelling any dns look up that will not succeed (such as when there is no internet connection) will never take less than 20 seconds on my machine. Here is a simple example of this:
#include <iostream>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
using namespace std;
int main() {
int ret;
gaicb* reqs;
reqs = new gaicb;
memset(reqs, 0, sizeof (gaicb));
reqs->ar_name = "google.com";
ret = getaddrinfo_a(GAI_NOWAIT, &reqs, 1, NULL);
if (ret != 0) {
cout << "something went wrong" << endl;
return false;
}
while (1) {
ret = gai_cancel(reqs);
if (ret == EAI_CANCELED || ret == EAI_ALLDONE) {
break;
}
usleep(100 * 1000); //sleep for 100 milliseconds
}
cout << "finished cancellation" << endl;
return 0;
}
Compile like this:
g++ -o main main.cpp -lanl
Then run the command on your linux based system without an internet connection like so:
time ./main
You will find that the program always takes about 20 seconds to close. Any help would be greatly appreciated!
Okay the answer is to not use getaddrinfo_a(3) if you need asynchronous dns lookup shorter than 20 seconds. Also per Martin Sustrik's second comment on http://sourceware-org.1504.n7.nabble.com/getaddrinfo-a-memory-leaks-td233794.html as well as my experience here it looks like getaddrinfo_a is fairly experimental and shouldn't be used anyways. I actually ended up using dns.c (https://github.com/wahern/dns). Here's a sample for anyone looking:
#include "dns.c"
uint8_t getaddrinfo_k(
uint32_t* ip_addr, const char* dns_address, uint32_t timeout) {
int32_t rc;
struct addrinfo hints;
struct dns_resolv_conf* dns_conf;
struct dns_hosts* dns_hosts;
struct dns_hints* dns_hints;
struct dns_resolver* resolver;
struct dns_addrinfo* ai;
struct addrinfo* it;
dns_conf = dns_resconf_local(&rc);
assert(dns_conf);
dns_hosts = dns_hosts_local(&rc);
assert(dns_hosts);
dns_hints = dns_hints_local(dns_conf, &rc);
assert(dns_hints);
resolver = dns_res_open(
dns_conf, dns_hosts, dns_hints, NULL, dns_opts(), &rc);
assert(resolver);
it = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_INET;
ai = dns_ai_open(dns_address, "80", DNS_T_A, &hints, resolver, &rc);
assert(ai);
while (timeout-- > 0) {
rc = dns_ai_nextent(&it, ai);
switch(rc) {
case 0:
*ip_addr = (
(struct sockaddr_in *) it->ai_addr)->sin_addr.s_addr;
free(it);
goto exit_loop;
case EAGAIN:
rc = dns_ai_poll(ai, 1);
assert(rc == 0);
break;
default:
goto exit_loop;
}
usleep(100 * 1000);
}
exit_loop:
dns_ai_close (ai);
dns_res_close (resolver);
dns_hints_close (dns_hints);
dns_hosts_close (dns_hosts);
dns_resconf_close (dns_conf);
switch(rc) {
case 0:
return 1;
case EAGAIN:
printf("DNS_WRAPPER: timed out\n");
break;
case ENOENT:
printf("DNS_WRAPPER: file doesn't exist\n");
break;
default:
printf("DNS_WRAPPER: unknown error\n");
break;
}
return 0;
}