"Fossies" - the Fresh Open Source Software Archive

Member "adns-1.5.1/src/event.c" (12 Aug 2016, 20896 Bytes) of package /linux/misc/dns/adns-1.5.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "event.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.0_vs_1.5.1.

    1 /*
    2  * event.c
    3  * - event loop core
    4  * - TCP connection management
    5  * - user-visible check/wait and event-loop-related functions
    6  */
    7 /*
    8  *  This file is part of adns, which is
    9  *    Copyright (C) 1997-2000,2003,2006,2014-2016  Ian Jackson
   10  *    Copyright (C) 2014  Mark Wooding
   11  *    Copyright (C) 1999-2000,2003,2006  Tony Finch
   12  *    Copyright (C) 1991 Massachusetts Institute of Technology
   13  *  (See the file INSTALL for full details.)
   14  *  
   15  *  This program is free software; you can redistribute it and/or modify
   16  *  it under the terms of the GNU General Public License as published by
   17  *  the Free Software Foundation; either version 3, or (at your option)
   18  *  any later version.
   19  *  
   20  *  This program is distributed in the hope that it will be useful,
   21  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   22  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   23  *  GNU General Public License for more details.
   24  *  
   25  *  You should have received a copy of the GNU General Public License
   26  *  along with this program; if not, write to the Free Software Foundation.
   27  */
   28 
   29 #include <errno.h>
   30 #include <stdlib.h>
   31 #include <unistd.h>
   32 
   33 #include <sys/types.h>
   34 #include <sys/time.h>
   35 #include <netdb.h>
   36 #include <sys/socket.h>
   37 #include <netinet/in.h>
   38 #include <arpa/inet.h>
   39 
   40 #include "internal.h"
   41 #include "tvarith.h"
   42 
   43 /* TCP connection management. */
   44 
   45 static void tcp_close(adns_state ads) {
   46   close(ads->tcpsocket);
   47   ads->tcpsocket= -1;
   48   ads->tcprecv.used= ads->tcprecv_skip= ads->tcpsend.used= 0;
   49 }
   50 
   51 void adns__tcp_broken(adns_state ads, const char *what, const char *why) {
   52   int serv;
   53   adns_query qu;
   54   
   55   assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);
   56   serv= ads->tcpserver;
   57   if (what) adns__warn(ads,serv,0,"TCP connection failed: %s: %s",what,why);
   58 
   59   if (ads->tcpstate == server_connecting) {
   60     /* Counts as a retry for all the queries waiting for TCP. */
   61     for (qu= ads->tcpw.head; qu; qu= qu->next)
   62       qu->retries++;
   63   }
   64 
   65   tcp_close(ads);
   66   ads->tcpstate= server_broken;
   67   ads->tcpserver= (serv+1)%ads->nservers;
   68 }
   69 
   70 static void tcp_connected(adns_state ads, struct timeval now) {
   71   adns_query qu, nqu;
   72   
   73   adns__debug(ads,ads->tcpserver,0,"TCP connected");
   74   ads->tcpstate= server_ok;
   75   for (qu= ads->tcpw.head; qu && ads->tcpstate == server_ok; qu= nqu) {
   76     nqu= qu->next;
   77     assert(qu->state == query_tcpw);
   78     adns__querysend_tcp(qu,now);
   79   }
   80 }
   81 
   82 static void tcp_broken_events(adns_state ads) {
   83   adns_query qu, nqu;
   84   
   85   assert(ads->tcpstate == server_broken);
   86   for (qu= ads->tcpw.head; qu; qu= nqu) {
   87     nqu= qu->next;
   88     assert(qu->state == query_tcpw);
   89     if (qu->retries > ads->nservers) {
   90       LIST_UNLINK(ads->tcpw,qu);
   91       adns__query_fail(qu,adns_s_allservfail);
   92     }
   93   }
   94   ads->tcpstate= server_disconnected;
   95 }
   96 
   97 void adns__tcp_tryconnect(adns_state ads, struct timeval now) {
   98   int r, fd, tries;
   99   adns_rr_addr *addr;
  100   struct protoent *proto;
  101 
  102   for (tries=0; tries<ads->nservers; tries++) {
  103     switch (ads->tcpstate) {
  104     case server_connecting:
  105     case server_ok:
  106     case server_broken:
  107       return;
  108     case server_disconnected:
  109       break;
  110     default:
  111       abort();
  112     }
  113     
  114     assert(!ads->tcpsend.used);
  115     assert(!ads->tcprecv.used);
  116     assert(!ads->tcprecv_skip);
  117 
  118     proto= getprotobyname("tcp");
  119     if (!proto) {
  120       adns__diag(ads,-1,0,"unable to find protocol no. for TCP !");
  121       return;
  122     }
  123     addr = &ads->servers[ads->tcpserver];
  124     fd= socket(addr->addr.sa.sa_family, SOCK_STREAM, proto->p_proto);
  125     if (fd<0) {
  126       adns__diag(ads,-1,0,"cannot create TCP socket: %s",strerror(errno));
  127       return;
  128     }
  129     r= adns__setnonblock(ads,fd);
  130     if (r) {
  131       adns__diag(ads,-1,0,"cannot make TCP socket nonblocking:"
  132          " %s",strerror(r));
  133       close(fd);
  134       return;
  135     }
  136     r= connect(fd,&addr->addr.sa,addr->len);
  137     ads->tcpsocket= fd;
  138     ads->tcpstate= server_connecting;
  139     if (r==0) { tcp_connected(ads,now); return; }
  140     if (errno == EWOULDBLOCK || errno == EINPROGRESS) {
  141       ads->tcptimeout= now;
  142       timevaladd(&ads->tcptimeout,TCPCONNMS);
  143       return;
  144     }
  145     adns__tcp_broken(ads,"connect",strerror(errno));
  146     tcp_broken_events(ads);
  147   }
  148 }
  149 
  150 /* Timeout handling functions. */
  151 
  152 void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,
  153                  struct timeval *tv_buf) {
  154   const struct timeval *now;
  155   int r;
  156 
  157   now= *now_io;
  158   if (now) return;
  159   r= gettimeofday(tv_buf,0); if (!r) { *now_io= tv_buf; return; }
  160   adns__diag(ads,-1,0,"gettimeofday failed: %s",strerror(errno));
  161   adns_globalsystemfailure(ads);
  162   return;
  163 }
  164 
  165 static void inter_immed(struct timeval **tv_io, struct timeval *tvbuf) {
  166   struct timeval *rbuf;
  167 
  168   if (!tv_io) return;
  169 
  170   rbuf= *tv_io;
  171   if (!rbuf) { *tv_io= rbuf= tvbuf; }
  172 
  173   timerclear(rbuf);
  174 }
  175     
  176 static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
  177             struct timeval maxto) {
  178   struct timeval *rbuf;
  179 
  180   if (!tv_io) return;
  181   rbuf= *tv_io;
  182   if (!rbuf) {
  183     *tvbuf= maxto; *tv_io= tvbuf;
  184   } else {
  185     if (timercmp(rbuf,&maxto,>)) *rbuf= maxto;
  186   }
  187 /*fprintf(stderr,"inter_maxto maxto=%ld.%06ld result=%ld.%06ld\n",
  188     maxto.tv_sec,maxto.tv_usec,(**tv_io).tv_sec,(**tv_io).tv_usec);*/
  189 }
  190 
  191 static void inter_maxtoabs(struct timeval **tv_io, struct timeval *tvbuf,
  192                struct timeval now, struct timeval maxtime) {
  193   /* tv_io may be 0 */
  194   ldiv_t dr;
  195 
  196 /*fprintf(stderr,"inter_maxtoabs now=%ld.%06ld maxtime=%ld.%06ld\n",
  197     now.tv_sec,now.tv_usec,maxtime.tv_sec,maxtime.tv_usec);*/
  198   if (!tv_io) return;
  199   maxtime.tv_sec -= (now.tv_sec+2);
  200   maxtime.tv_usec -= (now.tv_usec-2000000);
  201   dr= ldiv(maxtime.tv_usec,1000000);
  202   maxtime.tv_sec += dr.quot;
  203   maxtime.tv_usec -= dr.quot*1000000;
  204   if (maxtime.tv_sec<0) timerclear(&maxtime);
  205   inter_maxto(tv_io,tvbuf,maxtime);
  206 }
  207 
  208 static void timeouts_queue(adns_state ads, int act,
  209                struct timeval **tv_io, struct timeval *tvbuf,
  210                struct timeval now, struct query_queue *queue) {
  211   adns_query qu, nqu;
  212   
  213   for (qu= queue->head; qu; qu= nqu) {
  214     nqu= qu->next;
  215     if (!timercmp(&now,&qu->timeout,>)) {
  216       inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
  217     } else {
  218       if (!act) { inter_immed(tv_io,tvbuf); return; }
  219       LIST_UNLINK(*queue,qu);
  220       if (qu->state != query_tosend) {
  221     adns__query_fail(qu,adns_s_timeout);
  222       } else {
  223     adns__query_send(qu,now);
  224       }
  225       nqu= queue->head;
  226     }
  227   }
  228 }
  229 
  230 static void tcp_events(adns_state ads, int act,
  231                struct timeval **tv_io, struct timeval *tvbuf,
  232                struct timeval now) {
  233   for (;;) {
  234     switch (ads->tcpstate) {
  235     case server_broken:
  236       if (!act) { inter_immed(tv_io,tvbuf); return; }
  237       tcp_broken_events(ads);
  238     case server_disconnected: /* fall through */
  239       if (!ads->tcpw.head) return;
  240       if (!act) { inter_immed(tv_io,tvbuf); return; }
  241       adns__tcp_tryconnect(ads,now);
  242       break;
  243     case server_ok:
  244       if (ads->tcpw.head) return;
  245       if (!ads->tcptimeout.tv_sec) {
  246     assert(!ads->tcptimeout.tv_usec);
  247     ads->tcptimeout= now;
  248     timevaladd(&ads->tcptimeout,TCPIDLEMS);
  249       }
  250     case server_connecting: /* fall through */
  251       if (!act || !timercmp(&now,&ads->tcptimeout,>)) {
  252     inter_maxtoabs(tv_io,tvbuf,now,ads->tcptimeout);
  253     return;
  254       } {
  255     /* TCP timeout has happened */
  256     switch (ads->tcpstate) {
  257     case server_connecting: /* failed to connect */
  258       adns__tcp_broken(ads,"unable to make connection","timed out");
  259       break;
  260     case server_ok: /* idle timeout */
  261       tcp_close(ads);
  262       ads->tcpstate= server_disconnected;
  263       return;
  264     default:
  265       abort();
  266     }
  267       }
  268       break;
  269     default:
  270       abort();
  271     }
  272   }
  273   return;
  274 }
  275 
  276 void adns__timeouts(adns_state ads, int act,
  277             struct timeval **tv_io, struct timeval *tvbuf,
  278             struct timeval now) {
  279   timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->udpw);
  280   timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->tcpw);
  281   tcp_events(ads,act,tv_io,tvbuf,now);
  282 }
  283 
  284 void adns_firsttimeout(adns_state ads,
  285                struct timeval **tv_io, struct timeval *tvbuf,
  286                struct timeval now) {
  287   adns__consistency(ads,0,cc_entex);
  288   adns__timeouts(ads, 0, tv_io,tvbuf, now);
  289   adns__returning(ads,0);
  290 }
  291 
  292 void adns_processtimeouts(adns_state ads, const struct timeval *now) {
  293   struct timeval tv_buf;
  294 
  295   adns__consistency(ads,0,cc_entex);
  296   adns__must_gettimeofday(ads,&now,&tv_buf);
  297   if (now) adns__timeouts(ads, 1, 0,0, *now);
  298   adns__returning(ads,0);
  299 }
  300 
  301 /* fd handling functions.  These are the top-level of the real work of
  302  * reception and often transmission.
  303  */
  304 
  305 int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) {
  306   /* Returns the number of entries filled in.  Always zeroes revents. */
  307   int nwanted=0;
  308 #define ADD_POLLFD(wantfd, wantevents) do{  \
  309     pollfds_buf[nwanted].fd= (wantfd);      \
  310     pollfds_buf[nwanted].events= (wantevents);  \
  311     pollfds_buf[nwanted].revents= 0;        \
  312     nwanted++;                  \
  313   }while(0)
  314 
  315   int i;
  316 
  317   assert(MAX_POLLFDS == MAXUDP + 1);
  318 
  319   for (i=0; i<ads->nudpsockets; i++)
  320     ADD_POLLFD(ads->udpsockets[i].fd, POLLIN);
  321 
  322   switch (ads->tcpstate) {
  323   case server_disconnected:
  324   case server_broken:
  325     break;
  326   case server_connecting:
  327     ADD_POLLFD(ads->tcpsocket, POLLOUT);
  328     break;
  329   case server_ok:
  330     ADD_POLLFD(ads->tcpsocket,
  331            ads->tcpsend.used ? POLLIN|POLLOUT|POLLPRI : POLLIN|POLLPRI);
  332     break;
  333   default:
  334     abort();
  335   }
  336   assert(nwanted<=MAX_POLLFDS);
  337 #undef ADD_POLLFD
  338   return nwanted;
  339 }
  340 
  341 int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
  342   int want, dgramlen, r, i, serv, old_skip;
  343   socklen_t udpaddrlen;
  344   byte udpbuf[DNS_MAXUDP];
  345   char addrbuf[ADNS_ADDR2TEXT_BUFLEN];
  346   struct udpsocket *udp;
  347   adns_sockaddr udpaddr;
  348   
  349   adns__consistency(ads,0,cc_entex);
  350 
  351   switch (ads->tcpstate) {
  352   case server_disconnected:
  353   case server_broken:
  354   case server_connecting:
  355     break;
  356   case server_ok:
  357     if (fd != ads->tcpsocket) break;
  358     assert(!ads->tcprecv_skip);
  359     do {
  360       if (ads->tcprecv.used >= ads->tcprecv_skip+2) {
  361     dgramlen= ((ads->tcprecv.buf[ads->tcprecv_skip]<<8) |
  362                ads->tcprecv.buf[ads->tcprecv_skip+1]);
  363     if (ads->tcprecv.used >= ads->tcprecv_skip+2+dgramlen) {
  364       old_skip= ads->tcprecv_skip;
  365       ads->tcprecv_skip += 2+dgramlen;
  366       adns__procdgram(ads, ads->tcprecv.buf+old_skip+2,
  367               dgramlen, ads->tcpserver, 1,*now);
  368       continue;
  369     } else {
  370       want= 2+dgramlen;
  371     }
  372       } else {
  373     want= 2;
  374       }
  375       ads->tcprecv.used -= ads->tcprecv_skip;
  376       memmove(ads->tcprecv.buf, ads->tcprecv.buf+ads->tcprecv_skip,
  377           ads->tcprecv.used);
  378       ads->tcprecv_skip= 0;
  379       if (!adns__vbuf_ensure(&ads->tcprecv,want)) { r= ENOMEM; goto xit; }
  380       assert(ads->tcprecv.used <= ads->tcprecv.avail);
  381       if (ads->tcprecv.used == ads->tcprecv.avail) continue;
  382       r= read(ads->tcpsocket,
  383           ads->tcprecv.buf+ads->tcprecv.used,
  384           ads->tcprecv.avail-ads->tcprecv.used);
  385       if (r>0) {
  386     ads->tcprecv.used+= r;
  387       } else {
  388     if (r) {
  389       if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
  390       if (errno==EINTR) continue;
  391       if (errno_resources(errno)) { r= errno; goto xit; }
  392     }
  393     adns__tcp_broken(ads,"read",r?strerror(errno):"closed");
  394       }
  395     } while (ads->tcpstate == server_ok);
  396     r= 0; goto xit;
  397   default:
  398     abort();
  399   }
  400   for (i=0; i<ads->nudpsockets; i++) {
  401     udp= &ads->udpsockets[i];
  402     if (fd != udp->fd) continue;
  403     for (;;) {
  404       udpaddrlen= sizeof(udpaddr);
  405       r= recvfrom(fd,udpbuf,sizeof(udpbuf),0, &udpaddr.sa,&udpaddrlen);
  406       if (r<0) {
  407     if (errno == EAGAIN || errno == EWOULDBLOCK) { r= 0; goto xit; }
  408     if (errno == EINTR) continue;
  409     if (errno_resources(errno)) { r= errno; goto xit; }
  410     adns__warn(ads,-1,0,"datagram receive error: %s",strerror(errno));
  411     r= 0; goto xit;
  412       }
  413       for (serv= 0;
  414        serv < ads->nservers &&
  415          !adns__sockaddrs_equal(&udpaddr.sa,
  416                     &ads->servers[serv].addr.sa);
  417        serv++);
  418       if (serv >= ads->nservers) {
  419     adns__warn(ads,-1,0,"datagram received from unknown nameserver %s",
  420            adns__sockaddr_ntoa(&udpaddr.sa, addrbuf));
  421     continue;
  422       }
  423       adns__procdgram(ads,udpbuf,r,serv,0,*now);
  424     }
  425     break;
  426   }
  427   r= 0;
  428 xit:
  429   adns__returning(ads,0);
  430   return r;
  431 }
  432 
  433 int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) {
  434   int r;
  435   
  436   adns__consistency(ads,0,cc_entex);
  437 
  438   switch (ads->tcpstate) {
  439   case server_disconnected:
  440   case server_broken:
  441     break;
  442   case server_connecting:
  443     if (fd != ads->tcpsocket) break;
  444     assert(ads->tcprecv.used==0);
  445     assert(ads->tcprecv_skip==0);
  446     for (;;) {
  447       /* This function can be called even if the fd wasn't actually
  448        * flagged as writeable.  For asynch tcp connect we have to
  449        * actually use the writeability to tell us the connect has
  450        * completed (or failed), so we need to double check. */
  451       fd_set writeable;
  452       struct timeval timeout = { 0,0 };
  453       FD_ZERO(&writeable);
  454       FD_SET(ads->tcpsocket,&writeable);
  455       r= select(ads->tcpsocket+1,0,&writeable,0,&timeout);
  456       if (r==0) break;
  457       if (r<0) {
  458     if (errno==EINTR) continue;
  459     adns__tcp_broken(ads,"select","failed connecting writeability check");
  460     r= 0; goto xit;
  461       }
  462       assert(FD_ISSET(ads->tcpsocket,&writeable));
  463       if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
  464       r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
  465       if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
  466     tcp_connected(ads,*now);
  467     r= 0; goto xit;
  468       }
  469       if (r>0) {
  470     adns__tcp_broken(ads,"connect/read","sent data before first request");
  471     r= 0; goto xit;
  472       }
  473       if (errno==EINTR) continue;
  474       if (errno_resources(errno)) { r= errno; goto xit; }
  475       adns__tcp_broken(ads,"connect/read",strerror(errno));
  476       r= 0; goto xit;
  477     } /* not reached */
  478   case server_ok:
  479     if (fd != ads->tcpsocket) break;
  480     while (ads->tcpsend.used) {
  481       adns__sigpipe_protect(ads);
  482       r= write(ads->tcpsocket,ads->tcpsend.buf,ads->tcpsend.used);
  483       adns__sigpipe_unprotect(ads);
  484       if (r<0) {
  485     if (errno==EINTR) continue;
  486     if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
  487     if (errno_resources(errno)) { r= errno; goto xit; }
  488     adns__tcp_broken(ads,"write",strerror(errno));
  489     r= 0; goto xit;
  490       } else if (r>0) {
  491     ads->tcpsend.used -= r;
  492     memmove(ads->tcpsend.buf,ads->tcpsend.buf+r,ads->tcpsend.used);
  493       }
  494     }
  495     r= 0;
  496     goto xit;
  497   default:
  498     abort();
  499   }
  500   r= 0;
  501 xit:
  502   adns__returning(ads,0);
  503   return r;
  504 }
  505   
  506 int adns_processexceptional(adns_state ads, int fd,
  507                 const struct timeval *now) {
  508   adns__consistency(ads,0,cc_entex);
  509   switch (ads->tcpstate) {
  510   case server_disconnected:
  511   case server_broken:
  512     break;
  513   case server_connecting:
  514   case server_ok:
  515     if (fd != ads->tcpsocket) break;
  516     adns__tcp_broken(ads,"poll/select","exceptional condition detected");
  517     break;
  518   default:
  519     abort();
  520   }
  521   adns__returning(ads,0);
  522   return 0;
  523 }
  524 
  525 static void fd_event(adns_state ads, int fd,
  526              int revent, int pollflag,
  527              int maxfd, const fd_set *fds,
  528              int (*func)(adns_state, int fd,
  529                  const struct timeval *now),
  530              struct timeval now, int *r_r) {
  531   int r;
  532   
  533   if (!(revent & pollflag)) return;
  534   if (fds && !(fd<maxfd && FD_ISSET(fd,fds))) return;
  535   r= func(ads,fd,&now);
  536   if (r) {
  537     if (r_r) {
  538       *r_r= r;
  539     } else {
  540       adns__diag(ads,-1,0,"process fd failed after select:"
  541          " %s",strerror(errno));
  542       adns_globalsystemfailure(ads);
  543     }
  544   }
  545 }
  546 
  547 void adns__fdevents(adns_state ads,
  548             const struct pollfd *pollfds, int npollfds,
  549             int maxfd, const fd_set *readfds,
  550             const fd_set *writefds, const fd_set *exceptfds,
  551             struct timeval now, int *r_r) {
  552   int i, fd, revents;
  553 
  554   for (i=0; i<npollfds; i++) {
  555     fd= pollfds[i].fd;
  556     if (fd >= maxfd) maxfd= fd+1;
  557     revents= pollfds[i].revents;
  558 #define EV(pollfl,fds,how)  \
  559     fd_event(ads,fd, revents,pollfl, maxfd,fds, adns_process##how,now,r_r)
  560     EV( POLLIN,  readfds,   readable    );
  561     EV( POLLOUT, writefds,  writeable   );
  562     EV( POLLPRI, exceptfds, exceptional );
  563 #undef EV
  564   }
  565 }
  566 
  567 /* Wrappers for select(2). */
  568 
  569 void adns_beforeselect(adns_state ads, int *maxfd_io, fd_set *readfds_io,
  570                fd_set *writefds_io, fd_set *exceptfds_io,
  571                struct timeval **tv_mod, struct timeval *tv_tobuf,
  572                const struct timeval *now) {
  573   struct timeval tv_nowbuf;
  574   struct pollfd pollfds[MAX_POLLFDS];
  575   int i, fd, maxfd, npollfds;
  576   
  577   adns__consistency(ads,0,cc_entex);
  578 
  579   if (tv_mod && (!*tv_mod || (*tv_mod)->tv_sec || (*tv_mod)->tv_usec)) {
  580     /* The caller is planning to sleep. */
  581     adns__must_gettimeofday(ads,&now,&tv_nowbuf);
  582     if (!now) { inter_immed(tv_mod,tv_tobuf); goto xit; }
  583     adns__timeouts(ads, 0, tv_mod,tv_tobuf, *now);
  584   }
  585 
  586   npollfds= adns__pollfds(ads,pollfds);
  587   maxfd= *maxfd_io;
  588   for (i=0; i<npollfds; i++) {
  589     fd= pollfds[i].fd;
  590     if (fd >= maxfd) maxfd= fd+1;
  591     if (pollfds[i].events & POLLIN) FD_SET(fd,readfds_io);
  592     if (pollfds[i].events & POLLOUT) FD_SET(fd,writefds_io);
  593     if (pollfds[i].events & POLLPRI) FD_SET(fd,exceptfds_io);
  594   }
  595   *maxfd_io= maxfd;
  596 
  597 xit:
  598   adns__returning(ads,0);
  599 }
  600 
  601 void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
  602               const fd_set *writefds, const fd_set *exceptfds,
  603               const struct timeval *now) {
  604   struct timeval tv_buf;
  605   struct pollfd pollfds[MAX_POLLFDS];
  606   int npollfds, i;
  607 
  608   adns__consistency(ads,0,cc_entex);
  609   adns__must_gettimeofday(ads,&now,&tv_buf);
  610   if (!now) goto xit;
  611   adns_processtimeouts(ads,now);
  612 
  613   npollfds= adns__pollfds(ads,pollfds);
  614   for (i=0; i<npollfds; i++) pollfds[i].revents= POLLIN|POLLOUT|POLLPRI;
  615   adns__fdevents(ads,
  616          pollfds,npollfds,
  617          maxfd,readfds,writefds,exceptfds,
  618          *now, 0);
  619 xit:
  620   adns__returning(ads,0);
  621 }
  622 
  623 /* General helpful functions. */
  624 
  625 void adns_globalsystemfailure(adns_state ads) {
  626   adns__consistency(ads,0,cc_entex);
  627 
  628   while (ads->udpw.head) adns__query_fail(ads->udpw.head, adns_s_systemfail);
  629   while (ads->tcpw.head) adns__query_fail(ads->tcpw.head, adns_s_systemfail);
  630   
  631   switch (ads->tcpstate) {
  632   case server_connecting:
  633   case server_ok:
  634     adns__tcp_broken(ads,0,0);
  635     break;
  636   case server_disconnected:
  637   case server_broken:
  638     break;
  639   default:
  640     abort();
  641   }
  642   adns__returning(ads,0);
  643 }
  644 
  645 int adns_processany(adns_state ads) {
  646   int r, i;
  647   struct timeval now;
  648   struct pollfd pollfds[MAX_POLLFDS];
  649   int npollfds;
  650 
  651   adns__consistency(ads,0,cc_entex);
  652 
  653   r= gettimeofday(&now,0);
  654   if (!r) adns_processtimeouts(ads,&now);
  655 
  656   /* We just use adns__fdevents to loop over the fd's trying them.
  657    * This seems more sensible than calling select, since we're most
  658    * likely just to want to do a read on one or two fds anyway.
  659    */
  660   npollfds= adns__pollfds(ads,pollfds);
  661   for (i=0; i<npollfds; i++) pollfds[i].revents= pollfds[i].events & ~POLLPRI;
  662   adns__fdevents(ads,
  663          pollfds,npollfds,
  664          0,0,0,0,
  665          now,&r);
  666 
  667   adns__returning(ads,0);
  668   return 0;
  669 }
  670 
  671 void adns__autosys(adns_state ads, struct timeval now) {
  672   if (ads->iflags & adns_if_noautosys) return;
  673   adns_processany(ads);
  674 }
  675 
  676 int adns__internal_check(adns_state ads,
  677              adns_query *query_io,
  678              adns_answer **answer,
  679              void **context_r) {
  680   adns_query qu;
  681 
  682   qu= *query_io;
  683   if (!qu) {
  684     if (ads->output.head) {
  685       qu= ads->output.head;
  686     } else if (ads->udpw.head || ads->tcpw.head) {
  687       return EAGAIN;
  688     } else {
  689       return ESRCH;
  690     }
  691   } else {
  692     if (qu->id>=0) return EAGAIN;
  693   }
  694   LIST_UNLINK(ads->output,qu);
  695   *answer= qu->answer;
  696   if (context_r) *context_r= qu->ctx.ext;
  697   *query_io= qu;
  698   free(qu);
  699   return 0;
  700 }
  701 
  702 int adns_wait(adns_state ads,
  703           adns_query *query_io,
  704           adns_answer **answer_r,
  705           void **context_r) {
  706   int r, maxfd, rsel;
  707   fd_set readfds, writefds, exceptfds;
  708   struct timeval tvbuf, *tvp;
  709   
  710   adns__consistency(ads,*query_io,cc_entex);
  711   for (;;) {
  712     r= adns__internal_check(ads,query_io,answer_r,context_r);
  713     if (r != EAGAIN) break;
  714     maxfd= 0; tvp= 0;
  715     FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
  716     adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,&tvp,&tvbuf,0);
  717     assert(tvp);
  718     rsel= select(maxfd,&readfds,&writefds,&exceptfds,tvp);
  719     if (rsel==-1) {
  720       if (errno == EINTR) {
  721     if (ads->iflags & adns_if_eintr) { r= EINTR; break; }
  722       } else {
  723     adns__diag(ads,-1,0,"select failed in wait: %s",strerror(errno));
  724     adns_globalsystemfailure(ads);
  725       }
  726     } else {
  727       assert(rsel >= 0);
  728       adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,0);
  729     }
  730   }
  731   adns__returning(ads,0);
  732   return r;
  733 }
  734 
  735 int adns_check(adns_state ads,
  736            adns_query *query_io,
  737            adns_answer **answer_r,
  738            void **context_r) {
  739   struct timeval now;
  740   int r;
  741   
  742   adns__consistency(ads,*query_io,cc_entex);
  743   r= gettimeofday(&now,0);
  744   if (!r) adns__autosys(ads,now);
  745 
  746   r= adns__internal_check(ads,query_io,answer_r,context_r);
  747   adns__returning(ads,0);
  748   return r;
  749 }