From: ian Date: Sun, 4 Oct 1998 11:03:33 +0000 (+0000) Subject: Various improvements and more code; post-crash. X-Git-Tag: abandon.1998-10-04.rrtypenoenum~4 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=4bec51a44bf61bca32e7b947f20b1e7d0f971b94 Various improvements and more code; post-crash. --- diff --git a/src/adns.h b/src/adns.h index ae0a742..32e442a 100644 --- a/src/adns.h +++ b/src/adns.h @@ -65,6 +65,7 @@ typedef enum { adns_s_unknownqtype, adns_s_nolocalmem, adns_s_connlost, + adns_s_allservfail, 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 */ diff --git a/src/internal.h b/src/internal.h index eb8cd5d..b8f881d 100644 --- a/src/internal.h +++ b/src/internal.h @@ -90,6 +90,8 @@ 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); +adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, + adns_rrtype type, adns_queryflags flags, int *qml_r); /* From event.c: */ void adns__tcp_broken(adns_state ads, const char *what, const char *why); diff --git a/src/query.c b/src/query.c index 81acb61..f12e1a3 100644 --- a/src/query.c +++ b/src/query.c @@ -1,9 +1,9 @@ /**/ -#include "adns-internal.h" +#include "internal.h" -static adns_status mkquery(adns_state ads, const char *owner, int ol, int id, - adns_rrtype type, adns_queryflags flags, int *qml_r) { +adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, + adns_rrtype type, adns_queryflags flags, int *qml_r) { int ll, c, nlabs, qbufreq; unsigned char label[255], *nqbuf; const char *p, *pe; @@ -46,7 +46,7 @@ static adns_status mkquery(adns_state ads, const char *owner, int ol, int id, } } if (!(flags & adns_f_anyquote)) { - if ((c >= '0' && c <= '9') || c == '-') { + if (ctype_digit(c) || c == '-') { if (!ll) return adns_s_invaliddomain; } else if ((c < 'a' || c > 'z') && (c < 'A' && c > 'Z')) { return adns_s_invaliddomain; @@ -70,77 +70,105 @@ static adns_status mkquery(adns_state ads, const char *owner, int ol, int id, return adns_s_ok; } -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. - * fixme: Do not send more than 512-byte udp datagrams - */ - struct sockaddr_in servaddr; - int serv; +static void quproc_tosend_tcp(adns_state ads, adns_query qu, struct timeval now) { + unsigned char length[2]; + struct iovec iov[2]; - 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(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) { - warn("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; - } - } + length[0]= (qu->querylen&0x0ff00U) >>8; + length[1]= (qu->querylen&0x0ff); + + adns__tcp_tryconnect(ads); + /* fixme: try sending queries as soon as server comes up */ + /* fixme: use vbuf_ensure, and preallocate buffer space */ + if (ads->tcpstate != server_ok) return; - /* fixme: TCP queries preceded by length */ - for (;;) { - adns__tcp_tryconnect(ads); - /* fixme: make this work properly */ - 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; + DLIST_UNLINK(ads->tosend,qu); + timevaladd(&now,TCPMS); + qu->timeout= now; + qu->senttcpserver= ads->tcpserver; + DLIST_LINKTAIL(ads->timew,qu); + + if (ads->opbufused) { + r= 0; + } else { + iov[0].iovbase= length; + iov[0].iov_len= 2; + iov[1].iovbase= qu->querymsg; + iov[1].iov_len= qu->querylen; + r= writev(ads->tcpsocket,iov,2); + if (r < 0) { + if (!(errno == EAGAIN || errno == EINTR || errno == ENOSPC || + errno == ENOBUFS || errno == ENOMEM)) { + adns__tcp_broken(ads,"write",strerror(errno)); + return; + } + r= 0; } - tcpserver_broken(serv); } - if (r < qu->querylen) { - newopbufused= qu->opbufused + (qu->querylen-r); + + if (r < qu->querylen+2) { + newopbufused= qu->opbufused + qu->querylen + 2 - r; if (newopbufused > ads->opbufavail) { newopbufavail= ads->newopbufused<<1; newopbuf= realloc(newopbufavail); if (!newopbuf) { - DLIST_UNLINK(ads->tosend,qu); + DLIST_UNLINK(ads->timew,qu); query_fail(ads,qu,adns_s_nolocalmem); return; } ads->opbuf= newopbuf; ads->opbufavail= newopbufavail; } + if (r<2) { + memcpy(ads->opbuf+ads->opbufused,length+r,2-r); + ads->opbufused += (2-r); + r= 0; + } else { + r -= 2; + } memcpy(ads->opbuf+ads->opbufused,qu->querymsg+r,qu->querylen-r); ads->opbufused= newopbufused; } +} + +void adns__quproc_tosend(adns_state ads, adns_query qu, struct timeval now) { + /* Query must be on the `tosend' queue, and we guarantee to remove it. + */ + struct sockaddr_in servaddr; + int serv; + + if (qu->nextudpserver == -1) { quproc_tosend_tcp(ads,qu,now); return; } + if (qu->querylen > UDPMAXDGRAM) { + qu->nextudpserver= -1; + quproc_tosend_tcp(ads,qu,now); + return; + } + + 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(NSPORT); + + r= sendto(ads->udpsocket,qu->querymsg,qu->querylen,0,&servaddr,sizeof(servaddr)); + if (r<0 && errno == EMSGSIZE) { + qu->nextudpserver= -1; + quproc_tosend_tcp(ads,qu,now); return; + } + if (r<0) warn("sendto %s failed: %s",inet_ntoa(servaddr.sin_addr),strerror(errno)); + DLIST_UNLINK(ads->tosend,qu); - timevaladd(&now,TCPMS); + timevaladd(&now,UDPRETRYMS); qu->timeout= now; - qu->senttcp |= (1<nextserver); + qu->sentudp |= (1<nextudpserver= (serv+1)%ads->nservers; + qu->udpretries++; DLIST_LINKTAIL(ads->timew,qu); } diff --git a/src/setup.c b/src/setup.c index 7daea9b..d7d9892 100644 --- a/src/setup.c +++ b/src/setup.c @@ -231,6 +231,8 @@ int adns_init(adns_state *ads_r, adns_initflags flags) { proto= getprotobyname("udp"); if (!proto) { r= ENOPROTOOPT; goto x_free; } ads->udpsocket= socket(AF_INET,SOCK_DGRAM,proto->p_proto); if (ads->udpsocket<0) { r= errno; goto x_free; } + + /*fixme: nonblock */ *ads_r= ads; return 0; diff --git a/src/submit.c b/src/submit.c index 576c437..f2fd72c 100644 --- a/src/submit.c +++ b/src/submit.c @@ -55,7 +55,7 @@ int adns_submit(adns_state ads, return failsubmit(ads,context,query_r,type,flags,id,adns_s_invaliddomain); if (owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_f_search; ol--; } - stat= mkquery(ads,owner,ol,id,type,flags,&qml); + stat= adns__mkquery(ads,owner,ol,id,type,flags,&qml); 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;