ImperialViolet

Asynchronous DNS lookups with glibc (01 Jun 2005)

This is very poorly documented, but glibc can do DNS lookups asynchronously. You can get the original design document here, but it's a bit verbose.

Firstly, this is glibc specific and you need to link against libanl. The headers you'll need are netdb.h and signal.h

The core function is getaddrinfo_a which takes four arguments:

int getaddrinfo_a(int mode, struct gaicb *list[], int ent, struct sigevent *);

The mode is either GAI_NOWAIT or GAI_WAIT. Since you're trying to do asynchronous lookups you'll want GAI_NOWAIT. A gaicb looks like:

struct gaicb {
	const char *ar_name;
	const char *ar_service;
	const struct addrinfo *ar_request;
	struct addrinfo *ar_result;
};

You should see the manpage for getaddrinfo for details of those fields. In short, set ar_name to the hostname, ar_service, ar_request and ar_result to NULL.

So, getaddrinfo_a takes a pointer to a list of those structures and ent is the number of entries in that list. The final argument tells glibc how you want to be informed about the result. A sigevent structure looks like:

strict sigevent {
	sigval_t sigev_value;
	int sigev_signo;
	int sigev_notify;
	void (*sigev_notify_function) (sigval_t);
	pthread_addr_t *sigev_notify_attributes;
};

So you can either ignore the notification (set sigev_notify to SIGEV_NONE), get a signal (set sigev_notify to SIGEV_SIGNAL) or request a callback in a new thread (set SIGEV_THREAD).

Hopefully the rest of the values are fairly obvious in light of that. If you want the sigev_value to be passed to a signal handler you'll need to register the handler with the SA_SIGINFO flag to sigaction. Also remember that the realtime signals (SIGRTMIN+0 to SIGRTMIN+31) are free for user-defined uses.

When you get notified (or, indeed, at any time) you can call int gai_error(struct gaicb *) which will return 0 if the request is ready. A return value other than EAI_INPROGRESS is an error code which you can find as EAI_* in netdb.h. Once you know that a request has completed you can get the result from the ar_result member. And you will remember to call freeaddrinfo won't you?