Browse Source

merged the jinmei-dnsrdata2 branch into trunk

git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@973 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 15 years ago
parent
commit
1b6b71ac10
92 changed files with 4450 additions and 873 deletions
  1. 1 0
      configure.ac
  2. 1 1
      doc/Doxyfile
  3. 24 0
      src/bin/parkinglot/Makefile.am
  4. 241 0
      src/bin/parkinglot/b10-parkinglot.cc
  5. 44 0
      src/bin/parkinglot/b10-parkinglot.h
  6. 217 0
      src/bin/parkinglot/builtin.cc
  7. 49 0
      src/bin/parkinglot/builtin.h
  8. 241 0
      src/bin/parkinglot/builtin_bench.cc
  9. 23 0
      src/bin/parkinglot/common.cc
  10. 36 0
      src/bin/parkinglot/common.h
  11. 1 0
      src/bin/parkinglot/config.h.in
  12. 20 0
      src/bin/parkinglot/data_source.cc
  13. 123 0
      src/bin/parkinglot/data_source.h
  14. 188 0
      src/bin/parkinglot/data_source_plot.cc
  15. 96 0
      src/bin/parkinglot/data_source_plot.h
  16. 148 0
      src/bin/parkinglot/main.cc
  17. 74 0
      src/bin/parkinglot/parkinglot.spec
  18. 37 0
      src/bin/parkinglot/zoneset.cc
  19. 64 0
      src/bin/parkinglot/zoneset.h
  20. 2 24
      src/lib/dns/cpp/Makefile.am
  21. 105 60
      src/lib/dns/cpp/gen-rdatacode.py.in
  22. 152 25
      src/lib/dns/cpp/rdata.cc
  23. 356 40
      src/lib/dns/cpp/rdata.h
  24. 0 1
      src/lib/dns/cpp/rdata/generic/txt_16.h
  25. 5 0
      src/lib/dns/cpp/rdata/template.h
  26. 0 534
      src/lib/dns/cpp/rdata_unittest.cc
  27. 103 34
      src/lib/dns/cpp/rrparamregistry-placeholder.cc
  28. 171 20
      src/lib/dns/cpp/rrparamregistry.h
  29. 0 92
      src/lib/dns/cpp/rrparamregistry_unittest.cc
  30. 33 0
      src/lib/dns/cpp/tests/Makefile.am
  31. 1 1
      src/lib/dns/cpp/base64_unittest.cc
  32. 1 1
      src/lib/dns/cpp/buffer_unittest.cc
  33. 8 8
      src/lib/dns/cpp/message_unittest.cc
  34. 3 3
      src/lib/dns/cpp/messagerenderer_unittest.cc
  35. 3 3
      src/lib/dns/cpp/name_unittest.cc
  36. 6 6
      src/lib/dns/cpp/question_unittest.cc
  37. 121 0
      src/lib/dns/cpp/tests/rdata_cname_unittest.cc
  38. 117 0
      src/lib/dns/cpp/tests/rdata_in_a_unittest.cc
  39. 102 0
      src/lib/dns/cpp/tests/rdata_in_aaaa_unittest.cc
  40. 91 0
      src/lib/dns/cpp/tests/rdata_mx_unittest.cc
  41. 128 0
      src/lib/dns/cpp/tests/rdata_ns_unittest.cc
  42. 60 0
      src/lib/dns/cpp/tests/rdata_rrsig_unittest.cc
  43. 73 0
      src/lib/dns/cpp/tests/rdata_soa_unittest.cc
  44. 70 0
      src/lib/dns/cpp/tests/rdata_txt_unittest.cc
  45. 314 0
      src/lib/dns/cpp/tests/rdata_unittest.cc
  46. 51 0
      src/lib/dns/cpp/tests/rdata_unittest.h
  47. 3 3
      src/lib/dns/cpp/rrclass_unittest.cc
  48. 158 0
      src/lib/dns/cpp/tests/rrparamregistry_unittest.cc
  49. 9 9
      src/lib/dns/cpp/rrset_unittest.cc
  50. 3 3
      src/lib/dns/cpp/rrttl_unittest.cc
  51. 3 3
      src/lib/dns/cpp/rrtype_unittest.cc
  52. 0 0
      src/lib/dns/cpp/tests/run_unittests.cc
  53. 22 0
      src/lib/dns/cpp/tests/testdata/message_fromWire1
  54. 22 0
      src/lib/dns/cpp/tests/testdata/message_toWire1
  55. 14 0
      src/lib/dns/cpp/tests/testdata/name_fromWire1
  56. 12 0
      src/lib/dns/cpp/tests/testdata/name_fromWire10
  57. 12 0
      src/lib/dns/cpp/tests/testdata/name_fromWire11
  58. 13 0
      src/lib/dns/cpp/tests/testdata/name_fromWire12
  59. 5 0
      src/lib/dns/cpp/tests/testdata/name_fromWire13
  60. 7 0
      src/lib/dns/cpp/tests/testdata/name_fromWire14
  61. 15 0
      src/lib/dns/cpp/tests/testdata/name_fromWire2
  62. 11 0
      src/lib/dns/cpp/tests/testdata/name_fromWire3_1
  63. 13 0
      src/lib/dns/cpp/tests/testdata/name_fromWire3_2
  64. 45 0
      src/lib/dns/cpp/tests/testdata/name_fromWire4
  65. 14 0
      src/lib/dns/cpp/tests/testdata/name_fromWire6
  66. 6 0
      src/lib/dns/cpp/tests/testdata/name_fromWire7
  67. 27 0
      src/lib/dns/cpp/tests/testdata/name_fromWire8
  68. 12 0
      src/lib/dns/cpp/tests/testdata/name_fromWire9
  69. 12 0
      src/lib/dns/cpp/tests/testdata/name_toWire1
  70. 14 0
      src/lib/dns/cpp/tests/testdata/name_toWire2
  71. 14 0
      src/lib/dns/cpp/tests/testdata/name_toWire3
  72. 16 0
      src/lib/dns/cpp/tests/testdata/name_toWire4
  73. 0 0
      src/lib/dns/cpp/tests/testdata/question_fromWire
  74. 0 0
      src/lib/dns/cpp/tests/testdata/question_toWire1
  75. 0 0
      src/lib/dns/cpp/tests/testdata/question_toWire2
  76. 44 0
      src/lib/dns/cpp/tests/testdata/rdata_cname_fromWire
  77. 19 0
      src/lib/dns/cpp/tests/testdata/rdata_in_a_fromWire
  78. 9 0
      src/lib/dns/cpp/tests/testdata/rdata_in_aaaa_fromWire
  79. 15 0
      src/lib/dns/cpp/tests/testdata/rdata_mx_fromWire
  80. 12 0
      src/lib/dns/cpp/tests/testdata/rdata_mx_toWire1
  81. 44 0
      src/lib/dns/cpp/tests/testdata/rdata_ns_fromWire
  82. 20 0
      src/lib/dns/cpp/tests/testdata/rdata_soa_fromWire
  83. 9 0
      src/lib/dns/cpp/tests/testdata/rdata_txt_fromWire
  84. 13 0
      src/lib/dns/cpp/tests/testdata/rdata_unknown_fromWire
  85. 4 0
      src/lib/dns/cpp/tests/testdata/rrcode16_fromWire1
  86. 4 0
      src/lib/dns/cpp/tests/testdata/rrcode16_fromWire2
  87. 4 0
      src/lib/dns/cpp/tests/testdata/rrcode32_fromWire1
  88. 4 0
      src/lib/dns/cpp/tests/testdata/rrcode32_fromWire2
  89. 23 0
      src/lib/dns/cpp/tests/testdata/rrset_toWire1
  90. 38 0
      src/lib/dns/cpp/tests/testdata/rrset_toWire2
  91. 1 1
      src/lib/dns/cpp/unittest_util.cc
  92. 1 1
      src/lib/dns/cpp/unittest_util.h

+ 1 - 0
configure.ac

@@ -165,6 +165,7 @@ AC_CONFIG_FILES([Makefile
                  src/lib/config/python/isc/config/Makefile
                  src/lib/dns/Makefile
                  src/lib/dns/cpp/Makefile
+                 src/lib/dns/cpp/tests/Makefile
                  src/lib/exceptions/cpp/Makefile
                  src/lib/exceptions/Makefile
                  src/lib/auth/Makefile

+ 1 - 1
doc/Doxyfile

@@ -611,7 +611,7 @@ EXCLUDE_SYMLINKS       = NO
 # against the file with absolute path, so to exclude all test directories
 # for example use the pattern */test/*
 
-EXCLUDE_PATTERNS       = *unittest*.h
+EXCLUDE_PATTERNS       = */*-placeholder.* */cpp/*.py
 
 # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
 # (namespaces, classes, functions, etc.) that should be excluded from the

+ 24 - 0
src/bin/parkinglot/Makefile.am

@@ -0,0 +1,24 @@
+AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_builddir)/src/lib -I$(top_builddir)/src/lib/dns/cpp -I$(top_builddir)/include/dns/cpp -I$(top_builddir)/include -I$(top_srcdir)/ext
+
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+
+pkglibexec_PROGRAMS = b10-parkinglot
+
+b10_parkinglot_SOURCES = b10-parkinglot.cc b10-parkinglot.h
+b10_parkinglot_SOURCES += common.cc common.h zoneset.h zoneset.cc main.cc
+b10_parkinglot_SOURCES += data_source_plot.h data_source_plot.cc
+b10_parkinglot_SOURCES += data_source.h data_source.cc
+b10_parkinglot_SOURCES += builtin.h builtin.cc
+b10_parkinglot_LDADD =  $(top_builddir)/src/lib/dns/cpp/.libs/libdns.a
+b10_parkinglot_LDADD += $(top_builddir)/src/lib/config/cpp/libcfgclient.a
+b10_parkinglot_LDADD += $(top_builddir)/src/lib/cc/cpp/libcc.a
+b10_parkinglot_LDADD += $(top_builddir)/src/lib/exceptions/cpp/.libs/libexceptions.a
+
+b10_parkinglotdir = $(DESTDIR)$(pkgdatadir)
+b10_parkinglot_DATA = parkinglot.spec
+
+# TODO: don't install this here
+bin_PROGRAMS = builtin_bench
+builtin_bench_SOURCES = builtin_bench.cc builtin.h builtin.cc
+builtin_bench_LDADD = $(top_builddir)/src/lib/dns/cpp/.libs/libdns.a
+builtin_bench_LDADD += $(top_builddir)/src/lib/exceptions/cpp/.libs/libexceptions.a

+ 241 - 0
src/bin/parkinglot/b10-parkinglot.cc

@@ -0,0 +1,241 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <set>
+#include <iostream>
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/question.h>
+#include <dns/rdataclass.h>
+#include <dns/rrset.h>
+#include <dns/rrttl.h>
+#include <dns/message.h>
+
+#include <cc/data.h>
+
+#include "common.h"
+#include "builtin.h"
+#include "b10-parkinglot.h"
+
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+
+using namespace std;
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::data;
+
+ParkingLot::ParkingLot(int port) {
+    /*ns1 = Rdata::RdataPtr(new NS("ns1.parking.example"));
+    ns2 = Rdata::RdataPtr(new NS("ns2.parking.example"));
+    ns3 = Rdata::RdataPtr(new NS("ns3.parking.example"));
+    a = Rdata::RdataPtr(new A("127.0.0.1"));
+    aaaa = Rdata::RdataPtr(new AAAA("::1"));
+    */
+
+    int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (s < 0)
+        throw FatalError("failed to open socket");
+
+    struct sockaddr_in sin;
+    sin.sin_family = AF_INET;
+    sin.sin_addr.s_addr = INADDR_ANY;
+    sin.sin_port = htons(port);
+
+    socklen_t sa_len = sizeof(sin);
+#ifdef HAVE_SIN_LEN
+    sin.sin_len = sa_len;
+#endif
+
+    if (bind(s, (struct sockaddr *)&sin, sa_len) < 0)
+        throw FatalError("could not bind socket");
+
+    sock = s;
+}
+
+namespace {
+struct GlueInserter {
+    GlueInserter(const DataSourceParkingLot& data_source,
+                 const Name& zname, const RRClass& qclass,
+                 Message& msg) :
+        data_source_(&data_source), zname_(&zname), qclass_(&qclass),
+        msg_(&msg)
+    {}
+    void operator()(const RRsetPtr rrset)
+    {
+        if (rrset->getType() == RRType::NS()) {
+            RdataIteratorPtr it = rrset->getRdataIterator();
+            for (it->first(); !it->isLast(); it->next()) {
+                const generic::NS& nsrdata =
+                    dynamic_cast<const generic::NS&>(it->getCurrent());
+                data_source_->addToMessage(*msg_, Section::ADDITIONAL(),
+                                           *zname_, nsrdata.getNSName(),
+                                           *qclass_, RRType::A());
+                data_source_->addToMessage(*msg_, Section::ADDITIONAL(),
+                                           *zname_, nsrdata.getNSName(),
+                                           *qclass_, RRType::AAAA());
+            }
+        }
+    }
+    const DataSourceParkingLot* data_source_;
+    const Name* zname_;
+    const RRClass* qclass_;
+    Message* msg_;
+};
+}
+
+namespace {
+const Name authors_name("authors.bind");
+const Name version_name("version.bind");
+}
+
+void
+ParkingLot::processMessage() {
+    struct sockaddr_storage ss;
+    socklen_t sa_len = sizeof(ss);
+    struct sockaddr* sa = static_cast<struct sockaddr*>((void*)&ss);
+    int s = sock;
+    char recvbuf[4096];
+    int cc;
+
+    if ((cc = recvfrom(s, recvbuf, sizeof(recvbuf), 0, sa, &sa_len)) > 0) {
+        Message msg;
+        InputBuffer buffer(recvbuf, cc);
+
+        try {
+            msg.fromWire(buffer);
+        } catch (...) {
+            cerr << "parse failed" << endl;
+            return;
+        }
+
+        cout << "received a message:\n" << msg.toText() << endl;
+
+        if (msg.getRRCount(Section::QUESTION()) != 1) {
+            return;
+        }
+
+        QuestionPtr query = *msg.beginQuestion();
+
+        msg.makeResponse();
+        msg.setHeaderFlag(MessageFlag::AA());
+        Name zname(".");        // ugly, but should work for now
+        msg.setRcode(Rcode::NOERROR());
+        if (query->getType() == RRType::TXT() &&
+            query->getClass() == RRClass::CH() &&
+            query->getName() == authors_name) {
+            msg.addRRset(Section::ANSWER(), getBuiltinAuthors().getAnswer());
+            msg.addRRset(Section::AUTHORITY(),
+                         getBuiltinAuthors().getAuthority());
+        } else if (query->getType() == RRType::TXT() &&
+                   query->getClass() == RRClass::CH() &&
+            query->getName() == version_name) {
+            msg.addRRset(Section::ANSWER(), getBuiltinVersion().getAnswer());
+            msg.addRRset(Section::AUTHORITY(),
+                         getBuiltinVersion().getAuthority());
+        } else if (data_source.hasZoneFor(query->getName(), zname)) {
+            SearchResult::status_type status =
+                data_source.addToMessage(msg, Section::ANSWER(), zname,
+                                         query->getName(), query->getClass(),
+                                         query->getType());
+            bool included_ns = false;
+
+            // rcode is based on this result?
+            if (status == SearchResult::name_not_found) {
+                msg.setRcode(Rcode::NXDOMAIN());
+                if (query->getType() != RRType::NS()) {
+                    status = data_source.addToMessage(msg, Section::AUTHORITY(),
+                                                      zname, zname,
+                                                      query->getClass(),
+                                                      RRType::SOA());
+                }
+            } else {
+                if (query->getType() != RRType::NS()) {
+                    status = data_source.addToMessage(msg, Section::AUTHORITY(),
+                                                      zname, zname,
+                                                      query->getClass(),
+                                                      RRType::NS());
+                }
+                included_ns = true;
+            }
+            // If we included NS records, and their target falls below the zone, add glue
+            if (included_ns) {
+                for_each(msg.beginSection(Section::ANSWER()),
+                         msg.endSection(Section::ANSWER()),
+                         GlueInserter(data_source, zname, query->getClass(),
+                                      msg));
+                for_each(msg.beginSection(Section::AUTHORITY()),
+                         msg.endSection(Section::AUTHORITY()),
+                         GlueInserter(data_source, zname, query->getClass(),
+                                      msg));
+            }
+        } else {
+            msg.setRcode(Rcode::SERVFAIL());
+        }
+
+        OutputBuffer obuffer(4096);
+        MessageRenderer renderer(obuffer);
+        msg.toWire(renderer);
+        cout << "sending a response (" <<
+            boost::lexical_cast<string>(obuffer.getLength())
+                  << " bytes):\n" << msg.toText() << endl;
+        sendto(s, obuffer.getData(), obuffer.getLength(), 0, sa, sa_len);
+    }
+}
+
+ElementPtr
+ParkingLot::updateConfig(isc::data::ElementPtr config) {
+    if (config->contains("zones")) {
+        data_source.clear_zones();
+        BOOST_FOREACH(isc::data::ElementPtr zone_el, config->get("zones")->listValue()) {
+            data_source.serve(zone_el->stringValue());
+        }
+    }
+    if (config->contains("port")) {
+        // todo: what to do with port change. restart automatically?
+        // ignore atm
+    }
+    if (config->contains("a_records")) {
+        data_source.clearARecords();
+        BOOST_FOREACH(isc::data::ElementPtr rel, config->get("a_records")->listValue()) {
+            data_source.addARecord(rel->stringValue());
+        }
+    }
+    if (config->contains("aaaa_records")) {
+        data_source.clearAAAARecords();
+        BOOST_FOREACH(isc::data::ElementPtr rel, config->get("aaaa_records")->listValue()) {
+            data_source.addAAAARecord(rel->stringValue());
+        }
+    }
+    if (config->contains("ns_records")) {
+        data_source.clearNSRecords();
+        BOOST_FOREACH(isc::data::ElementPtr rel, config->get("ns_records")->listValue()) {
+            data_source.addNSRecord(rel->stringValue());
+        }
+    }
+    return isc::data::Element::createFromString("{ \"result\": [0] }");
+}

+ 44 - 0
src/bin/parkinglot/b10-parkinglot.h

@@ -0,0 +1,44 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __PARKINGLOT_H
+#define __PARKINGLOT_H 1
+
+#include "zoneset.h"
+#include <cc/data.h>
+#include "data_source_plot.h"
+
+class ParkingLot {
+public:
+    explicit ParkingLot(int port);
+    virtual ~ParkingLot() {}
+    int getSocket() { return (sock); }
+    void processMessage();
+    void command(std::pair<std::string,isc::data::ElementPtr>);
+    void serve(std::string zone_name);
+
+    isc::data::ElementPtr updateConfig(isc::data::ElementPtr config);
+private:
+
+    isc::dns::DataSourceParkingLot data_source;
+    int sock;
+};
+
+#endif // __PARKINGLOT_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 217 - 0
src/bin/parkinglot/builtin.cc

@@ -0,0 +1,217 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <string>
+#include <vector>
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+#include <dns/rrset.h>
+
+#include "builtin.h"
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+const Name authors_name("authors.bind");
+const Name version_name("version.bind");
+
+const char* authors[] = {
+    "Han Feng",
+    "Kazunori Fujiwara",
+    "Michael Graff",
+    "Evan Hunt",
+    "Jelte Jansen",
+    "Jin Jian",
+    "JINMEI Tatuya",
+    "Naoki Kambe",
+    "Shane Kerr",
+    "Zhang Likun",
+    "Jeremy C. Reed",
+    NULL
+};
+
+const char* version[] = {
+    "BIND10 0.0.1",
+    NULL
+};
+
+const char* author_authorities[] = {
+    "authors.bind",
+    NULL
+};
+
+const char* version_authorities[] = {
+    "version.bind",
+    NULL
+};
+
+class BuiltinRRset : public AbstractRRset {
+private:
+    BuiltinRRset(const BuiltinRRset& source);
+    void operator=(const BuiltinRRset& source);
+public:
+    BuiltinRRset(const Name& name, const RRType& rrtype,
+                 const char** rdata_string_list);
+    virtual void addRdata(const rdata::RdataPtr rdata)
+    {
+        // ignore it (or we might throw an exception)
+    }
+    virtual unsigned int getRdataCount() const { return (num_rdata_); }
+    virtual const Name& getName() const { return (name_); }
+    virtual const RRClass& getClass() const { return (rrclass_); }
+    virtual const RRType& getType() const { return (rrtype_); }
+    virtual const RRTTL& getTTL() const { return (rrttl_); }
+    virtual void setTTL(const RRTTL& ttl)
+    {
+        // ignore it (or we might throw an exception)
+    }
+    virtual unsigned int toWire(MessageRenderer& renderer) const;
+    virtual RdataIteratorPtr getRdataIterator() const;
+
+    const Name name_;
+    const RRType rrtype_;
+    const RRClass rrclass_;
+    const RRTTL rrttl_;
+    vector<RdataPtr> rdatavector_;
+    unsigned int num_rdata_;
+    OutputBuffer wire_data_;    // pre-rendered RRset
+    size_t data_offset_;        // offset to the RRset data
+
+    static const size_t DATA_OFFSET = 12; // length of DNS header
+};
+
+class BuiltinRdataIterator : public RdataIterator {
+private:
+    BuiltinRdataIterator() {}
+public:
+    BuiltinRdataIterator(const vector<RdataPtr>& datavector) :
+        datavector_(&datavector) {}
+    ~BuiltinRdataIterator() {}
+    virtual void first() { it_ = datavector_->begin(); }
+    virtual void next() { ++it_; }
+    virtual const rdata::Rdata& getCurrent() const { return (**it_); }
+    virtual bool isLast() const { return (it_ == datavector_->end()); }
+private:
+    const vector<RdataPtr>* datavector_;
+    vector<RdataPtr>::const_iterator it_;
+};
+}
+
+BuiltinRRset::BuiltinRRset(const Name& name, const RRType& rrtype,
+                           const char** rdata_string_list) :
+    name_(name), rrtype_(rrtype), rrclass_(RRClass::CH()), rrttl_(RRTTL(0)),
+    num_rdata_(0), wire_data_(512)
+{
+    MessageRenderer renderer(wire_data_);
+    renderer.skip(DATA_OFFSET); // leave the space for the DNS header
+    renderer.writeName(name);
+    data_offset_ = renderer.getLength(); // remember the start position
+
+    RRset tmprrset(name, rrclass_, rrtype_, rrttl_);
+
+    for (int i = 0; rdata_string_list[i] != NULL; ++i) {
+        RdataPtr rdata = createRdata(rrtype_, rrclass_,
+                                     string(rdata_string_list[i]));
+        rdatavector_.push_back(rdata);
+        tmprrset.addRdata(rdata);
+    }
+
+    // pre-render the RRset
+    tmprrset.toWire(renderer);
+    num_rdata_ = rdatavector_.size();
+}
+
+unsigned int
+BuiltinRRset::toWire(MessageRenderer& renderer) const
+{
+    // XXX: we should confirm the query name matches the pre-rendered data
+    // and it's stored in the Question section.  This proof-of-concept
+    // implementation omits the check for brevity.
+    renderer.writeData(static_cast<const uint8_t*>(wire_data_.getData())
+                       + data_offset_, wire_data_.getLength() - data_offset_);
+    return (num_rdata_);
+}
+
+RdataIteratorPtr
+BuiltinRRset::getRdataIterator() const
+{
+    return (RdataIteratorPtr(new BuiltinRdataIterator(rdatavector_)));
+}
+
+struct BuiltinRRsetsImpl {
+    BuiltinRRsetsImpl(const Name& answer_name, const char** answers,
+                      const char** authorities);
+    RRsetPtr rrset_answer;
+    RRsetPtr rrset_authority;
+};
+
+BuiltinRRsetsImpl::BuiltinRRsetsImpl(const Name& answer_name,
+                                     const char** answers,
+                                     const char** authorities)
+{
+    rrset_answer = RRsetPtr(new BuiltinRRset(answer_name, RRType::TXT(),
+                                             answers));
+    rrset_authority = RRsetPtr(new BuiltinRRset(answer_name, RRType::NS(),
+                                                authorities));
+}
+
+BuiltinRRsets::BuiltinRRsets(const Name& name,
+                             const char** answers,
+                             const char** authorities)
+{
+    impl_ = new BuiltinRRsetsImpl(name, answers, authorities);
+}
+
+BuiltinRRsets::~BuiltinRRsets()
+{
+    delete impl_;
+}
+
+RRsetPtr
+BuiltinRRsets::getAnswer() const
+{
+    return (impl_->rrset_answer);
+}
+
+RRsetPtr
+BuiltinRRsets::getAuthority() const
+{
+    return (impl_->rrset_authority);
+}
+
+const BuiltinRRsets&
+getBuiltinAuthors()
+{
+    static BuiltinRRsets builtin_authors(authors_name, authors,
+                                         author_authorities);
+    return (builtin_authors);
+}
+
+const BuiltinRRsets&
+getBuiltinVersion()
+{
+    static BuiltinRRsets builtin_version(version_name, version,
+                                         version_authorities);
+    return (builtin_version);
+}

+ 49 - 0
src/bin/parkinglot/builtin.h

@@ -0,0 +1,49 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __BUILTIN_H
+#define __BUILTIN_H 1
+
+#include <boost/shared_ptr.hpp>
+
+#include <dns/name.h>
+#include <dns/rrset.h>
+
+struct BuiltinRRsetsImpl;
+
+class isc::dns::Name;
+
+class BuiltinRRsets {
+public:
+    BuiltinRRsets(const isc::dns::Name& name, const char** answers,
+                  const char** authorities);
+    ~BuiltinRRsets();
+    isc::dns::RRsetPtr getAnswer() const;
+    isc::dns::RRsetPtr getAuthority() const;
+private:
+    BuiltinRRsets(const BuiltinRRsets& source);
+    void operator=(const BuiltinRRsets& source);
+    BuiltinRRsetsImpl* impl_;
+};
+
+const BuiltinRRsets& getBuiltinAuthors();
+const BuiltinRRsets& getBuiltinVersion();
+
+#endif // __BUILTIN_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 241 - 0
src/bin/parkinglot/builtin_bench.cc

@@ -0,0 +1,241 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <sys/time.h>
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+#include <dns/rrset.h>
+
+#include "builtin.h"
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+static const int ITERATION = 100000;
+
+namespace {
+Name authors_name("authors.bind");
+
+inline double
+tv_sub(const struct timeval& t1, const struct timeval& t2)
+{
+    struct timeval result;
+
+    result.tv_sec = t1.tv_sec - t2.tv_sec;
+    result.tv_usec = t1.tv_usec - t2.tv_usec;
+    if (result.tv_usec < 0) {
+        result.tv_usec += 1000000;
+        result.tv_sec--;
+    }
+
+    return (result.tv_sec + result.tv_usec / 1000000.0);
+}
+
+void
+buildAuthors(vector<string>& authors)
+{
+    authors.push_back("Han Feng");
+    authors.push_back("Kazunori Fujiwara");
+    authors.push_back("Michael Graff");
+    authors.push_back("Evan Hunt");
+    authors.push_back("Jelte Jansen");
+    authors.push_back("Jin Jian");
+    authors.push_back("JINMEI Tatuya");
+    authors.push_back("Naoki Kambe");
+    authors.push_back("Shane Kerr"); 
+    authors.push_back("Zhang Likun");
+    authors.push_back("Jeremy C. Reed");
+}
+
+struct RdataInserterFromText
+{
+    RdataInserterFromText(RRsetPtr rrset) : rrset_(rrset) {}
+    void operator()(const string& author)
+    {
+        rrset_->addRdata(generic::TXT(author));
+    }
+    RRsetPtr rrset_;
+};
+
+inline RRsetPtr
+getNormalRRset(const vector<string>& authors)
+{
+    RRsetPtr rrset = RRsetPtr(new RRset(authors_name,  RRClass::CH(),
+                                        RRType::TXT(), RRTTL(0)));
+    for_each(authors.begin(), authors.end(), RdataInserterFromText(rrset));
+
+    return (rrset);
+}
+
+struct RdataInserterFromWire
+{
+    RdataInserterFromWire(RRsetPtr rrset) : rrset_(rrset) {}
+    void operator()(const OutputBuffer& buffer)
+    {
+        InputBuffer b(buffer.getData(), buffer.getLength());
+        rrset_->addRdata(RdataPtr(new generic::TXT(b, buffer.getLength())));
+    }
+    RRsetPtr rrset_;
+};
+
+inline RRsetPtr
+getNormalRRset(const vector<OutputBuffer>& buffers)
+{
+    RRsetPtr rrset = RRsetPtr(new RRset(authors_name,  RRClass::CH(),
+                                        RRType::TXT(), RRTTL(0)));
+    for_each(buffers.begin(), buffers.end(), RdataInserterFromWire(rrset));
+
+    return (rrset);
+}
+
+struct WireDataInserter
+{
+    WireDataInserter(vector<OutputBuffer>& buffers) : buffers_(buffers)
+    {}
+    void operator()(const string& author)
+    {
+        OutputBuffer buffer(0);
+        generic::TXT(author).toWire(buffer);
+        buffers_.push_back(buffer);
+    }
+    vector<OutputBuffer>& buffers_;
+};
+
+void
+showResult(const struct timeval& tv_begin, const struct timeval& tv_end,
+           int iteration, const char* description)
+{
+    double diff = tv_sub(tv_end, tv_begin);
+    cout << description << " " << iteration << " times in "
+         << fixed << diff << "sec ("
+         << static_cast<int>(iteration / diff) << "qps)" << endl;
+}
+}
+
+int
+main(int argc, char* argv[])
+{
+    int iteration = ITERATION;
+    if (argc > 1) {
+        istringstream(argv[1]) >> dec >> iteration;
+    }
+
+    vector<string> authors;
+    buildAuthors(authors);
+
+    struct timeval tv_begin, tv_end;
+    OutputBuffer buffer(512);
+    MessageRenderer renderer(buffer);
+
+    //
+    // Benchmark for rendering an optimized pre-format RRset
+    //
+    gettimeofday(&tv_begin, NULL);
+    for (int i = 0; i < iteration; ++i) {
+        renderer.clear();
+        renderer.skip(12);
+        renderer.writeName(authors_name);
+        RRsetPtr rrset_optimized = getBuiltinAuthors().getAnswer();
+        rrset_optimized->toWire(renderer);
+    }
+    gettimeofday(&tv_end, NULL);
+    showResult(tv_begin, tv_end, iteration, "Rendered optimized RRset");
+
+    vector<unsigned char> data(buffer.getLength());
+    memcpy(&data[0], buffer.getData(), buffer.getLength());
+
+    //
+    // Benchmark for rendering a general purpose RRset of the same content
+    //
+    RRsetPtr rrset_normal = getNormalRRset(authors);
+    gettimeofday(&tv_begin, NULL);
+    for (int i = 0; i < iteration; ++i) {
+        renderer.clear();
+        renderer.skip(12);
+        renderer.writeName(authors_name);
+        rrset_normal->toWire(renderer);
+    }
+    gettimeofday(&tv_end, NULL);
+    showResult(tv_begin, tv_end, iteration, "Rendered normal RRset");
+
+    // Confirm the two sets of output are identical.
+    if (data.size() != buffer.getLength() ||
+        memcmp(&data[0], buffer.getData(), buffer.getLength())) {
+        cerr << "Rendered data mismatch" << endl;
+        return (1);
+    }
+
+    //
+    // Benchmark for rendering a general purpose RRset of the same content,
+    // create RRset from text every time
+    //
+    gettimeofday(&tv_begin, NULL);
+    for (int i = 0; i < iteration; ++i) {
+        renderer.clear();
+        renderer.skip(12);
+        renderer.writeName(authors_name);
+        getNormalRRset(authors)->toWire(renderer);
+    }
+    gettimeofday(&tv_end, NULL);
+    showResult(tv_begin, tv_end, iteration,
+               "Rendered normal RRset with fromText");
+
+    // Confirm the two sets of output are identical.
+    if (data.size() != buffer.getLength() ||
+        memcmp(&data[0], buffer.getData(), buffer.getLength())) {
+        cerr << "Rendered data mismatch" << endl;
+        return (1);
+    }
+
+    //
+    // Benchmark for rendering a general purpose RRset of the same content,
+    // create RRset from wire data every time
+    //
+    vector<OutputBuffer> buffers;
+    for_each(authors.begin(), authors.end(), WireDataInserter(buffers));
+    gettimeofday(&tv_begin, NULL);
+    for (int i = 0; i < iteration; ++i) {
+        renderer.clear();
+        renderer.skip(12);
+        renderer.writeName(authors_name);
+        getNormalRRset(buffers)->toWire(renderer);
+    }
+    gettimeofday(&tv_end, NULL);
+    showResult(tv_begin, tv_end, iteration,
+               "Rendered normal RRset with fromWire");
+
+    // Confirm the two sets of output are identical.
+    if (data.size() != buffer.getLength() ||
+        memcmp(&data[0], buffer.getData(), buffer.getLength())) {
+        cerr << "Rendered data mismatch" << endl;
+        return (1);
+    }
+
+    return (0);
+}

+ 23 - 0
src/bin/parkinglot/common.cc

@@ -0,0 +1,23 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+#include "common.h"
+#include <iostream>
+
+FatalError::FatalError(std::string m) {
+    msg = m;
+    std::cerr << msg << std::endl;
+    exit(1);
+}

+ 36 - 0
src/bin/parkinglot/common.h

@@ -0,0 +1,36 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __COMMON_H
+#define __COMMON_H 1
+
+#include <stdlib.h>
+#include <string>
+
+class FatalError : public std::exception {
+public:
+    FatalError(std::string m = "fatal error");
+    ~FatalError() throw() {}
+    const char* what() const throw() { return msg.c_str(); }
+private:
+    std::string msg;
+};
+
+#endif // __COMMON_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 1 - 0
src/bin/parkinglot/config.h.in

@@ -0,0 +1 @@
+#define PARKINGLOT_SPECFILE_LOCATION "@prefix@/share/bind/parkinglot.spec"

+ 20 - 0
src/bin/parkinglot/data_source.cc

@@ -0,0 +1,20 @@
+#include <dns/buffer.h>
+#include <dns/name.h>
+#include <dns/rrset.h>
+#include <dns/message.h>
+
+#include <cc/data.h>
+
+#include "data_source.h"
+
+namespace isc {
+namespace dns {
+
+void
+DataSource::getData(isc::dns::RRsetPtr query, isc::dns::Message& answer)
+{
+    return;
+}
+
+}
+}

+ 123 - 0
src/bin/parkinglot/data_source.h

@@ -0,0 +1,123 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __DATA_SOURCE_H
+#define __DATA_SOURCE_H
+
+#include <dns/name.h>
+#include <dns/rrset.h>
+
+namespace isc {
+namespace dns {
+
+// do we need to make a template for this?
+// i.e. do we want this to be able to hold more types than RRset?
+class SearchResult {
+public:
+    SearchResult() : status(success) {};
+    enum status_type { success, error, not_implemented,
+                       zone_not_found, name_not_found };
+
+    void addRRset(RRsetPtr rrset) { rrsets.push_back(rrset); }
+
+    status_type getStatus() { return status; }
+    void setStatus(status_type s) { status = s; }
+    
+    /* forward iterator interface */
+    typedef std::vector<RRsetPtr>::iterator iterator;
+    typedef std::vector<RRsetPtr>::const_iterator const_iterator;
+    std::vector<RRsetPtr>::iterator begin() { return rrsets.begin(); }
+    std::vector<RRsetPtr>::iterator end() { return rrsets.end(); }
+    std::vector<RRsetPtr>::const_iterator begin() const { return rrsets.begin(); }
+    std::vector<RRsetPtr>::const_iterator end() const { return rrsets.end(); }
+    
+private:
+    status_type status;
+    std::vector<RRsetPtr> rrsets;
+};
+
+// Base class for a DNS Data Source
+class DataSource {
+public:
+    //enum result { success, not_implemented, error, zone_not_found,
+    //              name_not_found };
+
+    DataSource() {};
+    virtual ~DataSource() {};
+
+    //
+    // 'high-level' methods, these may or may not be overwritten;
+    // depending on the data source the default implementation
+    // may not be most efficient, but should at least provide
+    // the needed functionality
+    //
+
+    // fill in separate lists or simple fill in an answer Message object?
+    void getData(const RRsetPtr query, Message& answer);
+
+    // how to provide highlevel update data?
+    //result handleUpdate()
+    
+
+    //
+    // mandatory 'low-level' methods, an implementation must overwrite these
+    //
+    //
+    // for a 'catch-all' datasource, we need to be able to find
+    // out if it has a zone for a given name
+    //
+    // perhaps this should not set a zone Name, but rather a specific
+    // ZoneRef option (which could be datasource-specific, as it will
+    // only be used to pass along to other calls)
+    // Or even more abstract;
+    // SomeHandler initFind(name, whatever else);
+    virtual bool hasZoneFor(const Name& name, Name& zone_name) = 0;
+
+    // for the zone_name, see getZoneFor, perhaps this needs to be a more
+    // general handle
+    // And perhaps we need a function that does not have that argument too
+    virtual SearchResult findRRsets(const Name& zone_name,
+                                    const Name& name,
+                                    const RRClass& clas,
+                                    const RRType& type) const = 0;
+
+    //
+    // optional 'low-level' methods, an implementation may overwrite these,
+    // by default they return not_implemented
+    //
+    virtual void init() {};
+    virtual void close() {};
+    //virtual result addRR(Name name, int clas, int type,
+    //                     int ttl, Rdata::RdataPtr data)
+    //                    { return not_implemented; };
+    //virtual result delRR(isc::dns::Name name, int clas, int type) = 0;
+    // on name/class/type again? or use an already constructed object?
+    //virtual result getRRSigs(RRsetPtr target, const RRsetPtr rrset)
+    //                        { return not_implemented; };
+    //virtual result getNSECs(RRsetPtr target, const RRsetPtr rrset)
+    //                        { return not_implemented; };
+
+    // check if the zone exists, and if so, return something that could
+    // be used as a pointer for the rest of these functions?
+    // do we need this? do we want this?
+    //virtual int getZone(void* zone, isc::dns::Name name);
+    
+};
+
+}
+}
+
+#endif

+ 188 - 0
src/bin/parkinglot/data_source_plot.cc

@@ -0,0 +1,188 @@
+
+#include <boost/foreach.hpp>
+
+#include <dns/rdataclass.h>
+#include <dns/rrttl.h>
+
+#include "data_source_plot.h"
+
+namespace isc {
+namespace dns {
+
+// this implementation returns fixed records,
+// and does not allow update statements
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::data;
+
+namespace {
+const Name authors_name("authors.bind");
+const Name version_name("version.bind");
+}
+
+void
+DataSourceParkingLot::serve(std::string zone_name) {
+    zones.serve(zone_name);
+}
+
+void
+DataSourceParkingLot::addARecord(std::string data) {
+    a_records.push_back(RdataPtr(new in::A(data)));
+}
+
+void
+DataSourceParkingLot::addAAAARecord(std::string data) {
+    aaaa_records.push_back(RdataPtr(new in::AAAA(data)));
+}
+
+void
+DataSourceParkingLot::addNSRecord(std::string data) {
+    ns_records.push_back(RdataPtr(new generic::NS(data)));
+}
+
+void
+DataSourceParkingLot::setSOARecord(RdataPtr soa_record) {
+}
+
+void
+DataSourceParkingLot::setDefaultZoneData() {
+    clearARecords();
+    clearAAAARecords();
+    clearNSRecords();
+
+    addARecord("127.0.0.1");
+    addAAAARecord("::1");
+    addNSRecord("ns1.parking.example");
+    addNSRecord("ns2.parking.example");
+    addNSRecord("ns3.parking.example");
+}
+
+DataSourceParkingLot::DataSourceParkingLot() {
+    setDefaultZoneData();
+    soa = RdataPtr(new generic::SOA(Name("parking.example"),
+                                    Name("noc.parking.example"),
+                                    1, 1800, 900, 604800, 86400));
+}
+
+bool
+DataSourceParkingLot::hasZoneFor(const Name& name, Name &zone_name)
+{
+    if (name == authors_name) {
+        zone_name = authors_name;
+        return (true);
+    } else if (name == version_name) {
+        zone_name = version_name;
+        return (true);
+    }
+    return zones.findClosest(name, zone_name);
+}
+
+SearchResult
+DataSourceParkingLot::findRRsets(const isc::dns::Name& zone_name,
+                                 const isc::dns::Name& name,
+                                 const isc::dns::RRClass& clas,
+                                 const isc::dns::RRType& type) const
+{
+    SearchResult result;
+    
+    if (clas == RRClass::CH()) {
+        if (type == RRType::TXT()) {
+            if (name == authors_name) {
+                RRsetPtr rrset = RRsetPtr(new RRset(authors_name, RRClass::CH(),
+                                                    RRType::TXT(), RRTTL(0)));
+                rrset->addRdata(generic::TXT("Han Feng"));
+                rrset->addRdata(generic::TXT("Kazunori Fujiwara"));
+                rrset->addRdata(generic::TXT("Michael Graff"));
+                rrset->addRdata(generic::TXT("Evan Hunt"));
+                rrset->addRdata(generic::TXT("Jelte Jansen"));
+                rrset->addRdata(generic::TXT("Jin Jian"));
+                rrset->addRdata(generic::TXT("JINMEI Tatuya"));
+                rrset->addRdata(generic::TXT("Naoki Kambe"));
+                rrset->addRdata(generic::TXT("Shane Kerr")); 
+                rrset->addRdata(generic::TXT("Zhang Likun"));
+                rrset->addRdata(generic::TXT("Jeremy C. Reed")); 
+
+                result.addRRset(rrset);
+                result.setStatus(SearchResult::success);
+            } else if (name == version_name) {
+                RRsetPtr rrset = RRsetPtr(new RRset(version_name, RRClass::CH(),
+                                                    RRType::TXT(), RRTTL(0)));
+                rrset->addRdata(generic::TXT("BIND10 0.0.1"));
+                result.addRRset(rrset);
+                result.setStatus(SearchResult::success);
+            } else {
+                result.setStatus(SearchResult::name_not_found);
+            }
+        } else if (type == RRType::NS()) {
+            if (name == authors_name || name == version_name) {
+                RRsetPtr rrset = RRsetPtr(new RRset(name, RRClass::CH(),
+                                                    RRType::NS(),
+                                                    RRTTL(0)));
+                rrset->addRdata(generic::NS(name));
+                result.addRRset(rrset);
+                result.setStatus(SearchResult::success);
+            } else {
+                result.setStatus(SearchResult::name_not_found);
+            }
+        } else {
+            result.setStatus(SearchResult::name_not_found);
+        }
+    } else if (clas == RRClass::IN()) {
+        if (zones.contains(name)) {
+            RRsetPtr rrset = RRsetPtr(new RRset(name, clas, type, RRTTL(3600)));
+            result.setStatus(SearchResult::success);
+            if (type == RRType::A()) {
+                BOOST_FOREACH(RdataPtr a, a_records) {
+                    rrset->addRdata(a);
+                }
+            } else if (type == RRType::AAAA()) {
+                BOOST_FOREACH(RdataPtr aaaa, aaaa_records) {
+                    rrset->addRdata(aaaa);
+                }
+            } else if (type == RRType::NS()) {
+                BOOST_FOREACH(RdataPtr ns, ns_records) {
+                    rrset->addRdata(ns);
+                }
+            } else if (type == RRType::SOA()) {
+                rrset->addRdata(soa);
+            }
+            result.addRRset(rrset);
+        } else {
+            // we don't have the name itself. Do we have the zone?
+            if (zones.contains(zone_name)) {
+                result.setStatus(SearchResult::name_not_found);
+            } else {
+                result.setStatus(SearchResult::zone_not_found);
+            }
+        }
+    } else {
+        result.setStatus(SearchResult::zone_not_found);
+    }
+    return result;
+}
+
+/// Do direct 'search' in database, no extra processing,
+/// and add the resulting rrsets to the specified section
+/// in the given message
+/// returns the status code of the searchresult
+/// Once the dns logic is moved from parkinglot to this class,
+/// we should probably make this private
+SearchResult::status_type
+DataSourceParkingLot::addToMessage(Message& msg,
+             const Section& section,
+             const Name& zone_name,
+             const Name& name,
+             const RRClass& clas,
+             const RRType& type) const
+{
+    SearchResult result = findRRsets(zone_name, name, clas, type);
+    BOOST_FOREACH(RRsetPtr rrset, result) {
+        msg.addRRset(section, rrset);
+    }
+    return result.getStatus();
+}
+
+
+}
+}

+ 96 - 0
src/bin/parkinglot/data_source_plot.h

@@ -0,0 +1,96 @@
+
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __DATA_SOURCE_SIMPLE_H
+#define __DATA_SOURCE_SIMPLE_H
+
+#include <dns/buffer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrset.h>
+#include <dns/message.h>
+
+#include <cc/data.h>
+
+#include "common.h"
+
+#include "data_source.h"
+
+#include "zoneset.h"
+
+namespace isc {
+namespace dns {
+
+class DataSourceParkingLot : public DataSource {
+public:
+    DataSourceParkingLot();
+    
+    void init() {};
+    void close() {};
+    bool hasZoneFor(const Name& name, Name &zone_name);
+    SearchResult findRRsets(const isc::dns::Name& zone_name,
+                            const isc::dns::Name& name,
+                            const isc::dns::RRClass& clas,
+                            const isc::dns::RRType& type) const;
+
+    /* move these to private (or to zoneset) and the calling functions
+     * from parkinglot to here? */
+    void serve(std::string zone_name);
+    void clear_zones() { zones.clear_zones(); };
+
+    void clearARecords() { a_records.clear(); };
+    void clearAAAARecords() { aaaa_records.clear(); };
+    void clearNSRecords() { ns_records.clear(); };
+
+    void addARecord(std::string data);
+    void addAAAARecord(std::string data);
+    void addNSRecord(std::string data);
+
+    void setSOARecord(isc::dns::rdata::RdataPtr soa_record);
+
+    /// Do direct 'search' in database, no extra processing,
+    /// and add the resulting rrsets to the specified section
+    /// in the given message
+    /// Once the dns logic is moved from parkinglot to this class,
+    /// we should probably make this private
+    SearchResult::status_type addToMessage(Message& msg,
+                                           const isc::dns::Section& section,
+                                           const isc::dns::Name& zone_name,
+                                           const isc::dns::Name& name,
+                                           const isc::dns::RRClass& clas,
+                                           const isc::dns::RRType& type) const;
+
+private:
+    //
+    void setDefaultZoneData();
+
+    std::vector<isc::dns::rdata::RdataPtr> a_records, aaaa_records, ns_records;
+    isc::dns::rdata::RdataPtr soa;
+    ZoneSet zones;
+
+};
+
+}
+}
+
+#endif
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 148 - 0
src/bin/parkinglot/main.cc

@@ -0,0 +1,148 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+#include <set>
+#include <iostream>
+
+#include <boost/foreach.hpp>
+
+#include <dns/buffer.h>
+#include <dns/name.h>
+#include <dns/rrset.h>
+#include <dns/message.h>
+
+#include <cc/session.h>
+#include <cc/data.h>
+#include <config/ccsession.h>
+
+#include "zoneset.h"
+#include "b10-parkinglot.h"
+
+#include "common.h"
+
+#include <boost/foreach.hpp>
+
+#include "config.h"
+
+using namespace std;
+
+//const string PROGRAM = "ParkingLot";
+const int DNSPORT = 5300;
+
+/* need global var for config/command handlers.
+ * todo: turn this around, and put handlers in the parkinglot
+ * class itself? */
+ParkingLot plot = ParkingLot(DNSPORT);
+
+static void
+usage() {
+    cerr << "Usage: parkinglot [-p port]" << endl;
+    exit(1);
+}
+
+isc::data::ElementPtr
+my_config_handler(isc::data::ElementPtr config)
+{
+    return plot.updateConfig(config);
+}
+
+isc::data::ElementPtr
+my_command_handler(isc::data::ElementPtr command)
+{
+    isc::data::ElementPtr answer = isc::data::Element::createFromString("{ \"result\": [0] }");
+
+    if (command->get(0)->stringValue() == "print_message") 
+    {
+        cout << command->get(1)->get("message") << endl;
+        /* let's add that message to our answer as well */
+        answer->get("result")->add(command->get(1));
+    }
+
+    return answer;
+}
+
+int
+main(int argc, char* argv[]) {
+    int ch;
+    int port = DNSPORT;
+
+    while ((ch = getopt(argc, argv, "p:")) != -1) {
+        switch (ch) {
+        case 'p':
+            port = atoi(optarg);
+            break;
+        case '?':
+        default:
+            usage();
+        }
+    }
+
+    if (argc - optind > 0)
+        usage();
+
+    // initialize parking lot
+    //plot = ParkingLot(port);
+
+    // initialize command channel
+    try {
+        std::string specfile;
+        if (getenv("B10_FROM_SOURCE")) {
+            specfile = std::string(getenv("B10_FROM_SOURCE")) + "/src/bin/parkinglot/parkinglot.spec";
+        } else {
+            specfile = std::string(PARKINGLOT_SPECFILE_LOCATION);
+        }
+        CommandSession cs = CommandSession(specfile, my_config_handler, my_command_handler);
+    
+        // main server loop
+        fd_set fds;
+        int ps = plot.getSocket();
+        int ss = cs.getSocket();
+        int nfds = max(ps, ss) + 1;
+        int counter = 0;
+    
+        cout << "[parkinglot] Server started." << endl;
+        while (true) {
+            FD_ZERO(&fds);
+            FD_SET(ps, &fds);
+            FD_SET(ss, &fds);
+    
+            int n = select(nfds, &fds, NULL, NULL, NULL);
+            if (n < 0)
+                throw FatalError("[parkinglot] select error");
+    
+            if (FD_ISSET(ps, &fds)) {
+                ++counter;
+                plot.processMessage();
+            }
+    
+            /* isset not really necessary, but keep it for now */
+            if (FD_ISSET(ss, &fds)) {
+                cs.check_command();
+            }
+        }
+    } catch (isc::cc::SessionError se) {
+        cout << se.what() << endl;
+        exit(1);
+    }
+    
+    return (0);
+}

+ 74 - 0
src/bin/parkinglot/parkinglot.spec

@@ -0,0 +1,74 @@
+{
+  "data_specification": {
+    "module_name": "ParkingLot",
+    "config_data": [
+      {
+        "item_name": "port",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 5300
+      },
+      {
+        "item_name": "zones",
+        "item_type": "list",
+        "item_optional": false,
+        "item_default": [ ],
+        "list_item_spec": {
+          "item_name": "zone_name",
+          "item_type": "string",
+          "item_optional": false,
+          "item_default": ""
+        }
+      },
+      {
+        "item_name": "a_records",
+        "item_type": "list",
+        "item_optional": false,
+        "item_default": [ "127.0.0.1" ],
+        "list_item_spec": {
+          "item_name": "address",
+          "item_type": "string",
+          "item_optional": false,
+          "item_default": ""
+        }
+      },
+      {
+        "item_name": "aaaa_records",
+        "item_type": "list",
+        "item_optional": false,
+        "item_default": [ "::1" ],
+        "list_item_spec": {
+          "item_name": "address",
+          "item_type": "string",
+          "item_optional": false,
+          "item_default": ""
+        }
+      },
+      {
+        "item_name": "ns_records",
+        "item_type": "list",
+        "item_optional": false,
+        "item_default": [ "ns1.parking.example", "ns2.parking.example" ],
+        "list_item_spec": {
+          "item_name": "address",
+          "item_type": "string",
+          "item_optional": false,
+          "item_default": ""
+        }
+      }
+    ],
+    "commands": [
+      {
+        "command_name": "print_message",
+        "command_description": "Print the given message to stdout",
+        "command_args": [ {
+          "item_name": "message",
+          "item_type": "string",
+          "item_optional": False,
+          "item_default": ""
+        } ]
+      }
+    ]
+  }
+}
+

+ 37 - 0
src/bin/parkinglot/zoneset.cc

@@ -0,0 +1,37 @@
+#include "zoneset.h"
+
+// see findClosest()
+static bool
+stripLabel(isc::dns::Name& n) {
+    std::string str = n.toText(false);
+    size_t pos = str.find('.');
+    if (pos + 1 < str.size()) {
+        n = isc::dns::Name(str.substr(pos+1));
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool
+ZoneSet::findClosest(const isc::dns::Name& n, isc::dns::Name& closest) {
+
+    // name compare doesnt work in this branch, so we convert and
+    // strip labels
+    isc::dns::Name cur = n;
+    if (contains(n)) {
+        closest = n;
+        return true;
+    }
+
+    bool labels_left = stripLabel(cur);
+    while(labels_left) {
+        if (contains(cur)) {
+            closest = cur;
+            return true;
+        } else {
+            labels_left = stripLabel(cur);
+        }
+    }
+    return false;
+}

+ 64 - 0
src/bin/parkinglot/zoneset.h

@@ -0,0 +1,64 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __ZONESET_H
+#define __ZONESET_H 1
+
+#include <set>
+#include <dns/buffer.h>
+#include <dns/name.h>
+
+class ZoneSet {
+public:
+    void serve(const std::string& s) {
+        serve(isc::dns::Name(s));
+    }
+
+    void serve(const isc::dns::Name& n) {
+        elements.insert(n);
+    }
+    
+    void forget(const std::string& s) {
+        forget(isc::dns::Name(s));
+    }
+
+    void forget(const isc::dns::Name& n) {
+        elements.erase(n);
+    }
+
+    void clear_zones() {
+        elements.clear();
+    }
+
+    bool contains(const std::string& s) const {
+        return contains(isc::dns::Name(s));
+    }
+
+    bool contains(const isc::dns::Name& n) const {
+        return (elements.find(n) != elements.end());
+    }
+
+    bool findClosest(const isc::dns::Name& n, isc::dns::Name& closest);
+
+private:
+    std::set<isc::dns::Name> elements;
+};
+
+#endif // __ZONESET_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 2 - 24
src/lib/dns/cpp/Makefile.am

@@ -1,3 +1,5 @@
+SUBDIRS = . tests
+
 AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/ext
 
 CLEANFILES = *.gcno *.gcda
@@ -23,27 +25,3 @@ rrtype.h: rrtype-placeholder.h
 rrparamregistry.cc: rrparamregistry-placeholder.cc
 rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 	./gen-rdatacode.py
-
-TESTS =
-if HAVE_GTEST
-TESTS += run_unittests
-run_unittests_SOURCES = unittest_util.h unittest_util.cc
-run_unittests_SOURCES += buffer_unittest.cc name_unittest.cc
-run_unittests_SOURCES += messagerenderer_unittest.cc
-run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
-run_unittests_SOURCES += rrttl_unittest.cc
-run_unittests_SOURCES += rdata_unittest.cc
-run_unittests_SOURCES += rrset_unittest.cc
-run_unittests_SOURCES += rrsetlist_unittest.cc
-run_unittests_SOURCES += question_unittest.cc
-run_unittests_SOURCES += rrparamregistry_unittest.cc
-run_unittests_SOURCES += message_unittest.cc
-run_unittests_SOURCES += base64_unittest.cc
-run_unittests_SOURCES += run_unittests.cc
-run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
-run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-run_unittests_LDADD = .libs/libdns.a $(GTEST_LDADD)
-run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/cpp/.libs/libexceptions.a
-endif
-
-noinst_PROGRAMS = $(TESTS)

+ 105 - 60
src/lib/dns/cpp/gen-rdatacode.py.in

@@ -22,6 +22,7 @@ classes and constants.
 """
 
 import os
+from os.path import getmtime
 import re
 import sys
 
@@ -30,13 +31,16 @@ classcode2txt = {}
 typecode2txt = {}
 typeandclass = []
 generic_code = 65536            # something larger than any code value
-class_declarations = ''
+rdata_declarations = ''
 class_definitions = ''
+classdir_mtime = 0
+rdatadef_mtime = 0
+rdatahdr_mtime = 0
 copyright_file = '@top_srcdir@' + os.sep + 'COPYING'
 
 def import_classdef(class_txt, file):
-    rdata_source = open(file, 'r')
     content = ''
+    rdata_source = open(file, 'r')
     for line in rdata_source.readlines():
         if re.match('// BEGIN_ISC_NAMESPACE', line):
             content += 'namespace isc {\n'
@@ -59,6 +63,9 @@ def import_classdef(class_txt, file):
     return content
 
 def import_classheader(class_txt, type_txt, type_code, file):
+    type_utxt = type_txt.upper()
+    class_utxt = class_txt.upper()
+
     # for each CLASS_n/TYPE_m.h
     rdata_header = open(file, 'r')
     content = ''
@@ -125,12 +132,19 @@ def import_copyright():
 '''
     return copyright_txt
 
-if __name__ == "__main__":
-    copyright_txt = import_copyright()
+def import_definitions(classcode2txt, typecode2txt, typeandclass):
+    global rdata_declarations
+    global class_definitions
+    global classdir_mtime
+    global rdatadef_mtime
+    global rdatahdr_mtime
+
     for dir in list(os.listdir('@srcdir@/rdata')):
         classdir = '@srcdir@/rdata' + os.sep + dir
         m = re_typecode.match(dir)
         if os.path.isdir(classdir) and (m != None or dir == 'generic'):
+            if classdir_mtime < getmtime(classdir):
+                classdir_mtime = getmtime(classdir)
             if dir == 'generic':
                 class_txt = 'generic'
                 class_code = generic_code
@@ -145,15 +159,16 @@ if __name__ == "__main__":
                 if m != None:
                     type_txt = m.group(1)
                     type_code = m.group(2)
-                    type_utxt = type_txt.upper()
-                    class_utxt = class_txt.upper()
-
                     if not type_code in typecode2txt:
                         typecode2txt[type_code] = type_txt
                     if re.search('\cc$', file):
+                        if rdatadef_mtime < getmtime(file):
+                            rdatadef_mtime = getmtime(file)
                         class_definitions += import_classdef(class_txt, file)
                     elif re.search('\h$', file):
-                        class_declarations += import_classheader(class_txt,
+                        if rdatahdr_mtime < getmtime(file):
+                            rdatahdr_mtime = getmtime(file)
+                        rdata_declarations += import_classheader(class_txt,
                                                                  type_txt,
                                                                  type_code,
                                                                  file)
@@ -163,78 +178,89 @@ if __name__ == "__main__":
                         if class_txt == 'generic':
                             typeandclass.append((type_txt, int(type_code),
                                                  (class_txt, 'in'), 1))
-    rdata_deffile = open('@srcdir@/rdataclass.cc', 'w')
+
+def need_generate(file, mtime):
+    '''Check if we need to generate the specified file.
+
+    To avoid unnecessary compilation, we skip (re)generating the file when
+    the file already exists and newer than the base file.
+    '''
+    if os.path.exists(file) and getmtime(file) > mtime:
+        return False
+    return True
+
+def generate_rdatadef(file, copyright_txt, basemtime):
+    if not need_generate(file, basemtime):
+        print('skip generating ' + file);
+        return
+    rdata_deffile = open(file, 'w')
     rdata_deffile.write(copyright_txt)
     rdata_deffile.write(class_definitions)
     rdata_deffile.close()
 
-    class_declarations += '''
+def generate_rdatahdr(file, copyright_txt, declarations, basemtime):
+    if not need_generate(file, basemtime):
+        print('skip generating ' + file);
+        return
+    declarations += '''
 // Local Variables:
 // mode: c++
 // End:
 '''
-    rdata_header = open('@srcdir@/rdataclass.h', 'w')
+    rdata_header = open(file, 'w')
     rdata_header.write(copyright_txt)
-    rdata_header.write(class_declarations)
+    rdata_header.write(declarations)
     rdata_header.close()
-    
-    declarationtxt = ''
-    deftxt = ''
-    for code in typecode2txt.keys():
-        # for rrtype.h
-        rrtype = typecode2txt[code].upper()
-        declarationtxt += ' ' * 4 + 'static const RRType& ' + rrtype + '();\n'
-        deftxt += '''inline const RRType&
-RRType::''' + rrtype + '''()
-{
-    static RRType rrtype(''' + code + ''');
-    return (rrtype);
-}\n
-'''
-    rrtype_header_temp = open('@srcdir@/rrtype-placeholder.h', 'r')
-    rrtype_header_out = open('@srcdir@/rrtype.h', 'w')
-    rrtype_header_out.write(copyright_txt)
-    for line in rrtype_header_temp.readlines():
-        rrtype_header_out.write(line)
-        if re.match('\s+// BEGIN_WELL_KNOWN_TYPE_DECLARATIONS$', line):
-            rrtype_header_out.write(declarationtxt)
-        if re.match('// BEGIN_WELL_KNOWN_TYPE_DEFINITIONS$', line):
-            rrtype_header_out.write('\n' + deftxt)
-    rrtype_header_out.close()
-    rrtype_header_temp.close()
+
+def generate_typeclasscode(fileprefix, basemtime, code2txt, type_or_class):
+    placeholder = fileprefix + '-placeholder.h'
+    outputfile = fileprefix + '.h'
+    upper_key = type_or_class.upper() # TYPE or CLASS
+    lower_key = 'rr' + type_or_class.lower() # rrtype or rrclass
+    cap_key = type_or_class           # Type or Class
+
+    if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
+        print('skip generating ' + outputfile)
+        return
 
     declarationtxt = ''
     deftxt = ''
-    for code in classcode2txt.keys():
-        # for rrclass.h
-        rrclass = classcode2txt[code].upper()
-        declarationtxt += ' ' * 4 + 'static const RRClass& ' + rrclass + '();\n'
-        deftxt += '''inline const RRClass&
-RRClass::''' + rrclass + '''()
+    for code in code2txt.keys():
+        codetxt = code2txt[code].upper()
+        declarationtxt += ' ' * 4 + 'static const RR' + cap_key + '& ' + codetxt + '();\n'
+        deftxt += '''inline const RR''' + cap_key + '''&
+RR''' + cap_key + '''::''' + codetxt + '''()
 {
-    static RRClass rrclass(''' + code + ''');
-    return (rrclass);
+    static RR''' + cap_key + ''' ''' + lower_key + '''(''' + code + ''');
+    return (''' + lower_key + ''');
 }\n
 '''
+    header_temp = open(placeholder, 'r')
+    header_out = open(outputfile, 'w')
+    header_out.write(copyright_txt)
+    for line in header_temp.readlines():
+        header_out.write(line)
+        if re.match('\s+// BEGIN_WELL_KNOWN_' + upper_key + '_DECLARATIONS$', line):
+            header_out.write(declarationtxt)
+        if re.match('// BEGIN_WELL_KNOWN_' + upper_key + '_DEFINITIONS$', line):
+            header_out.write('\n' + deftxt)
+    header_out.close()
+    header_temp.close()
 
-    rrclass_header_temp = open('@srcdir@/rrclass-placeholder.h', 'r')
-    rrclass_header_out = open('@srcdir@/rrclass.h', 'w')
-    rrclass_header_out.write(copyright_txt)
-    for line in rrclass_header_temp.readlines():
-        rrclass_header_out.write(line)
-        if re.match('\s+// BEGIN_WELL_KNOWN_CLASS_DECLARATIONS$', line):
-            rrclass_header_out.write(declarationtxt)
-        if re.match('// BEGIN_WELL_KNOWN_CLASS_DEFINITIONS$', line):
-            rrclass_header_out.write('\n' + deftxt)
-    rrclass_header_out.close()
-    rrclass_header_temp.close()
+def generate_rrparam(fileprefix, basemtime):
+    placeholder = fileprefix + '-placeholder.cc'
+    outputfile = fileprefix + '.cc'
+    if not need_generate(outputfile, basemtime) and getmtime(outputfile) > getmtime(placeholder):
+        print('skip generating ' + outputfile)
+        return
 
     # sort by class, then by type
     typeandclassparams = ''
     typeandclass.sort(key = lambda x: (x[3], x[1]))
     for param in typeandclass:
-        # for rdata.cc
-        # each param is a tuple of (type_txt, type_code, class_tuple, class_code)
+        # for rrparamregistry.cc
+        # each param is a tuple of (type_txt, type_code, class_tuple,
+        #                           class_code)
         (type_txt, type_code, class_tuple, class_code) = param
         type_utxt = type_txt.upper()
         class_txt = class_tuple[0]
@@ -252,8 +278,8 @@ RRClass::''' + rrclass + '''()
             typeandclassparams += ', RdataFactoryPtr(new RdataFactory<'
             typeandclassparams += class_txt + '::' + type_utxt + '>()));\n'
 
-    rrparam_temp = open('@srcdir@/rrparamregistry-placeholder.cc', 'r')
-    rrparam_out = open('@srcdir@/rrparamregistry.cc', 'w')
+    rrparam_temp = open(placeholder, 'r')
+    rrparam_out = open(outputfile, 'w')
     rrparam_out.write(copyright_txt)
     for line in rrparam_temp.readlines():
         rrparam_out.write(line)
@@ -261,3 +287,22 @@ RRClass::''' + rrclass + '''()
             rrparam_out.write(typeandclassparams)
     rrparam_temp.close()
     rrparam_out.close()
+
+if __name__ == "__main__":
+    try:
+        copyright_txt = import_copyright()
+        import_definitions(classcode2txt, typecode2txt, typeandclass)
+        generate_rdatadef('@srcdir@/rdataclass.cc', copyright_txt,
+                          rdatadef_mtime)
+        generate_rdatahdr('@srcdir@/rdataclass.h', copyright_txt,
+                          rdata_declarations, rdatahdr_mtime)
+        generate_typeclasscode('@srcdir@/rrtype',
+                               max(rdatadef_mtime, rdatahdr_mtime),
+                               typecode2txt, 'Type')
+        generate_typeclasscode('@srcdir@/rrclass', classdir_mtime,
+                               classcode2txt, 'Class')
+        generate_rrparam('@srcdir@/rrparamregistry', rdatahdr_mtime)
+    except:
+        sys.stderr.write('Code generation failed due to exception: %s\n' %
+                         sys.exc_info()[1])
+        exit(1)

+ 152 - 25
src/lib/dns/cpp/rdata.cc

@@ -14,8 +14,14 @@
 
 // $Id$
 
+#include <algorithm>
 #include <cctype>
 #include <string>
+#include <sstream>
+#include <iomanip>
+#include <ios>
+#include <ostream>
+#include <vector>
 
 #include <stdint.h>
 #include <string.h>
@@ -23,8 +29,6 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/shared_ptr.hpp>
 
-#include <arpa/inet.h> // XXX: for inet_pton/ntop(), not exist in C++ standards
-
 #include "buffer.h"
 #include "name.h"
 #include "messagerenderer.h"
@@ -53,6 +57,10 @@ RdataPtr
 createRdata(const RRType& rrtype, const RRClass& rrclass,
             InputBuffer& buffer, size_t len)
 {
+    if (len > MAX_RDLENGTH) {
+        dns_throw(InvalidRdataLength, "RDLENGTH too large");
+    }
+
     size_t old_pos = buffer.getPosition();
 
     RdataPtr rdata =
@@ -78,14 +86,14 @@ compareNames(const Name& n1, const Name& n2)
 {
     size_t len1 = n1.getLength();
     size_t len2 = n2.getLength();
-    size_t cmplen = (len1 < len2) ? len1 : len2;
+    size_t cmplen = min(len1, len2);
 
     for (size_t i = 0; i < cmplen; ++i) {
         uint8_t c1 = tolower(n1.at(i));
         uint8_t c2 = tolower(n2.at(i));
         if (c1 < c2) {
             return (-1);
-        } else if (c2 > c1) {
+        } else if (c1 > c2) {
             return (1);
         }
     }
@@ -94,62 +102,181 @@ compareNames(const Name& n1, const Name& n2)
 }
 
 namespace generic {
-Generic::Generic(InputBuffer& buffer, size_t rdata_len) :
-    data_(rdata_len)
+struct GenericImpl {
+    GenericImpl(const vector<uint8_t>& data) : data_(data) {}
+    vector<uint8_t> data_;
+};
+
+Generic::Generic(InputBuffer& buffer, size_t rdata_len)
 {
-    buffer.readData(&data_[0], rdata_len);
-    data_.resize(rdata_len);
+    if (rdata_len > MAX_RDLENGTH) {
+        dns_throw(InvalidRdataLength, "RDLENGTH too large");
+    }
+
+    vector<uint8_t> data(rdata_len);
+    buffer.readData(&data[0], rdata_len);
+    data.resize(rdata_len);
+
+    impl_ = new GenericImpl(data);
 }
 
 Generic::Generic(const string& rdata_string)
 {
-    // parse the \# n xx xx... format (TBD)
+    istringstream iss(rdata_string);
+    string unknown_mark;
+    iss >> unknown_mark;
+    if (unknown_mark != "\\#") {
+        dns_throw(InvalidRdataText,
+                  "Missing the special token (\\#) for generic RDATA encoding");
+    }
+
+    // RDLENGTH: read into a string so that we can easily reject invalid tokens
+    string rdlen_txt;
+    iss >> rdlen_txt;
+    istringstream iss_rdlen(rdlen_txt);
+    int32_t rdlen;
+    iss_rdlen >> rdlen;
+    if (iss_rdlen.rdstate() != ios::eofbit) {
+        dns_throw(InvalidRdataText,
+                  "Invalid representation for a generic RDLENGTH");
+    }
+    if (rdlen < 0 || rdlen > 0xffff) {
+        dns_throw(InvalidRdataLength, "RDATA length is out of range");
+    }
+    iss >> ws;                  // skip any white spaces
+
+    // Hexadecimal encoding of RDATA: each segment must consist of an even
+    // number of hex digits.
+    vector<uint8_t> data;
+    while (!iss.eof() && data.size() < rdlen) {
+        // extract two characters, which should compose a single byte of data.
+        char buf[2];
+        iss.read(buf, sizeof(buf));
+        if ((iss.rdstate() & (ios::badbit | ios::failbit)) != 0) {
+            dns_throw(InvalidRdataText,
+                      "Invalid hex encoding of generic RDATA");
+        }
+
+        // convert it to a single byte integer as a hex digit.
+        istringstream iss_byte(string(buf, sizeof(buf)));
+        unsigned int ch;
+        iss_byte >> hex >> ch;
+        if (iss_byte.rdstate() != ios::eofbit) {
+            dns_throw(InvalidRdataText,
+                      "Invalid hex encoding of generic RDATA");
+        }
+        data.push_back(ch);
+        iss >> ws;              // skip spaces
+    }
+
+    if (!iss.eof()) {
+        dns_throw(InvalidRdataLength,
+                  "RDLENGTH is too small for generic RDATA");
+    }
+
+    if (data.size() != rdlen) {
+        dns_throw(InvalidRdataLength,
+                  "Generic RDATA code doesn't match RDLENGTH");
+    }
+
+    impl_ = new GenericImpl(data);
+}
+
+Generic::~Generic()
+{
+    delete impl_;
+}
+
+Generic::Generic(const Generic& source) :
+    impl_(new GenericImpl(*source.impl_))
+{}
+
+Generic&
+Generic::operator=(const Generic& source)
+{
+    if (impl_ == source.impl_) {
+        return (*this);
+    }
+
+    GenericImpl* newimpl = new GenericImpl(*source.impl_);
+    delete impl_;
+    impl_ = newimpl;
+
+    return (*this);
+}
+
+namespace {
+class UnknownRdataDumper {
+public:
+    UnknownRdataDumper(ostringstream& oss) : oss_(&oss) {}
+    void operator()(const unsigned char d)
+    {
+        *oss_ << setw(2) << static_cast<unsigned int>(d);
+    }
+private:
+    ostringstream* oss_;
+};
 }
 
 string
 Generic::toText() const
 {
-    // return rdata in the \# n xx xx format (TBD)
-    dns_throw(InvalidRdataText, "Not implemented yet");
+    ostringstream oss;
+
+    oss << "\\# " << impl_->data_.size() << " ";
+    oss.fill('0');
+    oss << right << hex;
+    for_each(impl_->data_.begin(), impl_->data_.end(), UnknownRdataDumper(oss));
+
+    return (oss.str());
 }
 
 void
 Generic::toWire(OutputBuffer& buffer) const
 {
-    buffer.writeData(&data_[0], data_.size());
+    buffer.writeData(&impl_->data_[0], impl_->data_.size());
 }
 
 void
 Generic::toWire(MessageRenderer& renderer) const
 {
-    renderer.writeData(&data_[0], data_.size());
+    renderer.writeData(&impl_->data_[0], impl_->data_.size());
 }
 
-int
-Generic::compare(const Rdata& other) const
+namespace {
+inline int
+compare_internal(const GenericImpl& lhs, const GenericImpl& rhs)
 {
-    const Generic& other_rdata = dynamic_cast<const Generic&>(other);
-
-    size_t this_len = data_.size();
-    size_t other_len = other_rdata.data_.size();
+    size_t this_len = lhs.data_.size();
+    size_t other_len = rhs.data_.size();
     size_t len = (this_len < other_len) ? this_len : other_len;
     int cmp;
 
-    if ((cmp = memcmp(&data_[0], &other_rdata.data_[0], len)) != 0) {
+    if ((cmp = memcmp(&lhs.data_[0], &rhs.data_[0], len))
+        != 0) {
         return (cmp);
     } else {
         return ((this_len == other_len) ? 0 :
                 (this_len < other_len) ? -1 : 1);
     }
 }
+}
 
-} // end of namespace generic
+int
+Generic::compare(const Rdata& other) const
+{
+    const Generic& other_rdata = dynamic_cast<const Generic&>(other);
+
+    return (compare_internal(*impl_, *other_rdata.impl_));
+}
 
-namespace in {
-} // end of namespace in
+std::ostream&
+operator<<(std::ostream& os, const Generic& rdata)
+{
+    return (os << rdata.toText());
+}
+} // end of namespace generic
 
-namespace ch {
-} // end of namespace ch
 } // end of namespace rdata
 }
 }

+ 356 - 40
src/lib/dns/cpp/rdata.h

@@ -21,8 +21,6 @@
 
 #include <boost/shared_ptr.hpp>
 
-#include "name.h"
-
 namespace isc {
 namespace dns {
 class InputBuffer;
@@ -55,7 +53,9 @@ public:
 };
 
 ///
-/// \brief A standard DNS module exception that is thrown if ...TBD
+/// \brief A standard DNS module exception that is thrown if RDATA parser
+/// parser encounters a character-string (as defined in RFC1035) exceeding
+/// the maximum allowable length (\c MAX_CHARSTRING_LEN).
 ///
 class CharStringTooLong : public Exception {
 public:
@@ -63,89 +63,403 @@ public:
         isc::Exception(file, line, what) {}
 };
 
+// Forward declaration to define RdataPtr.
 class Rdata;
+
+///
+/// The \c RdataPtr type is a pointer-like type, pointing to an
+/// object of some concrete derived class of \c Rdata.
+///
 typedef boost::shared_ptr<Rdata> RdataPtr;
 typedef boost::shared_ptr<const Rdata> ConstRdataPtr;
 
-/// Abstract RDATA class
+/// \brief Possible maximum length of RDATA, which is the maximum unsigned
+/// 16 bit value.
+const size_t MAX_RDLENGTH = 65535;
+
+/// \brief The maximum allowable length of character-string containing in
+/// RDATA as defined in RFC1035, not including the 1-byte length field.
+const unsigned int MAX_CHARSTRING_LEN = 255;
+
+/// \brief The \c Rdata class is an abstract base class that provides
+/// a set of common interfaces to manipulate concrete RDATA objects.
+///
+/// Generally, a separate derived class directly inherited from the base
+/// \c Rdata class is defined for each well known RDATA.
+/// Each of such classes will define the common logic based on the
+/// corresponding protocol standard.
+///
+/// Since some types of RRs are class specific and the corresponding RDATA
+/// may have different semantics (e.g. type A for class IN and type A for
+/// class CH have different representations and semantics), we separate
+/// \c Rdata derived classes for such RR types in different namespaces.
+/// The namespace of types specific to a class is named the lower-cased class
+/// name; for example, RDATA of class IN-specific types are defined in the
+/// \c in namespace, and RDATA of class CH-specific types are defined in
+/// the \c ch namespace, and so on.
+/// The derived classes are named using the RR type name (upper cased) such as
+/// \c A or \c AAAA.
+/// Thus RDATA of type A RR for class IN and CH are defined as \c in::A and
+/// \c ch::A, respectively.
+/// Many other RR types are class independent; the derived \c Rdata classes
+/// for such RR types are defined in the \c generic namespace.  Examples are
+/// \c generic::NS and \c generic::SOA.
+///
+/// If applications need to refer to these derived classes, it is generally
+/// recommended to prepend at least some part of the namespace because the
+/// same class name can be used in different namespaces.
+/// So, instead of doing
+/// \code using namespace isc::dns::rdata::in;
+/// A& rdata_type_a; \endcode
+/// it is advisable to prepend at least \c in from the namespace:
+/// \code using namespace isc::dns::rdata;
+/// in::A& rdata_type_a; \endcode
+///
+/// In many cases, however, an application doesn't have to care about such
+/// derived classes.
+/// For instance, to parse an incoming DNS message an application wouldn't
+/// have to perform type specific operation unless the application is
+/// specifically concerned about a particular type.
+/// So, this API generally handles \c Rdata in a polymorphic way through
+/// a pointer or reference to this base abstract class.
 class Rdata {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are intentionally
+    /// defined as private.  Concrete classes should generally specialize their
+    /// own versions of these methods.
+    //@{
 protected:
+    /// The default constructor.
+    ///
+    /// This is intentionally defined as \c protected as this base class should
+    /// never be instantiated (except as part of a derived class).  In many
+    /// cases, the derived class wouldn't define a public default constructor
+    /// either, because an \c Rdata object without concrete data isn't
+    /// meaningful.
     Rdata() {}
 private:
-    /// Copy constructor is intentionally private.  Concrete classes should
-    /// generally specialize their own versions of copy constructor.
     Rdata(const Rdata& source);
     void operator=(const Rdata& source);
 public:
+    /// The destructor.
     virtual ~Rdata() {};
-
-    ///
-    /// \name Getter Methods
-    //
-    // need generic method for getting n-th field? c.f. ldns
-    // e.g. string getField(int n);
-    ///
-    //@{
-    // It's not yet clear if we really need to contain the RR type (and/or
-    // RR class) in RDATA.
-    //virtual const RRType& getType() const = 0;
     //@}
 
     ///
     /// \name Converter methods
     ///
     //@{
+    /// \brief Convert an \c Rdata to a string.
+    ///
+    /// This method returns a \c std::string object representing the \c Rdata.
+    ///
+    /// This is a pure virtual method without the definition; the actual
+    /// representation is specific to each derived concrete class and
+    /// should be explicitly defined in the derived class.
+    ///
+    /// \return A string representation of \c Rdata.
     virtual std::string toText() const = 0;
+    /// \brief Render the \c Rdata in the wire format into a buffer.
+    ///
+    /// This is a pure virtual method without the definition; the actual
+    /// conversion is specific to each derived concrete class and
+    /// should be explicitly defined in the derived class.
+    ///
+    /// \param buffer An output buffer to store the wire data.
     virtual void toWire(OutputBuffer& buffer) const = 0;
+    /// \brief Render the \c Rdata in the wire format into a
+    /// \c MessageRenderer object.
+    ///
+    /// This is a pure virtual method without the definition; the actual
+    /// conversion is specific to each derived concrete class and
+    /// should be explicitly defined in the derived class.
+    ///
+    /// \param renderer DNS message rendering context that encapsulates the
+    /// output buffer in which the \c Rdata is to be stored.
     virtual void toWire(MessageRenderer& renderer) const = 0;
     //@}
 
-    /// Note about implementation choice: the current implementation relies on
-    /// dynamic_cast to ensure that the \c other is the same concrete Rdata
-    /// class as \c this object.  Alternatively, we could first convert the
-    /// data into wire-format and compare the pair as opaque data.  This would
-    /// be more polymorphic, but might involve significant overhead, especially
-    /// for a large size of RDATA.
+    ///
+    /// \name Comparison method
+    ///
+    //@{
+    /// \brief Compare two instances of \c Rdata.
+    ///
+    /// This method compares \c this and the \c other Rdata objects
+    /// in terms of the DNSSEC sorting order as defined in RFC4034, and returns
+    /// the result as an integer.
+    ///
+    /// This is a pure virtual method without the definition; the actual
+    /// comparison logic is specific to each derived concrete class and
+    /// should be explicitly defined in the derived class.
+    ///
+    /// Specific implementations of this method must confirm that \c this
+    /// and the \c other are objects of the same concrete derived class of
+    /// \c Rdata.  This is normally done by \c dynamic_cast in the
+    /// implementation.  It also means if the assumption isn't met
+    /// an exception of class \c std::bad_cast will be thrown.
+    ///
+    /// Here is an implementation choice: instead of relying on
+    /// \c dynamic_cast, we could first convert the data into wire-format
+    /// and compare the pair as opaque data.  This would be more polymorphic,
+    /// but might involve significant overhead, especially for a large size
+    /// of RDATA.
+    ///
+    /// \param other the right-hand operand to compare against.
+    /// \return < 0 if \c this would be sorted before \c other.
+    /// \return 0 if \c this is identical to \c other in terms of sorting order.
+    /// \return > 0 if \c this would be sorted after \c other.
     virtual int compare(const Rdata& other) const = 0;
-
-    // not yet:
-    // methods specific derived classes: throw an exception by default
-    //virtual Address& getAddress() = 0;
-    //virtual Name& getName() = 0;
-
-    // polymorphic copy constructor (XXX should revisit it)
-    //virtual Rdata* copy() const = 0;
+    //@}
 };
 
 namespace generic {
+
+/// \brief The \c GenericImpl class is the actual implementation of the
+/// \c generic::Generic class.
+///
+/// The implementation is hidden from applications.  This approach requires
+/// dynamic memory allocation on construction, copy, or assignment, but
+/// we believe it should be acceptable as "unknown" RDATA should be pretty
+/// rare.
+struct GenericImpl;
+
+/// \brief The \c generic::Generic class represents generic "unknown" RDATA.
+///
+/// This class is used as a placeholder for all non well-known type of RDATA.
+/// By definition, the stored data is regarded as opaque binary without
+/// assuming any structure.
 class Generic : public Rdata {
 public:
+    ///
+    /// \name Constructors, Assignment Operator and Destructor.
+    ///
+    //@{
+    /// \brief Constructor from a string.
+    ///
+    /// This method constructs a \c generic::Generic object from a textual
+    /// representation as defined in RFC3597.
+    ///
+    /// If \c rdata_string isn't a valid textual representation of this type
+    /// of RDATA, an exception of class \c InvalidRdataText or
+    /// \c InvalidRdataLength will be thrown.
+    /// If resource allocation to store the data fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \param rdata_string A string of textual representation of generic
+    /// RDATA.
     explicit Generic(const std::string& rdata_string);
-    explicit Generic(InputBuffer& buffer, size_t rdata_len);
+    ///
+    /// \brief Constructor from wire-format data.
+    ///
+    /// The \c buffer parameter normally stores a complete DNS message
+    /// containing the generic RDATA to be constructed.
+    /// The current read position of the buffer points to the head of the
+    /// data.
+    ///
+    /// This method reads \c rdata_len bytes from the \c buffer, and internally
+    /// stores the data as an opaque byte sequence.
+    ///
+    /// \c rdata_len must not exceed \c MAX_RDLENGTH; otherwise, an exception
+    /// of class \c InvalidRdataLength will be thrown.
+    /// If resource allocation to hold the data fails, a corresponding standard
+    /// exception will be thrown; if the \c buffer doesn't contain \c rdata_len
+    /// bytes of unread data, an exception of class \c InvalidBufferPosition
+    /// will be thrown.
+    ///
+    /// \param buffer A reference to an \c InputBuffer object storing the
+    /// \c Rdata to parse.
+    /// \param rdata_len The length in buffer of the \c Rdata.  In bytes.
+    Generic(InputBuffer& buffer, size_t rdata_len);
+    ///
+    /// \brief The destructor.
+    virtual ~Generic();
+    ///
+    /// \brief The copy constructor.
+    ///
+    /// If resource allocation to copy the data fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \param source A reference to a \c generic::Generic object to copy from.
+    Generic(const Generic& source);
+    ///
+    /// \brief The assignment operator.
+    ///
+    /// If resource allocation to copy the data fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \param source A reference to a \c generic::Generic object to copy from.
+    Generic& operator=(const Generic& source);
+    //@}
+    ///
+    /// \name Converter methods
+    ///
+    //@{
+    /// \brief Convert an \c generic::Generic object to a string.
+    ///
+    /// This method converts a generic "unknown" RDATA object into a textual
+    /// representation of such unknown data as defined in RFC3597.
+    ///
+    /// If resource allocation to copy the data fails, a corresponding standard
+    /// exception will be thrown.
+    ///
+    /// \return A string representation of \c generic::Generic.
     virtual std::string toText() const;
+    ///
+    /// \brief Render the \c generic::Generic in the wire format into a buffer.
+    ///
+    /// This will require \c rdata_len bytes of remaining capacity in the
+    /// \c buffer.  If this is not the case and resource allocation for the
+    /// necessary memory space fails, a corresponding standard exception will
+    /// be thrown.
+    ///
+    /// \param buffer An output buffer to store the wire data.
     virtual void toWire(OutputBuffer& buffer) const;
+    /// \brief Render the \c generic::Generic in the wire format into a
+    /// \c MessageRenderer object.
+    ///
+    /// This will require \c rdata_len bytes of remaining capacity in the
+    /// \c buffer.  If this is not the case and resource allocation for the
+    /// necessary memory space fails, a corresponding standard exception will
+    /// be thrown.
+    ///
+    /// \param renderer DNS message rendering context that encapsulates the
+    /// output buffer in which the \c Generic object is to be stored.
     virtual void toWire(MessageRenderer& renderer) const;
+    //@}
     ///
-    /// Note: the comparison is RR type/class agnostic: this method doesn't
-    /// check whether the two Rdata objects to compare are of the comparable
-    /// RR type/class.  The caller must ensure this condition.
+    /// \name Comparison method
     ///
+    //@{
+    /// \brief Compare two instances of \c generic::Generic objects.
+    ///
+    /// As defined in RFC4034, this method simply compares the wire-format
+    /// representations of the two objects as left-justified unsigned octet
+    /// sequences.
+    ///
+    /// The object referenced by \c other must have been instantiated as
+    /// a c generic::Generic class object; otherwise, an exception of class
+    /// \c std::bad_cast will be thrown.
+    /// Note that the comparison is RR type/class agnostic: this method doesn't
+    /// check whether the two \c Rdata objects to compare are of the comparable
+    /// RR type/class.  For example, \c this object may come from an \c RRset
+    /// of \c RRType x, and the \c other may come from a different \c RRset
+    /// of \c RRType y (where x != y).  This situation would be considered a
+    /// bug, but this method cannot detect this type of error.
+    /// The caller must ensure this condition.
+    ///
+    /// \param other the right-hand operand to compare against.
+    /// \return < 0 if \c this would be sorted before \c other.
+    /// \return 0 if \c this is identical to \c other in terms of sorting order.
+    /// \return > 0 if \c this would be sorted after \c other.
     virtual int compare(const Rdata& other) const;
+    //@}
 private:
-    std::vector<uint8_t> data_;
+    GenericImpl* impl_;
 };
+
+///
+/// \brief Insert the name as a string into stream.
+///
+/// This method convert the \c rdata into a string and inserts it into the
+/// output stream \c os.
+///
+/// This function overloads the global \c operator<< to behave as described in
+/// \c ostream::operator<< but applied to \c generic::Generic Rdata objects.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param rdata The \c Generic object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const Generic& rdata);
 } // end of namespace "generic"
 
+//
+// Non class-member functions related to Rdata
+//
+
 ///
-/// Non class-member functions related to Rdata
+/// \name Parameterized Polymorphic RDATA Factories
 ///
-/// TBD: document them
+/// This set of global functions provide a unified interface to create an
+/// \c Rdata object in a parameterized polymorphic way,
+/// that is, these functions take a pair of \c RRType and \c RRClass
+/// objects and data specific to that pair, and create an object of
+/// the corresponding concrete derived class of \c Rdata.
+///
+/// These will be useful when parsing/constructing a DNS message or
+/// parsing a master file, where information for a specific type of RDATA
+/// is given but the resulting object, once created, should better be used
+/// in a polymorphic way.
+///
+/// For example, if a master file parser encounters an NS RR
+/// \verbatim example.com. 3600 IN NS ns.example.com.\endverbatim
+/// it stores the text fragments "IN", "NS", and "ns.example.com." in
+/// \c std::string objects \c class_txt, \c type_txt, and \c nsname_txt,
+/// respectively, then it would create a new \c RdataPtr object as follows:
+/// \code RdataPtr rdata = createRdata(RRType(type_txt), RRClass(class_txt),
+///                              nsname_txt); \endcode
+/// On success, \c rdata will point to an object of the \c generic::NS class
+/// that internally holds a domain name of "ns.example.com."
+///
+/// Internally, these functions uses the corresponding
+/// \c RRParamRegistry::createRdata methods of the \c RRParamRegistry.
+/// See also the description on these methods for related notes.
+//@{
+/// \brief Create RDATA of a given pair of RR type and class from a string.
+///
+/// This method creates from a string an \c Rdata object of the given pair
+/// of RR type and class.
+///
+/// \param rrtype An \c RRType object specifying the type/class pair.
+/// \param rrclass An \c RRClass object specifying the type/class pair.
+/// \param rdata_string A string of textual representation of the \c Rdata.
+/// \return An \c RdataPtr object pointing to the created \c Rdata
+/// object.
 RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                      const std::string& rdata_string);
+/// \brief Create RDATA of a given pair of RR type and class from
+/// wire-format data.
+///
+/// This method creates from wire-format binary data an \c Rdata object
+/// of the given pair of RR type and class.
+///
+/// \c len must not exceed the protocol defined maximum value, \c MAX_RDLENGTH;
+/// otherwise, an exception of class \c InvalidRdataLength will be thrown.
+///
+/// In some cases, the length of the RDATA is determined without the
+/// information of \c len.  For example, the RDATA length of an IN/A RR
+/// must always be 4.  If \c len is not equal to the actual length in such
+/// cases, an exception of class InvalidRdataLength will be thrown.
+///
+/// \param rrtype An \c RRType object specifying the type/class pair.
+/// \param rrclass An \c RRClass object specifying the type/class pair.
+/// \param buffer A reference to an \c InputBuffer object storing the
+/// \c Rdata to parse.
+/// \param len The length in buffer of the \c Rdata.  In bytes.
+/// \return An \c RdataPtr object pointing to the created \c Rdata
+/// object.
 RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                      InputBuffer& buffer, size_t len);
+/// \brief Create RDATA of a given pair of RR type and class, copying
+/// of another RDATA of same kind.
+///
+/// This method creates an \c Rdata object of the given pair of
+/// RR type and class, copying the  content of the given \c Rdata,
+/// \c source.
+///
+/// \param rrtype An \c RRType object specifying the type/class pair.
+/// \param rrclass An \c RRClass object specifying the type/class pair.
+/// \param source A reference to an \c Rdata object whose content
+/// is to be copied to the created \c Rdata object.
+/// \return An \c RdataPtr object pointing to the created
+/// \c Rdata object.
 RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                      const Rdata& source);
+//@}
 
 ///
 /// \brief Gives relative ordering of two names in terms of DNSSEC RDATA
@@ -165,6 +479,9 @@ RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
 /// This function is publicly open, however, for the convenience of
 /// external developers who want to implement new or experimental RR types.
 ///
+/// This function never throws an exception as long as the given names are
+/// valid \c Name objects.
+///
 /// Additional note about applicability: In fact, BIND9's similar function,
 /// \c dns_name_rdatacompare(), is only used in rdata implementations and
 /// for testing purposes.
@@ -174,8 +491,7 @@ RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
 /// \return 0 if \c n1 is identical to \c n2 in terms of sorting order.
 /// \return 1 if \c n1 would be sorted after \c n2.
 ///
-int
-compareNames(const Name& n1, const Name& n2);
+int compareNames(const Name& n1, const Name& n2);
 
 } // end of namespace "rdata"
 }

+ 0 - 1
src/lib/dns/cpp/rdata/generic/txt_16.h

@@ -37,7 +37,6 @@ public:
 private:
     /// Note: this is a prototype version; we may reconsider
     /// this representation later.
-    static const unsigned int MAX_CHARSTRING_LEN = 255;
     std::vector<std::vector<uint8_t> > string_list_;
 };
 

+ 5 - 0
src/lib/dns/cpp/rdata/template.h

@@ -37,10 +37,15 @@
 // "RR-type specific members" space (please make them private).  In addition,
 // you may want to define some specific member functions, either public or
 // private (or, though unlikely for a leaf class, protected).
+//
+// Note: do not remove the comment lines beginning with "BEGIN_" and "END_".
+// These are markers used by a script for auto-generating build-able source
+// files.
 
 class MyType : public Rdata {
 public:
     // BEGIN_COMMON_MEMBERS
+    // Do not remove the BEGIN_xxx and END_xxx comment lines.
     // END_COMMON_MEMBERS
 private:
     // RR-type specific members are here.

+ 0 - 534
src/lib/dns/cpp/rdata_unittest.cc

@@ -1,534 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// $Id: rrtype_unittest.cc 476 2010-01-19 00:29:28Z jinmei $
-
-#include <vector>
-
-#include "buffer.h"
-#include "messagerenderer.h"
-#include "rdata.h"
-#include "rdataclass.h"
-#include "rrclass.h"
-#include "rrtype.h"
-
-#include <gtest/gtest.h>
-
-#include "unittest_util.h"
-
-using isc::UnitTestUtil;
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-
-namespace {
-class RdataTest : public ::testing::Test {
-protected:
-    RdataTest() : obuffer(0), renderer(obuffer) {}
-    static RdataPtr rdataFactoryFromFile(const RRType& rrtype,
-                                         const RRClass& rrclass,
-                                         const char* datafile,
-                                         size_t position = 0);
-    OutputBuffer obuffer;
-    MessageRenderer renderer;
-    static const in::A rdata_in_a;
-    static const in::AAAA rdata_in_aaaa;
-    static const uint8_t wiredata_in_a[];
-    static const uint8_t wiredata_in_aaaa[];
-    static const uint8_t wiredata_ns[];
-    static const uint8_t wiredata_ns2[];
-    static const uint8_t wiredata_cname[];
-    static const uint8_t wiredata_cname2[];
-    static const uint8_t wiredata_txt[];
-    static const generic::NS rdata_ns, rdata_ns2;
-    static const generic::SOA rdata_soa;
-    static const generic::CNAME rdata_cname, rdata_cname2;
-    static const generic::MX rdata_mx;
-    static const generic::TXT rdata_txt;
-    static const generic::TXT rdata_txt_quoated;
-};
-
-const in::A RdataTest::rdata_in_a("192.0.2.1");
-const in::AAAA RdataTest::rdata_in_aaaa("2001:db8::1234");
-const generic::NS RdataTest::rdata_ns("ns.example.com");
-const generic::NS RdataTest::rdata_ns2("ns2.example.com");
-const generic::SOA RdataTest::rdata_soa(Name("ns.example.com"),
-                                        Name("root.example.com"),
-                                        2010012601, 3600, 300, 3600000, 1200);
-const generic::CNAME RdataTest::rdata_cname("cn.example.com");
-const generic::CNAME RdataTest::rdata_cname2("cn2.example.com");
-const generic::MX RdataTest::rdata_mx(10, Name("mx.example.com"));
-const generic::TXT RdataTest::rdata_txt("Test String");
-const generic::TXT RdataTest::rdata_txt_quoated("\"Test String\"");
-
-const uint8_t RdataTest::wiredata_in_a[] = { 192, 0, 2, 1 };
-const uint8_t RdataTest::wiredata_in_aaaa[] = {
-    0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x12, 0x34 };
-const uint8_t RdataTest::wiredata_ns[] = {
-    0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
-    0x63, 0x6f, 0x6d, 0x00 };
-const uint8_t RdataTest::wiredata_ns2[] = {
-    // first name: ns.example.com.
-    0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
-    0x63, 0x6f, 0x6d, 0x00,
-    // second name: ns2.example.com.  all labels except the first should be
-    // compressed.
-    0x03, 0x6e, 0x73, 0x32, 0xc0, 0x03 };
-const uint8_t RdataTest::wiredata_cname[] = {
-    0x02, 0x63, 0x6e, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
-    0x63, 0x6f, 0x6d, 0x00 };
-const uint8_t RdataTest::wiredata_cname2[] = {
-    // first name: cn.example.com.
-    0x02, 0x63, 0x6e, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
-    0x63, 0x6f, 0x6d, 0x00,
-    // second name: cn2.example.com.  all labels except the first should be
-    // compressed.
-    0x03, 0x63, 0x6e, 0x32, 0xc0, 0x03 };
-const uint8_t RdataTest::wiredata_txt[] = {
-    sizeof("Test String") - 1,
-    'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
-};
-
-RdataPtr
-RdataTest::rdataFactoryFromFile(const RRType& rrtype, const RRClass& rrclass,
-                                const char* datafile, size_t position)
-{
-    std::vector<unsigned char> data;
-    UnitTestUtil::readWireData(datafile, data);
-
-    InputBuffer buffer(&data[0], data.size());
-    buffer.setPosition(position);
-
-    uint16_t rdlen = buffer.readUint16();
-    return (createRdata(rrtype, rrclass, buffer, rdlen));
-}
-
-TEST_F(RdataTest, createFromText_IN_A)
-{
-    rdata_in_a.compare(in::A(string("192.0.2.1")));
-    //EXPECT_EQ(0, rdata_in_a.compare(in::A("192.0.2.1")));
-    // should reject an abbreviated form of IPv4 address
-    EXPECT_THROW(in::A("10.1"), InvalidRdataText);
-    // or an IPv6 address
-    EXPECT_THROW(in::A("2001:db8::1234"), InvalidRdataText);
-    // or any meaningless text as an IP address
-    EXPECT_THROW(in::A("xxx"), InvalidRdataText);
-}
-
-TEST_F(RdataTest, createFromWire_IN_A)
-{
-    // Valid data
-    EXPECT_EQ(0, rdata_in_a.compare(
-                  *rdataFactoryFromFile(RRType("A"), RRClass("IN"),
-                                        "testdata/rdata_in_a_fromWire")));
-    // RDLENGTH is too short
-    EXPECT_THROW(rdataFactoryFromFile(RRType("A"), RRClass("IN"),
-                                      "testdata/rdata_in_a_fromWire", 6),
-                 InvalidRdataLength);
-    // RDLENGTH is too long
-    EXPECT_THROW(rdataFactoryFromFile(RRType("A"), RRClass("IN"),
-                                      "testdata/rdata_in_a_fromWire", 12),
-                 InvalidRdataLength);
-    // buffer too short.  the error should be detected in buffer read
-    EXPECT_THROW(rdataFactoryFromFile(RRType("A"), RRClass("IN"),
-                                      "testdata/rdata_in_a_fromWire", 19),
-                 InvalidBufferPosition);
-}
-
-TEST_F(RdataTest, toWireBuffer_IN_A)
-{
-    rdata_in_a.toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_in_a, sizeof(wiredata_in_a));
-}
-
-TEST_F(RdataTest, toWireRenderer_IN_A)
-{
-    rdata_in_a.toWire(renderer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_in_a, sizeof(wiredata_in_a));
-}
-
-TEST_F(RdataTest, toText_IN_A)
-{
-    EXPECT_EQ("192.0.2.1", rdata_in_a.toText());
-    string longaddr("255.255.255.255"); // this shouldn't make the code crash
-    EXPECT_EQ(longaddr, in::A(longaddr).toText());
-}
-
-TEST_F(RdataTest, compare_IN_A)
-{
-    in::A small1("1.1.1.1");
-    in::A small2("1.2.3.4");
-    in::A large1("255.255.255.255");
-    in::A large2("4.3.2.1");
-
-    // trivial case: self equivalence
-    EXPECT_EQ(0, small1.compare(small1));
-
-    // confirm these are compared as unsigned values
-    EXPECT_GT(0, small1.compare(large1));
-    EXPECT_LT(0, large1.compare(small1));
-
-    // confirm these are compared in network byte order
-    EXPECT_GT(0, small2.compare(large2));
-    EXPECT_LT(0, large2.compare(small2));
-
-    // comparison attempt between incompatible RR types should be rejected
-    EXPECT_THROW(rdata_in_a.compare(rdata_ns), bad_cast); 
-}
-
-TEST_F(RdataTest, createFromText_IN_AAAA)
-{
-    rdata_in_aaaa.compare(in::AAAA(string("2001:db8::1234")));
-    EXPECT_THROW(in::AAAA("192.0.2.1"), InvalidRdataText);
-    EXPECT_THROW(in::AAAA("xxx"), InvalidRdataText);
-}
-
-TEST_F(RdataTest, createFromWire_IN_AAAA)
-{
-    // Valid data
-    EXPECT_EQ(0, rdata_in_aaaa.compare(
-                  *rdataFactoryFromFile(RRType("AAAA"), RRClass("IN"),
-                                        "testdata/rdata_in_aaaa_fromWire")));
-    //TBD: more tests
-}
-
-TEST_F(RdataTest, toWireBuffer_IN_AAAA)
-{
-    rdata_in_aaaa.toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_in_aaaa, sizeof(wiredata_in_aaaa));
-}
-
-TEST_F(RdataTest, toWireRenderer_IN_AAAA)
-{
-    rdata_in_aaaa.toWire(renderer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_in_aaaa, sizeof(wiredata_in_aaaa));
-}
-
-TEST_F(RdataTest, toText_IN_AAAA)
-{
-    EXPECT_EQ("2001:db8::1234", rdata_in_aaaa.toText());
-}
-
-TEST_F(RdataTest, compare_IN_AAAA)
-{
-    in::AAAA small1("::1");
-    in::AAAA small2("1:2:3:4:5:6:7:8");
-    in::AAAA large1("ffff::");
-    in::AAAA large2("8:7:6:5:4:3:2:1");
-
-    // trivial case: self equivalence
-    EXPECT_EQ(0, small1.compare(small1));
-
-    // confirm these are compared as unsigned values
-    EXPECT_GT(0, small1.compare(large1));
-    EXPECT_LT(0, large1.compare(small1));
-
-    // confirm these are compared in network byte order
-    EXPECT_GT(0, small2.compare(large2));
-    EXPECT_LT(0, large2.compare(small2));
-
-    // comparison attempt between incompatible RR types should be rejected
-    EXPECT_THROW(rdata_in_aaaa.compare(rdata_ns), bad_cast); 
-}
-
-TEST_F(RdataTest, createFromText_NS)
-{
-    EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com")));
-    // explicitly add a trailing dot.  should be the same RDATA.
-    EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com.")));
-    // should be case sensitive.
-    EXPECT_EQ(0, rdata_ns.compare(generic::NS("NS.EXAMPLE.COM")));
-    // RDATA of a class-independent type should be recognized for any
-    // "unknown" class.
-    EXPECT_EQ(0, rdata_ns.compare(*createRdata(RRType("NS"), RRClass(65000),
-                                               "ns.example.com")));
-}
-
-TEST_F(RdataTest, createFromWire_NS)
-{
-    EXPECT_EQ(0, rdata_ns.compare(
-                  *rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
-                                        "testdata/rdata_ns_fromWire")));
-    // RDLENGTH is too short
-    EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
-                                      "testdata/rdata_ns_fromWire", 18),
-                 InvalidRdataLength);
-    // RDLENGTH is too long
-    EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
-                                      "testdata/rdata_ns_fromWire", 36),
-                 InvalidRdataLength);
-    // incomplete name.  the error should be detected in the name constructor
-    EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
-                                      "testdata/rdata_ns_fromWire", 71),
-                 IncompleteName);
-
-    EXPECT_EQ(0, generic::NS("ns2.example.com").compare(
-                  *rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
-                                        "testdata/rdata_ns_fromWire", 55)));
-    EXPECT_THROW(*rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
-                                       "testdata/rdata_ns_fromWire", 63),
-                 InvalidRdataLength);
-}
-
-TEST_F(RdataTest, toWireBuffer_NS)
-{
-    rdata_ns.toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_ns, sizeof(wiredata_ns));
-}
-
-TEST_F(RdataTest, toWireRenderer_NS)
-{
-    rdata_ns.toWire(renderer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_ns, sizeof(wiredata_ns));
-    rdata_ns2.toWire(renderer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_ns2, sizeof(wiredata_ns2));
-}
-
-TEST_F(RdataTest, toText_NS)
-{
-    EXPECT_EQ("ns.example.com.", rdata_ns.toText());
-}
-
-TEST_F(RdataTest, compare_NS)
-{
-    generic::NS small("a.example");
-    generic::NS large("example");
-    EXPECT_EQ(true, Name("a.example") > Name("example"));
-    EXPECT_GT(0, small.compare(large));
-}
-
-TEST_F(RdataTest, getNSName)
-{
-    EXPECT_EQ(Name("ns.example.com"), rdata_ns.getNSName());
-}
-
-TEST_F(RdataTest, createFromText_SOA)
-{
-    EXPECT_EQ(0, rdata_soa.compare(generic::SOA("ns.example.com. "
-                                                "root.example.com. "
-                                                "2010012601 3600 300 3600000 "
-                                                "1200")));
-    // TBD: more tests
-}
-
-TEST_F(RdataTest, createFromWire_SOA)
-{
-    EXPECT_EQ(0, rdata_soa.compare(
-                  *rdataFactoryFromFile(RRType("SOA"), RRClass("IN"),
-                                        "testdata/rdata_soa_fromWire")));
-    // TBD: more tests
-}
-
-TEST_F(RdataTest, toWireRenderer_SOA)
-{
-    renderer.skip(2);
-    rdata_soa.toWire(renderer);
-
-    vector<unsigned char> data;
-    UnitTestUtil::readWireData("testdata/rdata_soa_fromWire", data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t *>(obuffer.getData()) + 2,
-                        obuffer.getLength() - 2, &data[0] + 2, data.size() - 2);
-}
-
-TEST_F(RdataTest, toText_SOA)
-{
-    EXPECT_EQ("ns.example.com. root.example.com. "
-              "2010012601 3600 300 3600000 1200", rdata_soa.toText());
-}
-
-TEST_F(RdataTest, createFromText_MX)
-{
-    //TBD
-}
-
-TEST_F(RdataTest, createFromWire_MX)
-{
-    EXPECT_EQ(0, rdata_mx.compare(
-                  *rdataFactoryFromFile(RRType("MX"), RRClass("IN"),
-                                        "testdata/rdata_mx_fromWire")));
-    // TBD: more tests
-}
-
-TEST_F(RdataTest, toWireRenderer_MX)
-{
-    renderer.writeName(Name("example.com"));
-    rdata_mx.toWire(renderer);
-
-    vector<unsigned char> data;
-    UnitTestUtil::readWireData("testdata/rdata_mx_toWire1", data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
-                        obuffer.getLength(), &data[0], data.size());
-}
-
-TEST_F(RdataTest, toText_MX)
-{
-    EXPECT_EQ("10 mx.example.com.", rdata_mx.toText());
-}
-
-TEST_F(RdataTest, compare_IN_MX)
-{
-    generic::MX small1(1, Name("mx.example.com"));
-    generic::MX small2(10, Name("mx.example.com"));
-    generic::MX large1(65535, Name("mx.example.com"));
-    generic::MX large2(256, Name("mx.example.com"));
-
-    // trivial case: self equivalence
-    EXPECT_EQ(0, small1.compare(small1));
-
-    // confirm these are compared as unsigned values
-    EXPECT_GT(0, small1.compare(large1));
-    EXPECT_LT(0, large1.compare(small1));
-
-    // confirm these are compared in network byte order
-    EXPECT_GT(0, small2.compare(large2));
-    EXPECT_LT(0, large2.compare(small2));
-
-    // comparison attempt between incompatible RR types should be rejected
-    EXPECT_THROW(rdata_mx.compare(rdata_ns), bad_cast); 
-}
-
-TEST_F(RdataTest, createFromText_TXT)
-{
-    EXPECT_EQ(0, rdata_txt.compare(rdata_txt_quoated));
-}
-
-TEST_F(RdataTest, createFromWire_TXT)
-{
-    EXPECT_EQ(0, rdata_txt.compare(
-                  *rdataFactoryFromFile(RRType("TXT"), RRClass("IN"),
-                                        "testdata/rdata_txt_fromWire")));
-}
-
-TEST_F(RdataTest, toWireBuffer_TXT)
-{
-    rdata_txt.toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_txt, sizeof(wiredata_txt));
-}
-
-TEST_F(RdataTest, toText_TXT)
-{
-    EXPECT_EQ("\"Test String\"", rdata_txt.toText());
-}
-
-TEST_F(RdataTest, createFromText_CNAME)
-{
-    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("cn.example.com")));
-    // explicitly add a trailing dot.  should be the same RDATA.
-    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("cn.example.com.")));
-    // should be case sensitive.
-    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("CN.EXAMPLE.COM")));
-    // RDATA of a class-independent type should be recognized for any
-    // "unknown" class.
-    EXPECT_EQ(0, rdata_cname.compare(*createRdata(RRType("CNAME"),
-                                                  RRClass(65000),
-                                                  "cn.example.com")));
-}
-
-TEST_F(RdataTest, createFromWire_CNAME)
-{
-    EXPECT_EQ(0, rdata_cname.compare(
-                  *rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
-                                        "testdata/rdata_cname_fromWire")));
-    // RDLENGTH is too short
-    EXPECT_THROW(rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
-                                      "testdata/rdata_cname_fromWire", 18),
-                 InvalidRdataLength);
-    // RDLENGTH is too long
-    EXPECT_THROW(rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
-                                      "testdata/rdata_cname_fromWire", 36),
-                 InvalidRdataLength);
-    // incomplete name.  the error should be detected in the name constructor
-    EXPECT_THROW(rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
-                                      "testdata/rdata_cname_fromWire", 71),
-                 IncompleteName);
-
-    EXPECT_EQ(0, generic::CNAME("cn2.example.com").compare(
-                  *rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
-                                        "testdata/rdata_cname_fromWire", 55)));
-    EXPECT_THROW(*rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
-                                       "testdata/rdata_cname_fromWire", 63),
-                 InvalidRdataLength);
-}
-
-TEST_F(RdataTest, toWireBuffer_CNAME)
-{
-    rdata_cname.toWire(obuffer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_cname, sizeof(wiredata_cname));
-}
-
-TEST_F(RdataTest, toWireRenderer_CNAME)
-{
-    rdata_cname.toWire(renderer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_cname, sizeof(wiredata_cname));
-    rdata_cname2.toWire(renderer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
-                        wiredata_cname2, sizeof(wiredata_cname2));
-}
-
-TEST_F(RdataTest, toText_CNAME)
-{
-    EXPECT_EQ("cn.example.com.", rdata_cname.toText());
-}
-
-TEST_F(RdataTest, getCname_CNAME)
-{
-    EXPECT_EQ(Name("cn.example.com."), rdata_cname.getCname());
-}
-
-TEST_F(RdataTest, fromText_RRSIG)
-{
-    string rrsig_txt("A 5 4 43200 1264801134 191145710 8496 isc.org. "
-                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
-                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
-                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
-                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
-    generic::RRSIG rdata_rrsig(rrsig_txt);
-    EXPECT_EQ(rrsig_txt, rdata_rrsig.toText());
-}
-
-TEST_F(RdataTest, toWireRenderer_RRSIG)
-{
-    string rrsig_txt("A 5 4 43200 1264801134 191145710 8496 isc.org. "
-                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
-                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
-                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
-                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
-    generic::RRSIG rdata_rrsig(rrsig_txt);
-    rdata_rrsig.toWire(renderer);
-}
-
-}

+ 103 - 34
src/lib/dns/cpp/rrparamregistry-placeholder.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// $Id: rrparamregistry.cc 530 2010-01-26 22:15:42Z jinmei $
+// $Id$
 
 #include <cassert>
 #include <algorithm>
@@ -72,22 +72,43 @@ struct RRTypeParam {
 
     /// magic constants
     static const unsigned int MAX_CODE = 0xffff;
-    static const string UNKNOWN_PREFIX;
-    static const size_t UNKNOWN_PREFIXLEN;
-    static const string UNKNOWN_MAX;
-    static const size_t UNKNOWN_MAXLEN;
+    static const string& UNKNOWN_PREFIX();
+    static size_t UNKNOWN_PREFIXLEN();
+    static const string& UNKNOWN_MAX();
+    static size_t UNKNOWN_MAXLEN();
 };
 
 typedef shared_ptr<RRTypeParam> RRTypeParamPtr;
 typedef map<string, RRTypeParamPtr, CIStringLess> StrRRTypeMap;
 typedef map<uint16_t, RRTypeParamPtr> CodeRRTypeMap;
 
-const string RRTypeParam::UNKNOWN_PREFIX = "TYPE";
-const size_t RRTypeParam::UNKNOWN_PREFIXLEN =
-    RRTypeParam::UNKNOWN_PREFIX.size();
-const string RRTypeParam::UNKNOWN_MAX = "TYPE65535";
-const size_t RRTypeParam::UNKNOWN_MAXLEN =
-    RRTypeParam::UNKNOWN_MAX.size();
+inline const string&
+RRTypeParam::UNKNOWN_PREFIX()
+{
+    static const string p("TYPE");
+    return (p);
+}
+
+inline size_t
+RRTypeParam::UNKNOWN_PREFIXLEN()
+{
+    static size_t plen = UNKNOWN_PREFIX().size();
+    return (plen);
+}
+
+inline const string&
+RRTypeParam::UNKNOWN_MAX()
+{
+    static const string p("TYPE65535");
+    return (p);
+}
+
+inline size_t
+RRTypeParam::UNKNOWN_MAXLEN()
+{
+    static size_t plen = UNKNOWN_MAX().size();
+    return (plen);
+}
 
 struct RRClassParam {
     RRClassParam(const string& code_string, uint16_t code) :
@@ -97,23 +118,44 @@ struct RRClassParam {
 
     /// magic constants
     static const unsigned int MAX_CODE = 0xffff;
-    static const string UNKNOWN_PREFIX;
-    static const size_t UNKNOWN_PREFIXLEN;
-    static const string UNKNOWN_MAX;
-    static const size_t UNKNOWN_MAXLEN;
+    static const string& UNKNOWN_PREFIX();
+    static size_t UNKNOWN_PREFIXLEN();
+    static const string& UNKNOWN_MAX();
+    static size_t UNKNOWN_MAXLEN();
 };
 
 typedef shared_ptr<RRClassParam> RRClassParamPtr;
 typedef map<string, RRClassParamPtr, CIStringLess> StrRRClassMap;
 typedef map<uint16_t, RRClassParamPtr> CodeRRClassMap;
 
-const string RRClassParam::UNKNOWN_PREFIX = "CLASS";
-const size_t RRClassParam::UNKNOWN_PREFIXLEN =
-    RRClassParam::UNKNOWN_PREFIX.size();
-const string RRClassParam::UNKNOWN_MAX = "CLASS65535";
-const size_t RRClassParam::UNKNOWN_MAXLEN =
-    RRClassParam::UNKNOWN_MAX.size();
+inline const string&
+RRClassParam::UNKNOWN_PREFIX()
+{
+    static const string p("CLASS");
+    return (p);
+}
+
+inline size_t
+RRClassParam::UNKNOWN_PREFIXLEN()
+{
+    static size_t plen = UNKNOWN_PREFIX().size();
+    return (plen);
+}
+
+inline const string&
+RRClassParam::UNKNOWN_MAX()
+{
+    static const string p("CLASS65535");
+    return (p);
+}
+
+inline size_t
+RRClassParam::UNKNOWN_MAXLEN()
+{
+    static size_t plen = UNKNOWN_MAX().size();
+    return (plen);
 }
+} // end of anonymous namespace
 
 /// Note: the element ordering in the type/class pair is intentional.
 /// The standard library will perform inequality comparison (i.e, '<')
@@ -132,17 +174,17 @@ class RdataFactory : public AbstractRdataFactory {
 public:
     virtual RdataPtr create(const string& rdata_str) const
     {
-        return (shared_ptr<T>(new T(rdata_str)));
+        return (RdataPtr(new T(rdata_str)));
     }
 
     virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const
     {
-        return (shared_ptr<T>(new T(buffer, rdata_len)));
+        return (RdataPtr(new T(buffer, rdata_len)));
     }
 
     virtual RdataPtr create(const Rdata& source) const
     {
-        return (shared_ptr<T>(new T(dynamic_cast<const T&>(source))));
+        return (RdataPtr(new T(dynamic_cast<const T&>(source))));
     }
 };
 
@@ -171,7 +213,6 @@ RRParamRegistry::RRParamRegistry()
     impl_ = new RRParamRegistryImpl;
 
     // set up parameters for well-known RRs
-    // XXX: this should eventually be more automatic.
     try {
         // BEGIN_WELL_KNOWN_PARAMS
         // END_WELL_KNOWN_PARAMS
@@ -244,6 +285,33 @@ RRParamRegistry::add(const string& typecode_string, uint16_t typecode,
     }
 }
 
+bool
+RRParamRegistry::removeRdataFactory(const RRType& rrtype,
+                                    const RRClass& rrclass)
+{
+    RdataFactoryMap::iterator found =
+        impl_->rdata_factories.find(RRTypeClass(rrtype, rrclass));
+    if (found != impl_->rdata_factories.end()) {
+        impl_->rdata_factories.erase(found);
+        return (true);
+    }
+
+    return (false);
+}
+
+bool
+RRParamRegistry::removeRdataFactory(const RRType& rrtype)
+{
+    GenericRdataFactoryMap::iterator found =
+        impl_->genericrdata_factories.find(rrtype);
+    if (found != impl_->genericrdata_factories.end()) {
+        impl_->genericrdata_factories.erase(found);
+        return (true);
+    }
+
+    return (false);
+}
+
 namespace {
 ///
 /// These are helper functions to implement case-insensitive string comparison.
@@ -338,12 +406,13 @@ textToCode(const string& code_str, MS& stringmap)
     }
 
     size_t l = code_str.size();
-    if (l > PT::UNKNOWN_PREFIXLEN &&
-        l <= PT::UNKNOWN_MAXLEN &&
-        caseStringEqual(code_str, PT::UNKNOWN_PREFIX, PT::UNKNOWN_PREFIXLEN)) {
+    if (l > PT::UNKNOWN_PREFIXLEN() &&
+        l <= PT::UNKNOWN_MAXLEN() &&
+        caseStringEqual(code_str, PT::UNKNOWN_PREFIX(),
+                        PT::UNKNOWN_PREFIXLEN())) {
         unsigned int code;
-        istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN,
-                                           l - PT::UNKNOWN_PREFIXLEN));
+        istringstream iss(code_str.substr(PT::UNKNOWN_PREFIXLEN(),
+                                          l - PT::UNKNOWN_PREFIXLEN()));
         iss >> dec >> code;
         if (iss.rdstate() == ios::eofbit && code <= PT::MAX_CODE) {
             return (code);
@@ -365,7 +434,7 @@ codeToText(uint16_t code, MC& codemap)
 
     ostringstream ss;
     ss << code;
-    return (PT::UNKNOWN_PREFIX + ss.str());
+    return (PT::UNKNOWN_PREFIX() + ss.str());
 }
 }
 
@@ -444,7 +513,7 @@ RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
         return (genfound->second->create(rdata_string));
     }
 
-    dns_throw(InvalidRdataText, "Unrecognized Rdata type to create from text");
+    return (RdataPtr(new generic::Generic(rdata_string)));
 }
 
 RdataPtr
@@ -463,7 +532,6 @@ RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
         return (genfound->second->create(buffer, rdata_len));
     }
 
-    // construct an "unknown" type of RDATA
     return (RdataPtr(new generic::Generic(buffer, rdata_len)));
 }
 
@@ -483,7 +551,8 @@ RRParamRegistry::createRdata(const RRType& rrtype, const RRClass& rrclass,
         return (genfound->second->create(source));
     }
 
-    dns_throw(InvalidRdataText, "TBD");
+    return (RdataPtr(new rdata::generic::Generic(
+                         dynamic_cast<const generic::Generic&>(source))));
 }
 }
 }

+ 171 - 20
src/lib/dns/cpp/rrparamregistry.h

@@ -52,26 +52,79 @@ public:
         isc::Exception(file, line, what) {}
 };
 
-class InvalidRdataText : public Exception {
-public:
-    InvalidRdataText(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
 namespace rdata {
+/// \brief The \c AbstractRdataFactory class is an abstract base class to
+/// encapsulate a set of Rdata factory methods in a polymorphic way.
+///
+/// An external developers who want to introduce a new or experimental RR type
+/// are expected to define a corresponding derived class of \c
+/// AbstractRdataFactory and register it via \c RRParamRegistry.
+///
+/// For other users of this API normally do not have to care about this class
+/// or its derived classes; this class is generally intended to be used
+/// as an internal utility of the API implementation.
 class AbstractRdataFactory {
+    ///
+    /// \name Constructors and Destructor
+    ///
+    //@{
 protected:
+    /// The default constructor
+    ///
+    /// This is intentionally defined as \c protected as this base class should
+    /// never be instantiated (except as part of a derived class).
     AbstractRdataFactory() {}
 public:
+    /// The destructor.
     virtual ~AbstractRdataFactory() {};
+    //@}
 
-    // Factory methods for polymorphic creation:
+    ///
+    /// \name Factory methods for polymorphic creation.
+    ///
+    //@{
+    ///
+    /// \brief Create RDATA from a string.
+    ///
+    /// This method creates from a string an \c Rdata object of specific class
+    /// corresponding to the specific derived class of \c AbstractRdataFactory.
+    ///
+    /// \param rdata_str A string of textual representation of the \c Rdata.
+    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
     virtual RdataPtr create(const std::string& rdata_str) const = 0;
+    ///
+    /// \brief Create RDATA from wire-format data.
+    ///
+    /// This method creates from wire-format binary data an \c Rdata object
+    /// of specific class corresponding to the specific derived class of
+    /// \c AbstractRdataFactory.
+    ///
+    /// \param buffer A reference to an \c InputBuffer object storing the
+    /// \c Rdata to parse.
+    /// \param rdata_len The length in buffer of the \c Rdata.  In bytes.
+    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
     virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const = 0;
+    ///
+    /// \brief Create RDATA from another \c Rdata object of the same type.
+    ///
+    /// This method creates an \c Rdata object of specific class corresponding
+    /// to the specific derived class of \c AbstractRdataFactory, copying the
+    /// content of the given \c Rdata, \c source.
+    ///
+    /// \c source must be an object of the concrete derived class corresponding
+    /// to the specific derived class of \c AbstractRdataFactory;
+    /// otherwise, an exception of class \c std::bad_cast will be thrown.
+    ///
+    /// \param source A reference to an \c Rdata object whose content is to
+    /// be copied to the created \c Rdata object.
+    /// \return An \c RdataPtr object pointing to the created \c Rdata object.
     virtual RdataPtr create(const rdata::Rdata& source) const = 0;
+    //@}
 };
+
 ///
-/// TBD: describe it
+/// The \c RdataFactoryPtr type is a pointer-like type, pointing to an
+/// object of some concrete derived class of \c AbstractRdataFactory.
 ///
 typedef boost::shared_ptr<AbstractRdataFactory> RdataFactoryPtr;
 } // end of namespace rdata
@@ -158,7 +211,7 @@ public:
     /// representations.
     ///
     /// Regarding the mappings between textual representations and integer
-    /// codes, this methods behaves in the same way as \c addType() and
+    /// codes, this method behaves in the same way as \c addType() and
     /// \c addClass().  That is, it ignores any overriding attempt as
     /// long as the mapping is the same; otherwise the corresponding exception
     /// will be thrown.
@@ -168,18 +221,25 @@ public:
     /// stored in the registry; if this method throws an exception the
     /// registry will remain in the state before this method is called.
     ///
-    /// Note: this method will be extended to support more parameters in a
-    /// near future version.
-    ///
     /// \param type_string The textual representation of the RR type.
     /// \param type_code The integer code of the RR type.
     /// \param class_string The textual representation of the RR class.
     /// \param class_code The integer code of the RR class.
+    /// \param rdata_factory An \c RdataFactoryPtr object pointing to a
+    /// concrete RDATA factory.
     void add(const std::string& type_string, uint16_t type_code,
              const std::string& class_string, uint16_t class_code,
              rdata::RdataFactoryPtr rdata_factory);
 
-    /// TBD
+    /// \brief Add a set of parameters for a class-independent RR type.
+    ///
+    /// This method behaves as exactly same as the other \c add method except
+    /// that it handles class-independent types (such as NS, CNAME, or SOA).
+    ///
+    /// \param type_string The textual representation of the RR type.
+    /// \param type_code The integer code of the RR type.
+    /// \param rdata_factory An \c RdataFactoryPtr object pointing to a
+    /// concrete RDATA factory.
     void add(const std::string& type_string, uint16_t type_code,
              rdata::RdataFactoryPtr rdata_factory);
 
@@ -219,7 +279,7 @@ public:
     /// exist in the registry.  If not, this method simply ignores the attempt
     /// and returns \c false.
     ///
-    /// This method never throw an exception.
+    /// This method never throws an exception.
     ///
     /// \param type_code The integer code of the RR type.
     /// \return \c true if mappings for the specified RR type exists and is
@@ -251,7 +311,8 @@ public:
     ///
     /// \param class_string The textual representation of the RR class.
     /// \param class_code The integer code of the RR class.
-    /// \return
+    /// \return \c true if a new mapping is added to the repository; \c false
+    /// if the same mapping is already registered.
     bool addClass(const std::string& class_string, uint16_t class_code);
 
     /// \brief Remove mappings between RR class code and textual representation
@@ -261,11 +322,43 @@ public:
     /// exist in the registry.  If not, this method simply ignores the attempt
     /// and returns \c false.
     ///
-    /// This method never throw an exception.
+    /// This method never throws an exception.
     ///
     /// \param class_code The integer code of the RR class.
-    /// \return
+    /// \return \c true if mappings for the specified RR type exists and is
+    /// removed; \c false if no such mapping is in the registry.
     bool removeClass(uint16_t class_code);
+
+    /// \brief Remove registered RDATA factory for the given pair of \c RRType
+    /// and \c RRClass.
+    ///
+    /// This method can safely be called whether or not the specified factory
+    /// object exist in the registry.  If not, this method simply ignores the
+    /// attempt and returns \c false.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \param rrclass An \c RRClass object specifying the type/class pair.
+    /// \return \c true if a factory object for the specified RR type/class
+    /// pair exists and is removed; \c false if no such object is in the
+    /// registry.
+    bool removeRdataFactory(const RRType& rrtype, const RRClass& rrclass);
+
+    /// \brief Remove registered RDATA factory for the given pair of \c RRType
+    /// and \c RRClass.
+    ///
+    /// This method can safely be called whether or not the specified factory
+    /// object exist in the registry.  If not, this method simply ignores the
+    /// attempt and returns \c false.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \return \c true if a factory object for the specified RR type/class
+    /// pair exists and is removed; \c false if no such object is in the
+    /// registry.
+    bool removeRdataFactory(const RRType& rrtype);
     //@}
 
     ///
@@ -338,14 +431,72 @@ public:
     ///
     /// \name RDATA Factories
     ///
+    /// This set of methods provide a unified interface to create an
+    /// \c rdata::Rdata object in a parameterized polymorphic way,
+    /// that is, these methods take a pair of \c RRType and \c RRClass
+    /// objects and data specific to that pair, and create an object of
+    /// the corresponding concrete derived class of \c rdata::Rdata.
+    ///
+    /// These methods first search the \c RRParamRegistry for a factory
+    /// method (a member of a concrete derived class of
+    /// \c AbstractRdataFactory) for the given RR type and class pair.
+    /// If the search fails, they then search for a factory method for
+    /// the given type ignoring the class, in case a RRClass independent
+    /// factory method is registered.
+    /// If it still fails, these methods assume the RDATA is of an "unknown"
+    /// type, and creates a new object by calling a constructor of the
+    /// \c rdata::generic::Generic class.
+    ///
     //@{
-    /// \brief TBD
+    /// \brief Create RDATA of a given pair of RR type and class from a string.
+    ///
+    /// This method creates from a string an \c Rdata object of the given pair
+    /// of RR type and class.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \param rrclass An \c RRClass object specifying the type/class pair.
+    /// \param rdata_string A string of textual representation of the \c Rdata.
+    /// \return An \c rdata::RdataPtr object pointing to the created \c Rdata
+    /// object.
     rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                 const std::string& rdata_string);
-    /// \brief TBD
+    /// \brief Create RDATA of a given pair of RR type and class from
+    /// wire-format data.
+    ///
+    /// This method creates from wire-format binary data an \c Rdata object
+    /// of the given pair of RR type and class.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \param rrclass An \c RRClass object specifying the type/class pair.
+    /// \param buffer A reference to an \c InputBuffer object storing the
+    /// \c Rdata to parse.
+    /// \param len The length in buffer of the \c Rdata.  In bytes.
+    /// \return An \c rdata::RdataPtr object pointing to the created \c Rdata
+    /// object.
     rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                 InputBuffer& buffer, size_t len);
-    /// \brief Polymorphic copy constructor (detailed TBD)
+    /// \brief Create RDATA of a given pair of RR type and class, copying
+    /// of another RDATA of same kind.
+    ///
+    /// This method creates an \c Rdata object of the given pair of
+    /// RR type and class, copying the  content of the given \c Rdata,
+    /// \c source.
+    ///
+    /// \c source must be an object of the concrete derived class of
+    /// \c rdata::Rdata for the given pair of RR type and class;
+    /// otherwise, an exception of class \c std::bad_cast will be thrown.
+    /// In case the \c RRParamRegistry doesn't have a factory method for
+    /// the given pair and it is assumed to be of an "unknown" type,
+    /// \c source must reference an object of class
+    /// \c rdata::generic::Generic; otherwise, an exception of class
+    /// \c std::bad_cast will be thrown.
+    ///
+    /// \param rrtype An \c RRType object specifying the type/class pair.
+    /// \param rrclass An \c RRClass object specifying the type/class pair.
+    /// \param source A reference to an \c rdata::Rdata object whose content
+    /// is to be copied to the created \c rdata::Rdata object.
+    /// \return An \c rdata::RdataPtr object pointing to the created
+    /// \c rdata::Rdata object.
     rdata::RdataPtr createRdata(const RRType& rrtype, const RRClass& rrclass,
                                 const rdata::Rdata& source);
     //@}

+ 0 - 92
src/lib/dns/cpp/rrparamregistry_unittest.cc

@@ -1,92 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// $Id$
-
-#include <string>
-#include <sstream>
-
-#include <stdint.h>
-
-#include <gtest/gtest.h>
-
-#include "rrclass.h"
-#include "rrparamregistry.h"
-#include "rrtype.h"
-
-using namespace std;
-using namespace isc::dns;
-
-namespace {
-class RRParamRegistryTest : public ::testing::Test {
-protected:
-    RRParamRegistryTest()
-    {
-        ostringstream oss1;
-        oss1 << test_class_code;
-        test_class_unknown_str = "CLASS" + oss1.str();
-
-        ostringstream oss2;
-        oss2 << test_type_code;
-        test_type_unknown_str = "TYPE" + oss2.str();
-    }
-
-    string test_class_unknown_str;
-    string test_type_unknown_str;
-
-    // we assume class/type numbers are officially unassigned.  If not we'll
-    // need to update the test cases.
-    static const uint16_t test_class_code = 65533; 
-    static const uint16_t test_type_code = 65534;
-    static const string test_class_str;
-    static const string test_type_str;
-};
-
-const string RRParamRegistryTest::test_class_str("TESTCLASS");
-const string RRParamRegistryTest::test_type_str("TESTTYPE");
-
-TEST_F(RRParamRegistryTest, addRemove)
-{
-    RRParamRegistry::getRegistry().addType(test_type_str, test_type_code);
-    RRParamRegistry::getRegistry().addClass(test_class_str, test_class_code);
-    EXPECT_EQ(65533, RRClass("TESTCLASS").getCode());
-    EXPECT_EQ(65534, RRType("TESTTYPE").getCode());
-
-    // the first removal attempt should succeed
-    EXPECT_TRUE(RRParamRegistry::getRegistry().removeType(65534));
-    // then toText() should treat it as an "unknown" 
-    EXPECT_EQ(test_type_unknown_str, RRType(test_type_code).toText());
-    // attempt of removing non-existent mapping should result in 'false'
-    EXPECT_FALSE(RRParamRegistry::getRegistry().removeType(65534));
-
-    // same set of tests for RR class.
-    EXPECT_TRUE(RRParamRegistry::getRegistry().removeClass(65533));
-    EXPECT_EQ(test_class_unknown_str, RRClass(test_class_code).toText());
-    EXPECT_FALSE(RRParamRegistry::getRegistry().removeClass(65533));
-}
-
-TEST_F(RRParamRegistryTest, addError)
-{
-    // An attempt to override a pre-registered class should fail with an
-    // exception, and the pre-registered one should remain in the registry.
-    EXPECT_THROW(RRParamRegistry::getRegistry().addClass(test_class_str, 1),
-                 RRClassExists);
-    EXPECT_EQ("IN", RRClass(1).toText());
-
-    // Same for RRType
-    EXPECT_THROW(RRParamRegistry::getRegistry().addType(test_type_str, 1),
-                 RRTypeExists);
-    EXPECT_EQ("A", RRType(1).toText());
-}
-}

+ 33 - 0
src/lib/dns/cpp/tests/Makefile.am

@@ -0,0 +1,33 @@
+AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/ext
+AM_CPPFLAGS += -I$(top_builddir)/include/dns/cpp
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = unittest_util.h unittest_util.cc
+run_unittests_SOURCES += buffer_unittest.cc name_unittest.cc
+run_unittests_SOURCES += messagerenderer_unittest.cc
+run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc
+run_unittests_SOURCES += rrttl_unittest.cc
+run_unittests_SOURCES += rdata_unittest.h rdata_unittest.cc
+run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc
+run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
+run_unittests_SOURCES += rdata_txt_unittest.cc rdata_mx_unittest.cc
+run_unittests_SOURCES += rdata_cname_unittest.cc
+run_unittests_SOURCES += rdata_rrsig_unittest.cc
+run_unittests_SOURCES += rrset_unittest.cc
+run_unittests_SOURCES += question_unittest.cc
+run_unittests_SOURCES += rrparamregistry_unittest.cc
+run_unittests_SOURCES += message_unittest.cc
+run_unittests_SOURCES += base64_unittest.cc
+run_unittests_SOURCES += run_unittests.cc
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/cpp/.libs/libdns.a
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/cpp/.libs/libexceptions.a
+endif
+
+noinst_PROGRAMS = $(TESTS)

+ 1 - 1
src/lib/dns/cpp/base64_unittest.cc

@@ -18,7 +18,7 @@
 #include <utility>
 #include <vector>
 
-#include "base64.h"
+#include <dns/base64.h>
 
 #include <gtest/gtest.h>
 

+ 1 - 1
src/lib/dns/cpp/buffer_unittest.cc

@@ -14,7 +14,7 @@
 
 // $Id$
 
-#include "buffer.h"
+#include <dns/buffer.h>
 
 #include <gtest/gtest.h>
 

+ 8 - 8
src/lib/dns/cpp/message_unittest.cc

@@ -14,14 +14,14 @@
 
 // $Id$
 
-#include "buffer.h"
-#include "message.h"
-#include "messagerenderer.h"
-#include "question.h"
-#include "rdataclass.h"
-#include "rrclass.h"
-#include "rrttl.h"
-#include "rrtype.h"
+#include <dns/buffer.h>
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/question.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrttl.h>
+#include <dns/rrtype.h>
 
 #include <gtest/gtest.h>
 

+ 3 - 3
src/lib/dns/cpp/messagerenderer_unittest.cc

@@ -16,9 +16,9 @@
 
 #include <vector>
 
-#include "buffer.h"
-#include "name.h"
-#include "messagerenderer.h"
+#include <dns/buffer.h>
+#include <dns/name.h>
+#include <dns/messagerenderer.h>
 
 #include "unittest_util.h"
 

+ 3 - 3
src/lib/dns/cpp/name_unittest.cc

@@ -20,9 +20,9 @@
 #include <iomanip>
 #include <stdexcept>
 
-#include "buffer.h"
-#include "name.h"
-#include "messagerenderer.h"
+#include <dns/buffer.h>
+#include <dns/name.h>
+#include <dns/messagerenderer.h>
 
 #include "unittest_util.h"
 

+ 6 - 6
src/lib/dns/cpp/question_unittest.cc

@@ -19,12 +19,12 @@
 
 #include <exceptions/exceptions.h>
 
-#include "buffer.h"
-#include "messagerenderer.h"
-#include "name.h"
-#include "question.h"
-#include "rrclass.h"
-#include "rrtype.h"
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/question.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
 
 #include <gtest/gtest.h>
 

+ 121 - 0
src/lib/dns/cpp/tests/rdata_cname_unittest.cc

@@ -0,0 +1,121 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_CNAME_Test : public RdataTest {
+    // there's nothing to specialize
+};
+
+const generic::CNAME rdata_cname("cn.example.com");
+const generic::CNAME rdata_cname2("cn2.example.com");
+const uint8_t wiredata_cname[] = {
+    0x02, 0x63, 0x6e, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
+    0x63, 0x6f, 0x6d, 0x00 };
+const uint8_t wiredata_cname2[] = {
+    // first name: cn.example.com.
+    0x02, 0x63, 0x6e, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
+    0x63, 0x6f, 0x6d, 0x00,
+    // second name: cn2.example.com.  all labels except the first should be
+    // compressed.
+    0x03, 0x63, 0x6e, 0x32, 0xc0, 0x03 };
+
+TEST_F(Rdata_CNAME_Test, createFromText)
+{
+    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("cn.example.com")));
+    // explicitly add a trailing dot.  should be the same RDATA.
+    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("cn.example.com.")));
+    // should be case sensitive.
+    EXPECT_EQ(0, rdata_cname.compare(generic::CNAME("CN.EXAMPLE.COM")));
+    // RDATA of a class-independent type should be recognized for any
+    // "unknown" class.
+    EXPECT_EQ(0, rdata_cname.compare(*createRdata(RRType("CNAME"),
+                                                  RRClass(65000),
+                                                  "cn.example.com")));
+}
+
+TEST_F(Rdata_CNAME_Test, createFromWire)
+{
+    EXPECT_EQ(0, rdata_cname.compare(
+                  *rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
+                                        "testdata/rdata_cname_fromWire")));
+    // RDLENGTH is too short
+    EXPECT_THROW(rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
+                                      "testdata/rdata_cname_fromWire", 18),
+                 InvalidRdataLength);
+    // RDLENGTH is too long
+    EXPECT_THROW(rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
+                                      "testdata/rdata_cname_fromWire", 36),
+                 InvalidRdataLength);
+    // incomplete name.  the error should be detected in the name constructor
+    EXPECT_THROW(rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
+                                      "testdata/rdata_cname_fromWire", 71),
+                 IncompleteName);
+
+    EXPECT_EQ(0, generic::CNAME("cn2.example.com").compare(
+                  *rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
+                                        "testdata/rdata_cname_fromWire", 55)));
+    EXPECT_THROW(*rdataFactoryFromFile(RRType("CNAME"), RRClass("IN"),
+                                       "testdata/rdata_cname_fromWire", 63),
+                 InvalidRdataLength);
+}
+
+TEST_F(Rdata_CNAME_Test, toWireBuffer)
+{
+    rdata_cname.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_cname, sizeof(wiredata_cname));
+}
+
+TEST_F(Rdata_CNAME_Test, toWireRenderer)
+{
+    rdata_cname.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_cname, sizeof(wiredata_cname));
+    rdata_cname2.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_cname2, sizeof(wiredata_cname2));
+}
+
+TEST_F(Rdata_CNAME_Test, toText)
+{
+    EXPECT_EQ("cn.example.com.", rdata_cname.toText());
+}
+
+TEST_F(Rdata_CNAME_Test, getCname)
+{
+    EXPECT_EQ(Name("cn.example.com."), rdata_cname.getCname());
+}
+}

+ 117 - 0
src/lib/dns/cpp/tests/rdata_in_a_unittest.cc

@@ -0,0 +1,117 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_IN_A_Test : public RdataTest {
+    // there's nothing to specialize
+};
+
+const in::A rdata_in_a("192.0.2.1");
+const uint8_t wiredata_in_a[] = { 192, 0, 2, 1 };
+
+TEST_F(Rdata_IN_A_Test, createFromText)
+{
+    EXPECT_EQ(0, rdata_in_a.compare(in::A("192.0.2.1")));
+    // should reject an abbreviated form of IPv4 address
+    EXPECT_THROW(in::A("10.1"), InvalidRdataText);
+    // or an IPv6 address
+    EXPECT_THROW(in::A("2001:db8::1234"), InvalidRdataText);
+    // or any meaningless text as an IP address
+    EXPECT_THROW(in::A("xxx"), InvalidRdataText);
+}
+
+TEST_F(RdataTest, createFromWire)
+{
+    // Valid data
+    EXPECT_EQ(0, rdata_in_a.compare(
+                  *rdataFactoryFromFile(RRType("A"), RRClass("IN"),
+                                        "testdata/rdata_in_a_fromWire")));
+    // RDLENGTH is too short
+    EXPECT_THROW(rdataFactoryFromFile(RRType("A"), RRClass("IN"),
+                                      "testdata/rdata_in_a_fromWire", 6),
+                 InvalidRdataLength);
+    // RDLENGTH is too long
+    EXPECT_THROW(rdataFactoryFromFile(RRType("A"), RRClass("IN"),
+                                      "testdata/rdata_in_a_fromWire", 12),
+                 InvalidRdataLength);
+    // buffer too short.  the error should be detected in buffer read
+    EXPECT_THROW(rdataFactoryFromFile(RRType("A"), RRClass("IN"),
+                                      "testdata/rdata_in_a_fromWire", 19),
+                 InvalidBufferPosition);
+}
+
+TEST_F(RdataTest, toWireBuffer)
+{
+    rdata_in_a.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_in_a, sizeof(wiredata_in_a));
+}
+
+TEST_F(RdataTest, toWireRenderer)
+{
+    rdata_in_a.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_in_a, sizeof(wiredata_in_a));
+}
+
+TEST_F(RdataTest, toText)
+{
+    EXPECT_EQ("192.0.2.1", rdata_in_a.toText());
+    string longaddr("255.255.255.255"); // this shouldn't make the code crash
+    EXPECT_EQ(longaddr, in::A(longaddr).toText());
+}
+
+TEST_F(RdataTest, compare)
+{
+    in::A small1("1.1.1.1");
+    in::A small2("1.2.3.4");
+    in::A large1("255.255.255.255");
+    in::A large2("4.3.2.1");
+
+    // trivial case: self equivalence
+    EXPECT_EQ(0, small1.compare(small1));
+
+    // confirm these are compared as unsigned values
+    EXPECT_GT(0, small1.compare(large1));
+    EXPECT_LT(0, large1.compare(small1));
+
+    // confirm these are compared in network byte order
+    EXPECT_GT(0, small2.compare(large2));
+    EXPECT_LT(0, large2.compare(small2));
+
+    // comparison attempt between incompatible RR types should be rejected
+    EXPECT_THROW(rdata_in_a.compare(*RdataTest::rdata_nomatch), bad_cast); 
+}
+}

+ 102 - 0
src/lib/dns/cpp/tests/rdata_in_aaaa_unittest.cc

@@ -0,0 +1,102 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_IN_AAAA_Test : public RdataTest {
+    // there's nothing to specialize
+};
+
+const in::AAAA rdata_in_aaaa("2001:db8::1234");
+const uint8_t wiredata_in_aaaa[] = {
+    0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x12, 0x34 };
+
+TEST_F(Rdata_IN_AAAA_Test, createFromText)
+{
+    rdata_in_aaaa.compare(in::AAAA(string("2001:db8::1234")));
+    EXPECT_THROW(in::AAAA("192.0.2.1"), InvalidRdataText);
+    EXPECT_THROW(in::AAAA("xxx"), InvalidRdataText);
+}
+
+TEST_F(Rdata_IN_AAAA_Test, createFromWire)
+{
+    // Valid data
+    EXPECT_EQ(0, rdata_in_aaaa.compare(
+                  *rdataFactoryFromFile(RRType("AAAA"), RRClass("IN"),
+                                        "testdata/rdata_in_aaaa_fromWire")));
+    //TBD: more tests
+}
+
+TEST_F(Rdata_IN_AAAA_Test, toWireBuffer)
+{
+    rdata_in_aaaa.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_in_aaaa, sizeof(wiredata_in_aaaa));
+}
+
+TEST_F(Rdata_IN_AAAA_Test, toWireRenderer)
+{
+    rdata_in_aaaa.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_in_aaaa, sizeof(wiredata_in_aaaa));
+}
+
+TEST_F(Rdata_IN_AAAA_Test, toText)
+{
+    EXPECT_EQ("2001:db8::1234", rdata_in_aaaa.toText());
+}
+
+TEST_F(Rdata_IN_AAAA_Test, compare)
+{
+    in::AAAA small1("::1");
+    in::AAAA small2("1:2:3:4:5:6:7:8");
+    in::AAAA large1("ffff::");
+    in::AAAA large2("8:7:6:5:4:3:2:1");
+
+    // trivial case: self equivalence
+    EXPECT_EQ(0, small1.compare(small1));
+
+    // confirm these are compared as unsigned values
+    EXPECT_GT(0, small1.compare(large1));
+    EXPECT_LT(0, large1.compare(small1));
+
+    // confirm these are compared in network byte order
+    EXPECT_GT(0, small2.compare(large2));
+    EXPECT_LT(0, large2.compare(small2));
+
+    // comparison attempt between incompatible RR types should be rejected
+    EXPECT_THROW(rdata_in_aaaa.compare(*RdataTest::rdata_nomatch), bad_cast); 
+}
+}

+ 91 - 0
src/lib/dns/cpp/tests/rdata_mx_unittest.cc

@@ -0,0 +1,91 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_MX_Test : public RdataTest {
+    // there's nothing to specialize
+};
+
+const generic::MX rdata_mx(10, Name("mx.example.com"));
+
+TEST_F(Rdata_MX_Test, createFromText)
+{
+    //TBD
+}
+
+TEST_F(Rdata_MX_Test, createFromWire)
+{
+    EXPECT_EQ(0, rdata_mx.compare(
+                  *rdataFactoryFromFile(RRType("MX"), RRClass("IN"),
+                                        "testdata/rdata_mx_fromWire")));
+    // TBD: more tests
+}
+
+TEST_F(Rdata_MX_Test, toWireRenderer)
+{
+    renderer.writeName(Name("example.com"));
+    rdata_mx.toWire(renderer);
+
+    vector<unsigned char> data;
+    UnitTestUtil::readWireData("testdata/rdata_mx_toWire1", data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
+                        obuffer.getLength(), &data[0], data.size());
+}
+
+TEST_F(Rdata_MX_Test, toText)
+{
+    EXPECT_EQ("10 mx.example.com.", rdata_mx.toText());
+}
+
+TEST_F(Rdata_MX_Test, compare)
+{
+    generic::MX small1(1, Name("mx.example.com"));
+    generic::MX small2(10, Name("mx.example.com"));
+    generic::MX large1(65535, Name("mx.example.com"));
+    generic::MX large2(256, Name("mx.example.com"));
+
+    // trivial case: self equivalence
+    EXPECT_EQ(0, small1.compare(small1));
+
+    // confirm these are compared as unsigned values
+    EXPECT_GT(0, small1.compare(large1));
+    EXPECT_LT(0, large1.compare(small1));
+
+    // confirm these are compared in network byte order
+    EXPECT_GT(0, small2.compare(large2));
+    EXPECT_LT(0, large2.compare(small2));
+
+    // comparison attempt between incompatible RR types should be rejected
+    EXPECT_THROW(rdata_mx.compare(*rdata_nomatch), bad_cast); 
+}
+}

+ 128 - 0
src/lib/dns/cpp/tests/rdata_ns_unittest.cc

@@ -0,0 +1,128 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_NS_Test : public RdataTest {
+    // there's nothing to specialize
+};
+
+const generic::NS rdata_ns("ns.example.com");
+const generic::NS rdata_ns2("ns2.example.com");
+const uint8_t wiredata_ns[] = {
+    0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
+    0x63, 0x6f, 0x6d, 0x00 };
+const uint8_t wiredata_ns2[] = {
+    // first name: ns.example.com.
+    0x02, 0x6e, 0x73, 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03,
+    0x63, 0x6f, 0x6d, 0x00,
+    // second name: ns2.example.com.  all labels except the first should be
+    // compressed.
+    0x03, 0x6e, 0x73, 0x32, 0xc0, 0x03 };
+
+TEST_F(Rdata_NS_Test, createFromText)
+{
+    EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com")));
+    // explicitly add a trailing dot.  should be the same RDATA.
+    EXPECT_EQ(0, rdata_ns.compare(generic::NS("ns.example.com.")));
+    // should be case sensitive.
+    EXPECT_EQ(0, rdata_ns.compare(generic::NS("NS.EXAMPLE.COM")));
+    // RDATA of a class-independent type should be recognized for any
+    // "unknown" class.
+    EXPECT_EQ(0, rdata_ns.compare(*createRdata(RRType("NS"), RRClass(65000),
+                                               "ns.example.com")));
+}
+
+TEST_F(Rdata_NS_Test, createFromWire)
+{
+    EXPECT_EQ(0, rdata_ns.compare(
+                  *rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+                                        "testdata/rdata_ns_fromWire")));
+    // RDLENGTH is too short
+    EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+                                      "testdata/rdata_ns_fromWire", 18),
+                 InvalidRdataLength);
+    // RDLENGTH is too long
+    EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+                                      "testdata/rdata_ns_fromWire", 36),
+                 InvalidRdataLength);
+    // incomplete name.  the error should be detected in the name constructor
+    EXPECT_THROW(rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+                                      "testdata/rdata_ns_fromWire", 71),
+                 IncompleteName);
+
+    EXPECT_EQ(0, generic::NS("ns2.example.com").compare(
+                  *rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+                                        "testdata/rdata_ns_fromWire", 55)));
+    EXPECT_THROW(*rdataFactoryFromFile(RRType("NS"), RRClass("IN"),
+                                       "testdata/rdata_ns_fromWire", 63),
+                 InvalidRdataLength);
+}
+
+TEST_F(Rdata_NS_Test, toWireBuffer)
+{
+    rdata_ns.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_ns, sizeof(wiredata_ns));
+}
+
+TEST_F(Rdata_NS_Test, toWireRenderer)
+{
+    rdata_ns.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_ns, sizeof(wiredata_ns));
+    rdata_ns2.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_ns2, sizeof(wiredata_ns2));
+}
+
+TEST_F(Rdata_NS_Test, toText)
+{
+    EXPECT_EQ("ns.example.com.", rdata_ns.toText());
+}
+
+TEST_F(Rdata_NS_Test, compare)
+{
+    generic::NS small("a.example");
+    generic::NS large("example");
+    EXPECT_EQ(true, Name("a.example") > Name("example"));
+    EXPECT_GT(0, small.compare(large));
+}
+
+TEST_F(Rdata_NS_Test, getNSName)
+{
+    EXPECT_EQ(Name("ns.example.com"), rdata_ns.getNSName());
+}
+}

+ 60 - 0
src/lib/dns/cpp/tests/rdata_rrsig_unittest.cc

@@ -0,0 +1,60 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_RRSIG_Test : public RdataTest {
+    // there's nothing to specialize
+};
+
+TEST_F(Rdata_RRSIG_Test, fromText)
+{
+    string rrsig_txt("A 5 4 43200 1264801134 191145710 8496 isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+    generic::RRSIG rdata_rrsig(rrsig_txt);
+    EXPECT_EQ(rrsig_txt, rdata_rrsig.toText());
+}
+
+TEST_F(Rdata_RRSIG_Test, toWireRenderer)
+{
+    string rrsig_txt("A 5 4 43200 1264801134 191145710 8496 isc.org. "
+                     "evxhlGx13mpKLVkKsjpGzycS5twtIoxOmlN14w9t5AgzGBmz"
+                     "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
+                     "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
+                     "f49t+sXKPzbipN9g+s1ZPiIyofc=");
+    generic::RRSIG rdata_rrsig(rrsig_txt);
+    rdata_rrsig.toWire(renderer);
+}
+}

+ 73 - 0
src/lib/dns/cpp/tests/rdata_soa_unittest.cc

@@ -0,0 +1,73 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_SOA_Test : public RdataTest {
+    // there's nothing to specialize
+};
+
+const generic::SOA rdata_soa(Name("ns.example.com"),
+                                        Name("root.example.com"),
+                                        2010012601, 3600, 300, 3600000, 1200);
+
+TEST_F(Rdata_SOA_Test, createFromText)
+{
+    //TBD
+}
+
+TEST_F(Rdata_SOA_Test, createFromWire)
+{
+    EXPECT_EQ(0, rdata_soa.compare(
+                  *rdataFactoryFromFile(RRType("SOA"), RRClass("IN"),
+                                        "testdata/rdata_soa_fromWire")));
+    // TBD: more tests
+}
+
+TEST_F(Rdata_SOA_Test, toWireRenderer)
+{
+    renderer.skip(2);
+    rdata_soa.toWire(renderer);
+
+    vector<unsigned char> data;
+    UnitTestUtil::readWireData("testdata/rdata_soa_fromWire", data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        static_cast<const uint8_t *>(obuffer.getData()) + 2,
+                        obuffer.getLength() - 2, &data[0] + 2, data.size() - 2);
+}
+
+TEST_F(Rdata_SOA_Test, toText)
+{
+    EXPECT_EQ("ns.example.com. root.example.com. "
+              "2010012601 3600 300 3600000 1200", rdata_soa.toText());
+}
+}

+ 70 - 0
src/lib/dns/cpp/tests/rdata_txt_unittest.cc

@@ -0,0 +1,70 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class Rdata_TXT_Test : public RdataTest {
+    // there's nothing to specialize
+};
+
+const generic::TXT rdata_txt("Test String");
+const generic::TXT rdata_txt_quoated("\"Test String\"");
+const uint8_t wiredata_txt[] = {
+    sizeof("Test String") - 1,
+    'T', 'e', 's', 't', ' ', 'S', 't', 'r', 'i', 'n', 'g'
+};
+
+TEST_F(RdataTest, createFromText)
+{
+    EXPECT_EQ(0, rdata_txt.compare(rdata_txt_quoated));
+}
+
+TEST_F(Rdata_TXT_Test, createFromWire)
+{
+    EXPECT_EQ(0, rdata_txt.compare(
+                  *rdataFactoryFromFile(RRType("TXT"), RRClass("IN"),
+                                        "testdata/rdata_txt_fromWire")));
+}
+
+TEST_F(Rdata_TXT_Test, toWireBuffer)
+{
+    rdata_txt.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_txt, sizeof(wiredata_txt));
+}
+
+TEST_F(Rdata_TXT_Test, toText)
+{
+    EXPECT_EQ("\"Test String\"", rdata_txt.toText());
+}
+}

+ 314 - 0
src/lib/dns/cpp/tests/rdata_unittest.cc

@@ -0,0 +1,314 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <vector>
+#include <string>
+#include <sstream>
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+
+#include <gtest/gtest.h>
+
+#include "unittest_util.h"
+#include "rdata_unittest.h"
+
+using isc::UnitTestUtil;
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace dns {
+namespace rdata {
+RdataTest::RdataTest() :
+    obuffer(0), renderer(obuffer),
+    rdata_nomatch(createRdata(RRType(0), RRClass(1), "\\# 0"))
+{}
+
+RdataPtr
+RdataTest::rdataFactoryFromFile(const RRType& rrtype, const RRClass& rrclass,
+                                const char* datafile, size_t position)
+{
+    std::vector<unsigned char> data;
+    UnitTestUtil::readWireData(datafile, data);
+
+    InputBuffer buffer(&data[0], data.size());
+    buffer.setPosition(position);
+
+    uint16_t rdlen = buffer.readUint16();
+    return (createRdata(rrtype, rrclass, buffer, rdlen));
+}
+}
+}
+}
+
+namespace {
+class Rdata_Unknown_Test : public RdataTest {
+protected:
+    static string getLongestRdataTxt();
+    static void getLongestRdataWire(vector<uint8_t>& v);
+};
+
+string
+Rdata_Unknown_Test::getLongestRdataTxt()
+{
+    ostringstream oss;
+
+    oss << "\\# " << MAX_RDLENGTH << " ";
+    oss.fill('0');
+    oss << right << hex;
+    for (int i = 0; i < MAX_RDLENGTH; i++) {
+        oss << setw(2) << (i & 0xff);
+    }
+
+    return (oss.str());
+}
+
+void
+Rdata_Unknown_Test::getLongestRdataWire(vector<uint8_t>& v)
+{
+    unsigned char ch = 0;
+    for (int i = 0; i < MAX_RDLENGTH; ++i, ++ch) {
+        v.push_back(ch);
+    }
+}
+
+const string rdata_unknowntxt("\\# 4 a1b2c30d");
+const generic::Generic rdata_unknown(rdata_unknowntxt);
+// Wire-format data correspond to rdata_unknown.  Note that it doesn't include
+// RDLENGTH
+const uint8_t wiredata_unknown[] = { 0xa1, 0xb2, 0xc3, 0x0d };
+
+// "Unknown" RR Type used for the test cases below.  If/when we use this
+// type number as a "well-known" (probably experimental) type, we'll need to
+// renumber it.
+const RRType unknown_rrtype = RRType("TYPE65000");
+
+TEST_F(Rdata_Unknown_Test, createFromText)
+{
+    // valid construction.  This also tests a normal case of "FromWire".
+    EXPECT_EQ(0, generic::Generic("\\# 4 a1b2c30d").compare(
+                  *rdataFactoryFromFile(unknown_rrtype, RRClass("IN"),
+                                        "testdata/rdata_unknown_fromWire")));
+    // upper case hexadecimal digits should also be okay. 
+    EXPECT_EQ(0, generic::Generic("\\# 4 A1B2C30D").compare(
+                  *rdataFactoryFromFile(unknown_rrtype, RRClass("IN"),
+                                        "testdata/rdata_unknown_fromWire")));
+    // 0-length RDATA should be accepted
+    EXPECT_EQ(0, generic::Generic("\\# 0").compare(
+                  *rdataFactoryFromFile(unknown_rrtype, RRClass("IN"),
+                                        "testdata/rdata_unknown_fromWire", 6)));
+    // hex encoding can be space-separated
+    EXPECT_EQ(0, generic::Generic("\\# 4 a1 b2c30d").compare(rdata_unknown));
+    EXPECT_EQ(0, generic::Generic("\\# 4 a1b2 c30d").compare(rdata_unknown));
+    EXPECT_EQ(0, generic::Generic("\\# 4 a1 b2 c3 0d").compare(rdata_unknown));
+    EXPECT_EQ(0, generic::Generic("\\# 4 a1\tb2c3 0d").compare(rdata_unknown));
+
+    // Max-length RDATA
+    vector<uint8_t> v;
+    getLongestRdataWire(v);
+    InputBuffer ibuffer(&v[0], v.size());
+    EXPECT_EQ(0, generic::Generic(getLongestRdataTxt()).compare(
+                  generic::Generic(ibuffer, v.size())));
+
+    // the length field must match the encoding data length.
+    EXPECT_THROW(generic::Generic("\\# 4 1080c0ff00"), InvalidRdataLength);
+    EXPECT_THROW(generic::Generic("\\# 5 1080c0ff"), InvalidRdataLength);
+    // RDATA encoding part must consist of an even number of hex digits.
+    EXPECT_THROW(generic::Generic("\\# 1 1"), InvalidRdataText);
+    EXPECT_THROW(generic::Generic("\\# 1 ax"), InvalidRdataText);
+    // the length should be 16-bit unsigned integer
+    EXPECT_THROW(generic::Generic("\\# 65536 a1b2c30d"), InvalidRdataLength);
+    EXPECT_THROW(generic::Generic("\\# -1 a1b2c30d"), InvalidRdataLength);
+    EXPECT_THROW(generic::Generic("\\# 1.1 a1"), InvalidRdataText);
+    EXPECT_THROW(generic::Generic("\\# 0a 00010203040506070809"),
+                 InvalidRdataText);
+    // should reject if the special token is missing.
+    EXPECT_THROW(generic::Generic("4 a1b2c30d"), InvalidRdataText);
+    // the special token, the RDLENGTH and the data must be space separated.
+    EXPECT_THROW(generic::Generic("\\#0"), InvalidRdataText);
+    EXPECT_THROW(generic::Generic("\\# 1ff"), InvalidRdataText);
+}
+
+TEST_F(Rdata_Unknown_Test, createFromWire)
+{
+    // normal case (including 0-length data) is covered in createFromText.
+
+    // buffer too short.  the error should be detected in buffer read
+    EXPECT_THROW(rdataFactoryFromFile(unknown_rrtype, RRClass("IN"),
+                                      "testdata/rdata_unknown_fromWire", 8),
+                 InvalidBufferPosition);
+
+    // too large data
+    vector<uint8_t> v;
+    getLongestRdataWire(v);
+    v.push_back(0);             // making it too long
+    InputBuffer ibuffer(&v[0], v.size());
+    EXPECT_THROW(generic::Generic(ibuffer, v.size()), InvalidRdataLength);
+}
+
+// The following 3 sets of tests check the behavior of createRdata() variants
+// with the "unknown" RRtype.  The result should be RRclass independent.
+TEST_F(Rdata_Unknown_Test, createRdataFromString)
+{
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("IN"),
+                               rdata_unknowntxt)));
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("CH"),
+                               rdata_unknowntxt)));
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("CLASS65000"),
+                               rdata_unknowntxt)));
+}
+
+TEST_F(Rdata_Unknown_Test, createRdataFromWire)
+{
+    InputBuffer ibuffer(wiredata_unknown, sizeof(wiredata_unknown));
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("IN"),
+                               ibuffer, sizeof(wiredata_unknown))));
+
+    InputBuffer ibuffer2(wiredata_unknown, sizeof(wiredata_unknown));
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("CH"),
+                               ibuffer2, sizeof(wiredata_unknown))));
+
+    InputBuffer ibuffer3(wiredata_unknown, sizeof(wiredata_unknown));
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("CLASS65000"),
+                               ibuffer3, sizeof(wiredata_unknown))));
+}
+
+TEST_F(Rdata_Unknown_Test, createRdataByCopy)
+{
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("IN"), rdata_unknown)));
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("CH"), rdata_unknown)));
+    EXPECT_EQ(0, rdata_unknown.compare(
+                  *createRdata(unknown_rrtype, RRClass("CLASS65000"),
+                               rdata_unknown)));
+}
+
+TEST_F(Rdata_Unknown_Test, copyConstruct)
+{
+    generic::Generic copy(rdata_unknown);
+    EXPECT_EQ(0, copy.compare(rdata_unknown));
+
+    // Check the copied data is valid even after the original is deleted
+    generic::Generic* copy2 = new generic::Generic(rdata_unknown);
+    generic::Generic copy3(*copy2);
+    delete copy2;
+    EXPECT_EQ(0, copy3.compare(rdata_unknown));
+}
+
+TEST_F(Rdata_Unknown_Test, assignment)
+{
+    generic::Generic copy("\\# 1 10");
+    copy = rdata_unknown;
+    EXPECT_EQ(0, copy.compare(rdata_unknown));
+
+    // Check if the copied data is valid even after the original is deleted
+    generic::Generic* copy2 = new generic::Generic(rdata_unknown);
+    generic::Generic copy3("\\# 1 10");
+    copy3 = *copy2;
+    delete copy2;
+    EXPECT_EQ(0, copy3.compare(rdata_unknown));
+
+    // Self assignment
+    copy = copy;
+    EXPECT_EQ(0, copy.compare(rdata_unknown));
+}
+
+TEST_F(Rdata_Unknown_Test, toText)
+{
+    EXPECT_EQ(rdata_unknowntxt, rdata_unknown.toText());
+    EXPECT_EQ(getLongestRdataTxt(),
+              generic::Generic(getLongestRdataTxt()).toText());
+}
+
+TEST_F(Rdata_Unknown_Test, toWireBuffer)
+{
+    rdata_unknown.toWire(obuffer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_unknown, sizeof(wiredata_unknown));
+}
+
+TEST_F(Rdata_Unknown_Test, toWireRenderer)
+{
+    rdata_unknown.toWire(renderer);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        obuffer.getData(), obuffer.getLength(),
+                        wiredata_unknown, sizeof(wiredata_unknown));
+}
+
+TEST_F(Rdata_Unknown_Test, compare)
+{
+    // comparison as left-justified unsigned octet sequences:
+    EXPECT_EQ(0, rdata_unknown.compare(rdata_unknown));
+
+    generic::Generic rdata_unknown_small("\\# 4 00b2c3ff");
+    EXPECT_GT(0, rdata_unknown_small.compare(rdata_unknown));
+    EXPECT_LT(0, rdata_unknown.compare(rdata_unknown_small));
+
+    generic::Generic rdata_unknown_large("\\# 4 ffb2c300");
+    EXPECT_LT(0, rdata_unknown_large.compare(rdata_unknown));
+    EXPECT_GT(0, rdata_unknown.compare(rdata_unknown_large));
+
+    // the absence of an octet sorts before a zero octet.
+    generic::Generic rdata_unknown_short("\\# 3 a1b2c3");
+    EXPECT_GT(0, rdata_unknown_short.compare(rdata_unknown));
+    EXPECT_LT(0, rdata_unknown.compare(rdata_unknown_short));
+}
+
+TEST_F(Rdata_Unknown_Test, LeftShiftOperator)
+{
+    ostringstream oss;
+    oss << rdata_unknown;
+    EXPECT_EQ(rdata_unknown.toText(), oss.str());
+}
+
+//
+// Tests for global utility functions
+//
+TEST_F(RdataTest, compareNames)
+{
+    Name small("a.example");
+    Name large("example");
+
+    // Check the case where the order is different from the owner name
+    // comparison:
+    EXPECT_EQ(true, small > large);
+    EXPECT_EQ(-1, compareNames(small, large));
+    EXPECT_EQ(1, compareNames(large, small));
+
+    // Check case insensitive comparison:
+    Name small_upper("A.EXAMPLE");
+    EXPECT_EQ(0, compareNames(small, small_upper));
+
+    // the absence of an octet sorts before a zero octet.
+    Name large2("a.example2");
+    EXPECT_EQ(-1, compareNames(small, large2));
+    EXPECT_EQ(1, compareNames(large2, small));
+}
+}

+ 51 - 0
src/lib/dns/cpp/tests/rdata_unittest.h

@@ -0,0 +1,51 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __RDATA_UNITTEST_H
+#define __RDATA_UNITTEST_H 1
+
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rdata.h>
+
+#include <gtest/gtest.h>
+
+namespace isc {
+namespace dns {
+namespace rdata {
+class RdataTest : public ::testing::Test {
+protected:
+    RdataTest();
+    static RdataPtr rdataFactoryFromFile(const RRType& rrtype,
+                                         const RRClass& rrclass,
+                                         const char* datafile,
+                                         size_t position = 0);
+    OutputBuffer obuffer;
+    MessageRenderer renderer;
+    /// This is an RDATA object of some "unknown" RR type so that it can be
+    /// used to test the compare() method against a well-known RR type.
+    RdataPtr rdata_nomatch;
+};
+}
+}
+}
+#endif // __RDATA_UNITTEST_H
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 3 - 3
src/lib/dns/cpp/rrclass_unittest.cc

@@ -16,9 +16,9 @@
 
 #include <gtest/gtest.h>
 
-#include "buffer.h"
-#include "messagerenderer.h"
-#include "rrclass.h"
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrclass.h>
 
 #include "unittest_util.h"
 

+ 158 - 0
src/lib/dns/cpp/tests/rrparamregistry_unittest.cc

@@ -0,0 +1,158 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <string>
+#include <sstream>
+
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/rrclass.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrparamregistry.h>
+#include <dns/rrtype.h>
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace {
+class RRParamRegistryTest : public ::testing::Test {
+protected:
+    RRParamRegistryTest()
+    {
+        ostringstream oss1;
+        oss1 << test_class_code;
+        test_class_unknown_str = "CLASS" + oss1.str();
+
+        ostringstream oss2;
+        oss2 << test_type_code;
+        test_type_unknown_str = "TYPE" + oss2.str();
+    }
+    ~RRParamRegistryTest()
+    {
+        // cleanup any non well-known parameters that possibly remain
+        // as a side effect.
+        RRParamRegistry::getRegistry().removeType(test_type_code);
+        RRParamRegistry::getRegistry().removeClass(test_class_code);
+        RRParamRegistry::getRegistry().removeRdataFactory(
+            RRType(test_type_code), RRClass(test_class_code));
+        RRParamRegistry::getRegistry().removeRdataFactory(
+            RRType(test_type_code));
+    }
+
+    string test_class_unknown_str;
+    string test_type_unknown_str;
+
+    // we assume class/type numbers are officially unassigned.  If not we'll
+    // need to update the test cases.
+    static const uint16_t test_class_code = 65533; 
+    static const uint16_t test_type_code = 65534;
+    static const string test_class_str;
+    static const string test_type_str;
+};
+
+const string RRParamRegistryTest::test_class_str("TESTCLASS");
+const string RRParamRegistryTest::test_type_str("TESTTYPE");
+
+TEST_F(RRParamRegistryTest, addRemove)
+{
+    RRParamRegistry::getRegistry().addType(test_type_str, test_type_code);
+    RRParamRegistry::getRegistry().addClass(test_class_str, test_class_code);
+    EXPECT_EQ(65533, RRClass("TESTCLASS").getCode());
+    EXPECT_EQ(65534, RRType("TESTTYPE").getCode());
+
+    // the first removal attempt should succeed
+    EXPECT_TRUE(RRParamRegistry::getRegistry().removeType(test_type_code));
+    // then toText() should treat it as an "unknown" 
+    EXPECT_EQ(test_type_unknown_str, RRType(test_type_code).toText());
+    // attempt of removing non-existent mapping should result in 'false'
+    EXPECT_FALSE(RRParamRegistry::getRegistry().removeType(test_type_code));
+
+    // same set of tests for RR class.
+    EXPECT_TRUE(RRParamRegistry::getRegistry().removeClass(test_class_code));
+    EXPECT_EQ(test_class_unknown_str, RRClass(test_class_code).toText());
+    EXPECT_FALSE(RRParamRegistry::getRegistry().removeClass(test_class_code));
+}
+
+TEST_F(RRParamRegistryTest, addError)
+{
+    // An attempt to override a pre-registered class should fail with an
+    // exception, and the pre-registered one should remain in the registry.
+    EXPECT_THROW(RRParamRegistry::getRegistry().addClass(test_class_str, 1),
+                 RRClassExists);
+    EXPECT_EQ("IN", RRClass(1).toText());
+
+    // Same for RRType
+    EXPECT_THROW(RRParamRegistry::getRegistry().addType(test_type_str, 1),
+                 RRTypeExists);
+    EXPECT_EQ("A", RRType(1).toText());
+}
+
+class TestRdataFactory : public AbstractRdataFactory {
+public:
+    virtual RdataPtr create(const string& rdata_str) const
+    { return RdataPtr(new in::A(rdata_str)); }
+    virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const
+    { return RdataPtr(new in::A(buffer, rdata_len)); }
+    virtual RdataPtr create(const Rdata& source) const
+    { return RdataPtr(new in::A(dynamic_cast<const in::A&>(source))); }
+};
+
+TEST_F(RRParamRegistryTest, addRemoveFactory)
+{
+    // By default, the test type/code pair should be considered "unknown",
+    // so the following should trigger an exception.
+    EXPECT_THROW(createRdata(RRType(test_type_code), RRClass(test_class_code),
+                             "192.0.2.1"),
+                 InvalidRdataText);
+    // Add factories so that we can treat this pair just like in::A.
+    RRParamRegistry::getRegistry().add(test_type_str, test_type_code,
+                                       test_class_str, test_class_code,
+                                       RdataFactoryPtr(new TestRdataFactory));
+    // Now it should be accepted, and should be identical to the same data of
+    // in::A.
+    EXPECT_EQ(0, in::A("192.0.2.1").compare(
+                  *createRdata(RRType(test_type_code), RRClass(test_class_code),
+                              "192.0.2.1")));
+    // It should still fail with other classes as we specified the factories
+    // as class-specific.
+    EXPECT_THROW(createRdata(RRType(test_type_code), RRClass("IN"),
+                             "192.0.2.1"),
+                 InvalidRdataText);
+    // Add the factories also as a class independent RRtype
+    RRParamRegistry::getRegistry().add(test_type_str, test_type_code,
+                                       RdataFactoryPtr(new TestRdataFactory));
+    // Now it should be okay for other classes than the test class.
+    EXPECT_EQ(0, in::A("192.0.2.1").compare(
+                  *createRdata(RRType(test_type_code), RRClass("IN"),
+                              "192.0.2.1")));
+
+    // Remove the added factories: first attempt should succeed; the second
+    // should return false as there's no match
+    EXPECT_TRUE(RRParamRegistry::getRegistry().removeRdataFactory(
+                    RRType(test_type_code), RRClass(test_class_code)));
+    EXPECT_FALSE(RRParamRegistry::getRegistry().removeRdataFactory(
+                     RRType(test_type_code), RRClass(test_class_code)));
+    EXPECT_TRUE(RRParamRegistry::getRegistry().removeRdataFactory(
+                    RRType(test_type_code)));
+    EXPECT_FALSE(RRParamRegistry::getRegistry().removeRdataFactory(
+                     RRType(test_type_code)));
+}
+
+}

+ 9 - 9
src/lib/dns/cpp/rrset_unittest.cc

@@ -16,15 +16,15 @@
 
 #include <stdexcept>
 
-#include "buffer.h"
-#include "messagerenderer.h"
-#include "name.h"
-#include "rdata.h"
-#include "rdataclass.h"
-#include "rrclass.h"
-#include "rrtype.h"
-#include "rrttl.h"
-#include "rrset.h"
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+#include <dns/rrset.h>
 
 #include <gtest/gtest.h>
 

+ 3 - 3
src/lib/dns/cpp/rrttl_unittest.cc

@@ -16,9 +16,9 @@
 
 #include <gtest/gtest.h>
 
-#include "buffer.h"
-#include "messagerenderer.h"
-#include "rrttl.h"
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrttl.h>
 
 #include "unittest_util.h"
 

+ 3 - 3
src/lib/dns/cpp/rrtype_unittest.cc

@@ -16,9 +16,9 @@
 
 #include <gtest/gtest.h>
 
-#include "buffer.h"
-#include "messagerenderer.h"
-#include "rrtype.h"
+#include <dns/buffer.h>
+#include <dns/messagerenderer.h>
+#include <dns/rrtype.h>
 
 #include "unittest_util.h"
 

src/lib/dns/cpp/run_unittests.cc → src/lib/dns/cpp/tests/run_unittests.cc


+ 22 - 0
src/lib/dns/cpp/tests/testdata/message_fromWire1

@@ -0,0 +1,22 @@
+#
+# A simple DNS query message
+# ID = 0x1035
+# QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=2, other COUNTS=0
+# Question: test.example.com. IN A
+# Answer:
+#  test.example.com. 3600 IN A 192.0.2.1
+#  test.example.com. 7200 IN A 192.0.2.2
+#
+1035 8500
+0001 0002 0000 0000
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+0001 0001
+# same name, fully compressed
+c0 0c
+# TTL=3600, A, IN, RDLENGTH=4, RDATA
+0001 0001 00000e10 0004 c0 00 02 01
+# mostly same, with the slight difference in RDATA and TTL
+c0 0c
+0001 0001 00001c20 0004 c0 00 02 02

+ 22 - 0
src/lib/dns/cpp/tests/testdata/message_toWire1

@@ -0,0 +1,22 @@
+#
+# A simple DNS query message
+# ID = 0x1035
+# QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=2, other COUNTS=0
+# Question: test.example.com. IN A
+# Answer:
+#  test.example.com. 3600 IN A 192.0.2.1
+#  test.example.com. 7200 IN A 192.0.2.2
+#
+1035 8500
+0001 0002 0000 0000
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+0001 0001
+# same name, fully compressed
+c0 0c
+# TTL=3600, A, IN, RDLENGTH=4, RDATA
+0001 0001 00000e10 0004 c0 00 02 01
+# mostly same, with the slight difference in RDATA
+c0 0c
+0001 0001 00000e10 0004 c0 00 02 02

+ 14 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire1

@@ -0,0 +1,14 @@
+#
+# a global14 compression pointer
+#
+000a85800001000300000003
+#  V i x   c o m
+0356697803636f6d0000020001c00c00
+02000100000e10000b05697372763102
+7061c00cc00c0002000100000e100009
+066e732d657874c00cc00c0002000100
+000e10000e036e733104676e61630363
+6f6d00c0250001000100000e100004cc
+98b886c03c0001000100000e100004cc
+98b840c051000100010002a14a0004c6
+97f8f6

+ 12 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire10

@@ -0,0 +1,12 @@
+#
+# Too large name; should trigger an exception.
+#
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 040102030400

+ 12 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire11

@@ -0,0 +1,12 @@
+#
+# A name with possible maximum number of labels; should be accepted safely.
+#
+01000100010001000100 01000100010001000100 01000100010001000100
+01000100010001000100 01000100010001000100 01000100010001000100
+01000100010001000100 01000100010001000100 01000100010001000100
+01000100010001000100 01000100010001000100 01000100010001000100
+01000100010001000100 01000100010001000100 01000100010001000100
+01000100010001000100 01000100010001000100 01000100010001000100
+01000100010001000100 01000100010001000100 01000100010001000100
+01000100010001000100 01000100010001000100 01000100010001000100
+01000100010001000100 0100010000

+ 13 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire12

@@ -0,0 +1,13 @@
+#
+# Wire format including an invalid label length
+#
+#(1) a (7) e  x  a  m  p  l  e
+ 01 61 07 65 78 61 6d 70 6c 65
+# invalid label length: 64
+40
+# a "label" of 64 characters: shouldn't be parsed
+00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
+10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
+20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
+30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
+00

+ 5 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire13

@@ -0,0 +1,5 @@
+#
+# A name including all "printable" characters
+#
+
+3f2122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f1f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e00

+ 7 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire14

@@ -0,0 +1,7 @@
+#
+# A name including all "non-printable" characters
+#
+
+3f000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f207f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c
+3f9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb
+24dcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff00

+ 15 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire2

@@ -0,0 +1,15 @@
+#
+# bogus label character (looks like a local compression pointer)
+#
+000a85800001000300000003
+#this is the bogus label character:
+83
+76697803636f6d0000020001c00c00
+02000100000e10000b05697372763102
+7061c00cc00c0002000100000e100009
+066e732d657874c00cc00c0002000100
+000e10000e036e733104676e61630363
+6f6d00c0250001000100000e100004cc
+98b886c03c0001000100000e100004cc
+98b840c051000100010002a14a0004c6
+97f8f6

+ 11 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire3_1

@@ -0,0 +1,11 @@
+#
+# a bad compression pointer starting with the bits 1111 (too big pointer)
+#
+000a85800001000300000003
+03766978 03636f6d 00 0002 0001
+f00c 0002 0001 0000 0e10 000b 056973727631 027061 c00c
+c00c 0002 0001 0000 0e10 0009 066e732d657874 c00c
+c00c 0002 0001 0000 0e10 000e 036e7331 04676e6163 03636f6d 00
+c025 0001 0001 0000 0e10 0004 cc98b886
+c03c 0001 0001 0000 0e10 0004 cc98b840
+c051 0001 0001 0002 a14a 0004 c697f8f6

+ 13 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire3_2

@@ -0,0 +1,13 @@
+#
+# a bad compression pointer due to forward reference of 0x30 to
+# another compression pointer with a valid backreference
+#
+000a85800001000300000003
+03766978 03636f6d 00 0002 0001
+#'30' is the forward reference, 'c00c' at the end is the valid pointer:
+c030 0002 0001 0000 0e10 000b 056973727631 027061 c00c
+c00c 0002 0001 0000 0e10 0009 066e732d657874 c00c
+c00c 0002 0001 0000 0e10 000e 036e7331 04676e6163 03636f6d 00
+c025 0001 0001 0000 0e10 0004 cc98b886
+c03c 0001 0001 0000 0e10 0004 cc98b840
+c051 0001 0001 0002 a14a 0004 c697f8f6

+ 45 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire4

@@ -0,0 +1,45 @@
+#
+# invalid name length, pointer at offset 0x0226 points to
+# long name at offset 0x25
+#
+000a 8580 0001 0003 0000 0001
+03 766978 03 636f6d 00 0002 0001
+c00c 0002 0001 00000e10
+0101
+# long name starts here
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a
+03616263 0358595a 03616263 0358595a
+03414243 0378797a 03414243 0378797a 00
+# compression pointer start here and refers back to long name
+c023 0002 0001 00000e10 0009 066e732d657874 c00c
+c00c 0002 0001 00000e10 000e 036e733104676e616303636f6d00
+c025 0001 0001 00000e10 0004 cc98b886

+ 14 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire6

@@ -0,0 +1,14 @@
+#
+# a bad pointer
+#
+000a85800001000300000003
+# the bad pointer is f00c (offset = 300c) which is too large
+0376697803636f6d0000020001 f00c 00
+02000100000e10000b05697372763102
+7061c00cc00c0002000100000e100009
+066e732d657874c00cc00c0002000100
+000e10000e036e733104676e61630363
+6f6d00c0250001000100000e100004cc
+98b886c03c0001000100000e100004cc
+98b840c051000100010002a14a0004c6
+97f8f6

+ 6 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire7

@@ -0,0 +1,6 @@
+#
+# input ends unexpectedly
+#
+000a85800001000300000003
+# parser will start at the ending 'c0', which is an incomplete sequence.
+0376697803636f6d0000020001 c0

+ 27 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire8

@@ -0,0 +1,27 @@
+#
+# many hops of compression.  absolutely many, but should be decompressed.
+#
+000a85800001000300000013
+03 766978 03 636f6d 00 0002 0001
+c00c 0002 0001 00000e10 000b 056973727631027061 c00c
+c019 0002 0001 00000e10 0009 066e732d657874 c00c
+c030 0002 0001 00000e10 000e 036e7331 04676e6163 03636f6d 00
+c045 0001 0001 00000e10 0004 cc98b886
+c05f 0001 0001 00000e10 0004 cc98b840
+c06f 0001 0001 0002a14a 0004 c697f8f6
+c07f 0001 0001 0002a14a 0004 c697f8f6
+c08f 0001 0001 0002a14a 0004 c697f8f6
+c09f 0001 0001 0002a14a 0004 c697f8f6
+c0af 0001 0001 0002a14a 0004 c697f8f6
+c0bf 0001 0001 0002a14a 0004 c697f8f6
+c0cf 0001 0001 0002a14a 0004 c697f8f6
+c0df 0001 0001 0002a14a 0004 c697f8f6
+c0ef 0001 0001 0002a14a 0004 c697f8f6
+c0ff 0001 0001 0002a14a 0004 c697f8f6
+c10f 0001 0001 0002a14a 0004 c697f8f6
+c11f 0001 0001 0002a14a 0004 c697f8f6
+c12f 0001 0001 0002a14a 0004 c697f8f6
+c13f 0001 0001 0002a14a 0004 c697f8f6
+c14f 0001 0001 0002a14a 0004 c697f8f6
+c15f 0001 0001 0002a14a 0004 c697f8f6
+c16f 0001 0001 0002a14a 0004 c697f8f6

+ 12 - 0
src/lib/dns/cpp/tests/testdata/name_fromWire9

@@ -0,0 +1,12 @@
+#
+# A possible longest name; should be accepted safely.
+#
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 09010203040506070809 09010203040506070809
+09010203040506070809 0301020300

+ 12 - 0
src/lib/dns/cpp/tests/testdata/name_toWire1

@@ -0,0 +1,12 @@
+#
+# Rendering 3 names with compression.  [x] means a compression pointer pointing
+# to offset 'x'.
+#
+#bytes:
+# 0 1 2 3 4 5 6 7 8 9 a b c d e
+#(1)a(7)e x a m p l e(3)c o m .
+ 0161076578616d706c6503636f6d00
+#(1)b [2]
+ 0162c002
+#   a . e x a m p l e . o r g .
+ 0161076578616d706c65036f726700

+ 14 - 0
src/lib/dns/cpp/tests/testdata/name_toWire2

@@ -0,0 +1,14 @@
+#
+# Rendering names in a large buffer.  [x] means a compression pointer pointing
+# to offset 'x'.
+#
+#bytes:
+#3f 40
+#ff 00
+#(1) a (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+#[3fff] = a.example.com: can be compressed
+ ffff
+#(1) b(7)  e  x  a  m  p  l  e (3) c  o  m  .; cannot compress as the pointer
+#                                            (0x4001) would exceed 0x4000
+ 01 62 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00

+ 14 - 0
src/lib/dns/cpp/tests/testdata/name_toWire3

@@ -0,0 +1,14 @@
+#
+# Rendering names including one explicitly uncompressed.
+# [x] means a compression pointer pointing to offset 'x'.
+#
+# 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 (bytes)
+#(1) a (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+
+#15                                        29 (bytes)
+#(1) b(7)  e  x  a  m  p  l  e (3) c  o  m  .; specified to be not compressed,
+#                                              but can be pointed to from others
+ 01 62 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+#[0f] referring to the second (uncompressed name)
+ c0 0f

+ 16 - 0
src/lib/dns/cpp/tests/testdata/name_toWire4

@@ -0,0 +1,16 @@
+#
+# Rendering 3 names with compression, including one resulting in a chain of
+# pointers (the last one).
+# legend: [x] means a compression pointer pointing to offset 'x'.
+#bytes:
+#00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e
+#(1) a (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+
+#0f 10 11 12
+#(1) b  [2] (b.example.com.)
+ 01 62 c0 02
+
+#13 14
+# [0f]: (b.example.com.)
+ c0 0f

src/lib/dns/cpp/testdata/question_fromWire → src/lib/dns/cpp/tests/testdata/question_fromWire


src/lib/dns/cpp/testdata/question_toWire1 → src/lib/dns/cpp/tests/testdata/question_toWire1


src/lib/dns/cpp/testdata/question_toWire2 → src/lib/dns/cpp/tests/testdata/question_toWire2


+ 44 - 0
src/lib/dns/cpp/tests/testdata/rdata_cname_fromWire

@@ -0,0 +1,44 @@
+#
+# various kinds of CNAME RDATA stored in an input buffer
+#
+# Valid non-compressed RDATA for cn.example.com.
+# RDLENGHT=16 bytes
+# 0  1
+ 00 10
+# 2  3  4  5  6  7  8  9 10  1  2  3  4  5  6  7(bytes)
+#(2) c  n (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 02 63 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+#
+# short length
+# 8  9
+ 00 0f
+#20  1  2  3  4  5  6  7  8  9 30  1  2  3  4  5
+ 02 63 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+#
+# length too long
+# 6  7
+ 00 11
+#
+# 8  9 40  1  2  3  4  5  6  7  8  9 50  1  2  3  4
+ 02 63 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00
+#
+# Valid compressed CNAME name: 'cn2' + pointer
+# 5  6
+ 00 06
+# 7  8  9 60  1  2
+#(3) c  n  2 ptr=5
+ 03 63 6e 32 c0 05
+#
+# Valid compressed CNAME name but RDLENGTH is incorrect: it must be the length
+# of the sequence from the head to the pointer, not the decompressed name
+# length.
+# 3  4
+ 00 11
+# 5  6  7  8  9 70
+ 03 63 6e 32 c0 05
+# incomplete name (no trailing dot).  this can be tested only at the end of
+# the buffer.
+# 1  2
+ 00 0f
+# 3  4  5  6  7  8  9 80  1  2  3  4  5  6  7
+ 02 63 6e 07 65 78 61 6d 70 6c 65 03 63 6f 6d

+ 19 - 0
src/lib/dns/cpp/tests/testdata/rdata_in_a_fromWire

@@ -0,0 +1,19 @@
+#
+# various kinds of IN/A RDATA stored in an input buffer
+#
+# valid RDATA for 192.0.2.1
+#
+# 0  1  2  3  4  5 (bytes)
+ 00 04 c0 00 02 01
+#
+# short length
+# 6  7  8  9 10 11 (bytes)
+ 00 03 c0 00 02 01
+#
+# length too long
+#12 13 14 15 16 17 18
+ 00 05 c0 00 02 01 00
+#
+# short buffer (this can be tested only at the end of the buffer)
+#19 20 21 22 23
+ 00 04 c0 00 02

+ 9 - 0
src/lib/dns/cpp/tests/testdata/rdata_in_aaaa_fromWire

@@ -0,0 +1,9 @@
+#
+# various kinds of IN/AAAA RDATA stored in an input buffer
+#
+# valid RDATA for 2001:db8::1234
+#
+#RDLENGTH=16
+0010
+#IPv6 address
+2001 0db8 0000 0000 0000 0000 0000 1234

+ 15 - 0
src/lib/dns/cpp/tests/testdata/rdata_mx_fromWire

@@ -0,0 +1,15 @@
+#
+# various kinds of MX RDATA stored in an input buffer
+#
+# Valid RDATA for "10 mail.example.com"
+#
+# RDLENGHT=18 bytes
+# 0  1
+ 00 12
+#  2  3
+# PREFERENCE: 10
+  00 0a
+# EXCHANGE: non compressed
+# 4  5  6  7  8  9 10  1  2  3  4  5  6  7  8  9 (bytes)
+#(4) m  x (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 02 6d 78 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00

+ 12 - 0
src/lib/dns/cpp/tests/testdata/rdata_mx_toWire1

@@ -0,0 +1,12 @@
+#
+# compressed MX RDATA stored in an output buffer
+#
+# sentinel name: example.com.
+# 0  1  2  3  4  5  6  7  8  9 10  1  2 (bytes)
+#(7) e  x  a  m  p  l  e (3) c  o  m  .
+ 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# PREFERENCE: 10
+  00 0a
+# EXCHANGE: compressed
+#(4) m  x ptr=0
+ 02 6d 78 c0 00

+ 44 - 0
src/lib/dns/cpp/tests/testdata/rdata_ns_fromWire

@@ -0,0 +1,44 @@
+#
+# various kinds of NS RDATA stored in an input buffer
+#
+# Valid non-compressed RDATA for ns.example.com.
+# RDLENGHT=16 bytes
+# 0  1
+ 00 10
+# 2  3  4  5  6  7  8  9 10  1  2  3  4  5  6  7(bytes)
+#(2) n  s (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 02 6e 73 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+#
+# short length
+# 8  9
+ 00 0f
+#20  1  2  3  4  5  6  7  8  9 30  1  2  3  4  5
+ 02 6e 73 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+#
+# length too long
+# 6  7
+ 00 11
+#
+# 8  9 40  1  2  3  4  5  6  7  8  9 50  1  2  3  4
+ 02 6e 73 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00
+#
+# Valid compressed NS name: 'ns2' + pointer
+# 5  6
+ 00 06
+# 7  8  9 60  1  2
+#(3) n  s  2 ptr=5
+ 03 6e 73 32 c0 05
+#
+# Valid compressed NS name but RDLENGTH is incorrect: it must be the length
+# of the sequence from the head to the pointer, not the decompressed name
+# length.
+# 3  4
+ 00 11
+# 5  6  7  8  9 70
+ 03 6e 73 32 c0 05
+# incomplete name (no trailing dot).  this can be tested only at the end of
+# the buffer.
+# 1  2
+ 00 0f
+# 3  4  5  6  7  8  9 80  1  2  3  4  5  6  7
+ 02 6e 73 07 65 78 61 6d 70 6c 65 03 63 6f 6d

+ 20 - 0
src/lib/dns/cpp/tests/testdata/rdata_soa_fromWire

@@ -0,0 +1,20 @@
+#
+# various kinds of SOA RDATA stored in an input buffer
+#
+# Valid compressed RDATA for "(ns.example.com. root.example.com.
+# 2010012601 3600 300 3600000 1200)"
+# RDLENGHT=43 bytes
+# 0  1
+ 00 2b
+# MNAME: non compressed
+# 2  3  4  5  6  7  8  9 10  1  2  3  4  5  6  7(bytes)
+#(2) n  s (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 02 6e 73 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# RNAME: compressed
+# 8  9  20  1  2  3  4
+#(4)  r  o  o  t ptr=5
+  04 72 6f 6f 74 c0 05
+# other numeric parameters
+#      28      32        36        40       44
+# serial, refresh,    retry,  expire,  minimum
+ 77ce5bb9 00000e10 0000012c  0036ee80 000004b0

+ 9 - 0
src/lib/dns/cpp/tests/testdata/rdata_txt_fromWire

@@ -0,0 +1,9 @@
+#
+# various kinds of TXT RDATA stored in an input buffer
+#
+# Valid RDATA for "Test String"
+#
+# RDLENGHT=12 bytes
+ 00 0c
+#    T  e  s  t     S  t  r  i  n  g
+ 0b 54 65 73 74 20 53 74 72 69 6e 67

+ 13 - 0
src/lib/dns/cpp/tests/testdata/rdata_unknown_fromWire

@@ -0,0 +1,13 @@
+#
+# various kinds of "unknown" RDATA stored in an input buffer
+#
+# 0  1  2  3  4  5 (bytes)
+ 00 04 a1 b2 c3 0d
+#
+# 0-length data
+# 6  7
+ 00 00
+#
+# short buffer (this can be tested only at the end of the buffer)
+# 8  9 10  1  2
+ 00 04 a1 b2 c3

+ 4 - 0
src/lib/dns/cpp/tests/testdata/rrcode16_fromWire1

@@ -0,0 +1,4 @@
+#
+# a 16 bit wire-format data (network byte order)
+#
+1234

+ 4 - 0
src/lib/dns/cpp/tests/testdata/rrcode16_fromWire2

@@ -0,0 +1,4 @@
+#
+# an incomplete segment for a 16 bit wire-format data
+#
+12

+ 4 - 0
src/lib/dns/cpp/tests/testdata/rrcode32_fromWire1

@@ -0,0 +1,4 @@
+#
+# a 32 bit wire-format data (network byte order)
+#
+12345678

+ 4 - 0
src/lib/dns/cpp/tests/testdata/rrcode32_fromWire2

@@ -0,0 +1,4 @@
+#
+# an incomplete segment for a 32 bit wire-format data
+#
+123456

+ 23 - 0
src/lib/dns/cpp/tests/testdata/rrset_toWire1

@@ -0,0 +1,23 @@
+#
+# Rendering an IN/A RRset containing 2 RRs:
+# test.example.com. 3600 IN A 192.0.2.1
+# test.example.com. 3600 IN A 192.0.2.2
+#
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# type/class: A = 1, IN = 1
+00 01 00 01
+# TTL: 3600
+00 00 0e 10
+#6  7
+# RDLENGTH: 4
+00 04
+# RDATA: 192.0.2.1
+c0 00 02 01
+#
+# 2nd RR: mostly the same except the RDATA
+04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+00 01 00 01
+00 00 0e 10
+00 04
+c0 00 02 02

+ 38 - 0
src/lib/dns/cpp/tests/testdata/rrset_toWire2

@@ -0,0 +1,38 @@
+#
+# Rendering an IN/A RRset and NS RRset as follows:
+# test.example.com. 3600 IN A 192.0.2.1
+# test.example.com. 3600 IN A 192.0.2.2
+# example.com. 1D IN NS ns.example.com.
+# Names will be compressed when possible.
+#
+# 0  1  2  3  4  5
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# type/class: A = 1, IN = 1
+00 01 00 01
+# TTL: 3600
+00 00 0e 10
+#6  7
+# RDLENGTH: 4
+00 04
+# RDATA: 192.0.2.1
+c0 00 02 01
+#
+# 2nd RR: the owner name is compresed
+c0 00
+00 01 00 01
+00 00 0e 10
+00 04
+c0 00 02 02
+# 3rd RR: the owner name and NS name are compressed
+# pointing to the 5th octet of the owner name of the 1st RR
+c0 05
+# type/class: NS = 2, IN = 1
+00 02 00 01
+# TTL: 1D = 86400sec = 0x15180
+00 01 51 80
+# RDLENGTH: 5 octets
+00 05
+# NSDNAME: "ns." + compression pointer
+#(2) n  s
+ 02 6e 73 c0 05

+ 1 - 1
src/lib/dns/cpp/unittest_util.cc

@@ -23,7 +23,7 @@
 
 #include <gtest/gtest.h>
 
-#include "name.h"
+#include <dns/name.h>
 #include "unittest_util.h"
 
 using isc::UnitTestUtil;

+ 1 - 1
src/lib/dns/cpp/unittest_util.h

@@ -20,7 +20,7 @@
 #include <vector>
 #include <string>
 
-#include "name.h"
+#include <dns/name.h>
 
 #include <gtest/gtest.h>