]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[1396] Add RRset::getLength()
authorMukund Sivaraman <muks@isc.org>
Tue, 28 Jan 2014 03:23:13 +0000 (08:53 +0530)
committerMukund Sivaraman <muks@isc.org>
Tue, 28 Jan 2014 03:54:24 +0000 (09:24 +0530)
src/lib/dns/rrset.cc
src/lib/dns/rrset.h
src/lib/dns/tests/rrset_unittest.cc

index 8dfe884dacc85a19c2439f0c962c421d37eaefc9..7fbd0d150318cd46676cbd90054fb64bdb24899e 100644 (file)
@@ -289,6 +289,50 @@ BasicRRset::toText() const {
     return (AbstractRRset::toText());
 }
 
+uint16_t
+BasicRRset::getLength() const {
+    uint16_t length = 0;
+    RdataIteratorPtr it = getRdataIterator();
+
+    if (it->isLast()) {
+        // empty rrsets are only allowed for classes ANY and NONE
+        if (getClass() != RRClass::ANY() &&
+            getClass() != RRClass::NONE()) {
+            isc_throw(EmptyRRset, "getLength() is attempted for an empty RRset");
+        }
+
+        // For an empty RRset, write the name, type, class and TTL once,
+        // followed by empty rdata.
+        length += getName().getLength();
+        length += 2; // TYPE field
+        length += 2; // CLASS field
+        length += 2; // TTL field
+        length += 2; // RDLENGTH field (=0 in wire format)
+
+        return (length);
+    }
+
+    do {
+        // This is a size_t as some of the following additions may
+        // overflow due to a programming mistake somewhere.
+        size_t rrlen = 0;
+
+        rrlen += getName().getLength();
+        rrlen += 2; // TYPE field
+        rrlen += 2; // CLASS field
+        rrlen += 2; // TTL field
+        rrlen += 2; // RDLENGTH field
+        rrlen += it->getCurrent().getLength();
+
+        assert(length + rrlen < 65536);
+        length += rrlen;
+
+        it->next();
+    } while (!it->isLast());
+
+    return (length);
+}
+
 unsigned int
 BasicRRset::toWire(OutputBuffer& buffer) const {
     return (AbstractRRset::toWire(buffer));
@@ -322,6 +366,21 @@ RRset::getRRsigDataCount() const {
     }
 }
 
+uint16_t
+RRset::getLength() const {
+    uint16_t length = BasicRRset::getLength();
+
+    if (rrsig_) {
+        const uint16_t rrsigs_length = rrsig_->getLength();
+        // the uint16_ts are promoted to ints during addition below, so
+        // it won't overflow a 16-bit register.
+        assert(length + rrsigs_length < 65536);
+        length += rrsigs_length;
+    }
+
+    return (length);
+}
+
 unsigned int
 RRset::toWire(OutputBuffer& buffer) const {
     unsigned int rrs_written = BasicRRset::toWire(buffer);
index eb8fa6ed0c7e7851b4cbbcd2c68c753d9fc40806..537c999d1f028918e8c4c225b0a6cd20a6dfe872 100644 (file)
@@ -206,6 +206,20 @@ public:
     /// \return The number of \c Rdata objects contained.
     virtual unsigned int getRdataCount() const = 0;
 
+    /// \brief Get the wire format length of the \c AbstractRRset.
+    ///
+    /// This method returns the wire format length of the
+    /// \c AbstractRRset, which is calculated by summing the individual
+    /// lengths of the various fields that make up each RR.
+    ///
+    /// NOTE: When including name lengths, the allocation for
+    /// uncompressed name wire format representation is used.
+    ///
+    /// \return The length of the wire format representation of the
+    /// \c AbstractRRset.
+    /// \throw \c EmptyRRset if the \c AbstractRRset is empty.
+    virtual uint16_t getLength() const = 0;
+
     /// \brief Returns the owner name of the \c RRset.
     ///
     /// \return A reference to a \c Name class object corresponding to the
@@ -642,6 +656,13 @@ public:
     /// \return The number of \c Rdata objects contained.
     virtual unsigned int getRdataCount() const;
 
+    /// \brief Get the wire format length of the \c BasicRRset.
+    ///
+    /// \return The length of the wire format representation of the
+    /// \c BasicRRset.
+    /// \throw \c EmptyRRset if the \c BasicRRset is empty.
+    virtual uint16_t getLength() const;
+
     /// \brief Returns the owner name of the \c RRset.
     ///
     /// This method never throws an exception.
@@ -813,6 +834,13 @@ public:
 
     virtual ~RRset();
 
+    /// \brief Get the wire format length of the \c RRset.
+    ///
+    /// \return The length of the wire format representation of the
+    /// \c RRset.
+    /// \throw \c EmptyRRset if the \c RRset is empty.
+    virtual uint16_t getLength() const;
+
     /// \brief Render the RRset in the wire format with name compression and
     /// truncation handling.
     ///
index da3eb52267390209bb43bd8177342e5386d7e907..72049b23ee23c95380d84e32883a8b272b36e960 100644 (file)
@@ -204,6 +204,30 @@ TEST_F(RRsetTest, toText) {
               rrset_none_a_empty.toText());
 }
 
+TEST_F(RRsetTest, getLength) {
+    // Empty RRset should throw
+    EXPECT_THROW(rrset_a_empty.getLength(), EmptyRRset);
+
+    // Unless it is type ANY or NONE:
+    // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+    // TYPE field = 2 octets
+    // CLASS field = 2 octets
+    // TTL field = 2 octets
+    // RDLENGTH field = 2 octets
+    // Total = 18 + 2 + 2 + 2 + 2 = 26 octets
+    EXPECT_EQ(26, rrset_any_a_empty.getLength());
+    EXPECT_EQ(26, rrset_none_a_empty.getLength());
+
+    // RRset with single RDATA
+    // 26 (above) + 4 octets (A RDATA) = 30 octets
+    rrset_a_empty.addRdata(in::A("192.0.2.1"));
+    EXPECT_EQ(30, rrset_a_empty.getLength());
+
+    // 2 A RRs
+    rrset_a_empty.addRdata(in::A("192.0.2.2"));
+    EXPECT_EQ(60, rrset_a_empty.getLength());
+}
+
 TEST_F(RRsetTest, toWireBuffer) {
     rrset_a.toWire(buffer);
 
@@ -365,4 +389,38 @@ TEST_F(RRsetRRSIGTest, toText) {
               "20100322084538 20100220084538 1 example.com. FAKEFAKEFAKEFAKE\n",
               rrset_aaaa->toText());
 }
+
+TEST_F(RRsetRRSIGTest, getLength) {
+    // A RR
+    // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+    // TYPE field = 2 octets
+    // CLASS field = 2 octets
+    // TTL field = 2 octets
+    // RDLENGTH field = 2 octets
+    // A RDATA = 4 octets
+    // Total = 18 + 2 + 2 + 2 + 2 + 4 = 30 octets
+
+    // 2 A RRs
+    EXPECT_EQ(60, rrset_a->getLength());
+
+    // RRSIG
+    // test.example.com = 1 + 4 + 1 + 7 + 1 + 3 + 1 = 18 octets
+    // TYPE field = 2 octets
+    // CLASS field = 2 octets
+    // TTL field = 2 octets
+    // RDLENGTH field = 2 octets
+    // RRSIG RDATA = 40 octets
+    // Total = 18 + 2 + 2 + 2 + 2 + 40 = 66 octets
+    RRsetPtr my_rrsig(new RRset(test_name, RRClass::IN(),
+                                RRType::RRSIG(), RRTTL(3600)));
+    my_rrsig->addRdata(generic::RRSIG("A 4 3 3600 "
+                                      "20000101000000 20000201000000 "
+                                      "12345 example.com. FAKEFAKEFAKE"));
+    EXPECT_EQ(66, my_rrsig->getLength());
+
+    // RRset with attached RRSIG
+    rrset_a->addRRsig(my_rrsig);
+
+    EXPECT_EQ(60 + 66, rrset_a->getLength());
+}
 }