Browse Source

sync with master
Merge branch 'master' into trac467

Conflicts:
src/bin/auth/tests/auth_srv_unittest.cc

JINMEI Tatuya 14 years ago
parent
commit
4f7e1f46da
49 changed files with 1336 additions and 625 deletions
  1. 1 0
      AUTHORS
  2. 22 6
      ChangeLog
  3. 2 1
      README
  4. 23 5
      configure.ac
  5. 1 1
      src/bin/Makefile.am
  6. 1 1
      src/bin/auth/auth_srv.h
  7. 93 3
      src/bin/auth/query.cc
  8. 78 9
      src/bin/auth/query.h
  9. 1 0
      src/bin/auth/tests/Makefile.am
  10. 21 10
      src/bin/auth/tests/auth_srv_unittest.cc
  11. 331 22
      src/bin/auth/tests/query_unittest.cc
  12. 17 17
      src/bin/bind10/bind10.py.in
  13. 1 1
      src/bin/bind10/bob.spec
  14. 1 1
      src/bin/bind10/run_bind10.sh.in
  15. 20 20
      src/bin/bind10/tests/bind10_test.py
  16. 0 57
      src/bin/recurse/Makefile.am
  17. 57 0
      src/bin/resolver/Makefile.am
  18. 10 10
      src/bin/recurse/b10-recurse.8
  19. 8 8
      src/bin/recurse/b10-recurse.xml
  20. 16 16
      src/bin/recurse/main.cc
  21. 30 30
      src/bin/recurse/recursor.cc
  22. 11 11
      src/bin/recurse/recursor.h
  23. 1 1
      src/bin/recurse/recurse.spec.pre.in
  24. 1 1
      src/bin/recurse/spec_config.h.pre.in
  25. 4 3
      src/bin/recurse/tests/Makefile.am
  26. 30 16
      src/bin/recurse/tests/recursor_config_unittest.cc
  27. 33 24
      src/bin/recurse/tests/recursor_unittest.cc
  28. 0 0
      src/bin/resolver/tests/run_unittests.cc
  29. 1 1
      src/lib/asiolink/Makefile.am
  30. 1 1
      src/lib/asiolink/README
  31. 1 1
      src/lib/asiolink/asiolink.h
  32. 1 0
      src/lib/asiolink/internal/Makefile.am
  33. 37 0
      src/lib/asiolink/internal/tests/Makefile.am
  34. 21 0
      src/lib/asiolink/internal/tests/run_unittests.cc
  35. 0 0
      src/lib/asiolink/internal/tests/udpdns_unittest.cc
  36. 0 1
      src/lib/asiolink/tests/Makefile.am
  37. 72 40
      src/lib/asiolink/tests/asiolink_unittest.cc
  38. 2 2
      src/lib/datasrc/cache.h
  39. 2 2
      src/lib/datasrc/data_source.cc
  40. 2 2
      src/lib/datasrc/rbtree.h
  41. 1 1
      src/lib/nsas/README
  42. 1 1
      src/lib/nsas/asiolink.h
  43. 10 9
      src/lib/python/isc/config/module_spec.py
  44. 4 0
      src/lib/python/isc/config/tests/module_spec_test.py
  45. 12 4
      src/lib/testutils/Makefile.am
  46. 0 2
      src/lib/testutils/README
  47. 272 0
      src/lib/testutils/srv_test.cc
  48. 82 126
      src/lib/testutils/srv_test.h
  49. 0 158
      src/lib/testutils/srv_unittest.h

+ 1 - 0
AUTHORS

@@ -0,0 +1 @@
+jreed

+ 22 - 6
ChangeLog

@@ -1,3 +1,17 @@
+  144.	[build]		jinmei
+	Introduced a workaround for clang++ build on FreeBSD (and probably
+	some other OSes).  If building BIND 10 fails with clang++ due to
+	a link error about "__dso_handle", try again from the configure
+	script with CXX_LIBTOOL_LDFLAGS=-L/usr/lib (the path actually
+	doesn't matter; the important part is the -L flag).  This
+	workaround is not automatically enabled as it's difficult to
+	detect the need for it dynamically, and must be enabled via the
+	variable by hand. (Trac #474, git cfde436)
+
+  143.	[build]		jinmei
+	Fixed build problems with clang++ in unit tests due to recent
+	changes.  No behavior change. (Trac #448, svn r4133)
+
   142.	[func]		jinmei
 	b10-auth: updated query benchmark so that it can test in memory
 	data source.  Also fixed a bug that the output buffer isn't
@@ -58,21 +72,21 @@
 	(Trac #202, svn r3967)
 
   135.  [func]      each
-	Add b10-recurse. This is an example recursive server that
+	Add b10-resolver. This is an example recursive server that
 	currently does forwarding only and no caching.
 	(Trac #327, svn r3903)
 
   134.  [func]      vorner
-	b10-recurse supports timeouts and retries in forwarder mode.
+	b10-resolver supports timeouts and retries in forwarder mode.
 	(Trac #401, svn r3660)
 
   133.  [func]      vorner
 	New temporary logging function available in isc::log. It is used by
-	b10-recurse.
+	b10-resolver.
 	(Trac #393, r3602)
 
   132.  [func]      vorner
-	The b10-recurse is configured through config manager.
+	The b10-resolver is configured through config manager.
 	It has "listen_on" and "forward_addresses" options.
 	(Trac #389, r3448)
 
@@ -135,7 +149,7 @@ bind10-devel-20101201 released on December 01, 2010
   122.  [func]		stephen
 	src/bin/bind10: Added configuration options to Boss to determine
 	whether to start the authoritative server, recursive server (or
-	both). A dummy recursor has been provided for test purposes.
+	both). A dummy program has been provided for test purposes.
 	(Trac #412, svn r3676)
 
   121.  [func]		jinmei
@@ -777,8 +791,10 @@ bind10-devel-20100421 released on April 21, 2010
 bind10-devel-20100319 released on March 19, 2010
 
 For complete code revision history, see http://bind10.isc.org/browser
-Specific subversion changesets can be accessed at:
+Specific git changesets can be accessed at:
 	http://bind10.isc.org/changeset/rrrr
+Subversion changesets are not accessible any more.  The subversion
+revision numbers will be replaced with corresponding git revisions.
 Trac tickets can be accessed at: https://bind10.isc.org/ticket/nnn
 
 LEGEND

+ 2 - 1
README

@@ -15,7 +15,7 @@ five year plan are described here:
 
 This release includes the bind10 master process, b10-msgq message
 bus, b10-auth authoritative DNS server (with SQLite3 backend),
-b10-recurse forwarding DNS server, b10-cmdctl remote control daemon,
+b10-resolver forwarding DNS server, b10-cmdctl remote control daemon,
 b10-cfgmgr configuration manager, b10-xfrin AXFR inbound service,
 b10-xfrout outgoing AXFR service, b10-zonemgr secondary manager,
 b10-stats statistics collection and reporting daemon, and a new
@@ -193,6 +193,7 @@ config revert:	Revert all changes that have not been committed
 config commit: Commit all changes
 config diff: Show the changes that have not been committed yet
 
+
 EXAMPLE SESSION
 
 ~> bindctl

+ 23 - 5
configure.ac

@@ -9,7 +9,23 @@ AC_CONFIG_HEADERS([config.h])
 
 # Checks for programs.
 AC_PROG_CXX
+
+# Libtool configuration
+#
+# On FreeBSD (and probably some others), clang++ does not meet an autoconf
+# assumption in identifying libtool configuration regarding shared library:
+# the configure script will execute "$CC -shared $CFLAGS -v -o" and expect
+# the output contains -Lxxx or -Ryyy.  This is the case for g++, but not for
+# clang++, and, as a result, it will cause various errors in linking programs
+# or running them with a shared object (such as some of our python scripts).
+# To work around this problem we define a temporary variable
+# "CXX_LIBTOOL_LDFLAGS".  It's expected to be defined as, e.g, "-L/usr/lib"
+# to temporarily fake the output so that it will be compatible with that of
+# g++.
+CFLAGS_SAVED=$CFLAGS
+CFLAGS="$CFLAGS $CXX_LIBTOOL_LDFLAGS"
 AC_PROG_LIBTOOL
+CFLAGS=$CFLAGS_SAVED
 
 # Use C++ language
 AC_LANG([C++])
@@ -577,8 +593,8 @@ AC_CONFIG_FILES([Makefile
                  src/bin/auth/Makefile
                  src/bin/auth/tests/Makefile
                  src/bin/auth/benchmarks/Makefile
-                 src/bin/recurse/Makefile
-                 src/bin/recurse/tests/Makefile
+                 src/bin/resolver/Makefile
+                 src/bin/resolver/tests/Makefile
                  src/bin/xfrin/Makefile
                  src/bin/xfrin/tests/Makefile
                  src/bin/xfrout/Makefile
@@ -597,6 +613,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/Makefile
                  src/lib/asiolink/Makefile
                  src/lib/asiolink/tests/Makefile
+                 src/lib/asiolink/internal/Makefile
+                 src/lib/asiolink/internal/tests/Makefile
                  src/lib/bench/Makefile
                  src/lib/bench/example/Makefile
                  src/lib/bench/tests/Makefile
@@ -650,8 +668,8 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/xfrout/xfrout.spec.pre
            src/bin/xfrout/tests/xfrout_test
            src/bin/xfrout/run_b10-xfrout.sh
-           src/bin/recurse/recurse.spec.pre
-           src/bin/recurse/spec_config.h.pre
+           src/bin/resolver/resolver.spec.pre
+           src/bin/resolver/spec_config.h.pre
            src/bin/zonemgr/zonemgr.py
            src/bin/zonemgr/zonemgr.spec.pre
            src/bin/zonemgr/tests/zonemgr_test
@@ -694,7 +712,7 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
            chmod +x src/bin/xfrin/run_b10-xfrin.sh
            chmod +x src/bin/xfrout/run_b10-xfrout.sh
-           chmod +x src/bin/recurse/run_b10-recurse.sh
+           chmod +x src/bin/resolver/run_b10-resolver.sh
            chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
            chmod +x src/bin/stats/tests/stats_test
            chmod +x src/bin/stats/run_b10-stats.sh

+ 1 - 1
src/bin/Makefile.am

@@ -1,4 +1,4 @@
 SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout \
-	usermgr zonemgr stats tests recurse
+	usermgr zonemgr stats tests resolver
 
 check-recursive: all-recursive

+ 1 - 1
src/bin/auth/auth_srv.h

@@ -194,7 +194,7 @@ public:
     /// control commands and configuration updates.
     void setConfigSession(isc::config::ModuleCCSession* config_session);
 
-    /// \brief Assign an ASIO IO Service queue to this Recursor object
+    /// \brief Assign an ASIO IO Service queue to this Resolver object
     void setIOService(asiolink::IOService& ios) { io_service_ = &ios; }
 
     /// \brief Return this object's ASIO IO Service queue

+ 93 - 3
src/bin/auth/query.cc

@@ -12,8 +12,12 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <vector>
+#include <boost/foreach.hpp>
+
 #include <dns/message.h>
 #include <dns/rcode.h>
+#include <dns/rdataclass.h>
 
 #include <datasrc/memory_datasrc.h>
 
@@ -21,11 +25,66 @@
 
 using namespace isc::dns;
 using namespace isc::datasrc;
+using namespace isc::dns::rdata;
 
 namespace isc {
 namespace auth {
 
 void
+Query::getAdditional(const Zone& zone, const RRset& rrset) const {
+    RdataIteratorPtr rdata_iterator(rrset.getRdataIterator());
+    for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
+        const Rdata& rdata(rdata_iterator->getCurrent());
+        if (rrset.getType() == RRType::NS()) {
+            // Need to perform the search in the "GLUE OK" mode.
+            const generic::NS& ns = dynamic_cast<const generic::NS&>(rdata);
+            findAddrs(zone, ns.getNSName(), Zone::FIND_GLUE_OK);
+        } else if (rrset.getType() == RRType::MX()) {
+            const generic::MX& mx(dynamic_cast<const generic::MX&>(rdata));
+            findAddrs(zone, mx.getMXName());
+        }
+    }
+}
+
+void
+Query::findAddrs(const Zone& zone, const Name& qname,
+                 const Zone::FindOptions options) const
+{
+    // Out of zone name
+    NameComparisonResult result = zone.getOrigin().compare(qname);
+    if ((result.getRelation() != NameComparisonResult::SUPERDOMAIN) &&
+        (result.getRelation() != NameComparisonResult::EQUAL))
+        return;
+
+    // Omit additional data which has already been provided in the answer
+    // section from the additional.
+    //
+    // All the address rrset with the owner name of qname have been inserted
+    // into ANSWER section.
+    if (qname_ == qname && qtype_ == RRType::ANY())
+        return;
+
+    // Find A rrset
+    if (qname_ != qname || qtype_ != RRType::A()) {
+        Zone::FindResult a_result = zone.find(qname, RRType::A(), options);
+        if (a_result.code == Zone::SUCCESS) {
+            response_.addRRset(Message::SECTION_ADDITIONAL,
+                    boost::const_pointer_cast<RRset>(a_result.rrset));
+        }
+    }
+
+    // Find AAAA rrset
+    if (qname_ != qname || qtype_ != RRType::AAAA()) {
+        Zone::FindResult aaaa_result =
+            zone.find(qname, RRType::AAAA(), options);
+        if (aaaa_result.code == Zone::SUCCESS) {
+            response_.addRRset(Message::SECTION_ADDITIONAL,
+                    boost::const_pointer_cast<RRset>(aaaa_result.rrset));
+        }
+    }
+}
+
+void
 Query::putSOA(const Zone& zone) const {
     Zone::FindResult soa_result(zone.find(zone.getOrigin(),
         RRType::SOA()));
@@ -44,6 +103,22 @@ Query::putSOA(const Zone& zone) const {
 }
 
 void
+Query::getAuthAdditional(const Zone& zone) const {
+    // Fill in authority and addtional sections.
+    Zone::FindResult ns_result = zone.find(zone.getOrigin(), RRType::NS());
+    // zone origin name should have NS records
+    if (ns_result.code != Zone::SUCCESS) {
+        isc_throw(NoApexNS, "There's no apex NS records in zone " <<
+                zone.getOrigin().toText());
+    } else {
+        response_.addRRset(Message::SECTION_AUTHORITY,
+            boost::const_pointer_cast<RRset>(ns_result.rrset));
+        // Handle additional for authority section
+        getAdditional(zone, *ns_result.rrset);
+    }
+}
+
+void
 Query::process() const {
     bool keep_doing = true;
     response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
@@ -70,11 +145,25 @@ Query::process() const {
             case Zone::SUCCESS:
                 response_.setRcode(Rcode::NOERROR());
                 response_.addRRset(Message::SECTION_ANSWER,
-                            boost::const_pointer_cast<RRset>(db_result.rrset));
-                // TODO : fill in authority and addtional sections.
+                    boost::const_pointer_cast<RRset>(db_result.rrset));
+                // Handle additional for answer section
+                getAdditional(*result.zone, *db_result.rrset);
+                // If apex NS records haven't been provided in the answer
+                // section, insert apex NS records into the authority section
+                // and AAAA/A RRS of each of the NS RDATA into the additional
+                // section.
+                if (qname_ != result.zone->getOrigin() ||
+                    (qtype_ != RRType::NS() && qtype_ != RRType::ANY()))
+                {
+                    getAuthAdditional(*result.zone);
+                }
                 break;
             case Zone::DELEGATION:
-                // TODO : add NS to authority section, fill in additional section.
+                response_.setHeaderFlag(Message::HEADERFLAG_AA, false);
+                response_.setRcode(Rcode::NOERROR());
+                response_.addRRset(Message::SECTION_AUTHORITY,
+                    boost::const_pointer_cast<RRset>(db_result.rrset));
+                getAdditional(*result.zone, *db_result.rrset);
                 break;
             case Zone::NXDOMAIN:
                 // Just empty answer with SOA in authority section
@@ -93,5 +182,6 @@ Query::process() const {
         }
     }
 }
+
 }
 }

+ 78 - 9
src/bin/auth/query.h

@@ -15,17 +15,18 @@
  */
 
 #include <exceptions/exceptions.h>
+#include <datasrc/zone.h>
 
 namespace isc {
 namespace dns {
 class Message;
 class Name;
 class RRType;
+class RRset;
 }
 
 namespace datasrc {
 class MemoryDataSrc;
-class Zone;
 }
 
 namespace auth {
@@ -63,6 +64,72 @@ namespace auth {
 /// accidentally, and since it's considered a temporary development state,
 /// we keep this name at the moment.
 class Query {
+private:
+
+    /// \brief Adds a SOA.
+    ///
+    /// Adds a SOA of the zone into the authority zone of response_.
+    /// Can throw NoSOA.
+    ///
+    void putSOA(const isc::datasrc::Zone& zone) const;
+
+    /// \brief Look up additional data (i.e., address records for the names
+    /// included in NS or MX records).
+    ///
+    /// Note: Any additional data which has already been provided in the
+    /// answer section (i.e., if the original query happend to be for the
+    /// address of the DNS server), it should be omitted from the additional.
+    ///
+    /// This method may throw a exception because its underlying methods may
+    /// throw exceptions.
+    ///
+    /// \param zone The Zone wherein the additional data to the query is bo be
+    /// found.
+    /// \param rrset The RRset (i.e., NS or MX rrset) which require additional
+    /// processing.
+    void getAdditional(const isc::datasrc::Zone& zone,
+                       const isc::dns::RRset& rrset) const;
+
+    /// \brief Find address records for a specified name.
+    ///
+    /// Search the specified zone for AAAA/A RRs of each of the NS/MX RDATA
+    /// (domain name), and insert the found ones into the additional section
+    /// if address records are available. By default the search will stop
+    /// once it encounters a zone cut.
+    ///
+    /// Note: we need to perform the search in the "GLUE OK" mode for NS RDATA,
+    /// which means that we should include A/AAAA RRs under a zone cut.
+    /// The glue records must exactly match the name in the NS RDATA, without
+    /// CNAME or wildcard processing.
+    ///
+    /// \param zone The \c Zone wherein the address records is to be found.
+    /// \param qname The name in rrset RDATA.
+    /// \param options The search options.
+    void findAddrs(const isc::datasrc::Zone& zone,
+                   const isc::dns::Name& qname,
+                   const isc::datasrc::Zone::FindOptions options
+                   = isc::datasrc::Zone::FIND_DEFAULT) const;
+
+    /// \brief Look up \c Zone's NS and address records for the NS RDATA
+    /// (domain name) for authoritative answer.
+    ///
+    /// On returning an authoritative answer, insert the \c Zone's NS into the
+    /// authority section and AAAA/A RRs of each of the NS RDATA into the
+    /// additional section.
+    ///
+    /// <b>Notes to developer:</b>
+    ///
+    /// We should omit address records which has already been provided in the
+    /// answer section from the additional.
+    ///
+    /// For now, in order to optimize the additional section processing, we
+    /// include AAAA/A RRs under a zone cut in additional section. (BIND 9
+    /// excludes under-cut RRs; NSD include them.)
+    ///
+    /// \param zone The \c Zone wherein the additional data to the query is to
+    /// be found.
+    void getAuthAdditional(const isc::datasrc::Zone& zone) const;
+
 public:
     /// Constructor from query parameters.
     ///
@@ -130,19 +197,21 @@ public:
         {}
     };
 
+    /// \short Zone is missing its apex NS records.
+    ///
+    /// We tried to add apex NS records into the authority section, but the
+    /// zone does not contain any.
+    struct NoApexNS: public BadZone {
+        NoApexNS(const char* file, size_t line, const char* what) :
+            BadZone(file, line, what)
+        {}
+    };
+
 private:
     const isc::datasrc::MemoryDataSrc& memory_datasrc_;
     const isc::dns::Name& qname_;
     const isc::dns::RRType& qtype_;
     isc::dns::Message& response_;
-
-    /**
-     * \short Adds a SOA.
-     *
-     * Adds a SOA of the zone into the authority zone of response_.
-     * Can throw NoSOA.
-     */
-    void putSOA(const isc::datasrc::Zone& zone) const;
 };
 
 }

+ 1 - 0
src/bin/auth/tests/Makefile.am

@@ -36,6 +36,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
+run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libdatasrc.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la

+ 21 - 10
src/bin/auth/tests/auth_srv_unittest.cc

@@ -33,14 +33,17 @@
 #include <auth/common.h>
 #include <auth/statistics.h>
 
-#include <testutils/srv_unittest.h>
+#include <dns/tests/unittest_util.h>
+#include <testutils/srv_test.h>
 
+using namespace std;
 using namespace isc::cc;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::data;
 using namespace isc::xfr;
 using namespace asiolink;
+using namespace isc::testutils;
 using isc::UnitTestUtil;
 
 namespace {
@@ -57,6 +60,10 @@ protected:
         server.setXfrinSession(&notify_session);
         server.setStatisticsSession(&statistics_session);
     }
+    virtual void processMessage() {
+        server.processMessage(*io_message, parse_message, response_obuffer,
+                              &dnsserv);
+    }
     MockSession statistics_session;
     MockXfroutClient xfrout;
     AuthSrv server;
@@ -161,48 +168,52 @@ TEST_F(AuthSrvTest, iqueryViaDNSServer) {
 
 // Unsupported requests.  Should result in NOTIMP.
 TEST_F(AuthSrvTest, unsupportedRequest) {
-    UNSUPPORTED_REQUEST_TEST;
+    unsupportedRequest();
 }
 
 // Simple API check
 TEST_F(AuthSrvTest, verbose) {
-    VERBOSE_TEST;
+    EXPECT_FALSE(server.getVerbose());
+    server.setVerbose(true);
+    EXPECT_TRUE(server.getVerbose());
+    server.setVerbose(false);
+    EXPECT_FALSE(server.getVerbose());
 }
 
 // Multiple questions.  Should result in FORMERR.
 TEST_F(AuthSrvTest, multiQuestion) {
-    MULTI_QUESTION_TEST;
+    multiQuestion();
 }
 
 // Incoming data doesn't even contain the complete header.  Must be silently
 // dropped.
 TEST_F(AuthSrvTest, shortMessage) {
-    SHORT_MESSAGE_TEST;
+    shortMessage();
 }
 
 // Response messages.  Must be silently dropped, whether it's a valid response
 // or malformed or could otherwise cause a protocol error.
 TEST_F(AuthSrvTest, response) {
-    RESPONSE_TEST;
+    response();
 }
 
 // Query with a broken question
 TEST_F(AuthSrvTest, shortQuestion) {
-    SHORT_QUESTION_TEST;
+    shortQuestion();
 }
 
 // Query with a broken answer section
 TEST_F(AuthSrvTest, shortAnswer) {
-    SHORT_ANSWER_TEST;
+    shortAnswer();
 }
 
 // Query with unsupported version of EDNS.
 TEST_F(AuthSrvTest, ednsBadVers) {
-    EDNS_BADVERS_TEST;
+    ednsBadVers();
 }
 
 TEST_F(AuthSrvTest, AXFROverUDP) {
-    AXFR_OVER_UDP_TEST;
+    axfrOverUDP();
 }
 
 TEST_F(AuthSrvTest, AXFRSuccess) {

+ 331 - 22
src/bin/auth/tests/query_unittest.cc

@@ -17,6 +17,7 @@
 #include <dns/rcode.h>
 #include <dns/rrttl.h>
 #include <dns/rrtype.h>
+#include <dns/rdataclass.h>
 
 #include <datasrc/memory_datasrc.h>
 
@@ -36,19 +37,70 @@ RRsetPtr a_rrset = RRsetPtr(new RRset(Name("www.example.com"),
 RRsetPtr soa_rrset = RRsetPtr(new RRset(Name("example.com"),
                                         RRClass::IN(), RRType::SOA(),
                                         RRTTL(3600)));
+RRsetPtr ns_rrset(RRsetPtr(new RRset(Name("ns.example.com"),
+                                     RRClass::IN(), RRType::NS(),
+                                     RRTTL(3600))));
+RRsetPtr glue_a_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
+                                         RRClass::IN(), RRType::A(),
+                                         RRTTL(3600))));
+RRsetPtr glue_aaaa_rrset(RRsetPtr(new RRset(Name("glue.ns.example.com"),
+                                            RRClass::IN(), RRType::AAAA(),
+                                            RRTTL(3600))));
+RRsetPtr noglue_a_rrset(RRsetPtr(new RRset(Name("noglue.example.com"),
+                                           RRClass::IN(), RRType::A(),
+                                           RRTTL(3600))));
+RRsetPtr delegated_mx_a_rrset(RRsetPtr(new RRset(
+    Name("mx.delegation.example.com"), RRClass::IN(), RRType::A(),
+    RRTTL(3600))));
+
 // This is a mock Zone class for testing.
-// It is a derived class of Zone, and simply hardcode the results of find()
-// return SUCCESS for "www.example.com",
-// return NXDOMAIN for "nxdomain.example.com",
-// return NXRRSET for "nxrrset.example.com",
-// return CNAME for "cname.example.com",
-// else return DNAME
+// It is a derived class of Zone, and simply hardcodes the results of find()
+// See the find() implementation if you want to know its content.
 class MockZone : public Zone {
 public:
-    MockZone(bool has_SOA = true) :
+    MockZone(bool has_SOA = true, bool has_apex_NS = true) :
         origin_(Name("example.com")),
-        has_SOA_(has_SOA)
-    {}
+        has_SOA_(has_SOA),
+        has_apex_NS_(has_apex_NS),
+        delegation_rrset(RRsetPtr(new RRset(Name("delegation.example.com"),
+                                            RRClass::IN(), RRType::NS(),
+                                            RRTTL(3600)))),
+        cname_rrset(RRsetPtr(new RRset(Name("cname.example.com"),
+                                       RRClass::IN(), RRType::CNAME(),
+                                       RRTTL(3600)))),
+        auth_ns_rrset(RRsetPtr(new RRset(Name("example.com"),
+                                         RRClass::IN(), RRType::NS(),
+                                         RRTTL(3600)))),
+        mx_cname_rrset_(new RRset(Name("cnamemailer.example.com"),
+            RRClass::IN(), RRType::CNAME(), RRTTL(3600))),
+        mx_rrset_(new RRset(Name("mx.example.com"), RRClass::IN(),
+            RRType::MX(), RRTTL(3600)))
+    {
+        delegation_rrset->addRdata(rdata::generic::NS(
+                          Name("glue.ns.example.com")));
+        delegation_rrset->addRdata(rdata::generic::NS(
+                          Name("noglue.example.com")));
+        delegation_rrset->addRdata(rdata::generic::NS(
+                          Name("cname.example.com")));
+        delegation_rrset->addRdata(rdata::generic::NS(
+                          Name("example.org")));
+        cname_rrset->addRdata(rdata::generic::CNAME(
+                          Name("www.example.com")));
+        auth_ns_rrset->addRdata(rdata::generic::NS(
+                          Name("glue.ns.example.com")));
+        auth_ns_rrset->addRdata(rdata::generic::NS(
+                          Name("noglue.example.com")));
+        auth_ns_rrset->addRdata(rdata::generic::NS(
+                          Name("example.net")));
+        mx_rrset_->addRdata(isc::dns::rdata::generic::MX(10,
+            Name("www.example.com")));
+        mx_rrset_->addRdata(isc::dns::rdata::generic::MX(20,
+            Name("mailer.example.org")));
+        mx_rrset_->addRdata(isc::dns::rdata::generic::MX(30,
+            Name("mx.delegation.example.com")));
+        mx_cname_rrset_->addRdata(rdata::generic::CNAME(
+            Name("mx.example.com")));
+    }
     virtual const isc::dns::Name& getOrigin() const;
     virtual const isc::dns::RRClass& getClass() const;
 
@@ -59,6 +111,12 @@ public:
 private:
     Name origin_;
     bool has_SOA_;
+    bool has_apex_NS_;
+    RRsetPtr delegation_rrset;
+    RRsetPtr cname_rrset;
+    RRsetPtr auth_ns_rrset;
+    RRsetPtr mx_cname_rrset_;
+    RRsetPtr mx_rrset_;
 };
 
 const Name&
@@ -72,22 +130,52 @@ MockZone::getClass() const {
 }
 
 Zone::FindResult
-MockZone::find(const Name& name, const RRType& type, const FindOptions) const {
+MockZone::find(const Name& name, const RRType& type,
+               const FindOptions options) const
+{
     // hardcode the find results
-    if (name == Name("www.example.com")) {
+    if (name == Name("www.example.com") && type == RRType::A()) {
         return (FindResult(SUCCESS, a_rrset));
+    } else if (name == Name("www.example.com")) {
+        return (FindResult(NXRRSET, RRsetPtr()));
+    } else if (name == Name("glue.ns.example.com") && type == RRType::A() &&
+        (options & FIND_GLUE_OK) != 0) {
+        return (FindResult(SUCCESS, glue_a_rrset));
+    } else if (name == Name("noglue.example.com") && (type == RRType::A() ||
+        type == RRType::ANY())) {
+        return (FindResult(SUCCESS, noglue_a_rrset));
+    } else if (name == Name("glue.ns.example.com") && type == RRType::AAAA() &&
+        (options & FIND_GLUE_OK) != 0) {
+        return (FindResult(SUCCESS, glue_aaaa_rrset));
     } else if (name == Name("example.com") && type == RRType::SOA() &&
         has_SOA_)
     {
         return (FindResult(SUCCESS, soa_rrset));
-    } else if (name == Name("delegation.example.com")) {
-        return (FindResult(DELEGATION, RRsetPtr()));
+    } else if (name == Name("example.com") && type == RRType::NS() &&
+        has_apex_NS_)
+    {
+        return (FindResult(SUCCESS, auth_ns_rrset));
+    } else if (name == Name("mx.delegation.example.com") &&
+        type == RRType::A() && (options & FIND_GLUE_OK) != 0)
+    {
+        return (FindResult(SUCCESS, delegated_mx_a_rrset));
+    } else if (name == Name("delegation.example.com") ||
+        name.compare(Name("delegation.example.com")).getRelation() ==
+        NameComparisonResult::SUBDOMAIN)
+    {
+        return (FindResult(DELEGATION, delegation_rrset));
+    } else if (name == Name("ns.example.com")) {
+        return (FindResult(DELEGATION, ns_rrset));
     } else if (name == Name("nxdomain.example.com")) {
         return (FindResult(NXDOMAIN, RRsetPtr()));
     } else if (name == Name("nxrrset.example.com")) {
         return (FindResult(NXRRSET, RRsetPtr()));
-    } else if (name == Name("cname.example.com")) {
-        return (FindResult(CNAME, RRsetPtr()));
+    } else if ((name == Name("cname.example.com"))) {
+        return (FindResult(CNAME, cname_rrset));
+    } else if (name == Name("cnamemailer.example.com")) {
+        return (FindResult(CNAME, mx_cname_rrset_));
+    } else if (name == Name("mx.example.com")) {
+        return (FindResult(SUCCESS, mx_rrset_));
     } else {
         return (FindResult(DNAME, RRsetPtr()));
     }
@@ -113,33 +201,175 @@ protected:
 TEST_F(QueryTest, noZone) {
     // There's no zone in the memory datasource.  So the response should have
     // REFUSED.
-    query.process();
+    EXPECT_NO_THROW(query.process());
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 
-TEST_F(QueryTest, matchZone) {
+TEST_F(QueryTest, exactMatch) {
     // add a matching zone.
     memory_datasrc.addZone(ZonePtr(new MockZone()));
-    query.process();
+    EXPECT_NO_THROW(query.process());
+    // find match rrset
+    EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
     EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
     EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
                                   Name("www.example.com"), RRClass::IN(),
                                   RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
+                                  Name("example.com"), RRClass::IN(),
+                                  RRType::NS()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::AAAA()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("noglue.example.com"),
+                                  RRClass::IN(), RRType::A()));
+}
+
+TEST_F(QueryTest, exactAddrMatch) {
+    // find match rrset, omit additional data which has already been provided
+    // in the answer section from the additional.
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    const Name noglue_name(Name("noglue.example.com"));
+    Query noglue_query(memory_datasrc, noglue_name, qtype, response);
+    EXPECT_NO_THROW(noglue_query.process());
+    EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
+                                  Name("noglue.example.com"), RRClass::IN(),
+                                  RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
+                                  Name("example.com"), RRClass::IN(),
+                                  RRType::NS()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::AAAA()));
+    EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("noglue.example.com"),
+                                  RRClass::IN(), RRType::A()));
+}
+
+TEST_F(QueryTest, apexNSMatch) {
+    // find match rrset, omit authority data which has already been provided
+    // in the answer section from the authority section.
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    const Name apex_name(Name("example.com"));
+    Query apex_ns_query(memory_datasrc, apex_name, RRType::NS(), response);
+    EXPECT_NO_THROW(apex_ns_query.process());
+    EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
+                                  Name("example.com"), RRClass::IN(),
+                                  RRType::NS()));
+    EXPECT_FALSE(response.hasRRset(Message::SECTION_AUTHORITY,
+                                  Name("example.com"), RRClass::IN(),
+                                  RRType::NS()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::AAAA()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("noglue.example.com"),
+                                  RRClass::IN(), RRType::A()));
+}
+
+TEST_F(QueryTest, exactAnyMatch) {
+    // find match rrset, omit additional data which has already been provided
+    // in the answer section from the additional.
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    const Name noglue_name(Name("noglue.example.com"));
+    Query noglue_query(memory_datasrc, noglue_name, RRType::ANY(), response);
+    EXPECT_NO_THROW(noglue_query.process());
+    EXPECT_TRUE(response.getHeaderFlag(Message::HEADERFLAG_AA));
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
+                                  Name("noglue.example.com"), RRClass::IN(),
+                                  RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
+                                  Name("example.com"), RRClass::IN(),
+                                  RRType::NS()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::AAAA()));
+    EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("noglue.example.com"),
+                                  RRClass::IN(), RRType::A()));
+}
+
+// This tests that when we need to look up Zone's apex NS records for
+// authoritative answer, and there is no apex NS records. It should
+// throw in that case.
+TEST_F(QueryTest, noApexNS) {
+    // Add a zone without apex NS records
+    memory_datasrc.addZone(ZonePtr(new MockZone(true, false)));
+    const Name noglue_name(Name("noglue.example.com"));
+    Query noglue_query(memory_datasrc, noglue_name, qtype, response);
+    EXPECT_THROW(noglue_query.process(), Query::NoApexNS);
+    // We don't look into the response, as it throwed
+}
 
-    // NXDOMAIN
+TEST_F(QueryTest, delegation) {
+    // add a matching zone.
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    const Name delegation_name(Name("delegation.example.com"));
+    Query delegation_query(memory_datasrc, delegation_name, qtype, response);
+    EXPECT_NO_THROW(delegation_query.process());
+    EXPECT_FALSE(response.getHeaderFlag(Message::HEADERFLAG_AA));
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
+                                  Name("delegation.example.com"),
+                                  RRClass::IN(), RRType::NS()));
+    // glue address records
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("glue.ns.example.com"),
+                                  RRClass::IN(), RRType::AAAA()));
+    // noglue address records
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("noglue.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    // NS name has a CNAME
+    EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("www.example.com"),
+                                  RRClass::IN(), RRType::A()));
+    // NS name is out of zone
+    EXPECT_FALSE(response.hasRRset(Message::SECTION_ADDITIONAL,
+                                  Name("example.org"),
+                                  RRClass::IN(), RRType::A()));
+}
+
+TEST_F(QueryTest, nxdomain) {
+    // add a matching zone.
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
     const Name nxdomain_name(Name("nxdomain.example.com"));
     Query nxdomain_query(memory_datasrc, nxdomain_name, qtype, response);
-    nxdomain_query.process();
+    EXPECT_NO_THROW(nxdomain_query.process());
     EXPECT_EQ(Rcode::NXDOMAIN(), response.getRcode());
     EXPECT_EQ(0, response.getRRCount(Message::SECTION_ANSWER));
     EXPECT_EQ(0, response.getRRCount(Message::SECTION_ADDITIONAL));
     EXPECT_TRUE(response.hasRRset(Message::SECTION_AUTHORITY,
         Name("example.com"), RRClass::IN(), RRType::SOA()));
+}
 
-    // NXRRSET
+TEST_F(QueryTest, nxrrset) {
+    // add a matching zone.
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
     const Name nxrrset_name(Name("nxrrset.example.com"));
     Query nxrrset_query(memory_datasrc, nxrrset_name, qtype, response);
-    nxrrset_query.process();
+    EXPECT_NO_THROW(nxrrset_query.process());
     EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
     EXPECT_EQ(0, response.getRRCount(Message::SECTION_ANSWER));
     EXPECT_EQ(0, response.getRRCount(Message::SECTION_ADDITIONAL));
@@ -176,4 +406,83 @@ TEST_F(QueryTest, noMatchZone) {
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 
+/*
+ * Test MX additional processing.
+ *
+ * The MX RRset has two RRs, one pointing to a known domain with
+ * A record, other to unknown out of zone one.
+ */
+TEST_F(QueryTest, MX) {
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    Name qname("mx.example.com");
+    Query mx_query(memory_datasrc, qname, RRType::MX(), response);
+    EXPECT_NO_THROW(mx_query.process());
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ANSWER,
+        Name("mx.example.com"), RRClass::IN(), RRType::MX()));
+    EXPECT_TRUE(response.hasRRset(Message::SECTION_ADDITIONAL,
+        Name("www.example.com"), RRClass::IN(), RRType::A()));
+    // We want to skip the additional ones related to authoritative
+    RRsetPtr ns;
+    for (SectionIterator<RRsetPtr> ai(response.beginSection(
+        Message::SECTION_AUTHORITY)); ai != response.endSection(
+        Message::SECTION_AUTHORITY); ++ai)
+    {
+        if ((*ai)->getName() == Name("example.com") && (*ai)->getType() ==
+            RRType::NS())
+        {
+            ns = *ai;
+            break;
+        }
+    }
+    /*
+     * In fact, the MX RRset mentions three names, but we don't know anything
+     * about one of them and one is under a zone cut, so we should have just
+     * one RRset (A for www.example.com)
+     */
+    // We can't use getRRCount, as it counts RRs, not RRsets
+    unsigned additional_count(0);
+    for (SectionIterator<RRsetPtr> ai(response.beginSection(
+        Message::SECTION_ADDITIONAL)); ai != response.endSection(
+        Message::SECTION_ADDITIONAL); ++ai)
+    {
+        // Skip the ones for the NS record
+        if (ns) {
+            for (RdataIteratorPtr nsi(ns->getRdataIterator()); !nsi->isLast();
+                nsi->next())
+            {
+                if ((*ai)->getName() ==
+                    dynamic_cast<const isc::dns::rdata::generic::NS&>(
+                    nsi->getCurrent()).getNSName())
+                {
+                    goto NS_ADDITIONAL_DATA;
+                }
+            }
+        }
+        // It is not related to the NS, then it must be related to the MX
+        ++additional_count;
+        EXPECT_EQ(Name("www.example.com"), (*ai)->getName());
+        EXPECT_EQ(RRType::A(), (*ai)->getType());
+        NS_ADDITIONAL_DATA:;
+    }
+    EXPECT_EQ(1, additional_count);
+}
+
+/*
+ * Test when we ask for MX and encounter an alias (CNAME in this case).
+ *
+ * This should not trigger the additional processing.
+ */
+TEST_F(QueryTest, MXAlias) {
+    memory_datasrc.addZone(ZonePtr(new MockZone()));
+    Name qname("cnamemailer.example.com");
+    Query mx_query(memory_datasrc, qname, RRType::MX(), response);
+    EXPECT_NO_THROW(mx_query.process());
+    EXPECT_EQ(Rcode::NOERROR(), response.getRcode());
+    // We should not have the IP address in additional section
+    // Currently, the section should be completely empty
+    EXPECT_TRUE(response.beginSection(Message::SECTION_ADDITIONAL) ==
+        response.endSection(Message::SECTION_ADDITIONAL));
+}
+
 }

+ 17 - 17
src/bin/bind10/bind10.py.in

@@ -208,13 +208,13 @@ class BoB:
         self.dns_port = dns_port
         self.forward = forward
         if forward:
-            self.recursive = True
+            self.resolver = True
         else:
-            self.recursive = False
+            self.resolver = False
         self.cc_session = None
         self.ccs = None
         self.cfg_start_auth = True
-        self.cfg_start_recurse = False
+        self.cfg_start_resolver = False
         self.curproc = None
         self.dead_processes = {}
         self.msgq_socket_file = msgq_socket_file
@@ -278,13 +278,13 @@ class BoB:
 
         config_data = self.ccs.get_full_config()
         self.cfg_start_auth = config_data.get("start_auth")
-        self.cfg_start_recurse = config_data.get("start_recurse")
+        self.cfg_start_resolver = config_data.get("start_resolver")
 
         if self.verbose:
             sys.stdout.write("[bind10] - start_auth: %s\n" %
                 str(self.cfg_start_auth))
-            sys.stdout.write("[bind10] - start_recurse: %s\n" %
-                str(self.cfg_start_recurse))
+            sys.stdout.write("[bind10] - start_resolver: %s\n" %
+                str(self.cfg_start_resolver))
 
     def log_starting(self, process, port = None, address = None):
         """
@@ -423,13 +423,13 @@ class BoB:
             Start the Authoritative server
         """
         # XXX: this must be read from the configuration manager in the future
-        if self.recursive:
-            dns_prog = 'b10-recurse'
+        if self.resolver:
+            dns_prog = 'b10-resolver'
         else:
             dns_prog = 'b10-auth'
         dnsargs = [dns_prog]
-        if not self.recursive:
-            # The recursive uses configuration manager for these
+        if not self.resolver:
+            # The resolver uses configuration manager for these
             dnsargs += ['-p', str(self.dns_port)]
             if self.address:
                 dnsargs += ['-a', str(self.address)]
@@ -444,22 +444,22 @@ class BoB:
         self.start_process("b10-auth", dnsargs, c_channel_env,
             self.dns_port, self.address)
 
-    def start_recurse(self, c_channel_env):
+    def start_resolver(self, c_channel_env):
         """
             Start the Resolver.  At present, all these arguments and switches
             are pure speculation.  As with the auth daemon, they should be
             read from the configuration database.
         """
-        self.curproc = "b10-recurse"
+        self.curproc = "b10-resolver"
         # XXX: this must be read from the configuration manager in the future
-        resargs = ['b10-recurse']
+        resargs = ['b10-resolver']
         if self.uid:
             resargs += ['-u', str(self.uid)]
         if self.verbose:
             resargs += ['-v']
 
         # ... and start
-        self.start_process("b10-recurse", resargs, c_channel_env)
+        self.start_process("b10-resolver", resargs, c_channel_env)
 
     def start_xfrout(self, c_channel_env):
         self.start_simple("b10-xfrout", c_channel_env)
@@ -496,8 +496,8 @@ class BoB:
             self.start_auth(c_channel_env)
 
         # ... and resolver (if selected):
-        if self.cfg_start_recurse:
-            self.start_recurse(c_channel_env)
+        if self.cfg_start_resolver:
+            self.start_resolver(c_channel_env)
 
         # Everything after the main components can run as non-root.
         # TODO: this is only temporary - once the privileged socket creator is
@@ -557,7 +557,7 @@ class BoB:
         self.cc_session.group_sendmsg(cmd, 'Cmdctl', 'Cmdctl')
         self.cc_session.group_sendmsg(cmd, "ConfigManager", "ConfigManager")
         self.cc_session.group_sendmsg(cmd, "Auth", "Auth")
-        self.cc_session.group_sendmsg(cmd, "Recurse", "Recurse")
+        self.cc_session.group_sendmsg(cmd, "Resolver", "Resolver")
         self.cc_session.group_sendmsg(cmd, "Xfrout", "Xfrout")
         self.cc_session.group_sendmsg(cmd, "Xfrin", "Xfrin")
         self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")

+ 1 - 1
src/bin/bind10/bob.spec

@@ -10,7 +10,7 @@
         "item_default": true
       },
       {
-        "item_name": "start_recurse",
+        "item_name": "start_resolver",
         "item_type": "boolean",
         "item_optional": false,
         "item_default": false

+ 1 - 1
src/bin/bind10/run_bind10.sh.in

@@ -20,7 +20,7 @@ export PYTHON_EXEC
 
 BIND10_PATH=@abs_top_builddir@/src/bin/bind10
 
-PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/recurse:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
+PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/resolver:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/stats:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
 export PATH
 
 PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs:@abs_top_builddir@/src/lib/log/.libs

+ 20 - 20
src/bin/bind10/tests/bind10_test.py

@@ -89,7 +89,7 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.username, None)
         self.assertEqual(bob.nocache, False)
         self.assertEqual(bob.cfg_start_auth, True)
-        self.assertEqual(bob.cfg_start_recurse, False)
+        self.assertEqual(bob.cfg_start_resolver, False)
 
     def test_init_alternate_socket(self):
         bob = BoB("alt_socket_file")
@@ -106,7 +106,7 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.username, None)
         self.assertEqual(bob.nocache, False)
         self.assertEqual(bob.cfg_start_auth, True)
-        self.assertEqual(bob.cfg_start_recurse, False)
+        self.assertEqual(bob.cfg_start_resolver, False)
 
     def test_init_alternate_dns_port(self):
         bob = BoB(None, 9999)
@@ -123,7 +123,7 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.username, None)
         self.assertEqual(bob.nocache, False)
         self.assertEqual(bob.cfg_start_auth, True)
-        self.assertEqual(bob.cfg_start_recurse, False)
+        self.assertEqual(bob.cfg_start_resolver, False)
 
     def test_init_alternate_address(self):
         bob = BoB(None, 1234, IPAddr('127.127.127.127'))
@@ -140,7 +140,7 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.username, None)
         self.assertEqual(bob.nocache, False)
         self.assertEqual(bob.cfg_start_auth, True)
-        self.assertEqual(bob.cfg_start_recurse, False)
+        self.assertEqual(bob.cfg_start_resolver, False)
 
 # Class for testing the Bob.start_all_processes() method call.
 #
@@ -157,7 +157,7 @@ class StartAllProcessesBob(BoB):
         self.cfgmgr = False
         self.ccsession = False
         self.auth = False
-        self.recurse = False
+        self.resolver = False
         self.xfrout = False
         self.xfrin = False
         self.zonemgr = False
@@ -180,8 +180,8 @@ class StartAllProcessesBob(BoB):
     def start_auth(self, c_channel_env):
         self.auth = True
 
-    def start_recurse(self, c_channel_env):
-        self.recurse = True
+    def start_resolver(self, c_channel_env):
+        self.resolver = True
 
     def start_xfrout(self, c_channel_env):
         self.xfrout = True
@@ -206,14 +206,14 @@ class TestStartAllProcessesBob(unittest.TestCase):
         self.assertEqual(bob.cfgmgr, False)
         self.assertEqual(bob.ccsession, False)
         self.assertEqual(bob.auth, False)
-        self.assertEqual(bob.recurse, False)
+        self.assertEqual(bob.resolver, False)
         self.assertEqual(bob.xfrout, False)
         self.assertEqual(bob.xfrin, False)
         self.assertEqual(bob.zonemgr, False)
         self.assertEqual(bob.stats, False)
         self.assertEqual(bob.cmdctl, False)
 
-    # Checks the processes started when starting neither auth nor recurse
+    # Checks the processes started when starting neither auth nor resolver
     # is specified.
     def test_start_none(self):
         # Created Bob and ensure initialization correct
@@ -223,7 +223,7 @@ class TestStartAllProcessesBob(unittest.TestCase):
         # Start processes and check what was started
         c_channel_env = {}
         bob.cfg_start_auth = False
-        bob.cfg_start_recurse = False
+        bob.cfg_start_resolver = False
 
         bob.start_all_processes(c_channel_env)
 
@@ -231,7 +231,7 @@ class TestStartAllProcessesBob(unittest.TestCase):
         self.assertEqual(bob.cfgmgr, True)
         self.assertEqual(bob.ccsession, True)
         self.assertEqual(bob.auth, False)
-        self.assertEqual(bob.recurse, False)
+        self.assertEqual(bob.resolver, False)
         self.assertEqual(bob.xfrout, False)
         self.assertEqual(bob.xfrin, False)
         self.assertEqual(bob.zonemgr, False)
@@ -247,7 +247,7 @@ class TestStartAllProcessesBob(unittest.TestCase):
         # Start processes and check what was started
         c_channel_env = {}
         bob.cfg_start_auth = True
-        bob.cfg_start_recurse = False
+        bob.cfg_start_resolver = False
 
         bob.start_all_processes(c_channel_env)
 
@@ -255,15 +255,15 @@ class TestStartAllProcessesBob(unittest.TestCase):
         self.assertEqual(bob.cfgmgr, True)
         self.assertEqual(bob.ccsession, True)
         self.assertEqual(bob.auth, True)
-        self.assertEqual(bob.recurse, False)
+        self.assertEqual(bob.resolver, False)
         self.assertEqual(bob.xfrout, True)
         self.assertEqual(bob.xfrin, True)
         self.assertEqual(bob.zonemgr, True)
         self.assertEqual(bob.stats, True)
         self.assertEqual(bob.cmdctl, True)
 
-    # Checks the processes started when starting only the recurse process
-    def test_start_recurse(self):
+    # Checks the processes started when starting only the resolver process
+    def test_start_resolver(self):
         # Created Bob and ensure initialization correct
         bob = StartAllProcessesBob()
         self.check_preconditions(bob)
@@ -271,7 +271,7 @@ class TestStartAllProcessesBob(unittest.TestCase):
         # Start processes and check what was started
         c_channel_env = {}
         bob.cfg_start_auth = False
-        bob.cfg_start_recurse = True
+        bob.cfg_start_resolver = True
 
         bob.start_all_processes(c_channel_env)
 
@@ -279,14 +279,14 @@ class TestStartAllProcessesBob(unittest.TestCase):
         self.assertEqual(bob.cfgmgr, True)
         self.assertEqual(bob.ccsession, True)
         self.assertEqual(bob.auth, False)
-        self.assertEqual(bob.recurse, True)
+        self.assertEqual(bob.resolver, True)
         self.assertEqual(bob.xfrout, False)
         self.assertEqual(bob.xfrin, False)
         self.assertEqual(bob.zonemgr, False)
         self.assertEqual(bob.stats, True)
         self.assertEqual(bob.cmdctl, True)
 
-    # Checks the processes started when starting both auth and recurse process
+    # Checks the processes started when starting both auth and resolver process
     def test_start_both(self):
         # Created Bob and ensure initialization correct
         bob = StartAllProcessesBob()
@@ -295,7 +295,7 @@ class TestStartAllProcessesBob(unittest.TestCase):
         # Start processes and check what was started
         c_channel_env = {}
         bob.cfg_start_auth = True
-        bob.cfg_start_recurse = True
+        bob.cfg_start_resolver = True
 
         bob.start_all_processes(c_channel_env)
 
@@ -303,7 +303,7 @@ class TestStartAllProcessesBob(unittest.TestCase):
         self.assertEqual(bob.cfgmgr, True)
         self.assertEqual(bob.ccsession, True)
         self.assertEqual(bob.auth, True)
-        self.assertEqual(bob.recurse, True)
+        self.assertEqual(bob.resolver, True)
         self.assertEqual(bob.xfrout, True)
         self.assertEqual(bob.xfrin, True)
         self.assertEqual(bob.zonemgr, True)

+ 0 - 57
src/bin/recurse/Makefile.am

@@ -1,57 +0,0 @@
-SUBDIRS = . tests
-
-AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
-AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
-AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
-AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc
-AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
-AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiolink
-AM_CPPFLAGS += $(BOOST_INCLUDES)
-
-AM_CXXFLAGS = $(B10_CXXFLAGS)
-
-if USE_STATIC_LINK
-AM_LDFLAGS = -static
-endif
-
-pkglibexecdir = $(libexecdir)/@PACKAGE@
-
-CLEANFILES = *.gcno *.gcda recurse.spec spec_config.h
-
-man_MANS = b10-recurse.8
-EXTRA_DIST = $(man_MANS) b10-recurse.xml
-
-if ENABLE_MAN
-
-b10-recurse.8: b10-recurse.xml
-	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-recurse.xml
-
-endif
-
-recurse.spec: recurse.spec.pre
-	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" recurse.spec.pre >$@
-
-spec_config.h: spec_config.h.pre
-	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@
-
-BUILT_SOURCES = spec_config.h 
-pkglibexec_PROGRAMS = b10-recurse
-b10_recurse_SOURCES = recursor.cc recursor.h
-b10_recurse_SOURCES += $(top_builddir)/src/bin/auth/change_user.h
-b10_recurse_SOURCES += $(top_builddir)/src/bin/auth/common.h
-b10_recurse_SOURCES += main.cc
-b10_recurse_LDADD =  $(top_builddir)/src/lib/dns/libdns++.la
-b10_recurse_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-b10_recurse_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-b10_recurse_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-b10_recurse_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-b10_recurse_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-b10_recurse_LDADD += $(top_builddir)/src/lib/log/liblog.la
-b10_recurse_LDADD += $(top_builddir)/src/bin/auth/change_user.o
-b10_recurse_LDFLAGS = -pthread
-
-# TODO: config.h.in is wrong because doesn't honor pkgdatadir
-# and can't use @datadir@ because doesn't expand default ${prefix}
-b10_recursedir = $(DESTDIR)$(pkgdatadir)
-b10_recurse_DATA = recurse.spec
-

+ 57 - 0
src/bin/resolver/Makefile.am

@@ -0,0 +1,57 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiolink
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+
+CLEANFILES = *.gcno *.gcda resolver.spec spec_config.h
+
+man_MANS = b10-resolver.8
+EXTRA_DIST = $(man_MANS) b10-resolver.xml
+
+if ENABLE_MAN
+
+b10-resolver.8: b10-resolver.xml
+	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-resolver.xml
+
+endif
+
+resolver.spec: resolver.spec.pre
+	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" resolver.spec.pre >$@
+
+spec_config.h: spec_config.h.pre
+	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@
+
+BUILT_SOURCES = spec_config.h 
+pkglibexec_PROGRAMS = b10-resolver
+b10_resolver_SOURCES = resolver.cc resolver.h
+b10_resolver_SOURCES += $(top_builddir)/src/bin/auth/change_user.h
+b10_resolver_SOURCES += $(top_builddir)/src/bin/auth/common.h
+b10_resolver_SOURCES += main.cc
+b10_resolver_LDADD =  $(top_builddir)/src/lib/dns/libdns++.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/log/liblog.la
+b10_resolver_LDADD += $(top_builddir)/src/bin/auth/change_user.o
+b10_resolver_LDFLAGS = -pthread
+
+# TODO: config.h.in is wrong because doesn't honor pkgdatadir
+# and can't use @datadir@ because doesn't expand default ${prefix}
+b10_resolverdir = $(DESTDIR)$(pkgdatadir)
+b10_resolver_DATA = resolver.spec
+

+ 10 - 10
src/bin/recurse/b10-recurse.8

@@ -1,13 +1,13 @@
 '\" t
-.\"     Title: b10-recurse
+.\"     Title: b10-resolver
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: December 27, 2010
+.\"      Date: January 3, 2011
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-RECURSE" "8" "December 27, 2010" "BIND10" "BIND10"
+.TH "B10\-RESOLVER" "8" "January 3, 2011" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -19,14 +19,14 @@
 .\" * MAIN CONTENT STARTS HERE *
 .\" -----------------------------------------------------------------
 .SH "NAME"
-b10-recurse \- Recursive DNS server
+b10-resolver \- Recursive DNS server
 .SH "SYNOPSIS"
-.HP \w'\fBb10\-recurse\fR\ 'u
-\fBb10\-recurse\fR [\fB\-u\ \fR\fB\fIusername\fR\fR] [\fB\-v\fR]
+.HP \w'\fBb10\-resolver\fR\ 'u
+\fBb10\-resolver\fR [\fB\-u\ \fR\fB\fIusername\fR\fR] [\fB\-v\fR]
 .SH "DESCRIPTION"
 .PP
 The
-\fBb10\-recurse\fR
+\fBb10\-resolver\fR
 daemon provides the BIND 10 recursive DNS server\&. Normally it is started by the
 \fBbind10\fR(8)
 boss process\&.
@@ -34,7 +34,7 @@ boss process\&.
 This daemon communicates with other BIND 10 components over a
 \fBb10-msgq\fR(8)
 C\-Channel connection\&. If this connection is not established,
-\fBb10\-recurse\fR
+\fBb10\-resolver\fR
 will exit\&.
 .PP
 It also receives its configurations from
@@ -63,7 +63,7 @@ The arguments are as follows:
 \fB\-u \fR\fB\fIusername\fR\fR
 .RS 4
 The user name of the
-\fBb10\-recurse\fR
+\fBb10\-resolver\fR
 daemon\&. If specified, the daemon changes the process owner to the specified user\&. The
 \fIusername\fR
 must be either a valid numeric user ID or a valid user name\&. By default the daemon runs as the user who invokes it\&.
@@ -87,7 +87,7 @@ BIND 10 Guide\&.
 .SH "HISTORY"
 .PP
 The
-\fBb10\-recurse\fR
+\fBb10\-resolver\fR
 daemon was first coded in September 2010\&.
 .SH "COPYRIGHT"
 .br

+ 8 - 8
src/bin/recurse/b10-recurse.xml

@@ -21,17 +21,17 @@
 <refentry>
 
   <refentryinfo>
-    <date>December 27, 2010</date>
+    <date>January 3, 2011</date>
   </refentryinfo>
 
   <refmeta>
-    <refentrytitle>b10-recurse</refentrytitle>
+    <refentrytitle>b10-resolver</refentrytitle>
     <manvolnum>8</manvolnum>
     <refmiscinfo>BIND10</refmiscinfo>
   </refmeta>
 
   <refnamediv>
-    <refname>b10-recurse</refname>
+    <refname>b10-resolver</refname>
     <refpurpose>Recursive DNS server</refpurpose>
   </refnamediv>
 
@@ -44,7 +44,7 @@
 
   <refsynopsisdiv>
     <cmdsynopsis>
-      <command>b10-recurse</command>
+      <command>b10-resolver</command>
       <arg><option>-u <replaceable>username</replaceable></option></arg>
       <arg><option>-v</option></arg>
     </cmdsynopsis>
@@ -52,7 +52,7 @@
 
   <refsect1>
     <title>DESCRIPTION</title>
-    <para>The <command>b10-recurse</command> daemon provides the BIND 10
+    <para>The <command>b10-resolver</command> daemon provides the BIND 10
       recursive DNS server.  Normally it is started by the
       <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       boss process.
@@ -62,7 +62,7 @@
       This daemon communicates with other BIND 10 components over a
       <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       C-Channel connection.  If this connection is not established,
-      <command>b10-recurse</command> will exit.
+      <command>b10-resolver</command> will exit.
     </para>
 
     <para>
@@ -89,7 +89,7 @@
         <term><option>-u <replaceable>username</replaceable></option></term>
         <listitem>
 	  <para>
-	    The user name of the <command>b10-recurse</command> daemon.
+	    The user name of the <command>b10-resolver</command> daemon.
 	    If specified, the daemon changes the process owner to the
 	    specified user.
 	    The <replaceable>username</replaceable> must be either a
@@ -141,7 +141,7 @@
   <refsect1>
     <title>HISTORY</title>
     <para>
-      The <command>b10-recurse</command> daemon was first coded in
+      The <command>b10-resolver</command> daemon was first coded in
       September 2010.
     </para>
   </refsect1>

+ 16 - 16
src/bin/recurse/main.cc

@@ -44,8 +44,8 @@
 #include <auth/change_user.h>
 #include <auth/common.h>
 
-#include <recurse/spec_config.h>
-#include <recurse/recursor.h>
+#include <resolver/spec_config.h>
+#include <resolver/resolver.h>
 
 #include <log/dummylog.h>
 
@@ -59,14 +59,14 @@ using namespace asiolink;
 namespace {
 
 // Default port current 5300 for testing purposes
-static const string PROGRAM = "Recurse";
+static const string PROGRAM = "Resolver";
 
 IOService io_service;
-static Recursor *recursor;
+static Resolver *resolver;
 
 ConstElementPtr
 my_config_handler(ConstElementPtr new_config) {
-    return (recursor->updateConfig(new_config));
+    return (resolver->updateConfig(new_config));
 }
 
 ConstElementPtr
@@ -86,7 +86,7 @@ my_command_handler(const string& command, ConstElementPtr args) {
 
 void
 usage() {
-    cerr << "Usage:  b10-recurse [-u user] [-v]" << endl;
+    cerr << "Usage:  b10-resolver [-u user] [-v]" << endl;
     cerr << "\t-u: change process UID to the specified user" << endl;
     cerr << "\t-v: verbose output" << endl;
     exit(1);
@@ -95,7 +95,7 @@ usage() {
 
 int
 main(int argc, char* argv[]) {
-    isc::log::dprefix = "b10-recurse";
+    isc::log::dprefix = "b10-resolver";
     int ch;
     const char* uid = NULL;
 
@@ -133,21 +133,21 @@ main(int argc, char* argv[]) {
         string specfile;
         if (getenv("B10_FROM_BUILD")) {
             specfile = string(getenv("B10_FROM_BUILD")) +
-                "/src/bin/recurse/recurse.spec";
+                "/src/bin/resolver/resolver.spec";
         } else {
-            specfile = string(RECURSE_SPECFILE_LOCATION);
+            specfile = string(RESOLVER_SPECFILE_LOCATION);
         }
 
-        recursor = new Recursor();
+        resolver = new Resolver();
         dlog("Server created.");
 
-        SimpleCallback* checkin = recursor->getCheckinProvider();
-        DNSLookup* lookup = recursor->getDNSLookupProvider();
-        DNSAnswer* answer = recursor->getDNSAnswerProvider();
+        SimpleCallback* checkin = resolver->getCheckinProvider();
+        DNSLookup* lookup = resolver->getDNSLookupProvider();
+        DNSAnswer* answer = resolver->getDNSAnswerProvider();
 
         DNSService dns_service(io_service, checkin, lookup, answer);
 
-        recursor->setDNSService(dns_service);
+        resolver->setDNSService(dns_service);
         dlog("IOService created.");
 
         cc_session = new Session(io_service.get_io_service());
@@ -163,7 +163,7 @@ main(int argc, char* argv[]) {
             changeUser(uid);
         }
 
-        recursor->setConfigSession(config_session);
+        resolver->setConfigSession(config_session);
         dlog("Config loaded");
 
         dlog("Server started.");
@@ -175,7 +175,7 @@ main(int argc, char* argv[]) {
 
     delete config_session;
     delete cc_session;
-    delete recursor;
+    delete resolver;
 
     return (ret);
 }

+ 30 - 30
src/bin/recurse/recursor.cc

@@ -45,7 +45,7 @@
 
 #include <log/dummylog.h>
 
-#include <recurse/recursor.h>
+#include <resolver/resolver.h>
 
 using namespace std;
 
@@ -58,18 +58,18 @@ using namespace asiolink;
 
 typedef pair<string, uint16_t> addr_t;
 
-class RecursorImpl {
+class ResolverImpl {
 private:
     // prohibit copy
-    RecursorImpl(const RecursorImpl& source);
-    RecursorImpl& operator=(const RecursorImpl& source);
+    ResolverImpl(const ResolverImpl& source);
+    ResolverImpl& operator=(const ResolverImpl& source);
 public:
-    RecursorImpl() :
+    ResolverImpl() :
         config_session_(NULL),
         rec_query_(NULL)
     {}
 
-    ~RecursorImpl() {
+    ~ResolverImpl() {
         queryShutdown();
     }
 
@@ -112,7 +112,7 @@ public:
     /// Currently non-configurable, but will be.
     static const uint16_t DEFAULT_LOCAL_UDPSIZE = 4096;
 
-    /// These members are public because Recursor accesses them directly.
+    /// These members are public because Resolver accesses them directly.
     ModuleCCSession* config_session_;
     /// Addresses of the forward nameserver
     vector<addr_t> upstream_;
@@ -201,10 +201,10 @@ makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
 
 // This is a derived class of \c DNSLookup, to serve as a
 // callback in the asiolink module.  It calls
-// Recursor::processMessage() on a single DNS message.
+// Resolver::processMessage() on a single DNS message.
 class MessageLookup : public DNSLookup {
 public:
-    MessageLookup(Recursor* srv) : server_(srv) {}
+    MessageLookup(Resolver* srv) : server_(srv) {}
 
     // \brief Handle the DNS Lookup
     virtual void operator()(const IOMessage& io_message, MessagePtr message,
@@ -213,7 +213,7 @@ public:
         server_->processMessage(io_message, message, buffer, server);
     }
 private:
-    Recursor* server_;
+    Resolver* server_;
 };
 
 // This is a derived class of \c DNSAnswer, to serve as a
@@ -300,50 +300,50 @@ public:
 // configuration messages, and executes them if found.
 class ConfigCheck : public SimpleCallback {
 public:
-    ConfigCheck(Recursor* srv) : server_(srv) {}
+    ConfigCheck(Resolver* srv) : server_(srv) {}
     virtual void operator()(const IOMessage&) const {
         if (server_->getConfigSession()->hasQueuedMsgs()) {
             server_->getConfigSession()->checkCommand();
         }
     }
 private:
-    Recursor* server_;
+    Resolver* server_;
 };
 
-Recursor::Recursor() :
-    impl_(new RecursorImpl()),
+Resolver::Resolver() :
+    impl_(new ResolverImpl()),
     checkin_(new ConfigCheck(this)),
     dns_lookup_(new MessageLookup(this)),
     dns_answer_(new MessageAnswer)
 {}
 
-Recursor::~Recursor() {
+Resolver::~Resolver() {
     delete impl_;
     delete checkin_;
     delete dns_lookup_;
     delete dns_answer_;
-    dlog("Deleting the Recursor");
+    dlog("Deleting the Resolver");
 }
 
 void
-Recursor::setDNSService(asiolink::DNSService& dnss) {
+Resolver::setDNSService(asiolink::DNSService& dnss) {
     impl_->queryShutdown();
     impl_->querySetup(dnss);
     dnss_ = &dnss;
 }
 
 void
-Recursor::setConfigSession(ModuleCCSession* config_session) {
+Resolver::setConfigSession(ModuleCCSession* config_session) {
     impl_->config_session_ = config_session;
 }
 
 ModuleCCSession*
-Recursor::getConfigSession() const {
+Resolver::getConfigSession() const {
     return (impl_->config_session_);
 }
 
 void
-Recursor::processMessage(const IOMessage& io_message, MessagePtr message,
+Resolver::processMessage(const IOMessage& io_message, MessagePtr message,
                         OutputBufferPtr buffer, DNSServer* server)
 {
     dlog("Got a DNS message");
@@ -422,7 +422,7 @@ Recursor::processMessage(const IOMessage& io_message, MessagePtr message,
 }
 
 void
-RecursorImpl::processNormalQuery(const Question& question, MessagePtr message,
+ResolverImpl::processNormalQuery(const Question& question, MessagePtr message,
                                  OutputBufferPtr buffer, DNSServer* server)
 {
     dlog("Processing normal query");
@@ -435,7 +435,7 @@ RecursorImpl::processNormalQuery(const Question& question, MessagePtr message,
     if (edns) {
         EDNSPtr edns_response(new EDNS());
         edns_response->setDNSSECAwareness(dnssec_ok);
-        edns_response->setUDPSize(RecursorImpl::DEFAULT_LOCAL_UDPSIZE);
+        edns_response->setUDPSize(ResolverImpl::DEFAULT_LOCAL_UDPSIZE);
         message->setEDNS(edns_response);
     }
     rec_query_->sendQuery(question, buffer, server);
@@ -482,7 +482,7 @@ parseAddresses(ConstElementPtr addresses) {
 }
 
 ConstElementPtr
-Recursor::updateConfig(ConstElementPtr config) {
+Resolver::updateConfig(ConstElementPtr config) {
     dlog("New config comes: " + config->toWire());
 
     try {
@@ -531,18 +531,18 @@ Recursor::updateConfig(ConstElementPtr config) {
 }
 
 void
-Recursor::setForwardAddresses(const vector<addr_t>& addresses)
+Resolver::setForwardAddresses(const vector<addr_t>& addresses)
 {
     impl_->setForwardAddresses(addresses, dnss_);
 }
 
 bool
-Recursor::isForwarding() const {
+Resolver::isForwarding() const {
     return (!impl_->upstream_.empty());
 }
 
 vector<addr_t>
-Recursor::getForwardAddresses() const {
+Resolver::getForwardAddresses() const {
     return (impl_->upstream_);
 }
 
@@ -559,7 +559,7 @@ setAddresses(DNSService *service, const vector<addr_t>& addresses) {
 }
 
 void
-Recursor::setListenAddresses(const vector<addr_t>& addresses) {
+Resolver::setListenAddresses(const vector<addr_t>& addresses) {
     try {
         dlog("Setting listen addresses:");
         BOOST_FOREACH(const addr_t& addr, addresses) {
@@ -591,7 +591,7 @@ Recursor::setListenAddresses(const vector<addr_t>& addresses) {
 }
 
 void
-Recursor::setTimeouts(int timeout, unsigned retries) {
+Resolver::setTimeouts(int timeout, unsigned retries) {
     dlog("Setting timeout to " + boost::lexical_cast<string>(timeout) +
         " and retry count to " + boost::lexical_cast<string>(retries));
     impl_->timeout_ = timeout;
@@ -600,11 +600,11 @@ Recursor::setTimeouts(int timeout, unsigned retries) {
     impl_->querySetup(*dnss_);
 }
 pair<int, unsigned>
-Recursor::getTimeouts() const {
+Resolver::getTimeouts() const {
     return (pair<int, unsigned>(impl_->timeout_, impl_->retries_));
 }
 
 vector<addr_t>
-Recursor::getListenAddresses() const {
+Resolver::getListenAddresses() const {
     return (impl_->listen_);
 }

+ 11 - 11
src/bin/recurse/recursor.h

@@ -14,8 +14,8 @@
 
 // $Id$
 
-#ifndef __RECURSOR_H
-#define __RECURSOR_H 1
+#ifndef __RESOLVER_H
+#define __RESOLVER_H 1
 
 #include <string>
 #include <vector>
@@ -26,7 +26,7 @@
 
 #include <asiolink/asiolink.h>
 
-class RecursorImpl;
+class ResolverImpl;
 
 /**
  * \short The recursive nameserver.
@@ -37,7 +37,7 @@ class RecursorImpl;
  * answer. It doesn't really know about chasing referrals and similar, it
  * simply plugs the parts that know into the network handling code.
  */
-class Recursor {
+class Resolver {
     ///
     /// \name Constructors, Assignment Operator and Destructor.
     ///
@@ -45,12 +45,12 @@ class Recursor {
     /// intentionally defined as private.
     //@{
 private:
-    Recursor(const Recursor& source);
-    Recursor& operator=(const Recursor& source);
+    Resolver(const Resolver& source);
+    Resolver& operator=(const Resolver& source);
 public:
     /// The constructor.
-    Recursor();
-    ~Recursor();
+    Resolver();
+    ~Resolver();
     //@}
 
     /// \brief Process an incoming DNS message, then signal 'server' to resume 
@@ -76,7 +76,7 @@ public:
     /// \brief Handle commands from the config session
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
 
-    /// \brief Assign an ASIO IO Service queue to this Recursor object
+    /// \brief Assign an ASIO IO Service queue to this Resolver object
     void setDNSService(asiolink::DNSService& dnss);
 
     /// \brief Return this object's ASIO IO Service queue
@@ -137,14 +137,14 @@ public:
     std::pair<int, unsigned> getTimeouts() const;
 
 private:
-    RecursorImpl* impl_;
+    ResolverImpl* impl_;
     asiolink::DNSService* dnss_;
     asiolink::SimpleCallback* checkin_;
     asiolink::DNSLookup* dns_lookup_;
     asiolink::DNSAnswer* dns_answer_;
 };
 
-#endif // __RECURSOR_H
+#endif // __RESOLVER_H
 
 // Local Variables: 
 // mode: c++

+ 1 - 1
src/bin/recurse/recurse.spec.pre.in

@@ -1,6 +1,6 @@
 {
   "module_spec": {
-    "module_name": "Recurse",
+    "module_name": "Resolver",
     "module_description": "Recursive service",
     "config_data": [
       {

+ 1 - 1
src/bin/recurse/spec_config.h.pre.in

@@ -12,4 +12,4 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#define RECURSE_SPECFILE_LOCATION "@prefix@/share/@PACKAGE@/recurse.spec"
+#define RESOLVER_SPECFILE_LOCATION "@prefix@/share/@PACKAGE@/resolver.spec"

+ 4 - 3
src/bin/recurse/tests/Makefile.am

@@ -19,14 +19,15 @@ if HAVE_GTEST
 TESTS += run_unittests
 run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
 run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
-run_unittests_SOURCES += ../recursor.h ../recursor.cc
-run_unittests_SOURCES += recursor_unittest.cc
-run_unittests_SOURCES += recursor_config_unittest.cc
+run_unittests_SOURCES += ../resolver.h ../resolver.cc
+run_unittests_SOURCES += resolver_unittest.cc
+run_unittests_SOURCES += resolver_config_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 += $(SQLITE_LIBS)
+run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libdatasrc.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la

+ 30 - 16
src/bin/recurse/tests/recursor_config_unittest.cc

@@ -12,18 +12,32 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// $Id$
+#include <string>
 
-#include <recurse/recursor.h>
-#include <testutils/srv_unittest.h>
+#include <gtest/gtest.h>
+
+#include <cc/data.h>
+
+#include <asiolink/asiolink.h>
+
+#include <resolver/resolver.h>
+
+#include <dns/tests/unittest_util.h>
+#include <testutils/srv_test.h>
+
+using namespace std;
+using namespace isc::data;
+using namespace isc::testutils;
+using namespace asiolink;
+using isc::UnitTestUtil;
 
 namespace {
-class RecursorConfig : public ::testing::Test {
+class ResolverConfig : public ::testing::Test {
     public:
         IOService ios;
         DNSService dnss;
-        Recursor server;
-        RecursorConfig() :
+        Resolver server;
+        ResolverConfig() :
             dnss(ios, NULL, NULL, NULL)
         {
             server.setDNSService(dnss);
@@ -31,7 +45,7 @@ class RecursorConfig : public ::testing::Test {
         void invalidTest(const string &JOSN);
 };
 
-TEST_F(RecursorConfig, forwardAddresses) {
+TEST_F(ResolverConfig, forwardAddresses) {
     // Default value should be fully recursive
     EXPECT_TRUE(server.getForwardAddresses().empty());
     EXPECT_FALSE(server.isForwarding());
@@ -55,7 +69,7 @@ TEST_F(RecursorConfig, forwardAddresses) {
     EXPECT_FALSE(server.isForwarding());
 }
 
-TEST_F(RecursorConfig, forwardAddressConfig) {
+TEST_F(ResolverConfig, forwardAddressConfig) {
     // Try putting there some address
     ElementPtr config(Element::fromJSON("{"
         "\"forward_addresses\": ["
@@ -83,13 +97,13 @@ TEST_F(RecursorConfig, forwardAddressConfig) {
 }
 
 void
-RecursorConfig::invalidTest(const string &JOSN) {
+ResolverConfig::invalidTest(const string &JOSN) {
     ElementPtr config(Element::fromJSON(JOSN));
     EXPECT_FALSE(server.updateConfig(config)->equals(
         *isc::config::createAnswer())) << "Accepted config " << JOSN << endl;
 }
 
-TEST_F(RecursorConfig, invalidForwardAddresses) {
+TEST_F(ResolverConfig, invalidForwardAddresses) {
     // Try torturing it with some invalid inputs
     invalidTest("{"
         "\"forward_addresses\": \"error\""
@@ -114,7 +128,7 @@ TEST_F(RecursorConfig, invalidForwardAddresses) {
         "}]}");
 }
 
-TEST_F(RecursorConfig, listenAddresses) {
+TEST_F(ResolverConfig, listenAddresses) {
     // Default value should be fully recursive
     EXPECT_TRUE(server.getListenAddresses().empty());
 
@@ -135,7 +149,7 @@ TEST_F(RecursorConfig, listenAddresses) {
     EXPECT_TRUE(server.getListenAddresses().empty());
 }
 
-TEST_F(RecursorConfig, DISABLED_listenAddressConfig) {
+TEST_F(ResolverConfig, DISABLED_listenAddressConfig) {
     // Try putting there some address
     ElementPtr config(Element::fromJSON("{"
         "\"listen_on\": ["
@@ -171,7 +185,7 @@ TEST_F(RecursorConfig, DISABLED_listenAddressConfig) {
     EXPECT_EQ(5300, server.getListenAddresses()[0].second);
 }
 
-TEST_F(RecursorConfig, invalidListenAddresses) {
+TEST_F(ResolverConfig, invalidListenAddresses) {
     // Try torturing it with some invalid inputs
     invalidTest("{"
         "\"listen_on\": \"error\""
@@ -197,7 +211,7 @@ TEST_F(RecursorConfig, invalidListenAddresses) {
 }
 
 // Just test it sets and gets the values correctly
-TEST_F(RecursorConfig, timeouts) {
+TEST_F(ResolverConfig, timeouts) {
     server.setTimeouts(0, 1);
     EXPECT_EQ(0, server.getTimeouts().first);
     EXPECT_EQ(1, server.getTimeouts().second);
@@ -206,7 +220,7 @@ TEST_F(RecursorConfig, timeouts) {
     EXPECT_EQ(0, server.getTimeouts().second);
 }
 
-TEST_F(RecursorConfig, timeoutsConfig) {
+TEST_F(ResolverConfig, timeoutsConfig) {
     ElementPtr config = Element::fromJSON("{"
             "\"timeout\": 1000,"
             "\"retries\": 3"
@@ -217,7 +231,7 @@ TEST_F(RecursorConfig, timeoutsConfig) {
     EXPECT_EQ(3, server.getTimeouts().second);
 }
 
-TEST_F(RecursorConfig, invalidTimeoutsConfig) {
+TEST_F(ResolverConfig, invalidTimeoutsConfig) {
     invalidTest("{"
         "\"timeout\": \"error\""
         "}");

+ 33 - 24
src/bin/recurse/tests/recursor_unittest.cc

@@ -12,62 +12,71 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// $Id$
+#include <dns/name.h>
 
-#include <recurse/recursor.h>
-#include <testutils/srv_unittest.h>
+#include <resolver/resolver.h>
+#include <dns/tests/unittest_util.h>
+#include <testutils/srv_test.h>
+
+using namespace isc::dns;
+using namespace isc::testutils;
+using isc::UnitTestUtil;
 
 namespace {
 const char* const TEST_PORT = "53535";
 
-class RecursorTest : public SrvTestBase{
+class ResolverTest : public SrvTestBase{
 protected:
-    RecursorTest() : server(){}
-    Recursor server;
+    ResolverTest() : server(){}
+    virtual void processMessage() {
+        server.processMessage(*io_message, parse_message, response_obuffer,
+                              &dnsserv);
+    }
+    Resolver server;
 };
 
 // Unsupported requests.  Should result in NOTIMP.
-TEST_F(RecursorTest, unsupportedRequest) {
-    UNSUPPORTED_REQUEST_TEST;
+TEST_F(ResolverTest, unsupportedRequest) {
+    unsupportedRequest();
 }
 
 // Multiple questions.  Should result in FORMERR.
-TEST_F(RecursorTest, multiQuestion) {
-    MULTI_QUESTION_TEST; 
+TEST_F(ResolverTest, multiQuestion) {
+    multiQuestion(); 
 }
 
 // Incoming data doesn't even contain the complete header.  Must be silently
 // dropped.
-TEST_F(RecursorTest, shortMessage) {
-    SHORT_MESSAGE_TEST;
+TEST_F(ResolverTest, shortMessage) {
+    shortMessage();
 }
 
 // Response messages.  Must be silently dropped, whether it's a valid response
 // or malformed or could otherwise cause a protocol error.
-TEST_F(RecursorTest, response) {
-    RESPONSE_TEST;
+TEST_F(ResolverTest, response) {
+     response();
 }
 
 // Query with a broken question
-TEST_F(RecursorTest, shortQuestion) {
-    SHORT_QUESTION_TEST;
+TEST_F(ResolverTest, shortQuestion) {
+    shortQuestion();
 }
 
 // Query with a broken answer section
-TEST_F(RecursorTest, shortAnswer) {
-    SHORT_ANSWER_TEST;
+TEST_F(ResolverTest, shortAnswer) {
+    shortAnswer();
 }
 
 // Query with unsupported version of EDNS.
-TEST_F(RecursorTest, ednsBadVers) {
-    EDNS_BADVERS_TEST;
+TEST_F(ResolverTest, ednsBadVers) {
+    ednsBadVers();
 }
 
-TEST_F(RecursorTest, AXFROverUDP) {
-    AXFR_OVER_UDP_TEST;
+TEST_F(ResolverTest, AXFROverUDP) {
+    axfrOverUDP();
 }
 
-TEST_F(RecursorTest, AXFRFail) {
+TEST_F(ResolverTest, AXFRFail) {
     UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
                                        Name("example.com"), RRClass::IN(),
                                        RRType::AXFR());
@@ -79,7 +88,7 @@ TEST_F(RecursorTest, AXFRFail) {
                 QR_FLAG, 1, 0, 0, 0);
 }
 
-TEST_F(RecursorTest, notifyFail) {
+TEST_F(ResolverTest, notifyFail) {
     // Notify should always return NOTAUTH
     request_message.clear(Message::RENDER);
     request_message.setOpcode(Opcode::NOTIFY());

src/bin/recurse/tests/run_unittests.cc → src/bin/resolver/tests/run_unittests.cc


+ 1 - 1
src/lib/asiolink/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . tests internal
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += $(BOOST_INCLUDES)

+ 1 - 1
src/lib/asiolink/README

@@ -17,7 +17,7 @@ including:
     leaving it in place elsewhere.
 
 Currently, the asiolink library only supports DNS servers (i.e., b10-auth
-and b10-recurse).  The plan is to make it more generic and allow it to
+and b10-resolver).  The plan is to make it more generic and allow it to
 support other modules as well.
 
 Some of the classes defined here--for example, IOSocket, IOEndpoint,

+ 1 - 1
src/lib/asiolink/asiolink.h

@@ -77,7 +77,7 @@ class io_service;
 ///
 /// Notes to developers:
 /// Currently the wrapper interface is fairly specific to use by a
-/// DNS server, i.e., b10-auth or b10-recurse.  But the plan is to
+/// DNS server, i.e., b10-auth or b10-resolver.  But the plan is to
 /// generalize it and have other modules use it as well.
 ///
 /// One obvious drawback of this approach is performance overhead

+ 1 - 0
src/lib/asiolink/internal/Makefile.am

@@ -0,0 +1 @@
+SUBDIRS = tests

+ 37 - 0
src/lib/asiolink/internal/tests/Makefile.am

@@ -0,0 +1,37 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = udpdns_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/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+run_unittests_CXXFLAGS += -Wno-unused-parameter
+endif
+if USE_CLANGPP
+# We need to disable -Werror for any test that uses internal definitions of
+# ASIO when using clang++
+run_unittests_CXXFLAGS += -Wno-error
+endif
+endif
+
+noinst_PROGRAMS = $(TESTS)

+ 21 - 0
src/lib/asiolink/internal/tests/run_unittests.cc

@@ -0,0 +1,21 @@
+// 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.
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return (RUN_ALL_TESTS());
+}

src/lib/asiolink/tests/udpdns_unittest.cc → src/lib/asiolink/internal/tests/udpdns_unittest.cc


+ 0 - 1
src/lib/asiolink/tests/Makefile.am

@@ -18,7 +18,6 @@ TESTS += run_unittests
 run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
 run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
 run_unittests_SOURCES += asiolink_unittest.cc
-run_unittests_SOURCES += udpdns_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

+ 72 - 40
src/lib/asiolink/tests/asiolink_unittest.cc

@@ -17,6 +17,9 @@
 
 #include <config.h>
 
+#include <sys/socket.h>
+#include <sys/time.h>
+
 #include <string.h>
 
 #include <boost/lexical_cast.hpp>
@@ -32,19 +35,21 @@
 #include <dns/buffer.h>
 #include <dns/message.h>
 
+// IMPORTANT: We shouldn't directly use ASIO definitions in this test.
+// In particular, we must not include asio.hpp in this file.
+// The asiolink module is primarily intended to be a wrapper that hide the
+// details of the underlying implementations.  We need to test the wrapper
+// level behaviors.  In addition, some compilers reject to compile this file
+// if we include asio.hpp unless we specify a special compiler option.
+// If we need to test something at the level of underlying ASIO and need
+// their definition, that test should go to asiolink/internal/tests.
 #include <asiolink/asiolink.h>
 #include <asiolink/iosocket.h>
-#include <asiolink/internal/tcpdns.h>
-#include <asiolink/internal/udpdns.h>
-
-#include <asio.hpp>
 
 using isc::UnitTestUtil;
 using namespace std;
 using namespace asiolink;
 using namespace isc::dns;
-using namespace asio;
-using asio::ip::udp;
 
 namespace {
 const char* const TEST_SERVER_PORT = "53535";
@@ -330,10 +335,30 @@ protected:
         // ... and this one will block until the send has completed
         io_service_->run_one();
 
-        // Now we attempt to recv() whatever was sent
-        const int ret = recv(sock_, buffer, size, MSG_DONTWAIT);
+        // Now we attempt to recv() whatever was sent.
+        // XXX: there's no guarantee the receiving socket can immediately get
+        // the packet.  Normally we can perform blocking recv to wait for it,
+        // but in theory it's even possible that the packet is lost.
+        // In order to prevent the test from hanging in such a worst case
+        // we add an ad hoc timeout.
+        const struct timeval timeo = { 10, 0 };
+        int recv_options = 0;
+        if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo,
+                       sizeof(timeo))) {
+            if (errno == ENOPROTOOPT) {
+                // Workaround for Solaris: it doesn't accept SO_RCVTIMEO
+                // with the error of ENOPROTOOPT.  Since this is a workaround
+                // for rare error cases anyway, we simply switch to the
+                // "don't wait" mode.  If we still find an error in recv()
+                // can happen often we'll consider a more complete solution.
+                recv_options = MSG_DONTWAIT;
+            } else {
+                isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
+            }
+        }
+        const int ret = recv(sock_, buffer, size, recv_options);
         if (ret < 0) {
-            isc_throw(IOError, "recvfrom failed");
+            isc_throw(IOError, "recvfrom failed: " << strerror(errno));
         }
         
         // Pass the message size back via the size parameter
@@ -411,8 +436,7 @@ protected:
     // has completed.
     class MockServer : public DNSServer {
     public:
-        explicit MockServer(asio::io_service& io_service,
-                            const asio::ip::address& addr, const uint16_t port,
+        explicit MockServer(IOService& io_service,
                             SimpleCallback* checkin = NULL,
                             DNSLookup* lookup = NULL,
                             DNSAnswer* answer = NULL) :
@@ -426,9 +450,7 @@ protected:
                         size_t length = 0)
         {}
 
-        void resume(const bool done) {
-            done_ = done;
-            io_.post(*this);
+        void resume(const bool) { // in our test this shouldn't be called
         }
 
         DNSServer* clone() {
@@ -443,7 +465,7 @@ protected:
         }
 
     protected:
-        asio::io_service& io_;
+        IOService& io_;
         bool done_;
 
     private:
@@ -462,8 +484,8 @@ protected:
     // This version of mock server just stops the io_service when it is resumed
     class MockServerStop : public MockServer {
         public:
-            explicit MockServerStop(asio::io_service& io_service, bool* done) :
-                MockServer(io_service, asio::ip::address(), 0),
+            explicit MockServerStop(IOService& io_service, bool* done) :
+                MockServer(io_service),
                 done_(done)
             {}
 
@@ -511,7 +533,6 @@ protected:
     string callback_address_;
     vector<uint8_t> callback_data_;
     int sock_;
-private:
     struct addrinfo* res_;
 };
 
@@ -640,14 +661,12 @@ TEST_F(ASIOLinkTest, recursiveSetupV6) {
 // full code coverage including error cases.
 TEST_F(ASIOLinkTest, recursiveSend) {
     setDNSService(true, false);
-    asio::io_service& io = io_service_->get_io_service();
 
     // Note: We use the test prot plus one to ensure we aren't binding
     // to the same port as the actual server
     uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
-    asio::ip::address addr = asio::ip::address::from_string(TEST_IPV4_ADDR);
 
-    MockServer server(io, addr, port, NULL, NULL, NULL);
+    MockServer server(*io_service_);
     RecursiveQuery rq(*dns_service_, singleAddress(TEST_IPV4_ADDR, port));
 
     Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
@@ -656,7 +675,7 @@ TEST_F(ASIOLinkTest, recursiveSend) {
 
     char data[4096];
     size_t size = sizeof(data);
-    EXPECT_NO_THROW(recvUDP(AF_INET, data, size));
+    ASSERT_NO_THROW(recvUDP(AF_INET, data, size));
 
     Message m(Message::PARSE);
     InputBuffer ibuf(data, size);
@@ -672,34 +691,27 @@ TEST_F(ASIOLinkTest, recursiveSend) {
     EXPECT_EQ(q.getClass(), q2->getClass());
 }
 
-void
-receive_and_inc(udp::socket* socket, int* num) {
-    (*num) ++;
-    static char inbuff[512];
-    socket->async_receive(asio::buffer(inbuff, 512),
-        boost::bind(receive_and_inc, socket, num));
-}
-
 // Test it tries the correct amount of times before giving up
 TEST_F(ASIOLinkTest, recursiveTimeout) {
     // Prepare the service (we do not use the common setup, we do not answer
     setDNSService();
-    asio::io_service& service = io_service_->get_io_service();
 
     // Prepare the socket
-    uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
-    udp::socket socket(service, udp::v4());
-    socket.set_option(socket_base::reuse_address(true));
-    socket.bind(udp::endpoint(ip::address::from_string(TEST_IPV4_ADDR), port));
-    // And count the answers
-    int num = -1; // One is counted before the receipt of the first one
-    receive_and_inc(&socket, &num);
+    res_ = resolveAddress(AF_INET, IPPROTO_UDP, true);
+    sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
+    if (sock_ < 0) {
+        isc_throw(IOError, "failed to open test socket");
+    }
+    if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
+        isc_throw(IOError, "failed to bind test socket");
+    }
 
     // Prepare the server
     bool done(true);
-    MockServerStop server(service, &done);
+    MockServerStop server(*io_service_, &done);
 
     // Do the answer
+    const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
     RecursiveQuery query(*dns_service_, singleAddress(TEST_IPV4_ADDR, port),
         10, 2);
     Question question(Name("example.net"), RRClass::IN(), RRType::A());
@@ -707,7 +719,27 @@ TEST_F(ASIOLinkTest, recursiveTimeout) {
     query.sendQuery(question, buffer, &server);
 
     // Run the test
-    service.run();
+    io_service_->run();
+
+    // Read up to 3 packets.  Use some ad hoc timeout to prevent an infinite
+    // block (see also recvUDP()).
+    const struct timeval timeo = { 10, 0 };
+    int recv_options = 0;
+    if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
+        if (errno == ENOPROTOOPT) { // see ASIOLinkTest::recvUDP()
+            recv_options = MSG_DONTWAIT;
+        } else {
+            isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
+        }
+    }
+    int num = 0;
+    do {
+        char inbuff[512];
+        if (recv(sock_, inbuff, sizeof(inbuff), recv_options) < 0) {
+            num = -1;
+            break;
+        }
+    } while (++num < 3);
 
     // The query should fail
     EXPECT_FALSE(done);

+ 2 - 2
src/lib/datasrc/cache.h

@@ -81,7 +81,7 @@ class HotCacheImpl;
 /// from the tail of the list.  This operation is not locked.  BIND 10
 /// does not currently use threads, but if it ever does (or if libdatasrc
 /// is ever used by a threaded application), this will need to be
-//revisited.
+/// revisited.
 class HotCache {
 private:
     /// \name Static definitions
@@ -164,7 +164,7 @@ public:
     ///
     /// Retrieves a record from the cache matching the given 
     /// query-tuple.  Returns true if one is found.  If it is a
-    /// posiitve cache entry, then 'rrset' is set to the cached
+    /// positive cache entry, then 'rrset' is set to the cached
     /// RRset.  For both positive and negative cache entries, 'flags'
     /// is set to the query response flags.  The cache entry is 
     /// then promoted to the head of the LRU queue.  (NOTE: Because

+ 2 - 2
src/lib/datasrc/data_source.cc

@@ -103,14 +103,14 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
                                new QueryTask(q, ns.getNSName(),
                                              Message::SECTION_ADDITIONAL,
                                              QueryTask::GLUE_QUERY,
-                                             QueryTask::GETADDITIONAL))); 
+                                             QueryTask::GETADDITIONAL)));
         } else if (rrset->getType() == RRType::MX()) {
             const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
             q.tasks().push(QueryTaskPtr(
                                new QueryTask(q, mx.getMXName(),
                                              Message::SECTION_ADDITIONAL,
                                              QueryTask::NOGLUE_QUERY,
-                                             QueryTask::GETADDITIONAL))); 
+                                             QueryTask::GETADDITIONAL)));
         }
     }
 }

+ 2 - 2
src/lib/datasrc/rbtree.h

@@ -672,7 +672,7 @@ void
 RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
     using namespace helper;
     const isc::dns::Name sub_name = node.name_ - base_name;
-    // using auto_ptr here is to avoid memory leak in case of exceptoin raised
+    // using auto_ptr here is to avoid memory leak in case of exception raised
     // after the RBNode creation
     std::auto_ptr<RBNode<T> > down_node(new RBNode<T>(sub_name));
     std::swap(node.data_, down_node->data_);
@@ -680,7 +680,7 @@ RBTree<T>::nodeFission(RBNode<T>& node, const isc::dns::Name& base_name) {
     down_node->down_ = node.down_;
     node.name_ = base_name;
     node.down_ = down_node.get();
-    //root node of sub tree, the initial color is BLACK
+    // root node of sub tree, the initial color is BLACK
     down_node->color_ = RBNode<T>::BLACK;
     ++node_count_;
     down_node.release();

+ 1 - 1
src/lib/nsas/README

@@ -2,6 +2,6 @@ For an overview of the Nameserver Address Store, see the requirements and design
 documents at http://bind10.isc.org/wiki/Resolver.
 
 At the time of writing (19 October 2010), the file asiolink.h is present in this
-directory only for the purposes of development.  When the recursor's
+directory only for the purposes of development.  When the resolver's
 asynchronous I/O code has been finished, this will be removed and the NSAS will
 use the "real" code.

+ 1 - 1
src/lib/nsas/asiolink.h

@@ -24,7 +24,7 @@ namespace asiolink {
 
 /// \brief IO Address Dummy Class
 ///
-/// As part of ther recursor, Evan has written the asiolink.h file, which
+/// As part of ther resolver, Evan has written the asiolink.h file, which
 /// encapsulates some of the boost::asio classes.  Until these are checked
 /// into trunk and merged with this branch, these dummy classes should fulfill
 /// their function.

+ 10 - 9
src/lib/python/isc/config/module_spec.py

@@ -339,13 +339,14 @@ def _validate_spec_list(module_spec, full, data, errors):
 
     # check if there are items in our data that are not in the
     # specification
-    for item_name in data:
-        found = False
-        for spec_item in module_spec:
-            if spec_item["item_name"] == item_name:
-                found = True
-        if not found:
-            if errors != None:
-                errors.append("unknown item " + item_name)
-            validated = False
+    if data is not None:
+        for item_name in data:
+            found = False
+            for spec_item in module_spec:
+                if spec_item["item_name"] == item_name:
+                    found = True
+            if not found:
+                if errors != None:
+                    errors.append("unknown item " + item_name)
+                validated = False
     return validated

+ 4 - 0
src/lib/python/isc/config/tests/module_spec_test.py

@@ -109,6 +109,9 @@ class TestModuleSpec(unittest.TestCase):
         return dd.validate_command(cmd_name, params)
 
     def test_command_validation(self):
+        # tests for a command that doesn't take an argument
+        self.assertEqual(True, self.read_spec_file("spec2.spec").validate_command("shutdown", None));
+        self.assertEqual(False, self.read_spec_file("spec2.spec").validate_command("shutdown", '{"val": 1}'));
         self.assertEqual(True, self.validate_command_params("spec27.spec", "data22_1.data", 'cmd1'))
         self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_2.data",'cmd1'))
         self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_3.data", 'cmd1'))
@@ -321,6 +324,7 @@ class TestModuleSpec(unittest.TestCase):
                }]
 
         errors = []
+        self.assertEqual(True, isc.config.module_spec._validate_spec_list(spec, True, None, None))
         self.assertEqual(False, isc.config.module_spec._validate_spec_list(spec, True, { 'does_not_exist': 1 }, None))
         self.assertEqual(False, isc.config.module_spec._validate_spec_list(spec, True, { 'does_not_exist': 1 }, errors))
         self.assertEqual(['unknown item does_not_exist'], errors)

+ 12 - 4
src/lib/testutils/Makefile.am

@@ -1,5 +1,13 @@
-SUBDIRS = testdata
+SUBDIRS = . testdata
 
-EXTRA_DIST = srv_test.h
-EXTRA_DIST += srv_unittest.h
-EXTRA_DIST += mockups.h
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS=$(B10_CXXFLAGS)
+
+if HAVE_GTEST
+lib_LTLIBRARIES = libtestutils.la
+
+libtestutils_la_SOURCES = srv_test.h srv_test.cc
+libtestutils_la_SOURCES += mockups.h
+libtestutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+endif

+ 0 - 2
src/lib/testutils/README

@@ -1,4 +1,2 @@
 Here is some code used by more than one test. No code is used for bind10
 itself, only for testing.
-
-As it contains headers only currently, it does not compile here.

+ 272 - 0
src/lib/testutils/srv_test.cc

@@ -0,0 +1,272 @@
+// 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.
+
+#include <netinet/in.h>
+
+#include <dns/message.h>
+#include <dns/rcode.h>
+
+#include <asiolink/asiolink.h>
+
+#include <dns/tests/unittest_util.h>
+
+#include <testutils/srv_test.h>
+
+using namespace isc::dns;
+using namespace asiolink;
+
+namespace isc {
+namespace testutils {
+const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
+
+const unsigned int QR_FLAG = 0x1;
+const unsigned int AA_FLAG = 0x2;
+const unsigned int TC_FLAG = 0x4;
+const unsigned int RD_FLAG = 0x8;
+const unsigned int RA_FLAG = 0x10;
+const unsigned int AD_FLAG = 0x20;
+const unsigned int CD_FLAG = 0x40;
+
+SrvTestBase::SrvTestBase() : request_message(Message::RENDER),
+                             parse_message(new Message(Message::PARSE)),
+                             default_qid(0x1035),
+                             opcode(Opcode(Opcode::QUERY())),
+                             qname("www.example.com"),
+                             qclass(RRClass::IN()),
+                             qtype(RRType::A()), io_sock(NULL),
+                             io_message(NULL), endpoint(NULL),
+                             request_obuffer(0),
+                             request_renderer(request_obuffer),
+                             response_obuffer(new OutputBuffer(0))
+{}
+
+SrvTestBase::~SrvTestBase() {
+    delete io_message;
+    delete endpoint;
+}
+
+void
+SrvTestBase::createDataFromFile(const char* const datafile,
+                                const int protocol)
+{
+    delete io_message;
+    data.clear();
+
+    delete endpoint;
+
+    endpoint = IOEndpoint::create(protocol,
+                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
+    UnitTestUtil::readWireData(datafile, data);
+    io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
+        &IOSocket::getDummyTCPSocket();
+    io_message = new IOMessage(&data[0], data.size(), *io_sock, *endpoint);
+}
+
+void
+SrvTestBase::createRequestPacket(Message& message,
+                                 const int protocol)
+{
+    message.toWire(request_renderer);
+
+    delete io_message;
+
+    endpoint = IOEndpoint::create(protocol,
+                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
+    io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
+        &IOSocket::getDummyTCPSocket();
+    io_message = new IOMessage(request_renderer.getData(),
+                               request_renderer.getLength(),
+                               *io_sock, *endpoint);
+}
+
+// Unsupported requests.  Should result in NOTIMP.
+void
+SrvTestBase::unsupportedRequest() {
+    for (unsigned int i = 0; i < 16; ++i) {
+        // set Opcode to 'i', which iterators over all possible codes except
+        // the standard query and notify 
+        if (i == isc::dns::Opcode::QUERY().getCode() ||
+            i == isc::dns::Opcode::NOTIFY().getCode()) {
+            continue;
+        }
+        createDataFromFile("simplequery_fromWire.wire");
+        data[2] = ((i << 3) & 0xff);
+
+        parse_message->clear(isc::dns::Message::PARSE);
+        processMessage();
+        EXPECT_TRUE(dnsserv.hasAnswer());
+        headerCheck(*parse_message, default_qid, isc::dns::Rcode::NOTIMP(), i,
+                    QR_FLAG, 0, 0, 0, 0);
+    }
+}
+
+// Multiple questions.  Should result in FORMERR.
+void
+SrvTestBase::multiQuestion() {
+    createDataFromFile("multiquestion_fromWire.wire");
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
+                opcode.getCode(), QR_FLAG, 2, 0, 0, 0);
+
+    isc::dns::QuestionIterator qit = parse_message->beginQuestion();
+    EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
+    EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
+    EXPECT_EQ(isc::dns::RRType::A(), (*qit)->getType());
+    ++qit;
+    EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
+    EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
+    EXPECT_EQ(isc::dns::RRType::AAAA(), (*qit)->getType());
+    ++qit;
+    EXPECT_TRUE(qit == parse_message->endQuestion());
+}
+
+// Incoming data doesn't even contain the complete header.  Must be silently
+// dropped.
+void
+SrvTestBase::shortMessage() {
+    createDataFromFile("shortmessage_fromWire");
+    processMessage();
+    EXPECT_FALSE(dnsserv.hasAnswer());
+}
+
+// Response messages.  Must be silently dropped, whether it's a valid response
+// or malformed or could otherwise cause a protocol error.
+void
+SrvTestBase::response() {
+    // A valid (although unusual) response 
+    createDataFromFile("simpleresponse_fromWire.wire");
+    processMessage();
+    EXPECT_FALSE(dnsserv.hasAnswer());
+
+    // A response with a broken question section.  must be dropped rather than
+    //returning FORMERR.
+    createDataFromFile("shortresponse_fromWire");
+    processMessage();
+    EXPECT_FALSE(dnsserv.hasAnswer());
+
+    // A response to iquery.  must be dropped rather than returning NOTIMP.
+    createDataFromFile("iqueryresponse_fromWire.wire");
+    processMessage();
+    EXPECT_FALSE(dnsserv.hasAnswer());
+}
+
+// Query with a broken question
+void
+SrvTestBase::shortQuestion() {
+    createDataFromFile("shortquestion_fromWire");
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    // Since the query's question is broken, the question section of the
+    // response should be empty.
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
+                opcode.getCode(), QR_FLAG, 0, 0, 0, 0);
+}
+
+// Query with a broken answer section
+void
+SrvTestBase::shortAnswer() {
+    createDataFromFile("shortanswer_fromWire.wire");
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+
+    // This is a bogus query, but question section is valid.  So the response
+    // should copy the question section.
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+
+    isc::dns::QuestionIterator qit = parse_message->beginQuestion();
+    EXPECT_EQ(isc::dns::Name("example.com"), (*qit)->getName());
+    EXPECT_EQ(isc::dns::RRClass::IN(), (*qit)->getClass());
+    EXPECT_EQ(isc::dns::RRType::A(), (*qit)->getType());
+    ++qit;
+    EXPECT_TRUE(qit == parse_message->endQuestion());
+}
+
+// Query with unsupported version of EDNS.
+void
+SrvTestBase::ednsBadVers() {
+    createDataFromFile("queryBadEDNS_fromWire.wire");
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+
+    // The response must have an EDNS OPT RR in the additional section,
+    // it will be added automatically at the render time.
+    // Note that the DNSSEC DO bit is cleared even if this bit in the query
+    // is set.  This is a limitation of the current implementation.
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::BADVERS(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 1);
+    EXPECT_FALSE(parse_message->getEDNS()); // EDNS isn't added at this point
+
+    isc::dns::InputBuffer ib(response_obuffer->getData(),
+                             response_obuffer->getLength());
+    isc::dns::Message parsed(isc::dns::Message::PARSE);
+    parsed.fromWire(ib);
+    EXPECT_EQ(isc::dns::Rcode::BADVERS(), parsed.getRcode());
+    isc::dns::ConstEDNSPtr edns(parsed.getEDNS());
+    ASSERT_TRUE(edns);
+    EXPECT_FALSE(edns->getDNSSECAwareness());
+}
+
+void
+SrvTestBase::axfrOverUDP() {
+    // AXFR over UDP is invalid and should result in FORMERR.
+    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
+                                       isc::dns::Name("example.com"),
+                                       isc::dns::RRClass::IN(),
+                                       isc::dns::RRType::AXFR());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    processMessage();
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, isc::dns::Rcode::FORMERR(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
+}
+
+void
+headerCheck(const Message& message, const qid_t qid, const Rcode& rcode,
+            const uint16_t opcodeval, const unsigned int flags,
+            const unsigned int qdcount,
+            const unsigned int ancount, const unsigned int nscount,
+            const unsigned int arcount)
+{
+    EXPECT_EQ(qid, message.getQid());
+    EXPECT_EQ(rcode, message.getRcode());
+    EXPECT_EQ(opcodeval, message.getOpcode().getCode());
+    EXPECT_EQ((flags & QR_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_QR));
+    EXPECT_EQ((flags & AA_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_AA));
+    EXPECT_EQ((flags & TC_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_TC));
+    EXPECT_EQ((flags & RA_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_RA));
+    EXPECT_EQ((flags & RD_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_RD));
+    EXPECT_EQ((flags & AD_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_AD));
+    EXPECT_EQ((flags & CD_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_CD));
+
+    EXPECT_EQ(qdcount, message.getRRCount(Message::SECTION_QUESTION));
+    EXPECT_EQ(ancount, message.getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(nscount, message.getRRCount(Message::SECTION_AUTHORITY));
+    EXPECT_EQ(arcount, message.getRRCount(Message::SECTION_ADDITIONAL));
+}
+} // end of namespace testutils
+} // end of namespace isc
+
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 82 - 126
src/lib/testutils/srv_test.h

@@ -12,10 +12,6 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// $Id: auth_srv_unittest.cc 3310 2010-10-21 23:10:24Z each $
-
-#include <config.h>
-
 #include <gtest/gtest.h>
 
 #include <dns/buffer.h>
@@ -27,139 +23,99 @@
 #include <dns/rrclass.h>
 #include <dns/rrtype.h>
 
-#include <cc/data.h>
-#include <cc/session.h>
-
-#include <xfr/xfrout_client.h>
-
-#include <auth/auth_srv.h>
-#include <asiolink/asiolink.h>
-
-#include <dns/tests/unittest_util.h>
 #include "mockups.h"
 
-using namespace std;
-using namespace isc::cc;
-using namespace isc::dns;
-using namespace isc::data;
-using namespace isc::xfr;
-using namespace asiolink;
-using isc::UnitTestUtil;
-
-namespace {
-const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
-
-// The base class for Auth and Recurse test case
-class SrvTestBase : public ::testing::Test {
-protected:
-    SrvTestBase() : request_message(Message::RENDER),
-                    parse_message(new Message(Message::PARSE)),
-                    default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
-                    qname("www.example.com"), qclass(RRClass::IN()),
-                    qtype(RRType::A()), io_sock(NULL), 
-                    io_message(NULL), endpoint(NULL),
-                    request_obuffer(0), request_renderer(request_obuffer),
-                    response_obuffer(new OutputBuffer(0))
-    {}
-    ~SrvTestBase() {
-        delete io_message;
-        delete endpoint;
-    }
-    MockSession notify_session;
-    MockServer dnsserv;
-    Message request_message;
-    MessagePtr parse_message;
-    const qid_t default_qid;
-    const Opcode opcode;
-    const Name qname;
-    const RRClass qclass;
-    const RRType qtype;
-    IOSocket* io_sock;
-    IOMessage* io_message;
-    const IOEndpoint* endpoint;
-    OutputBuffer request_obuffer;
-    MessageRenderer request_renderer;
-    OutputBufferPtr response_obuffer;
-    vector<uint8_t> data;
-
-    void createDataFromFile(const char* const datafile, int protocol);
-    void createRequestPacket(Message& message, const int protocol);
-};
-
-void
-SrvTestBase::createDataFromFile(const char* const datafile,
-                                const int protocol = IPPROTO_UDP)
-{
-    delete io_message;
-    data.clear();
-
-    delete endpoint;
-
-    endpoint = IOEndpoint::create(protocol,
-                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
-    UnitTestUtil::readWireData(datafile, data);
-    io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
-        &IOSocket::getDummyTCPSocket();
-    io_message = new IOMessage(&data[0], data.size(), *io_sock, *endpoint);
+namespace asiolink {
+class IOSocket;
+class IOMessage;
+class IOEndpoint;
 }
 
-void
-SrvTestBase::createRequestPacket(Message& message,
-                                 const int protocol = IPPROTO_UDP)
-{
-    message.toWire(request_renderer);
-
-    delete io_message;
-
-    endpoint = IOEndpoint::create(protocol,
-                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
-    io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
-        &IOSocket::getDummyTCPSocket();
-    io_message = new IOMessage(request_renderer.getData(),
-                               request_renderer.getLength(),
-                               *io_sock, *endpoint);
-}
+namespace isc {
+namespace testutils {
+extern const char* const DEFAULT_REMOTE_ADDRESS;
 
 // These are flags to indicate whether the corresponding flag bit of the
-// DNS header is to be set in the test cases.  (Note that the flag values
+// DNS header is to be set in the test cases.  (The flag values
 // is irrelevant to their wire-format values)
-const unsigned int QR_FLAG = 0x1;
-const unsigned int AA_FLAG = 0x2;
-const unsigned int TC_FLAG = 0x4;
-const unsigned int RD_FLAG = 0x8;
-const unsigned int RA_FLAG = 0x10;
-const unsigned int AD_FLAG = 0x20;
-const unsigned int CD_FLAG = 0x40;
+extern const unsigned int QR_FLAG;
+extern const unsigned int AA_FLAG;
+extern const unsigned int TC_FLAG;
+extern const unsigned int RD_FLAG;
+extern const unsigned int RA_FLAG;
+extern const unsigned int AD_FLAG;
+extern const unsigned int CD_FLAG;
 
 void
-headerCheck(const Message& message, const qid_t qid, const Rcode& rcode,
+headerCheck(const isc::dns::Message& message, const isc::dns::qid_t qid,
+            const isc::dns::Rcode& rcode,
             const uint16_t opcodeval, const unsigned int flags,
             const unsigned int qdcount,
             const unsigned int ancount, const unsigned int nscount,
-            const unsigned int arcount)
-{
-    EXPECT_EQ(qid, message.getQid());
-    EXPECT_EQ(rcode, message.getRcode());
-    EXPECT_EQ(opcodeval, message.getOpcode().getCode());
-    EXPECT_EQ((flags & QR_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_QR));
-    EXPECT_EQ((flags & AA_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_AA));
-    EXPECT_EQ((flags & TC_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_TC));
-    EXPECT_EQ((flags & RA_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_RA));
-    EXPECT_EQ((flags & RD_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_RD));
-    EXPECT_EQ((flags & AD_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_AD));
-    EXPECT_EQ((flags & CD_FLAG) != 0,
-              message.getHeaderFlag(Message::HEADERFLAG_CD));
+            const unsigned int arcount);
 
-    EXPECT_EQ(qdcount, message.getRRCount(Message::SECTION_QUESTION));
-    EXPECT_EQ(ancount, message.getRRCount(Message::SECTION_ANSWER));
-    EXPECT_EQ(nscount, message.getRRCount(Message::SECTION_AUTHORITY));
-    EXPECT_EQ(arcount, message.getRRCount(Message::SECTION_ADDITIONAL));
-}
+// The base class for Auth and Recurse test case
+class SrvTestBase : public ::testing::Test {
+protected:
+    SrvTestBase();
+    virtual ~SrvTestBase();
+
+    /// Let the server process a DNS message.
+    ///
+    /// The derived class implementation is expected to pass \c io_message,
+    /// \c parse_message, \c response_obuffer, and \c dnsserv to the server
+    /// implementation it is testing.
+    virtual void processMessage() = 0;
+
+    /// The following methods implement server independent test logic using
+    /// the template method pattern.  Each test calls \c processMessage()
+    /// to delegate the server-dependent behavior to the actual implementation
+    /// classes.
+    void unsupportedRequest();
+    void multiQuestion();
+    void shortMessage();
+    void response();
+    void shortQuestion();
+    void shortAnswer();
+    void ednsBadVers();
+    void axfrOverUDP();
+
+    /// Create DNS packet data from a file.
+    ///
+    /// It constructs wire-format DNS packet data from \c datafile in the
+    /// form of \c IOMessage in \c io_message.
+    /// The existing content of \c io_message, if any, will be deleted.
+    void createDataFromFile(const char* const datafile,
+                            int protocol = IPPROTO_UDP);
+
+    ///  Create DNS packet data from a message.
+    ///
+    /// It constructs wire-format DNS packet data from \c message in the
+    /// form of \c IOMessage in \c io_message.
+    /// The existing content of \c io_message, if any, will be deleted.
+    void createRequestPacket(isc::dns::Message& message,
+                             const int protocol = IPPROTO_UDP);
 
-}
+    MockSession notify_session;
+    MockServer dnsserv;
+    isc::dns::Message request_message;
+    isc::dns::MessagePtr parse_message;
+    const isc::dns::qid_t default_qid;
+    const isc::dns::Opcode opcode;
+    const isc::dns::Name qname;
+    const isc::dns::RRClass qclass;
+    const isc::dns::RRType qtype;
+    asiolink::IOSocket* io_sock;
+    asiolink::IOMessage* io_message;
+    const asiolink::IOEndpoint* endpoint;
+    isc::dns::OutputBuffer request_obuffer;
+    isc::dns::MessageRenderer request_renderer;
+    isc::dns::OutputBufferPtr response_obuffer;
+    std::vector<uint8_t> data;
+};
+} // end of namespace testutils
+} // end of namespace isc
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 0 - 158
src/lib/testutils/srv_unittest.h

@@ -1,158 +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: auth_srv_unittest.cc 3310 2010-10-21 23:10:24Z each $
-
-#include "srv_test.h"
-
-namespace {
-
-// Unsupported requests.  Should result in NOTIMP.
-#define UNSUPPORTED_REQUEST_TEST \
-    for (unsigned int i = 0; i < 16; ++i) { \
-        /* set Opcode to 'i', which iterators over all possible codes except \
-           the standard query and notify */ \
-        if (i == Opcode::QUERY().getCode() || \
-            i == Opcode::NOTIFY().getCode()) { \
-            continue; \
-        } \
-        createDataFromFile("simplequery_fromWire.wire"); \
-        data[2] = ((i << 3) & 0xff); \
- \
-        parse_message->clear(Message::PARSE); \
-        server.processMessage(*io_message, parse_message, response_obuffer, \
-                              &dnsserv); \
-        EXPECT_TRUE(dnsserv.hasAnswer()); \
-        headerCheck(*parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG, \
-                    0, 0, 0, 0); \
-    }
-
-// Simple API check
-#define VERBOSE_TEST \
-    EXPECT_FALSE(server.getVerbose()); \
-    server.setVerbose(true); \
-    EXPECT_TRUE(server.getVerbose()); \
-    server.setVerbose(false); \
-    EXPECT_FALSE(server.getVerbose()); \
-
-
-// Multiple questions.  Should result in FORMERR.
-#define MULTI_QUESTION_TEST \
-    createDataFromFile("multiquestion_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
-    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
-                QR_FLAG, 2, 0, 0, 0); \
- \
-    QuestionIterator qit = parse_message->beginQuestion(); \
-    EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
-    EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
-    EXPECT_EQ(RRType::A(), (*qit)->getType()); \
-    ++qit; \
-    EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
-    EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
-    EXPECT_EQ(RRType::AAAA(), (*qit)->getType()); \
-    ++qit; \
-    EXPECT_TRUE(qit == parse_message->endQuestion());
-
-// Incoming data doesn't even contain the complete header.  Must be silently
-// dropped.
-#define SHORT_MESSAGE_TEST \
-    createDataFromFile("shortmessage_fromWire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_FALSE(dnsserv.hasAnswer());
-
-// Response messages.  Must be silently dropped, whether it's a valid response
-// or malformed or could otherwise cause a protocol error.
-#define RESPONSE_TEST \
-    /* A valid (although unusual) response */\
-    createDataFromFile("simpleresponse_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_FALSE(dnsserv.hasAnswer()); \
- \
-    /* A response with a broken question section.  must be dropped rather than \
-       returning FORMERR. */\
-    createDataFromFile("shortresponse_fromWire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_FALSE(dnsserv.hasAnswer()); \
- \
-    /* A response to iquery.  must be dropped rather than returning NOTIMP. */\
-    createDataFromFile("iqueryresponse_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_FALSE(dnsserv.hasAnswer());
-
-// Query with a broken question
-#define SHORT_QUESTION_TEST \
-    createDataFromFile("shortquestion_fromWire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
-    /* Since the query's question is broken, the question section of the \
-       response should be empty. */\
-    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
-                QR_FLAG, 0, 0, 0, 0);
-
-// Query with a broken answer section
-#define SHORT_ANSWER_TEST \
-    createDataFromFile("shortanswer_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
- \
-    /* This is a bogus query, but question section is valid.  So the response \
-       should copy the question section. */ \
-    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
-                QR_FLAG, 1, 0, 0, 0); \
- \
-    QuestionIterator qit = parse_message->beginQuestion(); \
-    EXPECT_EQ(Name("example.com"), (*qit)->getName()); \
-    EXPECT_EQ(RRClass::IN(), (*qit)->getClass()); \
-    EXPECT_EQ(RRType::A(), (*qit)->getType()); \
-    ++qit; \
-    EXPECT_TRUE(qit == parse_message->endQuestion());
-
-// Query with unsupported version of EDNS.
-#define EDNS_BADVERS_TEST \
-    createDataFromFile("queryBadEDNS_fromWire.wire"); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
- \
-    /* The response must have an EDNS OPT RR in the additional section, \
-       it will be added automatically at the render time.
-       Note that the DNSSEC DO bit is cleared even if this bit in the query \
-       is set.  This is a limitation of the current implementation. */ \
-    headerCheck(*parse_message, default_qid, Rcode::BADVERS(), opcode.getCode(), \
-                QR_FLAG, 1, 0, 0, 1); \
-    EXPECT_FALSE(parse_message->getEDNS()); /* EDNS isn't added at this point */ \
- \
-    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength()); \
-    Message parsed(Message::PARSE); \
-    parsed.fromWire(ib); \
-    EXPECT_EQ(Rcode::BADVERS(), parsed.getRcode()); \
-    ConstEDNSPtr edns(parsed.getEDNS()); \
-    ASSERT_TRUE(edns); \
-    EXPECT_FALSE(edns->getDNSSECAwareness());
-
-
-#define AXFR_OVER_UDP_TEST \
-    /* AXFR over UDP is invalid and should result in FORMERR. */\
-    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid, \
-                         Name("example.com"), RRClass::IN(), \
-                         RRType::AXFR()); \
-    createRequestPacket(request_message, IPPROTO_UDP); \
-    server.processMessage(*io_message, parse_message, response_obuffer, &dnsserv); \
-    EXPECT_TRUE(dnsserv.hasAnswer()); \
-    headerCheck(*parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(), \
-                QR_FLAG, 1, 0, 0, 0);
-
-}
-