Browse Source

NSAS answers at last some queries

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac408@3540 e5f2f494-b856-4b98-b285-d166d9295462
Michal Vaner 14 years ago
parent
commit
76f00404a9

+ 30 - 3
src/lib/nsas/nameserver_address_store.cc

@@ -14,8 +14,10 @@
 
 // $Id$
 
+#include <boost/thread.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/foreach.hpp>
+#include <boost/random.hpp>
 
 #include <config.h>
 #include <dns/rdataclass.h>
@@ -45,7 +47,8 @@ NameserverAddressStore::NameserverAddressStore(ResolverInterface& resolver,
     zone_lru_((3 * zonehashsize), new HashDeleter<ZoneEntry>(zone_hash_)),
     nameserver_lru_((3 * nshashsize), new HashDeleter<NameserverEntry>(
         nameserver_hash_)),
-    resolver_(resolver)
+    resolver_(resolver),
+    callback_(*this)
 {
 }
 
@@ -89,7 +92,7 @@ newZone(const std::string* zone, uint16_t class_code,
     if (authority->getName() != Name(*zone)) {
         isc_throw(InconsistentZone,
             "Authority section is for different zone, expected: " <<
-            zone << ", got: " << authority->getName().toText());
+            *zone << ", got: " << authority->getName().toText());
     }
     if (authority->getType() != RRType::NS()) {
         isc_throw(NotNS, "Authority section with non-NS RR type: " <<
@@ -141,6 +144,21 @@ NameserverAddressStore::lookup(const std::string& zone, uint16_t class_code,
 
 namespace {
 
+mutex randMutex;
+
+size_t
+randIndex(size_t count) {
+    // We need to lock the global generator
+    // TODO If there's contention locking, we might want a generator
+    // for each thread?
+    mutex::scoped_lock lock(randMutex);
+    // This seems to be enough to use pseudo-random generator and according
+    // to boost docs, this one is fast.
+    static rand48 generator;
+    return variate_generator<rand48&, uniform_int<size_t> >(generator,
+        uniform_int<size_t>(0, count - 1))();
+}
+
 asiolink::IOAddress
 chooseAddress(const NameserverEntry::AddressVector& addresses) {
     // TODO Something little bit more inteligent than just picking the first
@@ -184,6 +202,7 @@ void NameserverAddressStore::processZone(ZonePtr zone) {
                         break;
                     case Fetchable::IN_PROGRESS:
                         pending = true;
+                        ns->ensureHasCallback(zone, callback_);
                         break;
                     case Fetchable::UNREACHABLE:
                         // Nothing. We do not care about it.
@@ -200,7 +219,15 @@ void NameserverAddressStore::processZone(ZonePtr zone) {
             zone->setState(Fetchable::UNREACHABLE);
         }
 
-        // TODO Pick up to two not_asked ones and ask them
+        // Pick up to two nameservers and try to resolve them
+        // TODO Any better way to choose one?
+        for (int i(0); i < 2 && !not_asked.empty(); ++ i) {
+            size_t index(randIndex(not_asked.size()));
+            not_asked[index]->askIP(resolver_, zone, callback_,
+                not_asked[index]);
+            // Remove from the vector so we do not choose it again
+            not_asked.erase(not_asked.begin() + index);
+        }
 
         state = zone->getState();
     } // Release the lock (and some other resources as a bonus)

+ 13 - 0
src/lib/nsas/nameserver_address_store.h

@@ -141,6 +141,19 @@ private:
      * \todo Pass some of the referral stuff there?
      */
     void processZone(boost::shared_ptr<ZoneEntry> zone);
+    /// \short Callback from nameserver entry to process zone.
+    class Callback : public NameserverEntry::Callback {
+        public:
+            Callback(NameserverAddressStore& store) :
+                store_(store)
+            { }
+            virtual void operator()(boost::shared_ptr<ZoneEntry> zone) {
+                store_.processZone(zone);
+            }
+        private:
+            NameserverAddressStore& store_;
+    } callback_;
+    friend class Callback;
 };
 
 } // namespace nsas

+ 4 - 2
src/lib/nsas/tests/nameserver_address_store_unittest.cc

@@ -211,7 +211,7 @@ TEST_F(NameserverAddressStoreTest, emptyLookup) {
         vector<AbstractRRset>(), getCallback());
     // It should ask for IP addresses for example.com.
     ASSERT_EQ(2, defaultTestResolver.requests.size());
-    defaultTestResolver.asksIPs(Name("example.com."), 0, 1);
+    defaultTestResolver.asksIPs(Name("ns.example.com."), 0, 1);
 
     // Ask another question for the same zone
     nsas.lookup("example.net.", RRClass::IN().getCode(), *authority_,
@@ -274,7 +274,7 @@ TEST_F(NameserverAddressStoreTest, unreachableNS) {
         vector<AbstractRRset>(), getCallback());
     // It should ask for IP addresses for example.com.
     ASSERT_EQ(2, defaultTestResolver.requests.size());
-    defaultTestResolver.asksIPs(Name("example.com."), 0, 1);
+    defaultTestResolver.asksIPs(Name("ns.example.com."), 0, 1);
 
     // Ask another question with different zone but the same nameserver
     authority_->setName(Name("example.com."));
@@ -291,8 +291,10 @@ TEST_F(NameserverAddressStoreTest, unreachableNS) {
     EXPECT_EQ(2, NSASCallback::results.size());
     // When we ask one same and one other zone with the same nameserver,
     // it should generate no questions and answer right away
+    authority_->setName(Name("example.net."));
     nsas.lookup("example.net.", RRClass::IN().getCode(), *authority_,
         vector<AbstractRRset>(), getCallback());
+    authority_->setName(Name("example.org."));
     nsas.lookup("example.org.", RRClass::IN().getCode(), *authority_,
         vector<AbstractRRset>(), getCallback());
     // There should be 4 negative answers now