Browse Source

[2098] supported toWire for renderer, still skipping some advanced cases.

JINMEI Tatuya 12 years ago
parent
commit
0e19763b34

+ 106 - 13
src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc

@@ -12,12 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <util/buffer.h>
 #include <util/memory_segment_local.h>
 
 #include <datasrc/memory/treenode_rrset.h>
 #include <datasrc/memory/rdataset.h>
 #include <datasrc/memory/rdata_serialization.h>
 
+#include <util/unittests/wiredata.h>
 #include <testutils/dnsmessage_test.h>
 
 #include <gtest/gtest.h>
@@ -26,23 +28,42 @@ using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::datasrc::memory;
 using namespace isc::testutils;
+using isc::util::unittests::matchWireData;
+using isc::util::OutputBuffer;
 
 namespace {
 
 class TreeNodeRRsetTest : public ::testing::Test {
 protected:
     TreeNodeRRsetTest() :
-        name_("www.example.com"),
+        rrclass_(RRClass::IN()),
+        origin_name_("example.com"), www_name_("www.example.com"),
+        ns_rrset_(textToRRset("example.com. 3600 IN NS ns.example.com.")),
         a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1")),
+        dname_rrset_(textToRRset("example.com. 3600 IN DNAME d.example.org.")),
         rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG "
                                  "A 5 2 3600 20120814220826 20120715220826 "
-                                 "1234 example.com. FAKE"))
-    {
+                                 "1234 example.com. FAKE")),
+        tree_(NULL)
+    {}
+    void SetUp() {
+        // We create some common test data here in SetUp() so it will be
+        // as exception safe as possible.
+
         tree_ = ZoneTree::create(mem_sgmt_, true);
-        tree_->insert(mem_sgmt_, name_, &zone_node_);
-        rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
-                                     rrsig_rrset_);
-        zone_node_->setData(mem_sgmt_, rdataset_);
+
+        tree_->insert(mem_sgmt_, origin_name_, &origin_node_);
+        ns_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, ns_rrset_,
+                                        ConstRRsetPtr());
+        origin_node_->setData(mem_sgmt_, ns_rdataset_);
+        dname_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, dname_rrset_,
+                                           ConstRRsetPtr());
+        ns_rdataset_->next = dname_rdataset_;
+
+        tree_->insert(mem_sgmt_, www_name_, &www_node_);
+        a_rdataset_ = RdataSet::create(mem_sgmt_, encoder_, a_rrset_,
+                                       rrsig_rrset_);
+        www_node_->setData(mem_sgmt_, a_rdataset_);
     }
     void TearDown() {
         ZoneTree::destroy(mem_sgmt_, tree_);
@@ -50,25 +71,97 @@ protected:
         EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
     }
 
-    const Name name_;
+    const RRClass rrclass_;
+    const Name origin_name_, www_name_;
     isc::util::MemorySegmentLocal mem_sgmt_;
     RdataEncoder encoder_;
-    ConstRRsetPtr a_rrset_, rrsig_rrset_;
+    MessageRenderer renderer_, renderer_expected_;
+    ConstRRsetPtr ns_rrset_, a_rrset_, dname_rrset_, rrsig_rrset_;
     ZoneTree* tree_;
-    ZoneNode* zone_node_;
-    RdataSet* rdataset_;
+    ZoneNode* origin_node_;
+    ZoneNode* www_node_;
+    RdataSet* ns_rdataset_;
+    RdataSet* dname_rdataset_;
+    RdataSet* a_rdataset_;
 };
 
 TEST_F(TreeNodeRRsetTest, create) {
-    const TreeNodeRRset rrset1(RRClass::IN(), zone_node_, rdataset_, true);
+    const TreeNodeRRset rrset1(RRClass::IN(), www_node_, a_rdataset_, true);
     EXPECT_EQ(RRClass::IN(), rrset1.getClass());
     EXPECT_EQ(RRType::A(), rrset1.getType());
     EXPECT_EQ(1, rrset1.getRdataCount());
     EXPECT_EQ(1, rrset1.getRRsigDataCount());
 
-    const TreeNodeRRset rrset2(RRClass::IN(), zone_node_, rdataset_, false);
+    const TreeNodeRRset rrset2(RRClass::IN(), www_node_, a_rdataset_, false);
     EXPECT_EQ(RRClass::IN(), rrset2.getClass());
     EXPECT_EQ(1, rrset2.getRdataCount());
     EXPECT_EQ(0, rrset2.getRRsigDataCount());
 }
+
+template <typename OutputType>
+void
+checkToWireResult(OutputType& expected_output, OutputType& actual_output,
+                  const TreeNodeRRset& actual_rrset,
+                  const Name& prepended_name,
+                  ConstRRsetPtr rrset, ConstRRsetPtr rrsig_rrset,
+                  bool dnssec_ok)
+{
+    expected_output.clear();
+    actual_output.clear();
+
+    // Prepare "actual" rendered data.  We prepend a name to confirm the
+    // owner name should be compressed in both cases.
+    prepended_name.toWire(actual_output);
+    const int expected_ret = (dnssec_ok && rrsig_rrset) ?
+        rrset->getRdataCount() + rrsig_rrset->getRdataCount() :
+        rrset->getRdataCount();
+    EXPECT_EQ(expected_ret, actual_rrset.toWire(actual_output));
+
+    // Prepare "expected" data.
+    prepended_name.toWire(expected_output);
+    rrset->toWire(expected_output);
+    if (dnssec_ok && rrsig_rrset) {
+        rrsig_rrset->toWire(expected_output);
+    }
+
+    // Compare the two.
+    matchWireData(expected_output.getData(), expected_output.getLength(),
+                  actual_output.getData(), actual_output.getLength());
+}
+
+TEST_F(TreeNodeRRsetTest, toWire) {
+    MessageRenderer expected_renderer, actual_renderer;
+    //OutputBuffer expected_buffer(0), actual_buffer(0);
+
+    // 1. with RRSIG, DNSSEC OK
+    const TreeNodeRRset rrset1(RRClass::IN(), www_node_, a_rdataset_, true);
+    checkToWireResult(expected_renderer, actual_renderer, rrset1, www_name_,
+                      a_rrset_, rrsig_rrset_, true);
+#ifdef notyet
+    checkToWireResult(expected_buffer, actual_buffer, rrset1,  www_name_,
+                      a_rrset_, rrsig_rrset_, true);
+#endif
+
+    // 2. with RRSIG, DNSSEC not OK
+    const TreeNodeRRset rrset2(rrclass_, www_node_, a_rdataset_, false);
+    checkToWireResult(expected_renderer, actual_renderer, rrset2, www_name_,
+                      a_rrset_, rrsig_rrset_, false);
+
+    // 3. without RRSIG, DNSSEC OK
+    const TreeNodeRRset rrset3(rrclass_, origin_node_, ns_rdataset_, true);
+    checkToWireResult(expected_renderer, actual_renderer, rrset3, origin_name_,
+                      ns_rrset_, ConstRRsetPtr(), true);
+
+    // 4. without RRSIG, DNSSEC not OK
+    const TreeNodeRRset rrset4(rrclass_, origin_node_, ns_rdataset_, false);
+    checkToWireResult(expected_renderer, actual_renderer, rrset4, origin_name_,
+                      ns_rrset_, ConstRRsetPtr(), false);
+
+    // RDATA of DNAME RR shouldn't be compressed.  Prepending "example.org"
+    // will check that.
+    const TreeNodeRRset rrset5(rrclass_, origin_node_, dname_rdataset_, false);
+    checkToWireResult(expected_renderer, actual_renderer, rrset5,
+                      Name("example.org"), dname_rrset_, ConstRRsetPtr(),
+                      false);
+}
 }

+ 71 - 4
src/lib/datasrc/memory/treenode_rrset.cc

@@ -25,7 +25,11 @@
 #include <dns/rrset.h>
 
 #include "treenode_rrset.h"
+#include "rdata_serialization.h"
 
+#include <boost/bind.hpp>
+
+#include <cassert>
 #include <string>
 
 using namespace isc::dns;
@@ -55,17 +59,80 @@ TreeNodeRRset::setTTL(const RRTTL&) {
     isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
 }
 
-    // needed
+// needed
 std::string
 TreeNodeRRset::toText() const {
     isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
 }
 
+namespace {
+void
+renderName(const LabelSequence& name_labels, RdataNameAttributes attr,
+           AbstractMessageRenderer* renderer)
+{
+    renderer->writeName(name_labels, (attr & NAMEATTR_COMPRESSIBLE) != 0);
+}
+
+void
+renderData(const void* data, size_t data_len,
+           AbstractMessageRenderer* renderer)
+{
+    renderer->writeData(data, data_len);
+}
+}
 
-// needed
 unsigned int
-TreeNodeRRset::toWire(AbstractMessageRenderer& /*renderer*/) const {
-    isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
+TreeNodeRRset::toWire(AbstractMessageRenderer& renderer) const {
+    RdataReader reader(rrclass_, rdataset_->type, rdataset_->getDataBuf(),
+                       rdataset_->getRdataCount(), rrsig_count_,
+                       boost::bind(renderName, _1, _2, &renderer),
+                       boost::bind(renderData, _1, _2, &renderer));
+
+    // Get the owner name of the RRset in the form of LabelSequence.
+    uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    const LabelSequence node_labels = node_->getAbsoluteLabels(labels_buf);
+
+    size_t i = 0;
+    for (; i < rdataset_->getRdataCount(); ++i) {
+        //const size_t pos0 = output.getLength();
+
+        renderer.writeName(node_labels, true);
+        rdataset_->type.toWire(renderer);
+        rrclass_.toWire(renderer);
+        renderer.writeData(rdataset_->getTTLData(), sizeof(uint32_t));
+
+        const size_t pos = renderer.getLength();
+        renderer.skip(sizeof(uint16_t)); // leave the space for RDLENGTH
+        const bool rendered = reader.iterateRdata();
+        assert(rendered == true);
+        renderer.writeUint16At(renderer.getLength() - pos - sizeof(uint16_t),
+                               pos);
+
+        // for truncation processing
+    }
+    const bool rendered = reader.iterateRdata();
+    assert(rendered == false); // we should've reached the end
+
+    size_t j = 0;
+    if (dnssec_ok_) {
+        for (; j < rrsig_count_; ++j) {
+            // TBD: truncation consideration
+
+            renderer.writeName(node_labels, true);
+            RRType::RRSIG().toWire(renderer);
+            rrclass_.toWire(renderer);
+            renderer.writeData(rdataset_->getTTLData(), sizeof(uint32_t));
+
+            const size_t pos = renderer.getLength();
+            renderer.skip(sizeof(uint16_t)); // leave the space for RDLENGTH
+            assert(reader.iterateSingleSig() == true);
+            renderer.writeUint16At(renderer.getLength() - pos -
+                                   sizeof(uint16_t), pos);
+        }
+        assert(reader.iterateSingleSig() == false);
+    }
+
+    return (i + j);
 }
 
 unsigned int

+ 8 - 4
src/lib/datasrc/memory/treenode_rrset.h

@@ -16,7 +16,7 @@
 #define DATASRC_MEMORY_TREENODE_RRSET_H 1
 
 #include <util/buffer.h>
-#include <util/memory_segment.h>
+#include <util/memory_segment.h> // CLEAN UP: only for temporary setup
 
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
@@ -26,7 +26,7 @@
 #include <dns/rdata.h>
 #include <dns/rrset.h>
 
-#include <datasrc/memory/domaintree.h>
+#include <datasrc/memory/domaintree.h> // CLEAN UP: only for temporary setup
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/rdataset.h>
 
@@ -36,6 +36,7 @@ namespace isc {
 namespace datasrc {
 namespace memory {
 
+// Temporary definition: Until we merge #2107 we need the following
 class RdataSetDeleter {
 public:
     RdataSetDeleter() {}
@@ -52,12 +53,14 @@ public:
 
 typedef DomainTree<RdataSet, RdataSetDeleter> ZoneTree;
 typedef DomainTreeNode<RdataSet, RdataSetDeleter> ZoneNode;
+// end of temporary definition
 
 class TreeNodeRRset : public dns::AbstractRRset {
 public:
     TreeNodeRRset(dns::RRClass rrclass, const ZoneNode* node,
                   const RdataSet* rdataset, bool dnssec_ok) :
-        node_(node), rdataset_(rdataset), rrclass_(rrclass),
+        node_(node), rdataset_(rdataset),
+        rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
         dnssec_ok_(dnssec_ok)
     {}
 
@@ -94,7 +97,7 @@ public:
     virtual dns::RRsetPtr getRRsig() const;
 
     virtual unsigned int getRRsigDataCount() const {
-        return (dnssec_ok_ ? rdataset_->getSigRdataCount() : 0);
+        return (dnssec_ok_ ? rrsig_count_ : 0);
     }
 
     virtual void addRRsig(const dns::rdata::ConstRdataPtr& rdata);
@@ -110,6 +113,7 @@ public:
 private:
     const ZoneNode* node_;
     const RdataSet* rdataset_;
+    const size_t rrsig_count_;
     const dns::RRClass rrclass_;
     const bool dnssec_ok_;
 };