Browse Source

[2429] added basic support for $TTL

JINMEI Tatuya 12 years ago
parent
commit
9fecf9fce1
2 changed files with 63 additions and 7 deletions
  1. 46 6
      src/lib/dns/master_loader.cc
  2. 17 1
      src/lib/dns/tests/master_loader_unittest.cc

+ 46 - 6
src/lib/dns/master_loader.cc

@@ -20,6 +20,8 @@
 #include <dns/rrtype.h>
 #include <dns/rdata.h>
 
+#include <boost/scoped_ptr.hpp>
+
 #include <string>
 #include <memory>
 #include <boost/algorithm/string/predicate.hpp> // for iequals
@@ -137,6 +139,30 @@ public:
         pushSource(filename);
     }
 
+    void setDefaultTTL(const string& ttl_txt) {
+        if (!default_ttl_) {
+            default_ttl_.reset(new RRTTL(ttl_txt));
+        }
+        //setCurrentTTL(*default_ttl_);
+    }
+
+    void setCurrentTTL(const RRTTL& ttl) {
+        if (!current_ttl_) {
+            current_ttl_.reset(new RRTTL(ttl));
+        } else {
+            *current_ttl_ = ttl;
+        }
+    }
+
+    bool setCurrentTTL(const string& ttl_txt) {
+        try {
+            setCurrentTTL(RRTTL(ttl_txt));
+            return (true);
+        } catch (const InvalidRRTTL&) {
+            return (false);
+        }
+    }
+
     void handleDirective(const char* directive, size_t length) {
         if (iequals(directive, "INCLUDE")) {
             doInclude();
@@ -145,9 +171,7 @@ public:
             isc_throw(isc::NotImplemented,
                       "Origin directive not implemented yet");
         } else if (iequals(directive, "TTL")) {
-            // TODO: Implement
-            isc_throw(isc::NotImplemented,
-                      "TTL directive not implemented yet");
+            setDefaultTTL(getString());
         } else {
             isc_throw(InternalException, "Unknown directive '" <<
                       string(directive, directive + length) << "'");
@@ -189,6 +213,8 @@ private:
     const RRClass zone_class_;
     MasterLoaderCallbacks callbacks_;
     AddRRCallback add_callback_;
+    boost::scoped_ptr<RRTTL> default_ttl_;
+    boost::scoped_ptr<RRTTL> current_ttl_;
     const MasterLoader::Options options_;
     const std::string master_file_;
     std::string string_token_;
@@ -260,10 +286,24 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
             // anything yet
 
             // The parameters
-            const RRTTL ttl(getString());
-            const RRClass rrclass(getString());
+            MasterToken rrparam_token = lexer_.getNextToken();
+            if (rrparam_token.getType() == MasterToken::STRING) {
+                // Try TTL
+                if (setCurrentTTL(rrparam_token.getString())) {
+                    rrparam_token = lexer_.getNextToken();
+                }
+            }
+
+            const RRClass rrclass(rrparam_token.getString());
             const RRType rrtype(getString());
 
+            // If the TTL is not yet determined, complete it.
+            if (!current_ttl_) {
+                if (default_ttl_) {
+                    setCurrentTTL(*default_ttl_);
+                } // TBD: else: try SOA min TTL for default, then error
+            }
+
             // TODO: Some more validation?
             if (rrclass != zone_class_) {
                 // It doesn't really matter much what type of exception
@@ -283,7 +323,7 @@ MasterLoader::MasterLoaderImpl::loadIncremental(size_t count_limit) {
             // callbacks_ already. We need to decide if we want to continue
             // or not.
             if (data) {
-                add_callback_(name, rrclass, rrtype, ttl, data);
+                add_callback_(name, rrclass, rrtype, *current_ttl_, data);
 
                 // Good, we loaded another one
                 ++count;

+ 17 - 1
src/lib/dns/tests/master_loader_unittest.cc

@@ -17,6 +17,7 @@
 #include <dns/rrtype.h>
 #include <dns/rrset.h>
 #include <dns/rrclass.h>
+#include <dns/rrttl.h>
 #include <dns/name.h>
 #include <dns/rdata.h>
 
@@ -102,7 +103,8 @@ public:
 
     // Check the next RR in the ones produced by the loader
     // Other than passed arguments are checked to be the default for the tests
-    void checkRR(const string& name, const RRType& type, const string& data) {
+    void checkRR(const string& name, const RRType& type, const string& data,
+                 const RRTTL& rrttl = RRTTL(3600)) {
         ASSERT_FALSE(rrsets_.empty());
         RRsetPtr current = rrsets_.front();
         rrsets_.pop_front();
@@ -110,6 +112,7 @@ public:
         EXPECT_EQ(Name(name), current->getName());
         EXPECT_EQ(type, current->getType());
         EXPECT_EQ(RRClass::IN(), current->getClass());
+        EXPECT_EQ(rrttl, current->getTTL());
         ASSERT_EQ(1, current->getRdataCount());
         EXPECT_EQ(0, isc::dns::rdata::createRdata(type, RRClass::IN(), data)->
                   compare(current->getRdataIterator()->getCurrent()));
@@ -377,6 +380,19 @@ TEST_F(MasterLoaderTest, includeWithGarbage) {
     checkRR("www.example.org", RRType::AAAA(), "2001:db8::1");
 }
 
+// Test for "$TTL"
+TEST_F(MasterLoaderTest, ttlDirective) {
+    // Set the default TTL with $TTL followed by an RR omitting the TTL
+    const string input("$TTL 1800\n"
+                       "example.org. IN A 192.0.2.1\n");
+    stringstream zone_stream(input);
+    setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+              MasterLoader::DEFAULT);
+    loader_->load();
+    EXPECT_TRUE(loader_->loadedSucessfully());
+    checkRR("example.org", RRType::A(), "192.0.2.1", RRTTL(1800));
+}
+
 // Test the constructor rejects empty add callback.
 TEST_F(MasterLoaderTest, emptyCallback) {
     EXPECT_THROW(MasterLoader(TEST_DATA_SRCDIR "/example.org",