TADNS - Tiny Asynchronous DNS lookup library

Overview

Do not want your code to block in gethostbyname() or getaddrinfo() calls? Then, TADNS is for you. Using it is easy because of the following:

Get it and try it. TADNS is licensed under the phk's beer-ware license:

/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * Sergey Lyubka wrote this file. As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.
 * ----------------------------------------------------------------------------
 */

Usage example


static void my_callback(void *context, enum dns_query_type qtype,
	const char *name, const unsigned char *addr, size_t addrlen)
{
	if (addrlen == 0) {
		(void) fprintf(stderr, "No idea about [%s]\n", name);
	} else {
		printf("%u.%u.%u.%u\n", addr[0], addr[1], addr[2], addr[3]);
	}
}

int main(int argc, char *const *argv)
{
	struct dns	*dns;
	char		host[] = "www.sourceforge.net";
	fd_set		set;
	struct timeval	tv = {3, 0};	/* Wait max for 3 seconds */

	/* ... */

	/* Initialize the library */
	dns = dns_init();

	/* ... */

	/* Make a request */
	dns_queue(dns, NULL, host, DNS_A_RECORD, my_callback);

	/* Wait for a reply. We can multiplex other IO here. */
	FD_ZERO(&set);
	FD_SET(dns_get_fd(dns), &set);
	
	if (select(dns_get_fd(dns) + 1, &set, NULL, NULL, &tv) == 1)
		dns_poll(dns);
	
	/* ... */
}

At the end of tdns.c file you can find a piece of code that emulates simple dig utility.

The API

enum dns_query_type {DNS_A_RECORD = 0x01, DNS_MX_RECORD = 0x0f};
Query types supported by TADNS. For gethostbyname() functionality, use DNS_A_RECORD query type.
#define DNS_QUERY_TIMEOUT 30
Default DNS query timeout is 30 seconds. If you want to change it, just tweak this value in a header file.
typedef void (*dns_callback_t)(void *context, enum dns_query_type qtype, const char *hostname, const unsigned char *addr, size_t addrlen);
This is a user callback prototype. The user function is called when by the dns_poll() function if the requested information available. The context parameter is any user data, but it must be unique between multiple request. The IP address for the requested hostname is of addrlen length, and located at addr pointer. If addrlen is 0, it means lookup failure - not existent host or lookup timeout.
struct dns *dns_init(void)
Initializes the library, and returns pointer to opaque struct dns. Must be called first.
void dns_fini(struct dns *)
Cleanup function.
int dns_get_fd(struct dns *)
Returns UDP socket used to send DNS queries. It can be used to multiplex the I/O by means of select() or other calls.
void dns_queue(struct dns *, void *context, const char *hostname, enum dns_query_type type, dns_callback_t callback)
The actual lookup request. This function does not block, so that is why the library is asynchronous. It searches the query cache first. If there was a query for the same host before, and the result has not being expired, the user callback is called immediately, and function returns. If there is no suitable entry in the cache, a UDP packet is crafted and sent to the DNS server. The user callback is called later, from the dns_poll() function.
void dns_cancel(struct dns *, const void *context)
Request cancellation. The callback will not be called for that context.
void dns_poll(struct dns *)
Check the UDP socket for DNS replies. If there are any, associated user callback is called with the reply data.

Author

Copyright © by Sergey Lyubka (valenok at gmail dot com). Feel free to drop me a letter if you have problems using TADNS. Also, if you feel a strong desire to buy me a beer, mail me so we can discuss this issue and come up with some suitable solution.