Skip to content

Instantly share code, notes, and snippets.

@baruch
Created May 5, 2013 19:02
Show Gist options
  • Save baruch/5521797 to your computer and use it in GitHub Desktop.
Save baruch/5521797 to your computer and use it in GitHub Desktop.
Asynchronous dns resolving with libev and the gethostbyname_r function.
#include <ev.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <netdb.h>
#include <memory.h>
typedef struct net_client_t {
ev_signal resolv_watcher;
char hostname[64];
struct gaicb gaicb;
struct addrinfo hints;
} net_client_t;
static void resolv_cb(struct ev_loop *loop, ev_signal *watcher, int revents)
{
net_client_t *client = (net_client_t*)watcher;
if (!client->gaicb.ar_result) {
printf("resolve result is null\n");
return;
}
printf("Resolved %p\n", client->gaicb.ar_result);
struct addrinfo *rp;
for (rp = client->gaicb.ar_result; rp != NULL; rp = rp->ai_next) {
printf("fam=%d type=%d proto=%d addr=%x len=%d\n", rp->ai_family, rp->ai_socktype, rp->ai_protocol, rp->ai_addr, rp->ai_addrlen);
}
freeaddrinfo(client->gaicb.ar_result);
ev_break(EV_DEFAULT, EVBREAK_ALL);
}
bool net_client_init(net_client_t *client, struct ev_loop *loop, const char *hostname)
{
memset(client, 0, sizeof(*client));
ev_signal_init(&client->resolv_watcher, resolv_cb, SIGRTMIN);
ev_signal_start(loop, &client->resolv_watcher);
snprintf(client->hostname, sizeof(client->hostname), "%s", hostname);
client->hints.ai_family = AF_UNSPEC;
client->hints.ai_socktype = SOCK_STREAM;
client->gaicb.ar_request = &client->hints;
client->gaicb.ar_name = client->hostname;
struct gaicb *host = &client->gaicb;
struct sigevent sig = {
.sigev_notify = SIGEV_SIGNAL,
.sigev_signo = SIGRTMIN,
.sigev_value.sival_ptr = client,
};
int ret = getaddrinfo_a(GAI_NOWAIT, &host, 1, &sig);
if (ret != 0) {
printf("Error attempting to resolve host '%s', code=%d\n", client->hostname, ret);
return false;
}
return true;
}
int main(int argc, const char **argv)
{
if (argc != 2) {
printf("Expected an argument for hostname to resolve\n");
return 1;
}
struct ev_loop *loop = EV_DEFAULT;
net_client_t client;
net_client_init(&client, loop, argv[1]);
ev_run(loop, 0);
return 0;
}
@baruch
Copy link
Author

baruch commented May 7, 2013

getaddrinfo_a of eglibc 2.13 seems to simply open a thread and execute the request there synchronously, this could be reimplemented on platforms that don't have getaddrinfo_a.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment