chiark / gitweb /
More rearrangements and code.
authorian <ian>
Sat, 3 Oct 1998 22:56:58 +0000 (22:56 +0000)
committerian <ian>
Sat, 3 Oct 1998 22:56:58 +0000 (22:56 +0000)
src/adns-internal.h [new file with mode: 0644]
src/adns.h
src/event.c
src/internal.h [new file with mode: 0644]
src/query.c
src/setup.c

diff --git a/src/adns-internal.h b/src/adns-internal.h
new file mode 100644 (file)
index 0000000..2cdafbf
--- /dev/null
@@ -0,0 +1,130 @@
+/**/
+
+#ifndef ADNS_INTERNAL_H_INCLUDED
+#define ADNS_INTERNAL_H_INCLUDED
+
+#include <sys/time.h>
+
+#include "adns.h"
+
+/* Configuration and constants */
+
+#define MAXSERVERS 5
+#define MAXUDPRETRIES 15
+#define UDPRETRYMS 2000
+#define TCPMS 30000
+#define LOCALRESOURCEMS 20
+#define UDPMAXDGRAM 512
+#define NSPORT 53
+
+/* Shared data structures */
+
+union adns__align {
+  adns_status status;
+  char *cp;
+  adns_rrtype type;
+  int int;
+  struct in_addr ia;
+  unsigned long ul;
+};
+
+struct adns__query {
+  /* FIXME: make sure this is all init'd properly */
+  adns_query back, next;
+  adns_query parent;
+  struct { adns_query head, tail; } children;
+  struct { adns_query back, next; } siblings;
+  adns_rrtype type;
+  adns_answer *answer;
+  size_t ansalloc; ansused;
+  int id, flags, udpretries; /* udpretries==-1 => _f_usevc or too big for UDP */
+  int nextudpserver;
+  unsigned long sentudp, senttcp; /* bitmaps indexed by server */
+  struct timeval timeout;
+  void *context;
+  unsigned char *querymsg;
+  int querylen;
+  char owner[1];
+  /* Possible states:
+   *  Queue   child  id   answer    nextserver  sentudp             senttcp
+   *  tosend  null   >=0  null      any         any                 any
+   *  timew   null   >=0  null      any         at least 1 bit set  any
+   *  childw  set    >=0  partial   any         any                 any
+   *  output  null   -1   set/null  any         any                 any
+   */
+};
+
+struct adns__vbuf {
+  size_t used, avail;
+  unsigned char *buf;
+};
+
+struct adns__state {
+  /* FIXME: make sure this is all init'd properly */
+  adns_initflags iflags;
+  FILE *diagfile;
+  struct { adns_query head, tail; } tosend, timew, childw, output;
+  int nextid, udpsocket;
+  adns_vbuf rqbuf, tcpsend, tcprecv;
+  int nservers, tcpserver;
+  enum adns__tcpstate { server_disc, server_connecting, server_ok } tcpstate;
+  int tcpsocket;
+  struct timeval tcptimeout;
+  struct server {
+    struct in_addr addr;
+  } servers[MAXSERVERS];
+};
+
+/* From setup.c: */
+
+void adns__vdiag(adns_state ads, adns_initflags prevent, const char *pfx,
+                int serv, const char *fmt, va_list al);
+void adns__debug(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
+void adns__warn(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
+void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
+
+/* From submit.c: */
+
+void adns__query_fail(adns_state ads, adns_query qu, adns_status stat);
+
+/* From query.c: */
+
+void adns__quproc_tosend(adns_state ads, adns_query qu, struct timeval now) {
+
+/* Useful static inline functions: */
+
+static inline void timevaladd(struct timeval *tv_io, long ms) {
+  struct timeval tmp;
+  assert(ms>=0);
+  tmp= *tv_io;
+  tmp.tv_usec += (ms%1000)*1000;
+  tmp.tv_sec += ms/1000;
+  if (tmp.tv_usec >= 1000) { tmp.tv_sec++; tmp.tv_usec -= 1000; }
+  *tv_io= tmp;
+}    
+
+static inline int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; }
+static inline int ctype_digit(int c) { return c>='0' && c<='9'; }
+
+/* Useful macros */
+
+#define LIST_UNLINK_PART(list,node,part) \
+  do { \
+    if ((node)->back) (node)->back->part next= (node)->part next; \
+      else                        (list).head= (node)->part next; \
+    if ((node)->next) (node)->next->part back= (node)->part back; \
+      else                        (list).tail= (node)->part back; \
+  } while(0)
+
+#define LIST_LINK_TAIL_PART(list,node,part) \
+  do { \
+    (node)->part back= 0; \
+    (node)->part next= (list).tail; \
+    if ((list).tail) (list).tail->part back= (node); else (list).part head= (node); \
+    (list).tail= (node); \
+  } while(0)
+
+#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,)
+#define LIST_LINK_TAIL_PART(list,node) LIST_LINK_TAIL(list,node,)
+
+#endif
index d11742f..23c71ef 100644 (file)
@@ -10,10 +10,11 @@ typedef struct adns__state *adns_state;
 typedef struct adns__query *adns_query;
 
 typedef enum {
-  adns_if_noenv=      0x0001, /* do not look at environment */
-  adns_if_noerrprint= 0x0002, /* never print output to stderr */
-  adns_if_debug=      0x0004, /* print debugging output to stderr */
-  adns_if_noautosys=  0x0008, /* do not do full flow-of-control whenever we can */
+  adns_if_noenv=        0x0001, /* do not look at environment */
+  adns_if_noerrprint=   0x0002, /* never print output to stderr (_debug overrides) */
+  adns_if_noserverwarn= 0x0004, /* do not warn to stderr about duff nameservers etc */
+  adns_if_debug=        0x0008, /* enable all output to stderr plus debug msgs*/
+  adns_if_noautosys=    0x0010, /* do not make syscalls at every opportunity */
 } adns_initflags;
 
 typedef enum {
@@ -60,24 +61,18 @@ typedef enum {
 
 typedef enum {
   adns_s_ok,
-  adns_s_notresponding,
-  adns_s_serverfailure,
+  adns_s_timeout,
   adns_s_unknownqtype,
-  adns_s_remoteerror,
   adns_s_nolocalmem,
   adns_s_max_tempfail= 99,
+  adns_s_inconsistent, /* PTR gives domain whose A does not match */
+  adns_s_badcname, /* CNAME found where actual record expected */
+  adns_s_max_misconfig= 199;
   adns_s_nxdomain,
   adns_s_norecord,
-  adns_s_inconsistent, /* for bad PTR */
   adns_s_invaliddomain
 } adns_status;
 
-/* In dereferenced answers, multiple addresses show up as multiple
- * answers with all the dm pointers being the same, with ref= adns_s_ok.
- * If no address is available then INADDR_NONE is used, and ref indicates
- * the error.
- */
-
 typedef struct {
   char *dm;
   adns_status astatus;
@@ -127,7 +122,7 @@ typedef struct {
  *  ands_check and _wait set *answer to 0.
  */
 
-int adns_init(adns_state *newstate_r, adns_initflags flags);
+int adns_init(adns_state *newstate_r, adns_initflags flags, FILE *diagfile/*0=>stderr*/);
 
 int adns_synchronous(adns_state ads,
                     const char *owner,
index 33998a8..68abb3c 100644 (file)
@@ -1,5 +1,7 @@
 /**/
 
+#include "adns-internal.h"
+
 static void autosys(adns_state ads, struct timeval now) {
   if (ads->iflags & adns_if_noautosys) return;
   adns_callback(ads,-1,0,0,0);
@@ -10,11 +12,21 @@ static int callb_checkfd(int maxfd, const fd_set *fds, int fd) {
          fd<maxfd && FD_ISSET(fd,fds);
 }
 
+static void tcpserver_broken(adns_state ads, const char *what, const char *why) {
+  assert(ads->tcpstate == server_connecting || ads->tcpstate == server_connected);
+  warn("nameserver %s TCP connection lost: %s: %s",
+       inet_ntoa(ads->servers[tcpserver].addr,what,why));
+  close(ads->tcpsocket);
+  ads->tcpstate= server_disconnected;
+  
+       
 int adns_callback(adns_state ads, int maxfd,
                  const fd_set *readfds, const fd_set *writefds,
                  const fd_set *exceptfds) {
-  int skip, dgramlen, count;
+  int skip, dgramlen, count, udpaddrlen;
   enum adns__tcpstate oldtcpstate;
+  unsigned char udpbuf[UDPMAXDGRAM];
+  struct sockaddr_in udpaddr;
 
   count= 0;
   oldtcpstate= ads->tcpstate;
@@ -27,8 +39,8 @@ int adns_callback(adns_state ads, int maxfd,
       if (ads->tcprecv.buf) {
        r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
        if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
-         diag("nameserver %s TCP connection made",
-              inet_ntoa(ads->servers[ads->tcpserver].addr));
+         debug("nameserver %s TCP connected",
+               inet_ntoa(ads->servers[ads->tcpserver].addr));
          ads->tcpstate= server_connected;
        } else if (r>0) {
          tcpserver_broken(ads,"connect/read","sent data before first request");
@@ -53,11 +65,11 @@ int adns_callback(adns_state ads, int maxfd,
          if (ads->tcprecv.used<skip+2+dgramlen) {
            want= 2+dgramlen;
          } else {
-           procdgram(ads,ads->tcprecv.buf+skip+2,dgramlen,-1);
+           procdgram(ads,ads->tcprecv.buf+skip+2,dgramlen,ads->tcpserver);
            skip+= 2+dgramlen; continue;
          }
        }
-       Ads->tcprecv.used -= skip;
+       ads->tcprecv.used -= skip;
        memmove(ads->tcprecv.buf,ads->tcprecv.buf+skip,ads->tcprecv.used);
        vbuf_ensure(&ads->tcprecv,want);
        if (ads->tcprecv.used >= ads->tcprecv.avail) break;
@@ -90,39 +102,44 @@ int adns_callback(adns_state ads, int maxfd,
     }
   }
 
-  if (
-    break;
-       
-      
-       }
-         
-  tcpserver_broken(
-               
-           if (ads-
-         used= 0;
-         for (;;) {
-         vbuf_ensure(&ads->tcprecv,2);
-         vbuf_ensure(&ads->tcprecv,
-         if (ads->tcprecv.avail<2) break;
-      if (ads->tcprecv.used
-      
-      if (ads->tcprecv.used<2 && ads->tcprecv.avail
-      if (ads->tcprecv.used<2 && ads->tcprecv.avail
-      r= read(ads->tcpsocket,
-      if (adns->tcprecv.used<2) {
-       if (
-         
-  if (ads->tcpstate != server_disc) {
-    
-      
+  if (callb_checkfd(maxfd,readfds,ads->udpsocket)) {
+    count++;
+    for (;;) {
+      udpaddrlen= sizeof(udpaddr);
+      r= recvfrom(ads->udpsocket,udpbuf,sizeof(udpbuf),0,&udpaddr,&udpaddrlen);
+      if (r<0) {
+       if (!(errno == EAGAIN || errno == EWOULDBLOCK ||
+             errno == EINTR || errno == ENOMEM || errno == ENOBUFS))
+         warn("datagram receive error: %s",strerror(errno));
+       break;
+      }
+      if (udpaddrlen != sizeof(udpaddr)) {
+       diag("datagram received with wrong address length %d (expected %d)",
+            udpaddrlen,sizeof(udpaddr));
+       continue;
+      }
+      if (udpaddr.sin_family != AF_INET) {
+       diag("datagram received with wrong protocol family %u (expected %u)",
+            udpaddr.sin_family,AF_INET);
+       continue;
+      }
+      if (ntohs(udpaddr.sin_port) != NSPORT) {
+       diag("datagram received from wrong port %u (expected %u)",
+            ntohs(udpaddr.sin_port),NSPORT);
+       continue;
+      }
+      for (serv= 0;
+          serv < ads->nservers &&
+            ads->servers[serv].addr.s_addr != udpaddr.sin_addr.s_addr;
+          serv++);
+      if (serv >= ads->nservers) {
+       warn("datagram received from unknown nameserver %s",inet_ntoa(udpaddr.sin_addr));
+       continue;
+      }
+      procdgram(ads,udpbuf,r,serv);
     }
-  if (maxfd<0 || !readfds || (FD_ISSET
-      ads->
-      
-  abort(); /* FIXME */
+  }
 }
-         diag("nameserver #%d (%s) TCP connection died: %s",
-              inet_ntoa(ads->servers[tcpserver].addr),
 
 static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
                        struct timeval maxto) {
@@ -149,7 +166,7 @@ static void localresourcerr(struct timeval **tv_io, struct timeval *tvbuf,
                            const char *syscall) {
   struct timeval tvto_lr;
   
-  diag(ads,"local system resources scarce (during %s): %s",syscall,strerror(errno));
+  warn(ads,"local system resources scarce (during %s): %s",syscall,strerror(errno));
   timerclear(&tvto_lr); timevaladd(&tvto_lr,LOCALRESOURCEMS);
   inter_maxto(tv_io, tvbuf, tvto_lr);
   return;
@@ -190,6 +207,7 @@ void adns_interest(adns_state ads, int *maxfd,
   }
 
   inter_addfd(maxfd,readfds,ads->udpsocket);
+
   switch (ads->tcpstate) {
   case server_disc:
     break;
@@ -203,7 +221,6 @@ void adns_interest(adns_state ads, int *maxfd,
   default:
     abort();
   }
-  
 }
 
 static int internal_check(adns_state ads,
@@ -237,8 +254,8 @@ int adns_wait(adns_state ads,
   for (;;) {
     r= internal_check(ads,query_io,answer_r,context_r);
     if (r && r != EWOULDBLOCK) return r;
-    FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
     maxfd= 0; tvp= 0;
+    FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
     adns_interest(ads,&maxfd,&readfds,&writefds,&exceptfds,&tvp,&tvbuf);
     rsel= select(maxfd,&readfds,&writefds,&exceptfds,tvp);
     if (rsel==-1) return r;
diff --git a/src/internal.h b/src/internal.h
new file mode 100644 (file)
index 0000000..2cdafbf
--- /dev/null
@@ -0,0 +1,130 @@
+/**/
+
+#ifndef ADNS_INTERNAL_H_INCLUDED
+#define ADNS_INTERNAL_H_INCLUDED
+
+#include <sys/time.h>
+
+#include "adns.h"
+
+/* Configuration and constants */
+
+#define MAXSERVERS 5
+#define MAXUDPRETRIES 15
+#define UDPRETRYMS 2000
+#define TCPMS 30000
+#define LOCALRESOURCEMS 20
+#define UDPMAXDGRAM 512
+#define NSPORT 53
+
+/* Shared data structures */
+
+union adns__align {
+  adns_status status;
+  char *cp;
+  adns_rrtype type;
+  int int;
+  struct in_addr ia;
+  unsigned long ul;
+};
+
+struct adns__query {
+  /* FIXME: make sure this is all init'd properly */
+  adns_query back, next;
+  adns_query parent;
+  struct { adns_query head, tail; } children;
+  struct { adns_query back, next; } siblings;
+  adns_rrtype type;
+  adns_answer *answer;
+  size_t ansalloc; ansused;
+  int id, flags, udpretries; /* udpretries==-1 => _f_usevc or too big for UDP */
+  int nextudpserver;
+  unsigned long sentudp, senttcp; /* bitmaps indexed by server */
+  struct timeval timeout;
+  void *context;
+  unsigned char *querymsg;
+  int querylen;
+  char owner[1];
+  /* Possible states:
+   *  Queue   child  id   answer    nextserver  sentudp             senttcp
+   *  tosend  null   >=0  null      any         any                 any
+   *  timew   null   >=0  null      any         at least 1 bit set  any
+   *  childw  set    >=0  partial   any         any                 any
+   *  output  null   -1   set/null  any         any                 any
+   */
+};
+
+struct adns__vbuf {
+  size_t used, avail;
+  unsigned char *buf;
+};
+
+struct adns__state {
+  /* FIXME: make sure this is all init'd properly */
+  adns_initflags iflags;
+  FILE *diagfile;
+  struct { adns_query head, tail; } tosend, timew, childw, output;
+  int nextid, udpsocket;
+  adns_vbuf rqbuf, tcpsend, tcprecv;
+  int nservers, tcpserver;
+  enum adns__tcpstate { server_disc, server_connecting, server_ok } tcpstate;
+  int tcpsocket;
+  struct timeval tcptimeout;
+  struct server {
+    struct in_addr addr;
+  } servers[MAXSERVERS];
+};
+
+/* From setup.c: */
+
+void adns__vdiag(adns_state ads, adns_initflags prevent, const char *pfx,
+                int serv, const char *fmt, va_list al);
+void adns__debug(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
+void adns__warn(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
+void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(2,3);
+
+/* From submit.c: */
+
+void adns__query_fail(adns_state ads, adns_query qu, adns_status stat);
+
+/* From query.c: */
+
+void adns__quproc_tosend(adns_state ads, adns_query qu, struct timeval now) {
+
+/* Useful static inline functions: */
+
+static inline void timevaladd(struct timeval *tv_io, long ms) {
+  struct timeval tmp;
+  assert(ms>=0);
+  tmp= *tv_io;
+  tmp.tv_usec += (ms%1000)*1000;
+  tmp.tv_sec += ms/1000;
+  if (tmp.tv_usec >= 1000) { tmp.tv_sec++; tmp.tv_usec -= 1000; }
+  *tv_io= tmp;
+}    
+
+static inline int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; }
+static inline int ctype_digit(int c) { return c>='0' && c<='9'; }
+
+/* Useful macros */
+
+#define LIST_UNLINK_PART(list,node,part) \
+  do { \
+    if ((node)->back) (node)->back->part next= (node)->part next; \
+      else                        (list).head= (node)->part next; \
+    if ((node)->next) (node)->next->part back= (node)->part back; \
+      else                        (list).tail= (node)->part back; \
+  } while(0)
+
+#define LIST_LINK_TAIL_PART(list,node,part) \
+  do { \
+    (node)->part back= 0; \
+    (node)->part next= (list).tail; \
+    if ((list).tail) (list).tail->part back= (node); else (list).part head= (node); \
+    (list).tail= (node); \
+  } while(0)
+
+#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,)
+#define LIST_LINK_TAIL_PART(list,node) LIST_LINK_TAIL(list,node,)
+
+#endif
index 667ec6d..c9ad8fd 100644 (file)
@@ -71,7 +71,9 @@ static adns_status mkquery(adns_state ads, const char *owner, int ol, int id,
 }
 
 void adns__quproc_tosend(adns_state ads, adns_query qu, struct timeval now) {
-  /* Query must be on the `tosend' queue, and guarantees to remove it. */
+  /* Query must be on the `tosend' queue, and guarantees to remove it.
+   * fixme: Do not send more than 512-byte udp datagrams
+   */
   struct sockaddr_in servaddr;
   int serv;
 
@@ -85,13 +87,13 @@ void adns__quproc_tosend(adns_state ads, adns_query qu, struct timeval now) {
     memset(&servaddr,0,sizeof(servaddr));
     servaddr.sin_family= AF_INET;
     servaddr.sin_addr= ads->servers[serv].addr;
-    servaddr.sin_port= htons(53);
+    servaddr.sin_port= htons(NSPORT);
     r= sendto(ads->udpsocket,qu->querymsg,qu->querylen,0,&servaddr,sizeof(servaddr));
     if (r<0 && errno == EMSGSIZE) {
       qu->nextudpserver= -1;
     } else {
       if (r<0) {
-       diag("sendto %s failed: %s",inet_ntoa(servaddr.sin_addr),strerror(errno));
+       warn("sendto %s failed: %s",inet_ntoa(servaddr.sin_addr),strerror(errno));
       }
       DLIST_UNLINK(ads->tosend,qu);
       timevaladd(&now,UDPRETRYMS);
@@ -104,6 +106,7 @@ void adns__quproc_tosend(adns_state ads, adns_query qu, struct timeval now) {
     }
   }
 
+  /* fixme: TCP queries preceded by length */
   for (;;) {
     serv= tcpserver_get(ads);
     if (serv<0) { r=0; break; }
index ecf92a2..8939ac6 100644 (file)
@@ -2,33 +2,39 @@
 
 #include "adns-internal.h"
 
-static void vdebug(adns_state ads, const char *fmt, va_list al) {
-  if (!(ads->iflags & adns_if_debug)) return;
-  fputs("adns debug: ",stderr);
+void adns__vdiag(adns_state ads, adns_initflags prevent, const char *pfx,
+                       int serv, const char *fmt, va_list al) {
+  if (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))) return;
+  if (serv>=0) {
+    fprintf(stderr,"adns%s: nameserver %s: ",pfx,inet_ntoa(ads->servers[serv].addr));
+  } else {
+    fprintf(stderr,"adns%s: ",pfx);
+  }
   vfprintf(stderr,fmt,al);
   fputc('\n',stderr);
 }
 
-void adns__debug(adns_state ads, const char *fmt, ...) {
+void adns__debug(adns_state ads, int serv, const char *fmt, ...) {
   va_list al;
 
   va_start(al,fmt);
-  vdebug(ads,fmt,al);
+  vdiag(ads," debug",0,serv,fmt,al);
   va_end(al);
 }
 
-static void vdiag(adns_state ads, const char *fmt, va_list al) {
-  if (ads->iflags & adns_if_noerrprint) return;
-  fputs("adns: ",stderr);
-  vfprintf(stderr,fmt,al);
-  fputc('\n',stderr);
+void adns__swarn(adns_state ads, int serv, const char *fmt, ...) {
+  va_list al;
+
+  va_start(al,fmt);
+  vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,fmt,al);
+  va_end(al);
 }
 
-void adns__diag(adns_state ads, const char *fmt, ...) {
+void adns__diag(adns_state ads, int serv, const char *fmt, ...) {
   va_list al;
 
   va_start(al,fmt);
-  vdiag(ads,fmt,al);
+  vdiag(ads,"",adns_if_noerrprint,serv,fmt,al);
   va_end(al);
 }
 
@@ -110,9 +116,6 @@ static const struct configcommandinfo {
   {  0                                   }
 };
 
-static int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; }
-static int ctype_digit(int c) { return c>='0' && c<='9'; }
-
 static void readconfig(adns_state ads, const char *filename) {
   char linebuf[2000], *p, *q;
   FILE *file;