chiark / gitweb /
Search list implementation compiles, but not tested.
authorian <ian>
Sat, 17 Apr 1999 13:45:47 +0000 (13:45 +0000)
committerian <ian>
Sat, 17 Apr 1999 13:45:47 +0000 (13:45 +0000)
src/internal.h
src/query.c
src/reply.c
src/setup.c
src/transmit.c
src/types.c

index a71d9dc4ee308e5c41b1fbebc3d1d395b34c4963..4ec3c3edd9957b0a99e449a6e275a54b78028cd6 100644 (file)
@@ -51,6 +51,7 @@ typedef unsigned char byte;
 #define DNS_MAXUDP 512
 #define DNS_MAXDOMAIN 255
 #define DNS_HDRSIZE 12
+#define DNS_IDOFFSET 0
 #define DNS_CLASS_IN 1
 
 #define DNS_INADDR_ARPA "in-addr", "arpa"
@@ -185,7 +186,8 @@ struct adns__query {
    * is copied into the vbuf, and _origlen set to its length.  Then
    * we walk the searchlist, if we want to.  _pos says where we are
    * (next entry to try), and _doneabs says whether we've done the
-   * absolute query yet.  If flags doesn't have adns_qf_search then
+   * absolute query yet (0=not yet, 1=done, -1=must do straight away,
+   * but not done yet).  If flags doesn't have adns_qf_search then
    * the vbuf is initialised but empty and everything else is zero.
    *
    * fixme: actually implement this!
@@ -259,7 +261,7 @@ struct adns__state {
   struct { adns_query head, tail; } timew, childw, output;
   int nextid, udpsocket, tcpsocket;
   vbuf tcpsend, tcprecv;
-  int nservers, nsortlist, nsearchlist, tcpserver;
+  int nservers, nsortlist, nsearchlist, searchndots, tcpserver;
   enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
   struct timeval tcptimeout;
   struct sigaction stdsigpipe;
@@ -332,7 +334,8 @@ void adns__sigpipe_unprotect(adns_state);
 adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
                          const char *owner, int ol,
                          const typeinfo *typei, adns_queryflags flags);
-/* Assembles a query packet in vb, and returns id at *id_r. */
+/* Assembles a query packet in vb.  A new id is allocated and returned.
+ */
 
 adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
                                  const byte *qd_dgram, int qd_dglen, int qd_begin,
@@ -362,10 +365,10 @@ void adns__query_udp(adns_query qu, struct timeval now);
 
 /* From query.c: */
 
-int adns__internal_submit(adns_state ads, adns_query *query_r,
-                         const typeinfo *typei, vbuf *qumsg_vb, int id,
-                         adns_queryflags flags, struct timeval now,
-                         adns_status failstat, const qcontext *ctx);
+adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
+                                 const typeinfo *typei, vbuf *qumsg_vb, int id,
+                                 adns_queryflags flags, struct timeval now,
+                                 const qcontext *ctx);
 /* Submits a query (for internal use, called during external submits).
  *
  * The new query is returned in *query_r, or we return adns_s_nomemory.
@@ -374,12 +377,19 @@ int adns__internal_submit(adns_state ads, adns_query *query_r,
  * the memory for it is _taken over_ by this routine whether it
  * succeeds or fails (if it succeeds, the vbuf is reused for qu->vb).
  *
- * If failstat is nonzero then if we are successful in creating the query
- * it is immediately failed with code failstat (but _submit still succeds).
- *
  * *ctx is copied byte-for-byte into the query.
  */
 
+void adns__search_next(adns_state ads, adns_query qu, struct timeval now);
+/* Walks down the searchlist for a query with adns_qf_search.
+ * The query should have just had a negative response, or not had
+ * any queries sent yet, and should not be on any queue.
+ * The query_dgram if any will be freed and forgotten and a new
+ * one constructed from the search_* members of the query.
+ *
+ * Cannot fail (in case of error, calls adns__query_fail).
+ */
+
 void *adns__alloc_interim(adns_query qu, size_t sz);
 /* Allocates some memory, and records which query it came from
  * and how much there was.
@@ -604,6 +614,7 @@ static inline int ctype_alpha(int c) {
    * sizeof(union maxalign) )
 
 #define LIST_INIT(list) ((list).head= (list).tail= 0)
+#define LINK_INIT(link) ((link).next= (link).back= 0)
 
 #define LIST_UNLINK_PART(list,node,part) \
   do { \
index f710d3e7baa32095c27030a6f7bbe897b52d3ab3..81c04cb2b1e44abba0588987e0b578605930d8dc 100644 (file)
 
 #include "internal.h"
 
-int adns__internal_submit(adns_state ads, adns_query *query_r,
-                         const typeinfo *typei, vbuf *qumsg_vb, int id,
-                         adns_queryflags flags, struct timeval now,
-                         adns_status failstat, const qcontext *ctx) {
+static adns_query query_alloc(adns_state ads, const typeinfo *typei,
+                             adns_queryflags flags, struct timeval now) {
+  /* Allocate a virgin query and return it. */
   adns_query qu;
-
-  qu= malloc(sizeof(*qu)); if (!qu) goto x_nomemory;
-  qu->answer= malloc(sizeof(*qu->answer)); if (!qu->answer) goto x_freequ_nomemory;
-
+  
+  qu= malloc(sizeof(*qu));  if (!qu) return 0;
+  qu->answer= malloc(sizeof(*qu->answer));  if (!qu->answer) { free(qu); return 0; }
+  
   qu->ads= ads;
   qu->state= query_udp;
   qu->back= qu->next= qu->parent= 0;
   LIST_INIT(qu->children);
-  qu->siblings.next= qu->siblings.back= 0;
+  LINK_INIT(qu->siblings);
   LIST_INIT(qu->allocations);
   qu->interim_allocd= 0;
   qu->final_allocspace= 0;
 
   qu->typei= typei;
+  qu->query_dgram= 0;
+  qu->query_dglen= 0;
   adns__vbuf_init(&qu->vb);
 
   qu->cname_dgram= 0;
   qu->cname_dglen= qu->cname_begin= 0;
-  
-  qu->id= id;
+
+  adns__vbuf_init(&qu->search_vb);
+  qu->search_origlen= qu->search_pos= qu->search_doneabs= 0;
+
+  qu->id= 0;
   qu->flags= flags;
   qu->udpretries= 0;
   qu->udpnextserver= 0;
   qu->udpsent= qu->tcpfailed= 0;
   timerclear(&qu->timeout);
-  memcpy(&qu->ctx,ctx,sizeof(qu->ctx));
   qu->expires= now.tv_sec + MAXTTLBELIEVE;
 
+  memset(&qu->ctx,0,sizeof(qu->ctx));
+
   qu->answer->status= adns_s_ok;
   qu->answer->cname= 0;
   qu->answer->type= typei->type;
+  qu->answer->expires= -1;
   qu->answer->nrrs= 0;
   qu->answer->rrs= 0;
   qu->answer->rrsz= typei->rrsz;
-  
-  *query_r= qu;
 
-  qu->query_dglen= qumsg_vb->used;
-  if (qumsg_vb->used) {
-    qu->query_dgram= malloc(qumsg_vb->used);
-    if (!qu->query_dgram) {
-      adns__query_fail(qu,adns_s_nomemory);
-      return adns_s_ok;
-    }
-    memcpy(qu->query_dgram,qumsg_vb->buf,qumsg_vb->used);
-  } else {
-    qu->query_dgram= 0;
-  }
+  return qu;
+}
+
+static void query_submit(adns_state ads, adns_query qu,
+                        const typeinfo *typei, vbuf *qumsg_vb, int id,
+                        adns_queryflags flags, struct timeval now) {
+  /* Fills in the query message in for a previously-allocated query,
+   * and submits it.  Cannot fail.
+   */
+
   qu->vb= *qumsg_vb;
   adns__vbuf_init(qumsg_vb);
+
+  qu->query_dgram= malloc(qu->vb.used);
+  if (!qu->query_dgram) { adns__query_fail(qu,adns_s_nomemory); return; }
+  
+  qu->id= id;
+  qu->query_dglen= qu->vb.used;
+  memcpy(qu->query_dgram,qu->vb.buf,qu->vb.used);
   
-  if (failstat) {
-    adns__query_fail(qu,failstat);
-    return adns_s_ok;
-  }
   adns__query_udp(qu,now);
   adns__autosys(ads,now);
+}
 
+adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
+                                 const typeinfo *typei, vbuf *qumsg_vb, int id,
+                                 adns_queryflags flags, struct timeval now,
+                                 const qcontext *ctx) {
+  adns_query qu;
+
+  qu= query_alloc(ads,typei,flags,now);
+  if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; }
+  *query_r= qu;
+
+  memcpy(&qu->ctx,ctx,sizeof(qu->ctx));
+  query_submit(ads,qu, typei,qumsg_vb,id,flags,now);
+  
   return adns_s_ok;
+}
 
- x_freequ_nomemory:
-  free(qu);
- x_nomemory:
-  adns__vbuf_free(qumsg_vb);
-  return adns_s_nomemory;
+static void query_simple(adns_state ads, adns_query qu,
+                        const char *owner, int ol,
+                        const typeinfo *typei, adns_queryflags flags,
+                        struct timeval now) {
+  vbuf vb;
+  int id;
+  adns_status stat;
+
+  adns__vbuf_init(&vb);
+  
+  stat= adns__mkquery(ads,&vb,&id, owner,ol, typei,flags);
+  if (stat) { adns__query_fail(qu,stat); return; }
+
+  query_submit(ads,qu, typei,&vb,id, flags,now);
+}
+
+void adns__search_next(adns_state ads, adns_query qu, struct timeval now) {
+  const char *nextentry;
+  adns_status stat;
+  
+  if (qu->search_doneabs<0) {
+    nextentry= 0;
+    qu->search_doneabs= 1;
+  } else {
+    if (qu->search_pos >= ads->nsearchlist) {
+      if (qu->search_doneabs) {
+       stat= adns_s_nxdomain; goto x_fail;
+       return;
+      } else {
+       nextentry= 0;
+       qu->search_doneabs= 1;
+      }
+    } else {
+      nextentry= ads->searchlist[qu->search_pos++];
+    }
+  }
+
+  if (nextentry) {
+    if (!adns__vbuf_append(&qu->search_vb,".",1) ||
+       !adns__vbuf_appendstr(&qu->search_vb,nextentry)) {
+      stat= adns_s_nomemory; goto x_fail;
+    } else {
+      qu->search_vb.used= qu->search_origlen;
+    }
+  }
+
+  free(qu->query_dgram);
+  qu->query_dgram= 0; qu->query_dglen= 0;
+
+  query_simple(ads,qu, qu->search_vb.buf, qu->search_vb.used, qu->typei, qu->flags, now);
+  return;
+  
+x_fail:
+  adns__query_fail(qu,stat);
 }
 
 int adns_submit(adns_state ads,
@@ -111,34 +181,53 @@ int adns_submit(adns_state ads,
                adns_queryflags flags,
                void *context,
                adns_query *query_r) {
-  qcontext ctx;
-  int id, r, ol;
-  vbuf vb, search_vb;
+  int r, ol, ndots;
   adns_status stat;
   const typeinfo *typei;
   struct timeval now;
+  adns_query qu;
+  const char *p;
 
   typei= adns__findtype(type);
   if (!typei) return adns_s_unknownrrtype;
-  
-  ctx.ext= context;
-  ctx.callback= 0;
-  memset(&ctx.info,0,sizeof(ctx.info));
-  
-  r= gettimeofday(&now,0); if (r) return errno;
-  id= 0;
 
-  adns__vbuf_init(&vb);
+  r= gettimeofday(&now,0); if (r) goto x_errno;
+  qu= query_alloc(ads,typei,flags,now); if (!qu) goto x_errno;
+  
+  qu->ctx.ext= context;
+  qu->ctx.callback= 0;
+  memset(&qu->ctx.info,0,sizeof(qu->ctx.info));
 
   ol= strlen(owner);
-  if (ol>DNS_MAXDOMAIN+1) { stat= adns_s_querydomaintoolong; goto xit; }
+  if (!ol) { stat= adns_s_querydomaininvalid; goto x_adnsfail; }
+  if (ol>DNS_MAXDOMAIN+1) { stat= adns_s_querydomaintoolong; goto x_adnsfail; }
                                 
   if (ol>=2 && owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_qf_search; ol--; }
 
-  stat= adns__mkquery(ads,&vb,&id, owner,ol, typei,flags);
-                       
- xit:
-  return adns__internal_submit(ads,query_r, typei,&vb,id, flags,now, stat,&ctx);       
+  if (flags & adns_qf_search) {
+    r= adns__vbuf_append(&qu->search_vb,owner,ol);
+    if (!r) { stat= adns_s_nomemory; goto x_adnsfail; }
+
+    for (ndots=0, p=owner; (p= strchr(p,'.')); p++, ndots++);
+    qu->search_doneabs= (ndots >= ads->searchndots) ? -1 : 0;
+
+    qu->search_origlen= ol;
+
+    adns__search_next(ads,qu,now);
+    return 0;
+  }
+
+  query_simple(ads,qu, owner,ol, typei,flags, now);
+  return 0;
+
+ x_adnsfail:
+  adns__query_fail(qu,stat);
+  return 0;
+
+ x_errno:
+  r= errno;
+  assert(r);
+  return r;
 }
 
 int adns_synchronous(adns_state ads,
index c1ad342e1cb29f3a20c5f3bc93548afacbe74b56..ab7c8ff4aadbc37c6cdb589baf43b49aa384cc88 100644 (file)
@@ -227,7 +227,12 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
     if (rcode == rcode_nxdomain) {
       /* We still wanted to look for the SOA so we could find the TTL. */
       adns__update_expires(qu,soattl,now);
-      adns__query_fail(qu,adns_s_nxdomain);
+
+      if (qu->flags & adns_qf_search) {
+       adns__search_next(ads,qu,now);
+      } else {
+       adns__query_fail(qu,adns_s_nxdomain);
+      }
       return;
     }
 
index 26a5cff3732d819d6649951e1b566db00465f92a..1b81da1fb07577c29b176d8cdf839d09c5670a40 100644 (file)
@@ -428,6 +428,7 @@ static int init_begin(adns_state *ads_r, adns_initflags flags, FILE *diagfile) {
   ads->nservers= ads->nsortlist= ads->nsearchlist= ads->tcpserver= 0;
   ads->tcpstate= server_disconnected;
   ads->searchlist= 0;
+  ads->searchndots= 1;
   timerclear(&ads->tcptimeout);
 
   *ads_r= ads;
index d0b9d9514ef6b50653e1ae9ab25b6fb508b004db..11d774bb05d56e5c7c58312e19678eb81e757fbf 100644 (file)
@@ -39,11 +39,10 @@ static adns_status mkquery_header(adns_state ads, vbuf *vb, int *id_r, int qdlen
   
   if (!adns__vbuf_ensure(vb,DNS_HDRSIZE+qdlen+4)) return adns_s_nomemory;
 
-  *id_r= id= (ads->nextid++) & 0x0ffff;
-  
   vb->used= 0;
   MKQUERY_START(vb);
   
+  *id_r= id= (ads->nextid++) & 0x0ffff;
   MKQUERY_ADDW(id);
   MKQUERY_ADDB(0x01); /* QR=Q(0), OPCODE=QUERY(0000), !AA, !TC, RD */
   MKQUERY_ADDB(0x00); /* !RA, Z=000, RCODE=NOERROR(0000) */
index e4e56f63859bd23e671dfb0e8d318bddc9d6eb8e..50fb1e8d91c0c98b4143577165736191f5416aae 100644 (file)
@@ -469,7 +469,7 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
   if (!(pai->qu->flags & adns_qf_cname_loose)) nflags |= adns_qf_cname_forbid;
   
   st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr),
-                           &pai->qu->vb, id, nflags, pai->now, 0, &ctx);
+                           &pai->qu->vb, id, nflags, pai->now, &ctx);
   if (st) return st;
 
   nqu->parent= pai->qu;
@@ -712,7 +712,7 @@ static adns_status pa_ptr(const parseinfo *pai, int dmstart, int max, void *data
   memset(&ctx.info,0,sizeof(ctx.info));
   st= adns__internal_submit(pai->ads, &nqu, adns__findtype(adns_r_addr),
                            &pai->qu->vb, id,
-                           adns_qf_quoteok_query, pai->now, 0, &ctx);
+                           adns_qf_quoteok_query, pai->now, &ctx);
   if (st) return st;
 
   nqu->parent= pai->qu;