int querylen;
char owner[1];
/* Possible states:
- * Queue child answer nextserver sentudp senttcp
- * input null null 0 all bits zero all bits zero
- * timew null null any at least 1 bit set any
- * childw set partial any any any
- * output null set any any any
+ * 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__state {
adns_initflags iflags;
- struct { adns_query head, tail; } input, timew, childw, output;
+ struct { adns_query head, tail; } tosend, timew, childw, output;
int nextid, udpsocket;
int qbufavail, tcpbufavail, tcpbufused, tcpbufdone;
unsigned char *qbuf, *tcpbuf;
int r;
ads= malloc(sizeof(*ads)); if (!ads) return errno;
- ads->input.head= ads->input.tail= 0;
+ ads->tosend.head= ads->tosend.tail= 0;
ads->timew.head= ads->timew.tail= 0;
ads->childw.head= ads->childw.tail= 0;
ads->output.head= ads->output.tail= 0;
ans->nrrs= 0;
}
qu->answer= ans;
- LIST_LINK_TAIL(ads->input,qu);
+ qu->id= -1;
+ LIST_LINK_TAIL(ads->output,qu);
}
int adns_finish(adns_state ads) {
static int internal_check(adns_state ads,
adns_query *query_io,
- adns_answer *answer,
- void *context_r) {
- abort(); /* FIXME */
+ adns_answer **answer,
+ void **context_r) {
+ adns_query qu;
+
+ qu= *query_io;
+ if (!qu) {
+ if (!ads->output.head) return EWOULDBLOCK;
+ qu= ads->output.head;
+ } else {
+ if (qu->id>=0) return EWOULDBLOCK;
+ }
+ LIST_UNLINK(ads->output,qu);
+ *answer= qu->answer;
+ if (context_r) *context_r= qu->context;
+ free(qu);
+ return 0;
}
int adns_wait(adns_state ads,
adns_query *query_io,
- adns_answer *answer,
- void *context_r) {
+ adns_answer **answer_r,
+ void **context_r) {
int r, maxfd, rsel, rcb;
fd_set readfds, writefds, exceptfds;
struct timeval tvbuf, *tvp;
for (;;) {
- r= internal_check(ads,query_io,answer,context_r);
+ 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;
int adns_check(adns_state ads,
adns_query *query_io,
- adns_answer *answer,
- void *context_r) {
+ adns_answer **answer_r,
+ void **context_r) {
autosys(ads);
- return internal_check(ads,query_io,answer,context_r);
+ return internal_check(ads,query_io,answer_r,context_r);
}
int adns_synchronous(adns_state ads,
const char *owner,
adns_rrtype type,
adns_queryflags flags,
- adns_answer *answer) {
+ adns_answer **answer_r) {
adns_query qu;
int r;
if (r) return r;
do {
- r= adns_wait(ads,&qu,answer,0);
+ r= adns_wait(ads,&qu,answer_r,0);
} while (r==EINTR);
if (r) adns_cancel(ads,qu);
return r;
return 0;
}
+static void trysendudp(adns_state ads, adns_query qu) {
+ 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 adns_submit(adns_state ads,
const char *owner,
adns_rrtype type,
qu= allocquery(ads,owner,ol,qml,id,type,flags,context); if (!qu) return errno;
- LIST_LINK_TAIL(ads->input,qu);
+ LIST_LINK_TAIL(ads->tosend,qu);
+ trysendudp(ads,qu);
autosys(ads);
*query_r= qu;
adns_s_max_tempfail= 99,
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. If no
- * address is available (permanent failure) then INADDR_NONE is
- * used.
+ * 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 {
adns_rrtype type;
int nrrs;
union {
- struct in_addr inaddr[1]; /* a */
- char (*str)[1]; /* ns_raw, cname, ptr, ptr_raw, txt */
- struct { char *dm; struct in_addr addr; } dmaddr; /* ns */
- struct { char *a, *b; } strpair[1]; /* hinfo, rp, rp_raw */
- struct { int pref; char *dm; struct in_addr addr; } intdmaddr[1]; /* mx */
- struct { int pref; char *str; } intstr[1]; /* mx_raw */
+ 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 */
+ 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; char *str; } intstr[1]; /* mx_raw */
struct {
char *ns0, *rp;
unsigned long serial, refresh, retry, expire, minimum;
- } soa[1]; /* soa, soa_raw */
+ } soa[1]; /* soa, soa_raw */
/* NULL is empty */
} rrs;
} adns_answer;
const char *owner,
adns_rrtype type,
adns_queryflags flags,
- adns_answer *answer);
+ adns_answer **answer_r);
/* Will not return EINTR. */
/* NB: if you set adns_if_noautosys then _submit and _check do not
int adns_check(adns_state ads,
adns_query *query_io,
- adns_answer *answer,
- void *context_r);
+ adns_answer **answer_r,
+ void **context_r);
int adns_wait(adns_state ads,
adns_query *query_io,
- adns_answer *answer,
- void *context_r);
+ adns_answer **answer_r,
+ void **context_r);
/* Might return EINTR - if so, try again */
void adns_cancel(adns_state ads, adns_query query);