loudmouth/src/asyncns.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /* $Id: asyncns.c 27 2007-02-16 13:51:03Z lennart $ */
       
     2 
       
     3 /***
       
     4   This file is part of libasyncns.
       
     5   Copyright (C) 2006 Collabora Ltd.
       
     6   
       
     7   libasyncns is free software; you can redistribute it and/or modify
       
     8   it under the terms of the GNU Lesser General Public License as
       
     9   published by the Free Software Foundation; either version 2 of the
       
    10   License, or (at your option) any later version.
       
    11  
       
    12   libasyncns is distributed in the hope that it will be useful, but
       
    13   WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
       
    15   General Public License for more details.
       
    16  
       
    17   You should have received a copy of the GNU Lesser General Public
       
    18   License along with libasyncns; if not, write to the Free Software
       
    19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
       
    20   USA.
       
    21 ***/
       
    22 
       
    23 /*#undef HAVE_PTHREAD */
       
    24 
       
    25 #include <assert.h>
       
    26 #include <fcntl.h>
       
    27 #include <signal.h>
       
    28 #include <unistd.h>
       
    29 #include <sys/select.h>
       
    30 #include <stdio.h>
       
    31 #include <string.h>
       
    32 #include <stdlib.h>
       
    33 #include <errno.h>
       
    34 #include <sys/wait.h>
       
    35 #include <sys/types.h>
       
    36 #include <pwd.h>
       
    37 #include <netinet/in.h>
       
    38 #include <arpa/nameser.h>
       
    39 #include <resolv.h>
       
    40 
       
    41 #ifdef HAVE_SYS_PRCTL_H
       
    42 #include <sys/prctl.h>
       
    43 #endif
       
    44 
       
    45 #if HAVE_PTHREAD
       
    46 #include <pthread.h>
       
    47 #endif
       
    48 
       
    49 #include "asyncns.h"
       
    50 
       
    51 #define MAX_WORKERS 16
       
    52 #define MAX_QUERIES 256
       
    53 #define BUFSIZE (10240)
       
    54 
       
    55 typedef enum {
       
    56     REQUEST_ADDRINFO,
       
    57     RESPONSE_ADDRINFO,
       
    58     REQUEST_NAMEINFO,
       
    59     RESPONSE_NAMEINFO,
       
    60     REQUEST_RES_QUERY,
       
    61     REQUEST_RES_SEARCH,
       
    62     RESPONSE_RES,
       
    63     REQUEST_TERMINATE
       
    64 } query_type_t;
       
    65 
       
    66 enum {
       
    67     REQUEST_RECV_FD = 0,
       
    68     REQUEST_SEND_FD = 1,
       
    69     RESPONSE_RECV_FD = 2,
       
    70     RESPONSE_SEND_FD = 3
       
    71 };
       
    72 
       
    73 struct asyncns {
       
    74     int fds[4];
       
    75 
       
    76 #ifndef HAVE_PTHREAD    
       
    77     pid_t workers[MAX_WORKERS];
       
    78 #else
       
    79     pthread_t workers[MAX_WORKERS];
       
    80 #endif
       
    81     unsigned valid_workers;
       
    82 
       
    83     unsigned current_id, current_index;
       
    84     asyncns_query_t* queries[MAX_QUERIES];
       
    85 
       
    86     asyncns_query_t *done_head, *done_tail;
       
    87 
       
    88     int n_queries;
       
    89 };
       
    90 
       
    91 struct asyncns_query {
       
    92     asyncns_t *asyncns;
       
    93     int done;
       
    94     unsigned id;
       
    95     query_type_t type;
       
    96     asyncns_query_t *done_next, *done_prev;
       
    97     int ret;
       
    98     struct addrinfo *addrinfo;
       
    99     char *serv, *host;
       
   100     void *userdata;
       
   101 };
       
   102 
       
   103 typedef struct rheader {
       
   104     query_type_t type;
       
   105     unsigned id;
       
   106     size_t length;
       
   107 } rheader_t;
       
   108 
       
   109 typedef struct addrinfo_request {
       
   110     struct rheader header;
       
   111     int hints_is_null;
       
   112     int ai_flags;
       
   113     int ai_family;
       
   114     int ai_socktype;
       
   115     int ai_protocol;
       
   116     size_t node_len, service_len;
       
   117 } addrinfo_request_t;
       
   118 
       
   119 typedef struct addrinfo_response {
       
   120     struct rheader header;
       
   121     int ret;
       
   122 } addrinfo_response_t;
       
   123 
       
   124 typedef struct addrinfo_serialization {
       
   125     int ai_flags;
       
   126     int ai_family;
       
   127     int ai_socktype;
       
   128     int ai_protocol;
       
   129     size_t ai_addrlen;
       
   130     size_t canonname_len;
       
   131 } addrinfo_serialization_t;
       
   132 
       
   133 typedef struct nameinfo_request {
       
   134     struct rheader header;
       
   135     int flags;
       
   136     socklen_t sockaddr_len;
       
   137     int gethost, getserv;
       
   138 } nameinfo_request_t;
       
   139 
       
   140 typedef struct nameinfo_response {
       
   141     struct rheader header;
       
   142     size_t hostlen, servlen;
       
   143     int ret;
       
   144 } nameinfo_response_t;
       
   145 
       
   146 typedef struct res_query_request {
       
   147     struct rheader header;
       
   148     int class;
       
   149     int type;
       
   150     size_t dlen;
       
   151 } res_request_t;
       
   152 
       
   153 typedef struct res_query_response {
       
   154     struct rheader header;
       
   155     int ret;
       
   156 } res_response_t;
       
   157 
       
   158 #ifndef HAVE_STRNDUP
       
   159 
       
   160 static char *strndup(const char *s, size_t l) {
       
   161     size_t a;
       
   162     char *n;
       
   163 
       
   164     a = strlen(s);
       
   165     if (a > l)
       
   166         a = l;
       
   167 
       
   168     if (!(n = malloc(a+1)))
       
   169         return NULL;
       
   170 
       
   171     strncpy(n, s, a);
       
   172     n[a] = 0;
       
   173 
       
   174     return n;
       
   175 }
       
   176 
       
   177 #endif
       
   178 
       
   179 static int fd_nonblock(int fd) {
       
   180     int i;
       
   181     assert(fd >= 0);
       
   182 
       
   183     if ((i = fcntl(fd, F_GETFL, 0)) < 0)
       
   184         return -1;
       
   185 
       
   186     if (i & O_NONBLOCK)
       
   187         return 0;
       
   188 
       
   189     return fcntl(fd, F_SETFL, i | O_NONBLOCK);
       
   190 }
       
   191 
       
   192 static int fd_cloexec(int fd) {
       
   193     int v;
       
   194     assert(fd >= 0);
       
   195 
       
   196     if ((v = fcntl(fd, F_GETFD, 0)) < 0)
       
   197         return -1;
       
   198 
       
   199     if (v & FD_CLOEXEC)
       
   200         return 0;
       
   201     
       
   202     return fcntl(fd, F_SETFD, v | FD_CLOEXEC);
       
   203 }
       
   204 
       
   205 
       
   206 static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *length, size_t maxlength) {
       
   207     addrinfo_serialization_t *s = p;
       
   208     size_t cnl, l;
       
   209     assert(p);
       
   210     assert(ai);
       
   211     assert(length);
       
   212     assert(*length <= maxlength);
       
   213 
       
   214     cnl = (ai->ai_canonname ? strlen(ai->ai_canonname)+1 : 0);
       
   215     l = sizeof(addrinfo_serialization_t) + ai->ai_addrlen + cnl;
       
   216 
       
   217     if (*length + l > maxlength)
       
   218         return NULL;
       
   219 
       
   220     s->ai_flags = ai->ai_flags;
       
   221     s->ai_family = ai->ai_family;
       
   222     s->ai_socktype = ai->ai_socktype;
       
   223     s->ai_protocol = ai->ai_protocol;
       
   224     s->ai_addrlen = ai->ai_addrlen;
       
   225     s->canonname_len = cnl;
       
   226 
       
   227     memcpy((uint8_t*) p + sizeof(addrinfo_serialization_t), ai->ai_addr, ai->ai_addrlen);
       
   228 
       
   229     if (ai->ai_canonname)
       
   230         strcpy((char*) p + sizeof(addrinfo_serialization_t) + ai->ai_addrlen, ai->ai_canonname);
       
   231 
       
   232     *length += l;
       
   233     return (uint8_t*) p + l;
       
   234 }
       
   235 
       
   236 static int send_addrinfo_reply(int out_fd, unsigned id, int ret, struct addrinfo *ai) {
       
   237     uint8_t data[BUFSIZE];
       
   238     addrinfo_response_t *resp = (addrinfo_response_t*) data;
       
   239     assert(out_fd >= 0);
       
   240 
       
   241     resp->header.type = RESPONSE_ADDRINFO;
       
   242     resp->header.id = id;
       
   243     resp->header.length = sizeof(addrinfo_response_t);
       
   244     resp->ret = ret;
       
   245 
       
   246     if (ret == 0 && ai) {
       
   247         void *p = data + sizeof(addrinfo_response_t);
       
   248 
       
   249         while (ai && p) {
       
   250             p = serialize_addrinfo(p, ai, &resp->header.length, BUFSIZE);
       
   251             ai = ai->ai_next;
       
   252         }
       
   253     }
       
   254 
       
   255     if (ai)
       
   256         freeaddrinfo(ai);
       
   257 
       
   258     return send(out_fd, resp, resp->header.length, 0);
       
   259 }
       
   260 
       
   261 static int send_nameinfo_reply(int out_fd, unsigned id, int ret, const char *host, const char *serv) {
       
   262     uint8_t data[BUFSIZE];
       
   263     size_t hl, sl;
       
   264     nameinfo_response_t *resp = (nameinfo_response_t*) data;
       
   265 
       
   266     assert(out_fd >= 0);
       
   267     
       
   268     sl = serv ? strlen(serv)+1 : 0;
       
   269     hl = host ? strlen(host)+1 : 0;
       
   270 
       
   271     resp->header.type = RESPONSE_NAMEINFO;
       
   272     resp->header.id = id;
       
   273     resp->header.length = sizeof(nameinfo_response_t) + hl + sl;
       
   274     resp->ret = ret;
       
   275     resp->hostlen = hl;
       
   276     resp->servlen = sl;
       
   277 
       
   278     assert(sizeof(data) >= resp->header.length);
       
   279     
       
   280     if (host)
       
   281         memcpy(data + sizeof(nameinfo_response_t), host, hl);
       
   282 
       
   283     if (serv)
       
   284         memcpy(data + sizeof(nameinfo_response_t) + hl, serv, sl);
       
   285     
       
   286     return send(out_fd, resp, resp->header.length, 0);
       
   287 }
       
   288 
       
   289 static int send_res_reply(int out_fd, unsigned id, const unsigned char *answer, int ret) {
       
   290     uint8_t data[BUFSIZE];
       
   291     res_response_t *resp = (res_response_t *) data;
       
   292 
       
   293     assert(out_fd >= 0);
       
   294     
       
   295     resp->header.type = RESPONSE_RES;
       
   296     resp->header.id = id;
       
   297     resp->header.length = sizeof(res_response_t) + (ret < 0 ? 0 : ret);
       
   298     resp->ret = (ret < 0) ? -errno : ret;
       
   299 
       
   300     assert(sizeof(data) >= resp->header.length);
       
   301     
       
   302     if (ret > 0)
       
   303         memcpy(data + sizeof(res_response_t), answer, ret);
       
   304 
       
   305     return send(out_fd, resp, resp->header.length, 0);
       
   306 }
       
   307 
       
   308 static int handle_request(int out_fd, const rheader_t *req, size_t length) {
       
   309     assert(out_fd >= 0);
       
   310     assert(req);
       
   311     assert(length >= sizeof(rheader_t));
       
   312     assert(length == req->length);
       
   313 
       
   314     switch (req->type) {
       
   315         case REQUEST_ADDRINFO: {
       
   316             struct addrinfo ai, *result = NULL;
       
   317             const addrinfo_request_t *ai_req = (const addrinfo_request_t*) req;
       
   318             const char *node, *service;
       
   319             int ret;
       
   320 
       
   321             assert(length >= sizeof(addrinfo_request_t));
       
   322             assert(length == sizeof(addrinfo_request_t) + ai_req->node_len + ai_req->service_len);
       
   323 
       
   324             memset(&ai, 0, sizeof(ai));
       
   325             ai.ai_flags = ai_req->ai_flags;
       
   326             ai.ai_family = ai_req->ai_family;
       
   327             ai.ai_socktype = ai_req->ai_socktype;
       
   328             ai.ai_protocol = ai_req->ai_protocol;
       
   329 
       
   330             node = ai_req->node_len ? (const char*) req + sizeof(addrinfo_request_t) : NULL;
       
   331             service = ai_req->service_len ? (const char*) req + sizeof(addrinfo_request_t) + ai_req->node_len : NULL;
       
   332 
       
   333             /*printf("[getaddrinfo for '%s']\n", node);*/
       
   334             ret = getaddrinfo(node, service,
       
   335                               ai_req->hints_is_null ? NULL : &ai,
       
   336                               &result);
       
   337             /*printf("[return value: %d: '%s']\n", ret, gai_strerror(ret));*/
       
   338 
       
   339             /* send_addrinfo_reply() frees result */
       
   340             return send_addrinfo_reply(out_fd, req->id, ret, result);
       
   341         }
       
   342 
       
   343         case REQUEST_NAMEINFO: {
       
   344             int ret;
       
   345             const nameinfo_request_t *ni_req = (const nameinfo_request_t*) req;
       
   346             char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
       
   347             const struct sockaddr *sa;
       
   348             
       
   349             assert(length >= sizeof(nameinfo_request_t));
       
   350             assert(length == sizeof(nameinfo_request_t) + ni_req->sockaddr_len);
       
   351 
       
   352             sa = (const struct sockaddr*) ((const char*) req + sizeof(nameinfo_request_t));
       
   353             
       
   354             ret = getnameinfo(sa, ni_req->sockaddr_len,
       
   355                               ni_req->gethost ? hostbuf : NULL, ni_req->gethost ? sizeof(hostbuf) : 0,
       
   356                               ni_req->getserv ? servbuf : NULL, ni_req->getserv ? sizeof(servbuf) : 0,
       
   357                               ni_req->flags);
       
   358 
       
   359             return send_nameinfo_reply(out_fd, req->id, ret,
       
   360                                        ret == 0 && ni_req->gethost ? hostbuf : NULL,
       
   361                                        ret == 0 && ni_req->getserv ? servbuf : NULL);
       
   362         }
       
   363 
       
   364         case REQUEST_RES_QUERY: 
       
   365         case REQUEST_RES_SEARCH: {
       
   366             int ret;
       
   367             unsigned char answer[BUFSIZE];
       
   368             const res_request_t *res_req = (const res_request_t *)req;
       
   369             const char *dname;
       
   370 
       
   371             assert(length >= sizeof(res_request_t));
       
   372             assert(length == sizeof(res_request_t) + res_req->dlen + 1);
       
   373 
       
   374             dname = (const char *) req + sizeof(res_request_t);
       
   375 
       
   376             if (req->type == REQUEST_RES_QUERY) { 
       
   377                 /*printf("[res query for '%s']\n", dname);*/
       
   378                 ret = res_query(dname, res_req->class, res_req->type, 
       
   379                                 answer, BUFSIZE);
       
   380                 /*printf("[return value: %d]\n", ret);*/
       
   381             } else {
       
   382                 ret = res_search(dname, res_req->class, res_req->type, 
       
   383                                  answer, BUFSIZE);
       
   384             }
       
   385             return send_res_reply(out_fd, req->id, answer, ret);
       
   386         }
       
   387 
       
   388         case REQUEST_TERMINATE: {
       
   389             /* Quit */
       
   390             return -1;
       
   391         }
       
   392 
       
   393         default:
       
   394             ;
       
   395     }
       
   396 
       
   397     return 0;
       
   398 }
       
   399 
       
   400 #ifndef HAVE_PTHREAD
       
   401 
       
   402 static int process_worker(int in_fd, int out_fd) {
       
   403     int have_death_sig = 0;
       
   404     assert(in_fd > 2);
       
   405     assert(out_fd > 2);
       
   406     
       
   407     close(0);
       
   408     close(1);
       
   409     close(2);
       
   410 
       
   411     open("/dev/null", O_RDONLY);
       
   412     open("/dev/null", O_WRONLY);
       
   413     open("/dev/null", O_WRONLY);
       
   414 
       
   415     chdir("/");
       
   416 
       
   417     if (geteuid() == 0) {
       
   418         struct passwd *pw;
       
   419 
       
   420         if ((pw = getpwnam("nobody"))) {
       
   421 #ifdef HAVE_SETRESUID            
       
   422             setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid);
       
   423 #elif HAVE_SETREUID
       
   424             setreuid(pw->pw_uid, pw->pw_uid);
       
   425 #else
       
   426             setuid(pw->pw_uid);
       
   427             seteuid(pw->pw_uid);
       
   428 #endif
       
   429         }
       
   430     }
       
   431 
       
   432     signal(SIGTERM, SIG_DFL);
       
   433 
       
   434     signal(SIGINT, SIG_IGN);
       
   435     signal(SIGHUP, SIG_IGN);
       
   436     signal(SIGPIPE, SIG_IGN);
       
   437     signal(SIGUSR1, SIG_IGN);
       
   438     signal(SIGUSR2, SIG_IGN);
       
   439 
       
   440 #ifdef PR_SET_PDEATHSIG
       
   441     if (prctl(PR_SET_PDEATHSIG, SIGTERM) >= 0)
       
   442         have_death_sig = 1;
       
   443 #endif
       
   444 
       
   445     if (!have_death_sig)
       
   446         fd_nonblock(in_fd);
       
   447     
       
   448     while (getppid() > 1) { /* if the parent PID is 1 our parent process died. */
       
   449         char buf[BUFSIZE];
       
   450         ssize_t length;
       
   451 
       
   452         if (!have_death_sig) {
       
   453             fd_set fds;
       
   454             struct timeval tv = { 0, 500000 } ;
       
   455             
       
   456             FD_ZERO(&fds);
       
   457             FD_SET(in_fd, &fds);
       
   458             
       
   459             if (select(in_fd+1, &fds, NULL, NULL, &tv) < 0)
       
   460                 break;
       
   461             
       
   462             if (getppid() == 1)
       
   463                 break;
       
   464         }
       
   465         
       
   466         if ((length = recv(in_fd, buf, sizeof(buf), 0)) <= 0) {
       
   467 
       
   468             if (length < 0 && errno == EAGAIN)
       
   469                 continue;
       
   470 
       
   471             break;
       
   472         }
       
   473 
       
   474         if (handle_request(out_fd, (rheader_t*) buf, (size_t) length) < 0)
       
   475             break;
       
   476     }
       
   477 
       
   478     close(in_fd);
       
   479     close(out_fd);
       
   480     
       
   481     return 0;
       
   482 }
       
   483 
       
   484 #else
       
   485 
       
   486 static void* thread_worker(void *p) {
       
   487     sigset_t fullset;
       
   488     int *fds = p;
       
   489     pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
       
   490 
       
   491     /* No signals in this thread please */
       
   492     sigfillset(&fullset);
       
   493     pthread_sigmask(SIG_BLOCK, &fullset, NULL);
       
   494     
       
   495     for (;;) {
       
   496         char buf[BUFSIZE];
       
   497         ssize_t length;
       
   498 
       
   499         if ((length = recv(fds[REQUEST_RECV_FD], buf, sizeof(buf), 0)) <= 0)
       
   500             break;
       
   501 
       
   502         if (handle_request(fds[RESPONSE_SEND_FD], (rheader_t*) buf, (size_t) length) < 0)
       
   503             break;
       
   504         
       
   505     }
       
   506 
       
   507     return NULL;
       
   508 }
       
   509 
       
   510 #endif
       
   511 
       
   512 asyncns_t* asyncns_new(unsigned n_proc) {
       
   513     asyncns_t *asyncns = NULL;
       
   514     int i;
       
   515     unsigned p;
       
   516     assert(n_proc >= 1);
       
   517 
       
   518     if (n_proc > MAX_WORKERS)
       
   519         n_proc = MAX_WORKERS;
       
   520 
       
   521     if (!(asyncns = malloc(sizeof(asyncns_t))))
       
   522         goto fail;
       
   523 
       
   524     asyncns->valid_workers = 0;
       
   525 
       
   526     for (i = 0; i < 4; i++) 
       
   527         asyncns->fds[i] = -1;
       
   528         
       
   529     for (p = 0; p < MAX_QUERIES; p++)
       
   530         asyncns->queries[p] = NULL;
       
   531     
       
   532     if (socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds) < 0 ||
       
   533         socketpair(PF_UNIX, SOCK_DGRAM, 0, asyncns->fds+2) < 0)
       
   534         goto fail;
       
   535     
       
   536     for (i = 0; i < 4; i++) 
       
   537         fd_cloexec(asyncns->fds[i]);
       
   538 
       
   539     for (asyncns->valid_workers = 0; asyncns->valid_workers < n_proc; asyncns->valid_workers++) {
       
   540 
       
   541 #ifndef HAVE_PTHREAD
       
   542         if ((asyncns->workers[asyncns->valid_workers] = fork()) < 0)
       
   543             goto fail;
       
   544         else if (asyncns->workers[asyncns->valid_workers] == 0) {
       
   545             close(asyncns->fds[REQUEST_SEND_FD]);
       
   546             close(asyncns->fds[RESPONSE_RECV_FD]);
       
   547             _exit(process_worker(asyncns->fds[REQUEST_RECV_FD], asyncns->fds[RESPONSE_SEND_FD]));
       
   548         }
       
   549 #else
       
   550         if (pthread_create(&asyncns->workers[asyncns->valid_workers], NULL, thread_worker, asyncns->fds) != 0)
       
   551             goto fail;
       
   552 #endif
       
   553     }
       
   554 
       
   555 #ifndef HAVE_PTHREAD
       
   556     close(asyncns->fds[REQUEST_RECV_FD]);
       
   557     close(asyncns->fds[RESPONSE_SEND_FD]);
       
   558     asyncns->fds[REQUEST_RECV_FD] = asyncns->fds[RESPONSE_SEND_FD] = -1;
       
   559 #endif    
       
   560     
       
   561     asyncns->current_index = asyncns->current_id = 0;
       
   562     asyncns->done_head = asyncns->done_tail = NULL;
       
   563     asyncns->n_queries = 0;
       
   564 
       
   565     fd_nonblock(asyncns->fds[RESPONSE_RECV_FD]);
       
   566 
       
   567     return asyncns;
       
   568 
       
   569 fail:
       
   570     if (asyncns) 
       
   571         asyncns_free(asyncns);
       
   572 
       
   573     return NULL;
       
   574 }
       
   575 
       
   576 void asyncns_free(asyncns_t *asyncns) {
       
   577     unsigned p;
       
   578     int i;
       
   579     rheader_t req;
       
   580     assert(asyncns);
       
   581 
       
   582     req.type = REQUEST_TERMINATE;
       
   583     req.length = sizeof(req);
       
   584     req.id = 0;
       
   585     
       
   586     /* Send one termiantion packet for each worker */
       
   587     for (p = 0; p < asyncns->valid_workers; p++)
       
   588         send(asyncns->fds[REQUEST_SEND_FD], &req, req.length, 0);
       
   589 
       
   590     /* No terminate them forcibly*/
       
   591     for (p = 0; p < asyncns->valid_workers; p++) {
       
   592 #ifndef HAVE_PTHREAD
       
   593         kill(asyncns->workers[p], SIGTERM);
       
   594         waitpid(asyncns->workers[p], NULL, 0);
       
   595 #else
       
   596         pthread_cancel(asyncns->workers[p]);
       
   597         pthread_join(asyncns->workers[p], NULL);
       
   598 #endif        
       
   599     }
       
   600 
       
   601     /* Due to Solaris' broken thread cancelation we first send an
       
   602      * termination request and then cancel th thread. */
       
   603 
       
   604     
       
   605     for (i = 0; i < 4; i++)
       
   606         if (asyncns->fds[i] >= 0)
       
   607             close(asyncns->fds[i]);
       
   608     
       
   609     for (p = 0; p < MAX_QUERIES; p++)
       
   610         if (asyncns->queries[p])
       
   611             asyncns_cancel(asyncns, asyncns->queries[p]);
       
   612     
       
   613     free(asyncns);
       
   614 }
       
   615 
       
   616 int asyncns_fd(asyncns_t *asyncns) {
       
   617     assert(asyncns);
       
   618 
       
   619     return asyncns->fds[RESPONSE_RECV_FD];
       
   620 }
       
   621 
       
   622 static asyncns_query_t *lookup_query(asyncns_t *asyncns, unsigned id) {
       
   623     asyncns_query_t *q;
       
   624     assert(asyncns);
       
   625 
       
   626     if ((q = asyncns->queries[id % MAX_QUERIES]))
       
   627         if (q->id == id)
       
   628             return q;
       
   629 
       
   630     return NULL;
       
   631 }
       
   632 
       
   633 static void complete_query(asyncns_t *asyncns, asyncns_query_t *q) {
       
   634     assert(asyncns);
       
   635     assert(q);
       
   636     assert(!q->done);
       
   637 
       
   638     q->done = 1;
       
   639     
       
   640     if ((q->done_prev = asyncns->done_tail))
       
   641         asyncns->done_tail->done_next = q;
       
   642     else
       
   643         asyncns->done_head = q;
       
   644 
       
   645     asyncns->done_tail = q;
       
   646     q->done_next = NULL;
       
   647 }
       
   648 
       
   649 static void *unserialize_addrinfo(void *p, struct addrinfo **ret_ai, size_t *length) {
       
   650     addrinfo_serialization_t *s = p;
       
   651     size_t l;
       
   652     struct addrinfo *ai;
       
   653     assert(p);
       
   654     assert(ret_ai);
       
   655     assert(length);
       
   656 
       
   657     if (*length < sizeof(addrinfo_serialization_t))
       
   658         return NULL;
       
   659 
       
   660     l = sizeof(addrinfo_serialization_t) + s->ai_addrlen + s->canonname_len;
       
   661     if (*length < l)
       
   662         return NULL;
       
   663 
       
   664     if (!(ai = malloc(sizeof(struct addrinfo))))
       
   665         goto fail;
       
   666     
       
   667     ai->ai_addr = NULL;
       
   668     ai->ai_canonname = NULL;
       
   669     ai->ai_next = NULL;
       
   670 
       
   671     if (s->ai_addrlen && !(ai->ai_addr = malloc(s->ai_addrlen)))
       
   672         goto fail;
       
   673     
       
   674     if (s->canonname_len && !(ai->ai_canonname = malloc(s->canonname_len)))
       
   675         goto fail;
       
   676 
       
   677     ai->ai_flags = s->ai_flags;
       
   678     ai->ai_family = s->ai_family;
       
   679     ai->ai_socktype = s->ai_socktype;
       
   680     ai->ai_protocol = s->ai_protocol;
       
   681     ai->ai_addrlen = s->ai_addrlen;
       
   682 
       
   683     if (ai->ai_addr)
       
   684         memcpy(ai->ai_addr, (uint8_t*) p + sizeof(addrinfo_serialization_t), s->ai_addrlen);
       
   685 
       
   686     if (ai->ai_canonname)
       
   687         memcpy(ai->ai_canonname, (uint8_t*) p + sizeof(addrinfo_serialization_t) + s->ai_addrlen, s->canonname_len);
       
   688 
       
   689     *length -= l;
       
   690     *ret_ai = ai;
       
   691     
       
   692     return (uint8_t*) p + l;
       
   693 
       
   694 
       
   695 fail:
       
   696     if (ai)
       
   697         asyncns_freeaddrinfo(ai);
       
   698 
       
   699     return NULL;
       
   700 }
       
   701 
       
   702 static int handle_response(asyncns_t *asyncns, rheader_t *resp, size_t length) {
       
   703     asyncns_query_t *q;
       
   704     assert(asyncns);
       
   705     assert(resp);
       
   706     assert(length >= sizeof(rheader_t));
       
   707     assert(length == resp->length);
       
   708 
       
   709     if (!(q = lookup_query(asyncns, resp->id)))
       
   710         return 0;
       
   711     
       
   712     switch (resp->type) {
       
   713         case RESPONSE_ADDRINFO: {
       
   714             const addrinfo_response_t *ai_resp = (addrinfo_response_t*) resp;
       
   715             void *p;
       
   716             size_t l;
       
   717             struct addrinfo *prev = NULL;
       
   718 
       
   719             assert(length >= sizeof(addrinfo_response_t));
       
   720             assert(q->type == REQUEST_ADDRINFO);
       
   721 
       
   722             q->ret = ai_resp->ret;
       
   723             l = length - sizeof(addrinfo_response_t);
       
   724             p = (uint8_t*) resp + sizeof(addrinfo_response_t);
       
   725 
       
   726             while (l > 0 && p) {
       
   727                 struct addrinfo *ai = NULL;
       
   728                 p = unserialize_addrinfo(p, &ai, &l);
       
   729 
       
   730                 if (!ai)
       
   731                     break;
       
   732 
       
   733                 if (prev)
       
   734                     prev->ai_next = ai;
       
   735                 else
       
   736                     q->addrinfo = ai;
       
   737 
       
   738                 prev = ai;
       
   739             }
       
   740 
       
   741             complete_query(asyncns, q);
       
   742             break;
       
   743         }
       
   744 
       
   745         case RESPONSE_NAMEINFO: {
       
   746             const nameinfo_response_t *ni_resp = (nameinfo_response_t*) resp;
       
   747 
       
   748             assert(length >= sizeof(nameinfo_response_t));
       
   749             assert(q->type == REQUEST_NAMEINFO);
       
   750 
       
   751             q->ret = ni_resp->ret;
       
   752 
       
   753             if (ni_resp->hostlen)
       
   754                 q->host = strndup((const char*) ni_resp + sizeof(nameinfo_response_t), ni_resp->hostlen-1);
       
   755 
       
   756             if (ni_resp->servlen)
       
   757                 q->serv = strndup((const char*) ni_resp + sizeof(nameinfo_response_t) + ni_resp->hostlen, ni_resp->servlen-1);
       
   758                     
       
   759 
       
   760             complete_query(asyncns, q);
       
   761             break;
       
   762         }
       
   763 
       
   764         case RESPONSE_RES: {
       
   765             const res_response_t *res_resp = (res_response_t *)resp;
       
   766 
       
   767             assert(length >= sizeof(res_response_t));
       
   768             assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
       
   769 
       
   770             q->ret = res_resp->ret;
       
   771 
       
   772             if (res_resp->ret >= 0)  {
       
   773                 q->serv = malloc(res_resp->ret);
       
   774                 memcpy(q->serv, (char *)resp + sizeof(res_response_t), res_resp->ret);
       
   775             }
       
   776 
       
   777             complete_query(asyncns, q);
       
   778             break;
       
   779         }
       
   780             
       
   781         default:
       
   782             ;
       
   783     }
       
   784     
       
   785     return 0;
       
   786 }
       
   787 
       
   788 int asyncns_wait(asyncns_t *asyncns, int block) {
       
   789     int handled = 0;
       
   790     assert(asyncns);
       
   791 
       
   792     for (;;) {
       
   793         char buf[BUFSIZE];
       
   794         ssize_t l;
       
   795 
       
   796         if (((l = recv(asyncns->fds[RESPONSE_RECV_FD], buf, sizeof(buf), 0)) < 0)) {
       
   797             fd_set fds;
       
   798 
       
   799             if (errno != EAGAIN)
       
   800                 return -1;
       
   801 
       
   802             if (!block || handled)
       
   803                 return 0;
       
   804                 
       
   805             FD_ZERO(&fds);
       
   806             FD_SET(asyncns->fds[RESPONSE_RECV_FD], &fds);
       
   807 
       
   808             if (select(asyncns->fds[RESPONSE_RECV_FD]+1, &fds, NULL, NULL, NULL) < 0)
       
   809                 return -1;
       
   810                 
       
   811             continue;
       
   812         }
       
   813 
       
   814 
       
   815         if (handle_response(asyncns, (rheader_t*) buf, (size_t) l) < 0)
       
   816             return -1;
       
   817 
       
   818         handled = 1;
       
   819     }
       
   820 }
       
   821 
       
   822 static asyncns_query_t *alloc_query(asyncns_t *asyncns) {
       
   823     asyncns_query_t *q;
       
   824     assert(asyncns);
       
   825 
       
   826     if (asyncns->n_queries >= MAX_QUERIES)
       
   827         return NULL;
       
   828 
       
   829     while (asyncns->queries[asyncns->current_index]) {
       
   830 
       
   831         asyncns->current_index++;
       
   832         asyncns->current_id++;
       
   833 
       
   834         while (asyncns->current_index >= MAX_QUERIES)
       
   835             asyncns->current_index -= MAX_QUERIES;
       
   836     }
       
   837         
       
   838     if (!(q = asyncns->queries[asyncns->current_index] = malloc(sizeof(asyncns_query_t))))
       
   839         return NULL;
       
   840 
       
   841     asyncns->n_queries++;
       
   842 
       
   843     q->asyncns = asyncns;
       
   844     q->done = 0;
       
   845     q->id = asyncns->current_id;
       
   846     q->done_next = q->done_prev = NULL;
       
   847     q->ret = 0;
       
   848     q->addrinfo = NULL;
       
   849     q->userdata = NULL;
       
   850     q->host = q->serv = NULL;
       
   851 
       
   852     return q;
       
   853 }
       
   854 
       
   855 asyncns_query_t* asyncns_getaddrinfo(asyncns_t *asyncns, const char *node, const char *service, const struct addrinfo *hints) {
       
   856     uint8_t data[BUFSIZE];
       
   857     addrinfo_request_t *req = (addrinfo_request_t*) data;
       
   858     asyncns_query_t *q;
       
   859     assert(asyncns);
       
   860     assert(node || service);
       
   861 
       
   862     if (!(q = alloc_query(asyncns)))
       
   863         return NULL;
       
   864 
       
   865     memset(req, 0, sizeof(addrinfo_request_t));
       
   866     
       
   867     req->node_len = node ? strlen(node)+1 : 0;
       
   868     req->service_len = service ? strlen(service)+1 : 0;
       
   869     
       
   870     req->header.id = q->id;
       
   871     req->header.type = q->type = REQUEST_ADDRINFO;
       
   872     req->header.length = sizeof(addrinfo_request_t) + req->node_len + req->service_len;
       
   873 
       
   874     if (req->header.length > BUFSIZE)
       
   875         goto fail;
       
   876 
       
   877     if (!(req->hints_is_null = !hints)) {
       
   878         req->ai_flags = hints->ai_flags; 
       
   879         req->ai_family = hints->ai_family;
       
   880         req->ai_socktype = hints->ai_socktype;
       
   881         req->ai_protocol = hints->ai_protocol;
       
   882     }
       
   883 
       
   884     if (node)
       
   885         strcpy((char*) req + sizeof(addrinfo_request_t), node);
       
   886 
       
   887     if (service)
       
   888         strcpy((char*) req + sizeof(addrinfo_request_t) + req->node_len, service);
       
   889 
       
   890     if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, 0) < 0)
       
   891         goto fail;
       
   892     
       
   893     return q;
       
   894 
       
   895 fail:
       
   896     if (q)
       
   897         asyncns_cancel(asyncns, q);
       
   898 
       
   899     return NULL;
       
   900 }
       
   901 
       
   902 int asyncns_getaddrinfo_done(asyncns_t *asyncns, asyncns_query_t* q, struct addrinfo **ret_res) {
       
   903     int ret;
       
   904     assert(asyncns);
       
   905     assert(q);
       
   906     assert(q->asyncns == asyncns);
       
   907     assert(q->type == REQUEST_ADDRINFO);
       
   908 
       
   909     if (!q->done)
       
   910         return EAI_AGAIN;
       
   911 
       
   912     *ret_res = q->addrinfo;
       
   913     q->addrinfo = NULL;
       
   914     ret = q->ret;
       
   915     asyncns_cancel(asyncns, q);
       
   916 
       
   917     return ret;
       
   918 }
       
   919 
       
   920 asyncns_query_t* asyncns_getnameinfo(asyncns_t *asyncns, const struct sockaddr *sa, socklen_t salen, int flags, int gethost, int getserv) {
       
   921     uint8_t data[BUFSIZE];
       
   922     nameinfo_request_t *req = (nameinfo_request_t*) data;
       
   923     asyncns_query_t *q;
       
   924 
       
   925     assert(asyncns);
       
   926     assert(sa);
       
   927     assert(salen > 0);
       
   928 
       
   929     if (!(q = alloc_query(asyncns)))
       
   930         return NULL;
       
   931 
       
   932     memset(req, 0, sizeof(nameinfo_request_t));
       
   933     
       
   934     req->header.id = q->id;
       
   935     req->header.type = q->type = REQUEST_NAMEINFO;
       
   936     req->header.length = sizeof(nameinfo_request_t) + salen;
       
   937 
       
   938     if (req->header.length > BUFSIZE)
       
   939         goto fail;
       
   940 
       
   941     req->flags = flags;
       
   942     req->sockaddr_len = salen;
       
   943     req->gethost = gethost;
       
   944     req->getserv = getserv;
       
   945 
       
   946     memcpy((uint8_t*) req + sizeof(nameinfo_request_t), sa, salen);
       
   947 
       
   948     if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, 0) < 0)
       
   949         goto fail;
       
   950     
       
   951     return q;
       
   952 
       
   953 fail:
       
   954     if (q)
       
   955         asyncns_cancel(asyncns, q);
       
   956 
       
   957     return NULL;
       
   958 }
       
   959 
       
   960 int asyncns_getnameinfo_done(asyncns_t *asyncns, asyncns_query_t* q, char *ret_host, size_t hostlen, char *ret_serv, size_t servlen) {
       
   961     int ret;
       
   962     assert(asyncns);
       
   963     assert(q);
       
   964     assert(q->asyncns == asyncns);
       
   965     assert(q->type == REQUEST_NAMEINFO);
       
   966     assert(!ret_host || hostlen);
       
   967     assert(!ret_serv || servlen);
       
   968 
       
   969     if (!q->done)
       
   970         return EAI_AGAIN;
       
   971 
       
   972     if (ret_host && q->host) {
       
   973         strncpy(ret_host, q->host, hostlen);
       
   974         ret_host[hostlen-1] = 0;
       
   975     }
       
   976 
       
   977     if (ret_serv && q->serv) {
       
   978         strncpy(ret_serv, q->serv, servlen);
       
   979         ret_serv[servlen-1] = 0;
       
   980     }
       
   981     
       
   982     ret = q->ret;
       
   983     asyncns_cancel(asyncns, q);
       
   984 
       
   985     return ret;
       
   986 }
       
   987 
       
   988 static asyncns_query_t *
       
   989 asyncns_res(asyncns_t *asyncns, query_type_t qtype, 
       
   990             const char *dname, int class, int type) {
       
   991     uint8_t data[BUFSIZE];
       
   992     res_request_t *req = (res_request_t*) data;
       
   993     asyncns_query_t *q;
       
   994     size_t dlen;
       
   995 
       
   996     assert(asyncns);
       
   997     assert(dname);
       
   998 
       
   999     dlen = strlen(dname);
       
  1000 
       
  1001     if (!(q = alloc_query(asyncns)))
       
  1002         return NULL;
       
  1003 
       
  1004     memset(req, 0, sizeof(res_request_t));
       
  1005     
       
  1006     req->header.id = q->id;
       
  1007     req->header.type = q->type = qtype;
       
  1008     req->header.length = sizeof(res_request_t) + dlen + 1;
       
  1009 
       
  1010     if (req->header.length > BUFSIZE)
       
  1011         goto fail;
       
  1012 
       
  1013     req->class = class;
       
  1014     req->type = type;
       
  1015     req->dlen = dlen;
       
  1016 
       
  1017     memcpy((uint8_t*) req + sizeof(res_request_t), dname, dlen + 1);
       
  1018 
       
  1019     if (send(asyncns->fds[REQUEST_SEND_FD], req, req->header.length, 0) < 0)
       
  1020         goto fail;
       
  1021 
       
  1022     return q;
       
  1023 
       
  1024 fail:
       
  1025     if (q)
       
  1026         asyncns_cancel(asyncns, q);
       
  1027 
       
  1028     return NULL;
       
  1029 }
       
  1030 
       
  1031 asyncns_query_t* asyncns_res_query(asyncns_t *asyncns, const char *dname, int class, int type) { 
       
  1032     return asyncns_res(asyncns, REQUEST_RES_QUERY, dname, class, type);
       
  1033 }
       
  1034 
       
  1035 asyncns_query_t* asyncns_res_search(asyncns_t *asyncns, const char *dname, int class, int type) { 
       
  1036     return asyncns_res(asyncns, REQUEST_RES_SEARCH, dname, class, type);
       
  1037 }
       
  1038 
       
  1039 int asyncns_res_done(asyncns_t *asyncns, asyncns_query_t* q, unsigned char **answer) {
       
  1040     int ret;
       
  1041     assert(asyncns);
       
  1042     assert(q);
       
  1043     assert(q->asyncns == asyncns);
       
  1044     assert(q->type == REQUEST_RES_QUERY || q->type == REQUEST_RES_SEARCH);
       
  1045     assert(answer);
       
  1046 
       
  1047     if (!q->done)
       
  1048         return -EAGAIN;
       
  1049 
       
  1050     *answer = (unsigned char *)q->serv;
       
  1051     q->serv = NULL;
       
  1052 
       
  1053     ret = q->ret;
       
  1054 
       
  1055     asyncns_cancel(asyncns, q);
       
  1056 
       
  1057     return ret;
       
  1058 }
       
  1059 
       
  1060 asyncns_query_t* asyncns_getnext(asyncns_t *asyncns) {
       
  1061     assert(asyncns);
       
  1062     return asyncns->done_head;
       
  1063 }
       
  1064 
       
  1065 int asyncns_getnqueries(asyncns_t *asyncns) {
       
  1066     assert(asyncns);
       
  1067     return asyncns->n_queries;
       
  1068 }
       
  1069 
       
  1070 void asyncns_cancel(asyncns_t *asyncns, asyncns_query_t* q) {
       
  1071     int i;
       
  1072     assert(asyncns);
       
  1073     assert(q);
       
  1074     assert(q->asyncns == asyncns);
       
  1075     assert(asyncns->n_queries > 0);
       
  1076 
       
  1077     if (q->done) {
       
  1078 
       
  1079         if (q->done_prev)
       
  1080             q->done_prev->done_next = q->done_next;
       
  1081         else 
       
  1082             asyncns->done_head = q->done_next;
       
  1083 
       
  1084         if (q->done_next)
       
  1085             q->done_next->done_prev = q->done_prev;
       
  1086         else
       
  1087             asyncns->done_tail = q->done_prev;
       
  1088     }
       
  1089 
       
  1090 
       
  1091     i = q->id % MAX_QUERIES;
       
  1092     assert(asyncns->queries[i] == q);
       
  1093     asyncns->queries[i] = NULL;
       
  1094 
       
  1095     asyncns_freeaddrinfo(q->addrinfo);
       
  1096     free(q->addrinfo);
       
  1097     free(q->host);
       
  1098     free(q->serv);
       
  1099 
       
  1100     asyncns->n_queries--;
       
  1101     free(q);
       
  1102 }
       
  1103 
       
  1104 void asyncns_freeaddrinfo(struct addrinfo *ai) {
       
  1105     if (!ai)
       
  1106         return;
       
  1107 
       
  1108     while (ai) {
       
  1109         struct addrinfo *next = ai->ai_next;
       
  1110 
       
  1111         free(ai->ai_addr);
       
  1112         free(ai->ai_canonname);
       
  1113         free(ai);
       
  1114 
       
  1115         ai = next;
       
  1116     }
       
  1117 }
       
  1118 
       
  1119 int asyncns_isdone(asyncns_t *asyncns, asyncns_query_t*q) {
       
  1120     assert(asyncns);
       
  1121     assert(q);
       
  1122     assert(q->asyncns == asyncns);
       
  1123 
       
  1124     return q->done;
       
  1125 }
       
  1126 
       
  1127 void asyncns_setuserdata(asyncns_t *asyncns, asyncns_query_t *q, void *userdata) {
       
  1128     assert(q);
       
  1129     assert(asyncns);
       
  1130     assert(q->asyncns = asyncns);
       
  1131     
       
  1132     q->userdata = userdata;
       
  1133 }
       
  1134 
       
  1135 void* asyncns_getuserdata(asyncns_t *asyncns, asyncns_query_t *q) {
       
  1136     assert(q);
       
  1137     assert(asyncns);
       
  1138     assert(q->asyncns = asyncns);
       
  1139 
       
  1140     return q->userdata;
       
  1141 }
       
  1142 
       
  1143