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?