int main(void) {
adns_state ads;
adns_query qu;
+ adns_answer *ans;
int r;
- r= adns_init(&ads,adns_if_debug|adns_if_noautosys);
+ r= adns_init(&ads,adns_if_debug|adns_if_noautosys,0);
if (r) { perror("init"); exit(2); }
r= adns_submit(ads,"anarres.greenend.org.uk",adns_r_a,0,0,&qu);
if (r) { perror("submit"); exit(2); }
+
+ r= adns_wait(ads,&qu,&ans,0);
+ if (r) { perror("wait"); exit(2); }
+
+ if (!ans) { fputs("no answer\n",stderr); exit(2); }
+ fprintf(stderr,"answer status %d type %d rrs %d cname %s\n",
+ ans->status,ans->type,ans->nrrs,
+ ans->cname ? ans->cname : "-");
exit(0);
}
all: dtest
-dtest: dtest.o event.o query.o setup.o submit.o
+dtest: dtest.o event.o query.o setup.o submit.o reply.o
+
+clean:
+ rm -f dtest *.o
+
+dtest.o event.o query.o setup.o submit.o reply.o: internal.h adns.h
-%.o: adns-internal.h adns.h
all: dtest
-dtest: dtest.o event.o query.o setup.o submit.o
+dtest: dtest.o event.o query.o setup.o submit.o reply.o
+
+clean:
+ rm -f dtest *.o
+
+dtest.o event.o query.o setup.o submit.o reply.o: internal.h adns.h
-%.o: adns-internal.h adns.h
+++ /dev/null
-/**/
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <unistd.h>
-
-#include <netdb.h>
-#include <arpa/nameser.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "adns-internal.h"
#ifndef ADNS_H_INCLUDED
#define ADNS_H_INCLUDED
+#include <stdio.h>
+
#include <sys/socket.h>
#include <netinet/in.h>
adns_r_none= 0,
adns_r_a= 1,
- adns_r_a_mf= adns_r_a|adns__qtf_mf,
+ adns_r_a_mf= adns_r_a|adns__qtf_masterfmt,
adns_r_ns_raw= 2,
adns_r_ns= adns_r_ns_raw|adns__qtf_deref,
- adns_r_ns_mf= adns_r_ns_raw|adns__qtf_mf,
+ adns_r_ns_mf= adns_r_ns_raw|adns__qtf_masterfmt,
adns_r_cname= 5,
- adns_r_cname_mf= adns_r_cname|adns__qtf_mf,
+ adns_r_cname_mf= adns_r_cname|adns__qtf_masterfmt,
adns_r_soa_raw= 6,
adns_r_soa= adns_r_soa_raw|adns__qtf_mail822,
- adns_r_soa_mf= adns_r_soa_raw|adns__qtf_mf,
+ adns_r_soa_mf= adns_r_soa_raw|adns__qtf_masterfmt,
adns_r_null= 10,
- adns_r_null_mf= adns_r_null|adns__qtf_mf,
+ adns_r_null_mf= adns_r_null|adns__qtf_masterfmt,
adns_r_ptr_raw= 12,
adns_r_ptr= adns_r_ptr_raw|adns__qtf_deref,
- adns_r_ptr_mf= adns_r_ptr_raw|adns__qtf_mf,
+ adns_r_ptr_mf= adns_r_ptr_raw|adns__qtf_masterfmt,
adns_r_hinfo= 13,
- adns_r_hinfo_mf= adns_r_hinfo|adns__qtf_mf,
+ adns_r_hinfo_mf= adns_r_hinfo|adns__qtf_masterfmt,
adns_r_mx_raw= 15,
adns_r_mx= adns_r_mx_raw|adns__qtf_deref,
- adns_r_mx_mf= adns_r_mx_raw|adns__qtf_mf,
+ adns_r_mx_mf= adns_r_mx_raw|adns__qtf_masterfmt,
adns_r_txt= 16,
- adns_r_txt_mf= adns_r_txt|adns__qtf_mf,
+ adns_r_txt_mf= adns_r_txt|adns__qtf_masterfmt,
adns_r_rp_raw= 17,
- adns_r_rp= adns_r_rp_raw|adns__qtf_mail822
- adns_r_rp_mf= adns_r_rp_raw|adns__qtf_mf,
+ adns_r_rp= adns_r_rp_raw|adns__qtf_mail822,
+ adns_r_rp_mf= adns_r_rp_raw|adns__qtf_masterfmt
} adns_rrtype;
adns_s_max_tempfail= 99,
adns_s_inconsistent, /* PTR gives domain whose A does not match */
adns_s_cname, /* CNAME found where data eg A expected (not if _qf_loosecname) */
- adns_s_max_misconfig= 199;
+ adns_s_max_misconfig= 199,
adns_s_nxdomain,
adns_s_norecord,
adns_s_invaliddomain
adns_status astatus;
int naddrs; /* temp fail => -1, perm fail => 0, s_ok => >0 */
struct in_addr *addrs;
-} adns_dmaddr;
+} adns_rr_dmaddr;
+
+typedef struct {
+ char *a, *b;
+} adns_rr_strpair;
+
+typedef struct {
+ int i;
+ adns_rr_dmaddr dmaddr;
+} adns_rr_intdmaddr;
+
+typedef struct {
+ int i;
+ char *str;
+} adns_rr_intstr;
+
+typedef struct {
+ char *ns0, *rp;
+ unsigned long serial, refresh, retry, expire, minimum;
+} adns_rr_soa;
typedef struct {
adns_status status;
adns_rrtype type;
int nrrs;
union {
- struct in_addr inaddr[1]; /* a */
- char (*str)[1]; /* ns_raw, cname, ptr, ptr_raw, txt, <any>_mf */
- adns_dmaddr dmaddr[1]; /* ns */
- struct { char *a, *b; } strpair[1]; /* hinfo, rp, rp_raw */
- struct { int pref; adns_dmaddrs dmaddr; } intdmaddr[1]; /* mx */
- struct { int pref; char *str; } intstr[1]; /* mx_raw */
- struct {
- char *ns0, *rp;
- unsigned long serial, refresh, retry, expire, minimum;
- } soa[1]; /* soa, soa_raw */
+ struct in_addr *inaddr; /* a */
+ char *(*str); /* ns_raw, cname, ptr, ptr_raw, txt, <any>_mf */
+ adns_rr_dmaddr *dmaddr; /* ns */
+ adns_rr_strpair *strpair; /* hinfo, rp, rp_raw */
+ adns_rr_intdmaddr *intdmaddr; /* mx */
+ adns_rr_intstr *intstr; /* mx_raw */
+ adns_rr_soa *soa; /* soa, soa_raw */
/* NULL is empty */
} rrs;
} adns_answer;
/* Memory management:
* adns_state and adns_query are actually pointers to malloc'd state;
* On submission questions are copied, including the owner domain;
- * Answers are malloc'd as a single piece of memory.
+ * Answers are malloc'd as a single piece of memory; pointers in the
+ * answer struct point into further memory in the answer.
* query_io:
* Must always be non-null pointer;
* If *query_io is 0 to start with then any query may be returned;
* Other fd's may be in the fd_sets, and will be ignored.
* _callback returns how many adns fd's were in the various sets, so
* you can tell if your select handling code has missed something and is going awol.
+ *
+ * May also return -1 if a critical syscall failed, setting errno.
*/
void adns_interest(adns_state, int *maxfd_io, fd_set *readfds_io,
/**/
-#include "adns-internal.h"
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include "internal.h"
/* TCP connection management */
void adns__tcp_broken(adns_state ads, const char *what, const char *why) {
int serv;
+ adns_query qu, nqu;
assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);
serv= ads->tcpserver;
- warn("TCP connection lost: %s: %s",serv,why);
+ adns__warn(ads,serv,"TCP connection lost: %s: %s",what,why);
close(ads->tcpsocket);
ads->tcpstate= server_disconnected;
- for (qu= ads->timew; qu; qu= nqu) {
+ for (qu= ads->timew.head; qu; qu= nqu) {
nqu= qu->next;
if (qu->state == query_udp) continue;
assert(qu->state == query_tcpwait || qu->state == query_tcpsent);
qu->state= query_tcpwait;
qu->tcpfailed |= (1<<serv);
if (qu->tcpfailed == (1<<ads->nservers)-1) {
- DLIST_UNLINK(ads->timew,qu);
+ LIST_UNLINK(ads->timew,qu);
adns__query_fail(ads,qu,adns_s_allservfail);
}
}
- ads->tcpbuf.used= 0;
+ ads->tcprecv.used= ads->tcpsend.used= 0;
ads->tcpserver= (serv+1)%ads->nservers;
}
static void tcp_connected(adns_state ads, struct timeval now) {
- debug("TCP connected",ads->tcpserver);
- ads->tcpstate= server_connected;
+ adns_query qu, nqu;
+
+ adns__debug(ads,ads->tcpserver,"TCP connected");
+ ads->tcpstate= server_ok;
for (qu= ads->timew.head; qu; qu= nqu) {
nqu= qu->next;
if (qu->state == query_udp) continue;
void adns__tcp_tryconnect(adns_state ads, struct timeval now) {
int r, fd, tries;
- sockaddr_in addr;
+ struct sockaddr_in addr;
+ struct protoent *proto;
/* fixme: single TCP timeout, not once per server */
for (tries=0; tries<ads->nservers; tries++) {
if (ads->tcpstate == server_connecting || ads->tcpstate == server_ok) return;
assert(ads->tcpstate == server_disconnected);
- assert(!ads->tcpbuf.used);
+ assert(!ads->tcpsend.used);
+ assert(!ads->tcprecv.used);
proto= getprotobyname("tcp");
- if (!proto) { diag(ads,"unable to find protocol number for TCP !",-1); return; }
+ if (!proto) { adns__diag(ads,-1,"unable to find protocol no. for TCP !"); return; }
fd= socket(AF_INET,SOCK_STREAM,proto->p_proto);
- if (fd<0) { diag(ads,"cannot create TCP socket: %s",-1,strerror(errno)); return; }
- if (!adns__setnonblock(fd)) return;
+ if (fd<0) {
+ adns__diag(ads,-1,"cannot create TCP socket: %s",strerror(errno));
+ return;
+ }
+ r= adns__setnonblock(ads,fd);
+ if (r) {
+ adns__diag(ads,-1,"cannot make TCP socket nonblocking: %s",strerror(r));
+ close(fd);
+ return;
+ }
memset(&addr,0,sizeof(addr));
addr.sin_family= AF_INET;
addr.sin_port= htons(NSPORT);
r= connect(fd,&addr,sizeof(addr));
ads->tcpsocket= fd;
ads->tcpstate= server_connecting;
- if (r==0) { tcp_connected(ads); continue; }
+ if (r==0) { tcp_connected(ads,now); continue; }
if (errno == EWOULDBLOCK || errno == EINPROGRESS) return;
adns__tcp_broken(ads,"connect",strerror(errno));
}
}
+/* `Interest' functions - find out which fd's we might be interested in,
+ * and when we want to be called back for a timeout.
+ */
+
+static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
+ struct timeval maxto) {
+ struct timeval *rbuf;
+
+ if (!tv_io) return;
+ 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;
+
+ if (!tv_io) return;
+ 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 inter_addfd(int *maxfd, fd_set *fds, int fd) {
+ if (!maxfd || !fds) return;
+ if (fd>=*maxfd) *maxfd= fd+1;
+ FD_SET(fd,fds);
+}
+
+static void checktimeouts(adns_state ads, struct timeval now,
+ struct timeval **tv_io, struct timeval *tvbuf) {
+ adns_query qu, nqu;
+
+ for (qu= ads->timew.head; qu; qu= nqu) {
+ nqu= qu->next;
+ if (timercmp(&now,&qu->timeout,>)) {
+ LIST_UNLINK(ads->timew,qu);
+ if (qu->state != query_udp) {
+ adns__query_fail(ads,qu,adns_s_timeout);
+ } else {
+ adns__query_udp(ads,qu,now);
+ }
+ } else {
+ inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
+ }
+ }
+}
+
+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;
+ struct timeval tvto_lr;
+ int r;
+
+ r= gettimeofday(&now,0);
+ if (r) {
+ adns__warn(ads,-1,"gettimeofday failed - will sleep for a bit: %s",strerror(errno));
+ timerclear(&tvto_lr); timevaladd(&tvto_lr,LOCALRESOURCEMS);
+ inter_maxto(tv_io, tvbuf, tvto_lr);
+ } else {
+ checktimeouts(ads,now,tv_io,tvbuf);
+ }
+
+ inter_addfd(maxfd,readfds,ads->udpsocket);
+
+ switch (ads->tcpstate) {
+ case server_disconnected:
+ break;
+ case server_connecting:
+ inter_addfd(maxfd,writefds,ads->tcpsocket);
+ break;
+ case server_ok:
+ inter_addfd(maxfd,readfds,ads->tcpsocket);
+ inter_addfd(maxfd,exceptfds,ads->tcpsocket);
+ if (ads->tcpsend.used) inter_addfd(maxfd,writefds,ads->tcpsocket);
+ default:
+ abort();
+ }
+}
+
/* Callback procedures - these do the real work of reception and timeout, etc. */
static int callb_checkfd(int maxfd, const fd_set *fds, int fd) {
static int internal_callback(adns_state ads, int maxfd,
const fd_set *readfds, const fd_set *writefds,
- const fd_set *exceptfds) {
- int skip, dgramlen, count, udpaddrlen, oldtcpsocket;
- enum adns__tcpstate oldtcpstate;
- unsigned char udpbuf[UDPMAXDGRAM];
+ const fd_set *exceptfds,
+ struct timeval now) {
+ int skip, want, dgramlen, count, udpaddrlen, r, serv;
+ byte udpbuf[MAXUDPDGRAM];
struct sockaddr_in udpaddr;
count= 0;
if (callb_checkfd(maxfd,writefds,ads->tcpsocket)) {
count++;
assert(ads->tcprecv.used==0);
- vbuf_ensure(&ads->tcprecv,1);
+ adns__vbuf_ensure(&ads->tcprecv,1);
if (ads->tcprecv.buf) {
r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
- tcpserver_connected(ads);
+ tcp_connected(ads,now);
} else if (r>0) {
- tcpserver_broken(ads,"connect/read","sent data before first request");
+ adns__tcp_broken(ads,"connect/read","sent data before first request");
} else if (errno!=EINTR) {
- tcpserver_broken(ads,"connect/read",strerror(errno));
+ adns__tcp_broken(ads,"connect/read",strerror(errno));
}
}
}
if (ads->tcprecv.used<skip+2+dgramlen) {
want= 2+dgramlen;
} else {
- procdgram(ads,ads->tcprecv.buf+skip+2,dgramlen,ads->tcpserver);
+ adns__procdgram(ads,ads->tcprecv.buf+skip+2,dgramlen,ads->tcpserver);
skip+= 2+dgramlen; continue;
}
}
ads->tcprecv.used -= skip;
memmove(ads->tcprecv.buf,ads->tcprecv.buf+skip,ads->tcprecv.used);
- vbuf_ensure(&ads->tcprecv,want);
+ adns__vbuf_ensure(&ads->tcprecv,want);
if (ads->tcprecv.used >= ads->tcprecv.avail) break;
r= read(ads->tcpsocket,
ads->tcprecv.buf+ads->tcprecv.used,
if (errno==EAGAIN || errno==EWOULDBLOCK || errno==ENOMEM) break;
if (errno==EINTR) continue;
}
- tcpserver_broken(ads->tcpserver,"read",r?strerror(errno):"closed");
+ adns__tcp_broken(ads,"read",r?strerror(errno):"closed");
break;
}
}
} else if (callb_checkfd(maxfd,exceptfds,ads->tcpsocket)) {
- tcpserver_broken(ads->tcpserver,"select","exceptional condition detected");
+ adns__tcp_broken(ads,"select","exceptional condition detected");
} else if (ads->tcpsend.used && callb_checkfd(maxfd,writefds,ads->tcpsocket)) {
r= write(ads->tcpsocket,ads->tcpsend.buf,ads->tcpsend.used);
if (r<0) {
if (errno!=EAGAIN && errno!=EWOULDBLOCK && errno!=ENOMEM && errno!=EINTR) {
- tcpserver_broken(ads->tcpserver,"write",strerror(errno));
+ adns__tcp_broken(ads,"write",strerror(errno));
}
} else if (r>0) {
ads->tcpsend.used -= r;
if (r<0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK ||
errno == EINTR || errno == ENOMEM || errno == ENOBUFS))
- warn("datagram receive error: %s",strerror(errno));
+ adns__warn(ads,-1,"datagram receive error: %s",strerror(errno));
break;
}
if (udpaddrlen != sizeof(udpaddr)) {
- diag("datagram received with wrong address length %d (expected %d)",
- udpaddrlen,sizeof(udpaddr));
+ adns__diag(ads,-1,"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);
+ adns__diag(ads,-1,"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);
+ adns__diag(ads,-1,"datagram received from wrong port %u (expected %u)",
+ ntohs(udpaddr.sin_port),NSPORT);
continue;
}
for (serv= 0;
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));
+ adns__warn(ads,-1,"datagram received from unknown nameserver %s",
+ inet_ntoa(udpaddr.sin_addr));
continue;
}
- procdgram(ads,udpbuf,r,serv);
+ adns__procdgram(ads,udpbuf,r,serv);
}
}
+ return count;
}
-static void checktimeouts(adns_state ads, struct timeval now,
- struct timeval **tv_io, struct timeval *tvbuf) {
- for (qu= ads->timew; qu; qu= nqu) {
- nqu= qu->next;
- if (timercmp(&now,qu->timeout,>)) {
- DLIST_UNLINK(ads->timew,qu);
- if (qu->state != state_udp) {
- query_fail(ads,qu,adns_s_notresponding);
- } else {
- adns__query_udp(ads,qu,now);
- }
- } else {
- inter_maxtoabs(tv_io,tvbuf,now,qu->timeout);
- }
- }
-}
-
int adns_callback(adns_state ads, int maxfd,
const fd_set *readfds, const fd_set *writefds,
const fd_set *exceptfds) {
struct timeval now;
-
- r= gettimeofday(&now,0);
- if (!r) checktimeouts(ads,now,0,0);
- return internal_callback(ads,maxfd,readfds,writefds,exceptfds);
-}
-
-/* `Interest' functions - find out which fd's we might be interested in,
- * and when we want to be called back for a timeout.
- */
-
-static void inter_maxto(struct timeval **tv_io, struct timeval *tvbuf,
- struct timeval maxto) {
- struct timeval rbuf;
-
- if (!tv_io) return;
- 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;
-
- if (!tv_io) return;
- 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 inter_addfd(int *maxfd, fd_set *fds, int fd) {
- if (!maxfd || !fds) return;
- if (fd>=*maxfd) *maxfd= fd+1;
- FD_SET(fd,fds);
-}
-
-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;
- struct timeval tvto_lr;
- adns_query qu;
int r;
-
- r= gettimeofday(&now,0);
- if (r) {
- warn(ads,"gettimeofday failed - will sleep for a bit: %s",-1,strerror(errno));
- timerclear(&tvto_lr); timevaladd(&tvto_lr,LOCALRESOURCEMS);
- inter_maxto(tv_io, tvbuf, tvto_lr);
- } else {
- checktimeouts(ads,now,tv_io,tvbuf);
- }
-
- inter_addfd(maxfd,readfds,ads->udpsocket);
- switch (ads->tcpstate) {
- case server_disc:
- break;
- case server_connecting:
- inter_addfd(maxfd,writefds,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();
- }
+ r= gettimeofday(&now,0); if (r) return -1;
+ checktimeouts(ads,now,0,0);
+ return internal_callback(ads,maxfd,readfds,writefds,exceptfds,now);
}
/* User-visible functions and their implementation. */
-static void autosys(adns_state ads, struct timeval now) {
+void adns__autosys(adns_state ads, struct timeval now) {
if (ads->iflags & adns_if_noautosys) return;
adns_callback(ads,-1,0,0,0);
}
if (qu->id>=0) return EWOULDBLOCK;
}
LIST_UNLINK(ads->output,qu);
- *answer= qu->answer;
- if (context_r) *context_r= qu->context;
+ *answer= (adns_answer*)qu->answer.buf;
+ if (context_r) *context_r= qu->context.ext;
free(qu);
return 0;
}
adns_interest(ads,&maxfd,&readfds,&writefds,&exceptfds,&tvp,&tvbuf);
rsel= select(maxfd,&readfds,&writefds,&exceptfds,tvp);
if (rsel==-1) return r;
- rcb= internal_callback(ads,maxfd,&readfds,&writefds,&exceptfds);
+ rcb= adns_callback(ads,maxfd,&readfds,&writefds,&exceptfds);
assert(rcb==rsel);
}
}
adns_query *query_io,
adns_answer **answer_r,
void **context_r) {
- autosys(ads);
+ struct timeval now;
+ int r;
+
+ r= gettimeofday(&now,0); if (r) return errno;
+ adns__autosys(ads,now);
return internal_check(ads,query_io,answer_r,context_r);
}
#ifndef ADNS_INTERNAL_H_INCLUDED
#define ADNS_INTERNAL_H_INCLUDED
+#define PRINTFFORMAT(a,b) __attribute__((format(printf,a,b)))
+typedef unsigned char byte;
+
+#include <stdarg.h>
+#include <assert.h>
+#include <unistd.h>
+
#include <sys/time.h>
#include "adns.h"
#define UDPRETRYMS 2000
#define TCPMS 30000
#define LOCALRESOURCEMS 20
-#define UDPMAXDGRAM 512
+#define MAXUDPDGRAM 512
#define NSPORT 53
+#define MAXDNAME 255
/* Shared data structures */
-union adns__align {
+typedef union {
adns_status status;
char *cp;
adns_rrtype type;
- int int;
+ int i;
struct in_addr ia;
unsigned long ul;
-};
+} rr_align;
+
+typedef struct {
+ int used, avail;
+ byte *buf;
+} vbuf;
+
+typedef union {
+ void *ext;
+ int dmaddr_index;
+} qcontext;
struct adns__query {
/* FIXME: make sure this is all init'd properly */
enum { query_udp, query_tcpwait, query_tcpsent, query_child, query_done } state;
- adns_query back, next;
- adns_query parent;
+ adns_query back, next, parent;
struct { adns_query head, tail; } children;
struct { adns_query back, next; } siblings;
adns_rrtype type;
- adns_answer *answer;
- size_t ansalloc; ansused;
+ vbuf answer;
int id, flags, udpretries;
- int nextudpserver;
- unsigned long sentudp, failedtcp; /* bitmap indexed by server */
+ int udpnextserver;
+ unsigned long udpsent, tcpfailed; /* bitmap indexed by server */
struct timeval timeout;
- void *context;
- unsigned char *querymsg;
+ byte *querymsg;
int querylen;
+ qcontext context;
char owner[1];
- /* After the owner name and nul comes the query message */
+ /* After the owner name and nul comes the query message, pointed to by querymsg */
/* Possible states:
*
*/
};
-typedef struct {
- size_t used, avail;
- unsigned char *buf;
-} adns__vbuf;
-
struct adns__state {
- /* FIXME: make sure this is all init'd properly */
adns_initflags iflags;
FILE *diagfile;
struct { adns_query head, tail; } timew, childw, output;
- int nextid, udpsocket;
- adns_vbuf rqbuf, tcpsend, tcprecv;
+ int nextid, udpsocket, tcpsocket;
+ vbuf rqbuf, tcpsend, tcprecv;
int nservers, tcpserver;
enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
- int tcpsocket;
struct timeval tcptimeout;
struct server {
struct in_addr addr;
/* From setup.c: */
-void adns__vdiag(adns_state ads, adns_initflags prevent, const char *pfx,
+void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
int serv, const char *fmt, va_list al);
void adns__debug(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
void adns__warn(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
-static inline int adns__vbuf_ensure(adns__vbuf *vb, size_t want);
-int adns__vbuf_append(adns__vbuf *vb, const byte *data, size_t len);
-int adns__vbuf_appendq(adns__vbuf *vb, const byte *data, size_t len);
+int adns__vbuf_ensure(vbuf *vb, int want);
+int adns__vbuf_append(vbuf *vb, const byte *data, int len);
/* 1=>success, 0=>realloc failed */
+void adns__vbuf_appendq(vbuf *vb, const byte *data, int len);
+void adns__vbuf_init(vbuf *vb);
+
+int adns__setnonblock(adns_state ads, int fd); /* => errno value */
/* From submit.c: */
+void adns__query_nomem(adns_state ads, adns_query qu);
void adns__query_fail(adns_state ads, adns_query qu, adns_status stat);
/* From query.c: */
void adns__query_udp(adns_state ads, adns_query qu, struct timeval now);
void adns__query_tcp(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);
+ adns_rrtype type, adns_queryflags flags);
+
+/* From reply.c: */
+
+void adns__procdgram(adns_state ads, const byte *dgram, int len, int serv);
/* From event.c: */
+
void adns__tcp_broken(adns_state ads, const char *what, const char *why);
-void adns__tcp_tryconnect(adns_state ads);
+void adns__tcp_tryconnect(adns_state ads, struct timeval now);
+void adns__autosys(adns_state ads, struct timeval now);
/* Useful static inline functions: */
/* Useful macros */
+#define LIST_INIT(list) ((list).head= (list).tail= 0)
+
#define LIST_UNLINK_PART(list,node,part) \
do { \
if ((node)->back) (node)->back->part next= (node)->part next; \
} while(0)
#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,)
-#define LIST_LINK_TAIL_PART(list,node) LIST_LINK_TAIL(list,node,)
+#define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,)
#endif
/**/
+#include <errno.h>
+#include <string.h>
+
+#include <sys/uio.h>
+
#include "internal.h"
adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id,
adns_rrtype type, adns_queryflags flags) {
/* Assembles a query packet in ads->rqbuf. */
int ll, c, nlabs;
- unsigned char label[255], *rqp;
+ byte label[255], *rqp;
const char *p, *pe;
#define MKQUERY_ADDB(b) *rqp++= (b)
#define MKQUERY_ADDW(w) (MKQUERY_ADDB(((w)>>8)&0x0ff), MKQUERY_ADDB((w)&0x0ff))
- if (!vbuf_ensure(&ads->rqbuf,12+strlen(owner)+3)) return adns_s_nolocalmem;
+ if (!adns__vbuf_ensure(&ads->rqbuf,12+strlen(owner)+3)) return adns_s_nolocalmem;
rqp= ads->rqbuf.buf;
MKQUERY_ADDW(id);
ll= 0;
while (p!=pe && (c= *p++)!='.') {
if (c=='\\') {
- if (!(flags & adns_f_anyquote)) return adns_s_invaliddomain;
+ if (!(flags & adns_qf_anyquote)) return adns_s_invaliddomain;
if (ctype_digit(p[0])) {
if (ctype_digit(p[1]) && ctype_digit(p[2])) {
c= (*p++ - '0')*100 + (*p++ - '0')*10 + (*p++ - '0');
return adns_s_invaliddomain;
}
}
- if (!(flags & adns_f_anyquote)) {
+ if (!(flags & adns_qf_anyquote)) {
if (ctype_digit(c) || c == '-') {
if (!ll) return adns_s_invaliddomain;
} else if ((c < 'a' || c > 'z') && (c < 'A' && c > 'Z')) {
MKQUERY_ADDW(type & adns__rrt_typemask); /* QTYPE */
MKQUERY_ADDW(1); /* QCLASS=IN */
- ads->rqbuf.used= rqp - ads->rqbuf.used;
+ ads->rqbuf.used= rqp - ads->rqbuf.buf;
assert(ads->rqbuf.used < ads->rqbuf.avail);
return adns_s_ok;
}
-void adns__query_tcp(adns_state ads, adns_query qu) {
+void adns__query_tcp(adns_state ads, adns_query qu, struct timeval now) {
/* Query must be in state tcpwait/timew; it will be moved to a new state
* if possible and no further processing can be done on it for now.
* (Resulting state is one of tcpwait/timew (if server not connected),
* may break. If the conn list lost then the caller is responsible for any
* reestablishment and retry.
*/
- unsigned char length[2];
+ byte length[2];
struct iovec iov[2];
+ int wr, r;
if (ads->tcpstate != server_ok) return;
length[0]= (qu->querylen&0x0ff00U) >>8;
length[1]= (qu->querylen&0x0ff);
- if (!vbuf_ensure(&ads->tcpsend,ads->tcpsend.used+qu->querylen+2)) return;
+ if (!adns__vbuf_ensure(&ads->tcpsend,ads->tcpsend.used+qu->querylen+2)) return;
timevaladd(&now,TCPMS);
qu->timeout= now;
- qu->senttcpserver= ads->tcpserver;
- DLIST_LINKTAIL(ads->timew,qu);
+ qu->state= query_tcpsent;
+ LIST_LINK_TAIL(ads->timew,qu);
- if (ads->opbufused) {
+ if (ads->tcpsend.used) {
wr= 0;
} else {
- iov[0].iovbase= length;
+ iov[0].iov_base= length;
iov[0].iov_len= 2;
- iov[1].iovbase= qu->querymsg;
+ iov[1].iov_base= qu->querymsg;
iov[1].iov_len= qu->querylen;
wr= writev(ads->tcpsocket,iov,2);
if (wr < 0) {
}
if (wr<2) {
- r= vbuf_append(&ads->tcpsend,length,2-wr); assert(r);
+ r= adns__vbuf_append(&ads->tcpsend,length,2-wr); assert(r);
wr= 0;
- } esle {
+ } else {
wr-= 2;
}
if (wr<qu->querylen) {
- r= vbuf_append(&ads->tcpsend,qu->querymsg+wr,qu->querylen-wr); assert(r);
+ r= adns__vbuf_append(&ads->tcpsend,qu->querymsg+wr,qu->querylen-wr); assert(r);
}
}
timevaladd(&now,TCPMS);
qu->timeout= now;
qu->state= query_tcpwait;
- DLIST_LINKTAIL(ads->timew,qu);
- adns__query_tcp(ads,qu);
- adns__tcp_tryconnect(ads);
+ LIST_LINK_TAIL(ads->timew,qu);
+ adns__query_tcp(ads,qu,now);
+ adns__tcp_tryconnect(ads,now);
}
void adns__query_udp(adns_state ads, adns_query qu, struct timeval now) {
* tcpsent/timew, child/childw or done/output.)
*/
struct sockaddr_in servaddr;
- int serv;
+ int serv, r;
assert(qu->state == query_udp);
- if ((qu->flags & adns_f_usevc) ||
- (qu->querylen > UDPMAXDGRAM)) {
+ if ((qu->flags & adns_qf_usevc) || (qu->querylen > MAXUDPDGRAM)) {
query_usetcp(ads,qu,now);
return;
}
- if (qu->udpretries >= UDPMAXRETRIES) {
- query_fail(ads,qu,adns_s_notresponding);
+ if (qu->udpretries >= MAXUDPRETRIES) {
+ adns__query_fail(ads,qu,adns_s_timeout);
return;
}
- serv= qu->nextudpserver;
+ serv= qu->udpnextserver;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family= AF_INET;
servaddr.sin_addr= ads->servers[serv].addr;
r= sendto(ads->udpsocket,qu->querymsg,qu->querylen,0,&servaddr,sizeof(servaddr));
if (r<0 && errno == EMSGSIZE) { query_usetcp(ads,qu,now); return; }
- if (r<0) warn("sendto %s failed: %s",inet_ntoa(servaddr.sin_addr),strerror(errno));
+ if (r<0) adns__warn(ads,serv,"sendto failed: %s",strerror(errno));
timevaladd(&now,UDPRETRYMS);
qu->timeout= now;
- qu->sentudp |= (1<<serv);
- qu->nextudpserver= (serv+1)%ads->nservers;
+ qu->udpsent |= (1<<serv);
+ qu->udpnextserver= (serv+1)%ads->nservers;
qu->udpretries++;
- DLIST_LINKTAIL(ads->timew,qu);
+ LIST_LINK_TAIL(ads->timew,qu);
+}
+
+void adns__query_nomem(adns_state ads, adns_query qu) {
+ qu->answer.used= 0;
+ qu->id= -1;
+ LIST_LINK_TAIL(ads->output,qu);
}
void adns__query_fail(adns_state ads, adns_query qu, adns_status stat) {
adns_answer *ans;
-
- ans= qu->answer;
- if (!ans) ans= malloc(sizeof(*qu->answer));
- if (ans) {
- ans->status= stat;
- ans->cname= 0;
- ans->type= qu->type;
- ans->nrrs= 0;
+
+ if (!adns__vbuf_ensure(&qu->answer,sizeof(adns_answer))) {
+ adns__query_nomem(ads,qu);
+ return;
}
- qu->answer= ans;
+ ans= (adns_answer*)qu->answer.buf;
+ ans->status= stat;
+ ans->cname= 0;
+ ans->type= qu->type;
+ ans->nrrs= 0;
+ qu->answer.used= sizeof(adns_answer);
qu->id= -1;
LIST_LINK_TAIL(ads->output,qu);
}
--- /dev/null
+/**/
+
+#include "internal.h"
+
+void adns__procdgram(adns_state ads, const byte *dgram, int len, int serv) {
+ /* FIXME do something with incoming datagrams */
+ adns__diag(ads,serv,"received datagram size %d",len);
+}
/**/
-#include "adns-internal.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
-void adns__vdiag(adns_state ads, adns_initflags prevent, const char *pfx,
- int serv, const char *fmt, va_list al) {
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include "internal.h"
+
+void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
+ 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));
va_list al;
va_start(al,fmt);
- vdiag(ads," debug",0,serv,fmt,al);
+ adns__vdiag(ads," debug",0,serv,fmt,al);
va_end(al);
}
-void adns__swarn(adns_state ads, int serv, const char *fmt, ...) {
+void adns__warn(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);
+ adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,fmt,al);
va_end(al);
}
va_list al;
va_start(al,fmt);
- vdiag(ads,"",adns_if_noerrprint,serv,fmt,al);
+ adns__vdiag(ads,"",adns_if_noerrprint,serv,fmt,al);
va_end(al);
}
-/* FIXME: unsigned char -> byte everywhere */
-
+
+void adns__vbuf_init(vbuf *vb) {
+ vb->used= vb->avail= 0; vb->buf= 0;
+}
-int adns__vbuf_ensure(adns__vbuf *vb, size_t want) {
- byte *nb;
+int adns__vbuf_ensure(vbuf *vb, int want) {
+ void *nb;
- if (vb->avail >= want) return;
+ if (vb->avail >= want) return 1;
nb= realloc(vb->buf,want); if (!nb) return 0;
vb->buf= nb;
vb->avail= want;
return 1;
}
-void adns__vbuf_appendq(adns__vbuf *vb, const byte *data, size_t len) {
+void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
memcpy(vb->buf+vb->used,data,len);
vb->used+= len;
}
-int adns__vbuf_append(adns__vbuf *vb, const byte *data, size_t len) {
- size_t newlen, newalloc;
- byte *nb;
+int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
+ int newlen;
+ void *nb;
newlen= vb->used+len;
if (vb->avail < newlen) {
return 1;
}
+
static void addserver(adns_state ads, struct in_addr addr) {
int i;
struct server *ss;
for (i=0; i<ads->nservers; i++) {
if (ads->servers[i].addr.s_addr == addr.s_addr) {
- debug(ads,"duplicate nameserver %s ignored",inet_ntoa(addr));
+ adns__debug(ads,-1,"duplicate nameserver %s ignored",inet_ntoa(addr));
return;
}
}
if (ads->nservers>=MAXSERVERS) {
- diag(ads,"too many nameservers, ignoring %s",inet_ntoa(addr));
+ adns__diag(ads,-1,"too many nameservers, ignoring %s",inet_ntoa(addr));
return;
}
ss= ads->servers+ads->nservers;
ss->addr= addr;
- ss->state= server_disc;
- ss->connw.head= ss->connw.tail= 0;
ads->nservers++;
}
configparseerr(ads,fn,lno,"invalid nameserver address `%s'",buf);
return;
}
- debug(ads,"using nameserver %s",inet_ntoa(ia));
+ adns__debug(ads,-1,"using nameserver %s",inet_ntoa(ia));
addserver(ads,ia);
}
static void ccf_search(adns_state ads, const char *fn, int lno, const char *buf) {
if (!buf) return;
- diag(ads,"warning - `search' ignored FIXME");
+ adns__diag(ads,-1,"warning - `search' ignored FIXME");
}
static void ccf_sortlist(adns_state ads, const char *fn, int lno, const char *buf) {
- diag(ads,"warning - `sortlist' ignored FIXME");
+ adns__diag(ads,-1,"warning - `sortlist' ignored FIXME");
}
static void ccf_options(adns_state ads, const char *fn, int lno, const char *buf) {
if (!buf) return;
- diag(ads,"warning - `options' ignored FIXME");
+ adns__diag(ads,-1,"warning - `options' ignored FIXME");
}
static void ccf_clearnss(adns_state ads, const char *fn, int lno, const char *buf) {
file= fopen(filename,"r");
if (!file) {
if (errno == ENOENT) {
- debug(ads,"configuration file `%s' does not exist",filename);
+ adns__debug(ads,-1,"configuration file `%s' does not exist",filename);
return;
}
- diag(ads,"cannot open configuration file `%s': %s",filename,strerror(errno));
+ adns__diag(ads,-1,"cannot open configuration file `%s': %s",
+ filename,strerror(errno));
return;
}
l= strlen(linebuf);
if (!l) continue;
if (linebuf[l-1] != '\n' && !feof(file)) {
- diag(ads,"%s:%d: line too long",filename,lno);
+ adns__diag(ads,-1,"%s:%d: line too long",filename,lno);
while ((c= getc(file)) != EOF && c != '\n') { }
if (c == EOF) break;
continue;
ccip->name && strncmp(ccip->name,p,q-p);
ccip++);
if (!ccip->name) {
- diag(ads,"%s:%d: unknown configuration directive `%.*s'",filename,lno,q-p,p);
+ adns__diag(ads,-1,"%s:%d: unknown configuration directive `%.*s'",
+ filename,lno,q-p,p);
continue;
}
while (ctype_whitespace(*q)) q++;
ccip->fn(ads,filename,lno,q);
}
if (ferror(file)) {
- diag(ads,"%s:%d: read error: %s",filename,lno,strerror(errno));
+ adns__diag(ads,-1,"%s:%d: read error: %s",filename,lno,strerror(errno));
}
fclose(file);
}
const char *value;
value= getenv(envvar);
- if (!value) debug(ads,"environment variable %s not set",envvar);
- else debug(ads,"environment variable %s set to `%s'",envvar,value);
+ if (!value) adns__debug(ads,-1,"environment variable %s not set",envvar);
+ else adns__debug(ads,-1,"environment variable %s set to `%s'",envvar,value);
return value;
}
const char *filename;
if (ads->iflags & adns_if_noenv) {
- debug(ads,"not checking environment variable `%s'",envvar);
+ adns__debug(ads,-1,"not checking environment variable `%s'",envvar);
return;
}
filename= instrum_getenv(ads,envvar);
if (filename) readconfig(ads,filename);
}
+
+
+int adns__setnonblock(adns_state ads, int fd) {
+ int r;
-int adns_init(adns_state *ads_r, adns_initflags flags) {
+ r= fcntl(fd,F_GETFL,0); if (r<0) return errno;
+ r |= O_NONBLOCK;
+ r= fcntl(fd,F_SETFL,r); if (r<0) return errno;
+ return 0;
+}
+
+int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
adns_state ads;
const char *res_options, *adns_res_options;
struct protoent *proto;
int r;
ads= malloc(sizeof(*ads)); if (!ads) return errno;
- ads->timew.head= ads->timew.tail= 0;
- ads->childw.head= ads->childw.tail= 0;
- ads->output.head= ads->output.tail= 0;
- ads->nextid= 0x311f;
- ads->udpsocket= -1;
- ads->qbufavail= 0;
- ads->qbuf= 0;
- ads->tcpbufavail= ads->tcpbufused= ads->tcpbufdone= 0;
- ads->tcpbuf= 0;
- ads->iflags= flags;
- ads->nservers= 0;
ads->iflags= flags;
+ ads->diagfile= diagfile ? diagfile : stderr;
+ LIST_INIT(ads->timew);
+ LIST_INIT(ads->childw);
+ LIST_INIT(ads->output);
+ ads->nextid= 0x311f;
+ ads->udpsocket= ads->tcpsocket= -1;
+ adns__vbuf_init(&ads->rqbuf);
+ adns__vbuf_init(&ads->tcpsend);
+ adns__vbuf_init(&ads->tcprecv);
+ ads->nservers= ads->tcpserver= 0;
+ ads->tcpstate= server_disconnected;
+ timerclear(&ads->tcptimeout);
res_options= instrum_getenv(ads,"RES_OPTIONS");
adns_res_options= instrum_getenv(ads,"ADNS_RES_OPTIONS");
/**/
-#include "adns-internal.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/time.h>
+
+#include "internal.h"
static adns_query allocquery(adns_state ads, const char *owner, int ol,
- int qml, int id, adns_rrtype type,
- adns_queryflags flags, void *context) {
+ int id, adns_rrtype type,
+ adns_queryflags flags, const qcontext *ctx) {
+ /* Query message used is the one assembled in ads->rqbuf */
adns_query qu;
- unsigned char *qm;
- qu= malloc(sizeof(*qu)+ol+1+qml); if (!qu) return 0;
+ qu= malloc(sizeof(*qu)+ol+1+ads->rqbuf.used); if (!qu) return 0;
+ qu->state= query_udp;
qu->next= qu->back= qu->parent= 0;
- qu->children.head= qu->children.tail= 0;
+ LIST_INIT(qu->children);
qu->siblings.next= qu->siblings.back= 0;
- qu->id= id;
qu->type= type;
- qu->answer= 0;
+ adns__vbuf_init(&qu->answer);
+ qu->id= id;
qu->flags= flags;
- qu->context= context;
qu->udpretries= 0;
- qu->sentudp= qu->senttcp= 0;
- qu->nextserver= 0;
+ qu->udpnextserver= 0;
+ qu->udpsent= qu->tcpfailed= 0;
+ timerclear(&qu->timeout);
+ memcpy(&qu->context,ctx,sizeof(qu->context));
memcpy(qu->owner,owner,ol); qu->owner[ol]= 0;
- qu->querymsg= qm= qu->owner+ol+1;
- memcpy(qm,ads->qbuf,qml);
- qu->querylen= qml;
+ qu->querymsg= qu->owner+ol+1;
+ memcpy(qu->owner+ol+1,ads->rqbuf.buf,ads->rqbuf.used);
+ qu->querylen= ads->rqbuf.used;
return qu;
}
-static int failsubmit(adns_state ads, void *context, adns_query *query_r,
+static int failsubmit(adns_state ads, const qcontext *ctx, adns_query *query_r,
adns_rrtype type, adns_queryflags flags,
int id, adns_status stat) {
adns_query qu;
- qu= allocquery(ads,0,0,0,id,type,flags,context); if (!qu) return errno;
- query_fail(ads,qu,stat);
+ ads->rqbuf.used= 0;
+ qu= allocquery(ads,0,0,id,type,flags,ctx); if (!qu) return errno;
+ adns__query_fail(ads,qu,stat);
*query_r= qu;
return 0;
}
adns_query *query_r) {
adns_query qu;
adns_status stat;
- int ol, id, qml;
+ int ol, id, r;
+ qcontext ctx;
+ struct timeval now;
+ ctx.ext= context;
id= ads->nextid++;
r= gettimeofday(&now,0); if (r) return errno;
ol= strlen(owner);
if (ol<=1 || ol>MAXDNAME+1)
return failsubmit(ads,context,query_r,type,flags,id,adns_s_invaliddomain);
- if (owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_f_search; ol--; }
+ if (owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_qf_search; ol--; }
- stat= adns__mkquery(ads,owner,ol,id,type,flags,&qml);
+ stat= adns__mkquery(ads,owner,ol,id,type,flags);
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;
+ qu= allocquery(ads,owner,ol,id,type,flags,context); if (!qu) return errno;
adns__query_udp(ads,qu,now);
- autosys(ads,now);
+ adns__autosys(ads,now);
*query_r= qu;
return 0;