# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: henrik@henriknordstrom.net-20120106203035-\
#   31rsk57yl1j7rniv
# target_branch: http://www.squid-cache.org/bzr/squid3/trunk/
# testament_sha1: 971ef9bbd003970f3447521922c7f7d30b9ebbe7
# timestamp: 2012-01-06 21:35:43 +0100
# base_revision_id: squid3@treenet.co.nz-20120105141204-\
#   wm58j1qdf5zuz6zz
# 
# Begin patch
=== modified file 'src/dns_internal.cc'
--- src/dns_internal.cc	2012-01-03 02:19:30 +0000
+++ src/dns_internal.cc	2012-01-06 20:30:35 +0000
@@ -127,11 +127,12 @@
     char name[NS_MAXDNAME + 1];
     char orig[NS_MAXDNAME + 1];
     ssize_t sz;
-    unsigned short msg_id; /// random query ID sent to server; changes with every query sent
+    unsigned short query_id; /// random query ID sent to server; changes with every query sent
     InstanceId<idns_query> xact_id; /// identifies our "transaction", stays constant when query is retried
 
     int nsends;
     int need_vc;
+    int pending;
 
     struct timeval start_t;
     struct timeval sent_t;
@@ -142,13 +143,12 @@
     int attempt;
     int rcode;
     idns_query *queue;
+    idns_query *slave;  // AAAA
+    idns_query *master; // A
     unsigned short domain;
     unsigned short do_searchpath;
-    bool need_A;
-    struct {
-        int count;
-        rfc1035_rr *answers;
-    } initial_AAAA;
+    rfc1035_message *message;
+    int ancount;
 };
 InstanceIdDefinitions(idns_query,  "dns");
 
@@ -249,6 +249,7 @@
 static void idnsRcodeCount(int, int);
 static CLCB idnsVCClosed;
 static unsigned short idnsQueryID(void);
+static void idnsSendSlaveAAAAQuery(idns_query *q);
 
 static void
 idnsAddNameserver(const char *buf)
@@ -670,7 +671,7 @@
     for (n = lru_list.head; n; n = n->next) {
         q = (idns_query *)n->data;
         storeAppendPrintf(sentry, "%#06x %4d %5d %10.3f %9.3f\n",
-                          (int) q->msg_id, (int) q->sz, q->nsends,
+                          (int) q->query_id, (int) q->sz, q->nsends,
                           tvSubDsec(q->start_t, current_time),
                           tvSubDsec(q->sent_t, current_time));
     }
@@ -906,8 +907,6 @@
     int ns;
 
     q->start_t = current_time;
-    q->msg_id = idnsQueryID();
-    rfc1035SetQueryID(q->buf, q->msg_id);
 
     do {
         ns = q->nsends % nns;
@@ -918,7 +917,7 @@
         } else {
             if (DnsSocketB >= 0 && nameservers[ns].S.IsIPv6())
                 y = comm_udp_sendto(DnsSocketB, nameservers[ns].S, q->buf, q->sz);
-            else if (DnsSocketA)
+            else if (DnsSocketA >= 0)
                 x = comm_udp_sendto(DnsSocketA, nameservers[ns].S, q->buf, q->sz);
         }
 
@@ -943,6 +942,7 @@
     nameservers[ns].nqueries++;
     q->queue_t = current_time;
     dlinkAdd(q, &q->lru, &lru_list);
+    q->pending = 1;
     idnsTickleQueue();
 }
 
@@ -973,7 +973,7 @@
     for (n = lru_list.tail; n; n = n->prev) {
         q = (idns_query*)n->data;
 
-        if (q->msg_id == id)
+        if (q->query_id == id)
             return q;
     }
 
@@ -1028,16 +1028,6 @@
     }
 }
 
-void
-idnsDropMessage(rfc1035_message *message, idns_query *q)
-{
-    rfc1035MessageDestroy(&message);
-    if (q->hash.key) {
-        hash_remove_link(idns_lookup_hash, &q->hash);
-        q->hash.key = NULL;
-    }
-}
-
 static void
 idnsGrokReply(const char *buf, size_t sz, int from_ns)
 {
@@ -1092,9 +1082,11 @@
     }
 #endif
 
+    dlinkDelete(&q->lru, &lru_list);
+    q->pending = 0;
+
     if (message->tc) {
         debugs(78, 3, HERE << "Resolver requested TC (" << q->query.name << ")");
-        dlinkDelete(&q->lru, &lru_list);
         rfc1035MessageDestroy(&message);
 
         if (!q->need_vc) {
@@ -1112,7 +1104,6 @@
         return;
     }
 
-    dlinkDelete(&q->lru, &lru_list);
     idnsRcodeCount(n, q->attempt);
 
     if (n < 0) {
@@ -1131,7 +1122,7 @@
             return;
         }
 
-        if (q->rcode == 3 && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
+        if (q->rcode == 3 && !q->master && q->do_searchpath && q->attempt < MAX_ATTEMPT) {
             assert(NULL == message->answer);
             strcpy(q->name, q->orig);
 
@@ -1146,17 +1137,21 @@
                 q->attempt++;
             }
 
-            idnsDropMessage(message, q);
+            rfc1035MessageDestroy(&message);
 
-            if (Ip::EnableIpv6 && q->query.qtype == RFC1035_TYPE_AAAA) {
-                debugs(78, 3, "idnsGrokReply: Trying AAAA Query for " << q->name);
-                q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, Config.dns.packet_max);
-            } else {
-                debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
-                // see EDNS notes at top of file why this sends 0
-                q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
+            // cleanup stale AAAA query
+            while (idns_query *slave = q->slave) {
+                dlinkDelete(&slave->lru, &lru_list);
+                q->slave = slave->slave;
+                rfc1035MessageDestroy(&slave->message);
+                cbdataFree(slave);
             }
-
+            
+            // Build new query
+            q->query_id = idnsQueryID();
+            debugs(78, 3, "idnsGrokReply: Trying A Query for " << q->name);
+            // see EDNS notes at top of file why this sends 0
+            q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
             if (q->sz < 0) {
                 /* problem with query data -- query not sent */
                 idnsCallback(static_cast<idns_query *>(q->callback_data), NULL, 0, "Internal error");
@@ -1164,94 +1159,62 @@
                 return;
             }
 
-            idnsCacheQuery(q);
             idnsSendQuery(q);
-            return;
-        }
-    }
-
-    if (q->need_A && (Config.onoff.dns_require_A == 1 || n <= 0 ) ) {
-        /* ERROR or NO AAAA exist. Failover to A records. */
-        /*      Apparently its also a good idea to lookup and store the A records
-         *      just in case the AAAA are not available when we need them.
-         *      This could occur due to number of network failings beyond our control
-         *      thus the || above allowing the user to request always both.
-         */
-
-        if (n == 0)
-            debugs(78, 3, "idnsGrokReply: " << q->name << " has no AAAA records. Looking up A record instead.");
-        else if (q->need_A && n <= 0)
-            debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query failed. Trying A now instead.");
-        else // admin requested this.
-            debugs(78, 3, "idnsGrokReply: " << q->name << " AAAA query done. Configured to retrieve A now also.");
-
-        // move the initial message results into the failover query for merging later.
-        if (n > 0) {
-            q->initial_AAAA.count = message->ancount;
-            q->initial_AAAA.answers = message->answer;
-            message->answer = NULL;
-        }
-
-        // remove the hashed query info
-        idnsDropMessage(message, q);
-
-        // reset the query as an A query
-        q->nsends = 0;
-        // see EDNS notes at top of file why this sends 0
-        q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
-        q->need_A = false;
-
-        if (q->sz < 0) {
-            /* problem with query data -- query not sent */
-            idnsCallback(static_cast<idns_query *>(q->callback_data), NULL, 0, "Internal error");
-            cbdataFree(q);
-            return;
-        }
-
-        idnsCacheQuery(q);
-        idnsSendQuery(q);
-        return;
-    }
-
-    /** If there are two result sets from preceeding AAAA and A lookups merge them with a preference for AAAA */
-    if (q->initial_AAAA.count > 0 && n > 0) {
-        /* two sets of RR need merging */
-        rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q->initial_AAAA.count) );
-        rfc1035_rr *tmp = result;
-
-        debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
-
-        if (Config.dns.v4_first) {
-            memcpy( tmp, message->answer, (sizeof(rfc1035_rr)*n) );
-            tmp += n;
-            /* free the RR object without freeing its child strings (they are now taken by the copy above) */
-            safe_free(message->answer);
-        }
-
-        memcpy(tmp, q->initial_AAAA.answers, (sizeof(rfc1035_rr)*(q->initial_AAAA.count)) );
-        tmp += q->initial_AAAA.count;
-        /* free the RR object without freeing its child strings (they are now taken by the copy above) */
-        safe_free(q->initial_AAAA.answers);
-
-        if (!Config.dns.v4_first) {
-            memcpy( tmp, message->answer, (sizeof(rfc1035_rr)*n) );
-            /* free the RR object without freeing its child strings (they are now taken by the copy above) */
-            safe_free(message->answer);
-        }
-
-        n += q->initial_AAAA.count;
-        q->initial_AAAA.count = 0;
-        message->answer = result;
-        message->ancount = n;
-    } else if (q->initial_AAAA.count > 0 && n <= 0) {
-        /* initial of dual queries was the only result set. */
-        debugs(78, 6, HERE << "Merging DNS results " << q->name << " AAAA has " << q->initial_AAAA.count << " RR, A has " << n << " RR");
-        rfc1035RRDestroy(&(message->answer), n);
-        message->answer = q->initial_AAAA.answers;
-        n = q->initial_AAAA.count;
-        message->ancount = n;
-    }
-    /* else initial results were empty. just use the final set as authoritative */
+            if (Ip::EnableIpv6)
+                idnsSendSlaveAAAAQuery(q);
+            return;
+        }
+    }
+
+    q->message = message;
+    q->ancount = n;
+
+    if (q->master)
+        q = q->master;
+
+    idns_query *q2;
+    // If any of our subqueries are still pending then wait for them to complete before continuing
+    for ( q2 = q; q2; q2 = q2->slave) {
+        if (q2->pending) {
+            return;
+        }
+    }
+
+    /* Merge results */
+    message = q->message;
+    n = q->ancount;
+    
+    while ( (q2 = q->slave) ) {
+        debugs(78, 6, HERE << "Merging DNS results " << q->name << " A has " << n << " RR, AAAA has " << q2->ancount << " RR");
+        q->slave = q2->slave;
+        if ( q2->ancount >= 0 ) {
+            if (n > 0 ) {
+                // two sets of RR need merging
+                rfc1035_rr *result = (rfc1035_rr*) xmalloc( sizeof(rfc1035_rr)*(n + q2->ancount) );
+                if (Config.dns.v4_first) {
+                    memcpy(result, message->answer, (sizeof(rfc1035_rr)*n) );
+                    memcpy(result+n, q2->message->answer, (sizeof(rfc1035_rr)*q2->ancount) );
+                } else {
+                    memcpy(result, q2->message->answer, (sizeof(rfc1035_rr)*q2->ancount) );
+                    memcpy(result+q2->ancount, message->answer, (sizeof(rfc1035_rr)*n) );
+                }
+                n += q2->ancount;
+                safe_free(message->answer);
+                message->answer = result;
+                message->ancount += q2->message->ancount;
+                safe_free(q2->message->answer);
+                q2->message->answer = NULL;
+            } else if (n < 0 || q2->ancount > 0) {
+                // first set empty / failed
+                rfc1035MessageDestroy(&message);
+                message = q->message = q2->message;
+                q2->message = NULL;
+                n = q2->ancount;
+            }
+        }
+        rfc1035MessageDestroy(&q2->message);
+        cbdataFree(q2);
+    }
 
     debugs(78, 6, HERE << "Sending " << n << " DNS results to caller.");
     idnsCallback(q, message->answer, n, rfc1035ErrorMessage(n));
@@ -1375,7 +1338,7 @@
 
         debugs(78, 3, "idnsCheckQueue: ID " << q->xact_id <<
                " QID 0x"  << std::hex << std::setfill('0')  <<
-               std::setw(4) << q->msg_id << ": timeout" );
+               std::setw(4) << q->query_id << ": timeout" );
 
         dlinkDelete(&q->lru, &lru_list);
 
@@ -1383,7 +1346,7 @@
             idnsSendQuery(q);
         } else {
             debugs(78, 2, "idnsCheckQueue: ID " << q->xact_id <<
-                   " QID 0x" << std::hex << q->msg_id <<
+                   " QID 0x" << std::hex << q->query_id <<
                    " : giving up after " << std::dec << q->nsends << " tries and " <<
                    std::setw(5)<< std::setprecision(2) << tvSubDsec(q->start_t, current_time) << " seconds");
 
@@ -1500,30 +1463,30 @@
     CBDATA_INIT_TYPE(idns_query);
 
     if (DnsSocketA < 0 && DnsSocketB < 0) {
-        Ip::Address addrA; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
+        Ip::Address addrV6; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own.
 
         if (!Config.Addrs.udp_outgoing.IsNoAddr())
-            addrA = Config.Addrs.udp_outgoing;
+            addrV6 = Config.Addrs.udp_outgoing;
         else
-            addrA = Config.Addrs.udp_incoming;
-
-        Ip::Address addrB = addrA;
-        addrA.SetIPv4();
-
-        if (Ip::EnableIpv6 && addrB.IsIPv6()) {
-            debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrB);
+            addrV6 = Config.Addrs.udp_incoming;
+
+        Ip::Address addrV4 = addrV6;
+        addrV4.SetIPv4();
+
+        if (Ip::EnableIpv6 && addrV6.IsIPv6()) {
+            debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV6);
             DnsSocketB = comm_open_listener(SOCK_DGRAM,
                                             IPPROTO_UDP,
-                                            addrB,
+                                            addrV6,
                                             COMM_NONBLOCKING,
                                             "DNS Socket IPv6");
         }
 
-        if (addrA.IsIPv4()) {
-            debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrA);
+        if (addrV4.IsIPv4()) {
+            debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addrV4);
             DnsSocketA = comm_open_listener(SOCK_DGRAM,
                                             IPPROTO_UDP,
-                                            addrA,
+                                            addrV4,
                                             COMM_NONBLOCKING,
                                             "DNS Socket IPv4");
         }
@@ -1536,12 +1499,12 @@
          */
         if (DnsSocketB >= 0) {
             comm_local_port(DnsSocketB);
-            debugs(78, 1, "DNS Socket created at " << addrB << ", FD " << DnsSocketB);
+            debugs(78, 1, "DNS Socket created at " << addrV6 << ", FD " << DnsSocketB);
             Comm::SetSelect(DnsSocketB, COMM_SELECT_READ, idnsRead, NULL, 0);
         }
         if (DnsSocketA >= 0) {
             comm_local_port(DnsSocketA);
-            debugs(78, 1, "DNS Socket created at " << addrA << ", FD " << DnsSocketA);
+            debugs(78, 1, "DNS Socket created at " << addrV4 << ", FD " << DnsSocketA);
             Comm::SetSelect(DnsSocketA, COMM_SELECT_READ, idnsRead, NULL, 0);
         }
     }
@@ -1629,6 +1592,7 @@
     q = cbdataAlloc(idns_query);
     // idns_query is POD so no constructors are called after allocation
     q->xact_id.change();
+    // no query_id on this instance.
 
     q->callback = callback;
 
@@ -1644,10 +1608,31 @@
 static void
 idnsCacheQuery(idns_query *q)
 {
-    q->hash.key = q->query.name;
+    q->hash.key = q->orig;
     hash_join(idns_lookup_hash, &q->hash);
 }
 
+static void
+idnsSendSlaveAAAAQuery(idns_query *master)
+{
+    idns_query *q = cbdataAlloc(idns_query);
+    memcpy(q->name, master->name, sizeof(q->name));
+    memcpy(q->orig, master->orig, sizeof(q->orig));
+    q->master = master;
+    q->query_id = idnsQueryID();
+    q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max);
+    q->slave = master->slave;
+    
+    debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
+           ", id = 0x" << std::hex << q->query_id);
+    if (!q->sz) {
+        cbdataFree(q);
+        return;
+    }
+    master->slave = q;
+    idnsSendQuery(q);
+}
+
 void
 idnsALookup(const char *name, IDNSCB * callback, void *data)
 {
@@ -1661,6 +1646,7 @@
     q = cbdataAlloc(idns_query);
     // idns_query is POD so no constructors are called after allocation
     q->xact_id.change();
+    q->query_id = idnsQueryID();
 
     for (i = 0; i < strlen(name); i++)
         if (name[i] == '.')
@@ -1682,14 +1668,8 @@
         debugs(78, 3, "idnsALookup: searchpath used for " << q->name);
     }
 
-    if (Ip::EnableIpv6) {
-        q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, Config.dns.packet_max);
-        q->need_A = true;
-    } else {
-        // see EDNS notes at top of file why this sends 0
-        q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), 0, &q->query, 0);
-        q->need_A = false;
-    }
+    // see EDNS notes at top of file why this sends 0
+    q->sz = rfc3596BuildAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, 0);
 
     if (q->sz < 0) {
         /* problem with query data -- query not sent */
@@ -1699,13 +1679,17 @@
     }
 
     debugs(78, 3, "idnsALookup: buf is " << q->sz << " bytes for " << q->name <<
-           ", id = 0x" << std::hex << q->msg_id);
+           ", id = 0x" << std::hex << q->query_id);
 
     q->callback = callback;
     q->callback_data = cbdataReference(data);
 
     idnsCacheQuery(q);
     idnsSendQuery(q);
+
+    if (Ip::EnableIpv6)
+        idnsSendSlaveAAAAQuery(q);
+
 }
 
 void
@@ -1721,6 +1705,7 @@
 
     // idns_query is POD so no constructors are called after allocation
     q->xact_id.change();
+    q->query_id = idnsQueryID();
 
     if (addr.IsIPv6()) {
         struct in6_addr addr6;
@@ -1733,9 +1718,6 @@
         q->sz = rfc3596BuildPTRQuery4(addr4, q->buf, sizeof(q->buf), 0, &q->query, 0);
     }
 
-    /* PTR does not do inbound A/AAAA */
-    q->need_A = false;
-
     if (q->sz < 0) {
         /* problem with query data -- query not sent */
         callback(data, NULL, 0, "Internal error");
@@ -1749,7 +1731,7 @@
     }
 
     debugs(78, 3, "idnsPTRLookup: buf is " << q->sz << " bytes for " << ip <<
-           ", id = 0x" << std::hex << q->msg_id);
+           ", id = 0x" << std::hex << q->query_id);
 
     q->callback = callback;
     q->callback_data = cbdataReference(data);

# Begin bundle
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

