Browse Source

[2148] add LabelSequence::extend() method

Jelte Jansen 12 years ago
parent
commit
8553a206e4

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

@@ -337,6 +337,46 @@ LabelSequence::toText() const {
     return (toText(!isAbsolute()));
 }
 
+void
+LabelSequence::extend(const LabelSequence& labels,
+                      uint8_t buf[MAX_SERIALIZED_LENGTH])
+{
+    // check whether this labelsequence appears to have anything to do with
+    // the given buf at all
+    if (data_ != buf || offsets_ != &buf[Name::MAX_WIRE]) {
+        isc_throw(BadValue,
+                  "extend() called with unrelated buffer");
+    }
+
+    // check name does not become too long
+    size_t orig_len = getDataLength() - 1;
+    if (orig_len + labels.getDataLength() > Name::MAX_WIRE) {
+        isc_throw(BadValue,
+                  "extend() would exceed maximum wire length");
+    }
+
+    // check offsets data does not become too long
+    if (getLabelCount() + labels.getLabelCount() > Name::MAX_LABELS) {
+        isc_throw(BadValue,
+                  "extend() would exceed maximum number of labels");
+    }
+
+    // append second to first labelsequence
+    size_t data_len;
+    const uint8_t *data = labels.getData(&data_len);
+    memcpy(buf + orig_len, data, data_len);
+
+    // append offsets
+    for (size_t i = 0; i < labels.getLabelCount(); ++i) {
+        buf[Name::MAX_WIRE + last_label_ + i] =
+                                  offsets_[last_label_] +
+                                  labels.offsets_[i + labels.first_label_] -
+                                  labels.offsets_[labels.first_label_];
+    }
+    last_label_ += labels.last_label_ - labels.first_label_;
+}
+
+
 std::ostream&
 operator<<(std::ostream& os, const LabelSequence& label_sequence) {
     os << label_sequence.toText();

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

@@ -103,6 +103,11 @@ public:
     ///
     /// \note The given buf MUST remain in scope during the lifetime of
     /// the LabelSequence created here.
+    /// \note The buffer should never be modified except through
+    /// calls to extend().
+    /// \note Also, only associate the buffer with at most one
+    /// LabelSequence. Behaviour is undefined if two LabelSequences are
+    /// using the same buffer.
     ///
     /// \param src LabelSequence to copy the initial data from
     /// \param buf external buffer to store this labelsequence's data in
@@ -261,6 +266,29 @@ public:
     /// \return a string representation of the <code>LabelSequence</code>.
     std::string toText() const;
 
+    /// \brief Extend this LabelSequence with the given labelsequence
+    ///
+    /// The given labels are added to the name data, and internal data
+    /// is updated accordingly.
+    /// The data from the given LabelSequence is copied into the buffer
+    /// associated with this LabelSequence; the appended LabelSequence
+    /// can be released if it is not needed for other operations anymore.
+    ///
+    /// Some minimal checking is done on the data, but internal integrity
+    /// is not assumed. Do NOT modify the given buffer except through calls
+    /// to this method, and do NOT call this method if the buffer is
+    /// associated to another LabelSequence (behaviour of the other
+    /// LabelSequence is undefined in that scenario).
+    ///
+    /// \exception BadValue If the buffer does not appear to be associated
+    /// with this LabelSequence, or if the maximum wire length or maximum
+    /// number of labels would be exceeded by this operation
+    ///
+    /// \param labels The labels to append to this LabelSequence
+    /// \param buf The buffer associated with this LabelSequence
+    void extend(const LabelSequence& labels,
+                uint8_t buf[MAX_SERIALIZED_LENGTH]);
+
 private:
     /// \brief Convert the LabelSequence to a string.
     ///

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

@@ -916,6 +916,95 @@ TEST(LabelSequence, extendableLabelSequenceRightStrippedSource) {
     }
 }
 
+// Check some basic 'extend' functionality
+TEST(LabelSequence, extend) {
+    Name n1("foo.bar.");
+    Name n2("foo");
+    Name n3("bar");
+    LabelSequence ls1(n1);
+    LabelSequence ls2(n2);
+    LabelSequence ls3(n3);
+    LabelSequence ls4(n1);
+
+    uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    memset(buf, 0, LabelSequence::MAX_SERIALIZED_LENGTH);
+    LabelSequence els(ls2, buf);
+
+    check_compare(ls1, els, isc::dns::NameComparisonResult::COMMONANCESTOR, 1);
+    els.extend(ls3, buf);
+
+    check_compare(ls1, els, isc::dns::NameComparisonResult::EQUAL, 3);
+    stripLeftCheck(ls1, els, ls4);
+    stripRightCheck(ls1, els, ls4);
+
+    els.extend(ls3, buf);
+    check_compare(ls1, ls2, isc::dns::NameComparisonResult::COMMONANCESTOR, 1);
+}
+
+// Check that when extending with itself, it does not cause horrible failures
+TEST(LabelSequence, extendWithItself) {
+    Name n1("foo.bar.");
+    Name n2("foo.bar.foo.bar.");
+    LabelSequence ls1(n1);
+    LabelSequence ls2(n2);
+
+    uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    memset(buf, 0, LabelSequence::MAX_SERIALIZED_LENGTH);
+    LabelSequence els(ls1, buf);
+
+    std::cout << "[XX] " << els.toText() << std::endl;
+    // some men just want to watch the world burn.
+    els.extend(els, buf);
+    std::cout << "[XX] " << els.toText() << std::endl;
+    check_equal(ls2, els);
+}
+
+// Test that 'extending' with just a root label is a no-op
+TEST(LabelSequence, extendWithRoot) {
+    Name n1("example.org");
+    LabelSequence ls1(n1);
+    uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
 
+    LabelSequence els(LabelSequence(ls1, buf));
+    check_equal(ls1, els);
+    els.extend(LabelSequence(Name(".")), buf);
+    check_equal(ls1, els);
+}
+
+// Check possible failure modes of extend()
+TEST(LabelSequence, extendBadData) {
+    Name n1("example.org.");
+    LabelSequence ls1(n1);
+
+    uint8_t buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    memset(buf, 0, LabelSequence::MAX_SERIALIZED_LENGTH);
+    LabelSequence els(ls1, buf);
+
+    // try use with unrelated labelsequence
+    EXPECT_THROW(ls1.extend(ls1, buf), isc::BadValue);
+
+    // Create a long name, but so that we can still extend once
+    Name longlabel("1234567890123456789012345678901234567890"
+                   "12345678901234567890");
+    LabelSequence ls2(longlabel);
+    els = LabelSequence(ls2, buf);
+    els.extend(els, buf);
+    els.extend(ls2, buf);
+    els.extend(ls2, buf);
+    ASSERT_EQ(245, els.getDataLength());
+    // Extending once more with 10 bytes should still work
+    els.extend(LabelSequence(Name("123456789")), buf);
+    // But now, even the shortest extension should fail
+    EXPECT_THROW(els.extend(LabelSequence(Name("1")), buf), isc::BadValue);
+
+    // Also check that extending past MAX_LABELS is not possible
+    Name shortname("1.");
+    LabelSequence short_ls(shortname);
+    els = LabelSequence(short_ls, buf);
+    for (size_t i=0; i < 125; ++i) {
+        els.extend(short_ls, buf);
+    }
+    EXPECT_THROW(els.extend(short_ls, buf), isc::BadValue);
+}
 
 }