chiark / gitweb /
Reads some config file directives; simple test program created.
authorian <ian>
Sun, 27 Sep 1998 17:03:03 +0000 (17:03 +0000)
committerian <ian>
Sun, 27 Sep 1998 17:03:03 +0000 (17:03 +0000)
client/adnstest.c [new file with mode: 0644]
regress/.cvsignore [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/Makefile.in [new file with mode: 0644]
src/adns-internal.h
src/adns.c
src/adns.h

diff --git a/client/adnstest.c b/client/adnstest.c
new file mode 100644 (file)
index 0000000..6763bab
--- /dev/null
@@ -0,0 +1,14 @@
+/**/
+
+#include <stdio.h>
+
+#include "adns.h"
+
+int main(void) {
+  adns_state ads;
+  int r;
+
+  r= adns_init(&ads,adns_if_debug);
+  if (r) { perror("init"); exit(2); }
+  exit(0);
+}
diff --git a/regress/.cvsignore b/regress/.cvsignore
new file mode 100644 (file)
index 0000000..04afedf
--- /dev/null
@@ -0,0 +1 @@
+dtest
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..7e5312e
--- /dev/null
@@ -0,0 +1,10 @@
+CC=gcc $(WARNS) $(WERROR) $(OPTIMISE) $(DEBUG)
+DEBUG=-g
+OPTIMISE=-O2
+WARNS= -Wall -Wmissing-prototypes -Wwrite-strings -Wstrict-prototypes \
+       -Wcast-qual -Wpointer-arith
+WERROR=-Werror
+
+all:           dtest
+
+dtest:         dtest.o adns.o
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644 (file)
index 0000000..7e5312e
--- /dev/null
@@ -0,0 +1,10 @@
+CC=gcc $(WARNS) $(WERROR) $(OPTIMISE) $(DEBUG)
+DEBUG=-g
+OPTIMISE=-O2
+WARNS= -Wall -Wmissing-prototypes -Wwrite-strings -Wstrict-prototypes \
+       -Wcast-qual -Wpointer-arith
+WERROR=-Werror
+
+all:           dtest
+
+dtest:         dtest.o adns.o
index cabb271..8666614 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef ADNS_INTERNAL_H_INCLUDED
 #define ADNS_INTERNAL_H_INCLUDED
 
+#include <sys/time.h>
+
 #include "adns.h"
 
 #define MAXSERVERS 5
@@ -14,7 +16,7 @@ struct adns__query {
   adns_query next, back;
   adns_query parent, child;
   adns_rrtype type;
-  stuct adns_answer *answer;
+  struct adns_answer *answer;
   int flags, udpretries, server;
   struct timeval timeout;
   void *context;
@@ -22,7 +24,8 @@ struct adns__query {
 };
 
 struct adns__state {
-  struct { adns_query head, tail } input, timew, childw, output;
+  adns_initflags iflags;
+  struct { adns_query head, tail; } input, timew, childw, output;
   int udpsocket;
   int qbufavail, tcpbufavail, tcpbufused, tcpbufdone;
   char *qbuf, *tcpbuf;
@@ -31,7 +34,7 @@ struct adns__state {
     struct in_addr addr;
     int tcpsocket;
     struct timeval timeout;
-    struct { adns_query head, tail } connw;
+    struct { adns_query head, tail; } connw;
   } servers[MAXSERVERS];
 };
 
index 381105d..210c256 100644 (file)
@@ -1,6 +1,15 @@
 /**/
 
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
 #include <arpa/nameser.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "adns-internal.h"
 
   do { \
     (node)->back= 0; \
     (node)->next= (list).tail; \
-    if (list).tail (list).tail->back= (node); else (list).head= (node); \
+    if ((list).tail) (list).tail->back= (node); else (list).head= (node); \
     (list).tail= (node); \
   } while(0)
 
-void addserver(adns_state ads, struct in_addr addr) {
+static void vdebug(adns_state ads, const char *fmt, va_list al) {
+  if (!(ads->iflags & adns_if_debug)) return;
+  fputs("adns debug: ",stderr);
+  vfprintf(stderr,fmt,al);
+  fputc('\n',stderr);
+}
+
+static void debug(adns_state ads, const char *fmt, ...) {
+  va_list al;
+
+  va_start(al,fmt);
+  vdebug(ads,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);
+}
+
+static void diag(adns_state ads, const char *fmt, ...) {
+  va_list al;
+
+  va_start(al,fmt);
+  vdiag(ads,fmt,al);
+  va_end(al);
+}
+
+static void addserver(adns_state ads, struct in_addr addr) {
   if (ads->nservers>=MAXSERVERS) {
-    if (ads->flags & adns_if_debug)
-      fprintf(stderr,"adns: too many nameservers, ignoring %s",
-             inet_ntoa(addr));
+    diag(ads,"too many nameservers, ignoring %s",inet_ntoa(addr));
   } else {
     ads->servers[ads->nservers].addr= addr;
     ads->servers[ads->nservers].tcpsocket= -1;
@@ -32,49 +69,180 @@ void addserver(adns_state ads, struct in_addr addr) {
   }
 }
 
-void readconfig(adns_state ads, const char *filename) {
+static void configparseerr(adns_state ads, const char *fn, int lno,
+                          const char *fmt, ...) {
+  va_list al;
+  
+  if (ads->iflags & adns_if_noerrprint) return;
+  if (lno==-1) fprintf(stderr,"adns: %s: ",fn);
+  else fprintf(stderr,"adns: %s:%d: ",fn,lno);
+  va_start(al,fmt);
+  vfprintf(stderr,fmt,al);
+  va_end(al);
+  fputc('\n',stderr);
+}
+
+static void ccf_nameserver(adns_state ads, const char *fn, int lno, const char *buf) {
+  struct in_addr ia;
+  
+  if (!inet_aton(buf,&ia)) {
+    configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf);
+    return;
+  }
+  debug(ads,"using nameserver %s",inet_ntoa(ia));
+  addserver(ads,ia);
+}
+
+static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) {
+  if (!buf) return;
+  diag(ads,"warning - `search' ignored FIXME");
+}
+
+static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) {
+  diag(ads,"warning - `sortlist' ignored FIXME");
+}
+
+static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) {
+  if (!buf) return;
+  diag(ads,"warning - `options' ignored FIXME");
+}
+
+static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) {
+  ads->nservers= 0;
+}
+
+static const struct configcommandinfo {
+  const char *name;
+  void (*fn)(adns_state ads, const char *fn, int lno, const char *buf);
+} configcommandinfos[]= {
+  { "nameserver",        ccf_nameserver  },
+  { "domain",            ccf_search      },
+  { "search",            ccf_search      },
+  { "sortlist",          ccf_sortlist    },
+  { "options",           ccf_options     },
+  { "clearnameservers",  ccf_clearnss    },
+  {  0                                   }
+};
+
+static int whitespace(int c) {
+  return c==' ' || c=='\n' || c=='\t';
+}
+
+static void readconfig(adns_state ads, const char *filename) {
+  char linebuf[2000], *p, *q;
+  FILE *file;
+  int lno, l, c;
+  const struct configcommandinfo *ccip;
+
+  file= fopen(filename,"r");
+  if (!file) {
+    if (errno == ENOENT) {
+      debug(ads,"configuration file `%s' does not exist",filename);
+      return;
+    }
+    diag(ads,"cannot open configuration file `%s': %s",filename,strerror(errno));
+    return;
+  }
+
+  for (lno=1; fgets(linebuf,sizeof(linebuf),file); lno++) {
+    l= strlen(linebuf);
+    if (!l) continue;
+    if (linebuf[l-1] != '\n' && !feof(file)) {
+      diag(ads,"%s:%d: line too long",filename,lno);
+      while ((c= getc(file)) != EOF && c != '\n') { }
+      if (c == EOF) break;
+      continue;
+    }
+    while (l>0 && whitespace(linebuf[l-1])) l--;
+    linebuf[l]= 0;
+    p= linebuf;
+    while (whitespace(*p)) p++;
+    if (*p == '#' || *p == '\n') continue;
+    q= p;
+    while (*q && !whitespace(*q)) q++;
+    for (ccip=configcommandinfos;
+        ccip->name && strncmp(ccip->name,p,q-p);
+        ccip++);
+    if (!ccip->name) {
+      diag(ads,"%s:%d: unknown configuration directive `%.*s'",filename,lno,q-p,p);
+      continue;
+    }
+    while (whitespace(*q)) q++;
+    ccip->fn(ads,filename,lno,q);
+  }
+  if (ferror(file)) {
+    diag(ads,"%s:%d: read error: %s",filename,lno,strerror(errno));
+  }
+  fclose(file);
+}
+
+static const char *instrum_getenv(adns_state ads, const char *envvar) {
+  const char *value;
+
+  value= getenv(envvar);
+  if (!value) debug(ads,"environment variable `%s' not set",envvar);
+  else debug(ads,"environment variable `%s' set to `%s'",envvar,value);
+  return value;
 }
 
-void readconfigenv(adns_state ads, const char *envvar) {
+static void readconfigenv(adns_state ads, const char *envvar) {
   const char *filename;
 
-  if (flags & adns_if_noenv) return;
-  filename= getenv(envvar); if (!filename) return;
-  readconfig(ads,filename);
+  if (ads->iflags & adns_if_noenv) {
+    debug(ads,"not checking environment variable `%s'",envvar);
+    return;
+  }
+  filename= instrum_getenv(ads,envvar);
+  if (filename) readconfig(ads,filename);
 }
   
-int adns_init(adns_state *ads_r, int flags) {
+int adns_init(adns_state *ads_r, adns_initflags flags) {
   adns_state ads;
-  const char *cfile;
+  const char *res_options, *adns_res_options;
   
   ads= malloc(sizeof(*ads)); if (!ads) return errno;
-  ads->queue.head= ads->queue.tail= 0;
+  ads->input.head= ads->input.tail= 0;
   ads->timew.head= ads->timew.tail= 0;
-  ads->child.head= ads->child.tail= 0;
-  ads->ready.head= ads->ready.tail= 0;
+  ads->childw.head= ads->childw.tail= 0;
+  ads->output.head= ads->output.tail= 0;
   ads->udpsocket= -1;
   ads->qbufavail= 0;
   ads->qbuf= 0;
   ads->tcpbufavail= ads->tcpbufused= ads->tcpbufdone= 0;
   ads->tcpbuf= 0;
-  ads->flags= flags;
+  ads->iflags= flags;
   ads->nservers= 0;
+  ads->iflags= flags;
+
+  res_options= instrum_getenv(ads,"RES_OPTIONS");
+  adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS");
+  ccf_options(ads,"RES_OPTIONS",-1,res_options);
+  ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
 
   readconfig(ads,"/etc/resolv.conf");
   readconfigenv(ads,"RES_CONF");
   readconfigenv(ads,"ADNS_RES_CONF");
+
+  ccf_options(ads,"RES_OPTIONS",-1,res_options);
+  ccf_options(ads,"ADNS_RES_OPTIONS",-1,adns_res_options);
+
+  ccf_search(ads,"LOCALDOMAIN",-1,instrum_getenv(ads,"LOCALDOMAIN"));
+  ccf_search(ads,"ADNS_LOCALDOMAIN",-1,instrum_getenv(ads,"ADNS_LOCALDOMAIN"));
+
   if (!ads->nservers) {
-    if (ads->flags & adns_if_debug)
+    struct in_addr ia;
+    if (ads->iflags & adns_if_debug)
       fprintf(stderr,"adns: no nameservers, using localhost\n");
-    addserver(ads,INADDR_LOOPBACK);
+    ia.s_addr= INADDR_LOOPBACK;
+    addserver(ads,ia);
   }
   
   *ads_r= ads;
   return 0;
 }
 
-void query_fail(adns_state ads, adns_query qu, ands_status stat) {
-  struct adns_answer ans;
+static void query_fail(adns_state ads, adns_query qu, adns_status stat) {
+  struct adns_answer *ans;
   
   ans= qu->answer;
   if (!ans) ans= malloc(sizeof(*qu->answer));
@@ -85,13 +253,13 @@ void query_fail(adns_state ads, adns_query qu, ands_status stat) {
     ans->nrrs= 0;
   }
   qu->answer= ans;
-  LIST_LINK_TAIL(ads.ready,qu);
+  LIST_LINK_TAIL(ads->input,qu);
 }
 
-void adns_event(adns_state ads,
-               fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
-               int *maxfd, struct timeval *tv) {
-  for (
+void adns_interest(adns_state ads,
+                  fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+                  int *maxfd, struct timeval **tv_io, struct timeval *tvbuf) {
+  abort(); /* FIXME */
 }
 
 int adns_submit(adns_state ads,
@@ -102,11 +270,11 @@ int adns_submit(adns_state ads,
                adns_query *query_r) {
   adns_query qu;
   adns_status stat;
-  int ol, r;
+  int ol;
 
   stat= 0;
   ol= strlen(owner);
-  if (ol>MAXDNAME+1) { stat= ands_s_invaliddomain; ol= 0; }
+  if (ol>MAXDNAME+1) { stat= adns_s_invaliddomain; ol= 0; }
   if (ol>0 && owner[ol-1]=='.') { flags &= ~adns_f_search; ol--; }
   qu= malloc(sizeof(*qu)+ol+1); if (!qu) return errno;
   qu->next= qu->back= qu->parent= qu->child= 0;
@@ -114,14 +282,16 @@ int adns_submit(adns_state ads,
   qu->answer= 0;
   qu->flags= flags;
   qu->context= context;
-  qu->retries= 0;
+  qu->udpretries= 0;
   qu->server= 0;
   memcpy(qu->owner,owner,ol); qu->owner[ol]= 0;
   if (stat) {
     query_fail(ads,qu,stat);
   } else {
     LIST_LINK_TAIL(ads->input,qu);
-    adns_event(ads,0,0,0,0,0);
+    adns_interest(ads,0,0,0,0,0,0);
   }
   *query_r= qu;
+
+  abort(); /* FIXME */
 }
index 61b3fc8..fd4c8ee 100644 (file)
@@ -3,8 +3,11 @@
 #ifndef ADNS_H_INCLUDED
 #define ADNS_H_INCLUDED
 
-typedef struct adns__state adns_state;
-typedef struct adns__query adns_query;
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+typedef struct adns__state *adns_state;
+typedef struct adns__query *adns_query;
 
 typedef enum {
   adns_if_noenv=      0x0001, /* do not look at environment */
@@ -15,30 +18,45 @@ typedef enum {
 typedef enum {
   adns_f_search=     0x0001, /* use the searchlist */
   adns_f_usevc=      0x0002, /* use a virtual circuit (TCP connection) */
+  adns_f_anyquote=   0x0004,
 } adns_queryflags;
 
 typedef enum {
-  adns_rrttype_mask=  0x0fff,
-  adns_qtf_deref=     0x1000,
-  adns_qtf_mailconv=  0x2000,
-  adns_r_none=             0,
-  adns_r_a=                1,
-  adns_r_ns_raw=           2,
-  adns_r_ns=                  adns_r_ns_raw|adns_qtf_deref,
-  adns_r_cname=            5,
-  adns_r_soa_raw=          6,
-  adns_r_soa=                 adns_r_soa_raw|adns_qtf_mailconv,
-  adns_r_null=            10,
-  adns_r_ptr_raw=         12,
-  adns_r_ptr=                 adns_r_ptr_raw|adns_rf_deref,
-  adns_r_hinfo=           13,  
-  adns_r_mx_raw=          15,
-  adns_r_mx=                  adns_r_mx_raw|adns_qtf_deref,
-  adns_r_txt=             16,
-  adns_r_rp_raw           17,
-  adns_r_rp=                  adns_r_rp_raw|adns_qtf_mailconv
+  adns__rrttype_mask=  0x0fff,
+  adns__qtf_deref=     0x1000, /* dereference domains and produce extra data */
+  adns__qtf_mailconv=  0x2000, /* put @ between first and second labels */
+  adns_r_none=              0,
+  adns_r_a=                 1,
+  adns_r_ns_raw=            2,
+  adns_r_ns=                   adns_r_ns_raw|adns__qtf_deref,
+  adns_r_cname=             5,
+  adns_r_soa_raw=           6,
+  adns_r_soa=                  adns_r_soa_raw|adns__qtf_mailconv,
+  adns_r_null=             10,
+  adns_r_ptr_raw=          12,
+  adns_r_ptr=                  adns_r_ptr_raw|adns__qtf_deref,
+  adns_r_hinfo=            13,  
+  adns_r_mx_raw=           15,
+  adns_r_mx=                   adns_r_mx_raw|adns__qtf_deref,
+  adns_r_txt=              16,
+  adns_r_rp_raw=           17,
+  adns_r_rp=                   adns_r_rp_raw|adns__qtf_mailconv
 } adns_rrtype;
 
+/* In queries without qtf_anyquote, all domains must have standard
+ * legal syntax.  In queries _with_ qtf_anyquote, domains in the query
+ * or response may contain any characters, quoted according to
+ * RFC1035 5.1.  On input to adns, the char* is a pointer to the
+ * interior of a " delimited string, except that " may appear in it,
+ * and on output, the char* is a pointer to a string which would be
+ * legal either inside or outside " delimiters, and any characters
+ * not usually legal in domain names will be quoted as \X
+ * (if the character is 33-126 except \ and ") or \DDD.
+ *
+ * Do not ask for records containing mailboxes without
+ * specifying qtf_mailconv or qtf_anyquote.
+ */
+
 typedef enum {
   adns_s_ok,
   adns_s_notresponding,
@@ -54,7 +72,8 @@ typedef enum {
 /* In dereferenced answers, multiple addresses show up as multiple
  * answers with all the dm pointers being the same.  If no
  * address is available (permanent failure) then INADDR_NONE is
- * used. */
+ * used.
+ */
 
 struct adns_answer {
   adns_status status;
@@ -98,7 +117,7 @@ struct adns_answer {
  *  ands_query, _wait and _answer set *answer to 0.
  */
 
-int adns_init(adns_state *newstate_r);
+int adns_init(adns_state *newstate_r, adns_initflags flags);
 
 int adns_synchronous(adns_state ads,
                     const char *owner,
@@ -111,9 +130,9 @@ int adns_submit(adns_state ads,
                adns_rrtype type,
                int flags,
                void *context,
-               const struct adns_query *query_r);
+               adns_query *query_r);
 
-int adns_query(adns_state ads,
+int adns_check(adns_state ads,
               adns_query *query_io,
               struct adns_answer *answer,
               void *context_r);
@@ -121,18 +140,29 @@ int adns_query(adns_state ads,
 int adns_wait(adns_state ads,
              adns_query *query_io,
              struct adns_answer *answer,
-              void *context_r);
+             void *context_r);
 
 int adns_cancel(adns_state ads, adns_query query);
 
 int adns_finish(adns_state);
 
-void adns_event(adns_state, fd_set *readfds_mod,
-               fd_set *writefds_mod, fd_set *exceptfds_mod,
-               int *maxfd_mod, struct timeval *tv_mod);
-/* You may call this with *_mod=0 to have a simple callback,
-   or with *fds_mod=*maxfd_mod=0 but tv_mod!=0 if you are
-   not going to sleep, or with all !=0 if you are going to sleep. */
+void adns_interest(adns_state, fd_set *readfds_mod,
+                  fd_set *writefds_mod, fd_set *exceptfds_mod,
+                  int *maxfd_mod, struct timeval **tv_mod, struct timeval *tv_buf);
+/* You may call this with *_mod=0 to allow adns to have flow-of-control
+ * briefly, or with *fds_mod=*maxfd_mod=0 but tv_mod!=0 if you are
+ * not going to sleep, or with all !=0 if you are going to sleep.
+ * If tv_mod!=0 and *tv_mod=0 then tv_buf must be !0 and *tv_buf is irrelevant
+ * and may be overwritten (and *tv_mod set to tv_buf); otherwise tv_buf is ignored.
+ */
+
+int adns_callback(adns_state, fd_set readfds, fd_set writefds,
+                 fd_set exceptfds, int maxfd);
+/* For select-driven programs, this allows adns to know which fd's are relevant,
+ * so that it doesn't need to make syscalls on others of its fd's.  It's a kind
+ * of limited flow-of-control allowance.  It will return how many adns fd's were
+ * in the set, so you can tell if your select handling code is missing things.
+ */
 
 /* Example expected/legal calling sequences:
  *  adns_init
@@ -140,7 +170,7 @@ void adns_event(adns_state, fd_set *readfds_mod,
  *  adns_submit 2
  *  adns_submit 3
  *  adns_wait 1
- *  adns_query 3 -> EWOULDBLOCK
+ *  adns_check 3 -> EWOULDBLOCK
  *  adns_wait 2
  *  adns_wait 3
  *  ....
@@ -149,7 +179,7 @@ void adns_event(adns_state, fd_set *readfds_mod,
  *  adns_init
  *  adns_submit ...
  *  loop {
- *   adns_query
+ *   adns_check
  *   adns_interest
  *   select
  *   adns_callback