From: ian Date: Sun, 7 Nov 1999 16:06:48 +0000 (+0000) Subject: New improved adnsfilter, but not yet debugged. X-Git-Tag: rel-adns-0-6~10 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=2953d358511ac5d196362f6b339c010d4e9cae3e New improved adnsfilter, but not yet debugged. --- diff --git a/client/adnsresfilter.c b/client/adnsresfilter.c index d7150e8..d091def 100644 --- a/client/adnsresfilter.c +++ b/client/adnsresfilter.c @@ -33,13 +33,73 @@ #include #include +#include + #include "adns.h" #include "config.h" +#include "dlist.h" +#include "tvarith.h" + +struct outqueuenode { + struct outqueuenode *next, *back; + void *buffer; + char *textp; + int textlen; + struct timeval printbefore; + struct treething *addr; +}; + +static int bracket, forever, timeout=10; +static adns_rrtype rrt= adns_r_ptr; + +static int outblocked, inputeof; +static struct { struct outqueuenode *head, *tail; } outqueue; +static int peroutqueuenode, outqueuelen; + +static struct sockaddr_in sa; +static adns_state ads; + +static char addrtextbuf[14]; +static int cbyte, inbyte, inbuf; +static unsigned char bytes[4]; +static struct timeval printbefore; + +struct treething { + unsigned char bytes[4]; + adns_query qu; + adns_answer *ans; +}; + +static struct treething *newthing; +static void *treeroot; + +static int nonblock(int fd, int isnonblock) { + int r; + + r= fcntl(fd,F_GETFL); + if (r==-1) return -1; + r= fcntl(fd,F_SETFL, isnonblock ? r|O_NONBLOCK : r&~O_NONBLOCK); + if (r==-1) return -1; + return 0; +} + +static void quit(int exitstatus) NONRETURNING; +static void quit(int exitstatus) { + nonblock(0,0); + nonblock(1,0); + exit(exitstatus); +} static void sysfail(const char *what) NONRETURNING; static void sysfail(const char *what) { fprintf(stderr,"adnsresfilter: system call failed: %s: %s\n",what,strerror(errno)); - exit(2); + quit(2); +} + +static void *xmalloc(size_t sz) { + void *r; + r= malloc(sz); if (r) return r; + sysfail("malloc"); } static void outputerr(void) NONRETURNING; @@ -50,6 +110,7 @@ static void usage(void) { " adnsresfilter -h|--help\n" "options: -b|--brackets\n" " -w|--wait\n" + " -t|--timeout \n" " -u|--unchecked\n") == EOF) outputerr(); } @@ -58,101 +119,22 @@ static void usageerr(const char *why) NONRETURNING; static void usageerr(const char *why) { fprintf(stderr,"adnsresfilter: bad usage: %s\n",why); usage(); - exit(1); + quit(1); } static void adnsfail(const char *what, int e) NONRETURNING; static void adnsfail(const char *what, int e) { fprintf(stderr,"adnsresfilter: adns call failed: %s: %s\n",what,strerror(e)); - exit(2); + quit(2); } -static int bracket, forever; -static adns_rrtype rrt= adns_r_ptr; - -static struct sockaddr_in sa; -static adns_state ads; - -static char buf[14]; -static int c, cbyte, inbyte, inbuf; -static unsigned char bytes[4]; - -struct treething { - unsigned char bytes[4]; - adns_query qu; - adns_answer *ans; -}; - -static struct treething *newthing; -static void *treeroot; - static int comparer(const void *a, const void *b) { return memcmp(a,b,4); } -static void restartbuf(void) { - if (inbuf>0) { - buf[inbuf++]= 0; - if (fputs(buf,stdout) < 0) outputerr(); - } - inbuf= 0; -} - -static void procaddr(void) { - struct treething *foundthing; - void *expectreturn, **searchfound; - int r; - - if (!newthing) { - newthing= malloc(sizeof(struct treething)); - if (!newthing) sysfail("malloc"); - newthing->qu= 0; - newthing->ans= 0; - } - - memcpy(newthing->bytes,bytes,4); - searchfound= tsearch(newthing,&treeroot,comparer); - if (!searchfound) sysfail("tsearch"); - foundthing= *searchfound; - - if (foundthing == newthing) { - newthing= 0; - memcpy(&sa.sin_addr,bytes,4); - r= adns_submit_reverse(ads, (const struct sockaddr*)&sa, - rrt,0,foundthing,&foundthing->qu); - if (r) adnsfail("submit",r); - } - if (!forever && foundthing->ans && foundthing->ans->status == adns_s_timeout) { - free(foundthing->ans); - foundthing->ans= 0; - } - if (!foundthing->ans) { - expectreturn= foundthing; - r= (forever ? adns_wait : adns_check) - (ads,&foundthing->qu,&foundthing->ans,&expectreturn); - assert(r==EAGAIN || (!r && foundthing->ans && expectreturn==foundthing)); - } - if (foundthing->ans && foundthing->ans->nrrs > 0) { - if (fputs(foundthing->ans->rrs.str[0],stdout) < 0) outputerr(); - inbuf= 0; - } else { - restartbuf(); - } - cbyte= -1; -} - -static void startaddr(void) { - bytes[cbyte=0]= 0; - inbyte= 0; -} - -static void mustputchar(int c) { - if (putchar(c) == EOF) outputerr(); -} - -int main(int argc, const char *const *argv) { +static void parseargs(const char *const *argv) { const char *arg; - int nbyte, r; + int c; while ((arg= *++argv)) { if (arg[0] != '-') usageerr("no non-option arguments are allowed"); @@ -164,7 +146,7 @@ int main(int argc, const char *const *argv) { } else if (!strcmp(arg,"--wait")) { forever= 1; } else if (!strcmp(arg,"--help")) { - usage(); exit(0); + usage(); quit(0); } else { usageerr("unknown long option"); } @@ -181,56 +163,250 @@ int main(int argc, const char *const *argv) { forever= 1; break; case 'h': - usage(); exit(0); + usage(); quit(0); default: usageerr("unknown short option"); } } } } - if (setvbuf(stdout,0,_IOLBF,0)) sysfail("setvbuf stdout"); +} - memset(&sa,0,sizeof(sa)); - sa.sin_family= AF_INET; +static void queueoutchar(int c) { + struct outqueuenode *entry; + + entry= outqueue.tail; + if (!entry->back || entry->addr || entry->textlen >= peroutqueuenode) { + entry= xmalloc(sizeof(*entry)); + peroutqueuenode= !entry->back || entry->addr ? 32 : + peroutqueuenode >= 1024 ? 2048 : peroutqueuenode<<1; + entry->buffer= xmalloc(peroutqueuenode); + entry->textp= entry->buffer; + entry->textlen= 0; + entry->addr= 0; + LIST_LINK_TAIL(outqueue,entry); + outqueuelen++; + } + *entry->textp++= c; + entry->textlen++; +} - r= adns_init(&ads,0,0); if (r) adnsfail("init",r); +static void queueoutstr(const char *str, int len) { + while (len > 0) queueoutchar(*str++); +} - cbyte= -1; - inbyte= -1; +static void writestdout(struct outqueuenode *entry) { + int r; + + while (entry->textlen) { + r= write(1, entry->textp, entry->textlen); + if (r < 0) { + if (errno == EINTR) continue; + if (errno == EAGAIN) { outblocked= 1; break; } + sysfail("write stdout"); + } + assert(r < entry->textlen); + entry->textp += r; + entry->textlen -= r; + } + if (!entry->textlen) { + LIST_UNLINK(outqueue,entry); + free(entry->buffer); + free(entry); + outqueuelen--; + } +} + +static void replacetextwithname(struct outqueuenode *entry) { + free(entry->buffer); + entry->buffer= 0; + entry->textp= entry->addr->ans->rrs.str[0]; + entry->textlen= strlen(entry->textp); +} + +static void checkadnsqueries(void) { + adns_query qu; + adns_answer *ans; + void *context; + struct treething *foundthing; + int r; + + for (;;) { + qu= 0; context= 0; ans= 0; + r= adns_check(ads,&qu,&ans,&context); + if (r == ESRCH || r == EAGAIN) break; + assert(!r); + foundthing= context; + foundthing->ans= ans; + foundthing->qu= 0; + } +} + +static void restartbuf(void) { + if (inbuf>0) queueoutstr(addrtextbuf,inbuf); inbuf= 0; - if (!bracket) startaddr(); - while ((c= getchar()) != EOF) { +} + +static void procaddr(void) { + struct treething *foundthing; + void **searchfound; + struct outqueuenode *entry; + int r; + + if (!newthing) { + newthing= xmalloc(sizeof(struct treething)); + newthing->qu= 0; + newthing->ans= 0; + } + + memcpy(newthing->bytes,bytes,4); + searchfound= tsearch(newthing,&treeroot,comparer); + if (!searchfound) sysfail("tsearch"); + foundthing= *searchfound; + + if (foundthing == newthing) { + memcpy(&sa.sin_addr,bytes,4); + r= adns_submit_reverse(ads, (const struct sockaddr*)&sa, + rrt,0,foundthing,&foundthing->qu); + if (r) adnsfail("submit",r); + } + entry= xmalloc(sizeof(*entry)); + entry->buffer= xmalloc(inbuf); + entry->textp= entry->buffer; + memcpy(entry->textp,addrtextbuf,inbuf); + entry->textlen= inbuf; + entry->addr= foundthing; + LIST_LINK_TAIL(outqueue,entry); + outqueuelen++; + inbuf= 0; + cbyte= -1; +} + +static void startaddr(void) { + bytes[cbyte=0]= 0; + inbyte= 0; +} + +static void readstdin(void) { + char readbuf[512], *p; + int r, c, nbyte; + + while ((r= read(0,readbuf,sizeof(readbuf))) <= 0) { + if (r == 0) { inputeof= 1; return; } + if (r == EAGAIN) return; + if (r != EINTR) sysfail("read stdin"); + } + for (p=readbuf; r>0; r--,p++) { + c= *p++; if (cbyte==-1 && bracket && c=='[') { - buf[inbuf++]= c; + addrtextbuf[inbuf++]= c; startaddr(); } else if (cbyte==-1 && !bracket && !isalnum(c)) { - mustputchar(c); + queueoutchar(c); startaddr(); } else if (cbyte>=0 && inbyte<3 && c>='0' && c<='9' && (nbyte= bytes[cbyte]*10 + (c-'0')) <= 255) { bytes[cbyte]= nbyte; - buf[inbuf++]= c; + addrtextbuf[inbuf++]= c; inbyte++; } else if (cbyte>=0 && cbyte<3 && inbyte>0 && c=='.') { bytes[++cbyte]= 0; - buf[inbuf++]= c; + addrtextbuf[inbuf++]= c; inbyte= 0; } else if (cbyte==3 && inbyte>0 && bracket && c==']') { - buf[inbuf++]= c; + addrtextbuf[inbuf++]= c; procaddr(); } else if (cbyte==3 && inbyte>0 && !bracket && !isalnum(c)) { procaddr(); - mustputchar(c); + queueoutchar(c); startaddr(); } else { restartbuf(); - mustputchar(c); + queueoutchar(c); cbyte= -1; if (!bracket && !isalnum(c)) startaddr(); } } - if (ferror(stdin) || fclose(stdin)) sysfail("read stdin"); if (cbyte==3 && inbyte>0 && !bracket) procaddr(); +} + +static void startup(void) { + int r; + + if (setvbuf(stdout,0,_IOLBF,0)) sysfail("setvbuf stdout"); + if (nonblock(0,1)) sysfail("set stdin to nonblocking mode"); + if (nonblock(1,1)) sysfail("set stdout to nonblocking mode"); + memset(&sa,0,sizeof(sa)); + sa.sin_family= AF_INET; + r= adns_init(&ads,0,0); if (r) adnsfail("init",r); + cbyte= -1; + inbyte= -1; + inbuf= 0; + if (!bracket) startaddr(); +} + +int main(int argc, const char *const *argv) { + int r, maxfd; + fd_set readfds, writefds, exceptfds; + struct outqueuenode *entry; + struct timeval *tv, tvbuf, now; + + parseargs(argv); + startup(); + + while (!inputeof || outqueue.head) { + maxfd= 2; + tv= 0; + FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); + if ((entry= outqueue.head) && !outblocked) { + if (!entry->addr) { + writestdout(entry); + continue; + } else if (entry->addr->ans) { + if (entry->addr->ans->nrrs) + replacetextwithname(entry); + entry->addr= 0; + continue; + } + r= gettimeofday(&now,0); if (r) sysfail("gettimeofday"); + if (forever) { + tv= 0; + } else if (!timercmp(&now,&entry->printbefore,<)) { + entry->addr= 0; + continue; + } else { + tvbuf.tv_sec= printbefore.tv_sec - now.tv_sec - 1; + tvbuf.tv_usec= printbefore.tv_usec - now.tv_usec + 1000000; + tvbuf.tv_sec += tvbuf.tv_usec / 1000000; + tvbuf.tv_usec %= 1000000; + tv= &tvbuf; + } + adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds, + &tv,&tvbuf,&now); + } + if (outblocked) FD_SET(1,&writefds); + if (!inputeof && outqueuelen<1000) FD_SET(0,&readfds); + + r= select(maxfd,&readfds,&writefds,&exceptfds,tv); + if (r < 0) { if (r == EINTR) continue; else sysfail("select"); } + + r= gettimeofday(&now,0); if (r) sysfail("gettimeofday"); + adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,&now); + checkadnsqueries(); + + if (FD_ISSET(0,&readfds)) { + if (!forever) { + printbefore= now; + timevaladd(&printbefore,timeout); + } + readstdin(); + } else if (FD_ISSET(1,&writefds)) { + outblocked= 0; + } + } + if (ferror(stdin) || fclose(stdin)) sysfail("read stdin"); if (fclose(stdout)) sysfail("close stdout"); + if (nonblock(0,0)) sysfail("un-nonblock stdin"); + if (nonblock(1,0)) sysfail("un-nonblock stdout"); exit(0); } diff --git a/src/event.c b/src/event.c index 48970c8..a1641c6 100644 --- a/src/event.c +++ b/src/event.c @@ -39,6 +39,7 @@ #include #include "internal.h" +#include "tvarith.h" /* TCP connection management. */ diff --git a/src/internal.h b/src/internal.h index 02951a6..9e442fe 100644 --- a/src/internal.h +++ b/src/internal.h @@ -677,16 +677,6 @@ void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc); /* 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)*1000000; - tmp.tv_sec += ms/1000; - if (tmp.tv_usec >= 1000000) { 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'; } static inline int ctype_alpha(int c) { diff --git a/src/transmit.c b/src/transmit.c index c5ae9dc..c669af6 100644 --- a/src/transmit.c +++ b/src/transmit.c @@ -32,6 +32,7 @@ #include #include "internal.h" +#include "tvarith.h" #define MKQUERY_START(vb) (rqp= (vb)->buf+(vb)->used) #define MKQUERY_ADDB(b) *rqp++= (b) diff --git a/tvarith.h b/tvarith.h new file mode 100644 index 0000000..4a9ba53 --- /dev/null +++ b/tvarith.h @@ -0,0 +1,41 @@ +/* + * tvarith.h + * - static inline functions for doing arithmetic on timevals + */ +/* + * This file is + * Copyright (C) 1997-1999 Ian Jackson + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson + * Copyright (C) 1999 Tony Finch + * + * 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. + */ + +#ifndef ADNS_TVARITH_H_INCLUDED +#define ADNS_TVARITH_H_INCLUDED + +static inline void timevaladd(struct timeval *tv_io, long ms) { + struct timeval tmp; + assert(ms>=0); + tmp= *tv_io; + tmp.tv_usec += (ms%1000)*1000000; + tmp.tv_sec += ms/1000; + if (tmp.tv_usec >= 1000000) { tmp.tv_sec++; tmp.tv_usec -= 1000; } + *tv_io= tmp; +} + +#endif