Browse Source

[1959] Merge branch 'master' into trac1959

Merge needed to get the StatsMgr.h and recent changes to DHCP Lib.

Conflicts:
	tests/tools/perfdhcp/Makefile.am
	tests/tools/perfdhcp/tests/Makefile.am
        src/lib/dhcp/iface_mgr.cc
Marcin Siodelski 12 years ago
parent
commit
e34ad6d48b
100 changed files with 3962 additions and 3157 deletions
  1. 1 0
      .gitignore
  2. 42 1
      ChangeLog
  3. 7 1
      Makefile.am
  4. 160 97
      configure.ac
  5. 1 1
      dns++.pc.in
  6. 2 1
      doc/Doxyfile
  7. 5 3
      doc/devel/02-dhcp.dox
  8. 388 330
      doc/guide/bind10-guide.html
  9. 558 522
      doc/guide/bind10-guide.txt
  10. 155 140
      doc/guide/bind10-guide.xml
  11. 61 11
      doc/guide/bind10-messages.html
  12. 98 18
      doc/guide/bind10-messages.xml
  13. 1 1
      src/bin/Makefile.am
  14. 14 13
      src/bin/auth/Makefile.am
  15. 0 4
      src/bin/auth/auth.spec.pre.in
  16. 9 90
      src/bin/auth/auth_config.cc
  17. 52 146
      src/bin/auth/auth_srv.cc
  18. 29 103
      src/bin/auth/auth_srv.h
  19. 1 6
      src/bin/auth/b10-auth.8
  20. 0 13
      src/bin/auth/b10-auth.xml
  21. 14 14
      src/bin/auth/benchmarks/Makefile.am
  22. 7 31
      src/bin/auth/benchmarks/query_bench.cc
  23. 30 137
      src/bin/auth/command.cc
  24. 223 0
      src/bin/auth/datasrc_configurator.h
  25. 12 8
      src/bin/auth/main.cc
  26. 27 27
      src/bin/auth/query.cc
  27. 9 11
      src/bin/auth/query.h
  28. 22 14
      src/bin/auth/tests/Makefile.am
  29. 284 216
      src/bin/auth/tests/auth_srv_unittest.cc
  30. 78 185
      src/bin/auth/tests/command_unittest.cc
  31. 5 383
      src/bin/auth/tests/config_unittest.cc
  32. 298 0
      src/bin/auth/tests/datasrc_configurator_unittest.cc
  33. 122 86
      src/bin/auth/tests/query_unittest.cc
  34. 8 0
      src/bin/auth/tests/testdata/.gitignore
  35. 1 0
      src/bin/auth/tests/testdata/Makefile.am
  36. 5 0
      src/bin/auth/tests/testdata/spec.spec
  37. 1 8
      src/bin/bind10/bind10.8
  38. 0 11
      src/bin/bind10/bind10.xml
  39. 2 7
      src/bin/bind10/bind10_src.py.in
  40. 0 2
      src/bin/bind10/tests/bind10_test.py.in
  41. 13 4
      src/bin/bindctl/bindctl.1
  42. 2 1
      src/bin/cfgmgr/Makefile.am
  43. 2 0
      src/bin/cfgmgr/plugins/.gitignore
  44. 6 3
      src/bin/cfgmgr/plugins/Makefile.am
  45. 74 0
      src/bin/cfgmgr/plugins/datasrc.spec.pre.in
  46. 80 0
      src/bin/cfgmgr/plugins/datasrc_config_plugin.py
  47. 1 1
      src/bin/cfgmgr/plugins/tests/Makefile.am
  48. 159 0
      src/bin/cfgmgr/plugins/tests/datasrc_test.py
  49. 9 0
      src/bin/cmdctl/b10-cmdctl.8
  50. 17 21
      src/bin/ddns/tests/ddns_test.py
  51. 6 6
      src/bin/dhcp4/Makefile.am
  52. 4 4
      src/bin/dhcp4/ctrl_dhcp4_srv.cc
  53. 12 7
      src/bin/dhcp4/dhcp4_srv.cc
  54. 36 15
      src/bin/dhcp4/main.cc
  55. 7 7
      src/bin/dhcp4/tests/Makefile.am
  56. 3 3
      src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
  57. 40 5
      src/bin/dhcp4/tests/dhcp4_test.py
  58. 7 4
      src/bin/dhcp6/Makefile.am
  59. 159 0
      src/bin/dhcp6/ctrl_dhcp6_srv.cc
  60. 123 0
      src/bin/dhcp6/ctrl_dhcp6_srv.h
  61. 14 2
      src/bin/dhcp6/dhcp6.spec
  62. 24 16
      src/bin/dhcp6/dhcp6_srv.cc
  63. 3 1
      src/bin/dhcp6/dhcp6_srv.h
  64. 56 49
      src/bin/dhcp6/main.cc
  65. 8 5
      src/bin/dhcp6/tests/Makefile.am
  66. 85 0
      src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
  67. 39 5
      src/bin/dhcp6/tests/dhcp6_test.py
  68. 3 3
      src/bin/host/Makefile.am
  69. 0 4
      src/bin/loadzone/Makefile.am
  70. 2 4
      src/bin/msgq/b10-msgq.8
  71. 14 14
      src/bin/resolver/Makefile.am
  72. 9 0
      src/bin/resolver/b10-resolver.8
  73. 16 16
      src/bin/resolver/tests/Makefile.am
  74. 0 2
      src/bin/showtech/.gitignore
  75. 2 2
      src/bin/sockcreator/Makefile.am
  76. 1 1
      src/bin/sockcreator/tests/Makefile.am
  77. 2 0
      src/bin/sysinfo/.gitignore
  78. 5 5
      src/bin/showtech/Makefile.am
  79. 9 9
      src/bin/showtech/b10-showtech.1
  80. 6 6
      src/bin/showtech/b10-showtech.xml
  81. 39 30
      src/bin/showtech/showtech.py.in
  82. 7 143
      src/bin/xfrin/tests/xfrin_test.py
  83. 1 1
      src/bin/xfrin/xfrin.py.in
  84. 3 4
      src/bin/xfrin/xfrin_messages.mes
  85. 10 1
      src/bin/zonemgr/b10-zonemgr.8
  86. 13 13
      src/lib/acl/Makefile.am
  87. 7 7
      src/lib/acl/tests/Makefile.am
  88. 17 17
      src/lib/asiodns/Makefile.am
  89. 6 6
      src/lib/asiodns/tests/Makefile.am
  90. 23 23
      src/lib/asiolink/Makefile.am
  91. 3 3
      src/lib/asiolink/tests/Makefile.am
  92. 2 2
      src/lib/bench/Makefile.am
  93. 1 1
      src/lib/bench/example/Makefile.am
  94. 4 4
      src/lib/bench/tests/Makefile.am
  95. 12 12
      src/lib/cache/Makefile.am
  96. 7 7
      src/lib/cache/tests/Makefile.am
  97. 5 5
      src/lib/cc/Makefile.am
  98. 3 3
      src/lib/cc/tests/Makefile.am
  99. 9 9
      src/lib/config/Makefile.am
  100. 0 0
      src/lib/config/module_spec.cc

+ 1 - 0
.gitignore

@@ -35,3 +35,4 @@ TAGS
 /coverage-cpp-html
 /coverage-cpp-html
 /dns++.pc
 /dns++.pc
 /report.info
 /report.info
+/logger_lockfile

+ 42 - 1
ChangeLog

@@ -1,3 +1,44 @@
+459.	[func]		tomek
+	b10-dhcp6: DHCPv6 server component is now integrated into
+	BIND10 framework. It can be started from BIND10 (using bindctl)
+	and can receive commands. The only supported command for now
+	is 'Dhcp6 shutdown'.
+	b10-dhcp4: Command line-switch '-s' to disable msgq was added.
+	b10-dhcp6: Command line-switch '-s' to disable msgq was added.
+	(Trac #1708, git e0d7c52a71414f4de1361b09d3c70431c96daa3f)
+
+458.	[build]*	jinmei
+	BIND 10 now relies on Boost offset_ptr, which caused some new
+	portability issues.  Such issues are detected at ./configure time.
+	If ./configure stops due to this, try the following workaround:
+	- If it's about the use of mutable for a reference with clang++,
+	  upgrade Boost version to 1.44 or higher, or try a different
+	  compiler (e.g. g++ generally seems to be free from this issue)
+	- If it's about the use of "variadic templates", specify
+	  --without-werror so the warning won't be promoted to an error.
+	  Specifying BOOST_NO_USER_CONFIG in CXXFLAGS may also work
+	  (which would be the case if Boost is installed via pkgsrc)
+	(Trac #2147, git 30061d1139aad8716e97d6b620c259752fd0a3cd)
+
+457.	[build]*	muks
+	BIND 10 library names now have a "b10-" prefix. This is to avoid
+	clashes with other similarly named libraries on the system.
+	(Trac #2071, git ac20a00c28069804edc0a36050995df52f601efb)
+
+456.	[build]*	muks
+	BIND 10 now compiles against log4cplus-1.1.0 (RC releases)
+	also.  Note: some older versions of log4cplus don't work any more;
+	known oldest workable version is 1.0.4.  Thanks to John Lumby for
+	sending a patch.
+	(Trac #2169, git 7d7e5269d57451191c0aef1b127d292d3615fe2c)
+
+455.	[func]*		vorner
+	The server now uses newer API for data sources. This would be an
+	internal change, however, the data sources are now configured
+	differently. Please, migrate your configuration to the top-level
+	"data_sources" module.
+	(Trac #1976, git 0d4685b3e7603585afde1b587cbfefdfaf6a1bb3)
+
 454.	[bug]		jelte
 454.	[bug]		jelte
 	b10-cfgmgr now loads its configuration check plugins directly from
 	b10-cfgmgr now loads its configuration check plugins directly from
 	the plugin search path, as opposed to importing them from the
 	the plugin search path, as opposed to importing them from the
@@ -13,7 +54,7 @@
 	(Trac #1986, git bd6b0a5ed3481f78fb4e5cb0b18c7b6e5920f9f8)
 	(Trac #1986, git bd6b0a5ed3481f78fb4e5cb0b18c7b6e5920f9f8)
 
 
 452.	[func]*		muks
 452.	[func]*		muks
-	b10-showtech: An initial implementation of the b10-showtech tool
+	isc-sysinfo: An initial implementation of the isc-sysinfo tool
 	is now available. It gathers and outputs system information which
 	is now available. It gathers and outputs system information which
 	can be used by future tech support staff.
 	can be used by future tech support staff.
 	(Trac #2062, git 144e80212746f8d55e6a59edcf689fec9f32ae95)
 	(Trac #2062, git 144e80212746f8d55e6a59edcf689fec9f32ae95)

+ 7 - 1
Makefile.am

@@ -2,7 +2,7 @@ ACLOCAL_AMFLAGS = -I m4macros ${ACLOCAL_FLAGS}
 # ^^^^^^^^ This has to be the first line and cannot come later in this
 # ^^^^^^^^ This has to be the first line and cannot come later in this
 # Makefile.am due to some bork in some versions of autotools.
 # Makefile.am due to some bork in some versions of autotools.
 
 
-SUBDIRS = compatcheck doc src tests
+SUBDIRS = compatcheck doc . src tests
 USE_LCOV=@USE_LCOV@
 USE_LCOV=@USE_LCOV@
 LCOV=@LCOV@
 LCOV=@LCOV@
 GENHTML=@GENHTML@
 GENHTML=@GENHTML@
@@ -427,3 +427,9 @@ pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = dns++.pc
 pkgconfig_DATA = dns++.pc
 
 
 CLEANFILES = $(abs_top_builddir)/logger_lockfile
 CLEANFILES = $(abs_top_builddir)/logger_lockfile
+
+if HAVE_GTEST_SOURCE
+noinst_LIBRARIES = libgtest.a
+libgtest_a_CXXFLAGS = $(GTEST_INCLUDES) $(AM_CXXFLAGS)
+nodist_libgtest_a_SOURCES = $(GTEST_SOURCE)/src/gtest-all.cc
+endif

+ 160 - 97
configure.ac

@@ -454,20 +454,30 @@ AC_SUBST(PYCOVERAGE)
 AC_SUBST(PYCOVERAGE_RUN)
 AC_SUBST(PYCOVERAGE_RUN)
 AC_SUBST(USE_PYCOVERAGE)
 AC_SUBST(USE_PYCOVERAGE)
 
 
+enable_gtest="no"
+GTEST_INCLUDES=
+
+AC_ARG_WITH([gtest-source],
+            [AS_HELP_STRING([--with-gtest-source=PATH],
+                            [location of the Googletest source, defaults to /usr/src/gtest])],
+            [enable_gtest="yes" ; GTEST_SOURCE="$withval"],
+            [GTEST_SOURCE="/usr/src/gtest"])
+
+AC_ARG_WITH([gtest],
+	    [AS_HELP_STRING([--with-gtest=PATH],
+			    [specify a path to gtest header files (PATH/include) and library (PATH/lib)])],
+	[gtest_path="$withval"; enable_gtest="yes"], [gtest_path="no"])
+
 AC_ARG_WITH(lcov,
 AC_ARG_WITH(lcov,
 [  --with-lcov[=PROGRAM]         enable gtest and coverage target using the specified lcov], lcov="$withval", lcov="no")
 [  --with-lcov[=PROGRAM]         enable gtest and coverage target using the specified lcov], lcov="$withval", lcov="no")
 
 
-AC_ARG_WITH(gtest,
-[  --with-gtest=PATH       specify a path to gtest header files (PATH/include) and library (PATH/lib)],
-    gtest_path="$withval", gtest_path="no")
-
 USE_LCOV="no"
 USE_LCOV="no"
 if test "$lcov" != "no"; then
 if test "$lcov" != "no"; then
 	# force gtest if not set
 	# force gtest if not set
-	if test "$gtest_path" = "no"; then
+	if test "$enable_gtest" = "no"; then
 #		AC_MSG_ERROR("lcov needs gtest for test coverage report")
 #		AC_MSG_ERROR("lcov needs gtest for test coverage report")
 		AC_MSG_NOTICE([gtest support is now enabled, because used by coverage tests])
 		AC_MSG_NOTICE([gtest support is now enabled, because used by coverage tests])
-		gtest_path="yes"
+		enable_gtest="yes"
 	fi
 	fi
 	if test "$lcov" != "yes"; then
 	if test "$lcov" != "yes"; then
 		LCOV=$lcov
 		LCOV=$lcov
@@ -799,6 +809,17 @@ AC_TRY_COMPILE([
  CPPFLAGS_BOOST_THREADCONF="-DBOOST_DISABLE_THREADS=1"],
  CPPFLAGS_BOOST_THREADCONF="-DBOOST_DISABLE_THREADS=1"],
 [AC_MSG_RESULT(yes)])
 [AC_MSG_RESULT(yes)])
 
 
+# Boost offset_ptr is required in one library (not optional right now), and
+# it's known it doesn't compile on some platforms, depending on boost version,
+# its local configuration, and compiler.
+AC_MSG_CHECKING([Boost offset_ptr compiles])
+AC_TRY_COMPILE([
+#include <boost/interprocess/offset_ptr.hpp>
+],,
+[AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)
+ AC_MSG_ERROR([Failed to compile a required header file.  Try upgrading Boost to 1.44 or higher (when using clang++) or specifying --without-werror.  See the ChangeLog entry for Trac no. 2147 for more details.])])
+
 CPPFLAGS="$CPPFLAGS_SAVES $CPPFLAGS_BOOST_THREADCONF"
 CPPFLAGS="$CPPFLAGS_SAVES $CPPFLAGS_BOOST_THREADCONF"
 AC_SUBST(BOOST_INCLUDES)
 AC_SUBST(BOOST_INCLUDES)
 
 
@@ -813,98 +834,138 @@ AC_SUBST(MULTITHREADING_FLAG)
 #
 #
 # Check availability of gtest, which will be used for unit tests.
 # Check availability of gtest, which will be used for unit tests.
 #
 #
-if test "$gtest_path" != "no"
-then
-	DISTCHECK_GTEST_CONFIGURE_FLAG="--with-gtest=\"$gtest_path\""
-	if test "$gtest_path" != "yes"; then
-		GTEST_PATHS=$gtest_path
-		if test -x "${gtest_path}/bin/gtest-config" ; then
-			GTEST_CONFIG="${gtest_path}/bin/gtest-config"
-		fi
-	else
-		AC_PATH_PROG([GTEST_CONFIG], [gtest-config])
-	fi
-	if test -x "${GTEST_CONFIG}" ; then :
-		# using cppflags instead of cxxflags
-		GTEST_INCLUDES=`${GTEST_CONFIG} --cppflags`
-		GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags`
-		GTEST_LDADD=`${GTEST_CONFIG} --libs`
-		GTEST_FOUND="true"
-	else
-		AC_MSG_WARN([Unable to locate Google Test gtest-config.])
-		if test -z "${GTEST_PATHS}" ; then
-			GTEST_PATHS="/usr /usr/local"
-		fi
-		GTEST_FOUND="false"
-	fi
-	if test "${GTEST_FOUND}" != "true"; then
-		GTEST_FOUND="false"
-		for dir in $GTEST_PATHS; do
-			if test -f "$dir/include/gtest/gtest.h"; then
-				GTEST_INCLUDES="-I$dir/include"
-				GTEST_LDFLAGS="-L$dir/lib"
-				GTEST_LDADD="-lgtest"
-				GTEST_FOUND="true"
-				# There is no gtest-config script on this
-				# system, which is supposed to inform us
-				# whether we need pthreads as well (a
-				# gtest compile-time option). So we still
-				# need to test that manually.
-				CPPFLAGS_SAVED="$CPPFLAGS"
-				CPPFLAGS="$CPPFLAGS $GTEST_INCLUDES"
-				LDFLAGS_SAVED="$LDFLAGS"
-				LDFLAGS="$LDFLAGS $GTEST_LDFLAGS"
-				LIBS_SAVED=$LIBS
-				LIBS="$LIBS $GTEST_LDADD"
-				AC_MSG_CHECKING([Checking whether gtest tests need pthreads])
-				# First try to compile without pthreads
-				AC_TRY_LINK([
-					#include <gtest/gtest.h>
-					],[
-						int i = 0;
-						char* c = NULL;
-						::testing::InitGoogleTest(&i, &c);
-						return (0);
-					],
-					[ AC_MSG_RESULT(no) ],
-					[
-						LIBS="$SAVED_LIBS $GTEST_LDADD $PTHREAD_LDFLAGS"
-						# Now try to compile with pthreads
-						AC_TRY_LINK([
-							#include <gtest/gtest.h>
-							],[
-								int i = 0;
-								char* c = NULL;
-								::testing::InitGoogleTest(&i, &c);
-								return (0);
-							],
-							[ AC_MSG_RESULT(yes)
-							  GTEST_LDADD="$GTEST_LDADD $PTHREAD_LDFLAGS"
-							],
-							# Apparently we can't compile it at all
-							[ AC_MSG_ERROR(unable to compile with gtest) ])
-				])
-				CPPFLAGS=$CPPFLAGS_SAVED
-				LDFLAGS=$LDFLAGS_SAVED
-				LIBS=$LIBS_SAVED
-				break
-			fi
-		done
-	fi
-	if test "${GTEST_FOUND}" != "true"; then
-		AC_MSG_ERROR([Cannot find gtest in: $GTEST_PATHS])
-	fi
-else
-	GTEST_INCLUDES=
-	GTEST_LDFLAGS=
-	GTEST_LDADD=
-	DISTCHECK_GTEST_CONFIGURE_FLAG=
+GTEST_LDFLAGS=
+GTEST_LDADD=
+# TODO: set DISTCHECK_GTEST_CONFIGURE_FLAG for --with-gtest too
+DISTCHECK_GTEST_CONFIGURE_FLAG=
+
+if test "x$enable_gtest" = "xyes" ; then
+
+    if test -n "$with_gtest_source" ; then
+
+          if test "x$GTEST_SOURCE" = "xyes" ; then
+
+            AC_MSG_CHECKING([for gtest source])
+            # If not specified, try some common paths.
+            GTEST_SOURCE=
+            for d in /usr/src/gtest /usr/local /usr/pkg /opt /opt/local ; do
+                if test -f $d/src/gtest-all.cc -a $d/src/gtest_main.cc; then
+                    GTEST_SOURCE=$d
+                    AC_MSG_RESULT([$GTEST_SOURCE])
+                    break
+                fi
+            done
+            if test -z $GTEST_SOURCE ; then
+                AC_MSG_ERROR([no gtest source but it was selected])
+            fi
+         else
+            AC_CHECK_FILES([$GTEST_SOURCE/src/gtest-all.cc]
+               [$GTEST_SOURCE/src/gtest_main.cc],
+               [have_gtest_source=yes],
+               [AC_MSG_ERROR([no gtest source at $GTEST_SOURCE])])
+          fi
+          have_gtest_source=yes
+          GTEST_LDFLAGS="\$(top_builddir)/libgtest.a"
+          DISTCHECK_GTEST_CONFIGURE_FLAG="--with-gtest-source=$GTEST_SOURCE"
+          GTEST_INCLUDES="-I$GTEST_SOURCE -I$GTEST_SOURCE/include"
+          # See $GTEST_SOURCE/include/gtest/internal/gtest-port.h
+          # about GTEST_HAS_PTHREAD.
+          case "$host" in
+            *-solaris*|*-linux*|*-hpux*)
+                GTEST_LDADD="$GTEST_LDADD $PTHREAD_LDFLAGS"
+                ;;
+          esac
+        fi
+
+if test "$gtest_path" != "no" ; then
+    if test "$gtest_path" != "yes"; then
+        GTEST_PATHS=$gtest_path
+        if test -x "${gtest_path}/bin/gtest-config" ; then
+            GTEST_CONFIG="${gtest_path}/bin/gtest-config"
+        fi
+    else
+        AC_PATH_PROG([GTEST_CONFIG], [gtest-config])
+    fi
+    if test -x "${GTEST_CONFIG}" ; then :
+        # using cppflags instead of cxxflags
+        GTEST_INCLUDES=`${GTEST_CONFIG} --cppflags`
+        GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags`
+        GTEST_LDADD=`${GTEST_CONFIG} --libs`
+        GTEST_FOUND="true"
+    else
+        AC_MSG_WARN([Unable to locate Google Test gtest-config.])
+        if test -z "${GTEST_PATHS}" ; then
+            GTEST_PATHS="/usr /usr/local"
+        fi
+        GTEST_FOUND="false"
+    fi
+    if test "${GTEST_FOUND}" != "true"; then
+        GTEST_FOUND="false"
+        for dir in $GTEST_PATHS; do
+            if test -f "$dir/include/gtest/gtest.h"; then
+                GTEST_INCLUDES="-I$dir/include"
+                GTEST_LDFLAGS="-L$dir/lib"
+                GTEST_LDADD="-lgtest"
+                GTEST_FOUND="true"
+                # There is no gtest-config script on this
+                # system, which is supposed to inform us
+                # whether we need pthreads as well (a
+                # gtest compile-time option). So we still
+                # need to test that manually.
+                CPPFLAGS_SAVED="$CPPFLAGS"
+                CPPFLAGS="$CPPFLAGS $GTEST_INCLUDES"
+                LDFLAGS_SAVED="$LDFLAGS"
+                LDFLAGS="$LDFLAGS $GTEST_LDFLAGS"
+                LIBS_SAVED=$LIBS
+                LIBS="$LIBS $GTEST_LDADD"
+                AC_MSG_CHECKING([Checking whether gtest tests need pthreads])
+                # First try to compile without pthreads
+                AC_TRY_LINK([
+                    #include <gtest/gtest.h>
+                    ],[
+                        int i = 0;
+                        char* c = NULL;
+                        ::testing::InitGoogleTest(&i, &c);
+                        return (0);
+                    ],
+                    [ AC_MSG_RESULT(no) ],
+                    [
+                        LIBS="$SAVED_LIBS $GTEST_LDADD $PTHREAD_LDFLAGS"
+                        # Now try to compile with pthreads
+                        AC_TRY_LINK([
+                            #include <gtest/gtest.h>
+                            ],[
+                                int i = 0;
+                                char* c = NULL;
+                                ::testing::InitGoogleTest(&i, &c);
+                                return (0);
+                            ],
+                            [ AC_MSG_RESULT(yes)
+                              GTEST_LDADD="$GTEST_LDADD $PTHREAD_LDFLAGS"
+                            ],
+                            # Apparently we can't compile it at all
+                            [ AC_MSG_ERROR(unable to compile with gtest) ])
+                ])
+                CPPFLAGS=$CPPFLAGS_SAVED
+                LDFLAGS=$LDFLAGS_SAVED
+                LIBS=$LIBS_SAVED
+                break
+            fi
+        done
+    fi
+    if test "${GTEST_FOUND}" != "true"; then
+        AC_MSG_ERROR([Cannot find gtest in: $GTEST_PATHS])
+    fi
+
+  fi
 fi
 fi
-AM_CONDITIONAL(HAVE_GTEST, test $gtest_path != "no")
+AM_CONDITIONAL(HAVE_GTEST, test $enable_gtest != "no")
+AM_CONDITIONAL(HAVE_GTEST_SOURCE, test "X$have_gtest_source" = "Xyes")
 AC_SUBST(DISTCHECK_GTEST_CONFIGURE_FLAG)
 AC_SUBST(DISTCHECK_GTEST_CONFIGURE_FLAG)
 AC_SUBST(GTEST_INCLUDES)
 AC_SUBST(GTEST_INCLUDES)
 AC_SUBST(GTEST_LDFLAGS)
 AC_SUBST(GTEST_LDFLAGS)
 AC_SUBST(GTEST_LDADD)
 AC_SUBST(GTEST_LDADD)
+AC_SUBST(GTEST_SOURCE)
 
 
 dnl check for pkg-config itself so we don't try the m4 macro without pkg-config
 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)
 AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes, no)
@@ -1018,6 +1079,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/msgq/tests/Makefile
                  src/bin/msgq/tests/Makefile
                  src/bin/auth/Makefile
                  src/bin/auth/Makefile
                  src/bin/auth/tests/Makefile
                  src/bin/auth/tests/Makefile
+                 src/bin/auth/tests/testdata/Makefile
                  src/bin/auth/benchmarks/Makefile
                  src/bin/auth/benchmarks/Makefile
                  src/bin/ddns/Makefile
                  src/bin/ddns/Makefile
                  src/bin/ddns/tests/Makefile
                  src/bin/ddns/tests/Makefile
@@ -1027,7 +1089,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/dhcp4/tests/Makefile
                  src/bin/dhcp4/tests/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/tests/Makefile
                  src/bin/resolver/tests/Makefile
-                 src/bin/showtech/Makefile
+                 src/bin/sysinfo/Makefile
                  src/bin/sockcreator/Makefile
                  src/bin/sockcreator/Makefile
                  src/bin/sockcreator/tests/Makefile
                  src/bin/sockcreator/tests/Makefile
                  src/bin/xfrin/Makefile
                  src/bin/xfrin/Makefile
@@ -1142,6 +1204,7 @@ AC_CONFIG_FILES([Makefile
 AC_OUTPUT([doc/version.ent
 AC_OUTPUT([doc/version.ent
            src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/cfgmgr/tests/b10-cfgmgr_test.py
            src/bin/cfgmgr/tests/b10-cfgmgr_test.py
+           src/bin/cfgmgr/plugins/datasrc.spec.pre
            src/bin/cmdctl/cmdctl.py
            src/bin/cmdctl/cmdctl.py
            src/bin/cmdctl/run_b10-cmdctl.sh
            src/bin/cmdctl/run_b10-cmdctl.sh
            src/bin/cmdctl/tests/cmdctl_test
            src/bin/cmdctl/tests/cmdctl_test
@@ -1164,7 +1227,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/zonemgr/zonemgr.spec.pre
            src/bin/zonemgr/zonemgr.spec.pre
            src/bin/zonemgr/tests/zonemgr_test
            src/bin/zonemgr/tests/zonemgr_test
            src/bin/zonemgr/run_b10-zonemgr.sh
            src/bin/zonemgr/run_b10-zonemgr.sh
-           src/bin/showtech/showtech.py
+           src/bin/sysinfo/sysinfo.py
            src/bin/stats/stats.py
            src/bin/stats/stats.py
            src/bin/stats/stats_httpd.py
            src/bin/stats/stats_httpd.py
            src/bin/bind10/bind10_src.py
            src/bin/bind10/bind10_src.py
@@ -1306,12 +1369,12 @@ Features:
   $enable_features
   $enable_features
 
 
 Developer:
 Developer:
-  Google Tests:  $gtest_path
+  Google Tests: $enable_gtest
   Valgrind: $found_valgrind
   Valgrind: $found_valgrind
   C++ Code Coverage: $USE_LCOV
   C++ Code Coverage: $USE_LCOV
   Python Code Coverage: $USE_PYCOVERAGE
   Python Code Coverage: $USE_PYCOVERAGE
   Logger checks: $enable_logger_checks
   Logger checks: $enable_logger_checks
-  Generate Manuals:  $enable_man
+  Generate Manuals: $enable_man
 
 
 END
 END
 
 

+ 1 - 1
dns++.pc.in

@@ -8,4 +8,4 @@ Description: BIND 10 DNS library
 Version: @PACKAGE_VERSION@
 Version: @PACKAGE_VERSION@
 Requires: botan-1.8
 Requires: botan-1.8
 Cflags: -I${includedir}/@PACKAGE_NAME@
 Cflags: -I${includedir}/@PACKAGE_NAME@
-Libs: -L${libdir} -ldns++ -lcryptolink -lutil -lexceptions -lm
+Libs: -L${libdir} -lb10-dns++ -lb10-cryptolink -lb10-util -lb10-exceptions -lm

+ 2 - 1
doc/Doxyfile

@@ -573,7 +573,8 @@ WARN_LOGFILE           =
 # with spaces.
 # with spaces.
 
 
 INPUT                  = ../src/lib/exceptions ../src/lib/cc \
 INPUT                  = ../src/lib/exceptions ../src/lib/cc \
-    ../src/lib/config ../src/lib/cryptolink ../src/lib/dns ../src/lib/datasrc \
+    ../src/lib/config ../src/lib/cryptolink ../src/lib/dns \
+    ../src/lib/datasrc ../src/lib/datasrc/memory \
     ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log \
     ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log \
     ../src/lib/log/compiler ../src/lib/asiolink/ ../src/lib/nsas \
     ../src/lib/log/compiler ../src/lib/asiolink/ ../src/lib/nsas \
     ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \
     ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/ \

+ 5 - 3
doc/devel/02-dhcp.dox

@@ -72,11 +72,13 @@
  * DHCPv6 server component does not support relayed traffic yet, as
  * DHCPv6 server component does not support relayed traffic yet, as
  * support for relay decapsulation is not implemented yet.
  * support for relay decapsulation is not implemented yet.
  *
  *
- * DHCPv6 server component does not listen to BIND10 message queue.
- *
  * DHCPv6 server component does not use BIND10 logging yet.
  * DHCPv6 server component does not use BIND10 logging yet.
  *
  *
- * DHCPv6 server component is not integrated with boss yet.
+ * @section dhcpv6Session BIND10 message queue integration
+ *
+ * DHCPv4 server component is now integrated with BIND10 message queue.
+ * It follows the same principle as DHCPv4. See \ref dhcpv4Session for
+ * details.
  *
  *
  * @page libdhcp libdhcp++
  * @page libdhcp libdhcp++
  *
  *

File diff suppressed because it is too large
+ 388 - 330
doc/guide/bind10-guide.html


File diff suppressed because it is too large
+ 558 - 522
doc/guide/bind10-guide.txt


+ 155 - 140
doc/guide/bind10-guide.xml

@@ -1485,134 +1485,165 @@ can use various data source backends.
 
 
     </section>
     </section>
 
 
-    <section>
+    <section id='datasrc'>
       <title>Data Source Backends</title>
       <title>Data Source Backends</title>
 
 
+      <para>
+        Bind 10 has the concept of data sources. A data source is a place
+        where authoritative zone data reside and where they can be served
+        from. This can be a master file, a database or something completely
+        different.
+      </para>
+
+      <para>
+        Once a query arrives, <command>b10-auth</command> goes through a
+        configured list of data sources and finds the one containing a best
+        matching zone. From the equally good ones, the first one is taken.
+        This data source is then used to answer the query.
+      </para>
+
       <note><para>
       <note><para>
-        For the development prototype release, <command>b10-auth</command>
-        supports a SQLite3 data source backend and in-memory data source
-        backend.
+        In the development prototype release, <command>b10-auth</command>
+        can serve data from a SQLite3 data source backend and from master
+        files.
         Upcoming versions will be able to use multiple different
         Upcoming versions will be able to use multiple different
         data sources, such as MySQL and Berkeley DB.
         data sources, such as MySQL and Berkeley DB.
       </para></note>
       </para></note>
 
 
-
       <para>
       <para>
-        By default, the SQLite3 backend uses the data file located at
+        The configuration is located in data_sources/classes. Each item there
+        represents one RR class and a list used to answer queries for that
+        class. The default contains two classes. The CH class contains a static
+        data source &mdash; one that serves things like
+        <quote>AUTHORS.BIND.</quote>. The IN class contains single SQLite3
+        data source with database file located at
         <filename>/usr/local/var/bind10-devel/zone.sqlite3</filename>.
         <filename>/usr/local/var/bind10-devel/zone.sqlite3</filename>.
-        (The full path is what was defined at build configure time for
-        <option>--localstatedir</option>.
-        The default is <filename>/usr/local/var/</filename>.)
-	This data file location may be changed by defining the
-	<quote>database_file</quote> configuration.
       </para>
       </para>
 
 
-      <section id="in-memory-datasource">
-	<title>In-memory Data Source</title>
-
-	<para>
-<!--	  How to configure it. -->
-	  The following commands to <command>bindctl</command>
-	  provide an example of configuring an in-memory data
-	  source containing the <quote>example.com</quote> zone
-	  with the zone file named <quote>example.com.zone</quote>:
-
-<!--
-	  <screen>&gt; <userinput> config set Auth/datasources/ [{"type": "memory", "zones": [{"origin": "example.com", "file": "example.com.zone"}]}]</userinput></screen>
--->
-
-          <screen>&gt; <userinput>config add Auth/datasources</userinput>
-&gt; <userinput>config set Auth/datasources[0]/type "<option>memory</option>"</userinput>
-&gt; <userinput>config add Auth/datasources[0]/zones</userinput>
-&gt; <userinput>config set Auth/datasources[0]/zones[0]/origin "<option>example.com</option>"</userinput>
-&gt; <userinput>config set Auth/datasources[0]/zones[0]/file "<option>example.com.zone</option>"</userinput>
-&gt; <userinput>config commit</userinput></screen>
-
-	  The authoritative server will begin serving it immediately
-	  after the zone data is loaded from the master text file.
-	</para>
-
-      </section>
-
-      <section id="in-memory-datasource-with-sqlite3-backend">
-	<title>In-memory Data Source with SQLite3 Backend</title>
-
-	<para>
-<!--	  How to configure it. -->
-	  The following commands to <command>bindctl</command>
-	  provide an example of configuring an in-memory data
-	  source containing the <quote>example.org</quote> zone
-	  with a SQLite3 backend file named <quote>example.org.sqlite3</quote>:
-
-<!--
-	  <screen>&gt; <userinput> config set Auth/datasources/ [{"type": "memory", "zones": [{"origin": "example.org", "file": "example.org.sqlite3", "filetype": "sqlite3"}]}]</userinput></screen>
--->
-
-          <screen>&gt; <userinput>config add Auth/datasources</userinput>
-&gt; <userinput>config set Auth/datasources[1]/type "<option>memory</option>"</userinput>
-&gt; <userinput>config add Auth/datasources[1]/zones</userinput>
-&gt; <userinput>config set Auth/datasources[1]/zones[0]/origin "<option>example.org</option>"</userinput>
-&gt; <userinput>config set Auth/datasources[1]/zones[0]/file "<option>example.org.sqlite3</option>"</userinput>
-&gt; <userinput>config set Auth/datasources[1]/zones[0]/filetype "<option>sqlite3</option>"</userinput>
-&gt; <userinput>config commit</userinput></screen>
-
-	  The authoritative server will begin serving it immediately
-	  after the zone data is loaded from the database file.
-	</para>
-
-      </section>
-
-      <section id="in-memory-datasource-loading">
-	<title>Reloading an In-memory Data Source</title>
-
-	<para>
-	  Use the <command>Auth loadzone</command> command in
-	  <command>bindctl</command> to reload a changed master
-	  file into memory; for example:
+      <para>
+        Each data source has several options. The first one is
+        <varname>type</varname>, which specifies the type of data source to
+        use. Valid types include the ones listed below, but bind10 uses
+        dynamically loaded modules for them, so there may be more in your
+        case. This option is mandatory.
+      </para>
 
 
-	  <screen>&gt; <userinput>Auth loadzone origin="example.com"</userinput>
-</screen>
+      <para>
+        Another option is <varname>params</varname>. This option is type
+        specific; it holds different data depending on the type
+        above. Also, depending on the type, it could be possible to omit it.
+      </para>
 
 
-	</para>
+      <para>
+        There are two options related to the so-called cache. If you enable
+        cache, zone data from the data source are loaded into memory.
+        Then, when answering a query, <command>b10-auth</command> looks
+        into the memory only instead of the data source, which speeds
+        answering up. The first option is <varname>cache-enable</varname>,
+        a boolean value turning the cache on and off (off is the default).
+        The second one, <varname>cache-zones</varname>, is a list of zone
+        origins to load into in-memory. Remember that zones in the data source
+        not listed here will not be loaded and will not be available at all.
+      </para>
 
 
-<!--
+      <section id='datasource-types'>
+        <title>Data source types</title>
         <para>
         <para>
-          The <varname>file</varname> may be an absolute path to the
-          master zone file or it is relative to the directory BIND 10 is
-          started from.
-	</para>
--->
+          As mentioned, the type used by default is <quote>sqlite3</quote>.
+          It has single configuration option inside <varname>params</varname>
+          &mdash; <varname>database_file</varname>, which contains the path
+          to the sqlite3 file containing the data.
+        </para>
 
 
+        <para>
+          Another type is called <quote>MasterFiles</quote>. This one is
+          slightly special. The data are stored in RFC1034 master files.
+          Because answering directly from them would be impractical,
+          this type mandates the cache to be enabled. Also, the list of
+          zones (<varname>cache-zones</varname>) should be omitted. The
+          <varname>params</varname> is a dictionary mapping from zone
+          origins to the files they reside in.
+        </para>
       </section>
       </section>
-      <section id="in-memory-datasource-disabling">
-	<title>Disabling In-memory Data Sources</title>
 
 
+      <section id='datasrc-examples'>
+        <title>Examples</title>
         <para>
         <para>
-	By default, the memory data source is disabled; it must be
-	configured explicitly.  To disable all the in-memory zones,
-	specify a null list for <varname>Auth/datasources</varname>:
+          As this is one of the more complex configurations of Bind10,
+          we show some examples. They all assume they start with default
+          configuration.
+        </para>
 
 
-<!-- TODO: this assumes that Auth/datasources is for memory only -->
+        <para>
+          First, let's disable the static data source
+          (<quote>VERSION.BIND</quote> and friends). As it is the only
+          data source in the CH class, we can remove the whole class.
 
 
-	  <screen>&gt; <userinput>config set Auth/datasources/ []</userinput>
+          <screen>&gt; <userinput>config remove data_sources/classes CH</userinput>
 &gt; <userinput>config commit</userinput></screen>
 &gt; <userinput>config commit</userinput></screen>
-	</para>
+        </para>
 
 
-	<para>
-          The following example stops serving a specific zone:
+        <para>
+          Another one, let's say our default data source contains zones
+          <quote>example.org.</quote> and <quote>example.net.</quote>.
+          We want them to be served from memory to make the answering
+          faster.
 
 
-	  <screen>&gt; <userinput>config remove Auth/datasources[<option>0</option>]/zones[<option>0</option>]</userinput>
+          <screen>&gt; <userinput>config set data_sources/classes/IN[0]/cache-enable true</userinput>
+&gt; <userinput>config add data_sources/classes/IN[0]/cache-zones example.org.</userinput>
+&gt; <userinput>config add data_sources/classes/IN[0]/cache-zones example.net.</userinput>
 &gt; <userinput>config commit</userinput></screen>
 &gt; <userinput>config commit</userinput></screen>
 
 
-	  (Replace the list number(s) in
-	  <varname>datasources[<replaceable>0</replaceable>]</varname>
-	  and/or <varname>zones[<replaceable>0</replaceable>]</varname>
-	  for the relevant zone as needed.)
+          Now every time the zone in the data source is changed by the
+          operator, Bind10 needs to be told to reload it, by
+          <screen>&gt; <userinput>Auth loadzone example.org</userinput></screen>
+          You don't need to do this when the zone is modified by
+          XfrIn, it does so automatically.
+        </para>
+
+        <para>
+          Now, the last example is when there are master files we want to
+          serve in addition to whatever is inside the sqlite3 database.
 
 
-	</para>
+          <screen>&gt; <userinput>config add data_sources/classes/IN</userinput>
+&gt; <userinput>config set data_sources/classes/IN[1]/type MasterFiles</userinput>
+&gt; <userinput>config set data_sources/classes/IN[1]/cache-enable true</userinput>
+&gt; <userinput>config set data_sources/classes/IN[1]/params { "example.org": "/path/to/example.org", "example.com": "/path/to/example.com" }</userinput>
+&gt; <userinput>config commit</userinput></screen>
 
 
+          Initially, a map value has to be set, but this value may be an
+          empty map. After that, key/value pairs can be added with 'config
+          add' and keys can be removed with 'config remove'. The initial
+          value may be an empty map, but it has to be set before zones are
+          added or removed.
+
+          <screen>
+&gt; <userinput>config set data_sources/classes/IN[1]/params {}</userinput>
+&gt; <userinput>config add data_sources/classes/IN[1]/params another.example.org /path/to/another.example.org</userinput>
+&gt; <userinput>config add data_sources/classes/IN[1]/params another.example.com /path/to/another.example.com</userinput>
+&gt; <userinput>config remove data_sources/classes/IN[1]/params another.example.org</userinput>
+          </screen>
+
+          <command>bindctl</command>. To reload a zone, you the same command
+          as above.
+        </para>
       </section>
       </section>
 
 
+      <note>
+      <para>
+        There's also <varname>Auth/database_file</varname> configuration
+        variable, pointing to a sqlite3 database file. This is no longer
+        used by <command>b10-auth</command>, but it is left in place for
+        now, since other modules use it. Once <command>b10-xfrin</command>,
+        <command>b10-xfrout</command> and <command>b10-ddns</command>
+        are ported to the new configuration, this will disappear. But for
+        now, make sure that if you use any of these modules, the new
+        and old configuration correspond. The defaults are consistent, so
+        unless you tweaked either the new or the old configuration, you're
+        good.
+      </para>
+      </note>
+
     </section>
     </section>
 
 
     <section>
     <section>
@@ -1854,7 +1885,7 @@ http://bind10.isc.org/wiki/ScalableZoneLoadDesign#a7.2UpdatingaZone
 	The administrator doesn't have to do anything for
 	The administrator doesn't have to do anything for
 	<command>b10-auth</command> to serve the new version of the
 	<command>b10-auth</command> to serve the new version of the
 	zone, except for the configuration such as the one described in
 	zone, except for the configuration such as the one described in
-	<xref linkend="in-memory-datasource-with-sqlite3-backend" />.
+	<xref linkend="datasrc" />.
       </para>
       </para>
     </section>
     </section>
 
 
@@ -1965,11 +1996,11 @@ what is XfroutClient xfr_client??
       notify <command>b10-xfrout</command> so that other secondary
       notify <command>b10-xfrout</command> so that other secondary
       servers will be notified via the DNS NOTIFY protocol.
       servers will be notified via the DNS NOTIFY protocol.
       In addition, if <command>b10-auth</command> serves the updated
       In addition, if <command>b10-auth</command> serves the updated
-      zone from its in-memory cache (as described in
-      <xref linkend="in-memory-datasource-with-sqlite3-backend" />),
+      zone (as described in
+      <xref linkend="datasrc" />),
       <command>b10-ddns</command> will also
       <command>b10-ddns</command> will also
       notify <command>b10-auth</command> so that <command>b10-auth</command>
       notify <command>b10-auth</command> so that <command>b10-auth</command>
-      will re-cache the updated zone content.
+      will re-cache the updated zone content if necessary.
     </para>
     </para>
 
 
     <para>
     <para>
@@ -2479,7 +2510,7 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
 &gt; <userinput>config commit</userinput></screen></para>
 &gt; <userinput>config commit</userinput></screen></para>
 
 
       <para>
       <para>
-        At start, the server will detect available network interfaces
+        During start-up the server will detect available network interfaces
         and will attempt to open UDP sockets on all interfaces that
         and will attempt to open UDP sockets on all interfaces that
         are up, running, are not loopback, and have IPv4 address
         are up, running, are not loopback, and have IPv4 address
         assigned.
         assigned.
@@ -2489,17 +2520,8 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
         will respond to them with OFFER and ACK, respectively.
         will respond to them with OFFER and ACK, respectively.
 
 
         Since the DHCPv4 server opens privileged ports, it requires root
         Since the DHCPv4 server opens privileged ports, it requires root
-        access. Make sure you run this daemon as root.</para>
-
-        <note>
-          <para>
-            Integration with <command>bind10</command> is
-            planned. Ultimately, <command>b10-dhcp4</command> will not
-            be started directly, but rather via
-            <command>bind10</command>. Please be aware of this planned
-            change.
-          </para>
-        </note>
+        access. Make sure you run this daemon as root.
+      </para>
 
 
     </section>
     </section>
 
 
@@ -2548,7 +2570,7 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
     </section>
     </section>
 
 
     <section id="dhcp4-limit">
     <section id="dhcp4-limit">
-      <title>DHCPv4 Server Limitations</title> 
+      <title>DHCPv4 Server Limitations</title>
       <para>These are the current limitations of the DHCPv4 server
       <para>These are the current limitations of the DHCPv4 server
       software. Most of them are reflections of the early stage of
       software. Most of them are reflections of the early stage of
       development and should be treated as <quote>not implemented
       development and should be treated as <quote>not implemented
@@ -2664,22 +2686,25 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
       </para>
       </para>
 
 
       <para>
       <para>
-        The DHCPv6 server is implemented as <command>b10-dhcp6</command>
-        daemon. As it is not configurable yet, it is fully autonomous,
-        that is it does not interact with <command>b10-cfgmgr</command>.
-        To start DHCPv6 server, simply input:
-
-        <screen>
-#<userinput>cd src/bin/dhcp6</userinput>
-#<userinput>./b10-dhcp6</userinput>
-</screen>
+        <command>b10-dhcp6</command> is a BIND10 component and is being
+        run under BIND10 framework. To add a DHCPv6 process to the set of running
+        BIND10 services, you can use following commands in <command>bindctl</command>:
+        <screen>&gt; <userinput>config add Boss/components b10-dhcp6</userinput>
+&gt; <userinput>config set Boss/components/b10-dhcp6/kind dispensable</userinput>
+&gt; <userinput>config commit</userinput></screen>
+      </para>
 
 
-        Depending on your installation, <command>b10-dhcp6</command>
-        binary may reside in src/bin/dhcp6 in your source code
-        directory, in /usr/local/bin/b10-dhcp6 or other directory
-        you specified during compilation.
+       <para>
+         To shutdown running <command>b10-dhcp6</command>, please use the
+         following command:
+         <screen>&gt; <userinput>Dhcp6 shutdown</userinput></screen>
+         or
+         <screen>&gt; <userinput>config remove Boss/components b10-dhcp6</userinput>
+&gt; <userinput>config commit</userinput></screen>
+       </para>
 
 
-        At start, server will detect available network interfaces
+      <para>
+        During start-up the server will detect available network interfaces
         and will attempt to open UDP sockets on all interfaces that
         and will attempt to open UDP sockets on all interfaces that
         are up, running, are not loopback, are multicast-capable, and
         are up, running, are not loopback, are multicast-capable, and
         have IPv6 address assigned.
         have IPv6 address assigned.
@@ -2692,16 +2717,6 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
         access. Make sure you run this daemon as root.
         access. Make sure you run this daemon as root.
       </para>
       </para>
 
 
-        <note>
-          <para>
-            Integration with <command>bind10</command> is
-            planned. Ultimately, <command>b10-dhcp6</command> will not
-            be started directly, but rather via
-            <command>bind10</command>. Please be aware of this planned
-            change.
-          </para>
-        </note>
-
     </section>
     </section>
 
 
     <section id="dhcp6-config">
     <section id="dhcp6-config">
@@ -2715,7 +2730,7 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
       <para>
       <para>
         At this stage of development, the only way to alter server
         At this stage of development, the only way to alter server
         configuration is to tweak its source code. To do so, please
         configuration is to tweak its source code. To do so, please
-        edit src/bin/dhcp6/dhcp6_srv.cc file and modify following
+        edit src/bin/dhcp6/dhcp6_srv.cc file, modify the following
         parameters and recompile:
         parameters and recompile:
         <screen>
         <screen>
 const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
 const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";

File diff suppressed because it is too large
+ 61 - 11
doc/guide/bind10-messages.html


+ 98 - 18
doc/guide/bind10-messages.xml

@@ -413,6 +413,13 @@ a command on the command channel.
 </para></listitem>
 </para></listitem>
 </varlistentry>
 </varlistentry>
 
 
+<varlistentry id="AUTH_RECEIVED_NOTIFY">
+<term>AUTH_RECEIVED_NOTIFY received incoming NOTIFY for zone name %1, zone class %2</term>
+<listitem><para>
+This is a debug message reporting that an incoming NOTIFY was received.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="AUTH_RECEIVED_SENDSTATS">
 <varlistentry id="AUTH_RECEIVED_SENDSTATS">
 <term>AUTH_RECEIVED_SENDSTATS command 'sendstats' received</term>
 <term>AUTH_RECEIVED_SENDSTATS command 'sendstats' received</term>
 <listitem><para>
 <listitem><para>
@@ -523,6 +530,17 @@ so no further validation is needed.
 </para></listitem>
 </para></listitem>
 </varlistentry>
 </varlistentry>
 
 
+<varlistentry id="AUTH_START_DDNS_FORWARDER">
+<term>AUTH_START_DDNS_FORWARDER DDNS UPDATE handling started</term>
+<listitem><para>
+This is a debug message indicating that b10-auth has received a message
+that it should internally forward UPDATE message to b10-ddns. When b10-ddns
+is not running, b10-auth will respond to UPDATE requests with rcode NOTIMP.
+When b10-ddns is running, b10-ddns will handle and respond to the UPDATE
+message.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="AUTH_STATS_CHANNEL_CREATED">
 <varlistentry id="AUTH_STATS_CHANNEL_CREATED">
 <term>AUTH_STATS_CHANNEL_CREATED STATS session channel created</term>
 <term>AUTH_STATS_CHANNEL_CREATED STATS session channel created</term>
 <listitem><para>
 <listitem><para>
@@ -578,6 +596,19 @@ at the specified interval.
 </para></listitem>
 </para></listitem>
 </varlistentry>
 </varlistentry>
 
 
+<varlistentry id="AUTH_STOP_DDNS_FORWARDER">
+<term>AUTH_STOP_DDNS_FORWARDER DDNS UPDATE handling stopped</term>
+<listitem><para>
+This is a debug message indicating that b10-auth has received a message
+that it should stop internally forwarding UPDATE message to b10-ddns.
+b10-auth will no longer forward UPDATE messages to b10-ddns, but will
+respond itself with error code NOTIMP.
+This message is also logged when the forwarding is restarted (for instance
+if b10-ddns is restarted and the internal connection needs to be created
+again), in which case it should be followed by AUTH_START_DDNS_FORWARDER.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="AUTH_UNSUPPORTED_OPCODE">
 <varlistentry id="AUTH_UNSUPPORTED_OPCODE">
 <term>AUTH_UNSUPPORTED_OPCODE unsupported opcode: %1</term>
 <term>AUTH_UNSUPPORTED_OPCODE unsupported opcode: %1</term>
 <listitem><para>
 <listitem><para>
@@ -2476,6 +2507,17 @@ processed.
 </para></listitem>
 </para></listitem>
 </varlistentry>
 </varlistentry>
 
 
+<varlistentry id="DATASRC_LIST_NOT_CACHED">
+<term>DATASRC_LIST_NOT_CACHED zone %1/%2 not cached, cache disabled globally. Will not be available.</term>
+<listitem><para>
+The process disabled caching of RR data completely. However, the given zone
+is provided as a master file and it can be served from memory cache only.
+Therefore, the zone will not be available for this process. If this is
+a problem, you should move the zone to some database backend (sqlite3, for
+example) and use it from there.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DATASRC_MEM_ADD_RRSET">
 <varlistentry id="DATASRC_MEM_ADD_RRSET">
 <term>DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'</term>
 <term>DATASRC_MEM_ADD_RRSET adding RRset '%1/%2' into zone '%3'</term>
 <listitem><para>
 <listitem><para>
@@ -3885,6 +3927,33 @@ and updates.
 </para></listitem>
 </para></listitem>
 </varlistentry>
 </varlistentry>
 
 
+<varlistentry id="DDNS_START_FORWARDER_ERROR">
+<term>DDNS_START_FORWARDER_ERROR Error from b10-auth when requesting DDNS UPDATE forwarding: %1</term>
+<listitem><para>
+There was an error response from b10-auth to the command to start
+forwarding DDNS UPDATE messages to b10-ddns.
+It is almost certain that DDNS UPDATE messages are not handled now, and that
+they will be responded to with a NOTIMP error code, even though b10-ddns is
+running.
+The error message is printed, and additional information may be found in
+the b10-auth log output. Since this is an error that is sent by the
+b10-auth module, it should have more information as to what the actual
+problem was.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="DDNS_START_FORWARDER_FAIL">
+<term>DDNS_START_FORWARDER_FAIL Error sending request for DDNS UPDATE forwarding to b10-auth: %1</term>
+<listitem><para>
+There was an error when attempting to send b10-auth the request to forward
+DDNS UPDATE messages to the b10-ddns module. This points to an internal
+problem using the inter-module messaging system.
+This needs to be inspected, as it is almost certain that DDNS UPDATE messages
+are not handled now.
+The specific error is printed in the log message.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DDNS_STOPPED">
 <varlistentry id="DDNS_STOPPED">
 <term>DDNS_STOPPED ddns server has stopped</term>
 <term>DDNS_STOPPED ddns server has stopped</term>
 <listitem><para>
 <listitem><para>
@@ -3901,6 +3970,32 @@ process will now shut down.
 </para></listitem>
 </para></listitem>
 </varlistentry>
 </varlistentry>
 
 
+<varlistentry id="DDNS_STOP_FORWARDER_ERROR">
+<term>DDNS_STOP_FORWARDER_ERROR Error from b10-auth when requesting to stop DDNS UPDATE forwarding: %1</term>
+<listitem><para>
+There was an error response from b10-auth to the command to stop
+forwarding DDNS UPDATE messages to b10-ddns.
+This specific error may not be fatal; instead of returning NOTIMP for future
+DDNS UPDATE messages, it will return SERVFAIL. However, this does point to
+an underlying problem in the messaging system, and should be inspected.
+The error message is printed, and additional information may be found in
+the b10-auth log output.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="DDNS_STOP_FORWARDER_FAIL">
+<term>DDNS_STOP_FORWARDER_FAIL Error sending request to stop DDNS UPDATE forwarding to b10-auth: %1</term>
+<listitem><para>
+There was an error when attempting to send b10-auth the request to stop
+forwarding DDNS UPDATE messages to the b10-ddns module. This points to an
+internal problem using the inter-module messaging system.
+This specific error may not be fatal; instead of returning NOTIMP for future
+DDNS UPDATE messages, it will return SERVFAIL. However, this does point to
+an underlying problem in the messaging system, and should be inspected.
+The specific error is printed in the log message.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DDNS_UNCAUGHT_EXCEPTION">
 <varlistentry id="DDNS_UNCAUGHT_EXCEPTION">
 <term>DDNS_UNCAUGHT_EXCEPTION uncaught exception of type %1: %2</term>
 <term>DDNS_UNCAUGHT_EXCEPTION uncaught exception of type %1: %2</term>
 <listitem><para>
 <listitem><para>
@@ -4781,20 +4876,6 @@ bug report.
 </para></listitem>
 </para></listitem>
 </varlistentry>
 </varlistentry>
 
 
-<varlistentry id="PYSERVER_COMMON_AUTH_CONFIG_NAME_PARSER_ERROR">
-<term>PYSERVER_COMMON_AUTH_CONFIG_NAME_PARSER_ERROR Invalid name when parsing Auth configuration: %1</term>
-<listitem><para>
-There was an invalid name when parsing Auth configuration.
-</para></listitem>
-</varlistentry>
-
-<varlistentry id="PYSERVER_COMMON_AUTH_CONFIG_RRCLASS_ERROR">
-<term>PYSERVER_COMMON_AUTH_CONFIG_RRCLASS_ERROR Invalid RRClass when parsing Auth configuration: %1</term>
-<listitem><para>
-There was an invalid RR class when parsing Auth configuration.
-</para></listitem>
-</varlistentry>
-
 <varlistentry id="PYSERVER_COMMON_DNS_TCP_SEND_DONE">
 <varlistentry id="PYSERVER_COMMON_DNS_TCP_SEND_DONE">
 <term>PYSERVER_COMMON_DNS_TCP_SEND_DONE completed sending TCP message to %1 (%2 bytes in total)</term>
 <term>PYSERVER_COMMON_DNS_TCP_SEND_DONE completed sending TCP message to %1 (%2 bytes in total)</term>
 <listitem><para>
 <listitem><para>
@@ -6078,11 +6159,10 @@ Please check your installation.
 </varlistentry>
 </varlistentry>
 
 
 <varlistentry id="XFRIN_AUTH_LOADZONE">
 <varlistentry id="XFRIN_AUTH_LOADZONE">
-<term>XFRIN_AUTH_LOADZONE sending Auth loadzone for origin=%1, class=%2, datasrc=%3</term>
+<term>XFRIN_AUTH_LOADZONE sending Auth loadzone for origin=%1, class=%2</term>
 <listitem><para>
 <listitem><para>
-There was a successful zone transfer, and the zone is served by b10-auth
-in the in-memory data source using sqlite3 as a backend. We send the
-"loadzone" command for the zone to b10-auth.
+There was a successful zone transfer.  We send the "loadzone" command for the
+zone to b10-auth.
 </para></listitem>
 </para></listitem>
 </varlistentry>
 </varlistentry>
 
 

+ 1 - 1
src/bin/Makefile.am

@@ -1,5 +1,5 @@
 SUBDIRS = bind10 bindctl cfgmgr ddns loadzone msgq host cmdctl auth xfrin \
 SUBDIRS = bind10 bindctl cfgmgr ddns loadzone msgq host cmdctl auth xfrin \
 	xfrout usermgr zonemgr stats tests resolver sockcreator dhcp4 dhcp6 \
 	xfrout usermgr zonemgr stats tests resolver sockcreator dhcp4 dhcp6 \
-	dbutil showtech
+	dbutil sysinfo
 
 
 check-recursive: all-recursive
 check-recursive: all-recursive

+ 14 - 13
src/bin/auth/Makefile.am

@@ -48,6 +48,7 @@ b10_auth_SOURCES += auth_config.cc auth_config.h
 b10_auth_SOURCES += command.cc command.h
 b10_auth_SOURCES += command.cc command.h
 b10_auth_SOURCES += common.h common.cc
 b10_auth_SOURCES += common.h common.cc
 b10_auth_SOURCES += statistics.cc statistics.h
 b10_auth_SOURCES += statistics.cc statistics.h
+b10_auth_SOURCES += datasrc_configurator.h
 b10_auth_SOURCES += main.cc
 b10_auth_SOURCES += main.cc
 # This is a temporary workaround for #1206, where the InMemoryClient has been
 # This is a temporary workaround for #1206, where the InMemoryClient has been
 # moved to an ldopened library. We could add that library to LDADD, but that
 # moved to an ldopened library. We could add that library to LDADD, but that
@@ -59,19 +60,19 @@ b10_auth_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
 nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
 nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
 EXTRA_DIST += auth_messages.mes
 EXTRA_DIST += auth_messages.mes
 
 
-b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/libdatasrc.la
-b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-b10_auth_LDADD += $(top_builddir)/src/lib/util/libutil.la
-b10_auth_LDADD += $(top_builddir)/src/lib/util/io/libutil_io.la
-b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-b10_auth_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
-b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-b10_auth_LDADD += $(top_builddir)/src/lib/log/liblog.la
-b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-b10_auth_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-b10_auth_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
+b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
+b10_auth_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
+b10_auth_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+b10_auth_LDADD += $(top_builddir)/src/lib/util/io/libb10-util-io.la
+b10_auth_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+b10_auth_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+b10_auth_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
+b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+b10_auth_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libb10-xfr.la
+b10_auth_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
+b10_auth_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
 b10_auth_LDADD += $(SQLITE_LIBS)
 b10_auth_LDADD += $(SQLITE_LIBS)
 
 
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir

+ 0 - 4
src/bin/auth/auth.spec.pre.in

@@ -125,10 +125,6 @@
 	  {
 	  {
             "item_name": "origin", "item_type": "string",
             "item_name": "origin", "item_type": "string",
             "item_optional": false, "item_default": ""
             "item_optional": false, "item_default": ""
-          },
-	  {
-            "item_name": "datasrc", "item_type": "string",
-            "item_optional": true, "item_default": "memory"
           }
           }
         ]
         ]
       },
       },

+ 9 - 90
src/bin/auth/auth_config.cc

@@ -43,20 +43,6 @@ using namespace isc::datasrc;
 using namespace isc::server_common::portconfig;
 using namespace isc::server_common::portconfig;
 
 
 namespace {
 namespace {
-/// A derived \c AuthConfigParser class for the "datasources" configuration
-/// identifier.
-class DatasourcesConfig : public AuthConfigParser {
-public:
-    DatasourcesConfig(AuthSrv& server) : server_(server)
-    {}
-    virtual void build(ConstElementPtr config_value);
-    virtual void commit();
-private:
-    AuthSrv& server_;
-    vector<boost::shared_ptr<AuthConfigParser> > datasources_;
-    set<string> configured_sources_;
-    vector<pair<RRClass, DataSourceClientContainerPtr> > clients_;
-};
 
 
 /// A derived \c AuthConfigParser for the version value
 /// A derived \c AuthConfigParser for the version value
 /// (which is not used at this moment)
 /// (which is not used at this moment)
@@ -67,79 +53,6 @@ public:
     virtual void commit() {};
     virtual void commit() {};
 };
 };
 
 
-void
-DatasourcesConfig::build(ConstElementPtr config_value) {
-    BOOST_FOREACH(ConstElementPtr datasrc_elem, config_value->listValue()) {
-        // The caller is supposed to perform syntax-level checks, but we'll
-        // do minimum level of validation ourselves so that we won't crash due
-        // to a buggy application.
-        ConstElementPtr datasrc_type = datasrc_elem->get("type");
-        if (!datasrc_type) {
-            isc_throw(AuthConfigError, "Missing data source type");
-        }
-
-        if (configured_sources_.find(datasrc_type->stringValue()) !=
-            configured_sources_.end()) {
-            isc_throw(AuthConfigError, "Data source type '" <<
-                      datasrc_type->stringValue() << "' already configured");
-        }
-
-        // Apart from that it's not really easy to get at the default
-        // class value for the class here, it should probably really
-        // be a property of the instantiated data source. For now
-        // use hardcoded default IN.
-        const RRClass rrclass =
-            datasrc_elem->contains("class") ?
-            RRClass(datasrc_elem->get("class")->stringValue()) : RRClass::IN();
-
-        // Right now, we only support the in-memory data source for the
-        // RR class of IN.  We reject other cases explicitly by hardcoded
-        // checks.  This will soon be generalized, at which point these
-        // checks will also have to be cleaned up.
-        if (rrclass != RRClass::IN()) {
-            isc_throw(isc::InvalidParameter, "Unsupported data source class: "
-                      << rrclass);
-        }
-        if (datasrc_type->stringValue() != "memory") {
-            isc_throw(AuthConfigError, "Unsupported data source type: "
-                      << datasrc_type->stringValue());
-        }
-
-        // Create a new client for the specified data source and store it
-        // in the local vector.  For now, we always build a new client
-        // from the scratch, and replace any existing ones with the new ones.
-        // We might eventually want to optimize building zones (in case of
-        // reloading) by selectively loading fresh zones for data source
-        // where zone loading is expensive (such as in-memory).
-        clients_.push_back(
-            pair<RRClass, DataSourceClientContainerPtr>(
-                rrclass,
-                DataSourceClientContainerPtr(new DataSourceClientContainer(
-                                                 datasrc_type->stringValue(),
-                                                 datasrc_elem))));
-
-        configured_sources_.insert(datasrc_type->stringValue());
-    }
-}
-
-void
-DatasourcesConfig::commit() {
-    // As noted in build(), the current implementation only supports the
-    // in-memory data source for class IN, and build() should have ensured
-    // it.  So, depending on the vector is empty or not, we either clear
-    // or install an in-memory data source for the server.
-    //
-    // When we generalize it, we'll somehow install all data source clients
-    // built in the vector, clearing deleted ones from the server.
-    if (clients_.empty()) {
-        server_.setInMemoryClient(RRClass::IN(),
-                                  DataSourceClientContainerPtr());
-    } else {
-        server_.setInMemoryClient(clients_.front().first,
-                                  clients_.front().second);
-    }
-}
-
 /// A derived \c AuthConfigParser class for the "statistics-internal"
 /// A derived \c AuthConfigParser class for the "statistics-internal"
 /// configuration identifier.
 /// configuration identifier.
 class StatisticsIntervalConfig : public AuthConfigParser {
 class StatisticsIntervalConfig : public AuthConfigParser {
@@ -242,9 +155,7 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
     // simplicity.  In future we'll probably generalize it using map-like
     // simplicity.  In future we'll probably generalize it using map-like
     // data structure, and may even provide external register interface so
     // data structure, and may even provide external register interface so
     // that it can be dynamically customized.
     // that it can be dynamically customized.
-    if (config_id == "datasources") {
-        return (new DatasourcesConfig(server));
-    } else if (config_id == "statistics-interval") {
+    if (config_id == "statistics-interval") {
         return (new StatisticsIntervalConfig(server));
         return (new StatisticsIntervalConfig(server));
     } else if (config_id == "listen_on") {
     } else if (config_id == "listen_on") {
         return (new ListenAddressConfig(server));
         return (new ListenAddressConfig(server));
@@ -261,6 +172,14 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
         // later be used to mark backwards incompatible changes in the
         // later be used to mark backwards incompatible changes in the
         // config data
         // config data
         return (new VersionConfig());
         return (new VersionConfig());
+    } else if (config_id == "datasources") {
+        // TODO: Ignored for now, since the value is probably used by
+        // other modules. Once they have been removed from there, remove
+        // it from here and the spec file.
+
+        // We need to return something. The VersionConfig is empty now,
+        // so we may abuse that one, as it is a short-term solution only.
+        return (new VersionConfig());
     } else {
     } else {
         isc_throw(AuthConfigError, "Unknown configuration identifier: " <<
         isc_throw(AuthConfigError, "Unknown configuration identifier: " <<
                   config_id);
                   config_id);

+ 52 - 146
src/bin/auth/auth_srv.cc

@@ -43,9 +43,9 @@
 
 
 #include <datasrc/query.h>
 #include <datasrc/query.h>
 #include <datasrc/data_source.h>
 #include <datasrc/data_source.h>
-#include <datasrc/memory_datasrc.h>
 #include <datasrc/static_datasrc.h>
 #include <datasrc/static_datasrc.h>
 #include <datasrc/sqlite3_datasrc.h>
 #include <datasrc/sqlite3_datasrc.h>
+#include <datasrc/client_list.h>
 
 
 #include <xfr/xfrout_client.h>
 #include <xfr/xfrout_client.h>
 
 
@@ -222,10 +222,9 @@ private:
     AuthSrvImpl(const AuthSrvImpl& source);
     AuthSrvImpl(const AuthSrvImpl& source);
     AuthSrvImpl& operator=(const AuthSrvImpl& source);
     AuthSrvImpl& operator=(const AuthSrvImpl& source);
 public:
 public:
-    AuthSrvImpl(const bool use_cache, AbstractXfroutClient& xfrout_client,
+    AuthSrvImpl(AbstractXfroutClient& xfrout_client,
                 BaseSocketSessionForwarder& ddns_forwarder);
                 BaseSocketSessionForwarder& ddns_forwarder);
     ~AuthSrvImpl();
     ~AuthSrvImpl();
-    isc::data::ConstElementPtr setDbFile(isc::data::ConstElementPtr config);
 
 
     bool processNormalQuery(const IOMessage& io_message, Message& message,
     bool processNormalQuery(const IOMessage& io_message, Message& message,
                             OutputBuffer& buffer,
                             OutputBuffer& buffer,
@@ -248,13 +247,6 @@ public:
     ModuleCCSession* config_session_;
     ModuleCCSession* config_session_;
     AbstractSession* xfrin_session_;
     AbstractSession* xfrin_session_;
 
 
-    /// In-memory data source.  Currently class IN only for simplicity.
-    const RRClass memory_client_class_;
-    isc::datasrc::DataSourceClientContainerPtr memory_client_container_;
-
-    /// Hot spot cache
-    isc::datasrc::HotCache cache_;
-
     /// Interval timer for periodic submission of statistics counters.
     /// Interval timer for periodic submission of statistics counters.
     IntervalTimer statistics_timer_;
     IntervalTimer statistics_timer_;
 
 
@@ -267,6 +259,22 @@ public:
     /// The TSIG keyring
     /// The TSIG keyring
     const boost::shared_ptr<TSIGKeyRing>* keyring_;
     const boost::shared_ptr<TSIGKeyRing>* keyring_;
 
 
+    /// The client list
+    std::map<RRClass, boost::shared_ptr<ConfigurableClientList> >
+        client_lists_;
+
+    boost::shared_ptr<ConfigurableClientList> getClientList(const RRClass&
+                                                            rrclass)
+    {
+        const std::map<RRClass, boost::shared_ptr<ConfigurableClientList> >::
+            const_iterator it(client_lists_.find(rrclass));
+        if (it == client_lists_.end()) {
+            return (boost::shared_ptr<ConfigurableClientList>());
+        } else {
+            return (it->second);
+        }
+    }
+
     /// Bind the ModuleSpec object in config_session_ with
     /// Bind the ModuleSpec object in config_session_ with
     /// isc:config::ModuleSpec::validateStatistics.
     /// isc:config::ModuleSpec::validateStatistics.
     void registerStatisticsValidator();
     void registerStatisticsValidator();
@@ -296,14 +304,6 @@ public:
                       bool done);
                       bool done);
 
 
 private:
 private:
-    std::string db_file_;
-
-    MetaDataSrc data_sources_;
-    /// We keep a pointer to the currently running sqlite datasource
-    /// so that we can specifically remove that one should the database
-    /// file change
-    ConstDataSrcPtr cur_datasrc_;
-
     bool xfrout_connected_;
     bool xfrout_connected_;
     AbstractXfroutClient& xfrout_client_;
     AbstractXfroutClient& xfrout_client_;
 
 
@@ -316,12 +316,10 @@ private:
     auth::Query query_;
     auth::Query query_;
 };
 };
 
 
-AuthSrvImpl::AuthSrvImpl(const bool use_cache,
-                         AbstractXfroutClient& xfrout_client,
+AuthSrvImpl::AuthSrvImpl(AbstractXfroutClient& xfrout_client,
                          BaseSocketSessionForwarder& ddns_forwarder) :
                          BaseSocketSessionForwarder& ddns_forwarder) :
     config_session_(NULL),
     config_session_(NULL),
     xfrin_session_(NULL),
     xfrin_session_(NULL),
-    memory_client_class_(RRClass::IN()),
     statistics_timer_(io_service_),
     statistics_timer_(io_service_),
     counters_(),
     counters_(),
     keyring_(NULL),
     keyring_(NULL),
@@ -329,17 +327,7 @@ AuthSrvImpl::AuthSrvImpl(const bool use_cache,
     ddns_forwarder_(NULL),
     ddns_forwarder_(NULL),
     xfrout_connected_(false),
     xfrout_connected_(false),
     xfrout_client_(xfrout_client)
     xfrout_client_(xfrout_client)
-{
-    // cur_datasrc_ is automatically initialized by the default constructor,
-    // effectively being an empty (sqlite) data source.  once ccsession is up
-    // the datasource will be set by the configuration setting
-
-    // add static data source
-    data_sources_.addDataSrc(ConstDataSrcPtr(new StaticDataSrc));
-
-    // enable or disable the cache
-    cache_.setEnabled(use_cache);
-}
+{}
 
 
 AuthSrvImpl::~AuthSrvImpl() {
 AuthSrvImpl::~AuthSrvImpl() {
     if (xfrout_connected_) {
     if (xfrout_connected_) {
@@ -398,11 +386,10 @@ private:
     AuthSrv* server_;
     AuthSrv* server_;
 };
 };
 
 
-AuthSrv::AuthSrv(const bool use_cache,
-                 isc::xfr::AbstractXfroutClient& xfrout_client,
+AuthSrv::AuthSrv(isc::xfr::AbstractXfroutClient& xfrout_client,
                  isc::util::io::BaseSocketSessionForwarder& ddns_forwarder)
                  isc::util::io::BaseSocketSessionForwarder& ddns_forwarder)
 {
 {
-    impl_ = new AuthSrvImpl(use_cache, xfrout_client, ddns_forwarder);
+    impl_ = new AuthSrvImpl(xfrout_client, ddns_forwarder);
     checkin_ = new ConfigChecker(this);
     checkin_ = new ConfigChecker(this);
     dns_lookup_ = new MessageLookup(this);
     dns_lookup_ = new MessageLookup(this);
     dns_answer_ = new MessageAnswer(this);
     dns_answer_ = new MessageAnswer(this);
@@ -482,16 +469,6 @@ AuthSrv::getIOService() {
 }
 }
 
 
 void
 void
-AuthSrv::setCacheSlots(const size_t slots) {
-    impl_->cache_.setSlots(slots);
-}
-
-size_t
-AuthSrv::getCacheSlots() const {
-    return (impl_->cache_.getSlots());
-}
-
-void
 AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
 AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
     impl_->xfrin_session_ = xfrin_session;
     impl_->xfrin_session_ = xfrin_session;
 }
 }
@@ -512,48 +489,6 @@ AuthSrv::getConfigSession() const {
     return (impl_->config_session_);
     return (impl_->config_session_);
 }
 }
 
 
-isc::datasrc::DataSourceClientContainerPtr
-AuthSrv::getInMemoryClientContainer(const RRClass& rrclass) {
-    if (rrclass != impl_->memory_client_class_) {
-        isc_throw(InvalidParameter,
-                  "Memory data source is not supported for RR class "
-                  << rrclass);
-    }
-    return (impl_->memory_client_container_);
-}
-
-isc::datasrc::DataSourceClient*
-AuthSrv::getInMemoryClient(const RRClass& rrclass) {
-    if (hasInMemoryClient()) {
-        return (&getInMemoryClientContainer(rrclass)->getInstance());
-    } else {
-        return (NULL);
-    }
-}
-
-bool
-AuthSrv::hasInMemoryClient() const {
-    return (impl_->memory_client_container_);
-}
-
-void
-AuthSrv::setInMemoryClient(const isc::dns::RRClass& rrclass,
-                           DataSourceClientContainerPtr memory_client)
-{
-    if (rrclass != impl_->memory_client_class_) {
-        isc_throw(InvalidParameter,
-                  "Memory data source is not supported for RR class "
-                  << rrclass);
-    } else if (!impl_->memory_client_container_ && memory_client) {
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_MEM_DATASRC_ENABLED)
-                  .arg(rrclass);
-    } else if (impl_->memory_client_container_ && !memory_client) {
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_MEM_DATASRC_DISABLED)
-                  .arg(rrclass);
-    }
-    impl_->memory_client_container_ = memory_client;
-}
-
 uint32_t
 uint32_t
 AuthSrv::getStatisticsTimerInterval() const {
 AuthSrv::getStatisticsTimerInterval() const {
     return (impl_->statistics_timer_.getInterval() / 1000);
     return (impl_->statistics_timer_.getInterval() / 1000);
@@ -725,18 +660,16 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
     }
     }
 
 
     try {
     try {
-        // If a memory data source is configured call the separate
-        // Query::process()
         const ConstQuestionPtr question = *message.beginQuestion();
         const ConstQuestionPtr question = *message.beginQuestion();
-        if (memory_client_container_ &&
-            memory_client_class_ == question->getClass()) {
+        const boost::shared_ptr<datasrc::ClientList>
+            list(getClientList(question->getClass()));
+        if (list) {
             const RRType& qtype = question->getType();
             const RRType& qtype = question->getType();
             const Name& qname = question->getName();
             const Name& qname = question->getName();
-            query_.process(memory_client_container_->getInstance(),
-                           qname, qtype, message, dnssec_ok);
+            query_.process(*list, qname, qtype, message, dnssec_ok);
         } else {
         } else {
-            datasrc::Query query(message, cache_, dnssec_ok);
-            data_sources_.doQuery(query);
+            makeErrorMessage(renderer_, message, buffer, Rcode::REFUSED());
+            return (true);
         }
         }
     } catch (const Exception& ex) {
     } catch (const Exception& ex) {
         LOG_ERROR(auth_logger, AUTH_PROCESS_FAIL).arg(ex.what());
         LOG_ERROR(auth_logger, AUTH_PROCESS_FAIL).arg(ex.what());
@@ -926,56 +859,6 @@ AuthSrvImpl::validateStatistics(isc::data::ConstElementPtr data) const {
             data, true));
             data, true));
 }
 }
 
 
-ConstElementPtr
-AuthSrvImpl::setDbFile(ConstElementPtr config) {
-    ConstElementPtr answer = isc::config::createAnswer();
-
-    if (config && config->contains("database_file")) {
-        db_file_ = config->get("database_file")->stringValue();
-    } else if (config_session_ != NULL) {
-        bool is_default;
-        string item("database_file");
-        ConstElementPtr value = config_session_->getValue(is_default, item);
-        ElementPtr final = Element::createMap();
-
-        // 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);
-        config = final;
-
-        db_file_ = value->stringValue();
-    } else {
-        return (answer);
-    }
-    LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_DATA_SOURCE).arg(db_file_);
-
-    // create SQL data source
-    // Note: the following step is tricky to be exception-safe and to ensure
-    // exception guarantee: We first need to perform all operations that can
-    // fail, while acquiring resources in the RAII manner.  We then perform
-    // delete and swap operations which should not fail.
-    DataSrcPtr datasrc_ptr(DataSrcPtr(new Sqlite3DataSrc));
-    datasrc_ptr->init(config);
-    data_sources_.addDataSrc(datasrc_ptr);
-
-    // The following code should be exception free.
-    if (cur_datasrc_ != NULL) {
-        data_sources_.removeDataSrc(cur_datasrc_);
-    }
-    cur_datasrc_ = datasrc_ptr;
-
-    return (answer);
-}
-
 void
 void
 AuthSrvImpl::resumeServer(DNSServer* server, Message& message, bool done) {
 AuthSrvImpl::resumeServer(DNSServer* server, Message& message, bool done) {
     if (done) {
     if (done) {
@@ -992,7 +875,7 @@ AuthSrv::updateConfig(ConstElementPtr new_config) {
         if (new_config) {
         if (new_config) {
             configureAuthServer(*this, new_config);
             configureAuthServer(*this, new_config);
         }
         }
-        return (impl_->setDbFile(new_config));
+        return (isc::config::createAnswer());
     } catch (const isc::Exception& error) {
     } catch (const isc::Exception& error) {
         LOG_ERROR(auth_logger, AUTH_CONFIG_UPDATE_FAIL).arg(error.what());
         LOG_ERROR(auth_logger, AUTH_CONFIG_UPDATE_FAIL).arg(error.what());
         return (isc::config::createAnswer(1, error.what()));
         return (isc::config::createAnswer(1, error.what()));
@@ -1056,4 +939,27 @@ AuthSrv::destroyDDNSForwarder() {
     }
     }
 }
 }
 
 
+void
+AuthSrv::setClientList(const RRClass& rrclass,
+                       const boost::shared_ptr<ConfigurableClientList>& list) {
+    if (list) {
+        impl_->client_lists_[rrclass] = list;
+    } else {
+        impl_->client_lists_.erase(rrclass);
+    }
+}
+boost::shared_ptr<ConfigurableClientList>
+AuthSrv::getClientList(const RRClass& rrclass) {
+    return (impl_->getClientList(rrclass));
+}
 
 
+vector<RRClass>
+AuthSrv::getClientListClasses() const {
+    vector<RRClass> result;
+    for (std::map<RRClass, boost::shared_ptr<ConfigurableClientList> >::
+         const_iterator it(impl_->client_lists_.begin());
+         it != impl_->client_lists_.end(); ++it) {
+        result.push_back(it->first);
+    }
+    return (result);
+}

+ 29 - 103
src/bin/auth/auth_srv.h

@@ -43,7 +43,7 @@ class BaseSocketSessionForwarder;
 }
 }
 }
 }
 namespace datasrc {
 namespace datasrc {
-class InMemoryClient;
+class ConfigurableClientList;
 }
 }
 namespace xfr {
 namespace xfr {
 class AbstractXfroutClient;
 class AbstractXfroutClient;
@@ -92,13 +92,11 @@ private:
 public:
 public:
     /// The constructor.
     /// The constructor.
     ///
     ///
-    /// \param use_cache Whether to enable hot spot cache for lookup results.
     /// \param xfrout_client Communication interface with a separate xfrout
     /// \param xfrout_client Communication interface with a separate xfrout
     /// process.  It's normally a reference to an xfr::XfroutClient object,
     /// process.  It's normally a reference to an xfr::XfroutClient object,
     /// but can refer to a local mock object for testing (or other
     /// but can refer to a local mock object for testing (or other
     /// experimental) purposes.
     /// experimental) purposes.
-    AuthSrv(const bool use_cache,
-            isc::xfr::AbstractXfroutClient& xfrout_client,
+    AuthSrv(isc::xfr::AbstractXfroutClient& xfrout_client,
             isc::util::io::BaseSocketSessionForwarder& ddns_forwarder);
             isc::util::io::BaseSocketSessionForwarder& ddns_forwarder);
     ~AuthSrv();
     ~AuthSrv();
     //@}
     //@}
@@ -129,20 +127,7 @@ public:
                         isc::util::OutputBuffer& buffer,
                         isc::util::OutputBuffer& buffer,
                         isc::asiodns::DNSServer* server);
                         isc::asiodns::DNSServer* server);
 
 
-    /// \brief Updates the data source for the \c AuthSrv object.
-    ///
-    /// This method installs or replaces the data source that the \c AuthSrv
-    /// object refers to for query processing.
-    /// Although the method name is generic, the only thing it does is to
-    /// update the data source information.
-    /// If there is a data source installed, it will be replaced with the
-    /// new one.
-    ///
-    /// In the current implementation, the SQLite data source and InMemoryClient
-    /// are assumed.
-    /// We can enable memory data source and get the path of SQLite database by
-    /// the \c config parameter.  If we disabled memory data source, the SQLite
-    /// data source will be used.
+    /// \brief Updates the configuration for the \c AuthSrv object.
     ///
     ///
     /// On success this method returns a data \c Element (in the form of a
     /// On success this method returns a data \c Element (in the form of a
     /// pointer like object) indicating the successful result,
     /// pointer like object) indicating the successful result,
@@ -200,26 +185,6 @@ public:
     /// \brief Return pointer to the Checkin callback function
     /// \brief Return pointer to the Checkin callback function
     isc::asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); }
     isc::asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); }
 
 
-    /// \brief Set or update the size (number of slots) of hot spot cache.
-    ///
-    /// If the specified size is 0, it means the size will be unlimited.
-    /// The specified size is recorded even if the cache is disabled; the
-    /// new size will be effective when the cache is enabled.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \param slots The number of cache slots.
-    void setCacheSlots(const size_t slots);
-
-    /// \brief Get the current size (number of slots) of hot spot cache.
-    ///
-    /// It always returns the recorded size regardless of the cache is enabled.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \return The current number of cache slots.
-    size_t getCacheSlots() const;
-
     /// \brief Set the communication session with a separate process for
     /// \brief Set the communication session with a separate process for
     /// outgoing zone transfers.
     /// outgoing zone transfers.
     ///
     ///
@@ -238,71 +203,6 @@ public:
     ///
     ///
     void setXfrinSession(isc::cc::AbstractSession* xfrin_session);
     void setXfrinSession(isc::cc::AbstractSession* xfrin_session);
 
 
-    /// Returns the in-memory data source configured for the \c AuthSrv,
-    /// if any, as a pointer.
-    ///
-    /// This is mostly a convenience function around
-    /// \c getInMemoryClientContainer, which saves the caller the step
-    /// of having to call getInstance().
-    /// The pointer is of course only valid as long as the container
-    /// exists.
-    ///
-    /// The in-memory data source is configured per RR class.  However,
-    /// the data source may not be available for all RR classes.
-    /// If it is not available for the specified RR class, an exception of
-    /// class \c InvalidParameter will be thrown.
-    /// This method never throws an exception otherwise.
-    ///
-    /// Even for supported RR classes, the in-memory data source is not
-    /// configured by default.  In that case a NULL (shared) pointer will
-    /// be returned.
-    ///
-    /// \param rrclass The RR class of the requested in-memory data source.
-    /// \return A pointer to the in-memory data source, if configured;
-    /// otherwise NULL.
-    isc::datasrc::DataSourceClient* getInMemoryClient(
-        const isc::dns::RRClass& rrclass);
-
-    /// Returns the DataSourceClientContainer of the in-memory datasource
-    ///
-    /// \exception InvalidParameter if the given class does not match
-    ///            the one in the memory data source, or if the memory
-    ///            datasource has not been set (callers can check with
-    ///            \c hasMemoryDataSource())
-    ///
-    /// \param rrclass The RR class of the requested in-memory data source.
-    /// \return A shared pointer to the in-memory data source, if configured;
-    /// otherwise an empty shared pointer.
-    isc::datasrc::DataSourceClientContainerPtr getInMemoryClientContainer(
-        const isc::dns::RRClass& rrclass);
-
-    /// Checks if the in-memory data source has been set.
-    ///
-    /// Right now, only one datasource at a time is effectively supported.
-    /// This is a helper method to check whether it is the in-memory one.
-    /// This is mostly useful for current testing, and is expected to be
-    /// removed (or changed in behaviour) soon, when the general
-    /// multi-data-source framework is completed.
-    ///
-    /// \return True if the in-memory datasource has been set.
-    bool hasInMemoryClient() const;
-
-    /// Sets or replaces the in-memory data source of the specified RR class.
-    ///
-    /// Some RR classes may not be supported, in which case an exception
-    /// of class \c InvalidParameter will be thrown.
-    /// This method never throws an exception otherwise.
-    ///
-    /// If there is already an in memory data source configured, it will be
-    /// replaced with the newly specified one.
-    /// \c memory_client can be an empty shared pointer, in which case it
-    /// will (re)disable the in-memory data source.
-    ///
-    /// \param rrclass The RR class of the in-memory data source to be set.
-    /// \param memory_client A (shared) pointer to \c InMemoryClient to be set.
-    void setInMemoryClient(const isc::dns::RRClass& rrclass,
-        isc::datasrc::DataSourceClientContainerPtr memory_client);
-
     /// \brief Set the communication session with Statistics.
     /// \brief Set the communication session with Statistics.
     ///
     ///
     /// This function never throws an exception as far as
     /// This function never throws an exception as far as
@@ -437,6 +337,32 @@ public:
     /// If there was no forwarder yet, this method does nothing.
     /// If there was no forwarder yet, this method does nothing.
     void destroyDDNSForwarder();
     void destroyDDNSForwarder();
 
 
+    /// \brief Sets the currently used list for data sources of given
+    ///     class.
+    ///
+    /// Replaces the internally used client list with a new one. Other
+    /// classes are not changed.
+    ///
+    /// \param rrclass The class to modify.
+    /// \param list Shared pointer to the client list. If it is NULL,
+    ///     the list is removed instead.
+    void setClientList(const isc::dns::RRClass& rrclass, const
+                       boost::shared_ptr<isc::datasrc::ConfigurableClientList>&
+                       list);
+
+    /// \brief Returns the currently used client list for the class.
+    ///
+    /// \param rrclass The class for which to get the list.
+    /// \return The list, or NULL if no list is set for the class.
+    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        getClientList(const isc::dns::RRClass& rrclass);
+
+    /// \brief Returns a list of classes that have a client list.
+    ///
+    /// \return List of classes for which a non-NULL client list
+    ///     has been set by setClientList.
+    std::vector<isc::dns::RRClass> getClientListClasses() const;
+
 private:
 private:
     AuthSrvImpl* impl_;
     AuthSrvImpl* impl_;
     isc::asiolink::SimpleCallback* checkin_;
     isc::asiolink::SimpleCallback* checkin_;

+ 1 - 6
src/bin/auth/b10-auth.8

@@ -22,7 +22,7 @@
 b10-auth \- Authoritative DNS server
 b10-auth \- Authoritative DNS server
 .SH "SYNOPSIS"
 .SH "SYNOPSIS"
 .HP \w'\fBb10\-auth\fR\ 'u
 .HP \w'\fBb10\-auth\fR\ 'u
-\fBb10\-auth\fR [\fB\-n\fR] [\fB\-v\fR]
+\fBb10\-auth\fR [\fB\-v\fR]
 .SH "DESCRIPTION"
 .SH "DESCRIPTION"
 .PP
 .PP
 The
 The
@@ -42,11 +42,6 @@ It receives its configurations from
 .PP
 .PP
 The arguments are as follows:
 The arguments are as follows:
 .PP
 .PP
-\fB\-n\fR
-.RS 4
-Do not cache answers in memory\&. The default is to use the cache for faster responses\&. The cache keeps the most recent 30,000 answers (positive and negative) in memory for 30 seconds (instead of querying the data source, such as SQLite3 database, each time)\&.
-.RE
-.PP
 \fB\-v\fR
 \fB\-v\fR
 .RS 4
 .RS 4
 Enable verbose logging mode\&. This enables logging of diagnostic messages at the maximum debug level\&.
 Enable verbose logging mode\&. This enables logging of diagnostic messages at the maximum debug level\&.

+ 0 - 13
src/bin/auth/b10-auth.xml

@@ -44,7 +44,6 @@
   <refsynopsisdiv>
   <refsynopsisdiv>
     <cmdsynopsis>
     <cmdsynopsis>
       <command>b10-auth</command>
       <command>b10-auth</command>
-      <arg><option>-n</option></arg>
       <arg><option>-v</option></arg>
       <arg><option>-v</option></arg>
     </cmdsynopsis>
     </cmdsynopsis>
   </refsynopsisdiv>
   </refsynopsisdiv>
@@ -80,18 +79,6 @@
 
 
     <variablelist>
     <variablelist>
       <varlistentry>
       <varlistentry>
-        <term><option>-n</option></term>
-        <listitem><para>
-          Do not cache answers in memory.
-          The default is to use the cache for faster responses.
-	  The cache keeps the most recent 30,000 answers (positive
-	  and negative) in memory for 30 seconds (instead of querying
-	  the data source, such as SQLite3 database, each time).
-        </para></listitem>
-<!-- TODO: this is SQLite3 only -->
-      </varlistentry>
-
-      <varlistentry>
         <term><option>-v</option></term>
         <term><option>-v</option></term>
         <listitem><para>
         <listitem><para>
 	  Enable verbose logging mode. This enables logging of
 	  Enable verbose logging mode. This enables logging of

+ 14 - 14
src/bin/auth/benchmarks/Makefile.am

@@ -26,19 +26,19 @@ query_bench_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
 
 
 nodist_query_bench_SOURCES = ../auth_messages.h ../auth_messages.cc
 nodist_query_bench_SOURCES = ../auth_messages.h ../auth_messages.cc
 
 
-query_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
-query_bench_LDADD += $(top_builddir)/src/lib/util/libutil.la
-query_bench_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-query_bench_LDADD += $(top_builddir)/src/lib/bench/libbench.la
-query_bench_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
-query_bench_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-query_bench_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-query_bench_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-query_bench_LDADD += $(top_builddir)/src/lib/log/liblog.la
-query_bench_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
-query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-query_bench_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-query_bench_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
-query_bench_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
+query_bench_LDADD = $(top_builddir)/src/lib/dns/libb10-dns++.la
+query_bench_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+query_bench_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+query_bench_LDADD += $(top_builddir)/src/lib/bench/libb10-bench.la
+query_bench_LDADD += $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
+query_bench_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+query_bench_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+query_bench_LDADD += $(top_builddir)/src/lib/xfr/libb10-xfr.la
+query_bench_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+query_bench_LDADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
+query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+query_bench_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
+query_bench_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
+query_bench_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
 query_bench_LDADD += $(SQLITE_LIBS)
 query_bench_LDADD += $(SQLITE_LIBS)
 
 

+ 7 - 31
src/bin/auth/benchmarks/query_bench.cc

@@ -77,10 +77,9 @@ protected:
 private:
 private:
     typedef boost::shared_ptr<const IOEndpoint> IOEndpointPtr;
     typedef boost::shared_ptr<const IOEndpoint> IOEndpointPtr;
 protected:
 protected:
-    QueryBenchMark(const bool enable_cache,
-                   const BenchQueries& queries, Message& query_message,
+    QueryBenchMark(const BenchQueries& queries, Message& query_message,
                    OutputBuffer& buffer) :
                    OutputBuffer& buffer) :
-        server_(new AuthSrv(enable_cache, xfrout_client, ddns_forwarder)),
+        server_(new AuthSrv(xfrout_client, ddns_forwarder)),
         queries_(queries),
         queries_(queries),
         query_message_(query_message),
         query_message_(query_message),
         buffer_(buffer),
         buffer_(buffer),
@@ -119,17 +118,12 @@ private:
 
 
 class Sqlite3QueryBenchMark  : public QueryBenchMark {
 class Sqlite3QueryBenchMark  : public QueryBenchMark {
 public:
 public:
-    Sqlite3QueryBenchMark(const int cache_slots,
-                          const char* const datasrc_file,
+    Sqlite3QueryBenchMark(const char* const datasrc_file,
                           const BenchQueries& queries,
                           const BenchQueries& queries,
                           Message& query_message,
                           Message& query_message,
                           OutputBuffer& buffer) :
                           OutputBuffer& buffer) :
-        QueryBenchMark(cache_slots >= 0 ? true : false, queries,
-                       query_message, buffer)
+        QueryBenchMark(queries, query_message, buffer)
     {
     {
-        if (cache_slots >= 0) {
-            server_->setCacheSlots(cache_slots);
-        }
         server_->updateConfig(Element::fromJSON("{\"database_file\": \"" +
         server_->updateConfig(Element::fromJSON("{\"database_file\": \"" +
                                                 string(datasrc_file) + "\"}"));
                                                 string(datasrc_file) + "\"}"));
     }
     }
@@ -142,7 +136,7 @@ public:
                           const BenchQueries& queries,
                           const BenchQueries& queries,
                           Message& query_message,
                           Message& query_message,
                           OutputBuffer& buffer) :
                           OutputBuffer& buffer) :
-        QueryBenchMark(false, queries, query_message, buffer)
+        QueryBenchMark(queries, query_message, buffer)
     {
     {
         configureAuthServer(*server_,
         configureAuthServer(*server_,
                             Element::fromJSON(
                             Element::fromJSON(
@@ -274,27 +268,9 @@ main(int argc, char* argv[]) {
 
 
     switch (datasrc_type) {
     switch (datasrc_type) {
     case SQLITE3:
     case SQLITE3:
-        cout << "Benchmark enabling Hot Spot Cache with unlimited slots "
-             << endl;
-        BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(0, datasrc_file, queries,
-                                             message, buffer));
-
-        cout << "Benchmark enabling Hot Spot Cache with 10*#queries slots "
-             << endl;
-        BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(10 * queries.size(), datasrc_file,
-                                             queries, message, buffer));
-
-        cout << "Benchmark enabling Hot Spot Cache with #queries/2 slots "
-             << endl;
-        BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(queries.size() / 2, datasrc_file,
-                                             queries, message, buffer));
-
-        cout << "Benchmark disabling Hot Spot Cache" << endl;
+        cout << "Benchmark with SQLite3" << endl;
         BenchMark<Sqlite3QueryBenchMark>(
         BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(-1, datasrc_file, queries,
+            iteration, Sqlite3QueryBenchMark(datasrc_file, queries,
                                              message, buffer));
                                              message, buffer));
         break;
         break;
     case MEMORY:
     case MEMORY:

+ 30 - 137
src/bin/auth/command.cc

@@ -17,8 +17,7 @@
 #include <auth/auth_srv.h>
 #include <auth/auth_srv.h>
 
 
 #include <cc/data.h>
 #include <cc/data.h>
-#include <datasrc/memory_datasrc.h>
-#include <datasrc/factory.h>
+#include <datasrc/client_list.h>
 #include <config/ccsession.h>
 #include <config/ccsession.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 #include <dns/rrclass.h>
 #include <dns/rrclass.h>
@@ -159,156 +158,50 @@ public:
 class LoadZoneCommand : public AuthCommand {
 class LoadZoneCommand : public AuthCommand {
 public:
 public:
     virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) {
     virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) {
-        // parse and validate the args.
-        if (!validate(server, args)) {
-            return;
-        }
-
-        const ConstElementPtr zone_config = getZoneConfig(server);
-
-        // Load a new zone and replace the current zone with the new one.
-        // TODO: eventually this should be incremental or done in some way
-        // that doesn't block other server operations.
-        // TODO: we may (should?) want to check the "last load time" and
-        // the timestamp of the file and skip loading if the file isn't newer.
-        const ConstElementPtr type(zone_config->get("filetype"));
-        boost::shared_ptr<InMemoryZoneFinder> zone_finder(
-            new InMemoryZoneFinder(old_zone_finder_->getClass(),
-                                   old_zone_finder_->getOrigin()));
-        if (type && type->stringValue() == "sqlite3") {
-            scoped_ptr<DataSourceClientContainer>
-                container(new DataSourceClientContainer("sqlite3",
-                                                        Element::fromJSON(
-                    "{\"database_file\": \"" +
-                    zone_config->get("file")->stringValue() + "\"}")));
-            zone_finder->load(*container->getInstance().getIterator(
-                old_zone_finder_->getOrigin()));
-        } else {
-            zone_finder->load(old_zone_finder_->getFileName());
-        }
-        old_zone_finder_->swap(*zone_finder);
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_LOAD_ZONE)
-                  .arg(zone_finder->getOrigin()).arg(zone_finder->getClass());
-    }
-
-private:
-    // zone finder to be updated with the new file.
-    boost::shared_ptr<InMemoryZoneFinder> old_zone_finder_;
-
-    // A helper private method to parse and validate command parameters.
-    // On success, it sets 'old_zone_finder_' to the zone to be updated.
-    // It returns true if everything is okay; and false if the command is
-    // valid but there's no need for further process.
-    bool validate(AuthSrv& server, isc::data::ConstElementPtr args) {
         if (args == NULL) {
         if (args == NULL) {
             isc_throw(AuthCommandError, "Null argument");
             isc_throw(AuthCommandError, "Null argument");
         }
         }
 
 
-        // In this initial implementation, we assume memory data source
-        // for class IN by default.
-        ConstElementPtr datasrc_elem = args->get("datasrc");
-        if (datasrc_elem) {
-            if (datasrc_elem->stringValue() == "sqlite3") {
-                LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_SQLITE3);
-                return (false);
-            } else if (datasrc_elem->stringValue() != "memory") {
-                // (note: at this point it's guaranteed that datasrc_elem
-                // is of string type)
-                isc_throw(AuthCommandError,
-                          "Data source type " << datasrc_elem->stringValue()
-                          << " is not supported");
-            }
-        }
-
         ConstElementPtr class_elem = args->get("class");
         ConstElementPtr class_elem = args->get("class");
-        const RRClass zone_class =
-            class_elem ? RRClass(class_elem->stringValue()) : RRClass::IN();
-
-        isc::datasrc::DataSourceClient* datasrc(
-            server.getInMemoryClient(zone_class));
-        if (datasrc == NULL) {
-            isc_throw(AuthCommandError, "Memory data source is disabled");
-        }
+        RRClass zone_class(class_elem ? RRClass(class_elem->stringValue()) :
+            RRClass::IN());
 
 
         ConstElementPtr origin_elem = args->get("origin");
         ConstElementPtr origin_elem = args->get("origin");
         if (!origin_elem) {
         if (!origin_elem) {
             isc_throw(AuthCommandError, "Zone origin is missing");
             isc_throw(AuthCommandError, "Zone origin is missing");
         }
         }
-        const Name origin = Name(origin_elem->stringValue());
+        Name origin(origin_elem->stringValue());
 
 
-        // Get the current zone
-        const DataSourceClient::FindResult result = datasrc->findZone(origin);
-        if (result.code != result::SUCCESS) {
-            isc_throw(AuthCommandError, "Zone " << origin <<
-                      " is not found in data source");
-        }
-
-        // It would appear that dynamic_cast does not work on all systems;
-        // it seems to confuse the RTTI system, resulting in NULL return
-        // values. So we use the more dangerous static_pointer_cast here.
-        old_zone_finder_ = boost::static_pointer_cast<InMemoryZoneFinder>(
-            result.zone_finder);
-
-        return (true);
-    }
+        const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+            list(server.getClientList(zone_class));
 
 
-    ConstElementPtr getZoneConfig(const AuthSrv &server) {
-        if (!server.getConfigSession()) {
-            // FIXME: This is a hack to make older tests pass. We should
-            // update these tests as well sometime and remove this hack.
-            // (note that under normal situation, the
-            // server.getConfigSession() does not return NULL)
-
-            // We provide an empty map, which means no configuration --
-            // defaults.
-            return (ConstElementPtr(new MapElement()));
+        if (!list) {
+            isc_throw(AuthCommandError, "There's no client list for "
+                      "class " << zone_class);
         }
         }
 
 
-        // Find the config corresponding to the zone.
-        // We expect the configuration to be valid, as we have it and we
-        // accepted it before, therefore it must be validated.
-        const ConstElementPtr config(server.getConfigSession()->
-                                     getValue("datasources"));
-        ConstElementPtr zone_list;
-        // Unfortunately, we need to walk the list to find the correct data
-        // source.
-        // TODO: Make it named sets. These lists are uncomfortable.
-        for (size_t i(0); i < config->size(); ++i) {
-            // We use the getValue to get defaults as well
-            const ConstElementPtr dsrc_config(config->get(i));
-            const ConstElementPtr class_config(dsrc_config->get("class"));
-            const string class_type(class_config ?
-                                    class_config->stringValue() : "IN");
-            // It is in-memory and our class matches.
-            // FIXME: Is it allowed to have two datasources for the same
-            // type and class at once? It probably would not work now
-            // anyway and we may want to change the configuration of
-            // datasources somehow.
-            if (dsrc_config->get("type")->stringValue() == "memory" &&
-                RRClass(class_type) == old_zone_finder_->getClass()) {
-                zone_list = dsrc_config->get("zones");
-                break;
-            }
-        }
-
-        if (!zone_list) {
-            isc_throw(AuthCommandError,
-                      "Corresponding data source configuration was not found");
-        }
-
-        // Now we need to walk the zones and find the correct one.
-        for (size_t i(0); i < zone_list->size(); ++i) {
-            const ConstElementPtr zone_config(zone_list->get(i));
-            if (Name(zone_config->get("origin")->stringValue()) ==
-                old_zone_finder_->getOrigin()) {
-                // The origins are the same, so we consider this config to be
-                // for the zone.
-                return (zone_config);
-            }
+        switch (list->reload(origin)) {
+            case ConfigurableClientList::ZONE_RELOADED:
+                // Everything worked fine.
+                LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_LOAD_ZONE)
+                    .arg(zone_class).arg(origin);
+                return;
+            case ConfigurableClientList::ZONE_NOT_FOUND:
+                isc_throw(AuthCommandError, "Zone " << origin << "/" <<
+                          zone_class << " was not found in any configured "
+                          "data source. Configure it first.");
+            case ConfigurableClientList::ZONE_NOT_CACHED:
+                isc_throw(AuthCommandError, "Zone " << origin << "/" <<
+                          zone_class << " is not served from memory, but "
+                          "direcly from the data source. It is not possible "
+                          "to reload it into memory. Configure it to be cached "
+                          "first.");
+            case ConfigurableClientList::CACHE_DISABLED:
+                // This is an internal error. Auth server must have the cache
+                // enabled.
+                isc_throw(isc::Unexpected, "Cache disabled in client list of "
+                          "class " << zone_class);
         }
         }
-
-        isc_throw(AuthCommandError,
-                  "Corresponding zone configuration was not found");
     }
     }
 };
 };
 
 

+ 223 - 0
src/bin/auth/datasrc_configurator.h

@@ -0,0 +1,223 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_CONFIGURATOR_H
+#define DATASRC_CONFIGURATOR_H
+
+#include "auth_srv.h"
+
+#include <datasrc/client_list.h>
+#include <config/ccsession.h>
+#include <cc/data.h>
+
+#include <set>
+
+/// \brief A class to configure the authoritative server's data source lists
+///
+/// This will hook into the data_sources module configuration and it will
+/// keep the local copy of data source clients in the list in the authoritative
+/// server.
+///
+/// The class is slightly unusual. Due to some technical limitations, the hook
+/// needs to be static method. Therefore it is not possible to create instances
+/// of the class.
+///
+/// Also, the class is a template. This is simply because of easier testing.
+/// You don't need to pay attention to it, use the DataSourceConfigurator
+/// type alias instead.
+template<class Server, class List>
+class DataSourceConfiguratorGeneric {
+private:
+    /// \brief Disallow creation of instances
+    DataSourceConfiguratorGeneric();
+    /// \brief Internal method to hook into the ModuleCCSession
+    ///
+    /// It simply calls reconfigure.
+    static void reconfigureInternal(const std::string&,
+                                    isc::data::ConstElementPtr config,
+                                    const isc::config::ConfigData&)
+    {
+        if (config->contains("classes")) {
+            reconfigure(config->get("classes"));
+        }
+    }
+    static Server* server_;
+    static isc::config::ModuleCCSession* session_;
+    typedef boost::shared_ptr<List> ListPtr;
+public:
+    /// \brief Initializes the class.
+    ///
+    /// This configures which session and server should be used.
+    /// It hooks to the session now and downloads the configuration.
+    /// It is synchronous (it may block for some time).
+    ///
+    /// Note that you need to call cleanup before the server or
+    /// session dies, otherwise it might access them after they
+    /// are destroyed.
+    ///
+    /// \param session The session to hook into and to access the configuration
+    ///     through.
+    /// \param server It is the server to configure.
+    /// \throw isc::InvalidOperation if this is called when already initialized.
+    /// \throw isc::InvalidParameter if any of the parameters is NULL
+    /// \throw isc::config::ModuleCCError if the remote configuration is not
+    ///     available for some reason.
+    static void init(isc::config::ModuleCCSession* session,
+                     Server* server)
+    {
+        if (session == NULL) {
+            isc_throw(isc::InvalidParameter, "The session must not be NULL");
+        }
+        if (server == NULL) {
+            isc_throw(isc::InvalidParameter, "The server must not be NULL");
+        }
+        if (server_ != NULL) {
+            isc_throw(isc::InvalidOperation,
+                      "The configurator is already initialized");
+        }
+        server_ = server;
+        session_ = session;
+        session->addRemoteConfig("data_sources", reconfigureInternal, false);
+    }
+    /// \brief Deinitializes the class.
+    ///
+    /// This detaches from the session and removes the server from internal
+    /// storage. The current configuration in the server is preserved.
+    ///
+    /// This can be called even if it is not initialized currently. You
+    /// can initialize it again after this.
+    static void cleanup() {
+        if (session_ != NULL) {
+            session_->removeRemoteConfig("data_sources");
+        }
+        session_ = NULL;
+        server_ = NULL;
+    }
+    /// \brief Reads new configuration and replaces the old one.
+    ///
+    /// It instructs the server to replace the lists with new ones as needed.
+    /// You don't need to call it directly (but you could, though the benefit
+    /// is unknown and it would be questionable at least). It is called
+    /// automatically on normal updates.
+    ///
+    /// \param config The configuration value to parse. It is in the form
+    ///     as an update from the config manager.
+    /// \throw InvalidOperation if it is called when not initialized.
+    static void reconfigure(const isc::data::ConstElementPtr& config) {
+        if (server_ == NULL) {
+            isc_throw(isc::InvalidOperation,
+                      "Can't reconfigure while not initialized by init()");
+        }
+        typedef std::map<std::string, isc::data::ConstElementPtr> Map;
+        typedef std::pair<isc::dns::RRClass, ListPtr> RollbackPair;
+        typedef std::pair<isc::dns::RRClass, isc::data::ConstElementPtr>
+            RollbackConfiguration;
+        // Some structures to be able to perform a rollback
+        std::vector<RollbackPair> rollback_sets;
+        std::vector<RollbackConfiguration> rollback_configurations;
+        try {
+            // Get the configuration and current state.
+            const Map& map(config->mapValue());
+            const std::vector<isc::dns::RRClass>
+                activeVector(server_->getClientListClasses());
+            std::set<isc::dns::RRClass> active(activeVector.begin(),
+                                               activeVector.end());
+            // Go through the configuration and change everything.
+            for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
+                isc::dns::RRClass rrclass(it->first);
+                active.erase(rrclass);
+                ListPtr list(server_->getClientList(rrclass));
+                bool need_set(false);
+                if (list) {
+                    rollback_configurations.
+                        push_back(RollbackConfiguration(rrclass,
+                            list->getConfiguration()));
+                } else {
+                    list.reset(new List(rrclass));
+                    need_set = true;
+                    rollback_sets.push_back(RollbackPair(rrclass, ListPtr()));
+                }
+                list->configure(it->second, true);
+                if (need_set) {
+                    server_->setClientList(rrclass, list);
+                }
+            }
+            // Remove the ones that are not in the configuration.
+            for (std::set<isc::dns::RRClass>::iterator it(active.begin());
+                 it != active.end(); ++it) {
+                // There seems to be no way the setClientList could throw.
+                // But this is just to make sure in case it did to restore
+                // the original.
+                rollback_sets.push_back(
+                    RollbackPair(*it, server_->getClientList(*it)));
+                server_->setClientList(*it, ListPtr());
+            }
+        } catch (...) {
+            // Perform a rollback of the changes. The old configuration should
+            // work.
+            for (typename std::vector<RollbackPair>::const_iterator
+                 it(rollback_sets.begin()); it != rollback_sets.end(); ++it) {
+                server_->setClientList(it->first, it->second);
+            }
+            for (typename std::vector<RollbackConfiguration>::const_iterator
+                 it(rollback_configurations.begin());
+                 it != rollback_configurations.end(); ++it) {
+                server_->getClientList(it->first)->configure(it->second, true);
+            }
+            throw;
+        }
+    }
+    /// \brief Version of reconfigure for easier testing.
+    ///
+    /// This method can be used to reconfigure a server without first
+    /// initializing the configurator. This does not need a session.
+    /// Otherwise, it acts the same as reconfigure.
+    ///
+    /// This is not meant for production code. Do not use there.
+    ///
+    /// \param server The server to configure.
+    /// \param config The config to use.
+    /// \throw isc::InvalidOperation if the configurator is initialized.
+    /// \throw anything that reconfigure does.
+    static void testReconfigure(Server* server,
+                                const isc::data::ConstElementPtr& config)
+    {
+        if (server_ != NULL) {
+            isc_throw(isc::InvalidOperation, "Currently initialized.");
+        }
+        try {
+            server_ = server;
+            reconfigure(config);
+            server_ = NULL;
+        } catch (...) {
+            server_ = NULL;
+            throw;
+        }
+    }
+};
+
+template<class Server, class List>
+isc::config::ModuleCCSession*
+DataSourceConfiguratorGeneric<Server, List>::session_(NULL);
+
+template<class Server, class List>
+Server* DataSourceConfiguratorGeneric<Server, List>::server_(NULL);
+
+/// \brief Concrete version of DataSourceConfiguratorGeneric for the
+///     use in authoritative server.
+typedef DataSourceConfiguratorGeneric<AuthSrv,
+        isc::datasrc::ConfigurableClientList>
+    DataSourceConfigurator;
+
+#endif

+ 12 - 8
src/bin/auth/main.cc

@@ -45,6 +45,7 @@
 #include <auth/command.h>
 #include <auth/command.h>
 #include <auth/auth_srv.h>
 #include <auth/auth_srv.h>
 #include <auth/auth_log.h>
 #include <auth/auth_log.h>
+#include <auth/datasrc_configurator.h>
 #include <asiodns/asiodns.h>
 #include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 #include <asiolink/asiolink.h>
 #include <log/logger_support.h>
 #include <log/logger_support.h>
@@ -84,9 +85,8 @@ my_command_handler(const string& command, ConstElementPtr args) {
 
 
 void
 void
 usage() {
 usage() {
-    cerr << "Usage:  b10-auth [-u user] [-nv]"
+    cerr << "Usage:  b10-auth [-v]"
          << endl;
          << endl;
-    cerr << "\t-n: do not cache answers in memory" << endl;
     cerr << "\t-v: verbose logging (debug-level)" << endl;
     cerr << "\t-v: verbose logging (debug-level)" << endl;
     exit(1);
     exit(1);
 }
 }
@@ -96,14 +96,10 @@ usage() {
 int
 int
 main(int argc, char* argv[]) {
 main(int argc, char* argv[]) {
     int ch;
     int ch;
-    bool cache = true;
     bool verbose = false;
     bool verbose = false;
 
 
     while ((ch = getopt(argc, argv, ":nu:v")) != -1) {
     while ((ch = getopt(argc, argv, ":nu:v")) != -1) {
         switch (ch) {
         switch (ch) {
-        case 'n':
-            cache = false;
-            break;
         case 'v':
         case 'v':
             verbose = true;
             verbose = true;
             break;
             break;
@@ -142,7 +138,7 @@ main(int argc, char* argv[]) {
             specfile = string(AUTH_SPECFILE_LOCATION);
             specfile = string(AUTH_SPECFILE_LOCATION);
         }
         }
 
 
-        auth_server = new AuthSrv(cache, xfrout_client, ddns_forwarder);
+        auth_server = new AuthSrv(xfrout_client, ddns_forwarder);
         LOG_INFO(auth_logger, AUTH_SERVER_CREATED);
         LOG_INFO(auth_logger, AUTH_SERVER_CREATED);
 
 
         SimpleCallback* checkin = auth_server->getCheckinProvider();
         SimpleCallback* checkin = auth_server->getCheckinProvider();
@@ -204,6 +200,14 @@ main(int argc, char* argv[]) {
         isc::server_common::initKeyring(*config_session);
         isc::server_common::initKeyring(*config_session);
         auth_server->setTSIGKeyRing(&isc::server_common::keyring);
         auth_server->setTSIGKeyRing(&isc::server_common::keyring);
 
 
+        // Start the data source configuration
+        DataSourceConfigurator::init(config_session, auth_server);
+        // HACK: The default is not passed to the handler. This one will
+        // get the default (or, current value). Further updates will work
+        // the usual way.
+        DataSourceConfigurator::reconfigure(
+            config_session->getRemoteConfigValue("data_sources", "classes"));
+
         // Now start asynchronous read.
         // Now start asynchronous read.
         config_session->start();
         config_session->start();
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_CONFIG_CHANNEL_STARTED);
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_CONFIG_CHANNEL_STARTED);
@@ -217,7 +221,6 @@ main(int argc, char* argv[]) {
         cc_session->group_sendmsg(
         cc_session->group_sendmsg(
             isc::config::createCommand(AUTH_STARTED_NOTIFICATION), "DDNS");
             isc::config::createCommand(AUTH_STARTED_NOTIFICATION), "DDNS");
         io_service.run();
         io_service.run();
-
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
         LOG_FATAL(auth_logger, AUTH_SERVER_FAILED).arg(ex.what());
         LOG_FATAL(auth_logger, AUTH_SERVER_FAILED).arg(ex.what());
         ret = 1;
         ret = 1;
@@ -231,6 +234,7 @@ main(int argc, char* argv[]) {
         xfrin_session->disconnect();
         xfrin_session->disconnect();
     }
     }
 
 
+    DataSourceConfigurator::cleanup();
     delete statistics_session;
     delete statistics_session;
     delete xfrin_session;
     delete xfrin_session;
     delete config_session;
     delete config_session;

+ 27 - 27
src/bin/auth/query.cc

@@ -19,6 +19,7 @@
 #include <dns/rdataclass.h>
 #include <dns/rdataclass.h>
 
 
 #include <datasrc/client.h>
 #include <datasrc/client.h>
+#include <datasrc/client_list.h>
 
 
 #include <auth/query.h>
 #include <auth/query.h>
 
 
@@ -341,17 +342,17 @@ namespace {
 // the qname consists of a single label, which also means it's the root name),
 // the qname consists of a single label, which also means it's the root name),
 // we should search the deepest zone we have (which should be the root zone;
 // we should search the deepest zone we have (which should be the root zone;
 // otherwise it's a query error).
 // otherwise it's a query error).
-DataSourceClient::FindResult
-findZone(const DataSourceClient& client, const Name& qname, RRType qtype) {
+ClientList::FindResult
+findZone(const ClientList& list, const Name& qname, RRType qtype) {
     if (qtype != RRType::DS() || qname.getLabelCount() == 1) {
     if (qtype != RRType::DS() || qname.getLabelCount() == 1) {
-        return (client.findZone(qname));
+        return (list.find(qname));
     }
     }
-    return (client.findZone(qname.split(1)));
+    return (list.find(qname.split(1)));
 }
 }
 }
 }
 
 
 void
 void
-Query::process(datasrc::DataSourceClient& datasrc_client,
+Query::process(datasrc::ClientList& client_list,
                const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                isc::dns::Message& response, bool dnssec)
                isc::dns::Message& response, bool dnssec)
 {
 {
@@ -360,19 +361,18 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
     QueryCleaner cleaner(*this);
     QueryCleaner cleaner(*this);
 
 
     // Set up query parameters for the rest of the (internal) methods
     // Set up query parameters for the rest of the (internal) methods
-    initialize(datasrc_client, qname, qtype, response, dnssec);
+    initialize(client_list, qname, qtype, response, dnssec);
 
 
     // Found a zone which is the nearest ancestor to QNAME
     // Found a zone which is the nearest ancestor to QNAME
-    const DataSourceClient::FindResult result = findZone(*datasrc_client_,
-                                                         *qname_, *qtype_);
+    const ClientList::FindResult result = findZone(*client_list_, *qname_,
+                                                   *qtype_);
 
 
     // If we have no matching authoritative zone for the query name, return
     // If we have no matching authoritative zone for the query name, return
     // REFUSED.  In short, this is to be compatible with BIND 9, but the
     // REFUSED.  In short, this is to be compatible with BIND 9, but the
     // background discussion is not that simple.  See the relevant topic
     // background discussion is not that simple.  See the relevant topic
     // at the BIND 10 developers's ML:
     // at the BIND 10 developers's ML:
     // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
     // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
-    if (result.code != result::SUCCESS &&
-        result.code != result::PARTIALMATCH) {
+    if (result.dsrc_client_ == NULL) {
         // If we tried to find a "parent zone" for a DS query and failed,
         // If we tried to find a "parent zone" for a DS query and failed,
         // we may still have authority at the child side.  If we do, the query
         // we may still have authority at the child side.  If we do, the query
         // has to be handled there.
         // has to be handled there.
@@ -384,7 +384,7 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
         response_->setRcode(Rcode::REFUSED());
         response_->setRcode(Rcode::REFUSED());
         return;
         return;
     }
     }
-    ZoneFinder& zfinder = *result.zone_finder;
+    ZoneFinder& zfinder = *result.finder_;
 
 
     // We have authority for a zone that contain the query name (possibly
     // We have authority for a zone that contain the query name (possibly
     // indirectly via delegation).  Look into the zone.
     // indirectly via delegation).  Look into the zone.
@@ -457,7 +457,7 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
             // If the answer is a result of wildcard substitution,
             // If the answer is a result of wildcard substitution,
             // add a proof that there's no closer name.
             // add a proof that there's no closer name.
             if (dnssec_ && db_context->isWildcard()) {
             if (dnssec_ && db_context->isWildcard()) {
-                addWildcardProof(*result.zone_finder, *db_context);
+                addWildcardProof(*result.finder_, *db_context);
             }
             }
             break;
             break;
         case ZoneFinder::SUCCESS:
         case ZoneFinder::SUCCESS:
@@ -475,17 +475,17 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
             // section.
             // section.
             // Checking the findZone() is a lightweight check to see if
             // Checking the findZone() is a lightweight check to see if
             // qname is the zone origin.
             // qname is the zone origin.
-            if (result.code != result::SUCCESS ||
+            if (!result.exact_match_ ||
                 db_context->code != ZoneFinder::SUCCESS ||
                 db_context->code != ZoneFinder::SUCCESS ||
                 (*qtype_ != RRType::NS() && !qtype_is_any))
                 (*qtype_ != RRType::NS() && !qtype_is_any))
             {
             {
-                addAuthAdditional(*result.zone_finder, additionals_);
+                addAuthAdditional(*result.finder_, additionals_);
             }
             }
 
 
             // If the answer is a result of wildcard substitution,
             // If the answer is a result of wildcard substitution,
             // add a proof that there's no closer name.
             // add a proof that there's no closer name.
             if (dnssec_ && db_context->isWildcard()) {
             if (dnssec_ && db_context->isWildcard()) {
-                addWildcardProof(*result.zone_finder, *db_context);
+                addWildcardProof(*result.finder_, *db_context);
             }
             }
             break;
             break;
         case ZoneFinder::DELEGATION:
         case ZoneFinder::DELEGATION:
@@ -505,12 +505,12 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
             // If DNSSEC is requested, see whether there is a DS
             // If DNSSEC is requested, see whether there is a DS
             // record for this delegation.
             // record for this delegation.
             if (dnssec_) {
             if (dnssec_) {
-                addDS(*result.zone_finder, db_context->rrset->getName());
+                addDS(*result.finder_, db_context->rrset->getName());
             }
             }
             break;
             break;
         case ZoneFinder::NXDOMAIN:
         case ZoneFinder::NXDOMAIN:
             response_->setRcode(Rcode::NXDOMAIN());
             response_->setRcode(Rcode::NXDOMAIN());
-            addSOA(*result.zone_finder);
+            addSOA(*result.finder_);
             if (dnssec_) {
             if (dnssec_) {
                 if (db_context->isNSECSigned() && db_context->rrset) {
                 if (db_context->isNSECSigned() && db_context->rrset) {
                     addNXDOMAINProofByNSEC(zfinder, db_context->rrset);
                     addNXDOMAINProofByNSEC(zfinder, db_context->rrset);
@@ -520,7 +520,7 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
             }
             }
             break;
             break;
         case ZoneFinder::NXRRSET:
         case ZoneFinder::NXRRSET:
-            addSOA(*result.zone_finder);
+            addSOA(*result.finder_);
             if (dnssec_) {
             if (dnssec_) {
                 addNXRRsetProof(zfinder, *db_context);
                 addNXRRsetProof(zfinder, *db_context);
             }
             }
@@ -538,11 +538,11 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
 }
 }
 
 
 void
 void
-Query::initialize(datasrc::DataSourceClient& datasrc_client,
+Query::initialize(datasrc::ClientList& client_list,
                   const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                   const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                   isc::dns::Message& response, bool dnssec)
                   isc::dns::Message& response, bool dnssec)
 {
 {
-    datasrc_client_ = &datasrc_client;
+    client_list_ = &client_list;
     qname_ = &qname;
     qname_ = &qname;
     qtype_ = &qtype;
     qtype_ = &qtype;
     response_ = &response;
     response_ = &response;
@@ -553,7 +553,7 @@ Query::initialize(datasrc::DataSourceClient& datasrc_client,
 
 
 void
 void
 Query::reset() {
 Query::reset() {
-    datasrc_client_ = NULL;
+    client_list_ = NULL;
     qname_ = NULL;
     qname_ = NULL;
     qtype_ = NULL;
     qtype_ = NULL;
     response_ = NULL;
     response_ = NULL;
@@ -565,10 +565,10 @@ Query::reset() {
 
 
 bool
 bool
 Query::processDSAtChild() {
 Query::processDSAtChild() {
-    const DataSourceClient::FindResult zresult =
-        datasrc_client_->findZone(*qname_);
+    const ClientList::FindResult zresult =
+        client_list_->find(*qname_, true);
 
 
-    if (zresult.code != result::SUCCESS) {
+    if (zresult.dsrc_client_ == NULL) {
         return (false);
         return (false);
     }
     }
 
 
@@ -583,12 +583,12 @@ Query::processDSAtChild() {
     // by seeing the SOA.
     // by seeing the SOA.
     response_->setHeaderFlag(Message::HEADERFLAG_AA);
     response_->setHeaderFlag(Message::HEADERFLAG_AA);
     response_->setRcode(Rcode::NOERROR());
     response_->setRcode(Rcode::NOERROR());
-    addSOA(*zresult.zone_finder);
+    addSOA(*zresult.finder_);
     ConstZoneFinderContextPtr ds_context =
     ConstZoneFinderContextPtr ds_context =
-        zresult.zone_finder->find(*qname_, RRType::DS(), dnssec_opt_);
+        zresult.finder_->find(*qname_, RRType::DS(), dnssec_opt_);
     if (ds_context->code == ZoneFinder::NXRRSET) {
     if (ds_context->code == ZoneFinder::NXRRSET) {
         if (dnssec_) {
         if (dnssec_) {
-            addNXRRsetProof(*zresult.zone_finder, *ds_context);
+            addNXRRsetProof(*zresult.finder_, *ds_context);
         }
         }
     }
     }
 
 

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

@@ -32,7 +32,7 @@ class RRset;
 }
 }
 
 
 namespace datasrc {
 namespace datasrc {
-class DataSourceClient;
+class ClientList;
 }
 }
 
 
 namespace auth {
 namespace auth {
@@ -55,8 +55,6 @@ namespace auth {
 ///   separate attribute setter.
 ///   separate attribute setter.
 /// - likewise, we'll eventually need to do per zone access control, for which
 /// - likewise, we'll eventually need to do per zone access control, for which
 ///   we need querier's information such as its IP address.
 ///   we need querier's information such as its IP address.
-/// - datasrc_client and response may better be parameters to process() instead
-///   of the constructor.
 ///
 ///
 /// <b>Note:</b> The class name is intentionally the same as the one used in
 /// <b>Note:</b> The class name is intentionally the same as the one used in
 /// the datasrc library.  This is because the plan is to eventually merge
 /// the datasrc library.  This is because the plan is to eventually merge
@@ -240,14 +238,14 @@ private:
     /// This is the first step of the process() method, and initializes
     /// This is the first step of the process() method, and initializes
     /// the member data
     /// the member data
     ///
     ///
-    /// \param datasrc_client The datasource wherein the answer to the query is
-    /// to be found.
+    /// \param client_list The datasource list wherein the answer to the query
+    /// is to be found.
     /// \param qname The query name
     /// \param qname The query name
     /// \param qtype The RR type of the query
     /// \param qtype The RR type of the query
     /// \param response The response message to store the answer to the query.
     /// \param response The response message to store the answer to the query.
     /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
     /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
     ///     possible.
     ///     possible.
-    void initialize(datasrc::DataSourceClient& datasrc_client,
+    void initialize(datasrc::ClientList& client_list,
                     const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                     const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                     isc::dns::Message& response, bool dnssec = false);
                     isc::dns::Message& response, bool dnssec = false);
 
 
@@ -281,7 +279,7 @@ public:
     /// Query parameters will be set by the call to process()
     /// Query parameters will be set by the call to process()
     ///
     ///
     Query() :
     Query() :
-        datasrc_client_(NULL), qname_(NULL), qtype_(NULL),
+        client_list_(NULL), qname_(NULL), qtype_(NULL),
         dnssec_(false), dnssec_opt_(isc::datasrc::ZoneFinder::FIND_DEFAULT),
         dnssec_(false), dnssec_opt_(isc::datasrc::ZoneFinder::FIND_DEFAULT),
         response_(NULL)
         response_(NULL)
     {
     {
@@ -318,14 +316,14 @@ public:
     /// shouldn't happen in real-life (as BadZone means wrong data, it should
     /// shouldn't happen in real-life (as BadZone means wrong data, it should
     /// have been rejected upon loading).
     /// have been rejected upon loading).
     ///
     ///
-    /// \param datasrc_client The datasource wherein the answer to the query is
-    /// to be found.
+    /// \param client_list The datasource list wherein the answer to the query
+    /// is to be found.
     /// \param qname The query name
     /// \param qname The query name
     /// \param qtype The RR type of the query
     /// \param qtype The RR type of the query
     /// \param response The response message to store the answer to the query.
     /// \param response The response message to store the answer to the query.
     /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
     /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
     ///     possible.
     ///     possible.
-    void process(datasrc::DataSourceClient& datasrc_client,
+    void process(datasrc::ClientList& client_list,
                  const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                  const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                  isc::dns::Message& response, bool dnssec = false);
                  isc::dns::Message& response, bool dnssec = false);
 
 
@@ -483,7 +481,7 @@ public:
     };
     };
 
 
 private:
 private:
-    const isc::datasrc::DataSourceClient* datasrc_client_;
+    const isc::datasrc::ClientList* client_list_;
     const isc::dns::Name* qname_;
     const isc::dns::Name* qname_;
     const isc::dns::RRType* qtype_;
     const isc::dns::RRType* qtype_;
     bool dnssec_;
     bool dnssec_;

+ 22 - 14
src/bin/auth/tests/Makefile.am

@@ -1,3 +1,5 @@
+SUBDIRS = testdata .
+
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
 AM_CPPFLAGS += -I$(top_builddir)/src/bin # for generated spec_config.h header
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
@@ -5,7 +7,10 @@ AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DAUTH_OBJ_DIR=\"$(abs_top_builddir)/src/bin/auth\"
 AM_CPPFLAGS += -DAUTH_OBJ_DIR=\"$(abs_top_builddir)/src/bin/auth\"
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
+AM_CPPFLAGS += -DTEST_OWN_DATA_DIR=\"$(abs_top_srcdir)/src/bin/auth/tests/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/testutils/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/testutils/testdata\"
+AM_CPPFLAGS += -DDSRC_DIR=\"$(abs_top_builddir)/src/lib/datasrc\"
+AM_CPPFLAGS += -DPLUGIN_DATA_PATH=\"$(abs_top_builddir)/src/bin/cfgmgr/plugins\"
 AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
 AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -18,6 +23,7 @@ AM_CPPFLAGS += -DUSE_STATIC_LINK=1
 endif
 endif
 
 
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
+CLEANFILES += $(abs_top_builddir)/src/lib/testutils/testdata/does-not-exist.sqlite3
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
         $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
         $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
@@ -44,6 +50,7 @@ run_unittests_SOURCES += command_unittest.cc
 run_unittests_SOURCES += common_unittest.cc
 run_unittests_SOURCES += common_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += statistics_unittest.cc
 run_unittests_SOURCES += statistics_unittest.cc
+run_unittests_SOURCES += datasrc_configurator_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_SOURCES += run_unittests.cc
 # This is a temporary workaround for #1206, where the InMemoryClient has been
 # This is a temporary workaround for #1206, where the InMemoryClient has been
 # moved to an ldopened library. We could add that library to LDADD, but that
 # moved to an ldopened library. We could add that library to LDADD, but that
@@ -57,21 +64,22 @@ nodist_run_unittests_SOURCES = ../auth_messages.h ../auth_messages.cc
 
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-run_unittests_LDADD = $(top_builddir)/src/lib/testutils/libtestutils.la
-run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libdatasrc.la
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
-run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
+run_unittests_LDADD = $(top_builddir)/src/lib/testutils/libb10-testutils.la
+run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
+run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libb10-dns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libb10-xfr.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
+run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
+run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/tests/libfake_session.la
 run_unittests_LDADD += $(GTEST_LDADD)
 run_unittests_LDADD += $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
 run_unittests_LDADD += $(SQLITE_LIBS)
 
 

+ 284 - 216
src/bin/auth/tests/auth_srv_unittest.cc

@@ -30,10 +30,12 @@
 #include <server_common/keyring.h>
 #include <server_common/keyring.h>
 
 
 #include <datasrc/memory_datasrc.h>
 #include <datasrc/memory_datasrc.h>
+#include <datasrc/client_list.h>
 #include <auth/auth_srv.h>
 #include <auth/auth_srv.h>
 #include <auth/command.h>
 #include <auth/command.h>
 #include <auth/common.h>
 #include <auth/common.h>
 #include <auth/statistics.h>
 #include <auth/statistics.h>
+#include <auth/datasrc_configurator.h>
 
 
 #include <util/unittests/mock_socketsession.h>
 #include <util/unittests/mock_socketsession.h>
 #include <dns/tests/unittest_util.h>
 #include <dns/tests/unittest_util.h>
@@ -48,6 +50,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
+#include <boost/foreach.hpp>
 
 
 #include <vector>
 #include <vector>
 
 
@@ -79,19 +82,17 @@ const char* const CONFIG_TESTDB =
 const char* const BADCONFIG_TESTDB =
 const char* const BADCONFIG_TESTDB =
     "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
     "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
 
 
+const char* const STATIC_DSRC_FILE = DSRC_DIR "/static.zone";
+
 // This is a configuration that uses the in-memory data source containing
 // This is a configuration that uses the in-memory data source containing
 // a signed example zone.
 // a signed example zone.
-const char* const CONFIG_INMEMORY_EXAMPLE =
-    "{\"datasources\": [{\"type\": \"memory\","
-    "\"zones\": [{\"origin\": \"example\","
-    "\"file\": \"" TEST_DATA_DIR "/rfc5155-example.zone.signed\"}]}]}";
+const char* const CONFIG_INMEMORY_EXAMPLE = TEST_DATA_DIR "/rfc5155-example.zone.signed";
 
 
 class AuthSrvTest : public SrvTestBase {
 class AuthSrvTest : public SrvTestBase {
 protected:
 protected:
     AuthSrvTest() :
     AuthSrvTest() :
         dnss_(),
         dnss_(),
-        server(true, xfrout, ddns_forwarder),
-        rrclass(RRClass::IN()),
+        server(xfrout, ddns_forwarder),
         // The empty string is expected value of the parameter of
         // The empty string is expected value of the parameter of
         // requestSocket, not the app_name (there's no fallback, it checks
         // requestSocket, not the app_name (there's no fallback, it checks
         // the empty string is passed).
         // the empty string is passed).
@@ -183,7 +184,6 @@ protected:
     MockXfroutClient xfrout;
     MockXfroutClient xfrout;
     MockSocketSessionForwarder ddns_forwarder;
     MockSocketSessionForwarder ddns_forwarder;
     AuthSrv server;
     AuthSrv server;
-    const RRClass rrclass;
     vector<uint8_t> response_data;
     vector<uint8_t> response_data;
     AddressList address_store_;
     AddressList address_store_;
     TestSocketRequestor sock_requestor_;
     TestSocketRequestor sock_requestor_;
@@ -194,7 +194,8 @@ protected:
 // by default.  The resulting wire-format data will be stored in 'data'.
 // by default.  The resulting wire-format data will be stored in 'data'.
 void
 void
 createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
 createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
-    const Name version_name("version.bind");
+    const Name version_name("VERSION.BIND.");
+    const Name apex_name("BIND.");
     Message message(Message::RENDER);
     Message message(Message::RENDER);
 
 
     UnitTestUtil::createRequestMessage(message, Opcode::QUERY(),
     UnitTestUtil::createRequestMessage(message, Opcode::QUERY(),
@@ -207,9 +208,9 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
     rrset_version->addRdata(generic::TXT(PACKAGE_STRING));
     rrset_version->addRdata(generic::TXT(PACKAGE_STRING));
     message.addRRset(Message::SECTION_ANSWER, rrset_version);
     message.addRRset(Message::SECTION_ANSWER, rrset_version);
 
 
-    RRsetPtr rrset_version_ns = RRsetPtr(new RRset(version_name, RRClass::CH(),
+    RRsetPtr rrset_version_ns = RRsetPtr(new RRset(apex_name, RRClass::CH(),
                                                    RRType::NS(), RRTTL(0)));
                                                    RRType::NS(), RRTTL(0)));
-    rrset_version_ns->addRdata(generic::NS(version_name));
+    rrset_version_ns->addRdata(generic::NS(apex_name));
     message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);
     message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);
 
 
     MessageRenderer renderer;
     MessageRenderer renderer;
@@ -221,69 +222,18 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
                 renderer.getLength());
                 renderer.getLength());
 }
 }
 
 
-// In the following tests we confirm the response data is rendered in
-// wire format in the expected way.
-
-// The most primitive check: checking the result of the processMessage()
-// method
-TEST_F(AuthSrvTest, builtInQuery) {
+// We did not configure any client lists. Therefore it should be REFUSED
+TEST_F(AuthSrvTest, noClientList) {
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                        default_qid, Name("version.bind"),
                                        default_qid, Name("version.bind"),
                                        RRClass::CH(), RRType::TXT());
                                        RRClass::CH(), RRType::TXT());
     createRequestPacket(request_message, IPPROTO_UDP);
     createRequestPacket(request_message, IPPROTO_UDP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
                           &dnsserv);
-    createBuiltinVersionResponse(default_qid, response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
-    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
-}
-
-// Same test emulating the UDPServer class behavior (defined in libasiolink).
-// This is not a good test in that it assumes internal implementation details
-// of UDPServer, but we've encountered a regression due to the introduction
-// of that class, so we add a test for that case to prevent such a regression
-// in future.
-// Besides, the generalization of UDPServer is probably too much for the
-// authoritative only server in terms of performance, and it's quite likely
-// we need to drop it for the authoritative server implementation.
-// At that point we can drop this test, too.
-TEST_F(AuthSrvTest, builtInQueryViaDNSServer) {
-    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
-                                       default_qid, Name("version.bind"),
-                                       RRClass::CH(), RRType::TXT());
-    createRequestPacket(request_message, IPPROTO_UDP);
 
 
-    (*server.getDNSLookupProvider())(*io_message, parse_message,
-                                     response_message,
-                                     response_obuffer, &dnsserv);
-    (*server.getDNSAnswerProvider())(*io_message, parse_message,
-                                     response_message, response_obuffer);
-
-    createBuiltinVersionResponse(default_qid, response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
-}
-
-// Same type of test as builtInQueryViaDNSServer but for an error response.
-TEST_F(AuthSrvTest, iqueryViaDNSServer) {
-    createDataFromFile("iquery_fromWire.wire");
-    (*server.getDNSLookupProvider())(*io_message, parse_message,
-                                     response_message,
-                                     response_obuffer, &dnsserv);
-    (*server.getDNSAnswerProvider())(*io_message, parse_message,
-                                     response_message, response_obuffer);
-
-    UnitTestUtil::readWireData("iquery_response_fromWire.wire",
-                               response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::REFUSED(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 }
 
 
 // Unsupported requests.  Should result in NOTIMP.
 // Unsupported requests.  Should result in NOTIMP.
@@ -350,43 +300,6 @@ TEST_F(AuthSrvTest, AXFRSuccess) {
     checkAllRcodeCountersZero();
     checkAllRcodeCountersZero();
 }
 }
 
 
-// Try giving the server a TSIG signed request and see it can anwer signed as
-// well
-TEST_F(AuthSrvTest, TSIGSigned) {
-    // Prepare key, the client message, etc
-    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
-    TSIGContext context(key);
-    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
-                                       Name("version.bind"), RRClass::CH(),
-                                       RRType::TXT());
-    createRequestPacket(request_message, IPPROTO_UDP, &context);
-
-    // Run the message through the server
-    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
-    keyring->add(key);
-    server.setTSIGKeyRing(&keyring);
-    server.processMessage(*io_message, *parse_message, *response_obuffer,
-                          &dnsserv);
-
-    // What did we get?
-    EXPECT_TRUE(dnsserv.hasAnswer());
-    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
-                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
-    // We need to parse the message ourself, or getTSIGRecord won't work
-    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
-    Message m(Message::PARSE);
-    m.fromWire(ib);
-
-    const TSIGRecord* tsig = m.getTSIGRecord();
-    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
-    TSIGError error(context.verify(tsig, response_obuffer->getData(),
-                                   response_obuffer->getLength()));
-    EXPECT_EQ(TSIGError::NOERROR(), error) <<
-        "The server signed the response, but it doesn't seem to be valid";
-
-    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
-}
-
 // Give the server a signed request, but don't give it the key. It will
 // Give the server a signed request, but don't give it the key. It will
 // not be able to verify it, returning BADKEY
 // not be able to verify it, returning BADKEY
 TEST_F(AuthSrvTest, TSIGSignedBadKey) {
 TEST_F(AuthSrvTest, TSIGSignedBadKey) {
@@ -813,23 +726,171 @@ TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
 }
 }
 
 
 void
 void
-updateConfig(AuthSrv* server, const char* const config_data,
-             const bool expect_success)
-{
-    ConstElementPtr config_answer =
-        server->updateConfig(Element::fromJSON(config_data));
-    EXPECT_EQ(Element::map, config_answer->getType());
-    EXPECT_TRUE(config_answer->contains("result"));
+updateDatabase(AuthSrv* server, const char* params) {
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "    \"type\": \"sqlite3\","
+        "    \"params\": " + string(params) +
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(server, config);
+}
+
+void
+updateInMemory(AuthSrv* server, const char* origin, const char* filename) {
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": {"
+        "       \"" + string(origin) + "\": \"" + string(filename) + "\""
+        "   },"
+        "   \"cache-enable\": true"
+        "}],"
+        "\"CH\": [{"
+        "   \"type\": \"static\","
+        "   \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(server, config);
+}
+
+void
+updateBuiltin(AuthSrv* server) {
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"CH\": [{"
+        "   \"type\": \"static\","
+        "   \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(server, config);
+}
+
+// Try giving the server a TSIG signed request and see it can anwer signed as
+// well
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_TSIGSigned) { // Needs builtin
+#else
+TEST_F(AuthSrvTest, TSIGSigned) {
+#endif
+    // Prepare key, the client message, etc
+    updateBuiltin(&server);
+    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
+    TSIGContext context(key);
+    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
+                                       Name("VERSION.BIND."), RRClass::CH(),
+                                       RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP, &context);
+
+    // Run the message through the server
+    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
+    keyring->add(key);
+    server.setTSIGKeyRing(&keyring);
+    server.processMessage(*io_message, *parse_message, *response_obuffer,
+                          &dnsserv);
+
+    // What did we get?
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
+    // We need to parse the message ourself, or getTSIGRecord won't work
+    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
+    Message m(Message::PARSE);
+    m.fromWire(ib);
+
+    const TSIGRecord* tsig = m.getTSIGRecord();
+    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
+    TSIGError error(context.verify(tsig, response_obuffer->getData(),
+                                   response_obuffer->getLength()));
+    EXPECT_EQ(TSIGError::NOERROR(), error) <<
+        "The server signed the response, but it doesn't seem to be valid";
+
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
+}
+
+// Same test emulating the UDPServer class behavior (defined in libasiolink).
+// This is not a good test in that it assumes internal implementation details
+// of UDPServer, but we've encountered a regression due to the introduction
+// of that class, so we add a test for that case to prevent such a regression
+// in future.
+// Besides, the generalization of UDPServer is probably too much for the
+// authoritative only server in terms of performance, and it's quite likely
+// we need to drop it for the authoritative server implementation.
+// At that point we can drop this test, too.
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_builtInQueryViaDNSServer) {
+#else
+TEST_F(AuthSrvTest, builtInQueryViaDNSServer) {
+#endif
+    updateBuiltin(&server);
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("VERSION.BIND."),
+                                       RRClass::CH(), RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP);
+
+    (*server.getDNSLookupProvider())(*io_message, parse_message,
+                                     response_message,
+                                     response_obuffer, &dnsserv);
+    (*server.getDNSAnswerProvider())(*io_message, parse_message,
+                                     response_message, response_obuffer);
+
+    createBuiltinVersionResponse(default_qid, response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
+}
+
+// In the following tests we confirm the response data is rendered in
+// wire format in the expected way.
+
+// The most primitive check: checking the result of the processMessage()
+// method
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_builtInQuery) {
+#else
+TEST_F(AuthSrvTest, builtInQuery) {
+#endif
+    updateBuiltin(&server);
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("VERSION.BIND."),
+                                       RRClass::CH(), RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    server.processMessage(*io_message, *parse_message, *response_obuffer,
+                          &dnsserv);
+    createBuiltinVersionResponse(default_qid, response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
+}
+
+// Same type of test as builtInQueryViaDNSServer but for an error response.
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_iqueryViaDNSServer) { // Needs builtin
+#else
+TEST_F(AuthSrvTest, iqueryViaDNSServer) { // Needs builtin
+#endif
+    updateBuiltin(&server);
+    createDataFromFile("iquery_fromWire.wire");
+    (*server.getDNSLookupProvider())(*io_message, parse_message,
+                                     response_message,
+                                     response_obuffer, &dnsserv);
+    (*server.getDNSAnswerProvider())(*io_message, parse_message,
+                                     response_message, response_obuffer);
 
 
-    ConstElementPtr result = config_answer->get("result");
-    EXPECT_EQ(Element::list, result->getType());
-    EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue()) <<
-        "Bad result from updateConfig: " << result->str();
+    UnitTestUtil::readWireData("iquery_response_fromWire.wire",
+                               response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
 }
 }
 
 
 // Install a Sqlite3 data source with testing data.
 // Install a Sqlite3 data source with testing data.
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_updateConfig) {
+#else
 TEST_F(AuthSrvTest, updateConfig) {
 TEST_F(AuthSrvTest, updateConfig) {
-    updateConfig(&server, CONFIG_TESTDB, true);
+#endif
+    updateDatabase(&server, CONFIG_TESTDB);
 
 
     // query for existent data in the installed data source.  The resulting
     // query for existent data in the installed data source.  The resulting
     // response should have the AA flag on, and have an RR in each answer
     // response should have the AA flag on, and have an RR in each answer
@@ -842,8 +903,12 @@ TEST_F(AuthSrvTest, updateConfig) {
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 }
 
 
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_datasourceFail) {
+#else
 TEST_F(AuthSrvTest, datasourceFail) {
 TEST_F(AuthSrvTest, datasourceFail) {
-    updateConfig(&server, CONFIG_TESTDB, true);
+#endif
+    updateDatabase(&server, CONFIG_TESTDB);
 
 
     // This query will hit a corrupted entry of the data source (the zoneload
     // This query will hit a corrupted entry of the data source (the zoneload
     // tool and the data source itself naively accept it).  This will result
     // tool and the data source itself naively accept it).  This will result
@@ -857,40 +922,40 @@ TEST_F(AuthSrvTest, datasourceFail) {
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 }
 
 
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_updateConfigFail) {
+#else
 TEST_F(AuthSrvTest, updateConfigFail) {
 TEST_F(AuthSrvTest, updateConfigFail) {
+#endif
     // First, load a valid data source.
     // First, load a valid data source.
-    updateConfig(&server, CONFIG_TESTDB, true);
+    updateDatabase(&server, CONFIG_TESTDB);
 
 
     // Next, try to update it with a non-existent one.  This should fail.
     // Next, try to update it with a non-existent one.  This should fail.
-    updateConfig(&server, BADCONFIG_TESTDB, false);
+    EXPECT_THROW(updateDatabase(&server, BADCONFIG_TESTDB),
+                 isc::datasrc::DataSourceError);
 
 
     // The original data source should still exist.
     // The original data source should still exist.
     createDataFromFile("examplequery_fromWire.wire");
     createDataFromFile("examplequery_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
                           &dnsserv);
     EXPECT_TRUE(dnsserv.hasAnswer());
     EXPECT_TRUE(dnsserv.hasAnswer());
-    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
-                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 }
 
 
-TEST_F(AuthSrvTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_updateWithInMemoryClient
-#else
-       updateWithInMemoryClient
-#endif
-    )
-{
+TEST_F(AuthSrvTest, updateWithInMemoryClient) {
     // Test configuring memory data source.  Detailed test cases are covered
     // Test configuring memory data source.  Detailed test cases are covered
     // in the configuration tests.  We only check the AuthSrv interface here.
     // in the configuration tests.  We only check the AuthSrv interface here.
 
 
-    // By default memory data source isn't enabled
-    EXPECT_FALSE(server.hasInMemoryClient());
-    updateConfig(&server,
-                 "{\"datasources\": [{\"type\": \"memory\"}]}", true);
+    // Create an empty in-memory
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": {},"
+        "   \"cache-enable\": true"
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(&server, config);
     // after successful configuration, we should have one (with empty zoneset).
     // after successful configuration, we should have one (with empty zoneset).
-    EXPECT_TRUE(server.hasInMemoryClient());
-    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
 
 
     // The memory data source is empty, should return REFUSED rcode.
     // The memory data source is empty, should return REFUSED rcode.
     createDataFromFile("examplequery_fromWire.wire");
     createDataFromFile("examplequery_fromWire.wire");
@@ -901,21 +966,16 @@ TEST_F(AuthSrvTest,
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 }
 
 
-TEST_F(AuthSrvTest,
 #ifdef USE_STATIC_LINK
 #ifdef USE_STATIC_LINK
-       DISABLED_queryWithInMemoryClientNoDNSSEC
+TEST_F(AuthSrvTest, DISABLED_queryWithInMemoryClientNoDNSSEC) {
 #else
 #else
-       queryWithInMemoryClientNoDNSSEC
+TEST_F(AuthSrvTest, queryWithInMemoryClientNoDNSSEC) {
 #endif
 #endif
-    )
-{
     // In this example, we do simple check that query is handled from the
     // In this example, we do simple check that query is handled from the
     // query handler class, and confirm it returns no error and a non empty
     // query handler class, and confirm it returns no error and a non empty
     // answer section.  Detailed examination on the response content
     // answer section.  Detailed examination on the response content
     // for various types of queries are tested in the query tests.
     // for various types of queries are tested in the query tests.
-    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
-    EXPECT_TRUE(server.hasInMemoryClient());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
 
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -926,20 +986,15 @@ TEST_F(AuthSrvTest,
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
 }
 }
 
 
-TEST_F(AuthSrvTest,
 #ifdef USE_STATIC_LINK
 #ifdef USE_STATIC_LINK
-       DISABLED_queryWithInMemoryClientDNSSEC
+TEST_F(AuthSrvTest, DISABLED_queryWithInMemoryClientDNSSEC) {
 #else
 #else
-       queryWithInMemoryClientDNSSEC
+TEST_F(AuthSrvTest, queryWithInMemoryClientDNSSEC) {
 #endif
 #endif
-    )
-{
     // Similar to the previous test, but the query has the DO bit on.
     // Similar to the previous test, but the query has the DO bit on.
     // The response should contain RRSIGs, and should have more RRs than
     // The response should contain RRSIGs, and should have more RRs than
     // the previous case.
     // the previous case.
-    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
-    EXPECT_TRUE(server.hasInMemoryClient());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
 
     createDataFromFile("nsec3query_fromWire.wire");
     createDataFromFile("nsec3query_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -958,13 +1013,12 @@ TEST_F(AuthSrvTest,
 #endif
 #endif
     )
     )
 {
 {
-    // Configure memory data source for class IN
-    updateConfig(&server, "{\"datasources\": "
-                 "[{\"class\": \"IN\", \"type\": \"memory\"}]}", true);
+    // Set up the in-memory
+    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
 
     // This shouldn't affect the result of class CH query
     // This shouldn't affect the result of class CH query
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
-                                       default_qid, Name("version.bind"),
+                                       default_qid, Name("VERSION.BIND."),
                                        RRClass::CH(), RRType::TXT());
                                        RRClass::CH(), RRType::TXT());
     createRequestPacket(request_message, IPPROTO_UDP);
     createRequestPacket(request_message, IPPROTO_UDP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -974,16 +1028,6 @@ TEST_F(AuthSrvTest,
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 }
 
 
-TEST_F(AuthSrvTest, cacheSlots) {
-    // simple check for the get/set operations
-    server.setCacheSlots(10);    // 10 = arbitrary choice
-    EXPECT_EQ(10, server.getCacheSlots());
-
-    // 0 is a valid size
-    server.setCacheSlots(0);
-    EXPECT_EQ(00, server.getCacheSlots());
-}
-
 // Submit UDP normal query and check query counter
 // Submit UDP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterUDPNormal) {
 TEST_F(AuthSrvTest, queryCounterUDPNormal) {
     // The counter should be initialized to 0.
     // The counter should be initialized to 0.
@@ -1290,7 +1334,7 @@ public:
     ///                      throw std::exception
     ///                      throw std::exception
     /// \param fake_rrset If non NULL, it will be used as an answer to
     /// \param fake_rrset If non NULL, it will be used as an answer to
     /// find() for that name and type.
     /// find() for that name and type.
-    FakeClient(isc::datasrc::DataSourceClientContainerPtr real_client,
+    FakeClient(const DataSourceClient* real_client,
                ThrowWhen throw_when, bool isc_exception,
                ThrowWhen throw_when, bool isc_exception,
                ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
                ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
         real_client_ptr_(real_client),
         real_client_ptr_(real_client),
@@ -1309,7 +1353,7 @@ public:
     findZone(const isc::dns::Name& name) const {
     findZone(const isc::dns::Name& name) const {
         checkThrow(THROW_AT_FIND_ZONE, throw_when_, isc_exception_);
         checkThrow(THROW_AT_FIND_ZONE, throw_when_, isc_exception_);
         const FindResult result =
         const FindResult result =
-            real_client_ptr_->getInstance().findZone(name);
+            real_client_ptr_->findZone(name);
         return (FindResult(result.code, isc::datasrc::ZoneFinderPtr(
         return (FindResult(result.code, isc::datasrc::ZoneFinderPtr(
                                         new FakeZoneFinder(result.zone_finder,
                                         new FakeZoneFinder(result.zone_finder,
                                                            throw_when_,
                                                            throw_when_,
@@ -1329,38 +1373,39 @@ public:
                   "fake data source");
                   "fake data source");
     }
     }
 private:
 private:
-    const isc::datasrc::DataSourceClientContainerPtr real_client_ptr_;
+    const DataSourceClient* real_client_ptr_;
     ThrowWhen throw_when_;
     ThrowWhen throw_when_;
     bool isc_exception_;
     bool isc_exception_;
     ConstRRsetPtr fake_rrset_;
     ConstRRsetPtr fake_rrset_;
 };
 };
 
 
-class FakeContainer : public isc::datasrc::DataSourceClientContainer {
+class FakeList : public isc::datasrc::ConfigurableClientList {
 public:
 public:
-    /// \brief Creates a fake container for the given in-memory client
+    /// \brief Creates a fake list for the given in-memory client
     ///
     ///
-    /// The initializer creates a fresh instance of a memory datasource,
-    /// which is ignored for the rest (but we do not allow 'null' containers
-    /// atm, and this is only needed in these tests, this may be changed
-    /// if we generalize the container class a bit more)
-    ///
-    /// It will also create a FakeClient, with the given arguments, which
-    /// is actually used when the instance is requested.
-    FakeContainer(isc::datasrc::DataSourceClientContainerPtr real_client,
-                  ThrowWhen throw_when, bool isc_exception,
-                  ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
-        DataSourceClientContainer("memory",
-                                  Element::fromJSON("{\"type\": \"memory\"}")),
-        client_(new FakeClient(real_client, throw_when, isc_exception,
-                               fake_rrset))
-    {}
-
-    isc::datasrc::DataSourceClient& getInstance() {
-        return (*client_);
+    /// It will create a FakeClient for each client in the original list,
+    /// with the given arguments, which is used when searching for the
+    /// corresponding data source.
+    FakeList(const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+             real_list, ThrowWhen throw_when, bool isc_exception,
+             ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
+        ConfigurableClientList(RRClass::IN()),
+        real_(real_list)
+    {
+        BOOST_FOREACH(const DataSourceInfo& info, real_->getDataSources()) {
+             const isc::datasrc::DataSourceClientPtr
+                 client(new FakeClient(info.data_src_client_ != NULL ?
+                                       info.data_src_client_ :
+                                       info.cache_.get(),
+                                       throw_when, isc_exception, fake_rrset));
+             clients_.push_back(client);
+             data_sources_.push_back(DataSourceInfo(client.get(),
+                 isc::datasrc::DataSourceClientContainerPtr(), false));
+        }
     }
     }
-
 private:
 private:
-    const boost::scoped_ptr<isc::datasrc::DataSourceClient> client_;
+    const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
+    vector<isc::datasrc::DataSourceClientPtr> clients_;
 };
 };
 
 
 } // end anonymous namespace for throwing proxy classes
 } // end anonymous namespace for throwing proxy classes
@@ -1378,13 +1423,11 @@ TEST_F(AuthSrvTest,
     )
     )
 {
 {
     // Set real inmem client to proxy
     // Set real inmem client to proxy
-    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
-    EXPECT_TRUE(server.hasInMemoryClient());
-
-    isc::datasrc::DataSourceClientContainerPtr fake_client_container(
-        new FakeContainer(server.getInMemoryClientContainer(rrclass),
-                          THROW_NEVER, false));
-    server.setInMemoryClient(rrclass, fake_client_container);
+    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
+    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        list(new FakeList(server.getClientList(RRClass::IN()), THROW_NEVER,
+                          false));
+    server.setClientList(RRClass::IN(), list);
 
 
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1402,21 +1445,15 @@ TEST_F(AuthSrvTest,
 // If non null rrset is given, it will be passed to the proxy so it can
 // If non null rrset is given, it will be passed to the proxy so it can
 // return some faked response.
 // return some faked response.
 void
 void
-setupThrow(AuthSrv* server, const char *config, ThrowWhen throw_when,
-           bool isc_exception, ConstRRsetPtr rrset = ConstRRsetPtr())
+setupThrow(AuthSrv* server, ThrowWhen throw_when, bool isc_exception,
+           ConstRRsetPtr rrset = ConstRRsetPtr())
 {
 {
-    // Set real inmem client to proxy
-    updateConfig(server, config, true);
+    updateInMemory(server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
 
-    // Set it to throw on findZone(), this should result in
-    // SERVFAIL on any exception
-    isc::datasrc::DataSourceClientContainerPtr fake_client_container(
-        new FakeContainer(
-            server->getInMemoryClientContainer(isc::dns::RRClass::IN()),
-            throw_when, isc_exception, rrset));
-
-    ASSERT_TRUE(server->hasInMemoryClient());
-    server->setInMemoryClient(isc::dns::RRClass::IN(), fake_client_container);
+    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        list(new FakeList(server->getClientList(RRClass::IN()), throw_when,
+                          isc_exception, rrset));
+    server->setClientList(RRClass::IN(), list);
 }
 }
 
 
 TEST_F(AuthSrvTest,
 TEST_F(AuthSrvTest,
@@ -1439,11 +1476,11 @@ TEST_F(AuthSrvTest,
                                              RRClass::IN(), RRType::TXT());
                                              RRClass::IN(), RRType::TXT());
     for (ThrowWhen* when(throws); *when != THROW_NEVER; ++when) {
     for (ThrowWhen* when(throws); *when != THROW_NEVER; ++when) {
         createRequestPacket(request_message, IPPROTO_UDP);
         createRequestPacket(request_message, IPPROTO_UDP);
-        setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, true);
+        setupThrow(&server, *when, true);
         processAndCheckSERVFAIL();
         processAndCheckSERVFAIL();
         // To be sure, check same for non-isc-exceptions
         // To be sure, check same for non-isc-exceptions
         createRequestPacket(request_message, IPPROTO_UDP);
         createRequestPacket(request_message, IPPROTO_UDP);
-        setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, false);
+        setupThrow(&server, *when, false);
         processAndCheckSERVFAIL();
         processAndCheckSERVFAIL();
     }
     }
 }
 }
@@ -1459,7 +1496,7 @@ TEST_F(AuthSrvTest,
     )
     )
 {
 {
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
-    setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_AT_GET_CLASS, true);
+    setupThrow(&server, THROW_AT_GET_CLASS, true);
 
 
     // getClass is not called so it should just answer
     // getClass is not called so it should just answer
     server.processMessage(*io_message, *parse_message, *response_obuffer,
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1483,8 +1520,7 @@ TEST_F(AuthSrvTest,
     ConstRRsetPtr empty_rrset(new RRset(Name("foo.example"),
     ConstRRsetPtr empty_rrset(new RRset(Name("foo.example"),
                                         RRClass::IN(), RRType::TXT(),
                                         RRClass::IN(), RRType::TXT(),
                                         RRTTL(0)));
                                         RRTTL(0)));
-    setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_NEVER, true,
-               empty_rrset);
+    setupThrow(&server, THROW_NEVER, true, empty_rrset);
 
 
     // Repeat the query processing two times.  Due to the faked RRset,
     // Repeat the query processing two times.  Due to the faked RRset,
     // toWire() should throw, and it should result in SERVFAIL.
     // toWire() should throw, and it should result in SERVFAIL.
@@ -1627,7 +1663,7 @@ TEST_F(AuthSrvTest, DDNSForwardPushFail) {
 }
 }
 
 
 TEST_F(AuthSrvTest, DDNSForwardClose) {
 TEST_F(AuthSrvTest, DDNSForwardClose) {
-    scoped_ptr<AuthSrv> tmp_server(new AuthSrv(true, xfrout, ddns_forwarder));
+    scoped_ptr<AuthSrv> tmp_server(new AuthSrv(xfrout, ddns_forwarder));
     tmp_server->createDDNSForwarder();
     tmp_server->createDDNSForwarder();
     UnitTestUtil::createRequestMessage(request_message, Opcode::UPDATE(),
     UnitTestUtil::createRequestMessage(request_message, Opcode::UPDATE(),
                                        default_qid, Name("example.com"),
                                        default_qid, Name("example.com"),
@@ -1660,7 +1696,7 @@ TEST_F(AuthSrvTest, DDNSForwardCreateDestroy) {
     // that the ddns_forwarder is connected when the 'start_ddns_forwarder'
     // that the ddns_forwarder is connected when the 'start_ddns_forwarder'
     // command has been sent, and that it is no longer connected and auth
     // command has been sent, and that it is no longer connected and auth
     // returns NOTIMP after the stop_ddns_forwarding command is sent.
     // returns NOTIMP after the stop_ddns_forwarding command is sent.
-    scoped_ptr<AuthSrv> tmp_server(new AuthSrv(true, xfrout, ddns_forwarder));
+    scoped_ptr<AuthSrv> tmp_server(new AuthSrv(xfrout, ddns_forwarder));
 
 
     // Prepare update message to send
     // Prepare update message to send
     UnitTestUtil::createRequestMessage(request_message, Opcode::UPDATE(),
     UnitTestUtil::createRequestMessage(request_message, Opcode::UPDATE(),
@@ -1724,4 +1760,36 @@ TEST_F(AuthSrvTest, DDNSForwardCreateDestroy) {
                 Opcode::UPDATE().getCode(), QR_FLAG, 0, 0, 0, 0);
                 Opcode::UPDATE().getCode(), QR_FLAG, 0, 0, 0, 0);
 }
 }
 
 
+// Check the client list accessors
+TEST_F(AuthSrvTest, clientList) {
+    // The lists don't exist. Therefore, the list of RRClasses is empty.
+    // We also have no IN list.
+    EXPECT_TRUE(server.getClientListClasses().empty());
+    EXPECT_EQ(boost::shared_ptr<const isc::datasrc::ClientList>(),
+              server.getClientList(RRClass::IN()));
+    // Put something in.
+    const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        list(new isc::datasrc::ConfigurableClientList(RRClass::IN()));
+    const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        list2(new isc::datasrc::ConfigurableClientList(RRClass::CH()));
+    server.setClientList(RRClass::IN(), list);
+    server.setClientList(RRClass::CH(), list2);
+    // There are two things in the list and they are IN and CH
+    vector<RRClass> classes(server.getClientListClasses());
+    ASSERT_EQ(2, classes.size());
+    EXPECT_EQ(RRClass::IN(), classes[0]);
+    EXPECT_EQ(RRClass::CH(), classes[1]);
+    // And the lists can be retrieved.
+    EXPECT_EQ(list, server.getClientList(RRClass::IN()));
+    EXPECT_EQ(list2, server.getClientList(RRClass::CH()));
+    // Remove one of them
+    server.setClientList(RRClass::CH(),
+        boost::shared_ptr<isc::datasrc::ConfigurableClientList>());
+    // This really got deleted, including the class.
+    classes = server.getClientListClasses();
+    ASSERT_EQ(1, classes.size());
+    EXPECT_EQ(RRClass::IN(), classes[0]);
+    EXPECT_EQ(list, server.getClientList(RRClass::IN()));
+}
+
 }
 }

+ 78 - 185
src/bin/auth/tests/command_unittest.cc

@@ -19,6 +19,7 @@
 #include <auth/auth_srv.h>
 #include <auth/auth_srv.h>
 #include <auth/auth_config.h>
 #include <auth/auth_config.h>
 #include <auth/command.h>
 #include <auth/command.h>
+#include <auth/datasrc_configurator.h>
 
 
 #include <dns/name.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <dns/rrclass.h>
@@ -62,14 +63,16 @@ namespace {
 class AuthCommandTest : public ::testing::Test {
 class AuthCommandTest : public ::testing::Test {
 protected:
 protected:
     AuthCommandTest() :
     AuthCommandTest() :
-        server_(false, xfrout_, ddns_forwarder_),
+        server_(xfrout_, ddns_forwarder_),
         rcode_(-1),
         rcode_(-1),
         expect_rcode_(0),
         expect_rcode_(0),
         itimer_(server_.getIOService())
         itimer_(server_.getIOService())
     {
     {
         server_.setStatisticsSession(&statistics_session_);
         server_.setStatisticsSession(&statistics_session_);
     }
     }
-    void checkAnswer(const int expected_code) {
+    void checkAnswer(const int expected_code, const char* name = "") {
+        SCOPED_TRACE(name);
+
         parseAnswer(rcode_, result_);
         parseAnswer(rcode_, result_);
         EXPECT_EQ(expected_code, rcode_) << result_->str();
         EXPECT_EQ(expected_code, rcode_) << result_->str();
     }
     }
@@ -182,18 +185,17 @@ TEST_F(AuthCommandTest, shutdownIncorrectPID) {
 // zones, and checks the zones are correctly loaded.
 // zones, and checks the zones are correctly loaded.
 void
 void
 zoneChecks(AuthSrv& server) {
 zoneChecks(AuthSrv& server) {
-    EXPECT_TRUE(server.getInMemoryClient(RRClass::IN()));
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test1.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test1.example")).finder_->
               find(Name("ns.test1.example"), RRType::A())->code);
               find(Name("ns.test1.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test1.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXRRSET, server.getClientList(RRClass::IN())->
+              find(Name("ns.test1.example")).finder_->
               find(Name("ns.test1.example"), RRType::AAAA())->code);
               find(Name("ns.test1.example"), RRType::AAAA())->code);
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test2.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test2.example")).finder_->
               find(Name("ns.test2.example"), RRType::A())->code);
               find(Name("ns.test2.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test2.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXRRSET, server.getClientList(RRClass::IN())->
+              find(Name("ns.test2.example")).finder_->
               find(Name("ns.test2.example"), RRType::AAAA())->code);
               find(Name("ns.test2.example"), RRType::AAAA())->code);
 }
 }
 
 
@@ -203,48 +205,44 @@ configureZones(AuthSrv& server) {
                         TEST_DATA_BUILDDIR "/test1.zone.copied"));
                         TEST_DATA_BUILDDIR "/test1.zone.copied"));
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR "/test2.zone.in "
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR "/test2.zone.in "
                         TEST_DATA_BUILDDIR "/test2.zone.copied"));
                         TEST_DATA_BUILDDIR "/test2.zone.copied"));
-    configureAuthServer(server, Element::fromJSON(
-                            "{\"datasources\": "
-                            " [{\"type\": \"memory\","
-                            "   \"zones\": "
-                            "[{\"origin\": \"test1.example\","
-                            "  \"file\": \""
-                               TEST_DATA_BUILDDIR "/test1.zone.copied\"},"
-                            " {\"origin\": \"test2.example\","
-                            "  \"file\": \""
-                               TEST_DATA_BUILDDIR "/test2.zone.copied\"}"
-                            "]}]}"));
+
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": {"
+        "       \"test1.example\": \"" +
+                string(TEST_DATA_BUILDDIR "/test1.zone.copied") + "\","
+        "       \"test2.example\": \"" +
+                string(TEST_DATA_BUILDDIR "/test2.zone.copied") + "\""
+        "   },"
+        "   \"cache-enable\": true"
+        "}]}"));
+
+    DataSourceConfigurator::testReconfigure(&server, config);
+
     zoneChecks(server);
     zoneChecks(server);
 }
 }
 
 
 void
 void
 newZoneChecks(AuthSrv& server) {
 newZoneChecks(AuthSrv& server) {
-    EXPECT_TRUE(server.getInMemoryClient(RRClass::IN()));
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test1.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test1.example")).finder_->
               find(Name("ns.test1.example"), RRType::A())->code);
               find(Name("ns.test1.example"), RRType::A())->code);
     // now test1.example should have ns/AAAA
     // now test1.example should have ns/AAAA
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test1.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test1.example")).finder_->
               find(Name("ns.test1.example"), RRType::AAAA())->code);
               find(Name("ns.test1.example"), RRType::AAAA())->code);
 
 
     // test2.example shouldn't change
     // test2.example shouldn't change
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test2.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test2.example")).finder_->
               find(Name("ns.test2.example"), RRType::A())->code);
               find(Name("ns.test2.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test2.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXRRSET, server.getClientList(RRClass::IN())->
+              find(Name("ns.test2.example")).finder_->
               find(Name("ns.test2.example"), RRType::AAAA())->code);
               find(Name("ns.test2.example"), RRType::AAAA())->code);
 }
 }
 
 
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadZone
-#else
-       loadZone
-#endif
-    )
-{
+TEST_F(AuthCommandTest, loadZone) {
     configureZones(server_);
     configureZones(server_);
 
 
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
@@ -269,47 +267,24 @@ TEST_F(AuthCommandTest,
 #endif
 #endif
     )
     )
 {
 {
-    const char* const SPEC_FILE = AUTH_OBJ_DIR "/auth.spec";
-
     // Prepare the database first
     // Prepare the database first
     const string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
     const string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
     const string bad_db = TEST_DATA_BUILDDIR "/does-not-exist.sqlite3";
     const string bad_db = TEST_DATA_BUILDDIR "/does-not-exist.sqlite3";
     stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
     stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
     createSQLite3DB(RRClass::IN(), Name("example.org"), test_db.c_str(), ss);
     createSQLite3DB(RRClass::IN(), Name("example.org"), test_db.c_str(), ss);
-
-    // Then store a config of the zone to the auth server
-    // This omits many config options of the auth server, but these are
-    // not read now.
-    isc::testutils::MockSession session;
-    // The session should not take care of anything or start anything, we
-    // need it only to hold the config we're going to put into it.
-    ModuleCCSession module_session(SPEC_FILE, session, NULL, NULL, false,
-                                  false);
     // This describes the data source in the configuration
     // This describes the data source in the configuration
-    const ElementPtr
-        map(Element::fromJSON("{\"datasources\": ["
-                              "  {"
-                              "    \"type\": \"memory\","
-                              "    \"zones\": ["
-                              "      {"
-                              "        \"origin\": \"example.org\","
-                              "        \"file\": \"" + test_db + "\","
-                              "        \"filetype\": \"sqlite3\""
-                              "      }"
-                              "    ]"
-                              "  }"
-                              "],"
-                              " \"database_file\": \"" + test_db + "\""
-                              "}"));
-    module_session.setLocalConfig(map);
-    server_.setConfigSession(&module_session);
-
-    server_.updateConfig(map);
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "    \"type\": \"sqlite3\","
+        "    \"params\": {\"database_file\": \"" + test_db + "\"},"
+        "    \"cache-enable\": true,"
+        "    \"cache-zones\": [\"example.org\"]"
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(&server_, config);
 
 
     // Check that the A record at www.example.org does not exist
     // Check that the A record at www.example.org does not exist
-    ASSERT_TRUE(server_.hasInMemoryClient());
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("www.example.org"), RRType::A())->code);
               find(Name("www.example.org"), RRType::A())->code);
 
 
     // Add the record to the underlying sqlite database, by loading
     // Add the record to the underlying sqlite database, by loading
@@ -328,90 +303,52 @@ TEST_F(AuthCommandTest,
     sql_updater->addRRset(*rrset);
     sql_updater->addRRset(*rrset);
     sql_updater->commit();
     sql_updater->commit();
 
 
-    // This new record is in the database now, but should not be in the
-    // memory-datasource yet, so check again
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("www.example.org"), RRType::A())->code);
               find(Name("www.example.org"), RRType::A())->code);
 
 
     // Now send the command to reload it
     // Now send the command to reload it
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON(
                                     Element::fromJSON(
                                         "{\"origin\": \"example.org\"}"));
                                         "{\"origin\": \"example.org\"}"));
-    checkAnswer(0);
+    checkAnswer(0, "Successful load");
 
 
     // And now it should be present too.
     // And now it should be present too.
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("www.example.org"), RRType::A())->code);
               find(Name("www.example.org"), RRType::A())->code);
 
 
     // Some error cases. First, the zone has no configuration. (note .com here)
     // Some error cases. First, the zone has no configuration. (note .com here)
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
         Element::fromJSON("{\"origin\": \"example.com\"}"));
         Element::fromJSON("{\"origin\": \"example.com\"}"));
-    checkAnswer(1);
+    checkAnswer(1, "example.com");
+
     // The previous zone is not hurt in any way
     // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("example.org"), RRType::SOA())->code);
               find(Name("example.org"), RRType::SOA())->code);
 
 
-    module_session.setLocalConfig(Element::fromJSON("{\"datasources\": []}"));
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"example.org\"}"));
-    checkAnswer(1);
+    const ConstElementPtr config2(Element::fromJSON("{"
+        "\"IN\": [{"
+        "    \"type\": \"sqlite3\","
+        "    \"params\": {\"database_file\": \"" + bad_db + "\"},"
+        "    \"cache-enable\": true,"
+        "    \"cache-zones\": [\"example.com\"]"
+        "}]}"));
+    EXPECT_THROW(DataSourceConfigurator::testReconfigure(&server_, config2),
+                 ConfigurableClientList::ConfigurationError);
 
 
-    // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
-              find(Name("example.org"), RRType::SOA())->code);
-    // Configure an unreadable zone. Should fail, but leave the original zone
-    // data there
-    const ElementPtr
-        mapBad(Element::fromJSON("{\"datasources\": ["
-                                 "  {"
-                                 "    \"type\": \"memory\","
-                                 "    \"zones\": ["
-                                 "      {"
-                                 "        \"origin\": \"example.org\","
-                                 "        \"file\": \"" + bad_db + "\","
-                                 "        \"filetype\": \"sqlite3\""
-                                 "      }"
-                                 "    ]"
-                                 "  }"
-                                 "]}"));
-    module_session.setLocalConfig(mapBad);
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
         Element::fromJSON("{\"origin\": \"example.com\"}"));
         Element::fromJSON("{\"origin\": \"example.com\"}"));
-    checkAnswer(1);
-    // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
-              find(Name("example.org"), RRType::SOA())->code);
+    checkAnswer(1, "Unreadable");
 
 
-    // Broken configuration (not valid against the spec)
-    const ElementPtr
-        broken(Element::fromJSON("{\"datasources\": ["
-                                 "  {"
-                                 "    \"type\": \"memory\","
-                                 "    \"zones\": [[]]"
-                                 "  }"
-                                 "]}"));
-    module_session.setLocalConfig(broken);
-    checkAnswer(1);
     // The previous zone is not hurt in any way
     // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("example.org"), RRType::SOA())->code);
               find(Name("example.org"), RRType::SOA())->code);
 }
 }
 
 
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadBrokenZone
-#else
-       loadBrokenZone
-#endif
-    )
-{
+TEST_F(AuthCommandTest, loadBrokenZone) {
     configureZones(server_);
     configureZones(server_);
 
 
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
@@ -424,14 +361,7 @@ TEST_F(AuthCommandTest,
     zoneChecks(server_);     // zone shouldn't be replaced
     zoneChecks(server_);     // zone shouldn't be replaced
 }
 }
 
 
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadUnreadableZone
-#else
-       loadUnreadableZone
-#endif
-    )
-{
+TEST_F(AuthCommandTest, loadUnreadableZone) {
     configureZones(server_);
     configureZones(server_);
 
 
     // install the zone file as unreadable
     // install the zone file as unreadable
@@ -454,82 +384,45 @@ TEST_F(AuthCommandTest, loadZoneWithoutDataSrc) {
     checkAnswer(1);
     checkAnswer(1);
 }
 }
 
 
-TEST_F(AuthCommandTest, loadSqlite3DataSrc) {
-    // For sqlite3 data source we don't have to do anything (the data source
-    // (re)loads itself automatically)
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"datasrc\": \"sqlite3\"}"));
-    checkAnswer(0);
-}
-
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadZoneInvalidParams
-#else
-       loadZoneInvalidParams
-#endif
-    )
-{
+TEST_F(AuthCommandTest, loadZoneInvalidParams) {
     configureZones(server_);
     configureZones(server_);
 
 
     // null arg
     // null arg
     result_ = execAuthServerCommand(server_, "loadzone", ElementPtr());
     result_ = execAuthServerCommand(server_, "loadzone", ElementPtr());
-    checkAnswer(1);
+    checkAnswer(1, "Null arg");
 
 
     // zone class is bogus
     // zone class is bogus
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON(
                                     Element::fromJSON(
                                         "{\"origin\": \"test1.example\","
                                         "{\"origin\": \"test1.example\","
                                         " \"class\": \"no_such_class\"}"));
                                         " \"class\": \"no_such_class\"}"));
-    checkAnswer(1);
+    checkAnswer(1, "No such class");
 
 
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON(
                                     Element::fromJSON(
                                         "{\"origin\": \"test1.example\","
                                         "{\"origin\": \"test1.example\","
                                         " \"class\": 1}"));
                                         " \"class\": 1}"));
-    checkAnswer(1);
+    checkAnswer(1, "Integral class");
 
 
-    // unsupported zone class
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"class\": \"CH\"}"));
-    checkAnswer(1);
-
-    // unsupported data source class
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"datasrc\": \"not supported\"}"));
-    checkAnswer(1);
-
-    // data source is bogus
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"datasrc\": 0}"));
-    checkAnswer(1);
 
 
     // origin is missing
     // origin is missing
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON("{}"));
                                     Element::fromJSON("{}"));
-    checkAnswer(1);
+    checkAnswer(1, "Missing origin");
 
 
     // zone doesn't exist in the data source
     // zone doesn't exist in the data source
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON("{\"origin\": \"xx\"}"));
                                     Element::fromJSON("{\"origin\": \"xx\"}"));
-    checkAnswer(1);
+    checkAnswer(1, "No such zone");
 
 
     // origin is bogus
     // origin is bogus
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON(
                                     Element::fromJSON(
                                         "{\"origin\": \"...\"}"));
                                         "{\"origin\": \"...\"}"));
-    checkAnswer(1);
+    checkAnswer(1, "Wrong name");
 
 
     result_ = execAuthServerCommand(server_, "loadzone",
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON("{\"origin\": 10}"));
                                     Element::fromJSON("{\"origin\": 10}"));
-    checkAnswer(1);
+    checkAnswer(1, "Integral name");
 }
 }
 }
 }

+ 5 - 383
src/bin/auth/tests/config_unittest.cc

@@ -54,7 +54,7 @@ protected:
     AuthConfigTest() :
     AuthConfigTest() :
         dnss_(),
         dnss_(),
         rrclass(RRClass::IN()),
         rrclass(RRClass::IN()),
-        server(true, xfrout, ddns_forwarder),
+        server(xfrout, ddns_forwarder),
         // The empty string is expected value of the parameter of
         // The empty string is expected value of the parameter of
         // requestSocket, not the app_name (there's no fallback, it checks
         // requestSocket, not the app_name (there's no fallback, it checks
         // the empty string is passed).
         // the empty string is passed).
@@ -72,32 +72,6 @@ private:
     isc::testutils::TestSocketRequestor sock_requestor_;
     isc::testutils::TestSocketRequestor sock_requestor_;
 };
 };
 
 
-TEST_F(AuthConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_datasourceConfig
-#else
-       datasourceConfig
-#endif
-    )
-{
-    // By default, we don't have any in-memory data source.
-    EXPECT_FALSE(server.hasInMemoryClient());
-    configureAuthServer(server, Element::fromJSON(
-                            "{\"datasources\": [{\"type\": \"memory\"}]}"));
-    // after successful configuration, we should have one (with empty zoneset).
-    EXPECT_TRUE(server.hasInMemoryClient());
-    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(AuthConfigTest, databaseConfig) {
-    // right now, "database_file" is handled separately, so the parser
-    // doesn't recognize it, but it shouldn't throw an exception due to that.
-    EXPECT_NO_THROW(configureAuthServer(
-                        server,
-                        Element::fromJSON(
-                            "{\"database_file\": \"should_be_ignored\"}")));
-}
-
 TEST_F(AuthConfigTest, versionConfig) {
 TEST_F(AuthConfigTest, versionConfig) {
     // make sure it does not throw on 'version'
     // make sure it does not throw on 'version'
     EXPECT_NO_THROW(configureAuthServer(
     EXPECT_NO_THROW(configureAuthServer(
@@ -106,32 +80,17 @@ TEST_F(AuthConfigTest, versionConfig) {
 }
 }
 
 
 TEST_F(AuthConfigTest, exceptionGuarantee) {
 TEST_F(AuthConfigTest, exceptionGuarantee) {
-    EXPECT_FALSE(server.hasInMemoryClient());
+    server.setStatisticsTimerInterval(1234);
+    EXPECT_EQ(1234, server.getStatisticsTimerInterval());
     // This configuration contains an invalid item, which will trigger
     // This configuration contains an invalid item, which will trigger
     // an exception.
     // an exception.
     EXPECT_THROW(configureAuthServer(
     EXPECT_THROW(configureAuthServer(
                      server,
                      server,
                      Element::fromJSON(
                      Element::fromJSON(
-                         "{\"datasources\": [{\"type\": \"memory\"}], "
-                         " \"no_such_config_var\": 1}")),
+                         "{ \"no_such_config_var\": 1}")),
                  AuthConfigError);
                  AuthConfigError);
     // The server state shouldn't change
     // The server state shouldn't change
-    EXPECT_FALSE(server.hasInMemoryClient());
-}
-
-TEST_F(AuthConfigTest, exceptionConversion) {
-    // This configuration contains a bogus RR class, which will trigger an
-    // exception from libdns++.  configureAuthServer() should convert this
-    // to AuthConfigError and rethrow the converted one.
-    EXPECT_THROW(configureAuthServer(
-                     server,
-                     Element::fromJSON(
-                         "{\"datasources\": "
-                         " [{\"type\": \"memory\","
-                         "   \"class\": \"BADCLASS\","
-                         "   \"zones\": [{\"origin\": \"example.com\","
-                         "                \"file\": \"example.zone\"}]}]}")),
-                 AuthConfigError);
+    EXPECT_EQ(1234, server.getStatisticsTimerInterval());
 }
 }
 
 
 TEST_F(AuthConfigTest, badConfig) {
 TEST_F(AuthConfigTest, badConfig) {
@@ -172,343 +131,6 @@ TEST_F(AuthConfigTest, listenAddressConfig) {
     EXPECT_EQ(DNSService::SERVER_SYNC_OK, dnss_.getUDPFdParams().at(1).options);
     EXPECT_EQ(DNSService::SERVER_SYNC_OK, dnss_.getUDPFdParams().at(1).options);
 }
 }
 
 
-class MemoryDatasrcConfigTest : public AuthConfigTest {
-protected:
-    MemoryDatasrcConfigTest() :
-        parser(createAuthConfigParser(server, "datasources"))
-    {}
-    ~MemoryDatasrcConfigTest() {
-        delete parser;
-    }
-    AuthConfigParser* parser;
-};
-
-TEST_F(MemoryDatasrcConfigTest, addZeroDataSrc) {
-    parser->build(Element::fromJSON("[]"));
-    parser->commit();
-    EXPECT_FALSE(server.hasInMemoryClient());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addEmpty
-#else
-       addEmpty
-#endif
-    )
-{
-    // By default, we don't have any in-memory data source.
-    EXPECT_FALSE(server.hasInMemoryClient());
-    parser->build(Element::fromJSON("[{\"type\": \"memory\"}]"));
-    parser->commit();
-    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addZeroZone
-#else
-       addZeroZone
-#endif
-    )
-{
-    parser->build(Element::fromJSON("[{\"type\": \"memory\","
-                                    "  \"zones\": []}]"));
-    parser->commit();
-    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addOneZone
-#else
-       addOneZone
-#endif
-    )
-{
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-    // Check it actually loaded something
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(rrclass)->findZone(
-        Name("ns.example.com.")).zone_finder->find(Name("ns.example.com."),
-        RRType::A())->code);
-}
-
-// This test uses dynamic load of a data source module, and won't work when
-// statically linked.
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addOneWithFiletypeSQLite3
-#else
-       addOneWithFiletypeSQLite3
-#endif
-    )
-{
-    const string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
-    stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
-    createSQLite3DB(rrclass, Name("example.org"), test_db.c_str(), ss);
-
-    // In-memory with an SQLite3 data source as the backend.
-    parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.org\","
-                      "               \"file\": \""
-                      + test_db +  "\","
-                      "               \"filetype\": \"sqlite3\"}]}]"));
-    parser->commit();
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-
-    // Failure case: the specified zone doesn't exist in the DB file.
-    delete parser;
-    parser = createAuthConfigParser(server, "datasources");
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"origin\": \"example.com\","
-                         "               \"file\": \""
-                         + test_db +  "\","
-                         "               \"filetype\": \"sqlite3\"}]}]")),
-                 DataSourceError);
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addOneWithFiletypeText
-#else
-       addOneWithFiletypeText
-#endif
-    )
-{
-    // Explicitly specifying "text" is okay.
-    parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \""
-                      TEST_DATA_DIR "/example.zone\","
-                      "               \"filetype\": \"text\"}]}]"));
-    parser->commit();
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addMultiZones
-#else
-       addMultiZones
-#endif
-    )
-{
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"},"
-                      "              {\"origin\": \"example.org\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.org.zone\"},"
-                      "              {\"origin\": \"example.net\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.net.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(3, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_replace
-#else
-       replace
-#endif
-    )
-{
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-    EXPECT_EQ(isc::datasrc::result::SUCCESS,
-              server.getInMemoryClient(rrclass)->findZone(
-                  Name("example.com")).code);
-
-    // create a new parser, and install a new set of configuration.  It
-    // should replace the old one.
-    delete parser;
-    parser = createAuthConfigParser(server, "datasources"); 
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.org\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.org.zone\"},"
-                      "              {\"origin\": \"example.net\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.net.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(2, server.getInMemoryClient(rrclass)->getZoneCount());
-    EXPECT_EQ(isc::datasrc::result::NOTFOUND,
-              server.getInMemoryClient(rrclass)->findZone(
-                  Name("example.com")).code);
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_exception
-#else
-       exception
-#endif
-    )
-{
-    // Load a zone
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-    EXPECT_EQ(isc::datasrc::result::SUCCESS,
-              server.getInMemoryClient(rrclass)->findZone(
-                  Name("example.com")).code);
-
-    // create a new parser, and try to load something. It will throw,
-    // the given master file should not exist
-    delete parser;
-    parser = createAuthConfigParser(server, "datasources");
-    EXPECT_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.org\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.org.zone\"},"
-                      "              {\"origin\": \"example.net\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/nonexistent.zone\"}]}]")),
-                 isc::datasrc::DataSourceError);
-    // As that one throwed exception, it is not expected from us to
-    // commit it
-
-    // The original should be untouched
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-    EXPECT_EQ(isc::datasrc::result::SUCCESS,
-              server.getInMemoryClient(rrclass)->findZone(
-                  Name("example.com")).code);
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_remove
-#else
-       remove
-#endif
-    )
-{
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-
-    delete parser;
-    parser = createAuthConfigParser(server, "datasources"); 
-    EXPECT_NO_THROW(parser->build(Element::fromJSON("[]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_FALSE(server.hasInMemoryClient());
-}
-
-TEST_F(MemoryDatasrcConfigTest, addDuplicateZones) {
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"origin\": \"example.com\","
-                         "               \"file\": \"" TEST_DATA_DIR
-                         "/example.zone\"},"
-                         "              {\"origin\": \"example.com\","
-                         "               \"file\": \"" TEST_DATA_DIR
-                         "/example.com.zone\"}]}]")),
-                 DataSourceError);
-}
-
-TEST_F(MemoryDatasrcConfigTest, addBadZone) {
-    // origin and file are missing
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{}]}]")),
-                 DataSourceError);
-
-    // origin is missing
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"file\": \"example.zone\"}]}]")),
-                 DataSourceError);
-
-    // file is missing
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"origin\": \"example.com\"}]}]")),
-                 DataSourceError);
-
-    // missing zone file
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"origin\": \"example.com\"}]}]")),
-                 DataSourceError);
-
-    // bogus origin name
-    EXPECT_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example..com\","
-                      "               \"file\": \"example.zone\"}]}]")),
-                 DataSourceError);
-
-    // bogus RR class name
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"class\": \"BADCLASS\","
-                         "  \"zones\": [{\"origin\": \"example.com\","
-                         "               \"file\": \"example.zone\"}]}]")),
-                 InvalidRRClass);
-
-    // valid RR class, but not currently supported
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"class\": \"CH\","
-                         "  \"zones\": [{\"origin\": \"example.com\","
-                         "               \"file\": \"example.zone\"}]}]")),
-                 isc::InvalidParameter);
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_badDatasrcType
-#else
-       badDatasrcType
-#endif
-    )
-{
-    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": \"badsrc\"}]")),
-                 AuthConfigError);
-    EXPECT_THROW(parser->build(Element::fromJSON("[{\"notype\": \"memory\"}]")),
-                 AuthConfigError);
-    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": 1}]")),
-                                      isc::data::TypeError);
-    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": \"memory\"},"
-                                                 " {\"type\": \"memory\"}]")),
-                 AuthConfigError);
-}
-
 class StatisticsIntervalConfigTest : public AuthConfigTest {
 class StatisticsIntervalConfigTest : public AuthConfigTest {
 protected:
 protected:
     StatisticsIntervalConfigTest() :
     StatisticsIntervalConfigTest() :

+ 298 - 0
src/bin/auth/tests/datasrc_configurator_unittest.cc

@@ -0,0 +1,298 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <auth/datasrc_configurator.h>
+
+#include <config/tests/fake_session.h>
+#include <config/ccsession.h>
+
+#include <gtest/gtest.h>
+#include <memory>
+#include <boost/shared_ptr.hpp>
+
+using namespace isc;
+using namespace isc::cc;
+using namespace isc::config;
+using namespace isc::data;
+using namespace isc::dns;
+using namespace std;
+using namespace boost;
+
+namespace {
+
+class DatasrcConfiguratorTest;
+
+class FakeList {
+public:
+    FakeList(const RRClass&) :
+        configuration_(new ListElement)
+    {}
+    void configure(const ConstElementPtr& configuration, bool allow_cache) {
+        EXPECT_TRUE(allow_cache);
+        conf_ = configuration->get(0)->get("type")->stringValue();
+        configuration_ = configuration;
+    }
+    const string& getConf() const {
+        return (conf_);
+    }
+    ConstElementPtr getConfiguration() const {
+        return (configuration_);
+    }
+private:
+    string conf_;
+    ConstElementPtr configuration_;
+};
+
+typedef shared_ptr<FakeList> ListPtr;
+
+// We use the test fixture as both parameters, this makes it possible
+// to easily fake all needed methods and look that they were called.
+typedef DataSourceConfiguratorGeneric<DatasrcConfiguratorTest,
+        FakeList> Configurator;
+
+class DatasrcConfiguratorTest : public ::testing::Test {
+public:
+    // These pretend to be the server
+    ListPtr getClientList(const RRClass& rrclass) {
+        log_ += "get " + rrclass.toText() + "\n";
+        return (lists_[rrclass]);
+    }
+    void setClientList(const RRClass& rrclass, const ListPtr& list) {
+        log_ += "set " + rrclass.toText() + " " +
+            (list ? list->getConf() : "") + "\n";
+        lists_[rrclass] = list;
+    }
+    vector<RRClass> getClientListClasses() const {
+        vector<RRClass> result;
+        for (std::map<RRClass, ListPtr>::const_iterator it(lists_.begin());
+             it != lists_.end(); ++it) {
+            result.push_back(it->first);
+        }
+        return (result);
+    }
+protected:
+    DatasrcConfiguratorTest() :
+        session(ElementPtr(new ListElement), ElementPtr(new ListElement),
+                ElementPtr(new ListElement)),
+        specfile(string(TEST_OWN_DATA_DIR) + "/spec.spec")
+    {
+        initSession();
+    }
+    void initSession() {
+        session.getMessages()->add(createAnswer());
+        mccs.reset(new ModuleCCSession(specfile, session, NULL, NULL, false,
+                                       false));
+    }
+    void TearDown() {
+        // Make sure no matter what we did, it is cleaned up.
+        Configurator::cleanup();
+    }
+    void init(const ElementPtr& config = ElementPtr()) {
+        session.getMessages()->
+            add(createAnswer(0,
+                             moduleSpecFromFile(string(PLUGIN_DATA_PATH) +
+                                                "/datasrc.spec").
+                             getFullSpec()));
+        if (config) {
+            session.getMessages()->add(createAnswer(0, config));
+        } else {
+            session.getMessages()->
+                add(createAnswer(0, ElementPtr(new MapElement)));
+        }
+        Configurator::init(mccs.get(), this);
+    }
+    void SetUp() {
+        init();
+    }
+    ElementPtr buildConfig(const string& config) const {
+        const ElementPtr internal(Element::fromJSON(config));
+        const ElementPtr external(Element::fromJSON("{\"version\": 1}"));
+        external->set("classes", internal);
+        return (external);
+    }
+    void initializeINList() {
+        const ElementPtr
+            config(buildConfig("{\"IN\": [{\"type\": \"xxx\"}]}"));
+        session.addMessage(createCommand("config_update", config), "data_sources",
+                           "*");
+        mccs->checkCommand();
+        // Check it called the correct things (check that there's no IN yet and
+        // set a new one.
+        EXPECT_EQ("get IN\nset IN xxx\n", log_);
+        EXPECT_EQ(1, lists_.size());
+    }
+    FakeSession session;
+    auto_ptr<ModuleCCSession> mccs;
+    const string specfile;
+    std::map<RRClass, ListPtr> lists_;
+    string log_;
+};
+
+// Check the initialization (and cleanup)
+TEST_F(DatasrcConfiguratorTest, initialization) {
+    // It can't be initialized again
+    EXPECT_THROW(init(), InvalidOperation);
+    EXPECT_TRUE(session.haveSubscription("data_sources", "*"));
+    // Deinitialize to make the tests reasonable
+    Configurator::cleanup();
+    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
+    // We can't reconfigure now (not even manually)
+    EXPECT_THROW(Configurator::reconfigure(ElementPtr(new MapElement())),
+                 InvalidOperation);
+    // If one of them is NULL, it does not work
+    EXPECT_THROW(Configurator::init(NULL, this), InvalidParameter);
+    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
+    EXPECT_THROW(Configurator::init(mccs.get(), NULL), InvalidParameter);
+    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
+    // But we can initialize it again now
+    EXPECT_NO_THROW(init());
+    EXPECT_TRUE(session.haveSubscription("data_sources", "*"));
+}
+
+// Push there a configuration with a single list.
+TEST_F(DatasrcConfiguratorTest, createList) {
+    initializeINList();
+}
+
+TEST_F(DatasrcConfiguratorTest, modifyList) {
+    // First, initialize the list
+    initializeINList();
+    // And now change the configuration of the list
+    const ElementPtr
+        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}]}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    log_ = "";
+    mccs->checkCommand();
+    // This one does not set
+    EXPECT_EQ("get IN\n", log_);
+    // But this should contain the yyy configuration
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ(1, lists_.size());
+}
+
+// Check we can have multiple lists at once
+TEST_F(DatasrcConfiguratorTest, multiple) {
+    const ElementPtr
+        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}], "
+                                 "\"CH\": [{\"type\": \"xxx\"}]}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    mccs->checkCommand();
+    // We have set commands for both classes.
+    EXPECT_EQ("get CH\nset CH xxx\nget IN\nset IN yyy\n", log_);
+    // We should have both there
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
+    EXPECT_EQ(2, lists_.size());
+}
+
+// Check we can add another one later and the old one does not get
+// overwritten.
+//
+// It's almost like above, but we initialize first with single-list
+// config.
+TEST_F(DatasrcConfiguratorTest, updateAdd) {
+    initializeINList();
+    const ElementPtr
+        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}], "
+                           "\"CH\": [{\"type\": \"xxx\"}]}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    log_ = "";
+    mccs->checkCommand();
+    // The CH is set, IN not
+    EXPECT_EQ("get CH\nset CH xxx\nget IN\n", log_);
+    // But this should contain the yyy configuration
+    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ(2, lists_.size());
+}
+
+// We delete a class list in this test.
+TEST_F(DatasrcConfiguratorTest, updateDelete) {
+    initializeINList();
+    const ElementPtr
+        config(buildConfig("{}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    log_ = "";
+    mccs->checkCommand();
+    EXPECT_EQ("get IN\nset IN \n", log_);
+    EXPECT_FALSE(lists_[RRClass::IN()]);
+    // In real auth server, the NULL one would be removed. However, we just
+    // store it, so the IN bucket is still in there. This checks there's nothing
+    // else.
+    EXPECT_EQ(1, lists_.size());
+}
+
+// Check that we can rollback an addition if something else fails
+TEST_F(DatasrcConfiguratorTest, rollbackAddition) {
+    initializeINList();
+    // The configuration is wrong. However, the CH one will get done first.
+    const ElementPtr
+        config(buildConfig("{\"IN\": [{\"type\": 13}], "
+                           "\"CH\": [{\"type\": \"xxx\"}]}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    log_ = "";
+    // It does not throw, as it is handled in the ModuleCCSession.
+    // Throwing from the reconfigure is checked in other tests.
+    EXPECT_NO_THROW(mccs->checkCommand());
+    // Anyway, the result should not contain CH now and the original IN should
+    // be there.
+    EXPECT_EQ("xxx", lists_[RRClass::IN()]->getConf());
+    EXPECT_FALSE(lists_[RRClass::CH()]);
+}
+
+// Check that we can rollback a deletion if something else fails
+TEST_F(DatasrcConfiguratorTest, rollbackDeletion) {
+    initializeINList();
+    // Put the CH there
+    const ElementPtr
+        config1(Element::fromJSON("{\"IN\": [{\"type\": \"yyy\"}], "
+                                  "\"CH\": [{\"type\": \"xxx\"}]}"));
+    Configurator::reconfigure(config1);
+    const ElementPtr
+        config2(Element::fromJSON("{\"IN\": [{\"type\": 13}]}"));
+    // This would delete CH. However, the IN one fails.
+    // As the deletions happen after the additions/settings
+    // and there's no known way to cause an exception during the
+    // deletions, it is not a true rollback, but the result should
+    // be the same.
+    EXPECT_THROW(Configurator::reconfigure(config2), TypeError);
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
+}
+
+// Check that we can roll back configuration change if something
+// fails later on.
+TEST_F(DatasrcConfiguratorTest, rollbackConfiguration) {
+    initializeINList();
+    // Put the CH there
+    const ElementPtr
+        config1(Element::fromJSON("{\"IN\": [{\"type\": \"yyy\"}], "
+                                  "\"CH\": [{\"type\": \"xxx\"}]}"));
+    Configurator::reconfigure(config1);
+    // Now, the CH happens first. But nevertheless, it should be
+    // restored to the previoeus version.
+    const ElementPtr
+        config2(Element::fromJSON("{\"IN\": [{\"type\": 13}], "
+                                  "\"CH\": [{\"type\": \"yyy\"}]}"));
+    EXPECT_THROW(Configurator::reconfigure(config2), TypeError);
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
+}
+
+}

+ 122 - 86
src/bin/auth/tests/query_unittest.cc

@@ -32,6 +32,7 @@
 #include <dns/rdataclass.h>
 #include <dns/rdataclass.h>
 
 
 #include <datasrc/memory_datasrc.h>
 #include <datasrc/memory_datasrc.h>
+#include <datasrc/client_list.h>
 
 
 #include <auth/query.h>
 #include <auth/query.h>
 
 
@@ -48,6 +49,37 @@ using namespace isc::testutils;
 
 
 namespace {
 namespace {
 
 
+// Simple wrapper for a sincle data source client.
+// The list simply delegates all the answers to the single
+// client.
+class SingletonList : public ClientList {
+public:
+    SingletonList(DataSourceClient& client) :
+        client_(client)
+    {}
+    virtual FindResult find(const Name& zone, bool exact, bool) const {
+        DataSourceClient::FindResult result(client_.findZone(zone));
+        // We don't complicate the tests with real life keepers, but we
+        // need to put something to the parameter anyway.
+        const boost::shared_ptr<ClientList::FindResult::LifeKeeper> keeper;
+        switch (result.code) {
+            case result::SUCCESS:
+                return (FindResult(&client_, result.zone_finder, true,
+                                   keeper));
+            case result::PARTIALMATCH:
+                if (!exact) {
+                    return (FindResult(&client_, result.zone_finder, false,
+                                       keeper));
+                }
+            default:
+                return (FindResult());
+        }
+    }
+private:
+    DataSourceClient& client_;
+};
+
+
 // This is the content of the mock zone (see below).
 // This is the content of the mock zone (see below).
 // It's a sequence of textual RRs that is supposed to be parsed by
 // It's a sequence of textual RRs that is supposed to be parsed by
 // dns::masterLoad().  Some of the RRs are also used as the expected
 // dns::masterLoad().  Some of the RRs are also used as the expected
@@ -875,6 +907,7 @@ MockZoneFinder::find(const Name& name, const RRType& type,
 class QueryTest : public ::testing::Test {
 class QueryTest : public ::testing::Test {
 protected:
 protected:
     QueryTest() :
     QueryTest() :
+        list(memory_client),
         qname(Name("www.example.com")), qclass(RRClass::IN()),
         qname(Name("www.example.com")), qclass(RRClass::IN()),
         qtype(RRType::A()), response(Message::RENDER),
         qtype(RRType::A()), response(Message::RENDER),
         qid(response.getQid()), query_code(Opcode::QUERY().getCode()),
         qid(response.getQid()), query_code(Opcode::QUERY().getCode()),
@@ -898,6 +931,8 @@ protected:
     // (originally named MemoryDataSrc) and was tested with it, so we keep
     // (originally named MemoryDataSrc) and was tested with it, so we keep
     // it like this for now.
     // it like this for now.
     InMemoryClient memory_client;
     InMemoryClient memory_client;
+    // A wrapper client list to wrap the single data source.
+    SingletonList list;
     const Name qname;
     const Name qname;
     const RRClass qclass;
     const RRClass qclass;
     const RRType qtype;
     const RRType qtype;
@@ -949,20 +984,21 @@ TEST_F(QueryTest, noZone) {
     // There's no zone in the memory datasource.  So the response should have
     // There's no zone in the memory datasource.  So the response should have
     // REFUSED.
     // REFUSED.
     InMemoryClient empty_memory_client;
     InMemoryClient empty_memory_client;
-    EXPECT_NO_THROW(query.process(empty_memory_client, qname, qtype,
+    SingletonList empty_list(empty_memory_client);
+    EXPECT_NO_THROW(query.process(empty_list, qname, qtype,
                                   response));
                                   response));
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 }
 
 
 TEST_F(QueryTest, exactMatch) {
 TEST_F(QueryTest, exactMatch) {
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
     // find match rrset
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
 }
 }
 
 
 TEST_F(QueryTest, exactMatchMultipleQueries) {
 TEST_F(QueryTest, exactMatchMultipleQueries) {
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
     // find match rrset
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
@@ -971,7 +1007,7 @@ TEST_F(QueryTest, exactMatchMultipleQueries) {
     response.clear(isc::dns::Message::RENDER);
     response.clear(isc::dns::Message::RENDER);
     response.setRcode(Rcode::NOERROR());
     response.setRcode(Rcode::NOERROR());
     response.setOpcode(Opcode::QUERY());
     response.setOpcode(Opcode::QUERY());
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
     // find match rrset
     // find match rrset
     SCOPED_TRACE("Second query");
     SCOPED_TRACE("Second query");
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -982,7 +1018,7 @@ TEST_F(QueryTest, exactMatchIgnoreSIG) {
     // Check that we do not include the RRSIG when not requested even when
     // Check that we do not include the RRSIG when not requested even when
     // we receive it from the data source.
     // we receive it from the data source.
     mock_finder->setIncludeRRSIGAnyway(true);
     mock_finder->setIncludeRRSIGAnyway(true);
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
     // find match rrset
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
@@ -990,7 +1026,7 @@ TEST_F(QueryTest, exactMatchIgnoreSIG) {
 
 
 TEST_F(QueryTest, dnssecPositive) {
 TEST_F(QueryTest, dnssecPositive) {
     // Just like exactMatch, but the signatures should be included as well
     // Just like exactMatch, but the signatures should be included as well
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response,
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response,
                                   true));
                                   true));
     // find match rrset
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 4, 6,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 4, 6,
@@ -1009,7 +1045,7 @@ TEST_F(QueryTest, dnssecPositive) {
 TEST_F(QueryTest, exactAddrMatch) {
 TEST_F(QueryTest, exactAddrMatch) {
     // find match rrset, omit additional data which has already been provided
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("noglue.example.com"),
                                   Name("noglue.example.com"),
                                   qtype, response));
                                   qtype, response));
 
 
@@ -1022,7 +1058,7 @@ TEST_F(QueryTest, exactAddrMatch) {
 TEST_F(QueryTest, apexNSMatch) {
 TEST_F(QueryTest, apexNSMatch) {
     // find match rrset, omit authority data which has already been provided
     // find match rrset, omit authority data which has already been provided
     // in the answer section from the authority section.
     // in the answer section from the authority section.
-    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("example.com"),
                                   RRType::NS(), response));
                                   RRType::NS(), response));
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 0, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 0, 3,
@@ -1033,7 +1069,7 @@ TEST_F(QueryTest, apexNSMatch) {
 TEST_F(QueryTest, exactAnyMatch) {
 TEST_F(QueryTest, exactAnyMatch) {
     // find match rrset, omit additional data which has already been provided
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(memory_client, Name("noglue.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("noglue.example.com"),
                                   RRType::ANY(), response));
                                   RRType::ANY(), response));
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 3, 2,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 3, 2,
@@ -1047,7 +1083,7 @@ TEST_F(QueryTest, exactAnyMatch) {
 TEST_F(QueryTest, apexAnyMatch) {
 TEST_F(QueryTest, apexAnyMatch) {
     // find match rrset, omit additional data which has already been provided
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("example.com"),
                                   RRType::ANY(), response));
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 5, 0, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 5, 0, 3,
                   (string(soa_txt) + string(zone_ns_txt) +
                   (string(soa_txt) + string(zone_ns_txt) +
@@ -1056,7 +1092,7 @@ TEST_F(QueryTest, apexAnyMatch) {
 }
 }
 
 
 TEST_F(QueryTest, mxANYMatch) {
 TEST_F(QueryTest, mxANYMatch) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("mx.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("mx.example.com"),
                                   RRType::ANY(), response));
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 3, 4,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 3, 4,
                   (string(mx_txt) + string(nsec_mx_txt)).c_str(), zone_ns_txt,
                   (string(mx_txt) + string(nsec_mx_txt)).c_str(), zone_ns_txt,
@@ -1064,14 +1100,14 @@ TEST_F(QueryTest, mxANYMatch) {
 }
 }
 
 
 TEST_F(QueryTest, glueANYMatch) {
 TEST_F(QueryTest, glueANYMatch) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("delegation.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("delegation.example.com"),
                                   RRType::ANY(), response));
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
     responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
                   NULL, delegation_txt, ns_addrs_txt);
                   NULL, delegation_txt, ns_addrs_txt);
 }
 }
 
 
 TEST_F(QueryTest, nodomainANY) {
 TEST_F(QueryTest, nodomainANY) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("nxdomain.example.com"),
                                   RRType::ANY(), response));
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
                   NULL, soa_txt, NULL, mock_finder->getOrigin());
                   NULL, soa_txt, NULL, mock_finder->getOrigin());
@@ -1084,13 +1120,13 @@ TEST_F(QueryTest, noApexNS) {
     // Disable apex NS record
     // Disable apex NS record
     mock_finder->setApexNSFlag(false);
     mock_finder->setApexNSFlag(false);
 
 
-    EXPECT_THROW(query.process(memory_client, Name("noglue.example.com"), qtype,
+    EXPECT_THROW(query.process(list, Name("noglue.example.com"), qtype,
                                response), Query::NoApexNS);
                                response), Query::NoApexNS);
     // We don't look into the response, as it threw
     // We don't look into the response, as it threw
 }
 }
 
 
 TEST_F(QueryTest, delegation) {
 TEST_F(QueryTest, delegation) {
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("delegation.example.com"),
                                   Name("delegation.example.com"),
                                   qtype, response));
                                   qtype, response));
 
 
@@ -1102,7 +1138,7 @@ TEST_F(QueryTest, delegationWithDNSSEC) {
     // Similar to the previous one, but with requesting DNSSEC.
     // Similar to the previous one, but with requesting DNSSEC.
     // In this case the parent zone would behave as unsigned, so the result
     // In this case the parent zone would behave as unsigned, so the result
     // should be just like non DNSSEC delegation.
     // should be just like non DNSSEC delegation.
-    query.process(memory_client, Name("www.nosec-delegation.example.com"),
+    query.process(list, Name("www.nosec-delegation.example.com"),
                   qtype, response, true);
                   qtype, response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), 0, 0, 1, 0,
     responseCheck(response, Rcode::NOERROR(), 0, 0, 1, 0,
@@ -1110,7 +1146,7 @@ TEST_F(QueryTest, delegationWithDNSSEC) {
 }
 }
 
 
 TEST_F(QueryTest, secureDelegation) {
 TEST_F(QueryTest, secureDelegation) {
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("foo.signed-delegation.example.com"),
                                   Name("foo.signed-delegation.example.com"),
                                   qtype, response, true));
                                   qtype, response, true));
 
 
@@ -1125,7 +1161,7 @@ TEST_F(QueryTest, secureDelegation) {
 }
 }
 
 
 TEST_F(QueryTest, secureUnsignedDelegation) {
 TEST_F(QueryTest, secureUnsignedDelegation) {
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("foo.unsigned-delegation.example.com"),
                                   Name("foo.unsigned-delegation.example.com"),
                                   qtype, response, true));
                                   qtype, response, true));
 
 
@@ -1146,7 +1182,7 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3) {
     mock_finder->setNSEC3Flag(true);
     mock_finder->setNSEC3Flag(true);
     mock_finder->addRecord(unsigned_delegation_nsec3_txt);
     mock_finder->addRecord(unsigned_delegation_nsec3_txt);
 
 
-    query.process(memory_client,
+    query.process(list,
                   Name("foo.unsigned-delegation.example.com"),
                   Name("foo.unsigned-delegation.example.com"),
                   qtype, response, true);
                   qtype, response, true);
 
 
@@ -1165,7 +1201,7 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) {
     // Similar to the previous case, but the delegation is an optout.
     // Similar to the previous case, but the delegation is an optout.
     mock_finder->setNSEC3Flag(true);
     mock_finder->setNSEC3Flag(true);
 
 
-    query.process(memory_client,
+    query.process(list,
                   Name("foo.unsigned-delegation.example.com"),
                   Name("foo.unsigned-delegation.example.com"),
                   qtype, response, true);
                   qtype, response, true);
 
 
@@ -1190,20 +1226,20 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) {
 TEST_F(QueryTest, badSecureDelegation) {
 TEST_F(QueryTest, badSecureDelegation) {
     // Test whether exception is raised if DS query at delegation results in
     // Test whether exception is raised if DS query at delegation results in
     // something different than SUCCESS or NXRRSET
     // something different than SUCCESS or NXRRSET
-    EXPECT_THROW(query.process(memory_client,
+    EXPECT_THROW(query.process(list,
                                Name("bad-delegation.example.com"),
                                Name("bad-delegation.example.com"),
                                qtype, response, true), Query::BadDS);
                                qtype, response, true), Query::BadDS);
 
 
     // But only if DNSSEC is requested (it shouldn't even try to look for
     // But only if DNSSEC is requested (it shouldn't even try to look for
     // the DS otherwise)
     // the DS otherwise)
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("bad-delegation.example.com"),
                                   Name("bad-delegation.example.com"),
                                   qtype, response));
                                   qtype, response));
 }
 }
 
 
 
 
 TEST_F(QueryTest, nxdomain) {
 TEST_F(QueryTest, nxdomain) {
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("nxdomain.example.com"), qtype,
                                   Name("nxdomain.example.com"), qtype,
                                   response));
                                   response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
@@ -1214,7 +1250,7 @@ TEST_F(QueryTest, nxdomainWithNSEC) {
     // NXDOMAIN with DNSSEC proof.  We should have SOA, NSEC that proves
     // NXDOMAIN with DNSSEC proof.  We should have SOA, NSEC that proves
     // NXDOMAIN and NSEC that proves nonexistence of matching wildcard,
     // NXDOMAIN and NSEC that proves nonexistence of matching wildcard,
     // as well as their RRSIGs.
     // as well as their RRSIGs.
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("nxdomain.example.com"), qtype,
                                   Name("nxdomain.example.com"), qtype,
                                   response, true));
                                   response, true));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
@@ -1235,7 +1271,7 @@ TEST_F(QueryTest, nxdomainWithNSEC2) {
     // is derived from the next domain of the NSEC that proves NXDOMAIN, and
     // is derived from the next domain of the NSEC that proves NXDOMAIN, and
     // the NSEC to provide the non existence of wildcard is different from
     // the NSEC to provide the non existence of wildcard is different from
     // the first NSEC.
     // the first NSEC.
-    query.process(memory_client, Name("(.no.example.com"), qtype, response,
+    query.process(list, Name("(.no.example.com"), qtype, response,
                   true);
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
                   NULL, (string(soa_txt) +
                   NULL, (string(soa_txt) +
@@ -1253,7 +1289,7 @@ TEST_F(QueryTest, nxdomainWithNSEC2) {
 TEST_F(QueryTest, nxdomainWithNSECDuplicate) {
 TEST_F(QueryTest, nxdomainWithNSECDuplicate) {
     // See comments about nz_txt.  In this case we only need one NSEC,
     // See comments about nz_txt.  In this case we only need one NSEC,
     // which proves both NXDOMAIN and the non existence of wildcard.
     // which proves both NXDOMAIN and the non existence of wildcard.
-    query.process(memory_client, Name("nx.no.example.com"), qtype, response,
+    query.process(list, Name("nx.no.example.com"), qtype, response,
                   true);
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 4, 0,
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 4, 0,
                   NULL, (string(soa_txt) +
                   NULL, (string(soa_txt) +
@@ -1270,7 +1306,7 @@ TEST_F(QueryTest, nxdomainBadNSEC1) {
     mock_finder->setNSECResult(Name("badnsec.example.com"),
     mock_finder->setNSECResult(Name("badnsec.example.com"),
                                ZoneFinder::NXDOMAIN,
                                ZoneFinder::NXDOMAIN,
                                mock_finder->dname_rrset_);
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("badnsec.example.com"),
+    EXPECT_THROW(query.process(list, Name("badnsec.example.com"),
                                qtype, response, true),
                                qtype, response, true),
                  std::bad_cast);
                  std::bad_cast);
 }
 }
@@ -1280,7 +1316,7 @@ TEST_F(QueryTest, nxdomainBadNSEC2) {
     mock_finder->setNSECResult(Name("emptynsec.example.com"),
     mock_finder->setNSECResult(Name("emptynsec.example.com"),
                                ZoneFinder::NXDOMAIN,
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("emptynsec.example.com"),
+    EXPECT_THROW(query.process(list, Name("emptynsec.example.com"),
                                qtype, response, true),
                                qtype, response, true),
                  Query::BadNSEC);
                  Query::BadNSEC);
 }
 }
@@ -1290,7 +1326,7 @@ TEST_F(QueryTest, nxdomainBadNSEC3) {
     mock_finder->setNSECResult(Name("*.example.com"),
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::SUCCESS,
                                ZoneFinder::SUCCESS,
                                mock_finder->dname_rrset_);
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                qtype, response, true),
                                qtype, response, true),
                  Query::BadNSEC);
                  Query::BadNSEC);
 }
 }
@@ -1299,7 +1335,7 @@ TEST_F(QueryTest, nxdomainBadNSEC4) {
     // "no-wildcard proof" doesn't return RRset.
     // "no-wildcard proof" doesn't return RRset.
     mock_finder->setNSECResult(Name("*.example.com"),
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::NXDOMAIN, ConstRRsetPtr());
                                ZoneFinder::NXDOMAIN, ConstRRsetPtr());
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                qtype, response, true),
                                qtype, response, true),
                  Query::BadNSEC);
                  Query::BadNSEC);
 }
 }
@@ -1310,7 +1346,7 @@ TEST_F(QueryTest, nxdomainBadNSEC5) {
                                ZoneFinder::NXDOMAIN,
                                ZoneFinder::NXDOMAIN,
                                mock_finder->dname_rrset_);
                                mock_finder->dname_rrset_);
     // This is a bit odd, but we'll simply include the returned RRset.
     // This is a bit odd, but we'll simply include the returned RRset.
-    query.process(memory_client, Name("nxdomain.example.com"), qtype,
+    query.process(list, Name("nxdomain.example.com"), qtype,
                   response, true);
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
                   NULL, (string(soa_txt) +
                   NULL, (string(soa_txt) +
@@ -1330,13 +1366,13 @@ TEST_F(QueryTest, nxdomainBadNSEC6) {
     mock_finder->setNSECResult(Name("*.example.com"),
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::NXDOMAIN,
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                qtype, response, true),
                                qtype, response, true),
                  Query::BadNSEC);
                  Query::BadNSEC);
 }
 }
 
 
 TEST_F(QueryTest, nxrrset) {
 TEST_F(QueryTest, nxrrset) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("www.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("www.example.com"),
                                   RRType::TXT(), response));
                                   RRType::TXT(), response));
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
@@ -1346,7 +1382,7 @@ TEST_F(QueryTest, nxrrset) {
 TEST_F(QueryTest, nxrrsetWithNSEC) {
 TEST_F(QueryTest, nxrrsetWithNSEC) {
     // NXRRSET with DNSSEC proof.  We should have SOA, NSEC that proves the
     // NXRRSET with DNSSEC proof.  We should have SOA, NSEC that proves the
     // NXRRSET and their RRSIGs.
     // NXRRSET and their RRSIGs.
-    query.process(memory_client, Name("www.example.com"), RRType::TXT(),
+    query.process(list, Name("www.example.com"), RRType::TXT(),
                   response, true);
                   response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1367,7 +1403,7 @@ TEST_F(QueryTest, emptyNameWithNSEC) {
     // exact match), so we only need one NSEC.
     // exact match), so we only need one NSEC.
     // From the point of the Query::process(), this is actually no different
     // From the point of the Query::process(), this is actually no different
     // from the other NXRRSET case, but we check that explicitly just in case.
     // from the other NXRRSET case, but we check that explicitly just in case.
-    query.process(memory_client, Name("no.example.com"), RRType::A(),
+    query.process(list, Name("no.example.com"), RRType::A(),
                   response, true);
                   response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1383,7 +1419,7 @@ TEST_F(QueryTest, nxrrsetWithoutNSEC) {
     // NXRRSET with DNSSEC proof requested, but there's no NSEC at that node.
     // NXRRSET with DNSSEC proof requested, but there's no NSEC at that node.
     // This is an unexpected event (if the zone is supposed to be properly
     // This is an unexpected event (if the zone is supposed to be properly
     // signed with NSECs), but we accept and ignore the oddity.
     // signed with NSECs), but we accept and ignore the oddity.
-    query.process(memory_client, Name("nonsec.example.com"), RRType::TXT(),
+    query.process(list, Name("nonsec.example.com"), RRType::TXT(),
                   response, true);
                   response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
@@ -1395,7 +1431,7 @@ TEST_F(QueryTest, nxrrsetWithoutNSEC) {
 TEST_F(QueryTest, wildcardNSEC) {
 TEST_F(QueryTest, wildcardNSEC) {
     // The qname matches *.wild.example.com.  The response should contain
     // The qname matches *.wild.example.com.  The response should contain
     // an NSEC that proves the non existence of a closer name.
     // an NSEC that proves the non existence of a closer name.
-    query.process(memory_client, Name("www.wild.example.com"), RRType::A(),
+    query.process(list, Name("www.wild.example.com"), RRType::A(),
                   response, true);
                   response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
                   (string(wild_txt).replace(0, 1, "www") +
                   (string(wild_txt).replace(0, 1, "www") +
@@ -1415,7 +1451,7 @@ TEST_F(QueryTest, wildcardNSEC) {
 TEST_F(QueryTest, CNAMEwildNSEC) {
 TEST_F(QueryTest, CNAMEwildNSEC) {
     // Similar to the previous case, but the matching wildcard record is
     // Similar to the previous case, but the matching wildcard record is
     // CNAME.
     // CNAME.
-    query.process(memory_client, Name("www.cnamewild.example.com"),
+    query.process(list, Name("www.cnamewild.example.com"),
                   RRType::A(), response, true);
                   RRType::A(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(cnamewild_txt).replace(0, 1, "www") +
                   (string(cnamewild_txt).replace(0, 1, "www") +
@@ -1438,7 +1474,7 @@ TEST_F(QueryTest, wildcardNSEC3) {
     // of identifying the next closer name.
     // of identifying the next closer name.
     mock_finder->addRecord(nsec3_atwild_txt);
     mock_finder->addRecord(nsec3_atwild_txt);
 
 
-    query.process(memory_client, Name("x.y.wild.example.com"), RRType::A(),
+    query.process(list, Name("x.y.wild.example.com"), RRType::A(),
                   response, true);
                   response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
                   (string(wild_txt).replace(0, 1, "x.y") +
                   (string(wild_txt).replace(0, 1, "x.y") +
@@ -1463,7 +1499,7 @@ TEST_F(QueryTest, CNAMEwildNSEC3) {
     mock_finder->setNSEC3Flag(true);
     mock_finder->setNSEC3Flag(true);
     mock_finder->addRecord(nsec3_atcnamewild_txt);
     mock_finder->addRecord(nsec3_atcnamewild_txt);
 
 
-    query.process(memory_client, Name("www.cnamewild.example.com"),
+    query.process(list, Name("www.cnamewild.example.com"),
                   RRType::A(), response, true);
                   RRType::A(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(cnamewild_txt).replace(0, 1, "www") +
                   (string(cnamewild_txt).replace(0, 1, "www") +
@@ -1486,7 +1522,7 @@ TEST_F(QueryTest, badWildcardNSEC3) {
                                       ConstRRsetPtr());
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
     mock_finder->setNSEC3Result(&nsec3);
 
 
-    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                                RRType::A(), response, true),
                  Query::BadNSEC3);
                  Query::BadNSEC3);
 }
 }
@@ -1497,7 +1533,7 @@ TEST_F(QueryTest, badWildcardProof1) {
     mock_finder->setNSECResult(Name("www.wild.example.com"),
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::SUCCESS,
                                ZoneFinder::SUCCESS,
                                mock_finder->dname_rrset_);
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                                RRType::A(), response, true),
                  Query::BadNSEC);
                  Query::BadNSEC);
 }
 }
@@ -1506,7 +1542,7 @@ TEST_F(QueryTest, badWildcardProof2) {
     // "wildcard proof" doesn't return RRset.
     // "wildcard proof" doesn't return RRset.
     mock_finder->setNSECResult(Name("www.wild.example.com"),
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::NXDOMAIN, ConstRRsetPtr());
                                ZoneFinder::NXDOMAIN, ConstRRsetPtr());
-    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                                RRType::A(), response, true),
                  Query::BadNSEC);
                  Query::BadNSEC);
 }
 }
@@ -1516,7 +1552,7 @@ TEST_F(QueryTest, badWildcardProof3) {
     mock_finder->setNSECResult(Name("www.wild.example.com"),
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::NXDOMAIN,
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                                RRType::A(), response, true),
                  Query::BadNSEC);
                  Query::BadNSEC);
 }
 }
@@ -1525,7 +1561,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
     // NXRRSET on WILDCARD with DNSSEC proof.  We should have SOA, NSEC that
     // NXRRSET on WILDCARD with DNSSEC proof.  We should have SOA, NSEC that
     // proves the NXRRSET and their RRSIGs. In this case we only need one NSEC,
     // proves the NXRRSET and their RRSIGs. In this case we only need one NSEC,
     // which proves both NXDOMAIN and the non existence RRSETs of wildcard.
     // which proves both NXDOMAIN and the non existence RRSETs of wildcard.
-    query.process(memory_client, Name("www.wild.example.com"), RRType::TXT(),
+    query.process(list, Name("www.wild.example.com"), RRType::TXT(),
                   response, true);
                   response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1542,7 +1578,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC) {
     // proves the NXRRSET and their RRSIGs. In this case we need two NSEC RRs,
     // proves the NXRRSET and their RRSIGs. In this case we need two NSEC RRs,
     // one proves NXDOMAIN and the other proves non existence RRSETs of
     // one proves NXDOMAIN and the other proves non existence RRSETs of
     // wildcard.
     // wildcard.
-    query.process(memory_client, Name("www1.uwild.example.com"),
+    query.process(list, Name("www1.uwild.example.com"),
                   RRType::TXT(), response, true);
                   RRType::TXT(), response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
@@ -1565,7 +1601,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3) {
     mock_finder->addRecord(nsec3_uwild_txt);
     mock_finder->addRecord(nsec3_uwild_txt);
     mock_finder->setNSEC3Flag(true);
     mock_finder->setNSEC3Flag(true);
 
 
-    query.process(memory_client, Name("www1.uwild.example.com"),
+    query.process(list, Name("www1.uwild.example.com"),
                   RRType::TXT(), response, true);
                   RRType::TXT(), response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 8, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 8, 0, NULL,
@@ -1599,7 +1635,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Collision) {
                                       ConstRRsetPtr());
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
     mock_finder->setNSEC3Result(&nsec3);
 
 
-    EXPECT_THROW(query.process(memory_client, Name("www1.uwild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www1.uwild.example.com"),
                                RRType::TXT(), response, true),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
                  Query::BadNSEC3);
 }
 }
@@ -1616,7 +1652,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Broken) {
     mock_finder->addRecord(nsec3_wild_txt);
     mock_finder->addRecord(nsec3_wild_txt);
     mock_finder->addRecord(nsec3_uwild_txt);
     mock_finder->addRecord(nsec3_uwild_txt);
 
 
-    EXPECT_THROW(query.process(memory_client, Name("www1.uwild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www1.uwild.example.com"),
                                RRType::TXT(), response, true),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
                  Query::BadNSEC3);
 }
 }
@@ -1625,7 +1661,7 @@ TEST_F(QueryTest, wildcardEmptyWithNSEC) {
     // Empty WILDCARD with DNSSEC proof.  We should have SOA, NSEC that proves
     // Empty WILDCARD with DNSSEC proof.  We should have SOA, NSEC that proves
     // the NXDOMAIN and their RRSIGs. In this case we need two NSEC RRs,
     // the NXDOMAIN and their RRSIGs. In this case we need two NSEC RRs,
     // one proves NXDOMAIN and the other proves non existence wildcard.
     // one proves NXDOMAIN and the other proves non existence wildcard.
-    query.process(memory_client, Name("a.t.example.com"), RRType::A(),
+    query.process(list, Name("a.t.example.com"), RRType::A(),
                   response, true);
                   response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
@@ -1649,19 +1685,19 @@ TEST_F(QueryTest, noSOA) {
     mock_finder->setSOAFlag(false);
     mock_finder->setSOAFlag(false);
 
 
     // The NX Domain
     // The NX Domain
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                qtype, response), Query::NoSOA);
                                qtype, response), Query::NoSOA);
     // Of course, we don't look into the response, as it throwed
     // Of course, we don't look into the response, as it throwed
 
 
     // NXRRSET
     // NXRRSET
-    EXPECT_THROW(query.process(memory_client, Name("nxrrset.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxrrset.example.com"),
                                qtype, response), Query::NoSOA);
                                qtype, response), Query::NoSOA);
 }
 }
 
 
 TEST_F(QueryTest, noMatchZone) {
 TEST_F(QueryTest, noMatchZone) {
     // there's a zone in the memory datasource but it doesn't match the qname.
     // there's a zone in the memory datasource but it doesn't match the qname.
     // should result in REFUSED.
     // should result in REFUSED.
-    query.process(memory_client, Name("example.org"), qtype, response);
+    query.process(list, Name("example.org"), qtype, response);
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 }
 
 
@@ -1672,7 +1708,7 @@ TEST_F(QueryTest, noMatchZone) {
  * A record, other to unknown out of zone one.
  * A record, other to unknown out of zone one.
  */
  */
 TEST_F(QueryTest, MX) {
 TEST_F(QueryTest, MX) {
-    query.process(memory_client, Name("mx.example.com"), RRType::MX(),
+    query.process(list, Name("mx.example.com"), RRType::MX(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
@@ -1686,7 +1722,7 @@ TEST_F(QueryTest, MX) {
  * This should not trigger the additional processing for the exchange.
  * This should not trigger the additional processing for the exchange.
  */
  */
 TEST_F(QueryTest, MXAlias) {
 TEST_F(QueryTest, MXAlias) {
-    query.process(memory_client, Name("cnamemx.example.com"), RRType::MX(),
+    query.process(list, Name("cnamemx.example.com"), RRType::MX(),
                   response);
                   response);
 
 
     // there shouldn't be no additional RRs for the exchanges (we have 3
     // there shouldn't be no additional RRs for the exchanges (we have 3
@@ -1706,7 +1742,7 @@ TEST_F(QueryTest, MXAlias) {
  * returned.
  * returned.
  */
  */
 TEST_F(QueryTest, CNAME) {
 TEST_F(QueryTest, CNAME) {
-    query.process(memory_client, Name("cname.example.com"), RRType::A(),
+    query.process(list, Name("cname.example.com"), RRType::A(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1716,7 +1752,7 @@ TEST_F(QueryTest, CNAME) {
 TEST_F(QueryTest, explicitCNAME) {
 TEST_F(QueryTest, explicitCNAME) {
     // same owner name as the CNAME test but explicitly query for CNAME RR.
     // same owner name as the CNAME test but explicitly query for CNAME RR.
     // expect the same response as we don't provide a full chain yet.
     // expect the same response as we don't provide a full chain yet.
-    query.process(memory_client, Name("cname.example.com"), RRType::CNAME(),
+    query.process(list, Name("cname.example.com"), RRType::CNAME(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1728,7 +1764,7 @@ TEST_F(QueryTest, CNAME_NX_RRSET) {
     // note: with chaining, what should be expected is not trivial:
     // note: with chaining, what should be expected is not trivial:
     // BIND 9 returns the CNAME in answer and SOA in authority, no additional.
     // BIND 9 returns the CNAME in answer and SOA in authority, no additional.
     // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional.
     // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional.
-    query.process(memory_client, Name("cname.example.com"), RRType::TXT(),
+    query.process(list, Name("cname.example.com"), RRType::TXT(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1737,7 +1773,7 @@ TEST_F(QueryTest, CNAME_NX_RRSET) {
 
 
 TEST_F(QueryTest, explicitCNAME_NX_RRSET) {
 TEST_F(QueryTest, explicitCNAME_NX_RRSET) {
     // same owner name as the NXRRSET test but explicitly query for CNAME RR.
     // same owner name as the NXRRSET test but explicitly query for CNAME RR.
-    query.process(memory_client, Name("cname.example.com"), RRType::CNAME(),
+    query.process(list, Name("cname.example.com"), RRType::CNAME(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1751,7 +1787,7 @@ TEST_F(QueryTest, CNAME_NX_DOMAIN) {
     // RCODE being NXDOMAIN.
     // RCODE being NXDOMAIN.
     // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional,
     // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional,
     // RCODE being NOERROR.
     // RCODE being NOERROR.
-    query.process(memory_client, Name("cnamenxdom.example.com"), RRType::A(),
+    query.process(list, Name("cnamenxdom.example.com"), RRType::A(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1760,7 +1796,7 @@ TEST_F(QueryTest, CNAME_NX_DOMAIN) {
 
 
 TEST_F(QueryTest, explicitCNAME_NX_DOMAIN) {
 TEST_F(QueryTest, explicitCNAME_NX_DOMAIN) {
     // same owner name as the NXDOMAIN test but explicitly query for CNAME RR.
     // same owner name as the NXDOMAIN test but explicitly query for CNAME RR.
-    query.process(memory_client, Name("cnamenxdom.example.com"),
+    query.process(list, Name("cnamenxdom.example.com"),
                   RRType::CNAME(), response);
                   RRType::CNAME(), response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1776,7 +1812,7 @@ TEST_F(QueryTest, CNAME_OUT) {
      * Then the same test should be done with .org included there and
      * Then the same test should be done with .org included there and
      * see what it does (depends on what we want to do)
      * see what it does (depends on what we want to do)
      */
      */
-    query.process(memory_client, Name("cnameout.example.com"), RRType::A(),
+    query.process(list, Name("cnameout.example.com"), RRType::A(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1785,7 +1821,7 @@ TEST_F(QueryTest, CNAME_OUT) {
 
 
 TEST_F(QueryTest, explicitCNAME_OUT) {
 TEST_F(QueryTest, explicitCNAME_OUT) {
     // same owner name as the OUT test but explicitly query for CNAME RR.
     // same owner name as the OUT test but explicitly query for CNAME RR.
-    query.process(memory_client, Name("cnameout.example.com"), RRType::CNAME(),
+    query.process(list, Name("cnameout.example.com"), RRType::CNAME(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1801,7 +1837,7 @@ TEST_F(QueryTest, explicitCNAME_OUT) {
  * pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
  * pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
  */
  */
 TEST_F(QueryTest, DNAME) {
 TEST_F(QueryTest, DNAME) {
-    query.process(memory_client, Name("www.dname.example.com"), RRType::A(),
+    query.process(list, Name("www.dname.example.com"), RRType::A(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
@@ -1817,7 +1853,7 @@ TEST_F(QueryTest, DNAME) {
  * DNAME.
  * DNAME.
  */
  */
 TEST_F(QueryTest, DNAME_ANY) {
 TEST_F(QueryTest, DNAME_ANY) {
-    query.process(memory_client, Name("www.dname.example.com"), RRType::ANY(),
+    query.process(list, Name("www.dname.example.com"), RRType::ANY(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
@@ -1826,7 +1862,7 @@ TEST_F(QueryTest, DNAME_ANY) {
 
 
 // Test when we ask for DNAME explicitly, it does no synthetizing.
 // Test when we ask for DNAME explicitly, it does no synthetizing.
 TEST_F(QueryTest, explicitDNAME) {
 TEST_F(QueryTest, explicitDNAME) {
-    query.process(memory_client, Name("dname.example.com"), RRType::DNAME(),
+    query.process(list, Name("dname.example.com"), RRType::DNAME(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1838,7 +1874,7 @@ TEST_F(QueryTest, explicitDNAME) {
  * the CNAME, it should return the RRset.
  * the CNAME, it should return the RRset.
  */
  */
 TEST_F(QueryTest, DNAME_A) {
 TEST_F(QueryTest, DNAME_A) {
-    query.process(memory_client, Name("dname.example.com"), RRType::A(),
+    query.process(list, Name("dname.example.com"), RRType::A(),
                   response);
                   response);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1850,7 +1886,7 @@ TEST_F(QueryTest, DNAME_A) {
  * It should not synthetize the CNAME.
  * It should not synthetize the CNAME.
  */
  */
 TEST_F(QueryTest, DNAME_NX_RRSET) {
 TEST_F(QueryTest, DNAME_NX_RRSET) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("dname.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("dname.example.com"),
                     RRType::TXT(), response));
                     RRType::TXT(), response));
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
@@ -1870,7 +1906,7 @@ TEST_F(QueryTest, LongDNAME) {
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "dname.example.com.");
         "dname.example.com.");
-    EXPECT_NO_THROW(query.process(memory_client, longname, RRType::A(),
+    EXPECT_NO_THROW(query.process(list, longname, RRType::A(),
                     response));
                     response));
 
 
     responseCheck(response, Rcode::YXDOMAIN(), AA_FLAG, 1, 0, 0,
     responseCheck(response, Rcode::YXDOMAIN(), AA_FLAG, 1, 0, 0,
@@ -1889,7 +1925,7 @@ TEST_F(QueryTest, MaxLenDNAME) {
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "dname.example.com.");
         "dname.example.com.");
-    EXPECT_NO_THROW(query.process(memory_client, longname, RRType::A(),
+    EXPECT_NO_THROW(query.process(list, longname, RRType::A(),
                     response));
                     response));
 
 
     // Check the answer is OK
     // Check the answer is OK
@@ -2075,7 +2111,7 @@ TEST_F(QueryTest, dsAboveDelegation) {
 
 
     // The following will succeed only if the search goes to the parent
     // The following will succeed only if the search goes to the parent
     // zone, not the child one we added above.
     // zone, not the child one we added above.
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("delegation.example.com"),
                                   Name("delegation.example.com"),
                                   RRType::DS(), response, true));
                                   RRType::DS(), response, true));
 
 
@@ -2099,7 +2135,7 @@ TEST_F(QueryTest, dsAboveDelegationNoData) {
 
 
     // The following will succeed only if the search goes to the parent
     // The following will succeed only if the search goes to the parent
     // zone, not the child one we added above.
     // zone, not the child one we added above.
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("unsigned-delegation.example.com"),
                                   Name("unsigned-delegation.example.com"),
                                   RRType::DS(), response, true));
                                   RRType::DS(), response, true));
 
 
@@ -2117,7 +2153,7 @@ TEST_F(QueryTest, dsAboveDelegationNoData) {
 // when it happens to be sent to the child zone, as described in RFC 4035,
 // when it happens to be sent to the child zone, as described in RFC 4035,
 // section 3.1.4.1. The example is inspired by the B.8. example from the RFC.
 // section 3.1.4.1. The example is inspired by the B.8. example from the RFC.
 TEST_F(QueryTest, dsBelowDelegation) {
 TEST_F(QueryTest, dsBelowDelegation) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("example.com"),
                                   RRType::DS(), response, true));
                                   RRType::DS(), response, true));
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -2134,7 +2170,7 @@ TEST_F(QueryTest, dsBelowDelegation) {
 // In our implementation NSEC/NSEC3 isn't attached in this case.
 // In our implementation NSEC/NSEC3 isn't attached in this case.
 TEST_F(QueryTest, dsBelowDelegationWithDS) {
 TEST_F(QueryTest, dsBelowDelegationWithDS) {
     mock_finder->addRecord(zone_ds_txt); // add the DS to the child's apex
     mock_finder->addRecord(zone_ds_txt); // add the DS to the child's apex
-    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("example.com"),
                                   RRType::DS(), response, true));
                                   RRType::DS(), response, true));
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
@@ -2147,7 +2183,7 @@ TEST_F(QueryTest, dsBelowDelegationWithDS) {
 // server.  It should just like the "noZone" test case, but DS query involves
 // server.  It should just like the "noZone" test case, but DS query involves
 // special processing, so we test it explicitly.
 // special processing, so we test it explicitly.
 TEST_F(QueryTest, dsNoZone) {
 TEST_F(QueryTest, dsNoZone) {
-    query.process(memory_client, Name("example"), RRType::DS(), response,
+    query.process(list, Name("example"), RRType::DS(), response,
                   true);
                   true);
     responseCheck(response, Rcode::REFUSED(), 0, 0, 0, 0, NULL, NULL, NULL);
     responseCheck(response, Rcode::REFUSED(), 0, 0, 0, 0, NULL, NULL, NULL);
 }
 }
@@ -2155,7 +2191,7 @@ TEST_F(QueryTest, dsNoZone) {
 // DS query for a "grandchild" zone.  This should result in normal
 // DS query for a "grandchild" zone.  This should result in normal
 // delegation (unless this server also has authority of the grandchild zone).
 // delegation (unless this server also has authority of the grandchild zone).
 TEST_F(QueryTest, dsAtGrandParent) {
 TEST_F(QueryTest, dsAtGrandParent) {
-    query.process(memory_client, Name("grand.delegation.example.com"),
+    query.process(list, Name("grand.delegation.example.com"),
                   RRType::DS(), response, true);
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), 0, 0, 6, 6, NULL,
     responseCheck(response, Rcode::NOERROR(), 0, 0, 6, 6, NULL,
                   (string(delegation_txt) + string(delegation_ds_txt) +
                   (string(delegation_txt) + string(delegation_ds_txt) +
@@ -2174,7 +2210,7 @@ TEST_F(QueryTest, dsAtGrandParentAndChild) {
     const Name childname("grand.delegation.example.com");
     const Name childname("grand.delegation.example.com");
     memory_client.addZone(ZoneFinderPtr(
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(childname)));
                               new AlternateZoneFinder(childname)));
-    query.process(memory_client, childname, RRType::DS(), response, true);
+    query.process(list, childname, RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (childname.toText() + " 3600 IN SOA . . 0 0 0 0 0\n" +
                   (childname.toText() + " 3600 IN SOA . . 0 0 0 0 0\n" +
                    childname.toText() + " 3600 IN RRSIG " +
                    childname.toText() + " 3600 IN RRSIG " +
@@ -2192,7 +2228,7 @@ TEST_F(QueryTest, dsAtRoot) {
     // Pretend to be a root server.
     // Pretend to be a root server.
     memory_client.addZone(ZoneFinderPtr(
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(Name::ROOT_NAME())));
                               new AlternateZoneFinder(Name::ROOT_NAME())));
-    query.process(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
+    query.process(list, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
                   true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (string(". 3600 IN SOA . . 0 0 0 0 0\n") +
                   (string(". 3600 IN SOA . . 0 0 0 0 0\n") +
@@ -2209,7 +2245,7 @@ TEST_F(QueryTest, dsAtRootWithDS) {
     memory_client.addZone(ZoneFinderPtr(
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(Name::ROOT_NAME(),
                               new AlternateZoneFinder(Name::ROOT_NAME(),
                                                       true)));
                                                       true)));
-    query.process(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
+    query.process(list, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
                   true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(". 3600 IN DS 57855 5 1 49FD46E6C4B45C55D4AC69CBD"
                   (string(". 3600 IN DS 57855 5 1 49FD46E6C4B45C55D4AC69CBD"
@@ -2226,7 +2262,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3) {
 
 
     // NXRRSET with DNSSEC proof.  We should have SOA, NSEC3 that proves the
     // NXRRSET with DNSSEC proof.  We should have SOA, NSEC3 that proves the
     // NXRRSET and their RRSIGs.
     // NXRRSET and their RRSIGs.
-    query.process(memory_client, Name("www.example.com"), RRType::TXT(),
+    query.process(list, Name("www.example.com"), RRType::TXT(),
                   response, true);
                   response, true);
 
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -2249,7 +2285,7 @@ TEST_F(QueryTest, nxrrsetMissingNSEC3) {
                                       ConstRRsetPtr());
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
     mock_finder->setNSEC3Result(&nsec3);
 
 
-    EXPECT_THROW(query.process(memory_client, Name("www.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.example.com"),
                                RRType::TXT(), response, true),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
                  Query::BadNSEC3);
 }
 }
@@ -2260,7 +2296,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3_ds_exact) {
 
 
     // This delegation has no DS, but does have a matching NSEC3 record
     // This delegation has no DS, but does have a matching NSEC3 record
     // (See RFC5155 section 7.2.4)
     // (See RFC5155 section 7.2.4)
-    query.process(memory_client, Name("unsigned-delegation.example.com."),
+    query.process(list, Name("unsigned-delegation.example.com."),
                   RRType::DS(), response, true);
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2282,7 +2318,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3_ds_no_exact) {
     // 'next closer' should have opt-out set, though that is not
     // 'next closer' should have opt-out set, though that is not
     // actually checked)
     // actually checked)
     // (See RFC5155 section 7.2.4)
     // (See RFC5155 section 7.2.4)
-    query.process(memory_client, Name("unsigned-delegation-optout.example.com."),
+    query.process(list, Name("unsigned-delegation-optout.example.com."),
                   RRType::DS(), response, true);
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2309,7 +2345,7 @@ TEST_F(QueryTest, nxdomainWithNSEC3Proof) {
     // This will be the covering NSEC3 for the possible wildcard
     // This will be the covering NSEC3 for the possible wildcard
     mock_finder->addRecord(unsigned_delegation_nsec3_txt);
     mock_finder->addRecord(unsigned_delegation_nsec3_txt);
 
 
-    query.process(memory_client, Name("nxdomain.example.com"), qtype,
+    query.process(list, Name("nxdomain.example.com"), qtype,
                   response, true);
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 8, 0, NULL,
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 8, 0, NULL,
                   // SOA + its RRSIG
                   // SOA + its RRSIG
@@ -2344,7 +2380,7 @@ TEST_F(QueryTest, nxdomainWithBadNextNSEC3Proof) {
                                       ConstRRsetPtr());
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
     mock_finder->setNSEC3Result(&nsec3);
 
 
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                RRType::TXT(), response, true),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
                  Query::BadNSEC3);
 }
 }
@@ -2363,7 +2399,7 @@ TEST_F(QueryTest, nxdomainWithBadWildcardNSEC3Proof) {
                                       ConstRRsetPtr());
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3, &wname);
     mock_finder->setNSEC3Result(&nsec3, &wname);
 
 
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"), qtype,
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"), qtype,
                                response, true),
                                response, true),
                  Query::BadNSEC3);
                  Query::BadNSEC3);
 }
 }

+ 8 - 0
src/bin/auth/tests/testdata/.gitignore

@@ -0,0 +1,8 @@
+/badExampleQuery_fromWire.wire
+/examplequery_fromWire.wire
+/iqueryresponse_fromWire.wire
+/multiquestion_fromWire.wire
+/queryBadEDNS_fromWire.wire
+/shortanswer_fromWire.wire
+/simplequery_fromWire.wire
+/simpleresponse_fromWire.wire

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

@@ -18,6 +18,7 @@ EXTRA_DIST += shortquestion_fromWire
 EXTRA_DIST += shortresponse_fromWire
 EXTRA_DIST += shortresponse_fromWire
 EXTRA_DIST += simplequery_fromWire.spec
 EXTRA_DIST += simplequery_fromWire.spec
 EXTRA_DIST += simpleresponse_fromWire.spec
 EXTRA_DIST += simpleresponse_fromWire.spec
+EXTRA_DIST += spec.spec
 
 
 EXTRA_DIST += example.com
 EXTRA_DIST += example.com
 EXTRA_DIST += example.sqlite3
 EXTRA_DIST += example.sqlite3

+ 5 - 0
src/bin/auth/tests/testdata/spec.spec

@@ -0,0 +1,5 @@
+{
+    "module_spec": {
+        "module_name": "test"
+    }
+}

File diff suppressed because it is too large
+ 1 - 8
src/bin/bind10/bind10.8


+ 0 - 11
src/bin/bind10/bind10.xml

@@ -47,7 +47,6 @@
       <arg><option>-c <replaceable>config-filename</replaceable></option></arg>
       <arg><option>-c <replaceable>config-filename</replaceable></option></arg>
       <arg><option>-i</option></arg>
       <arg><option>-i</option></arg>
       <arg><option>-m <replaceable>file</replaceable></option></arg>
       <arg><option>-m <replaceable>file</replaceable></option></arg>
-      <arg><option>-n</option></arg>
       <arg><option>-p <replaceable>data_path</replaceable></option></arg>
       <arg><option>-p <replaceable>data_path</replaceable></option></arg>
       <arg><option>-u <replaceable>user</replaceable></option></arg>
       <arg><option>-u <replaceable>user</replaceable></option></arg>
       <arg><option>-v</option></arg>
       <arg><option>-v</option></arg>
@@ -57,7 +56,6 @@
       <arg><option>--config-file</option> <replaceable>config-filename</replaceable></arg>
       <arg><option>--config-file</option> <replaceable>config-filename</replaceable></arg>
       <arg><option>--data-path</option> <replaceable>directory</replaceable></arg>
       <arg><option>--data-path</option> <replaceable>directory</replaceable></arg>
       <arg><option>--msgq-socket-file <replaceable>file</replaceable></option></arg>
       <arg><option>--msgq-socket-file <replaceable>file</replaceable></option></arg>
-      <arg><option>--no-cache</option></arg>
       <arg><option>--no-kill</option></arg>
       <arg><option>--no-kill</option></arg>
       <arg><option>--pid-file</option> <replaceable>filename</replaceable></arg>
       <arg><option>--pid-file</option> <replaceable>filename</replaceable></arg>
       <arg><option>--pretty-name <replaceable>name</replaceable></option></arg>
       <arg><option>--pretty-name <replaceable>name</replaceable></option></arg>
@@ -169,15 +167,6 @@
       </varlistentry>
       </varlistentry>
 
 
       <varlistentry>
       <varlistentry>
-        <term><option>-n</option>, <option>--no-cache</option></term>
-        <listitem>
-	  <para>Disables the hot-spot caching used by the
-	    <citerefentry><refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-	  daemon.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
         <term><option>-i</option>, <option>--no-kill</option></term>
         <term><option>-i</option>, <option>--no-kill</option></term>
         <listitem>
         <listitem>
 	  <para>When this option is passed, <command>bind10</command>
 	  <para>When this option is passed, <command>bind10</command>

+ 2 - 7
src/bin/bind10/bind10_src.py.in

@@ -168,7 +168,7 @@ class BoB:
     """Boss of BIND class."""
     """Boss of BIND class."""
     
     
     def __init__(self, msgq_socket_file=None, data_path=None,
     def __init__(self, msgq_socket_file=None, data_path=None,
-                 config_filename=None, clear_config=False, nocache=False,
+                 config_filename=None, clear_config=False,
                  verbose=False, nokill=False, setuid=None, setgid=None,
                  verbose=False, nokill=False, setuid=None, setgid=None,
                  username=None, cmdctl_port=None, wait_time=10):
                  username=None, cmdctl_port=None, wait_time=10):
         """
         """
@@ -192,7 +192,6 @@ class BoB:
         self.ccs = None
         self.ccs = None
         self.curproc = None
         self.curproc = None
         self.msgq_socket_file = msgq_socket_file
         self.msgq_socket_file = msgq_socket_file
-        self.nocache = nocache
         self.component_config = {}
         self.component_config = {}
         # Some time in future, it may happen that a single component has
         # Some time in future, it may happen that a single component has
         # multple processes (like a pipeline-like component). If so happens,
         # multple processes (like a pipeline-like component). If so happens,
@@ -568,8 +567,6 @@ class BoB:
         if self.uid is not None and self.__started:
         if self.uid is not None and self.__started:
             logger.warn(BIND10_START_AS_NON_ROOT_AUTH)
             logger.warn(BIND10_START_AS_NON_ROOT_AUTH)
         authargs = ['b10-auth']
         authargs = ['b10-auth']
-        if self.nocache:
-            authargs += ['-n']
         if self.verbose:
         if self.verbose:
             authargs += ['-v']
             authargs += ['-v']
 
 
@@ -1052,8 +1049,6 @@ def parse_args(args=sys.argv[1:], Parser=OptionParser):
     parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
     parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
                       type="string", default=None,
                       type="string", default=None,
                       help="UNIX domain socket file the b10-msgq daemon will use")
                       help="UNIX domain socket file the b10-msgq daemon will use")
-    parser.add_option("-n", "--no-cache", action="store_true", dest="nocache",
-                      default=False, help="disable hot-spot cache in authoritative DNS server")
     parser.add_option("-i", "--no-kill", action="store_true", dest="nokill",
     parser.add_option("-i", "--no-kill", action="store_true", dest="nokill",
                       default=False, help="do not send SIGTERM and SIGKILL signals to modules during shutdown")
                       default=False, help="do not send SIGTERM and SIGKILL signals to modules during shutdown")
     parser.add_option("-u", "--user", dest="user", type="string", default=None,
     parser.add_option("-u", "--user", dest="user", type="string", default=None,
@@ -1208,7 +1203,7 @@ def main():
         # Go bob!
         # Go bob!
         boss_of_bind = BoB(options.msgq_socket_file, options.data_path,
         boss_of_bind = BoB(options.msgq_socket_file, options.data_path,
                            options.config_file, options.clear_config,
                            options.config_file, options.clear_config,
-                           options.nocache, options.verbose, options.nokill,
+                           options.verbose, options.nokill,
                            setuid, setgid, username, options.cmdctl_port,
                            setuid, setgid, username, options.cmdctl_port,
                            options.wait_time)
                            options.wait_time)
         startup_result = boss_of_bind.startup()
         startup_result = boss_of_bind.startup()

+ 0 - 2
src/bin/bind10/tests/bind10_test.py.in

@@ -349,7 +349,6 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.runnable, False)
         self.assertEqual(bob.runnable, False)
         self.assertEqual(bob.uid, None)
         self.assertEqual(bob.uid, None)
         self.assertEqual(bob.username, None)
         self.assertEqual(bob.username, None)
-        self.assertEqual(bob.nocache, False)
         self.assertIsNone(bob._socket_cache)
         self.assertIsNone(bob._socket_cache)
 
 
     def test_set_creator(self):
     def test_set_creator(self):
@@ -377,7 +376,6 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.runnable, False)
         self.assertEqual(bob.runnable, False)
         self.assertEqual(bob.uid, None)
         self.assertEqual(bob.uid, None)
         self.assertEqual(bob.username, None)
         self.assertEqual(bob.username, None)
-        self.assertEqual(bob.nocache, False)
 
 
     def test_command_handler(self):
     def test_command_handler(self):
         class DummySession():
         class DummySession():

+ 13 - 4
src/bin/bindctl/bindctl.1

@@ -9,6 +9,15 @@
 .\"
 .\"
 .TH "BINDCTL" "1" "June 20, 2012" "BIND10" "BIND10"
 .TH "BINDCTL" "1" "June 20, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" disable hyphenation
 .\" disable hyphenation
@@ -54,7 +63,7 @@ The PEM formatted server certificate validation chain file\&.
 .PP
 .PP
 \fB\-\-csv\-file\-dir\fR\fIfile\fR
 \fB\-\-csv\-file\-dir\fR\fIfile\fR
 .RS 4
 .RS 4
-The directory name in which the user/password CSV file is stored (see AUTHENTICATION)\&. By default this option doesn\'t have any value, in which case the "\&.bind10" directory under the user\'s home directory will be used\&.
+The directory name in which the user/password CSV file is stored (see AUTHENTICATION)\&. By default this option doesn\*(Aqt have any value, in which case the "\&.bind10" directory under the user\*(Aqs home directory will be used\&.
 .RE
 .RE
 .PP
 .PP
 \fB\-h\fR, \fB\-\-help\fR
 \fB\-h\fR, \fB\-\-help\fR
@@ -105,17 +114,17 @@ prompt shows
 \fIparam1 = value1 , \fR\fI\fIparam2 = value2\fR\fR
 \fIparam1 = value1 , \fR\fI\fIparam2 = value2\fR\fR
 .PP
 .PP
 
 
-\fBbindctl\fR\'s interactive interface provides command\-line completion and hints\&. Press the Tab key to get a hint for the module, command, and/or parameters\&.
+\fBbindctl\fR\*(Aqs interactive interface provides command\-line completion and hints\&. Press the Tab key to get a hint for the module, command, and/or parameters\&.
 The arrow keys and Emacs\-style editing keys may be used to edit and recall previous lines\&.
 The arrow keys and Emacs\-style editing keys may be used to edit and recall previous lines\&.
 .PP
 .PP
 You can use the
 You can use the
 \fBhelp\fR
 \fBhelp\fR
-keyword to receive usage assistance for a module or a module\'s command\&.
+keyword to receive usage assistance for a module or a module\*(Aqs command\&.
 .PP
 .PP
 The
 The
 \fBquit\fR
 \fBquit\fR
 command is used to exit
 command is used to exit
-\fBbindctl\fR\&. (It doesn\'t stop the BIND 10 services\&.)
+\fBbindctl\fR\&. (It doesn\*(Aqt stop the BIND 10 services\&.)
 .PP
 .PP
 The following module is available by default:
 The following module is available by default:
 \fBconfig\fR
 \fBconfig\fR

+ 2 - 1
src/bin/cfgmgr/Makefile.am

@@ -26,8 +26,9 @@ b10-cfgmgr: b10-cfgmgr.py
 
 
 install-data-local:
 install-data-local:
 	$(mkinstalldirs) $(DESTDIR)/@localstatedir@/@PACKAGE@
 	$(mkinstalldirs) $(DESTDIR)/@localstatedir@/@PACKAGE@
-# TODO: permissions handled later
 
 
+install-data-hook:
+	-chmod 2770 $(DESTDIR)/@localstatedir@/@PACKAGE@
 
 
 CLEANDIRS = __pycache__
 CLEANDIRS = __pycache__
 
 

+ 2 - 0
src/bin/cfgmgr/plugins/.gitignore

@@ -0,0 +1,2 @@
+/datasrc.spec
+/datasrc.spec.pre

+ 6 - 3
src/bin/cfgmgr/plugins/Makefile.am

@@ -2,13 +2,16 @@ SUBDIRS = tests
 
 
 EXTRA_DIST = README logging.spec tsig_keys.spec
 EXTRA_DIST = README logging.spec tsig_keys.spec
 
 
+datasrc.spec: datasrc.spec.pre
+	$(SED) -e "s|@@PKGDATADIR@@|$(pkgdatadir)|;s|@@LOCALSTATEDIR@@|$(localstatedir)|" datasrc.spec.pre >$@
+
 config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
 config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
-config_plugin_DATA = logging.spec tsig_keys.spec
+config_plugin_DATA = logging.spec tsig_keys.spec datasrc.spec
 
 
-python_PYTHON = b10logging.py tsig_keys.py
+python_PYTHON = b10logging.py tsig_keys.py datasrc_config_plugin.py
 pythondir = $(config_plugindir)
 pythondir = $(config_plugindir)
 
 
-CLEANFILES = b10logging.pyc tsig_keys.pyc
+CLEANFILES = b10logging.pyc tsig_keys.pyc datasrc.spec
 CLEANDIRS = __pycache__
 CLEANDIRS = __pycache__
 
 
 clean-local:
 clean-local:

+ 74 - 0
src/bin/cfgmgr/plugins/datasrc.spec.pre.in

@@ -0,0 +1,74 @@
+{
+    "module_spec": {
+        "module_name": "data_sources",
+        "module_description": "The sources of authoritative DNS data",
+        "config_data": [
+            {
+                "item_name": "classes",
+                "item_type": "named_set",
+                "item_optional": false,
+                "item_default": {
+                    "IN": [
+                        {
+                            "type": "sqlite3",
+                            "params": {
+                                "database_file": "@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3"
+                            }
+                        }
+                    ],
+                    "CH": [
+                        {
+                            "type": "static",
+                            "cache-enable": false,
+                            "params": "@@PKGDATADIR@@/static.zone"
+                        }
+                    ]
+                },
+                "named_set_item_spec": {
+                    "item_name": "class",
+                    "item_type": "list",
+                    "item_optional": false,
+                    "item_default": [],
+                    "list_item_spec": {
+                        "item_name": "source",
+                        "item_type": "map",
+                        "item_optional": false,
+                        "item_default": {},
+                        "map_item_spec": [
+                            {
+                                "item_name": "type",
+                                "item_type": "string",
+                                "item_optional": false,
+                                "item_default": ""
+                            },
+                            {
+                                "item_name": "params",
+                                "item_type": "any",
+                                "item_optional": false,
+                                "item_default": null
+                            },
+                            {
+                                "item_name": "cache-enable",
+                                "item_type": "boolean",
+                                "item_optional": false,
+                                "item_default": false
+                            },
+                            {
+                                "item_name": "cache-zones",
+                                "item_type": "list",
+                                "item_optional": true,
+                                "list_item_spec": {
+                                    "item_name": "zone",
+                                    "item_type": "string",
+                                    "item_optional": false,
+                                    "item_default": ""
+                                }
+                            }
+                        ]
+                    }
+                }
+            }
+        ],
+        "commands": []
+    }
+}

+ 80 - 0
src/bin/cfgmgr/plugins/datasrc_config_plugin.py

@@ -0,0 +1,80 @@
+# Copyright (C) 2012  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+from isc.config.module_spec import module_spec_from_file
+from isc.util.file import path_search
+from bind10_config import PLUGIN_PATHS
+import isc.dns
+import isc.datasrc
+import json
+import os.path
+import copy
+
+spec = module_spec_from_file(path_search('datasrc.spec', PLUGIN_PATHS))
+
+def check(config):
+    """
+    Check the configuration.
+    """
+    # Check the data layout first
+    errors=[]
+    if not spec.validate_config(False, config, errors):
+        return ' '.join(errors)
+
+    classes = config.get('classes')
+    # Nothing passed here
+    if classes is None:
+        return None
+
+    for rr_class_str in classes:
+        try:
+            rr_class = isc.dns.RRClass(rr_class_str)
+        except isc.dns.InvalidRRClass as irc:
+            return "The class '" + rr_class_str + "' is invalid"
+
+        dlist = isc.datasrc.ConfigurableClientList(rr_class)
+        # We get a copy here, as we are going to mangle the configuration.
+        # But we don't want our changes to propagate outside, to the real
+        # configuration.
+        client_config = copy.deepcopy(classes.get(rr_class_str))
+
+        for client in client_config:
+            if client['type'] == 'MasterFiles':
+                if not client.get('cache-enable', False):
+                    return 'The cache must be enabled in MasterFiles type'
+                params = client.get('params')
+                if type(params) != dict:
+                    return 'Params of MasterFiles must be a named set'
+                for name in params:
+                    try:
+                        isc.dns.Name(name)
+                    except Exception as e: # There are many related exceptions
+                        return str(e)
+                    if not os.path.exists(params[name]):
+                        return "Master file " + params[name] + " does not exist"
+                # We remove the list of zones locally. We already checked them,
+                # and the client list would have skipped them anyway, as we
+                # forbid cache. But it would produce a warning and we don't
+                # want that here.
+                client['params'] = {}
+
+        try:
+            dlist.configure(json.dumps(client_config), False)
+        except isc.datasrc.Error as dse:
+            return str(dse)
+    return None
+
+def load():
+    return (spec, check)

+ 1 - 1
src/bin/cfgmgr/plugins/tests/Makefile.am

@@ -1,5 +1,5 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-PYTESTS = tsig_keys_test.py logging_test.py
+PYTESTS = tsig_keys_test.py logging_test.py datasrc_test.py
 
 
 EXTRA_DIST = $(PYTESTS)
 EXTRA_DIST = $(PYTESTS)
 
 

+ 159 - 0
src/bin/cfgmgr/plugins/tests/datasrc_test.py

@@ -0,0 +1,159 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+# Make sure we can load the module, put it into path
+import sys
+import os
+import unittest
+import json
+sys.path.extend(os.environ["B10_TEST_PLUGIN_DIR"].split(':'))
+import isc.log
+
+import datasrc_config_plugin
+
+class DatasrcTest(unittest.TestCase):
+    def reject(self, config):
+        """
+        Just a shortcut to check the config is rejected.
+        """
+        old = json.dumps(config)
+        self.assertIsNotNone(datasrc_config_plugin.check({"classes":
+                                                         config}))
+        # There's some data mangling inside the plugin. Check it does
+        # not propagate out, as it could change the real configuration.
+        self.assertEqual(old, json.dumps(config))
+
+    def accept(self, config):
+        """
+        Just a shortcut to check the config is accepted.
+        """
+        old = json.dumps(config)
+        self.assertIsNone(datasrc_config_plugin.check({"classes":
+                                                      config}))
+        # There's some data mangling inside the plugin. Check it does
+        # not propagate out, as it could change the real configuration.
+        self.assertEqual(old, json.dumps(config))
+
+    def test_load(self):
+        """
+        Checks the entry point returns the correct values.
+        """
+        (spec, check) = datasrc_config_plugin.load()
+        # It returns the checking function
+        self.assertEqual(check, datasrc_config_plugin.check)
+        # The plugin stores it's spec
+        self.assertEqual(spec, datasrc_config_plugin.spec)
+
+    def test_empty(self):
+        """
+        Check an empty input is OK.
+        """
+        self.accept({})
+
+    def test_invalid_spec(self):
+        """
+        Check it rejects stuff that is not well-formed according
+        to the spec.
+        """
+        self.reject("test")
+        self.reject(13)
+        self.reject([])
+        self.reject({"IN": {}})
+        self.reject({"IN": [{"bad-name": True}]})
+
+    def test_class(self):
+        """
+        The class is rejected, if it is wrong.
+        """
+        self.reject({"BAD": []})
+        self.reject({"": []})
+        # But with a good one, it works
+        for c in ["IN", "CH", "HS"]:
+            self.accept({c: []})
+
+    def test_mem_ok(self):
+        """
+        Test we accept an in-memory data source. It doesn't really matter
+        which one it is. We just want to make sure we accept something
+        and this one does not need any kind of path mangling to find
+        plugins.
+        """
+        self.accept({"IN": [{
+            "type": "MasterFiles",
+            "cache-enable": True,
+            "params": {}
+        }]})
+
+    def test_dstype_bad(self):
+        """
+        The configuration is correct by the spec, but it would be rejected
+        by the client list. Check we reject it.
+        """
+        self.reject({"IN": [{
+            "type": "No such type"
+        }]})
+
+    def test_invalid_mem_params(self):
+        """
+        The client list skips in-memory sources. So we check it locally that
+        invalid things are rejected.
+        """
+        # The 'params' key is mandatory for MasterFiles
+        self.reject({"IN": [{
+            "type": "MasterFiles",
+            "cache-enable": True
+        }]})
+        # The cache must be enabled
+        self.reject({"IN": [{
+            "type": "MasterFiles",
+            "cache-enable": False,
+            "params": {}
+        }]})
+        self.reject({"IN": [{
+            "type": "MasterFiles",
+            "params": {}
+        }]})
+        # Bad params type
+        self.reject({"IN": [{
+            "type": "MasterFiles",
+            "cache-enable": True,
+            "params": []
+        }]})
+        # Bad name
+        self.reject({"IN": [{
+            "type": "MasterFiles",
+            "cache-enable": True,
+            "params": {
+                "example....org.": '/file/does/not/exist'
+            }
+        }]})
+
+    def test_no_such_file_mem(self):
+        """
+        We also check the existance of master files. Not the actual content,
+        though.
+        """
+        self.reject({"IN": [{
+            "type": "MasterFiles",
+            "cache-enable": True,
+            "params": {
+                "example.org.": '/file/does/not/exist'
+            }
+        }]})
+
+if __name__ == '__main__':
+    isc.log.init("bind10")
+    isc.log.resetUnitTestRootLogger()
+    unittest.main()

+ 9 - 0
src/bin/cmdctl/b10-cmdctl.8

@@ -9,6 +9,15 @@
 .\"
 .\"
 .TH "B10\-CMDCTL" "8" "February 28, 2012" "BIND10" "BIND10"
 .TH "B10\-CMDCTL" "8" "February 28, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" disable hyphenation
 .\" disable hyphenation

+ 17 - 21
src/bin/ddns/tests/ddns_test.py

@@ -1136,7 +1136,7 @@ class TestDDNSSession(unittest.TestCase):
         num_rrsets = len(self.__req_message.get_section(SECTION_PREREQUISITE))
         num_rrsets = len(self.__req_message.get_section(SECTION_PREREQUISITE))
         self.assertEqual(2, num_rrsets)
         self.assertEqual(2, num_rrsets)
 
 
-    def check_session_msg(self, result, expect_recv=1, notify_auth=False):
+    def check_session_msg(self, result, expect_recv=2):
         '''Check post update communication with other modules.'''
         '''Check post update communication with other modules.'''
         # iff the update succeeds, b10-ddns should tell interested other
         # iff the update succeeds, b10-ddns should tell interested other
         # modules the information about the update zone.  Possible modules
         # modules the information about the update zone.  Possible modules
@@ -1145,32 +1145,28 @@ class TestDDNSSession(unittest.TestCase):
         #                         'zone_class', <updated_zone_class>}]}
         #                         'zone_class', <updated_zone_class>}]}
         # for auth, it should be:
         # for auth, it should be:
         # {'command': ['loadzone', {'origin': <updated_zone_name>,
         # {'command': ['loadzone', {'origin': <updated_zone_name>,
-        #                           'class', <updated_zone_class>,
-        #                           'datasrc', <datasrc type, should be
-        #                                       "memory" in practice>}]}
+        #                           'class', <updated_zone_class>}]}
         # and expect an answer by calling group_recvmsg().
         # and expect an answer by calling group_recvmsg().
         #
         #
         # expect_recv indicates the expected number of calls to
         # expect_recv indicates the expected number of calls to
-        # group_recvmsg(), which is normally 1, but can be 0 if send fails;
+        # group_recvmsg(), which is normally 2, but can be 0 if send fails;
         # if the message is to be sent
         # if the message is to be sent
         if result == UPDATE_SUCCESS:
         if result == UPDATE_SUCCESS:
-            expected_sentmsg = 2 if notify_auth else 1
+            expected_sentmsg = 2
             self.assertEqual(expected_sentmsg,
             self.assertEqual(expected_sentmsg,
                              len(self.__cc_session._sent_msg))
                              len(self.__cc_session._sent_msg))
             self.assertEqual(expect_recv, self.__cc_session._recvmsg_called)
             self.assertEqual(expect_recv, self.__cc_session._recvmsg_called)
             msg_cnt = 0
             msg_cnt = 0
-            if notify_auth:
-                sent_msg, sent_group = self.__cc_session._sent_msg[msg_cnt]
-                sent_cmd = sent_msg['command']
-                self.assertEqual('Auth', sent_group)
-                self.assertEqual('loadzone', sent_cmd[0])
-                self.assertEqual(3, len(sent_cmd[1]))
-                self.assertEqual(TEST_ZONE_NAME.to_text(),
-                                 sent_cmd[1]['origin'])
-                self.assertEqual(TEST_RRCLASS.to_text(),
-                                 sent_cmd[1]['class'])
-                self.assertEqual('memory', sent_cmd[1]['datasrc'])
-                msg_cnt += 1
+            sent_msg, sent_group = self.__cc_session._sent_msg[msg_cnt]
+            sent_cmd = sent_msg['command']
+            self.assertEqual('Auth', sent_group)
+            self.assertEqual('loadzone', sent_cmd[0])
+            self.assertEqual(2, len(sent_cmd[1]))
+            self.assertEqual(TEST_ZONE_NAME.to_text(),
+                             sent_cmd[1]['origin'])
+            self.assertEqual(TEST_RRCLASS.to_text(),
+                             sent_cmd[1]['class'])
+            msg_cnt += 1
             sent_msg, sent_group = self.__cc_session._sent_msg[msg_cnt]
             sent_msg, sent_group = self.__cc_session._sent_msg[msg_cnt]
             sent_cmd = sent_msg['command']
             sent_cmd = sent_msg['command']
             self.assertEqual('Xfrout', sent_group)
             self.assertEqual('Xfrout', sent_group)
@@ -1267,21 +1263,21 @@ class TestDDNSSession(unittest.TestCase):
             [{'type': 'memory', 'class': 'IN', 'zones': [
             [{'type': 'memory', 'class': 'IN', 'zones': [
                     {'origin': TEST_ZONE_NAME_STR, 'filetype': 'sqlite3'}]}]
                     {'origin': TEST_ZONE_NAME_STR, 'filetype': 'sqlite3'}]}]
         self.check_session()
         self.check_session()
-        self.check_session_msg(UPDATE_SUCCESS, expect_recv=2, notify_auth=True)
+        self.check_session_msg(UPDATE_SUCCESS)
 
 
         # Let sendmsg() raise an exception.  The first exception shouldn't
         # Let sendmsg() raise an exception.  The first exception shouldn't
         # stop sending the second message.  There's just no recv calls.
         # stop sending the second message.  There's just no recv calls.
         self.__cc_session.clear_msg()
         self.__cc_session.clear_msg()
         self.__cc_session._sendmsg_exception = SessionError('send error')
         self.__cc_session._sendmsg_exception = SessionError('send error')
         self.check_session()
         self.check_session()
-        self.check_session_msg(UPDATE_SUCCESS, expect_recv=0, notify_auth=True)
+        self.check_session_msg(UPDATE_SUCCESS, expect_recv=0)
 
 
         # Likewise, in the case recvmsg() raises (and there should be recv
         # Likewise, in the case recvmsg() raises (and there should be recv
         # calls in this case)
         # calls in this case)
         self.__cc_session.clear_msg()
         self.__cc_session.clear_msg()
         self.__cc_session._recvmsg_exception = SessionError('recv error')
         self.__cc_session._recvmsg_exception = SessionError('recv error')
         self.check_session()
         self.check_session()
-        self.check_session_msg(UPDATE_SUCCESS, expect_recv=2, notify_auth=True)
+        self.check_session_msg(UPDATE_SUCCESS)
 
 
     def test_session_with_config(self):
     def test_session_with_config(self):
         '''Check a session with more realistic config setups.
         '''Check a session with more realistic config setups.

+ 6 - 6
src/bin/dhcp4/Makefile.am

@@ -39,12 +39,12 @@ if USE_CLANGPP
 b10_dhcp4_CXXFLAGS = -Wno-unused-parameter
 b10_dhcp4_CXXFLAGS = -Wno-unused-parameter
 endif
 endif
 
 
-b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp++.la
-b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-b10_dhcp4_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-b10_dhcp4_LDADD += $(top_builddir)/src/lib/log/liblog.la
-b10_dhcp4_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-b10_dhcp4_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
 
 
 
 
 b10_dhcp4dir = $(pkgdatadir)
 b10_dhcp4dir = $(pkgdatadir)

+ 4 - 4
src/bin/dhcp4/ctrl_dhcp4_srv.cc

@@ -82,19 +82,19 @@ void ControlledDhcpv4Srv::sessionReader(void) {
 }
 }
 
 
 void ControlledDhcpv4Srv::establishSession() {
 void ControlledDhcpv4Srv::establishSession() {
-    
+
     string specfile;
     string specfile;
     if (getenv("B10_FROM_BUILD")) {
     if (getenv("B10_FROM_BUILD")) {
         specfile = string(getenv("B10_FROM_BUILD")) +
         specfile = string(getenv("B10_FROM_BUILD")) +
-            "/src/bin/auth/dhcp4.spec";
+            "/src/bin/dhcp4/dhcp4.spec";
     } else {
     } else {
         specfile = string(DHCP4_SPECFILE_LOCATION);
         specfile = string(DHCP4_SPECFILE_LOCATION);
     }
     }
 
 
     /// @todo: Check if session is not established already. Throw, if it is.
     /// @todo: Check if session is not established already. Throw, if it is.
-    
+
     cout << "b10-dhcp4: my specfile is " << specfile << endl;
     cout << "b10-dhcp4: my specfile is " << specfile << endl;
-    
+
     cc_session_ = new Session(io_service_.get_io_service());
     cc_session_ = new Session(io_service_.get_io_service());
 
 
     config_session_ = new ModuleCCSession(specfile, *cc_session_,
     config_session_ = new ModuleCCSession(specfile, *cc_session_,

+ 12 - 7
src/bin/dhcp4/dhcp4_srv.cc

@@ -37,16 +37,21 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";
 Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
 Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
     cout << "Initialization: opening sockets on port " << port << endl;
     cout << "Initialization: opening sockets on port " << port << endl;
 
 
-    // first call to instance() will create IfaceMgr (it's a singleton)
-    // it may throw something if things go wrong
-    IfaceMgr::instance();
+    try {
+        // first call to instance() will create IfaceMgr (it's a singleton)
+        // it may throw something if things go wrong
+        IfaceMgr::instance();
 
 
-    /// @todo: instantiate LeaseMgr here once it is imlpemented.
-    IfaceMgr::instance().printIfaces();
+        /// @todo: instantiate LeaseMgr here once it is imlpemented.
 
 
-    IfaceMgr::instance().openSockets4(port);
+        IfaceMgr::instance().openSockets4(port);
 
 
-    setServerID();
+        setServerID();
+    } catch (const std::exception &e) {
+        cerr << "Error during DHCPv4 server startup: " << e.what() << endl;
+        shutdown_ = true;
+        return;
+    }
 
 
     shutdown_ = false;
     shutdown_ = false;
 }
 }

+ 36 - 15
src/bin/dhcp4/main.cc

@@ -14,18 +14,14 @@
 
 
 #include <config.h>
 #include <config.h>
 #include <iostream>
 #include <iostream>
-#include <exceptions/exceptions.h>
 #include <log/dummylog.h>
 #include <log/dummylog.h>
 #include <log/logger_support.h>
 #include <log/logger_support.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/ctrl_dhcp4_srv.h>
-#include <dhcp4/dhcp4_srv.h>
-#include <dhcp/dhcp4.h>
+#include <boost/lexical_cast.hpp>
 
 
 using namespace std;
 using namespace std;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 
 
-
-
 /// This file contains entry point (main() function) for standard DHCPv4 server
 /// This file contains entry point (main() function) for standard DHCPv4 server
 /// component for BIND10 framework. It parses command-line arguments and
 /// component for BIND10 framework. It parses command-line arguments and
 /// instantiates ControlledDhcpv4Srv class that is responsible for establishing
 /// instantiates ControlledDhcpv4Srv class that is responsible for establishing
@@ -44,7 +40,9 @@ usage() {
     cerr << "Usage:  b10-dhcp4 [-v]"
     cerr << "Usage:  b10-dhcp4 [-v]"
          << endl;
          << endl;
     cerr << "\t-v: verbose output" << endl;
     cerr << "\t-v: verbose output" << endl;
-    cerr << "\t-p number: specify non-standard port number 1-65535 (useful for testing only)" << endl;
+    cerr << "\t-s: stand-alone mode (don't connect to BIND10)" << endl;
+    cerr << "\t-p number: specify non-standard port number 1-65535 "
+         << "(useful for testing only)" << endl;
     exit(EXIT_FAILURE);
     exit(EXIT_FAILURE);
 }
 }
 } // end of anonymous namespace
 } // end of anonymous namespace
@@ -55,16 +53,26 @@ main(int argc, char* argv[]) {
     bool verbose_mode = false; // should server be verbose?
     bool verbose_mode = false; // should server be verbose?
     int port_number = DHCP4_SERVER_PORT; // The default. any other values are
     int port_number = DHCP4_SERVER_PORT; // The default. any other values are
                                          // useful for testing only.
                                          // useful for testing only.
+    bool stand_alone = false; // should be connect to BIND10 msgq?
 
 
-    while ((ch = getopt(argc, argv, "vp:")) != -1) {
+    while ((ch = getopt(argc, argv, "vsp:")) != -1) {
         switch (ch) {
         switch (ch) {
         case 'v':
         case 'v':
             verbose_mode = true;
             verbose_mode = true;
             isc::log::denabled = true;
             isc::log::denabled = true;
             break;
             break;
+        case 's':
+            stand_alone = true;
+            break;
         case 'p':
         case 'p':
-            port_number = strtol(optarg, NULL, 10);
-            if (port_number == 0) {
+            try {
+                port_number = boost::lexical_cast<int>(optarg);
+            } catch (const boost::bad_lexical_cast &) {
+                cerr << "Failed to parse port number: [" << optarg
+                     << "], 1-65535 allowed." << endl;
+                usage();
+            }
+            if (port_number <= 0 || port_number > 65535) {
                 cerr << "Failed to parse port number: [" << optarg
                 cerr << "Failed to parse port number: [" << optarg
                      << "], 1-65535 allowed." << endl;
                      << "], 1-65535 allowed." << endl;
                 usage();
                 usage();
@@ -81,8 +89,9 @@ main(int argc, char* argv[]) {
                          (verbose_mode ? isc::log::DEBUG : isc::log::INFO),
                          (verbose_mode ? isc::log::DEBUG : isc::log::INFO),
                          isc::log::MAX_DEBUG_LEVEL, NULL);
                          isc::log::MAX_DEBUG_LEVEL, NULL);
 
 
-    cout << "b10-dhcp4: My pid=" << getpid() << ", binding to port " 
-         << port_number << ", verbose " << (verbose_mode?"yes":"no") << endl;
+    cout << "b10-dhcp4: My pid=" << getpid() << ", binding to port "
+         << port_number << ", verbose " << (verbose_mode?"yes":"no")
+         << ", stand-alone=" << (stand_alone?"yes":"no") << endl;
 
 
     if (argc - optind > 0) {
     if (argc - optind > 0) {
         usage();
         usage();
@@ -94,11 +103,23 @@ main(int argc, char* argv[]) {
 
 
         cout << "[b10-dhcp4] Initiating DHCPv4 server operation." << endl;
         cout << "[b10-dhcp4] Initiating DHCPv4 server operation." << endl;
 
 
-        ControlledDhcpv4Srv* server = new ControlledDhcpv4Srv(port_number);
-        server->run();
-        delete server;
-        server = NULL;
+        /// @todo: pass verbose to the actul server once logging is implemented
+        ControlledDhcpv4Srv server(port_number);
+
+        if (!stand_alone) {
+            try {
+                server.establishSession();
+            } catch (const std::exception& ex) {
+                cerr << "Failed to establish BIND10 session. "
+                    "Running in stand-alone mode:" << ex.what() << endl;
+                // Let's continue. It is useful to have the ability to run
+                // DHCP server in stand-alone mode, e.g. for testing
+            }
+        } else {
+            cout << "Skipping connection to the BIND10 msgq." << endl;
+        }
 
 
+        server.run();
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
         cerr << "[b10-dhcp4] Server failed: " << ex.what() << endl;
         cerr << "[b10-dhcp4] Server failed: " << ex.what() << endl;
         ret = EXIT_FAILURE;
         ret = EXIT_FAILURE;

+ 7 - 7
src/bin/dhcp4/tests/Makefile.am

@@ -60,13 +60,13 @@ endif
 dhcp4_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 dhcp4_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 dhcp4_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 dhcp4_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 dhcp4_unittests_LDADD = $(GTEST_LDADD)
 dhcp4_unittests_LDADD = $(GTEST_LDADD)
-dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-dhcp4_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la
-dhcp4_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-dhcp4_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
-dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-dhcp4_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-dhcp4_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
 endif
 endif
 
 
 noinst_PROGRAMS = $(TESTS)
 noinst_PROGRAMS = $(TESTS)

+ 3 - 3
src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -64,7 +64,7 @@ TEST_F(CtrlDhcpv4SrvTest, commands) {
     ConstElementPtr comment = parseAnswer(rcode, result);
     ConstElementPtr comment = parseAnswer(rcode, result);
     EXPECT_EQ(1, rcode); // expect failure (no such command as blah)
     EXPECT_EQ(1, rcode); // expect failure (no such command as blah)
 
 
-    // case 1: send shutdown command without any parameters
+    // case 2: send shutdown command without any parameters
     result = ControlledDhcpv4Srv::execDhcpv4ServerCommand("shutdown", params);
     result = ControlledDhcpv4Srv::execDhcpv4ServerCommand("shutdown", params);
     comment = parseAnswer(rcode, result);
     comment = parseAnswer(rcode, result);
     EXPECT_EQ(0, rcode); // expect success
     EXPECT_EQ(0, rcode); // expect success
@@ -73,7 +73,7 @@ TEST_F(CtrlDhcpv4SrvTest, commands) {
     ConstElementPtr x(new isc::data::IntElement(pid));
     ConstElementPtr x(new isc::data::IntElement(pid));
     params->set("pid", x);
     params->set("pid", x);
 
 
-    // case 2: send shutdown command with 1 parameter: pid
+    // case 3: send shutdown command with 1 parameter: pid
     result = ControlledDhcpv4Srv::execDhcpv4ServerCommand("shutdown", params);
     result = ControlledDhcpv4Srv::execDhcpv4ServerCommand("shutdown", params);
     comment = parseAnswer(rcode, result);
     comment = parseAnswer(rcode, result);
     EXPECT_EQ(0, rcode); // expect success
     EXPECT_EQ(0, rcode); // expect success

+ 40 - 5
src/bin/dhcp4/tests/dhcp4_test.py

@@ -34,7 +34,7 @@ class TestDhcpv4Daemon(unittest.TestCase):
     def tearDown(self):
     def tearDown(self):
         pass
         pass
 
 
-    def runDhcp4(self, params, wait=1):
+    def runCommand(self, params, wait=1):
         """
         """
         This method runs dhcp4 and returns a touple: (returncode, stdout, stderr)
         This method runs dhcp4 and returns a touple: (returncode, stdout, stderr)
         """
         """
@@ -127,14 +127,14 @@ class TestDhcpv4Daemon(unittest.TestCase):
         print("Note: Purpose of some of the tests is to check if DHCPv4 server can be started,")
         print("Note: Purpose of some of the tests is to check if DHCPv4 server can be started,")
         print("      not that is can bind sockets correctly. Please ignore binding errors.")
         print("      not that is can bind sockets correctly. Please ignore binding errors.")
 
 
-        (returncode, output, error) = self.runDhcp4(["../b10-dhcp4", "-v"])
+        (returncode, output, error) = self.runCommand(["../b10-dhcp4", "-v"])
 
 
         self.assertEqual( str(output).count("[b10-dhcp4] Initiating DHCPv4 server operation."), 1)
         self.assertEqual( str(output).count("[b10-dhcp4] Initiating DHCPv4 server operation."), 1)
 
 
     def test_portnumber_0(self):
     def test_portnumber_0(self):
         print("Check that specifying port number 0 is not allowed.")
         print("Check that specifying port number 0 is not allowed.")
 
 
-        (returncode, output, error) = self.runDhcp4(['../b10-dhcp4', '-p', '0'])
+        (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p', '0'])
 
 
         # When invalid port number is specified, return code must not be success
         # When invalid port number is specified, return code must not be success
         self.assertTrue(returncode != 0)
         self.assertTrue(returncode != 0)
@@ -145,7 +145,7 @@ class TestDhcpv4Daemon(unittest.TestCase):
     def test_portnumber_missing(self):
     def test_portnumber_missing(self):
         print("Check that -p option requires a parameter.")
         print("Check that -p option requires a parameter.")
 
 
-        (returncode, output, error) = self.runDhcp4(['../b10-dhcp4', '-p'])
+        (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p'])
 
 
         # When invalid port number is specified, return code must not be success
         # When invalid port number is specified, return code must not be success
         self.assertTrue(returncode != 0)
         self.assertTrue(returncode != 0)
@@ -153,10 +153,32 @@ class TestDhcpv4Daemon(unittest.TestCase):
         # Check that there is an error message about invalid port number printed on stderr
         # Check that there is an error message about invalid port number printed on stderr
         self.assertEqual( str(error).count("option requires an argument"), 1)
         self.assertEqual( str(error).count("option requires an argument"), 1)
 
 
+    def test_portnumber_invalid1(self):
+        print("Check that -p option is check against bogus port number (999999).")
+
+        (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p','999999'])
+
+        # When invalid port number is specified, return code must not be success
+        self.assertTrue(returncode != 0)
+
+        # Check that there is an error message about invalid port number printed on stderr
+        self.assertEqual( str(error).count("Failed to parse port number"), 1)
+
+    def test_portnumber_invalid2(self):
+        print("Check that -p option is check against bogus port number (123garbage).")
+
+        (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-p','123garbage'])
+
+        # When invalid port number is specified, return code must not be success
+        self.assertTrue(returncode != 0)
+
+        # Check that there is an error message about invalid port number printed on stderr
+        self.assertEqual( str(error).count("Failed to parse port number"), 1)
+
     def test_portnumber_nonroot(self):
     def test_portnumber_nonroot(self):
         print("Check that specifying unprivileged port number will work.")
         print("Check that specifying unprivileged port number will work.")
 
 
-        (returncode, output, error) = self.runDhcp4(['../b10-dhcp4', '-p', '10057'])
+        (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-s', '-p', '10057'])
 
 
         # When invalid port number is specified, return code must not be success
         # When invalid port number is specified, return code must not be success
         # TODO: Temporarily commented out as socket binding on systems that do not have
         # TODO: Temporarily commented out as socket binding on systems that do not have
@@ -166,5 +188,18 @@ class TestDhcpv4Daemon(unittest.TestCase):
         # Check that there is an error message about invalid port number printed on stderr
         # Check that there is an error message about invalid port number printed on stderr
         self.assertEqual( str(output).count("opening sockets on port 10057"), 1)
         self.assertEqual( str(output).count("opening sockets on port 10057"), 1)
 
 
+    def test_skip_msgq(self):
+        print("Check that connection to BIND10 msgq can be disabled.")
+
+        (returncode, output, error) = self.runCommand(['../b10-dhcp4', '-s', '-p', '10057'])
+
+        # When invalid port number is specified, return code must not be success
+        # TODO: Temporarily commented out as socket binding on systems that do not have
+        #       interface detection implemented currently fails.
+        # self.assertTrue(returncode == 0)
+
+        # Check that there is an error message about invalid port number printed on stderr
+        self.assertEqual( str(output).count("Skipping connection to the BIND10 msgq."), 1)
+
 if __name__ == '__main__':
 if __name__ == '__main__':
     unittest.main()
     unittest.main()

+ 7 - 4
src/bin/dhcp6/Makefile.am

@@ -33,6 +33,7 @@ BUILT_SOURCES = spec_config.h
 pkglibexec_PROGRAMS = b10-dhcp6
 pkglibexec_PROGRAMS = b10-dhcp6
 
 
 b10_dhcp6_SOURCES = main.cc dhcp6_srv.cc dhcp6_srv.h
 b10_dhcp6_SOURCES = main.cc dhcp6_srv.cc dhcp6_srv.h
+b10_dhcp6_SOURCES += ctrl_dhcp6_srv.cc ctrl_dhcp6_srv.h
 
 
 if USE_CLANGPP
 if USE_CLANGPP
 # Disable unused parameter warning caused by some of the
 # Disable unused parameter warning caused by some of the
@@ -40,10 +41,12 @@ if USE_CLANGPP
 b10_dhcp6_CXXFLAGS = -Wno-unused-parameter
 b10_dhcp6_CXXFLAGS = -Wno-unused-parameter
 endif
 endif
 
 
-b10_dhcp6_LDADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/liblog.la
-b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la
+b10_dhcp6_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+b10_dhcp6_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
 
 
 b10_dhcp6dir = $(pkgdatadir)
 b10_dhcp6dir = $(pkgdatadir)
 b10_dhcp6_DATA = dhcp6.spec
 b10_dhcp6_DATA = dhcp6.spec

+ 159 - 0
src/bin/dhcp6/ctrl_dhcp6_srv.cc

@@ -0,0 +1,159 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <cassert>
+#include <iostream>
+
+#include <cc/session.h>
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
+#include <cc/session.h>
+#include <config/ccsession.h>
+#include <util/buffer.h>
+#include <dhcp6/spec_config.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
+#include <dhcp/iface_mgr.h>
+#include <asiolink/asiolink.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::dhcp;
+using namespace isc::util;
+using namespace isc::data;
+using namespace isc::cc;
+using namespace isc::config;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+ControlledDhcpv6Srv* ControlledDhcpv6Srv::server_ = NULL;
+
+ConstElementPtr
+ControlledDhcpv6Srv::dhcp6ConfigHandler(ConstElementPtr new_config) {
+    cout << "b10-dhcp6: Received new config:" << new_config->str() << endl;
+    ConstElementPtr answer = isc::config::createAnswer(0,
+                             "Thank you for sending config.");
+    return (answer);
+}
+
+ConstElementPtr
+ControlledDhcpv6Srv::dhcp6CommandHandler(const string& command, ConstElementPtr args) {
+    cout << "b10-dhcp6: Received new command: [" << command << "], args="
+         << args->str() << endl;
+    if (command == "shutdown") {
+        if (ControlledDhcpv6Srv::server_) {
+            ControlledDhcpv6Srv::server_->shutdown();
+        } else {
+            cout << "Server not initialized yet or already shut down." << endl;
+            ConstElementPtr answer = isc::config::createAnswer(1,
+                                     "Shutdown failure.");
+            return (answer);
+        }
+        ConstElementPtr answer = isc::config::createAnswer(0,
+                                 "Shutting down.");
+        return (answer);
+    }
+
+    ConstElementPtr answer = isc::config::createAnswer(1,
+                             "Unrecognized command.");
+
+    return (answer);
+}
+
+void ControlledDhcpv6Srv::sessionReader(void) {
+    // Process one asio event. If there are more events, iface_mgr will call
+    // this callback more than once.
+    if (server_) {
+        server_->io_service_.run_one();
+    }
+}
+
+void ControlledDhcpv6Srv::establishSession() {
+    
+    string specfile;
+    if (getenv("B10_FROM_BUILD")) {
+        specfile = string(getenv("B10_FROM_BUILD")) +
+            "/src/bin/dhcp6/dhcp6.spec";
+    } else {
+        specfile = string(DHCP6_SPECFILE_LOCATION);
+    }
+
+    /// @todo: Check if session is not established already. Throw, if it is.
+    
+    cout << "b10-dhcp6: my specfile is " << specfile << endl;
+    
+    cc_session_ = new Session(io_service_.get_io_service());
+
+    config_session_ = new ModuleCCSession(specfile, *cc_session_,
+                                          dhcp6ConfigHandler,
+                                          dhcp6CommandHandler, false);
+    config_session_->start();
+
+    /// Integrate the asynchronous I/O model of BIND 10 configuration
+    /// control with the "select" model of the DHCP server.  This is
+    /// fully explained in \ref dhcpv6Session.
+    int ctrl_socket = cc_session_->getSocketDesc();
+    cout << "b10-dhcp6: Control session started, socket="
+         << ctrl_socket << endl;
+    IfaceMgr::instance().set_session_socket(ctrl_socket, sessionReader);
+}
+
+void ControlledDhcpv6Srv::disconnectSession() {
+    if (config_session_) {
+        delete config_session_;
+        config_session_ = NULL;
+    }
+    if (cc_session_) {
+        cc_session_->disconnect();
+        delete cc_session_;
+        cc_session_ = NULL;
+    }
+
+    // deregister session socket
+    IfaceMgr::instance().set_session_socket(IfaceMgr::INVALID_SOCKET, NULL);
+}
+
+ControlledDhcpv6Srv::ControlledDhcpv6Srv(uint16_t port /*= DHCP6_SERVER_PORT*/)
+    :Dhcpv6Srv(port), cc_session_(NULL), config_session_(NULL) {
+    server_ = this; // remember this instance for use in callback
+}
+
+void ControlledDhcpv6Srv::shutdown() {
+    io_service_.stop(); // Stop ASIO transmissions
+    Dhcpv6Srv::shutdown(); // Initiate DHCPv6 shutdown procedure.
+}
+
+ControlledDhcpv6Srv::~ControlledDhcpv6Srv() {
+    disconnectSession();
+
+    server_ = NULL; // forget this instance. There should be no callback anymore
+                    // at this stage anyway.
+}
+
+isc::data::ConstElementPtr
+ControlledDhcpv6Srv::execDhcpv6ServerCommand(const std::string& command_id,
+                                             isc::data::ConstElementPtr args) {
+    try {
+        return (dhcp6CommandHandler(command_id, args));
+    } catch (const Exception& ex) {
+        ConstElementPtr answer = isc::config::createAnswer(1, ex.what());
+        return (answer);
+    }
+}
+
+
+};
+};

+ 123 - 0
src/bin/dhcp6/ctrl_dhcp6_srv.h

@@ -0,0 +1,123 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef CTRL_DHCPV6_SRV_H
+#define CTRL_DHCPV6_SRV_H
+
+#include <dhcp6/dhcp6_srv.h>
+#include <asiolink/asiolink.h>
+#include <cc/session.h>
+#include <config/ccsession.h>
+#include <cc/data.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Controlled version of the DHCPv6 server
+///
+/// This is a class that is responsible for establishing connection
+/// with msqg (receving commands and configuration). This is an extended
+/// version of Dhcpv6Srv class that is purely a DHCPv6 server, without
+/// external control. ControlledDhcpv6Srv should be used in typical BIND10
+/// (i.e. featuring msgq) environment, while Dhcpv6Srv should be used in
+/// embedded environments.
+///
+/// For detailed explanation or relations between main(), ControlledDhcpv6Srv,
+/// Dhcpv6Srv and other classes, see \ref dhcpv6Session.
+class ControlledDhcpv6Srv : public isc::dhcp::Dhcpv6Srv {
+public:
+
+    /// @brief Constructor
+    ///
+    /// @param port UDP port to be opened for DHCP traffic
+    ControlledDhcpv6Srv(uint16_t port = DHCP6_SERVER_PORT);
+
+    /// @brief Destructor.
+    ~ControlledDhcpv6Srv();
+
+    /// @brief Establishes msgq session.
+    ///
+    /// Creates session that will be used to receive commands and updated
+    /// configuration from boss (or indirectly from user via bindctl).
+    void establishSession();
+
+    /// @brief Terminates existing msgq session.
+    ///
+    /// This method terminates existing session with msgq. After calling
+    /// it, no further messages over msgq (commands or configuration updates)
+    /// may be received.
+    ///
+    /// It is ok to call this method when session is disconnected already.
+    void disconnectSession();
+
+    /// @brief Initiates shutdown procedure for the whole DHCPv6 server.
+    void shutdown();
+
+    /// @brief Session callback, processes received commands.
+    ///
+    /// @param command_id text represenation of the command (e.g. "shutdown")
+    /// @param args optional parameters
+    ///
+    /// @return status of the command
+    static isc::data::ConstElementPtr
+    execDhcpv6ServerCommand(const std::string& command,
+                            isc::data::ConstElementPtr args);
+
+protected:
+    /// @brief Static pointer to the sole instance of the DHCP server.
+    ///
+    /// This is required for config and command handlers to gain access to
+    /// the server
+    static ControlledDhcpv6Srv* server_;
+
+    /// @brief A callback for handling incoming configuration updates.
+    ///
+    /// As pointer to this method is used a callback in ASIO used in
+    /// ModuleCCSession, it has to be static.
+    ///
+    /// @param new_config textual representation of the new configuration
+    ///
+    /// @return status of the config update
+    static isc::data::ConstElementPtr
+    dhcp6ConfigHandler(isc::data::ConstElementPtr new_config);
+
+    /// @brief A callback for handling incoming commands.
+    ///
+    /// @param command textual representation of the command
+    /// @param args parameters of the command
+    ///
+    /// @return status of the processed command
+    static isc::data::ConstElementPtr
+    dhcp6CommandHandler(const std::string& command, isc::data::ConstElementPtr args);
+
+    /// @brief Callback that will be called from iface_mgr when command/config arrives.
+    ///
+    /// This static callback method is called from IfaceMgr::receive6() method,
+    /// when there is a new command or configuration sent over msgq.
+    static void sessionReader(void);
+
+    /// @brief IOService object, used for all ASIO operations.
+    isc::asiolink::IOService io_service_;
+
+    /// @brief Helper session object that represents raw connection to msgq.
+    isc::cc::Session* cc_session_;
+
+    /// @brief Session that receives configuation and commands
+    isc::config::ModuleCCSession* config_session_;
+};
+
+}; // namespace isc::dhcp
+}; // namespace isc
+
+#endif

+ 14 - 2
src/bin/dhcp6/dhcp6.spec

@@ -1,6 +1,6 @@
 {
 {
   "module_spec": {
   "module_spec": {
-    "module_name": "dhcp6",
+    "module_name": "Dhcp6",
     "module_description": "DHCPv6 server daemon",
     "module_description": "DHCPv6 server daemon",
     "config_data": [
     "config_data": [
       { "item_name": "interface",
       { "item_name": "interface",
@@ -9,6 +9,18 @@
         "item_default": "eth0"
         "item_default": "eth0"
       }
       }
     ],
     ],
-    "commands": []
+    "commands": [
+        {
+            "command_name": "shutdown",
+            "command_description": "Shuts down DHCPv6 server.",
+            "command_args": [
+                {
+                    "item_name": "pid",
+                    "item_type": "integer",
+                    "item_optional": true
+                }
+            ]
+        }
+    ]
   }
   }
 }
 }

+ 24 - 16
src/bin/dhcp6/dhcp6_srv.cc

@@ -45,25 +45,26 @@ Dhcpv6Srv::Dhcpv6Srv(uint16_t port) {
     // first call to instance() will create IfaceMgr (it's a singleton)
     // first call to instance() will create IfaceMgr (it's a singleton)
     // it may throw something if things go wrong
     // it may throw something if things go wrong
     try {
     try {
-        IfaceMgr::instance();
-    } catch (const std::exception &e) {
-        cout << "Failed to instantiate InterfaceManager:" << e.what() << ". Aborting." << endl;
-        shutdown = true;
-    }
 
 
-    if (IfaceMgr::instance().countIfaces() == 0) {
-        cout << "Failed to detect any network interfaces. Aborting." << endl;
-        shutdown = true;
-    }
+        if (IfaceMgr::instance().countIfaces() == 0) {
+            cout << "Failed to detect any network interfaces. Aborting." << endl;
+            shutdown_ = true;
+            return;
+        }
+
+        IfaceMgr::instance().openSockets6(port);
 
 
-    // Now try to open IPv6 sockets on detected interfaces.
-    IfaceMgr::instance().openSockets6(port);
+        setServerID();
 
 
-    /// @todo: instantiate LeaseMgr here once it is imlpemented.
+        /// @todo: instantiate LeaseMgr here once it is imlpemented.
 
 
-    setServerID();
+    } catch (const std::exception &e) {
+        cerr << "Error during DHCPv4 server startup: " << e.what() << endl;
+        shutdown_ = true;
+        return;
+    }
 
 
-    shutdown = false;
+    shutdown_ = false;
 }
 }
 
 
 Dhcpv6Srv::~Dhcpv6Srv() {
 Dhcpv6Srv::~Dhcpv6Srv() {
@@ -72,11 +73,18 @@ Dhcpv6Srv::~Dhcpv6Srv() {
     IfaceMgr::instance().closeSockets();
     IfaceMgr::instance().closeSockets();
 }
 }
 
 
+void Dhcpv6Srv::shutdown() {
+    cout << "b10-dhcp6: DHCPv6 server shutdown." << endl;
+    shutdown_ = true;
+}
+
 bool Dhcpv6Srv::run() {
 bool Dhcpv6Srv::run() {
-    while (!shutdown) {
+    while (!shutdown_) {
+        /// @todo: calculate actual timeout once we have lease database
+        int timeout = 1000;
 
 
         // client's message and server's response
         // client's message and server's response
-        Pkt6Ptr query = IfaceMgr::instance().receive6();
+        Pkt6Ptr query = IfaceMgr::instance().receive6(timeout);
         Pkt6Ptr rsp;
         Pkt6Ptr rsp;
 
 
         if (query) {
         if (query) {

+ 3 - 1
src/bin/dhcp6/dhcp6_srv.h

@@ -67,6 +67,8 @@ public:
     ///         critical error.
     ///         critical error.
     bool run();
     bool run();
 
 
+    /// @brief Instructs the server to shut down.
+    void shutdown();
 protected:
 protected:
     /// @brief Processes incoming SOLICIT and returns response.
     /// @brief Processes incoming SOLICIT and returns response.
     ///
     ///
@@ -184,7 +186,7 @@ protected:
 
 
     /// indicates if shutdown is in progress. Setting it to true will
     /// indicates if shutdown is in progress. Setting it to true will
     /// initiate server shutdown procedure.
     /// initiate server shutdown procedure.
-    volatile bool shutdown;
+    volatile bool shutdown_;
 };
 };
 
 
 }; // namespace isc::dhcp
 }; // namespace isc::dhcp

+ 56 - 49
src/bin/dhcp6/main.cc

@@ -13,47 +13,36 @@
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
 #include <config.h>
 #include <config.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <cassert>
 #include <iostream>
 #include <iostream>
-
-#include <exceptions/exceptions.h>
-#if 0
-// TODO cc is not used yet. It should be eventually
-#include <cc/session.h>
-#include <config/ccsession.h>
-#endif
-
-#include <util/buffer.h>
 #include <log/dummylog.h>
 #include <log/dummylog.h>
-
-#include <dhcp6/spec_config.h>
-#include "dhcp6/dhcp6_srv.h"
+#include <log/logger_support.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
+#include <boost/lexical_cast.hpp>
 
 
 using namespace std;
 using namespace std;
-using namespace isc::util;
-
-using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 
 
+/// This file contains entry point (main() function) for standard DHCPv6 server
+/// component for BIND10 framework. It parses command-line arguments and
+/// instantiates ControlledDhcpv6Srv class that is responsible for establishing
+/// connection with msgq (receiving commands and configuration) and also
+/// creating Dhcpv6 server object as well.
+///
+/// For detailed explanation or relations between main(), ControlledDhcpv6Srv,
+/// Dhcpv6Srv and other classes, see \ref dhcpv6Session.
+
 namespace {
 namespace {
 
 
-bool verbose_mode = false;
+const char* const DHCP6_NAME = "b10-dhcp6";
 
 
 void
 void
 usage() {
 usage() {
-    cerr << "Usage:  b10-dhcp6 [-v]"
+    cerr << "Usage: b10-dhcp6 [-v]"
          << endl;
          << endl;
     cerr << "\t-v: verbose output" << endl;
     cerr << "\t-v: verbose output" << endl;
-    cerr << "\t-p number: specify non-standard port number 1-65535 (useful for testing only)" << endl;
+    cerr << "\t-s: stand-alone mode (don't connect to BIND10)" << endl;
+    cerr << "\t-p number: specify non-standard port number 1-65535 "
+         << "(useful for testing only)" << endl;
     exit(EXIT_FAILURE);
     exit(EXIT_FAILURE);
 }
 }
 } // end of anonymous namespace
 } // end of anonymous namespace
@@ -63,16 +52,27 @@ main(int argc, char* argv[]) {
     int ch;
     int ch;
     int port_number = DHCP6_SERVER_PORT; // The default. Any other values are
     int port_number = DHCP6_SERVER_PORT; // The default. Any other values are
                                          // useful for testing only.
                                          // useful for testing only.
+    bool verbose_mode = false; // Should server be verbose?
+    bool stand_alone = false; // should be connect to BIND10 msgq?
 
 
-    while ((ch = getopt(argc, argv, "vp:")) != -1) {
+    while ((ch = getopt(argc, argv, "vsp:")) != -1) {
         switch (ch) {
         switch (ch) {
         case 'v':
         case 'v':
             verbose_mode = true;
             verbose_mode = true;
             isc::log::denabled = true;
             isc::log::denabled = true;
             break;
             break;
+        case 's':
+            stand_alone = true;
+            break;
         case 'p':
         case 'p':
-            port_number = strtol(optarg, NULL, 10);
-            if (port_number == 0) {
+            try {
+                port_number = boost::lexical_cast<int>(optarg);
+            } catch (const boost::bad_lexical_cast &) {
+                cerr << "Failed to parse port number: [" << optarg
+                     << "], 1-65535 allowed." << endl;
+                usage();
+            }
+            if (port_number <= 0 || port_number > 65535) {
                 cerr << "Failed to parse port number: [" << optarg
                 cerr << "Failed to parse port number: [" << optarg
                      << "], 1-65535 allowed." << endl;
                      << "], 1-65535 allowed." << endl;
                 usage();
                 usage();
@@ -84,7 +84,14 @@ main(int argc, char* argv[]) {
         }
         }
     }
     }
 
 
-    cout << "My pid=" << getpid() << endl;
+    // Initialize logging.  If verbose, we'll use maximum verbosity.
+    isc::log::initLogger(DHCP6_NAME,
+                         (verbose_mode ? isc::log::DEBUG : isc::log::INFO),
+                         isc::log::MAX_DEBUG_LEVEL, NULL);
+
+    cout << "b10-dhcp6: My pid=" << getpid() << ", binding to port "
+         << port_number << ", verbose " << (verbose_mode?"yes":"no")
+         << ", stand-alone=" << (stand_alone?"yes":"no") << endl;
 
 
     if (argc - optind > 0) {
     if (argc - optind > 0) {
         usage();
         usage();
@@ -92,27 +99,27 @@ main(int argc, char* argv[]) {
 
 
     int ret = EXIT_SUCCESS;
     int ret = EXIT_SUCCESS;
 
 
-    // TODO remainder of auth to dhcp6 code copy. We need to enable this in
-    //      dhcp6 eventually
-#if 0
-    Session* cc_session = NULL;
-    Session* statistics_session = NULL;
-    ModuleCCSession* config_session = NULL;
-#endif
     try {
     try {
-        string specfile;
-        if (getenv("B10_FROM_BUILD")) {
-            specfile = string(getenv("B10_FROM_BUILD")) +
-                "/src/bin/auth/dhcp6.spec";
-        } else {
-            specfile = string(DHCP6_SPECFILE_LOCATION);
-        }
 
 
-        cout << "[b10-dhcp6] Initiating DHCPv6 operation." << endl;
+        cout << "b10-dhcp6: Initiating DHCPv6 server operation." << endl;
 
 
-        Dhcpv6Srv* srv = new Dhcpv6Srv(port_number);
+        /// @todo: pass verbose to the actual server once logging is implemented
+        ControlledDhcpv6Srv server(port_number);
+
+        if (!stand_alone) {
+            try {
+                server.establishSession();
+            } catch (const std::exception& ex) {
+                cerr << "Failed to establish BIND10 session. "
+                    "Running in stand-alone mode:" << ex.what() << endl;
+                // Let's continue. It is useful to have the ability to run 
+                // DHCP server in stand-alone mode, e.g. for testing
+            }
+        } else {
+            cout << "Skipping connection to the BIND10 msgq." << endl;
+        }
 
 
-        srv->run();
+        server.run();
 
 
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
         cerr << "[b10-dhcp6] Server failed: " << ex.what() << endl;
         cerr << "[b10-dhcp6] Server failed: " << ex.what() << endl;

+ 8 - 5
src/bin/dhcp6/tests/Makefile.am

@@ -42,9 +42,10 @@ if HAVE_GTEST
 
 
 TESTS += dhcp6_unittests
 TESTS += dhcp6_unittests
 
 
-dhcp6_unittests_SOURCES = ../dhcp6_srv.h ../dhcp6_srv.cc
+dhcp6_unittests_SOURCES = ../dhcp6_srv.h ../dhcp6_srv.cc ../ctrl_dhcp6_srv.cc
 dhcp6_unittests_SOURCES += dhcp6_unittests.cc
 dhcp6_unittests_SOURCES += dhcp6_unittests.cc
 dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
 dhcp6_unittests_SOURCES += dhcp6_srv_unittest.cc
+dhcp6_unittests_SOURCES += ctrl_dhcp6_srv_unittest.cc
 
 
 if USE_CLANGPP
 if USE_CLANGPP
 # Disable unused parameter warning caused by some of the
 # Disable unused parameter warning caused by some of the
@@ -55,10 +56,12 @@ endif
 dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 dhcp6_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 dhcp6_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 dhcp6_unittests_LDADD = $(GTEST_LDADD)
 dhcp6_unittests_LDADD = $(GTEST_LDADD)
-dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la
-dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
-dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libb10-dhcp++.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+dhcp6_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
 
 
 endif
 endif
 
 

+ 85 - 0
src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc

@@ -0,0 +1,85 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
+#include <config/ccsession.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::config;
+
+namespace {
+
+class NakedControlledDhcpv6Srv: public ControlledDhcpv6Srv {
+    // "naked" DHCPv6 server, exposes internal fields
+public:
+    NakedControlledDhcpv6Srv():ControlledDhcpv6Srv(DHCP6_SERVER_PORT + 10000) { }
+};
+
+class CtrlDhcpv6SrvTest : public ::testing::Test {
+public:
+    CtrlDhcpv6SrvTest() {
+    }
+
+    ~CtrlDhcpv6SrvTest() {
+    };
+};
+
+TEST_F(CtrlDhcpv6SrvTest, commands) {
+
+    ControlledDhcpv6Srv* srv = NULL;
+    ASSERT_NO_THROW({
+        srv = new ControlledDhcpv6Srv(DHCP6_SERVER_PORT + 10000);
+    });
+
+    // use empty parameters list
+    ElementPtr params(new isc::data::MapElement());
+    int rcode = -1;
+
+    // case 1: send bogus command
+    ConstElementPtr result = ControlledDhcpv6Srv::execDhcpv6ServerCommand("blah", params);
+    ConstElementPtr comment = parseAnswer(rcode, result);
+    EXPECT_EQ(1, rcode); // expect failure (no such command as blah)
+
+    // case 2: send shutdown command without any parameters
+    result = ControlledDhcpv6Srv::execDhcpv6ServerCommand("shutdown", params);
+    comment = parseAnswer(rcode, result);
+    EXPECT_EQ(0, rcode); // expect success
+
+    const pid_t pid(getpid());
+    ConstElementPtr x(new isc::data::IntElement(pid));
+    params->set("pid", x);
+
+    // case 3: send shutdown command with 1 parameter: pid
+    result = ControlledDhcpv6Srv::execDhcpv6ServerCommand("shutdown", params);
+    comment = parseAnswer(rcode, result);
+    EXPECT_EQ(0, rcode); // expect success
+
+
+    delete srv;
+}
+
+} // end of anonymous namespace

+ 39 - 5
src/bin/dhcp6/tests/dhcp6_test.py

@@ -1,4 +1,4 @@
-# Copyright (C) 2011,2012 Internet Systems Consortium.
+# copyright (C) 2011,2012 Internet Systems Consortium.
 #
 #
 # Permission to use, copy, modify, and distribute this software for any
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # purpose with or without fee is hereby granted, provided that the above
@@ -131,7 +131,7 @@ class TestDhcpv6Daemon(unittest.TestCase):
         print("      not that is can bind sockets correctly. Please ignore binding errors.")
         print("      not that is can bind sockets correctly. Please ignore binding errors.")
         (returncode, output, error) = self.runCommand(["../b10-dhcp6", "-v"])
         (returncode, output, error) = self.runCommand(["../b10-dhcp6", "-v"])
 
 
-        self.assertEqual( str(output).count("[b10-dhcp6] Initiating DHCPv6 operation."), 1)
+        self.assertEqual( str(output).count("b10-dhcp6: Initiating DHCPv6 server operation."), 1)
 
 
     def test_portnumber_0(self):
     def test_portnumber_0(self):
         print("Check that specifying port number 0 is not allowed.")
         print("Check that specifying port number 0 is not allowed.")
@@ -155,18 +155,52 @@ class TestDhcpv6Daemon(unittest.TestCase):
         # Check that there is an error message about invalid port number printed on stderr
         # Check that there is an error message about invalid port number printed on stderr
         self.assertEqual( str(error).count("option requires an argument"), 1)
         self.assertEqual( str(error).count("option requires an argument"), 1)
 
 
+    def test_portnumber_invalid1(self):
+        print("Check that -p option is check against bogus port number (999999).")
+
+        (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-p','999999'])
+
+        # When invalid port number is specified, return code must not be success
+        self.assertTrue(returncode != 0)
+
+        # Check that there is an error message about invalid port number printed on stderr
+        self.assertEqual( str(error).count("Failed to parse port number"), 1)
+
+    def test_portnumber_invalid2(self):
+        print("Check that -p option is check against bogus port number (123garbage).")
+
+        (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-p','123garbage'])
+
+        # When invalid port number is specified, return code must not be success
+        self.assertTrue(returncode != 0)
+
+        # Check that there is an error message about invalid port number printed on stderr
+        self.assertEqual( str(error).count("Failed to parse port number"), 1)
+
     def test_portnumber_nonroot(self):
     def test_portnumber_nonroot(self):
         print("Check that specifying unprivileged port number will work.")
         print("Check that specifying unprivileged port number will work.")
 
 
-        (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-p', '10057'])
+        (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-s', '-p', '10547'])
+
+        # When invalid port number is specified, return code must not be success
+        # TODO: Temporarily commented out as socket binding on systems that do not have
+        #       interface detection implemented currently fails.
+        # self.assertTrue(returncode == 0)
+
+        self.assertEqual( str(output).count("opening sockets on port 10547"), 1)
+
+    def test_skip_msgq(self):
+        print("Check that connection to BIND10 msgq can be disabled.")
+
+        (returncode, output, error) = self.runCommand(['../b10-dhcp6', '-s', '-p', '10547'])
 
 
         # When invalid port number is specified, return code must not be success
         # When invalid port number is specified, return code must not be success
         # TODO: Temporarily commented out as socket binding on systems that do not have
         # TODO: Temporarily commented out as socket binding on systems that do not have
         #       interface detection implemented currently fails.
         #       interface detection implemented currently fails.
         # self.assertTrue(returncode == 0)
         # self.assertTrue(returncode == 0)
 
 
-        # Check that there is a message on stdout about opening proper port
-        self.assertEqual( str(output).count("opening sockets on port 10057"), 1)
+        self.assertEqual( str(output).count("Skipping connection to the BIND10 msgq."), 1)
+
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
     unittest.main()
     unittest.main()

+ 3 - 3
src/bin/host/Makefile.am

@@ -12,9 +12,9 @@ CLEANFILES = *.gcno *.gcda
 
 
 bin_PROGRAMS = b10-host
 bin_PROGRAMS = b10-host
 b10_host_SOURCES = host.cc
 b10_host_SOURCES = host.cc
-b10_host_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
-b10_host_LDADD += $(top_builddir)/src/lib/util/libutil.la
-b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+b10_host_LDADD = $(top_builddir)/src/lib/dns/libb10-dns++.la
+b10_host_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+b10_host_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 
 
 man_MANS = b10-host.1
 man_MANS = b10-host.1
 EXTRA_DIST = $(man_MANS) b10-host.xml
 EXTRA_DIST = $(man_MANS) b10-host.xml

+ 0 - 4
src/bin/loadzone/Makefile.am

@@ -20,10 +20,6 @@ b10-loadzone: b10-loadzone.py
 	       -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" b10-loadzone.py >$@
 	       -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" b10-loadzone.py >$@
 	chmod a+x $@
 	chmod a+x $@
 
 
-install-data-local:
-	$(mkinstalldirs) $(DESTDIR)/@localstatedir@/@PACKAGE@
-# TODO: permissions handled later
-
 EXTRA_DIST += tests/normal/README
 EXTRA_DIST += tests/normal/README
 EXTRA_DIST += tests/normal/dsset-subzone.example.com
 EXTRA_DIST += tests/normal/dsset-subzone.example.com
 EXTRA_DIST += tests/normal/example.com
 EXTRA_DIST += tests/normal/example.com

+ 2 - 4
src/bin/msgq/b10-msgq.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-msgq
 .\"     Title: b10-msgq
 .\"    Author: [see the "AUTHORS" section]
 .\"    Author: [see the "AUTHORS" section]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: August 4, 2010
+.\"      Date: June 25, 2012
 .\"    Manual: BIND10
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"  Language: English
 .\"
 .\"
-.TH "B10\-MSGQ" "8" "August 4, 2010" "BIND10" "BIND10"
+.TH "B10\-MSGQ" "8" "June 25, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
@@ -87,8 +87,6 @@ is assigned a unique identifier \-\- this is the local name\&. The commands it h
 .sp
 .sp
 .RE
 .RE
 .PP
 .PP
-It listens on 127\&.0\&.0\&.1\&.
-.PP
 The
 The
 \fBb10\-msgq\fR
 \fBb10\-msgq\fR
 daemon may be cleanly stopped by sending the SIGTERM signal to the process\&. This shutdown does not notify the subscribers\&.
 daemon may be cleanly stopped by sending the SIGTERM signal to the process\&. This shutdown does not notify the subscribers\&.

+ 14 - 14
src/bin/resolver/Makefile.am

@@ -56,20 +56,20 @@ b10_resolver_SOURCES += common.cc common.h
 nodist_b10_resolver_SOURCES = resolver_messages.cc resolver_messages.h
 nodist_b10_resolver_SOURCES = resolver_messages.cc resolver_messages.h
 
 
 
 
-b10_resolver_LDADD =  $(top_builddir)/src/lib/dns/libdns++.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/util/libutil.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/acl/libdnsacl.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/log/liblog.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/cache/libcache.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
-b10_resolver_LDADD += $(top_builddir)/src/lib/resolve/libresolve.la
+b10_resolver_LDADD =  $(top_builddir)/src/lib/dns/libb10-dns++.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/acl/libb10-dnsacl.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/xfr/libb10-xfr.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/cache/libb10-cache.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/resolve/libb10-resolve.la
 b10_resolver_LDFLAGS = -pthread
 b10_resolver_LDFLAGS = -pthread
 
 
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir

+ 9 - 0
src/bin/resolver/b10-resolver.8

@@ -9,6 +9,15 @@
 .\"
 .\"
 .TH "B10\-RESOLVER" "8" "February 28, 2012" "BIND10" "BIND10"
 .TH "B10\-RESOLVER" "8" "February 28, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" disable hyphenation
 .\" disable hyphenation

+ 16 - 16
src/bin/resolver/tests/Makefile.am

@@ -37,22 +37,22 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 
 
 run_unittests_LDADD  = $(GTEST_LDADD)
 run_unittests_LDADD  = $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-run_unittests_LDADD += $(top_builddir)/src/lib/acl/libdnsacl.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
-run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-run_unittests_LDADD += $(top_builddir)/src/lib/resolve/libresolve.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la
-run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
-run_unittests_LDADD += $(top_builddir)/src/lib/acl/libacl.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libb10-testutils.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+run_unittests_LDADD += $(top_builddir)/src/lib/acl/libb10-dnsacl.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libb10-xfr.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
+run_unittests_LDADD += $(top_builddir)/src/lib/resolve/libb10-resolve.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cache/libb10-cache.la
+run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
+run_unittests_LDADD += $(top_builddir)/src/lib/acl/libb10-acl.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 
 
 # Note the ordering matters: -Wno-... must follow -Wextra (defined in
 # Note the ordering matters: -Wno-... must follow -Wextra (defined in

+ 0 - 2
src/bin/showtech/.gitignore

@@ -1,2 +0,0 @@
-/b10-showtech
-/showtech.py

+ 2 - 2
src/bin/sockcreator/Makefile.am

@@ -15,5 +15,5 @@ CLEANFILES = *.gcno *.gcda
 pkglibexec_PROGRAMS = b10-sockcreator
 pkglibexec_PROGRAMS = b10-sockcreator
 
 
 b10_sockcreator_SOURCES = sockcreator.cc sockcreator.h main.cc
 b10_sockcreator_SOURCES = sockcreator.cc sockcreator.h main.cc
-b10_sockcreator_LDADD  = $(top_builddir)/src/lib/util/io/libutil_io.la
-b10_sockcreator_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+b10_sockcreator_LDADD  = $(top_builddir)/src/lib/util/io/libb10-util-io.la
+b10_sockcreator_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la

+ 1 - 1
src/bin/sockcreator/tests/Makefile.am

@@ -22,7 +22,7 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD  = $(GTEST_LDADD)
 run_unittests_LDADD  = $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libutil_io.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/io/libb10-util-io.la
 endif
 endif
 
 
 noinst_PROGRAMS = $(TESTS)
 noinst_PROGRAMS = $(TESTS)

+ 2 - 0
src/bin/sysinfo/.gitignore

@@ -0,0 +1,2 @@
+/isc-sysinfo
+/sysinfo.py

+ 5 - 5
src/bin/showtech/Makefile.am

@@ -1,14 +1,14 @@
-bin_SCRIPTS = b10-showtech
+bin_SCRIPTS = isc-sysinfo
 
 
-CLEANFILES = b10-showtech showtech.pyc
+CLEANFILES = isc-sysinfo sysinfo.pyc
 
 
 # this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
 # this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
-b10-showtech: showtech.py
-	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" showtech.py >$@
+isc-sysinfo: sysinfo.py
+	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" sysinfo.py >$@
 	chmod a+x $@
 	chmod a+x $@
 
 
 MAN1_FILES = \
 MAN1_FILES = \
-	b10-showtech.xml
+	isc-sysinfo.xml
 
 
 man_MANS = \
 man_MANS = \
 	$(MAN1_FILES:.xml=.1)
 	$(MAN1_FILES:.xml=.1)

+ 9 - 9
src/bin/showtech/b10-showtech.1

@@ -1,13 +1,13 @@
 '\" t
 '\" t
-.\"     Title: b10-showtech
+.\"     Title: isc-sysinfo
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
 .\"      Date: June 26, 2012
 .\"      Date: June 26, 2012
 .\"    Manual: BIND10
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"  Language: English
 .\"
 .\"
-.TH "B10\-SHOWTECH" "1" "June 26, 2012" "BIND10" "BIND10"
+.TH "ISC\-SYSINFO" "1" "June 26, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
@@ -28,14 +28,14 @@
 .\" * MAIN CONTENT STARTS HERE *
 .\" * MAIN CONTENT STARTS HERE *
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .SH "NAME"
 .SH "NAME"
-b10-showtech \- BIND 10 system information display tool
+isc-sysinfo \- BIND 10 system information display tool
 .SH "SYNOPSIS"
 .SH "SYNOPSIS"
-.HP \w'\fBb10\-showtech\fR\ 'u
-\fBb10\-showtech\fR
+.HP \w'\fBisc\-sysinfo\fR\ 'u
+\fBisc\-sysinfo\fR
 .SH "DESCRIPTION"
 .SH "DESCRIPTION"
 .PP
 .PP
 The
 The
-\fBb10\-showtech\fR
+\fBisc\-sysinfo\fR
 program collects and outputs a variety of information about the system that BIND 10 is running on\&. This information can be useful to people involved in debugging and technical support\&.
 program collects and outputs a variety of information about the system that BIND 10 is running on\&. This information can be useful to people involved in debugging and technical support\&.
 .SH "ARGUMENTS"
 .SH "ARGUMENTS"
 .PP
 .PP
@@ -47,7 +47,7 @@ Displays usage instructions\&.
 \-o \fIoutput\-file\fR
 \-o \fIoutput\-file\fR
 .RS 4
 .RS 4
 If an output file is specified, the output of
 If an output file is specified, the output of
-\fBb10\-showtech\fR
+\fBisc\-sysinfo\fR
 is written to this file\&. By default, the output is written to standard output\&.
 is written to this file\&. By default, the output is written to standard output\&.
 .RE
 .RE
 .SH "SEE ALSO"
 .SH "SEE ALSO"
@@ -58,7 +58,7 @@ BIND 10 Guide\&.
 .SH "HISTORY"
 .SH "HISTORY"
 .PP
 .PP
 The
 The
-\fBb10\-showtech\fR
+\fBisc\-sysinfo\fR
 daemon was initially implemented by ISC staff in June, 2012\&.
 daemon was initially implemented by ISC staff in June, 2012\&.
 .SH "COPYRIGHT"
 .SH "COPYRIGHT"
 .br
 .br

+ 6 - 6
src/bin/showtech/b10-showtech.xml

@@ -24,13 +24,13 @@
   </refentryinfo>
   </refentryinfo>
 
 
   <refmeta>
   <refmeta>
-    <refentrytitle>b10-showtech</refentrytitle>
+    <refentrytitle>isc-sysinfo</refentrytitle>
     <manvolnum>1</manvolnum>
     <manvolnum>1</manvolnum>
     <refmiscinfo>BIND10</refmiscinfo>
     <refmiscinfo>BIND10</refmiscinfo>
   </refmeta>
   </refmeta>
 
 
   <refnamediv>
   <refnamediv>
-    <refname>b10-showtech</refname>
+    <refname>isc-sysinfo</refname>
     <refpurpose>BIND 10 system information display tool</refpurpose>
     <refpurpose>BIND 10 system information display tool</refpurpose>
   </refnamediv>
   </refnamediv>
 
 
@@ -43,14 +43,14 @@
 
 
   <refsynopsisdiv>
   <refsynopsisdiv>
     <cmdsynopsis>
     <cmdsynopsis>
-      <command>b10-showtech</command>
+      <command>isc-sysinfo</command>
     </cmdsynopsis>
     </cmdsynopsis>
   </refsynopsisdiv>
   </refsynopsisdiv>
 
 
   <refsect1>
   <refsect1>
     <title>DESCRIPTION</title>
     <title>DESCRIPTION</title>
     <para>
     <para>
-      The <command>b10-showtech</command> program collects and outputs a
+      The <command>isc-sysinfo</command> program collects and outputs a
       variety of information about the system that BIND 10 is running
       variety of information about the system that BIND 10 is running
       on. This information can be useful to people involved in debugging
       on. This information can be useful to people involved in debugging
       and technical support.
       and technical support.
@@ -73,7 +73,7 @@
         <term>-o <replaceable class="parameter">output-file</replaceable></term>
         <term>-o <replaceable class="parameter">output-file</replaceable></term>
         <listitem><para>
         <listitem><para>
           If an output file is specified, the output
           If an output file is specified, the output
-          of <command>b10-showtech</command> is written to this file. By
+          of <command>isc-sysinfo</command> is written to this file. By
           default, the output is written to standard output.
           default, the output is written to standard output.
         </para></listitem>
         </para></listitem>
       </varlistentry>
       </varlistentry>
@@ -95,7 +95,7 @@
   <refsect1>
   <refsect1>
     <title>HISTORY</title>
     <title>HISTORY</title>
     <para>
     <para>
-      The <command>b10-showtech</command> daemon was initially
+      The <command>isc-sysinfo</command> daemon was initially
       implemented by ISC staff in June, 2012.
       implemented by ISC staff in June, 2012.
     </para>
     </para>
   </refsect1>
   </refsect1>

+ 39 - 30
src/bin/showtech/showtech.py.in

@@ -16,7 +16,7 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 
 """
 """
-BIND 10 showtech program.
+ISC sysinfo program.
 
 
 """
 """
 
 
@@ -32,6 +32,15 @@ def usage():
               file=sys.stderr)
               file=sys.stderr)
     exit(1)
     exit(1)
 
 
+def write_value(out, fmt, call):
+    '''Helper function for standard value writing.
+       Writes the result from the call in the given format to out.
+       Does not write anything if the result of the call is None.
+    '''
+    value = call()
+    if value is not None:
+        out.write(fmt % value)
+
 def main():
 def main():
     try:
     try:
         opts, args = getopt.getopt(sys.argv[1:], "o:h", \
         opts, args = getopt.getopt(sys.argv[1:], "o:h", \
@@ -57,39 +66,39 @@ def main():
 
 
     s = SysInfoFromFactory()
     s = SysInfoFromFactory()
 
 
-    f.write('BIND 10 ShowTech tool\n')
-    f.write('=====================\n')
+    f.write('ISC Sysinfo tool\n')
+    f.write('================\n')
 
 
     f.write('\nCPU\n');
     f.write('\nCPU\n');
-    f.write(' + Number of processors: %d\n' % (s.get_num_processors()))
-    f.write(' + Endianness: %s\n' % (s.get_endianness()))
+    write_value(f, ' + Number of processors: %d\n', s.get_num_processors)
+    write_value(f, ' + Endianness: %s\n', s.get_endianness)
 
 
     f.write('\nPlatform\n');
     f.write('\nPlatform\n');
-    f.write(' + Operating system: %s\n' % (s.get_platform_name()))
-    f.write(' + Distribution: %s\n' % (s.get_platform_distro()))
-    f.write(' + Kernel version: %s\n' % (s.get_platform_version()))
-
-    f.write(' + SMP kernel: ')
-    if s.get_platform_is_smp():
-        f.write('yes')
-    else:
-        f.write('no')
-    f.write('\n')
+    write_value(f, ' + Operating system: %s\n', s.get_platform_name)
+    write_value(f, ' + Distribution: %s\n', s.get_platform_distro)
+    write_value(f, ' + Kernel version: %s\n', s.get_platform_version)
+
+    if s.get_platform_is_smp() is not None:
+        f.write(' + SMP kernel: ')
+        if s.get_platform_is_smp():
+            f.write('yes')
+        else:
+            f.write('no')
+        f.write('\n')
 
 
-    f.write(' + Machine name: %s\n' % (s.get_platform_machine()))
-    f.write(' + Hostname: %s\n' % (s.get_platform_hostname()))
-    f.write(' + Uptime: %d seconds\n' % (s.get_uptime()))
+    write_value(f, ' + Machine name: %s\n', s.get_platform_machine)
+    write_value(f, ' + Hostname: %s\n', s.get_platform_hostname)
+    write_value(f, ' + Uptime: %d seconds\n', s.get_uptime)
 
 
-    l = s.get_loadavg()
-    f.write(' + Loadavg: %f %f %f\n' % (l[0], l[1], l[2]))
+    write_value(f, ' + Loadavg: %f %f %f\n', s.get_loadavg)
 
 
     f.write('\nMemory\n');
     f.write('\nMemory\n');
-    f.write(' + Total: %d bytes\n' % (s.get_mem_total()))
-    f.write(' + Free: %d bytes\n' % (s.get_mem_free()))
-    f.write(' + Cached: %d bytes\n' % (s.get_mem_cached()))
-    f.write(' + Buffers: %d bytes\n' % (s.get_mem_buffers()))
-    f.write(' + Swap total: %d bytes\n' % (s.get_mem_swap_total()))
-    f.write(' + Swap free: %d bytes\n' % (s.get_mem_swap_free()))
+    write_value(f, ' + Total: %d bytes\n', s.get_mem_total)
+    write_value(f, ' + Free: %d bytes\n', s.get_mem_free)
+    write_value(f, ' + Cached: %d bytes\n', s.get_mem_cached)
+    write_value(f, ' + Buffers: %d bytes\n', s.get_mem_buffers)
+    write_value(f, ' + Swap total: %d bytes\n', s.get_mem_swap_total)
+    write_value(f, ' + Swap free: %d bytes\n', s.get_mem_swap_free)
 
 
     f.write('\n\nNetwork\n');
     f.write('\n\nNetwork\n');
     f.write('-------\n\n');
     f.write('-------\n\n');
@@ -97,19 +106,19 @@ def main():
     f.write('Interfaces\n')
     f.write('Interfaces\n')
     f.write('~~~~~~~~~~\n\n')
     f.write('~~~~~~~~~~\n\n')
 
 
-    f.write(s.get_net_interfaces())
+    write_value(f, '%s', s.get_net_interfaces)
 
 
     f.write('\nRouting table\n')
     f.write('\nRouting table\n')
     f.write('~~~~~~~~~~~~~\n\n')
     f.write('~~~~~~~~~~~~~\n\n')
-    f.write(s.get_net_routing_table())
+    write_value(f, '%s', s.get_net_routing_table)
 
 
     f.write('\nStatistics\n')
     f.write('\nStatistics\n')
     f.write('~~~~~~~~~~\n\n')
     f.write('~~~~~~~~~~\n\n')
-    f.write(s.get_net_stats())
+    write_value(f, '%s', s.get_net_stats)
 
 
     f.write('\nConnections\n')
     f.write('\nConnections\n')
     f.write('~~~~~~~~~~~\n\n')
     f.write('~~~~~~~~~~~\n\n')
-    f.write(s.get_net_connections())
+    write_value(f, '%s', s.get_net_connections)
 
 
     try:
     try:
         if os.getuid() != 0:
         if os.getuid() != 0:

+ 7 - 143
src/bin/xfrin/tests/xfrin_test.py

@@ -2739,18 +2739,8 @@ class TestMain(unittest.TestCase):
 
 
 class TestXfrinProcessMockCC:
 class TestXfrinProcessMockCC:
     def __init__(self):
     def __init__(self):
-        self.get_called = False
-        self.get_called_correctly = False
         self.config = []
         self.config = []
 
 
-    def get_remote_config_value(self, module, identifier):
-        self.get_called = True
-        if module == 'Auth' and identifier == 'datasources':
-            self.get_called_correctly = True
-            return (self.config, False)
-        else:
-            return (None, True)
-
 class TestXfrinProcessMockCCSession:
 class TestXfrinProcessMockCCSession:
     def __init__(self):
     def __init__(self):
         self.send_called = False
         self.send_called = False
@@ -2869,22 +2859,17 @@ class TestXfrinProcess(unittest.TestCase):
         # Create a connection for each attempt
         # Create a connection for each attempt
         self.assertEqual(len(transfers), self.__created_connections)
         self.assertEqual(len(transfers), self.__created_connections)
         self.assertEqual([published], self.__published)
         self.assertEqual([published], self.__published)
-        if published == XFRIN_OK:
-            self.assertTrue(self._module_cc.get_called)
-            self.assertTrue(self._module_cc.get_called_correctly)
-        else:
-            self.assertFalse(self._module_cc.get_called)
-            self.assertFalse(self._module_cc.get_called_correctly)
 
 
     def test_ixfr_ok(self):
     def test_ixfr_ok(self):
         """
         """
         Everything OK the first time, over IXFR.
         Everything OK the first time, over IXFR.
         """
         """
         self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
         self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
+        # Check there was loadzone command
+        self.assertTrue(self._send_cc_session.send_called)
+        self.assertTrue(self._send_cc_session.send_called_correctly)
+        self.assertTrue(self._send_cc_session.recv_called)
+        self.assertTrue(self._send_cc_session.recv_called_correctly)
 
 
     def test_axfr_ok(self):
     def test_axfr_ok(self):
         """
         """
@@ -2916,137 +2901,16 @@ class TestXfrinProcess(unittest.TestCase):
         self.__do_test([XFRIN_FAIL, XFRIN_FAIL],
         self.__do_test([XFRIN_FAIL, XFRIN_FAIL],
                        [RRType.IXFR(), RRType.AXFR()], RRType.IXFR())
                        [RRType.IXFR(), RRType.AXFR()], RRType.IXFR())
 
 
-    def test_inmem_ok(self):
+    def test_send_loadzone(self):
         """
         """
-        Inmem configuration where all the configuration is just right
-        for loadzone to be sent to b10-auth (origin is the name received
-        by xfrin, filetype is sqlite3, type is memory and class is the
-        one received by xfrin).
+        Check the loadzone command is sent after successful transfer.
         """
         """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory', 'class': 'IN'}]
         self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
         self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
         self.assertTrue(self._send_cc_session.send_called)
         self.assertTrue(self._send_cc_session.send_called)
         self.assertTrue(self._send_cc_session.send_called_correctly)
         self.assertTrue(self._send_cc_session.send_called_correctly)
         self.assertTrue(self._send_cc_session.recv_called)
         self.assertTrue(self._send_cc_session.recv_called)
         self.assertTrue(self._send_cc_session.recv_called_correctly)
         self.assertTrue(self._send_cc_session.recv_called_correctly)
 
 
-    def test_inmem_datasource_type_not_memory(self):
-        """
-        Inmem configuration where the datasource type is not memory. In
-        this case, loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'punched-card', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_datasource_type_is_missing(self):
-        """
-        Inmem configuration where the datasource type is missing. In
-        this case, loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_backend_type_not_sqlite3(self):
-        """
-        Inmem configuration where the datasource backing file is not of
-        type sqlite3. In this case, loadzone should not be sent to
-        b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'postgresql',
-                                              'file': 'data/inmem-xfrin.db'}],
-                                   'type': 'memory', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_backend_type_is_missing(self):
-        """
-        Inmem configuration where the datasource backing file type is
-        not set. In this case, loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org',
-                                              'file': 'data/inmem-xfrin'}],
-                                   'type': 'memory', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_class_is_different(self):
-        """
-        Inmem configuration where the datasource class does not match
-        the received class. In this case, loadzone should not be sent to
-        b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory', 'class': 'XX'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_class_is_missing(self):
-        """
-        Inmem configuration where the datasource class is missing. In
-        this case, we assume the IN class and loadzone may be sent to
-        b10-auth if everything else matches.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertTrue(self._send_cc_session.send_called)
-        self.assertTrue(self._send_cc_session.send_called_correctly)
-        self.assertTrue(self._send_cc_session.recv_called)
-        self.assertTrue(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_name_doesnt_match(self):
-        """
-        Inmem configuration where the origin does not match the received
-        name. In this case, loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'isc.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_name_is_missing(self):
-        """
-        Inmem configuration where the origin is missing. In this case,
-        loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
 class TestFormatting(unittest.TestCase):
 class TestFormatting(unittest.TestCase):
     # If the formatting functions are moved to a more general library
     # If the formatting functions are moved to a more general library
     # (ticket #1379), these tests should be moved with them.
     # (ticket #1379), these tests should be moved with them.

+ 1 - 1
src/bin/xfrin/xfrin.py.in

@@ -1256,7 +1256,7 @@ def _do_auth_loadzone(server, zone_name, zone_class):
     if msg is not None:
     if msg is not None:
         param = msg['command'][1]
         param = msg['command'][1]
         logger.debug(DBG_XFRIN_TRACE, XFRIN_AUTH_LOADZONE, param["origin"],
         logger.debug(DBG_XFRIN_TRACE, XFRIN_AUTH_LOADZONE, param["origin"],
-                     param["class"], param["datasrc"])
+                     param["class"])
         seq = server._send_cc_session.group_sendmsg(msg, AUTH_MODULE_NAME)
         seq = server._send_cc_session.group_sendmsg(msg, AUTH_MODULE_NAME)
         answer, env = server._send_cc_session.group_recvmsg(False, seq)
         answer, env = server._send_cc_session.group_recvmsg(False, seq)
 
 

+ 3 - 4
src/bin/xfrin/xfrin_messages.mes

@@ -15,10 +15,9 @@
 # No namespace declaration - these constants go in the global namespace
 # No namespace declaration - these constants go in the global namespace
 # of the xfrin messages python module.
 # of the xfrin messages python module.
 
 
-% XFRIN_AUTH_LOADZONE sending Auth loadzone for origin=%1, class=%2, datasrc=%3
-There was a successful zone transfer, and the zone is served by b10-auth
-in the in-memory data source using sqlite3 as a backend. We send the
-"loadzone" command for the zone to b10-auth.
+% XFRIN_AUTH_LOADZONE sending Auth loadzone for origin=%1, class=%2
+There was a successful zone transfer.  We send the "loadzone" command for the
+zone to b10-auth.
 
 
 % XFRIN_AXFR_INCONSISTENT_SOA AXFR SOAs are inconsistent for %1: %2 expected, %3 received
 % XFRIN_AXFR_INCONSISTENT_SOA AXFR SOAs are inconsistent for %1: %2 expected, %3 received
 The serial fields of the first and last SOAs of AXFR (including AXFR-style
 The serial fields of the first and last SOAs of AXFR (including AXFR-style

+ 10 - 1
src/bin/zonemgr/b10-zonemgr.8

@@ -9,6 +9,15 @@
 .\"
 .\"
 .TH "B10\-ZONEMGR" "8" "February 28, 2012" "BIND10" "BIND10"
 .TH "B10\-ZONEMGR" "8" "February 28, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" disable hyphenation
 .\" disable hyphenation
@@ -92,7 +101,7 @@ The configuration commands are:
 (sent by
 (sent by
 \fBb10-auth\fR(8)) tells
 \fBb10-auth\fR(8)) tells
 \fBb10\-zonemgr\fR
 \fBb10\-zonemgr\fR
-the zone name and class, and the IP address for the master (source of the NOTIFY message)\&. This will set the zone\'s refresh time to now\&.
+the zone name and class, and the IP address for the master (source of the NOTIFY message)\&. This will set the zone\*(Aqs refresh time to now\&.
 This is an internal command and not exposed to the administrator\&.
 This is an internal command and not exposed to the administrator\&.
 .PP
 .PP
 
 

+ 13 - 13
src/lib/acl/Makefile.am

@@ -5,23 +5,23 @@ AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 
 # The core library
 # The core library
-lib_LTLIBRARIES = libacl.la
-libacl_la_SOURCES  = acl.h
-libacl_la_SOURCES += check.h
-libacl_la_SOURCES += ip_check.h ip_check.cc
-libacl_la_SOURCES += logic_check.h
-libacl_la_SOURCES += loader.h loader.cc
+lib_LTLIBRARIES = libb10-acl.la
+libb10_acl_la_SOURCES  = acl.h
+libb10_acl_la_SOURCES += check.h
+libb10_acl_la_SOURCES += ip_check.h ip_check.cc
+libb10_acl_la_SOURCES += logic_check.h
+libb10_acl_la_SOURCES += loader.h loader.cc
 
 
-libacl_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
-libacl_la_LIBADD += $(top_builddir)/src/lib/cc/libcc.la
-libacl_la_LIBADD += $(top_builddir)/src/lib/util/libutil.la
+libb10_acl_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+libb10_acl_la_LIBADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+libb10_acl_la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
 
 
 # DNS specialized one
 # DNS specialized one
-lib_LTLIBRARIES += libdnsacl.la
+lib_LTLIBRARIES += libb10-dnsacl.la
 
 
-libdnsacl_la_SOURCES = dns.h dns.cc dnsname_check.h
+libb10_dnsacl_la_SOURCES = dns.h dns.cc dnsname_check.h
 
 
-libdnsacl_la_LIBADD = libacl.la
-libdnsacl_la_LIBADD += $(top_builddir)/src/lib/dns/libdns++.la
+libb10_dnsacl_la_LIBADD = libb10-acl.la
+libb10_dnsacl_la_LIBADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
 
 
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda

+ 7 - 7
src/lib/acl/tests/Makefile.am

@@ -31,13 +31,13 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 
 
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/acl/libacl.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/acl/libdnsacl.la
+run_unittests_LDADD += $(top_builddir)/src/lib/acl/libb10-acl.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/acl/libb10-dnsacl.la
 endif
 endif
 
 
 noinst_PROGRAMS = $(TESTS)
 noinst_PROGRAMS = $(TESTS)

+ 17 - 17
src/lib/asiodns/Makefile.am

@@ -16,28 +16,28 @@ asiodns_messages.h asiodns_messages.cc: asiodns_messages.mes
 
 
 BUILT_SOURCES = asiodns_messages.h asiodns_messages.cc
 BUILT_SOURCES = asiodns_messages.h asiodns_messages.cc
 
 
-lib_LTLIBRARIES = libasiodns.la
-libasiodns_la_SOURCES = dns_answer.h
-libasiodns_la_SOURCES += asiodns.h
-libasiodns_la_SOURCES += dns_lookup.h
-libasiodns_la_SOURCES += dns_server.h
-libasiodns_la_SOURCES += dns_service.cc dns_service.h
-libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
-libasiodns_la_SOURCES += udp_server.cc udp_server.h
-libasiodns_la_SOURCES += sync_udp_server.cc sync_udp_server.h
-libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
-libasiodns_la_SOURCES += logger.h logger.cc
-
-nodist_libasiodns_la_SOURCES = asiodns_messages.cc asiodns_messages.h
+lib_LTLIBRARIES = libb10-asiodns.la
+libb10_asiodns_la_SOURCES = dns_answer.h
+libb10_asiodns_la_SOURCES += asiodns.h
+libb10_asiodns_la_SOURCES += dns_lookup.h
+libb10_asiodns_la_SOURCES += dns_server.h
+libb10_asiodns_la_SOURCES += dns_service.cc dns_service.h
+libb10_asiodns_la_SOURCES += tcp_server.cc tcp_server.h
+libb10_asiodns_la_SOURCES += udp_server.cc udp_server.h
+libb10_asiodns_la_SOURCES += sync_udp_server.cc sync_udp_server.h
+libb10_asiodns_la_SOURCES += io_fetch.cc io_fetch.h
+libb10_asiodns_la_SOURCES += logger.h logger.cc
+
+nodist_libb10_asiodns_la_SOURCES = asiodns_messages.cc asiodns_messages.h
 
 
 EXTRA_DIST = asiodns_messages.mes
 EXTRA_DIST = asiodns_messages.mes
 
 
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
 # B10_CXXFLAGS)
-libasiodns_la_CXXFLAGS = $(AM_CXXFLAGS)
+libb10_asiodns_la_CXXFLAGS = $(AM_CXXFLAGS)
 if USE_CLANGPP
 if USE_CLANGPP
 # Same for clang++, but we need to turn off -Werror completely.
 # Same for clang++, but we need to turn off -Werror completely.
-libasiodns_la_CXXFLAGS += -Wno-error
+libb10_asiodns_la_CXXFLAGS += -Wno-error
 endif
 endif
-libasiodns_la_CPPFLAGS = $(AM_CPPFLAGS)
-libasiodns_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la
+libb10_asiodns_la_CPPFLAGS = $(AM_CPPFLAGS)
+libb10_asiodns_la_LIBADD = $(top_builddir)/src/lib/log/libb10-log.la

+ 6 - 6
src/lib/asiodns/tests/Makefile.am

@@ -28,13 +28,13 @@ run_unittests_SOURCES += io_fetch_unittest.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 
 
 run_unittests_LDADD  = $(GTEST_LDADD)
 run_unittests_LDADD  = $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
 
 
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 
 

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

@@ -13,32 +13,32 @@ CLEANFILES = *.gcno *.gcda
 # gcc's unused-parameter warning, which would make the build fail
 # gcc's unused-parameter warning, which would make the build fail
 # with -Werror (our default setting).
 # with -Werror (our default setting).
 
 
-lib_LTLIBRARIES = libasiolink.la
-
-libasiolink_la_LDFLAGS = -no-undefined -version-info 1:0:1
-
-libasiolink_la_SOURCES  = asiolink.h
-libasiolink_la_SOURCES += dummy_io_cb.h
-libasiolink_la_SOURCES += interval_timer.cc interval_timer.h
-libasiolink_la_SOURCES += io_address.cc io_address.h
-libasiolink_la_SOURCES += io_asio_socket.h
-libasiolink_la_SOURCES += io_endpoint.cc io_endpoint.h
-libasiolink_la_SOURCES += io_error.h
-libasiolink_la_SOURCES += io_message.h
-libasiolink_la_SOURCES += io_service.h io_service.cc
-libasiolink_la_SOURCES += io_socket.h io_socket.cc
-libasiolink_la_SOURCES += simple_callback.h
-libasiolink_la_SOURCES += tcp_endpoint.h
-libasiolink_la_SOURCES += tcp_socket.h
-libasiolink_la_SOURCES += udp_endpoint.h
-libasiolink_la_SOURCES += udp_socket.h
+lib_LTLIBRARIES = libb10-asiolink.la
+
+libb10_asiolink_la_LDFLAGS = -no-undefined -version-info 1:0:1
+
+libb10_asiolink_la_SOURCES  = asiolink.h
+libb10_asiolink_la_SOURCES += dummy_io_cb.h
+libb10_asiolink_la_SOURCES += interval_timer.cc interval_timer.h
+libb10_asiolink_la_SOURCES += io_address.cc io_address.h
+libb10_asiolink_la_SOURCES += io_asio_socket.h
+libb10_asiolink_la_SOURCES += io_endpoint.cc io_endpoint.h
+libb10_asiolink_la_SOURCES += io_error.h
+libb10_asiolink_la_SOURCES += io_message.h
+libb10_asiolink_la_SOURCES += io_service.h io_service.cc
+libb10_asiolink_la_SOURCES += io_socket.h io_socket.cc
+libb10_asiolink_la_SOURCES += simple_callback.h
+libb10_asiolink_la_SOURCES += tcp_endpoint.h
+libb10_asiolink_la_SOURCES += tcp_socket.h
+libb10_asiolink_la_SOURCES += udp_endpoint.h
+libb10_asiolink_la_SOURCES += udp_socket.h
 
 
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
 # B10_CXXFLAGS)
-libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)
+libb10_asiolink_la_CXXFLAGS = $(AM_CXXFLAGS)
 if USE_CLANGPP
 if USE_CLANGPP
 # Same for clang++, but we need to turn off -Werror completely.
 # Same for clang++, but we need to turn off -Werror completely.
-libasiolink_la_CXXFLAGS += -Wno-error
+libb10_asiolink_la_CXXFLAGS += -Wno-error
 endif
 endif
-libasiolink_la_CPPFLAGS = $(AM_CPPFLAGS)
-libasiolink_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la
+libb10_asiolink_la_CPPFLAGS = $(AM_CPPFLAGS)
+libb10_asiolink_la_LIBADD = $(top_builddir)/src/lib/log/libb10-log.la

+ 3 - 3
src/lib/asiolink/tests/Makefile.am

@@ -36,10 +36,10 @@ run_unittests_SOURCES += udp_socket_unittest.cc
 
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 
 
-run_unittests_LDADD = $(top_builddir)/src/lib/asiolink/libasiolink.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 run_unittests_LDADD += $(GTEST_LDADD)
 run_unittests_LDADD += $(GTEST_LDADD)
 
 
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

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

@@ -6,6 +6,6 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
-noinst_LTLIBRARIES = libbench.la
-libbench_la_SOURCES = benchmark_util.h benchmark_util.cc
+noinst_LTLIBRARIES = libb10-bench.la
+libb10_bench_la_SOURCES = benchmark_util.h benchmark_util.cc
 EXTRA_DIST = benchmark.h
 EXTRA_DIST = benchmark.h

+ 1 - 1
src/lib/bench/example/Makefile.am

@@ -5,5 +5,5 @@ CLEANFILES = *.gcno *.gcda
 noinst_PROGRAMS = search_bench
 noinst_PROGRAMS = search_bench
 search_bench_SOURCES = search_bench.cc
 search_bench_SOURCES = search_bench.cc
 
 
-search_bench_LDADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
+search_bench_LDADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 
 

+ 4 - 4
src/lib/bench/tests/Makefile.am

@@ -17,11 +17,11 @@ run_unittests_SOURCES += loadquery_unittest.cc
 
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-run_unittests_LDADD  = $(top_builddir)/src/lib/bench/libbench.la
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
+run_unittests_LDADD  = $(top_builddir)/src/lib/bench/libb10-bench.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 run_unittests_LDADD += $(GTEST_LDADD)
 run_unittests_LDADD += $(GTEST_LDADD)
 endif
 endif
 
 

+ 12 - 12
src/lib/cache/Makefile.am

@@ -21,18 +21,18 @@ if USE_CLANGPP
 AM_CXXFLAGS += -Wno-unused-parameter
 AM_CXXFLAGS += -Wno-unused-parameter
 endif
 endif
 
 
-lib_LTLIBRARIES = libcache.la
-libcache_la_SOURCES  = resolver_cache.h resolver_cache.cc
-libcache_la_SOURCES  += message_cache.h message_cache.cc
-libcache_la_SOURCES  += message_entry.h message_entry.cc
-libcache_la_SOURCES  += rrset_cache.h rrset_cache.cc
-libcache_la_SOURCES  += rrset_entry.h rrset_entry.cc
-libcache_la_SOURCES  += cache_entry_key.h cache_entry_key.cc
-libcache_la_SOURCES  += rrset_copy.h rrset_copy.cc
-libcache_la_SOURCES  += local_zone_data.h local_zone_data.cc
-libcache_la_SOURCES  += message_utility.h message_utility.cc
-libcache_la_SOURCES  += logger.h logger.cc
-nodist_libcache_la_SOURCES = cache_messages.cc cache_messages.h
+lib_LTLIBRARIES = libb10-cache.la
+libb10_cache_la_SOURCES  = resolver_cache.h resolver_cache.cc
+libb10_cache_la_SOURCES  += message_cache.h message_cache.cc
+libb10_cache_la_SOURCES  += message_entry.h message_entry.cc
+libb10_cache_la_SOURCES  += rrset_cache.h rrset_cache.cc
+libb10_cache_la_SOURCES  += rrset_entry.h rrset_entry.cc
+libb10_cache_la_SOURCES  += cache_entry_key.h cache_entry_key.cc
+libb10_cache_la_SOURCES  += rrset_copy.h rrset_copy.cc
+libb10_cache_la_SOURCES  += local_zone_data.h local_zone_data.cc
+libb10_cache_la_SOURCES  += message_utility.h message_utility.cc
+libb10_cache_la_SOURCES  += logger.h logger.cc
+nodist_libb10_cache_la_SOURCES = cache_messages.cc cache_messages.h
 
 
 BUILT_SOURCES = cache_messages.cc cache_messages.h
 BUILT_SOURCES = cache_messages.cc cache_messages.h
 
 

+ 7 - 7
src/lib/cache/tests/Makefile.am

@@ -50,14 +50,14 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD    = $(GTEST_LDADD)
 run_unittests_LDADD    = $(GTEST_LDADD)
 
 
-run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
-run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cache/libb10-cache.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 endif
 endif
 
 
 noinst_PROGRAMS = $(TESTS)
 noinst_PROGRAMS = $(TESTS)

+ 5 - 5
src/lib/cc/Makefile.am

@@ -20,11 +20,11 @@ if USE_CLANGPP
 AM_CXXFLAGS += -Wno-error
 AM_CXXFLAGS += -Wno-error
 endif
 endif
 
 
-lib_LTLIBRARIES = libcc.la
-libcc_la_SOURCES = data.cc data.h session.cc session.h
-libcc_la_SOURCES += logger.cc logger.h
-nodist_libcc_la_SOURCES = cc_messages.cc cc_messages.h
-libcc_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la
+lib_LTLIBRARIES = libb10-cc.la
+libb10_cc_la_SOURCES = data.cc data.h session.cc session.h
+libb10_cc_la_SOURCES += logger.cc logger.h
+nodist_libb10_cc_la_SOURCES = cc_messages.cc cc_messages.h
+libb10_cc_la_LIBADD = $(top_builddir)/src/lib/log/libb10-log.la
 
 
 CLEANFILES = *.gcno *.gcda session_config.h cc_messages.cc cc_messages.h
 CLEANFILES = *.gcno *.gcda session_config.h cc_messages.cc cc_messages.h
 
 

+ 3 - 3
src/lib/cc/tests/Makefile.am

@@ -30,10 +30,10 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 # We need to put our libs first, in case gtest (or any dependency, really)
 # We need to put our libs first, in case gtest (or any dependency, really)
 # is installed in the same location as a different version of bind10
 # is installed in the same location as a different version of bind10
 # Otherwise the linker may not use the source tree libs
 # Otherwise the linker may not use the source tree libs
-run_unittests_LDADD =  $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD +=  $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD =  $(top_builddir)/src/lib/cc/libb10-cc.la
+run_unittests_LDADD +=  $(top_builddir)/src/lib/log/libb10-log.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD +=  $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 run_unittests_LDADD += $(GTEST_LDADD)
 run_unittests_LDADD += $(GTEST_LDADD)
 
 
 endif
 endif

+ 9 - 9
src/lib/config/Makefile.am

@@ -11,18 +11,18 @@ config_messages.h config_messages.cc: config_messages.mes
 
 
 BUILT_SOURCES = config_messages.h config_messages.cc
 BUILT_SOURCES = config_messages.h config_messages.cc
 
 
-lib_LTLIBRARIES = libcfgclient.la
-libcfgclient_la_SOURCES = config_data.h config_data.cc
-libcfgclient_la_SOURCES += module_spec.h module_spec.cc
-libcfgclient_la_SOURCES += ccsession.cc ccsession.h
-libcfgclient_la_SOURCES += config_log.h config_log.cc
+lib_LTLIBRARIES = libb10-cfgclient.la
+libb10_cfgclient_la_SOURCES = config_data.h config_data.cc
+libb10_cfgclient_la_SOURCES += module_spec.h module_spec.cc
+libb10_cfgclient_la_SOURCES += ccsession.cc ccsession.h
+libb10_cfgclient_la_SOURCES += config_log.h config_log.cc
 
 
-libcfgclient_la_LIBADD = $(top_builddir)/src/lib/cc/libcc.la
-libcfgclient_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+libb10_cfgclient_la_LIBADD = $(top_builddir)/src/lib/cc/libb10-cc.la
+libb10_cfgclient_la_LIBADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
 
 
-libcfgclient_la_LDFLAGS = -no-undefined -version-info 1:0:1
+libb10_cfgclient_la_LDFLAGS = -no-undefined -version-info 1:0:1
 
 
-nodist_libcfgclient_la_SOURCES  = config_messages.h config_messages.cc
+nodist_libb10_cfgclient_la_SOURCES  = config_messages.h config_messages.cc
 
 
 # The message file should be in the distribution.
 # The message file should be in the distribution.
 EXTRA_DIST = config_messages.mes
 EXTRA_DIST = config_messages.mes

+ 0 - 0
src/lib/config/module_spec.cc


Some files were not shown because too many files changed in this diff