From: ian Date: Sat, 3 Oct 1998 22:56:58 +0000 (+0000) Subject: More rearrangements and code. X-Git-Tag: abandon.1998-10-04.rrtypenoenum~6 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=37e28fde2d1d358ca0b887fc131f0ca108318b2a;hp=aa98c861c1bc8aa0c91a38afbc1fa8f30b85bdf0 More rearrangements and code. --- diff --git a/src/adns-internal.h b/src/adns-internal.h new file mode 100644 index 0000000..2cdafbf --- /dev/null +++ b/src/adns-internal.h @@ -0,0 +1,130 @@ +/**/ + +#ifndef ADNS_INTERNAL_H_INCLUDED +#define ADNS_INTERNAL_H_INCLUDED + +#include + +#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 diff --git a/src/adns.h b/src/adns.h index d11742f..23c71ef 100644 --- a/src/adns.h +++ b/src/adns.h @@ -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, diff --git a/src/event.c b/src/event.c index 33998a8..68abb3c 100644 --- a/src/event.c +++ b/src/event.c @@ -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) { fdtcpstate == 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.usedtcprecv.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 index 0000000..2cdafbf --- /dev/null +++ b/src/internal.h @@ -0,0 +1,130 @@ +/**/ + +#ifndef ADNS_INTERNAL_H_INCLUDED +#define ADNS_INTERNAL_H_INCLUDED + +#include + +#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 diff --git a/src/query.c b/src/query.c index 667ec6d..c9ad8fd 100644 --- a/src/query.c +++ b/src/query.c @@ -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; } diff --git a/src/setup.c b/src/setup.c index ecf92a2..8939ac6 100644 --- a/src/setup.c +++ b/src/setup.c @@ -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;