Browse Source

sync with trunk.

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac372@3647 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 14 years ago
parent
commit
500de4b34b
100 changed files with 3190 additions and 1223 deletions
  1. 81 3
      ChangeLog
  2. 28 5
      configure.ac
  3. 1 1
      src/bin/Makefile.am
  4. 5 0
      src/bin/auth/Makefile.am
  5. 1 3
      src/bin/auth/asio_link.cc
  6. 2 2
      src/bin/auth/asio_link.h
  7. 23 24
      src/bin/auth/auth_srv.cc
  8. 2 2
      src/bin/auth/auth_srv.h
  9. 1 0
      src/bin/auth/benchmarks/Makefile.am
  10. 1 0
      src/bin/auth/benchmarks/query_bench.cc
  11. 2 1
      src/bin/auth/tests/Makefile.am
  12. 86 90
      src/bin/auth/tests/auth_srv_unittest.cc
  13. 1 2
      src/bin/auth/tests/run_unittests.cc
  14. 76 58
      src/bin/bind10/bind10.py.in
  15. 1 1
      src/bin/bind10/run_bind10.sh.in
  16. 3 24
      src/bin/bind10/tests/bind10_test.py
  17. 2 2
      src/bin/bindctl/bindctl-source.py.in
  18. 2 2
      src/bin/cfgmgr/b10-cfgmgr.py.in
  19. 17 16
      src/bin/cmdctl/cmdctl.py.in
  20. 1 0
      src/bin/host/Makefile.am
  21. 6 5
      src/bin/host/host.cc
  22. 2 2
      src/bin/loadzone/b10-loadzone.py.in
  23. 1 1
      src/bin/loadzone/tests/error/error.known
  24. 2 2
      src/bin/msgq/msgq.py.in
  25. 1 0
      src/bin/msgq/tests/Makefile.am
  26. 7 0
      src/bin/msgq/tests/msgq_test.py
  27. 37 0
      src/bin/stats/Makefile.am
  28. 68 0
      src/bin/stats/b10-stats.8
  29. 124 0
      src/bin/stats/b10-stats.xml
  30. 30 0
      src/bin/stats/run_b10-stats.sh.in
  31. 30 0
      src/bin/stats/run_b10-stats_stub.sh.in
  32. 416 0
      src/bin/stats/stats.py.in
  33. 140 0
      src/bin/stats/stats.spec.pre.in
  34. 155 0
      src/bin/stats/stats_stub.py.in
  35. 0 151
      src/bin/stats/statsd.py
  36. 0 55
      src/bin/stats/statsd.txt
  37. 0 6
      src/bin/stats/test/shutdown.py
  38. 0 178
      src/bin/stats/test/test_agent.py
  39. 0 54
      src/bin/stats/test_total.py
  40. 15 0
      src/bin/stats/tests/Makefile.am
  41. 116 0
      src/bin/stats/tests/b10-stats_stub_test.py
  42. 646 0
      src/bin/stats/tests/b10-stats_test.py
  43. 48 0
      src/bin/stats/tests/fake_time.py
  44. 3 0
      src/bin/stats/tests/isc/Makefile.am
  45. 0 0
      src/bin/stats/tests/isc/__init__.py
  46. 2 0
      src/bin/stats/tests/isc/cc/Makefile.am
  47. 1 0
      src/bin/stats/tests/isc/cc/__init__.py
  48. 127 0
      src/bin/stats/tests/isc/cc/session.py
  49. 2 0
      src/bin/stats/tests/isc/config/Makefile.am
  50. 1 0
      src/bin/stats/tests/isc/config/__init__.py
  51. 114 0
      src/bin/stats/tests/isc/config/ccsession.py
  52. 2 0
      src/bin/stats/tests/isc/util/Makefile.am
  53. 0 0
      src/bin/stats/tests/isc/util/__init__.py
  54. 20 0
      src/bin/stats/tests/isc/util/process.py
  55. 2 0
      src/bin/stats/tests/isc/utils/Makefile.am
  56. 0 0
      src/bin/stats/tests/isc/utils/__init__.py
  57. 20 0
      src/bin/stats/tests/isc/utils/process.py
  58. 31 0
      src/bin/stats/tests/stats_test.in
  59. 1 0
      src/bin/stats/tests/testdata/Makefile.am
  60. 19 0
      src/bin/stats/tests/testdata/stats_test.spec
  61. 3 3
      src/bin/tests/process_rename_test.py.in
  62. 2 2
      src/bin/usermgr/b10-cmdctl-usermgr.py.in
  63. 7 7
      src/bin/xfrin/tests/xfrin_test.py
  64. 36 36
      src/bin/xfrin/xfrin.py.in
  65. 52 36
      src/bin/xfrout/tests/xfrout_test.py
  66. 132 112
      src/bin/xfrout/xfrout.py.in
  67. 2 0
      src/bin/zonemgr/tests/Makefile.am
  68. 49 23
      src/bin/zonemgr/tests/zonemgr_test.py
  69. 129 78
      src/bin/zonemgr/zonemgr.py.in
  70. 1 0
      src/lib/bench/Makefile.am
  71. 2 2
      src/lib/bench/benchmark.h
  72. 6 3
      src/lib/bench/example/search_bench.cc
  73. 1 0
      src/lib/bench/tests/Makefile.am
  74. 6 6
      src/lib/bench/tests/loadquery_unittest.cc
  75. 10 3
      src/lib/cc/Makefile.am
  76. 35 37
      src/lib/cc/data.cc
  77. 4 0
      src/lib/cc/tests/Makefile.am
  78. 1 1
      src/lib/cc/tests/data_unittests.cc
  79. 1 2
      src/lib/cc/tests/run_unittests.cc
  80. 1 1
      src/lib/cc/tests/session_unittests.cc
  81. 1 0
      src/lib/config/Makefile.am
  82. 3 4
      src/lib/config/ccsession.cc
  83. 18 11
      src/lib/config/ccsession.h
  84. 13 11
      src/lib/config/config_data.h
  85. 1 0
      src/lib/config/module_spec.cc
  86. 26 19
      src/lib/config/module_spec.h
  87. 2 5
      src/lib/config/tests/Makefile.am
  88. 16 17
      src/lib/config/tests/ccsession_unittests.cc
  89. 5 10
      src/lib/config/tests/fake_session.cc
  90. 1 1
      src/lib/config/tests/fake_session.h
  91. 2 4
      src/lib/config/tests/module_spec_unittests.cc
  92. 1 2
      src/lib/config/tests/run_unittests.cc
  93. 2 0
      src/lib/datasrc/Makefile.am
  94. 3 3
      src/lib/datasrc/cache.h
  95. 60 66
      src/lib/datasrc/data_source.cc
  96. 13 9
      src/lib/datasrc/query.cc
  97. 10 6
      src/lib/datasrc/query.h
  98. 5 13
      src/lib/datasrc/static_datasrc.cc
  99. 3 0
      src/lib/datasrc/tests/Makefile.am
  100. 0 0
      src/lib/datasrc/tests/datasrc_unittest.cc

+ 81 - 3
ChangeLog

@@ -1,7 +1,85 @@
-  108.	[func]		jerry		
+  120.  [func]		jinmei
+	src/lib/dns: introduced two new classes, TSIGKey and TSIGKeyRing,
+	to manage TSIG keys. (Trac #381, svn r3622)
+
+  119.	[bug]		jinmei
+	The master file parser of the python datasrc module incorrectly
+	regarded a domain name beginning with a decimal number as a TTL
+	specification.  This confused b10-loadzone and had it reject to
+	load a zone file that contains such a name.
+	Note: this fix is incomplete and the loadzone would still be
+	confused if the owner name is a syntactically indistinguishable
+	from a TTL specification.  This is part of a more general issue
+	and will be addressed in Trac #413.  (Trac #411, svn r3599)
+
+  118.	[func]		jinmei
+	src/lib/dns: changed the interface of AbstractRRset::getRdataIterator()
+	so that the internal cursor would point to the first RDATA
+	automatically.  This will be a more intuitive and less error prone
+	behavior.  This is a backward compatible change. (Trac #410, r3595)
+
+  117.  [func]		jinmei
+	src/lib/datasrc: added new zone and zone table classes for the
+	support of in memory data source.  This is an intermediate step to
+	the bigger feature, and is not yet actually usable in practice.
+	(Trac #399, svn r3590)
+
+  116.	[bug]		jerry
+	src/bin/xfrout: Xfrout and Auth will communicate by long tcp
+	connection, Auth needs to make a new connection only on the first
+	time or if an error occurred.
+	(Trac #299, svn r3482)
+
+  115.	[func]*		jinmei
+	src/lib/dns: Changed DNS message flags and section names from
+	separate classes to simpler enums, considering the balance between
+	type safety and usability.  API has been changed accordingly.
+	More documentation and tests were provided with these changes.
+	(Trac #358, r3439)
+
+  114.	[build]		jinmei
+	Supported clang++.  Note: Boost >= 1.44 is required.
+	(Trac #365, svn r3383)
+
+  113.	[func]*		zhanglikun
+	Folder name 'utils'(the folder in /src/lib/python/isc/) has been
+	renamed	to 'util'. Programs that used 'import isc.utils.process'
+	now need to use 'import isc.util.process'. The folder
+	/src/lib/python/isc/Util is removed since it isn't used by any
+	program. (Trac #364, r3382)
+
+  112.	[func]		zhang likun
+	Add one mixin class to override the naive serve_forever() provided
+	in python library socketserver. Instead of polling for shutdwon
+	every poll_interval seconds, one socketpair is used to wake up
+	the waiting server.(Trac #352, svn r3366)
+
+  111.	[bug]*   zhanglikun, Michal Vaner
+	Make sure process xfrin/xfrout/zonemgr/cmdctl can be stoped
+	properly when user enter "ctrl+c" or 'Boss shutdown' command
+	through	bindctl.
+
+	The ZonemgrRefresh.run_timer and NotifyOut.dispatcher spawn
+	a thread themselves.
+	(Trac #335, svn r3273)
+
+  110.  [func]      Michal Vaner
+	Added isc.net.check module to check ip addresses and ports for
+	correctness and isc.net.addr to hold IP address. The bind10, xfrin
+	and cmdctl programs are modified to use it.
+	(Trac #353, svn r3240)
+
+  109.  [func]		naokikambe
+	Added the initial version of the stats module for the statistics
+	feature of BIND 10, which supports the restricted features and
+	items and reports via bindctl command (Trac #191, r3218)
+	Added the document of the stats module, which is about how stats
+	module collects the data (Trac #170, [wiki:StatsModule])
+
+  108.	[func]		jerry
 	src/bin/zonemgr: Provide customizable configurations for
 	src/bin/zonemgr: Provide customizable configurations for
 	lowerbound_refresh, lowerbound_retry, max_transfer_timeout and
 	lowerbound_refresh, lowerbound_retry, max_transfer_timeout and
-	jitter_scope. (Trac #340, r3205)	
+	jitter_scope. (Trac #340, r3205)
 
 
   107.  [func]       zhang likun
   107.  [func]       zhang likun
 	Remove the parameter 'db_file' for command 'retransfer' of
 	Remove the parameter 'db_file' for command 'retransfer' of
@@ -16,7 +94,7 @@
   105.  [bug]       Michal Vaner
   105.  [bug]       Michal Vaner
 	Python processes: they no longer take 100% CPU while idle
 	Python processes: they no longer take 100% CPU while idle
 	due to a busy loop in reading command session in a nonblocking way.
 	due to a busy loop in reading command session in a nonblocking way.
-	(Trac #349, svn r3153)
+	(Trac #349, svn r3153), (Trac #382, svn r3294)
 
 
   104.	[bug]		jerry
   104.	[bug]		jerry
 	bin/zonemgr: zonemgr should be attempting to refresh expired zones.
 	bin/zonemgr: zonemgr should be attempting to refresh expired zones.

+ 28 - 5
configure.ac

@@ -17,6 +17,8 @@ AC_LANG([C++])
 # Identify the compiler: this check must be after AC_PROG_CXX and AC_LANG.
 # Identify the compiler: this check must be after AC_PROG_CXX and AC_LANG.
 AM_CONDITIONAL(USE_GXX, test "X${GXX}" = "Xyes")
 AM_CONDITIONAL(USE_GXX, test "X${GXX}" = "Xyes")
 AC_CHECK_DECL([__SUNPRO_CC], [SUNCXX="yes"], [SUNCXX="no"])
 AC_CHECK_DECL([__SUNPRO_CC], [SUNCXX="yes"], [SUNCXX="no"])
+AC_CHECK_DECL([__clang__], [CLANGPP="yes"], [CLANGPP="no"])
+AM_CONDITIONAL(USE_CLANGPP, test "X${CLANGPP}" = "Xyes")
 
 
 # Linker options
 # Linker options
 
 
@@ -204,7 +206,6 @@ fi
 # gcc specific settings:
 # gcc specific settings:
 if test "X$GXX" = "Xyes"; then
 if test "X$GXX" = "Xyes"; then
 B10_CXXFLAGS="-Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
 B10_CXXFLAGS="-Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
-UNUSED_PARAM_ATTRIBUTE='__attribute__((unused))'
 
 
 # Certain versions of gcc (g++) have a bug that incorrectly warns about
 # Certain versions of gcc (g++) have a bug that incorrectly warns about
 # the use of anonymous name spaces even if they're closed in a single
 # the use of anonymous name spaces even if they're closed in a single
@@ -223,7 +224,6 @@ CXXFLAGS="$CXXFLAGS_SAVED"
 fi				dnl GXX = yes
 fi				dnl GXX = yes
 
 
 AM_CONDITIONAL(GCC_WERROR_OK, test $werror_ok = 1)
 AM_CONDITIONAL(GCC_WERROR_OK, test $werror_ok = 1)
-AC_DEFINE_UNQUOTED(UNUSED_PARAM, $UNUSED_PARAM_ATTRIBUTE, Define to compiler keyword indicating a function argument is intentionally unused)
 
 
 # produce PIC unless we disable shared libraries. need this for python bindings.
 # produce PIC unless we disable shared libraries. need this for python bindings.
 if test $enable_shared != "no" -a "X$GXX" = "Xyes"; then
 if test $enable_shared != "no" -a "X$GXX" = "Xyes"; then
@@ -313,12 +313,14 @@ if test -z "$with_boost_include"; then
 		fi
 		fi
 	done
 	done
 fi
 fi
+CPPFLAGS_SAVES="$CPPFLAGS"
 if test "${boost_include_path}" ; then
 if test "${boost_include_path}" ; then
 	BOOST_INCLUDES="-I${boost_include_path}"
 	BOOST_INCLUDES="-I${boost_include_path}"
 	CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES"
 	CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES"
 fi
 fi
 AC_CHECK_HEADERS([boost/shared_ptr.hpp boost/foreach.hpp],,
 AC_CHECK_HEADERS([boost/shared_ptr.hpp boost/foreach.hpp],,
   AC_MSG_ERROR([Missing required header files.]))
   AC_MSG_ERROR([Missing required header files.]))
+CPPFLAGS="$CPPFLAGS_SAVES"
 AC_SUBST(BOOST_INCLUDES)
 AC_SUBST(BOOST_INCLUDES)
 
 
 #
 #
@@ -471,6 +473,13 @@ AC_CONFIG_FILES([Makefile
                  src/bin/xfrout/tests/Makefile
                  src/bin/xfrout/tests/Makefile
                  src/bin/zonemgr/Makefile
                  src/bin/zonemgr/Makefile
                  src/bin/zonemgr/tests/Makefile
                  src/bin/zonemgr/tests/Makefile
+                 src/bin/stats/Makefile
+                 src/bin/stats/tests/Makefile
+                 src/bin/stats/tests/isc/Makefile
+                 src/bin/stats/tests/isc/cc/Makefile
+                 src/bin/stats/tests/isc/config/Makefile
+                 src/bin/stats/tests/isc/util/Makefile
+                 src/bin/stats/tests/testdata/Makefile
                  src/bin/usermgr/Makefile
                  src/bin/usermgr/Makefile
                  src/bin/tests/Makefile
                  src/bin/tests/Makefile
                  src/lib/Makefile
                  src/lib/Makefile
@@ -481,15 +490,18 @@ AC_CONFIG_FILES([Makefile
                  src/lib/cc/tests/Makefile
                  src/lib/cc/tests/Makefile
                  src/lib/python/Makefile
                  src/lib/python/Makefile
                  src/lib/python/isc/Makefile
                  src/lib/python/isc/Makefile
-                 src/lib/python/isc/utils/Makefile
+                 src/lib/python/isc/util/Makefile
-                 src/lib/python/isc/utils/tests/Makefile
+                 src/lib/python/isc/util/tests/Makefile
                  src/lib/python/isc/datasrc/Makefile
                  src/lib/python/isc/datasrc/Makefile
+                 src/lib/python/isc/datasrc/tests/Makefile
                  src/lib/python/isc/cc/Makefile
                  src/lib/python/isc/cc/Makefile
                  src/lib/python/isc/cc/tests/Makefile
                  src/lib/python/isc/cc/tests/Makefile
                  src/lib/python/isc/config/Makefile
                  src/lib/python/isc/config/Makefile
                  src/lib/python/isc/config/tests/Makefile
                  src/lib/python/isc/config/tests/Makefile
                  src/lib/python/isc/log/Makefile
                  src/lib/python/isc/log/Makefile
                  src/lib/python/isc/log/tests/Makefile
                  src/lib/python/isc/log/tests/Makefile
+                 src/lib/python/isc/net/Makefile
+                 src/lib/python/isc/net/tests/Makefile
                  src/lib/python/isc/notify/Makefile
                  src/lib/python/isc/notify/Makefile
                  src/lib/python/isc/notify/tests/Makefile
                  src/lib/python/isc/notify/tests/Makefile
                  src/lib/config/Makefile
                  src/lib/config/Makefile
@@ -523,6 +535,12 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            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/stats/stats.py
+           src/bin/stats/stats_stub.py
+           src/bin/stats/stats.spec.pre
+           src/bin/stats/run_b10-stats.sh
+           src/bin/stats/run_b10-stats_stub.sh
+           src/bin/stats/tests/stats_test
            src/bin/bind10/bind10.py
            src/bin/bind10/bind10.py
            src/bin/bind10/tests/bind10_test
            src/bin/bind10/tests/bind10_test
            src/bin/bind10/run_bind10.sh
            src/bin/bind10/run_bind10.sh
@@ -556,6 +574,9 @@ AC_OUTPUT([src/bin/cfgmgr/b10-cfgmgr.py
            chmod +x src/bin/xfrin/run_b10-xfrin.sh
            chmod +x src/bin/xfrin/run_b10-xfrin.sh
            chmod +x src/bin/xfrout/run_b10-xfrout.sh
            chmod +x src/bin/xfrout/run_b10-xfrout.sh
            chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
            chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
+           chmod +x src/bin/stats/tests/stats_test
+           chmod +x src/bin/stats/run_b10-stats.sh
+           chmod +x src/bin/stats/run_b10-stats_stub.sh
            chmod +x src/bin/bind10/run_bind10.sh
            chmod +x src/bin/bind10/run_bind10.sh
            chmod +x src/bin/cmdctl/tests/cmdctl_test
            chmod +x src/bin/cmdctl/tests/cmdctl_test
            chmod +x src/bin/xfrin/tests/xfrin_test
            chmod +x src/bin/xfrin/tests/xfrin_test
@@ -586,6 +607,8 @@ Package:
   Name:          $PACKAGE_NAME
   Name:          $PACKAGE_NAME
   Version:       $PACKAGE_VERSION
   Version:       $PACKAGE_VERSION
 
 
+C++ Compiler:    $CXX
+
 Flags:
 Flags:
   DEFS:          $DEFS
   DEFS:          $DEFS
   CPPFLAGS:      $CPPFLAGS
   CPPFLAGS:      $CPPFLAGS
@@ -595,6 +618,7 @@ dnl includes too
   Python:        ${PYTHON_INCLUDES}
   Python:        ${PYTHON_INCLUDES}
                  ${PYTHON_LDFLAGS}
                  ${PYTHON_LDFLAGS}
                  ${PYTHON_LIB}
                  ${PYTHON_LIB}
+  Boost:         ${BOOST_INCLUDES}
   SQLite:        $SQLITE_CFLAGS
   SQLite:        $SQLITE_CFLAGS
                  $SQLITE_LIBS
                  $SQLITE_LIBS
 
 
@@ -614,4 +638,3 @@ cat <<EOF
   Now you can type "make" to build BIND 10
   Now you can type "make" to build BIND 10
 
 
 EOF
 EOF
-

+ 1 - 1
src/bin/Makefile.am

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

+ 5 - 0
src/bin/auth/Makefile.am

@@ -5,6 +5,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 
@@ -46,6 +47,10 @@ libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS)
 if USE_GXX
 if USE_GXX
 libasio_link_a_CXXFLAGS += -Wno-unused-parameter
 libasio_link_a_CXXFLAGS += -Wno-unused-parameter
 endif
 endif
+if USE_CLANGPP
+# Same for clang++, but we need to turn off -Werror completely.
+libasio_link_a_CXXFLAGS += -Wno-error
+endif
 libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
 libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
 
 
 BUILT_SOURCES = spec_config.h 
 BUILT_SOURCES = spec_config.h 

+ 1 - 3
src/bin/auth/asio_link.cc

@@ -505,9 +505,7 @@ public:
         }
         }
     }
     }
 
 
-    void sendCompleted(const asio::error_code& error UNUSED_PARAM,
+    void sendCompleted(const asio::error_code&, size_t) {
-                       size_t bytes_sent UNUSED_PARAM)
-    {
         // Even if error occurred there's nothing to do.  Simply handle
         // Even if error occurred there's nothing to do.  Simply handle
         // the next request.
         // the next request.
         startReceive();
         startReceive();

+ 2 - 2
src/bin/auth/asio_link.h

@@ -88,7 +88,7 @@ class AuthSrv;
 /// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html
 /// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html
 
 
 namespace asio_link {
 namespace asio_link {
-struct IOServiceImpl;
+class IOServiceImpl;
 
 
 /// \brief An exception that is thrown if an error occurs within the IO
 /// \brief An exception that is thrown if an error occurs within the IO
 /// module.  This is mainly intended to be a wrapper exception class for
 /// module.  This is mainly intended to be a wrapper exception class for
@@ -132,7 +132,7 @@ public:
     /// This constructor never throws an exception.
     /// This constructor never throws an exception.
     ///
     ///
     /// \param asio_address The ASIO \c ip::address to be converted.
     /// \param asio_address The ASIO \c ip::address to be converted.
-    IOAddress(const asio::ip::address& asio_adress);
+    IOAddress(const asio::ip::address& asio_address);
     //@}
     //@}
 
 
     /// \brief Convert the address to a string.
     /// \brief Convert the address to a string.

+ 23 - 24
src/bin/auth/auth_srv.cc

@@ -77,7 +77,7 @@ public:
                             MessageRenderer& response_renderer);
                             MessageRenderer& response_renderer);
     bool processAxfrQuery(const IOMessage& io_message, Message& message,
     bool processAxfrQuery(const IOMessage& io_message, Message& message,
                             MessageRenderer& response_renderer);
                             MessageRenderer& response_renderer);
-    bool processNotify(const IOMessage& io_message, Message& message, 
+    bool processNotify(const IOMessage& io_message, Message& message,
                             MessageRenderer& response_renderer);
                             MessageRenderer& response_renderer);
     std::string db_file_;
     std::string db_file_;
     ModuleCCSession* config_session_;
     ModuleCCSession* config_session_;
@@ -152,8 +152,8 @@ makeErrorMessage(Message& message, MessageRenderer& renderer,
     // XXX: with the current implementation, it's not easy to set EDNS0
     // XXX: with the current implementation, it's not easy to set EDNS0
     // depending on whether the query had it.  So we'll simply omit it.
     // depending on whether the query had it.  So we'll simply omit it.
     const qid_t qid = message.getQid();
     const qid_t qid = message.getQid();
-    const bool rd = message.getHeaderFlag(MessageFlag::RD());
+    const bool rd = message.getHeaderFlag(Message::HEADERFLAG_RD);
-    const bool cd = message.getHeaderFlag(MessageFlag::CD());
+    const bool cd = message.getHeaderFlag(Message::HEADERFLAG_CD);
     const Opcode& opcode = message.getOpcode();
     const Opcode& opcode = message.getOpcode();
     vector<QuestionPtr> questions;
     vector<QuestionPtr> questions;
 
 
@@ -166,12 +166,12 @@ makeErrorMessage(Message& message, MessageRenderer& renderer,
     message.clear(Message::RENDER);
     message.clear(Message::RENDER);
     message.setQid(qid);
     message.setQid(qid);
     message.setOpcode(opcode);
     message.setOpcode(opcode);
-    message.setHeaderFlag(MessageFlag::QR());
+    message.setHeaderFlag(Message::HEADERFLAG_QR);
     if (rd) {
     if (rd) {
-        message.setHeaderFlag(MessageFlag::RD());
+        message.setHeaderFlag(Message::HEADERFLAG_RD);
     }
     }
     if (cd) {
     if (cd) {
-        message.setHeaderFlag(MessageFlag::CD());
+        message.setHeaderFlag(Message::HEADERFLAG_CD);
     }
     }
     for_each(questions.begin(), questions.end(), QuestionInserter(&message));
     for_each(questions.begin(), questions.end(), QuestionInserter(&message));
     message.setRcode(rcode);
     message.setRcode(rcode);
@@ -231,7 +231,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         message.parseHeader(request_buffer);
         message.parseHeader(request_buffer);
 
 
         // Ignore all responses.
         // Ignore all responses.
-        if (message.getHeaderFlag(MessageFlag::QR())) {
+        if (message.getHeaderFlag(Message::HEADERFLAG_QR)) {
             if (impl_->verbose_mode_) {
             if (impl_->verbose_mode_) {
                 cerr << "[b10-auth] received unexpected response, ignoring"
                 cerr << "[b10-auth] received unexpected response, ignoring"
                      << endl;
                      << endl;
@@ -279,7 +279,7 @@ AuthSrv::processMessage(const IOMessage& io_message, Message& message,
         return (true);
         return (true);
     }
     }
 
 
-    if (message.getRRCount(Section::QUESTION()) != 1) {
+    if (message.getRRCount(Message::SECTION_QUESTION) != 1) {
         makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
         makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
                          impl_->verbose_mode_);
                          impl_->verbose_mode_);
         return (true);
         return (true);
@@ -307,10 +307,10 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
     ConstEDNSPtr remote_edns = message.getEDNS();
     ConstEDNSPtr remote_edns = message.getEDNS();
     const bool dnssec_ok = remote_edns && remote_edns->getDNSSECAwareness();
     const bool dnssec_ok = remote_edns && remote_edns->getDNSSECAwareness();
     const uint16_t remote_bufsize = remote_edns ? remote_edns->getUDPSize() :
     const uint16_t remote_bufsize = remote_edns ? remote_edns->getUDPSize() :
-        Message::DEFAULT_MAX_UDPSIZE; 
+        Message::DEFAULT_MAX_UDPSIZE;
 
 
     message.makeResponse();
     message.makeResponse();
-    message.setHeaderFlag(MessageFlag::AA());
+    message.setHeaderFlag(Message::HEADERFLAG_AA);
     message.setRcode(Rcode::NOERROR());
     message.setRcode(Rcode::NOERROR());
 
 
     if (remote_edns) {
     if (remote_edns) {
@@ -360,8 +360,10 @@ AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
     }
     }
 
 
     try {
     try {
-        xfrout_client_.connect();
+        if (!xfrout_connected_) {
-        xfrout_connected_ = true;
+            xfrout_client_.connect();
+            xfrout_connected_ = true;
+        }
         xfrout_client_.sendXfroutRequestInfo(
         xfrout_client_.sendXfroutRequestInfo(
             io_message.getSocket().getNative(),
             io_message.getSocket().getNative(),
             io_message.getData(),
             io_message.getData(),
@@ -375,7 +377,7 @@ AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
             xfrout_client_.disconnect();
             xfrout_client_.disconnect();
             xfrout_connected_ = false;
             xfrout_connected_ = false;
         }
         }
-        
+
         if (verbose_mode_) {
         if (verbose_mode_) {
             cerr << "[b10-auth] Error in handling XFR request: " << err.what()
             cerr << "[b10-auth] Error in handling XFR request: " << err.what()
                  << endl;
                  << endl;
@@ -385,22 +387,19 @@ AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
         return (true);
         return (true);
     }
     }
 
 
-    xfrout_client_.disconnect();
-    xfrout_connected_ = false;
-
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message, 
+AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
-                           MessageRenderer& response_renderer) 
+                           MessageRenderer& response_renderer)
 {
 {
     // The incoming notify must contain exactly one question for SOA of the
     // The incoming notify must contain exactly one question for SOA of the
     // zone name.
     // zone name.
-    if (message.getRRCount(Section::QUESTION()) != 1) {
+    if (message.getRRCount(Message::SECTION_QUESTION) != 1) {
         if (verbose_mode_) {
         if (verbose_mode_) {
                 cerr << "[b10-auth] invalid number of questions in notify: "
                 cerr << "[b10-auth] invalid number of questions in notify: "
-                     << message.getRRCount(Section::QUESTION()) << endl;
+                     << message.getRRCount(Message::SECTION_QUESTION) << endl;
         }
         }
         makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
         makeErrorMessage(message, response_renderer, Rcode::FORMERR(),
                          verbose_mode_);
                          verbose_mode_);
@@ -435,7 +434,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         }
         }
         return (false);
         return (false);
     }
     }
-    
+
     const string remote_ip_address =
     const string remote_ip_address =
         io_message.getRemoteEndpoint().getAddress().toText();
         io_message.getRemoteEndpoint().getAddress().toText();
     static const string command_template_start =
     static const string command_template_start =
@@ -446,7 +445,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
 
 
     try {
     try {
         ConstElementPtr notify_command = Element::fromJSON(
         ConstElementPtr notify_command = Element::fromJSON(
-                command_template_start + question->getName().toText() + 
+                command_template_start + question->getName().toText() +
                 command_template_master + remote_ip_address +
                 command_template_master + remote_ip_address +
                 command_template_rrclass + question->getClass().toText() +
                 command_template_rrclass + question->getClass().toText() +
                 command_template_end);
                 command_template_end);
@@ -460,7 +459,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         if (rcode != 0) {
         if (rcode != 0) {
             if (verbose_mode_) {
             if (verbose_mode_) {
                 cerr << "[b10-auth] failed to notify Zonemgr: "
                 cerr << "[b10-auth] failed to notify Zonemgr: "
-                     << parsed_answer->str() << endl; 
+                     << parsed_answer->str() << endl;
             }
             }
             return (false);
             return (false);
         }
         }
@@ -472,7 +471,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
     }
     }
 
 
     message.makeResponse();
     message.makeResponse();
-    message.setHeaderFlag(MessageFlag::AA());
+    message.setHeaderFlag(Message::HEADERFLAG_AA);
     message.setRcode(Rcode::NOERROR());
     message.setRcode(Rcode::NOERROR());
     message.toWire(response_renderer);
     message.toWire(response_renderer);
     return (true);
     return (true);

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

@@ -84,7 +84,7 @@ public:
             isc::xfr::AbstractXfroutClient& xfrout_client);
             isc::xfr::AbstractXfroutClient& xfrout_client);
     ~AuthSrv();
     ~AuthSrv();
     //@}
     //@}
-    /// \return \c true if the \message contains a response to be returned;
+    /// \return \c true if the \a message contains a response to be returned;
     /// otherwise \c false.
     /// otherwise \c false.
     bool processMessage(const asio_link::IOMessage& io_message,
     bool processMessage(const asio_link::IOMessage& io_message,
                         isc::dns::Message& message,
                         isc::dns::Message& message,
@@ -138,7 +138,7 @@ public:
     /// containing the result of the update operation.
     /// containing the result of the update operation.
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
 
 
-    /// \param Returns the command and configuration session for the
+    /// \brief Returns the command and configuration session for the
     /// \c AuthSrv.
     /// \c AuthSrv.
     ///
     ///
     /// This method never throws an exception.
     /// This method never throws an exception.

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

@@ -1,5 +1,6 @@
 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_srcdir)/src/bin -I$(top_builddir)/src/bin
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 

+ 1 - 0
src/bin/auth/benchmarks/query_bench.cc

@@ -38,6 +38,7 @@
 
 
 using namespace std;
 using namespace std;
 using namespace isc;
 using namespace isc;
+using namespace isc::data;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::xfr;
 using namespace isc::xfr;
 using namespace isc::bench;
 using namespace isc::bench;

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

@@ -3,8 +3,9 @@ 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/lib/dns -I$(top_srcdir)/src/bin
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
-AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(top_builddir)/src/bin/auth/tests/testdata\"
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/bin/auth/tests/testdata\"
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 

+ 86 - 90
src/bin/auth/tests/auth_srv_unittest.cc

@@ -97,7 +97,7 @@ private:
         virtual void startRead(boost::function<void()> read_callback);
         virtual void startRead(boost::function<void()> read_callback);
         virtual int reply(ConstElementPtr envelope, ConstElementPtr newmsg);
         virtual int reply(ConstElementPtr envelope, ConstElementPtr newmsg);
         virtual bool hasQueuedMsgs() const;
         virtual bool hasQueuedMsgs() const;
-        virtual void setTimeout(size_t timeout UNUSED_PARAM) {};
+        virtual void setTimeout(size_t) {}
         virtual size_t getTimeout() const { return 0; };
         virtual size_t getTimeout() const { return 0; };
 
 
         void setMessage(ConstElementPtr msg) { msg_ = msg; }
         void setMessage(ConstElementPtr msg) { msg_ = msg; }
@@ -156,30 +156,25 @@ protected:
 };
 };
 
 
 void
 void
-AuthSrvTest::MockSession::establish(const char* socket_file UNUSED_PARAM) {}
+AuthSrvTest::MockSession::establish(const char*) {}
 
 
 void
 void
 AuthSrvTest::MockSession::disconnect() {}
 AuthSrvTest::MockSession::disconnect() {}
 
 
 void
 void
-AuthSrvTest::MockSession::subscribe(string group UNUSED_PARAM,
+AuthSrvTest::MockSession::subscribe(string, string)
-                                    string instance UNUSED_PARAM)
 {}
 {}
 
 
 void
 void
-AuthSrvTest::MockSession::unsubscribe(string group UNUSED_PARAM,
+AuthSrvTest::MockSession::unsubscribe(string, string)
-                                      string instance UNUSED_PARAM)
 {}
 {}
 
 
 void
 void
-AuthSrvTest::MockSession::startRead(
+AuthSrvTest::MockSession::startRead(boost::function<void()>)
-    boost::function<void()> read_callback UNUSED_PARAM)
 {}
 {}
 
 
 int
 int
-AuthSrvTest::MockSession::reply(ConstElementPtr envelope UNUSED_PARAM,
+AuthSrvTest::MockSession::reply(ConstElementPtr, ConstElementPtr) {
-                                ConstElementPtr newmsg UNUSED_PARAM)
-{
     return (-1);
     return (-1);
 }
 }
 
 
@@ -190,8 +185,7 @@ AuthSrvTest::MockSession::hasQueuedMsgs() const {
 
 
 int
 int
 AuthSrvTest::MockSession::group_sendmsg(ConstElementPtr msg, string group,
 AuthSrvTest::MockSession::group_sendmsg(ConstElementPtr msg, string group,
-                                        string instance UNUSED_PARAM,
+                                        string, string)
-                                        string to UNUSED_PARAM)
 {
 {
     if (!send_ok_) {
     if (!send_ok_) {
         isc_throw(XfroutError, "mock session send is disabled for test");
         isc_throw(XfroutError, "mock session send is disabled for test");
@@ -203,10 +197,8 @@ AuthSrvTest::MockSession::group_sendmsg(ConstElementPtr msg, string group,
 }
 }
 
 
 bool
 bool
-AuthSrvTest::MockSession::group_recvmsg(ConstElementPtr& envelope UNUSED_PARAM,
+AuthSrvTest::MockSession::group_recvmsg(ConstElementPtr&,
-                                        ConstElementPtr& msg,
+                                        ConstElementPtr& msg, bool, int)
-                                        bool nonblock UNUSED_PARAM,
-                                        int seq UNUSED_PARAM)
 {
 {
     if (!receive_ok_) {
     if (!receive_ok_) {
         isc_throw(XfroutError, "mock session receive is disabled for test");
         isc_throw(XfroutError, "mock session receive is disabled for test");
@@ -234,10 +226,9 @@ AuthSrvTest::MockXfroutClient::disconnect() {
 }
 }
 
 
 int
 int
-AuthSrvTest::MockXfroutClient::sendXfroutRequestInfo(
+AuthSrvTest::MockXfroutClient::sendXfroutRequestInfo(const int,
-    const int tcp_sock UNUSED_PARAM,
+                                                     const void*,
-    const void* msg_data UNUSED_PARAM,
+                                                     const uint16_t)
-    const uint16_t msg_len UNUSED_PARAM)
 {
 {
     if (!send_ok_) {
     if (!send_ok_) {
         isc_throw(XfroutError, "xfrout connection send is disabled for test");
         isc_throw(XfroutError, "xfrout connection send is disabled for test");
@@ -321,18 +312,25 @@ headerCheck(const Message& message, const qid_t qid, const Rcode& rcode,
     EXPECT_EQ(qid, message.getQid());
     EXPECT_EQ(qid, message.getQid());
     EXPECT_EQ(rcode, message.getRcode());
     EXPECT_EQ(rcode, message.getRcode());
     EXPECT_EQ(opcodeval, message.getOpcode().getCode());
     EXPECT_EQ(opcodeval, message.getOpcode().getCode());
-    EXPECT_EQ((flags & QR_FLAG) != 0, message.getHeaderFlag(MessageFlag::QR()));
+    EXPECT_EQ((flags & QR_FLAG) != 0,
-    EXPECT_EQ((flags & AA_FLAG) != 0, message.getHeaderFlag(MessageFlag::AA()));
+              message.getHeaderFlag(Message::HEADERFLAG_QR));
-    EXPECT_EQ((flags & TC_FLAG) != 0, message.getHeaderFlag(MessageFlag::TC()));
+    EXPECT_EQ((flags & AA_FLAG) != 0,
-    EXPECT_EQ((flags & RA_FLAG) != 0, message.getHeaderFlag(MessageFlag::RA()));
+              message.getHeaderFlag(Message::HEADERFLAG_AA));
-    EXPECT_EQ((flags & RD_FLAG) != 0, message.getHeaderFlag(MessageFlag::RD()));
+    EXPECT_EQ((flags & TC_FLAG) != 0,
-    EXPECT_EQ((flags & AD_FLAG) != 0, message.getHeaderFlag(MessageFlag::AD()));
+              message.getHeaderFlag(Message::HEADERFLAG_TC));
-    EXPECT_EQ((flags & CD_FLAG) != 0, message.getHeaderFlag(MessageFlag::CD()));
+    EXPECT_EQ((flags & RA_FLAG) != 0,
-
+              message.getHeaderFlag(Message::HEADERFLAG_RA));
-    EXPECT_EQ(qdcount, message.getRRCount(Section::QUESTION()));
+    EXPECT_EQ((flags & RD_FLAG) != 0,
-    EXPECT_EQ(ancount, message.getRRCount(Section::ANSWER()));
+              message.getHeaderFlag(Message::HEADERFLAG_RD));
-    EXPECT_EQ(nscount, message.getRRCount(Section::AUTHORITY()));
+    EXPECT_EQ((flags & AD_FLAG) != 0,
-    EXPECT_EQ(arcount, message.getRRCount(Section::ADDITIONAL()));
+              message.getHeaderFlag(Message::HEADERFLAG_AD));
+    EXPECT_EQ((flags & CD_FLAG) != 0,
+              message.getHeaderFlag(Message::HEADERFLAG_CD));
+
+    EXPECT_EQ(qdcount, message.getRRCount(Message::SECTION_QUESTION));
+    EXPECT_EQ(ancount, message.getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(nscount, message.getRRCount(Message::SECTION_AUTHORITY));
+    EXPECT_EQ(arcount, message.getRRCount(Message::SECTION_ADDITIONAL));
 }
 }
 
 
 // Unsupported requests.  Should result in NOTIMP.
 // Unsupported requests.  Should result in NOTIMP.
@@ -348,8 +346,8 @@ TEST_F(AuthSrvTest, unsupportedRequest) {
         data[2] = ((i << 3) & 0xff);
         data[2] = ((i << 3) & 0xff);
 
 
         parse_message.clear(Message::PARSE);
         parse_message.clear(Message::PARSE);
-        EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+        EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                              response_renderer));
+                                          response_renderer));
         headerCheck(parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG,
         headerCheck(parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG,
                     0, 0, 0, 0);
                     0, 0, 0, 0);
     }
     }
@@ -367,8 +365,8 @@ TEST_F(AuthSrvTest, verbose) {
 // Multiple questions.  Should result in FORMERR.
 // Multiple questions.  Should result in FORMERR.
 TEST_F(AuthSrvTest, multiQuestion) {
 TEST_F(AuthSrvTest, multiQuestion) {
     createDataFromFile("multiquestion_fromWire.wire");
     createDataFromFile("multiquestion_fromWire.wire");
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
     headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 2, 0, 0, 0);
                 QR_FLAG, 2, 0, 0, 0);
 
 
@@ -388,8 +386,8 @@ TEST_F(AuthSrvTest, multiQuestion) {
 // dropped.
 // dropped.
 TEST_F(AuthSrvTest, shortMessage) {
 TEST_F(AuthSrvTest, shortMessage) {
     createDataFromFile("shortmessage_fromWire");
     createDataFromFile("shortmessage_fromWire");
-    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
+    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
-                                           response_renderer));
+                                       response_renderer));
 }
 }
 
 
 // Response messages.  Must be silently dropped, whether it's a valid response
 // Response messages.  Must be silently dropped, whether it's a valid response
@@ -397,26 +395,26 @@ TEST_F(AuthSrvTest, shortMessage) {
 TEST_F(AuthSrvTest, response) {
 TEST_F(AuthSrvTest, response) {
     // A valid (although unusual) response
     // A valid (although unusual) response
     createDataFromFile("simpleresponse_fromWire.wire");
     createDataFromFile("simpleresponse_fromWire.wire");
-    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
+    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
-                                           response_renderer));
+                                       response_renderer));
 
 
     // A response with a broken question section.  must be dropped rather than
     // A response with a broken question section.  must be dropped rather than
     // returning FORMERR.
     // returning FORMERR.
     createDataFromFile("shortresponse_fromWire");
     createDataFromFile("shortresponse_fromWire");
-    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
+    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
-                                           response_renderer));
+                                       response_renderer));
 
 
     // A response to iquery.  must be dropped rather than returning NOTIMP.
     // A response to iquery.  must be dropped rather than returning NOTIMP.
     createDataFromFile("iqueryresponse_fromWire.wire");
     createDataFromFile("iqueryresponse_fromWire.wire");
-    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
+    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
-                                           response_renderer));
+                                       response_renderer));
 }
 }
 
 
 // Query with a broken question
 // Query with a broken question
 TEST_F(AuthSrvTest, shortQuestion) {
 TEST_F(AuthSrvTest, shortQuestion) {
     createDataFromFile("shortquestion_fromWire");
     createDataFromFile("shortquestion_fromWire");
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     // Since the query's question is broken, the question section of the
     // Since the query's question is broken, the question section of the
     // response should be empty.
     // response should be empty.
     headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
     headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
@@ -426,8 +424,8 @@ TEST_F(AuthSrvTest, shortQuestion) {
 // Query with a broken answer section
 // Query with a broken answer section
 TEST_F(AuthSrvTest, shortAnswer) {
 TEST_F(AuthSrvTest, shortAnswer) {
     createDataFromFile("shortanswer_fromWire.wire");
     createDataFromFile("shortanswer_fromWire.wire");
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
 
 
     // This is a bogus query, but question section is valid.  So the response
     // This is a bogus query, but question section is valid.  So the response
     // should copy the question section.
     // should copy the question section.
@@ -445,8 +443,8 @@ TEST_F(AuthSrvTest, shortAnswer) {
 // Query with unsupported version of EDNS.
 // Query with unsupported version of EDNS.
 TEST_F(AuthSrvTest, ednsBadVers) {
 TEST_F(AuthSrvTest, ednsBadVers) {
     createDataFromFile("queryBadEDNS_fromWire.wire");
     createDataFromFile("queryBadEDNS_fromWire.wire");
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
 
 
     // The response must have an EDNS OPT RR in the additional section, but
     // The response must have an EDNS OPT RR in the additional section, but
     // it will be added automatically at the render time.
     // it will be added automatically at the render time.
@@ -468,8 +466,8 @@ TEST_F(AuthSrvTest, AXFROverUDP) {
     // AXFR over UDP is invalid and should result in FORMERR.
     // AXFR over UDP is invalid and should result in FORMERR.
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_UDP);
                         RRType::AXFR(), IPPROTO_UDP);
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
     headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                 QR_FLAG, 1, 0, 0, 0);
                 QR_FLAG, 1, 0, 0, 0);
 }
 }
@@ -480,9 +478,9 @@ TEST_F(AuthSrvTest, AXFRSuccess) {
                         RRType::AXFR(), IPPROTO_TCP);
                         RRType::AXFR(), IPPROTO_TCP);
     // On success, the AXFR query has been passed to a separate process,
     // On success, the AXFR query has been passed to a separate process,
     // so we shouldn't have to respond.
     // so we shouldn't have to respond.
-    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
+    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
-                                           response_renderer));
+                                       response_renderer));
-    EXPECT_FALSE(xfrout.isConnected());
+    EXPECT_TRUE(xfrout.isConnected());
 }
 }
 
 
 TEST_F(AuthSrvTest, AXFRConnectFail) {
 TEST_F(AuthSrvTest, AXFRConnectFail) {
@@ -494,8 +492,6 @@ TEST_F(AuthSrvTest, AXFRConnectFail) {
                                       response_renderer));
                                       response_renderer));
     headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
     headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
-    // For a shot term workaround with xfrout we currently close the connection
-    // for each AXFR attempt
     EXPECT_FALSE(xfrout.isConnected());
     EXPECT_FALSE(xfrout.isConnected());
 }
 }
 
 
@@ -505,7 +501,7 @@ TEST_F(AuthSrvTest, AXFRSendFail) {
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
     createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                         RRType::AXFR(), IPPROTO_TCP);
                         RRType::AXFR(), IPPROTO_TCP);
     server.processMessage(*io_message, parse_message, response_renderer);
     server.processMessage(*io_message, parse_message, response_renderer);
-    EXPECT_FALSE(xfrout.isConnected()); // see above
+    EXPECT_TRUE(xfrout.isConnected());
 
 
     xfrout.disableSend();
     xfrout.disableSend();
     parse_message.clear(Message::PARSE);
     parse_message.clear(Message::PARSE);
@@ -540,10 +536,10 @@ TEST_F(AuthSrvTest, AXFRDisconnectFail) {
 TEST_F(AuthSrvTest, notify) {
 TEST_F(AuthSrvTest, notify) {
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
                         RRType::SOA());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
 
 
     // An internal command message should have been created and sent to an
     // An internal command message should have been created and sent to an
     // external module.  Check them.
     // external module.  Check them.
@@ -572,10 +568,10 @@ TEST_F(AuthSrvTest, notifyForCHClass) {
     // Same as the previous test, but for the CH RRClass.
     // Same as the previous test, but for the CH RRClass.
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::CH(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::CH(),
                         RRType::SOA());
                         RRType::SOA());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
 
 
     // Other conditions should be the same, so simply confirm the RR class is
     // Other conditions should be the same, so simply confirm the RR class is
     // set correctly.
     // set correctly.
@@ -588,12 +584,12 @@ TEST_F(AuthSrvTest, notifyEmptyQuestion) {
     request_message.clear(Message::RENDER);
     request_message.clear(Message::RENDER);
     request_message.setOpcode(Opcode::NOTIFY());
     request_message.setOpcode(Opcode::NOTIFY());
     request_message.setRcode(Rcode::NOERROR());
     request_message.setRcode(Rcode::NOERROR());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     request_message.setQid(default_qid);
     request_message.setQid(default_qid);
     request_message.toWire(request_renderer);
     request_message.toWire(request_renderer);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::FORMERR(),
     headerCheck(parse_message, default_qid, Rcode::FORMERR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
                 Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
 }
 }
@@ -604,10 +600,10 @@ TEST_F(AuthSrvTest, notifyMultiQuestions) {
     // add one more SOA question
     // add one more SOA question
     request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
     request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
                                          RRType::SOA()));
                                          RRType::SOA()));
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::FORMERR(),
     headerCheck(parse_message, default_qid, Rcode::FORMERR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
                 Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
 }
 }
@@ -615,10 +611,10 @@ TEST_F(AuthSrvTest, notifyMultiQuestions) {
 TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
 TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::NS());
                         RRType::NS());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::FORMERR(),
     headerCheck(parse_message, default_qid, Rcode::FORMERR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG, 1, 0, 0, 0);
                 Opcode::NOTIFY().getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 }
@@ -627,8 +623,8 @@ TEST_F(AuthSrvTest, notifyWithoutAA) {
     // implicitly leave the AA bit off.  our implementation will accept it.
     // implicitly leave the AA bit off.  our implementation will accept it.
     createRequestPacket(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestPacket(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
                         RRType::SOA());
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::NOERROR(),
     headerCheck(parse_message, default_qid, Rcode::NOERROR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
                 Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
 }
 }
@@ -636,11 +632,11 @@ TEST_F(AuthSrvTest, notifyWithoutAA) {
 TEST_F(AuthSrvTest, notifyWithErrorRcode) {
 TEST_F(AuthSrvTest, notifyWithErrorRcode) {
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
                         RRType::SOA());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     request_message.setRcode(Rcode::SERVFAIL());
     request_message.setRcode(Rcode::SERVFAIL());
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::NOERROR(),
     headerCheck(parse_message, default_qid, Rcode::NOERROR(),
                 Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
                 Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
 }
 }
@@ -650,7 +646,7 @@ TEST_F(AuthSrvTest, notifyWithoutSession) {
 
 
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
                         RRType::SOA());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
 
 
     // we simply ignore the notify and let it be resent if an internal error
     // we simply ignore the notify and let it be resent if an internal error
@@ -664,7 +660,7 @@ TEST_F(AuthSrvTest, notifySendFail) {
 
 
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
                         RRType::SOA());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
 
 
     EXPECT_FALSE(server.processMessage(*io_message, parse_message,
     EXPECT_FALSE(server.processMessage(*io_message, parse_message,
@@ -676,7 +672,7 @@ TEST_F(AuthSrvTest, notifyReceiveFail) {
 
 
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
                         RRType::SOA());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
     EXPECT_FALSE(server.processMessage(*io_message, parse_message,
     EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                        response_renderer));
                                        response_renderer));
@@ -687,7 +683,7 @@ TEST_F(AuthSrvTest, notifyWithBogusSessionMessage) {
 
 
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
                         RRType::SOA());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
     EXPECT_FALSE(server.processMessage(*io_message, parse_message,
     EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                        response_renderer));
                                        response_renderer));
@@ -699,7 +695,7 @@ TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
 
 
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
     createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                         RRType::SOA());
                         RRType::SOA());
-    request_message.setHeaderFlag(MessageFlag::AA());
+    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
     createRequestPacket(IPPROTO_UDP);
     createRequestPacket(IPPROTO_UDP);
     EXPECT_FALSE(server.processMessage(*io_message, parse_message,
     EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                        response_renderer));
                                        response_renderer));
@@ -727,8 +723,8 @@ TEST_F(AuthSrvTest, updateConfig) {
     // 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
     // and authority section.
     // and authority section.
     createDataFromFile("examplequery_fromWire.wire");
     createDataFromFile("examplequery_fromWire.wire");
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
     headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 }
@@ -741,8 +737,8 @@ TEST_F(AuthSrvTest, datasourceFail) {
     // in a SERVFAIL response, and the answer and authority sections should
     // in a SERVFAIL response, and the answer and authority sections should
     // be empty.
     // be empty.
     createDataFromFile("badExampleQuery_fromWire.wire");
     createDataFromFile("badExampleQuery_fromWire.wire");
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
     headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 }
@@ -756,8 +752,8 @@ TEST_F(AuthSrvTest, updateConfigFail) {
 
 
     // The original data source should still exist.
     // The original data source should still exist.
     createDataFromFile("examplequery_fromWire.wire");
     createDataFromFile("examplequery_fromWire.wire");
-    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
+    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
-                                          response_renderer));
+                                      response_renderer));
     headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
     headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 }

+ 1 - 2
src/bin/auth/tests/run_unittests.cc

@@ -19,8 +19,7 @@
 #include <dns/tests/unittest_util.h>
 #include <dns/tests/unittest_util.h>
 
 
 int
 int
-main(int argc, char* argv[])
+main(int argc, char* argv[]) {
-{
     ::testing::InitGoogleTest(&argc, argv);
     ::testing::InitGoogleTest(&argc, argv);
     isc::UnitTestUtil::addDataPath(TEST_DATA_DIR);
     isc::UnitTestUtil::addDataPath(TEST_DATA_DIR);
     isc::UnitTestUtil::addDataPath(TEST_DATA_BUILDDIR);
     isc::UnitTestUtil::addDataPath(TEST_DATA_BUILDDIR);

+ 76 - 58
src/bin/bind10/bind10.py.in

@@ -63,16 +63,20 @@ import pwd
 import posix
 import posix
 
 
 import isc.cc
 import isc.cc
-import isc.utils.process
+import isc.util.process
+import isc.net.parse
 
 
 # Assign this process some longer name
 # Assign this process some longer name
-isc.utils.process.rename(sys.argv[0])
+isc.util.process.rename(sys.argv[0])
 
 
 # This is the version that gets displayed to the user.
 # This is the version that gets displayed to the user.
 # The VERSION string consists of the module name, the module version
 # The VERSION string consists of the module name, the module version
 # number, and the overall BIND 10 version number (set in configure.ac).
 # number, and the overall BIND 10 version number (set in configure.ac).
 VERSION = "bind10 20100916 (BIND 10 @PACKAGE_VERSION@)"
 VERSION = "bind10 20100916 (BIND 10 @PACKAGE_VERSION@)"
 
 
+# This is for bind10.boottime of stats module
+_BASETIME = time.gmtime()
+
 class RestartSchedule:
 class RestartSchedule:
     """
     """
 Keeps state when restarting something (in this case, a process).
 Keeps state when restarting something (in this case, a process).
@@ -137,9 +141,14 @@ class ProcessInfo:
         self.username = username
         self.username = username
         self._spawn()
         self._spawn()
 
 
-    def _setuid(self):
+    def _preexec_work(self):
         """Function used before running a program that needs to run as a
         """Function used before running a program that needs to run as a
         different user."""
         different user."""
+        # First, put us into a separate process group so we don't get
+        # SIGINT signals on Ctrl-C (the boss will shut everthing down by
+        # other means).
+        os.setpgrp()
+        # Second, set the user ID if one has been specified
         if self.uid is not None:
         if self.uid is not None:
             try:
             try:
                 posix.setuid(self.uid)
                 posix.setuid(self.uid)
@@ -173,42 +182,17 @@ class ProcessInfo:
                                         stderr=spawn_stderr,
                                         stderr=spawn_stderr,
                                         close_fds=True,
                                         close_fds=True,
                                         env=spawn_env,
                                         env=spawn_env,
-                                        preexec_fn=self._setuid)
+                                        preexec_fn=self._preexec_work)
         self.pid = self.process.pid
         self.pid = self.process.pid
         self.restart_schedule.set_run_start_time()
         self.restart_schedule.set_run_start_time()
 
 
     def respawn(self):
     def respawn(self):
         self._spawn()
         self._spawn()
 
 
-class IPAddr:
-    """Stores an IPv4 or IPv6 address."""
-    family = None
-    addr = None
-
-    def __init__(self, addr):
-        try:
-            a = socket.inet_pton(socket.AF_INET, addr)
-            self.family = socket.AF_INET
-            self.addr = a
-            return
-        except:
-            pass
-
-        try:
-            a = socket.inet_pton(socket.AF_INET6, addr)
-            self.family = socket.AF_INET6
-            self.addr = a
-            return
-        except Exception as e:
-            raise e
-    
-    def __str__(self):
-        return socket.inet_ntop(self.family, self.addr)
-
 class BoB:
 class BoB:
     """Boss of BIND class."""
     """Boss of BIND class."""
     
     
-    def __init__(self, msgq_socket_file=None, auth_port=5300, address='',
+    def __init__(self, msgq_socket_file=None, auth_port=5300, address=None,
                  nocache=False, verbose=False, setuid=None, username=None):
                  nocache=False, verbose=False, setuid=None, username=None):
         """Initialize the Boss of BIND. This is a singleton (only one
         """Initialize the Boss of BIND. This is a singleton (only one
         can run).
         can run).
@@ -222,7 +206,7 @@ class BoB:
         self.auth_port = auth_port
         self.auth_port = auth_port
         self.address = None
         self.address = None
         if address:
         if address:
-            self.address = IPAddr(address)
+            self.address = address
         self.cc_session = None
         self.cc_session = None
         self.ccs = None
         self.ccs = None
         self.processes = {}
         self.processes = {}
@@ -424,6 +408,27 @@ class BoB:
             sys.stdout.write("[bind10] Started b10-zonemgr(PID %d)\n" % 
             sys.stdout.write("[bind10] Started b10-zonemgr(PID %d)\n" % 
                              zonemgr.pid)
                              zonemgr.pid)
 
 
+        # start b10-stats
+        stats_args = ['b10-stats']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-stats\n")
+            stats_args += ['-v']
+        try:
+            statsd = ProcessInfo("b10-stats", stats_args,
+                                 c_channel_env)
+        except Exception as e:
+            c_channel.process.kill()
+            bind_cfgd.process.kill()
+            xfrout.process.kill()
+            auth.process.kill()
+            xfrind.process.kill()
+            zonemgr.process.kill()
+            return "Unable to start b10-stats; " + str(e)
+
+        self.processes[statsd.pid] = statsd
+        if self.verbose:
+            sys.stdout.write("[bind10] Started b10-stats (PID %d)\n" % statsd.pid)
+
         # start the b10-cmdctl
         # start the b10-cmdctl
         # XXX: we hardcode port 8080
         # XXX: we hardcode port 8080
         cmdctl_args = ['b10-cmdctl']
         cmdctl_args = ['b10-cmdctl']
@@ -440,6 +445,7 @@ class BoB:
             auth.process.kill()
             auth.process.kill()
             xfrind.process.kill()
             xfrind.process.kill()
             zonemgr.process.kill()
             zonemgr.process.kill()
+            statsd.process.kill()
             return "Unable to start b10-cmdctl; " + str(e)
             return "Unable to start b10-cmdctl; " + str(e)
         self.processes[cmd_ctrld.pid] = cmd_ctrld
         self.processes[cmd_ctrld.pid] = cmd_ctrld
         if self.verbose:
         if self.verbose:
@@ -453,12 +459,13 @@ class BoB:
     def stop_all_processes(self):
     def stop_all_processes(self):
         """Stop all processes."""
         """Stop all processes."""
         cmd = { "command": ['shutdown']}
         cmd = { "command": ['shutdown']}
-        self.cc_session.group_sendmsg(cmd, 'Boss', 'Cmdctl')
+        self.cc_session.group_sendmsg(cmd, 'Cmdctl', 'Cmdctl')
-        self.cc_session.group_sendmsg(cmd, "Boss", "ConfigManager")
+        self.cc_session.group_sendmsg(cmd, "ConfigManager", "ConfigManager")
-        self.cc_session.group_sendmsg(cmd, "Boss", "Auth")
+        self.cc_session.group_sendmsg(cmd, "Auth", "Auth")
-        self.cc_session.group_sendmsg(cmd, "Boss", "Xfrout")
+        self.cc_session.group_sendmsg(cmd, "Xfrout", "Xfrout")
-        self.cc_session.group_sendmsg(cmd, "Boss", "Xfrin")
+        self.cc_session.group_sendmsg(cmd, "Xfrin", "Xfrin")
-        self.cc_session.group_sendmsg(cmd, "Boss", "Zonemgr")
+        self.cc_session.group_sendmsg(cmd, "Zonemgr", "Zonemgr")
+        self.cc_session.group_sendmsg(cmd, "Boss", "Stats")
 
 
     def stop_process(self, process):
     def stop_process(self, process):
         """Stop the given process, friendly-like."""
         """Stop the given process, friendly-like."""
@@ -475,7 +482,9 @@ class BoB:
         except:
         except:
             pass
             pass
         # XXX: some delay probably useful... how much is uncertain
         # XXX: some delay probably useful... how much is uncertain
-        time.sleep(0.5)  
+        # I have changed the delay from 0.5 to 1, but sometime it's 
+        # still not enough.
+        time.sleep(1)  
         self.reap_children()
         self.reap_children()
         # next try sending a SIGTERM
         # next try sending a SIGTERM
         processes_to_stop = list(self.processes.values())
         processes_to_stop = list(self.processes.values())
@@ -582,7 +591,7 @@ def reaper(signal_number, stack_frame):
     # the Python signal handler has been set up to write
     # the Python signal handler has been set up to write
     # down a pipe, waking up our select() bit
     # down a pipe, waking up our select() bit
     pass
     pass
-                   
+
 def get_signame(signal_number):
 def get_signame(signal_number):
     """Return the symbolic name for a signal."""
     """Return the symbolic name for a signal."""
     for sig in dir(signal):
     for sig in dir(signal):
@@ -604,30 +613,28 @@ def fatal_signal(signal_number, stack_frame):
 def check_port(option, opt_str, value, parser):
 def check_port(option, opt_str, value, parser):
     """Function to insure that the port we are passed is actually 
     """Function to insure that the port we are passed is actually 
     a valid port number. Used by OptionParser() on startup."""
     a valid port number. Used by OptionParser() on startup."""
-    if not re.match('^(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)$', value):
+    try:
-        raise OptionValueError("%s requires a port number (0-65535)" % opt_str)
+        if opt_str in ['-p', '--port']:
-    if (opt_str == '-m' or opt_str == '--msgq-port'):
+            parser.values.auth_port = isc.net.parse.port_parse(value)
-        parser.values.msgq_port = value
+        else:
-    elif (opt_str == '-p' or opt_str == '--port'):
+            raise OptionValueError("Unknown option " + opt_str)
-        parser.values.auth_port = value
+    except ValueError as e:
-    else:
+        raise OptionValueError(str(e))
-        raise OptionValueError("Unknown option " + opt_str)
+
-  
 def check_addr(option, opt_str, value, parser):
 def check_addr(option, opt_str, value, parser):
     """Function to insure that the address we are passed is actually 
     """Function to insure that the address we are passed is actually 
     a valid address. Used by OptionParser() on startup."""
     a valid address. Used by OptionParser() on startup."""
     try:
     try:
-        IPAddr(value)
+        if opt_str in ['-a', '--address']:
-    except:
+            parser.values.address = isc.net.parse.addr_parse(value)
+        else:
+            raise OptionValueError("Unknown option " + opt_str)
+    except ValueError:
         raise OptionValueError("%s requires a valid IPv4 or IPv6 address" % opt_str)
         raise OptionValueError("%s requires a valid IPv4 or IPv6 address" % opt_str)
-    if (opt_str == '-a' or opt_str == '--address'):
-        parser.values.address = value
-    else:
-        raise OptionValueError("Unknown option " + opt_str)
 
 
 def process_rename(option, opt_str, value, parser):
 def process_rename(option, opt_str, value, parser):
     """Function that renames the process if it is requested by a option."""
     """Function that renames the process if it is requested by a option."""
-    isc.utils.process.rename(value)
+    isc.util.process.rename(value)
 
 
 def main():
 def main():
     global options
     global options
@@ -646,8 +653,8 @@ def main():
                       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",
     parser.add_option("-n", "--no-cache", action="store_true", dest="nocache",
                       default=False, help="disable hot-spot cache in b10-auth")
                       default=False, help="disable hot-spot cache in b10-auth")
-    parser.add_option("-p", "--port", dest="auth_port", type="string",
+    parser.add_option("-p", "--port", dest="auth_port", type="int",
-                      action="callback", callback=check_port, default="5300",
+                      action="callback", callback=check_port, default=5300,
                       help="port the b10-auth daemon will use (default 5300)")
                       help="port the b10-auth daemon will use (default 5300)")
     parser.add_option("-u", "--user", dest="user",
     parser.add_option("-u", "--user", dest="user",
                       type="string", default=None,
                       type="string", default=None,
@@ -714,7 +721,7 @@ def main():
     signal.signal(signal.SIGPIPE, signal.SIG_IGN)
     signal.signal(signal.SIGPIPE, signal.SIG_IGN)
 
 
     # Go bob!
     # Go bob!
-    boss_of_bind = BoB(options.msgq_socket_file, int(options.auth_port),
+    boss_of_bind = BoB(options.msgq_socket_file, options.auth_port,
                        options.address, options.nocache, options.verbose,
                        options.address, options.nocache, options.verbose,
                        setuid, username)
                        setuid, username)
     startup_result = boss_of_bind.startup()
     startup_result = boss_of_bind.startup()
@@ -723,6 +730,17 @@ def main():
         sys.exit(1)
         sys.exit(1)
     sys.stdout.write("[bind10] BIND 10 started\n")
     sys.stdout.write("[bind10] BIND 10 started\n")
 
 
+    # send "bind10.boot_time" to b10-stats
+    time.sleep(1) # wait a second
+    if options.verbose:
+        sys.stdout.write("[bind10] send \"bind10.boot_time\" to b10-stats\n")
+    cmd = isc.config.ccsession.create_command('set', 
+            { "stats_data": {
+              'bind10.boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
+              }
+            })
+    boss_of_bind.cc_session.group_sendmsg(cmd, 'Stats')
+
     # In our main loop, we check for dead processes or messages 
     # In our main loop, we check for dead processes or messages 
     # on the c-channel.
     # on the c-channel.
     wakeup_fd = wakeup_pipe[0]
     wakeup_fd = wakeup_pipe[0]

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

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

+ 3 - 24
src/bin/bind10/tests/bind10_test.py

@@ -1,4 +1,4 @@
-from bind10 import ProcessInfo, BoB, IPAddr
+from bind10 import ProcessInfo, BoB
 
 
 # XXX: environment tests are currently disabled, due to the preprocessor
 # XXX: environment tests are currently disabled, due to the preprocessor
 #      setup that we have now complicating the environment
 #      setup that we have now complicating the environment
@@ -8,6 +8,7 @@ import sys
 import os
 import os
 import signal
 import signal
 import socket
 import socket
+from isc.net.addr import IPAddr
 
 
 class TestProcessInfo(unittest.TestCase):
 class TestProcessInfo(unittest.TestCase):
     def setUp(self):
     def setUp(self):
@@ -72,28 +73,6 @@ class TestProcessInfo(unittest.TestCase):
         self.assertTrue(type(pi.pid) is int)
         self.assertTrue(type(pi.pid) is int)
         self.assertNotEqual(pi.pid, old_pid)
         self.assertNotEqual(pi.pid, old_pid)
 
 
-class TestIPAddr(unittest.TestCase):
-    def test_v6ok(self):
-        addr = IPAddr('2001:4f8::1')
-        self.assertEqual(addr.family, socket.AF_INET6)
-        self.assertEqual(addr.addr, socket.inet_pton(socket.AF_INET6, '2001:4f8::1'))
-
-    def test_v4ok(self):
-        addr = IPAddr('127.127.127.127')
-        self.assertEqual(addr.family, socket.AF_INET)
-        self.assertEqual(addr.addr, socket.inet_aton('127.127.127.127'))
-
-    def test_badaddr(self):
-        self.assertRaises(socket.error, IPAddr, 'foobar')
-        self.assertRaises(socket.error, IPAddr, 'foo::bar')
-        self.assertRaises(socket.error, IPAddr, '123')
-        self.assertRaises(socket.error, IPAddr, '123.456.789.0')
-        self.assertRaises(socket.error, IPAddr, '127/8')
-        self.assertRaises(socket.error, IPAddr, '0/0')
-        self.assertRaises(socket.error, IPAddr, '1.2.3.4/32')
-        self.assertRaises(socket.error, IPAddr, '0')
-        self.assertRaises(socket.error, IPAddr, '')
-
 class TestBoB(unittest.TestCase):
 class TestBoB(unittest.TestCase):
     def test_init(self):
     def test_init(self):
         bob = BoB()
         bob = BoB()
@@ -127,7 +106,7 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.runnable, False)
         self.assertEqual(bob.runnable, False)
 
 
     def test_init_alternate_address(self):
     def test_init_alternate_address(self):
-        bob = BoB(None, 5300, '127.127.127.127')
+        bob = BoB(None, 5300, IPAddr('127.127.127.127'))
         self.assertEqual(bob.verbose, False)
         self.assertEqual(bob.verbose, False)
         self.assertEqual(bob.auth_port, 5300)
         self.assertEqual(bob.auth_port, 5300)
         self.assertEqual(bob.msgq_socket_file, None)
         self.assertEqual(bob.msgq_socket_file, None)

+ 2 - 2
src/bin/bindctl/bindctl-source.py.in

@@ -24,9 +24,9 @@ from bindctl.moduleinfo import *
 from bindctl.bindcmd import *
 from bindctl.bindcmd import *
 import pprint
 import pprint
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
-import isc.utils.process
+import isc.util.process
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 __version__ = 'Bindctl'
 __version__ = 'Bindctl'
 
 

+ 2 - 2
src/bin/cfgmgr/b10-cfgmgr.py.in

@@ -21,11 +21,11 @@ import sys; sys.path.append ('@@PYTHONPATH@@')
 
 
 from isc.config.cfgmgr import ConfigManager, ConfigManagerDataReadError
 from isc.config.cfgmgr import ConfigManager, ConfigManagerDataReadError
 from isc.cc import SessionError
 from isc.cc import SessionError
-import isc.utils.process
+import isc.util.process
 import signal
 import signal
 import os
 import os
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 # If B10_FROM_SOURCE is set in the environment, we use data files
 # If B10_FROM_SOURCE is set in the environment, we use data files
 # from a directory relative to that, otherwise we use the ones
 # from a directory relative to that, otherwise we use the ones

+ 17 - 16
src/bin/cmdctl/cmdctl.py.in

@@ -43,15 +43,18 @@ import random
 import time
 import time
 import signal
 import signal
 from isc.config import ccsession
 from isc.config import ccsession
-import isc.utils.process
+import isc.util.process
+import isc.net.parse
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
 from hashlib import sha1
 from hashlib import sha1
+from isc.util import socketserver_mixin
+
 try:
 try:
     import threading
     import threading
 except ImportError:
 except ImportError:
     import dummy_threading as threading
     import dummy_threading as threading
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 __version__ = 'BIND10'
 __version__ = 'BIND10'
 URL_PATTERN = re.compile('/([\w]+)(?:/([\w]+))?/?')
 URL_PATTERN = re.compile('/([\w]+)(?:/([\w]+))?/?')
@@ -440,7 +443,9 @@ class CommandControl():
 
 
         return (keyfile, certfile, accountsfile)
         return (keyfile, certfile, accountsfile)
 
 
-class SecureHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
+class SecureHTTPServer(socketserver_mixin.NoPollMixIn,
+                       socketserver.ThreadingMixIn,
+                       http.server.HTTPServer):
     '''Make the server address can be reused.'''
     '''Make the server address can be reused.'''
     allow_reuse_address = True
     allow_reuse_address = True
 
 
@@ -448,6 +453,7 @@ class SecureHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
                  CommandControlClass,
                  CommandControlClass,
                  idle_timeout = 1200, verbose = False):
                  idle_timeout = 1200, verbose = False):
         '''idle_timeout: the max idle time for login'''
         '''idle_timeout: the max idle time for login'''
+        socketserver_mixin.NoPollMixIn.__init__(self)
         try:
         try:
             http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass)
             http.server.HTTPServer.__init__(self, server_address, RequestHandlerClass)
         except socket.error as err:
         except socket.error as err:
@@ -565,22 +571,17 @@ def run(addr = 'localhost', port = 8080, idle_timeout = 1200, verbose = False):
     httpd.serve_forever()
     httpd.serve_forever()
 
 
 def check_port(option, opt_str, value, parser):
 def check_port(option, opt_str, value, parser):
-    if (value < 0) or (value > 65535):
+    try:
-        raise OptionValueError('%s requires a port number (0-65535)' % opt_str)
+        parser.values.port = isc.net.parse.port_parse(value)
-    parser.values.port = value
+    except ValueError as e:
+        raise OptionValueError(str(e))
 
 
 def check_addr(option, opt_str, value, parser):
 def check_addr(option, opt_str, value, parser):
-    ipstr = value
-    ip_family = socket.AF_INET
-    if (ipstr.find(':') != -1):
-        ip_family = socket.AF_INET6
-
     try:
     try:
-        socket.inet_pton(ip_family, ipstr)
+        isc.net.parse.addr_parse(value)
-    except:
+        parser.values.addr = value
-        raise OptionValueError("%s invalid ip address" % ipstr)
+    except ValueError as e:
-
+        raise OptionValueError(str(e))
-    parser.values.addr = value
 
 
 def set_cmd_options(parser):
 def set_cmd_options(parser):
     parser.add_option('-p', '--port', dest = 'port', type = 'int',
     parser.add_option('-p', '--port', dest = 'port', type = 'int',

+ 1 - 0
src/bin/host/Makefile.am

@@ -1,5 +1,6 @@
 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_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 

+ 6 - 5
src/bin/host/host.cc

@@ -58,7 +58,7 @@ host_lookup(const char* const name, const char* const type) {
     msg.setOpcode(Opcode::QUERY());
     msg.setOpcode(Opcode::QUERY());
     msg.setRcode(Rcode::NOERROR());
     msg.setRcode(Rcode::NOERROR());
     if (recursive_bit) {
     if (recursive_bit) {
-        msg.setHeaderFlag(MessageFlag::RD());    // set recursive bit
+        msg.setHeaderFlag(Message::HEADERFLAG_RD); // set recursive bit
     }
     }
 
 
     msg.addQuestion(Question(Name(name),
     msg.addQuestion(Question(Name(name),
@@ -122,15 +122,16 @@ host_lookup(const char* const name, const char* const type) {
 
 
             rmsg.fromWire(ibuffer);
             rmsg.fromWire(ibuffer);
             if (!verbose) {
             if (!verbose) {
-                  for (RRsetIterator it = rmsg.beginSection(Section::ANSWER());
+                for (RRsetIterator it =
-                       it != rmsg.endSection(Section::ANSWER());
+                         rmsg.beginSection(Message::SECTION_ANSWER);
-                       ++it) {
+                     it != rmsg.endSection(Message::SECTION_ANSWER);
+                     ++it) {
                       if ((*it)->getType() != RRType::A()) {
                       if ((*it)->getType() != RRType::A()) {
                           continue;
                           continue;
                       }
                       }
 
 
                       RdataIteratorPtr rit = (*it)->getRdataIterator();
                       RdataIteratorPtr rit = (*it)->getRdataIterator();
-                      for (rit->first(); !rit->isLast(); rit->next()) {
+                      for (; !rit->isLast(); rit->next()) {
                           // instead of using my name, maybe use returned label?
                           // instead of using my name, maybe use returned label?
                           cout << name << " has address " <<
                           cout << name << " has address " <<
                               (*rit).getCurrent().toText() << endl;
                               (*rit).getCurrent().toText() << endl;

+ 2 - 2
src/bin/loadzone/b10-loadzone.py.in

@@ -18,12 +18,12 @@
 import sys; sys.path.append ('@@PYTHONPATH@@')
 import sys; sys.path.append ('@@PYTHONPATH@@')
 import re, getopt
 import re, getopt
 import isc.datasrc
 import isc.datasrc
-import isc.utils.process
+import isc.util.process
 from isc.datasrc.master import MasterFile
 from isc.datasrc.master import MasterFile
 import time
 import time
 import os
 import os
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 #########################################################################
 #########################################################################
 # usage: print usage note and exit
 # usage: print usage note and exit

+ 1 - 1
src/bin/loadzone/tests/error/error.known

@@ -1,5 +1,5 @@
 Error reading zone file: Cannot parse RR, No $ORIGIN: @ IN SOA ns hostmaster 1 3600 1800 1814400 3600
 Error reading zone file: Cannot parse RR, No $ORIGIN: @ IN SOA ns hostmaster 1 3600 1800 1814400 3600
-Error reading zone file: $ORIGIN is not absolute in record:$ORIGIN com
+Error reading zone file: $ORIGIN is not absolute in record: $ORIGIN com
 Error reading zone file: Cannot parse RR: $TL 300
 Error reading zone file: Cannot parse RR: $TL 300
 Error reading zone file: Cannot parse RR: $OIGIN com.
 Error reading zone file: Cannot parse RR: $OIGIN com.
 Error loading database: Error while loading com.: Cannot parse RR: $INLUDE file.txt
 Error loading database: Error while loading com.: Cannot parse RR: $INLUDE file.txt

+ 2 - 2
src/bin/msgq/msgq.py.in

@@ -31,11 +31,11 @@ import select
 import pprint
 import pprint
 import random
 import random
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
-import isc.utils.process
+import isc.util.process
 
 
 import isc.cc
 import isc.cc
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 # This is the version that gets displayed to the user.
 # This is the version that gets displayed to the user.
 __version__ = "v20091030 (Paving the DNS Parking Lot)"
 __version__ = "v20091030 (Paving the DNS Parking Lot)"

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

@@ -8,6 +8,7 @@ check-local:
 	for pytest in $(PYTESTS) ; do \
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/msgq:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/msgq:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
+	BIND10_TEST_SOCKET_FILE=$(builddir)/test_msgq_socket.sock \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done
 	done
 
 

+ 7 - 0
src/bin/msgq/tests/msgq_test.py

@@ -79,9 +79,14 @@ class TestSubscriptionManager(unittest.TestCase):
 
 
     def test_open_socket_default(self):
     def test_open_socket_default(self):
         env_var = None
         env_var = None
+        orig_socket_file = None
         if "BIND10_MSGQ_SOCKET_FILE" in os.environ:
         if "BIND10_MSGQ_SOCKET_FILE" in os.environ:
             env_var = os.environ["BIND10_MSGQ_SOCKET_FILE"]
             env_var = os.environ["BIND10_MSGQ_SOCKET_FILE"]
             del os.environ["BIND10_MSGQ_SOCKET_FILE"]
             del os.environ["BIND10_MSGQ_SOCKET_FILE"]
+        # temporarily replace the class "default" not to be disrupted by
+        # any running BIND 10 instance.
+        if "BIND10_TEST_SOCKET_FILE" in os.environ:
+            MsgQ.SOCKET_FILE = os.environ["BIND10_TEST_SOCKET_FILE"]
         socket_file = MsgQ.SOCKET_FILE
         socket_file = MsgQ.SOCKET_FILE
         self.assertFalse(os.path.exists(socket_file))
         self.assertFalse(os.path.exists(socket_file))
         msgq = MsgQ();
         msgq = MsgQ();
@@ -96,6 +101,8 @@ class TestSubscriptionManager(unittest.TestCase):
             pass
             pass
         if env_var is not None:
         if env_var is not None:
             os.environ["BIND10_MSGQ_SOCKET_FILE"] = env_var
             os.environ["BIND10_MSGQ_SOCKET_FILE"] = env_var
+        if orig_socket_file is not None:
+            MsgQ.SOCKET_FILE = orig_socket_file
 
 
     def test_open_socket_bad(self):
     def test_open_socket_bad(self):
         msgq = MsgQ("/does/not/exist")
         msgq = MsgQ("/does/not/exist")

+ 37 - 0
src/bin/stats/Makefile.am

@@ -0,0 +1,37 @@
+SUBDIRS = tests
+
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+
+pkglibexec_SCRIPTS = b10-stats
+noinst_SCRIPTS = b10-stats_stub
+
+b10_statsdir = $(DESTDIR)$(pkgdatadir)
+b10_stats_DATA = stats.spec
+
+CLEANFILES = stats.spec b10-stats stats.pyc stats.pyo b10-stats_stub stats_stub.pyc stats_stub.pyo
+
+man_MANS = b10-stats.8
+EXTRA_DIST = $(man_MANS) b10-stats.xml
+
+if ENABLE_MAN
+
+b10-stats.8: b10-stats.xml
+	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-stats.xml
+
+endif
+
+stats.spec: stats.spec.pre
+	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats.spec.pre >$@
+
+# TODO: does this need $$(DESTDIR) also?
+# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
+b10-stats: stats.py
+	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
+	       -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" \
+	       -e "s|.*#@@REMOVED@@$$||"  stats.py >$@
+	chmod a+x $@
+
+b10-stats_stub: stats_stub.py stats.py
+	$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
+	       -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats_stub.py >$@
+	chmod a+x $@

+ 68 - 0
src/bin/stats/b10-stats.8

@@ -0,0 +1,68 @@
+'\" t
+.\"     Title: b10-stats
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: Oct 15, 2010
+.\"    Manual: BIND10
+.\"    Source: BIND10
+.\"  Language: English
+.\"
+.TH "B10\-STATS" "8" "Oct 15, 2010" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-stats \- BIND 10 statistics module
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-stats\fR\ 'u
+\fBb10\-stats\fR [\fB\-v\fR] [\fB\-\-verbose\fR]
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-stats\fR
+is a daemon forked by
+\fBbind10\fR\&. Stats module collects statistics data from each module and reports statistics information via
+\fBbindctl\fR\&. It communicates by using the Command Channel by
+\fBb10\-msgq\fR
+with other modules like
+\fBbind10\fR,
+\fBb10\-auth\fR
+and so on\&. It waits for coming data from other modules, then other modules send data to stats module periodically\&. Other modules send stats data to stats module independently from implementation of stats module, so the frequency of sending data may not be constant\&. Stats module collects data and aggregates it\&.
+.SH "OPTIONS"
+.PP
+The arguments are as follows:
+.PP
+\fB\-v\fR, \fB\-\-verbose\fR
+.RS 4
+This
+\fBb10\-stats\fR
+switches to verbose mode\&. It sends verbose messages to STDOUT\&.
+.RE
+.SH "FILES"
+.PP
+/usr/local/share/bind10\-devel/stats\&.spec
+\(em This is a spec file for
+\fBb10\-stats\fR\&. It contains definitions of statistics items of BIND 10 and commands received vi bindctl\&.
+.SH "SEE ALSO"
+.PP
+
+\fBbind10\fR(8),
+\fBbindctl\fR(1),
+\fBb10-auth\fR(8),
+BIND 10 Guide\&.
+.SH "HISTORY"
+.PP
+The
+\fBb10\-stats\fR
+daemon was initially designed and implemented by Naoki Kambe of JPRS in Oct 2010\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+.br

+ 124 - 0
src/bin/stats/b10-stats.xml

@@ -0,0 +1,124 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+	       [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id$ -->
+<refentry>
+
+  <refentryinfo>
+    <date>Oct 15, 2010</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-stats</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-stats</refname>
+    <refpurpose>BIND 10 statistics module</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2010</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-stats</command>
+      <arg><option>-v</option></arg>
+      <arg><option>--verbose</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>
+      The <command>b10-stats</command> is a daemon forked by
+      <command>bind10</command>. Stats module collects statistics data
+      from each module and reports statistics information
+      via <command>bindctl</command>.  It communicates by using the
+      Command Channel by <command>b10-msgq</command> with other
+      modules
+      like <command>bind10</command>, <command>b10-auth</command> and
+      so on. It waits for coming data from other modules, then other
+      modules send data to stats module periodically. Other modules
+      send stats data to stats module independently from
+      implementation of stats module, so the frequency of sending data
+      may not be constant. Stats module collects data and aggregates
+      it.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+    <para>The arguments are as follows:</para>
+    <variablelist>
+      <varlistentry>
+        <term><option>-v</option>, <option>--verbose</option></term>
+        <listitem>
+	  <para>
+          This <command>b10-stats</command> switches to verbose
+          mode. It sends verbose messages to STDOUT.
+	  </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>FILES</title>
+    <para><filename>/usr/local/share/bind10-devel/stats.spec</filename>
+      &mdash; This is a spec file for <command>b10-stats</command>. It
+      contains definitions of statistics items of BIND 10 and commands
+      received vi bindctl.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>bindctl</refentrytitle><manvolnum>1</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citetitle>BIND 10 Guide</citetitle>.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The <command>b10-stats</command> daemon was initially designed
+      and implemented by Naoki Kambe of JPRS in Oct 2010.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->

+ 30 - 0
src/bin/stats/run_b10-stats.sh.in

@@ -0,0 +1,30 @@
+#! /bin/sh
+
+# Copyright (C) 2010  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.
+
+PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
+export PYTHON_EXEC
+
+PYTHONPATH=@abs_top_builddir@/src/lib/python
+export PYTHONPATH
+
+B10_FROM_BUILD=@abs_top_builddir@
+export B10_FROM_BUILD
+
+STATS_PATH=@abs_top_builddir@/src/bin/stats
+
+cd ${STATS_PATH}
+exec ${PYTHON_EXEC} -O b10-stats $*

+ 30 - 0
src/bin/stats/run_b10-stats_stub.sh.in

@@ -0,0 +1,30 @@
+#! /bin/sh
+
+# Copyright (C) 2010  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.
+
+PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
+export PYTHON_EXEC
+
+PYTHONPATH=@abs_top_builddir@/src/lib/python
+export PYTHONPATH
+
+B10_FROM_BUILD=@abs_top_srcdir@
+export B10_FROM_BUILD
+
+STATS_PATH=@abs_top_builddir@/src/bin/stats
+
+cd ${STATS_PATH}
+exec ${PYTHON_EXEC} -O b10-stats_stub $*

+ 416 - 0
src/bin/stats/stats.py.in

@@ -0,0 +1,416 @@
+#!@PYTHON@
+
+# Copyright (C) 2010  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.
+
+# $Id$
+__version__ = "$Revision$"
+
+import sys; sys.path.append ('@@PYTHONPATH@@')
+import os
+import signal
+import select
+from time import time, strftime, gmtime
+from optparse import OptionParser, OptionValueError
+from collections import defaultdict
+from isc.config.ccsession import ModuleCCSession, create_answer
+from isc.cc import Session, SessionError
+# Note: Following lines are removed in b10-stats	#@@REMOVED@@
+if __name__ == 'stats':					#@@REMOVED@@
+    try:						#@@REMOVED@@
+        from fake_time import time, strftime, gmtime	#@@REMOVED@@
+    except ImportError:					#@@REMOVED@@
+        pass						#@@REMOVED@@
+
+# for setproctitle
+import isc.util.process
+isc.util.process.rename()
+
+# If B10_FROM_BUILD is set in the environment, we use data files
+# from a directory relative to that, otherwise we use the ones
+# installed on the system
+if "B10_FROM_BUILD" in os.environ:
+    SPECFILE_LOCATION = os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec"
+else:
+    PREFIX = "@prefix@"
+    DATAROOTDIR = "@datarootdir@"
+    SPECFILE_LOCATION = "@datadir@/@PACKAGE@/stats.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+
+class Singleton(type):
+    """
+    A abstract class of singleton pattern
+    """
+    # Because of singleton pattern: 
+    #   At the beginning of coding, one UNIX domain socket is needed
+    #  for config manager, another socket is needed for stats module,
+    #  then stats module might need two sockets. So I adopted the
+    #  singleton pattern because I avoid creating multiple sockets in
+    #  one stats module. But in the initial version stats module
+    #  reports only via bindctl, so just one socket is needed. To use
+    #  the singleton pattern is not important now. :(
+
+    def __init__(self, *args, **kwargs):
+        type.__init__(self, *args, **kwargs)
+        self._instances = {}
+
+    def __call__(self, *args, **kwargs):
+        if args not in self._instances:
+            self._instances[args]={}
+        kw = tuple(kwargs.items())
+        if  kw not in self._instances[args]:
+            self._instances[args][kw] = type.__call__(self, *args, **kwargs)
+        return self._instances[args][kw]
+
+class Callback():
+    """
+    A Callback handler class
+    """
+    def __init__(self, name=None, callback=None, args=(), kwargs={}):
+        self.name = name
+        self.callback = callback
+        self.args = args
+        self.kwargs = kwargs
+
+    def __call__(self, *args, **kwargs):
+        if not args:
+            args = self.args
+        if not kwargs:
+            kwargs = self.kwargs
+        if self.callback:
+            return self.callback(*args, **kwargs)
+
+class Subject():
+    """
+    A abstract subject class of observer pattern
+    """
+    # Because of observer pattern:
+    #   In the initial release, I'm also sure that observer pattern
+    #  isn't definitely needed because the interface between gathering
+    #  and reporting statistics data is single.  However in the future
+    #  release, the interfaces may be multiple, that is, multiple
+    #  listeners may be needed. For example, one interface, which
+    #  stats module has, is for between ''config manager'' and stats
+    #  module, another interface is for between ''HTTP server'' and
+    #  stats module, and one more interface is for between ''SNMP
+    #  server'' and stats module. So by considering that stats module
+    #  needs multiple interfaces in the future release, I adopted the
+    #  observer pattern in stats module. But I don't have concrete
+    #  ideas in case of multiple listener currently.
+
+    def __init__(self):
+        self._listeners = []
+
+    def attach(self, listener):
+        if not listener in self._listeners:
+            self._listeners.append(listener)
+
+    def detach(self, listener):
+        try:
+            self._listeners.remove(listener)
+        except ValueError:
+            pass
+
+    def notify(self, event, modifier=None):
+        for listener in self._listeners:
+            if modifier != listener:
+                listener.update(event)
+
+class Listener():
+    """
+    A abstract listener class of observer pattern
+    """
+    def __init__(self, subject):
+        self.subject = subject
+        self.subject.attach(self)
+        self.events = {}
+
+    def update(self, name):
+        if name in self.events:
+            callback = self.events[name]
+            return callback()
+
+    def add_event(self, event):
+        self.events[event.name]=event
+
+class SessionSubject(Subject, metaclass=Singleton):
+    """
+    A concrete subject class which creates CC session object
+    """
+    def __init__(self, session=None, verbose=False):
+        Subject.__init__(self)
+        self.verbose = verbose
+        self.session=session
+        self.running = False
+
+    def start(self):
+        self.running = True
+        self.notify('start')
+
+    def stop(self):
+        self.running = False
+        self.notify('stop')
+
+    def check(self):
+        self.notify('check')
+
+class CCSessionListener(Listener):
+    """
+    A concrete listener class which creates SessionSubject object and
+    ModuleCCSession object
+    """
+    def __init__(self, subject, verbose=False):
+        Listener.__init__(self, subject)
+        self.verbose = verbose
+        self.session = subject.session
+        self.boot_time = get_datetime()
+
+        # create ModuleCCSession object
+        self.cc_session = ModuleCCSession(SPECFILE_LOCATION,
+                                          self.config_handler,
+                                          self.command_handler,
+                                          self.session)
+
+        self.session = self.subject.session = self.cc_session._session
+
+        # initialize internal data
+        self.config_spec = self.cc_session.get_module_spec().get_config_spec()
+        self.stats_spec = self.config_spec
+        self.stats_data = self.initialize_data(self.stats_spec)
+
+        # add event handler invoked via SessionSubject object
+        self.add_event(Callback('start', self.start))
+        self.add_event(Callback('stop', self.stop))
+        self.add_event(Callback('check', self.check))
+        # don't add 'command_' suffix to the special commands in
+        # order to prevent executing internal command via bindctl
+
+        # get commands spec
+        self.commands_spec = self.cc_session.get_module_spec().get_commands_spec()
+
+        # add event handler related command_handler of ModuleCCSession
+        # invoked via bindctl
+        for cmd in self.commands_spec:
+            try:
+                # add prefix "command_"
+                name = "command_" + cmd["command_name"]
+                callback = getattr(self, name)
+                kwargs = self.initialize_data(cmd["command_args"])
+                self.add_event(Callback(name=name, callback=callback, args=(), kwargs=kwargs))
+            except AttributeError as ae:
+                sys.stderr.write("[b10-stats] Caught undefined command while parsing spec file: "
+                                 +str(cmd["command_name"])+"\n")
+
+    def start(self):
+        """
+        start the cc chanel
+        """
+        # set initial value
+        self.stats_data['stats.boot_time'] = self.boot_time
+        self.stats_data['stats.start_time'] = get_datetime()
+        self.stats_data['stats.last_update_time'] = get_datetime()
+        self.stats_data['stats.lname'] = self.session.lname
+        return self.cc_session.start()
+
+    def stop(self):
+        """
+        stop the cc chanel
+        """
+        return self.cc_session.close()
+
+    def check(self):
+        """
+        check the cc chanel
+        """
+        return self.cc_session.check_command(False)
+
+    def config_handler(self, new_config):
+        """
+        handle a configure from the cc channel
+        """
+        if self.verbose:
+            sys.stdout.write("[b10-stats] newconfig received: "+str(new_config)+"\n")
+
+        # do nothing currently
+        return create_answer(0)
+
+    def command_handler(self, command, *args, **kwargs):
+        """
+        handle commands from the cc channel
+        """
+        # add 'command_' suffix in order to executing command via bindctl
+        name = 'command_' + command
+        
+        if name in self.events:
+            event = self.events[name]
+            return event(*args, **kwargs)
+        else:
+            return self.command_unknown(command, args)
+
+    def command_shutdown(self, args):
+        """
+        handle shutdown command
+        """
+        if self.verbose:
+            sys.stdout.write("[b10-stats] 'shutdown' command received\n")
+        self.subject.running = False
+        return create_answer(0)
+
+    def command_set(self, args, stats_data={}):
+        """
+        handle set command
+        """
+        if self.verbose:
+            sys.stdout.write("[b10-stats] 'set' command received, args: "+str(args)+"\n")
+
+        # 'args' must be dictionary type
+        self.stats_data.update(args['stats_data'])
+
+        # overwrite "stats.LastUpdateTime"
+        self.stats_data['stats.last_update_time'] = get_datetime()
+
+        return create_answer(0)
+
+    def command_remove(self, args, stats_item_name=''):
+        """
+        handle remove command
+        """
+        if self.verbose:
+            sys.stdout.write("[b10-stats] 'remove' command received, args: "+str(args)+"\n")
+
+        # 'args' must be dictionary type
+        if args and args['stats_item_name'] in self.stats_data:
+            stats_item_name = args['stats_item_name']
+
+        # just remove one item
+        self.stats_data.pop(stats_item_name)
+
+        return create_answer(0)
+
+    def command_show(self, args, stats_item_name=''):
+        """
+        handle show command
+        """
+        if self.verbose:
+            sys.stdout.write("[b10-stats] 'show' command received, args: "+str(args)+"\n")
+
+        # always overwrite 'report_time' and 'stats.timestamp'
+        # if "show" command invoked
+        self.stats_data['report_time'] = get_datetime()
+        self.stats_data['stats.timestamp'] = get_timestamp()
+
+        # if with args
+        if args and args['stats_item_name'] in self.stats_data:
+            stats_item_name = args['stats_item_name']
+            return create_answer(0, {stats_item_name: self.stats_data[stats_item_name]})
+
+        return create_answer(0, self.stats_data)
+
+    def command_reset(self, args):
+        """
+        handle reset command
+        """
+        if self.verbose:
+            sys.stdout.write("[b10-stats] 'reset' command received\n")
+
+        # re-initialize internal variables
+        self.stats_data = self.initialize_data(self.stats_spec)
+
+        # reset initial value
+        self.stats_data['stats.boot_time'] = self.boot_time
+        self.stats_data['stats.start_time'] = get_datetime()
+        self.stats_data['stats.last_update_time'] = get_datetime()
+        self.stats_data['stats.lname'] = self.session.lname
+
+        return create_answer(0)
+
+    def command_status(self, args):
+        """
+        handle status command
+        """
+        if self.verbose:
+            sys.stdout.write("[b10-stats] 'status' command received\n")
+        # just return "I'm alive."
+        return create_answer(0, "I'm alive.")
+
+    def command_unknown(self, command, args):
+        """
+        handle an unknown command
+        """
+        if self.verbose:
+            sys.stdout.write("[b10-stats] Unknown command received: '"
+                             + str(command) + "'\n")
+        return create_answer(1, "Unknown command: '"+str(command)+"'")
+
+
+    def initialize_data(self, spec):
+        """
+        initialize stats data
+        """
+        def __get_init_val(spec):
+            if spec['item_type'] == 'null':
+                return None
+            elif spec['item_type'] == 'boolean':
+                return bool(spec.get('item_default', False))
+            elif spec['item_type'] == 'string':
+                return str(spec.get('item_default', ''))
+            elif spec['item_type'] in set(['number', 'integer']):
+                return int(spec.get('item_default', 0))
+            elif spec['item_type'] in set(['float', 'double', 'real']):
+                return float(spec.get('item_default', 0.0))
+            elif spec['item_type'] in set(['list', 'array']):
+                return spec.get('item_default',
+                                [ __get_init_val(s) for s in spec['list_item_spec'] ])
+            elif spec['item_type'] in set(['map', 'object']):
+                return spec.get('item_default',
+                                dict([ (s['item_name'], __get_init_val(s)) for s in spec['map_item_spec'] ]) )
+            else:
+                return spec.get('item_default')
+        return dict([ (s['item_name'], __get_init_val(s)) for s in spec ])
+
+def get_timestamp():
+    """
+    get current timestamp
+    """
+    return time()
+
+def get_datetime():
+    """
+    get current datetime
+    """
+    return strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
+
+def main(session=None):
+    try:
+        parser = OptionParser()
+        parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
+                      help="display more about what is going on")
+        (options, args) = parser.parse_args()
+        subject = SessionSubject(session=session, verbose=options.verbose)
+        listener = CCSessionListener(subject, verbose=options.verbose)
+        subject.start()
+        while subject.running:
+            subject.check()
+        subject.stop()
+
+    except OptionValueError:
+        sys.stderr.write("[b10-stats] Error parsing options\n")
+    except SessionError as se:
+        sys.stderr.write("[b10-stats] Error creating Stats module, "
+              + "is the command channel daemon running?\n")
+    except KeyboardInterrupt as kie:
+        sys.stderr.write("[b10-stats] Interrupted, exiting\n")
+
+if __name__ == "__main__":
+    main()

+ 140 - 0
src/bin/stats/stats.spec.pre.in

@@ -0,0 +1,140 @@
+{
+  "module_spec": {
+    "module_name": "Stats",
+    "module_description": "Stats daemon",
+    "config_data": [
+      {
+        "item_name": "report_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "Report time",
+        "item_description": "A date time when stats module reports",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "bind10.boot_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.BootTime",
+        "item_description": "A date time when bind10 process starts initially",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.boot_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.BootTime",
+        "item_description": "A date time when the stats module starts initially or when the stats module restarts",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.start_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.StartTime",
+        "item_description": "A date time when the stats module starts collecting data or resetting values last time",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.last_update_time",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "1970-01-01T00:00:00Z",
+        "item_title": "stats.LastUpdateTime",
+        "item_description": "The latest date time when the stats module receives from other modules like auth server or boss process and so on",
+        "item_format": "date-time"
+      },
+      {
+        "item_name": "stats.timestamp",
+        "item_type": "real",
+        "item_optional": false,
+        "item_default": 0.0,
+        "item_title": "stats.Timestamp",
+        "item_description": "A current time stamp since epoch time (1970-01-01T00:00:00Z)",
+        "item_format": "second"
+      },
+      {
+        "item_name": "stats.lname",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": "",
+        "item_title": "stats.LocalName",
+        "item_description": "A localname of stats module given via CC protocol"
+      },
+      {
+        "item_name": "auth.queries.tcp",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 0,
+        "item_title": "auth.queries.tcp",
+        "item_description": "A number of total query counts which all auth servers receive over TCP since they started initially"
+      },
+      {
+        "item_name": "auth.queries.udp",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 0,
+        "item_title": "auth.queries.udp",
+        "item_description": "A number of total query counts which all auth servers receive over UDP since they started initially"
+      }
+    ],
+    "commands": [
+      {
+        "command_name": "status",
+        "command_description": "identify whether stats module is alive or not",
+        "command_args": []
+      },
+      {
+        "command_name": "show",
+        "command_description": "show the specified/all statistics data",
+        "command_args": [
+          {
+            "item_name": "stats_item_name",
+            "item_type": "string",
+            "item_optional": true,
+            "item_default": ""
+          }
+        ]
+      },
+      {
+        "command_name": "set",
+        "command_description": "set the value of specified name in statistics data",
+        "command_args": [
+          {
+            "item_name": "stats_data",
+            "item_type": "map",
+            "item_optional": false,
+            "item_default": {},
+            "map_item_spec": []
+          }
+        ]
+      },
+      {
+        "command_name": "remove",
+        "command_description": "remove the specified name from statistics data",
+        "command_args": [
+          {
+            "item_name": "stats_item_name",
+            "item_type": "string",
+            "item_optional": false,
+            "item_default": ""
+          }
+        ]
+      },
+      {
+        "command_name": "reset",
+        "command_description": "reset all statistics data to default values except for several constant names",
+        "command_args": []
+      },
+      {
+        "command_name": "shutdown",
+        "command_description": "Shut down the stats module",
+        "command_args": []
+      }
+    ]
+  }
+}

+ 155 - 0
src/bin/stats/stats_stub.py.in

@@ -0,0 +1,155 @@
+#!@PYTHON@
+
+# Copyright (C) 2010  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.
+
+# $Id$
+__version__ = "$Revision$"
+
+import sys; sys.path.append ('@@PYTHONPATH@@')
+import os
+import time
+from optparse import OptionParser, OptionValueError
+from isc.config.ccsession import ModuleCCSession, create_command, parse_answer, parse_command, create_answer
+from isc.cc import Session, SessionError
+from stats import get_datetime
+
+# for setproctitle
+import isc.util.process
+isc.util.process.rename()
+
+# If B10_FROM_BUILD is set in the environment, we use data files
+# from a directory relative to that, otherwise we use the ones
+# installed on the system
+if "B10_FROM_BUILD" in os.environ:
+    SPECFILE_LOCATION = os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec"
+else:
+    PREFIX = "@prefix@"
+    DATAROOTDIR = "@datarootdir@"
+    SPECFILE_LOCATION = "@datadir@/@PACKAGE@/stats.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
+
+class CCSessionStub:
+    """
+    This class is intended to behaves as a sender to Stats module. It
+    creates MoudleCCSession object and send specified command.
+    """
+    def __init__(self, session=None, verbose=False):
+        # create ModuleCCSession object
+        self.verbose = verbose
+        self.cc_session = ModuleCCSession(SPECFILE_LOCATION,
+                                          self.__dummy, self.__dummy, session)
+        self.module_name = self.cc_session._module_name
+        self.session = self.cc_session._session
+
+    def __dummy(self, *args):
+        pass
+
+    def send_command(self, command, args):
+        """
+        send command to stats module with args
+        """
+        cmd = create_command(command, args)
+        if self.verbose:
+            sys.stdout.write("[b10-stats_stub] send command : " + str(cmd) + "\n")
+        seq = self.session.group_sendmsg(cmd, self.module_name)
+        msg, env = self.session.group_recvmsg(False, seq) # non-blocking is False
+        if self.verbose:
+            sys.stdout.write("[b10-stats_stub] received env : " + str(env) + "\n")
+            sys.stdout.write("[b10-stats_stub] received message : " + str(msg) + "\n")
+        (ret, arg) = (None, None)
+        if 'result' in msg:
+            ret, arg = parse_answer(msg)
+        elif 'command' in msg:
+            ret, arg = parse_command(msg)
+        self.session.group_reply(env, create_answer(0))
+        return ret, arg, env
+        
+class BossModuleStub:
+    """
+    This class is customized from CCSessionStub and is intended to behaves
+    as a virtual Boss module to send to Stats Module.
+    """
+    def __init__(self, session=None, verbose=False):
+        self.stub = CCSessionStub(session=session, verbose=verbose)
+    
+    def send_boottime(self):
+        return self.stub.send_command("set", {"stats_data": {"bind10.boot_time": get_datetime()}})
+
+class AuthModuleStub:
+    """
+    This class is customized CCSessionStub and is intended to behaves
+    as a virtual Auth module to send to Stats Module.
+    """
+    def __init__(self, session=None, verbose=False):
+        self.stub = CCSessionStub(session=session, verbose=verbose)
+        self.count = { "udp": 0, "tcp": 0 }
+    
+    def send_udp_query_count(self, cmd="set", cnt=0):
+        """
+        count up udp query count
+        """
+        prt = "udp"
+        self.count[prt] = 1
+        if cnt > 0:
+            self.count[prt] = cnt
+        return self.stub.send_command(cmd,
+                                      {"stats_data":
+                                           {"auth.queries."+prt: self.count[prt]}
+                                       })
+
+    def send_tcp_query_count(self, cmd="set", cnt=0):
+        """
+        set udp query count
+        """
+        prt = "tcp"
+        self.count[prt] = self.count[prt] + 1
+        if cnt > 0:
+            self.count[prt] = cnt
+        return self.stub.send_command(cmd,
+                                      {"stats_data":
+                                           {"auth.queries."+prt: self.count[prt]}
+                                       })
+
+def main(session=None):
+    try:
+        parser=OptionParser()
+        parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
+                      help="display more about what is going on")
+        (options, args) = parser.parse_args()
+        stub = CCSessionStub(session=session, verbose=options.verbose)
+        boss = BossModuleStub(session=stub.session, verbose=options.verbose)
+        auth = AuthModuleStub(session=stub.session, verbose=options.verbose)
+        stub.send_command("status", None)
+        boss.send_boottime()
+        t_cnt=0
+        u_cnt=81120
+        auth.send_udp_query_count(cnt=u_cnt) # This is an example.
+        while True:
+            u_cnt = u_cnt + 1
+            t_cnt = t_cnt + 1
+            auth.send_udp_query_count(cnt=u_cnt)
+            auth.send_tcp_query_count(cnt=t_cnt)
+            time.sleep(1)
+
+    except OptionValueError:
+        sys.stderr.write("[b10-stats_stub] Error parsing options\n")
+    except SessionError as se:
+        sys.stderr.write("[b10-stats_stub] Error creating Stats module, "
+              + "is the command channel daemon running?\n")
+    except KeyboardInterrupt as kie:
+        sys.stderr.write("[b10-stats_stub] Interrupted, exiting\n")
+
+if __name__ == "__main__":
+    main()

+ 0 - 151
src/bin/stats/statsd.py

@@ -1,151 +0,0 @@
-#!/usr/bin/python
-#
-# This program collects 'counters' from 'statistics' channel.
-# It accepts one command: 'Boss' group 'shutdown'
-
-import isc.cc
-import time
-import select
-import os
-
-bossgroup = 'Boss'
-myname = 'statsd'
-debug = 0
-
-def total(s):
-    def totalsub(d,s):
-        for k in s.keys():
-            if (k == 'component' or k == 'version' 
-                or k == 'timestamp' or k == 'from'):
-                continue
-            if (k in d):
-                if (isinstance(s[k], dict)):
-                    totalsub(d[k], s[k])
-                else:
-                    d[k] = s[k] + d[k]
-            else:
-                d[k] = s[k]
-
-    if (len(s) == 0):
-        return {}
-    if (len(s) == 1):
-        for k in s.keys():
-            out = s[k]
-        out['components'] = 1
-        out['timestamp2'] = out['timestamp']
-        del out['from']
-        return out
-    _time1 = 0
-    _time2 = 0
-    out = {}
-    for i in s.values():
-        if (_time1 == 0 or _time1 < i['timestamp']):
-            _time1 = i['timestamp']
-        if (_time2 == 0 or _time2 > i['timestamp']):
-            _time2 = i['timestamp']
-        totalsub(out, i)
-    out['components'] = len(s)
-    out['timestamp'] = _time1;
-    out['timestamp2'] = _time2;
-    return out
-
-def dicttoxml(stats, level = 0):
-    def dicttoxmlsub(s, level):
-        output = ''
-        spaces = ' ' * level
-        for k in s.keys():
-            if (isinstance(s[k], dict)):
-                output += spaces + ('<%s>\n' %k) \
-                  + dicttoxmlsub(s[k], level+1) \
-                  + spaces + '</%s>\n' %k
-            else:
-                output += spaces + '<%s>%s</%s>\n' % (k, s[k], k)
-        return output
-
-    for k in stats.keys():
-        space = ' ' * level
-        output = space + '<component component="%s">\n' % k
-        s = stats[k]
-        if ('component' in s or 'components' in s):
-            output += dicttoxmlsub(s, level+1)
-        else:
-            for l in s.keys():
-                output +=  space + ' <from from="%s">\n' % l \
-                          + dicttoxmlsub(s[l], level+2) \
-                          + space + ' </from>\n'
-        output += space + '</component>\n'
-        return output
-
-def dump_stats(statpath, statcount, stat, statraw):
-    newfile = open(statpath + '.new', 'w')
-    newfile.write('<?xml version="1.0" encoding="UTF-8"?>\n')
-    newfile.write('<!-- created at '+time.strftime('%Y%m%d %H%M%S')+' -->\n')
-    newfile.write('<isc version="0.0">\n')
-    newfile.write(' <bind10>\n')
-    newfile.write('  <total>\n')
-    newfile.write(dicttoxml(stat, 3))
-    newfile.write('  </total>\n')
-    newfile.write('  <each>\n')
-    newfile.write(dicttoxml(statraw, 3))
-    newfile.write('  </each>\n')
-    newfile.write(' </bind10>\n')
-    newfile.write('</isc>\n')
-    newfile.close()
-    loop = statcount
-    while(loop > 0):
-        old = statpath + '.%d' % loop
-        loop -= 1
-        new = statpath + '.%d' % loop
-        if (os.access(new, os.F_OK)):
-            os.rename(new, old)
-    if (os.access(statpath, os.F_OK)):
-        os.rename(statpath, new)
-    os.rename(statpath + '.new', statpath)
-
-def collector(statgroup,step,statpath,statcount):
-    cc = isc.cc.Session()
-    if debug:
-        print ("cc.lname=",cc.lname)
-    cc.group_subscribe(statgroup)
-    cc.group_subscribe(bossgroup, myname)
-    wrote_time = -1
-    last_wrote_time = -1
-    last_recvd_time = -1
-    stats = {}
-    statstotal = {}
-    while 1:
-        wait = wrote_time + step - time.time()
-        if wait <= 0 and last_recvd_time > wrote_time:
-            if debug:
-                print ("dump stats")
-            dump_stats(statpath, statcount, statstotal, stats)
-            last_wrote_time = wrote_time;
-            wrote_time = time.time();
-            wait = last_wrote_time + step - time.time()
-            if wait < 0:
-                wait = step
-        r,w,e = select.select([cc._socket],[],[], wait)
-        for sock in r:
-            if sock == cc._socket:
-                data,envelope = cc.group_recvmsg(False)
-                if (envelope['group'] == bossgroup):
-                    if ('shutdown' in data):
-                        exit()
-                if (envelope['group'] == statgroup):
-                    # Check received data
-                    if (not('component' in data and 'version' in data
-                        and 'stats' in data)):
-                        continue
-                    component = data['component']
-                    _from = envelope['from']
-                    data['from'] = _from
-                    if debug:
-                        print ("received from ",_from)
-                    if (not (component in stats)):
-                        stats[component] = {}
-                    (stats[component])[_from] = data;
-                    statstotal[component] = total(stats[component])
-                    last_recvd_time = time.time()
-
-if __name__ == '__main__':
-    collector('statistics', 10, '/tmp/stats.xml', 100)

+ 0 - 55
src/bin/stats/statsd.txt

@@ -1,55 +0,0 @@
-= Statistics overview =
-
-Result of 26 Jan 2010 evening discussion,
-statistics overview was almost fixed.
-
-Statsd listens msgq "statistics" channel, gathers statistics
-from each BIND 10 components and dump them into a XML file periodically.
-
-= Statsd current status =
-
-Statsd can run with msgq.
-Statsd is not controlled by BoB.
-Statsd does not read configuration from cfgd.
-File path, dump frequency, rotate generations are fixed.
-Statsd dumps to "/tmp/stats" every 10 seconds except no statistics received.
-"/tmp/stats" are preserved 100 generations.
-
-Current implementation is put on "bind10/branches/parkinglot/src/bin/stats/".
-
-= statistics channel Message format =
-
-The Statsd accepts python dictionary format data from msgq
-"statistics" channel.
-
-The data need to contain "components", "version", "timestamp", "stats" keys.
-
-The statistics data format is { "component" : "<component_name>",
-"version": "<version number>", "timestamp": "<unixtime>", "stats":
-<python dictionary format statistics>}.
-
-"stats" data may be nested.
-"stats" data is defined by each component.
-
-Each component sends statistics data to "statistics" group periodically
-without joining the group.
-
-See a example component: "stats/test/test-agent.py".
-
-= How to publish statistics from each component =
-
-For example, parkinglot auth server has one "counter".
-Then, parkinglot's statistics message may be
- { "component":"parkinglot", "version":1, "timestamp":unixtime,
-   stats: { "counter": counter } }.
-Send it to msgq "statistics" channel periodically
-(For example, every 10 second).
-
-Then "Statsd" will write it to the statistics file periodically.
-
-= TODO =
-
-- statsd.spec
-- read configuration from cfgd.
-- how to publish statistics data
-- controlled by BoB

+ 0 - 6
src/bin/stats/test/shutdown.py

@@ -1,6 +0,0 @@
-#!/usr/bin/python
-
-import isc
-cc = isc.cc.Session()
-cc.group_subscribe("Boss")
-cc.group_sendmsg({ "command":"shutdown"},"Boss")

+ 0 - 178
src/bin/stats/test/test_agent.py

@@ -1,178 +0,0 @@
-#!/usr/bin/python
-
-# This program acts statistics agent.
-# It has pseudo counters which is incremented each 10 second and
-# sends data to "statistics" channel periodically.
-# One command is available
-#   "Boss"       group: "shutdown"
-
-import isc
-import time
-import select
-import random
-
-step_time = 10
-statgroup = "statistics"
-
-cc = isc.cc.Session()
-print (cc.lname)
-#cc.group_subscribe(statgroup)
-cc.group_subscribe("Boss")
-
-# counters
-
-NSSTATDESC={}
-NSSTATDESC["counterid"] = 0
-NSSTATDESC["requestv4"] = 0
-NSSTATDESC["requestv6"] = 0
-NSSTATDESC["edns0in"] = 0
-NSSTATDESC["badednsver"] = 0
-NSSTATDESC["tsigin"] = 0
-NSSTATDESC["sig0in"] = 0
-NSSTATDESC["invalidsig"] = 0
-NSSTATDESC["tcp"] = 0
-NSSTATDESC["authrej"] = 0
-NSSTATDESC["recurserej"] = 0
-NSSTATDESC["xfrrej"] = 0
-NSSTATDESC["updaterej"] = 0
-NSSTATDESC["response"] = 0
-NSSTATDESC["truncatedresp"] = 0
-NSSTATDESC["edns0out"] = 0
-NSSTATDESC["tsigout"] = 0
-NSSTATDESC["sig0out"] = 0
-NSSTATDESC["success"] = 0
-NSSTATDESC["authans"] = 0
-NSSTATDESC["nonauthans"] = 0
-NSSTATDESC["referral"] = 0
-NSSTATDESC["nxrrset"] = 0
-NSSTATDESC["servfail"] = 0
-NSSTATDESC["formerr"] = 0
-NSSTATDESC["nxdomain"] = 0
-NSSTATDESC["recursion"] = 0
-NSSTATDESC["duplicate"] = 0
-NSSTATDESC["dropped"] = 0
-NSSTATDESC["failure"] = 0
-NSSTATDESC["xfrdone"] = 0
-NSSTATDESC["updatereqfwd"] = 0
-NSSTATDESC["updaterespfwd"] = 0
-NSSTATDESC["updatefwdfail"] = 0
-NSSTATDESC["updatedone"] = 0
-NSSTATDESC["updatefail"] = 0
-NSSTATDESC["updatebadprereq"] = 0
-RESSTATDESC={}
-RESSTATDESC["counterid"] = 0
-RESSTATDESC["queryv4"] = 0
-RESSTATDESC["queryv6"] = 0
-RESSTATDESC["responsev4"] = 0
-RESSTATDESC["responsev6"] = 0
-RESSTATDESC["nxdomain"] = 0
-RESSTATDESC["servfail"] = 0
-RESSTATDESC["formerr"] = 0
-RESSTATDESC["othererror"] = 0
-RESSTATDESC["edns0fail"] = 0
-RESSTATDESC["mismatch"] = 0
-RESSTATDESC["truncated"] = 0
-RESSTATDESC["lame"] = 0
-RESSTATDESC["retry"] = 0
-RESSTATDESC["dispabort"] = 0
-RESSTATDESC["dispsockfail"] = 0
-RESSTATDESC["querytimeout"] = 0
-RESSTATDESC["gluefetchv4"] = 0
-RESSTATDESC["gluefetchv6"] = 0
-RESSTATDESC["gluefetchv4fail"] = 0
-RESSTATDESC["gluefetchv6fail"] = 0
-RESSTATDESC["val"] = 0
-RESSTATDESC["valsuccess"] = 0
-RESSTATDESC["valnegsuccess"] = 0
-RESSTATDESC["valfail"] = 0
-RESSTATDESC["queryrtt0"] = 0
-RESSTATDESC["queryrtt1"] = 0
-RESSTATDESC["queryrtt2"] = 0
-RESSTATDESC["queryrtt3"] = 0
-RESSTATDESC["queryrtt4"] = 0
-RESSTATDESC["queryrtt5"] = 0
-SOCKSTATDESC={}
-SOCKSTATDESC["counterid"] = 0
-SOCKSTATDESC["udp4open"] = 0
-SOCKSTATDESC["udp6open"] = 0
-SOCKSTATDESC["tcp4open"] = 0
-SOCKSTATDESC["tcp6open"] = 0
-SOCKSTATDESC["unixopen"] = 0
-SOCKSTATDESC["udp4openfail"] = 0
-SOCKSTATDESC["udp6openfail"] = 0
-SOCKSTATDESC["tcp4openfail"] = 0
-SOCKSTATDESC["tcp6openfail"] = 0
-SOCKSTATDESC["unixopenfail"] = 0
-SOCKSTATDESC["udp4close"] = 0
-SOCKSTATDESC["udp6close"] = 0
-SOCKSTATDESC["tcp4close"] = 0
-SOCKSTATDESC["tcp6close"] = 0
-SOCKSTATDESC["unixclose"] = 0
-SOCKSTATDESC["fdwatchclose"] = 0
-SOCKSTATDESC["udp4bindfail"] = 0
-SOCKSTATDESC["udp6bindfail"] = 0
-SOCKSTATDESC["tcp4bindfail"] = 0
-SOCKSTATDESC["tcp6bindfail"] = 0
-SOCKSTATDESC["unixbindfail"] = 0
-SOCKSTATDESC["fdwatchbindfail"] = 0
-SOCKSTATDESC["udp4connectfail"] = 0
-SOCKSTATDESC["udp6connectfail"] = 0
-SOCKSTATDESC["tcp4connectfail"] = 0
-SOCKSTATDESC["tcp6connectfail"] = 0
-SOCKSTATDESC["unixconnectfail"] = 0
-SOCKSTATDESC["fdwatchconnectfail"] = 0
-SOCKSTATDESC["udp4connect"] = 0
-SOCKSTATDESC["udp6connect"] = 0
-SOCKSTATDESC["tcp4connect"] = 0
-SOCKSTATDESC["tcp6connect"] = 0
-SOCKSTATDESC["unixconnect"] = 0
-SOCKSTATDESC["fdwatchconnect"] = 0
-SOCKSTATDESC["tcp4acceptfail"] = 0
-SOCKSTATDESC["tcp6acceptfail"] = 0
-SOCKSTATDESC["unixacceptfail"] = 0
-SOCKSTATDESC["tcp4accept"] = 0
-SOCKSTATDESC["tcp6accept"] = 0
-SOCKSTATDESC["unixaccept"] = 0
-SOCKSTATDESC["udp4sendfail"] = 0
-SOCKSTATDESC["udp6sendfail"] = 0
-SOCKSTATDESC["tcp4sendfail"] = 0
-SOCKSTATDESC["tcp6sendfail"] = 0
-SOCKSTATDESC["unixsendfail"] = 0
-SOCKSTATDESC["fdwatchsendfail"] = 0
-SOCKSTATDESC["udp4recvfail"] = 0
-SOCKSTATDESC["udp6recvfail"] = 0
-SOCKSTATDESC["tcp4recvfail"] = 0
-SOCKSTATDESC["tcp6recvfail"] = 0
-SOCKSTATDESC["unixrecvfail"] = 0
-SOCKSTATDESC["fdwatchrecvfail"] = 0
-SYSSTATDESC={}
-SYSSTATDESC['sockets'] = 0
-SYSSTATDESC['memory'] = 0
-
-sent = -1
-last_sent = -1
-loop = 0
-
-while 1:
-    NSSTATDESC["requestv4"] += random.randint(1,1000)
-    wait = sent + step_time - time.time()
-    if wait <= 0:
-        last_sent = sent;
-        sent = time.time();
-        msg = {'component':'auth', 'version':1, 'timestamp':time.time(),'stats':{'NSSTATDESC':NSSTATDESC,'RESSTATDESC':RESSTATDESC,'SOCKSTATDESC':SOCKSTATDESC,'SYSSTATDESC':SYSSTATDESC}}
-        print (msg)
-        print (cc.group_sendmsg(msg, statgroup))
-        wait = last_sent + step_time - time.time()
-        if wait < 0:
-            wait = step_time
-        loop += 1
-    r,w,e = select.select([cc._socket],[],[], wait)
-    for sock in r:
-        if sock == cc._socket:
-            data,envelope = cc.group_recvmsg(False)
-            print (data)
-            if (envelope["group"] == "Boss"):
-                if ("shutdown" in data):
-                    exit()
-            else:
-                print ("Unknown data: ", envelope,data)

+ 0 - 54
src/bin/stats/test_total.py

@@ -1,54 +0,0 @@
-import sys
-sys.path.insert(0, '.')
-from statsd import *
-
-def test_total():
-    stats = {
-              'auth': {
-                     'from1': {
-                               'component':'auth',
-                               'version':1,
-                               'from':'from1',
-                               'timestamp':20100125,
-                               'stats': {
-                                   'AUTH': {
-                                       'counterid': 1,
-                                       'requestv4': 2,
-                                       'requestv6': 4,
-                                   },
-                                   'SYS': {
-                                       'sockets': 8,
-                                       'memory': 16,
-                                   },
-                                },
-                     },
-                     'from2': {
-                               'component':'auth',
-                               'version':1,
-                               'from':'from1',
-                               'timestamp':20100126,
-                               'stats': {
-                                   'AUTH': {
-                                       'counterid': 256,
-                                       'requestv4': 512,
-                                       'requestv6': 1024,
-                                   },
-                                   'SYS': {
-                                       'sockets': 2048,
-                                       'memory': 4096,
-                                   },
-                                },
-                     },
-              },
-            };
-    t = {}
-    for key in stats:
-        t[key] = total(stats[key])
-    print (stats)
-    print (dicttoxml(stats))
-    print (t)
-    print (dicttoxml(t))
-
-
-if __name__ == "__main__":
-    test_total()

+ 15 - 0
src/bin/stats/tests/Makefile.am

@@ -0,0 +1,15 @@
+SUBDIRS = isc testdata
+PYTESTS = b10-stats_test.py b10-stats_stub_test.py
+EXTRA_DIST = $(PYTESTS) fake_time.py
+CLEANFILES = fake_time.pyc
+
+# later will have configure option to choose this, like: coverage run --branch
+PYCOVERAGE = $(PYTHON)
+# test using command-line arguments, so use check-local target instead of TESTS
+check-local:
+	for pytest in $(PYTESTS) ; do \
+	echo Running test: $$pytest ; \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/stats:$(abs_top_builddir)/src/bin/stats/tests \
+	B10_FROM_BUILD=$(abs_top_builddir) \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
+	done

+ 116 - 0
src/bin/stats/tests/b10-stats_stub_test.py

@@ -0,0 +1,116 @@
+# Copyright (C) 2010  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.
+
+# $Id$
+__version__ = "$Revision$"
+
+#
+# Tests for the stats stub module
+#
+import unittest
+import time
+import os
+import imp
+import stats_stub
+from isc.cc.session import Session
+from stats_stub import CCSessionStub, BossModuleStub, AuthModuleStub
+from stats import get_datetime
+
+class TestStats(unittest.TestCase):
+
+    def setUp(self):
+        self.session = Session()
+        self.stub = CCSessionStub(session=self.session, verbose=True)
+        self.boss = BossModuleStub(session=self.session, verbose=True)
+        self.auth = AuthModuleStub(session=self.session, verbose=True)
+        self.env = {'from': self.session.lname, 'group': 'Stats',
+                    'instance': '*', 'to':'*',
+                    'type':'send','seq':0}
+        self.result_ok = {'result': [0]}
+
+    def tearDown(self):
+        self.session.close()
+
+    def test_stub(self):
+        """
+        Test for send_command of CCSessionStub object
+        """
+        env = self.env
+        result_ok = self.result_ok
+        self.assertEqual(('status', None, env),
+                         self.stub.send_command('status', None))
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+        self.assertEqual(('shutdown', None, env),
+                         self.stub.send_command('shutdown', None))
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+        self.assertEqual(('show', None, env),
+                         self.stub.send_command('show', None))
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+        self.assertEqual(('set', {'atest': 100.0}, env),
+                         self.stub.send_command('set', {'atest': 100.0}))
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+
+    def test_boss_stub(self):
+        """
+        Test for send_command of BossModuleStub object
+        """
+        env = self.env
+        result_ok = self.result_ok
+        self.assertEqual(('set', {"stats_data":
+                                      {"bind10.boot_time": get_datetime()}
+                                  }, env), self.boss.send_boottime())
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+
+    def test_auth_stub(self):
+        """
+        Test for send_command of AuthModuleStub object
+        """
+        env = self.env
+        result_ok = self.result_ok
+        self.assertEqual(
+            ('set', {"stats_data": {"auth.queries.udp": 1}}, env),
+            self.auth.send_udp_query_count())
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+        self.assertEqual(
+            ('set', {"stats_data": {"auth.queries.tcp": 1}}, env),
+            self.auth.send_tcp_query_count())
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+        self.assertEqual(
+            ('set', {"stats_data": {"auth.queries.udp": 100}}, env),
+            self.auth.send_udp_query_count(cmd='set', cnt=100))
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+        self.assertEqual(
+            ('set', {"stats_data": {"auth.queries.tcp": 99}}, env),
+            self.auth.send_tcp_query_count(cmd='set', cnt=99))
+        self.assertEqual(result_ok, self.session.get_message("Stats", None))
+
+    def test_func_main(self):
+        # explicitly make failed
+        self.session.close()
+        stats_stub.main(session=self.session)
+
+    def test_osenv(self):
+        """
+        test for not having environ "B10_FROM_BUILD"
+        """
+        if "B10_FROM_BUILD" in os.environ:
+            path = os.environ["B10_FROM_BUILD"]
+            os.environ.pop("B10_FROM_BUILD")
+            imp.reload(stats_stub)
+            os.environ["B10_FROM_BUILD"] = path
+            imp.reload(stats_stub)
+
+if __name__ == "__main__":
+    unittest.main()

+ 646 - 0
src/bin/stats/tests/b10-stats_test.py

@@ -0,0 +1,646 @@
+# Copyright (C) 2010  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.
+
+# $Id$
+__version__ = "$Revision$"
+
+#
+# Tests for the stats module
+#
+import os
+import sys
+import time
+import unittest
+import imp
+from isc.cc.session import Session, SessionError
+from isc.config.ccsession import ModuleCCSession, ModuleCCSessionError
+import stats
+from stats import SessionSubject, CCSessionListener, get_timestamp, get_datetime
+from fake_time import _TEST_TIME_SECS, _TEST_TIME_STRF
+
+# setting Constant
+if sys.path[0] == '':
+    TEST_SPECFILE_LOCATION = "./testdata/stats_test.spec"
+else:
+    TEST_SPECFILE_LOCATION = sys.path[0] + "/testdata/stats_test.spec"
+
+class TestStats(unittest.TestCase):
+
+    def setUp(self):
+        self.session = Session()
+        self.subject = SessionSubject(session=self.session, verbose=True)
+        self.listener = CCSessionListener(self.subject, verbose=True)
+        self.stats_spec = self.listener.cc_session.get_module_spec().get_config_spec()
+        self.module_name = self.listener.cc_session.get_module_spec().get_module_name()
+        self.stats_data = {
+                'report_time' : get_datetime(),
+                'bind10.boot_time' : "1970-01-01T00:00:00Z",
+                'stats.timestamp' : get_timestamp(),
+                'stats.lname' : self.session.lname,
+                'auth.queries.tcp': 0,
+                'auth.queries.udp': 0,
+                "stats.boot_time": get_datetime(),
+                "stats.start_time": get_datetime(),
+                "stats.last_update_time": get_datetime()
+                }
+        # check starting
+        self.assertFalse(self.subject.running)
+        self.subject.start()
+        self.assertTrue(self.subject.running)
+        self.assertEqual(len(self.session.message_queue), 0)
+        self.assertEqual(self.module_name, 'Stats')
+
+    def tearDown(self):
+        # check closing
+        self.subject.stop()
+        self.assertFalse(self.subject.running)
+        self.subject.detach(self.listener)
+        self.listener.stop()
+        self.session.close()
+
+    def test_local_func(self):
+        """
+        Test for local function
+        
+        """
+        # test for result_ok
+        self.assertEqual(type(result_ok()), dict)
+        self.assertEqual(result_ok(), {'result': [0]})
+        self.assertEqual(result_ok(1), {'result': [1]})
+        self.assertEqual(result_ok(0,'OK'), {'result': [0, 'OK']})
+        self.assertEqual(result_ok(1,'Not good'), {'result': [1, 'Not good']})
+        self.assertEqual(result_ok(None,"It's None"), {'result': [None, "It's None"]})
+        self.assertNotEqual(result_ok(), {'RESULT': [0]})
+
+        # test for get_timestamp
+        self.assertEqual(get_timestamp(), _TEST_TIME_SECS)
+
+        # test for get_datetime
+        self.assertEqual(get_datetime(), _TEST_TIME_STRF)
+
+    def test_show_command(self):
+        """
+        Test for show command
+        
+        """
+        # test show command without arg
+        self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        # ignore under 0.9 seconds
+        self.assertEqual(result_ok(0, self.stats_data), result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test show command with arg
+        self.session.group_sendmsg({"command": [ "show", {"stats_item_name": "stats.lname"}]}, "Stats")
+        self.assertEqual(len(self.subject.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.subject.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'stats.lname': self.stats_data['stats.lname']}),
+                         result_data)
+        self.assertEqual(len(self.subject.session.message_queue), 0)
+
+        # test show command with arg which has wrong name
+        self.session.group_sendmsg({"command": [ "show", {"stats_item_name": "stats.dummy"}]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        # ignore under 0.9 seconds
+        self.assertEqual(result_ok(0, self.stats_data), result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_set_command(self):
+        """
+        Test for set command
+        
+        """
+        # test set command
+        self.stats_data['auth.queries.udp'] = 54321
+        self.assertEqual(self.stats_data['auth.queries.udp'], 54321)
+        self.assertEqual(self.stats_data['auth.queries.tcp'], 0)
+        self.session.group_sendmsg({ "command": [
+                                      "set", {
+                                          'stats_data': {'auth.queries.udp': 54321 }
+                                      } ] },
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test show command
+        self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, self.stats_data), result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test set command 2
+        self.stats_data['auth.queries.udp'] = 0
+        self.assertEqual(self.stats_data['auth.queries.udp'], 0)
+        self.assertEqual(self.stats_data['auth.queries.tcp'], 0)
+        self.session.group_sendmsg({ "command": [ "set", {'stats_data': {'auth.queries.udp': 0}} ]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test show command 2
+        self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, self.stats_data), result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test set command 3
+        self.stats_data['auth.queries.tcp'] = 54322
+        self.assertEqual(self.stats_data['auth.queries.udp'], 0)
+        self.assertEqual(self.stats_data['auth.queries.tcp'], 54322)
+        self.session.group_sendmsg({ "command": [
+                                      "set", {
+                                          'stats_data': {'auth.queries.tcp': 54322 }
+                                      } ] },
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test show command 3
+        self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, self.stats_data), result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_remove_command(self):
+        """
+        Test for remove command
+        
+        """
+        self.session.group_sendmsg({"command":
+                                   [ "remove", {"stats_item_name": 'bind10.boot_time' }]},
+                              "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+        self.assertEqual(self.stats_data.pop('bind10.boot_time'), "1970-01-01T00:00:00Z")
+        self.assertFalse('bind10.boot_time' in self.stats_data)
+
+        # test show command with arg
+        self.session.group_sendmsg({"command":
+                                    [ "show", {"stats_item_name": 'bind10.boot_time'}]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertFalse('bind10.boot_time' in result_data['result'][1])
+        self.assertEqual(result_ok(0, self.stats_data), result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_reset_command(self):
+        """
+        Test for reset command
+        
+        """
+        self.session.group_sendmsg({"command": [ "reset" ] }, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test show command
+        self.session.group_sendmsg({"command": [ "show" ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, self.stats_data), result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_status_command(self):
+        """
+        Test for status command
+        
+        """
+        self.session.group_sendmsg({"command": [ "status" ] }, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(0, "I'm alive."),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_unknown_command(self):
+        """
+        Test for unknown command
+        
+        """
+        self.session.group_sendmsg({"command": [ "hoge", None ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(1, "Unknown command: 'hoge'"),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_shutdown_command(self):
+        """
+        Test for shutdown command
+        
+        """
+        self.session.group_sendmsg({"command": [ "shutdown", None ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.assertTrue(self.subject.running)
+        self.subject.check()
+        self.assertFalse(self.subject.running)
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+
+    def test_some_commands(self):
+        """
+        Test for some commands in a row
+        
+        """
+        # test set command
+        self.stats_data['bind10.boot_time'] = '2010-08-02T14:47:56Z'
+        self.assertEqual(self.stats_data['bind10.boot_time'], '2010-08-02T14:47:56Z')
+        self.session.group_sendmsg({ "command": [
+                                      "set", {
+                                          'stats_data': {'bind10.boot_time': '2010-08-02T14:47:56Z' }
+                                      }]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # check its value
+        self.session.group_sendmsg({ "command": [
+                                      "show", { 'stats_item_name': 'bind10.boot_time' }
+                                     ] }, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'bind10.boot_time': '2010-08-02T14:47:56Z'}),
+                         result_data)
+        self.assertEqual(result_ok(0, {'bind10.boot_time': self.stats_data['bind10.boot_time']}),
+                         result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test set command 2nd
+        self.stats_data['auth.queries.udp'] = 98765
+        self.assertEqual(self.stats_data['auth.queries.udp'], 98765)
+        self.session.group_sendmsg({ "command": [
+                                      "set", { 'stats_data': {
+                                            'auth.queries.udp':
+                                              self.stats_data['auth.queries.udp']
+                                            } } 
+                                     ] }, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # check its value
+        self.session.group_sendmsg({"command": [
+				      "show", {'stats_item_name': 'auth.queries.udp'}
+                                    ] }, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'auth.queries.udp': 98765}),
+                         result_data)
+        self.assertEqual(result_ok(0, {'auth.queries.udp': self.stats_data['auth.queries.udp']}),
+                         result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test set command 3
+        self.stats_data['auth.queries.tcp'] = 4321
+        self.session.group_sendmsg({"command": [
+                                      "set",
+                                      {'stats_data': {'auth.queries.tcp': 4321 }} ]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # check value
+        self.session.group_sendmsg({"command": [ "show", {'stats_item_name': 'auth.queries.tcp'} ]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'auth.queries.tcp': 4321}),
+                         result_data)
+        self.assertEqual(result_ok(0, {'auth.queries.tcp': self.stats_data['auth.queries.tcp']}),
+                         result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        self.session.group_sendmsg({"command": [ "show", {'stats_item_name': 'auth.queries.udp'} ]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'auth.queries.udp': 98765}),
+                         result_data)
+        self.assertEqual(result_ok(0, {'auth.queries.udp': self.stats_data['auth.queries.udp']}),
+                         result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test set command 4
+        self.stats_data['auth.queries.tcp'] = 67890
+        self.session.group_sendmsg({"command": [
+                                      "set", {'stats_data': {'auth.queries.tcp': 67890 }} ]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test show command for all values
+        self.session.group_sendmsg({"command": [ "show", None ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, self.stats_data), result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_some_commands2(self):
+        """
+        Test for some commands in a row using list-type value
+        
+        """
+        self.stats_data['listtype'] = [1, 2, 3]
+        self.assertEqual(self.stats_data['listtype'], [1, 2, 3])
+        self.session.group_sendmsg({ "command": [
+                                      "set", {'stats_data': {'listtype': [1, 2, 3] }}
+                                      ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # check its value
+        self.session.group_sendmsg({ "command": [
+                                      "show", { 'stats_item_name': 'listtype'}
+                                     ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'listtype': [1, 2, 3]}),
+                         result_data)
+        self.assertEqual(result_ok(0, {'listtype': self.stats_data['listtype']}),
+                         result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test set list-type value
+        self.assertEqual(self.stats_data['listtype'], [1, 2, 3])
+        self.session.group_sendmsg({"command": [
+                                      "set", {'stats_data': {'listtype': [3, 2, 1, 0] }}
+                                    ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # check its value
+        self.session.group_sendmsg({ "command": [
+                                      "show", { 'stats_item_name': 'listtype' }
+                                     ] }, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'listtype': [3, 2, 1, 0]}),
+                         result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_some_commands3(self):
+        """
+        Test for some commands in a row using dictionary-type value
+        
+        """
+        self.stats_data['dicttype'] = {"a": 1, "b": 2, "c": 3}
+        self.assertEqual(self.stats_data['dicttype'], {"a": 1, "b": 2, "c": 3})
+        self.session.group_sendmsg({ "command": [
+                                      "set", {
+                                          'stats_data': {'dicttype': {"a": 1, "b": 2, "c": 3} }
+                                      }]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # check its value
+        self.session.group_sendmsg({ "command": [ "show", { 'stats_item_name': 'dicttype' } ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'dicttype': {"a": 1, "b": 2, "c": 3}}),
+                         result_data)
+        self.assertEqual(result_ok(0, {'dicttype': self.stats_data['dicttype']}),
+                         result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # test set list-type value
+        self.assertEqual(self.stats_data['dicttype'], {"a": 1, "b": 2, "c": 3})
+        self.session.group_sendmsg({"command": [
+                                      "set", {'stats_data': {'dicttype': {"a": 3, "b": 2, "c": 1, "d": 0} }} ]},
+                                   "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+        self.assertEqual(len(self.session.message_queue), 0)
+
+        # check its value
+        self.session.group_sendmsg({ "command": [ "show", { 'stats_item_name': 'dicttype' }]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        result_data = self.session.get_message("Stats", None)
+        self.assertEqual(result_ok(0, {'dicttype': {"a": 3, "b": 2, "c": 1, "d": 0} }),
+                         result_data)
+        self.assertEqual(len(self.session.message_queue), 0)
+
+    def test_config_update(self):
+        """
+        Test for config update
+        
+        """
+        # test show command without arg
+        self.session.group_sendmsg({"command": [ "config_update", {"x-version":999} ]}, "Stats")
+        self.assertEqual(len(self.session.message_queue), 1)
+        self.subject.check()
+        self.assertEqual(result_ok(),
+                         self.session.get_message("Stats", None))
+
+class TestStats2(unittest.TestCase):
+
+    def setUp(self):
+        self.session = Session(verbose=True)
+        self.subject = SessionSubject(session=self.session, verbose=True)
+        self.listener = CCSessionListener(self.subject, verbose=True)
+        self.module_name = self.listener.cc_session.get_module_spec().get_module_name()
+        # check starting
+        self.assertFalse(self.subject.running)
+        self.subject.start()
+        self.assertTrue(self.subject.running)
+        self.assertEqual(len(self.session.message_queue), 0)
+        self.assertEqual(self.module_name, 'Stats')
+
+    def tearDown(self):
+        # check closing
+        self.subject.stop()
+        self.assertFalse(self.subject.running)
+        self.subject.detach(self.listener)
+        self.listener.stop()
+
+    def test_specfile(self):
+        """
+        Test for specfile
+        
+        """
+        if "B10_FROM_BUILD" in os.environ:
+            self.assertEqual(stats.SPECFILE_LOCATION,
+                             os.environ["B10_FROM_BUILD"] + "/src/bin/stats/stats.spec")
+        imp.reload(stats)
+        # change path of SPECFILE_LOCATION
+        stats.SPECFILE_LOCATION = TEST_SPECFILE_LOCATION
+        self.assertEqual(stats.SPECFILE_LOCATION, TEST_SPECFILE_LOCATION)
+        self.subject = stats.SessionSubject(session=self.session, verbose=True)
+        self.session = self.subject.session
+        self.listener = stats.CCSessionListener(self.subject, verbose=True)
+
+        self.assertEqual(self.listener.stats_spec, [])
+        self.assertEqual(self.listener.stats_data, {})
+
+        self.assertEqual(self.listener.commands_spec, [
+                {
+                    "command_name": "status",
+                    "command_description": "identify whether stats module is alive or not",
+                    "command_args": []
+                },
+                {
+                    "command_name": "the_dummy",
+                    "command_description": "this is for testing",
+                    "command_args": []
+                }])
+
+    def test_func_initialize_data(self):
+        """
+        Test for initialize_data function 
+        
+        """
+        # prepare for sample data set
+        stats_spec = [
+            {
+                "item_name": "none_sample",
+                "item_type": "null",
+                "item_default": "None"
+            },
+            {
+                "item_name": "boolean_sample",
+                "item_type": "boolean",
+                "item_default": True
+            },
+            {
+                "item_name": "string_sample",
+                "item_type": "string",
+                "item_default": "A something"
+            },
+            {
+                "item_name": "int_sample",
+                "item_type": "integer",
+                "item_default": 9999999
+            },
+            {
+                "item_name": "real_sample",
+                "item_type": "real",
+                "item_default": 0.0009
+            },
+            {
+                "item_name": "list_sample",
+                "item_type": "list",
+                "item_default": [0, 1, 2, 3, 4],
+                "list_item_spec": []
+            },
+            {
+                "item_name": "map_sample",
+                "item_type": "map",
+                "item_default": {'name':'value'},
+                "map_item_spec": []
+            },
+            {
+                "item_name": "other_sample",
+                "item_type": "__unknown__",
+                "item_default": "__unknown__"
+            }
+        ]
+        # data for comparison
+        stats_data = {
+            'none_sample': None,
+            'boolean_sample': True,
+            'string_sample': 'A something',
+            'int_sample': 9999999,
+            'real_sample': 0.0009,
+            'list_sample': [0, 1, 2, 3, 4],
+            'map_sample': {'name':'value'},
+            'other_sample': '__unknown__'
+        }
+        self.assertEqual(self.listener.initialize_data(stats_spec), stats_data)
+
+    def test_func_main(self):
+        # explicitly make failed
+        self.session.close()
+        stats.main(session=self.session)
+
+    def test_osenv(self):
+        """
+        test for not having environ "B10_FROM_BUILD"
+        """
+        if "B10_FROM_BUILD" in os.environ:
+            path = os.environ["B10_FROM_BUILD"]
+            os.environ.pop("B10_FROM_BUILD")
+            imp.reload(stats)
+            os.environ["B10_FROM_BUILD"] = path
+            imp.reload(stats)
+
+def result_ok(*args):
+    if args:
+        return { 'result': list(args) }
+    else:
+        return { 'result': [ 0 ] }
+
+if __name__ == "__main__":
+    unittest.main()

+ 48 - 0
src/bin/stats/tests/fake_time.py

@@ -0,0 +1,48 @@
+# Copyright (C) 2010  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.
+
+# $Id$
+__version__ = "$Revision$"
+
+# This is a dummy time class against a Python standard time class.
+# It is just testing use only.
+# Other methods which time class has is not implemented.
+# (This class isn't orderloaded for time class.)
+
+# These variables are constant. These are example.
+_TEST_TIME_SECS = 1283364938.229088
+_TEST_TIME_STRF = '2010-09-01T18:15:38Z'
+
+def time():
+    """
+    This is a dummy time() method against time.time()
+    """
+    # return float constant value
+    return _TEST_TIME_SECS
+
+def gmtime():
+    """
+    This is a dummy gmtime() method against time.gmtime()
+    """
+    # always return nothing
+    return None
+
+def strftime(*arg):
+    """
+    This is a dummy gmtime() method against time.gmtime()
+    """
+    return _TEST_TIME_STRF
+
+

+ 3 - 0
src/bin/stats/tests/isc/Makefile.am

@@ -0,0 +1,3 @@
+SUBDIRS = cc config util
+EXTRA_DIST = __init__.py
+CLEANFILES = __init__.pyc

+ 0 - 0
src/bin/stats/tests/isc/__init__.py


+ 2 - 0
src/bin/stats/tests/isc/cc/Makefile.am

@@ -0,0 +1,2 @@
+EXTRA_DIST = __init__.py session.py
+CLEANFILES = __init__.pyc session.pyc

+ 1 - 0
src/bin/stats/tests/isc/cc/__init__.py

@@ -0,0 +1 @@
+from isc.cc.session import *

+ 127 - 0
src/bin/stats/tests/isc/cc/session.py

@@ -0,0 +1,127 @@
+# Copyright (C) 2010  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.
+
+# $Id$
+# This module is a mock-up class of isc.cc.session
+
+__version__ = "$Revision$"
+
+import sys
+
+# set a dummy lname
+_TEST_LNAME = '123abc@xxxx'
+
+class Queue():
+    def __init__(self, msg=None, env={}):
+        self.msg = msg
+        self.env = env
+
+    def dump(self):
+        return { 'msg': self.msg, 'env': self.env }
+               
+class SessionError(Exception):
+    pass
+
+class Session:
+    def __init__(self, socket_file=None, verbose=False):
+        self._lname = _TEST_LNAME
+        self.message_queue = []
+        self.old_message_queue = []
+        self._socket = True
+        self.verbose = verbose
+
+    @property
+    def lname(self):
+        return self._lname
+
+    def close(self):
+        self._socket = False
+
+    def _next_sequence(self, que=None):
+        return len(self.message_queue)
+
+    def enqueue(self, msg=None, env={}):
+        if not self._socket:
+            raise SessionError("Session has been closed.")
+        seq = self._next_sequence()
+        env.update({"seq": 0}) # fixed here
+        que = Queue(msg=msg, env=env)
+        self.message_queue.append(que)
+        if self.verbose:
+            sys.stdout.write("[Session] enqueue: " + str(que.dump()) + "\n")
+        return seq
+
+    def dequeue(self, seq=0):
+        if not self._socket:
+            raise SessionError("Session has been closed.")
+        que = None
+        try:
+            que = self.message_queue.pop(seq)
+            self.old_message_queue.append(que)
+        except IndexError:
+            que = Queue()
+        if self.verbose:
+            sys.stdout.write("[Session] dequeue: " + str(que.dump()) + "\n")
+        return que
+
+    def get_queue(self, seq=None):
+        if not self._socket:
+            raise SessionError("Session has been closed.")
+        if seq is None:
+            seq = len(self.message_queue) - 1
+        que = None
+        try:
+            que = self.message_queue[seq]
+        except IndexError:
+            raise IndexError
+            que = Queue()
+        if self.verbose:
+            sys.stdout.write("[Session] get_queue: " + str(que.dump()) + "\n")
+        return que
+
+    def group_sendmsg(self, msg, group, instance="*", to="*"):
+        return self.enqueue(msg=msg, env={
+                "type": "send",
+                "from": self._lname,
+                "to": to,
+                "group": group,
+                "instance": instance })
+
+    def group_recvmsg(self, nonblock=True, seq=0):
+        que = self.dequeue(seq)
+        return que.msg, que.env
+        
+    def group_reply(self, routing, msg):
+        return self.enqueue(msg=msg, env={
+                "type": "send",
+                "from": self._lname,
+                "to": routing["from"],
+                "group": routing["group"],
+                "instance": routing["instance"],
+                "reply": routing["seq"] })
+
+    def get_message(self, group, to='*'):
+        if not self._socket:
+            raise SessionError("Session has been closed.")
+        que = Queue()
+        for q in self.message_queue:
+            if q.env['group'] == group:
+                self.message_queue.remove(q)
+                self.old_message_queue.append(q)
+                que = q
+        if self.verbose:
+            sys.stdout.write("[Session] get_message: " + str(que.dump()) + "\n")
+        return q.msg
+

+ 2 - 0
src/bin/stats/tests/isc/config/Makefile.am

@@ -0,0 +1,2 @@
+EXTRA_DIST = __init__.py ccsession.py
+CLEANFILES = __init__.pyc ccsession.pyc

+ 1 - 0
src/bin/stats/tests/isc/config/__init__.py

@@ -0,0 +1 @@
+from isc.config.ccsession import *

+ 114 - 0
src/bin/stats/tests/isc/config/ccsession.py

@@ -0,0 +1,114 @@
+# Copyright (C) 2010  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.
+
+# $Id$
+# This module is a mock-up class of isc.cc.session
+
+__version__ = "$Revision$"
+
+import json
+from isc.cc.session import Session
+
+COMMAND_CONFIG_UPDATE = "config_update"
+
+def parse_answer(msg):
+    try:
+        return msg['result'][0], msg['result'][1]
+    except IndexError:
+        return msg['result'][0], None
+
+def create_answer(rcode, arg = None):
+    if arg is None:
+        return { 'result': [ rcode ] }
+    else:
+        return { 'result': [ rcode, arg ] }
+
+def parse_command(msg):
+    try:
+        return msg['command'][0], msg['command'][1]
+    except IndexError:
+        return msg['command'][0], None
+
+def create_command(command_name, params = None):
+    if params is None:
+        return {"command": [command_name]}
+    else:
+        return {"command": [command_name, params]}
+
+def module_spec_from_file(spec_file, check = True):
+    file = open(spec_file)
+    module_spec = json.loads(file.read())
+    return ModuleSpec(module_spec['module_spec'], check)
+
+class ModuleSpec:
+    def __init__(self, module_spec, check = True):
+        self._module_spec = module_spec
+
+    def get_config_spec(self):
+        return self._module_spec['config_data']
+
+    def get_commands_spec(self):
+        return self._module_spec['commands']
+
+    def get_module_name(self):
+        return self._module_spec['module_name']
+
+class ModuleCCSessionError(Exception):
+    pass
+
+class ConfigData:
+    def __init__(self, specification):
+        self.specification = specification
+
+class ModuleCCSession(ConfigData):
+    def __init__(self, spec_file_name, config_handler, command_handler, cc_session = None):
+        module_spec = module_spec_from_file(spec_file_name)
+        ConfigData.__init__(self, module_spec)
+        self._module_name = module_spec.get_module_name()
+        self.set_config_handler(config_handler)
+        self.set_command_handler(command_handler)
+        if not cc_session:
+            self._session = Session(verbose=True)
+        else:
+            self._session = cc_session
+
+    def start(self):
+        pass
+
+    def close(self):
+        self._session.close()
+
+    def check_command(self, nonblock=True):
+        msg, env = self._session.group_recvmsg(nonblock)
+        if not msg or 'result' in msg:
+            return
+        cmd, arg = parse_command(msg)
+        answer = None
+        if cmd == COMMAND_CONFIG_UPDATE and self._config_handler:
+            answer = self._config_handler(arg)
+        elif env['group'] == self._module_name and self._command_handler:
+            answer = self._command_handler(cmd, arg)
+        if answer:
+            self._session.group_reply(env, answer)
+
+    def set_config_handler(self, config_handler):
+        self._config_handler = config_handler
+        # should we run this right now since we've changed the handler?
+
+    def set_command_handler(self, command_handler):
+        self._command_handler = command_handler
+
+    def get_module_spec(self):
+        return self.specification

+ 2 - 0
src/bin/stats/tests/isc/util/Makefile.am

@@ -0,0 +1,2 @@
+EXTRA_DIST = __init__.py process.py
+CLEANFILES = __init__.pyc process.pyc

+ 0 - 0
src/bin/stats/tests/isc/util/__init__.py


+ 20 - 0
src/bin/stats/tests/isc/util/process.py

@@ -0,0 +1,20 @@
+# Copyright (C) 2010  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.
+
+# $Id$
+
+# A dummy function of isc.util.process.rename()
+def rename(name=None):
+    pass

+ 2 - 0
src/bin/stats/tests/isc/utils/Makefile.am

@@ -0,0 +1,2 @@
+EXTRA_DIST = __init__.py process.py
+CLEANFILES = __init__.pyc process.pyc

+ 0 - 0
src/bin/stats/tests/isc/utils/__init__.py


+ 20 - 0
src/bin/stats/tests/isc/utils/process.py

@@ -0,0 +1,20 @@
+# Copyright (C) 2010  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.
+
+# $Id$
+
+# A dummy function of isc.utils.process.rename()
+def rename(name=None):
+    pass

+ 31 - 0
src/bin/stats/tests/stats_test.in

@@ -0,0 +1,31 @@
+#! /bin/sh
+
+# Copyright (C) 2010  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.
+
+PYTHON_EXEC=${PYTHON_EXEC:-@PYTHON@}
+export PYTHON_EXEC
+
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/bin/stats:@abs_top_srcdir@/src/bin/stats/tests
+export PYTHONPATH
+
+B10_FROM_BUILD=@abs_top_builddir@
+export B10_FROM_BUILD
+
+TEST_PATH=@abs_top_srcdir@/src/bin/stats/tests
+
+cd ${TEST_PATH}
+${PYTHON_EXEC} -O b10-stats_test.py $*
+${PYTHON_EXEC} -O b10-stats_stub_test.py $*

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

@@ -0,0 +1 @@
+EXTRA_DIST = stats_test.spec

+ 19 - 0
src/bin/stats/tests/testdata/stats_test.spec

@@ -0,0 +1,19 @@
+{
+  "module_spec": {
+    "module_name": "Stats",
+    "module_description": "Stats daemon",
+    "config_data": [],
+    "commands": [
+      {
+        "command_name": "status",
+        "command_description": "identify whether stats module is alive or not",
+        "command_args": []
+      },
+      {
+        "command_name": "the_dummy",
+        "command_description": "this is for testing",
+        "command_args": []
+      }
+    ]
+  }
+}

+ 3 - 3
src/bin/tests/process_rename_test.py.in

@@ -17,7 +17,7 @@
 import unittest
 import unittest
 import os
 import os
 import os.path
 import os.path
-import isc.utils.process
+import isc.util.process
 import re
 import re
 
 
 class TestRename(unittest.TestCase):
 class TestRename(unittest.TestCase):
@@ -28,7 +28,7 @@ class TestRename(unittest.TestCase):
         data = ''.join(open(filename).readlines())
         data = ''.join(open(filename).readlines())
         prettyname = 'src' + filename[filename.rfind('../') + 2:]
         prettyname = 'src' + filename[filename.rfind('../') + 2:]
         self.assertTrue(fun.search(data),
         self.assertTrue(fun.search(data),
-            "Didn't find a call to isc.utils.process.rename in " + prettyname)
+            "Didn't find a call to isc.util.process.rename in " + prettyname)
 
 
     def test_calls(self):
     def test_calls(self):
         """
         """
@@ -45,7 +45,7 @@ class TestRename(unittest.TestCase):
         # Script name regular expression
         # Script name regular expression
         scripts = re.compile(r'((\w|[-.0-9])+)')
         scripts = re.compile(r'((\w|[-.0-9])+)')
         # Line with the call
         # Line with the call
-        fun = re.compile(r'^\s*isc\.utils\.process\.rename\s*\(.*\)\s*(|#.*)$',
+        fun = re.compile(r'^\s*isc\.util\.process\.rename\s*\(.*\)\s*(|#.*)$',
             re.MULTILINE)
             re.MULTILINE)
 
 
         # Find all Makefile and extract names of scripts
         # Find all Makefile and extract names of scripts

+ 2 - 2
src/bin/usermgr/b10-cmdctl-usermgr.py.in

@@ -25,9 +25,9 @@ import csv
 import getpass
 import getpass
 import getopt
 import getopt
 import sys
 import sys
-import isc.utils.process
+import isc.util.process
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 VERSION_NUMBER = 'bind10'
 VERSION_NUMBER = 'bind10'
 DEFAULT_FILE = 'cmdctl-accounts.csv'
 DEFAULT_FILE = 'cmdctl-accounts.csv'

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

@@ -135,9 +135,9 @@ class MockXfrinConnection(XfrinConnection):
         resp.set_opcode(Opcode.QUERY())
         resp.set_opcode(Opcode.QUERY())
         resp.set_rcode(rcode)
         resp.set_rcode(rcode)
         if response:
         if response:
-            resp.set_header_flag(MessageFlag.QR())
+            resp.set_header_flag(Message.HEADERFLAG_QR)
         [resp.add_question(q) for q in questions]
         [resp.add_question(q) for q in questions]
-        [resp.add_rrset(Section.ANSWER(), a) for a in answers]
+        [resp.add_rrset(Message.SECTION_ANSWER, a) for a in answers]
 
 
         renderer = MessageRenderer()
         renderer = MessageRenderer()
         resp.to_wire(renderer)
         resp.to_wire(renderer)
@@ -421,21 +421,21 @@ class TestXfrin(unittest.TestCase):
         name, rrclass = self._do_parse_zone_name_class()
         name, rrclass = self._do_parse_zone_name_class()
         master_addrinfo = self._do_parse_master_port()
         master_addrinfo = self._do_parse_master_port()
         db_file = self.args.get('db_file')
         db_file = self.args.get('db_file')
-        self.assertEqual(master_addrinfo[4][1], int(TEST_MASTER_PORT))
+        self.assertEqual(master_addrinfo[2][1], int(TEST_MASTER_PORT))
         self.assertEqual(name, TEST_ZONE_NAME)
         self.assertEqual(name, TEST_ZONE_NAME)
         self.assertEqual(rrclass, TEST_RRCLASS)
         self.assertEqual(rrclass, TEST_RRCLASS)
-        self.assertEqual(master_addrinfo[4][0], TEST_MASTER_IPV4_ADDRESS)
+        self.assertEqual(master_addrinfo[2][0], TEST_MASTER_IPV4_ADDRESS)
         self.assertEqual(db_file, TEST_DB_FILE)
         self.assertEqual(db_file, TEST_DB_FILE)
 
 
     def test_parse_cmd_params_default_port(self):
     def test_parse_cmd_params_default_port(self):
         del self.args['port']
         del self.args['port']
         master_addrinfo = self._do_parse_master_port()
         master_addrinfo = self._do_parse_master_port()
-        self.assertEqual(master_addrinfo[4][1], 53)
+        self.assertEqual(master_addrinfo[2][1], 53)
 
 
     def test_parse_cmd_params_ip6master(self):
     def test_parse_cmd_params_ip6master(self):
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
         master_addrinfo = self._do_parse_master_port()
         master_addrinfo = self._do_parse_master_port()
-        self.assertEqual(master_addrinfo[4][0], TEST_MASTER_IPV6_ADDRESS)
+        self.assertEqual(master_addrinfo[2][0], TEST_MASTER_IPV6_ADDRESS)
 
 
     def test_parse_cmd_params_chclass(self):
     def test_parse_cmd_params_chclass(self):
         self.args['zone_class'] = 'CH'
         self.args['zone_class'] = 'CH'
@@ -454,7 +454,7 @@ class TestXfrin(unittest.TestCase):
         # master address is mandatory.
         # master address is mandatory.
         del self.args['master']
         del self.args['master']
         master_addrinfo = self._do_parse_master_port()
         master_addrinfo = self._do_parse_master_port()
-        self.assertEqual(master_addrinfo[4][0], DEFAULT_MASTER)
+        self.assertEqual(master_addrinfo[2][0], DEFAULT_MASTER)
 
 
     def test_parse_cmd_params_bad_ip4(self):
     def test_parse_cmd_params_bad_ip4(self):
         self.args['master'] = '3.3.3.3.3'
         self.args['master'] = '3.3.3.3.3'

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

@@ -30,7 +30,8 @@ import random
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
 from isc.config.ccsession import *
 from isc.config.ccsession import *
 from isc.notify import notify_out
 from isc.notify import notify_out
-import isc.utils.process
+import isc.util.process
+import isc.net.parse
 try:
 try:
     from pydnspp import *
     from pydnspp import *
 except ImportError as e:
 except ImportError as e:
@@ -38,7 +39,7 @@ except ImportError as e:
     # must keep running, so we warn about it and move forward.
     # must keep running, so we warn about it and move forward.
     sys.stderr.write('[b10-xfrin] failed to import DNS module: %s\n' % str(e))
     sys.stderr.write('[b10-xfrin] failed to import DNS module: %s\n' % str(e))
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 # If B10_FROM_BUILD is set in the environment, we use data files
 # If B10_FROM_BUILD is set in the environment, we use data files
 # from a directory relative to that, otherwise we use the ones
 # from a directory relative to that, otherwise we use the ones
@@ -94,7 +95,7 @@ class XfrinConnection(asyncore.dispatcher):
         self.setblocking(1)
         self.setblocking(1)
         self._shutdown_event = shutdown_event
         self._shutdown_event = shutdown_event
         self._verbose = verbose
         self._verbose = verbose
-        self._master_address = master_addrinfo[4]
+        self._master_address = master_addrinfo[2]
 
 
     def connect_to_master(self):
     def connect_to_master(self):
         '''Connect to master in TCP.'''
         '''Connect to master in TCP.'''
@@ -239,7 +240,7 @@ class XfrinConnection(asyncore.dispatcher):
         if msg_rcode != Rcode.NOERROR():
         if msg_rcode != Rcode.NOERROR():
             raise XfrinException('error response: %s' % msg_rcode.to_text())
             raise XfrinException('error response: %s' % msg_rcode.to_text())
 
 
-        if not msg.get_header_flag(MessageFlag.QR()):
+        if not msg.get_header_flag(Message.HEADERFLAG_QR):
             raise XfrinException('response is not a response ')
             raise XfrinException('response is not a response ')
 
 
         if msg.get_qid() != self._query_id:
         if msg.get_qid() != self._query_id:
@@ -250,10 +251,10 @@ class XfrinConnection(asyncore.dispatcher):
 
 
         self._check_response_header(msg)
         self._check_response_header(msg)
 
 
-        if msg.get_rr_count(Section.ANSWER()) == 0:
+        if msg.get_rr_count(Message.SECTION_ANSWER) == 0:
             raise XfrinException('answer section is empty')
             raise XfrinException('answer section is empty')
 
 
-        if msg.get_rr_count(Section.QUESTION()) > 1:
+        if msg.get_rr_count(Message.SECTION_QUESTION) > 1:
             raise XfrinException('query section count greater than 1')
             raise XfrinException('query section count greater than 1')
 
 
     def _handle_answer_section(self, answer_section):
     def _handle_answer_section(self, answer_section):
@@ -293,7 +294,7 @@ class XfrinConnection(asyncore.dispatcher):
             msg.from_wire(recvdata)
             msg.from_wire(recvdata)
             self._check_response_status(msg)
             self._check_response_status(msg)
             
             
-            answer_section = msg.get_section(Section.ANSWER())
+            answer_section = msg.get_section(Message.SECTION_ANSWER)
             for rr in self._handle_answer_section(answer_section):
             for rr in self._handle_answer_section(answer_section):
                 yield rr
                 yield rr
 
 
@@ -406,15 +407,15 @@ class Xfrin:
     def config_handler(self, new_config):
     def config_handler(self, new_config):
         self._max_transfers_in = new_config.get("transfers_in") or self._max_transfers_in
         self._max_transfers_in = new_config.get("transfers_in") or self._max_transfers_in
         if ('master_addr' in new_config) or ('master_port' in new_config):
         if ('master_addr' in new_config) or ('master_port' in new_config):
-            # Check if the new master is valid, there should be library for check it.
+            # User should change the port and address together.
-            # and user should change the port and address together.
             try:
             try:
                 addr = new_config.get('master_addr') or self._master_addr
                 addr = new_config.get('master_addr') or self._master_addr
                 port = new_config.get('master_port') or self._master_port
                 port = new_config.get('master_port') or self._master_port
-                check_addr_port(addr, port)
+                isc.net.parse.addr_parse(addr)
+                isc.net.parse.port_parse(port)
                 self._master_addr = addr
                 self._master_addr = addr
                 self._master_port = port
                 self._master_port = port
-            except:
+            except ValueError:
                 errmsg = "bad format for zone's master: " + str(new_config)
                 errmsg = "bad format for zone's master: " + str(new_config)
                 log_error(errmsg)
                 log_error(errmsg)
                 return create_answer(1, errmsg)
                 return create_answer(1, errmsg)
@@ -443,7 +444,7 @@ class Xfrin:
                 # specify the notifyfrom address and port, according the RFC1996, zone
                 # specify the notifyfrom address and port, according the RFC1996, zone
                 # transfer should starts first from the notifyfrom, but now, let 'TODO' it.
                 # transfer should starts first from the notifyfrom, but now, let 'TODO' it.
                 (zone_name, rrclass) = self._parse_zone_name_and_class(args)
                 (zone_name, rrclass) = self._parse_zone_name_and_class(args)
-                (master_addr) = check_addr_port(self._master_addr, self._master_port)
+                (master_addr) = build_addr_info(self._master_addr, self._master_port)
                 ret = self.xfrin_start(zone_name, 
                 ret = self.xfrin_start(zone_name, 
                                        rrclass, 
                                        rrclass, 
                                        self._get_db_file(),
                                        self._get_db_file(),
@@ -491,7 +492,7 @@ class Xfrin:
     def _parse_master_and_port(self, args):
     def _parse_master_and_port(self, args):
         port = args.get('port') or self._master_port
         port = args.get('port') or self._master_port
         master = args.get('master') or self._master_addr
         master = args.get('master') or self._master_addr
-        return check_addr_port(master, port)
+        return build_addr_info(master, port)
  
  
     def _get_db_file(self):
     def _get_db_file(self):
         #TODO, the db file path should be got in auth server's configuration
         #TODO, the db file path should be got in auth server's configuration
@@ -518,11 +519,21 @@ class Xfrin:
         param = {'zone_name': zone_name, 'zone_class': zone_class.to_text()}
         param = {'zone_name': zone_name, 'zone_class': zone_class.to_text()}
         if xfr_result == XFRIN_OK:
         if xfr_result == XFRIN_OK:
             msg = create_command(notify_out.ZONE_NEW_DATA_READY_CMD, param)
             msg = create_command(notify_out.ZONE_NEW_DATA_READY_CMD, param)
-            self._send_cc_session.group_sendmsg(msg, XFROUT_MODULE_NAME)
+            # catch the exception, in case msgq has been killed.
-            self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
+            try:
+                self._send_cc_session.group_sendmsg(msg, XFROUT_MODULE_NAME)
+                self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
+            except socket.error as err: 
+                log_error("Fail to send message to %s and %s, msgq may has been killed" 
+                          % (XFROUT_MODULE_NAME, ZONE_MANAGER_MODULE_NAME))
         else:
         else:
             msg = create_command(ZONE_XFRIN_FAILED, param)
             msg = create_command(ZONE_XFRIN_FAILED, param)
-            self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
+            # catch the exception, in case msgq has been killed.
+            try:
+                self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
+            except socket.error as err:
+                log_error("Fail to send message to %s, msgq may has been killed" 
+                          % ZONE_MANAGER_MODULE_NAME)
 
 
     def startup(self):
     def startup(self):
         while not self._shutdown_event.is_set():
         while not self._shutdown_event.is_set():
@@ -564,31 +575,20 @@ def set_signal_handler():
     signal.signal(signal.SIGTERM, signal_handler)
     signal.signal(signal.SIGTERM, signal_handler)
     signal.signal(signal.SIGINT, signal_handler)
     signal.signal(signal.SIGINT, signal_handler)
 
 
-def check_addr_port(addrstr, portstr):
+def build_addr_info(addrstr, portstr):
-    # XXX: Linux (glibc)'s getaddrinfo incorrectly accepts numeric port
+    """
-    # string larger than 65535.  So we need to explicit validate it separately.
+    Return tuple (family, socktype, sockaddr) for given address and port.
+    IPv4 and IPv6 are the only supported addresses now, so sockaddr will be
+    (address, port). The socktype is socket.SOCK_STREAM for now.
+    """
     try:
     try:
-        portnum = int(portstr)
+        port = isc.net.parse.port_parse(portstr)
-        if portnum < 0 or portnum > 65535:
+        addr = isc.net.parse.addr_parse(addrstr)
-            raise ValueError("invalid port number (out of range): " + portstr)
+        return (addr.family, socket.SOCK_STREAM, (addrstr, port))
     except ValueError as err:
     except ValueError as err:
         raise XfrinException("failed to resolve master address/port=%s/%s: %s" %
         raise XfrinException("failed to resolve master address/port=%s/%s: %s" %
                              (addrstr, portstr, str(err)))
                              (addrstr, portstr, str(err)))
 
 
-    try:
-        addrinfo = socket.getaddrinfo(addrstr, portstr, socket.AF_UNSPEC,
-                                      socket.SOCK_STREAM, socket.IPPROTO_TCP,
-                                      socket.AI_NUMERICHOST|
-                                      socket.AI_NUMERICSERV)
-    except socket.gaierror as err:
-        raise XfrinException("failed to resolve master address/port=%s/%s: %s" %
-                             (addrstr, portstr, str(err)))
-    if len(addrinfo) != 1:
-        # with the parameters above the result must be uniquely determined.
-        errmsg = "unexpected result for address/port resolution for %s:%s"
-        raise XfrinException(errmsg % (addrstr, portstr))
-    return addrinfo[0]
-
 def set_cmd_options(parser):
 def set_cmd_options(parser):
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
             help="display more about what is going on")
             help="display more about what is going on")

+ 52 - 36
src/bin/xfrout/tests/xfrout_test.py

@@ -47,22 +47,29 @@ class MySocket():
         result = self.sendqueue[:size]
         result = self.sendqueue[:size]
         self.sendqueue = self.sendqueue[size:]
         self.sendqueue = self.sendqueue[size:]
         return result
         return result
-    
+
     def read_msg(self):
     def read_msg(self):
         sent_data = self.readsent()
         sent_data = self.readsent()
         get_msg = Message(Message.PARSE)
         get_msg = Message(Message.PARSE)
         get_msg.from_wire(bytes(sent_data[2:]))
         get_msg.from_wire(bytes(sent_data[2:]))
         return get_msg
         return get_msg
-    
+
     def clear_send(self):
     def clear_send(self):
         del self.sendqueue[:]
         del self.sendqueue[:]
 
 
 # We subclass the Session class we're testing here, only
 # We subclass the Session class we're testing here, only
-# to override the __init__() method, which wants a socket,
+# to override the handle() and _send_data() method
 class MyXfroutSession(XfroutSession):
 class MyXfroutSession(XfroutSession):
     def handle(self):
     def handle(self):
         pass
         pass
-    
+
+    def _send_data(self, sock, data):
+        size = len(data)
+        total_count = 0
+        while total_count < size:
+            count = sock.send(data[total_count:])
+            total_count += count
+
 class Dbserver:
 class Dbserver:
     def __init__(self):
     def __init__(self):
         self._shutdown_event = threading.Event()
         self._shutdown_event = threading.Event()
@@ -80,12 +87,21 @@ class TestXfroutSession(unittest.TestCase):
     def setUp(self):
     def setUp(self):
         request = MySocket(socket.AF_INET,socket.SOCK_STREAM)
         request = MySocket(socket.AF_INET,socket.SOCK_STREAM)
         self.log = isc.log.NSLogger('xfrout', '',  severity = 'critical', log_to_console = False )
         self.log = isc.log.NSLogger('xfrout', '',  severity = 'critical', log_to_console = False )
-        self.xfrsess = MyXfroutSession(request, None, None, self.log)
+        (self.write_sock, self.read_sock) = socket.socketpair()
+        self.xfrsess = MyXfroutSession(request, None, None, self.log, self.read_sock)
         self.xfrsess.server = Dbserver()
         self.xfrsess.server = Dbserver()
         self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
         self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
         self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
         self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
         self.soa_record = (4, 3, 'example.com.', 'com.example.', 3600, 'SOA', None, 'master.example.com. admin.example.com. 1234 3600 1800 2419200 7200')
         self.soa_record = (4, 3, 'example.com.', 'com.example.', 3600, 'SOA', None, 'master.example.com. admin.example.com. 1234 3600 1800 2419200 7200')
 
 
+    def test_receive_query_message(self):
+        send_msg = b"\xd6=\x00\x00\x00\x01\x00"
+        msg_len = struct.pack('H', socket.htons(len(send_msg)))
+        self.write_sock.send(msg_len)
+        self.write_sock.send(send_msg)
+        recv_msg = self.xfrsess._receive_query_message(self.read_sock)
+        self.assertEqual(recv_msg, send_msg)
+
     def test_parse_query_message(self):
     def test_parse_query_message(self):
         [get_rcode, get_msg] = self.xfrsess._parse_query_message(self.mdata)
         [get_rcode, get_msg] = self.xfrsess._parse_query_message(self.mdata)
         self.assertEqual(get_rcode.to_text(), "NOERROR")
         self.assertEqual(get_rcode.to_text(), "NOERROR")
@@ -93,7 +109,7 @@ class TestXfroutSession(unittest.TestCase):
     def test_get_query_zone_name(self):
     def test_get_query_zone_name(self):
         msg = self.getmsg()
         msg = self.getmsg()
         self.assertEqual(self.xfrsess._get_query_zone_name(msg), "example.com.")
         self.assertEqual(self.xfrsess._get_query_zone_name(msg), "example.com.")
-  
+
     def test_send_data(self):
     def test_send_data(self):
         self.xfrsess._send_data(self.sock, self.mdata)
         self.xfrsess._send_data(self.sock, self.mdata)
         senddata = self.sock.readsent()
         senddata = self.sock.readsent()
@@ -103,8 +119,8 @@ class TestXfroutSession(unittest.TestCase):
         msg = self.getmsg()
         msg = self.getmsg()
         self.xfrsess._reply_query_with_error_rcode(msg, self.sock, Rcode(3))
         self.xfrsess._reply_query_with_error_rcode(msg, self.sock, Rcode(3))
         get_msg = self.sock.read_msg()
         get_msg = self.sock.read_msg()
-        self.assertEqual(get_msg.get_rcode().to_text(), "NXDOMAIN") 
+        self.assertEqual(get_msg.get_rcode().to_text(), "NXDOMAIN")
-     
+
     def test_clear_message(self):
     def test_clear_message(self):
         msg = self.getmsg()
         msg = self.getmsg()
         qid = msg.get_qid()
         qid = msg.get_qid()
@@ -115,10 +131,10 @@ class TestXfroutSession(unittest.TestCase):
         self.assertEqual(msg.get_qid(), qid)
         self.assertEqual(msg.get_qid(), qid)
         self.assertEqual(msg.get_opcode(), opcode)
         self.assertEqual(msg.get_opcode(), opcode)
         self.assertEqual(msg.get_rcode(), rcode)
         self.assertEqual(msg.get_rcode(), rcode)
-        self.assertTrue(msg.get_header_flag(MessageFlag.AA()))
+        self.assertTrue(msg.get_header_flag(Message.HEADERFLAG_AA))
 
 
     def test_reply_query_with_format_error(self):
     def test_reply_query_with_format_error(self):
-         
+
         msg = self.getmsg()
         msg = self.getmsg()
         self.xfrsess._reply_query_with_format_error(msg, self.sock)
         self.xfrsess._reply_query_with_format_error(msg, self.sock)
         get_msg = self.sock.read_msg()
         get_msg = self.sock.read_msg()
@@ -140,12 +156,12 @@ class TestXfroutSession(unittest.TestCase):
         self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 0)
         self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 0)
         get_msg = self.sock.read_msg()
         get_msg = self.sock.read_msg()
 
 
-        self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
-        self.assertEqual(get_msg.get_rr_count(Section.ANSWER()), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
-        self.assertEqual(get_msg.get_rr_count(Section.AUTHORITY()), 0)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
 
 
         #answer_rrset_iter = section_iter(get_msg, section.ANSWER())
         #answer_rrset_iter = section_iter(get_msg, section.ANSWER())
-        answer = get_msg.get_section(Section.ANSWER())[0]#answer_rrset_iter.get_rrset()
+        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]#answer_rrset_iter.get_rrset()
         self.assertEqual(answer.get_name().to_text(), "example.com.")
         self.assertEqual(answer.get_name().to_text(), "example.com.")
         self.assertEqual(answer.get_class(), RRClass("IN"))
         self.assertEqual(answer.get_class(), RRClass("IN"))
         self.assertEqual(answer.get_type().to_text(), "SOA")
         self.assertEqual(answer.get_type().to_text(), "SOA")
@@ -160,7 +176,7 @@ class TestXfroutSession(unittest.TestCase):
         msg = self.getmsg()
         msg = self.getmsg()
         msg.make_response()
         msg.make_response()
 
 
-        msg.add_rrset(Section.ANSWER(), rrset_a)
+        msg.add_rrset(Message.SECTION_ANSWER, rrset_a)
         # give the function a value that is larger than MAX-len(rrset)
         # give the function a value that is larger than MAX-len(rrset)
         self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 65520)
         self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 65520)
 
 
@@ -168,11 +184,11 @@ class TestXfroutSession(unittest.TestCase):
         # (1 with the rrset we added manually, and 1 that triggered
         # (1 with the rrset we added manually, and 1 that triggered
         # the sending in _with_last_soa)
         # the sending in _with_last_soa)
         get_msg = self.sock.read_msg()
         get_msg = self.sock.read_msg()
-        self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 1)
-        self.assertEqual(get_msg.get_rr_count(Section.ANSWER()), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
-        self.assertEqual(get_msg.get_rr_count(Section.AUTHORITY()), 0)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
 
 
-        answer = get_msg.get_section(Section.ANSWER())[0]
+        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
         self.assertEqual(answer.get_name().to_text(), "example.com.")
         self.assertEqual(answer.get_name().to_text(), "example.com.")
         self.assertEqual(answer.get_class(), RRClass("IN"))
         self.assertEqual(answer.get_class(), RRClass("IN"))
         self.assertEqual(answer.get_type().to_text(), "A")
         self.assertEqual(answer.get_type().to_text(), "A")
@@ -180,12 +196,12 @@ class TestXfroutSession(unittest.TestCase):
         self.assertEqual(rdata[0].to_text(), "192.0.2.1")
         self.assertEqual(rdata[0].to_text(), "192.0.2.1")
 
 
         get_msg = self.sock.read_msg()
         get_msg = self.sock.read_msg()
-        self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 0)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_QUESTION), 0)
-        self.assertEqual(get_msg.get_rr_count(Section.ANSWER()), 1)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_ANSWER), 1)
-        self.assertEqual(get_msg.get_rr_count(Section.AUTHORITY()), 0)
+        self.assertEqual(get_msg.get_rr_count(Message.SECTION_AUTHORITY), 0)
 
 
-        #answer_rrset_iter = section_iter(get_msg, section.ANSWER())
+        #answer_rrset_iter = section_iter(get_msg, Message.SECTION_ANSWER)
-        answer = get_msg.get_section(Section.ANSWER())[0]
+        answer = get_msg.get_section(Message.SECTION_ANSWER)[0]
         self.assertEqual(answer.get_name().to_text(), "example.com.")
         self.assertEqual(answer.get_name().to_text(), "example.com.")
         self.assertEqual(answer.get_class(), RRClass("IN"))
         self.assertEqual(answer.get_class(), RRClass("IN"))
         self.assertEqual(answer.get_type().to_text(), "SOA")
         self.assertEqual(answer.get_type().to_text(), "SOA")
@@ -217,7 +233,7 @@ class TestXfroutSession(unittest.TestCase):
         sqlite3_ds.get_zone_soa = zone_soa
         sqlite3_ds.get_zone_soa = zone_soa
         self.assertEqual(self.xfrsess._zone_exist(True), True)
         self.assertEqual(self.xfrsess._zone_exist(True), True)
         self.assertEqual(self.xfrsess._zone_exist(False), False)
         self.assertEqual(self.xfrsess._zone_exist(False), False)
-    
+
     def test_check_xfrout_available(self):
     def test_check_xfrout_available(self):
         def zone_exist(zone):
         def zone_exist(zone):
             return zone
             return zone
@@ -243,7 +259,7 @@ class TestXfroutSession(unittest.TestCase):
         self.xfrsess.dns_xfrout_start(self.sock, b"\xd6=\x00\x00\x00\x01\x00")
         self.xfrsess.dns_xfrout_start(self.sock, b"\xd6=\x00\x00\x00\x01\x00")
         sent_data = self.sock.readsent()
         sent_data = self.sock.readsent()
         self.assertEqual(len(sent_data), 0)
         self.assertEqual(len(sent_data), 0)
-    
+
     def default(self, param):
     def default(self, param):
         return "example.com"
         return "example.com"
 
 
@@ -255,20 +271,20 @@ class TestXfroutSession(unittest.TestCase):
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
         get_msg = self.sock.read_msg()
         get_msg = self.sock.read_msg()
         self.assertEqual(get_msg.get_rcode().to_text(), "NOTAUTH")
         self.assertEqual(get_msg.get_rcode().to_text(), "NOTAUTH")
-    
+
     def test_dns_xfrout_start_noerror(self):
     def test_dns_xfrout_start_noerror(self):
         self.xfrsess._get_query_zone_name = self.default
         self.xfrsess._get_query_zone_name = self.default
         def noerror(form):
         def noerror(form):
-            return Rcode.NOERROR() 
+            return Rcode.NOERROR()
         self.xfrsess._check_xfrout_available = noerror
         self.xfrsess._check_xfrout_available = noerror
-        
+
         def myreply(msg, sock, zonename):
         def myreply(msg, sock, zonename):
             self.sock.send(b"success")
             self.sock.send(b"success")
-        
+
         self.xfrsess._reply_xfrout_query = myreply
         self.xfrsess._reply_xfrout_query = myreply
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
         self.assertEqual(self.sock.readsent(), b"success")
         self.assertEqual(self.sock.readsent(), b"success")
-    
+
     def test_reply_xfrout_query_noerror(self):
     def test_reply_xfrout_query_noerror(self):
         global sqlite3_ds
         global sqlite3_ds
         def get_zone_soa(zonename, file):
         def get_zone_soa(zonename, file):
@@ -281,7 +297,7 @@ class TestXfroutSession(unittest.TestCase):
         sqlite3_ds.get_zone_datas = get_zone_datas
         sqlite3_ds.get_zone_datas = get_zone_datas
         self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock, "example.com.")
         self.xfrsess._reply_xfrout_query(self.getmsg(), self.sock, "example.com.")
         reply_msg = self.sock.read_msg()
         reply_msg = self.sock.read_msg()
-        self.assertEqual(reply_msg.get_rr_count(Section.ANSWER()), 2)
+        self.assertEqual(reply_msg.get_rr_count(Message.SECTION_ANSWER), 2)
 
 
 class MyCCSession():
 class MyCCSession():
     def __init__(self):
     def __init__(self):
@@ -292,7 +308,7 @@ class MyCCSession():
             return "initdb.file", False
             return "initdb.file", False
         else:
         else:
             return "unknown", False
             return "unknown", False
-    
+
 
 
 class MyUnixSockServer(UnixSockServer):
 class MyUnixSockServer(UnixSockServer):
     def __init__(self):
     def __init__(self):
@@ -306,7 +322,7 @@ class MyUnixSockServer(UnixSockServer):
 class TestUnixSockServer(unittest.TestCase):
 class TestUnixSockServer(unittest.TestCase):
     def setUp(self):
     def setUp(self):
         self.unix = MyUnixSockServer()
         self.unix = MyUnixSockServer()
-     
+
     def test_updata_config_data(self):
     def test_updata_config_data(self):
         self.unix.update_config_data({'transfers_out':10 })
         self.unix.update_config_data({'transfers_out':10 })
         self.assertEqual(self.unix._max_transfers_out, 10)
         self.assertEqual(self.unix._max_transfers_out, 10)
@@ -324,7 +340,7 @@ class TestUnixSockServer(unittest.TestCase):
         count = self.unix._transfers_counter
         count = self.unix._transfers_counter
         self.assertEqual(self.unix.increase_transfers_counter(), False)
         self.assertEqual(self.unix.increase_transfers_counter(), False)
         self.assertEqual(count, self.unix._transfers_counter)
         self.assertEqual(count, self.unix._transfers_counter)
- 
+
     def test_decrease_transfers_counter(self):
     def test_decrease_transfers_counter(self):
         count = self.unix._transfers_counter
         count = self.unix._transfers_counter
         self.unix.decrease_transfers_counter()
         self.unix.decrease_transfers_counter()
@@ -335,7 +351,7 @@ class TestUnixSockServer(unittest.TestCase):
             os.remove(sock_file)
             os.remove(sock_file)
         except OSError:
         except OSError:
             pass
             pass
- 
+
     def test_sock_file_in_use_file_exist(self):
     def test_sock_file_in_use_file_exist(self):
         sock_file = 'temp.sock.file'
         sock_file = 'temp.sock.file'
         self._remove_file(sock_file)
         self._remove_file(sock_file)

+ 132 - 112
src/bin/xfrout/xfrout.py.in

@@ -30,11 +30,13 @@ from isc.config.ccsession import *
 from isc.log.log import *
 from isc.log.log import *
 from isc.cc import SessionError, SessionTimeout
 from isc.cc import SessionError, SessionTimeout
 from isc.notify import notify_out
 from isc.notify import notify_out
-import isc.utils.process
+import isc.util.process
 import socket
 import socket
 import select
 import select
 import errno
 import errno
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
+from isc.util import socketserver_mixin
+
 try:
 try:
     from libxfr_python import *
     from libxfr_python import *
     from pydnspp import *
     from pydnspp import *
@@ -43,7 +45,7 @@ except ImportError as e:
     # must keep running, so we warn about it and move forward.
     # must keep running, so we warn about it and move forward.
     sys.stderr.write('[b10-xfrout] failed to import DNS or XFR module: %s\n' % str(e))
     sys.stderr.write('[b10-xfrout] failed to import DNS or XFR module: %s\n' % str(e))
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 if "B10_FROM_BUILD" in os.environ:
 if "B10_FROM_BUILD" in os.environ:
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
@@ -61,6 +63,7 @@ AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + os.sep + "auth.spec"
 MAX_TRANSFERS_OUT = 10
 MAX_TRANSFERS_OUT = 10
 VERBOSE_MODE = False
 VERBOSE_MODE = False
 
 
+
 XFROUT_MAX_MESSAGE_SIZE = 65535
 XFROUT_MAX_MESSAGE_SIZE = 65535
 
 
 def get_rrset_len(rrset):
 def get_rrset_len(rrset):
@@ -71,46 +74,78 @@ def get_rrset_len(rrset):
 
 
 
 
 class XfroutSession(BaseRequestHandler):
 class XfroutSession(BaseRequestHandler):
-    def __init__(self, request, client_address, server, log):
+    def __init__(self, request, client_address, server, log, sock):
         # The initializer for the superclass may call functions
         # The initializer for the superclass may call functions
         # that need _log to be set, so we set it first
         # that need _log to be set, so we set it first
         self._log = log
         self._log = log
+        self._shutdown_sock = sock
         BaseRequestHandler.__init__(self, request, client_address, server)
         BaseRequestHandler.__init__(self, request, client_address, server)
 
 
     def handle(self):
     def handle(self):
-        fd = recv_fd(self.request.fileno())
+        '''Handle a request until shutdown or xfrout client is closed.'''
-        
+        # check self.server._shutdown_event to ensure the real shutdown comes.
-        if fd < 0:
+        # Linux could trigger a spurious readable event on the _shutdown_sock 
-            # This may happen when one xfrout process try to connect to
+        # due to a bug, so we need perform a double check. 
-            # xfrout unix socket server, to check whether there is another
+        while not self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
-            # xfrout running. 
+            try:
-            self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
+                (rlist, wlist, xlist) = select.select([self._shutdown_sock, self.request], [], [])
-            return
+            except select.error as e:
-
+                if e.args[0] == errno.EINTR:
-        data_len = self.request.recv(2)
+                    (rlist, wlist, xlist) = ([], [], [])
-        msg_len = struct.unpack('!H', data_len)[0]
+                    continue
-        msgdata = self.request.recv(msg_len)
+                else:
-        sock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
+                    self._log.log_message("error", "Error with select(): %s" %e)
-        try:
+                    break
-            self.dns_xfrout_start(sock, msgdata)
+            # self.server._shutdown_evnet will be set by now, if it is not a false
-            #TODO, avoid catching all exceptions
+            # alarm
-        except Exception as e:
+            if self._shutdown_sock in rlist:
-            self._log.log_message("error", str(e))
+                continue
 
 
-        try:
+            sock_fd = recv_fd(self.request.fileno())
-            sock.shutdown(socket.SHUT_RDWR)
+
-        except socket.error:
+            if sock_fd < 0:
-            # Avoid socket error caused by shutting down 
+                # This may happen when one xfrout process try to connect to
-            # one non-connected socket.
+                # xfrout unix socket server, to check whether there is another
-            pass
+                # xfrout running.
+                if sock_fd == XFR_FD_RECEIVE_FAIL:
+                    self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
+                break
 
 
-        sock.close()
+            # receive query msg
-        os.close(fd)
+            msgdata = self._receive_query_message(self.request)
-        pass
+            if not msgdata:
+                break
+
+            try:
+                self.dns_xfrout_start(sock_fd, msgdata)
+                #TODO, avoid catching all exceptions
+            except Exception as e:
+                self._log.log_message("error", str(e))
+
+            os.close(sock_fd)
+
+    def _receive_query_message(self, sock):
+        ''' receive query message from sock'''
+        # receive data length
+        data_len = sock.recv(2)
+        if not data_len:
+            return None
+        msg_len = struct.unpack('!H', data_len)[0]
+        # receive data
+        recv_size = 0
+        msgdata = b''
+        while recv_size < msg_len:
+            data = sock.recv(msg_len - recv_size)
+            if not data:
+                return None
+            recv_size += len(data)
+            msgdata += data
+
+        return msgdata
 
 
     def _parse_query_message(self, mdata):
     def _parse_query_message(self, mdata):
         ''' parse query message to [socket,message]'''
         ''' parse query message to [socket,message]'''
-        #TODO, need to add parseHeader() in case the message header is invalid 
+        #TODO, need to add parseHeader() in case the message header is invalid
         try:
         try:
             msg = Message(Message.PARSE)
             msg = Message(Message.PARSE)
             Message.from_wire(msg, mdata)
             Message.from_wire(msg, mdata)
@@ -125,37 +160,37 @@ class XfroutSession(BaseRequestHandler):
         return question.get_name().to_text()
         return question.get_name().to_text()
 
 
 
 
-    def _send_data(self, sock, data):
+    def _send_data(self, sock_fd, data):
         size = len(data)
         size = len(data)
         total_count = 0
         total_count = 0
         while total_count < size:
         while total_count < size:
-            count = sock.send(data[total_count:])
+            count = os.write(sock_fd, data[total_count:])
             total_count += count
             total_count += count
 
 
 
 
-    def _send_message(self, sock, msg):
+    def _send_message(self, sock_fd, msg):
         render = MessageRenderer()
         render = MessageRenderer()
         render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
         render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
         msg.to_wire(render)
         msg.to_wire(render)
         header_len = struct.pack('H', socket.htons(render.get_length()))
         header_len = struct.pack('H', socket.htons(render.get_length()))
-        self._send_data(sock, header_len)
+        self._send_data(sock_fd, header_len)
-        self._send_data(sock, render.get_data())
+        self._send_data(sock_fd, render.get_data())
 
 
 
 
-    def _reply_query_with_error_rcode(self, msg, sock, rcode_):
+    def _reply_query_with_error_rcode(self, msg, sock_fd, rcode_):
         msg.make_response()
         msg.make_response()
         msg.set_rcode(rcode_)
         msg.set_rcode(rcode_)
-        self._send_message(sock, msg)
+        self._send_message(sock_fd, msg)
 
 
 
 
-    def _reply_query_with_format_error(self, msg, sock):
+    def _reply_query_with_format_error(self, msg, sock_fd):
         '''query message format isn't legal.'''
         '''query message format isn't legal.'''
         if not msg:
         if not msg:
-            return # query message is invalid. send nothing back. 
+            return # query message is invalid. send nothing back.
 
 
         msg.make_response()
         msg.make_response()
         msg.set_rcode(Rcode.FORMERR())
         msg.set_rcode(Rcode.FORMERR())
-        self._send_message(sock, msg)
+        self._send_message(sock_fd, msg)
 
 
 
 
     def _zone_is_empty(self, zone):
     def _zone_is_empty(self, zone):
@@ -165,24 +200,24 @@ class XfroutSession(BaseRequestHandler):
         return True
         return True
 
 
     def _zone_exist(self, zonename):
     def _zone_exist(self, zonename):
-        # Find zone in datasource, should this works? maybe should ask 
+        # Find zone in datasource, should this works? maybe should ask
         # config manager.
         # config manager.
         soa = sqlite3_ds.get_zone_soa(zonename, self.server.get_db_file())
         soa = sqlite3_ds.get_zone_soa(zonename, self.server.get_db_file())
         if soa:
         if soa:
             return True
             return True
         return False
         return False
 
 
-    
+
     def _check_xfrout_available(self, zone_name):
     def _check_xfrout_available(self, zone_name):
         '''Check if xfr request can be responsed.
         '''Check if xfr request can be responsed.
            TODO, Get zone's configuration from cfgmgr or some other place
            TODO, Get zone's configuration from cfgmgr or some other place
-           eg. check allow_transfer setting, 
+           eg. check allow_transfer setting,
         '''
         '''
         if not self._zone_exist(zone_name):
         if not self._zone_exist(zone_name):
             return Rcode.NOTAUTH()
             return Rcode.NOTAUTH()
 
 
         if self._zone_is_empty(zone_name):
         if self._zone_is_empty(zone_name):
-            return Rcode.SERVFAIL() 
+            return Rcode.SERVFAIL()
 
 
         #TODO, check allow_transfer
         #TODO, check allow_transfer
         if not self.server.increase_transfers_counter():
         if not self.server.increase_transfers_counter():
@@ -191,45 +226,45 @@ class XfroutSession(BaseRequestHandler):
         return Rcode.NOERROR()
         return Rcode.NOERROR()
 
 
 
 
-    def dns_xfrout_start(self, sock, msg_query):
+    def dns_xfrout_start(self, sock_fd, msg_query):
         rcode_, msg = self._parse_query_message(msg_query)
         rcode_, msg = self._parse_query_message(msg_query)
         #TODO. create query message and parse header
         #TODO. create query message and parse header
         if rcode_ != Rcode.NOERROR():
         if rcode_ != Rcode.NOERROR():
-            return self._reply_query_with_format_error(msg, sock)
+            return self._reply_query_with_format_error(msg, sock_fd)
 
 
         zone_name = self._get_query_zone_name(msg)
         zone_name = self._get_query_zone_name(msg)
         rcode_ = self._check_xfrout_available(zone_name)
         rcode_ = self._check_xfrout_available(zone_name)
         if rcode_ != Rcode.NOERROR():
         if rcode_ != Rcode.NOERROR():
             self._log.log_message("info", "transfer of '%s/IN' failed: %s",
             self._log.log_message("info", "transfer of '%s/IN' failed: %s",
                                   zone_name, rcode_.to_text())
                                   zone_name, rcode_.to_text())
-            return self. _reply_query_with_error_rcode(msg, sock, rcode_)
+            return self. _reply_query_with_error_rcode(msg, sock_fd, rcode_)
 
 
         try:
         try:
             self._log.log_message("info", "transfer of '%s/IN': AXFR started" % zone_name)
             self._log.log_message("info", "transfer of '%s/IN': AXFR started" % zone_name)
-            self._reply_xfrout_query(msg, sock, zone_name)
+            self._reply_xfrout_query(msg, sock_fd, zone_name)
             self._log.log_message("info", "transfer of '%s/IN': AXFR end" % zone_name)
             self._log.log_message("info", "transfer of '%s/IN': AXFR end" % zone_name)
         except Exception as err:
         except Exception as err:
             self._log.log_message("error", str(err))
             self._log.log_message("error", str(err))
 
 
         self.server.decrease_transfers_counter()
         self.server.decrease_transfers_counter()
-        return    
+        return
 
 
 
 
     def _clear_message(self, msg):
     def _clear_message(self, msg):
         qid = msg.get_qid()
         qid = msg.get_qid()
         opcode = msg.get_opcode()
         opcode = msg.get_opcode()
         rcode = msg.get_rcode()
         rcode = msg.get_rcode()
-        
+
         msg.clear(Message.RENDER)
         msg.clear(Message.RENDER)
         msg.set_qid(qid)
         msg.set_qid(qid)
         msg.set_opcode(opcode)
         msg.set_opcode(opcode)
         msg.set_rcode(rcode)
         msg.set_rcode(rcode)
-        msg.set_header_flag(MessageFlag.AA())
+        msg.set_header_flag(Message.HEADERFLAG_AA)
-        msg.set_header_flag(MessageFlag.QR())
+        msg.set_header_flag(Message.HEADERFLAG_QR)
         return msg
         return msg
 
 
     def _create_rrset_from_db_record(self, record):
     def _create_rrset_from_db_record(self, record):
-        '''Create one rrset from one record of datasource, if the schema of record is changed, 
+        '''Create one rrset from one record of datasource, if the schema of record is changed,
         This function should be updated first.
         This function should be updated first.
         '''
         '''
         rrtype_ = RRType(record[5])
         rrtype_ = RRType(record[5])
@@ -237,36 +272,37 @@ class XfroutSession(BaseRequestHandler):
         rrset_ = RRset(Name(record[2]), RRClass("IN"), rrtype_, RRTTL( int(record[4])))
         rrset_ = RRset(Name(record[2]), RRClass("IN"), rrtype_, RRTTL( int(record[4])))
         rrset_.add_rdata(rdata_)
         rrset_.add_rdata(rdata_)
         return rrset_
         return rrset_
-         
+
-    def _send_message_with_last_soa(self, msg, sock, rrset_soa, message_upper_len):
+    def _send_message_with_last_soa(self, msg, sock_fd, rrset_soa, message_upper_len):
         '''Add the SOA record to the end of message. If it can't be
         '''Add the SOA record to the end of message. If it can't be
         added, a new message should be created to send out the last soa .
         added, a new message should be created to send out the last soa .
         '''
         '''
         rrset_len = get_rrset_len(rrset_soa)
         rrset_len = get_rrset_len(rrset_soa)
 
 
         if message_upper_len + rrset_len < XFROUT_MAX_MESSAGE_SIZE:
         if message_upper_len + rrset_len < XFROUT_MAX_MESSAGE_SIZE:
-            msg.add_rrset(Section.ANSWER(), rrset_soa)
+            msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
         else:
         else:
-            self._send_message(sock, msg)
+            self._send_message(sock_fd, msg)
             msg = self._clear_message(msg)
             msg = self._clear_message(msg)
-            msg.add_rrset(Section.ANSWER(), rrset_soa)
+            msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
 
 
-        self._send_message(sock, msg)
+        self._send_message(sock_fd, msg)
 
 
 
 
-    def _reply_xfrout_query(self, msg, sock, zone_name):
+    def _reply_xfrout_query(self, msg, sock_fd, zone_name):
         #TODO, there should be a better way to insert rrset.
         #TODO, there should be a better way to insert rrset.
         msg.make_response()
         msg.make_response()
-        msg.set_header_flag(MessageFlag.AA())
+        msg.set_header_flag(Message.HEADERFLAG_AA)
         soa_record = sqlite3_ds.get_zone_soa(zone_name, self.server.get_db_file())
         soa_record = sqlite3_ds.get_zone_soa(zone_name, self.server.get_db_file())
         rrset_soa = self._create_rrset_from_db_record(soa_record)
         rrset_soa = self._create_rrset_from_db_record(soa_record)
-        msg.add_rrset(Section.ANSWER(), rrset_soa)
+        msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
 
 
         message_upper_len = get_rrset_len(rrset_soa)
         message_upper_len = get_rrset_len(rrset_soa)
 
 
         for rr_data in sqlite3_ds.get_zone_datas(zone_name, self.server.get_db_file()):
         for rr_data in sqlite3_ds.get_zone_datas(zone_name, self.server.get_db_file()):
             if  self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
             if  self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
-                self._log.log_message("error", "shutdown!")
+                self._log.log_message("info", "xfrout process is being shutdown")
+                return
 
 
             # TODO: RRType.SOA() ?
             # TODO: RRType.SOA() ?
             if RRType(rr_data[5]) == RRType("SOA"): #ignore soa record
             if RRType(rr_data[5]) == RRType("SOA"): #ignore soa record
@@ -279,43 +315,45 @@ class XfroutSession(BaseRequestHandler):
             # may have reached the limit
             # may have reached the limit
             rrset_len = get_rrset_len(rrset_)
             rrset_len = get_rrset_len(rrset_)
             if message_upper_len + rrset_len < XFROUT_MAX_MESSAGE_SIZE:
             if message_upper_len + rrset_len < XFROUT_MAX_MESSAGE_SIZE:
-                msg.add_rrset(Section.ANSWER(), rrset_)
+                msg.add_rrset(Message.SECTION_ANSWER, rrset_)
                 message_upper_len += rrset_len
                 message_upper_len += rrset_len
                 continue
                 continue
 
 
-            self._send_message(sock, msg)
+            self._send_message(sock_fd, msg)
             msg = self._clear_message(msg)
             msg = self._clear_message(msg)
-            msg.add_rrset(Section.ANSWER(), rrset_) # Add the rrset to the new message
+            msg.add_rrset(Message.SECTION_ANSWER, rrset_) # Add the rrset to the new message
             message_upper_len = rrset_len
             message_upper_len = rrset_len
 
 
-        self._send_message_with_last_soa(msg, sock, rrset_soa, message_upper_len)
+        self._send_message_with_last_soa(msg, sock_fd, rrset_soa, message_upper_len)
 
 
-class UnixSockServer(ThreadingUnixStreamServer):
+class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer):
     '''The unix domain socket server which accept xfr query sent from auth server.'''
     '''The unix domain socket server which accept xfr query sent from auth server.'''
 
 
     def __init__(self, sock_file, handle_class, shutdown_event, config_data, cc, log):
     def __init__(self, sock_file, handle_class, shutdown_event, config_data, cc, log):
         self._remove_unused_sock_file(sock_file)
         self._remove_unused_sock_file(sock_file)
         self._sock_file = sock_file
         self._sock_file = sock_file
+        socketserver_mixin.NoPollMixIn.__init__(self)
         ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
         ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
         self._lock = threading.Lock()
         self._lock = threading.Lock()
         self._transfers_counter = 0
         self._transfers_counter = 0
         self._shutdown_event = shutdown_event
         self._shutdown_event = shutdown_event
+        self._write_sock, self._read_sock = socket.socketpair()
         self._log = log
         self._log = log
         self.update_config_data(config_data)
         self.update_config_data(config_data)
         self._cc = cc
         self._cc = cc
-        
+
     def finish_request(self, request, client_address):
     def finish_request(self, request, client_address):
         '''Finish one request by instantiating RequestHandlerClass.'''
         '''Finish one request by instantiating RequestHandlerClass.'''
-        self.RequestHandlerClass(request, client_address, self, self._log)
+        self.RequestHandlerClass(request, client_address, self, self._log, self._read_sock)
 
 
     def _remove_unused_sock_file(self, sock_file):
     def _remove_unused_sock_file(self, sock_file):
-        '''Try to remove the socket file. If the file is being used 
+        '''Try to remove the socket file. If the file is being used
-        by one running xfrout process, exit from python. 
+        by one running xfrout process, exit from python.
         If it's not a socket file or nobody is listening
         If it's not a socket file or nobody is listening
         , it will be removed. If it can't be removed, exit from python. '''
         , it will be removed. If it can't be removed, exit from python. '''
         if self._sock_file_in_use(sock_file):
         if self._sock_file_in_use(sock_file):
-            sys.stderr.write("[b10-xfrout] Fail to start xfrout process, unix socket" 
+            self._log.log_message("error", "Fail to start xfrout process, unix socket file '%s'"
-                  " file '%s' is being used by another xfrout process\n" % sock_file)
+                                 " is being used by another xfrout process\n" % sock_file)
             sys.exit(0)
             sys.exit(0)
         else:
         else:
             if not os.path.exists(sock_file):
             if not os.path.exists(sock_file):
@@ -324,12 +362,12 @@ class UnixSockServer(ThreadingUnixStreamServer):
             try:
             try:
                 os.unlink(sock_file)
                 os.unlink(sock_file)
             except OSError as err:
             except OSError as err:
-                sys.stderr.write('[b10-xfrout] Fail to remove file %s: %s\n' % (sock_file, err))
+                self._log.log_message("error", '[b10-xfrout] Fail to remove file %s: %s\n' % (sock_file, err))
                 sys.exit(0)
                 sys.exit(0)
-   
+
     def _sock_file_in_use(self, sock_file):
     def _sock_file_in_use(self, sock_file):
-        '''Check whether the socket file 'sock_file' exists and 
+        '''Check whether the socket file 'sock_file' exists and
-        is being used by one running xfrout process. If it is, 
+        is being used by one running xfrout process. If it is,
         return True, or else return False. '''
         return True, or else return False. '''
         try:
         try:
             sock = socket.socket(socket.AF_UNIX)
             sock = socket.socket(socket.AF_UNIX)
@@ -337,10 +375,11 @@ class UnixSockServer(ThreadingUnixStreamServer):
         except socket.error as err:
         except socket.error as err:
             return False
             return False
         else:
         else:
-            return True 
+            return True
 
 
     def shutdown(self):
     def shutdown(self):
-        ThreadingUnixStreamServer.shutdown(self)
+        self._write_sock.send(b"shutdown") #terminate the xfrout session thread
+        super().shutdown() # call the shutdown() of class socketserver_mixin.NoPollMixIn
         try:
         try:
             os.unlink(self._sock_file)
             os.unlink(self._sock_file)
         except Exception as e:
         except Exception as e:
@@ -382,30 +421,11 @@ class UnixSockServer(ThreadingUnixStreamServer):
         self._transfers_counter -= 1
         self._transfers_counter -= 1
         self._lock.release()
         self._lock.release()
 
 
-def listen_on_xfr_query(unix_socket_server):
-    '''Listen xfr query in one single thread. Polls for shutdown 
-    every 0.1 seconds, is there a better time?
-    '''
-
-    while True:
-        try:
-            unix_socket_server.serve_forever(poll_interval = 0.1)
-        except select.error as err:
-            # serve_forever() calls select.select(), which can be 
-            # interrupted.
-            # If it is interrupted, it raises select.error with the 
-            # errno set to EINTR. We ignore this case, and let the
-            # normal program flow continue by trying serve_forever()
-            # again.
-            if err.args[0] != errno.EINTR: raise
-
-   
-
 class XfroutServer:
 class XfroutServer:
     def __init__(self):
     def __init__(self):
         self._unix_socket_server = None
         self._unix_socket_server = None
         self._log = None
         self._log = None
-        self._listen_sock_file = UNIX_SOCKET_FILE 
+        self._listen_sock_file = UNIX_SOCKET_FILE
         self._shutdown_event = threading.Event()
         self._shutdown_event = threading.Event()
         self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
         self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
         self._config_data = self._cc.get_full_config()
         self._config_data = self._cc.get_full_config()
@@ -419,18 +439,16 @@ class XfroutServer:
 
 
     def _start_xfr_query_listener(self):
     def _start_xfr_query_listener(self):
         '''Start a new thread to accept xfr query. '''
         '''Start a new thread to accept xfr query. '''
-        self._unix_socket_server = UnixSockServer(self._listen_sock_file, XfroutSession, 
+        self._unix_socket_server = UnixSockServer(self._listen_sock_file, XfroutSession,
                                                   self._shutdown_event, self._config_data,
                                                   self._shutdown_event, self._config_data,
                                                   self._cc, self._log);
                                                   self._cc, self._log);
-        listener = threading.Thread(target = listen_on_xfr_query, args = (self._unix_socket_server,))
+        listener = threading.Thread(target=self._unix_socket_server.serve_forever)
         listener.start()
         listener.start()
-        
+
     def _start_notifier(self):
     def _start_notifier(self):
         datasrc = self._unix_socket_server.get_db_file()
         datasrc = self._unix_socket_server.get_db_file()
         self._notifier = notify_out.NotifyOut(datasrc, self._log)
         self._notifier = notify_out.NotifyOut(datasrc, self._log)
-        td = threading.Thread(target = notify_out.dispatcher, args = (self._notifier,))
+        self._notifier.dispatcher()
-        td.daemon = True
-        td.start()
 
 
     def send_notify(self, zone_name, zone_class):
     def send_notify(self, zone_name, zone_class):
         self._notifier.send_notify(zone_name, zone_class)
         self._notifier.send_notify(zone_name, zone_class)
@@ -443,7 +461,7 @@ class XfroutServer:
                 answer = create_answer(1, "Unknown config data: " + str(key))
                 answer = create_answer(1, "Unknown config data: " + str(key))
                 continue
                 continue
             self._config_data[key] = new_config[key]
             self._config_data[key] = new_config[key]
-        
+
         if self._log:
         if self._log:
             self._log.update_config(new_config)
             self._log.update_config(new_config)
 
 
@@ -461,9 +479,11 @@ class XfroutServer:
         global xfrout_server
         global xfrout_server
         xfrout_server = None #Avoid shutdown is called twice
         xfrout_server = None #Avoid shutdown is called twice
         self._shutdown_event.set()
         self._shutdown_event.set()
+        self._notifier.shutdown()
         if self._unix_socket_server:
         if self._unix_socket_server:
             self._unix_socket_server.shutdown()
             self._unix_socket_server.shutdown()
 
 
+        # Wait for all threads to terminate
         main_thread = threading.currentThread()
         main_thread = threading.currentThread()
         for th in threading.enumerate():
         for th in threading.enumerate():
             if th is main_thread:
             if th is main_thread:
@@ -475,7 +495,7 @@ class XfroutServer:
             self._log.log_message("info", "Received shutdown command.")
             self._log.log_message("info", "Received shutdown command.")
             self.shutdown()
             self.shutdown()
             answer = create_answer(0)
             answer = create_answer(0)
-        
+
         elif cmd == notify_out.ZONE_NEW_DATA_READY_CMD:
         elif cmd == notify_out.ZONE_NEW_DATA_READY_CMD:
             zone_name = args.get('zone_name')
             zone_name = args.get('zone_name')
             zone_class = args.get('zone_class')
             zone_class = args.get('zone_class')
@@ -487,10 +507,10 @@ class XfroutServer:
             else:
             else:
                 answer = create_answer(1, "Bad command parameter:" + str(args))
                 answer = create_answer(1, "Bad command parameter:" + str(args))
 
 
-        else: 
+        else:
             answer = create_answer(1, "Unknown command:" + str(cmd))
             answer = create_answer(1, "Unknown command:" + str(cmd))
 
 
-        return answer    
+        return answer
 
 
     def run(self):
     def run(self):
         '''Get and process all commands sent from cfgmgr or other modules. '''
         '''Get and process all commands sent from cfgmgr or other modules. '''
@@ -529,7 +549,7 @@ if '__main__' == __name__:
         sys.stderr.write("[b10-xfrout] Error creating xfrout, "
         sys.stderr.write("[b10-xfrout] Error creating xfrout, "
                            "is the command channel daemon running?\n")
                            "is the command channel daemon running?\n")
     except SessionTimeout as e:
     except SessionTimeout as e:
-        sys.stderr.write("[b10-xfrout] Error creating xfrout, " 
+        sys.stderr.write("[b10-xfrout] Error creating xfrout, "
                            "is the configuration manager running?\n")
                            "is the configuration manager running?\n")
     except ModuleCCSessionError as e:
     except ModuleCCSessionError as e:
         sys.stderr.write("[b10-xfrout] exit xfrout process:%s\n" % str(e))
         sys.stderr.write("[b10-xfrout] exit xfrout process:%s\n" % str(e))

+ 2 - 0
src/bin/zonemgr/tests/Makefile.am

@@ -1,6 +1,8 @@
 PYTESTS = zonemgr_test.py
 PYTESTS = zonemgr_test.py
 EXTRA_DIST = $(PYTESTS)
 EXTRA_DIST = $(PYTESTS)
 
 
+CLEANFILES = initdb.file
+
 # later will have configure option to choose this, like: coverage run --branch
 # later will have configure option to choose this, like: coverage run --branch
 PYCOVERAGE = $(PYTHON)
 PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
 # test using command-line arguments, so use check-local target instead of TESTS

+ 49 - 23
src/bin/zonemgr/tests/zonemgr_test.py

@@ -45,13 +45,22 @@ class MySession():
 
 
 class MyZonemgrRefresh(ZonemgrRefresh):
 class MyZonemgrRefresh(ZonemgrRefresh):
     def __init__(self):
     def __init__(self):
-        self._cc = MySession()
+        class FakeConfig:
-        self._db_file = "initdb.file"
+            def get(self, name):
+                if name == 'lowerbound_refresh':
+                    return LOWERBOUND_REFRESH
+                elif name == 'lowerbound_retry':
+                    return LOWERBOUND_RETRY
+                elif name == 'max_transfer_timeout':
+                    return MAX_TRANSFER_TIMEOUT
+                elif name == 'jitter_scope':
+                    return JITTER_SCOPE
+                else:
+                    raise ValueError('Uknown config option')
+        self._master_socket, self._slave_socket = socket.socketpair()
+        ZonemgrRefresh.__init__(self, MySession(), "initdb.file",
+            self._slave_socket, FakeConfig())
         current_time = time.time()
         current_time = time.time()
-        self._max_transfer_timeout = MAX_TRANSFER_TIMEOUT
-        self._lowerbound_refresh = LOWERBOUND_REFRESH
-        self._lowerbound_retry = LOWERBOUND_RETRY
-        self._jitter_scope = JITTER_SCOPE
         self._zonemgr_refresh_info = { 
         self._zonemgr_refresh_info = { 
          ('sd.cn.', 'IN'): {
          ('sd.cn.', 'IN'): {
          'last_refresh_time': current_time,
          'last_refresh_time': current_time,
@@ -67,8 +76,8 @@ class MyZonemgrRefresh(ZonemgrRefresh):
 
 
 class TestZonemgrRefresh(unittest.TestCase):
 class TestZonemgrRefresh(unittest.TestCase):
     def setUp(self):
     def setUp(self):
-        self.stdout_backup = sys.stdout
+        self.stderr_backup = sys.stderr
-        sys.stdout = open(os.devnull, 'w')
+        sys.stderr = open(os.devnull, 'w')
         self.zone_refresh = MyZonemgrRefresh()
         self.zone_refresh = MyZonemgrRefresh()
 
 
     def test_random_jitter(self):
     def test_random_jitter(self):
@@ -101,7 +110,7 @@ class TestZonemgrRefresh(unittest.TestCase):
         time2 = time.time()
         time2 = time.time()
         self.assertTrue((time1 + 7200 * 3 / 4) <= zone_timeout)
         self.assertTrue((time1 + 7200 * 3 / 4) <= zone_timeout)
         self.assertTrue(zone_timeout <= time2 + 7200)
         self.assertTrue(zone_timeout <= time2 + 7200)
-        
+
     def test_set_zone_retry_timer(self):
     def test_set_zone_retry_timer(self):
         time1 = time.time()
         time1 = time.time()
         self.zone_refresh._set_zone_retry_timer(ZONE_NAME_CLASS1_IN)
         self.zone_refresh._set_zone_retry_timer(ZONE_NAME_CLASS1_IN)
@@ -147,6 +156,8 @@ class TestZonemgrRefresh(unittest.TestCase):
          
          
     def test_zonemgr_reload_zone(self):
     def test_zonemgr_reload_zone(self):
         soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
         soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
+        # We need to restore this not to harm other tests
+        old_get_zone_soa = sqlite3_ds.get_zone_soa
         def get_zone_soa(zone_name, db_file):
         def get_zone_soa(zone_name, db_file):
             return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 
             return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 
                     'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
                     'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600')
@@ -154,6 +165,7 @@ class TestZonemgrRefresh(unittest.TestCase):
 
 
         self.zone_refresh.zonemgr_reload_zone(ZONE_NAME_CLASS1_IN)
         self.zone_refresh.zonemgr_reload_zone(ZONE_NAME_CLASS1_IN)
         self.assertEqual(soa_rdata, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"])
         self.assertEqual(soa_rdata, self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_soa_rdata"])
+        sqlite3_ds.get_zone_soa = old_get_zone_soa
 
 
     def test_get_zone_notifier_master(self):
     def test_get_zone_notifier_master(self):
         notify_master = "192.168.1.1"
         notify_master = "192.168.1.1"
@@ -231,6 +243,9 @@ class TestZonemgrRefresh(unittest.TestCase):
 
 
     def test_zonemgr_add_zone(self):
     def test_zonemgr_add_zone(self):
         soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
         soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
+        # This needs to be restored. The following test actually failed if we left
+        # this unclean
+        old_get_zone_soa = sqlite3_ds.get_zone_soa
 
 
         def get_zone_soa(zone_name, db_file):
         def get_zone_soa(zone_name, db_file):
             return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 
             return (1, 2, 'sd.cn.', 'cn.sd.', 21600, 'SOA', None, 
@@ -251,7 +266,8 @@ class TestZonemgrRefresh(unittest.TestCase):
             return None
             return None
         sqlite3_ds.get_zone_soa = get_zone_soa2
         sqlite3_ds.get_zone_soa = get_zone_soa2
         self.assertRaises(ZonemgrException, self.zone_refresh.zonemgr_add_zone, \
         self.assertRaises(ZonemgrException, self.zone_refresh.zonemgr_add_zone, \
-                                          ZONE_NAME_CLASS1_IN)
+                                         ZONE_NAME_CLASS1_IN)
+        sqlite3_ds.get_zone_soa = old_get_zone_soa
 
 
     def test_build_zonemgr_refresh_info(self):
     def test_build_zonemgr_refresh_info(self):
         soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
         soa_rdata = 'a.dns.cn. root.cnnic.cn. 2009073106 1800 900 2419200 21600'
@@ -382,7 +398,7 @@ class TestZonemgrRefresh(unittest.TestCase):
         """This case will run timer in daemon thread. 
         """This case will run timer in daemon thread. 
         The zone's next_refresh_time is less than now, so zonemgr will do zone refresh 
         The zone's next_refresh_time is less than now, so zonemgr will do zone refresh 
         immediately. The zone's state will become "refreshing". 
         immediately. The zone's state will become "refreshing". 
-        Then closing the socket ,the timer will stop, and throw a ZonemgrException."""
+        """
         time1 = time.time()
         time1 = time.time()
         self.zone_refresh._zonemgr_refresh_info = {
         self.zone_refresh._zonemgr_refresh_info = {
                 ("sd.cn.", "IN"):{
                 ("sd.cn.", "IN"):{
@@ -391,17 +407,11 @@ class TestZonemgrRefresh(unittest.TestCase):
                     'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 
                     'zone_soa_rdata': 'a.dns.cn. root.cnnic.cn. 2009073105 7200 3600 2419200 21600', 
                     'zone_state': ZONE_OK}
                     'zone_state': ZONE_OK}
                 }
                 }
-        master_socket, slave_socket = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+        self.zone_refresh._check_sock = self.zone_refresh._master_socket 
-        self.zone_refresh._socket = master_socket 
+        listener = self.zone_refresh.run_timer(daemon=True)
-        master_socket.close()
+        # Shut down the timer thread
-        self.assertRaises(ZonemgrException, self.zone_refresh.run_timer)
+        self.zone_refresh.shutdown()
-
+        # After running timer, the zone's state should become "refreshing".
-        self.zone_refresh._socket = slave_socket
-        listener = threading.Thread(target = self.zone_refresh.run_timer, args = ())
-        listener.setDaemon(True)
-        listener.start()
-        time.sleep(1)
-
         zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]
         zone_state = self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN]["zone_state"]
         self.assertTrue("refresh_timeout" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
         self.assertTrue("refresh_timeout" in self.zone_refresh._zonemgr_refresh_info[ZONE_NAME_CLASS1_IN].keys())
         self.assertTrue(zone_state == ZONE_REFRESHING)
         self.assertTrue(zone_state == ZONE_REFRESHING)
@@ -419,9 +429,16 @@ class TestZonemgrRefresh(unittest.TestCase):
         self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
         self.assertEqual(19800, self.zone_refresh._max_transfer_timeout)
         self.assertEqual(0.25, self.zone_refresh._jitter_scope)
         self.assertEqual(0.25, self.zone_refresh._jitter_scope)
 
 
+    def test_shutdown(self):
+        self.zone_refresh._check_sock = self.zone_refresh._master_socket 
+        listener = self.zone_refresh.run_timer()
+        self.assertTrue(listener.is_alive())
+        # Shut down the timer thread
+        self.zone_refresh.shutdown()
+        self.assertFalse(listener.is_alive())
 
 
     def tearDown(self):
     def tearDown(self):
-        sys.stdout = self.stdout_backup
+        sys.stderr= self.stderr_backup
 
 
 
 
 class MyCCSession():
 class MyCCSession():
@@ -489,6 +506,15 @@ class TestZonemgr(unittest.TestCase):
         params1 = {"zone_class" : "CH"}
         params1 = {"zone_class" : "CH"}
         self.assertRaises(ZonemgrException, self.zonemgr._parse_cmd_params, params2, ZONE_NOTIFY_COMMAND)
         self.assertRaises(ZonemgrException, self.zonemgr._parse_cmd_params, params2, ZONE_NOTIFY_COMMAND)
 
 
+    def test_config_data_check(self):
+        # jitter should not be bigger than half of the original value
+        config_data2 = {"jitter_scope" : 0.2}
+        config_data3 = {"jitter_scope" : 0.6}
+        self.zonemgr._config_data_check(config_data2)
+        self.assertEqual(0.2, config_data2.get("jitter_scope"))
+        self.zonemgr._config_data_check(config_data3)
+        self.assertEqual(0.5, config_data3.get("jitter_scope"))
+
     def tearDown(self):
     def tearDown(self):
         pass
         pass
 
 

+ 129 - 78
src/bin/zonemgr/zonemgr.py.in

@@ -16,7 +16,7 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 
-"""\
+"""
 This file implements the Secondary Manager program.
 This file implements the Secondary Manager program.
 
 
 The secondary manager is one of the co-operating processes
 The secondary manager is one of the co-operating processes
@@ -37,9 +37,9 @@ import errno
 from isc.datasrc import sqlite3_ds
 from isc.datasrc import sqlite3_ds
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
 from isc.config.ccsession import *
 from isc.config.ccsession import *
-import isc.utils.process
+import isc.util.process
 
 
-isc.utils.process.rename()
+isc.util.process.rename()
 
 
 # If B10_FROM_BUILD is set in the environment, we use data files
 # If B10_FROM_BUILD is set in the environment, we use data files
 # from a directory relative to that, otherwise we use the ones
 # from a directory relative to that, otherwise we use the ones
@@ -90,22 +90,26 @@ class ZonemgrException(Exception):
 
 
 class ZonemgrRefresh:
 class ZonemgrRefresh:
     """This class will maintain and manage zone refresh info.
     """This class will maintain and manage zone refresh info.
-    It also provides methods to keep track of zone timers and 
+    It also provides methods to keep track of zone timers and
     do zone refresh.
     do zone refresh.
+    Zone timers can be started by calling run_timer(), and it
+    can be stopped by calling shutdown() in another thread.
+
     """
     """
 
 
     def __init__(self, cc, db_file, slave_socket, config_data):
     def __init__(self, cc, db_file, slave_socket, config_data):
         self._cc = cc
         self._cc = cc
-        self._socket = slave_socket 
+        self._check_sock = slave_socket
         self._db_file = db_file
         self._db_file = db_file
         self.update_config_data(config_data)
         self.update_config_data(config_data)
-        self._zonemgr_refresh_info = {} 
+        self._zonemgr_refresh_info = {}
         self._build_zonemgr_refresh_info()
         self._build_zonemgr_refresh_info()
-    
+        self._running = False
+
     def _random_jitter(self, max, jitter):
     def _random_jitter(self, max, jitter):
         """Imposes some random jitters for refresh and
         """Imposes some random jitters for refresh and
         retry timers to avoid many zones need to do refresh
         retry timers to avoid many zones need to do refresh
-        at the same time. 
+        at the same time.
         The value should be between (max - jitter) and max.
         The value should be between (max - jitter) and max.
         """
         """
         if 0 == jitter:
         if 0 == jitter:
@@ -116,7 +120,7 @@ class ZonemgrRefresh:
         return time.time()
         return time.time()
 
 
     def _set_zone_timer(self, zone_name_class, max, jitter):
     def _set_zone_timer(self, zone_name_class, max, jitter):
-        """Set zone next refresh time. 
+        """Set zone next refresh time.
         jitter should not be bigger than half the original value."""
         jitter should not be bigger than half the original value."""
         self._set_zone_next_refresh_time(zone_name_class, self._get_current_time() + \
         self._set_zone_next_refresh_time(zone_name_class, self._get_current_time() + \
                                             self._random_jitter(max, jitter))
                                             self._random_jitter(max, jitter))
@@ -139,7 +143,7 @@ class ZonemgrRefresh:
 
 
     def _set_zone_notify_timer(self, zone_name_class):
     def _set_zone_notify_timer(self, zone_name_class):
         """Set zone next refresh time after receiving notify
         """Set zone next refresh time after receiving notify
-           next_refresh_time = now 
+           next_refresh_time = now
         """
         """
         self._set_zone_timer(zone_name_class, 0, 0)
         self._set_zone_timer(zone_name_class, 0, 0)
 
 
@@ -195,7 +199,7 @@ class ZonemgrRefresh:
             raise ZonemgrException("[b10-zonemgr] zone (%s, %s) doesn't have soa." % zone_name_class)
             raise ZonemgrException("[b10-zonemgr] zone (%s, %s) doesn't have soa." % zone_name_class)
         zone_info["zone_soa_rdata"] = zone_soa[7]
         zone_info["zone_soa_rdata"] = zone_soa[7]
         zone_info["zone_state"] = ZONE_OK
         zone_info["zone_state"] = ZONE_OK
-        zone_info["last_refresh_time"] = self._get_current_time() 
+        zone_info["last_refresh_time"] = self._get_current_time()
         zone_info["next_refresh_time"] = self._get_current_time() + \
         zone_info["next_refresh_time"] = self._get_current_time() + \
                                          float(zone_soa[7].split(" ")[REFRESH_OFFSET])
                                          float(zone_soa[7].split(" ")[REFRESH_OFFSET])
         self._zonemgr_refresh_info[zone_name_class] = zone_info
         self._zonemgr_refresh_info[zone_name_class] = zone_info
@@ -229,7 +233,7 @@ class ZonemgrRefresh:
 
 
     def _get_zone_notifier_master(self, zone_name_class):
     def _get_zone_notifier_master(self, zone_name_class):
         if ("notify_master" in self._zonemgr_refresh_info[zone_name_class].keys()):
         if ("notify_master" in self._zonemgr_refresh_info[zone_name_class].keys()):
-            return self._zonemgr_refresh_info[zone_name_class]["notify_master"] 
+            return self._zonemgr_refresh_info[zone_name_class]["notify_master"]
 
 
         return None
         return None
 
 
@@ -244,7 +248,7 @@ class ZonemgrRefresh:
         return self._zonemgr_refresh_info[zone_name_class]["zone_state"]
         return self._zonemgr_refresh_info[zone_name_class]["zone_state"]
 
 
     def _set_zone_state(self, zone_name_class, zone_state):
     def _set_zone_state(self, zone_name_class, zone_state):
-        self._zonemgr_refresh_info[zone_name_class]["zone_state"] = zone_state 
+        self._zonemgr_refresh_info[zone_name_class]["zone_state"] = zone_state
 
 
     def _get_zone_refresh_timeout(self, zone_name_class):
     def _get_zone_refresh_timeout(self, zone_name_class):
         return self._zonemgr_refresh_info[zone_name_class]["refresh_timeout"]
         return self._zonemgr_refresh_info[zone_name_class]["refresh_timeout"]
@@ -264,7 +268,7 @@ class ZonemgrRefresh:
         try:
         try:
             self._cc.group_sendmsg(msg, module_name)
             self._cc.group_sendmsg(msg, module_name)
         except socket.error:
         except socket.error:
-            sys.stderr.write("[b10-zonemgr] Failed to send to module %s, the session has been closed." % module_name) 
+            sys.stderr.write("[b10-zonemgr] Failed to send to module %s, the session has been closed." % module_name)
 
 
     def _find_need_do_refresh_zone(self):
     def _find_need_do_refresh_zone(self):
         """Find the first zone need do refresh, if no zone need
         """Find the first zone need do refresh, if no zone need
@@ -277,10 +281,10 @@ class ZonemgrRefresh:
             if (ZONE_REFRESHING == zone_state and
             if (ZONE_REFRESHING == zone_state and
                 (self._get_zone_refresh_timeout(zone_name_class) > self._get_current_time())):
                 (self._get_zone_refresh_timeout(zone_name_class) > self._get_current_time())):
                 continue
                 continue
-                    
+
-            # Get the zone with minimum next_refresh_time 
+            # Get the zone with minimum next_refresh_time
-            if ((zone_need_refresh is None) or 
+            if ((zone_need_refresh is None) or
-                (self._get_zone_next_refresh_time(zone_name_class) < 
+                (self._get_zone_next_refresh_time(zone_name_class) <
                  self._get_zone_next_refresh_time(zone_need_refresh))):
                  self._get_zone_next_refresh_time(zone_need_refresh))):
                 zone_need_refresh = zone_name_class
                 zone_need_refresh = zone_name_class
 
 
@@ -288,14 +292,14 @@ class ZonemgrRefresh:
             if (self._get_zone_next_refresh_time(zone_need_refresh) < self._get_current_time()):
             if (self._get_zone_next_refresh_time(zone_need_refresh) < self._get_current_time()):
                 break
                 break
 
 
-        return zone_need_refresh 
+        return zone_need_refresh
+
 
 
-    
     def _do_refresh(self, zone_name_class):
     def _do_refresh(self, zone_name_class):
         """Do zone refresh."""
         """Do zone refresh."""
         log_msg("Do refresh for zone (%s, %s)." % zone_name_class)
         log_msg("Do refresh for zone (%s, %s)." % zone_name_class)
         self._set_zone_state(zone_name_class, ZONE_REFRESHING)
         self._set_zone_state(zone_name_class, ZONE_REFRESHING)
-        self._set_zone_refresh_timeout(zone_name_class, self._get_current_time() + self._max_transfer_timeout) 
+        self._set_zone_refresh_timeout(zone_name_class, self._get_current_time() + self._max_transfer_timeout)
         notify_master = self._get_zone_notifier_master(zone_name_class)
         notify_master = self._get_zone_notifier_master(zone_name_class)
         # If the zone has notify master, send notify command to xfrin module
         # If the zone has notify master, send notify command to xfrin module
         if notify_master:
         if notify_master:
@@ -303,7 +307,7 @@ class ZonemgrRefresh:
                      "zone_class" : zone_name_class[1],
                      "zone_class" : zone_name_class[1],
                      "master" : notify_master
                      "master" : notify_master
                      }
                      }
-            self._send_command(XFRIN_MODULE_NAME, ZONE_NOTIFY_COMMAND, param) 
+            self._send_command(XFRIN_MODULE_NAME, ZONE_NOTIFY_COMMAND, param)
             self._clear_zone_notifier_master(zone_name_class)
             self._clear_zone_notifier_master(zone_name_class)
         # Send refresh command to xfrin module
         # Send refresh command to xfrin module
         else:
         else:
@@ -319,40 +323,93 @@ class ZonemgrRefresh:
 
 
         return False
         return False
 
 
-    def run_timer(self):
+    def _run_timer(self, start_event):
-        """Keep track of zone timers."""
+        while self._running:
-        while True:
+            # Notify run_timer that we already started and are inside the loop.
-            # Zonemgr has no zone.
+            # It is set only once, but when it was outside the loop, there was
+            # a race condition and _running could be set to false before we
+            # could enter it
+            if start_event:
+                start_event.set()
+                start_event = None
+            # If zonemgr has no zone, set timer timeout to self._lowerbound_retry.
             if self._zone_mgr_is_empty():
             if self._zone_mgr_is_empty():
-                time.sleep(self._lowerbound_retry) # A better time?
+                timeout = self._lowerbound_retry
-                continue
-
-            zone_need_refresh = self._find_need_do_refresh_zone()
-            # If don't get zone with minimum next refresh time, set timer timeout = lowerbound_retry 
-            if not zone_need_refresh:
-                timeout = self._lowerbound_retry 
             else:
             else:
-                timeout = self._get_zone_next_refresh_time(zone_need_refresh) - self._get_current_time()
+                zone_need_refresh = self._find_need_do_refresh_zone()
-                if (timeout < 0):
+                # If don't get zone with minimum next refresh time, set timer timeout to self._lowerbound_retry.
-                    self._do_refresh(zone_need_refresh)
+                if not zone_need_refresh:
-                    continue
+                    timeout = self._lowerbound_retry
+                else:
+                    timeout = self._get_zone_next_refresh_time(zone_need_refresh) - self._get_current_time()
+                    if (timeout < 0):
+                        self._do_refresh(zone_need_refresh)
+                        continue
 
 
-            """ Wait for the socket notification for a maximum time of timeout 
+            """ Wait for the socket notification for a maximum time of timeout
             in seconds (as float)."""
             in seconds (as float)."""
             try:
             try:
-                (rlist, wlist, xlist) = select.select([self._socket], [], [], timeout)
+                rlist, wlist, xlist = select.select([self._check_sock, self._read_sock], [], [], timeout)
-                if rlist:
-                    self._socket.recv(32)
-            except ValueError as e:
-                raise ZonemgrException("[b10-zonemgr] Socket has been closed\n")
-                break
             except select.error as e:
             except select.error as e:
                 if e.args[0] == errno.EINTR:
                 if e.args[0] == errno.EINTR:
                     (rlist, wlist, xlist) = ([], [], [])
                     (rlist, wlist, xlist) = ([], [], [])
                 else:
                 else:
-                    raise ZonemgrException("[b10-zonemgr] Error with select(): %s\n" % e)
+                    sys.stderr.write("[b10-zonemgr] Error with select(); %s\n" % e)
                     break
                     break
 
 
+            for fd in rlist:
+                if fd == self._read_sock: # awaken by shutdown socket
+                    # self._running will be False by now, if it is not a false
+                    # alarm (linux kernel is said to trigger spurious wakeup
+                    # on a filehandle that is not really readable).
+                    continue
+                if fd == self._check_sock: # awaken by check socket
+                    self._check_sock.recv(32)
+
+    def run_timer(self, daemon=False):
+        """
+        Keep track of zone timers. Spawns and starts a thread. The thread object is returned.
+
+        You can stop it by calling shutdown().
+        """
+        # Small sanity check
+        if self._running:
+            raise RuntimeError("Trying to run the timers twice at the same time")
+
+        # Prepare the launch
+        self._running = True
+        (self._read_sock, self._write_sock) = socket.socketpair()
+        start_event = threading.Event()
+
+        # Start the thread
+        self._thread = threading.Thread(target = self._run_timer,
+            args = (start_event,))
+        if daemon:
+            self._thread.setDaemon(True)
+        self._thread.start()
+        start_event.wait()
+
+        # Return the thread to anyone interested
+        return self._thread
+
+    def shutdown(self):
+        """
+        Stop the run_timer() thread. Block until it finished. This must be
+        called from a different thread.
+        """
+        if not self._running:
+            raise RuntimeError("Trying to shutdown, but not running")
+
+        # Ask the thread to stop
+        self._running = False
+        self._write_sock.send(b'shutdown') # make self._read_sock readble
+        # Wait for it to actually finnish
+        self._thread.join()
+        # Wipe out what we do not need
+        self._thread = None
+        self._read_sock = None
+        self._write_sock = None
+
     def update_config_data(self, new_config):
     def update_config_data(self, new_config):
         """ update ZonemgrRefresh config """
         """ update ZonemgrRefresh config """
         self._lowerbound_refresh = new_config.get('lowerbound_refresh')
         self._lowerbound_refresh = new_config.get('lowerbound_refresh')
@@ -360,29 +417,23 @@ class ZonemgrRefresh:
         self._max_transfer_timeout = new_config.get('max_transfer_timeout')
         self._max_transfer_timeout = new_config.get('max_transfer_timeout')
         self._jitter_scope = new_config.get('jitter_scope')
         self._jitter_scope = new_config.get('jitter_scope')
 
 
-
 class Zonemgr:
 class Zonemgr:
     """Zone manager class."""
     """Zone manager class."""
     def __init__(self):
     def __init__(self):
         self._zone_refresh = None
         self._zone_refresh = None
         self._setup_session()
         self._setup_session()
         self._db_file = self.get_db_file()
         self._db_file = self.get_db_file()
-        # Create socket pair for communicating between main thread and zonemgr timer thread 
+        # Create socket pair for communicating between main thread and zonemgr timer thread
         self._master_socket, self._slave_socket = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
         self._master_socket, self._slave_socket = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
         self._zone_refresh = ZonemgrRefresh(self._cc, self._db_file, self._slave_socket, self._config_data)
         self._zone_refresh = ZonemgrRefresh(self._cc, self._db_file, self._slave_socket, self._config_data)
-        self._start_zone_refresh_timer()
+        self._zone_refresh.run_timer()
 
 
         self._lock = threading.Lock()
         self._lock = threading.Lock()
         self._shutdown_event = threading.Event()
         self._shutdown_event = threading.Event()
-
+        self.running = False
-    def _start_zone_refresh_timer(self):
-        """Start a new thread to keep track of zone timers"""
-        listener = threading.Thread(target = self._zone_refresh.run_timer, args = ())
-        listener.setDaemon(True)
-        listener.start()
 
 
     def _setup_session(self):
     def _setup_session(self):
-        """Setup two sessions for zonemgr, one(self._module_cc) is used for receiving 
+        """Setup two sessions for zonemgr, one(self._module_cc) is used for receiving
         commands and config data sent from other modules, another one (self._cc)
         commands and config data sent from other modules, another one (self._cc)
         is used to send commands to proper modules."""
         is used to send commands to proper modules."""
         self._cc = isc.cc.Session()
         self._cc = isc.cc.Session()
@@ -391,10 +442,7 @@ class Zonemgr:
                                                   self.command_handler)
                                                   self.command_handler)
         self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION)
         self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION)
         self._config_data = self._module_cc.get_full_config()
         self._config_data = self._module_cc.get_full_config()
-        # jitter should not be bigger than half of the original value
+        self._config_data_check(self._config_data)
-        if self._config_data.get('jitter_scope') > 0.5:
-            self._config_data['jitter_scope'] = 0.5
-            log_msg("[b10-zonemgr] jitter_scope should not be bigger than 0.5.") 
         self._module_cc.start()
         self._module_cc.start()
 
 
     def get_db_file(self):
     def get_db_file(self):
@@ -409,16 +457,13 @@ class Zonemgr:
     def shutdown(self):
     def shutdown(self):
         """Shutdown the zonemgr process. the thread which is keeping track of zone
         """Shutdown the zonemgr process. the thread which is keeping track of zone
         timers should be terminated.
         timers should be terminated.
-        """ 
+        """
+        self._zone_refresh.shutdown()
+
         self._slave_socket.close()
         self._slave_socket.close()
         self._master_socket.close()
         self._master_socket.close()
-
         self._shutdown_event.set()
         self._shutdown_event.set()
-        main_thread = threading.currentThread()
+        self.running = False
-        for th in threading.enumerate():
-            if th is main_thread:
-                continue
-            th.join()
 
 
     def config_handler(self, new_config):
     def config_handler(self, new_config):
         """ Update config data. """
         """ Update config data. """
@@ -427,18 +472,23 @@ class Zonemgr:
             if key not in self._config_data:
             if key not in self._config_data:
                 answer = create_answer(1, "Unknown config data: " + str(key))
                 answer = create_answer(1, "Unknown config data: " + str(key))
                 continue
                 continue
-            # jitter should not be bigger than half of the original value
-            if key == 'jitter_scope':
-                if new_config.get(key) > 0.5:
-                    new_config[key] = 0.5
-                    log_msg("[b10-zonemgr] jitter_scope should not be bigger than 0.5.") 
             self._config_data[key] = new_config[key]
             self._config_data[key] = new_config[key]
 
 
+        self._config_data_check(self._config_data)
         if (self._zone_refresh):
         if (self._zone_refresh):
             self._zone_refresh.update_config_data(self._config_data)
             self._zone_refresh.update_config_data(self._config_data)
 
 
         return answer
         return answer
 
 
+    def _config_data_check(self, config_data):
+        """Check whether the new config data is valid or 
+        not. """ 
+        # jitter should not be bigger than half of the original value
+        if config_data.get('jitter_scope') > 0.5:
+            config_data['jitter_scope'] = 0.5
+            log_msg("[b10-zonemgr] jitter_scope is too big, its value will "
+                      "be set to 0.5") 
+
     def _parse_cmd_params(self, args, command):
     def _parse_cmd_params(self, args, command):
         zone_name = args.get("zone_name")
         zone_name = args.get("zone_name")
         if not zone_name:
         if not zone_name:
@@ -460,7 +510,7 @@ class Zonemgr:
 
 
     def command_handler(self, command, args):
     def command_handler(self, command, args):
         """Handle command receivd from command channel.
         """Handle command receivd from command channel.
-        ZONE_NOTIFY_COMMAND is issued by Auth process; ZONE_XFRIN_SUCCESS_COMMAND 
+        ZONE_NOTIFY_COMMAND is issued by Auth process; ZONE_XFRIN_SUCCESS_COMMAND
         and ZONE_XFRIN_FAILED_COMMAND are issued by Xfrin process; shutdown is issued
         and ZONE_XFRIN_FAILED_COMMAND are issued by Xfrin process; shutdown is issued
         by a user or Boss process. """
         by a user or Boss process. """
         answer = create_answer(0)
         answer = create_answer(0)
@@ -472,21 +522,21 @@ class Zonemgr:
             with self._lock:
             with self._lock:
                 self._zone_refresh.zone_handle_notify(zone_name_class, master)
                 self._zone_refresh.zone_handle_notify(zone_name_class, master)
             # Send notification to zonemgr timer thread
             # Send notification to zonemgr timer thread
-            self._master_socket.send(b" ")
+            self._master_socket.send(b" ")# make self._slave_socket readble
 
 
         elif command == ZONE_XFRIN_SUCCESS_COMMAND:
         elif command == ZONE_XFRIN_SUCCESS_COMMAND:
             """ Handle xfrin success command"""
             """ Handle xfrin success command"""
             zone_name_class = self._parse_cmd_params(args, command)
             zone_name_class = self._parse_cmd_params(args, command)
             with self._lock:
             with self._lock:
                 self._zone_refresh.zone_refresh_success(zone_name_class)
                 self._zone_refresh.zone_refresh_success(zone_name_class)
-            self._master_socket.send(b" ")
+            self._master_socket.send(b" ")# make self._slave_socket readble
 
 
         elif command == ZONE_XFRIN_FAILED_COMMAND:
         elif command == ZONE_XFRIN_FAILED_COMMAND:
             """ Handle xfrin fail command"""
             """ Handle xfrin fail command"""
             zone_name_class = self._parse_cmd_params(args, command)
             zone_name_class = self._parse_cmd_params(args, command)
             with self._lock:
             with self._lock:
                 self._zone_refresh.zone_refresh_fail(zone_name_class)
                 self._zone_refresh.zone_refresh_fail(zone_name_class)
-            self._master_socket.send(b" ")
+            self._master_socket.send(b" ")# make self._slave_socket readble
 
 
         elif command == "shutdown":
         elif command == "shutdown":
             self.shutdown()
             self.shutdown()
@@ -497,6 +547,7 @@ class Zonemgr:
         return answer
         return answer
 
 
     def run(self):
     def run(self):
+        self.running = True
         while not self._shutdown_event.is_set():
         while not self._shutdown_event.is_set():
             self._module_cc.check_command(False)
             self._module_cc.check_command(False)
 
 
@@ -528,14 +579,14 @@ if '__main__' == __name__:
     except KeyboardInterrupt:
     except KeyboardInterrupt:
         sys.stderr.write("[b10-zonemgr] exit zonemgr process\n")
         sys.stderr.write("[b10-zonemgr] exit zonemgr process\n")
     except isc.cc.session.SessionError as e:
     except isc.cc.session.SessionError as e:
-        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
+        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, "
                            "is the command channel daemon running?\n")
                            "is the command channel daemon running?\n")
     except isc.cc.session.SessionTimeout as e:
     except isc.cc.session.SessionTimeout as e:
-        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
+        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, "
                            "is the configuration manager running?\n")
                            "is the configuration manager running?\n")
     except isc.config.ModuleCCSessionError as e:
     except isc.config.ModuleCCSessionError as e:
         sys.stderr.write("[b10-zonemgr] exit zonemgr process: %s\n" % str(e))
         sys.stderr.write("[b10-zonemgr] exit zonemgr process: %s\n" % str(e))
 
 
-    if zonemgrd:
+    if zonemgrd and zonemgrd.running:
         zonemgrd.shutdown()
         zonemgrd.shutdown()
 
 

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

@@ -1,6 +1,7 @@
 SUBDIRS = . tests example
 SUBDIRS = . tests example
 
 
 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 += $(BOOST_INCLUDES)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda

+ 2 - 2
src/lib/bench/benchmark.h

@@ -200,7 +200,7 @@ private:
     BenchMark(const BenchMark& source);
     BenchMark(const BenchMark& source);
     BenchMark& operator=(const BenchMark& source);
     BenchMark& operator=(const BenchMark& source);
 public:
 public:
-    /// \bench Constructor for immediate run.
+    /// \brief Constructor for immediate run.
     ///
     ///
     /// This is the constructor that is expected to be used normally.
     /// This is the constructor that is expected to be used normally.
     /// It runs the benchmark within the constructor and prints the result,
     /// It runs the benchmark within the constructor and prints the result,
@@ -217,7 +217,7 @@ public:
         initialize(true);
         initialize(true);
     }
     }
 
 
-    /// \bench Constructor for finer-grained control.
+    /// \brief Constructor for finer-grained control.
     ///
     ///
     /// This constructor takes the third parameter, \c immediate, to control
     /// This constructor takes the third parameter, \c immediate, to control
     /// whether to run the benchmark within the constructor.
     /// whether to run the benchmark within the constructor.

+ 6 - 3
src/lib/bench/example/search_bench.cc

@@ -16,6 +16,7 @@
 
 
 #include <unistd.h>             // for getpid
 #include <unistd.h>             // for getpid
 
 
+#include <cassert>
 #include <cstdlib>              // for rand
 #include <cstdlib>              // for rand
 #include <algorithm>
 #include <algorithm>
 #include <iostream>
 #include <iostream>
@@ -42,9 +43,11 @@ public:
         vector<int>::const_iterator end_key = keys_.end();
         vector<int>::const_iterator end_key = keys_.end();
         for (iter = keys_.begin(); iter != end_key; ++iter) {
         for (iter = keys_.begin(); iter != end_key; ++iter) {
             if (Sorted) {
             if (Sorted) {
-                binary_search(data_.begin(), data_.end(), *iter);
+                // perform simple sanity check with assert() to ensure
+                // compiler optimization won't skip the search.
+                assert(binary_search(data_.begin(), data_.end(), *iter));
             } else {
             } else {
-                find(data_.begin(), data_.end(), *iter);
+                assert(find(data_.begin(), data_.end(), *iter) != data_.end());
             }
             }
         }
         }
         return (keys_.size());
         return (keys_.size());
@@ -63,7 +66,7 @@ public:
         vector<int>::const_iterator iter;
         vector<int>::const_iterator iter;
         vector<int>::const_iterator end_key = keys_.end();
         vector<int>::const_iterator end_key = keys_.end();
         for (iter = keys_.begin(); iter != end_key; ++iter) {
         for (iter = keys_.begin(); iter != end_key; ++iter) {
-            data_.find(*iter);
+            assert(data_.find(*iter) != data_.end());
         }        
         }        
         return (keys_.size());
         return (keys_.size());
     }
     }

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

@@ -1,4 +1,5 @@
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 

+ 6 - 6
src/lib/bench/tests/loadquery_unittest.cc

@@ -82,12 +82,12 @@ public:
         EXPECT_EQ(0, message.getQid());
         EXPECT_EQ(0, message.getQid());
         EXPECT_EQ(Opcode::QUERY(), message.getOpcode());
         EXPECT_EQ(Opcode::QUERY(), message.getOpcode());
         EXPECT_EQ(Rcode::NOERROR(), message.getRcode());
         EXPECT_EQ(Rcode::NOERROR(), message.getRcode());
-        EXPECT_FALSE(message.getHeaderFlag(MessageFlag::QR()));
+        EXPECT_FALSE(message.getHeaderFlag(Message::HEADERFLAG_QR));
-        EXPECT_FALSE(message.getHeaderFlag(MessageFlag::AA()));
+        EXPECT_FALSE(message.getHeaderFlag(Message::HEADERFLAG_AA));
-        EXPECT_EQ(1, message.getRRCount(Section::QUESTION()));
+        EXPECT_EQ(1, message.getRRCount(Message::SECTION_QUESTION));
-        EXPECT_EQ(0, message.getRRCount(Section::ANSWER()));
+        EXPECT_EQ(0, message.getRRCount(Message::SECTION_ANSWER));
-        EXPECT_EQ(0, message.getRRCount(Section::AUTHORITY()));
+        EXPECT_EQ(0, message.getRRCount(Message::SECTION_AUTHORITY));
-        EXPECT_EQ(0, message.getRRCount(Section::ADDITIONAL()));
+        EXPECT_EQ(0, message.getRRCount(Message::SECTION_ADDITIONAL));
 
 
         // Check if the question matches our original data, if the expected
         // Check if the question matches our original data, if the expected
         // data is given.
         // data is given.

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

@@ -1,16 +1,23 @@
 SUBDIRS = . tests
 SUBDIRS = . tests
 
 
 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 += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
-# ASIO header files used in session.cc will trigger "unused-parameter"
+if USE_GXX
-# error.  Unfortunately there doesn't seem to be an easy way to selectively
+# ASIO header files used in session.cc will trigger the "unused-parameter"
+# warning.  Unfortunately there doesn't seem to be an easy way to selectively
 # avoid the error.  As a short term workaround we suppress this warning
 # avoid the error.  As a short term workaround we suppress this warning
 # for the entire this module.  See also src/bin/auth/Makefile.am.
 # for the entire this module.  See also src/bin/auth/Makefile.am.
-if USE_GXX
 AM_CXXFLAGS += -Wno-unused-parameter
 AM_CXXFLAGS += -Wno-unused-parameter
 endif
 endif
+if USE_CLANGPP
+# Likewise, ASIO header files will trigger various warnings with clang++.
+# Worse, there doesn't seem to be any option to disable one of the warnings
+# in any way, so we need to turn off -Werror.
+AM_CXXFLAGS += -Wno-error
+endif
 
 
 lib_LTLIBRARIES = libcc.la
 lib_LTLIBRARIES = libcc.la
 libcc_la_SOURCES = data.cc data.h session.cc session.h
 libcc_la_SOURCES = data.cc data.h session.cc session.h

+ 35 - 37
src/lib/cc/data.cc

@@ -62,84 +62,82 @@ Element::toWire(std::ostream& ss) const {
 // installed files we define the methods here.
 // installed files we define the methods here.
 //
 //
 bool
 bool
-Element::getValue(long int& t UNUSED_PARAM) {
+Element::getValue(long int&) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::getValue(double& t UNUSED_PARAM) {
+Element::getValue(double&) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::getValue(bool& t UNUSED_PARAM) {
+Element::getValue(bool&) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::getValue(std::string& t UNUSED_PARAM) {
+Element::getValue(std::string&) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::getValue(std::vector<ConstElementPtr>& t UNUSED_PARAM) {
+Element::getValue(std::vector<ConstElementPtr>&) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::getValue(std::map<std::string, ConstElementPtr>& t UNUSED_PARAM) {
+Element::getValue(std::map<std::string, ConstElementPtr>&) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::setValue(const long int v UNUSED_PARAM) {
+Element::setValue(const long int) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::setValue(const double v UNUSED_PARAM) {
+Element::setValue(const double) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::setValue(const bool t UNUSED_PARAM) {
+Element::setValue(const bool) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::setValue(const std::string& v UNUSED_PARAM) {
+Element::setValue(const std::string&) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::setValue(const std::vector<ConstElementPtr>& v UNUSED_PARAM) {
+Element::setValue(const std::vector<ConstElementPtr>&) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::setValue(const std::map<std::string,
+Element::setValue(const std::map<std::string, ConstElementPtr>&) {
-                  ConstElementPtr>& v UNUSED_PARAM)
-{
     return (false);
     return (false);
 }
 }
 
 
 ConstElementPtr
 ConstElementPtr
-Element::get(const int i UNUSED_PARAM) const {
+Element::get(const int) const {
     isc_throw(TypeError, "get(int) called on a non-list Element");
     isc_throw(TypeError, "get(int) called on a non-list Element");
 }
 }
 
 
 void
 void
-Element::set(const size_t i UNUSED_PARAM, ConstElementPtr element UNUSED_PARAM) {
+Element::set(const size_t, ConstElementPtr) {
     isc_throw(TypeError, "set(int, element) called on a non-list Element");
     isc_throw(TypeError, "set(int, element) called on a non-list Element");
 }
 }
 
 
 void
 void
-Element::add(ConstElementPtr element UNUSED_PARAM) {
+Element::add(ConstElementPtr) {
     isc_throw(TypeError, "add() called on a non-list Element");
     isc_throw(TypeError, "add() called on a non-list Element");
 }
 }
 
 
 void
 void
-Element::remove(const int i UNUSED_PARAM) {
+Element::remove(const int) {
     isc_throw(TypeError, "remove(int) called on a non-list Element");
     isc_throw(TypeError, "remove(int) called on a non-list Element");
 }
 }
 
 
@@ -149,42 +147,39 @@ Element::size() const {
 }
 }
 
 
 ConstElementPtr
 ConstElementPtr
-Element::get(const std::string& name UNUSED_PARAM) const {
+Element::get(const std::string&) const {
     isc_throw(TypeError, "get(string) called on a non-map Element");
     isc_throw(TypeError, "get(string) called on a non-map Element");
 }
 }
 
 
 void
 void
-Element::set(const std::string& name UNUSED_PARAM,
+Element::set(const std::string&, ConstElementPtr) {
-             ConstElementPtr element UNUSED_PARAM)
-{
     isc_throw(TypeError, "set(name, element) called on a non-map Element");
     isc_throw(TypeError, "set(name, element) called on a non-map Element");
 }
 }
 
 
 void
 void
-Element::remove(const std::string& name UNUSED_PARAM) {
+Element::remove(const std::string&) {
     isc_throw(TypeError, "remove(string) called on a non-map Element");
     isc_throw(TypeError, "remove(string) called on a non-map Element");
 }
 }
 
 
 bool
 bool
-Element::contains(const std::string& name UNUSED_PARAM) const {
+Element::contains(const std::string&) const {
     isc_throw(TypeError, "contains(string) called on a non-map Element");
     isc_throw(TypeError, "contains(string) called on a non-map Element");
 }
 }
 
 
 ConstElementPtr
 ConstElementPtr
-Element::find(const std::string& identifier UNUSED_PARAM) const {
+Element::find(const std::string&) const {
     isc_throw(TypeError, "find(string) called on a non-map Element");
     isc_throw(TypeError, "find(string) called on a non-map Element");
 }
 }
 
 
 bool
 bool
-Element::find(const std::string& identifier UNUSED_PARAM,
+Element::find(const std::string&, ConstElementPtr) const {
-              ConstElementPtr t UNUSED_PARAM) const
-{
     return (false);
     return (false);
 }
 }
 
 
 namespace {
 namespace {
 inline void
 inline void
-throwJSONError(const std::string& error, const std::string& file, int line, int pos)
+throwJSONError(const std::string& error, const std::string& file, int line,
+               int pos)
 {
 {
     std::stringstream ss;
     std::stringstream ss;
     ss << error << " in " + file + ":" << line << ":" << pos;
     ss << error << " in " + file + ":" << line << ":" << pos;
@@ -427,13 +422,15 @@ from_stringstream_null(std::istream &in, const std::string& file,
 }
 }
 
 
 ElementPtr
 ElementPtr
-from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos)
+from_stringstream_string(std::istream& in, const std::string& file, int& line,
+                         int& pos)
 {
 {
     return (Element::create(str_from_stringstream(in, file, line, pos)));
     return (Element::create(str_from_stringstream(in, file, line, pos)));
 }
 }
 
 
 ElementPtr
 ElementPtr
-from_stringstream_list(std::istream &in, const std::string& file, int& line, int& pos)
+from_stringstream_list(std::istream &in, const std::string& file, int& line,
+                       int& pos)
 {
 {
     char c = 0;
     char c = 0;
     ElementPtr list = Element::createList();
     ElementPtr list = Element::createList();
@@ -484,8 +481,7 @@ from_stringstream_map(std::istream &in, const std::string& file, int& line,
 }
 }
 
 
 std::string
 std::string
-Element::typeToName(Element::types type)
+Element::typeToName(Element::types type) {
-{
     switch (type) {
     switch (type) {
     case Element::integer:
     case Element::integer:
         return (std::string("integer"));
         return (std::string("integer"));
@@ -538,14 +534,16 @@ Element::fromJSON(std::istream& in) throw(JSONError) {
 }
 }
 
 
 ElementPtr
 ElementPtr
-Element::fromJSON(std::istream& in, const std::string& file_name) throw(JSONError)
+Element::fromJSON(std::istream& in, const std::string& file_name)
+    throw(JSONError)
 {
 {
     int line = 1, pos = 1;
     int line = 1, pos = 1;
     return (fromJSON(in, file_name, line, pos));
     return (fromJSON(in, file_name, line, pos));
 }
 }
 
 
 ElementPtr
 ElementPtr
-Element::fromJSON(std::istream &in, const std::string& file, int& line, int& pos) throw(JSONError)
+Element::fromJSON(std::istream &in, const std::string& file, int& line,
+                  int& pos) throw(JSONError)
 {
 {
     char c = 0;
     char c = 0;
     ElementPtr element;
     ElementPtr element;
@@ -721,7 +719,7 @@ Element::fromWire(const std::string& s) {
 }
 }
 
 
 ElementPtr
 ElementPtr
-Element::fromWire(std::stringstream& in, int length) {
+Element::fromWire(std::stringstream& in, int) {
     //
     //
     // Check protocol version
     // Check protocol version
     //
     //
@@ -892,7 +890,7 @@ merge(ElementPtr element, ConstElementPtr other) {
         isc_throw(TypeError, "merge arguments not MapElements");
         isc_throw(TypeError, "merge arguments not MapElements");
     }
     }
     
     
-    std::map<std::string, ConstElementPtr> m = other->mapValue();
+    const std::map<std::string, ConstElementPtr>& m = other->mapValue();
     for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
     for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
          it != m.end() ; ++it) {
          it != m.end() ; ++it) {
         if ((*it).second && (*it).second->getType() != Element::null) {
         if ((*it).second && (*it).second->getType() != Element::null) {

+ 4 - 0
src/lib/cc/tests/Makefile.am

@@ -1,10 +1,14 @@
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 if USE_GXX			#XXX: see ../Makefile.am
 if USE_GXX			#XXX: see ../Makefile.am
 AM_CXXFLAGS += -Wno-unused-parameter
 AM_CXXFLAGS += -Wno-unused-parameter
 endif
 endif
+if USE_CLANGPP
+AM_CXXFLAGS += -Wno-error
+endif
 
 
 if USE_STATIC_LINK
 if USE_STATIC_LINK
 AM_LDFLAGS = -static
 AM_LDFLAGS = -static

+ 1 - 1
src/lib/cc/tests/data_unittests.cc

@@ -247,7 +247,7 @@ TEST(Element, create_and_value_throws) {
     EXPECT_EQ(b, true);
     EXPECT_EQ(b, true);
     b = false;
     b = false;
     EXPECT_TRUE(el->setValue(b));
     EXPECT_TRUE(el->setValue(b));
-    EXPECT_EQ(false, el->boolValue());
+    EXPECT_FALSE(el->boolValue());
 
 
     el = Element::create("foo");
     el = Element::create("foo");
     EXPECT_THROW(el->intValue(), TypeError);
     EXPECT_THROW(el->intValue(), TypeError);

+ 1 - 2
src/lib/cc/tests/run_unittests.cc

@@ -17,8 +17,7 @@
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 int
 int
-main(int argc, char* argv[])
+main(int argc, char* argv[]) {
-{
     ::testing::InitGoogleTest(&argc, argv);
     ::testing::InitGoogleTest(&argc, argv);
     return (RUN_ALL_TESTS());
     return (RUN_ALL_TESTS());
 }
 }

+ 1 - 1
src/lib/cc/tests/session_unittests.cc

@@ -76,7 +76,7 @@ public:
     }
     }
 
 
     void
     void
-    acceptHandler(const asio::error_code& error UNUSED_PARAM) {
+    acceptHandler(const asio::error_code&) {
     }
     }
 
 
     void
     void

+ 1 - 0
src/lib/config/Makefile.am

@@ -2,6 +2,7 @@ SUBDIRS = . tests
 
 
 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/lib/cc
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CXXFLAGS = $(B10_CXXFLAGS) -Wno-strict-aliasing
 AM_CXXFLAGS = $(B10_CXXFLAGS) -Wno-strict-aliasing
 
 
 lib_LTLIBRARIES = libcfgclient.la
 lib_LTLIBRARIES = libcfgclient.la

+ 3 - 4
src/lib/config/ccsession.cc

@@ -45,6 +45,7 @@
 using namespace std;
 using namespace std;
 
 
 using isc::data::Element;
 using isc::data::Element;
+using isc::data::ConstElementPtr;
 using isc::data::ElementPtr;
 using isc::data::ElementPtr;
 using isc::data::JSONError;
 using isc::data::JSONError;
 
 
@@ -333,8 +334,7 @@ ModuleCCSession::checkCommand() {
 }
 }
 
 
 std::string
 std::string
-ModuleCCSession::addRemoteConfig(const std::string& spec_file_name)
+ModuleCCSession::addRemoteConfig(const std::string& spec_file_name) {
-{
     ModuleSpec rmod_spec = readModuleSpecification(spec_file_name);
     ModuleSpec rmod_spec = readModuleSpecification(spec_file_name);
     std::string module_name = rmod_spec.getFullSpec()->get("module_name")->stringValue();
     std::string module_name = rmod_spec.getFullSpec()->get("module_name")->stringValue();
     ConfigData rmod_config = ConfigData(rmod_spec);
     ConfigData rmod_config = ConfigData(rmod_spec);
@@ -362,8 +362,7 @@ ModuleCCSession::addRemoteConfig(const std::string& spec_file_name)
 }
 }
 
 
 void
 void
-ModuleCCSession::removeRemoteConfig(const std::string& module_name)
+ModuleCCSession::removeRemoteConfig(const std::string& module_name) {
-{
     std::map<std::string, ConfigData>::iterator it;
     std::map<std::string, ConfigData>::iterator it;
 
 
     it = remote_module_configs_.find(module_name);
     it = remote_module_configs_.find(module_name);

+ 18 - 11
src/lib/config/ccsession.h

@@ -31,7 +31,7 @@ namespace config {
 /// \brief Creates a standard config/command level success answer message
 /// \brief Creates a standard config/command level success answer message
 ///        (i.e. of the form { "result": [ 0 ] }
 ///        (i.e. of the form { "result": [ 0 ] }
 /// \return Standard command/config success answer message
 /// \return Standard command/config success answer message
-ConstElementPtr createAnswer();
+isc::data::ConstElementPtr createAnswer();
 
 
 ///
 ///
 /// \brief Creates a standard config/command level answer message
 /// \brief Creates a standard config/command level answer message
@@ -43,7 +43,8 @@ ConstElementPtr createAnswer();
 ///            Element type. For rcode == 1, this argument is mandatory,
 ///            Element type. For rcode == 1, this argument is mandatory,
 ///            and must be a StringElement containing an error description
 ///            and must be a StringElement containing an error description
 /// \return Standard command/config answer message
 /// \return Standard command/config answer message
-ConstElementPtr createAnswer(const int rcode, ConstElementPtr arg);
+isc::data::ConstElementPtr createAnswer(const int rcode,
+                                        isc::data::ConstElementPtr arg);
 
 
 ///
 ///
 /// \brief Creates a standard config/command level answer message
 /// \brief Creates a standard config/command level answer message
@@ -52,7 +53,8 @@ ConstElementPtr createAnswer(const int rcode, ConstElementPtr arg);
 /// \param rcode The return code (0 for success)
 /// \param rcode The return code (0 for success)
 /// \param arg A string to put into the StringElement argument
 /// \param arg A string to put into the StringElement argument
 /// \return Standard command/config answer message
 /// \return Standard command/config answer message
-ConstElementPtr createAnswer(const int rcode, const std::string& arg);
+isc::data::ConstElementPtr createAnswer(const int rcode,
+                                        const std::string& arg);
 
 
 ///
 ///
 /// Parses a standard config/command level answer message
 /// Parses a standard config/command level answer message
@@ -63,7 +65,8 @@ ConstElementPtr createAnswer(const int rcode, const std::string& arg);
 /// \return The optional argument in the message, or an empty ElementPtr
 /// \return The optional argument in the message, or an empty ElementPtr
 ///         if there was no argument. If rcode != 0, this contains a
 ///         if there was no argument. If rcode != 0, this contains a
 ///         StringElement with the error description.
 ///         StringElement with the error description.
-ConstElementPtr parseAnswer(int &rcode, ConstElementPtr msg);
+isc::data::ConstElementPtr parseAnswer(int &rcode,
+                                       isc::data::ConstElementPtr msg);
 
 
 ///
 ///
 /// \brief Creates a standard config/command command message with no
 /// \brief Creates a standard config/command command message with no
@@ -71,7 +74,7 @@ ConstElementPtr parseAnswer(int &rcode, ConstElementPtr msg);
 /// 
 /// 
 /// \param command The command string
 /// \param command The command string
 /// \return The created message
 /// \return The created message
-ConstElementPtr createCommand(const std::string& command);
+isc::data::ConstElementPtr createCommand(const std::string& command);
 
 
 ///
 ///
 /// \brief Creates a standard config/command command message with the
 /// \brief Creates a standard config/command command message with the
@@ -81,7 +84,8 @@ ConstElementPtr createCommand(const std::string& command);
 /// \param arg The optional argument for the command. This can be of 
 /// \param arg The optional argument for the command. This can be of 
 ///        any Element type, but it should conform to the .spec file.
 ///        any Element type, but it should conform to the .spec file.
 /// \return The created message
 /// \return The created message
-ConstElementPtr createCommand(const std::string& command, ConstElementPtr arg);
+isc::data::ConstElementPtr createCommand(const std::string& command,
+                                         isc::data::ConstElementPtr arg);
 
 
 ///
 ///
 /// \brief Parses the given command into a string containing the actual
 /// \brief Parses the given command into a string containing the actual
@@ -92,7 +96,8 @@ ConstElementPtr createCommand(const std::string& command, ConstElementPtr arg);
 /// \param command The command message containing the command (as made
 /// \param command The command message containing the command (as made
 ///        by createCommand()
 ///        by createCommand()
 /// \return The command string
 /// \return The command string
-std::string parseCommand(ConstElementPtr& arg, ConstElementPtr command);
+std::string parseCommand(isc::data::ConstElementPtr& arg,
+                         isc::data::ConstElementPtr command);
 
 
 
 
 ///
 ///
@@ -225,8 +230,9 @@ public:
      * \param identifier The identifier of the config value
      * \param identifier The identifier of the config value
      * \return The configuration setting at the given identifier
      * \return The configuration setting at the given identifier
      */
      */
-    ConstElementPtr getRemoteConfigValue(const std::string& module_name,
+    isc::data::ConstElementPtr getRemoteConfigValue(
-                                         const std::string& identifier) const;
+        const std::string& module_name,
+        const std::string& identifier) const;
     
     
 private:
 private:
     ModuleSpec readModuleSpecification(const std::string& filename);
     ModuleSpec readModuleSpecification(const std::string& filename);
@@ -235,7 +241,8 @@ private:
     std::string module_name_;
     std::string module_name_;
     isc::cc::AbstractSession& session_;
     isc::cc::AbstractSession& session_;
     ModuleSpec module_specification_;
     ModuleSpec module_specification_;
-    ConstElementPtr handleConfigUpdate(ConstElementPtr new_config);
+    isc::data::ConstElementPtr handleConfigUpdate(
+        isc::data::ConstElementPtr new_config);
 
 
     isc::data::ConstElementPtr(*config_handler_)(
     isc::data::ConstElementPtr(*config_handler_)(
         isc::data::ConstElementPtr new_config);
         isc::data::ConstElementPtr new_config);
@@ -245,7 +252,7 @@ private:
 
 
     std::map<std::string, ConfigData> remote_module_configs_;
     std::map<std::string, ConfigData> remote_module_configs_;
     void updateRemoteConfig(const std::string& module_name,
     void updateRemoteConfig(const std::string& module_name,
-                            ConstElementPtr new_config);
+                            isc::data::ConstElementPtr new_config);
 };
 };
 
 
 }
 }

+ 13 - 11
src/lib/config/config_data.h

@@ -39,12 +39,14 @@ class ConfigData {
 public:
 public:
     /// Constructs a ConfigData option with no specification and an
     /// Constructs a ConfigData option with no specification and an
     /// empty configuration.
     /// empty configuration.
-    ConfigData() { _config = Element::createMap(); };
+    ConfigData() { _config = isc::data::Element::createMap(); };
 
 
     /// Constructs a ConfigData option with the given specification
     /// Constructs a ConfigData option with the given specification
     /// and an empty configuration.
     /// and an empty configuration.
     /// \param module_spec A ModuleSpec for the relevant module
     /// \param module_spec A ModuleSpec for the relevant module
-    ConfigData(const ModuleSpec& module_spec) : _module_spec(module_spec) { _config = Element::createMap(); }
+    ConfigData(const ModuleSpec& module_spec) : _module_spec(module_spec) {
+        _config = isc::data::Element::createMap();
+    }
 
 
     virtual ~ConfigData() {};
     virtual ~ConfigData() {};
 
 
@@ -55,7 +57,7 @@ public:
     /// Raises a DataNotFoundError if the identifier is bad.
     /// Raises a DataNotFoundError if the identifier is bad.
     /// \param identifier The identifier pointing to the configuration
     /// \param identifier The identifier pointing to the configuration
     ///        value that is to be returned
     ///        value that is to be returned
-    ConstElementPtr getValue(const std::string& identifier) const;
+    isc::data::ConstElementPtr getValue(const std::string& identifier) const;
 
 
     /// Returns the value currently set for the given identifier
     /// Returns the value currently set for the given identifier
     /// If no value is set, the default value (as specified by the
     /// If no value is set, the default value (as specified by the
@@ -67,8 +69,8 @@ public:
     ///                   false otherwise
     ///                   false otherwise
     /// \param identifier The identifier pointing to the configuration
     /// \param identifier The identifier pointing to the configuration
     ///        value that is to be returned
     ///        value that is to be returned
-    ConstElementPtr getValue(bool& is_default,
+    isc::data::ConstElementPtr getValue(bool& is_default,
-                             const std::string& identifier) const;
+                                        const std::string& identifier) const;
 
 
     /// Returns the ModuleSpec associated with this ConfigData object
     /// Returns the ModuleSpec associated with this ConfigData object
     const ModuleSpec& getModuleSpec() const { return (_module_spec); }
     const ModuleSpec& getModuleSpec() const { return (_module_spec); }
@@ -80,12 +82,12 @@ public:
     /// \param config An ElementPtr pointing to a MapElement containing
     /// \param config An ElementPtr pointing to a MapElement containing
     ///        *all* non-default configuration values. Existing values
     ///        *all* non-default configuration values. Existing values
     ///        will be removed.
     ///        will be removed.
-    void setLocalConfig(ElementPtr config) { _config = config; }
+    void setLocalConfig(isc::data::ElementPtr config) { _config = config; }
 
 
     /// Returns the local (i.e. non-default) configuration.
     /// Returns the local (i.e. non-default) configuration.
     /// \returns An ElementPtr pointing to a MapElement containing all
     /// \returns An ElementPtr pointing to a MapElement containing all
     ///          non-default configuration options.
     ///          non-default configuration options.
-    ElementPtr getLocalConfig() { return (_config); }
+    isc::data::ElementPtr getLocalConfig() { return (_config); }
 
 
     /// Returns a list of all possible configuration options as specified
     /// Returns a list of all possible configuration options as specified
     ///         by the ModuleSpec.
     ///         by the ModuleSpec.
@@ -97,18 +99,18 @@ public:
     ///         StringElements that specify the identifiers at the given
     ///         StringElements that specify the identifiers at the given
     ///         location (or all possible identifiers if identifier==""
     ///         location (or all possible identifiers if identifier==""
     ///         and recurse==false)
     ///         and recurse==false)
-    ConstElementPtr getItemList(const std::string& identifier = "",
+    isc::data::ConstElementPtr getItemList(const std::string& identifier = "",
-                                bool recurse = false) const;
+                                           bool recurse = false) const;
 
 
     /// Returns all current configuration settings (both non-default and default).
     /// Returns all current configuration settings (both non-default and default).
     /// \return An ElementPtr pointing to a MapElement containing
     /// \return An ElementPtr pointing to a MapElement containing
     ///         string->value elements, where the string is the
     ///         string->value elements, where the string is the
     ///         full identifier of the configuration option and the
     ///         full identifier of the configuration option and the
     ///         value is an ElementPtr with the value.
     ///         value is an ElementPtr with the value.
-    ConstElementPtr getFullConfig() const;
+    isc::data::ConstElementPtr getFullConfig() const;
 
 
 private:
 private:
-    ElementPtr _config;
+    isc::data::ElementPtr _config;
     ModuleSpec _module_spec;
     ModuleSpec _module_spec;
 };
 };
 
 

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

@@ -24,6 +24,7 @@
 
 
 // todo: add more context to thrown ModuleSpecErrors?
 // todo: add more context to thrown ModuleSpecErrors?
 
 
+using namespace isc::data;
 using namespace isc::config;
 using namespace isc::config;
 
 
 namespace {
 namespace {

+ 26 - 19
src/lib/config/module_spec.h

@@ -20,8 +20,6 @@
 
 
 #include <sstream>
 #include <sstream>
 
 
-using namespace isc::data;
-
 namespace isc { namespace config {
 namespace isc { namespace config {
 
 
     ///
     ///
@@ -55,24 +53,27 @@ namespace isc { namespace config {
         /// Create a \c ModuleSpec instance with the given data as
         /// Create a \c ModuleSpec instance with the given data as
         /// the specification
         /// the specification
         /// \param e The Element containing the data specification
         /// \param e The Element containing the data specification
-        explicit ModuleSpec(ConstElementPtr e, const bool check = true)
+        explicit ModuleSpec(isc::data::ConstElementPtr e,
+                            const bool check = true)
             throw(ModuleSpecError);
             throw(ModuleSpecError);
 
 
         /// Returns the commands part of the specification as an
         /// Returns the commands part of the specification as an
         /// ElementPtr, returns an empty ElementPtr if there is none
         /// ElementPtr, returns an empty ElementPtr if there is none
         /// \return ElementPtr Shared pointer to the commands
         /// \return ElementPtr Shared pointer to the commands
         ///                    part of the specification
         ///                    part of the specification
-        ConstElementPtr getCommandsSpec() const;
+        isc::data::ConstElementPtr getCommandsSpec() const;
 
 
         /// Returns the configuration part of the specification as an
         /// Returns the configuration part of the specification as an
         /// ElementPtr
         /// ElementPtr
         /// \return ElementPtr Shared pointer to the configuration
         /// \return ElementPtr Shared pointer to the configuration
         ///                    part of the specification
         ///                    part of the specification
-        ConstElementPtr getConfigSpec() const;
+        isc::data::ConstElementPtr getConfigSpec() const;
 
 
         /// Returns the full module specification as an ElementPtr
         /// Returns the full module specification as an ElementPtr
         /// \return ElementPtr Shared pointer to the specification
         /// \return ElementPtr Shared pointer to the specification
-        ConstElementPtr getFullSpec() const { return module_specification; }
+        isc::data::ConstElementPtr getFullSpec() const {
+            return module_specification;
+        }
 
 
         /// Returns the module name as specified by the specification
         /// Returns the module name as specified by the specification
         const std::string getModuleName() const;
         const std::string getModuleName() const;
@@ -87,22 +88,28 @@ namespace isc { namespace config {
         /// \param data The base \c Element of the data to check
         /// \param data The base \c Element of the data to check
         /// \return true if the data conforms to the specification,
         /// \return true if the data conforms to the specification,
         /// false otherwise.
         /// false otherwise.
-        bool validate_config(ConstElementPtr data,
+        bool validate_config(isc::data::ConstElementPtr data,
                              const bool full = false) const;
                              const bool full = false) const;
 
 
         /// errors must be of type ListElement
         /// errors must be of type ListElement
-        bool validate_config(ConstElementPtr data, const bool full,
+        bool validate_config(isc::data::ConstElementPtr data, const bool full,
-                             ElementPtr errors) const;
+                             isc::data::ElementPtr errors) const;
 
 
     private:
     private:
-        bool validate_item(ConstElementPtr spec, ConstElementPtr data,
+        bool validate_item(isc::data::ConstElementPtr spec,
-                           const bool full, ElementPtr errors) const;
+                           isc::data::ConstElementPtr data,
-        bool validate_spec(ConstElementPtr spec, ConstElementPtr data,
+                           const bool full,
-                           const bool full, ElementPtr errors) const;
+                           isc::data::ElementPtr errors) const;
-        bool validate_spec_list(ConstElementPtr spec, ConstElementPtr data,
+        bool validate_spec(isc::data::ConstElementPtr spec,
-                                const bool full, ElementPtr errors) const;
+                           isc::data::ConstElementPtr data,
-
+                           const bool full,
-        ConstElementPtr module_specification;
+                           isc::data::ElementPtr errors) const;
+        bool validate_spec_list(isc::data::ConstElementPtr spec,
+                                isc::data::ConstElementPtr data,
+                                const bool full,
+                                isc::data::ElementPtr errors) const;
+
+        isc::data::ConstElementPtr module_specification;
     };
     };
 
 
     /// Creates a \c ModuleSpec instance from the contents
     /// Creates a \c ModuleSpec instance from the contents
@@ -115,7 +122,7 @@ namespace isc { namespace config {
     /// is checked to be of the correct form
     /// is checked to be of the correct form
     ModuleSpec
     ModuleSpec
     moduleSpecFromFile(const std::string& file_name, const bool check = true)
     moduleSpecFromFile(const std::string& file_name, const bool check = true)
-                       throw(JSONError, ModuleSpecError);
+        throw(isc::data::JSONError, ModuleSpecError);
 
 
     /// Creates a \c ModuleSpec instance from the given input
     /// Creates a \c ModuleSpec instance from the given input
     /// stream that contains the contents of a .spec file.
     /// stream that contains the contents of a .spec file.
@@ -127,7 +134,7 @@ namespace isc { namespace config {
     /// to be of the correct form
     /// to be of the correct form
     ModuleSpec
     ModuleSpec
     moduleSpecFromFile(std::ifstream& in, const bool check = true)
     moduleSpecFromFile(std::ifstream& in, const bool check = true)
-                       throw(JSONError, ModuleSpecError);
+                       throw(isc::data::JSONError, ModuleSpecError);
 } }
 } }
 
 
 #endif // _DATA_DEF_H
 #endif // _DATA_DEF_H

+ 2 - 5
src/lib/config/tests/Makefile.am

@@ -1,12 +1,9 @@
 SUBDIRS = testdata .
 SUBDIRS = testdata .
 
 
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
-# see src/lib/cc/Makefile.am for -Wno-unused-parameter
-if USE_GXX
-AM_CXXFLAGS += -Wno-unused-parameter
-endif
 
 
 if USE_STATIC_LINK
 if USE_STATIC_LINK
 AM_LDFLAGS = -static
 AM_LDFLAGS = -static
@@ -25,8 +22,8 @@ run_unittests_SOURCES = ccsession_unittests.cc module_spec_unittests.cc config_d
 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 =  $(GTEST_LDADD)
 run_unittests_LDADD =  $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD += libfake_session.la
 run_unittests_LDADD += libfake_session.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 
 

+ 16 - 17
src/lib/config/tests/ccsession_unittests.cc

@@ -150,9 +150,9 @@ TEST_F(CCSessionTest, parseCommand) {
 }
 }
 
 
 TEST_F(CCSessionTest, session1) {
 TEST_F(CCSessionTest, session1) {
-    EXPECT_EQ(false, session.haveSubscription("Spec1", "*"));
+    EXPECT_FALSE(session.haveSubscription("Spec1", "*"));
     ModuleCCSession mccs(ccspecfile("spec1.spec"), session, NULL, NULL);
     ModuleCCSession mccs(ccspecfile("spec1.spec"), session, NULL, NULL);
-    EXPECT_EQ(true, session.haveSubscription("Spec1", "*"));
+    EXPECT_TRUE(session.haveSubscription("Spec1", "*"));
 
 
     EXPECT_EQ(1, session.getMsgQueue()->size());
     EXPECT_EQ(1, session.getMsgQueue()->size());
     ConstElementPtr msg;
     ConstElementPtr msg;
@@ -164,11 +164,10 @@ TEST_F(CCSessionTest, session1) {
     EXPECT_EQ(0, session.getMsgQueue()->size());
     EXPECT_EQ(0, session.getMsgQueue()->size());
 }
 }
 
 
-TEST_F(CCSessionTest, session2)
+TEST_F(CCSessionTest, session2) {
-{
+    EXPECT_FALSE(session.haveSubscription("Spec2", "*"));
-    EXPECT_EQ(false, session.haveSubscription("Spec2", "*"));
     ModuleCCSession mccs(ccspecfile("spec2.spec"), session, NULL, NULL);
     ModuleCCSession mccs(ccspecfile("spec2.spec"), session, NULL, NULL);
-    EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
+    EXPECT_TRUE(session.haveSubscription("Spec2", "*"));
 
 
     EXPECT_EQ(1, session.getMsgQueue()->size());
     EXPECT_EQ(1, session.getMsgQueue()->size());
     ConstElementPtr msg;
     ConstElementPtr msg;
@@ -189,7 +188,7 @@ ConstElementPtr my_config_handler(ConstElementPtr new_config) {
 }
 }
 
 
 ConstElementPtr my_command_handler(const std::string& command,
 ConstElementPtr my_command_handler(const std::string& command,
-                                   ConstElementPtr arg UNUSED_PARAM)
+                                   ConstElementPtr arg)
 {
 {
     if (command == "good_command") {
     if (command == "good_command") {
         return (createAnswer());
         return (createAnswer());
@@ -212,10 +211,10 @@ TEST_F(CCSessionTest, session3) {
     // client will ask for config
     // client will ask for config
     session.getMessages()->add(createAnswer(0, el("{}")));
     session.getMessages()->add(createAnswer(0, el("{}")));
 
 
-    EXPECT_EQ(false, session.haveSubscription("Spec2", "*"));
+    EXPECT_FALSE(session.haveSubscription("Spec2", "*"));
     ModuleCCSession mccs(ccspecfile("spec2.spec"), session, my_config_handler,
     ModuleCCSession mccs(ccspecfile("spec2.spec"), session, my_config_handler,
                          my_command_handler);
                          my_command_handler);
-    EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
+    EXPECT_TRUE(session.haveSubscription("Spec2", "*"));
 
 
     EXPECT_EQ(2, session.getMsgQueue()->size());
     EXPECT_EQ(2, session.getMsgQueue()->size());
     ConstElementPtr msg;
     ConstElementPtr msg;
@@ -236,10 +235,10 @@ TEST_F(CCSessionTest, checkCommand) {
     // client will ask for config
     // client will ask for config
     session.getMessages()->add(createAnswer(0, el("{}")));
     session.getMessages()->add(createAnswer(0, el("{}")));
 
 
-    EXPECT_EQ(false, session.haveSubscription("Spec2", "*"));
+    EXPECT_FALSE(session.haveSubscription("Spec2", "*"));
     ModuleCCSession mccs(ccspecfile("spec2.spec"), session, my_config_handler,
     ModuleCCSession mccs(ccspecfile("spec2.spec"), session, my_config_handler,
                          my_command_handler);
                          my_command_handler);
-    EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
+    EXPECT_TRUE(session.haveSubscription("Spec2", "*"));
 
 
     EXPECT_EQ(2, session.getMsgQueue()->size());
     EXPECT_EQ(2, session.getMsgQueue()->size());
     ConstElementPtr msg;
     ConstElementPtr msg;
@@ -341,23 +340,23 @@ TEST_F(CCSessionTest, remoteConfig) {
     int item1;
     int item1;
     
     
     ModuleCCSession mccs(ccspecfile("spec1.spec"), session, NULL, NULL);
     ModuleCCSession mccs(ccspecfile("spec1.spec"), session, NULL, NULL);
-    EXPECT_EQ(true, session.haveSubscription("Spec1", "*"));
+    EXPECT_TRUE(session.haveSubscription("Spec1", "*"));
     
     
     // first simply connect, with no config values, and see we get
     // first simply connect, with no config values, and see we get
     // the default
     // the default
     session.getMessages()->add(createAnswer(0, el("{}")));
     session.getMessages()->add(createAnswer(0, el("{}")));
 
 
-    EXPECT_EQ(false, session.haveSubscription("Spec2", "*"));
+    EXPECT_FALSE(session.haveSubscription("Spec2", "*"));
     module_name = mccs.addRemoteConfig(ccspecfile("spec2.spec"));
     module_name = mccs.addRemoteConfig(ccspecfile("spec2.spec"));
     EXPECT_EQ("Spec2", module_name);
     EXPECT_EQ("Spec2", module_name);
-    EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
+    EXPECT_TRUE(session.haveSubscription("Spec2", "*"));
 
 
     item1 = mccs.getRemoteConfigValue(module_name, "item1")->intValue();
     item1 = mccs.getRemoteConfigValue(module_name, "item1")->intValue();
     EXPECT_EQ(1, item1);
     EXPECT_EQ(1, item1);
 
 
     // Remove it and see we get an error asking for a config value
     // Remove it and see we get an error asking for a config value
     mccs.removeRemoteConfig(module_name);
     mccs.removeRemoteConfig(module_name);
-    EXPECT_EQ(false, session.haveSubscription("Spec2", "*"));
+    EXPECT_FALSE(session.haveSubscription("Spec2", "*"));
     EXPECT_THROW(mccs.getRemoteConfigValue(module_name, "item1"), CCSessionError);
     EXPECT_THROW(mccs.getRemoteConfigValue(module_name, "item1"), CCSessionError);
 
 
     // Now re-add it, with a specific config value, and see we get that
     // Now re-add it, with a specific config value, and see we get that
@@ -388,9 +387,9 @@ TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
     // client will ask for config
     // client will ask for config
     session.getMessages()->add(createAnswer(0, el("{  }")));
     session.getMessages()->add(createAnswer(0, el("{  }")));
 
 
-    EXPECT_EQ(false, session.haveSubscription("Spec2", "*"));
+    EXPECT_FALSE(session.haveSubscription("Spec2", "*"));
     ModuleCCSession mccs(ccspecfile("spec2.spec"), session, my_config_handler, my_command_handler);
     ModuleCCSession mccs(ccspecfile("spec2.spec"), session, my_config_handler, my_command_handler);
-    EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
+    EXPECT_TRUE(session.haveSubscription("Spec2", "*"));
 
 
     EXPECT_EQ(2, session.getMsgQueue()->size());
     EXPECT_EQ(2, session.getMsgQueue()->size());
     ConstElementPtr msg;
     ConstElementPtr msg;

+ 5 - 10
src/lib/config/tests/fake_session.cc

@@ -87,17 +87,15 @@ FakeSession::disconnect() {
 }
 }
 
 
 void
 void
-FakeSession::startRead(boost::function<void()> read_callback UNUSED_PARAM) {
+FakeSession::startRead(boost::function<void()>) {
 }
 }
 
 
 void
 void
-FakeSession::establish(const char* socket_file) {
+FakeSession::establish(const char*) {
 }
 }
 
 
 bool
 bool
-FakeSession::recvmsg(ConstElementPtr& msg, bool nonblock UNUSED_PARAM,
+FakeSession::recvmsg(ConstElementPtr& msg, bool, int) {
-                     int seq UNUSED_PARAM)
-{
     //cout << "[XX] client asks for message " << endl;
     //cout << "[XX] client asks for message " << endl;
     if (messages_ &&
     if (messages_ &&
         messages_->getType() == Element::list &&
         messages_->getType() == Element::list &&
@@ -111,10 +109,7 @@ FakeSession::recvmsg(ConstElementPtr& msg, bool nonblock UNUSED_PARAM,
 }
 }
 
 
 bool
 bool
-FakeSession::recvmsg(ConstElementPtr& env, ConstElementPtr& msg,
+FakeSession::recvmsg(ConstElementPtr& env, ConstElementPtr& msg, bool, int) {
-                     bool nonblock UNUSED_PARAM,
-                     int seq UNUSED_PARAM)
-{
     //cout << "[XX] client asks for message and env" << endl;
     //cout << "[XX] client asks for message and env" << endl;
     env = ElementPtr();
     env = ElementPtr();
     if (messages_ &&
     if (messages_ &&
@@ -172,7 +167,7 @@ FakeSession::unsubscribe(std::string group, std::string instance) {
 
 
 int
 int
 FakeSession::group_sendmsg(ConstElementPtr msg, std::string group,
 FakeSession::group_sendmsg(ConstElementPtr msg, std::string group,
-                           std::string to, std::string instance UNUSED_PARAM)
+                           std::string to, std::string)
 {
 {
     //cout << "[XX] client sends message: " << msg << endl;
     //cout << "[XX] client sends message: " << msg << endl;
     //cout << "[XX] to: " << group << " . " << instance << "." << to << endl;
     //cout << "[XX] to: " << group << " . " << instance << "." << to << endl;

+ 1 - 1
src/lib/config/tests/fake_session.h

@@ -63,7 +63,7 @@ public:
     virtual int reply(isc::data::ConstElementPtr envelope,
     virtual int reply(isc::data::ConstElementPtr envelope,
                       isc::data::ConstElementPtr newmsg);
                       isc::data::ConstElementPtr newmsg);
     virtual bool hasQueuedMsgs() const;
     virtual bool hasQueuedMsgs() const;
-    virtual void setTimeout(size_t milliseconds) {}
+    virtual void setTimeout(size_t) {}
     virtual size_t getTimeout() const { return (0); }
     virtual size_t getTimeout() const { return (0); }
     isc::data::ConstElementPtr getFirstMessage(std::string& group,
     isc::data::ConstElementPtr getFirstMessage(std::string& group,
                                                std::string& to) const;
                                                std::string& to) const;

+ 2 - 4
src/lib/config/tests/module_spec_unittests.cc

@@ -105,8 +105,7 @@ TEST(ModuleSpec, SpecfileItems) {
                    "badname is not a valid type name");
                    "badname is not a valid type name");
 }
 }
 
 
-TEST(ModuleSpec, SpecfileConfigData)
+TEST(ModuleSpec, SpecfileConfigData) {
-{
     module_spec_error("spec7.spec",
     module_spec_error("spec7.spec",
                    "module_name missing in {  }");
                    "module_name missing in {  }");
     module_spec_error("spec8.spec",
     module_spec_error("spec8.spec",
@@ -117,8 +116,7 @@ TEST(ModuleSpec, SpecfileConfigData)
                    "commands is not a list of elements");
                    "commands is not a list of elements");
 }
 }
 
 
-TEST(ModuleSpec, SpecfileCommands)
+TEST(ModuleSpec, SpecfileCommands) {
-{
     module_spec_error("spec17.spec",
     module_spec_error("spec17.spec",
                    "command_name missing in { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\" }");
                    "command_name missing in { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\" }");
     module_spec_error("spec18.spec",
     module_spec_error("spec18.spec",

+ 1 - 2
src/lib/config/tests/run_unittests.cc

@@ -17,8 +17,7 @@
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
 int
 int
-main(int argc, char* argv[])
+main(int argc, char* argv[]) {
-{
     ::testing::InitGoogleTest(&argc, argv);
     ::testing::InitGoogleTest(&argc, argv);
     return (RUN_ALL_TESTS());
     return (RUN_ALL_TESTS());
 }
 }

+ 2 - 0
src/lib/datasrc/Makefile.am

@@ -2,6 +2,7 @@ SUBDIRS = . tests
 
 
 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_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += $(SQLITE_CFLAGS)
 AM_CPPFLAGS += $(SQLITE_CFLAGS)
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -14,3 +15,4 @@ libdatasrc_la_SOURCES += static_datasrc.h static_datasrc.cc
 libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
 libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
 libdatasrc_la_SOURCES += query.h query.cc
 libdatasrc_la_SOURCES += query.h query.cc
 libdatasrc_la_SOURCES += cache.h cache.cc
 libdatasrc_la_SOURCES += cache.h cache.cc
+libdatasrc_la_SOURCES += zonetable.h zonetable.cc

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

@@ -170,9 +170,9 @@ public:
     /// then promoted to the head of the LRU queue.  (NOTE: Because
     /// then promoted to the head of the LRU queue.  (NOTE: Because
     /// of this, "retrieve" cannot be implemented as a const method.)
     /// of this, "retrieve" cannot be implemented as a const method.)
     ///
     ///
-    /// \param name The query name
+    /// \param qname The query name
-    /// \param rrclass The query class
+    /// \param qclass The query class
-    /// \param rrtype The query type
+    /// \param qtype The query type
     /// \param rrset Returns the RRset found, if any, to the caller
     /// \param rrset Returns the RRset found, if any, to the caller
     /// \param flags Returns the flags, if any, to the caller
     /// \param flags Returns the flags, if any, to the caller
     ///
     ///

+ 60 - 66
src/lib/datasrc/data_source.cc

@@ -95,20 +95,20 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
     }
     }
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    for (it->first(); !it->isLast(); it->next()) {
+    for (; !it->isLast(); it->next()) {
         const Rdata& rd(it->getCurrent());
         const Rdata& rd(it->getCurrent());
         if (rrset->getType() == RRType::NS()) {
         if (rrset->getType() == RRType::NS()) {
             const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
             const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
             q.tasks().push(QueryTaskPtr(
             q.tasks().push(QueryTaskPtr(
                                new QueryTask(q, ns.getNSName(),
                                new QueryTask(q, ns.getNSName(),
-                                             Section::ADDITIONAL(),
+                                             Message::SECTION_ADDITIONAL,
                                              QueryTask::GLUE_QUERY,
                                              QueryTask::GLUE_QUERY,
                                              QueryTask::GETADDITIONAL))); 
                                              QueryTask::GETADDITIONAL))); 
         } else if (rrset->getType() == RRType::MX()) {
         } else if (rrset->getType() == RRType::MX()) {
             const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
             const generic::MX& mx = dynamic_cast<const generic::MX&>(rd);
             q.tasks().push(QueryTaskPtr(
             q.tasks().push(QueryTaskPtr(
                                new QueryTask(q, mx.getMXName(),
                                new QueryTask(q, mx.getMXName(),
-                                             Section::ADDITIONAL(),
+                                             Message::SECTION_ADDITIONAL,
                                              QueryTask::NOGLUE_QUERY,
                                              QueryTask::NOGLUE_QUERY,
                                              QueryTask::GETADDITIONAL))); 
                                              QueryTask::GETADDITIONAL))); 
         }
         }
@@ -123,7 +123,6 @@ synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
 
 
     // More than one DNAME RR in the RRset is illegal, so we only have
     // More than one DNAME RR in the RRset is illegal, so we only have
     // to process the first one.
     // to process the first one.
-    it->first();
     if (it->isLast()) {
     if (it->isLast()) {
         return;
         return;
     }
     }
@@ -152,7 +151,6 @@ chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
 
 
     // More than one CNAME RR in the RRset is illegal, so we only have
     // More than one CNAME RR in the RRset is illegal, so we only have
     // to process the first one.
     // to process the first one.
-    it->first();
     if (it->isLast()) {
     if (it->isLast()) {
         return;
         return;
     }
     }
@@ -165,7 +163,7 @@ chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
     q.tasks().push(QueryTaskPtr(
     q.tasks().push(QueryTaskPtr(
                        new QueryTask(q, dynamic_cast<const generic::CNAME&>
                        new QueryTask(q, dynamic_cast<const generic::CNAME&>
                                      (it->getCurrent()).getCname(),
                                      (it->getCurrent()).getCname(),
-                                     task->qtype, Section::ANSWER(),
+                                     task->qtype, Message::SECTION_ANSWER,
                                      QueryTask::FOLLOWCNAME)));
                                      QueryTask::FOLLOWCNAME)));
 }
 }
 
 
@@ -473,16 +471,19 @@ doQueryTask(QueryTask& task, ZoneInfo& zoneinfo, RRsetList& target) {
 // checking first to ensure that there isn't already an RRset with
 // checking first to ensure that there isn't already an RRset with
 // the same name and type.
 // the same name and type.
 inline void
 inline void
-addToMessage(Query& q, const Section& sect, RRsetPtr rrset,
+addToMessage(Query& q, const Message::Section sect, RRsetPtr rrset,
              bool no_dnssec = false)
              bool no_dnssec = false)
 {
 {
     Message& m = q.message();
     Message& m = q.message();
     if (no_dnssec) {
     if (no_dnssec) {
-        if (rrset->getType() == RRType::RRSIG() || !m.hasRRset(sect, rrset)) {
+        if (rrset->getType() == RRType::RRSIG() ||
+            !m.hasRRset(sect, rrset->getName(), rrset->getClass(),
+                        rrset->getType())) {
             m.addRRset(sect, rrset, false);
             m.addRRset(sect, rrset, false);
         }
         }
     } else {
     } else {
-        if (!m.hasRRset(sect, rrset)) {
+        if (!m.hasRRset(sect, rrset->getName(), rrset->getClass(),
+                        rrset->getType())) {
             m.addRRset(sect, rrset, q.wantDnssec());
             m.addRRset(sect, rrset, q.wantDnssec());
         }
         }
     }
     }
@@ -498,7 +499,7 @@ copyAuth(Query& q, RRsetList& auth) {
         if (rrset->getType() == RRType::DS() && !q.wantDnssec()) {
         if (rrset->getType() == RRType::DS() && !q.wantDnssec()) {
             continue;
             continue;
         }
         }
-        addToMessage(q, Section::AUTHORITY(), rrset);
+        addToMessage(q, Message::SECTION_AUTHORITY, rrset);
         getAdditional(q, rrset);
         getAdditional(q, rrset);
     }
     }
 }
 }
@@ -560,11 +561,11 @@ hasDelegation(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo) {
             RRsetPtr r = ref.findRRset(RRType::DNAME(), q.qclass());
             RRsetPtr r = ref.findRRset(RRType::DNAME(), q.qclass());
             if (r != NULL) {
             if (r != NULL) {
                 RRsetList syn;
                 RRsetList syn;
-                addToMessage(q, Section::ANSWER(), r);
+                addToMessage(q, Message::SECTION_ANSWER, r);
-                q.message().setHeaderFlag(MessageFlag::AA());
+                q.message().setHeaderFlag(Message::HEADERFLAG_AA);
                 synthesizeCname(task, r, syn);
                 synthesizeCname(task, r, syn);
                 if (syn.size() == 1) {
                 if (syn.size() == 1) {
-                    addToMessage(q, Section::ANSWER(),
+                    addToMessage(q, Message::SECTION_ANSWER,
                                  syn.findRRset(RRType::CNAME(), q.qclass()));
                                  syn.findRRset(RRType::CNAME(), q.qclass()));
                     chaseCname(q, task, syn.findRRset(RRType::CNAME(),
                     chaseCname(q, task, syn.findRRset(RRType::CNAME(),
                                                       q.qclass()));
                                                       q.qclass()));
@@ -582,7 +583,7 @@ hasDelegation(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo) {
     // at the actual qname node.)
     // at the actual qname node.)
     if (task->op == QueryTask::AUTH_QUERY &&
     if (task->op == QueryTask::AUTH_QUERY &&
         task->state == QueryTask::GETANSWER) {
         task->state == QueryTask::GETANSWER) {
-        q.message().setHeaderFlag(MessageFlag::AA());
+        q.message().setHeaderFlag(Message::HEADERFLAG_AA);
     }
     }
 
 
     return (false);
     return (false);
@@ -599,7 +600,7 @@ addSOA(Query& q, ZoneInfo& zoneinfo) {
         return (DataSrc::ERROR);
         return (DataSrc::ERROR);
     }
     }
 
 
-    addToMessage(q, Section::AUTHORITY(),
+    addToMessage(q, Message::SECTION_AUTHORITY,
                  soa.findRRset(RRType::SOA(), q.qclass()));
                  soa.findRRset(RRType::SOA(), q.qclass()));
     return (DataSrc::SUCCESS);
     return (DataSrc::SUCCESS);
 }
 }
@@ -611,7 +612,7 @@ addNSEC(Query& q, const Name& name, ZoneInfo& zoneinfo) {
     QueryTask newtask(q, name, RRType::NSEC(), QueryTask::SIMPLE_QUERY); 
     QueryTask newtask(q, name, RRType::NSEC(), QueryTask::SIMPLE_QUERY); 
     RETERR(doQueryTask(newtask, zoneinfo, nsec));
     RETERR(doQueryTask(newtask, zoneinfo, nsec));
     if (newtask.flags == 0) {
     if (newtask.flags == 0) {
-        addToMessage(q, Section::AUTHORITY(),
+        addToMessage(q, Message::SECTION_AUTHORITY,
                      nsec.findRRset(RRType::NSEC(), q.qclass()));
                      nsec.findRRset(RRType::NSEC(), q.qclass()));
     }
     }
 
 
@@ -657,7 +658,6 @@ getNsec3Param(Query& q, ZoneInfo& zoneinfo) {
     // XXX: currently only one NSEC3 chain per zone is supported;
     // XXX: currently only one NSEC3 chain per zone is supported;
     // we will need to revisit this.
     // we will need to revisit this.
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     if (it->isLast()) {
     if (it->isLast()) {
         return (ConstNsec3ParamPtr());
         return (ConstNsec3ParamPtr());
     }
     }
@@ -680,7 +680,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
         RRsetPtr rrset;
         RRsetPtr rrset;
         string hash1(nsec3->getHash(task->qname));
         string hash1(nsec3->getHash(task->qname));
         RETERR(getNsec3(q, zoneinfo, hash1, rrset));
         RETERR(getNsec3(q, zoneinfo, hash1, rrset));
-        addToMessage(q, Section::AUTHORITY(), rrset);
+        addToMessage(q, Message::SECTION_AUTHORITY, rrset);
 
 
         // If this is an NXRRSET or NOERROR/NODATA, we're done
         // If this is an NXRRSET or NOERROR/NODATA, we're done
         if ((task->flags & DataSrc::TYPE_NOT_FOUND) != 0) {
         if ((task->flags & DataSrc::TYPE_NOT_FOUND) != 0) {
@@ -705,7 +705,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
             // we don't want to use one until we find an exact match
             // we don't want to use one until we find an exact match
             RETERR(getNsec3(q, zoneinfo, hash2, rrset));
             RETERR(getNsec3(q, zoneinfo, hash2, rrset));
             if (hash2 == nodehash) {
             if (hash2 == nodehash) {
-                addToMessage(q, Section::AUTHORITY(), rrset);
+                addToMessage(q, Message::SECTION_AUTHORITY, rrset);
                 break;
                 break;
             }
             }
         }
         }
@@ -720,7 +720,7 @@ proveNX(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, const bool wildcard) {
         string hash3(nsec3->getHash(Name("*").concatenate(enclosure)));
         string hash3(nsec3->getHash(Name("*").concatenate(enclosure)));
         RETERR(getNsec3(q, zoneinfo, hash3, rrset));
         RETERR(getNsec3(q, zoneinfo, hash3, rrset));
         if (hash3 != hash1 && hash3 != hash2) {
         if (hash3 != hash1 && hash3 != hash2) {
-            addToMessage(q, Section::AUTHORITY(), rrset);
+            addToMessage(q, Message::SECTION_AUTHORITY, rrset);
         }
         }
     } else {
     } else {
         Name nsecname(task->qname);
         Name nsecname(task->qname);
@@ -778,7 +778,7 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
 
 
     for (int i = 1; i <= diff; ++i) {
     for (int i = 1; i <= diff; ++i) {
         const Name& wname(star.concatenate(task->qname.split(i)));
         const Name& wname(star.concatenate(task->qname.split(i)));
-        QueryTask newtask(q, wname, task->qtype, Section::ANSWER(),
+        QueryTask newtask(q, wname, task->qtype, Message::SECTION_ANSWER,
                           QueryTask::AUTH_QUERY); 
                           QueryTask::AUTH_QUERY); 
         result = doQueryTask(newtask, zoneinfo, wild);
         result = doQueryTask(newtask, zoneinfo, wild);
         if (result == DataSrc::SUCCESS) {
         if (result == DataSrc::SUCCESS) {
@@ -820,13 +820,13 @@ tryWildcard(Query& q, QueryTaskPtr task, ZoneInfo& zoneinfo, bool& found) {
             RRsetPtr rrset = wild.findRRset(RRType::CNAME(), q.qclass());
             RRsetPtr rrset = wild.findRRset(RRType::CNAME(), q.qclass());
             if (rrset != NULL) {
             if (rrset != NULL) {
                 rrset->setName(task->qname);
                 rrset->setName(task->qname);
-                addToMessage(q, Section::ANSWER(), rrset);
+                addToMessage(q, Message::SECTION_ANSWER, rrset);
                 chaseCname(q, task, rrset);
                 chaseCname(q, task, rrset);
             }
             }
         } else {
         } else {
             BOOST_FOREACH (RRsetPtr rrset, wild) {
             BOOST_FOREACH (RRsetPtr rrset, wild) {
                 rrset->setName(task->qname);
                 rrset->setName(task->qname);
-                addToMessage(q, Section::ANSWER(), rrset);
+                addToMessage(q, Message::SECTION_ANSWER, rrset);
             }
             }
 
 
             RRsetList auth;
             RRsetList auth;
@@ -855,7 +855,7 @@ DataSrc::doQuery(Query& q) {
 
 
     // Process the query task queue.  (The queue is initialized
     // Process the query task queue.  (The queue is initialized
     // and the first task placed on it by the Query constructor.)
     // and the first task placed on it by the Query constructor.)
-    m.clearHeaderFlag(MessageFlag::AA());
+    m.setHeaderFlag(Message::HEADERFLAG_AA, false);
     while (!q.tasks().empty()) {
     while (!q.tasks().empty()) {
         QueryTaskPtr task = q.tasks().front();
         QueryTaskPtr task = q.tasks().front();
         q.tasks().pop();
         q.tasks().pop();
@@ -982,19 +982,19 @@ DataSrc::doQuery(Query& q) {
             // The qname node contains an out-of-zone referral.
             // The qname node contains an out-of-zone referral.
             if (task->state == QueryTask::GETANSWER) {
             if (task->state == QueryTask::GETANSWER) {
                 RRsetList auth;
                 RRsetList auth;
-                m.clearHeaderFlag(MessageFlag::AA());
+                m.setHeaderFlag(Message::HEADERFLAG_AA, false);
                 if (!refQuery(q, task->qname, zoneinfo, auth)) {
                 if (!refQuery(q, task->qname, zoneinfo, auth)) {
                     m.setRcode(Rcode::SERVFAIL());
                     m.setRcode(Rcode::SERVFAIL());
                     return;
                     return;
                 }
                 }
                 BOOST_FOREACH (RRsetPtr rrset, auth) {
                 BOOST_FOREACH (RRsetPtr rrset, auth) {
                     if (rrset->getType() == RRType::NS()) {
                     if (rrset->getType() == RRType::NS()) {
-                        addToMessage(q, Section::AUTHORITY(), rrset);
+                        addToMessage(q, Message::SECTION_AUTHORITY, rrset);
                     } else if (rrset->getType() == task->qtype) {
                     } else if (rrset->getType() == task->qtype) {
-                        addToMessage(q, Section::ANSWER(), rrset);
+                        addToMessage(q, Message::SECTION_ANSWER, rrset);
                     } else if (rrset->getType() == RRType::DS() &&
                     } else if (rrset->getType() == RRType::DS() &&
                                q.wantDnssec()) {
                                q.wantDnssec()) {
-                        addToMessage(q, Section::AUTHORITY(), rrset);
+                        addToMessage(q, Message::SECTION_AUTHORITY, rrset);
                     }
                     }
                     getAdditional(q, rrset);
                     getAdditional(q, rrset);
                 }
                 }
@@ -1063,13 +1063,14 @@ DataSrc::doQuery(Query& q) {
     // space, signatures in additional section are
     // space, signatures in additional section are
     // optional.)
     // optional.)
     BOOST_FOREACH(RRsetPtr rrset, additional) {
     BOOST_FOREACH(RRsetPtr rrset, additional) {
-        addToMessage(q, Section::ADDITIONAL(), rrset, true);
+        addToMessage(q, Message::SECTION_ADDITIONAL, rrset, true);
     }
     }
 
 
     if (q.wantDnssec()) {
     if (q.wantDnssec()) {
         BOOST_FOREACH(RRsetPtr rrset, additional) {
         BOOST_FOREACH(RRsetPtr rrset, additional) {
             if (rrset->getRRsig()) {
             if (rrset->getRRsig()) {
-                addToMessage(q, Section::ADDITIONAL(), rrset->getRRsig(), true);
+                addToMessage(q, Message::SECTION_ADDITIONAL, rrset->getRRsig(),
+                             true);
             }
             }
         }
         }
     }
     }
@@ -1243,72 +1244,65 @@ Nsec3Param::getHash(const Name& name) const {
     return (encodeBase32Hex(vector<uint8_t>(digest, digest + SHA1_HASHSIZE)));
     return (encodeBase32Hex(vector<uint8_t>(digest, digest + SHA1_HASHSIZE)));
 }
 }
 
 
-//
-// The following methods are effectively empty, and their parameters are
-// unused.  To silence compilers that warn unused function parameters,
-// we specify a (compiler dependent) special keyword when available.
-// It's defined in config.h, and to avoid including this header file from
-// installed files we define the methods here.
-//
 DataSrc::Result
 DataSrc::Result
-DataSrc::init(isc::data::ConstElementPtr config UNUSED_PARAM) {
+DataSrc::init(isc::data::ConstElementPtr) {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-MetaDataSrc::findRRset(const isc::dns::Name& qname UNUSED_PARAM,
+MetaDataSrc::findRRset(const isc::dns::Name&,
-                       const isc::dns::RRClass& qclass UNUSED_PARAM,
+                       const isc::dns::RRClass&,
-                       const isc::dns::RRType& qtype UNUSED_PARAM,
+                       const isc::dns::RRType&,
-                       isc::dns::RRsetList& target UNUSED_PARAM,
+                       isc::dns::RRsetList&,
-                       uint32_t& flags UNUSED_PARAM,
+                       uint32_t&,
-                       const isc::dns::Name* zonename UNUSED_PARAM) const
+                       const isc::dns::Name*) const
 {
 {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-MetaDataSrc::findExactRRset(const isc::dns::Name& qname UNUSED_PARAM,
+MetaDataSrc::findExactRRset(const isc::dns::Name&,
-                            const isc::dns::RRClass& qclass UNUSED_PARAM,
+                            const isc::dns::RRClass&,
-                            const isc::dns::RRType& qtype UNUSED_PARAM,
+                            const isc::dns::RRType&,
-                            isc::dns::RRsetList& target UNUSED_PARAM,
+                            isc::dns::RRsetList&,
-                            uint32_t& flags UNUSED_PARAM,
+                            uint32_t&,
-                            const isc::dns::Name* zonename UNUSED_PARAM) const
+                            const isc::dns::Name*) const
 {
 {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-MetaDataSrc::findAddrs(const isc::dns::Name& qname UNUSED_PARAM,
+MetaDataSrc::findAddrs(const isc::dns::Name&,
-                       const isc::dns::RRClass& qclass UNUSED_PARAM,
+                       const isc::dns::RRClass&,
-                       isc::dns::RRsetList& target UNUSED_PARAM,
+                       isc::dns::RRsetList&,
-                       uint32_t& flags UNUSED_PARAM,
+                       uint32_t&,
-                       const isc::dns::Name* zonename UNUSED_PARAM) const
+                       const isc::dns::Name*) const
 {
 {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-MetaDataSrc::findReferral(const isc::dns::Name& qname UNUSED_PARAM,
+MetaDataSrc::findReferral(const isc::dns::Name&,
-                          const isc::dns::RRClass& qclass UNUSED_PARAM,
+                          const isc::dns::RRClass&,
-                          isc::dns::RRsetList& target UNUSED_PARAM,
+                          isc::dns::RRsetList&,
-                          uint32_t& flags UNUSED_PARAM,
+                          uint32_t&,
-                          const isc::dns::Name* zonename UNUSED_PARAM) const
+                          const isc::dns::Name*) const
 {
 {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-MetaDataSrc::findPreviousName(const isc::dns::Name& qname UNUSED_PARAM,
+MetaDataSrc::findPreviousName(const isc::dns::Name&,
-                              isc::dns::Name& target UNUSED_PARAM,
+                              isc::dns::Name&,
-                              const isc::dns::Name* zonename UNUSED_PARAM) const
+                              const isc::dns::Name*) const
 {
 {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-MetaDataSrc::findCoveringNSEC3(const isc::dns::Name& zonename UNUSED_PARAM,
+MetaDataSrc::findCoveringNSEC3(const isc::dns::Name&,
-                               std::string& hash UNUSED_PARAM,
+                               std::string&,
-                               isc::dns::RRsetList& target UNUSED_PARAM) const
+                               isc::dns::RRsetList&) const
 {
 {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }

+ 13 - 9
src/lib/datasrc/query.cc

@@ -29,27 +29,31 @@ namespace isc {
 namespace datasrc {
 namespace datasrc {
 
 
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
-                     const isc::dns::RRType& t, const isc::dns::Section& sect) :
+                     const isc::dns::RRType& t,
+                     const isc::dns::Message::Section sect) :
     q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect),
     q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect),
     op(AUTH_QUERY), state(GETANSWER), flags(0)
     op(AUTH_QUERY), state(GETANSWER), flags(0)
 {}
 {}
 
 
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, 
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, 
-                     const isc::dns::RRType& t, const isc::dns::Section& sect,
+                     const isc::dns::RRType& t,
+                     const isc::dns::Message::Section sect,
                      const Op o) :
                      const Op o) :
     q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect), op(o),
     q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect), op(o),
     state(GETANSWER), flags(0)
     state(GETANSWER), flags(0)
 {}
 {}
 
 
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
-                     const isc::dns::RRType& t, const isc::dns::Section& sect,
+                     const isc::dns::RRType& t,
+                     const isc::dns::Message::Section sect,
                      const State st) :
                      const State st) :
     q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect),
     q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect),
     op(AUTH_QUERY), state(st), flags(0)
     op(AUTH_QUERY), state(st), flags(0)
 {}
 {}
 
 
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
-                     const isc::dns::RRType& t, const isc::dns::Section& sect,
+                     const isc::dns::RRType& t,
+                     const isc::dns::Message::Section sect,
                      const Op o, const State st) :
                      const Op o, const State st) :
     q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect), op(o),
     q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect), op(o),
     state(st), flags(0) 
     state(st), flags(0) 
@@ -58,7 +62,7 @@ QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, 
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, 
                      const isc::dns::RRType& t, const Op o) :
                      const isc::dns::RRType& t, const Op o) :
     q(qry), qname(n), qclass(qry.qclass()), qtype(t),
     q(qry), qname(n), qclass(qry.qclass()), qtype(t),
-    section(Section::ANSWER()), op(o), state(GETANSWER), flags(0)
+    section(Message::SECTION_ANSWER), op(o), state(GETANSWER), flags(0)
 {
 {
     if (op != SIMPLE_QUERY) {
     if (op != SIMPLE_QUERY) {
         isc_throw(Unexpected, "invalid constructor for this task operation");
         isc_throw(Unexpected, "invalid constructor for this task operation");
@@ -68,7 +72,7 @@ QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
 // A referral query doesn't need to specify section, state, or type.
 // A referral query doesn't need to specify section, state, or type.
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, const Op o) :
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, const Op o) :
     q(qry), qname(n), qclass(qry.qclass()), qtype(RRType::ANY()),
     q(qry), qname(n), qclass(qry.qclass()), qtype(RRType::ANY()),
-    section(Section::ANSWER()), op(o), state(GETANSWER), flags(0)
+    section(Message::SECTION_ANSWER), op(o), state(GETANSWER), flags(0)
 {
 {
     if (op != REF_QUERY) {
     if (op != REF_QUERY) {
         isc_throw(Unexpected, "invalid constructor for this task operation");
         isc_throw(Unexpected, "invalid constructor for this task operation");
@@ -76,7 +80,7 @@ QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, const Op o) :
 }
 }
 
 
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
 QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
-                     const isc::dns::Section& sect, const Op o,
+                     const isc::dns::Message::Section sect, const Op o,
                      const State st) :
                      const State st) :
         q(qry), qname(n), qclass(qry.qclass()), qtype(RRType::ANY()),
         q(qry), qname(n), qclass(qry.qclass()), qtype(RRType::ANY()),
         section(sect), op(o), state(st), flags(0)
         section(sect), op(o), state(st), flags(0)
@@ -93,7 +97,7 @@ Query::Query(Message& m, HotCache& c, bool dnssec) :
     cache_(&c), message_(&m), want_additional_(true), want_dnssec_(dnssec)
     cache_(&c), message_(&m), want_additional_(true), want_dnssec_(dnssec)
 {
 {
     // Check message formatting
     // Check message formatting
-    if (message_->getRRCount(Section::QUESTION()) != 1) {
+    if (message_->getRRCount(Message::SECTION_QUESTION) != 1) {
         isc_throw(Unexpected, "malformed message: too many questions");
         isc_throw(Unexpected, "malformed message: too many questions");
     }
     }
 
 
@@ -105,7 +109,7 @@ Query::Query(Message& m, HotCache& c, bool dnssec) :
     restarts_ = 0;
     restarts_ = 0;
 
 
     querytasks_.push(QueryTaskPtr(new QueryTask(*this, *qname_, *qtype_,
     querytasks_.push(QueryTaskPtr(new QueryTask(*this, *qname_, *qtype_,
-                                                Section::ANSWER())));
+                                                Message::SECTION_ANSWER)));
 }
 }
 
 
 Query::~Query() {}
 Query::~Query() {}

+ 10 - 6
src/lib/datasrc/query.h

@@ -57,7 +57,7 @@ public:
 
 
     // The section of the reply into which the data should be
     // The section of the reply into which the data should be
     // written after it has been fetched from the data source.
     // written after it has been fetched from the data source.
-    const isc::dns::Section section;
+    const isc::dns::Message::Section section;
 
 
     // The op field indicates the operation to be carried out by
     // The op field indicates the operation to be carried out by
     // this query task:
     // this query task:
@@ -127,14 +127,18 @@ public:
 
 
     // Constructors
     // Constructors
     QueryTask(const Query& q, const isc::dns::Name& n,
     QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t, const isc::dns::Section& sect);
+              const isc::dns::RRType& t,
+              const isc::dns::Message::Section sect);
     QueryTask(const Query& q, const isc::dns::Name& n,
     QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t, const isc::dns::Section& sect, Op o);
+              const isc::dns::RRType& t,
+              const isc::dns::Message::Section sect, Op o);
     QueryTask(const Query& q, const isc::dns::Name& n,
     QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t, const isc::dns::Section& sect,
+              const isc::dns::RRType& t,
+              const isc::dns::Message::Section sect,
               const State st);
               const State st);
     QueryTask(const Query& q, const isc::dns::Name& n,
     QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t, const isc::dns::Section& sect,
+              const isc::dns::RRType& t,
+              const isc::dns::Message::Section sect,
               Op o, State st);
               Op o, State st);
 
 
     // These are special constructors for particular query task types,
     // These are special constructors for particular query task types,
@@ -147,7 +151,7 @@ public:
     QueryTask(const Query& q, const isc::dns::Name& n, Op o);
     QueryTask(const Query& q, const isc::dns::Name& n, Op o);
     // A glue (or noglue) query doesn't need to specify type.
     // A glue (or noglue) query doesn't need to specify type.
     QueryTask(const Query& q, const isc::dns::Name& n,
     QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::Section& sect, Op o, State st);
+              const isc::dns::Message::Section sect, Op o, State st);
 
 
     ~QueryTask();
     ~QueryTask();
 };
 };

+ 5 - 13
src/lib/datasrc/static_datasrc.cc

@@ -110,14 +110,12 @@ StaticDataSrcImpl::StaticDataSrcImpl() :
                                "0 28800 7200 604800 86400"));
                                "0 28800 7200 604800 86400"));
 }
 }
 
 
-StaticDataSrc::StaticDataSrc()
+StaticDataSrc::StaticDataSrc() {
-{
     setClass(RRClass::CH());
     setClass(RRClass::CH());
     impl_ = new StaticDataSrcImpl;
     impl_ = new StaticDataSrcImpl;
 }
 }
 
 
-StaticDataSrc::~StaticDataSrc()
+StaticDataSrc::~StaticDataSrc() {
-{
     delete impl_;
     delete impl_;
 }
 }
 
 
@@ -237,18 +235,12 @@ StaticDataSrc::findExactRRset(const Name& qname,
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-StaticDataSrc::findPreviousName(const Name& qname UNUSED_PARAM,
+StaticDataSrc::findPreviousName(const Name&, Name&, const Name*) const {
-                                Name& target UNUSED_PARAM,
-                                const Name* zonename UNUSED_PARAM) const
-{
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-StaticDataSrc::findCoveringNSEC3(const Name& zonename UNUSED_PARAM,
+StaticDataSrc::findCoveringNSEC3(const Name&, string&, RRsetList&) const {
-                                 string& hash UNUSED_PARAM,
-                                 RRsetList& target UNUSED_PARAM) const
-{
    return (NOT_IMPLEMENTED);
    return (NOT_IMPLEMENTED);
 }
 }
 
 
@@ -260,7 +252,7 @@ StaticDataSrc::init() {
 // Static data source is "configuration less", so the \c config parameter
 // Static data source is "configuration less", so the \c config parameter
 // is intentionally ignored.
 // is intentionally ignored.
 DataSrc::Result
 DataSrc::Result
-StaticDataSrc::init(isc::data::ConstElementPtr config UNUSED_PARAM) {
+StaticDataSrc::init(isc::data::ConstElementPtr) {
     return (init());
     return (init());
 }
 }
 
 

+ 3 - 0
src/lib/datasrc/tests/Makefile.am

@@ -1,5 +1,7 @@
 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/lib/dns -I$(top_srcdir)/src/lib/dns
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += $(SQLITE_CFLAGS)
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -22,6 +24,7 @@ run_unittests_SOURCES += static_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += cache_unittest.cc
 run_unittests_SOURCES += cache_unittest.cc
 run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
 run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
+run_unittests_SOURCES += zonetable_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 = $(GTEST_LDADD)
 run_unittests_LDADD = $(GTEST_LDADD)

+ 0 - 0
src/lib/datasrc/tests/datasrc_unittest.cc


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