From: Mukund Sivaraman Date: Tue, 28 Jan 2014 03:23:13 +0000 (+0530) Subject: [1396] Add RRset::getLength() X-Git-Tag: bind10-1.2.0beta1-release~100^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=000f7efd1c2d316c3ee02902713cedc355efefba;p=thirdparty%2Fkea.git [1396] Add RRset::getLength() --- diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc index 8dfe884dac..7fbd0d1503 100644 --- a/src/lib/dns/rrset.cc +++ b/src/lib/dns/rrset.cc @@ -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); diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h index eb8fa6ed0c..537c999d1f 100644 --- a/src/lib/dns/rrset.h +++ b/src/lib/dns/rrset.h @@ -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. /// diff --git a/src/lib/dns/tests/rrset_unittest.cc b/src/lib/dns/tests/rrset_unittest.cc index da3eb52267..72049b23ee 100644 --- a/src/lib/dns/tests/rrset_unittest.cc +++ b/src/lib/dns/tests/rrset_unittest.cc @@ -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()); +} }