Created
May 5, 2013 19:02
-
-
Save baruch/5521797 to your computer and use it in GitHub Desktop.
Asynchronous dns resolving with libev and the gethostbyname_r function.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.