chiark / gitweb /
adnshost improvements - now runs for at least one query.
authorian <ian>
Tue, 12 Oct 1999 23:00:04 +0000 (23:00 +0000)
committerian <ian>
Tue, 12 Oct 1999 23:00:04 +0000 (23:00 +0000)
changelog
client/adh-main.c
client/adh-opts.c
client/adh-query.c
client/adnshost.h

index cc9e0582d882d753214c3a55464e543550dfa3f7..6b6340987d3be0820f43da9515f94b0702980a51 100644 (file)
--- a/changelog
+++ b/changelog
@@ -5,7 +5,7 @@ adns (0.5) unstable; urgency=medium
     Thanks to Tony Finch for the program and the performance figure.
   * New internal consistency checking with assert if right options set.
   * New adns_wait_poll function like adns_wait but uses poll, not select.
-  * New adnshost utility - currently only a usage message :-).
+  * New adnshost utility - very alpha.
 
   Incompatible changes:
   * RRs with mailboxes never rejected due to strange chars if _raw.
@@ -19,6 +19,7 @@ adns (0.5) unstable; urgency=medium
   * Do not scramble innards when a query on the output queue is cancelled.
   * Do not close tcp socket twice.
   * Mailboxes containing spaces in their names are quoted.
+  * Give ESRCH, not EAGAIN, if _check called with no queries outstanding.
   * adns_rr_hostaddr naddrs is -1 on temporary failure (as documented).
   * Reject TXT RRs with no strings.
   * Correct error messages for qname CNAME foo, foo CNAME bar.
index 855a258c9a2f874f42ace81c984dc89598b5aed2..33b1f59b9b2431337d753b7ca9643f4c0cc1ecbf 100644 (file)
@@ -43,9 +43,14 @@ void usageerr(const char *fmt, ...) {
   exit(11);
 }
 
+void outerr(void) {
+  sysfail("write to stdout",errno);
+}
+
 static void domain_do_arg(const char *domain) {
   if (ov_pipe) usageerr("-f/--pipe not consistent with domains on command line");
-  domain_do(domain);
+  ensure_adns_init();
+  query_do(domain);
 }
 
 void *xmalloc(size_t sz) {
@@ -65,9 +70,21 @@ char *xstrsave(const char *str) {
 
 void of_type(const struct optioninfo *oi, const char *arg) { abort(); }
 
+int rcode;
+
+void setnonblock(int fd, int nonblock) { }
+
+static void read_query(void) { abort(); }
+
 int main(int argc, const char *const *argv) {
   const char *arg;
   const struct optioninfo *oip;
+  struct timeval *tv, tvbuf;
+  adns_query qu;
+  void *qun_v;
+  adns_answer *answer;
+  int r, maxfd;
+  fd_set readfds, writefds, exceptfds;
   
   while ((arg= *++argv)) {
     if (arg[0] == '-') {
@@ -104,6 +121,37 @@ int main(int argc, const char *const *argv) {
       domain_do_arg(arg);
     }
   }
+
   if (!ov_pipe && !ads) usageerr("no domains given, and -f/--pipe not used; try --help");
-  abort();
+
+  for (;;) {
+    for (;;) {
+      qu= ov_asynch ? 0 : outstanding.head ? outstanding.head->qu : 0;
+      r= adns_check(ads,&qu,&answer,&qun_v);
+      if (r == EAGAIN) break;
+      if (r == ESRCH) { if (!ov_pipe) goto x_quit; else break; }
+      assert(!r);
+      query_done(qun_v,answer);
+    }
+    maxfd= 0;
+    FD_ZERO(&readfds);
+    FD_ZERO(&writefds);
+    FD_ZERO(&exceptfds);
+    if (ov_pipe) {
+      maxfd= 1;
+      FD_SET(0,&readfds);
+    }
+    tv= 0;
+    adns_beforeselect(ads, &maxfd, &readfds,&writefds,&exceptfds, &tv,&tvbuf,0);
+    r= select(maxfd, &readfds,&writefds,&exceptfds, tv);
+    if (r == -1) {
+      if (errno == EINTR) continue;
+      sysfail("select",errno);
+    }
+    adns_afterselect(ads, maxfd, &readfds,&writefds,&exceptfds, 0);
+    if (ov_pipe && FD_ISSET(0,&readfds)) read_query();
+  }
+x_quit:
+  if (fclose(stdout)) outerr();
+  exit(rcode);
 }
index 03ba5bbfc28eecfa189f1f5ea20193cb01eb8e97..6af9e021b84502a944972689f3242563951cdc7f 100644 (file)
@@ -216,11 +216,13 @@ static void printusage(void) {
        "or if the <owner> domain refers to a CNAME and --show-cname is on\n"
        "   [<owner>] [<ttl>] CNAME <cname>\n"
        "   [<cname>] [<ttl>] <type> <data>\n"
-       "When a query fails you get a line like:\n"
- "   ; failed <statustype> [<owner>] [<ttl>] [<type>] <status> \"<status string>\"\n"
+       "When a query fails you get a line like this (broken here for readability):\n"
+       "   ; failed <statustype> <statusnum> <statusabbrev> \\\n"
+       "       [<owner>] [<ttl>] [<cname>] \"<status string>\"\n"
        "\n"
        "If you use --asynch each answer (success or failure) is preceded by a line\n"
-       "   <id> <statustype> <status> <nrrs> [<cname>] \"<status string>\"\n"
+       "   <id> <nrrs> <statustype> <statusnum> <statusabbrev> \\\n"
+       "       [<owner>] [<ttl>] [<cname>] \"<status string>\"\n"
        "where <nrrs> is the number of RRs that follow and <cname> will be `$' or\n"
        "the CNAME target; the CNAME indirection and error formats above are not used.\n"
        "\n"
index 5c023a686a740b22a55593f1b6e816196604f1c4..f2dd5c1b4b971ec9adc04e94e87ce8040d5ccd58 100644 (file)
 #include "adnshost.h"
 
 adns_state ads;
+struct outstanding_list outstanding;
 
-struct query_node {
-  struct query_node *next, *back;
-  struct perqueryflags_remember pqfr;
-  char *id;
-  adns_query qu;
+static unsigned long idcounter;
+
+#define STATUSTYPEMAX(v) { adns_s_max_##v, #v }
+static const struct statustypemax {
+  adns_status smax;
+  const char *abbrev;
+} statustypemaxes[]= {
+  { adns_s_ok, "ok" },
+  STATUSTYPEMAX(localfail),
+  STATUSTYPEMAX(remotefail),
+  STATUSTYPEMAX(tempfail),
+  STATUSTYPEMAX(misconfig),
+  STATUSTYPEMAX(misquery),
+  STATUSTYPEMAX(permfail),
 };
 
-static struct { struct query_node *head, *tail; } outstanding;
+void ensure_adns_init(void) {
+  int r;
+  
+  if (ads) return;
 
-static unsigned long idcounter;
+  if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) sysfail("ignore SIGPIPE",errno);
+  r= adns_init(&ads,
+              adns_if_noautosys|adns_if_nosigpipe |
+              (ov_env ? 0 : adns_if_noenv) |
+              ov_verbose,
+              0);
+  if (r) sysfail("adns_init",r);
+}
 
-void domain_do(const char *domain) {
+void query_do(const char *domain) {
   struct query_node *qun;
   char idbuf[20];
   int r;
 
-  if (!ads) {
-    if (signal(SIGPIPE,SIG_IGN) == SIG_ERR) sysfail("ignore SIGPIPE",errno);
-    r= adns_init(&ads,
-                adns_if_noautosys|adns_if_nosigpipe |
-                (ov_env ? 0 : adns_if_noenv) |
-                ov_verbose,
-                0);
-    if (r) sysfail("adns_init",r);
-  }
-
   qun= malloc(sizeof(*qun));
   qun->pqfr= ov_pqfr;
   if (ov_id) {
@@ -82,5 +92,115 @@ void domain_do(const char *domain) {
   LIST_LINK_TAIL(outstanding,qun);
 }
 
-void of_asynch_id(const struct optioninfo *oi, const char *arg) { abort(); }
+static void print_withspace(const char *str) {
+  if (printf("%s ", str) == EOF) outerr();
+}
+
+static void print_ttl(struct query_node *qun, adns_answer *answer) {
+  unsigned long ttl;
+  time_t now;
+  
+  switch (qun->pqfr.ttl) {
+  case tm_none:
+    return;
+  case tm_rel:
+    if (time(&now) == (time_t)-1) sysfail("get current time",errno);
+    ttl= answer->expires < now ? 0 : answer->expires - now;
+    break;
+  case tm_abs:
+    ttl= answer->expires;
+    break;
+  default:
+    abort();
+  }
+  if (printf("%lu ",ttl) == EOF) outerr();
+}
+
+static void print_owner_ttl(struct query_node *qun, adns_answer *answer) {
+  if (qun->pqfr.show_owner) print_withspace(answer->owner);
+  print_ttl(qun,answer);
+}
+
+static void print_status(adns_status st, struct query_node *qun, adns_answer *answer) {
+  int stnmin, stnmax, stn;
+  const char *statusabbrev, *statusstring;
+
+  stnmin= 0;
+  stnmax= sizeof(statustypemaxes)/sizeof(statustypemaxes[0]);
+  while (stnmin < stnmax) {
+    stn= (stnmin+stnmax)>>1;
+    if (st > statustypemaxes[stn].smax) stnmin= stn+1; else stnmax= stn;
+  }
+  stn= stnmin;
+  assert(statustypemaxes[stn].smax >= st);
+  
+  if (rcode < stn) rcode= stn;
+
+  statusabbrev= adns_errabbrev(st);
+  statusstring= adns_strerror(st);
+  assert(!strchr(statusstring,'"'));
+
+  if (printf("%s %d %s ", statustypemaxes[stn].abbrev, st, statusabbrev)
+      == EOF) outerr();
+  print_owner_ttl(qun,answer);
+  if (qun->pqfr.show_cname)
+    print_withspace(answer->cname ? answer->cname : "$");
+  if (printf("\"%s\"\n", statusstring) == EOF) outerr();
+}
+
+void query_done(struct query_node *qun, adns_answer *answer) {
+  adns_status st, ist;
+  int rrn, nrrs;
+  const char *rrp, *realowner, *typename;
+  char *datastr;
+
+  if (ov_pipe) setnonblock(1,0);
+
+  st= answer->status;
+  nrrs= answer->nrrs;
+  if (ov_asynch) {
+    if (printf("%s %d", qun->id, nrrs) == EOF) outerr();
+    print_status(st,qun,answer);
+  } else {
+    if (st) {
+      if (fputs("; failed",stdout) == EOF) outerr();
+      print_status(st,qun,answer);
+    } else if (answer->cname) {
+      print_owner_ttl(qun,answer);
+      if (printf("CNAME %s\n",answer->cname) == EOF) outerr();
+    }
+  }
+  if (qun->pqfr.show_owner) {
+    realowner= answer->cname ? answer->cname : answer->owner;;
+    assert(realowner);
+  } else {
+    realowner= 0;
+  }
+  if (nrrs) {
+    for (rrn=0, rrp = answer->rrs.untyped;
+        rrn < nrrs;
+        rrn++, rrp += answer->rrsz) {
+      if (realowner) print_withspace(realowner);
+      print_ttl(qun,answer);
+      ist= adns_rr_info(answer->type, &typename, 0, 0, rrp, &datastr);
+      if (ist == adns_s_nomemory) sysfail("adns_rr_info failed",ENOMEM);
+      assert(!ist);
+      if (qun->pqfr.show_type) print_withspace(typename);
+      if (printf("%s\n",datastr) == EOF) outerr();
+      free(datastr);
+    }
+  }
+  if (fflush(stdout)) outerr();
+  LIST_UNLINK(outstanding,qun);
+  free(answer);
+  free(qun->id);
+  free(qun);
+}
+
+void of_asynch_id(const struct optioninfo *oi, const char *arg) {
+  free(ov_id);
+  ov_id= xstrsave(arg);
+}
+
 void of_cancel_id(const struct optioninfo *oi, const char *arg) { abort(); }
+
index 3e93ca7b90ca6b7155d4f6e485c3b1748b83fc24..d512b4f184a397b6919bd204b9403b26076c592d 100644 (file)
@@ -33,6 +33,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <assert.h>
 
 #include "config.h"
@@ -79,9 +80,19 @@ void opt_do(const struct optioninfo *oip, const char *arg);
 
 /* declarations related to query processing */
 
+struct query_node {
+  struct query_node *next, *back;
+  struct perqueryflags_remember pqfr;
+  char *id;
+  adns_query qu;
+};
+
 extern adns_state ads;
+extern struct outstanding_list { struct query_node *head, *tail; } outstanding;
 
-void domain_do(const char *domain);
+void ensure_adns_init(void);
+void query_do(const char *domain);
+void query_done(struct query_node *qun, adns_answer *answer);
 
 void of_asynch_id(const struct optioninfo *oi, const char *arg);
 void of_cancel_id(const struct optioninfo *oi, const char *arg);
@@ -90,8 +101,12 @@ void of_cancel_id(const struct optioninfo *oi, const char *arg);
 
 void sysfail(const char *what, int errnoval) NONRETURNING;
 void usageerr(const char *what, ...) NONRETURNPRINTFFORMAT(1,2);
+void outerr(void) NONRETURNING;
+void setnonblock(int fd, int nonblock);
 
 void *xmalloc(size_t sz);
 char *xstrsave(const char *str);
 
+extern int rcode;
+
 #endif