[svn] commit: r2346 - in /experiments/python-binding: ./ src/bin/auth/ src/bin/auth/tests/ src/bin/bind10/ src/bin/bind10/tests/ src/bin/bindctl/ src/bin/cfgmgr/ src/bin/cfgmgr/tests/ src/bin/cmdctl/ src/bin/host/ src/bin/loadzone/ src/bin/loadzone/testdata/ src/bin/loadzone/tests/ src/bin/xfrin/ src/bin/xfrin/tests/ src/bin/xfrout/ src/bin/xfrout/tests/ src/lib/cc/ src/lib/config/tests/ src/lib/datasrc/ src/lib/datasrc/tests/ src/lib/datasrc/tests/testdata/ src/lib/dns/ src/lib/dns/python/ src/lib/dns/python/tests/ src/lib/dns/rdata/generic/ src/lib/dns/tests/ src/lib/python/isc/ src/lib/python/isc/datasrc/ src/lib/python/isc/log/

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Jun 30 13:47:22 UTC 2010


Author: jelte
Date: Wed Jun 30 13:47:21 2010
New Revision: 2346

Log:
sync with trunk for merge

Added:
    experiments/python-binding/src/bin/bind10/tests/args_test.py
      - copied unchanged from r2345, trunk/src/bin/bind10/tests/args_test.py
    experiments/python-binding/src/bin/cfgmgr/tests/
      - copied from r2345, trunk/src/bin/cfgmgr/tests/
    experiments/python-binding/src/bin/loadzone/tests/
      - copied from r2345, trunk/src/bin/loadzone/tests/
    experiments/python-binding/src/lib/python/isc/log/
      - copied from r2345, trunk/src/lib/python/isc/log/
Removed:
    experiments/python-binding/src/bin/loadzone/testdata/
Modified:
    experiments/python-binding/   (props changed)
    experiments/python-binding/ChangeLog
    experiments/python-binding/configure.ac
    experiments/python-binding/src/bin/auth/Makefile.am
    experiments/python-binding/src/bin/auth/asio_link.cc
    experiments/python-binding/src/bin/auth/asio_link.h
    experiments/python-binding/src/bin/auth/auth_srv.cc
    experiments/python-binding/src/bin/auth/main.cc
    experiments/python-binding/src/bin/auth/tests/Makefile.am
    experiments/python-binding/src/bin/bind10/bind10.py.in
    experiments/python-binding/src/bin/bind10/tests/bind10_test.in
    experiments/python-binding/src/bin/bindctl/bindcmd.py
    experiments/python-binding/src/bin/cfgmgr/Makefile.am
    experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.py.in   (contents, props changed)
    experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.xml   (props changed)
    experiments/python-binding/src/bin/cmdctl/cmdctl.py.in
    experiments/python-binding/src/bin/host/Makefile.am
    experiments/python-binding/src/bin/host/host.cc
    experiments/python-binding/src/bin/loadzone/Makefile.am
    experiments/python-binding/src/bin/loadzone/b10-loadzone.py.in
    experiments/python-binding/src/bin/xfrin/   (props changed)
    experiments/python-binding/src/bin/xfrin/tests/Makefile.am
    experiments/python-binding/src/bin/xfrin/xfrin.py.in
    experiments/python-binding/src/bin/xfrout/tests/Makefile.am
    experiments/python-binding/src/bin/xfrout/tests/xfrout_test.py
    experiments/python-binding/src/bin/xfrout/xfrout.py.in
    experiments/python-binding/src/bin/xfrout/xfrout.spec.pre.in
    experiments/python-binding/src/lib/cc/   (props changed)
    experiments/python-binding/src/lib/cc/Makefile.am
    experiments/python-binding/src/lib/cc/session.cc
    experiments/python-binding/src/lib/cc/session_unittests.cc
    experiments/python-binding/src/lib/config/tests/Makefile.am
    experiments/python-binding/src/lib/datasrc/   (props changed)
    experiments/python-binding/src/lib/datasrc/data_source.cc
    experiments/python-binding/src/lib/datasrc/sqlite3_datasrc.cc
    experiments/python-binding/src/lib/datasrc/tests/Makefile.am
    experiments/python-binding/src/lib/datasrc/tests/datasrc_unittest.cc
    experiments/python-binding/src/lib/datasrc/tests/test_datasrc.cc
    experiments/python-binding/src/lib/datasrc/tests/test_datasrc.h
    experiments/python-binding/src/lib/datasrc/tests/testdata/example.org
    experiments/python-binding/src/lib/datasrc/tests/testdata/example.org.sqlite3
    experiments/python-binding/src/lib/dns/   (props changed)
    experiments/python-binding/src/lib/dns/Makefile.am
    experiments/python-binding/src/lib/dns/message.cc
    experiments/python-binding/src/lib/dns/name.cc
    experiments/python-binding/src/lib/dns/python/Makefile.am
    experiments/python-binding/src/lib/dns/python/tests/Makefile.am
    experiments/python-binding/src/lib/dns/rdata/generic/rrsig_46.cc   (props changed)
    experiments/python-binding/src/lib/dns/rrsetlist.cc
    experiments/python-binding/src/lib/dns/rrsetlist.h
    experiments/python-binding/src/lib/dns/tests/   (props changed)
    experiments/python-binding/src/lib/dns/tests/Makefile.am
    experiments/python-binding/src/lib/python/isc/Makefile.am
    experiments/python-binding/src/lib/python/isc/__init__.py
    experiments/python-binding/src/lib/python/isc/datasrc/master.py

Modified: experiments/python-binding/ChangeLog
==============================================================================
--- experiments/python-binding/ChangeLog (original)
+++ experiments/python-binding/ChangeLog Wed Jun 30 13:47:21 2010
@@ -1,11 +1,73 @@
-  53.   [bug]      zhanglikun
+  65.  [func]       shentingting
+    Added verbose options to exactly what is happening with loadzone.
+	Added loadzone test suite of different file formats to load.
+	(Trac #197, #199, #244, #161, #198, #174, #175, svn r2340)
+
+  64.  [func]       jerry
+    Added python logging framework. It is for testing and experimenting
+	with logging ideas. Currently, it supports three channels(file, 
+	syslog and stderr) and five levels(debug, info, warning, error and
+	critical).
+	(Trac #176, svn r2338)
+
+  63.  [func]       shane
+    Added initial support for setuid(), using the "-u" flag. This will
+    be replaced in the future, but for now provides a reasonable 
+    starting point.
+    (Trac #180, svn r2330)
+
+  62.  [func]		jelte
+	bin/xfrin: Use the database_file as configured in Auth to transfers
+	bin/xfrout: Use the database_file as configured in Auth to transfers
+
+  61.  [bug]		jelte
+	bin/auth: Enable b10-auth to be launched in source tree
+	(i.e. use a zone database file relative to that)
+
+  60.	[build]		jinmei
+	Supported SunStudio C++ compiler.  Note: gtest still doesn't work.
+	(Trac #251, svn r2310)
+
+  59.	[bug]		jinmei
+	lib/datasrc,bin/auth: The authoritative server could return a
+	SERVFAIL with a partial answer if it finds a data source broken
+	while looking for an answer.  This can happen, for example, if a
+	zone that doesn't have an NS RR is configured and loaded as a
+	sqlite3 data source. (Trac #249, r2286)
+
+  58.	[bug]		jinmei
+	Worked around an interaction issue between ASIO and standard C++
+	library headers.  Without this ASIO didn't work: sometimes the
+	application crashes, sometimes it blocked in the ASIO module.
+	(Trac #248, svn r2187, r2190)
+
+  57.	[func]		jinmei
+	lib/datasrc: used a simpler version of Name::split (change 31) for
+	better readability.  No behavior change. (Trac #200, svn r2159)
+
+  56.	[func]*		jinmei
+	lib/dns: renamed the library name to libdns++ to avoid confusion
+	with the same name of library of BIND 9.
+	(Trac #190, svn r2153)
+
+  55.	[bug]		shane
+	bin/xfrout: xfrout exception on Ctrl-C now no longer generates
+	exception for 'Interrupted system call'
+	(Track #136, svn r2147)
+
+  54.	[bug]		zhanglikun
+	bin/xfrout: Enable b10-xfrout can be launched in source
+	code tree.
+	(Trac #224, svn r2103)
+
+  53.	[bug]		zhanglikun
 	bin/bindctl: Generate a unique session ID by using 
 	socket.gethostname() instead of socket.gethostbyname(), 
 	since the latter one could make bindctl	stall if its own 
 	host name can't be resolved.
 	(Trac #228, svn r2096)
 
-  52.   [func]      zhanglikun
+  52.	[func]		zhanglikun
 	bin/xfrout: When xfrout is launched, check whether the
 	socket file is being used by one running xfrout process, 
 	if it is, exit from python.	If the file isn't a socket file 
@@ -67,6 +129,10 @@
 	Renamed libauth to libdatasrc.
 
   38.   [bug]           zhanglikun
+	Send command 'shutdown' to Xfrin and Xfrout when boss receive SIGINT.
+	Remove unused socket file when Xfrout process exits. Make sure Xfrout
+	exit by itself when it receives SIGINT, instead of being killed by the
+	signal SIGTERM or SIGKILL sent from boss.
 	(Trac #135, #151, #134, svn r1797)
 
   37.   [build]         jinmei
@@ -127,7 +193,7 @@
 
   24.	[func]
 	Support case-sensitive name compression in MessageRenderer.
-	(svn r1704)
+	(Trac #142, svn r1704)
 
   23.	[func]
 	Support a simple name with possible compression. (svn r1701)

Modified: experiments/python-binding/configure.ac
==============================================================================
--- experiments/python-binding/configure.ac (original)
+++ experiments/python-binding/configure.ac Wed Jun 30 13:47:21 2010
@@ -9,11 +9,23 @@
 
 # Checks for programs.
 AC_PROG_CXX
-AC_PROG_CC
 AC_PROG_LIBTOOL
 
 # Use C++ language
-AC_LANG_CPLUSPLUS
+AC_LANG([C++])
+
+# Identify the compiler: this check must be after AC_PROG_CXX and AC_LANG.
+AM_CONDITIONAL(USE_GXX, test "X${GXX}" = "Xyes")
+AC_CHECK_DECL([__SUNPRO_CC], [SUNCXX="yes"], [SUNCXX="no"])
+
+# OS dependent compiler flags
+case "$host" in
+*-solaris*)
+	# Solaris requires special definitions to get some standard libraries
+	# (e.g. getopt(3)) available with common used header files.
+	CPPFLAGS="$CPPFLAGS -D_XPG4_2 -D__EXTENSIONS__"
+	;;
+esac
 
 m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3 python3.1])
 AC_ARG_WITH([pythonpath],
@@ -93,8 +105,8 @@
 
 # TODO: check for _sqlite3.py module
 
-#
-# B10_CXXFLAGS is the default C++ compiler flags.  This will (and should) be
+# Compiler dependent settings: define some mandatory CXXFLAGS here.
+# We also use a separate variable B10_CXXFLAGS.  This will (and should) be
 # used as the default value for each specifc AM_CXXFLAGS:
 # AM_CXXFLAGS = $(B10_CXXFLAGS)
 # AM_CXXFLAGS += ... # add module specific flags
@@ -103,17 +115,24 @@
 # gcc's -Wno-XXX option must be specified after -Wall or -Wextra, we cannot
 # specify the default warning flags in CXXFLAGS and let specific modules
 # "override" the default.
-#
-B10_CXXFLAGS=
-
-if test "X$GCC" = "Xyes"; then
-B10_CXXFLAGS="-g -Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
+
+CXXFLAGS=-g
+werror_ok=0
+
+# SunStudio compiler requires special compiler options for boost
+# (http://blogs.sun.com/sga/entry/boost_mini_howto)
+if test "$SUNCXX" = "yes"; then
+CXXFLAGS="$CXXFLAGS -library=stlport4 -features=tmplife -features=tmplrefstatic"
+fi
+
+# gcc specific settings:
+if test "X$GXX" = "Xyes"; then
+B10_CXXFLAGS="-Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
 UNUSED_PARAM_ATTRIBUTE='__attribute__((unused))'
 
 # Certain versions of gcc (g++) have a bug that incorrectly warns about
 # the use of anonymous name spaces even if they're closed in a single
 # translation unit.  For these versions we have to disable -Werror.
-werror_ok=0
 CXXFLAGS_SAVED="$CXXFLAGS"
 CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
 AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
@@ -124,13 +143,13 @@
 	 B10_CXXFLAGS="$B10_CXXFLAGS -Werror"],
 	[AC_MSG_RESULT(yes)])
 CXXFLAGS="$CXXFLAGS_SAVED"
-fi				dnl GCC = yes
+fi				dnl GXX = yes
 
 AM_CONDITIONAL(GCC_WERROR_OK, test $werror_ok = 1)
 AC_DEFINE_UNQUOTED(UNUSED_PARAM, $UNUSED_PARAM_ATTRIBUTE, Define to compiler keyword indicating a function argument is intentionally unused)
 
 # produce PIC unless we disable shared libraries. need this for python bindings.
-if test $enable_shared != "no" -a "X$GCC" = "Xyes"; then
+if test $enable_shared != "no" -a "X$GXX" = "Xyes"; then
    B10_CXXFLAGS="$B10_CXXFLAGS -fPIC"
 fi
 
@@ -270,6 +289,11 @@
 AC_SUBST(GTEST_LDFLAGS)
 AC_SUBST(GTEST_LDADD)
 
+dnl check for pkg-config itself so we don't try the m4 macro without pkg-config
+AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes, no)
+if test "x$HAVE_PKG_CONFIG" = "xno" ; then
+  AC_MSG_ERROR(Please install pkg-config)
+fi
 PKG_CHECK_MODULES(SQLITE, sqlite3 >= 3.3.9, enable_features="$enable_features SQLite3")
 
 # I can't get some of the #include <asio.hpp> right without this
@@ -319,7 +343,7 @@
 # run time performance.  Hpefully we can find a better solution or the ASIO
 # code will be updated by the time we really need it.
 AC_CHECK_HEADERS(sys/devpoll.h, ac_cv_have_devpoll=yes, ac_cv_have_devpoll=no)
-if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GCC" = "Xyes"; then
+if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GXX" = "Xyes"; then
 	CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
 fi
 
@@ -348,8 +372,11 @@
                  src/bin/bindctl/Makefile
                  src/bin/bindctl/tests/Makefile
                  src/bin/cfgmgr/Makefile
+                 src/bin/cfgmgr/tests/Makefile
                  src/bin/host/Makefile
                  src/bin/loadzone/Makefile
+                 src/bin/loadzone/tests/correct/Makefile
+                 src/bin/loadzone/tests/error/Makefile
                  src/bin/msgq/Makefile
                  src/bin/msgq/tests/Makefile
                  src/bin/auth/Makefile
@@ -368,6 +395,8 @@
                  src/lib/python/isc/cc/tests/Makefile
                  src/lib/python/isc/config/Makefile
                  src/lib/python/isc/config/tests/Makefile
+                 src/lib/python/isc/log/Makefile
+                 src/lib/python/isc/log/tests/Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
                  src/lib/dns/Makefile
@@ -380,6 +409,7 @@
                  src/lib/xfr/Makefile
                ])
 AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
+           src/bin/cfgmgr/tests/b10-cfgmgr_test.py
            src/bin/cmdctl/cmdctl.py
            src/bin/cmdctl/run_b10-cmdctl.sh
            src/bin/cmdctl/tests/cmdctl_test
@@ -398,6 +428,8 @@
            src/bin/bindctl/bindctl-source.py
            src/bin/bindctl/tests/bindctl_test
            src/bin/loadzone/run_loadzone.sh
+           src/bin/loadzone/tests/correct/correct_test.sh
+           src/bin/loadzone/tests/error/error_test.sh
            src/bin/loadzone/b10-loadzone.py
            src/bin/usermgr/run_b10-cmdctl-usermgr.sh
            src/bin/usermgr/b10-cmdctl-usermgr.py
@@ -409,7 +441,7 @@
            src/lib/config/tests/data_def_unittests_config.h
            src/lib/python/isc/config/tests/config_test
            src/lib/python/isc/cc/tests/cc_test
-           src/lib/dns/python/tests/libdns_python_test
+           src/lib/python/isc/log/tests/log_test
            src/lib/dns/gen-rdatacode.py
            src/lib/python/bind10_config.py
            src/lib/dns/tests/testdata/gen-wiredata.py
@@ -425,6 +457,8 @@
            chmod +x src/bin/bindctl/tests/bindctl_test
            chmod +x src/bin/bindctl/run_bindctl.sh
            chmod +x src/bin/loadzone/run_loadzone.sh
+           chmod +x src/bin/loadzone/tests/correct/correct_test.sh
+           chmod +x src/bin/loadzone/tests/error/error_test.sh
            chmod +x src/bin/usermgr/run_b10-cmdctl-usermgr.sh
            chmod +x src/bin/msgq/run_msgq.sh
            chmod +x src/bin/msgq/tests/msgq_test

Modified: experiments/python-binding/src/bin/auth/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/auth/Makefile.am (original)
+++ experiments/python-binding/src/bin/auth/Makefile.am Wed Jun 30 13:47:21 2010
@@ -36,7 +36,10 @@
 libasio_link_a_SOURCES = asio_link.cc asio_link.h
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
-libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS) -Wno-unused-parameter
+libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+libasio_link_a_CXXFLAGS += -Wno-unused-parameter
+endif
 libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
 
 BUILT_SOURCES = spec_config.h 
@@ -45,9 +48,9 @@
 b10_auth_SOURCES += common.h
 b10_auth_SOURCES += main.cc
 b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-b10_auth_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
+b10_auth_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
 b10_auth_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
-b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.a
+b10_auth_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
 b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 b10_auth_LDADD += $(top_builddir)/src/bin/auth/libasio_link.a
 b10_auth_LDADD += $(SQLITE_LIBS)

Modified: experiments/python-binding/src/bin/auth/asio_link.cc
==============================================================================
--- experiments/python-binding/src/bin/auth/asio_link.cc (original)
+++ experiments/python-binding/src/bin/auth/asio_link.cc Wed Jun 30 13:47:21 2010
@@ -16,6 +16,7 @@
 
 #include <config.h>
 
+#include <unistd.h>             // for some IPC/network system calls
 #include <asio.hpp>
 #include <boost/bind.hpp>
 
@@ -66,7 +67,13 @@
 dispatch_axfr_query(const int tcp_sock, char const axfr_query[],
                     const uint16_t query_len)
 {
-    string path(UNIX_SOCKET_FILE);
+    string path;
+    if (getenv("B10_FROM_BUILD")) {
+        path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
+    } else {
+        path = UNIX_SOCKET_FILE;
+    }
+    
     if (getenv("B10_FROM_BUILD")) {
         path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
     }

Modified: experiments/python-binding/src/bin/auth/asio_link.h
==============================================================================
--- experiments/python-binding/src/bin/auth/asio_link.h (original)
+++ experiments/python-binding/src/bin/auth/asio_link.h Wed Jun 30 13:47:21 2010
@@ -24,7 +24,7 @@
 
 class IOService {
 public:
-    IOService(AuthSrv* auth_server, const char* port,
+    IOService(AuthSrv* auth_server, const char* const port,
               const bool use_ipv4, const bool use_ipv6);
     ~IOService();
     void run();

Modified: experiments/python-binding/src/bin/auth/auth_srv.cc
==============================================================================
--- experiments/python-binding/src/bin/auth/auth_srv.cc (original)
+++ experiments/python-binding/src/bin/auth/auth_srv.cc Wed Jun 30 13:47:21 2010
@@ -243,7 +243,8 @@
         impl_->data_sources_.doQuery(query);
     } catch (const Exception& ex) {
         if (impl_->verbose_mode_) {
-            cerr << "[b10-auth] Internal error, returning SERVFAIL: " << ex.what() << endl;
+            cerr << "[b10-auth] Internal error, returning SERVFAIL: " <<
+                ex.what() << endl;
         }
         makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
                          impl_->verbose_mode_);
@@ -273,9 +274,22 @@
         bool is_default;
         string item("database_file");
         ElementPtr value = cs_->getValue(is_default, item);
+        final = Element::createFromString("{}");
+
+        // If the value is the default, and we are running from
+        // a specific directory ('from build'), we need to use
+        // a different value than the default (which may not exist)
+        // (btw, this should not be done here in the end, i think
+        //  the from-source script should have a check for this,
+        //  but for that we need offline access to config, so for
+        //  now this is a decent solution)
+        if (is_default && getenv("B10_FROM_BUILD")) {
+            value = Element::create(string(getenv("B10_FROM_BUILD")) +
+                                    "/bind10_zones.sqlite3");
+        }
+        final->set(item, value);
+
         db_file_ = value->stringValue();
-        final = Element::createFromString("{}");
-        final->set(item, value);
     } else {
         return (answer);
     }

Modified: experiments/python-binding/src/bin/auth/main.cc
==============================================================================
--- experiments/python-binding/src/bin/auth/main.cc (original)
+++ experiments/python-binding/src/bin/auth/main.cc Wed Jun 30 13:47:21 2010
@@ -148,12 +148,12 @@
         io_service = new asio_link::IOService(auth_server, port, use_ipv4,
                                               use_ipv6);
 
-        ModuleCCSession cs(specfile, io_service->get_io_service(), my_config_handler, my_command_handler);
+        ModuleCCSession cs(specfile, io_service->get_io_service(),
+                           my_config_handler, my_command_handler);
 
         auth_server->setConfigSession(&cs);
         auth_server->updateConfig(ElementPtr());
 
-        
         cout << "[b10-auth] Server started." << endl;
         io_service->run();
     } catch (const std::exception& ex) {

Modified: experiments/python-binding/src/bin/auth/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/auth/tests/Makefile.am (original)
+++ experiments/python-binding/src/bin/auth/tests/Makefile.am Wed Jun 30 13:47:21 2010
@@ -20,9 +20,9 @@
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
 run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns++.a
 run_unittests_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 endif
 

Modified: experiments/python-binding/src/bin/bind10/bind10.py.in
==============================================================================
--- experiments/python-binding/src/bin/bind10/bind10.py.in (original)
+++ experiments/python-binding/src/bin/bind10/bind10.py.in Wed Jun 30 13:47:21 2010
@@ -57,6 +57,9 @@
 import select
 import random
 from optparse import OptionParser, OptionValueError
+import io
+import pwd
+import posix
 
 import isc.cc
 
@@ -108,21 +111,38 @@
             when = time.time()
         return max(when, self.restart_time)
 
+class ProcessInfoError(Exception): pass
+
 class ProcessInfo:
     """Information about a process"""
 
     dev_null = open(os.devnull, "w")
 
     def __init__(self, name, args, env={}, dev_null_stdout=False,
-                 dev_null_stderr=False):
+                 dev_null_stderr=False, uid=None, username=None):
         self.name = name 
         self.args = args
         self.env = env
         self.dev_null_stdout = dev_null_stdout
         self.dev_null_stderr = dev_null_stderr
         self.restart_schedule = RestartSchedule()
+        self.uid = uid
+        self.username = username
         self._spawn()
 
+    def _setuid(self):
+        """Function used before running a program that needs to run as a
+        different user."""
+        if self.uid is not None:
+            try:
+                posix.setuid(self.uid)
+            except OSError as e:
+                if e.errno == errno.EPERM:
+                    # if we failed to change user due to permission report that
+                    raise ProcessInfoError("Unable to change to user %s (uid %d)" % (self.username, self.uid))
+                else:
+                    # otherwise simply re-raise whatever error we found
+                    raise
 
     def _spawn(self):
         if self.dev_null_stdout:
@@ -138,14 +158,15 @@
         # on construction (self.env).
         spawn_env = os.environ
         spawn_env.update(self.env)
-        if not 'B10_FROM_SOURCE' in os.environ:
+        if 'B10_FROM_SOURCE' not in os.environ:
             spawn_env['PATH'] = "@@LIBEXECDIR@@:" + spawn_env['PATH']
         self.process = subprocess.Popen(self.args,
                                         stdin=subprocess.PIPE,
                                         stdout=spawn_stdout,
                                         stderr=spawn_stderr,
                                         close_fds=True,
-                                        env=spawn_env,)
+                                        env=spawn_env,
+                                        preexec_fn=self._setuid)
         self.pid = self.process.pid
         self.restart_schedule.set_run_start_time()
 
@@ -155,7 +176,8 @@
 class BoB:
     """Boss of BIND class."""
     
-    def __init__(self, msgq_socket_file=None, auth_port=5300, verbose=False):
+    def __init__(self, msgq_socket_file=None, auth_port=5300, verbose=False,
+                 setuid=None, username=None):
         """Initialize the Boss of BIND. This is a singleton (only one
         can run).
         
@@ -171,6 +193,8 @@
         self.processes = {}
         self.dead_processes = {}
         self.runnable = False
+        self.uid = setuid
+        self.username = username
 
     def config_handler(self, new_config):
         if self.verbose:
@@ -225,12 +249,14 @@
                 sys.stdout.write("[bind10] Starting b10-msgq\n")
         try:
             c_channel = ProcessInfo("b10-msgq", ["b10-msgq"], c_channel_env,
-                                    True, not self.verbose)
+                                    True, not self.verbose, uid=self.uid,
+                                    username=self.username)
         except Exception as e:
             return "Unable to start b10-msgq; " + str(e)
         self.processes[c_channel.pid] = c_channel
         if self.verbose:
-            sys.stdout.write("[bind10] Started b10-msgq (PID %d)\n" % c_channel.pid)
+            sys.stdout.write("[bind10] Started b10-msgq (PID %d)\n" % 
+                             c_channel.pid)
 
         # now connect to the c-channel
         cc_connect_start = time.time()
@@ -250,7 +276,8 @@
             sys.stdout.write("[bind10] Starting b10-cfgmgr\n")
         try:
             bind_cfgd = ProcessInfo("b10-cfgmgr", ["b10-cfgmgr"],
-                                    c_channel_env)
+                                    c_channel_env, uid=self.uid,
+                                    username=self.username)
         except Exception as e:
             c_channel.process.kill()
             return "Unable to start b10-cfgmgr; " + str(e)
@@ -271,23 +298,6 @@
         self.ccs.start()
         if self.verbose:
             sys.stdout.write("[bind10] ccsession started\n")
-
-        # start the xfrout before auth-server, to make sure every xfr-query can
-        # be processed properly.
-        xfrout_args = ['b10-xfrout']
-        if self.verbose:
-            sys.stdout.write("[bind10] Starting b10-xfrout\n")
-            xfrout_args += ['-v']
-        try:
-            xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
-                                 c_channel_env )
-        except Exception as e:
-            c_channel.process.kill()
-            bind_cfgd.process.kill()
-            return "Unable to start b10-xfrout; " + str(e)
-        self.processes[xfrout.pid] = xfrout
-        if self.verbose:
-            sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % xfrout.pid)
 
         # start b10-auth
         # XXX: this must be read from the configuration manager in the future
@@ -307,6 +317,28 @@
         self.processes[auth.pid] = auth
         if self.verbose:
             sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
+
+        # everything after the authoritative server can run as non-root
+        if self.uid is not None:
+            posix.setuid(self.uid)
+
+        # start the xfrout before auth-server, to make sure every xfr-query can
+        # be processed properly.
+        xfrout_args = ['b10-xfrout']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-xfrout\n")
+            xfrout_args += ['-v']
+        try:
+            xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
+                                 c_channel_env )
+        except Exception as e:
+            c_channel.process.kill()
+            bind_cfgd.process.kill()
+            return "Unable to start b10-xfrout; " + str(e)
+        self.processes[xfrout.pid] = xfrout
+        if self.verbose:
+            sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % 
+                             xfrout.pid)
 
         # start b10-xfrin
         xfrin_args = ['b10-xfrin']
@@ -324,7 +356,8 @@
             return "Unable to start b10-xfrin; " + str(e)
         self.processes[xfrind.pid] = xfrind
         if self.verbose:
-            sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % xfrind.pid)
+            sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % 
+                             xfrind.pid)
 
         # start the b10-cmdctl
         # XXX: we hardcode port 8080
@@ -344,7 +377,8 @@
             return "Unable to start b10-cmdctl; " + str(e)
         self.processes[cmd_ctrld.pid] = cmd_ctrld
         if self.verbose:
-            sys.stdout.write("[bind10] Started b10-cmdctl (PID %d)\n" % cmd_ctrld.pid)
+            sys.stdout.write("[bind10] Started b10-cmdctl (PID %d)\n" % 
+                             cmd_ctrld.pid)
 
         self.runnable = True
 
@@ -435,11 +469,16 @@
                 sys.stdout.write("[bind10] Unknown child pid %d exited.\n" % pid)
 
     def restart_processes(self):
-        """Restart any dead processes."""
+        """Restart any dead processes.
+        Returns the time when the next process is ready to be restarted. 
+          If the server is shutting down, returns 0.
+          If there are no processes, returns None.
+        The values returned can be safely passed into select() as the 
+        timeout value."""
         next_restart = None
         # if we're shutting down, then don't restart
         if not self.runnable:
-            return next_restart
+            return 0
         # otherwise look through each dead process and try to restart
         still_dead = {}
         now = time.time()
@@ -510,6 +549,10 @@
 def main():
     global options
     global boss_of_bind
+    # Enforce line buffering on stdout, even when not a TTY
+    sys.stdout = io.TextIOWrapper(sys.stdout.detach(), line_buffering=True)
+
+
     # Parse any command-line options.
     parser = OptionParser(version=__version__)
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
@@ -520,7 +563,42 @@
     parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
                       type="string", default=None,
                       help="UNIX domain socket file the b10-msgq daemon will use")
+    parser.add_option("-u", "--user", dest="user",
+                      type="string", default=None,
+                      help="Change user after startup (must run as root)")
     (options, args) = parser.parse_args()
+    if args:
+        parser.print_help()
+        sys.exit(1)
+
+    # Check user ID.
+    setuid = None
+    username = None
+    if options.user:
+        # Try getting information about the user, assuming UID passed.
+        try:
+            pw_ent = pwd.getpwuid(int(options.user))
+            setuid = pw_ent.pw_uid
+            username = pw_ent.pw_name
+        except ValueError:
+            pass
+        except KeyError:
+            pass
+
+        # Next try getting information about the user, assuming user name 
+        # passed.
+        # If the information is both a valid user name and user number, we
+        # prefer the name because we try it second. A minor point, hopefully.
+        try:
+            pw_ent = pwd.getpwnam(options.user)
+            setuid = pw_ent.pw_uid
+            username = pw_ent.pw_name
+        except KeyError:
+            pass
+
+        if setuid is None:
+            sys.stderr.write("bind10: invalid user: '%s'\n" % options.user)
+            sys.exit(1)
 
     # Announce startup.
     if options.verbose:
@@ -543,11 +621,12 @@
 
     # Go bob!
     boss_of_bind = BoB(options.msgq_socket_file, int(options.auth_port),
-                       options.verbose)
+                       options.verbose, setuid, username)
     startup_result = boss_of_bind.startup()
     if startup_result:
         sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
         sys.exit(1)
+    sys.stdout.write("[bind10] BIND 10 started\n")
 
     # In our main loop, we check for dead processes or messages 
     # on the c-channel.
@@ -584,6 +663,7 @@
     # shutdown
     signal.signal(signal.SIGCHLD, signal.SIG_DFL)
     boss_of_bind.shutdown()
+    sys.exit(0)
 
 if __name__ == "__main__":
     main()

Modified: experiments/python-binding/src/bin/bind10/tests/bind10_test.in
==============================================================================
--- experiments/python-binding/src/bin/bind10/tests/bind10_test.in (original)
+++ experiments/python-binding/src/bin/bind10/tests/bind10_test.in Wed Jun 30 13:47:21 2010
@@ -27,5 +27,6 @@
 export PYTHONPATH
 
 cd ${BIND10_PATH}/tests
-exec ${PYTHON_EXEC} -O bind10_test.py $*
+${PYTHON_EXEC} -O bind10_test.py $*
+exec ${PYTHON_EXEC} -O args_test.py $*
 

Modified: experiments/python-binding/src/bin/bindctl/bindcmd.py
==============================================================================
--- experiments/python-binding/src/bin/bindctl/bindcmd.py (original)
+++ experiments/python-binding/src/bin/bindctl/bindcmd.py Wed Jun 30 13:47:21 2010
@@ -87,7 +87,7 @@
         '''Generate one session id for the connection. '''
         rand = os.urandom(16)
         now = time.time()
-        session_id = sha1(("%s%s%s" %(rand, now, 
+        session_id = sha1(("%s%s%s" %(rand, now,
                                       socket.gethostname())).encode())
         digest = session_id.hexdigest()
         return digest

Modified: experiments/python-binding/src/bin/cfgmgr/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/cfgmgr/Makefile.am (original)
+++ experiments/python-binding/src/bin/cfgmgr/Makefile.am Wed Jun 30 13:47:21 2010
@@ -1,8 +1,10 @@
+SUBDIRS = tests
+
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 pkglibexec_SCRIPTS = b10-cfgmgr
 
-CLEANFILES = b10-cfgmgr
+CLEANFILES = b10-cfgmgr b10-cfgmgr.pyc
 
 b10_cfgmgrdir = @localstatedir@/@PACKAGE@
 #B10_cfgmgr_DATA = 

Modified: experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.py.in
==============================================================================
--- experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.py.in (original)
+++ experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.py.in Wed Jun 30 13:47:21 2010
@@ -14,6 +14,8 @@
 # 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$
 
 import sys; sys.path.append ('@@PYTHONPATH@@')
 
@@ -38,7 +40,8 @@
     if cm:
         cm.running = False
 
-if __name__ == "__main__":
+def main():
+    global cm
     try:
         cm = ConfigManager(DATA_PATH)
         signal.signal(signal.SIGINT, signal_handler)
@@ -53,3 +56,6 @@
         print("[b10-cfgmgr] Interrupted, exiting")
     if cm:
         cm.write_config()
+
+if __name__ == "__main__":
+    main()

Modified: experiments/python-binding/src/bin/cmdctl/cmdctl.py.in
==============================================================================
--- experiments/python-binding/src/bin/cmdctl/cmdctl.py.in (original)
+++ experiments/python-binding/src/bin/cmdctl/cmdctl.py.in Wed Jun 30 13:47:21 2010
@@ -416,7 +416,7 @@
 def run(addr = 'localhost', port = 8080, idle_timeout = 1200, verbose = False):
     ''' Start cmdctl as one https server. '''
     if verbose:
-        sys.stdout.write("[b10-cmdctl] starting on :%s port:%d\n" %(addr, port))
+        sys.stdout.write("[b10-cmdctl] starting on %s port:%d\n" %(addr, port))
     httpd = SecureHTTPServer((addr, port), SecureHTTPRequestHandler, idle_timeout, verbose)
     httpd.serve_forever()
 

Modified: experiments/python-binding/src/bin/host/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/host/Makefile.am (original)
+++ experiments/python-binding/src/bin/host/Makefile.am Wed Jun 30 13:47:21 2010
@@ -7,7 +7,7 @@
 
 bin_PROGRAMS = host
 host_SOURCES = host.cc
-host_LDADD = $(top_builddir)/src/lib/dns/.libs/libdns.a
+host_LDADD = $(top_builddir)/src/lib/dns/.libs/libdns++.a
 host_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 
 #man_MANS = host.1

Modified: experiments/python-binding/src/bin/host/host.cc
==============================================================================
--- experiments/python-binding/src/bin/host/host.cc (original)
+++ experiments/python-binding/src/bin/host/host.cc Wed Jun 30 13:47:21 2010
@@ -19,6 +19,8 @@
 #include <sys/time.h>       // for gettimeofday
 #include <sys/socket.h>     // networking functions and definitions on FreeBSD
 
+#include <unistd.h>
+
 #include <string>
 #include <iostream>
 

Modified: experiments/python-binding/src/bin/loadzone/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/loadzone/Makefile.am (original)
+++ experiments/python-binding/src/bin/loadzone/Makefile.am Wed Jun 30 13:47:21 2010
@@ -1,3 +1,5 @@
+SUBDIRS = tests/correct
+SUBDIRS += tests/error
 bin_SCRIPTS = b10-loadzone
 
 CLEANFILES = b10-loadzone
@@ -22,23 +24,27 @@
 	$(mkinstalldirs) $(DESTDIR)/@localstatedir@/@PACKAGE@
 # TODO: permissions handled later
 
-EXTRA_DIST += testdata/README
-EXTRA_DIST += testdata/dsset-subzone.example.com.
-EXTRA_DIST += testdata/example.com
-EXTRA_DIST += testdata/example.com.signed
-EXTRA_DIST += testdata/Kexample.com.+005+04456.key
-EXTRA_DIST += testdata/Kexample.com.+005+04456.private
-EXTRA_DIST += testdata/Kexample.com.+005+33495.key
-EXTRA_DIST += testdata/Kexample.com.+005+33495.private
-EXTRA_DIST += testdata/Ksql1.example.com.+005+12447.key
-EXTRA_DIST += testdata/Ksql1.example.com.+005+12447.private
-EXTRA_DIST += testdata/Ksql1.example.com.+005+33313.key
-EXTRA_DIST += testdata/Ksql1.example.com.+005+33313.private
-EXTRA_DIST += testdata/Ksql2.example.com.+005+38482.key
-EXTRA_DIST += testdata/Ksql2.example.com.+005+38482.private
-EXTRA_DIST += testdata/Ksql2.example.com.+005+63192.key
-EXTRA_DIST += testdata/Ksql2.example.com.+005+63192.private
-EXTRA_DIST += testdata/sql1.example.com
-EXTRA_DIST += testdata/sql1.example.com.signed
-EXTRA_DIST += testdata/sql2.example.com
-EXTRA_DIST += testdata/sql2.example.com.signed
+EXTRA_DIST += tests/normal/README
+EXTRA_DIST += tests/normal/dsset-subzone.example.com
+EXTRA_DIST += tests/normal/example.com
+EXTRA_DIST += tests/normal/example.com.signed
+EXTRA_DIST += tests/normal/Kexample.com.+005+04456.key
+EXTRA_DIST += tests/normal/Kexample.com.+005+04456.private
+EXTRA_DIST += tests/normal/Kexample.com.+005+33495.key
+EXTRA_DIST += tests/normal/Kexample.com.+005+33495.private
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+12447.key
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+12447.private
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+33313.key
+EXTRA_DIST += tests/normal/Ksql1.example.com.+005+33313.private
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+38482.key
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+38482.private
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+63192.key
+EXTRA_DIST += tests/normal/Ksql2.example.com.+005+63192.private
+EXTRA_DIST += tests/normal/sql1.example.com
+EXTRA_DIST += tests/normal/sql1.example.com.signed
+EXTRA_DIST += tests/normal/sql2.example.com
+EXTRA_DIST += tests/normal/sql2.example.com.signed
+
+pytest:
+	$(SHELL) tests/correct/correct_test.sh
+	$(SHELL) tests/error/error_test.sh

Modified: experiments/python-binding/src/bin/loadzone/b10-loadzone.py.in
==============================================================================
--- experiments/python-binding/src/bin/loadzone/b10-loadzone.py.in (original)
+++ experiments/python-binding/src/bin/loadzone/b10-loadzone.py.in Wed Jun 30 13:47:21 2010
@@ -19,7 +19,8 @@
 import re, getopt
 import isc.datasrc
 from isc.datasrc.master import MasterFile
-
+import time
+import os
 #########################################################################
 # usage: print usage note and exit
 #########################################################################
@@ -57,23 +58,32 @@
     if len(args) != 1:
         usage()
     zonefile = args[0]
-
+    verbose = os.isatty(sys.stdout.fileno())
     try:
-        master = MasterFile(zonefile, initial_origin)
+        master = MasterFile(zonefile, initial_origin, verbose)
     except Exception as e:
-        print("Error reading zone file: " + str(e))
+        sys.stderr.write("Error reading zone file: %s\n" % str(e))
         exit(1)
 
     try:
         zone = master.zonename()
+        if verbose:
+            sys.stdout.write("Using SQLite3 database file %s\n" % dbfile)
+            sys.stdout.write("Zone name is %s\n" % zone)
+            sys.stdout.write("Loading file \"%s\"\n" % zonefile)
     except Exception as e:
-        print("Error reading zone file: " + str(e))
+        sys.stdout.write("\n")
+        sys.stderr.write("Error reading zone file: %s\n" % str(e))
         exit(1)
 
     try:
         isc.datasrc.sqlite3_ds.load(dbfile, zone, master.zonedata)
+        if verbose:
+            master.closeverbose()
+            sys.stdout.write("\nDone.\n")
     except Exception as e:
-        print("Error loading database: " + str(e))
+        sys.stdout.write("\n")
+        sys.stderr.write("Error loading database: %s\n"% str(e))
         exit(1)
 
 if __name__ == "__main__":

Modified: experiments/python-binding/src/bin/xfrin/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/xfrin/tests/Makefile.am (original)
+++ experiments/python-binding/src/bin/xfrin/tests/Makefile.am Wed Jun 30 13:47:21 2010
@@ -7,6 +7,6 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python \
+	env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

Modified: experiments/python-binding/src/bin/xfrin/xfrin.py.in
==============================================================================
--- experiments/python-binding/src/bin/xfrin/xfrin.py.in (original)
+++ experiments/python-binding/src/bin/xfrin/xfrin.py.in Wed Jun 30 13:47:21 2010
@@ -40,11 +40,14 @@
 # installed on the system
 if "B10_FROM_BUILD" in os.environ:
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrin"
+    AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
 else:
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
     SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+    AUTH_SPECFILE_PATH = SPECFILE_PATH
 SPECFILE_LOCATION = SPECFILE_PATH + "/xfrin.spec"
+AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + "/auth.spec"
 
 
 __version__ = 'BIND10'
@@ -434,7 +437,18 @@
         db_file = args.get('db_file')
         if not db_file:
             #TODO, the db file path should be got in auth server's configuration
-            db_file = '@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3'
+            # if we need access to this configuration more often, we
+            # should add it on start, and not remove it here
+            # (or, if we have writable ds, we might not need this in
+            # the first place)
+            self._cc.add_remote_config(AUTH_SPECFILE_LOCATION)
+            db_file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
+            if is_default and "B10_FROM_BUILD" in os.environ:
+                # this too should be unnecessary, but currently the
+                # 'from build' override isn't stored in the config
+                # (and we don't have writable datasources yet)
+                db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
+            self._cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
 
         return (zone_name, master_addrinfo, db_file)
 

Modified: experiments/python-binding/src/bin/xfrout/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/xfrout/tests/Makefile.am (original)
+++ experiments/python-binding/src/bin/xfrout/tests/Makefile.am Wed Jun 30 13:47:21 2010
@@ -7,6 +7,6 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
+	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

Modified: experiments/python-binding/src/bin/xfrout/tests/xfrout_test.py
==============================================================================
--- experiments/python-binding/src/bin/xfrout/tests/xfrout_test.py (original)
+++ experiments/python-binding/src/bin/xfrout/tests/xfrout_test.py Wed Jun 30 13:47:21 2010
@@ -75,7 +75,8 @@
 
     def setUp(self):
         request = MySocket(socket.AF_INET,socket.SOCK_STREAM)
-        self.xfrsess = MyXfroutSession(request, None, None)
+        self.log = isc.log.NSLogger('xfrout', '',  severity = 'critical', log_to_console = False )
+        self.xfrsess = MyXfroutSession(request, None, None, self.log)
         self.xfrsess.server = Dbserver()
         self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
         self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
@@ -193,7 +194,7 @@
 
     def test_dns_xfrout_start_formerror(self):
         # formerror
-        self.assertRaises(MessageTooShort, self.xfrsess.dns_xfrout_start, self.sock, b"\xd6=\x00\x00\x00\x01\x00")
+        self.xfrsess.dns_xfrout_start(self.sock, b"\xd6=\x00\x00\x00\x01\x00")
         sent_data = self.sock.readsent()
         self.assertEqual(len(sent_data), 0)
     
@@ -236,26 +237,33 @@
         reply_msg = self.sock.read_msg()
         self.assertEqual(reply_msg.get_rr_count(Section.ANSWER()), 2)
 
-        # set event
-        self.xfrsess.server._shutdown_event.set()
-        self.assertRaises(XfroutException, self.xfrsess._reply_xfrout_query, self.getmsg(), self.sock, "example.com.")
+class MyCCSession():
+    def __init__(self):
+        pass
+
+    def get_remote_config_value(self, module_name, identifier):
+        if module_name == "Auth" and identifier == "database_file":
+            return "initdb.file", False
+        else:
+            return "unknown", False
+    
 
 class MyUnixSockServer(UnixSockServer):
     def __init__(self):
         self._lock = threading.Lock()
         self._transfers_counter = 0
         self._shutdown_event = threading.Event()
-        self._db_file = "initdb.file"
         self._max_transfers_out = 10
+        self._cc = MyCCSession()
+        self._log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
 
 class TestUnixSockServer(unittest.TestCase):
     def setUp(self):
         self.unix = MyUnixSockServer()
      
     def test_updata_config_data(self):
-        self.unix.update_config_data({'transfers_out':10, 'db_file':"db.file"})
+        self.unix.update_config_data({'transfers_out':10 })
         self.assertEqual(self.unix._max_transfers_out, 10)
-        self.assertEqual(self.unix._db_file, "db.file")
 
     def test_get_db_file(self):
         self.assertEqual(self.unix.get_db_file(), "initdb.file")

Modified: experiments/python-binding/src/bin/xfrout/xfrout.py.in
==============================================================================
--- experiments/python-binding/src/bin/xfrout/xfrout.py.in (original)
+++ experiments/python-binding/src/bin/xfrout/xfrout.py.in Wed Jun 30 13:47:21 2010
@@ -26,8 +26,10 @@
 from socketserver import *
 import os
 from isc.config.ccsession import *
+from isc.log.log import *
 from isc.cc import SessionError
 import socket
+import select
 import errno
 from optparse import OptionParser, OptionValueError
 try:
@@ -40,22 +42,25 @@
 
 if "B10_FROM_BUILD" in os.environ:
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
-    UNIX_SOCKET_FILE = os.environ["B10_FROM_SOURCE"] + "/auth_xfrout_conn"
+    AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
+    UNIX_SOCKET_FILE= os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
 else:
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
     SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+    AUTH_SPECFILE_PATH = SPECFILE_PATH
     UNIX_SOCKET_FILE = "@@LOCALSTATEDIR@@/auth_xfrout_conn"
+
 SPECFILE_LOCATION = SPECFILE_PATH + "/xfrout.spec"
-
+AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + os.sep + "auth.spec"
 MAX_TRANSFERS_OUT = 10
-verbose_mode = False
-
-
-class XfroutException(Exception): pass
-class TmpException(Exception): pass
+VERBOSE_MODE = False
 
 class XfroutSession(BaseRequestHandler):
+    def __init__(self, request, client_address, server, log):
+        BaseRequestHandler.__init__(self, request, client_address, server)
+        self._log = log
+
     def handle(self):
         fd = recv_fd(self.request.fileno())
         
@@ -63,8 +68,7 @@
             # This may happen when one xfrout process try to connect to
             # xfrout unix socket server, to check whether there is another
             # xfrout running. 
-            print("[b10-xfrout] Failed to receive the FD for XFR connection, "
-                  "maybe because another xfrout process was started.")
+            self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
             return
 
         data_len = self.request.recv(2)
@@ -73,9 +77,8 @@
         sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
         try:
             self.dns_xfrout_start(sock, msgdata)
-        except TmpException as e:
-            if verbose_mode:
-                self.log_msg(str(e))
+        except Exception as e:
+            self._log.log_message("error", str(e))
 
         sock.shutdown(socket.SHUT_RDWR)
         sock.close()
@@ -88,9 +91,8 @@
         try:
             msg = Message(Message.PARSE)
             Message.from_wire(msg, mdata)
-        except TmpException as err:
-            if verbose_mode:
-                self.log_msg(str(err))
+        except Exception as err:
+            self._log.log_message("error", str(err))
             return Rcode.FORMERR(), None
 
         return Rcode.NOERROR(), msg
@@ -180,16 +182,11 @@
             return self. _reply_query_with_error_rcode(msg, sock, rcode_)
 
         try:
-            if verbose_mode:
-                self.log_msg("transfer of '%s/IN': AXFR started" % zone_name)
-
+            self._log.log_message("info", "transfer of '%s/IN': AXFR started" % zone_name)
             self._reply_xfrout_query(msg, sock, zone_name)
-
-            if verbose_mode:
-                self.log_msg("transfer of '%s/IN': AXFR end" % zone_name)
-        except TmpException as err:
-            if verbose_mode:
-                sys.stderr.write("[b10-xfrout] %s\n" % str(err))
+            self._log.log_message("info", "transfer of '%s/IN': AXFR end" % zone_name)
+        except Exception as err:
+            self._log.log_message("error", str(err))
 
         self.server.decrease_transfers_counter()
         return    
@@ -261,7 +258,7 @@
         # the message length to know if the rrset has been added sucessfully.
         for rr_data in sqlite3_ds.get_zone_datas(zone_name, self.server.get_db_file()):
             if  self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
-                raise XfroutException("shutdown!")
+                self._log.log_message("error", "shutdown!")
 
             # TODO: RRType.SOA() ?
             if RRType(rr_data[5]) == RRType("SOA"): #ignore soa record
@@ -281,21 +278,24 @@
 
         self._send_message_with_last_soa(msg, sock, rrset_soa)
 
-    def log_msg(self, msg):
-        print('[b10-xfrout] ', msg)
-   
 
 class UnixSockServer(ThreadingUnixStreamServer):
     '''The unix domain socket server which accept xfr query sent from auth server.'''
 
-    def __init__(self, sock_file, handle_class, shutdown_event, config_data):
+    def __init__(self, sock_file, handle_class, shutdown_event, config_data, cc, log):
         self._remove_unused_sock_file(sock_file)
         self._sock_file = sock_file
         ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
         self._lock = threading.Lock()
         self._transfers_counter = 0
         self._shutdown_event = shutdown_event
+        self._log = log
         self.update_config_data(config_data)
+        self._cc = cc
+
+    def finish_request(self, request, client_address):
+        '''Finish one request by instantiating RequestHandlerClass.'''
+        self.RequestHandlerClass(request, client_address, self, self._log)
 
     def _remove_unused_sock_file(self, sock_file):
         '''Try to remove the socket file. If the file is being used 
@@ -332,22 +332,27 @@
         ThreadingUnixStreamServer.shutdown(self)
         try:
             os.unlink(self._sock_file)
-        except:
-            pass
+        except Exception as e:
+            self._log.log_message("error", str(e))
 
     def update_config_data(self, new_config):
         '''Apply the new config setting of xfrout module. '''
-
+        self._log.log_message('info', 'update config data start.')
         self._lock.acquire()
         self._max_transfers_out = new_config.get('transfers_out')
-        self._db_file = new_config.get('db_file')
+        self._log.log_message('info', 'max transfer out : %d', self._max_transfers_out)
         self._lock.release()
+        self._log.log_message('info', 'update config data complete.')
 
     def get_db_file(self):
-        self._lock.acquire()
-        file = self._db_file
-        self._lock.release()
+        file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
+        # this too should be unnecessary, but currently the
+        # 'from build' override isn't stored in the config
+        # (and we don't have indirect python access to datasources yet)
+        if is_default and "B10_FROM_BUILD" in os.environ:
+            file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
         return file
+
 
     def increase_transfers_counter(self):
         '''Return False, if counter + 1 > max_transfers_out, or else
@@ -367,29 +372,45 @@
         self._lock.release()
 
 def listen_on_xfr_query(unix_socket_server):
-
     '''Listen xfr query in one single thread. Polls for shutdown 
     every 0.1 seconds, is there a better time?
     '''
-    unix_socket_server.serve_forever(poll_interval = 0.1)
+
+    while True:
+        try:
+            unix_socket_server.serve_forever(poll_interval = 0.1)
+        except select.error as err:
+            # serve_forever() calls select.select(), which can be 
+            # interrupted.
+            # If it is interrupted, it raises select.error with the 
+            # errno set to EINTR. We ignore this case, and let the
+            # normal program flow continue by trying serve_forever()
+            # again.
+            if err.args[0] != errno.EINTR: raise
+
    
 
 class XfroutServer:
     def __init__(self):
         self._unix_socket_server = None
+        self._log = None
         self._listen_sock_file = UNIX_SOCKET_FILE 
         self._shutdown_event = threading.Event()
         self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
+        self._cc.add_remote_config(AUTH_SPECFILE_LOCATION);
         self._config_data = self._cc.get_full_config()
         self._cc.start()
+        self._log = isc.log.NSLogger(self._config_data.get('log_name'), self._config_data.get('log_file'),
+                                self._config_data.get('log_severity'), self._config_data.get('log_versions'),
+                                self._config_data.get('log_max_bytes'), True)
         self._start_xfr_query_listener()
-
 
     def _start_xfr_query_listener(self):
         '''Start a new thread to accept xfr query. '''
     
         self._unix_socket_server = UnixSockServer(self._listen_sock_file, XfroutSession, 
-                                                  self._shutdown_event, self._config_data);
+                                                  self._shutdown_event, self._config_data,
+                                                  self._cc, self._log);
         listener = threading.Thread(target = listen_on_xfr_query, args = (self._unix_socket_server,))
         listener.start()
 
@@ -403,6 +424,9 @@
                 continue
             self._config_data[key] = new_config[key]
         
+        if self._log:
+            self._log.update_config(new_config)
+
         if self._unix_socket_server:
             self._unix_socket_server.update_config_data(self._config_data)
 
@@ -428,8 +452,7 @@
 
     def command_handler(self, cmd, args):
         if cmd == "shutdown":
-            if verbose_mode:
-                print("[b10-xfrout] Received shutdown command")
+            self._log.log_message("info", "Received shutdown command.")
             self.shutdown()
             answer = create_answer(0)
         else: 
@@ -464,18 +487,18 @@
         parser = OptionParser()
         set_cmd_options(parser)
         (options, args) = parser.parse_args()
-        verbose_mode = options.verbose
+        VERBOSE_MODE = options.verbose
 
         set_signal_handler()
         xfrout_server = XfroutServer()
         xfrout_server.run()
     except KeyboardInterrupt:
-        print("[b10-xfrout] exit xfrout process")
+        sys.stderr.write("[b10-xfrout] exit xfrout process")
     except SessionError as e:
-        print('[b10-xfrout] Error creating xfrout, '
-              'is the command channel daemon running?' )
+        sys.stderr.write("[b10-xfrout] Error creating xfrout," 
+                           "is the command channel daemon running?")
     except ModuleCCSessionError as e:
-        print('[b10-xfrout] exit xfrout process:', e)
+        sys.stderr.write("info", '[b10-xfrout] exit xfrout process:', e)
 
     if xfrout_server:
         xfrout_server.shutdown()

Modified: experiments/python-binding/src/bin/xfrout/xfrout.spec.pre.in
==============================================================================
--- experiments/python-binding/src/bin/xfrout/xfrout.spec.pre.in (original)
+++ experiments/python-binding/src/bin/xfrout/xfrout.spec.pre.in Wed Jun 30 13:47:21 2010
@@ -12,7 +12,37 @@
          "item_name": "db_file",
          "item_type": "string",
          "item_optional": False,
-         "item_default": '@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3'
+         "item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3"
+       },
+       {
+         "item_name": "log_name",
+         "item_type": "string",
+         "item_optional": False,
+         "item_default": "Xfrout"
+       },
+       {
+         "item_name": "log_file",
+    	 "item_type": "string",
+         "item_optional": False,
+         "item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/log/Xfrout.log"
+       },
+       {
+         "item_name": "log_severity",
+    	 "item_type": "string",
+         "item_optional": False,
+    	 "item_default": "debug"
+       },
+       {
+         "item_name": "log_versions",
+    	 "item_type": "integer",
+         "item_optional": False,
+    	 "item_default": 5
+       },
+       {
+         "item_name": "log_max_bytes",
+    	 "item_type": "integer",
+         "item_optional": False,
+    	 "item_default": 1048576
        }
       ],
       "commands": [

Modified: experiments/python-binding/src/lib/cc/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/cc/Makefile.am (original)
+++ experiments/python-binding/src/lib/cc/Makefile.am Wed Jun 30 13:47:21 2010
@@ -6,10 +6,12 @@
 # error.  Unfortunately there doesn't seem to be an easy way to selectively
 # avoid the error.  As a short term workaround we suppress this warning
 # for the entire this module.  See also src/bin/auth/Makefile.am.
+if USE_GXX
 AM_CXXFLAGS += -Wno-unused-parameter
+endif
 
-lib_LIBRARIES = libcc.a
-libcc_a_SOURCES = data.cc data.h session.cc session.h
+lib_LTLIBRARIES = libcc.la
+libcc_la_SOURCES = data.cc data.h session.cc session.h
 
 CLEANFILES = *.gcno *.gcda session_config.h
 
@@ -27,8 +29,8 @@
 # TODO: remove PTHREAD_LDFLAGS (and from configure too)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) $(PTHREAD_LDFLAGS)
 
-run_unittests_LDADD = libcc.a $(GTEST_LDADD)
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD = libcc.la $(GTEST_LDADD)
+run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns++.a
 run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 
 endif

Modified: experiments/python-binding/src/lib/cc/session.cc
==============================================================================
--- experiments/python-binding/src/lib/cc/session.cc (original)
+++ experiments/python-binding/src/lib/cc/session.cc Wed Jun 30 13:47:21 2010
@@ -19,6 +19,17 @@
 
 #include <stdint.h>
 
+// XXX: there seems to be a strange dependency between ASIO and std library
+// definitions.  On some platforms if we include std headers before ASIO
+// headers unexpected behaviors will happen.
+// A middle term solution is to generalize our local wrapper interface
+// (currently only available for the auth server), where all such portability
+// issues are hidden, and to have other modules use the wrapper.
+#include <unistd.h>             // for some IPC/network system calls
+#include <asio.hpp>
+#include <asio/error_code.hpp>
+#include <asio/system_error.hpp>
+
 #include <cstdio>
 #include <vector>
 #include <iostream>
@@ -28,10 +39,6 @@
 
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
-
-#include <asio.hpp>
-#include <asio/error_code.hpp>
-#include <asio/system_error.hpp>
 
 #include <exceptions/exceptions.h>
 

Modified: experiments/python-binding/src/lib/cc/session_unittests.cc
==============================================================================
--- experiments/python-binding/src/lib/cc/session_unittests.cc (original)
+++ experiments/python-binding/src/lib/cc/session_unittests.cc Wed Jun 30 13:47:21 2010
@@ -15,10 +15,13 @@
 // $Id: data_unittests.cc 1899 2010-05-21 12:03:59Z jelte $
 
 #include "config.h"
+
+// XXX: the ASIO header must be included before others.  See session.cc.
+#include <asio.hpp>
+
 #include <gtest/gtest.h>
 #include <session.h>
 
-#include <asio.hpp>
 #include <exceptions/exceptions.h>
 
 using namespace isc::cc;

Modified: experiments/python-binding/src/lib/config/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/config/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/config/tests/Makefile.am Wed Jun 30 13:47:21 2010
@@ -2,7 +2,9 @@
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 # see src/lib/cc/Makefile.am for -Wno-unused-parameter
+if USE_GXX
 AM_CXXFLAGS += -Wno-unused-parameter
+endif
 
 CLEANFILES = *.gcno *.gcda
 
@@ -20,6 +22,9 @@
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD += libfake_session.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+# link *only* to data.o from lib/cc (more importantly, don't link in
+# the session class provided there, since we use our own fake_session
+# here)
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/data.o
 
 endif

Modified: experiments/python-binding/src/lib/datasrc/data_source.cc
==============================================================================
--- experiments/python-binding/src/lib/datasrc/data_source.cc (original)
+++ experiments/python-binding/src/lib/datasrc/data_source.cc Wed Jun 30 13:47:21 2010
@@ -192,7 +192,7 @@
         // Lookup failed
         return (false);
     }
-    
+
     // Referral bit is expected, so clear it when checking flags
     if ((newtask.flags & ~DataSrc::REFERRAL) != 0) {
         return (false);
@@ -202,18 +202,18 @@
 }
 
 // Match downward, from the zone apex to the query name, looking for
-// referrals.
+// referrals.  Note that we exclude the apex name and query name themselves;
+// they'll be handled in a normal lookup in the zone.
 inline bool
 hasDelegation(const DataSrc* ds, const Name* zonename, Query& q,
               QueryTaskPtr task)
 {
-    const int nlen = task->qname.getLabelCount();
-    const int diff = nlen - zonename->getLabelCount();
+    const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
     if (diff > 1) {
         bool found = false;
         RRsetList ref;
-        for (int i = diff; i > 1; --i) {
-            const Name sub(task->qname.split(i - 1, nlen - i));
+        for (int i = diff - 1; i > 0; --i) {
+            const Name sub(task->qname.split(i));
             if (refQuery(sub, q.qclass(), ds, zonename, ref)) {
                 found = true;
                 break;
@@ -360,11 +360,11 @@
 
         // Find the closest provable enclosing name for QNAME
         Name enclosure(zonename);
-        const int nlen = task->qname.getLabelCount();
-        const int diff = nlen - enclosure.getLabelCount();
+        const int diff = task->qname.getLabelCount() -
+            enclosure.getLabelCount();
         string hash2;
         for (int i = 1; i <= diff; ++i) {
-            enclosure = task->qname.split(i, nlen - i);
+            enclosure = task->qname.split(i);
             string nodehash(nsec3->getHash(enclosure));
             if (nodehash == hash1) {
                 break;
@@ -434,8 +434,7 @@
         return (DataSrc::SUCCESS);
     }
 
-    const int nlen = task->qname.getLabelCount();
-    const int diff = nlen - zonename->getLabelCount();
+    const int diff = task->qname.getLabelCount() - zonename->getLabelCount();
     if (diff < 1) {
         return (DataSrc::SUCCESS);
     }
@@ -445,7 +444,7 @@
     bool cname = false;
 
     for (int i = 1; i <= diff; ++i) {
-        const Name& wname(star.concatenate(task->qname.split(i, nlen - i)));
+        const Name& wname(star.concatenate(task->qname.split(i)));
         QueryTask newtask(wname, task->qclass, task->qtype, Section::ANSWER(),
                           QueryTask::AUTH_QUERY); 
         result = doQueryTask(ds, zonename, newtask, wild);
@@ -541,8 +540,7 @@
         // (Note that RRtype DS queries need to go to the parent.)
         const int nlabels = task->qname.getLabelCount() - 1;
         NameMatch match(nlabels != 0 && task->qtype == RRType::DS() ?
-                        task->qname.split(1, task->qname.getLabelCount() - 1) :
-                        task->qname);
+                        task->qname.split(1) : task->qname);
         findClosestEnclosure(match, task->qclass);
         const DataSrc* datasource = match.bestDataSrc();
         const Name* zonename = match.closestName();
@@ -615,9 +613,12 @@
                     // the authority section.
                     RRsetList auth;
                     if (!refQuery(*zonename, q.qclass(), datasource, zonename,
-                                  auth)) {
-                        m.setRcode(Rcode::SERVFAIL());
-                        return;
+                                  auth) ||
+                        !auth.findRRset(RRType::NS(),
+                                        datasource->getClass())) {
+                        isc_throw(DataSourceError,
+                                  "NS RR not found in " << *zonename << "/" <<
+                                  datasource->getClass());
                     }
 
                     copyAuth(q, auth);
@@ -706,8 +707,9 @@
 
                 result = addSOA(q, zonename, datasource);
                 if (result != SUCCESS) {
-                    m.setRcode(Rcode::SERVFAIL());
-                    return;
+                    isc_throw(DataSourceError,
+                              "SOA RR not found in" << *zonename <<
+                              "/" << datasource->getClass());
                 }
             }
 

Modified: experiments/python-binding/src/lib/datasrc/sqlite3_datasrc.cc
==============================================================================
--- experiments/python-binding/src/lib/datasrc/sqlite3_datasrc.cc (original)
+++ experiments/python-binding/src/lib/datasrc/sqlite3_datasrc.cc Wed Jun 30 13:47:21 2010
@@ -330,7 +330,7 @@
 Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
     const unsigned int nlabels = name.getLabelCount();
     for (unsigned int i = 0; i < nlabels; ++i) {
-        const Name matchname(name.split(i, nlabels - i));
+        const Name matchname(name.split(i));
         const int rc = hasExactZone(matchname.toText().c_str());
         if (rc >= 0) {
             if (position != NULL) {
@@ -356,9 +356,7 @@
         return;
     }
 
-    match.update(*this, match.qname().split(position,
-                                            match.qname().getLabelCount() -
-                                            position));
+    match.update(*this, match.qname().split(position));
 }
 
 DataSrc::Result

Modified: experiments/python-binding/src/lib/datasrc/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/datasrc/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/datasrc/tests/Makefile.am Wed Jun 30 13:47:21 2010
@@ -22,8 +22,8 @@
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
 run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a 
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a 
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a 
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a 
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 endif
 

Modified: experiments/python-binding/src/lib/datasrc/tests/datasrc_unittest.cc
==============================================================================
--- experiments/python-binding/src/lib/datasrc/tests/datasrc_unittest.cc (original)
+++ experiments/python-binding/src/lib/datasrc/tests/datasrc_unittest.cc Wed Jun 30 13:47:21 2010
@@ -540,6 +540,15 @@
     EXPECT_TRUE(it->isLast());
 }
 
+TEST_F(DataSrcTest, DnameExact) {
+    // The example.org test zone has a DNAME RR for dname2.foo.example.org.
+    // A query for that name with a different RR type than DNAME shouldn't
+    // confuse delegation processing.
+    createAndProcessQuery(Name("dname2.foo.example.org"), RRClass::IN(),
+                          RRType::A());
+    headerCheck(msg, Rcode::NOERROR(), true, true, true, 0, 1, 0);
+}
+
 TEST_F(DataSrcTest, Cname) {
     readAndProcessQuery("q_cname");
 
@@ -761,7 +770,7 @@
 }
 
 TEST_F(DataSrcTest, CNAMELoop) {
-    createAndProcessQuery(Name("loop1.example.com"), RRClass::IN(),
+    createAndProcessQuery(Name("one.loop.example"), RRClass::IN(),
                           RRType::A());
 }
 
@@ -843,8 +852,8 @@
     EXPECT_EQ(0, ds.dataSrcCount());
 }
 
-#if 0                           // currently fails
-TEST_F(DataSrcTest, synthesizedCnameTooLong) {
+// currently fails
+TEST_F(DataSrcTest, DISABLED_synthesizedCnameTooLong) {
     // qname has the possible max length (255 octets).  it matches a DNAME,
     // and the synthesized CNAME would exceed the valid length.
     createAndProcessQuery(
@@ -854,6 +863,23 @@
              "0123456789abcdef0123456789abcdef0123456789a.dname.example.org."),
         RRClass::IN(), RRType::A());
 }
-#endif
-
-}
+
+TEST_F(DataSrcTest, noNSZone) {
+    EXPECT_THROW(createAndProcessQuery(Name("www.nons.example"),
+                                       RRClass::IN(), RRType::A()),
+                 DataSourceError);
+}
+
+TEST_F(DataSrcTest, noNSButDnameZone) {
+    EXPECT_THROW(createAndProcessQuery(Name("www.nons-dname.example"),
+                                       RRClass::IN(), RRType::A()),
+                 DataSourceError);
+}
+
+TEST_F(DataSrcTest, noSOAZone) {
+    EXPECT_THROW(createAndProcessQuery(Name("notexist.nosoa.example"),
+                                       RRClass::IN(), RRType::A()),
+                 DataSourceError);
+}
+
+}

Modified: experiments/python-binding/src/lib/datasrc/tests/test_datasrc.cc
==============================================================================
--- experiments/python-binding/src/lib/datasrc/tests/test_datasrc.cc (original)
+++ experiments/python-binding/src/lib/datasrc/tests/test_datasrc.cc Wed Jun 30 13:47:21 2010
@@ -17,6 +17,8 @@
 #include "config.h"
 
 #include <cassert>
+
+#include <algorithm>
 
 #include <dns/tests/unittest_util.h>
 #include "test_datasrc.h"
@@ -45,69 +47,297 @@
 namespace datasrc {
 
 namespace {
-const Name example("example.com");
-const Name sql1("sql1.example.com");
-const Name www_sql1("www.sql1.example.com");
-const Name www("www.example.com");
-const Name foo("foo.example.com");
-const Name dns01("dns01.example.com");
-const Name dns02("dns02.example.com");
-const Name dns03("dns03.example.com");
-const Name cnameint("cname-int.example.com");
-const Name cnameext("cname-ext.example.com");
-const Name dname("dname.example.com");
-const Name wild("*.wild.example.com");
-const Name wild2("*.wild2.example.com");
-const Name wild3("*.wild3.example.com");
-const Name subzone("subzone.example.com");
-const Name loop1("loop1.example.com");
-const Name loop2("loop2.example.com");
-
-RRsetPtr example_ns;
-RRsetPtr example_soa;
-RRsetPtr example_nsec;
-RRsetPtr www_a;
-RRsetPtr www_nsec;
-RRsetPtr foo_cname;
-RRsetPtr foo_nsec;
-RRsetPtr cnameint_cname;
-RRsetPtr cnameint_nsec;
-RRsetPtr cnameext_cname;
-RRsetPtr cnameext_nsec;
-RRsetPtr dns01_a;
-RRsetPtr dns01_nsec;
-RRsetPtr dns02_a;
-RRsetPtr dns02_nsec;
-RRsetPtr dns03_a;
-RRsetPtr dns03_nsec;
-RRsetPtr wild_a;
-RRsetPtr wild_nsec;
-RRsetPtr wild2_cname;
-RRsetPtr wild2_nsec;
-RRsetPtr wild3_cname;
-RRsetPtr wild3_nsec;
-RRsetPtr dname_dname;
-RRsetPtr dname_nsec;
-RRsetPtr sql1_ns;
-RRsetPtr sql1_soa;
-RRsetPtr sql1_nsec;
-RRsetPtr sql1_ds;
-RRsetPtr sql1_ds_nsec;
-RRsetPtr www_sql1_a;
-RRsetPtr www_sql1_nsec;
-RRsetPtr subzone_ns;
-RRsetPtr subzone_nsec;
-RRsetPtr subzone_glue1;
-RRsetPtr subzone_glue2;
-RRsetPtr subzone_ds;
-RRsetPtr loop1_cname;
-RRsetPtr loop2_cname;
+
+// This is a mock data source for testing.  It can contain multiple zones.
+// The content of each zone should be configured in the form of RRData{}.
+// Each RRData element is a tuple of char strings, representing
+// "name, RRtype, RDATA".  For simplicity we use the same single TTL for
+// RRs (TEST_TTL) defined below.
+// Multiple RRs of the same pair of (name, RRtype) can be defined, but
+// they must not be interleaved with other types of pair.  For example,
+// This is okay:
+// {"example.com", "AAAA", "2001:db8::1"},
+// {"example.com", "AAAA", "2001:db8::2"},
+// ...
+// but this is invalid:
+// {"example.com", "AAAA", "2001:db8::1"},
+// {"example.com", "A", "192.0.2.1"},
+// {"example.com", "AAAA", "2001:db8::2"},
+// ...
+// If an RRset is associated with an RRSIG, the RRSIG must immediately follow
+// the RRset to be signed.  Currently, only one (or zero) RRSIG can be
+// specified per RRset.
+//
+// Names are sorted internally, and don't have to be sorted in the data.
+//
+// A zone is defined in the form of ZoneData{}, which contains:
+// zone name (character string)
+// RRclass (character string)
+// A pointer to in-zone RRs in the form of RRData{}
+// A pointer to glue RRs in the form of RRData{}
+// Glues can be omitted, in which case a convenient constant "empty_records"
+// can be specified.
+
+// For simplicity we use the same single TTL for all test RRs.
+const uint32_t TEST_TTL = 3600;
+
+struct RRData {
+    const char* const name;
+    const char* const rrtype;
+    const char* const rdata;
+};
+
+struct ZoneData {
+    const char* const zone_name;
+    const char* const rrclass;
+    const struct RRData* records;
+    const struct RRData* glue_records;
+};
+
+//
+// zone data for example.com
+//
+const struct RRData example_com_records[] = {
+    // example.com
+    {"example.com", "NS", "dns01.example.com"},
+    {"example.com", "NS", "dns02.example.com"},
+    {"example.com", "NS", "dns03.example.com"},
+    {"example.com", "RRSIG", "NS 5 2 3600 20100322084538 20100220084538 33495 example.com. ClcrfjkQZUY5L6ZlCkU3cJHzcrEGrofKSVeeoeZ+w6yeEowFNVXs2YBo3tom53DiCrdD9rs3feVSLGW5rjsz/O6lDuomgQG+EVSnWa7GTIPBXj1BmDXXp3XxeldYmhf4UzaN5BA+RUA5E8NChNKuNNof76j2S9tilfN/kvpy4fw="},
+    {"example.com", "SOA", "master.example.com. admin.example.com. 1234 3600 1800 2419200 7200"},
+    {"example.com", "RRSIG", "SOA 5 2 3600 20100322084538 20100220084538 33495 example.com.  KUun66Qaw36osk2BJS6U1fAy3PPDkNo2QK4meGNbDBY8q8b+f2o+IXJ14YCvssGl1ORW0CcLnDRxssnk8V/Svmj5iFhO+8HC2hnVBdi2zewvdVtwRb+lWwKN7pkXXwuy6g1t9WCd/j5FCc/wgxqtZUTPb6XgZcnHrORDMOTqLs4="},
+    {"example.com", "NSEC", "cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY"},
+    {"example.com", "RRSIG", "NSEC 5 2 7200 20100322084538 20100220084538 33495 example.com. KxuVaPPKNPJzr/q+cJPiNlkHVTQK0LVsgTbSqruXQc25lAd0wn5oKUtxL1bEAchHkfA8eLzcYCj2ZqqAv9OJubw53mfskTad7UHs4Uj2RTrIsNGMCiZGgOpvNb9JcWpQtoyXVT1uNse+Qsbeir0eyeYIufUynFU041jtNrlJMio="},
+
+    // dns01.example.com
+    {"dns01.example.com", "A", "192.0.2.1"},
+    {"dns01.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. NIawlZLk8WZAjNux7oQM2mslfW52OZFFkWt++7FHu2SU98XqEeKfCMnpgtWe5T8Nr9cS8df901iEOJoWQzGTEaHYUBtEhsSjBVn7mKp3fz6473a2xxy75SUKZ0rxjNXSZ8Q5rnFmkX0HTH2Sg51mtjH6aC2pfheQnA2t193BnSg="},
+    {"dns01.example.com", "NSEC", "dns02.example.com. A RRSIG NSEC"},
+    {"dns01.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. EkyeshmMNP9xiAz6mDFDIwksTdmkF9zsFzLuVKAgK6eUk7St6tp5PSvjA8nWol0vdvvz4LK85a4ffTFEiNRyvWeYP2vOhEkyDcrwuCd8Vc3jh/8Sm1Js+nX7hJStrZGFvp2TWPpt9nKH5p3MxXvTb/YVurnue0xSeFAE17O3+I0="},
+
+    // dns02.example.com
+    {"dns02.example.com", "A", "192.0.2.2"},
+    {"dns02.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. XJtVMbUIRE0mk6Hn/Nx6k36jaxaBDPK2/IYB6vCQjJETz6gW4T6q/H/eY9/Lsw5iYPFhoBRDxT4XFj575t98kELXnJe1WhuMbRPlOhyOjxkLECaUne/sbFPOtbGFx9ohuojI0RgxxZiCFaO8wJuv6nfPuzmlLajWS6z9NZeOMIk="},
+    {"dns02.example.com", "NSEC", "dns03.example.com. A RRSIG NSEC"},
+    {"dns02.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. imBNTMB3sPU4kblcaAH6V7lCVt5xgtAybi3DA/SbLEulLaV2NE6vcoEn/AieaM4mOJicQnUDj/H+1hSEhzxU2tRM8zfVlvztxQWn6eh7ZR4mKfNDSvRUGU9ykhpwMyC7wjOt1j5bcSA/OTnLRAilslnJyOM4bSaxVEFo8YPjncY="},
+
+    // dns03.example.com
+    {"dns03.example.com", "A", "192.0.2.3"},
+    {"dns03.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. Ubrcm1H+F6m8khle7P9zU8eO+Jtuj+1Vx1MM5KAkmZPJwQe9uTcoCpQa6DXOGG9kajDTnNN1Be1gkZuJDTZJG4SmJLXLbNY3RDnxpGmWta3qs/VgDq78/YM8ropt1/s7YKyrCfGE2ff+FUB0mLObiG01ZV2gu5HJzgE7SEWLEiI="},
+    {"dns03.example.com", "NSEC", "foo.example.com. A RRSIG NSEC"},
+    {"dns03.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com.  nn829Xw5CJFnPHwI9WHeT5epQv+odtCkHnjlPFGoPTLOyiks+041UmMqtq3uiSp4d2meMSe9UuDvoROT0L6NTtQQvVqiDhTn0irTFw1uw7fO8ZTG7eyu6Ypfz0+HvfbNvd4kMoD2OTgADRXPVsCTwK+PBOIIG9YTEQfl8pCqW5g="},
+
+    // www.example.com
+    {"www.example.com", "A", "192.0.2.1"},
+    {"www.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. qyFyyV/mE8x4pdhudr5iycwhDsva31MzwO1kBR+bDKvzJg8mN8KxlPZrOlNNUhd3YRXQVwieMyxOTWRPXoxrNEDkNwimXkfe3rrHY7ibV9eNS4OIBUjb44VjCNr9CmQSzfuQ2yxO2r+YIuPYHRCjieD4xh6t9ay4IaCN/tDAJ+Q="},
+    {"www.example.com", "NSEC", "example.com. A RRSIG NSEC"},
+    {"www.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. ZLZlSVBa2oe4U+7SZASnypP2VkI5gg1/1cVGqYUvfYNIUkcVMWDgn7DZCfpmo+2vdlV/4VhAc+sjDd+X+e57XGnW8+lqZHvG6NMMhmSGmeATD3D+8lEJJGo0dxoN4rHJQyp/eT2S4nChz+D/ze+YRagYxGF7pXm9zcrw3kKZGTs="},
+
+    // *.wild.example.com
+    {"*.wild.example.com", "A", "192.0.2.2"},
+    {"*.wild.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. FdO+UWONgtLKFxUzzygGunw67F9y8SzsP7yOLEYVJclRR8X3Ii62L0gtQHq2y0TcKsXttRsD6XY+tM5P/pgXlTNi7Bk4Fgb0PIDPjOsfT4DrS80kWn0YbinM/4/FA1j5ru5sTTboOY5UGhvDnoA9ogNuQQYb2/3wkoH0PrA2Q/0="},
+    {"*.wild.example.com", "NSEC", "*.wild2.example.com. A RRSIG NSEC"},
+    {"*.wild.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. OoGYslRj4xjZnBuzgOqsrvkDAHWycmQzbUxCRmgWnCbXiobJK7/ynONH3jm8G3vGlU0lwpHkhNs6cUK+6Nu8W49X3MT0Xksl/brroLcXYLi3vfxnYUNMMpXdeFl6WNNfoJRo90F/f/TWXAClRrDS29qiG3G1PEJZikIxZsZ0tyM="},
+
+    // *.wild2.example.com
+    {"*.wild2.example.com", "CNAME", "www.example.com"},
+    {"*.wild2.example.com", "RRSIG", "CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="},
+    {"*.wild2.example.com", "NSEC", "*.wild3.example.com. CNAME RRSIG NSEC"},
+    {"*.wild2.example.com", "RRSIG", "NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="},
+
+    // *.wild3.example.com -- a wildcard record with a lame CNAME
+    {"*.wild3.example.com", "CNAME", "spork.example.com"},
+    {"*.wild3.example.com", "RRSIG", "CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="},
+    {"*.wild3.example.com", "NSEC", "www.example.com. CNAME RRSIG NSEC"},
+    {"*.wild3.example.com", "RRSIG", "NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="},
+
+    // foo.example.com
+    {"foo.example.com", "CNAME", "cnametest.flame.org"},
+    {"foo.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. DSqkLnsh0gCeCPVW/Q8viy9GNP+KHmFGfWqyVG1S6koBtGN/VQQ16M4PHZ9Zssmf/JcDVJNIhAChHPE2WJiaPCNGTprsaUshf1Q2vMPVnkrJKgDY8SVRYMptmT8eaT0gGri4KhqRoFpMT5OYfesybwDgfhFSQQAh6ps3bIUsy4o="},
+    {"foo.example.com", "NSEC", "mail.example.com. CNAME RRSIG NSEC"},
+    {"foo.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. RTQwlSqui6StUYye1KCSOEr1d3irndWFqHBpwP7g7n+w8EDXJ8I7lYgwzHvlQt6BLAxe5fUDi7ct8M5hXvsm7FoWPZ5wXH+2/eJUCYxIw4vezKMkMwBP6M/YkJ2CMqY8DppYf60QaLDONQAr7AcK/naSyioeI5h6eaoVitUDMso="},
+
+    // cname-int.example.com
+    {"cname-int.example.com", "CNAME", "www.example.com."},
+    {"cname-int.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. U1wjt0XY9xjTwvUmWSUcfLGMhCjfX2ylWfHrycy50x2oxcK9z94E1ejen9wDTIEBSGYgi6wpZ8RK0+02N1DWTGpDqNXd7aFRfDrWQJ/q/XJHDx0vlcmhkWhrT82LBfKxkrptOzchuSo/c0mpK+mpiIMc1VOwY+yuQ2ALfcD6EHw="},
+    {"cname-int.example.com", "NSEC", "dname.example.com. CNAME RRSIG NSEC"},
+    {"cname-int.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. rbV+gaxfrsoha59NOLF4EFyWQ+GuFCVK/8D77x1atan3HNlXBlZ1smgudKTaJ3CtlobIDt0MEdPxY1yn2Tskw/5mlP1PWf8oaP3BwGSQdn4gLI8+sMpNOPFEdXpxqxngm2F6/7fqniL1QuSAQBEdO+5UiCAgnncPmAsSJg3u1zg="},
+
+    // cname-ext.example.com
+    {"cname-ext.example.com", "CNAME", "www.sql1.example.com"},
+    {"cname-ext.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. bGPIuZilyygvTThK4BrdECuaBcnZUgW/0d09iN2CrNjckchQl3dtbnMNirFsVs9hShDSldRNlQpiAVMpnPgXHhReNum7jmX6yqIH6s8GKIo91zr3VL/ramlezie5w4MilDHrxXLK2pb8IHmP+ZHivQ2EtdYQZgETWBWxr5FDfwk="},
+    {"cname-ext.example.com", "NSEC", "cname-int.example.com. CNAME RRSIG NSEC"},
+    {"cname-ext.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. inWsFwSDWG7TakjwbUTzTRpXz0WifelA5Kn3ABk6BVirIPmd+yQoNj2QZBDFAQwhnLPlNws2Oo4vgMsBMyx1Fv5eHgMUuCN3DUDaLlzlPtUb42CjOUa+jZBeTV/Hd7WZrirluASE1QFDprLdSSqoPPfAKvN3pORtW7y580dMOIM="},
+
+    // dname.example.com
+    {"dname.example.com", "DNAME", "sql1.example.com."},
+    {"dname.example.com", "RRSIG", "DNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. ae8U47oaiwWdurkSyzcsCAF6DxBqjukizwF7K7U6lQVMtfoUE14oiAqfj1fjH8YLDOO/Hd1twrd/u0vgjnI1Gg32YTi7cYOzwE912SV1u2B/y0awaQKWPBwOW0aI7vxelt1vMUF81xosiQD04gOIdDBTqbHKcDxum87iWbhk4Ug="},
+    {"dname.example.com", "NSEC", "dns01.example.com. DNAME RRSIG NSEC"},
+    {"dname.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. c21Fff2D8vBrLzohBnUeflkaRdUAnUxAFGp+UQ0miACDCMOFBlCS9v9g/2+orOnKfd3l4vyz55C310t8JXgXb119ofaZWj2zkdUe+X8Bax+sMS0Y5K/sUhSNvbJbozr9UYPdvjSVBiWgh3s9fsb+etKq9uFukAzGU/FuGYpO0r0="},
+
+    // subzone.example.com
+    {"subzone.example.com", "NS", "ns1.subzone.example.com"},
+    {"subzone.example.com", "NS", "ns2.subzone.example.com"},
+    {"subzone.example.com", "NSEC", "*.wild.example.com. NS DS RRSIG NSEC"},
+    {"subzone.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. Oe2kgIhsLtPJ4+lDZDxznV8/vEVoXKOBFN9lwWyebaKa19BaSXlQ+YVejmulmKDDjEucMvEfuItfn6w7bnU+DzOLk5D1lJCjwDlKz8u3xOAx16TiuQn4bgQAOiFtBQygmGGqO3BVpX+jxsmw7eH3emofy8uUqr/C4aopnwuf28g="},
+    {"subzone.example.com", "DS", "33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"},
+    {"subzone.example.com", "DS", "33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"},
+    {"subzone.example.com", "RRSIG", "DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="},
+
+    // subset of child zone: sql1
+    {"sql1.example.com", "NS", "dns01.example.com"},
+    {"sql1.example.com", "NS", "dns02.example.com"},
+    {"sql1.example.com", "NS", "dns03.example.com"},
+
+    {"sql1.example.com", "DS", "33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"},
+    {"sql1.example.com", "DS", "33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"},
+    {"sql1.example.com", "RRSIG", "DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="},
+    {"sql1.example.com", "NSEC", "subzone.example.com. NS DS RRSIG NSEC"},
+    {"sql1.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. k9FRdFyk/cPdkmmaoZbGZPpzIzfbFWQ3QCHd2qhJa0xAXaEOT/GBL6aFqx9SlunDu2wgES+To5fWPZGi4NzWpp6c5t27rnATN/oCEQ/UYIJKmWbqrXdst0Ps5boznk7suK2Y+km31KxaIf3fDd/T3kZCVsR0aWKRRRatPb7GfLw="},
+
+    {NULL, NULL, NULL}
+};
+const struct RRData example_com_glue_records[] = {
+    {"ns1.subzone.example.com", "A", "192.0.2.1"},
+    {"ns2.subzone.example.com", "A", "192.0.2.2"},
+    {NULL, NULL, NULL}
+};
+
+//
+// zone data for sql1.example.com
+//
+const struct RRData sql1_example_com_records[] = {
+    {"sql1.example.com", "NS", "dns01.example.com"},
+    {"sql1.example.com", "NS", "dns02.example.com"},
+    {"sql1.example.com", "NS", "dns03.example.com"},
+    {"sql1.example.com", "RRSIG", "NS 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. 0CL8noy0NSgoWwuKd+Dc6vyIIw2BrAEBx0IJzcSB6GlB25x/zjEd6AJG0be13HN6jOaTX8iWTuCVrEYuXg76V+M4EvTZHjEScj0az74TrDv4Vdo459paGKCX9B8NLJW1mW4fzZrrXQ8jmBEZeS91Q5rJrO+UKJEuUz3LYdTPvao="},
+    {"sql1.example.com", "SOA", "master.example.com. admin.example.com. 678 3600 1800 2419200 7200"},
+    {"sql1.example.com", "RRSIG", "SOA 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. oakulfyljL/RAKgCKXEZ3KsG8BJj5WG4JK4moWFB6c9OKem6jIk8hKP2XlUVXFuOYJlRdIM4KicmR2GAK+5jJp6z5ShssstYTXo3QosVm6oCKumuFeLFHzcjfqP1D+F9NsvHldJIBnS/4ebPkmR5OENyCZXQF5HmN2awIj4CLjE="},
+    {"sql1.example.com", "NSEC", "www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY"},
+    {"sql1.example.com", "RRSIG", "NSEC 5 3 7200 20100322084536 20100220084536 12447 sql1.example.com. v71CgdTYccCiTqfRcn6HsvISQa8ruvUfCKtpwym0RW/G27xlZn8otj2IMtWwkLxti8Rqqu+PTViLaOIbeVfHBcqzAd7U59cAOYoq3ODZx6auiE3C23HAKqUavKcP7Esaajm1cbcWy6Kyie4CAZc8M7EeKxgkXMKJGqBQzF+/FOo="},
+
+    // www.sql1.example.com
+    {"www.sql1.example.com", "A", "192.0.2.2"},
+    {"www.sql1.example.com", "RRSIG", "A 5 4 3600 20100322084536 20100220084536 12447 sql1.example.com. DNdVKxB3oBsB14NPoV9WG14Y/g4zMcIXLYnFjj9vRZRZJpAvbTEipiXlayuhOxnqU827OipETQyeULZmLsqIQ1wK4Fgf+9b5aJ8D85/o4wBka00X4hZ3MwDPRb4mjuogwBTBg5NRpNSzUfbkPGiav08BFwgg+Efm9veSB05arS0="},
+    {"www.sql1.example.com", "NSEC", "sql1.example.com. A RRSIG NSEC"},
+    {"www.sql1.example.com", "RRSIG", "NSEC 5 4 7200 20100322084536 20100220084536 12447 sql1.example.com. cJMJhDx/ND7/9j3zhyXe+6eaSsU7ByYpXhJzbe+OhjFgH0VasQXq7o1QB3I293UZ+yhkjgXap+9QtPlraaNaYyTyOMQ42OoxSefJpYz9CME/FI2tsUfyrCnLFxYRNet7sMS0q+hLqxRayuEHDFDp72hHPGLJQ8a7jq4SrIonT50="},
+
+    {NULL, NULL, NULL}
+};
+
+//
+// zone data for loop.example
+//
+const struct RRData loop_example_records[] = {
+    {"loop.example", "SOA", "master.loop.example admin.loop.example. "
+     "1234 3600 1800 2419200 7200"},
+    {"loop.example", "NS", "ns.loop.example"},
+    {"one.loop.example", "CNAME", "two.loop.example"},
+    {"two.loop.example", "CNAME", "one.loop.example"},
+    {NULL, NULL, NULL}
+};
+
+//
+// zone data for nons.example
+//
+const struct RRData nons_example_records[] = {
+    {"nons.example", "SOA", "master.nons.example admin.nons.example. "
+     "1234 3600 1800 2419200 7200"},
+    {"www.nons.example", "A", "192.0.2.1"},
+    {"ns.nons.example", "A", "192.0.2.2"},
+    {NULL, NULL, NULL}
+};
+
+//
+// zone data for nons-dname.example
+//
+const struct RRData nonsdname_example_records[] = {
+    {"nons-dname.example", "SOA", "master.nons-dname.example "
+     "admin.nons-dname.example. 1234 3600 1800 2419200 7200"},
+    {"nons-dname.example", "DNAME", "example.org"},
+    {"www.nons-dname.example", "A", "192.0.2.1"},
+    {"ns.nons-dname.example", "A", "192.0.2.2"},
+    {NULL, NULL, NULL}
+};
+
+//
+// zone data for nosoa.example
+//
+const struct RRData nosoa_example_records[] = {
+    {"nosoa.example", "NS", "ns.nosoa.example"},
+    {"www.nosoa.example", "A", "192.0.2.1"},
+    {"ns.nosoa.example", "A", "192.0.2.2"},
+    {NULL, NULL, NULL}
+};
+
+//
+// empty data set, for convenience.
+//
+const struct RRData empty_records[] = {
+    {NULL, NULL, NULL}
+};
+
+//
+// test zones
+//
+const struct ZoneData zone_data[] = {
+    { "example.com", "IN", example_com_records, example_com_glue_records },
+    { "sql1.example.com", "IN", sql1_example_com_records, empty_records },
+    { "loop.example", "IN", loop_example_records, empty_records },
+    { "nons.example", "IN", nons_example_records, empty_records },
+    { "nons-dname.example", "IN", nonsdname_example_records, empty_records },
+    { "nosoa.example", "IN", nosoa_example_records, empty_records }
+};
+const size_t NUM_ZONES = sizeof(zone_data) / sizeof(zone_data[0]);
+
+struct Zone {
+    Zone(const char* const name, const char* const class_txt) :
+        zone_name(Name(name)), rrclass(class_txt)
+    {}
+    Name zone_name;
+    RRClass rrclass;
+    vector<Name> names;
+    vector<RRsetPtr> rrsets;
+};
+vector<Zone> zones;
 }
 
 DataSrc::Result
 TestDataSrc::init(const isc::data::ElementPtr config UNUSED_PARAM)
 {
     return init();
+}
+
+void
+buildZone(Zone& zone, const RRData* records, const bool is_glue) {
+    RRsetPtr prev_rrset;
+    for (int i = 0; records[i].name != NULL; ++i) {
+        Name name(records[i].name);
+        RRType rrtype(records[i].rrtype);
+        RRsetPtr rrset;
+        bool new_name = false;
+
+        if (!prev_rrset || prev_rrset->getName() != name) {
+            if (!is_glue) {
+                zone.names.push_back(name);
+            }
+            new_name = true;
+        }
+
+        if (new_name || prev_rrset->getType() != rrtype) {
+            rrset = RRsetPtr(new RRset(name, zone.rrclass, rrtype,
+                                       RRTTL(TEST_TTL)));
+            if (rrtype != RRType::RRSIG()) {
+                zone.rrsets.push_back(rrset);
+            }
+        } else {
+            rrset = prev_rrset;
+        }
+        rrset->addRdata(createRdata(rrtype, zone.rrclass, records[i].rdata));
+        if (rrtype == RRType::RRSIG()) {
+            prev_rrset->addRRsig(rrset);
+        }
+        prev_rrset = rrset;
+    }
 }
 
 DataSrc::Result
@@ -116,353 +346,15 @@
         return (SUCCESS);
     }
 
-    RRset* rp;
-    RRsetPtr rrsig;
-
-    // example.com
-    example_ns = RRsetPtr(new RRset(example, RRClass::IN(),
-                                    RRType::NS(), RRTTL(3600)));
-    example_ns->addRdata(generic::NS(dns01));
-    example_ns->addRdata(generic::NS(dns02));
-    example_ns->addRdata(generic::NS(dns03));
-
-    rp = new RRset(example, RRClass::IN(), RRType::RRSIG(), RRTTL(3600));
-    rrsig = RRsetPtr(rp);
-    rrsig->addRdata(generic::RRSIG("NS 5 2 3600 20100322084538 20100220084538 33495 example.com. ClcrfjkQZUY5L6ZlCkU3cJHzcrEGrofKSVeeoeZ+w6yeEowFNVXs2YBo3tom53DiCrdD9rs3feVSLGW5rjsz/O6lDuomgQG+EVSnWa7GTIPBXj1BmDXXp3XxeldYmhf4UzaN5BA+RUA5E8NChNKuNNof76j2S9tilfN/kvpy4fw="));
-    example_ns->addRRsig(rrsig);
-
-    example_soa = RRsetPtr(new RRset(example, RRClass::IN(),
-                                    RRType::SOA(), RRTTL(3600)));
-    example_soa->addRdata(generic::SOA("master.example.com. admin.example.com. 1234 3600 1800 2419200 7200"));
-
-    rrsig = RRsetPtr(new RRset(example, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("SOA 5 2 3600 20100322084538 20100220084538 33495 example.com.  KUun66Qaw36osk2BJS6U1fAy3PPDkNo2QK4meGNbDBY8q8b+f2o+IXJ14YCvssGl1ORW0CcLnDRxssnk8V/Svmj5iFhO+8HC2hnVBdi2zewvdVtwRb+lWwKN7pkXXwuy6g1t9WCd/j5FCc/wgxqtZUTPb6XgZcnHrORDMOTqLs4="));
-    example_soa->addRRsig(rrsig);
-
-    example_nsec = RRsetPtr(new RRset(example, RRClass::IN(),
-                                      RRType::NSEC(), RRTTL(3600)));
-    example_nsec->addRdata(generic::NSEC("cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY"));
-    rrsig = RRsetPtr(new RRset(example, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 2 7200 20100322084538 20100220084538 33495 example.com. KxuVaPPKNPJzr/q+cJPiNlkHVTQK0LVsgTbSqruXQc25lAd0wn5oKUtxL1bEAchHkfA8eLzcYCj2ZqqAv9OJubw53mfskTad7UHs4Uj2RTrIsNGMCiZGgOpvNb9JcWpQtoyXVT1uNse+Qsbeir0eyeYIufUynFU041jtNrlJMio="));
-    example_nsec->addRRsig(rrsig);
-
-    // sql1.example.com
-    sql1_ns = RRsetPtr(new RRset(sql1, RRClass::IN(),
-                                 RRType::NS(), RRTTL(3600)));
-    sql1_ns->addRdata(generic::NS(dns01));
-    sql1_ns->addRdata(generic::NS(dns02));
-    sql1_ns->addRdata(generic::NS(dns03));
-
-    rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NS 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. 0CL8noy0NSgoWwuKd+Dc6vyIIw2BrAEBx0IJzcSB6GlB25x/zjEd6AJG0be13HN6jOaTX8iWTuCVrEYuXg76V+M4EvTZHjEScj0az74TrDv4Vdo459paGKCX9B8NLJW1mW4fzZrrXQ8jmBEZeS91Q5rJrO+UKJEuUz3LYdTPvao="));
-    sql1_ns->addRRsig(rrsig);
-
-    sql1_soa = RRsetPtr(new RRset(sql1, RRClass::IN(),
-                                 RRType::SOA(), RRTTL(3600)));
-    sql1_soa->addRdata(generic::SOA("master.example.com. admin.example.com. 678 3600 1800 2419200 7200"));
-
-    rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("SOA 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. oakulfyljL/RAKgCKXEZ3KsG8BJj5WG4JK4moWFB6c9OKem6jIk8hKP2XlUVXFuOYJlRdIM4KicmR2GAK+5jJp6z5ShssstYTXo3QosVm6oCKumuFeLFHzcjfqP1D+F9NsvHldJIBnS/4ebPkmR5OENyCZXQF5HmN2awIj4CLjE="));
-    sql1_soa->addRRsig(rrsig);
-
-    sql1_nsec = RRsetPtr(new RRset(sql1, RRClass::IN(),
-                                      RRType::NSEC(), RRTTL(3600)));
-    sql1_nsec->addRdata(generic::NSEC("www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY"));
-    rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(), RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084536 20100220084536 12447 sql1.example.com. v71CgdTYccCiTqfRcn6HsvISQa8ruvUfCKtpwym0RW/G27xlZn8otj2IMtWwkLxti8Rqqu+PTViLaOIbeVfHBcqzAd7U59cAOYoq3ODZx6auiE3C23HAKqUavKcP7Esaajm1cbcWy6Kyie4CAZc8M7EeKxgkXMKJGqBQzF+/FOo="));
-    sql1_nsec->addRRsig(rrsig);
-    sql1_ds = RRsetPtr(new RRset(sql1, RRClass::IN(),
-                                 RRType::DS(), RRTTL(3600)));
-    sql1_ds->addRdata(generic::DS("33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"));
-    sql1_ds->addRdata(generic::DS("33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"));
-
-    rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="));
-    sql1_ds->addRRsig(rrsig);
-
-
-    sql1_ds_nsec = RRsetPtr(new RRset(sql1, RRClass::IN(),
-                                   RRType::NSEC(), RRTTL(3600)));
-    sql1_ds_nsec->addRdata(generic::NSEC("subzone.example.com. NS DS RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(sql1, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. k9FRdFyk/cPdkmmaoZbGZPpzIzfbFWQ3QCHd2qhJa0xAXaEOT/GBL6aFqx9SlunDu2wgES+To5fWPZGi4NzWpp6c5t27rnATN/oCEQ/UYIJKmWbqrXdst0Ps5boznk7suK2Y+km31KxaIf3fDd/T3kZCVsR0aWKRRRatPb7GfLw="));
-    sql1_ds_nsec->addRRsig(rrsig);
-
-    // www.sql1.example.com
-    www_sql1_a = RRsetPtr(new RRset(www_sql1,
-                                    RRClass::IN(), RRType::A(),
-                                    RRTTL(3600)));
-    www_sql1_a->addRdata(in::A("192.0.2.2"));
-
-    rrsig = RRsetPtr(new RRset(www_sql1, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("A 5 4 3600 20100322084536 20100220084536 12447 sql1.example.com. DNdVKxB3oBsB14NPoV9WG14Y/g4zMcIXLYnFjj9vRZRZJpAvbTEipiXlayuhOxnqU827OipETQyeULZmLsqIQ1wK4Fgf+9b5aJ8D85/o4wBka00X4hZ3MwDPRb4mjuogwBTBg5NRpNSzUfbkPGiav08BFwgg+Efm9veSB05arS0="));
-    www_sql1_a->addRRsig(rrsig);
-
-    www_sql1_nsec = RRsetPtr(new RRset(www_sql1,
-                                       RRClass::IN(), RRType::NSEC(),
-                                       RRTTL(3600)));
-    www_sql1_nsec->addRdata(generic::NSEC("sql1.example.com. A RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(www_sql1, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 4 7200 20100322084536 20100220084536 12447 sql1.example.com. cJMJhDx/ND7/9j3zhyXe+6eaSsU7ByYpXhJzbe+OhjFgH0VasQXq7o1QB3I293UZ+yhkjgXap+9QtPlraaNaYyTyOMQ42OoxSefJpYz9CME/FI2tsUfyrCnLFxYRNet7sMS0q+hLqxRayuEHDFDp72hHPGLJQ8a7jq4SrIonT50="));
-    www_sql1_nsec->addRRsig(rrsig);
-
-    // dns01.example.com
-    dns01_a = RRsetPtr(new RRset(dns01,
-                                         RRClass::IN(), RRType::A(),
-                                         RRTTL(3600)));
-    dns01_a->addRdata(in::A("192.0.2.1"));
-
-    rrsig = RRsetPtr(new RRset(dns01, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. NIawlZLk8WZAjNux7oQM2mslfW52OZFFkWt++7FHu2SU98XqEeKfCMnpgtWe5T8Nr9cS8df901iEOJoWQzGTEaHYUBtEhsSjBVn7mKp3fz6473a2xxy75SUKZ0rxjNXSZ8Q5rnFmkX0HTH2Sg51mtjH6aC2pfheQnA2t193BnSg="));
-    dns01_a->addRRsig(rrsig);
-
-    dns01_nsec = RRsetPtr(new RRset(dns01, RRClass::IN(), RRType::NSEC(), RRTTL(3600)));
-    dns01_nsec->addRdata(generic::NSEC("dns02.example.com. A RRSIG NSEC"));
-
-    rrsig = RRsetPtr(new RRset(dns01, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. EkyeshmMNP9xiAz6mDFDIwksTdmkF9zsFzLuVKAgK6eUk7St6tp5PSvjA8nWol0vdvvz4LK85a4ffTFEiNRyvWeYP2vOhEkyDcrwuCd8Vc3jh/8Sm1Js+nX7hJStrZGFvp2TWPpt9nKH5p3MxXvTb/YVurnue0xSeFAE17O3+I0="));
-    dns01_nsec->addRRsig(rrsig);
-
-    // dns02.example.com
-    dns02_a = RRsetPtr(new RRset(dns02, RRClass::IN(), RRType::A(), RRTTL(3600)));
-    dns02_a->addRdata(in::A("192.0.2.2"));
-
-    rrsig = RRsetPtr(new RRset(dns02, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. XJtVMbUIRE0mk6Hn/Nx6k36jaxaBDPK2/IYB6vCQjJETz6gW4T6q/H/eY9/Lsw5iYPFhoBRDxT4XFj575t98kELXnJe1WhuMbRPlOhyOjxkLECaUne/sbFPOtbGFx9ohuojI0RgxxZiCFaO8wJuv6nfPuzmlLajWS6z9NZeOMIk="));
-    dns02_a->addRRsig(rrsig);
-
-    dns02_nsec = RRsetPtr(new RRset(dns02, RRClass::IN(),
-                                      RRType::NSEC(), RRTTL(3600)));
-    dns02_nsec->addRdata(generic::NSEC("dns03.example.com. A RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(dns02, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. imBNTMB3sPU4kblcaAH6V7lCVt5xgtAybi3DA/SbLEulLaV2NE6vcoEn/AieaM4mOJicQnUDj/H+1hSEhzxU2tRM8zfVlvztxQWn6eh7ZR4mKfNDSvRUGU9ykhpwMyC7wjOt1j5bcSA/OTnLRAilslnJyOM4bSaxVEFo8YPjncY="));
-    dns02_nsec->addRRsig(rrsig);
-
-    // dns03.example.com
-    dns03_a = RRsetPtr(new RRset(dns03,
-                                         RRClass::IN(), RRType::A(),
-                                         RRTTL(3600)));
-    dns03_a->addRdata(in::A("192.0.2.3"));
-
-    rrsig = RRsetPtr(new RRset(dns03, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. Ubrcm1H+F6m8khle7P9zU8eO+Jtuj+1Vx1MM5KAkmZPJwQe9uTcoCpQa6DXOGG9kajDTnNN1Be1gkZuJDTZJG4SmJLXLbNY3RDnxpGmWta3qs/VgDq78/YM8ropt1/s7YKyrCfGE2ff+FUB0mLObiG01ZV2gu5HJzgE7SEWLEiI="));
-    dns03_a->addRRsig(rrsig);
-
-    dns03_nsec = RRsetPtr(new RRset(dns03, RRClass::IN(),
-                                      RRType::NSEC(), RRTTL(3600)));
-    dns03_nsec->addRdata(generic::NSEC("foo.example.com. A RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(dns03, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com.  nn829Xw5CJFnPHwI9WHeT5epQv+odtCkHnjlPFGoPTLOyiks+041UmMqtq3uiSp4d2meMSe9UuDvoROT0L6NTtQQvVqiDhTn0irTFw1uw7fO8ZTG7eyu6Ypfz0+HvfbNvd4kMoD2OTgADRXPVsCTwK+PBOIIG9YTEQfl8pCqW5g="));
-    dns03_nsec->addRRsig(rrsig);
-
-    // www.example.com
-    www_a = RRsetPtr(new RRset(www, RRClass::IN(), RRType::A(),
-                                       RRTTL(3600)));
-    www_a->addRdata(in::A("192.0.2.1"));
-
-    rrsig = RRsetPtr(new RRset(www, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. qyFyyV/mE8x4pdhudr5iycwhDsva31MzwO1kBR+bDKvzJg8mN8KxlPZrOlNNUhd3YRXQVwieMyxOTWRPXoxrNEDkNwimXkfe3rrHY7ibV9eNS4OIBUjb44VjCNr9CmQSzfuQ2yxO2r+YIuPYHRCjieD4xh6t9ay4IaCN/tDAJ+Q="));
-    www_a->addRRsig(rrsig);
-
-    www_nsec = RRsetPtr(new RRset(www, RRClass::IN(),
-                                  RRType::NSEC(), RRTTL(3600)));
-    www_nsec->addRdata(generic::NSEC("example.com. A RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(www, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. ZLZlSVBa2oe4U+7SZASnypP2VkI5gg1/1cVGqYUvfYNIUkcVMWDgn7DZCfpmo+2vdlV/4VhAc+sjDd+X+e57XGnW8+lqZHvG6NMMhmSGmeATD3D+8lEJJGo0dxoN4rHJQyp/eT2S4nChz+D/ze+YRagYxGF7pXm9zcrw3kKZGTs="));
-    www_nsec->addRRsig(rrsig);
-
-    // *.wild.example.com
-    wild_a = RRsetPtr(new RRset(wild, RRClass::IN(), RRType::A(),
-                                        RRTTL(3600)));
-    wild_a->addRdata(in::A("192.0.2.2"));
-
-    rrsig = RRsetPtr(new RRset(wild, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("A 5 3 3600 20100322084538 20100220084538 33495 example.com. FdO+UWONgtLKFxUzzygGunw67F9y8SzsP7yOLEYVJclRR8X3Ii62L0gtQHq2y0TcKsXttRsD6XY+tM5P/pgXlTNi7Bk4Fgb0PIDPjOsfT4DrS80kWn0YbinM/4/FA1j5ru5sTTboOY5UGhvDnoA9ogNuQQYb2/3wkoH0PrA2Q/0="));
-    wild_a->addRRsig(rrsig);
-
-    wild_nsec = RRsetPtr(new RRset(wild, RRClass::IN(),
-                                   RRType::NSEC(), RRTTL(3600)));
-    wild_nsec->addRdata(generic::NSEC("*.wild2.example.com. A RRSIG NSEC"));
-
-    rrsig = RRsetPtr(new RRset(wild, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. OoGYslRj4xjZnBuzgOqsrvkDAHWycmQzbUxCRmgWnCbXiobJK7/ynONH3jm8G3vGlU0lwpHkhNs6cUK+6Nu8W49X3MT0Xksl/brroLcXYLi3vfxnYUNMMpXdeFl6WNNfoJRo90F/f/TWXAClRrDS29qiG3G1PEJZikIxZsZ0tyM="));
-    wild_nsec->addRRsig(rrsig);
-
-    // *.wild2.example.com
-    wild2_cname = RRsetPtr(new RRset(wild2, RRClass::IN(), RRType::CNAME(),
-                                     RRTTL(3600)));
-    wild2_cname->addRdata(generic::CNAME("www.example.com"));
-
-    rrsig = RRsetPtr(new RRset(wild2, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="));
-    wild2_cname->addRRsig(rrsig);
-
-    wild2_nsec = RRsetPtr(new RRset(wild2, RRClass::IN(),
-                                    RRType::NSEC(), RRTTL(3600)));
-    wild2_nsec->addRdata(generic::NSEC("*.wild3.example.com. CNAME RRSIG NSEC"));
-
-    rrsig = RRsetPtr(new RRset(wild2, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="));
-    wild2_nsec->addRRsig(rrsig);
-
-    // *.wild3.example.com -- a wildcard record with a lame CNAME
-    wild3_cname = RRsetPtr(new RRset(wild3, RRClass::IN(), RRType::CNAME(),
-                                     RRTTL(3600)));
-    wild3_cname->addRdata(generic::CNAME("spork.example.com"));
-
-    rrsig = RRsetPtr(new RRset(wild3, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="));
-    wild3_cname->addRRsig(rrsig);
-
-    wild3_nsec = RRsetPtr(new RRset(wild3, RRClass::IN(),
-                                    RRType::NSEC(), RRTTL(3600)));
-    wild3_nsec->addRdata(generic::NSEC("www.example.com. CNAME RRSIG NSEC"));
-
-    rrsig = RRsetPtr(new RRset(wild3, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="));
-    wild3_nsec->addRRsig(rrsig);
-
-    // foo.example.com
-    foo_cname = RRsetPtr(new RRset(foo, RRClass::IN(), RRType::CNAME(),
-                                           RRTTL(3600)));
-    foo_cname->addRdata(generic::CNAME("cnametest.flame.org"));
-
-    rrsig = RRsetPtr(new RRset(foo, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. DSqkLnsh0gCeCPVW/Q8viy9GNP+KHmFGfWqyVG1S6koBtGN/VQQ16M4PHZ9Zssmf/JcDVJNIhAChHPE2WJiaPCNGTprsaUshf1Q2vMPVnkrJKgDY8SVRYMptmT8eaT0gGri4KhqRoFpMT5OYfesybwDgfhFSQQAh6ps3bIUsy4o="));
-    foo_cname->addRRsig(rrsig);
-
-    foo_nsec = RRsetPtr(new RRset(foo, RRClass::IN(),
-                                  RRType::NSEC(), RRTTL(3600)));
-    foo_nsec->addRdata(generic::NSEC("mail.example.com. CNAME RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(foo, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. RTQwlSqui6StUYye1KCSOEr1d3irndWFqHBpwP7g7n+w8EDXJ8I7lYgwzHvlQt6BLAxe5fUDi7ct8M5hXvsm7FoWPZ5wXH+2/eJUCYxIw4vezKMkMwBP6M/YkJ2CMqY8DppYf60QaLDONQAr7AcK/naSyioeI5h6eaoVitUDMso="));
-    foo_nsec->addRRsig(rrsig);
-
-    // cname-int.example.com
-    cnameint_cname = RRsetPtr(new RRset(cnameint, RRClass::IN(),
-                                        RRType::CNAME(), RRTTL(3600)));
-    cnameint_cname->addRdata(generic::CNAME("www.example.com."));
-
-    rrsig = RRsetPtr(new RRset(cnameint, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. U1wjt0XY9xjTwvUmWSUcfLGMhCjfX2ylWfHrycy50x2oxcK9z94E1ejen9wDTIEBSGYgi6wpZ8RK0+02N1DWTGpDqNXd7aFRfDrWQJ/q/XJHDx0vlcmhkWhrT82LBfKxkrptOzchuSo/c0mpK+mpiIMc1VOwY+yuQ2ALfcD6EHw="));
-    cnameint_cname->addRRsig(rrsig);
-
-    cnameint_nsec = RRsetPtr(new RRset(cnameint, RRClass::IN(),
-                                      RRType::NSEC(), RRTTL(3600)));
-    cnameint_nsec->addRdata(generic::NSEC("dname.example.com. CNAME RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(cnameint, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. rbV+gaxfrsoha59NOLF4EFyWQ+GuFCVK/8D77x1atan3HNlXBlZ1smgudKTaJ3CtlobIDt0MEdPxY1yn2Tskw/5mlP1PWf8oaP3BwGSQdn4gLI8+sMpNOPFEdXpxqxngm2F6/7fqniL1QuSAQBEdO+5UiCAgnncPmAsSJg3u1zg="));
-    cnameint_nsec->addRRsig(rrsig);
-
-    // cname-ext.example.com
-    cnameext_cname = RRsetPtr(new RRset(cnameext, RRClass::IN(),
-                                        RRType::CNAME(), RRTTL(3600)));
-    cnameext_cname->addRdata(generic::CNAME("www.sql1.example.com"));
-
-    rrsig = RRsetPtr(new RRset(cnameext, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. bGPIuZilyygvTThK4BrdECuaBcnZUgW/0d09iN2CrNjckchQl3dtbnMNirFsVs9hShDSldRNlQpiAVMpnPgXHhReNum7jmX6yqIH6s8GKIo91zr3VL/ramlezie5w4MilDHrxXLK2pb8IHmP+ZHivQ2EtdYQZgETWBWxr5FDfwk="));
-    cnameext_cname->addRRsig(rrsig);
-
-    cnameext_nsec = RRsetPtr(new RRset(cnameext, RRClass::IN(),
-                                      RRType::NSEC(), RRTTL(3600)));
-    cnameext_nsec->addRdata(generic::NSEC("cname-int.example.com. CNAME RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(cnameext, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. inWsFwSDWG7TakjwbUTzTRpXz0WifelA5Kn3ABk6BVirIPmd+yQoNj2QZBDFAQwhnLPlNws2Oo4vgMsBMyx1Fv5eHgMUuCN3DUDaLlzlPtUb42CjOUa+jZBeTV/Hd7WZrirluASE1QFDprLdSSqoPPfAKvN3pORtW7y580dMOIM="));
-    cnameext_nsec->addRRsig(rrsig);
-
-    // dname.example.com
-    dname_dname = RRsetPtr(new RRset(dname, RRClass::IN(), RRType::DNAME(),
-                               RRTTL(3600)));
-    dname_dname->addRdata(generic::DNAME("sql1.example.com."));
-
-    rrsig = RRsetPtr(new RRset(dname, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("DNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. ae8U47oaiwWdurkSyzcsCAF6DxBqjukizwF7K7U6lQVMtfoUE14oiAqfj1fjH8YLDOO/Hd1twrd/u0vgjnI1Gg32YTi7cYOzwE912SV1u2B/y0awaQKWPBwOW0aI7vxelt1vMUF81xosiQD04gOIdDBTqbHKcDxum87iWbhk4Ug="));
-    dname_dname->addRRsig(rrsig);
-
-    dname_nsec = RRsetPtr(new RRset(dname, RRClass::IN(),
-                                      RRType::NSEC(), RRTTL(3600)));
-    dname_nsec->addRdata(generic::NSEC("dns01.example.com. DNAME RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(dname, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. c21Fff2D8vBrLzohBnUeflkaRdUAnUxAFGp+UQ0miACDCMOFBlCS9v9g/2+orOnKfd3l4vyz55C310t8JXgXb119ofaZWj2zkdUe+X8Bax+sMS0Y5K/sUhSNvbJbozr9UYPdvjSVBiWgh3s9fsb+etKq9uFukAzGU/FuGYpO0r0="));
-    dname_nsec->addRRsig(rrsig);
-
-    // subzone.example.com
-    subzone_ns = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::NS(),
-                                    RRTTL(3600)));
-    subzone_ns->addRdata(generic::NS(Name("ns1.subzone.example.com")));
-    subzone_ns->addRdata(generic::NS(Name("ns2.subzone.example.com")));
-
-    subzone_ds = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::DS(),
-                                    RRTTL(3600)));
-
-    subzone_glue1 = RRsetPtr(new RRset(Name("ns1.subzone.example.com"),
-                                    RRClass::IN(), RRType::A(),
-                                    RRTTL(3600)));
-    subzone_glue1->addRdata(in::A("192.0.2.1"));
-    subzone_glue2 = RRsetPtr(new RRset(Name("ns2.subzone.example.com"),
-                                    RRClass::IN(), RRType::A(),
-                                    RRTTL(3600)));
-    subzone_glue2->addRdata(in::A("192.0.2.2"));
-
-    subzone_ds = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::DS(),
-                                    RRTTL(3600)));
-
-    subzone_ds->addRdata(generic::DS("33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"));
-    subzone_ds->addRdata(generic::DS("33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"));
-
-    rrsig = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::RRSIG(),
-                               RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="));
-    subzone_ds->addRRsig(rrsig);
-
-    subzone_nsec = RRsetPtr(new RRset(subzone, RRClass::IN(),
-                                      RRType::NSEC(), RRTTL(3600)));
-    subzone_nsec->addRdata(generic::NSEC("*.wild.example.com. NS DS RRSIG NSEC"));
-    rrsig = RRsetPtr(new RRset(subzone, RRClass::IN(), RRType::RRSIG(), RRTTL(3600)));
-    rrsig->addRdata(generic::RRSIG("NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. Oe2kgIhsLtPJ4+lDZDxznV8/vEVoXKOBFN9lwWyebaKa19BaSXlQ+YVejmulmKDDjEucMvEfuItfn6w7bnU+DzOLk5D1lJCjwDlKz8u3xOAx16TiuQn4bgQAOiFtBQygmGGqO3BVpX+jxsmw7eH3emofy8uUqr/C4aopnwuf28g="));
-    subzone_nsec->addRRsig(rrsig);
-
-    loop1_cname = RRsetPtr(new RRset(loop1, RRClass::IN(), RRType::CNAME(),
-                                     RRTTL(3600)));
-    loop1_cname->addRdata(generic::CNAME(loop2));
-    loop2_cname = RRsetPtr(new RRset(loop2, RRClass::IN(), RRType::CNAME(),
-                                     RRTTL(3600)));
-    loop2_cname->addRdata(generic::CNAME(loop1));
+    if (zones.empty()) {
+        for (int i = 0; i < NUM_ZONES; ++i) {
+            Zone zone(zone_data[i].zone_name, zone_data[i].rrclass);
+            buildZone(zone, zone_data[i].records, false);
+            buildZone(zone, zone_data[i].glue_records, true);
+            sort(zone.names.begin(), zone.names.end());
+            zones.push_back(zone);
+        }
+    }
 
     initialized = true;
     return (SUCCESS);
@@ -470,276 +362,160 @@
 
 void
 TestDataSrc::findClosestEnclosure(NameMatch& match,
-                                  const RRClass& qclass) const {
+                                  const RRClass& qclass) const
+{
     const Name& qname = match.qname();
-    NameComparisonResult::NameRelation cmp;
 
     if (qclass != getClass() && qclass != RRClass::ANY()) {
         return;
     }
 
-    cmp = qname.compare(sql1).getRelation();
-    if (cmp == NameComparisonResult::EQUAL ||
-          cmp == NameComparisonResult::SUBDOMAIN) {
-        match.update(*this, sql1);
-        return;
-    }
-
-    cmp = qname.compare(example).getRelation();
-    if (cmp == NameComparisonResult::EQUAL ||
-          cmp == NameComparisonResult::SUBDOMAIN) {
-        match.update(*this, example);
-        return;
-    }
-
-}
+    vector<Zone>::const_iterator it;
+    vector<Zone>::const_iterator best_it = zones.end();
+    unsigned int best_common_labels = 0;
+    for (it = zones.begin(); it != zones.end(); ++it) {
+        const NameComparisonResult cmp = qname.compare(it->zone_name);
+        const NameComparisonResult::NameRelation reln = cmp.getRelation();
+
+        if ((reln == NameComparisonResult::EQUAL ||
+             reln == NameComparisonResult::SUBDOMAIN) &&
+            cmp.getCommonLabels() > best_common_labels) {
+            best_it = it;
+            best_common_labels = cmp.getCommonLabels();
+        }
+    }
+
+    if (best_it != zones.end()) {
+        match.update(*this, best_it->zone_name);
+    }
+}
+
+struct ZoneNameMatch : public unary_function<Name, bool> {
+    ZoneNameMatch(const Name& name) : name_(name) {}
+    bool operator()(const Zone& zone) const {
+        return (zone.zone_name == name_);
+    }
+    const Name& name_;
+};
+
+// XXX: the main data source module can override the returned RRset.
+// That's bad and should be fixed (Trac #254), but for now we work around it.
+RRsetPtr
+copyRRset(RRsetPtr const source) {
+    RRsetPtr rrset = RRsetPtr(new RRset(source->getName(), source->getClass(),
+                                        source->getType(), source->getTTL()));
+    RdataIteratorPtr it = source->getRdataIterator();
+    for (it->first(); !it->isLast(); it->next()) {
+        rrset->addRdata(it->getCurrent());
+    }
+    if (source->getRRsig()) {
+        rrset->addRRsig(copyRRset(source->getRRsig()));
+    }
+
+    return (rrset);
+}
+
+class TestDataSrc::RRsetMatch {
+public:
+    struct MatchResult {
+        MatchResult(const bool name_found, const bool has_delegation) :
+            name_found_(name_found), has_delegation_(has_delegation)
+        {}
+        bool name_found_;
+        bool has_delegation_;
+    };
+    RRsetMatch(const Name& name, const RRType& rrtype, const Mode mode,
+               RRsetList& target, uint32_t& flags) :
+        name_(name), rrtype_(rrtype), mode_(mode), target_(target),
+        flags_(flags), name_found_(false), has_delegation_(false)
+    {}
+    void operator()(const RRsetPtr& rrset) {
+        if (rrset->getName() != name_) {
+            return;
+        }
+        name_found_ = true;
+
+        if (rrset->getType() == RRType::NS() ||
+            rrset->getType() == RRType::DNAME()) {
+            has_delegation_ = true;
+        }
+
+        if (mode_ == DELEGATION) {
+            if (rrset->getType() == RRType::NS() ||
+                rrset->getType() == RRType::DNAME() ||
+                rrset->getType() == RRType::DS()) {
+                target_.addRRset(copyRRset(rrset));
+            }
+        } else if (mode_ == ADDRESS) {
+            if (rrset->getType() == RRType::A() ||
+                rrset->getType() == RRType::AAAA()) {
+                target_.addRRset(copyRRset(rrset));
+            }
+        } else {
+            if (rrtype_ == RRType::NSEC() &&
+                rrset->getType() == RRType::CNAME()) {
+                // XXX: ignore CNAME if the qtype is NSEC.
+                // tricky, but necessary.
+                return;
+            }
+            if (rrtype_ == RRType::ANY() || rrtype_ == rrset->getType() ||
+                rrset->getType() == RRType::CNAME() ||
+                rrset->getType() == RRType::DNAME()) {
+                target_.addRRset(copyRRset(rrset));
+                if (rrset->getType() == RRType::CNAME()) {
+                    flags_ |= CNAME_FOUND;
+                }
+                if (rrset->getType() == RRType::DNAME()) {
+                    flags_ |= REFERRAL;
+                }
+            }
+        }
+        
+    }
+    MatchResult getResult() { return (MatchResult(name_found_,
+                                                  has_delegation_)); }
+    const Name& name_;
+    const RRType& rrtype_;
+    const Mode mode_;
+    RRsetList& target_;
+    uint32_t& flags_;
+    bool name_found_;
+    bool has_delegation_;
+};
 
 void
 TestDataSrc::findRecords(const Name& name, const RRType& rdtype,
-                         RRsetList& target, const Name* zonename, const Mode mode,
-                         uint32_t& flags) const
-{
-    const bool any = (rdtype == RRType::ANY());
+                         RRsetList& target, const Name* zonename,
+                         const Mode mode, uint32_t& flags) const
+{
     flags = 0;
 
     assert(zonename != NULL);
-    if (*zonename == sql1) {
-        if (name == sql1 && mode == DELEGATION) {
-            target.addRRset(sql1_ns);
-            flags |= REFERRAL;
-        } else if (name == sql1) {
-            flags |= REFERRAL;
-            if (any) {
-                target.addRRset(sql1_ns);
-                target.addRRset(sql1_nsec);
-            } else if (rdtype == RRType::NS()) {
-                target.addRRset(sql1_ns);
-            } else if (rdtype == RRType::SOA()) {
-                target.addRRset(sql1_soa);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(sql1_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == www_sql1) {
-            if (any) {
-                target.addRRset(www_sql1_a);
-                target.addRRset(www_sql1_nsec);
-            } else if (rdtype == RRType::A()) {
-                target.addRRset(www_sql1_a);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(www_sql1_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
+
+    vector<Zone>::const_iterator zone = find_if(zones.begin(), zones.end(),
+                                                ZoneNameMatch(*zonename));
+    if (zone == zones.end()) {
+        return;
+    }
+
+    const RRsetMatch::MatchResult match_result =
+        for_each(zone->rrsets.begin(), zone->rrsets.end(),
+                 RRsetMatch(name, rdtype, mode, target, flags)).getResult();
+    if (match_result.has_delegation_) {
+        flags |= REFERRAL;
+    }
+    if (target.size() == 0) {
+        if (match_result.name_found_) {
+            flags |= TYPE_NOT_FOUND;
         } else {
             flags |= NAME_NOT_FOUND;
         }
-    } else {
-        if (name == example && mode == DELEGATION) {
-            target.addRRset(example_ns);
-            flags |= REFERRAL;
-        } else if (name == example) {
-            flags |= REFERRAL;
-            if (any) {
-                target.addRRset(example_ns);
-                target.addRRset(example_soa);
-                target.addRRset(example_nsec);
-            } else if (rdtype == RRType::NS()) {
-                target.addRRset(example_ns);
-            } else if (rdtype == RRType::SOA()) {
-                target.addRRset(example_soa);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(example_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == sql1 && mode == DELEGATION) {
-            target.addRRset(sql1_ns);
-            target.addRRset(sql1_ds);
-            target.addRRset(sql1_ds_nsec);
-            flags |= REFERRAL;
-        } else if (name == sql1) {
-            flags |= REFERRAL;
-            if (any) {
-                target.addRRset(sql1_ns);
-                target.addRRset(sql1_ds);
-                target.addRRset(sql1_ds_nsec);
-            } else if (rdtype == RRType::DS()) {
-                target.addRRset(sql1_ds);
-            } else if (rdtype == RRType::NS()) {
-                target.addRRset(sql1_ns);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(sql1_ds_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == subzone && mode == DELEGATION) {
-            target.addRRset(subzone_ns);
-            target.addRRset(subzone_ds);
-            flags |= REFERRAL;
-        } else if (name == subzone) {
-            flags |= REFERRAL;
-            if (any) {
-                target.addRRset(subzone_ns);
-                target.addRRset(subzone_nsec);
-            } else if (rdtype == RRType::NS()) {
-                target.addRRset(subzone_ns);
-            } else if (rdtype == RRType::DS()) {
-                target.addRRset(subzone_ds);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(subzone_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == dns01 && mode == ADDRESS) {
-            target.addRRset(dns01_a);
-        } else if (name == dns01) {
-            if (any) {
-                target.addRRset(dns01_a);
-                target.addRRset(dns01_nsec);
-            } else if (rdtype == RRType::A()) {
-                target.addRRset(dns01_a);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(dns01_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == dns02 && mode == ADDRESS) {
-            target.addRRset(dns02_a);
-        } else if (name == dns02) {
-            if (any) {
-                target.addRRset(dns02_a);
-                target.addRRset(dns02_nsec);
-            } else if (rdtype == RRType::A()) {
-                target.addRRset(dns02_a);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(dns02_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == dns03 && mode == ADDRESS) {
-            target.addRRset(dns03_a);
-        } else if (name == dns03) {
-            if (any) {
-                target.addRRset(dns03_a);
-                target.addRRset(dns03_nsec);
-            } else if (rdtype == RRType::A()) {
-                target.addRRset(dns03_a);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(dns03_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == wild) {
-            if (any) {
-                target.addRRset(wild_a);
-                target.addRRset(wild_nsec);
-            } else if (rdtype == RRType::A()) {
-                target.addRRset(wild_a);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(wild_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == wild2) {
-            if (any) {
-                target.addRRset(wild2_cname);
-                target.addRRset(wild2_nsec);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(wild2_nsec);
-            } else {
-                target.addRRset(wild2_cname);
-                if (rdtype != RRType::CNAME()) {
-                    flags |= CNAME_FOUND;
-                }
-            }
-        } else if (name == wild3) {
-            if (any) {
-                target.addRRset(wild3_cname);
-                target.addRRset(wild3_nsec);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(wild3_nsec);
-            } else {
-                target.addRRset(wild3_cname);
-                if (rdtype != RRType::CNAME()) {
-                    flags |= CNAME_FOUND;
-                }
-            }
-        } else if (name == www) {
-            if (any) {
-                target.addRRset(www_a);
-                target.addRRset(www_nsec);
-            } else if (rdtype == RRType::A()) {
-                target.addRRset(www_a);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(www_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == foo) {
-            if (rdtype == RRType::NSEC()) {
-                target.addRRset(foo_nsec);
-            } else {
-                target.addRRset(foo_cname);
-                if (rdtype != RRType::CNAME()) {
-                    flags |= CNAME_FOUND;
-                }
-            }
-        } else if (name == cnameint) {
-            if (rdtype == RRType::NSEC()) {
-                target.addRRset(cnameint_nsec);
-            } else {
-                target.addRRset(cnameint_cname);
-                if (rdtype != RRType::CNAME()) {
-                    flags |= CNAME_FOUND;
-                }
-            }
-        } else if (name == cnameext) {
-            if (rdtype == RRType::NSEC()) {
-                target.addRRset(cnameext_nsec);
-            } else {
-                target.addRRset(cnameext_cname);
-                if (rdtype != RRType::CNAME()) {
-                    flags |= CNAME_FOUND;
-                }
-            }
-        } else if (name == dname) {
-            flags |= REFERRAL;
-            if (any) {
-                target.addRRset(dname_dname);
-                target.addRRset(dname_nsec);
-            } else if (rdtype == RRType::DNAME()) {
-                target.addRRset(dname_dname);
-            } else if (rdtype == RRType::NSEC()) {
-                target.addRRset(dns01_nsec);
-            } else {
-                flags |= TYPE_NOT_FOUND;
-            }
-        } else if (name == Name("ns1.subzone.example.com") && mode == ADDRESS) {
-            target.addRRset(subzone_glue1);
-        } else if (name == Name("ns2.subzone.example.com") && mode == ADDRESS) {
-            target.addRRset(subzone_glue2);
-        } else if (name == loop1) {
-            target.addRRset(loop1_cname);
-            if (rdtype != RRType::CNAME()) {
-                flags |= CNAME_FOUND;
-            }
-        } else if (name == loop2) {
-            target.addRRset(loop1_cname);
-            if (rdtype != RRType::CNAME()) {
-                flags |= CNAME_FOUND;
-            }
-        } else {
-            flags |= NAME_NOT_FOUND;
-        }
-    }
-    return;
+    }
 }
 
 DataSrc::Result
 TestDataSrc::findRRset(const Name& qname,
-                       const RRClass& qclass UNUSED_PARAM,
+                       const RRClass& qclass,
                        const RRType& qtype,
                        RRsetList& target,
                        uint32_t& flags,
@@ -755,7 +531,7 @@
 
 DataSrc::Result
 TestDataSrc::findExactRRset(const Name& qname,
-                            const RRClass& qclass UNUSED_PARAM,
+                            const RRClass& qclass,
                             const RRType& qtype,
                             RRsetList& target,
                             uint32_t& flags,
@@ -770,7 +546,7 @@
     flags &= ~REFERRAL;
 
     // CNAMEs don't count in this case
-    if (flags & CNAME_FOUND) {
+    if ((flags & CNAME_FOUND) != 0) {
         flags &= ~CNAME_FOUND;
         flags |= TYPE_NOT_FOUND;
     }
@@ -780,7 +556,7 @@
 
 DataSrc::Result
 TestDataSrc::findAddrs(const Name& qname,
-                       const RRClass& qclass UNUSED_PARAM,
+                       const RRClass& qclass,
                        RRsetList& target,
                        uint32_t& flags,
                        const Name* zonename) const
@@ -795,7 +571,7 @@
 
 DataSrc::Result
 TestDataSrc::findReferral(const Name& qname,
-                          const RRClass& qclass UNUSED_PARAM,
+                          const RRClass& qclass,
                           RRsetList& target,
                           uint32_t& flags,
                           const Name* zonename) const
@@ -815,42 +591,30 @@
 {
     assert(zonename != NULL);
 
-    if (*zonename == example) {
-        if (qname >= example && qname < cnameext) {
-            target = example;
-        } else if (qname < cnameint) {
-            target = cnameext;
-        } else if (qname < dname) {
-            target = cnameint;
-        } else if (qname < dns01) {
-            target = dname;
-        } else if (qname < dns02) {
-            target = dns01;
-        } else if (qname < dns03) {
-            target = dns02;
-        } else if (qname < foo) {
-            target = dns03;
-        } else if (qname < sql1) {
-            target = foo;
-        } else if (qname < subzone) {
-            target = sql1;
-        } else if (qname < wild) {
-            target = subzone;
-        } else if (qname < wild2) {
-            target = wild;
-        } else if (qname < wild3) {
-            target = wild2;
-        } else if (qname < www) {
-            target = wild3;
-        } else {
-            target = www;
-        }
+    vector<Zone>::const_iterator zone = find_if(zones.begin(), zones.end(),
+                                                ZoneNameMatch(*zonename));
+    if (zone == zones.end()) {
+        return (ERROR);
+    }
+
+    if (zone->names.empty()) {
+        return (ERROR);
+    }
+
+    // if found, next_name >= qname.
+    vector<Name>::const_iterator next_name =
+        lower_bound(zone->names.begin(), zone->names.end(), qname);
+    if (next_name == zone->names.end()) {
+        // if no such name was found, the previous name is the last name.
+        target = zone->names.back();
+    } else if (*next_name == qname) {
+        target = *next_name;
+    } else if (next_name == zone->names.begin()) {
+        // if qname < first_name, the "previous name" is the last name.
+        target = zone->names.back();
     } else {
-        if (qname >= sql1 || qname < www_sql1) {
-            target = sql1;
-        } else {
-            target = www_sql1;
-        }
+        // otherwise, qname and next_name share the same previous name.
+        target = *(next_name - 1);
     }
     return (SUCCESS);
 }

Modified: experiments/python-binding/src/lib/datasrc/tests/test_datasrc.h
==============================================================================
--- experiments/python-binding/src/lib/datasrc/tests/test_datasrc.h (original)
+++ experiments/python-binding/src/lib/datasrc/tests/test_datasrc.h Wed Jun 30 13:47:21 2010
@@ -96,6 +96,7 @@
         ADDRESS,
         DELEGATION
     };
+    class RRsetMatch;
 
     void findRecords(const isc::dns::Name& name, const isc::dns::RRType& rdtype,
                      isc::dns::RRsetList& target,

Modified: experiments/python-binding/src/lib/datasrc/tests/testdata/example.org
==============================================================================
--- experiments/python-binding/src/lib/datasrc/tests/testdata/example.org (original)
+++ experiments/python-binding/src/lib/datasrc/tests/testdata/example.org Wed Jun 30 13:47:21 2010
@@ -11,3 +11,4 @@
 sub.example.org. NS ns.sub.example.org.
 ns.sub.example.org. A 192.0.2.101
 dname.example.org. DNAME dname.example.info.
+dname2.foo.example.org. DNAME dname2.example.info.

Modified: experiments/python-binding/src/lib/datasrc/tests/testdata/example.org.sqlite3
==============================================================================
Binary files - no diff available.

Modified: experiments/python-binding/src/lib/dns/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/dns/Makefile.am (original)
+++ experiments/python-binding/src/lib/dns/Makefile.am Wed Jun 30 13:47:21 2010
@@ -55,52 +55,30 @@
 BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
 #TODO: check this###BUILT_SOURCES = rdataclass.h rdataclass.cc
 
-lib_LTLIBRARIES = libdns.la
+lib_LTLIBRARIES = libdns++.la
 
-libdns_la_SOURCES = base32.h base32.cc
-libdns_la_SOURCES += base64.h base64.cc
-libdns_la_SOURCES += buffer.h
-libdns_la_SOURCES += dnssectime.h dnssectime.cc
-libdns_la_SOURCES += exceptions.h exceptions.cc
-libdns_la_SOURCES += hex.h hex.cc
-libdns_la_SOURCES += message.h message.cc
-libdns_la_SOURCES += messagerenderer.h messagerenderer.cc
-libdns_la_SOURCES += name.h name.cc
-libdns_la_SOURCES += rdata.h rdata.cc
-libdns_la_SOURCES += rrclass.cc
-libdns_la_SOURCES += rrparamregistry.h
-libdns_la_SOURCES += rrset.h rrset.cc
-libdns_la_SOURCES += rrsetlist.h rrsetlist.cc
-libdns_la_SOURCES += rrttl.h rrttl.cc
-libdns_la_SOURCES += rrtype.cc
-libdns_la_SOURCES += question.h question.cc
-libdns_la_SOURCES += sha1.h sha1.cc
-libdns_la_SOURCES += tsig.h tsig.cc
+libdns___la_SOURCES = base32.h base32.cc
+libdns___la_SOURCES += base64.h base64.cc
+libdns___la_SOURCES += buffer.h
+libdns___la_SOURCES += dnssectime.h dnssectime.cc
+libdns___la_SOURCES += exceptions.h exceptions.cc
+libdns___la_SOURCES += hex.h hex.cc
+libdns___la_SOURCES += message.h message.cc
+libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
+libdns___la_SOURCES += name.h name.cc
+libdns___la_SOURCES += rdata.h rdata.cc
+libdns___la_SOURCES += rrclass.cc
+libdns___la_SOURCES += rrparamregistry.h
+libdns___la_SOURCES += rrset.h rrset.cc
+libdns___la_SOURCES += rrsetlist.h rrsetlist.cc
+libdns___la_SOURCES += rrttl.h rrttl.cc
+libdns___la_SOURCES += rrtype.cc
+libdns___la_SOURCES += question.h question.cc
+libdns___la_SOURCES += sha1.h sha1.cc
+libdns___la_SOURCES += tsig.h tsig.cc
 
-
-#if HAVE_BOOST_PYTHON
-## This is a loadable module for python scripts, so we use the prefix "pyexec"
-## to make sure the object files will be installed in the appropriate place
-## for this purpose.
-#pyexec_LTLIBRARIES = bind10_dns.la
-#bind10_dns_la_SOURCES = python_dns.cc
-#bind10_dns_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-#bind10_dns_la_CXXFLAGS = $(AM_CXXFLAGS) $(B10_CXXFLAGS)
-#if GCC_WERROR_OK
-## XXX: Boost.Python triggers strict aliasing violation, so if we use -Werror
-## we need to suppress the warnings.
-#bind10_dns_la_CXXFLAGS += -fno-strict-aliasing
-#endif
-#bind10_dns_la_LDFLAGS = $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
-## Python prefers .so, while some OSes (specifically MacOS) use a different
-## suffix for dynamic objects.  -module is necessary to work this around.
-#bind10_dns_la_LDFLAGS += -module
-#bind10_dns_la_LIBADD = $(top_builddir)/src/lib/dns/libdns.la
-#bind10_dns_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-#bind10_dns_la_LIBADD += $(BOOST_PYTHON_LIB) $(PYTHON_LIB)
-#endif
-
-nodist_libdns_la_SOURCES = rdataclass.cc rrclass.h rrtype.h rrparamregistry.cc
+nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
+nodist_libdns___la_SOURCES += rrparamregistry.cc
 
 rrclass.h: rrclass-placeholder.h
 rrtype.h: rrtype-placeholder.h
@@ -108,8 +86,8 @@
 rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 	./gen-rdatacode.py
 
-libdns_includedir = $(includedir)/dns
-libdns_include_HEADERS = \
+libdns++_includedir = $(includedir)/dns
+libdns++_include_HEADERS = \
 	buffer.h \
 	dnssectime.h \
 	exceptions.h \

Modified: experiments/python-binding/src/lib/dns/message.cc
==============================================================================
--- experiments/python-binding/src/lib/dns/message.cc (original)
+++ experiments/python-binding/src/lib/dns/message.cc Wed Jun 30 13:47:21 2010
@@ -923,7 +923,7 @@
 template <typename T>
 const T*
 SectionIterator<T>::operator->() const {
-    return (impl_->it_.operator->());
+    return (&(operator*()));
 }
 
 template <typename T>

Modified: experiments/python-binding/src/lib/dns/name.cc
==============================================================================
--- experiments/python-binding/src/lib/dns/name.cc (original)
+++ experiments/python-binding/src/lib/dns/name.cc Wed Jun 30 13:47:21 2010
@@ -267,7 +267,7 @@
         if (state == ft_ordinary) {
             assert(count != 0);
             ndata.at(offsets.back()) = count;
-            
+
             offsets.push_back(ndata.size());
             // add a trailing \0
             ndata.push_back('\0');

Modified: experiments/python-binding/src/lib/dns/python/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/dns/python/Makefile.am (original)
+++ experiments/python-binding/src/lib/dns/python/Makefile.am Wed Jun 30 13:47:21 2010
@@ -13,17 +13,22 @@
 libdns_python_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
 libdns_python_la_LDFLAGS = $(PYTHON_LDFLAGS)
 
-#libdns_python_rrset_la_SOURCES = rrset_python.cc
-#libdns_python_rrset_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-#libdns_python_rrset_la_LDFLAGS = $(PYTHON_LDFLAGS) libdns_python_name.la
-
-#libdns_python_rrset_la_SOURCES = rrset_python.cc
-#libdns_python_rrset_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-#libdns_python_rrset_la_LDFLAGS = $(PYTHON_LDFLAGS)
+# directly included from source files, so these don't have their own
+# rules
+EXTRA_DIST = libdns_python_common.h
+EXTRA_DIST += messagerenderer_python.cc
+EXTRA_DIST += message_python.cc
+EXTRA_DIST += rrclass_python.cc
+EXTRA_DIST += name_python.cc
+EXTRA_DIST += rrset_python.cc
+EXTRA_DIST += question_python.cc
+EXTRA_DIST += rrttl_python.cc
+EXTRA_DIST += rdata_python.cc
+EXTRA_DIST += rrtype_python.cc
 
 # Python prefers .so, while some OSes (specifically MacOS) use a different
 # suffix for dynamic objects.  -module is necessary to work this around.
 libdns_python_la_LDFLAGS += -module
-libdns_python_la_LIBADD = $(top_builddir)/src/lib/dns/libdns.la
+libdns_python_la_LIBADD = $(top_builddir)/src/lib/dns/libdns++.la
 libdns_python_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 libdns_python_la_LIBADD += $(PYTHON_LIB)

Modified: experiments/python-binding/src/lib/dns/python/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/dns/python/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/dns/python/tests/Makefile.am Wed Jun 30 13:47:21 2010
@@ -16,7 +16,7 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_srcdir)/src/lib/dns/python/.libs \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
 	TESTDATA_PATH=$(abs_top_srcdir)/src/lib/dns/tests/testdata \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

Modified: experiments/python-binding/src/lib/dns/rrsetlist.cc
==============================================================================
--- experiments/python-binding/src/lib/dns/rrsetlist.cc (original)
+++ experiments/python-binding/src/lib/dns/rrsetlist.cc Wed Jun 30 13:47:21 2010
@@ -29,8 +29,7 @@
 namespace dns {
 
 void
-RRsetList::addRRset(RRsetPtr rrsetptr)
-{
+RRsetList::addRRset(RRsetPtr rrsetptr) {
     ConstRRsetPtr rrset_found = findRRset(rrsetptr->getType(),
                                           rrsetptr->getClass());
     if (rrset_found != NULL) {
@@ -42,8 +41,7 @@
 }
 
 RRsetPtr
-RRsetList::findRRset(const RRType& rrtype, const RRClass& rrclass)
-{
+RRsetList::findRRset(const RRType& rrtype, const RRClass& rrclass) {
     BOOST_FOREACH(RRsetPtr rrsetptr, rrsets_) {
         if ((rrsetptr->getClass() == rrclass) &&
             (rrsetptr->getType() == rrtype)) {

Modified: experiments/python-binding/src/lib/dns/rrsetlist.h
==============================================================================
--- experiments/python-binding/src/lib/dns/rrsetlist.h (original)
+++ experiments/python-binding/src/lib/dns/rrsetlist.h Wed Jun 30 13:47:21 2010
@@ -60,7 +60,7 @@
     }
     P operator->() const
     {
-        return (it_.operator->());
+        return (&(operator*()));
     }
     bool operator==(const RRsetListIterator& other)
     {

Modified: experiments/python-binding/src/lib/dns/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/dns/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/dns/tests/Makefile.am Wed Jun 30 13:47:21 2010
@@ -40,7 +40,7 @@
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
 endif
 

Modified: experiments/python-binding/src/lib/python/isc/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/python/isc/Makefile.am (original)
+++ experiments/python-binding/src/lib/python/isc/Makefile.am Wed Jun 30 13:47:21 2010
@@ -1,4 +1,4 @@
-SUBDIRS = datasrc cc config # Util
+SUBDIRS = datasrc cc config log # Util
 
 python_PYTHON = __init__.py
 

Modified: experiments/python-binding/src/lib/python/isc/__init__.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/__init__.py (original)
+++ experiments/python-binding/src/lib/python/isc/__init__.py Wed Jun 30 13:47:21 2010
@@ -2,3 +2,4 @@
 import isc.cc
 import isc.config
 #import isc.dns
+import isc.log

Modified: experiments/python-binding/src/lib/python/isc/datasrc/master.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/datasrc/master.py (original)
+++ experiments/python-binding/src/lib/python/isc/datasrc/master.py Wed Jun 30 13:47:21 2010
@@ -16,7 +16,8 @@
 # $Id$
 
 import sys, re, string
-
+import time
+import os
 #########################################################################
 # define exceptions
 #########################################################################
@@ -102,7 +103,7 @@
 # isttl: check whether a string is a valid TTL specifier.
 # returns: boolean
 #########################################################################
-ttl_regex = re.compile('[0-9]+[wdhms]?', re.I)
+ttl_regex = re.compile('([0-9]+[wdhms]?)+', re.I)
 def isttl(s):
     global ttl_regex
     if ttl_regex.match(s):
@@ -121,19 +122,26 @@
 #   MasterFileError
 #########################################################################
 def parse_ttl(s):
-    m = re.match('([0-9]+)(.*)', s)
-    if not m:
+    sum = 0
+    if not isttl(s):
         raise MasterFileError('Invalid TTL: ' + s)
-    ttl, suffix = int(m.group(1)), m.group(2)
-    if suffix.lower() == 'w':
-        ttl *= 604800
-    elif suffix.lower() == 'd':
-        ttl *= 86400
-    elif suffix.lower() == 'h':
-        ttl *= 3600
-    elif suffix.lower() == 'm':
-        ttl *= 60
-    return str(ttl)
+    for ttl_expr in re.findall('\d+[wdhms]?', s, re.I):
+        if ttl_expr.isdigit():
+            ttl = int(ttl_expr)
+            sum += ttl
+            continue
+        ttl = int(ttl_expr[:-1])
+        suffix = ttl_expr[-1].lower()
+        if suffix == 'w':
+            ttl *= 604800
+        elif suffix == 'd':
+            ttl *= 86400
+        elif suffix == 'h':
+            ttl *= 3600
+        elif suffix == 'm':
+            ttl *= 60
+        sum += ttl
+    return str(sum)
 
 #########################################################################
 # records: generator function to return complete RRs from the zone file,
@@ -147,7 +155,9 @@
     record = []
     complete = True
     paren = 0
+    size = 0
     for line in input:
+        size += len(line)
         list = cleanup(line).split()
         for word in list:
             if paren == 0:
@@ -169,10 +179,12 @@
 
         if paren == 1 or not record:
             continue
-
+        
         ret = ' '.join(record)
         record = []
-        yield ret
+        oldsize = size
+        size = 0
+        yield ret, oldsize
 
 #########################################################################
 # define the MasterFile class for reading zone master files
@@ -181,24 +193,62 @@
     __rrclass = 'IN'
     __maxttl = 0x7fffffff
     __ttl = ''
+    __lastttl = ''
     __zonefile = ''
     __name = ''
-
-    def __init__(self, filename, initial_origin = ''):
-        if initial_origin == '.':
-            initial_origin = ''
+    __file_level = 0
+    __file_type = ""
+    __init_time = time.time()
+    __records_num = 0
+
+    def __init__(self, filename, initial_origin = '', verbose = False):
         self.__initial_origin = initial_origin
         self.__origin = initial_origin
+        self.__datafile = filename
+
         try:
             self.__zonefile = open(filename, 'r')
         except:
             raise MasterFileError("Could not open " + filename)
+        self.__filesize = os.fstat(self.__zonefile.fileno()).st_size
+
+        self.__cur = 0
+        self.__numback = 0
+        self.__verbose = verbose
+        try:
+            self.__zonefile = open(filename, 'r')
+        except:
+            raise MasterFileError("Could not open " + filename)
+
+    def __status(self):
+        interval = time.time() - MasterFile.__init_time
+        if self.__filesize == 0:
+            percent = 100
+        else:
+            percent = (self.__cur * 100)/self.__filesize
+
+        sys.stdout.write("\r" + (80 * " "))
+        sys.stdout.write("\r%d RR(s) loaded in %d second(s) (%.2f%% of %s%s)"\
+                % (MasterFile.__records_num, interval, percent, MasterFile.__file_type, self.__datafile))
 
     def __del__(self):
         if self.__zonefile:
             self.__zonefile.close()
-
-    #########################################################################
+    ########################################################################
+    # check if the zonename is relative
+    # no then return
+    # yes , sets the relative domain name to the stated name
+    #######################################################################
+    def __statedname(self, name, record):
+        if name[-1] != '.':
+            if not self.__origin:
+                raise MasterFileError("Cannot parse RR, No $ORIGIN: " + record)
+            elif self.__origin == '.':
+                name += '.'
+            else:
+                name += '.' + self.__origin
+        return name
+    #####################################################################
     # handle $ORIGIN, $TTL and $GENERATE directives
     # (currently only $ORIGIN and $TTL are implemented)
     # input:
@@ -216,20 +266,22 @@
                 raise MasterFileError('Invalid $ORIGIN')
             if more:
                 raise MasterFileError('Invalid $ORIGIN')
-            if second == '.':
-                self.__origin = ''
-            elif second[-1] == '.':
+            if second[-1] == '.':
                 self.__origin = second
+            elif not self.__origin:
+                raise MasterFileError("$ORIGIN is not absolute in record:%s" % s)
+            elif self.__origin != '.':
+                self.__origin = second + '.' + self.__origin
             else:
-                self.__origin = second + '.' + self.__origin
+                self.__origin = second + '.'
             return True
         elif re.match('\$ttl', first, re.I):
             if not second or not isttl(second):
                 raise MasterFileError('Invalid TTL: "' + second + '"')
             if more:
                 raise MasterFileError('Invalid $TTL statement')
-            self.__ttl = parse_ttl(second)
-            if int(self.__ttl) > self.__maxttl:
+            MasterFile.__ttl = parse_ttl(second)
+            if int(MasterFile.__ttl) > self.__maxttl:
                 raise MasterFileError('TTL too high: ' + second)
             return True
         elif re.match('\$generate', first, re.I):
@@ -246,14 +298,28 @@
     # throws:
     #   MasterFileError
     #########################################################################
-    __filename = re.compile('[\"\']*([^\'\"]+)[\"\']*')
+    __include_syntax1 = re.compile('\s+(\S+)(?:\s+(\S+))?$', re.I)
+    __include_syntax2 = re.compile('\s+"([^"]+)"(?:\s+(\S+))?$', re.I)
+    __include_syntax3 = re.compile("\s+'([^']+)'(?:\s+(\S+))?$", re.I)
     def __include(self, s):
-        first, rest = pop(s)
-        if re.match('\$include', first, re.I):
-            m = self.__filename.match(rest)
-            if m:
-                file = m.group(1)
-                return file
+        if not s.lower().startswith('$include'):
+            return "", ""
+        s = s[len('$include'):]
+        m = self.__include_syntax1.match(s)
+        if not m:
+            m = self.__include_syntax2.match(s)
+        if not m:
+            m = self.__include_syntax3.match(s)
+        if not m:
+            raise MasterFileError('Invalid $include format')
+        file = m.group(1)
+        if m.group(2):
+            if not isname(m.group(2)):
+                raise MasterFileError('Invalid $include format (invalid origin)')
+            origin = self.__statedname(m.group(2), s)
+        else:
+            origin = self.__origin
+        return file, origin
 
     #########################################################################
     # try parsing an RR on the assumption that the type is specified in
@@ -272,6 +338,14 @@
         if istype(list[3]):
             if isclass(list[2]) and isttl(list[1]) and isname(list[0]):
                 name, ttl, rrclass, rrtype = list[0:4]
+                ttl = parse_ttl(ttl)
+                MasterFile.__lastttl = ttl or MasterFile.__lastttl
+                rdata = ' '.join(list[4:])
+                ret = name, ttl, rrclass, rrtype, rdata
+            elif isclass(list[1]) and isttl(list[2]) and isname(list[0]):
+                name, rrclass, ttl, rrtype = list[0:4]
+                ttl = parse_ttl(ttl)
+                MasterFile.__lastttl = ttl or MasterFile.__lastttl
                 rdata = ' '.join(list[4:])
                 ret = name, ttl, rrclass, rrtype, rdata
         return ret
@@ -284,6 +358,9 @@
     # returns:
     #   empty list if parse failed, else name, ttl, class, type, rdata
     #########################################################################
+    def __getttl(self):
+        return MasterFile.__ttl or MasterFile.__lastttl
+
     def __three(self, record, curname):
         ret = ''
         list = record.split()
@@ -292,19 +369,25 @@
         if istype(list[2]) and not istype(list[1]):
             if isclass(list[1]) and not isttl(list[0]) and isname(list[0]):
                 rrclass = list[1]
-                ttl = self.__ttl
+                ttl = self.__getttl()
                 name = list[0]
-            elif not isclass(list[1]) and isttl(list[1]) and isname(list[0]):
+            elif not isclass(list[1]) and isttl(list[1]) and not isclass(list[0]) and isname(list[0]):
                 rrclass = self.__rrclass
                 ttl = parse_ttl(list[1])
+                MasterFile.__lastttl = ttl or MasterFile.__lastttl
                 name = list[0]
             elif curname and isclass(list[1]) and isttl(list[0]):
-                rrclass = self.__rrclass
+                rrclass = list[1]
                 ttl = parse_ttl(list[0])
+                MasterFile.__lastttl = ttl or MasterFile.__lastttl
+                name = curname
+            elif curname and isttl(list[1]) and isclass(list[0]):
+                rrclass = list[0]
+                ttl = parse_ttl(list[1])
+                MasterFile.__lastttl = ttl or MasterFile.__lastttl
                 name = curname
             else:
                 return ret
-
             rrtype = list[2]
             rdata = ' '.join(list[3:])
             ret = name, ttl, rrclass, rrtype, rdata
@@ -325,29 +408,37 @@
         list = record.split()
         if len(list) <= 2:
             return ret
-
         if istype(list[1]):
             rrclass = self.__rrclass
             rrtype = list[1]
             if list[0].lower() == 'rrsig':
                 name = curname
-                ttl = self.__ttl
+                ttl = self.__getttl()
                 rrtype = list[0]
                 rdata = ' '.join(list[1:])
             elif isttl(list[0]):
                 ttl = parse_ttl(list[0])
                 name = curname
                 rdata = ' '.join(list[2:])
+            elif isclass(list[0]):
+                ttl = self.__getttl()
+                name = curname
+                rdata = ' '.join(list[2:])
             elif isname(list[0]):
                 name = list[0]
-                ttl = self.__ttl
+                ttl = self.__getttl()
                 rdata = ' '.join(list[2:])
             else:
                 raise MasterFileError("Cannot parse RR: " + record)
 
             ret = name, ttl, rrclass, rrtype, rdata
-
         return ret
+
+    ########################################################################
+    #close verbose
+    ######################################################################
+    def closeverbose(self):
+        self.__status()
 
     #########################################################################
     # zonedata: generator function to parse a zone master file and return
@@ -355,16 +446,43 @@
     #########################################################################
     def zonedata(self):
         name = ''
-
-        for record in records(self.__zonefile):
+        last_status = 0.0
+        flag = 1
+
+        for record, size in records(self.__zonefile):
+            if self.__verbose:
+                now = time.time()
+                if flag == 1:
+                    self.__status()
+                    flag = 0
+                if now - last_status >= 1.0:
+                    self.__status()
+                    last_status = now
+
+            self.__cur += size
             if self.__directive(record):
                 continue
 
-            incl = self.__include(record)
+            incl, suborigin = self.__include(record)
             if incl:
-                sub = MasterFile(incl, self.__origin)
-                for name, ttl, rrclass, rrtype, rdata in sub.zonedata():
-                    yield (name, ttl, rrclass, rrtype, rdata)
+                if self.__filesize == 0:
+                    percent = 100
+                else:
+                    percent = (self.__cur * 100)/self.__filesize
+                if self.__verbose:
+                    sys.stdout.write("\r" + (80 * " "))
+                    sys.stdout.write("\rIncluding \"%s\" from \"%s\"\n" % (incl, self.__datafile))
+                MasterFile.__file_level += 1
+                MasterFile.__file_type = "included "
+                sub = MasterFile(incl, suborigin, self.__verbose)
+
+                for rrname, ttl, rrclass, rrtype, rdata in sub.zonedata():
+                    yield (rrname, ttl, rrclass, rrtype, rdata)
+                if self.__verbose:
+                    sub.closeverbose()
+                MasterFile.__file_level -= 1
+                if MasterFile.__file_level == 0:
+                    MasterFile.__file_type = ""
                 del sub
                 continue
 
@@ -373,7 +491,7 @@
             if rl[0] == '@':
                 rl[0] = self.__origin
                 if not self.__origin:
-                    rl[0] = '.'
+                    raise MasterFileError("Cannot parse RR, No $ORIGIN: " + record)
                 record = ' '.join(rl)
 
             result = self.__four(record, name)
@@ -387,36 +505,43 @@
             if not result:
                 first, rdata = pop(record)
                 if istype(first):
-                    result = name, self.__ttl, self.__rrclass, first, rdata
+                    result = name, self.__getttl(), self.__rrclass, first, rdata
 
             if not result:
                 raise MasterFileError("Cannot parse RR: " + record)
 
             name, ttl, rrclass, rrtype, rdata = result
-            if name[-1] != '.':
-                name += '.' + self.__origin
+            name = self.__statedname(name, record)
 
             if rrclass.lower() != 'in':
                 raise MasterFileError("CH and HS zones not supported")
-
-            if not ttl:
-                raise MasterFileError("No TTL specified; zone rejected")
 
             # add origin to rdata containing names, if necessary
             if rrtype.lower() in ('cname', 'dname', 'ns', 'ptr'):
                 if not isname(rdata):
                     raise MasterFileError("Invalid " + rrtype + ": " + rdata)
-                if rdata[-1] != '.':
-                    rdata += '.' + self.__origin
+                rdata = self.__statedname(rdata, record)
+
             if rrtype.lower() == 'soa':
                 soa = rdata.split()
                 if len(soa) < 2 or not isname(soa[0]) or not isname(soa[1]):
                     raise MasterFileError("Invalid " + rrtype + ": " + rdata)
-                if soa[0][-1] != '.':
-                    soa[0] += '.' + self.__origin
-                if soa[1][-1] != '.':
-                    soa[1] += '.' + self.__origin
+                soa[0] = self.__statedname(soa[0], record)
+                soa[1] = self.__statedname(soa[1], record)
+                if not MasterFile.__ttl and not ttl:
+                    MasterFile.__ttl = MasterFile.__ttl or parse_ttl(soa[-1])
+                    ttl = MasterFile.__ttl
+
+                for index in range(3, len(soa)):
+                    if isttl(soa[index]):
+                        soa[index] = parse_ttl(soa[index])
+                    else :
+                        raise MasterFileError("No TTL specified; in soa record!")
                 rdata = ' '.join(soa)
+
+            if not ttl:
+                raise MasterFileError("No TTL specified; zone rejected")
+
             if rrtype.lower() == 'mx':
                 mx = rdata.split()
                 if len(mx) != 2 or not isname(mx[1]):
@@ -424,7 +549,7 @@
                 if mx[1][-1] != '.':
                     mx[1] += '.' + self.__origin
                     rdata = ' '.join(mx)
-
+            MasterFile.__records_num += 1
             yield (name, ttl, rrclass, rrtype, rdata)
 
     #########################################################################
@@ -436,16 +561,22 @@
             return self.__name
         old_origin = self.__origin
         self.__origin = self.__initial_origin
+        cur_value = self.__cur
         old_location = self.__zonefile.tell()
+        old_verbose = self.__verbose
+        self.__verbose = False
         self.__zonefile.seek(0)
+
         for name, ttl, rrclass, rrtype, rdata in self.zonedata():
             if rrtype.lower() == 'soa':
                 break
         self.__zonefile.seek(old_location)
         self.__origin = old_origin
+        self.__cur = cur_value
         if rrtype.lower() != 'soa':
             raise MasterFileError("No SOA found")
         self.__name = name
+        self.__verbose = old_verbose
         return name
 
     #########################################################################
@@ -454,7 +585,8 @@
     def reset(self):
         self.__zonefile.seek(0)
         self.__origin = self.__initial_origin
-        self.__ttl = ''
+        MasterFile.__ttl = ''
+        MasterFile.__lastttl = ''
 
 #########################################################################
 # main: used for testing; parse a zone file and print out each record




More information about the bind10-changes mailing list