From 57d68ed152f47a68cd91fa25a67b11161f11d82a Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 12 Oct 1999 23:00:04 +0000 Subject: [PATCH] adnshost improvements - now runs for at least one query. --- changelog | 3 +- client/adh-main.c | 52 ++++++++++++++- client/adh-opts.c | 8 ++- client/adh-query.c | 158 +++++++++++++++++++++++++++++++++++++++------ client/adnshost.h | 17 ++++- 5 files changed, 212 insertions(+), 26 deletions(-) diff --git a/changelog b/changelog index cc9e058..6b63409 100644 --- 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. diff --git a/client/adh-main.c b/client/adh-main.c index 855a258..33b1f59 100644 --- a/client/adh-main.c +++ b/client/adh-main.c @@ -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); } diff --git a/client/adh-opts.c b/client/adh-opts.c index 03ba5bb..6af9e02 100644 --- a/client/adh-opts.c +++ b/client/adh-opts.c @@ -216,11 +216,13 @@ static void printusage(void) { "or if the domain refers to a CNAME and --show-cname is on\n" " [] [] CNAME \n" " [] [] \n" - "When a query fails you get a line like:\n" - " ; failed [] [] [] \"\"\n" + "When a query fails you get a line like this (broken here for readability):\n" + " ; failed \\\n" + " [] [] [] \"\"\n" "\n" "If you use --asynch each answer (success or failure) is preceded by a line\n" - " [] \"\"\n" + " \\\n" + " [] [] [] \"\"\n" "where is the number of RRs that follow and will be `$' or\n" "the CNAME target; the CNAME indirection and error formats above are not used.\n" "\n" diff --git a/client/adh-query.c b/client/adh-query.c index 5c023a6..f2dd5c1 100644 --- a/client/adh-query.c +++ b/client/adh-query.c @@ -29,33 +29,43 @@ #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(); } + diff --git a/client/adnshost.h b/client/adnshost.h index 3e93ca7..d512b4f 100644 --- a/client/adnshost.h +++ b/client/adnshost.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #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 -- 2.30.2