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 *); 
  1. the mode either gai_wait (which not want) , gai_nowait async lookups
  2. the gaicb argument accepts array of hosts lookup ent argument specifying how many elements array has
  3. 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; }; 
  1. you can ignore notification via setting _sigev_notify_ sigev_none
  2. 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
  3. 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

Popular posts from this blog

c++ - How do I get a multi line tooltip in MFC -

asp.net - In javascript how to find the height and width -

c# - DataTable to EnumerableRowCollection -