Browse Source

[2148] 'extendable' labelsequence constructor

Jelte Jansen 12 years ago
parent
commit
1780e99cd2
3 changed files with 171 additions and 8 deletions
  1. 19 0
      src/lib/dns/labelsequence.cc
  2. 18 8
      src/lib/dns/labelsequence.h
  3. 134 0
      src/lib/dns/tests/labelsequence_unittest.cc

+ 19 - 0
src/lib/dns/labelsequence.cc

@@ -55,6 +55,25 @@ LabelSequence::LabelSequence(const void* buf) {
     }
 }
 
+LabelSequence::LabelSequence(const LabelSequence& src,
+                             uint8_t buf[MAX_SERIALIZED_LENGTH])
+{
+    size_t data_len;
+    const uint8_t *data = src.getData(&data_len);
+    memcpy(buf, data, data_len);
+
+    for (size_t i = 0; i < src.getLabelCount(); ++i) {
+        buf[Name::MAX_WIRE + i] = src.offsets_[i + src.first_label_] -
+                                  src.offsets_[src.first_label_];
+    }
+
+    first_label_ = 0;
+    last_label_ = src.last_label_ - src.first_label_;
+    data_ = buf;
+    offsets_ = &buf[Name::MAX_WIRE];
+}
+
+
 const uint8_t*
 LabelSequence::getData(size_t *len) const {
     *len = getDataLength();

+ 18 - 8
src/lib/dns/labelsequence.h

@@ -45,6 +45,14 @@ class LabelSequence {
     friend std::string Name::toText(bool) const;
 
 public:
+    /// \brief Max possible size of serialized image generated by \c serialize
+    ///
+    /// A fixed length buffer of this size can be always passed to
+    /// \c serialize() safely.  (But the application shouldn't use the
+    /// specific size value; it must use this constant variable).
+    static const size_t MAX_SERIALIZED_LENGTH =
+        Name::MAX_WIRE + Name::MAX_LABELS + 1;
+
     /// \brief Constructs a LabelSequence for the given name
     ///
     /// \note The associated Name MUST remain in scope during the lifetime
@@ -78,6 +86,16 @@ public:
     /// \param buf Pointer to the serialized image generated by \c serialize().
     explicit LabelSequence(const void* buf);
 
+    /// \brief Construct 'extendable' LabelSequence
+    ///
+    /// This form of LabelSequence copies the data from the given
+    /// labelsequence into the given external buffer, which is subsequently
+    /// extendable by calling extend()
+    ///
+    /// \param src LabelSequence to copy the initial data from
+    /// \param buf external buffer to store this labelsequence's data in
+    LabelSequence(const LabelSequence& src, uint8_t buf[MAX_SERIALIZED_LENGTH]);
+
     /// \brief Copy constructor.
     ///
     /// \note The associated data MUST remain in scope during the lifetime
@@ -125,14 +143,6 @@ public:
     /// \return The length of the data of the label sequence in octets.
     size_t getDataLength() const;
 
-    /// \brief Max possible size of serialized image generated by \c serialize
-    ///
-    /// A fixed length buffer of this size can be always passed to
-    /// \c serialize() safely.  (But the application shouldn't use the
-    /// specific size value; it must use this constant variable).
-    static const size_t MAX_SERIALIZED_LENGTH =
-        Name::MAX_WIRE + Name::MAX_LABELS + 1;
-
     /// \brief Return the size of serialized image of the \c LabelSequence.
     ///
     /// This method calculates the size of necessary storage to store

+ 134 - 0
src/lib/dns/tests/labelsequence_unittest.cc

@@ -34,6 +34,25 @@ const size_t LabelSequence::MAX_SERIALIZED_LENGTH;
 
 namespace {
 
+// Common check that two labelsequences are equal
+void check_equal(const LabelSequence& ls1, const LabelSequence& ls2) {
+    NameComparisonResult result = ls1.compare(ls2);
+    EXPECT_EQ(isc::dns::NameComparisonResult::EQUAL,
+              result.getRelation()) << ls1.toText() << " <> " << ls2.toText();
+    EXPECT_EQ(0, result.getOrder()) << ls1.toText() << " <> " << ls2.toText();
+    EXPECT_EQ(ls1.getLabelCount(), result.getCommonLabels());
+}
+
+// Common check for general comparison of two labelsequences
+void check_compare(const LabelSequence& ls1, const LabelSequence& ls2,
+                   isc::dns::NameComparisonResult::NameRelation relation,
+                   size_t common_labels) {
+    NameComparisonResult result = ls1.compare(ls2);
+    EXPECT_EQ(relation, result.getRelation());
+    EXPECT_EQ(common_labels, result.getCommonLabels());
+}
+
+
 class LabelSequenceTest : public ::testing::Test {
 public:
     LabelSequenceTest() : n1("example.org"), n2("example.com"),
@@ -784,4 +803,119 @@ TEST_F(LabelSequenceTest, badDeserialize) {
     EXPECT_THROW(LabelSequence ls(offsets_noincrease), isc::BadValue);
 }
 
+namespace {
+
+// Helper function; repeatedly calls
+// - Initially, all three labelsequences should be the same
+// - repeatedly performs:
+//   - checks all three are equal
+//   - stripLeft on ls1
+//   - checks ls1 and ls2 are different, and ls2 and ls3 are equal
+//   - stripLeft on ls2
+//   - checks ls1 and ls2 are equal, and ls2 and ls3 are different
+//   - stripLeft on ls3
+//
+// (this test makes sure the stripLeft of one has no effect on the other
+// two, and that the strip properties hold regardless of how they were
+// constructed)
+//
+void stripLeftCheck(LabelSequence ls1, LabelSequence ls2, LabelSequence ls3) {
+    ASSERT_LT(1, ls1.getLabelCount());
+    while (ls1.getLabelCount() > 1) {
+        check_equal(ls1, ls2);
+        check_equal(ls2, ls3);
+
+        ls1.stripLeft(1);
+        check_compare(ls1, ls2, isc::dns::NameComparisonResult::SUPERDOMAIN,
+                      ls1.getLabelCount());
+        check_equal(ls2, ls3);
+
+        ls2.stripLeft(1);
+        check_equal(ls1, ls2);
+        check_compare(ls2, ls3, isc::dns::NameComparisonResult::SUPERDOMAIN,
+                      ls1.getLabelCount());
+
+        ls3.stripLeft(1);
+    }
+}
+
+// Similar to stripLeftCheck, but using stripRight()
+void stripRightCheck(LabelSequence ls1, LabelSequence ls2, LabelSequence ls3) {
+    ASSERT_LT(1, ls1.getLabelCount());
+    while (ls1.getLabelCount() > 1) {
+        check_equal(ls1, ls2);
+        check_equal(ls2, ls3);
+
+        ls1.stripRight(1);
+        check_compare(ls1, ls2, isc::dns::NameComparisonResult::NONE, 0);
+        check_equal(ls2, ls3);
+
+        ls2.stripRight(1);
+        check_equal(ls1, ls2);
+        check_compare(ls2, ls3, isc::dns::NameComparisonResult::NONE, 0);
+
+        ls3.stripRight(1);
+    }
+}
+
+} // end anonymous namespace
+
+// Test that 'extendable' labelsequences behave correctly when using
+// stripLeft() and stripRight()
+TEST(LabelSequence, extendableLabelSequence) {
+    Name n1("example.org.");
+    LabelSequence ls1(n1);
+    LabelSequence ls2(n1);
+
+    uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    memset(buf, 0, LabelSequence::MAX_SERIALIZED_LENGTH);
+    LabelSequence els(ls1, buf);
+
+    ASSERT_EQ(ls1.getDataLength(), els.getDataLength());
+    stripLeftCheck(ls1, els, ls2);
+    stripRightCheck(ls1, els, ls2);
+}
+
+// Test that 'extendable' LabelSequences behave correctly when initialized
+// with a stripped source LabelSequence
+TEST(LabelSequence, extendableLabelSequenceStrippedSource) {
+    Name n1("foo.bar.example.org.");
+    LabelSequence ls1(n1);
+    LabelSequence ls2(n1);
+
+    while (ls1.getLabelCount() > 2) {
+        ls1.stripLeft(1);
+        ls2.stripLeft(1);
+
+        uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+        memset(buf, 0, LabelSequence::MAX_SERIALIZED_LENGTH);
+        LabelSequence els(ls1, buf);
+
+        ASSERT_EQ(ls1.getDataLength(), els.getDataLength());
+        stripLeftCheck(ls1, els, ls2);
+        stripRightCheck(ls1, els, ls2);
+    }
+}
+
+TEST(LabelSequence, extendableLabelSequenceRightStrippedSource) {
+    Name n1("foo.bar.example.org.");
+    LabelSequence ls1(n1);
+    LabelSequence ls2(n1);
+
+    while (ls1.getLabelCount() > 2) {
+        ls1.stripRight(1);
+        ls2.stripRight(1);
+
+        uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+        memset(buf, 0, LabelSequence::MAX_SERIALIZED_LENGTH);
+        LabelSequence els(ls1, buf);
+
+        ASSERT_EQ(ls1.getDataLength(), els.getDataLength());
+        stripLeftCheck(ls1, els, ls2);
+        stripRightCheck(ls1, els, ls2);
+    }
+}
+
+
+
 }