Browse Source

ported minimal set of RR-related API for rapid prototyping and some test cases.

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/f2f200910@120 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 15 years ago
parent
commit
b056392c5e

+ 18 - 0
configure

@@ -691,6 +691,7 @@ ac_subst_files=''
 ac_user_opts='
 enable_option_checking
 enable_dependency_tracking
+with_boost
 with_gtest
 '
       ac_precious_vars='build_alias
@@ -1326,6 +1327,7 @@ Optional Features:
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-boost=PATH       specify a path to the boost if it's not automatically found
   --with-gtest=PATH       specify a path to Gtest header files (PATH/include) and library (PATH/lib)
 
 Some influential environment variables:
@@ -4476,6 +4478,22 @@ fi
 
 
 #
+# Check availablity of boost
+#
+
+# Check whether --with-boost was given.
+if test "${with_boost+set}" = set; then :
+  withval=$with_boost; boost_path="$withval"
+else
+  boost_path="no"
+fi
+
+if test "$boost_path" != "no"
+then
+	CPPFLAGS="$CPPFLAGS -I$boost_path"
+fi
+
+#
 # Check availablity of gtest, which might be used for unit tests.
 #
 

+ 11 - 0
configure.ac

@@ -21,6 +21,17 @@ AC_HEADER_STDBOOL
 AC_TYPE_SIZE_T
 
 #
+# Check availablity of boost
+#
+AC_ARG_WITH(boost,
+[  --with-boost=PATH       specify a path to the boost if it's not automatically found],
+    boost_path="$withval", boost_path="no")
+if test "$boost_path" != "no"
+then
+	CPPFLAGS="$CPPFLAGS -I$boost_path"	
+fi
+
+#
 # Check availablity of gtest, which might be used for unit tests.
 #
 AC_ARG_WITH(gtest,

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

@@ -1,12 +1,12 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib
 
 lib_LIBRARIES = libdns.a
-libdns_a_SOURCES = name.cc buffer.cc name.h buffer.h
+libdns_a_SOURCES = name.cc buffer.cc rrset.cc name.h buffer.h rrset.h
 
 TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
-run_unittests_SOURCES = name_unittest.cc
+run_unittests_SOURCES = run_unittests.cc name_unittest.cc rrset_unittest.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(GTEST_LDFLAGS)
 run_unittests_LDADD = ./libdns.a $(GTEST_LDADD)

+ 39 - 5
src/lib/dns/Makefile.in

@@ -73,14 +73,17 @@ AR = ar
 ARFLAGS = cru
 libdns_a_AR = $(AR) $(ARFLAGS)
 libdns_a_LIBADD =
-am_libdns_a_OBJECTS = name.$(OBJEXT) buffer.$(OBJEXT)
+am_libdns_a_OBJECTS = name.$(OBJEXT) buffer.$(OBJEXT) rrset.$(OBJEXT)
 libdns_a_OBJECTS = $(am_libdns_a_OBJECTS)
 @HAVE_GTEST_TRUE@am__EXEEXT_1 = run_unittests$(EXEEXT)
 am__EXEEXT_2 = $(am__EXEEXT_1)
 PROGRAMS = $(noinst_PROGRAMS)
-am__run_unittests_SOURCES_DIST = name_unittest.cc
+am__run_unittests_SOURCES_DIST = run_unittests.cc name_unittest.cc \
+	rrset_unittest.cc
 @HAVE_GTEST_TRUE@am_run_unittests_OBJECTS =  \
-@HAVE_GTEST_TRUE@	run_unittests-name_unittest.$(OBJEXT)
+@HAVE_GTEST_TRUE@	run_unittests-run_unittests.$(OBJEXT) \
+@HAVE_GTEST_TRUE@	run_unittests-name_unittest.$(OBJEXT) \
+@HAVE_GTEST_TRUE@	run_unittests-rrset_unittest.$(OBJEXT)
 run_unittests_OBJECTS = $(am_run_unittests_OBJECTS)
 am__DEPENDENCIES_1 =
 @HAVE_GTEST_TRUE@run_unittests_DEPENDENCIES = ./libdns.a \
@@ -203,8 +206,8 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib
 lib_LIBRARIES = libdns.a
-libdns_a_SOURCES = name.cc buffer.cc name.h buffer.h
-@HAVE_GTEST_TRUE@run_unittests_SOURCES = name_unittest.cc
+libdns_a_SOURCES = name.cc buffer.cc rrset.cc name.h buffer.h rrset.h
+@HAVE_GTEST_TRUE@run_unittests_SOURCES = run_unittests.cc name_unittest.cc rrset_unittest.cc
 @HAVE_GTEST_TRUE@run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 @HAVE_GTEST_TRUE@run_unittests_LDFLAGS = $(GTEST_LDFLAGS)
 @HAVE_GTEST_TRUE@run_unittests_LDADD = ./libdns.a $(GTEST_LDADD)
@@ -293,7 +296,10 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/name.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rrset.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-name_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-rrset_unittest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_unittests-run_unittests.Po@am__quote@
 
 .cc.o:
 @am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -309,6 +315,20 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
 
+run_unittests-run_unittests.o: run_unittests.cc
+@am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.o -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='run_unittests.cc' object='run_unittests-run_unittests.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.o `test -f 'run_unittests.cc' || echo '$(srcdir)/'`run_unittests.cc
+
+run_unittests-run_unittests.obj: run_unittests.cc
+@am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-run_unittests.obj -MD -MP -MF $(DEPDIR)/run_unittests-run_unittests.Tpo -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/run_unittests-run_unittests.Tpo $(DEPDIR)/run_unittests-run_unittests.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='run_unittests.cc' object='run_unittests-run_unittests.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-run_unittests.obj `if test -f 'run_unittests.cc'; then $(CYGPATH_W) 'run_unittests.cc'; else $(CYGPATH_W) '$(srcdir)/run_unittests.cc'; fi`
+
 run_unittests-name_unittest.o: name_unittest.cc
 @am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-name_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-name_unittest.Tpo -c -o run_unittests-name_unittest.o `test -f 'name_unittest.cc' || echo '$(srcdir)/'`name_unittest.cc
 @am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/run_unittests-name_unittest.Tpo $(DEPDIR)/run_unittests-name_unittest.Po
@@ -323,6 +343,20 @@ run_unittests-name_unittest.obj: name_unittest.cc
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-name_unittest.obj `if test -f 'name_unittest.cc'; then $(CYGPATH_W) 'name_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/name_unittest.cc'; fi`
 
+run_unittests-rrset_unittest.o: rrset_unittest.cc
+@am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-rrset_unittest.o -MD -MP -MF $(DEPDIR)/run_unittests-rrset_unittest.Tpo -c -o run_unittests-rrset_unittest.o `test -f 'rrset_unittest.cc' || echo '$(srcdir)/'`rrset_unittest.cc
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/run_unittests-rrset_unittest.Tpo $(DEPDIR)/run_unittests-rrset_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='rrset_unittest.cc' object='run_unittests-rrset_unittest.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-rrset_unittest.o `test -f 'rrset_unittest.cc' || echo '$(srcdir)/'`rrset_unittest.cc
+
+run_unittests-rrset_unittest.obj: rrset_unittest.cc
+@am__fastdepCXX_TRUE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT run_unittests-rrset_unittest.obj -MD -MP -MF $(DEPDIR)/run_unittests-rrset_unittest.Tpo -c -o run_unittests-rrset_unittest.obj `if test -f 'rrset_unittest.cc'; then $(CYGPATH_W) 'rrset_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/rrset_unittest.cc'; fi`
+@am__fastdepCXX_TRUE@	$(am__mv) $(DEPDIR)/run_unittests-rrset_unittest.Tpo $(DEPDIR)/run_unittests-rrset_unittest.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='rrset_unittest.cc' object='run_unittests-rrset_unittest.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(run_unittests_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o run_unittests-rrset_unittest.obj `if test -f 'rrset_unittest.cc'; then $(CYGPATH_W) 'rrset_unittest.cc'; else $(CYGPATH_W) '$(srcdir)/rrset_unittest.cc'; fi`
+
 ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
 	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
 	unique=`for i in $$list; do \

+ 1 - 1
src/lib/dns/buffer.h

@@ -66,7 +66,7 @@ public:
     }
     void write_data(const void *data, size_t len)
     {
-        const uint8_t* cp = static_cast<const uint8_t*>(cp);
+        const uint8_t* cp = static_cast<const uint8_t*>(data);
         buf_.insert(buf_.end(), cp, cp + len);
     }
     void write_uint32(uint32_t data)

+ 1 - 1
src/lib/dns/name.cc

@@ -266,7 +266,7 @@ Name::Name(const std::string& namestr)
     length_ = nused;
 }
 
-Name::Name(NameDecompressor& decompressor, Buffer& buffer)
+Name::Name(Buffer& buffer, NameDecompressor& decompressor)
 {
     unsigned int nused, labels, n, nmax;
     unsigned int current;

+ 1 - 1
src/lib/dns/name.h

@@ -54,7 +54,7 @@ class Name {
 public:
     Name() : length_(0), labels_(0) {}
     explicit Name(const std::string& namestr);
-    explicit Name(NameDecompressor& decompressor, Buffer& buffer);
+    explicit Name(Buffer& buffer, NameDecompressor& decompressor);
     // copy constructor (default cp-ctor should work fine)
     //Name(const Name& orig);
     // destructor (default dtor should work fine)

+ 2 - 10
src/lib/dns/name_unittest.cc

@@ -79,15 +79,7 @@ TEST_F(NameTest, to_from_wire)
     ISC::DNS::NameDecompressor decompressor;
 
     example_name->to_wire(buffer, compressor);
-
-    Name name2(decompressor, buffer);
-    EXPECT_EQ(true, *example_name == name2);
-}
+    EXPECT_EQ(std::string("www.example.com."),
+              Name(buffer, decompressor).to_text(false));
 }
-
-int
-main(int argc, char* argv[])
-{
-    ::testing::InitGoogleTest(&argc, argv);
-    return (RUN_ALL_TESTS());
 }

+ 290 - 0
src/lib/dns/rrset.cc

@@ -0,0 +1,290 @@
+// 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 <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <stdexcept>
+#include <cstring>
+
+#include <dns/buffer.h>
+#include <dns/rrset.h>
+
+using ISC::DNS::RRClass;
+using ISC::DNS::RRType;
+using ISC::DNS::TTL;
+
+RRClass::RRClass(const std::string& classstr)
+{
+    // XXX: this is a quick hack implementation to see feasibility.
+    // should be rewritten in a cleaner way.
+    if (classstr == "IN")
+        classval_ = 1;
+    else if (classstr == "CHAOS" || classstr == "CH")
+        classval_ = 3;
+    else
+        throw DNSInvalidRRClass();
+}
+
+const std::string
+RRClass::to_text() const
+{
+    // XXX: quick hack
+    if (classval_ == 1)
+        return ("IN");
+    else if (classval_ == 3)
+        return ("CH");
+    throw std::runtime_error("unexpected class");
+}
+
+void
+RRClass::to_wire(ISC::Buffer& b) const
+{
+    b.write_uint16(classval_);
+}
+
+const RRClass RRClass::IN("IN");
+const RRClass RRClass::CH("CH");
+
+RRType::RRType(const std::string& typestr)
+{
+    // XXX: this is a quick hack implementation to see feasibility.
+    // should be rewritten in a cleaner way.
+    if (typestr == "A")
+        typeval_ = 1;
+    else if (typestr == "NS")
+        typeval_ = 2;
+    else if (typestr == "AAAA")
+        typeval_ = 28;
+    else
+        throw DNSInvalidRRType();
+}
+
+const std::string
+RRType::to_text() const
+{
+    if (typeval_ == 1)
+        return ("A");
+    else if (typeval_ == 2)
+        return ("NS");
+    else if (typeval_ == 28)
+        return ("AAAA");
+    throw std::runtime_error("unexpected type");
+}
+
+void
+RRType::to_wire(Buffer& buffer) const
+{
+    buffer.write_uint16(typeval_);
+}
+
+const RRType RRType::A("A");
+const RRType RRType::NS("NS");
+const RRType RRType::AAAA("AAAA");
+// ...more to follow
+
+void
+TTL::to_wire(Buffer& buffer) const
+{
+    buffer.write_uint32(ttlval_);
+}
+
+#ifdef notyet
+ARdata::ARdata(const std::string& addrstr)
+{
+    if (inet_pton(AF_INET, addrstr.c_str(), &_addr) != 1)
+        throw ISCInvalidAddressString();
+}
+
+void
+ARdata::from_wire(IOBuffer& buffer, NameDecompressor& decompressor)
+{
+    //TBD
+}
+
+void
+ARdata::to_wire(IOBuffer& buffer, NameCompressor& compressor) const
+{
+    buffer.write_uint16(sizeof(_addr));
+    buffer.write_data(&_addr, sizeof(_addr));
+}
+
+std::string
+ARdata::to_text() const
+{
+    char addrbuf[sizeof("255.255.255.255")];
+
+    if (inet_ntop(AF_INET, &_addr, addrbuf, sizeof(addrbuf)) == NULL)
+        throw runtime_error("unexpected inet_ntop() failure");
+
+    return (std::string(addrbuf));
+}
+
+AAAARdata::AAAARdata(const std::string& addrstr)
+{
+    if (inet_pton(AF_INET6, addrstr.c_str(), &_addr) != 1)
+        throw ISCInvalidAddressString();
+}
+
+void
+AAAARdata::from_wire(IOBuffer& buffer, NameDecompressor& decompressor)
+{
+    //TBD
+}
+
+void
+AAAARdata::to_wire(IOBuffer& buffer, NameCompressor& compressor) const
+{
+    buffer.write_uint16(sizeof(_addr));
+    buffer.write_data(&_addr, sizeof(_addr));
+}
+
+std::string
+AAAARdata::to_text() const
+{
+    char addrbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+
+    if (inet_ntop(AF_INET6, &_addr, addrbuf, sizeof(addrbuf)) == NULL)
+        throw runtime_error("unexpected inet_ntop() failure");
+
+    return (std::string(addrbuf));
+}
+
+void
+NSRdata::from_wire(IOBuffer& buffer, NameDecompressor& decompressor)
+{
+    //TBD
+}
+
+void
+NSRdata::to_wire(IOBuffer& buffer, NameCompressor& compressor) const
+{
+    // XXX: note that a complete implementation cannot be that simple
+    // because we need to disable compression for the NS name.
+    buffer.write_uint16(_nsname.get_length());
+    _nsname.to_wire(buffer, compressor);
+}
+
+std::string
+NSRdata::to_text() const
+{
+    return (_nsname.to_text());
+}
+
+void
+RdataSet::add_rdata(rdataptr_t rdata)
+{
+    if (rdata->get_type() != _rdtype)
+        throw DNSRdtypeMismatch();
+    _rdatalist.push_back(rdata);
+}
+
+std::string
+RdataSet::to_text() const
+{
+    std::string s;
+
+    for (vector<rdataptr_t>::const_iterator it = _rdatalist.begin();
+         it != _rdatalist.end();
+         ++it)
+    {
+        if (!s.empty())
+            s.push_back('\n');
+        s += _ttl.to_text() + " " + _rdclass.to_text() + " " +
+            _rdtype.to_text() + " " + (**it).to_text();
+    }
+
+    return (s);
+}
+
+std::string
+RRSet::to_text() const
+{
+    std::string s;
+
+    for (vector<rdataptr_t>::const_iterator it = _rdatalist.begin();
+         it != _rdatalist.end();
+         ++it)
+    {
+        if (!s.empty())
+            s.push_back('\n');
+        s += _name.to_text() + " ";
+        s += _ttl.to_text() + " " + _rdclass.to_text() + " " +
+            _rdtype.to_text() + " " + (**it).to_text();
+    }
+
+    return (s);
+}
+
+void
+RRSet::add_rdata(rdataptr_t rdata)
+{
+    if (rdata->get_type() != _rdtype)
+        throw DNSRdtypeMismatch();
+    _rdatalist.push_back(rdata);
+}
+
+int
+RRSet::to_wire(Message& message, section_t section)
+{
+    int num_rrs = 0;
+
+    // sort Rdata list based on rrset-order and sortlist, and possible
+    // other options.  Details to be considered.
+
+    IOBuffer& b = message.get_iobuffer();
+    NameCompressor& c = message.get_compressor();
+    for (vector<rdataptr_t>::iterator it = _rdatalist.begin();
+         it != _rdatalist.end();
+         ++it, ++num_rrs)
+    {
+        _name.to_wire(b, c);
+        _rdtype.to_wire(b);
+        _rdclass.to_wire(b);
+        _ttl.to_wire(b);
+        (**it).to_wire(b, c);
+
+        // TBD: handle truncation case
+    }
+
+    return (num_rrs);
+}
+
+std::string
+Question::to_text() const
+{
+    // return in dig-style format.  note that in the wire format class follows
+    // type.
+    return (_name.to_text() + " " + _rdclass.to_text() + " " +
+            _rdtype.to_text());
+}
+
+int
+Question::to_wire(Message& message, section_t section)
+{
+    IOBuffer& b = message.get_iobuffer();
+    NameCompressor& c = message.get_compressor();
+
+    _name.to_wire(b, c);
+    _rdtype.to_wire(b);
+    _rdclass.to_wire(b);
+
+    return (1);
+}
+
+#endif  // notyet

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

@@ -0,0 +1,314 @@
+// 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 __RRSET_H
+#define __RRSET_H 1
+
+#include <netinet/in.h>
+
+#include <vector>
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <dns/exceptions.h>
+#include <dns/buffer.h>
+#include <dns/name.h>
+
+namespace ISC {
+namespace DNS {
+class Message;
+class NameCompressor;
+
+// XXX: this should be defined somewhere else.
+typedef enum { SECTION_QUESTION = 0,
+               SECTION_ANSWER = 1,
+               SECTION_AUTHORITY = 2,
+               SECTION_ADDITIONAL = 3,
+               SECTION_MAX = 4 } section_t;
+
+class RRClass {
+public:
+    RRClass() {}
+    explicit RRClass(uint16_t classval) : classval_(classval) {}
+    explicit RRClass(const std::string& classstr);
+    const std::string to_text() const;
+    void to_wire(Buffer& b) const;
+    uint16_t get_value() const { return (classval_); }
+    bool operator==(const RRClass& other) const
+    { return (classval_ == other.classval_); }
+    bool operator!=(const RRClass& other) const
+    { return (classval_ != other.classval_); }
+
+    // (Some) well-known Rdclass constants
+    static const RRClass IN;
+    static const RRClass CH;
+private:
+    uint16_t classval_;
+};
+
+class RRType {
+public:
+    RRType() {}
+    explicit RRType(uint16_t typeval) : typeval_(typeval) {}
+    explicit RRType(const std::string& typestr);
+    const std::string to_text() const;
+    void to_wire(Buffer& b) const;
+    uint16_t get_value() const { return (typeval_); }
+    bool operator==(const RRType& other) const
+    { return (typeval_ == other.typeval_); }
+    bool operator!=(const RRType& other) const
+    { return (typeval_ != other.typeval_); }
+
+    // (Some) Well-known Rdtype constants
+    static const RRType A;
+    static const RRType NS;
+    static const RRType AAAA;
+    // more to follow...
+
+private:
+    uint16_t typeval_;
+};
+
+class TTL {
+public:
+    TTL() {}
+    explicit TTL(uint32_t ttlval) : ttlval_(ttlval) {}
+    std::string to_text() const
+    { return (boost::lexical_cast<std::string>(ttlval_)); }
+    void to_wire(Buffer& b) const;
+    uint32_t get_value() { return (ttlval_); }
+    bool operator==(const TTL& other) const
+    { return (ttlval_ == other.ttlval_); }
+    bool operator!=(const TTL& other) const
+    { return (ttlval_ != other.ttlval_); }
+    // define the following using serial number arithmetic:
+    bool operator<=(const TTL &other) const;
+    bool operator>=(const TTL &other) const;
+    bool operator<(const TTL &other) const;
+    bool operator>(const TTL &other) const;
+private:
+    uint32_t ttlval_;
+};
+
+namespace Rdata {
+// Standard DNS Rdata Subclasses
+// if we worry about data copy, we may have to use
+// shared pointers at the cost of depending on boost.
+class Rdata;
+typedef boost::shared_ptr<Rdata> rdataptr_t;
+// if we want to avoid the dependency, use this; but we'll have
+// to care much more about resource leak.
+//typedef Rdata * rdataptr_t;
+
+// Abstract RDATA class
+class Rdata {
+public:
+    virtual ~Rdata() {};
+    virtual unsigned int count() const = 0;
+    virtual const RRType& get_type() const = 0;
+    virtual std::string to_text() const = 0;
+    virtual void from_wire(Buffer& b, NameDecompressor& c) = 0;
+    virtual void to_wire(Buffer& b, NameCompressor& c) const = 0;
+    // need generic method for getting n-th field? c.f. ldns
+    // e.g. string getField(int n);
+};
+
+namespace Generic {
+class NS : public Rdata::Rdata {
+public:
+    NS() {}
+    explicit NS(const std::string& namestr) : nsname_(namestr) {}
+    explicit NS(const Name& nsname) : nsname_(nsname) {}
+    unsigned int count() const { return (1); }
+    const RRType& get_type() const { return (RRType::NS); }
+    static const RRType& get_type_static() { return (RRType::NS); }
+    std::string to_text() const;
+    void from_wire(Buffer& b, NameDecompressor& c);
+    void to_wire(Buffer& b, NameCompressor& c) const;
+    const std::string get_nsname() const { return (nsname_.to_text(false)); }
+    bool operator==(const NS &other) const
+    { return (nsname_ == other.nsname_); }
+    virtual bool operator!=(const NS &other) const { return !(*this == other); }
+private:
+    Name nsname_;
+};
+// add MXRdata, etc...
+}
+
+namespace IN {
+class A : public Rdata::Rdata {
+public:
+    A() {}
+    // constructor from a textual IPv4 address
+    explicit A(const std::string& addrstr);
+    unsigned int count() const { return (1); }
+    const RRType& get_type() const { return (RRType::A); }
+    static const RRType& get_type_static() { return (RRType::A); }
+    std::string to_text() const;
+    void from_wire(Buffer& b, NameDecompressor& c);
+    void to_wire(Buffer& b, NameCompressor& c) const;
+    const struct in_addr& getAddress() const { return (addr_); }
+    bool operator==(const A &other) const
+    { return (addr_.s_addr == other.addr_.s_addr); }
+    virtual bool operator!=(const A &other) const
+    { return !(*this == other); }
+private:
+    // XXX: should probably define an "address class" and use it.
+    struct in_addr addr_;
+};
+
+class AAAA : public Rdata::Rdata {
+public:
+    AAAA() {}
+    // constructor from a textual IPv6 address
+    explicit AAAA(const std::string& addrstr);
+    unsigned int count() const { return (1); }
+    std::string to_text() const;
+    const RRType& get_type() const { return (RRType::AAAA); }
+    static const RRType& get_type_static() { return (RRType::AAAA); }
+    void from_wire(Buffer& b, NameDecompressor& c);
+    void to_wire(Buffer& b, NameCompressor& c) const;
+    const struct in6_addr& getAddress() const { return (addr_); }
+    bool operator==(const AAAA &other) const
+    { return (IN6_ARE_ADDR_EQUAL(&addr_, &other.addr_)); }
+    virtual bool operator!=(const AAAA &other) const
+    { return !(*this == other); }
+private:
+    // XXX: should probably define an "address class" and use it.
+    struct in6_addr addr_;
+};
+}
+}
+
+// An RRSet.  Conceptually it's a named RdataSet.  A (section
+// of) DNS message would consist of a list of RRSets.
+// This is a primary class internally used in our major software such as name
+// servers.
+//
+// Open Issues:
+//   - add more set-like operations, e.g, merge?
+//   - add a "sort" method?  "search(find)" method?
+//   - BIND9 libdns has some special DNSSEC-related methods
+//     such as addnoqname(), addclosest().  do we need these?
+//   - need to check duplicate rdata in addrdata()?
+//   - need a comparison method?  if so, should it compare
+//     rdata's as a set or as a list (compare each rdata one
+//     by one)?  ldns has ldns_rr_list_compare(), which takes
+//     the latter approach (assuming the caller sorts the lists
+//     beforehand?).
+class AbstractRRSet {
+public:
+    virtual ~AbstractRRSet() {}
+    virtual std::string to_text() const = 0;
+    virtual int to_wire(Message& message, section_t section) = 0;
+    virtual unsigned int count_rdata() const = 0;
+    virtual const Name& get_name() const = 0;
+    virtual const RRClass& get_class() const = 0;
+    virtual const RRType& get_type() const = 0;
+};
+
+class RRSet : public AbstractRRSet {
+public:
+    RRSet() {}
+    explicit RRSet(const Name &name, const RRClass &rdclass,
+                   const RRType &rdtype, const TTL &ttl) :
+        name_(name), rdclass_(rdclass), rdtype_(rdtype), ttl_(ttl) {}
+    unsigned int count_rdata() const { return (rdatalist_.size()); }
+    void add_rdata(Rdata::rdataptr_t rdata);
+    void remove_rdata(const Rdata::Rdata& rdata);
+    std::string to_text() const;
+    int to_wire(Message& message, section_t section);
+    const Name& get_name() const { return (name_); } 
+    const RRClass& get_class() const { return (rdclass_); }
+    const RRType& get_type() const { return (rdtype_); }
+    const TTL& get_ttl() const { return (ttl_); }
+    template <typename T> void get_rdatalist(std::vector<T>&) const;
+private:
+    Name name_;
+    RRClass rdclass_;
+    RRType rdtype_;
+    TTL ttl_;
+    std::vector<Rdata::rdataptr_t> rdatalist_;
+};
+
+//
+// Generic Question section entry
+//
+class Question : public AbstractRRSet {
+public:
+    explicit Question(const Name& name, const RRClass& rdclass,
+             const RRType& rdtype) :
+        name_(name), rdclass_(rdclass), rdtype_(rdtype) {}
+    std::string to_text() const;
+    int to_wire(Message& message, section_t section);
+    unsigned int count_rdata() const { return (0); }
+    const Name& get_name() const { return (name_); } 
+    const RRClass& get_class() const { return (rdclass_); }
+    const RRType& get_type() const { return (rdtype_); }
+    
+private:
+    Name name_;
+    RRClass rdclass_;
+    RRType rdtype_;
+};
+
+// TBD: this interface should be revisited.
+template <typename T>
+void
+RRSet::get_rdatalist(std::vector<T>& v) const
+{
+    std::vector<Rdata::rdataptr_t>::const_iterator it;
+    for (it = rdatalist_.begin(); it != rdatalist_.end(); ++it) {
+        const T& concreteRdata = static_cast<const T&>(**it); // XXX
+        if (T::get_type_static() != (**it).get_type()) {
+            throw DNSRdtypeMismatch();
+        }
+        v.push_back(concreteRdata);
+    }
+}
+
+// A single RR.  Architecturally this is redundant, but it
+// would often be convenient if we can handle each RR
+// separately.
+// Note: an RR *is-not-a* set, so conceptually it cannot be a
+// derived class of RdataSet.
+class RR {
+public:
+    RR() {}
+    explicit RR(const std::string& rrstr);
+    explicit RR(const Name &name, const RRClass &rdclass,
+                const RRType &rdtype, const TTL &ttl,
+                const Rdata::Rdata &rdata);
+    std::string to_text() const { return (rrset_.to_text()); }
+    const Name& get_name() const { return (rrset_.get_name()); }
+    const RRClass& get_class() const { return (rrset_.get_class()); }
+    const RRType& get_type() const { return (rrset_.get_type()); }
+    const TTL& get_ttl() const { return (rrset_.get_ttl()); }
+private:
+    // An RR is (could be) actually implemented as an RRSet
+    // containing at most one RR.
+    RRSet rrset_;
+};
+}
+}
+#endif  // __RRSET_H
+
+// Local Variables: 
+// mode: c++
+// End: 
+

+ 3 - 41
src/lib/dns/run_unittests.cc

@@ -14,49 +14,11 @@
 
 // $Id$
 
-#include <iostream>
-#include <stdexcept>
-
-#include <cppunit/CompilerOutputter.h>
-#include <cppunit/TestCase.h>
-#include <cppunit/TestResult.h>
-#include <cppunit/TestResultCollector.h>
-#include <cppunit/TestRunner.h>
-#include <cppunit/TextTestProgressListener.h>
-
-#include <dns/name_unittest.h>
+#include <gtest/gtest.h>
 
 int
 main(int argc, char* argv[])
 {
-    CppUnit::TestRunner runner;
-    CppUnit::TestResult controller;
-
-    // Add a listener that collects test result
-    CppUnit::TestResultCollector result;
-    controller.addListener( &result );        
-
-    // Add a listener that print dots as test run.
-    CppUnit::TextTestProgressListener progress;
-    controller.addListener(&progress);
-
-    runner.addTest(NameTest::suite());
-
-    try {
-        std::cout << "Running ";
-        runner.run(controller, "");
-
-        std::cerr << std::endl;
-
-        // Print test in a compiler compatible format.
-        CppUnit::CompilerOutputter outputter(&result, std::cerr);
-        outputter.write();                      
-    } catch (std::invalid_argument& e) {  // Test path not resolved
-        std::cerr  <<  std::endl  
-                   <<  "ERROR: "  <<  e.what()
-                   << std::endl;
-        return 0;
-    }
-
-    return (result.wasSuccessful() ? 0 : 1);
+    ::testing::InitGoogleTest(&argc, argv);
+    return (RUN_ALL_TESTS());
 }