c - How to use getaddrinfo_a to do async resolve with glibc -
an overlooked function requires no external library, has no documentation whatsoever.
update (2010-10-11): linux man-pages have documentation of getaddrinfo_a, can find here: http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo_a.3.html
as disclaimer should add i'm quite new c not newbie, there might bugs, or bad coding practices, please correct me (and grammar sucks too).
i didn't know until came upon this post adam langley, shall give few code snippets illustrate usage of , clarify things might not clear on first use. benefits of using data readily usable in socket(), listen() , other functions, , if done right won't have worry ipv4/v6 either.
start off basics, taken link above (you need link against libanl (-lanl)) :
here function prototype:
int getaddrinfo_a(int mode, struct gaicb *list[], int ent, struct sigevent *);
- the mode either gai_wait (which not want) , gai_nowait async lookups
- the gaicb argument accepts array of hosts lookup ent argument specifying how many elements array has
- the sigevent responsible telling function how notified, more on in moment
a gaicb struct looks this:
struct gaicb { const char *ar_name; const char *ar_service; const struct addrinfo *ar_request; struct addrinfo *ar_result; };
if you're familiar getaddrinfo, these fields correspond them so:
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
the node ar_name field, service port, hints argument corresponds ar_request member , result stored in rest.
specify how want notified through sigevent structure:
struct sigevent { sigval_t sigev_value; int sigev_signo; int sigev_notify; void (*sigev_notify_function) (sigval_t); pthread_addr_t *sigev_notify_attributes; };
- you can ignore notification via setting _sigev_notify_ sigev_none
- you can trigger signal via setting sigev_notify sigev_signal , sigev_signo desired signal. note when using real-time signal (sigrtmin-sigrtmax, use via macros , addition sigrtmin+2 etc.) can pass along pointer or value in sigev_value.sival_ptr or sigev_value.sival_int member respectivley
- you can request callback in new thread via setting sigev_notify sigev_none
so if want hostname set ar_name host , set else null, if want connect host set ar_name , ar_service , , if want create server specify ar_service , ar_result field. can of course customize ar_request member hearts content, @ man getaddrinfo more info.
if have event loop select/poll/epoll/kqueue might want use signalfd convenience. signalfd creates file descriptor on can use usuall event polling mechanisms so:
#define _gnu_source //yes not standardish #include <netdb.h> #include <signal.h> #include <sys/signalfd.h> void signalfd_setup(void) { int sfd; sigset_t mask; sigemptyset(&mask); sigaddset(&mask, sigrtmin); sigprocmask(sig_block, &mask, null); //we block signal sfd = signalfd(-1, &mask, 0); //add event queue } void signalfd_read(int fd) { ssize_t s; struct signalfd_siginfo fdsi; struct gaicb *host; while((s = read(fd, &fdsi, sizeof(struct signalfd_siginfo))) > 0){ if (s != sizeof(struct signalfd_siginfo)) return; //thats bad host = fdsi.ssi_ptr; //the pointer passed sigevent structure //the result in host->ar_result member create_server(host); } } void create_server(struct gaicb *host) { struct addrinfo *rp, *result; int fd; result = host->ar_result; for(rp = result; rp != null; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); bind(fd, rp->ai_addr, rp->ai_addrlen); listen(fd, somaxconn); //error checks missing! freeaddrinfo(host->ar_request); freeaddrinfo(result); //you should free put gaicb } } int main(int argc, char *argv[]) { struct gaicb *host; struct addrinfo *hints; struct sigevent sig; host = calloc(1, sizeof(struct gaicb)); hints = calloc(1, sizeof(struct addrinfo)); hints->ai_family = af_unspec; //we dont care if v4 or v6 hints->ai_socktype = sock_stream; hints->ai_flags = ai_passive; //every other field null-d calloc host->ar_service = "8888"; //the port listen on host->ar_request = hints; sig.sigev_notify = sigev_signal; sig.sigev_value.sival_ptr = host; sig.sigev_signo = sigrtmin; getaddrinfo_a(gai_nowait, &host, 1, &sig); signalfd_setup(); //start event loop return 0; }
you can of course use simple signal handler job too, @ man sigaction more info.
Comments
Post a Comment