Parcourir la source

[2087] Add MessageRenderer::writeName() variant for LabelSequence

The Name tests are not repeated as the Name variant is a wrapper
around the LabelSequence variant. Such tests would be redundant.
Instead, tests for LabelSequence specific stripLeft(), stripRight()
were added.
Mukund Sivaraman il y a 12 ans
Parent
commit
a16d2686dc

+ 17 - 0
src/lib/dns/labelsequence.h

@@ -45,6 +45,23 @@ class LabelSequence {
     friend std::string Name::toText(bool) const;
 
 public:
+    /// \brief Constructs a LabelSequence for the given label sequence
+    ///
+    /// \note The associated data MUST remain in scope during the lifetime
+    /// of this LabelSequence, since only the pointers are copied.
+    ///
+    /// \note No validation is done on the given data upon construction;
+    ///       use with care.
+    ///
+    /// \param ls The LabelSequence to construct a LabelSequence from
+    explicit LabelSequence(const LabelSequence& ls):
+                                     data_(ls.data_),
+                                     offsets_(ls.offsets_),
+                                     offsets_size_(ls.offsets_size_),
+                                     first_label_(ls.first_label_),
+                                     last_label_(ls.last_label_)
+    {}
+
     /// \brief Constructs a LabelSequence for the given name
     ///
     /// \note The associated Name MUST remain in scope during the lifetime

+ 13 - 5
src/lib/dns/messagerenderer.cc

@@ -289,8 +289,8 @@ MessageRenderer::setCompressMode(const CompressMode mode) {
 }
 
 void
-MessageRenderer::writeName(const Name& name, const bool compress) {
-    LabelSequence sequence(name);
+MessageRenderer::writeName(const LabelSequence& ls, const bool compress) {
+    LabelSequence sequence(ls);
     const size_t nlabels = sequence.getLabelCount();
     size_t data_len;
     const uint8_t* data;
@@ -317,14 +317,17 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
         if (ptr_offset != MessageRendererImpl::NO_OFFSET) {
             break;
         }
-        sequence.stripLeft(1);
+
+        if (nlabels_uncomp + 1 < nlabels) {
+            sequence.stripLeft(1);
+        }
     }
 
     // Record the current offset before updating the offset table
     size_t offset = getLength();
     // Write uncompress part:
     if (nlabels_uncomp > 0 || !compress) {
-        LabelSequence uncomp_sequence(name);
+        LabelSequence uncomp_sequence(ls);
         if (compress && nlabels > nlabels_uncomp) {
             // If there's compressed part, strip off that part.
             uncomp_sequence.stripRight(nlabels - nlabels_uncomp);
@@ -342,7 +345,7 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
     // in the hash table.  The renderer's buffer has just stored the
     // corresponding data, so we use the rendered data to get the length
     // of each label of the names.
-    size_t seqlen = name.getLength();
+    size_t seqlen = ls.getDataLength();
     for (size_t i = 0; i < nlabels_uncomp; ++i) {
         const uint8_t label_len = getBuffer()[offset];
         if (label_len == 0) { // offset for root doesn't need to be stored.
@@ -359,6 +362,11 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
     }
 }
 
+void
+MessageRenderer::writeName(const Name& name, const bool compress) {
+    writeName(LabelSequence(name), compress);
+}
+
 AbstractMessageRenderer::AbstractMessageRenderer() :
     local_buffer_(0), buffer_(&local_buffer_)
 {

+ 18 - 0
src/lib/dns/messagerenderer.h

@@ -22,6 +22,7 @@ namespace isc {
 namespace dns {
 // forward declarations
 class Name;
+class LabelSequence;
 
 /// \brief The \c AbstractMessageRenderer class is an abstract base class
 /// that provides common interfaces for rendering a DNS message into a buffer
@@ -372,6 +373,23 @@ public:
 
     virtual void clear();
     virtual void writeName(const Name& name, bool compress = true);
+
+    /// \brief Write a \c LabelSequence object into the internal buffer
+    /// in wire format, with or without name compression.
+    ///
+    /// If the optional parameter \c compress is \c true, this method tries to
+    /// compress the \c ls if possible, searching the entire message that has
+    /// been rendered.  Otherwise name compression is omitted.  Its default
+    /// value is \c true.
+    ///
+    /// Note: even if \c compress is \c true, the position of the \c ls (and
+    /// possibly its ancestor names) in the message is recorded and may be used
+    /// for compressing subsequent names.
+    ///
+    /// \param ls A \c LabelSequence object to be written.
+    /// \param compress A boolean indicating whether to enable name compression.
+    void writeName(const LabelSequence& ls, bool compress = true);
+
 private:
     struct MessageRendererImpl;
     MessageRendererImpl* impl_;

+ 63 - 0
src/lib/dns/tests/messagerenderer_unittest.cc

@@ -15,6 +15,7 @@
 #include <exceptions/exceptions.h>
 #include <util/buffer.h>
 #include <dns/name.h>
+#include <dns/labelsequence.h>
 #include <dns/messagerenderer.h>
 
 #include <dns/tests/unittest_util.h>
@@ -28,6 +29,7 @@
 
 using isc::UnitTestUtil;
 using isc::dns::Name;
+using isc::dns::LabelSequence;
 using isc::dns::MessageRenderer;
 using isc::util::OutputBuffer;
 using boost::lexical_cast;
@@ -176,6 +178,67 @@ TEST_F(MessageRendererTest, writeRootName) {
                         expected.getLength());
 }
 
+TEST_F(MessageRendererTest, writeNameLabelSequence1) {
+    UnitTestUtil::readWireData("name_toWire7", data);
+
+    Name n1("a.example.com");
+    LabelSequence ls1(n1);
+
+    // a.example.com.
+    renderer.writeName(ls1);
+
+    ls1.stripLeft(1);
+
+    // example.com.
+    renderer.writeName(ls1);
+
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
+}
+
+TEST_F(MessageRendererTest, writeNameLabelSequence2) {
+    UnitTestUtil::readWireData("name_toWire8", data);
+
+    Name n1("a.example.com");
+    LabelSequence ls1(n1);
+
+    ls1.stripRight(1);
+
+    // a.example.com (without root .)
+    renderer.writeName(ls1);
+
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
+}
+
+TEST_F(MessageRendererTest, writeNameLabelSequence3) {
+    UnitTestUtil::readWireData("name_toWire9", data);
+
+    Name n1("a.example.com");
+    LabelSequence ls1(n1);
+
+    // a.example.com.
+    renderer.writeName(ls1);
+
+    ls1.stripRight(1);
+
+    // a.example.com (without root .)
+    renderer.writeName(ls1);
+
+    ls1.stripRight(1);
+
+    // a.example
+    renderer.writeName(ls1);
+
+    ls1.stripLeft(1);
+
+    // example
+    renderer.writeName(ls1);
+
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
+}
+
 TEST_F(MessageRendererTest, setBuffer) {
     OutputBuffer new_buffer(0);
     renderer.setBuffer(&new_buffer);

+ 1 - 0
src/lib/dns/tests/testdata/Makefile.am

@@ -93,6 +93,7 @@ EXTRA_DIST += name_fromWire9 name_fromWire10 name_fromWire11 name_fromWire12
 EXTRA_DIST += name_fromWire13 name_fromWire14
 EXTRA_DIST += name_toWire1 name_toWire2 name_toWire3 name_toWire4
 EXTRA_DIST += name_toWire5.spec name_toWire6.spec
+EXTRA_DIST += name_toWire7 name_toWire8 name_toWire9
 EXTRA_DIST += question_fromWire question_toWire1 question_toWire2
 EXTRA_DIST += rdatafields1.spec rdatafields2.spec rdatafields3.spec
 EXTRA_DIST += rdatafields4.spec rdatafields5.spec rdatafields6.spec

+ 10 - 0
src/lib/dns/tests/testdata/name_toWire7

@@ -0,0 +1,10 @@
+#
+# Rendering names including one explicitly uncompressed.
+# [x] means a compression pointer pointing to offset 'x'.
+#
+# 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 (bytes)
+#(1) a (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+
+#[02] pointing to -> "example.com."
+ c0 02

+ 7 - 0
src/lib/dns/tests/testdata/name_toWire8

@@ -0,0 +1,7 @@
+#
+# Rendering names.
+# [x] means a compression pointer pointing to offset 'x'.
+#
+# 0  1  2  3  4  5  6  7  8  9 10 11 12 13 (bytes)
+#(1) a (7) e  x  a  m  p  l  e (3) c  o  m
+ 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d

+ 13 - 0
src/lib/dns/tests/testdata/name_toWire9

@@ -0,0 +1,13 @@
+#
+# Rendering names including one explicitly uncompressed.
+# [x] means a compression pointer pointing to offset 'x'.
+#
+# 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 (bytes)
+#(1) a (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+#(1) a (7) e  x  a  m  p  l  e (3) c  o  m
+ 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d
+#(1) a (7) e  x  a  m  p  l  e
+ 01 61 07 65 78 61 6d 70 6c 65
+#[1f] pointing to ^^ "example"
+ c0 1f