chiark / gitweb /
+ * Avoid infinite timeouts, causing lockup, when they should be zero !
[adns.git] / src / event.c
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
9  *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
10  *
11  *  It is part of adns, which is
12  *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
13  *    Copyright (C) 1999 Tony Finch <dot@dotat.at>
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 2, 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  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
28  */
29
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33
34 #include <sys/types.h>
35 #include <sys/time.h>
36 #include <netdb.h>
37 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
40
41 #include "internal.h"
42
43 /* TCP connection management. */
44
45 void adns__tcp_closenext(adns_state ads) {
46   int serv;
47   
48   serv= ads->tcpserver;
49   close(ads->tcpsocket);
50   ads->tcpsocket= -1;
51   ads->tcpstate= server_disconnected;
52   ads->tcprecv.used= ads->tcprecv_skip= ads->tcpsend.used= 0;
53   ads->tcpserver= (serv+1)%ads->nservers;
54 }
55
56 void adns__tcp_broken(adns_state ads, const char *what, const char *why) {
57   int serv;
58   adns_query qu, nqu;
59   
60   assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);
61   serv= ads->tcpserver;
62   adns__warn(ads,serv,0,"TCP connection lost: %s: %s",what,why);
63   adns__tcp_closenext(ads);
64   
65   for (qu= ads->timew.head; qu; qu= nqu) {
66     nqu= qu->next;
67     if (qu->state == query_tosend) continue;
68     assert(qu->state == query_tcpwait || qu->state == query_tcpsent);
69     qu->state= query_tcpwait;
70     qu->tcpfailed |= (1<<serv);
71     if (qu->tcpfailed == (1<<ads->nservers)-1) {
72       LIST_UNLINK(ads->timew,qu);
73       adns__query_fail(qu,adns_s_allservfail);
74     }
75   }
76 }
77
78 static void tcp_connected(adns_state ads, struct timeval now) {
79   adns_query qu, nqu;
80   
81   adns__debug(ads,ads->tcpserver,0,"TCP connected");
82   ads->tcpstate= server_ok;
83   for (qu= ads->timew.head; qu; qu= nqu) {
84     nqu= qu->next;
85     if (qu->state == query_tosend) continue;
86     assert (qu->state == query_tcpwait);
87     adns__query_tcp(qu,now);
88   }
89 }
90
91 void adns__tcp_tryconnect(adns_state ads, struct timeval now) {
92   int r, fd, tries;
93   struct sockaddr_in addr;
94   struct protoent *proto;
95
96   for (tries=0; tries<ads->nservers; tries++) {
97     if (ads->tcpstate == server_connecting || ads->tcpstate == server_ok) return;
98     assert(ads->tcpstate == server_disconnected);
99     assert(!ads->tcpsend.used);
100     assert(!ads->tcprecv.used);
101     assert(!ads->tcprecv_skip);
102
103     proto= getprotobyname("tcp");
104     if (!proto) { adns__diag(ads,-1,0,"unable to find protocol no. for TCP !"); return; }
105     fd= socket(AF_INET,SOCK_STREAM,proto->p_proto);
106     if (fd<0) {
107       adns__diag(ads,-1,0,"cannot create TCP socket: %s",strerror(errno));
108       return;
109     }
110     r= adns__setnonblock(ads,fd);
111     if (r) {
112       adns__diag(ads,-1,0,"cannot make TCP socket nonblocking: %s",strerror(r));
113       close(fd);
114       return;
115     }
116     memset(&addr,0,sizeof(addr));
117     addr.sin_family= AF_INET;
118     addr.sin_port= htons(DNS_PORT);
119     addr.sin_addr= ads->servers[ads->tcpserver].addr;
120     r= connect(fd,(const struct sockaddr*)&addr,sizeof(addr));
121     ads->tcpsocket= fd;
122     ads->tcpstate= server_connecting;
123     if (r==0) { tcp_connected(ads,now); continue; }
124     if (errno == EWOULDBLOCK || errno == EINPROGRESS) return;
125     adns__tcp_broken(ads,"connect",strerror(errno));
126   }
127 }
128
129 /* Timeout handling functions. */
130
131 void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,
132                              struct timeval *tv_buf) {
133   const struct timeval *now;
134   int r;
135
136   now= *now_io;
137   if (now) return;
138   r= gettimeofday(tv_buf,0); if (!r) { *now_io= tv_buf; return; }
139   adns__diag(ads,-1,0,"gettimeofday failed: %s",strerror(errno));
140   adns_globalsystemfailure(ads);
141   return;
142 }
143
144 static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
145                         struct timeval maxto) {
146   struct timeval *rbuf;
147
148   if (!tv_io) return;
149   rbuf= *tv_io;
150   if (!rbuf) {
151     *tvbuf= maxto; *tv_io= tvbuf;
152   } else {
153     if (timercmp(rbuf,&maxto,>)) *rbuf= maxto;
154   }
155 /*fprintf(stderr,"inter_maxto maxto=%ld.%06ld result=%ld.%06ld\n",
156         maxto.tv_sec,maxto.tv_usec,(**tv_io).tv_sec,(**tv_io).tv_usec);*/
157 }
158
159 static void inter_maxtoabs(struct timeval **tv_io, struct timeval *tvbuf,
160                            struct timeval now, struct timeval maxtime) {
161   ldiv_t dr;
162
163 /*fprintf(stderr,"inter_maxtoabs now=%ld.%06ld maxtime=%ld.%06ld\n",
164         now.tv_sec,now.tv_usec,maxtime.tv_sec,maxtime.tv_usec);*/
165   if (!tv_io) return;
166   maxtime.tv_sec -= (now.tv_sec+2);
167   maxtime.tv_usec -= (now.tv_usec-2000000);
168   dr= ldiv(maxtime.tv_usec,1000000);
169   maxtime.tv_sec += dr.quot;
170   maxtime.tv_usec -= dr.quot*1000000;
171   if (maxtime.tv_sec<0) timerclear(&maxtime);
172   inter_maxto(tv_io,tvbuf,maxtime);
173 }
174
175 void adns__timeouts(adns_state ads, int act,
176                     struct timeval **tv_io, struct timeval *tvbuf,
177                     struct timeval now) {
178   adns_query qu, nqu;
179
180   for (qu= ads->timew.head; qu; qu= nqu) {
181     nqu= qu->next;
182     if (!timercmp(&now,&qu->timeout,>)) {
183       if (!tv_io) continue;
184       inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
185     } else {
186       if (!act) {
187         tvbuf.tv_sec= 0;
188         tvbuf.tv_usec= 0;
189         *tv_io= &tvbuf;
190         return;
191       }
192       LIST_UNLINK(ads->timew,qu);
193       if (qu->state != query_tosend) {
194         adns__query_fail(qu,adns_s_timeout);
195       } else {
196         adns__query_send(qu,now);
197       }
198       nqu= ads->timew.head;
199     }
200   }
201 }  
202
203 void adns_firsttimeout(adns_state ads,
204                        struct timeval **tv_io, struct timeval *tvbuf,
205                        struct timeval now) {
206   adns__consistency(ads,0,cc_entex);
207   adns__timeouts(ads, 0, tv_io,tvbuf, now);
208   adns__consistency(ads,0,cc_entex);
209 }
210
211 void adns_processtimeouts(adns_state ads, const struct timeval *now) {
212   struct timeval tv_buf;
213
214   adns__consistency(ads,0,cc_entex);
215   adns__must_gettimeofday(ads,&now,&tv_buf);
216   if (now) adns__timeouts(ads, 1, 0,0, *now);
217   adns__consistency(ads,0,cc_entex);
218 }
219
220 /* fd handling functions.  These are the top-level of the real work of
221  * reception and often transmission.
222  */
223
224 int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]) {
225   /* Returns the number of entries filled in.  Always zeroes revents. */
226
227   assert(MAX_POLLFDS==2);
228
229   pollfds_buf[0].fd= ads->udpsocket;
230   pollfds_buf[0].events= POLLIN;
231   pollfds_buf[0].revents= 0;
232
233   switch (ads->tcpstate) {
234   case server_disconnected:
235     return 1;
236   case server_connecting:
237     pollfds_buf[1].events= POLLOUT;
238     break;
239   case server_ok:
240     pollfds_buf[1].events= ads->tcpsend.used ? POLLIN|POLLOUT|POLLPRI : POLLIN|POLLPRI;
241     break;
242   default:
243     abort();
244   }
245   pollfds_buf[1].fd= ads->tcpsocket;
246   return 2;
247 }
248
249 int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
250   int want, dgramlen, r, udpaddrlen, serv, old_skip;
251   byte udpbuf[DNS_MAXUDP];
252   struct sockaddr_in udpaddr;
253   
254   adns__consistency(ads,0,cc_entex);
255
256   switch (ads->tcpstate) {
257   case server_disconnected:
258   case server_connecting:
259     break;
260   case server_ok:
261     if (fd != ads->tcpsocket) break;
262     assert(!ads->tcprecv_skip);
263     for (;;) {
264       if (ads->tcprecv.used >= ads->tcprecv_skip+2) {
265         dgramlen= ((ads->tcprecv.buf[ads->tcprecv_skip]<<8) |
266                    ads->tcprecv.buf[ads->tcprecv_skip+1]);
267         if (ads->tcprecv.used >= ads->tcprecv_skip+2+dgramlen) {
268           old_skip= ads->tcprecv_skip;
269           ads->tcprecv_skip += 2+dgramlen;
270           adns__procdgram(ads, ads->tcprecv.buf+old_skip+2,
271                           dgramlen, ads->tcpserver, 1,*now);
272           continue;
273         } else {
274           want= 2+dgramlen;
275         }
276       } else {
277         want= 2;
278       }
279       ads->tcprecv.used -= ads->tcprecv_skip;
280       memmove(ads->tcprecv.buf,ads->tcprecv.buf+ads->tcprecv_skip,ads->tcprecv.used);
281       ads->tcprecv_skip= 0;
282       if (!adns__vbuf_ensure(&ads->tcprecv,want)) { r= ENOMEM; goto xit; }
283       assert(ads->tcprecv.used <= ads->tcprecv.avail);
284       if (ads->tcprecv.used == ads->tcprecv.avail) continue;
285       r= read(ads->tcpsocket,
286               ads->tcprecv.buf+ads->tcprecv.used,
287               ads->tcprecv.avail-ads->tcprecv.used);
288       if (r>0) {
289         ads->tcprecv.used+= r;
290       } else {
291         if (r) {
292           if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
293           if (errno==EINTR) continue;
294           if (errno_resources(errno)) { r= errno; goto xit; }
295         }
296         adns__tcp_broken(ads,"read",r?strerror(errno):"closed");
297         r= 0; goto xit;
298       }
299     } /* never reached */
300   default:
301     abort();
302   }
303   if (fd == ads->udpsocket) {
304     for (;;) {
305       udpaddrlen= sizeof(udpaddr);
306       r= recvfrom(ads->udpsocket,udpbuf,sizeof(udpbuf),0,
307                   (struct sockaddr*)&udpaddr,&udpaddrlen);
308       if (r<0) {
309         if (errno == EAGAIN || errno == EWOULDBLOCK) { r= 0; goto xit; }
310         if (errno == EINTR) continue;
311         if (errno_resources(errno)) { r= errno; goto xit; }
312         adns__warn(ads,-1,0,"datagram receive error: %s",strerror(errno));
313         r= 0; goto xit;
314       }
315       if (udpaddrlen != sizeof(udpaddr)) {
316         adns__diag(ads,-1,0,"datagram received with wrong address length %d"
317                    " (expected %d)", udpaddrlen,sizeof(udpaddr));
318         continue;
319       }
320       if (udpaddr.sin_family != AF_INET) {
321         adns__diag(ads,-1,0,"datagram received with wrong protocol family"
322                    " %u (expected %u)",udpaddr.sin_family,AF_INET);
323         continue;
324       }
325       if (ntohs(udpaddr.sin_port) != DNS_PORT) {
326         adns__diag(ads,-1,0,"datagram received from wrong port %u (expected %u)",
327                    ntohs(udpaddr.sin_port),DNS_PORT);
328         continue;
329       }
330       for (serv= 0;
331            serv < ads->nservers &&
332              ads->servers[serv].addr.s_addr != udpaddr.sin_addr.s_addr;
333            serv++);
334       if (serv >= ads->nservers) {
335         adns__warn(ads,-1,0,"datagram received from unknown nameserver %s",
336                    inet_ntoa(udpaddr.sin_addr));
337         continue;
338       }
339       adns__procdgram(ads,udpbuf,r,serv,0,*now);
340     }
341   }
342   r= 0;
343 xit:
344   adns__consistency(ads,0,cc_entex);
345   return r;
346 }
347
348 int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) {
349   int r;
350   
351   adns__consistency(ads,0,cc_entex);
352
353   switch (ads->tcpstate) {
354   case server_disconnected:
355     break;
356   case server_connecting:
357     if (fd != ads->tcpsocket) break;
358     assert(ads->tcprecv.used==0);
359     assert(ads->tcprecv_skip==0);
360     for (;;) {
361       if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
362       r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
363       if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
364         tcp_connected(ads,*now);
365         r= 0; goto xit;
366       }
367       if (r>0) {
368         adns__tcp_broken(ads,"connect/read","sent data before first request");
369         r= 0; goto xit;
370       }
371       if (errno==EINTR) continue;
372       if (errno_resources(errno)) { r= errno; goto xit; }
373       adns__tcp_broken(ads,"connect/read",strerror(errno));
374       r= 0; goto xit;
375     } /* not reached */
376   case server_ok:
377     if (!(ads->tcpsend.used && fd == ads->tcpsocket)) break;
378     for (;;) {
379       adns__sigpipe_protect(ads);
380       r= write(ads->tcpsocket,ads->tcpsend.buf,ads->tcpsend.used);
381       adns__sigpipe_unprotect(ads);
382       if (r<0) {
383         if (errno==EINTR) continue;
384         if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
385         if (errno_resources(errno)) { r= errno; goto xit; }
386         adns__tcp_broken(ads,"write",strerror(errno));
387         r= 0; goto xit;
388       } else if (r>0) {
389         ads->tcpsend.used -= r;
390         memmove(ads->tcpsend.buf,ads->tcpsend.buf+r,ads->tcpsend.used);
391       }
392     } /* not reached */
393   default:
394     abort();
395   }
396   r= 0;
397 xit:
398   adns__consistency(ads,0,cc_entex);
399   return r;
400 }
401   
402 int adns_processexceptional(adns_state ads, int fd, const struct timeval *now) {
403   adns__consistency(ads,0,cc_entex);
404   switch (ads->tcpstate) {
405   case server_disconnected:
406     break;
407   case server_connecting:
408   case server_ok:
409     if (fd != ads->tcpsocket) break;
410     adns__tcp_broken(ads,"poll/select","exceptional condition detected");
411     break;
412   default:
413     abort();
414   }
415   adns__consistency(ads,0,cc_entex);
416   return 0;
417 }
418
419 static void fd_event(adns_state ads, int fd,
420                      int revent, int pollflag,
421                      int maxfd, const fd_set *fds,
422                      int (*func)(adns_state, int fd, const struct timeval *now),
423                      struct timeval now, int *r_r) {
424   int r;
425   
426   if (!(revent & pollflag)) return;
427   if (fds && !(fd<maxfd && FD_ISSET(fd,fds))) return;
428   r= func(ads,fd,&now);
429   if (r) {
430     if (r_r) {
431       *r_r= r;
432     } else {
433       adns__diag(ads,-1,0,"process fd failed after select: %s",strerror(errno));
434       adns_globalsystemfailure(ads);
435     }
436   }
437 }
438
439 void adns__fdevents(adns_state ads,
440                     const struct pollfd *pollfds, int npollfds,
441                     int maxfd, const fd_set *readfds,
442                     const fd_set *writefds, const fd_set *exceptfds,
443                     struct timeval now, int *r_r) {
444   int i, fd, revents;
445
446   for (i=0; i<npollfds; i++) {
447     fd= pollfds[i].fd;
448     if (fd >= maxfd) maxfd= fd+1;
449     revents= pollfds[i].revents;
450     fd_event(ads,fd, revents,POLLIN, maxfd,readfds, adns_processreadable,now,r_r);
451     fd_event(ads,fd, revents,POLLOUT, maxfd,writefds, adns_processwriteable,now,r_r);
452     fd_event(ads,fd, revents,POLLPRI, maxfd,exceptfds, adns_processexceptional,now,r_r);
453   }
454 }
455
456 /* Wrappers for select(2). */
457
458 void adns_beforeselect(adns_state ads, int *maxfd_io, fd_set *readfds_io,
459                        fd_set *writefds_io, fd_set *exceptfds_io,
460                        struct timeval **tv_mod, struct timeval *tv_tobuf,
461                        const struct timeval *now) {
462   struct timeval tv_nowbuf;
463   struct pollfd pollfds[MAX_POLLFDS];
464   int i, fd, maxfd, npollfds;
465   
466   adns__consistency(ads,0,cc_entex);
467
468   if (tv_mod && (!*tv_mod || (*tv_mod)->tv_sec || (*tv_mod)->tv_usec)) {
469     /* The caller is planning to sleep. */
470     adns__must_gettimeofday(ads,&now,&tv_nowbuf);
471     if (!now) goto xit;
472     adns__timeouts(ads, 1, tv_mod,tv_tobuf, *now);
473   }
474
475   npollfds= adns__pollfds(ads,pollfds);
476   maxfd= *maxfd_io;
477   for (i=0; i<npollfds; i++) {
478     fd= pollfds[i].fd;
479     if (fd >= maxfd) maxfd= fd+1;
480     if (pollfds[i].events & POLLIN) FD_SET(fd,readfds_io);
481     if (pollfds[i].events & POLLOUT) FD_SET(fd,writefds_io);
482     if (pollfds[i].events & POLLPRI) FD_SET(fd,exceptfds_io);
483   }
484   *maxfd_io= maxfd;
485
486 xit:
487   adns__consistency(ads,0,cc_entex);
488 }
489
490 void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
491                       const fd_set *writefds, const fd_set *exceptfds,
492                       const struct timeval *now) {
493   struct timeval tv_buf;
494   struct pollfd pollfds[MAX_POLLFDS];
495   int npollfds, i;
496
497   adns__consistency(ads,0,cc_entex);
498   adns__must_gettimeofday(ads,&now,&tv_buf);
499   if (!now) goto xit;
500   adns_processtimeouts(ads,now);
501
502   npollfds= adns__pollfds(ads,pollfds);
503   for (i=0; i<npollfds; i++) pollfds[i].revents= POLLIN|POLLOUT|POLLPRI;
504   adns__fdevents(ads,
505                  pollfds,npollfds,
506                  maxfd,readfds,writefds,exceptfds,
507                  *now, 0);
508 xit:
509   adns__consistency(ads,0,cc_entex);
510 }
511
512 /* General helpful functions. */
513
514 void adns_globalsystemfailure(adns_state ads) {
515   adns__consistency(ads,0,cc_entex);
516
517   while (ads->timew.head) {
518     adns__query_fail(ads->timew.head, adns_s_systemfail);
519   }
520   
521   switch (ads->tcpstate) {
522   case server_connecting:
523   case server_ok:
524     adns__tcp_closenext(ads);
525     break;
526   case server_disconnected:
527     break;
528   default:
529     abort();
530   }
531   adns__consistency(ads,0,cc_entex);
532 }
533
534 int adns_processany(adns_state ads) {
535   int r, i;
536   struct timeval now;
537   struct pollfd pollfds[MAX_POLLFDS];
538   int npollfds;
539
540   adns__consistency(ads,0,cc_entex);
541
542   r= gettimeofday(&now,0);
543   if (!r) adns_processtimeouts(ads,&now);
544
545   /* We just use adns__fdevents to loop over the fd's trying them.
546    * This seems more sensible than calling select, since we're most
547    * likely just to want to do a read on one or two fds anyway.
548    */
549   npollfds= adns__pollfds(ads,pollfds);
550   for (i=0; i<npollfds; i++) pollfds[i].revents= pollfds[i].events;
551   adns__fdevents(ads,
552                  pollfds,npollfds,
553                  0,0,0,0,
554                  now,&r);
555
556   adns__consistency(ads,0,cc_entex);
557   return 0;
558 }
559
560 void adns__autosys(adns_state ads, struct timeval now) {
561   if (ads->iflags & adns_if_noautosys) return;
562   adns_processany(ads);
563 }
564
565 int adns__internal_check(adns_state ads,
566                          adns_query *query_io,
567                          adns_answer **answer,
568                          void **context_r) {
569   adns_query qu;
570
571   qu= *query_io;
572   if (!qu) {
573     if (ads->output.head) {
574       qu= ads->output.head;
575     } else if (ads->timew.head) {
576       return EAGAIN;
577     } else {
578       return ESRCH;
579     }
580   } else {
581     if (qu->id>=0) return EAGAIN;
582   }
583   LIST_UNLINK(ads->output,qu);
584   *answer= qu->answer;
585   if (context_r) *context_r= qu->ctx.ext;
586   *query_io= qu;
587   free(qu);
588   return 0;
589 }
590
591 int adns_wait(adns_state ads,
592               adns_query *query_io,
593               adns_answer **answer_r,
594               void **context_r) {
595   int r, maxfd, rsel;
596   fd_set readfds, writefds, exceptfds;
597   struct timeval tvbuf, *tvp;
598   
599   adns__consistency(ads,*query_io,cc_entex);
600   for (;;) {
601     r= adns__internal_check(ads,query_io,answer_r,context_r);
602     if (r != EAGAIN) break;
603     maxfd= 0; tvp= 0;
604     FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
605     adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,&tvp,&tvbuf,0);
606     rsel= select(maxfd,&readfds,&writefds,&exceptfds,tvp);
607     if (rsel==-1) {
608       if (errno == EINTR) {
609         if (ads->iflags & adns_if_eintr) { r= EINTR; break; }
610       } else {
611         adns__diag(ads,-1,0,"select failed in wait: %s",strerror(errno));
612         adns_globalsystemfailure(ads);
613       }
614     } else {
615       assert(rsel >= 0);
616       adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,0);
617     }
618   }
619   adns__consistency(ads,0,cc_entex);
620   return r;
621 }
622
623 int adns_check(adns_state ads,
624                adns_query *query_io,
625                adns_answer **answer_r,
626                void **context_r) {
627   struct timeval now;
628   int r;
629   
630   adns__consistency(ads,*query_io,cc_entex);
631   r= gettimeofday(&now,0);
632   if (!r) adns__autosys(ads,now);
633
634   r= adns__internal_check(ads,query_io,answer_r,context_r);
635   adns__consistency(ads,0,cc_entex);
636   return r;
637 }