chiark / gitweb /
Change how addr queries track which subqueries to make.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 17 May 2014 17:52:13 +0000 (18:52 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 17 May 2014 17:52:13 +0000 (18:52 +0100)
Now we have a vector of query types we might want to make, and a pair of
bitmaps tracking whether (a) we want to issue that kind of query,
and (b) whether we've had an answer to it yet.  This replaces
the (sometimes tricky) messing about with raw rrtype vectors.

As a bonus, these bitmaps are now set in the context structure, where
they can be pushed through adns__internal_submit and into qs_addr, so we
no longer need adns__qf_nosend.  This is, accordingly, killed.

src/internal.h
src/query.c
src/types.c

index 2de6b563eff7f5470a3cbfa3777908d8c4e7d2b7..f5f185ec1be1df90721b1c5ed6bef6ad72fc9390 100644 (file)
@@ -72,7 +72,6 @@ typedef unsigned char byte;
 #define DNS_INADDR_ARPA "in-addr", "arpa"
 #define DNS_IP6_ARPA "ip6", "arpa"
 
-#define ADDR_MAXRRTYPES 2
 #define MAX_ADDRSTRLEN 64
 
 #define STRINGIFY(x) REALLY_STRINGIFY(x)
@@ -96,8 +95,6 @@ typedef enum {
 } dns_rcode;
 
 enum {
-  adns__qf_senddirect = 0x00100000,/* don't call the `query_send' type hook */
-  adns__qf_nosend     = 0x00200000,/* don't send the query when submitting */
   adns__qf_addr_answer= 0x01000000,/* addr query received an answer */
   adns__qf_addr_cname = 0x02000000 /* addr subquery performed on cname */
 };
@@ -251,8 +248,7 @@ typedef struct {
 
   union {
     struct {
-      size_t nrrty, onrrty;
-      adns_rrtype rrty[ADDR_MAXRRTYPES];
+      unsigned want, have;
     } addr;
   } tinfo; /* type-specific state for the query itself: zero-init if you
            * don't know better. */
index ff721855651fce6304ca7fc86eb398562c1c45f9..84a6cb2f48670d0bb3d55fa21eadb0dbcbadc066 100644 (file)
@@ -105,12 +105,8 @@ static void query_submit(adns_state ads, adns_query qu,
   qu->query_dglen= qu->vb.used;
   memcpy(qu->query_dgram,qu->vb.buf,qu->vb.used);
 
-  if (flags & adns__qf_nosend)
-    ;
-  else if (typei->query_send && !(flags & adns__qf_senddirect))
-    typei->query_send(qu,now);
-  else
-    adns__query_send(qu, now);
+  if (typei->query_send) typei->query_send(qu,now);
+  else adns__query_send(qu, now);
 }
 
 adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
@@ -120,7 +116,7 @@ adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
                                  const qcontext *ctx) {
   adns_query qu;
 
-  qu= query_alloc(ads,typei,type,flags & ~adns__qf_nosend,now);
+  qu= query_alloc(ads,typei,type,flags,now);
   if (!qu) { adns__vbuf_free(qumsg_vb); return adns_s_nomemory; }
   *query_r= qu;
 
index daedf1bdc6226ce9472c52bd4b373fe5bfac50d1..3bed29e94bfe8d67c5c27e599c70bcbcb324f9e4 100644 (file)
@@ -341,6 +341,35 @@ static adns_status cs_in6addr(vbuf *vb, const void *datap) {
 
 static const typeinfo tinfo_addrsub;
 
+#define ADDR_RRTYPES(_) _(a) _(aaaa)
+
+static const adns_rrtype addr_all_rrtypes[] = {
+#define RRTY_CODE(ty) adns_r_##ty,
+  ADDR_RRTYPES(RRTY_CODE)
+#undef RRTY_CODE
+};
+
+enum {
+#define RRTY_INDEX(ty) addr__ri_##ty,
+  ADDR_RRTYPES(RRTY_INDEX)
+#undef RRTY_INDEX
+  addr_nrrtypes,
+#define RRTY_FLAG(ty) addr_rf_##ty = 1 << addr__ri_##ty,
+  ADDR_RRTYPES(RRTY_FLAG)
+  addr__rrty_hunoz
+#undef RRTY_FLAG
+};
+
+static unsigned addr_rrtypeflag(adns_rrtype type)
+{
+  int i;
+
+  type &= adns_rrt_typemask;
+  for (i = 0; i < addr_nrrtypes && type != addr_all_rrtypes[i]; i++);
+  assert(i < addr_nrrtypes);
+  return 1 << i;
+}
+
 /* About CNAME handling in addr queries.
  *
  * A user-level addr query is translated into a number of protocol-level
@@ -481,13 +510,11 @@ static adns_status cs_addr(vbuf *vb, const void *datap) {
   return csp_addr(vb,rrp);
 }
 
-static void addr_rrtypes(adns_state ads, adns_rrtype type,
-                        adns_queryflags qf,
-                        adns_rrtype *rrty, size_t *nrrty)
+static unsigned addr_rrtypes(adns_state ads, adns_rrtype type,
+                            adns_queryflags qf)
 {
-  size_t n = 0;
-  adns_rrtype qtf = type & adns__qtf_deref;
   adns_queryflags permitaf = 0, hackaf = 0;
+  unsigned want = 0;
 
   if (!(qf & (adns_qf_ipv4_only | adns_qf_ipv6_only)))
     qf |= adns_qf_ipv4_only | adns_qf_ipv6_only;
@@ -504,10 +531,10 @@ static void addr_rrtypes(adns_state ads, adns_rrtype type,
       qf &= hackaf | permitaf | ~adns__qf_afmask;
   }
 
-  if (qf & adns_qf_ipv4_only) rrty[n++] = adns_r_a | qtf;
-  if (qf & adns_qf_ipv6_only) rrty[n++] = adns_r_aaaa | qtf;
+  if (qf & adns_qf_ipv4_only) want |= addr_rf_a;
+  if (qf & adns_qf_ipv6_only) want |= addr_rf_aaaa;
 
-  *nrrty = n;
+  return want;
 }
 
 static int gsz_addr(adns_rrtype type)
@@ -540,26 +567,25 @@ static adns_status append_addrs(adns_query qu, adns_query from, size_t rrsz,
 static void icb_addr(adns_query parent, adns_query child);
 
 static void addr_subqueries(adns_query qu, struct timeval now,
+                           adns_queryflags qf_extra,
                            const byte *qd_dgram, int qd_dglen)
 {
   int i, err, id;
   adns_query cqu;
-  adns_queryflags qf =qu->flags & ~adns_qf_search;
+  adns_queryflags qf = (qu->flags & ~adns_qf_search) | qf_extra;
+  adns_rrtype qtf = qu->answer->type & adns__qtf_deref;
+  unsigned which = qu->ctx.tinfo.addr.want & ~qu->ctx.tinfo.addr.have;
   qcontext ctx;
 
-  /* This always makes child queries, even if there's only the one.  This
-   * seems wasteful, but there's only one case where it'd be safe -- namely
-   * IPv4-only -- and that's not the case I want to optimize.
-   */
   memset(&ctx, 0, sizeof(ctx));
   ctx.callback = icb_addr;
-  qu->ctx.tinfo.addr.onrrty = qu->ctx.tinfo.addr.nrrty;
-  for (i = 0; i < qu->ctx.tinfo.addr.nrrty; i++) {
+  for (i = 0; i < addr_nrrtypes; i++) {
+    if (!(which & (1 << i))) continue;
     err = adns__mkquery_frdgram(qu->ads, &qu->vb, &id, qd_dgram, qd_dglen,
-                               DNS_HDRSIZE, qu->ctx.tinfo.addr.rrty[i], qf);
+                               DNS_HDRSIZE, addr_all_rrtypes[i], qf);
     if (err) goto x_error;
     err = adns__internal_submit(qu->ads, &cqu, &tinfo_addrsub,
-                               qu->ctx.tinfo.addr.rrty[i],
+                               addr_all_rrtypes[i] | qtf,
                                &qu->vb, id, qf, now, &ctx);
     if (err) goto x_error;
     cqu->answer->rrsz = qu->answer->rrsz;
@@ -575,10 +601,9 @@ x_error:
 }
 
 static adns_status addr_submit(adns_query parent, adns_query *query_r,
-                              vbuf *qumsg_vb, int id,
-                              const adns_rrtype *rrty, size_t nrrty,
+                              vbuf *qumsg_vb, int id, unsigned want,
                               adns_queryflags flags, struct timeval now,
-                              const qcontext *ctx)
+                              qcontext *ctx)
 {
   /* This is effectively a substitute for adns__internal_submit, intended for
    * the case where the caller (possibly) only wants a subset of the
@@ -587,7 +612,9 @@ static adns_status addr_submit(adns_query parent, adns_query *query_r,
    *
    * Some differences: the query is linked onto the parent's children list
    * before exit (though the parent's state is not changed, and it is not
-   * linked into the childw list queue).
+   * linked into the childw list queue); and we fiddle with the `tinfo'
+   * portion of the context structure (yes, modifying *ctx), since this is,
+   * in fact, the main purpose of this function.
    */
 
   adns_state ads = parent->ads;
@@ -597,17 +624,14 @@ static adns_status addr_submit(adns_query parent, adns_query *query_r,
     (adns_r_addr & adns_rrt_reprmask) |
     (parent->answer->type & ~adns_rrt_reprmask);
 
+  ctx->tinfo.addr.want = want;
+  ctx->tinfo.addr.have = 0;
   err = adns__internal_submit(ads, &qu, adns__findtype(adns_r_addr),
-                             type, qumsg_vb, id, flags | adns__qf_nosend,
-                             now, ctx);
+                             type, qumsg_vb, id, flags, now, ctx);
   if (err) return err;
 
   qu->parent = parent;
   LIST_LINK_TAIL_PART(parent->children, qu, siblings.);
-
-  memcpy(qu->ctx.tinfo.addr.rrty, rrty, nrrty*sizeof(*rrty));
-  qu->ctx.tinfo.addr.nrrty = nrrty;
-  addr_subqueries(qu, now, qu->query_dgram, qu->query_dglen);
   *query_r = qu;
   return adns_s_ok;
 }
@@ -624,18 +648,7 @@ static adns_status copy_cname_from_child(adns_query parent, adns_query child)
 }
 
 static void done_addr_type(adns_query qu, adns_rrtype type)
-{
-  size_t i;
-
-  for (i = 0;
-       i < qu->ctx.tinfo.addr.nrrty &&
-        type != qu->ctx.tinfo.addr.rrty[i];
-       i++);
-  assert(i < qu->ctx.tinfo.addr.nrrty);
-  qu->ctx.tinfo.addr.rrty[i] =
-    qu->ctx.tinfo.addr.rrty[--qu->ctx.tinfo.addr.nrrty];
-  qu->ctx.tinfo.addr.rrty[qu->ctx.tinfo.addr.nrrty] = type;
-}
+  { qu->ctx.tinfo.addr.have |= addr_rrtypeflag(type); }
 
 static void icb_addr(adns_query parent, adns_query child)
 {
@@ -663,7 +676,7 @@ static void icb_addr(adns_query parent, adns_query child)
       adns__transfer_interim(child, parent, cans->rrs.bytes);
       pans->rrs.bytes = cans->rrs.bytes;
       pans->nrrs = cans->nrrs;
-      parent->ctx.tinfo.addr.nrrty = parent->ctx.tinfo.addr.onrrty;
+      parent->ctx.tinfo.addr.have = 0;
       done_addr_type(parent, cans->type);
       err = copy_cname_from_child(parent, child); if (err) goto x_err;
     }
@@ -674,7 +687,7 @@ static void icb_addr(adns_query parent, adns_query child)
      * families.  The child's vbuf looks handy for this.
      */
     err = adns__mkquery(ads, &child->vb, &id, pans->cname,
-                       strlen(pans->cname), adns__findtype(adns_r_addr),
+                       strlen(pans->cname), &tinfo_addrsub,
                        adns_r_addr, parent->flags);
     if (err) goto x_err;
 
@@ -683,7 +696,8 @@ static void icb_addr(adns_query parent, adns_query child)
      */
     adns__cancel_children(parent);
     if (gettimeofday(&now, 0)) goto x_gtod;
-    addr_subqueries(parent, now, child->vb.buf, child->vb.used);
+    addr_subqueries(parent, now, adns__qf_addr_cname,
+                   child->vb.buf, child->vb.used);
     return;
   }
 
@@ -734,9 +748,12 @@ x_err:
 
 static void qs_addr(adns_query qu, struct timeval now)
 {
-  addr_rrtypes(qu->ads, qu->answer->type, qu->flags,
-              qu->ctx.tinfo.addr.rrty, &qu->ctx.tinfo.addr.nrrty);
-  addr_subqueries(qu, now, qu->query_dgram, qu->query_dglen);
+  if (!qu->ctx.tinfo.addr.want) {
+    qu->ctx.tinfo.addr.want =
+      addr_rrtypes(qu->ads, qu->answer->type, qu->flags);
+    qu->ctx.tinfo.addr.have = 0;
+  }
+  addr_subqueries(qu, now, 0, qu->query_dgram, qu->query_dglen);
 }
 
 /*
@@ -809,12 +826,11 @@ static adns_status pa_host_raw(const parseinfo *pai, int cbyte,
  */
 
 static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha,
-                                adns_rrtype *rrty, size_t *nrrty_io,
-                                size_t addrsz, int *cbyte_io, int count,
-                                int dmstart) {
-  int rri, naddrs, j;
+                                unsigned *want_io, size_t addrsz,
+                                int *cbyte_io, int count, int dmstart) {
+  int rri, naddrs;
+  unsigned typef, want = *want_io;
   int type, class, rdlen, rdend, rdstart, ownermatched;
-  size_t nrrty = *nrrty_io;
   unsigned long ttl;
   adns_status st;
   
@@ -825,14 +841,9 @@ static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha,
                            pai->dgram, pai->dglen, dmstart, &ownermatched);
     if (st) return st;
     if (!ownermatched || class != DNS_CLASS_IN) continue;
-    for (j = 0; j < nrrty && type != (rrty[j] & adns_rrt_typemask); j++);
-    if (j >= nrrty) continue;
-    if (j < *nrrty_io) {
-      (*nrrty_io)--;
-      adns_rrtype t = rrty[j];
-      rrty[j] = rrty[*nrrty_io];
-      rrty[*nrrty_io] = t;
-    }
+    typef = addr_rrtypeflag(type);
+    if (!(want & typef)) continue;
+    want &= ~typef;
     if (!adns__vbuf_ensure(&pai->qu->vb, (naddrs+1)*addrsz)) R_NOMEM;
     adns__update_expires(pai->qu,ttl,pai->now);
     rdend = rdstart + rdlen;
@@ -848,11 +859,12 @@ static adns_status pap_findaddrs(const parseinfo *pai, adns_rr_hostaddr *ha,
     if (st) return st;
     ha->astatus= adns_s_ok;
 
-    if (!*nrrty_io) {
+    if (!want) {
       adns__isort(ha->addrs, naddrs, addrsz, pai->qu->vb.buf,
                  div_addr, pai->ads);
     }
   }
+  *want_io = want;
   return adns_s_ok;
 }
 
@@ -900,8 +912,7 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
   int id;
   adns_query nqu;
   adns_queryflags nflags;
-  adns_rrtype rrty[ADDR_MAXRRTYPES];
-  size_t nrrty;
+  unsigned want;
   size_t addrsz = gsz_addr(pai->qu->answer->type);
 
   dmstart= cbyte= *cbyte_io;
@@ -916,18 +927,15 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
 
   cbyte= pai->nsstart;
 
-  addr_rrtypes(pai->ads, pai->qu->answer->type,
-              pai->qu->flags, rrty, &nrrty);
+  want = addr_rrtypes(pai->ads, pai->qu->answer->type, pai->qu->flags);
 
-  st= pap_findaddrs(pai, rrp, rrty, &nrrty, addrsz,
-                   &cbyte, pai->nscount, dmstart);
+  st= pap_findaddrs(pai, rrp, &want, addrsz, &cbyte, pai->nscount, dmstart);
   if (st) return st;
-  if (!nrrty) return adns_s_ok;
+  if (!want) return adns_s_ok;
 
-  st= pap_findaddrs(pai, rrp, rrty, &nrrty, addrsz,
-                   &cbyte, pai->arcount, dmstart);
+  st= pap_findaddrs(pai, rrp, &want, addrsz, &cbyte, pai->arcount, dmstart);
   if (st) return st;
-  if (!nrrty) return adns_s_ok;
+  if (!want) return adns_s_ok;
 
   st= adns__mkquery_frdgram(pai->ads, &pai->qu->vb, &id,
                            pai->dgram, pai->dglen, dmstart,
@@ -941,7 +949,7 @@ static adns_status pap_hostaddr(const parseinfo *pai, int *cbyte_io,
   nflags= adns_qf_quoteok_query | (pai->qu->flags & adns__qf_afmask);
   if (!(pai->qu->flags & adns_qf_cname_loose)) nflags |= adns_qf_cname_forbid;
   
-  st= addr_submit(pai->qu, &nqu, &pai->qu->vb, id, rrty, nrrty,
+  st= addr_submit(pai->qu, &nqu, &pai->qu->vb, id, want,
                  nflags, pai->now, &ctx);
   if (st) return st;