ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

event.c
Go to the documentation of this file.
00001 /*
00002  * event.c
00003  * - event loop core
00004  * - TCP connection management
00005  * - user-visible check/wait and event-loop-related functions
00006  */
00007 /*
00008  *  This file is
00009  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
00010  *
00011  *  It is part of adns, which is
00012  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
00013  *    Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
00014  *
00015  *  This program is free software; you can redistribute it and/or modify
00016  *  it under the terms of the GNU General Public License as published by
00017  *  the Free Software Foundation; either version 2, or (at your option)
00018  *  any later version.
00019  *
00020  *  This program is distributed in the hope that it will be useful,
00021  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  *  GNU General Public License for more details.
00024  *
00025  *  You should have received a copy of the GNU General Public License
00026  *  along with this program; if not, adns_socket_write to the Free Software Foundation,
00027  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00028  */
00029 
00030 #include <errno.h>
00031 #include <stdlib.h>
00032 
00033 #ifdef ADNS_JGAA_WIN32
00034 # include "adns_win32.h"
00035 #else
00036 # include <unistd.h>
00037 # include <sys/types.h>
00038 # include <sys/time.h>
00039 # include <netdb.h>
00040 # include <sys/socket.h>
00041 # include <netinet/in.h>
00042 # include <arpa/inet.h>
00043 #endif
00044 
00045 #include "internal.h"
00046 #include "tvarith.h"
00047 
00048 /* TCP connection management. */
00049 
00050 static void tcp_close(adns_state ads) {
00051   int serv;
00052 
00053   serv= ads->tcpserver;
00054   adns_socket_close(ads->tcpsocket);
00055   ads->tcpsocket= -1;
00056   ads->tcprecv.used= ads->tcprecv_skip= ads->tcpsend.used= 0;
00057 }
00058 
00059 void adns__tcp_broken(adns_state ads, const char *what, const char *why) {
00060   int serv;
00061   adns_query qu;
00062 
00063   assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);
00064   serv= ads->tcpserver;
00065   if (what) adns__warn(ads,serv,0,"TCP connection failed: %s: %s",what,why);
00066 
00067   if (ads->tcpstate == server_connecting) {
00068     /* Counts as a retry for all the queries waiting for TCP. */
00069     for (qu= ads->tcpw.head; qu; qu= qu->next)
00070       qu->retries++;
00071   }
00072 
00073   tcp_close(ads);
00074   ads->tcpstate= server_broken;
00075   ads->tcpserver= (serv+1)%ads->nservers;
00076 }
00077 
00078 static void tcp_connected(adns_state ads, struct timeval now) {
00079   adns_query qu, nqu;
00080 
00081   adns__debug(ads,ads->tcpserver,0,"TCP connected");
00082   ads->tcpstate= server_ok;
00083   for (qu= ads->tcpw.head; qu && ads->tcpstate == server_ok; qu= nqu) {
00084     nqu= qu->next;
00085     assert(qu->state == query_tcpw);
00086     adns__querysend_tcp(qu,now);
00087   }
00088 }
00089 
00090 void adns__tcp_tryconnect(adns_state ads, struct timeval now) {
00091   int r, tries;
00092   ADNS_SOCKET fd;
00093   struct sockaddr_in addr;
00094   struct protoent *proto;
00095 
00096   for (tries=0; tries<ads->nservers; tries++) {
00097     switch (ads->tcpstate) {
00098     case server_connecting:
00099     case server_ok:
00100     case server_broken:
00101       return;
00102     case server_disconnected:
00103       break;
00104     default:
00105       abort();
00106     }
00107 
00108     assert(!ads->tcpsend.used);
00109     assert(!ads->tcprecv.used);
00110     assert(!ads->tcprecv_skip);
00111 
00112     proto= getprotobyname("tcp");
00113     if (!proto) { adns__diag(ads,-1,0,"unable to find protocol no. for TCP !"); return; }
00114     ADNS_CLEAR_ERRNO
00115     fd= socket(AF_INET,SOCK_STREAM,proto->p_proto);
00116     ADNS_CAPTURE_ERRNO;
00117     if (fd<0) {
00118       adns__diag(ads,-1,0,"cannot create TCP socket: %s",strerror(errno));
00119       return;
00120     }
00121     r= adns__setnonblock(ads,fd);
00122     if (r) {
00123       adns__diag(ads,-1,0,"cannot make TCP socket nonblocking: %s",strerror(r));
00124       adns_socket_close(fd);
00125       return;
00126     }
00127     memset(&addr,0,sizeof(addr));
00128     addr.sin_family= AF_INET;
00129     addr.sin_port= htons(DNS_PORT);
00130     addr.sin_addr= ads->servers[ads->tcpserver].addr;
00131     ADNS_CLEAR_ERRNO;
00132     r= connect(fd,(const struct sockaddr*)&addr,sizeof(addr));
00133     ADNS_CAPTURE_ERRNO;
00134     ads->tcpsocket= fd;
00135     ads->tcpstate= server_connecting;
00136     if (r==0) { tcp_connected(ads,now); return; }
00137     if (errno == EWOULDBLOCK || errno == EINPROGRESS) {
00138       ads->tcptimeout= now;
00139       timevaladd(&ads->tcptimeout,TCPCONNMS);
00140       return;
00141     }
00142     adns__tcp_broken(ads,"connect",strerror(errno));
00143     ads->tcpstate= server_disconnected;
00144   }
00145 }
00146 
00147 /* Timeout handling functions. */
00148 
00149 void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,
00150                  struct timeval *tv_buf) {
00151   const struct timeval *now;
00152   int r;
00153 
00154   now= *now_io;
00155   if (now) return;
00156   r= gettimeofday(tv_buf,0); if (!r) { *now_io= tv_buf; return; }
00157   adns__diag(ads,-1,0,"gettimeofday failed: %s",strerror(errno));
00158   adns_globalsystemfailure(ads);
00159   return;
00160 }
00161 
00162 static void inter_immed(struct timeval **tv_io, struct timeval *tvbuf) {
00163   struct timeval *rbuf;
00164 
00165   if (!tv_io) return;
00166 
00167   rbuf= *tv_io;
00168   if (!rbuf) { *tv_io= rbuf= tvbuf; }
00169 
00170   timerclear(rbuf);
00171 }
00172 
00173 static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
00174             struct timeval maxto) {
00175   struct timeval *rbuf;
00176 
00177   if (!tv_io) return;
00178   rbuf= *tv_io;
00179   if (!rbuf) {
00180     *tvbuf= maxto; *tv_io= tvbuf;
00181   } else {
00182     if (timercmp(rbuf,&maxto,>)) *rbuf= maxto;
00183   }
00184 /*fprintf(stderr,"inter_maxto maxto=%ld.%06ld result=%ld.%06ld\n",
00185     maxto.tv_sec,maxto.tv_usec,(**tv_io).tv_sec,(**tv_io).tv_usec);*/
00186 }
00187 
00188 static void inter_maxtoabs(struct timeval **tv_io, struct timeval *tvbuf,
00189                struct timeval now, struct timeval maxtime) {
00190   /* tv_io may be 0 */
00191   ldiv_t dr;
00192 
00193 /*fprintf(stderr,"inter_maxtoabs now=%ld.%06ld maxtime=%ld.%06ld\n",
00194     now.tv_sec,now.tv_usec,maxtime.tv_sec,maxtime.tv_usec);*/
00195   if (!tv_io) return;
00196   maxtime.tv_sec -= (now.tv_sec+2);
00197   maxtime.tv_usec -= (now.tv_usec-2000000);
00198   dr= ldiv(maxtime.tv_usec,1000000);
00199   maxtime.tv_sec += dr.quot;
00200   maxtime.tv_usec -= dr.quot*1000000;
00201   if (maxtime.tv_sec<0) timerclear(&maxtime);
00202   inter_maxto(tv_io,tvbuf,maxtime);
00203 }
00204 
00205 static void timeouts_queue(adns_state ads, int act,
00206                struct timeval **tv_io, struct timeval *tvbuf,
00207                struct timeval now, struct query_queue *queue) {
00208   adns_query qu, nqu;
00209 
00210   for (qu= queue->head; qu; qu= nqu) {
00211     nqu= qu->next;
00212     if (!timercmp(&now,&qu->timeout,>)) {
00213       inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
00214     } else {
00215       if (!act) { inter_immed(tv_io,tvbuf); return; }
00216       LIST_UNLINK(*queue,qu);
00217       if (qu->state != query_tosend) {
00218     adns__query_fail(qu,adns_s_timeout);
00219       } else {
00220     adns__query_send(qu,now);
00221       }
00222       nqu= queue->head;
00223     }
00224   }
00225 }
00226 
00227 static void tcp_events(adns_state ads, int act,
00228                struct timeval **tv_io, struct timeval *tvbuf,
00229                struct timeval now) {
00230   adns_query qu, nqu;
00231 
00232   for (;;) {
00233     switch (ads->tcpstate) {
00234     case server_broken:
00235       if (!act) { inter_immed(tv_io,tvbuf); return; }
00236       for (qu= ads->tcpw.head; qu; qu= nqu) {
00237     nqu= qu->next;
00238     assert(qu->state == query_tcpw);
00239     if (qu->retries > ads->nservers) {
00240       LIST_UNLINK(ads->tcpw,qu);
00241       adns__query_fail(qu,adns_s_allservfail);
00242     }
00243       }
00244       ads->tcpstate= server_disconnected;
00245     case server_disconnected: /* fall through */
00246       if (!ads->tcpw.head) return;
00247       if (!act) { inter_immed(tv_io,tvbuf); return; }
00248       adns__tcp_tryconnect(ads,now);
00249       break;
00250     case server_ok:
00251       if (ads->tcpw.head) return;
00252       if (!ads->tcptimeout.tv_sec) {
00253     assert(!ads->tcptimeout.tv_usec);
00254     ads->tcptimeout= now;
00255     timevaladd(&ads->tcptimeout,TCPIDLEMS);
00256       }
00257     case server_connecting: /* fall through */
00258       if (!act || !timercmp(&now,&ads->tcptimeout,>)) {
00259     inter_maxtoabs(tv_io,tvbuf,now,ads->tcptimeout);
00260     return;
00261       } {
00262     /* TCP timeout has happened */
00263     switch (ads->tcpstate) {
00264     case server_connecting: /* failed to connect */
00265       adns__tcp_broken(ads,"unable to make connection","timed out");
00266       break;
00267     case server_ok: /* idle timeout */
00268       tcp_close(ads);
00269       ads->tcpstate= server_disconnected;
00270       return;
00271     default:
00272       abort();
00273     }
00274       }
00275       break;
00276     default:
00277       abort();
00278     }
00279   }
00280   return;
00281 }
00282 
00283 void adns__timeouts(adns_state ads, int act,
00284             struct timeval **tv_io, struct timeval *tvbuf,
00285             struct timeval now) {
00286   timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->udpw);
00287   timeouts_queue(ads,act,tv_io,tvbuf,now, &ads->tcpw);
00288   tcp_events(ads,act,tv_io,tvbuf,now);
00289 }
00290 
00291 void adns_firsttimeout(adns_state ads,
00292                struct timeval **tv_io, struct timeval *tvbuf,
00293                struct timeval now) {
00294   adns__consistency(ads,0,cc_entex);
00295   adns__timeouts(ads, 0, tv_io,tvbuf, now);
00296   adns__consistency(ads,0,cc_entex);
00297 }
00298 
00299 void adns_processtimeouts(adns_state ads, const struct timeval *now) {
00300   struct timeval tv_buf;
00301 
00302   adns__consistency(ads,0,cc_entex);
00303   adns__must_gettimeofday(ads,&now,&tv_buf);
00304   if (now) adns__timeouts(ads, 1, 0,0, *now);
00305   adns__consistency(ads,0,cc_entex);
00306 }
00307 
00308 /* fd handling functions.  These are the top-level of the real work of
00309  * reception and often transmission.
00310  */
00311 
00312 int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) {
00313   /* Returns the number of entries filled in.  Always zeroes revents. */
00314 
00315   assert(MAX_POLLFDS==2);
00316 
00317   pollfds_buf[0].fd= ads->udpsocket;
00318   pollfds_buf[0].events= POLLIN;
00319   pollfds_buf[0].revents= 0;
00320 
00321   switch (ads->tcpstate) {
00322   case server_disconnected:
00323   case server_broken:
00324     return 1;
00325   case server_connecting:
00326     pollfds_buf[1].events= POLLOUT;
00327     break;
00328   case server_ok:
00329     pollfds_buf[1].events= ads->tcpsend.used ? POLLIN|POLLOUT|POLLPRI : POLLIN|POLLPRI;
00330     break;
00331   default:
00332     abort();
00333   }
00334   pollfds_buf[1].fd= ads->tcpsocket;
00335   return 2;
00336 }
00337 
00338 int adns_processreadable(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
00339   int want, dgramlen, r, udpaddrlen, serv, old_skip;
00340   byte udpbuf[DNS_MAXUDP];
00341   struct sockaddr_in udpaddr;
00342 
00343   adns__consistency(ads,0,cc_entex);
00344 
00345   switch (ads->tcpstate) {
00346   case server_disconnected:
00347   case server_broken:
00348   case server_connecting:
00349     break;
00350   case server_ok:
00351     if (fd != ads->tcpsocket) break;
00352     assert(!ads->tcprecv_skip);
00353     do {
00354       if (ads->tcprecv.used >= ads->tcprecv_skip+2) {
00355     dgramlen= ((ads->tcprecv.buf[ads->tcprecv_skip]<<8) |
00356                ads->tcprecv.buf[ads->tcprecv_skip+1]);
00357     if (ads->tcprecv.used >= ads->tcprecv_skip+2+dgramlen) {
00358       old_skip= ads->tcprecv_skip;
00359       ads->tcprecv_skip += 2+dgramlen;
00360       adns__procdgram(ads, ads->tcprecv.buf+old_skip+2,
00361               dgramlen, ads->tcpserver, 1,*now);
00362       continue;
00363     } else {
00364       want= 2+dgramlen;
00365     }
00366       } else {
00367     want= 2;
00368       }
00369       ads->tcprecv.used -= ads->tcprecv_skip;
00370       memmove(ads->tcprecv.buf,ads->tcprecv.buf+ads->tcprecv_skip, (size_t) ads->tcprecv.used);
00371       ads->tcprecv_skip= 0;
00372       if (!adns__vbuf_ensure(&ads->tcprecv,want)) { r= ENOMEM; goto xit; }
00373       assert(ads->tcprecv.used <= ads->tcprecv.avail);
00374       if (ads->tcprecv.used == ads->tcprecv.avail) continue;
00375       ADNS_CLEAR_ERRNO;
00376       r= adns_socket_read(ads->tcpsocket,
00377           ads->tcprecv.buf+ads->tcprecv.used,
00378           ads->tcprecv.avail-ads->tcprecv.used);
00379       ADNS_CAPTURE_ERRNO;
00380       if (r>0) {
00381     ads->tcprecv.used+= r;
00382       } else {
00383     if (r) {
00384       if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
00385       if (errno==EINTR) continue;
00386       if (errno_resources(errno)) { r= errno; goto xit; }
00387     }
00388     adns__tcp_broken(ads,"adns_socket_read",r?strerror(errno):"closed");
00389       }
00390     } while (ads->tcpstate == server_ok);
00391     r= 0; goto xit;
00392   default:
00393     abort();
00394   }
00395   if (fd == ads->udpsocket) {
00396     for (;;) {
00397       udpaddrlen= sizeof(udpaddr);
00398       ADNS_CLEAR_ERRNO;
00399       r= recvfrom(ads->udpsocket,(char*)udpbuf,sizeof(udpbuf),0,
00400           (struct sockaddr*)&udpaddr,&udpaddrlen);
00401       ADNS_CAPTURE_ERRNO;
00402       if (r<0) {
00403     if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ECONNRESET) { r= 0; goto xit; }
00404     if (errno == EINTR) continue;
00405     if (errno_resources(errno)) { r= errno; goto xit; }
00406     adns__warn(ads,-1,0,"datagram receive error: %s (%d)",strerror(errno), errno);
00407     r= 0; goto xit;
00408       }
00409       if (udpaddrlen != sizeof(udpaddr)) {
00410     adns__diag(ads,-1,0,"datagram received with wrong address length %d"
00411            " (expected %lu)", udpaddrlen,
00412            (unsigned long)sizeof(udpaddr));
00413     continue;
00414       }
00415       if (udpaddr.sin_family != AF_INET) {
00416     adns__diag(ads,-1,0,"datagram received with wrong protocol family"
00417            " %u (expected %u)",udpaddr.sin_family,AF_INET);
00418     continue;
00419       }
00420       if (ntohs(udpaddr.sin_port) != DNS_PORT) {
00421     adns__diag(ads,-1,0,"datagram received from wrong port %u (expected %u)",
00422            ntohs(udpaddr.sin_port),DNS_PORT);
00423     continue;
00424       }
00425       for (serv= 0;
00426        serv < ads->nservers &&
00427          ads->servers[serv].addr.s_addr != udpaddr.sin_addr.s_addr;
00428        serv++);
00429       if (serv >= ads->nservers) {
00430     adns__warn(ads,-1,0,"datagram received from unknown nameserver %s",
00431            inet_ntoa(udpaddr.sin_addr));
00432     continue;
00433       }
00434       adns__procdgram(ads,udpbuf,r,serv,0,*now);
00435     }
00436   }
00437   r= 0;
00438 xit:
00439   adns__consistency(ads,0,cc_entex);
00440   return r;
00441 }
00442 
00443 int adns_processwriteable(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
00444   int r;
00445 
00446   adns__consistency(ads,0,cc_entex);
00447 
00448   switch (ads->tcpstate) {
00449   case server_disconnected:
00450   case server_broken:
00451     break;
00452   case server_connecting:
00453     if (fd != ads->tcpsocket) break;
00454     assert(ads->tcprecv.used==0);
00455     assert(ads->tcprecv_skip==0);
00456     for (;;) {
00457       if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
00458       ADNS_CLEAR_ERRNO;
00459       r= adns_socket_read(ads->tcpsocket,&ads->tcprecv.buf,1);
00460       ADNS_CAPTURE_ERRNO;
00461       if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
00462     tcp_connected(ads,*now);
00463     r= 0; goto xit;
00464       }
00465       if (r>0) {
00466     adns__tcp_broken(ads,"connect/adns_socket_read","sent data before first request");
00467     r= 0; goto xit;
00468       }
00469       if (errno==EINTR) continue;
00470       if (errno_resources(errno)) { r= errno; goto xit; }
00471       adns__tcp_broken(ads,"connect/adns_socket_read",strerror(errno));
00472       r= 0; goto xit;
00473     } /* not reached */
00474   case server_ok:
00475     if (fd != ads->tcpsocket) break;
00476     while (ads->tcpsend.used) {
00477       adns__sigpipe_protect(ads);
00478       ADNS_CLEAR_ERRNO;
00479       r= adns_socket_write(ads->tcpsocket,ads->tcpsend.buf,ads->tcpsend.used);
00480       ADNS_CAPTURE_ERRNO;
00481       adns__sigpipe_unprotect(ads);
00482       if (r<0) {
00483     if (errno==EINTR) continue;
00484     if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
00485     if (errno_resources(errno)) { r= errno; goto xit; }
00486     adns__tcp_broken(ads,"adns_socket_write",strerror(errno));
00487     r= 0; goto xit;
00488       } else if (r>0) {
00489     ads->tcpsend.used -= r;
00490     memmove(ads->tcpsend.buf,ads->tcpsend.buf+r, (size_t) ads->tcpsend.used);
00491       }
00492     }
00493     r= 0;
00494     goto xit;
00495   default:
00496     abort();
00497   }
00498   r= 0;
00499 xit:
00500   adns__consistency(ads,0,cc_entex);
00501   return r;
00502 }
00503 
00504 int adns_processexceptional(adns_state ads, ADNS_SOCKET fd, const struct timeval *now) {
00505   adns__consistency(ads,0,cc_entex);
00506   switch (ads->tcpstate) {
00507   case server_disconnected:
00508   case server_broken:
00509     break;
00510   case server_connecting:
00511   case server_ok:
00512     if (fd != ads->tcpsocket) break;
00513     adns__tcp_broken(ads,"poll/select","exceptional condition detected");
00514     break;
00515   default:
00516     abort();
00517   }
00518   adns__consistency(ads,0,cc_entex);
00519   return 0;
00520 }
00521 
00522 static void fd_event(adns_state ads, ADNS_SOCKET fd,
00523              int revent, int pollflag,
00524              int maxfd, const fd_set *fds,
00525              int (*func)(adns_state, ADNS_SOCKET fd, const struct timeval *now),
00526              struct timeval now, int *r_r) {
00527   int r;
00528 
00529   if (!(revent & pollflag)) return;
00530   if (fds && !((int)fd<maxfd && FD_ISSET(fd,fds))) return;
00531   r= func(ads,fd,&now);
00532   if (r) {
00533     if (r_r) {
00534       *r_r= r;
00535     } else {
00536       adns__diag(ads,-1,0,"process fd failed after select: %s",strerror(errno));
00537       adns_globalsystemfailure(ads);
00538     }
00539   }
00540 }
00541 
00542 void adns__fdevents(adns_state ads,
00543             const struct pollfd *pollfds, int npollfds,
00544             int maxfd, const fd_set *readfds,
00545             const fd_set *writefds, const fd_set *exceptfds,
00546             struct timeval now, int *r_r) {
00547   int i, revents;
00548   ADNS_SOCKET fd;
00549 
00550   for (i=0; i<npollfds; i++) {
00551     fd= pollfds[i].fd;
00552     if ((int)fd >= maxfd) maxfd= fd+1;
00553     revents= pollfds[i].revents;
00554     fd_event(ads,fd, revents,POLLIN, maxfd,readfds, adns_processreadable,now,r_r);
00555     fd_event(ads,fd, revents,POLLOUT, maxfd,writefds, adns_processwriteable,now,r_r);
00556     fd_event(ads,fd, revents,POLLPRI, maxfd,exceptfds, adns_processexceptional,now,r_r);
00557   }
00558 }
00559 
00560 /* Wrappers for select(2). */
00561 
00562 void adns_beforeselect(adns_state ads, int *maxfd_io, fd_set *readfds_io,
00563                fd_set *writefds_io, fd_set *exceptfds_io,
00564                struct timeval **tv_mod, struct timeval *tv_tobuf,
00565                const struct timeval *now) {
00566   struct timeval tv_nowbuf;
00567   struct pollfd pollfds[MAX_POLLFDS];
00568   int i, maxfd, npollfds;
00569   ADNS_SOCKET fd;
00570 
00571   adns__consistency(ads,0,cc_entex);
00572 
00573   if (tv_mod && (!*tv_mod || (*tv_mod)->tv_sec || (*tv_mod)->tv_usec)) {
00574     /* The caller is planning to sleep. */
00575     adns__must_gettimeofday(ads,&now,&tv_nowbuf);
00576     if (!now) { inter_immed(tv_mod,tv_tobuf); goto xit; }
00577     adns__timeouts(ads, 0, tv_mod,tv_tobuf, *now);
00578   }
00579 
00580   npollfds= adns__pollfds(ads,pollfds);
00581   maxfd= *maxfd_io;
00582   for (i=0; i<npollfds; i++) {
00583     fd= pollfds[i].fd;
00584     if ((int)fd >= maxfd) maxfd= fd+1;
00585     if (pollfds[i].events & POLLIN) FD_SET(fd,readfds_io);
00586     if (pollfds[i].events & POLLOUT) FD_SET(fd,writefds_io);
00587     if (pollfds[i].events & POLLPRI) FD_SET(fd,exceptfds_io);
00588   }
00589   *maxfd_io= maxfd;
00590 
00591 xit:
00592   adns__consistency(ads,0,cc_entex);
00593 }
00594 
00595 void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
00596               const fd_set *writefds, const fd_set *exceptfds,
00597               const struct timeval *now) {
00598   struct timeval tv_buf;
00599   struct pollfd pollfds[MAX_POLLFDS];
00600   int npollfds, i;
00601 
00602   adns__consistency(ads,0,cc_entex);
00603   adns__must_gettimeofday(ads,&now,&tv_buf);
00604   if (!now) goto xit;
00605   adns_processtimeouts(ads,now);
00606 
00607   npollfds= adns__pollfds(ads,pollfds);
00608   for (i=0; i<npollfds; i++) pollfds[i].revents= POLLIN|POLLOUT|POLLPRI;
00609   adns__fdevents(ads,
00610          pollfds,npollfds,
00611          maxfd,readfds,writefds,exceptfds,
00612          *now, 0);
00613 xit:
00614   adns__consistency(ads,0,cc_entex);
00615 }
00616 
00617 /* General helpful functions. */
00618 
00619 void adns_globalsystemfailure(adns_state ads) {
00620   adns__consistency(ads,0,cc_entex);
00621 
00622   while (ads->udpw.head) adns__query_fail(ads->udpw.head, adns_s_systemfail);
00623   while (ads->tcpw.head) adns__query_fail(ads->tcpw.head, adns_s_systemfail);
00624 
00625   switch (ads->tcpstate) {
00626   case server_connecting:
00627   case server_ok:
00628     adns__tcp_broken(ads,0,0);
00629     break;
00630   case server_disconnected:
00631   case server_broken:
00632     break;
00633   default:
00634     abort();
00635   }
00636   adns__consistency(ads,0,cc_entex);
00637 }
00638 
00639 int adns_processany(adns_state ads) {
00640   int r, i;
00641   struct timeval now;
00642   struct pollfd pollfds[MAX_POLLFDS];
00643   int npollfds;
00644 
00645   adns__consistency(ads,0,cc_entex);
00646 
00647   r= gettimeofday(&now,0);
00648   if (!r) adns_processtimeouts(ads,&now);
00649 
00650   /* We just use adns__fdevents to loop over the fd's trying them.
00651    * This seems more sensible than calling select, since we're most
00652    * likely just to want to do a adns_socket_read on one or two fds anyway.
00653    */
00654   npollfds= adns__pollfds(ads,pollfds);
00655   for (i=0; i<npollfds; i++) pollfds[i].revents= pollfds[i].events & ~POLLPRI;
00656   adns__fdevents(ads,
00657          pollfds,npollfds,
00658          0,0,0,0,
00659          now,&r);
00660 
00661   adns__consistency(ads,0,cc_entex);
00662   return 0;
00663 }
00664 
00665 void adns__autosys(adns_state ads, struct timeval now) {
00666   if (ads->iflags & adns_if_noautosys) return;
00667   adns_processany(ads);
00668 }
00669 
00670 int adns__internal_check(adns_state ads,
00671              adns_query *query_io,
00672              adns_answer **answer,
00673              void **context_r) {
00674   adns_query qu;
00675 
00676   qu= *query_io;
00677   if (!qu) {
00678     if (ads->output.head) {
00679       qu= ads->output.head;
00680     } else if (ads->udpw.head || ads->tcpw.head) {
00681       return EAGAIN;
00682     } else {
00683       return ESRCH;
00684     }
00685   } else {
00686     if (qu->id>=0) return EAGAIN;
00687   }
00688   LIST_UNLINK(ads->output,qu);
00689   *answer= qu->answer;
00690   if (context_r) *context_r= qu->ctx.ext;
00691   *query_io= qu;
00692   free(qu);
00693   return 0;
00694 }
00695 
00696 int adns_wait(adns_state ads,
00697           adns_query *query_io,
00698           adns_answer **answer_r,
00699           void **context_r) {
00700   int r, maxfd, rsel;
00701   fd_set readfds, writefds, exceptfds;
00702   struct timeval tvbuf, *tvp;
00703 
00704   adns__consistency(ads,*query_io,cc_entex);
00705   for (;;) {
00706     r= adns__internal_check(ads,query_io,answer_r,context_r);
00707     if (r != EAGAIN) break;
00708     maxfd= 0; tvp= 0;
00709     FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
00710     adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,&tvp,&tvbuf,0);
00711     assert(tvp);
00712     ADNS_CLEAR_ERRNO;
00713     rsel= select(maxfd,&readfds,&writefds,&exceptfds,tvp);
00714     ADNS_CAPTURE_ERRNO;
00715     if (rsel==-1) {
00716       if (errno == EINTR) {
00717     if (ads->iflags & adns_if_eintr) { r= EINTR; break; }
00718       } else {
00719     adns__diag(ads,-1,0,"select failed in wait: %s",strerror(errno));
00720     adns_globalsystemfailure(ads);
00721       }
00722     } else {
00723       assert(rsel >= 0);
00724       adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,0);
00725     }
00726   }
00727   adns__consistency(ads,0,cc_entex);
00728   return r;
00729 }
00730 
00731 int adns_check(adns_state ads,
00732            adns_query *query_io,
00733            adns_answer **answer_r,
00734            void **context_r) {
00735   struct timeval now;
00736   int r;
00737 
00738   adns__consistency(ads,*query_io,cc_entex);
00739   r= gettimeofday(&now,0);
00740   if (!r) adns__autosys(ads,now);
00741 
00742   r= adns__internal_check(ads,query_io,answer_r,context_r);
00743   adns__consistency(ads,0,cc_entex);
00744   return r;
00745 }

Generated on Sun May 27 2012 04:24:46 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.