Browse Source

Merge branch 'trac1839'

Mukund Sivaraman 11 years ago
parent
commit
e303832140
2 changed files with 93 additions and 34 deletions
  1. 75 19
      src/lib/dns/rrset.cc
  2. 18 15
      src/lib/dns/tests/rrset_unittest.cc

+ 75 - 19
src/lib/dns/rrset.cc

@@ -17,6 +17,7 @@
 #include <vector>
 #include <vector>
 
 
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/foreach.hpp>
 
 
 #include <util/buffer.h>
 #include <util/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/messagerenderer.h>
@@ -71,7 +72,10 @@ AbstractRRset::toText() const {
     return (s);
     return (s);
 }
 }
 
 
-namespace {
+namespace { // unnamed namespace
+
+// FIXME: This method's code should somehow be unified with
+// BasicRRsetImpl::toWire() below to avoid duplication.
 template <typename T>
 template <typename T>
 inline unsigned int
 inline unsigned int
 rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) {
 rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) {
@@ -124,7 +128,8 @@ rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) {
 
 
     return (n);
     return (n);
 }
 }
-}
+
+} // end of unnamed namespace
 
 
 unsigned int
 unsigned int
 AbstractRRset::toWire(OutputBuffer& buffer) const {
 AbstractRRset::toWire(OutputBuffer& buffer) const {
@@ -164,6 +169,9 @@ public:
     BasicRRsetImpl(const Name& name, const RRClass& rrclass,
     BasicRRsetImpl(const Name& name, const RRClass& rrclass,
                    const RRType& rrtype, const RRTTL& ttl) :
                    const RRType& rrtype, const RRTTL& ttl) :
         name_(name), rrclass_(rrclass), rrtype_(rrtype), ttl_(ttl) {}
         name_(name), rrclass_(rrclass), rrtype_(rrtype), ttl_(ttl) {}
+
+    unsigned int toWire(AbstractMessageRenderer& renderer, size_t limit) const;
+
     Name name_;
     Name name_;
     RRClass rrclass_;
     RRClass rrclass_;
     RRType rrtype_;
     RRType rrtype_;
@@ -174,6 +182,58 @@ public:
     vector<ConstRdataPtr> rdatalist_;
     vector<ConstRdataPtr> rdatalist_;
 };
 };
 
 
+// FIXME: This method's code should somehow be unified with
+// rrsetToWire() above to avoid duplication.
+unsigned int
+BasicRRsetImpl::toWire(AbstractMessageRenderer& renderer, size_t limit) const {
+    if (rdatalist_.empty()) {
+        // empty rrsets are only allowed for classes ANY and NONE
+        if (rrclass_ != RRClass::ANY() &&
+            rrclass_ != RRClass::NONE()) {
+            isc_throw(EmptyRRset, "toWire() is attempted for an empty RRset");
+        }
+
+        // For an empty RRset, write the name, type, class and TTL once,
+        // followed by empty rdata.
+        name_.toWire(renderer);
+        rrtype_.toWire(renderer);
+        rrclass_.toWire(renderer);
+        ttl_.toWire(renderer);
+        renderer.writeUint16(0);
+        // Still counts as 1 'rr'; it does show up in the message
+        return (1);
+    }
+
+    unsigned int n = 0;
+
+    // sort the set of Rdata based on rrset-order and sortlist, and possible
+    // other options.  Details to be considered.
+    BOOST_FOREACH(const ConstRdataPtr& rdata, rdatalist_) {
+        const size_t pos0 = renderer.getLength();
+        assert(pos0 < 65536);
+
+        name_.toWire(renderer);
+        rrtype_.toWire(renderer);
+        rrclass_.toWire(renderer);
+        ttl_.toWire(renderer);
+
+        const size_t pos = renderer.getLength();
+        renderer.skip(sizeof(uint16_t)); // leave the space for RDLENGTH
+        rdata->toWire(renderer);
+        renderer.writeUint16At(renderer.getLength() - pos - sizeof(uint16_t),
+                               pos);
+
+        if (limit > 0 && renderer.getLength() > limit) {
+            // truncation is needed
+            renderer.trim(renderer.getLength() - pos0);
+            return (n);
+        }
+        ++n;
+    }
+
+    return (n);
+}
+
 BasicRRset::BasicRRset(const Name& name, const RRClass& rrclass,
 BasicRRset::BasicRRset(const Name& name, const RRClass& rrclass,
                        const RRType& rrtype, const RRTTL& ttl)
                        const RRType& rrtype, const RRTTL& ttl)
 {
 {
@@ -236,7 +296,12 @@ BasicRRset::toWire(OutputBuffer& buffer) const {
 
 
 unsigned int
 unsigned int
 BasicRRset::toWire(AbstractMessageRenderer& renderer) const {
 BasicRRset::toWire(AbstractMessageRenderer& renderer) const {
-    return (AbstractRRset::toWire(renderer));
+    const unsigned int rrs_written = impl_->toWire(renderer,
+                                                   renderer.getLengthLimit());
+    if (impl_->rdatalist_.size() > rrs_written) {
+        renderer.setTruncated();
+    }
+    return (rrs_written);
 }
 }
 
 
 RRset::RRset(const Name& name, const RRClass& rrclass,
 RRset::RRset(const Name& name, const RRClass& rrclass,
@@ -259,15 +324,13 @@ RRset::getRRsigDataCount() const {
 
 
 unsigned int
 unsigned int
 RRset::toWire(OutputBuffer& buffer) const {
 RRset::toWire(OutputBuffer& buffer) const {
-    unsigned int rrs_written;
-
-    rrs_written = rrsetToWire<OutputBuffer>(*this, buffer, 0);
+    unsigned int rrs_written = BasicRRset::toWire(buffer);
     if (getRdataCount() > rrs_written) {
     if (getRdataCount() > rrs_written) {
         return (rrs_written);
         return (rrs_written);
     }
     }
 
 
     if (rrsig_) {
     if (rrsig_) {
-        rrs_written += rrsetToWire<OutputBuffer>(*(rrsig_.get()), buffer, 0);
+        rrs_written += rrsig_->toWire(buffer);
     }
     }
 
 
     return (rrs_written);
     return (rrs_written);
@@ -275,24 +338,17 @@ RRset::toWire(OutputBuffer& buffer) const {
 
 
 unsigned int
 unsigned int
 RRset::toWire(AbstractMessageRenderer& renderer) const {
 RRset::toWire(AbstractMessageRenderer& renderer) const {
-    unsigned int rrs_written;
-
-    rrs_written =
-        rrsetToWire<AbstractMessageRenderer>(*this, renderer,
-                                             renderer.getLengthLimit());
+    unsigned int rrs_written = BasicRRset::toWire(renderer);
     if (getRdataCount() > rrs_written) {
     if (getRdataCount() > rrs_written) {
-        renderer.setTruncated();
         return (rrs_written);
         return (rrs_written);
     }
     }
 
 
     if (rrsig_) {
     if (rrsig_) {
-        rrs_written +=
-            rrsetToWire<AbstractMessageRenderer>(*(rrsig_.get()), renderer,
-                                                 renderer.getLengthLimit());
-    }
+        rrs_written += rrsig_->toWire(renderer);
 
 
-    if (getRdataCount() + getRRsigDataCount() > rrs_written) {
-        renderer.setTruncated();
+        if (getRdataCount() + getRRsigDataCount() > rrs_written) {
+            renderer.setTruncated();
+        }
     }
     }
 
 
     return (rrs_written);
     return (rrs_written);

+ 18 - 15
src/lib/dns/tests/rrset_unittest.cc

@@ -211,11 +211,13 @@ TEST_F(RRsetTest, toWireBuffer) {
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
                         buffer.getLength(), &wiredata[0], wiredata.size());
                         buffer.getLength(), &wiredata[0], wiredata.size());
 
 
-    // toWire() cannot be performed for an empty RRset.
+    // toWire() cannot be performed for an empty RRset except when
+    // class=ANY or class=NONE.
     buffer.clear();
     buffer.clear();
     EXPECT_THROW(rrset_a_empty.toWire(buffer), EmptyRRset);
     EXPECT_THROW(rrset_a_empty.toWire(buffer), EmptyRRset);
 
 
-    // Unless it is type ANY or None
+    // When class=ANY or class=NONE, toWire() can also be performed for
+    // an empty RRset.
     buffer.clear();
     buffer.clear();
     rrset_any_a_empty.toWire(buffer);
     rrset_any_a_empty.toWire(buffer);
     wiredata.clear();
     wiredata.clear();
@@ -240,25 +242,26 @@ TEST_F(RRsetTest, toWireRenderer) {
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
                         renderer.getLength(), &wiredata[0], wiredata.size());
                         renderer.getLength(), &wiredata[0], wiredata.size());
 
 
-    // toWire() cannot be performed for an empty RRset.
-    buffer.clear();
-    EXPECT_THROW(rrset_a_empty.toWire(buffer), EmptyRRset);
+    // toWire() cannot be performed for an empty RRset except when
+    // class=ANY or class=NONE.
+    renderer.clear();
+    EXPECT_THROW(rrset_a_empty.toWire(renderer), EmptyRRset);
 
 
-    // Unless it is type ANY or None
-    // toWire() can also be performed for an empty RRset.
-    buffer.clear();
-    rrset_any_a_empty.toWire(buffer);
+    // When class=ANY or class=NONE, toWire() can also be performed for
+    // an empty RRset.
+    renderer.clear();
+    rrset_any_a_empty.toWire(renderer);
     wiredata.clear();
     wiredata.clear();
     UnitTestUtil::readWireData("rrset_toWire3", wiredata);
     UnitTestUtil::readWireData("rrset_toWire3", wiredata);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
-                        buffer.getLength(), &wiredata[0], wiredata.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &wiredata[0], wiredata.size());
 
 
-    buffer.clear();
-    rrset_none_a_empty.toWire(buffer);
+    renderer.clear();
+    rrset_none_a_empty.toWire(renderer);
     wiredata.clear();
     wiredata.clear();
     UnitTestUtil::readWireData("rrset_toWire4", wiredata);
     UnitTestUtil::readWireData("rrset_toWire4", wiredata);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
-                        buffer.getLength(), &wiredata[0], wiredata.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &wiredata[0], wiredata.size());
 }
 }
 
 
 // test operator<<.  We simply confirm it appends the result of toText().
 // test operator<<.  We simply confirm it appends the result of toText().