From: Jelte Jansen Date: Wed, 25 Jul 2012 13:29:01 +0000 (+0200) Subject: [2148] add LabelSequence::extend() method X-Git-Tag: trac2351_base~157^2~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8553a206e41a621f1f81ef8bb02bdf2647f79c63;p=thirdparty%2Fkea.git [2148] add LabelSequence::extend() method --- diff --git a/src/lib/dns/labelsequence.cc b/src/lib/dns/labelsequence.cc index 8f22415892..ce17181ed6 100644 --- a/src/lib/dns/labelsequence.cc +++ b/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(); diff --git a/src/lib/dns/labelsequence.h b/src/lib/dns/labelsequence.h index b81116e145..3802557612 100644 --- a/src/lib/dns/labelsequence.h +++ b/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 LabelSequence. 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. /// diff --git a/src/lib/dns/tests/labelsequence_unittest.cc b/src/lib/dns/tests/labelsequence_unittest.cc index 3e96d94854..e7ad5307f5 100644 --- a/src/lib/dns/tests/labelsequence_unittest.cc +++ b/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); +} }