Browse Source

supported TXT RR (partially) so that we can implement authors.bind:-)

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/f2f200910@172 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 15 years ago
parent
commit
7a310b66f8
5 changed files with 157 additions and 5 deletions
  1. 1 0
      src/lib/dns/exceptions.h
  2. 2 2
      src/lib/dns/message.cc
  3. 104 2
      src/lib/dns/rrset.cc
  4. 22 0
      src/lib/dns/rrset.h
  5. 28 1
      src/lib/dns/rrset_unittest.cc

+ 1 - 0
src/lib/dns/exceptions.h

@@ -46,6 +46,7 @@ class DNSNoMessageParser : public DNSException {};
 class DNSInvalidMessageSection : public DNSException {};
 class DNSInvalidRendererPosition : public DNSException {};
 class DNSMessageTooShort : public DNSException {};
+class DNSCharStringTooLong : public DNSException {};
 }
 }
 #endif  // __EXCEPTIONS_HH

+ 2 - 2
src/lib/dns/message.cc

@@ -307,11 +307,11 @@ Message::addRR(section_t section, const RR& rr)
                  std::bind2nd(MatchRR(), rr));
     if (it != sections_[section].end()) {
         (*it)->setTtl(std::min((*it)->getTtl(), rr.getTtl()));
-        (*it)->addRdata(Rdata::RDATAPTR(rr.getRdata()->copy()));
+        (*it)->addRdata(Rdata::RdataPtr(rr.getRdata()->copy()));
     } else {
         RRset *rrset = new RRset(rr.getName(), rr.getClass(), rr.getType(),
                                  rr.getTtl());
-        rrset->addRdata(Rdata::RDATAPTR(rr.getRdata()->copy()));
+        rrset->addRdata(Rdata::RdataPtr(rr.getRdata()->copy()));
         sections_[section].push_back(RRsetPtr(rrset));
     }
 }

+ 104 - 2
src/lib/dns/rrset.cc

@@ -36,6 +36,7 @@ using isc::dns::TTL;
 using isc::dns::Rdata::IN::A;
 using isc::dns::Rdata::IN::AAAA;
 using isc::dns::Rdata::Generic::NS;
+using isc::dns::Rdata::Generic::TXT;
 using isc::dns::RRset;
 using isc::dns::Rdata::Rdata;
 using isc::dns::Question;
@@ -81,6 +82,8 @@ RRType::RRType(const std::string& typestr)
         typeval_ = 1;
     else if (typestr == "NS")
         typeval_ = 2;
+    else if (typestr == "TXT")
+        typeval_ = 16;
     else if (typestr == "AAAA")
         typeval_ = 28;
     else
@@ -94,6 +97,8 @@ RRType::toText() const
         return ("A");
     else if (typeval_ == 2)
         return ("NS");
+    else if (typeval_ == 16)
+        return ("TXT");
     else if (typeval_ == 28)
         return ("AAAA");
     throw std::runtime_error("unexpected type");
@@ -107,6 +112,7 @@ RRType::toWire(Buffer& buffer) const
 
 const RRType RRType::A("A");
 const RRType RRType::NS("NS");
+const RRType RRType::TXT("TXT");
 const RRType RRType::AAAA("AAAA");
 // ...more to follow
 
@@ -147,6 +153,12 @@ createNSDataFromText(const std::string& text_rdata)
     return (new NS(text_rdata));
 }
 
+Rdata *
+createTXTDataFromText(const std::string& text_rdata)
+{
+    return (new TXT(text_rdata));
+}
+
 RdataFactoryRegister::RdataFactoryRegister()
 {
     rdata_factory_repository.insert(pair<RRClassTypePair, RdataFactory>
@@ -155,11 +167,17 @@ RdataFactoryRegister::RdataFactoryRegister()
     rdata_factory_repository.insert(pair<RRClassTypePair, RdataFactory>
                                     (RRClassTypePair(RRClass::IN, RRType::AAAA),
                                      createAAAADataFromText));
-    //XXX: NS belongs to the 'generic' class.  should revisit it.
+    //XXX: NS/TXT belongs to the 'generic' class.  should revisit it.
     rdata_factory_repository.insert(pair<RRClassTypePair, RdataFactory>
                                     (RRClassTypePair(RRClass::IN, RRType::NS),
                                      createNSDataFromText));
-}
+    rdata_factory_repository.insert(pair<RRClassTypePair, RdataFactory>
+                                    (RRClassTypePair(RRClass::IN, RRType::TXT),
+                                     createTXTDataFromText));
+    // XXX: we should treat class-agnostic type accordingly.
+    rdata_factory_repository.insert(pair<RRClassTypePair, RdataFactory>
+                                    (RRClassTypePair(RRClass::CH, RRType::TXT),
+                                     createTXTDataFromText));}
 
 Rdata *
 Rdata::fromText(const RRClass& rrclass, const RRType& rrtype,
@@ -273,6 +291,90 @@ NS::copy() const
     return (new NS(toText()));
 }
 
+TXT::TXT(const std::string& text_data)
+{
+    size_t length = text_data.size();
+    size_t pos_begin = 0;
+
+    if (length > 1 && text_data[0] == '"' && text_data[length - 1] == '"') {
+        pos_begin = 1;
+        length -= 2;
+    }
+    if (text_data.size() > MAX_CHARACTER_STRING)
+        throw DNSCharStringTooLong();
+    string_list.push_back(text_data.substr(pos_begin, length));
+}
+
+bool
+TXT::operator==(const TXT& other) const
+{
+    std::vector<std::string>::const_iterator lit, rit;
+
+    if (count() != other.count())
+        return (false);
+
+    lit = string_list.begin();
+    rit = other.string_list.begin();
+    while (lit != string_list.end()) {
+        if (*lit != *rit)
+            return (false);
+        ++lit;
+        ++rit;
+    }
+
+    return (true);
+}
+
+void
+TXT::fromWire(Buffer& buffer, NameDecompressor& decompressor)
+{
+    //TBD
+}
+
+void
+TXT::toWire(Buffer& buffer, NameCompressor& compressor) const
+{
+    std::vector<std::string>::const_iterator it;
+    size_t total_length = 0;
+    size_t length_pos;
+
+    length_pos = buffer.getSize();
+    buffer.writeUint16(0);      // dummy data.  filled in later
+
+    for (it = string_list.begin(); it != string_list.end(); ++it) {
+        buffer.writeUint8((*it).size());
+        buffer.writeData((*it).c_str(), (*it).size());
+        total_length += (*it).size() + 1;
+    }
+
+    buffer.writeUint16At(total_length, length_pos);
+}
+
+std::string
+TXT::toText() const
+{
+    std::vector<std::string>::const_iterator it;
+    std::string s;
+
+    // XXX: this implementation is not entirely correct.  for example, it
+    // should escape double-quotes if they appear in the character string.
+    for (it = string_list.begin(); it != string_list.end(); ++it) {
+        if (!s.empty())
+            s.push_back(' ');
+        s.push_back('"');
+        s += *it;
+        s.push_back('"');
+    }
+
+    return (s);
+}
+
+Rdata*
+TXT::copy() const
+{
+    return (new TXT(toText()));
+}
+
 std::string
 RRset::toText() const
 {

+ 22 - 0
src/lib/dns/rrset.h

@@ -81,6 +81,7 @@ public:
     // (Some) Well-known RRtype constants
     static const RRType A;
     static const RRType NS;
+    static const RRType TXT;
     static const RRType AAAA;
     // more to follow...
 
@@ -163,6 +164,27 @@ public:
 private:
     Name nsname_;
 };
+
+// A quick hack implementation of TXT RR.  It currently supports only one
+// "character-string".
+class TXT : public Rdata::Rdata {
+public:
+    TXT() {}
+    explicit TXT(const std::string& text_data);
+    unsigned int count() const { return (string_list.size()); }
+    const RRType& getType() const { return (RRType::TXT); }
+    static const RRType& getTypeStatic() { return (RRType::TXT); }
+    std::string toText() const;
+    void fromWire(Buffer& b, NameDecompressor& c);
+    void toWire(Buffer& b, NameCompressor& c) const;
+    bool operator==(const TXT &other) const;
+    virtual bool operator!=(const TXT &other) const
+    { return !(*this == other); }
+    virtual Rdata* copy() const;
+private:
+    static const unsigned int MAX_CHARACTER_STRING = 255;
+    std::vector<std::string> string_list;
+};
 // add MXRdata, etc...
 }
 

+ 28 - 1
src/lib/dns/rrset_unittest.cc

@@ -30,6 +30,7 @@ using isc::dns::Rdata::Rdata;
 using isc::dns::Rdata::IN::A;
 using isc::dns::Rdata::IN::AAAA;
 using isc::dns::Rdata::Generic::NS;
+using isc::dns::Rdata::Generic::TXT;
 using isc::dns::RRset;
 using isc::dns::RR;
 using isc::dns::Question;
@@ -52,10 +53,12 @@ TEST_F(RRClassTest, fromToText)
 class RRTypeTest : public ::testing::Test {
 protected:
     RRTypeTest() :
-        rrtype_a("A"), rrtype_aaaa("AAAA"), rrtype_ns("NS") {}
+        rrtype_a("A"), rrtype_aaaa("AAAA"), rrtype_ns("NS"), rrtype_txt("TXT")
+    {}
     RRType rrtype_a;
     RRType rrtype_aaaa;
     RRType rrtype_ns;
+    RRType rrtype_txt;
 };
 
 TEST_F(RRTypeTest, fromToText)
@@ -63,6 +66,7 @@ TEST_F(RRTypeTest, fromToText)
     EXPECT_EQ("A", rrtype_a.toText());
     EXPECT_EQ("AAAA", rrtype_aaaa.toText());
     EXPECT_EQ("NS", rrtype_ns.toText());
+    EXPECT_EQ("TXT", rrtype_txt.toText());
 }
 
 // The fixture for testing class TTL.
@@ -135,6 +139,29 @@ TEST_F(Rdata_Generic_NS_Test, fromToText)
     EXPECT_EQ("ns.example.com.", rdata.toText());
 }
 
+// The fixture for testing Generic/TXT Rdata class
+class Rdata_Generic_TXT_Test : public ::testing::Test {
+protected:
+    Rdata_Generic_TXT_Test() : rdata("this is a test string") {}
+    TXT rdata;
+};
+
+TEST_F(Rdata_Generic_TXT_Test, longCharString)
+{
+    EXPECT_THROW(TXT("0123456789abcdef0123456789abcdef0123456789abcdef"
+                     "0123456789abcdef0123456789abcdef0123456789abcdef"
+                     "0123456789abcdef0123456789abcdef0123456789abcdef"
+                     "0123456789abcdef0123456789abcdef0123456789abcdef"
+                     "0123456789abcdef0123456789abcdef0123456789abcdef"
+                     "0123456789abcdef"),
+                 isc::dns::DNSCharStringTooLong);
+}
+
+TEST_F(Rdata_Generic_TXT_Test, fromToText)
+{
+    EXPECT_EQ("\"this is a test string\"", rdata.toText());
+}
+
 // The fixture for testing class RRset
 class RRsetTest : public ::testing::Test {
 protected: