Here's a simple example that uses a thread pool from libeio inside libev's event loop to do asynchronous DNS lookups using the blocking getaddrinfo function. A timer in the loop should intersperse ticks in the program's output as the DNS lookups are in progress.
#include <ev.h>
#include <eio.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
// To compile: cc <file> -leio -lev
typedef struct {
const char *host;
struct addrinfo *address;
} resolve_t;
struct ev_loop *loop;
ev_idle idle_watcher;
ev_async async_watcher;
ev_timer timer_watcher;
// This is only executed when eio_poll returns -1
void idle_cb(struct ev_loop *loop, ev_idle *w, int revents) {
if (eio_poll() != -1)
ev_idle_stop(loop, w);
}
void async_cb(struct ev_loop *loop, ev_async *w, int revents) {
if (eio_poll() == -1) {
ev_idle_start(loop, &idle_watcher);
} else if (!eio_nreqs()) {
ev_timer_stop(loop, &timer_watcher);
ev_async_stop(loop, &async_watcher);
}
}
// Need to call eio_poll, but not from this function.
// Signal async_watcher instead and call from there.
void want_poll(void) {
ev_async_send(loop, &async_watcher);
}
int on_resolve(eio_req *req) {
char ipstr[INET6_ADDRSTRLEN];
resolve_t *r = (resolve_t *)req->data;
struct addrinfo *p;
for (p = r->address; p; p = p->ai_next) {
void *addr;
if (p->ai_family == AF_INET) { // IPv4
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &ipv4->sin_addr;
} else { // IPv6
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
addr = &ipv6->sin6_addr;
}
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
printf(" %s: %s\n", r->host, ipstr);
}
freeaddrinfo(r->address);
return 0;
}
void resolve(eio_req *req) {
resolve_t *r = (resolve_t *)req->data;
struct addrinfo hints;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
printf("resolving %s...\n", r->host);
req->result = getaddrinfo(r->host, "80", &hints, &r->address);
}
void tick(struct ev_loop *loop, ev_timer *w, int revents) {
puts("tick");
ev_timer_again(loop, w);
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, " Usage: %s host ...\n", argv[0]);
return 1;
}
loop = EV_DEFAULT;
resolve_t r[argc-1];
ev_idle_init(&idle_watcher, idle_cb);
ev_async_init(&async_watcher, async_cb);
ev_timer_init(&timer_watcher, tick, 0., .001);
eio_init(want_poll, 0);
ev_async_start(loop, &async_watcher);
ev_timer_again(loop, &timer_watcher);
int i = 0;
while (i < argc-1) {
r[i].host = argv[i+1];
eio_custom(resolve, 0, on_resolve, r+i++);
}
ev_run(loop, 0);
return 0;
}