chiark / gitweb /
New internal consistency checking with assert if right options set.
authorian <ian>
Sat, 25 Sep 1999 15:46:39 +0000 (15:46 +0000)
committerian <ian>
Sat, 25 Sep 1999 15:46:39 +0000 (15:46 +0000)
changelog
client/adnstest.c
src/adns.h
src/adns.make
src/check.c [new file with mode: 0644]
src/event.c
src/internal.h
src/poll.c
src/query.c
src/setup.c

index 204bd21ea3d303d3b98fe01aa3d35034056d2d23..fc5132788a5401ecdafc4730d154fc20d2d80893 100644 (file)
--- a/changelog
+++ b/changelog
@@ -4,6 +4,7 @@ adns (0.5) unstable; urgency=medium
   * New adnslogres, ~100x faster replacement for Apache logresolve;
     Thanks to Tony Finch for the program and the performance figure.
   * New adnshost utility - currently only a usage message :-).
+  * New internal consistency checking with assert if right options set.
 
   Incompatible changes:
   * RRs with mailboxes never rejected due to strange chars if _raw.
index b994e7bde8283bfee8685d46e483ed0e1ac01035..c4dd6b120709b28fa3bc15f0a57aea722f2673cc 100644 (file)
@@ -206,7 +206,8 @@ int main(int argc, char *const *argv) {
 
   if (initstring) {
     r= adns_init_strcfg(&ads,
-                       (adns_if_debug|adns_if_noautosys)^initflagsnum,
+                       (adns_if_debug|adns_if_noautosys|adns_if_checkc_freq)
+                       ^initflagsnum,
                        stdout,initstring);
   } else {
     r= adns_init(&ads,
index 9caf44f057454d1b87c764ac488081bb73163909..c440222d9f1f1ec2595cedbab6f596f128e42cc2 100644 (file)
@@ -49,6 +49,8 @@ typedef enum {
   adns_if_noautosys=    0x0010, /* do not make syscalls at every opportunity */
   adns_if_eintr=        0x0020, /* allow _wait and _synchronous to return EINTR */
   adns_if_nosigpipe=    0x0040, /* applic has SIGPIPE set to SIG_IGN, do not protect */
+  adns_if_checkc_entex= 0x0100, /* do consistency checks on entry/exit to adns funcs */
+  adns_if_checkc_freq=  0x0300, /* do consistency checks very frequently (slow!) */
 } adns_initflags;
 
 typedef enum {
@@ -379,6 +381,11 @@ adns_query adns_forallqueries_next(adns_state ads, void **context_r);
  * context_r may be 0.  *context_r may not be set when _next returns 0.
  */
 
+void adns_checkconsistency(adns_state ads);
+/* Checks the consistency of adns's internal data structures.
+ * If any error is found, the program will abort().
+ */
+
 /*
  * Example expected/legal calling sequence for submit/check/wait:
  *  adns_init
index 36b6820f74ee52cb747f38933e0d80861b12447a..e7ba997bb15ec9fe19f04224e8643dabe1c3b765 100644 (file)
@@ -17,4 +17,4 @@
 #  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 
 LIBOBJS=       types.o event.o query.o reply.o general.o setup.o transmit.o \
-               parse.o poll.o
+               parse.o poll.o check.o
diff --git a/src/check.c b/src/check.c
new file mode 100644 (file)
index 0000000..80c5ac3
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * check.c
+ * - consistency checks
+ */
+/*
+ *  This file is part of adns, which is Copyright (C) 1997-1999 Ian Jackson
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software Foundation,
+ *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+ */
+
+#include "internal.h"
+
+void adns_checkconsistency(adns_state ads) { adns__consistency(ads,cc_user); }
+
+#define DLIST_CHECK(list, nodevar, part, body)                                 \
+  if ((list).head) {                                                           \
+    assert(! (list).head->part back);                                          \
+    for ((nodevar)= (list).head; (nodevar); (nodevar)= (nodevar)->part next) { \
+      assert((nodevar)->part next                                              \
+            ? (nodevar) == (nodevar)->part next->part back                     \
+            : (nodevar) == (list).tail);                                       \
+      body                                                                     \
+    }                                                                          \
+  }
+
+static void checkc_query_alloc(adns_state ads, adns_query qu) {
+  allocnode *an;
+
+  DLIST_CHECK(qu->allocations, an, , {
+  });
+}
+
+static void checkc_query(adns_state ads, adns_query qu) {
+  assert(qu->udpnextserver < ads->nservers);
+  assert(!(qu->udpsent & (~0UL << ads->nservers)));
+  assert(!(qu->tcpfailed & (~0UL << ads->nservers)));
+  assert(qu->udpretries <= UDPMAXRETRIES);
+  assert(qu->search_pos <= ads->nsearchlist);
+}
+
+static void checkc_global(adns_state ads) {
+  int i;
+  
+  assert(ads->udpsocket >= 0);
+
+  for (i=0; i<ads->nsortlist; i++)
+    assert(!(ads->sortlist[i].base.s_addr & ~ads->sortlist[i].mask.s_addr));
+
+  assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers);
+  
+  switch (ads->tcpstate) {
+  case server_connecting:
+    assert(ads->tcpsocket >= 0);
+  case server_disconnected: /* fall through */
+    assert(!ads->tcprecv.used);
+    assert(!ads->tcpsend.used);
+    break;
+  case server_ok:
+    assert(ads->tcpsocket >= 0);
+    break;
+  default:
+    assert(!"ads->tcpstate value");
+  }
+
+  assert(ads->searchlist || !ads->nsearchlist);
+}
+
+static void checkc_queue_timew(adns_state ads) {
+  adns_query qu;
+  
+  DLIST_CHECK(ads->timew, qu, , {
+    switch (qu->state) {
+    case query_tosend:
+      assert(qu->udpsent);
+      assert(!qu->tcpfailed);
+      break;
+    case query_tcpwait:
+      assert(ads->tcpstate != server_ok);
+      break;
+    case query_tcpsent:
+      break;
+    default:
+      assert(!"timew state");
+    }
+    assert(!qu->children.head && !qu->children.tail);
+    checkc_query(ads,qu);
+    checkc_query_alloc(ads,qu);
+  });
+}
+
+static void checkc_queue_childw(adns_state ads) {
+  adns_query parent, child;
+
+  DLIST_CHECK(ads->childw, parent, , {
+    assert(parent->state == query_child);
+    assert(parent->children.head);
+    DLIST_CHECK(parent->children, child, siblings., {
+      assert(child->parent == parent);
+      assert(child->state != query_done);
+    });
+    checkc_query(ads,parent);
+    checkc_query_alloc(ads,parent);
+  });
+}
+
+static void checkc_queue_output(adns_state ads) {
+  adns_query qu;
+  
+  DLIST_CHECK(ads->output, qu, , {
+    assert(qu->state == query_done);
+    assert(!qu->children.head && !qu->children.tail);
+    assert(!qu->parent);
+    checkc_query(ads,qu);
+  });
+}
+
+void adns__consistency(adns_state ads, consistency_checks cc) {
+  switch (cc) {
+  case cc_user:
+    break;
+  case cc_entex:
+    if (!(ads->iflags & adns_if_checkc_entex)) return;
+    break;
+  case cc_freq:
+    if ((ads->iflags & adns_if_checkc_freq) != adns_if_checkc_freq) return;
+    break;
+  default:
+    abort();
+  }
+
+  checkc_global(ads);
+  checkc_queue_timew(ads);
+  checkc_queue_childw(ads);
+  checkc_queue_output(ads);
+}
index 5bdda8f6dd3cc0c3f3846f1f6258d95569d3b661..f84204d9c2c1b80b42e8044f4413bc7f49c1aaed 100644 (file)
@@ -191,14 +191,18 @@ void adns__timeouts(adns_state ads, int act,
 void adns_firsttimeout(adns_state ads,
                       struct timeval **tv_io, struct timeval *tvbuf,
                       struct timeval now) {
+  adns__consistency(ads,cc_entex);
   adns__timeouts(ads, 0, tv_io,tvbuf, now);
+  adns__consistency(ads,cc_entex);
 }
 
 void adns_processtimeouts(adns_state ads, const struct timeval *now) {
   struct timeval tv_buf;
 
-  adns__must_gettimeofday(ads,&now,&tv_buf); if (!now) return;
-  adns__timeouts(ads, 1, 0,0, *now);
+  adns__consistency(ads,cc_entex);
+  adns__must_gettimeofday(ads,&now,&tv_buf);
+  if (now) adns__timeouts(ads, 1, 0,0, *now);
+  adns__consistency(ads,cc_entex);
 }
 
 /* fd handling functions.  These are the top-level of the real work of
@@ -235,6 +239,8 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
   byte udpbuf[DNS_MAXUDP];
   struct sockaddr_in udpaddr;
   
+  adns__consistency(ads,cc_entex);
+
   switch (ads->tcpstate) {
   case server_disconnected:
   case server_connecting:
@@ -257,7 +263,7 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
       ads->tcprecv.used -= skip;
       memmove(ads->tcprecv.buf,ads->tcprecv.buf+skip,ads->tcprecv.used);
       skip= 0;
-      if (!adns__vbuf_ensure(&ads->tcprecv,want)) return ENOMEM;
+      if (!adns__vbuf_ensure(&ads->tcprecv,want)) { r= ENOMEM; goto xit; }
       assert(ads->tcprecv.used <= ads->tcprecv.avail);
       if (ads->tcprecv.used == ads->tcprecv.avail) continue;
       r= read(ads->tcpsocket,
@@ -267,12 +273,12 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
        ads->tcprecv.used+= r;
       } else {
        if (r) {
-         if (errno==EAGAIN || errno==EWOULDBLOCK) return 0;
+         if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
          if (errno==EINTR) continue;
-         if (errno_resources(errno)) return errno;
+         if (errno_resources(errno)) { r= errno; goto xit; }
        }
        adns__tcp_broken(ads,"read",r?strerror(errno):"closed");
-       return 0;
+       r= 0; goto xit;
       }
     } /* never reached */
   default:
@@ -284,11 +290,11 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
       r= recvfrom(ads->udpsocket,udpbuf,sizeof(udpbuf),0,
                  (struct sockaddr*)&udpaddr,&udpaddrlen);
       if (r<0) {
-       if (errno == EAGAIN || errno == EWOULDBLOCK) return 0;
+       if (errno == EAGAIN || errno == EWOULDBLOCK) { r= 0; goto xit; }
        if (errno == EINTR) continue;
-       if (errno_resources(errno)) return errno;
+       if (errno_resources(errno)) { r= errno; goto xit; }
        adns__warn(ads,-1,0,"datagram receive error: %s",strerror(errno));
-       return 0;
+       r= 0; goto xit;
       }
       if (udpaddrlen != sizeof(udpaddr)) {
        adns__diag(ads,-1,0,"datagram received with wrong address length %d"
@@ -317,12 +323,17 @@ int adns_processreadable(adns_state ads, int fd, const struct timeval *now) {
       adns__procdgram(ads,udpbuf,r,serv,0,*now);
     }
   }
-  return 0;
+  r= 0;
+xit:
+  adns__consistency(ads,cc_entex);
+  return r;
 }
 
 int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) {
   int r;
   
+  adns__consistency(ads,cc_entex);
+
   switch (ads->tcpstate) {
   case server_disconnected:
     break;
@@ -330,20 +341,20 @@ int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) {
     if (fd != ads->tcpsocket) break;
     assert(ads->tcprecv.used==0);
     for (;;) {
-      if (!adns__vbuf_ensure(&ads->tcprecv,1)) return ENOMEM;
+      if (!adns__vbuf_ensure(&ads->tcprecv,1)) { r= ENOMEM; goto xit; }
       r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
       if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
        tcp_connected(ads,*now);
-       return 0;
+       r= 0; goto xit;
       }
       if (r>0) {
        adns__tcp_broken(ads,"connect/read","sent data before first request");
-       return 0;
+       r= 0; goto xit;
       }
       if (errno==EINTR) continue;
-      if (errno_resources(errno)) return errno;
+      if (errno_resources(errno)) { r= errno; goto xit; }
       adns__tcp_broken(ads,"connect/read",strerror(errno));
-      return 0;
+      r= 0; goto xit;
     } /* not reached */
   case server_ok:
     if (!(ads->tcpsend.used && fd == ads->tcpsocket)) break;
@@ -353,10 +364,10 @@ int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) {
       adns__sigpipe_unprotect(ads);
       if (r<0) {
        if (errno==EINTR) continue;
-       if (errno==EAGAIN || errno==EWOULDBLOCK) return 0;
-       if (errno_resources(errno)) return errno;
+       if (errno==EAGAIN || errno==EWOULDBLOCK) { r= 0; goto xit; }
+       if (errno_resources(errno)) { r= errno; goto xit; }
        adns__tcp_broken(ads,"write",strerror(errno));
-       return 0;
+       r= 0; goto xit;
       } else if (r>0) {
        ads->tcpsend.used -= r;
        memmove(ads->tcpsend.buf,ads->tcpsend.buf+r,ads->tcpsend.used);
@@ -365,10 +376,14 @@ int adns_processwriteable(adns_state ads, int fd, const struct timeval *now) {
   default:
     abort();
   }
-  return 0;
+  r= 0;
+xit:
+  adns__consistency(ads,cc_entex);
+  return r;
 }
   
 int adns_processexceptional(adns_state ads, int fd, const struct timeval *now) {
+  adns__consistency(ads,cc_entex);
   switch (ads->tcpstate) {
   case server_disconnected:
     break;
@@ -376,10 +391,11 @@ int adns_processexceptional(adns_state ads, int fd, const struct timeval *now) {
   case server_ok:
     if (fd != ads->tcpsocket) break;
     adns__tcp_broken(ads,"poll/select","exceptional condition detected");
-    return 0;
+    break;
   default:
     abort();
   }
+  adns__consistency(ads,cc_entex);
   return 0;
 }
 
@@ -430,10 +446,12 @@ void adns_beforeselect(adns_state ads, int *maxfd_io, fd_set *readfds_io,
   struct pollfd pollfds[MAX_POLLFDS];
   int i, fd, maxfd, npollfds;
   
+  adns__consistency(ads,cc_entex);
+
   if (tv_mod && (!*tv_mod || (*tv_mod)->tv_sec || (*tv_mod)->tv_usec)) {
     /* The caller is planning to sleep. */
     adns__must_gettimeofday(ads,&now,&tv_nowbuf);
-    if (!now) return;
+    if (!now) goto xit;
     adns__timeouts(ads, 1, tv_mod,tv_tobuf, *now);
   }
 
@@ -447,6 +465,9 @@ void adns_beforeselect(adns_state ads, int *maxfd_io, fd_set *readfds_io,
     if (pollfds[i].events & POLLPRI) FD_SET(fd,exceptfds_io);
   }
   *maxfd_io= maxfd;
+
+xit:
+  adns__consistency(ads,cc_entex);
 }
 
 void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
@@ -456,8 +477,9 @@ void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
   struct pollfd pollfds[MAX_POLLFDS];
   int npollfds, i;
 
+  adns__consistency(ads,cc_entex);
   adns__must_gettimeofday(ads,&now,&tv_buf);
-  if (!now) return;
+  if (!now) goto xit;
   adns_processtimeouts(ads,now);
 
   npollfds= adns__pollfds(ads,pollfds);
@@ -466,11 +488,15 @@ void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
                 pollfds,npollfds,
                 maxfd,readfds,writefds,exceptfds,
                 *now, 0);
+xit:
+  adns__consistency(ads,cc_entex);
 }
 
 /* General helpful functions. */
 
 void adns_globalsystemfailure(adns_state ads) {
+  adns__consistency(ads,cc_entex);
+
   while (ads->timew.head) {
     adns__query_fail(ads->timew.head, adns_s_systemfail);
   }
@@ -485,6 +511,7 @@ void adns_globalsystemfailure(adns_state ads) {
   default:
     abort();
   }
+  adns__consistency(ads,cc_entex);
 }
 
 int adns_processany(adns_state ads) {
@@ -493,6 +520,8 @@ int adns_processany(adns_state ads) {
   struct pollfd pollfds[MAX_POLLFDS];
   int npollfds;
 
+  adns__consistency(ads,cc_entex);
+
   r= gettimeofday(&now,0);
   if (!r) adns_processtimeouts(ads,&now);
 
@@ -501,6 +530,8 @@ int adns_processany(adns_state ads) {
                 pollfds,npollfds,
                 0,0,0,0,
                 now,&r);
+
+  adns__consistency(ads,cc_entex);
   return r;
 }
 
@@ -538,16 +569,17 @@ int adns_wait(adns_state ads,
   fd_set readfds, writefds, exceptfds;
   struct timeval tvbuf, *tvp;
   
+  adns__consistency(ads,cc_entex);
   for (;;) {
     r= internal_check(ads,query_io,answer_r,context_r);
-    if (r != EWOULDBLOCK) return r;
+    if (r != EWOULDBLOCK) break;
     maxfd= 0; tvp= 0;
     FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
     adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,&tvp,&tvbuf,0);
     rsel= select(maxfd,&readfds,&writefds,&exceptfds,tvp);
     if (rsel==-1) {
       if (errno == EINTR) {
-       if (ads->iflags & adns_if_eintr) return EINTR;
+       if (ads->iflags & adns_if_eintr) { r= EINTR; break; }
       } else {
        adns__diag(ads,-1,0,"select failed in wait: %s",strerror(errno));
        adns_globalsystemfailure(ads);
@@ -557,6 +589,8 @@ int adns_wait(adns_state ads,
       adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,0);
     }
   }
+  adns__consistency(ads,cc_entex);
+  return r;
 }
 
 int adns_check(adns_state ads,
@@ -566,8 +600,11 @@ int adns_check(adns_state ads,
   struct timeval now;
   int r;
   
+  adns__consistency(ads,cc_entex);
   r= gettimeofday(&now,0);
   if (!r) adns__autosys(ads,now);
-  
-  return internal_check(ads,query_io,answer_r,context_r);
+
+  r= internal_check(ads,query_io,answer_r,context_r);
+  adns__consistency(ads,cc_entex);
+  return r;
 }
index eba0b05050941397f4abfb1aa0c8601c2cd492d9..6dbbff059c7a80f368410eb36a3942a98b0e159a 100644 (file)
@@ -59,6 +59,12 @@ typedef unsigned char byte;
 
 #define MAX_POLLFDS  ADNS_POLLFDS_RECOMMENDED
 
+typedef enum {
+  cc_user,
+  cc_entex,
+  cc_freq
+} consistency_checks;
+
 typedef enum {
   rcode_noerror,
   rcode_formaterror,
@@ -206,14 +212,14 @@ struct adns__query {
 
   /* Possible states:
    *
-   *  state   Queue   child  id   nextudpserver  sentudp     failedtcp
+   *  state   Queue   child  id   nextudpserver  udpsent     tcpfailed
    *                             
    *  tosend  NONE    null   >=0  0              zero        zero
    *  tosend  timew   null   >=0  any            nonzero     zero
    *  tosend  NONE    null   >=0  any            nonzero     zero
    *                             
-   *  tcpwait timew   null   >=0  irrelevant     zero        any
-   *  tcpsent timew   null   >=0  irrelevant     zero        any
+   *  tcpwait timew   null   >=0  irrelevant     any         any
+   *  tcpsent timew   null   >=0  irrelevant     any         any
    *                             
    *  child   childw  set    >=0  irrelevant     irrelevant  irrelevant
    *  child   NONE    null   >=0  irrelevant     irrelevant  irrelevant
@@ -634,6 +640,10 @@ void adns__fdevents(adns_state ads,
                    const fd_set *writefds, const fd_set *exceptfds,
                    struct timeval now, int *r_r);
 
+/* From check.c: */
+
+void adns__consistency(adns_state ads, consistency_checks cc);
+
 /* Useful static inline functions: */
 
 static inline void timevaladd(struct timeval *tv_io, long ms) {
index f4b9e05590cdd5c4db69911a98b72d7a7f47c3d9..6183e4667503e84fabac9f26d08f762fc79606f0 100644 (file)
 int adns_beforepoll(adns_state ads, struct pollfd *fds, int *nfds_io, int *timeout_io,
                    const struct timeval *now) {
   struct timeval tv_nowbuf, tv_tobuf, *tv_to;
-  int space, found, timeout_ms;
+  int space, found, timeout_ms, r;
   struct pollfd fds_tmp[MAX_POLLFDS];
 
+  adns__consistency(ads,cc_entex);
+
   if (timeout_io) {
     adns__must_gettimeofday(ads,&now,&tv_nowbuf);
-    if (!now) { *nfds_io= 0; return 0; }
+    if (!now) { *nfds_io= 0; r= 0; goto xit; }
 
     timeout_ms= *timeout_io;
     if (timeout_ms == -1) {
@@ -65,21 +67,26 @@ int adns_beforepoll(adns_state ads, struct pollfd *fds, int *nfds_io, int *timeo
   } else {
     found= adns__pollfds(ads,fds_tmp);
     *nfds_io= found;
-    if (space < found) return ERANGE;
+    if (space < found) { r= ERANGE; goto xit; }
     memcpy(fds,fds_tmp,sizeof(struct pollfd)*found);
   }
-  return 0;
+  r= 0;
+xit:
+  adns__consistency(ads,cc_entex);
+  return r;
 }
 
 void adns_afterpoll(adns_state ads, const struct pollfd *fds, int nfds,
                    const struct timeval *now) {
   struct timeval tv_buf;
 
+  adns__consistency(ads,cc_entex);
   adns__must_gettimeofday(ads,&now,&tv_buf);
-  if (!now) return;
-
-  adns__timeouts(ads, 1, 0,0, *now);
-  adns__fdevents(ads, fds,nfds, 0,0,0,0, *now,0);
+  if (now) {
+    adns__timeouts(ads, 1, 0,0, *now);
+    adns__fdevents(ads, fds,nfds, 0,0,0,0, *now,0);
+  }
+  adns__consistency(ads,cc_entex);
 }
 
 #endif
index 81fedb8af48c318c430d1d412c9976a22e50d872..d1d0b31b997e52ecd9e719be2ea62e22d28e4e86 100644 (file)
@@ -201,6 +201,8 @@ int adns_submit(adns_state ads,
   adns_query qu;
   const char *p;
 
+  adns__consistency(ads,cc_entex);
+
   typei= adns__findtype(type);
   if (!typei) return ENOSYS;
 
@@ -236,15 +238,18 @@ int adns_submit(adns_state ads,
     }
     query_simple(ads,qu, owner,ol, typei,flags, now);
   }
+  adns__consistency(ads,cc_entex);
   return 0;
 
  x_adnsfail:
   adns__query_fail(qu,stat);
+  adns__consistency(ads,cc_entex);
   return 0;
 
  x_errno:
   r= errno;
   assert(r);
+  adns__consistency(ads,cc_entex);
   return r;
 }
 
@@ -361,15 +366,19 @@ static void free_query_allocs(adns_query qu) {
 }
 
 void adns_cancel(adns_query qu) {
+  adns_state ads;
+
+  ads= qu->ads;
+  adns__consistency(ads,cc_entex);
   switch (qu->state) {
   case query_tosend: case query_tcpwait: case query_tcpsent:
-    LIST_UNLINK(qu->ads->timew,qu);
+    LIST_UNLINK(ads->timew,qu);
     break;
   case query_child:
-    LIST_UNLINK(qu->ads->childw,qu);
+    LIST_UNLINK(ads->childw,qu);
     break;
   case query_done:
-    LIST_UNLINK(qu->ads->output,qu);
+    LIST_UNLINK(ads->output,qu);
     break;
   default:
     abort();
@@ -377,6 +386,7 @@ void adns_cancel(adns_query qu) {
   free_query_allocs(qu);
   free(qu->answer);
   free(qu);
+  adns__consistency(ads,cc_entex);
 }
 
 void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now) {
@@ -464,6 +474,7 @@ void adns__query_done(adns_query qu) {
     makefinal_query(qu);
     LIST_LINK_TAIL(qu->ads->output,qu);
   }
+  qu->state= query_done;
 }
 
 void adns__query_fail(adns_query qu, adns_status stat) {
index d1bdb04306a17dd7dfd152e6ab13312c6cb17054..e29c2cf1955d2eaf5c28c3cb44a5cb4e9fbbd6c5 100644 (file)
@@ -226,6 +226,21 @@ static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf
       ads->searchndots= v;
       continue;
     }
+    if (l>=12 && !memcmp(word,"adns_checkc:",12)) {
+      if (!strcmp(word+12,"none")) {
+       ads->iflags &= ~adns_if_checkc_freq;
+       ads->iflags |= adns_if_checkc_entex;
+      } else if (!strcmp(word+12,"entex")) {
+       ads->iflags &= ~adns_if_checkc_freq;
+       ads->iflags |= adns_if_checkc_entex;
+      } else if (!strcmp(word+12,"freq")) {
+       ads->iflags |= adns_if_checkc_freq;
+      } else {
+       configparseerr(ads,fn,lno, "option adns_checkc has bad value `%s' "
+                      "(must be none, entex or freq", word+12);
+      }
+      continue;
+    }
     adns__diag(ads,-1,0,"%s:%d: unknown option `%.*s'", fn,lno, l,word);
   }
 }
@@ -530,6 +545,7 @@ int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
   r= init_finish(ads);
   if (r) return r;
 
+  adns__consistency(ads,cc_entex);
   *ads_r= ads;
   return 0;
 }
@@ -549,11 +565,14 @@ int adns_init_strcfg(adns_state *ads_r, adns_initflags flags,
   }
 
   r= init_finish(ads);  if (r) return r;
+  adns__consistency(ads,cc_entex);
   *ads_r= ads;
   return 0;
 }
 
+
 void adns_finish(adns_state ads) {
+  adns__consistency(ads,cc_entex);
   for (;;) {
     if (ads->timew.head) adns_cancel(ads->timew.head);
     else if (ads->childw.head) adns_cancel(ads->childw.head);
@@ -568,6 +587,7 @@ void adns_finish(adns_state ads) {
 }
 
 void adns_forallqueries_begin(adns_state ads) {
+  adns__consistency(ads,cc_entex);
   ads->forallnext=
     ads->timew.head ? ads->timew.head :
     ads->childw.head ? ads->childw.head :
@@ -577,6 +597,7 @@ void adns_forallqueries_begin(adns_state ads) {
 adns_query adns_forallqueries_next(adns_state ads, void **context_r) {
   adns_query qu, nqu;
 
+  adns__consistency(ads,cc_entex);
   nqu= ads->forallnext;
   for (;;) {
     qu= nqu;