From 84fe28dbf1b4d178b54d84becc0ee91c1b2db5d4 Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 3 Oct 1998 13:42:02 +0000 Subject: [PATCH] Cleanups, development. --- src/adns-internal.h | 35 +++++--- src/adns.c | 208 ++++++++++++++++++++++++++++++++++++++------ src/adns.h | 14 +-- 3 files changed, 215 insertions(+), 42 deletions(-) diff --git a/src/adns-internal.h b/src/adns-internal.h index f47fc96..7caba2f 100644 --- a/src/adns-internal.h +++ b/src/adns-internal.h @@ -8,16 +8,30 @@ #include "adns.h" #define MAXSERVERS 5 -#define MAXUDPRETRIES 10 +#define MAXUDPRETRIES 15 #define UDPRETRYMS 2000 -#define TCPMS 20000 +#define TCPMS 30000 +#define LOCALRESOURCEMS 20 + +union adns__align { + adns_status status; + char *cp; + adns_rrtype type; + int int; + struct in_addr ia; + unsigned long ul; +}; struct adns__query { - adns_query next, back; - adns_query parent, child; + 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; - int id, flags, udpretries, nextserver; + 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; @@ -39,13 +53,14 @@ struct adns__state { int nextid, udpsocket; int qbufavail, tcpbufavail, tcpbufused, tcpbufdone; unsigned char *qbuf, *tcpbuf; - int nservers; + int nservers, tcpserver; + enum { server_disc, server_connecting, server_ok } tcpstate; + int tcpsocket; + struct timeval tcptimeout; + int opbufavail, opbufused; + unsigned char *opbuf; struct server { struct in_addr addr; - enum { server_disc, server_connecting, server_ok } state; - int tcpsocket; - struct timeval timeout; - struct { adns_query head, tail; } connw; } servers[MAXSERVERS]; }; diff --git a/src/adns.c b/src/adns.c index bde99e2..31a64dc 100644 --- a/src/adns.c +++ b/src/adns.c @@ -16,22 +16,25 @@ #include "adns-internal.h" -#define LIST_UNLINK(list,node) \ +#define LIST_UNLINK_PART(list,node,part) \ do { \ - if ((node)->back) (node)->back->next= (node)->next; \ - else (list).head= (node)->next; \ - if ((node)->next) (node)->next->back= (node)->back; \ - else (list).tail= (node)->back; \ + 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(list,node) \ +#define LIST_LINK_TAIL_PART(list,node,part) \ do { \ - (node)->back= 0; \ - (node)->next= (list).tail; \ - if ((list).tail) (list).tail->back= (node); else (list).head= (node); \ + (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,) + static void vdebug(adns_state ads, const char *fmt, va_list al) { if (!(ads->iflags & adns_if_debug)) return; fputs("adns debug: ",stderr); @@ -289,13 +292,7 @@ int adns_finish(adns_state ads) { abort(); /* FIXME */ } -void adns_interest(adns_state ads, int *maxfd, - fd_set *readfds, fd_set *writefds, fd_set *exceptfds, - struct timeval **tv_io, struct timeval *tvbuf) { - abort(); /* FIXME */ -} - -static void autosys(adns_state ads) { +static void autosys(adns_state ads, struct timeval now) { if (ads->iflags & adns_if_noautosys) return; adns_callback(ads,-1,0,0,0); } @@ -310,6 +307,100 @@ int adns_callback(adns_state ads, int maxfd, abort(); /* FIXME */ } +static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf, + struct timeval maxto) { + struct timeval rbuf; + + rbuf= *tv_io; + if (!rbuf) { *tvbuf= maxto; *tv_io= tvbuf; return; } + if (timercmp(rbuf,&maxto,>)) *rbuf= maxto; +} + +static void inter_maxtoabs(struct timeval **tv_io, struct timeval *tvbuf, + struct timeval now, struct timeval maxtime) { + ldiv_t dr; + + maxtime.tv_sec -= (now.tv_sec-1); + maxtime.tv_usec += (1000-now.tv_usec); + dr= ldiv(maxtime.tv_usec,1000); + maxtime.tv_sec += dr.quot; + maxtime.tv_usec -= dr.rem; + inter_maxto(tv_io,tvbuf,maxtime); +} + +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)); + timerclear(&tvto_lr); timevaladd(&tvto_lr,LOCALRESOURCEMS); + inter_maxto(tv_io, tvbuf, tvto_lr); + return; +} + +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; +} + +void adns_interest(adns_state ads, int *maxfd, + fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + struct timeval **tv_io, struct timeval *tvbuf) { + struct timeval now; + adns_query qu; + int r; + + r= gettimeofday(&now,0); + if (r) { localresourcerr(tv_io,tvbuf,"gettimeofday"); return; } + + for (qu= ads->timew; qu; qu= nqu) { + nqu= qu->next; + if (timercmp(&now,qu->timeout,>)) { + DLIST_UNLINK(ads->timew,qu); + if (qu->nextudpserver == -1) { + query_fail(ads,qu,adns_s_notresponding); + } else { + DLIST_LINKTAIL(ads->tosend,qu); + } + } else { + inter_maxtoabs(tv_io,tvbuf,now,qu->timeout); + } + } + + for (qu= ads->tosend; qu; qu= nqu) { + nqu= qu->next; + quproc_tosend(ads,qu,now); + } + + for (qu= ads->timew; qu; qu= qu->next) { + if (qu->sentudp) { + inter_addfd(maxfd,readfds,ads->udpsocket); + break; + } + } + switch (ads->tcpstate) { + case server_disc: + break; + case server_connecting: + inter_addfd(maxfd,readfds,ads->tcpsocket); + inter_addfd(maxfd,writefds,ads->tcpsocket); + inter_addfd(maxfd,exceptfds,ads->tcpsocket); + break; + case server_connected: + inter_addfd(maxfd,readfds,ads->tcpsocket); + inter_addfd(maxfd,exceptfds,ads->tcpsocket); + if (ads->opbufused) inter_addfd(maxfd,writefds,ads->tcpsocket); + default: + abort(); + } + +} + static int internal_check(adns_state ads, adns_query *query_io, adns_answer **answer, @@ -452,7 +543,9 @@ static adns_query allocquery(adns_state ads, const char *owner, int ol, unsigned char *qm; qu= malloc(sizeof(*qu)+ol+1+qml); if (!qu) return 0; - qu->next= qu->back= qu->parent= qu->child= 0; + qu->next= qu->back= qu->parent= 0; + qu->children.head= qu->children.tail= 0; + qu->siblings.next= qu->siblings.back= 0; qu->id= id; qu->type= type; qu->answer= 0; @@ -479,14 +572,73 @@ static int failsubmit(adns_state ads, void *context, adns_query *query_r, return 0; } -static void trysendudp(adns_state ads, adns_query qu) { +static void quproc_tosend(adns_state ads, adns_query qu, struct timeval now) { + /* Query must be on the `tosend' queue, and guarantees to remove it. */ struct sockaddr_in servaddr; - /* FIXME: _f_usevc not implemented */ - memset(&servaddr,0,sizeof(servaddr)); - servaddr.sin_family= AF_INET; - servaddr.sin_addr= ads->servers[qu->nextserver].addr; - servaddr.sin_port= htons(53); - sendto(ads->udpsocket,qu->querymsg,qu->querylen,0,&servaddr,sizeof(servaddr)); + int serv; + + if (qu->nextudpserver != -1) { + if (qu->udpretries >= UDPMAXRETRIES) { + DLIST_UNLINK(ads->tosend,qu); + query_fail(ads,qu,adns_s_notresponding); + return; + } + serv= qu->nextudpserver; + memset(&servaddr,0,sizeof(servaddr)); + servaddr.sin_family= AF_INET; + servaddr.sin_addr= ads->servers[serv].addr; + servaddr.sin_port= htons(53); + 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)); + } + DLIST_UNLINK(ads->tosend,qu); + timevaladd(&now,UDPRETRYMS); + qu->timeout= now; + qu->sentudp |= (1<nextudpserver= (serv+1)%ads->nservers; + qu->udpretries++; + DLIST_LINKTAIL(ads->timew,qu); + return; + } + } + + for (;;) { + serv= tcpserver_get(ads); + if (serv<0) { r=0; break; } + if (ads->opbufused) { r=0; break; } + r= write(ads->tcpsocket,qu->querymsg,qu->querylen); + if (r >= 0) break; + if (errno == EAGAIN || errno == EINTR || errno == ENOSPC || + errno == ENOBUFS || errno == ENOMEM) { + r= 0; break; + } + tcpserver_broken(serv); + } + if (r < qu->querylen) { + newopbufused= qu->opbufused + (qu->querylen-r); + if (newopbufused > ads->opbufavail) { + newopbufavail= ads->newopbufused<<1; + newopbuf= realloc(newopbufavail); + if (!newopbuf) { + DLIST_UNLINK(ads->tosend,qu); + query_fail(ads,qu,adns_s_nolocalmem); + return; + } + ads->opbuf= newopbuf; + ads->opbufavail= newopbufavail; + } + memcpy(ads->opbuf+ads->opbufused,qu->querymsg+r,qu->querylen-r); + ads->opbufused= newopbufused; + } + DLIST_UNLINK(ads->tosend,qu); + timevaladd(&now,TCPMS); + qu->timeout= now; + qu->senttcp |= (1<nextserver); + DLIST_LINKTAIL(ads->timew,qu); } int adns_submit(adns_state ads, @@ -510,10 +662,12 @@ int adns_submit(adns_state ads, if (stat) return failsubmit(ads,context,query_r,type,flags,id,stat); qu= allocquery(ads,owner,ol,qml,id,type,flags,context); if (!qu) return errno; - + if (qu->flags & adns_f_usevc) qu->udpretries= -1; LIST_LINK_TAIL(ads->tosend,qu); - trysendudp(ads,qu); - autosys(ads); + + r= gettimeofday(&now,0); if (r) return; + quproc_tosend(ads,qu,now); + autosys(ads,now); *query_r= qu; return 0; diff --git a/src/adns.h b/src/adns.h index 87e94e6..d11742f 100644 --- a/src/adns.h +++ b/src/adns.h @@ -78,6 +78,13 @@ typedef enum { * the error. */ +typedef struct { + char *dm; + adns_status astatus; + int naddrs; /* temp fail => -1, perm fail => 0, s_ok => >0 */ + struct in_addr *addrs; +} adns_dmaddr; + typedef struct { adns_status status; char *cname; /* always NULL if query was for CNAME records */ @@ -86,12 +93,9 @@ typedef struct { union { struct in_addr inaddr[1]; /* a */ char (*str)[1]; /* ns_raw, cname, ptr, ptr_raw, txt */ - struct { char *dm; adns_status ref; struct in_addr addr; } dmaddr; /* ns */ + adns_dmaddr dmaddr[1]; /* ns */ struct { char *a, *b; } strpair[1]; /* hinfo, rp, rp_raw */ - struct { - int pref; char *dm; - adns_status ref; struct in_addr addr; - } intdmaddr[1]; /* mx */ + struct { int pref; adns_dmaddrs dmaddr; } intdmaddr[1]; /* mx */ struct { int pref; char *str; } intstr[1]; /* mx_raw */ struct { char *ns0, *rp; -- 2.30.2