Parcourir la source

[1687]Merge branch 'master' into trac1687

removed the conflicting generated files
Jeremy C. Reed il y a 12 ans
Parent
commit
4cae76215b
100 fichiers modifiés avec 2903 ajouts et 1813 suppressions
  1. 1 0
      .gitignore
  2. 132 15
      ChangeLog
  3. 16 3
      configure.ac
  4. 1 1
      dns++.pc.in
  5. 5 3
      doc/devel/02-dhcp.dox
  6. 418 271
      doc/guide/bind10-guide.xml
  7. 1 1
      src/bin/Makefile.am
  8. 13 13
      src/bin/auth/Makefile.am
  9. 2 7
      src/bin/auth/auth.spec.pre.in
  10. 1 34
      src/bin/auth/auth_config.cc
  11. 1 43
      src/bin/auth/auth_messages.mes
  12. 2 38
      src/bin/auth/auth_srv.cc
  13. 6 50
      src/bin/auth/auth_srv.h
  14. 14 14
      src/bin/auth/benchmarks/Makefile.am
  15. 65 49
      src/bin/auth/benchmarks/query_bench.cc
  16. 34 18
      src/bin/auth/command.cc
  17. 0 14
      src/bin/auth/main.cc
  18. 8 12
      src/bin/auth/query.cc
  19. 4 8
      src/bin/auth/query.h
  20. 16 65
      src/bin/auth/statistics.cc
  21. 7 37
      src/bin/auth/statistics.h
  22. 14 14
      src/bin/auth/tests/Makefile.am
  23. 0 2
      src/bin/auth/tests/auth_srv_unittest.cc
  24. 9 12
      src/bin/auth/tests/command_unittest.cc
  25. 18 54
      src/bin/auth/tests/config_unittest.cc
  26. 28 32
      src/bin/auth/tests/query_unittest.cc
  27. 21 74
      src/bin/auth/tests/statistics_unittest.cc
  28. 4 9
      src/bin/bind10/bind10.xml
  29. 6 24
      src/bin/bind10/bind10_src.py.in
  30. 0 5
      src/bin/bind10/bob.spec
  31. 6 18
      src/bin/bind10/tests/bind10_test.py.in
  32. 2 1
      src/bin/cfgmgr/Makefile.am
  33. 1 1
      src/bin/cfgmgr/plugins/Makefile.am
  34. 8 0
      src/bin/cfgmgr/plugins/datasrc.spec.pre.in
  35. 5 4
      src/bin/ddns/ddns.spec
  36. 6 6
      src/bin/dhcp4/Makefile.am
  37. 1 1
      src/bin/dhcp4/ctrl_dhcp4_srv.cc
  38. 12 7
      src/bin/dhcp4/dhcp4_srv.cc
  39. 35 14
      src/bin/dhcp4/main.cc
  40. 7 7
      src/bin/dhcp4/tests/Makefile.am
  41. 3 3
      src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
  42. 40 5
      src/bin/dhcp4/tests/dhcp4_test.py
  43. 7 4
      src/bin/dhcp6/Makefile.am
  44. 159 0
      src/bin/dhcp6/ctrl_dhcp6_srv.cc
  45. 123 0
      src/bin/dhcp6/ctrl_dhcp6_srv.h
  46. 14 2
      src/bin/dhcp6/dhcp6.spec
  47. 24 16
      src/bin/dhcp6/dhcp6_srv.cc
  48. 3 1
      src/bin/dhcp6/dhcp6_srv.h
  49. 56 49
      src/bin/dhcp6/main.cc
  50. 8 5
      src/bin/dhcp6/tests/Makefile.am
  51. 85 0
      src/bin/dhcp6/tests/ctrl_dhcp6_srv_unittest.cc
  52. 39 5
      src/bin/dhcp6/tests/dhcp6_test.py
  53. 3 3
      src/bin/host/Makefile.am
  54. 0 4
      src/bin/loadzone/Makefile.am
  55. 1 0
      src/bin/loadzone/tests/correct/Makefile.am
  56. 8 0
      src/bin/loadzone/tests/correct/comment.db
  57. 4 0
      src/bin/loadzone/tests/correct/correct_test.sh.in
  58. 1 1
      src/bin/loadzone/tests/correct/get_zonedatas.py
  59. 6 0
      src/bin/loadzone/tests/correct/known.test.out
  60. 14 14
      src/bin/resolver/Makefile.am
  61. 17 31
      src/bin/resolver/resolver.spec.pre.in
  62. 16 16
      src/bin/resolver/tests/Makefile.am
  63. 0 2
      src/bin/showtech/.gitignore
  64. 2 2
      src/bin/sockcreator/Makefile.am
  65. 1 1
      src/bin/sockcreator/tests/Makefile.am
  66. 25 18
      src/bin/stats/b10-stats.xml
  67. 326 142
      src/bin/stats/stats.py.in
  68. 7 29
      src/bin/stats/stats.spec
  69. 7 3
      src/bin/stats/stats_messages.mes
  70. 3 1
      src/bin/stats/tests/Makefile.am
  71. 7 1
      src/bin/stats/tests/b10-stats-httpd_test.py
  72. 617 274
      src/bin/stats/tests/b10-stats_test.py
  73. 142 30
      src/bin/stats/tests/test_utils.py
  74. 1 0
      src/bin/stats/tests/testdata/Makefile.am
  75. 14 0
      src/bin/stats/tests/testdata/b10-config.db
  76. 2 0
      src/bin/sysinfo/.gitignore
  77. 5 5
      src/bin/showtech/Makefile.am
  78. 6 6
      src/bin/showtech/b10-showtech.xml
  79. 39 30
      src/bin/showtech/showtech.py.in
  80. 4 2
      src/bin/xfrout/xfrout.spec.pre.in
  81. 13 13
      src/lib/acl/Makefile.am
  82. 7 7
      src/lib/acl/tests/Makefile.am
  83. 17 17
      src/lib/asiodns/Makefile.am
  84. 6 6
      src/lib/asiodns/tests/Makefile.am
  85. 23 23
      src/lib/asiolink/Makefile.am
  86. 3 3
      src/lib/asiolink/tests/Makefile.am
  87. 2 2
      src/lib/bench/Makefile.am
  88. 1 1
      src/lib/bench/example/Makefile.am
  89. 4 4
      src/lib/bench/tests/Makefile.am
  90. 12 12
      src/lib/cache/Makefile.am
  91. 5 8
      src/lib/cache/message_entry.cc
  92. 1 3
      src/lib/cache/message_entry.h
  93. 7 7
      src/lib/cache/tests/Makefile.am
  94. 5 5
      src/lib/cc/Makefile.am
  95. 3 3
      src/lib/cc/tests/Makefile.am
  96. 9 9
      src/lib/config/Makefile.am
  97. 4 4
      src/lib/config/tests/Makefile.am
  98. 9 0
      src/lib/config/tests/module_spec_unittests.cc
  99. 3 0
      src/lib/config/tests/testdata/Makefile.am
  100. 0 0
      src/lib/config/tests/testdata/data41_1.data

+ 1 - 0
.gitignore

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

+ 132 - 15
ChangeLog

@@ -1,4 +1,117 @@
-456.	[build]*	muks
+471.    [bug]       vorner
+	Fixed a problem when b10-loadzone tried to tread semicolon in string data
+	as start of comment, which caused invalid data being loaded.
+	(Trac #2188, git 12efec3477feb62d7cbe36bdcfbfc7aa28a36f57)
+
+470.	[func]		naokikambe
+	The stats module now supports partial statistics updates. Each
+	module can return only statistics data which have been updated since
+	the last time it sent them to the stats module. The purpose of partial
+	updates is to reduce the amount of statistics data sent through the
+	message queue.
+	(Trac #2179, git d659abdd9f3f369a29830831297f64484ac7b051)
+
+469.	[bug]		jelte
+	libdatasrc: the data source client list class now ignores zone
+	content problems (such as out-of-zone data) in MasterFiles type
+	zones, instead of aborting the entire configuration.  It only logs
+	an error, and all other zones and datasources are still loaded. The
+	error log message has been improved to include the zone origin and
+	source file name.  As a result of this change, b10-auth no longer
+	exits upon encountering such errors during startup.
+	(Trac #2178, git a75ed413e8a1c8e3702beea4811a46a1bf519bbd)
+
+468.	[func]*		naokikambe, fujiwara
+	b10-stats polls the bind10 and b10-auth with new 'getstats' command
+	to retrieve statistics data.  The "poll-interval" parameter in
+	b10-stats is for configuring the polling interval.  All statistics
+	data collected once are preserved while b10-stats is running.
+	The "sendstats" command was removed from bind10 and b10-auth. The
+	"statistics-interval" configuration item was removed from b10-auth.
+	(Trac #2136, git dcb5ce50b4b4e50d28247d5f8b5cb8d90bda942a)
+	(Trac #2137, git d53bb65a43f6027b15a6edc08c137951e3ce5e0e)
+	(Trac #2138, git b34e3313460eebc9c272ca8c1beb27297c195150)
+
+bind10-devel-20120816 released on August 16, 2012
+
+467.	[bug]		jelte
+	For configurations, allow named sets to contain lists of items.
+	(Trac #2114, git 712637513505f7afb8434292ca2a98c3517dffd3)
+
+466.	[func]		jelte
+	Allow bindctl to add and remove items to and from lists
+	and dicts for items of type "any". This is for easier
+	configurations.
+	(Trac #2184, git ad2d728d1496a9ff59d622077850eed0638b54eb)
+
+465.	[doc]		vorner
+	Improved documentation about ACLs in the Guide.
+	(Trac #2066, git 76f733925b3f3560cfc2ee96d2a19905b623bfc3)
+
+464.	[func]		jelte, muks
+	libdns++: The LabelSequence class has been extended with some new
+	methods.  These are mainly intended for internal development, but
+	the class is public, so interested users may want to look into the
+	extensions.
+	(Trac #2052, git 57c61f2^..dbef0e2)
+	(Trac #2053, git 1fc2b06b57a008ec602daa2dac79939b3cc6b65d)
+	(Trac #2086, git 3fac7d5579c5f51b8e952b50db510b45bfa986f3)
+	(Trac #2087, git 49ad6346f574d00cfbd1d12905915fd0dd6a0bac)
+	(Trac #2148, git 285c2845ca96e7ef89f9158f1dea8cda147b6566)
+
+463.	[func]		jinmei
+	Python isc.dns: the Name, RRType and RRClass classes are now
+	hashable.  So, for example, objects of these classes can be used
+	as a dictionary key.
+	(Trac #1883, git 93ec40dd0a1df963c676037cc60c066c748b3030)
+
+462.	[build]		jreed
+	BIND 10 now compiles against googletest-1.6.0 versions that are
+	installed on the system as source code. For such versions, use the
+	--with-gtest-source configure switch.
+	(Trac #1999, git 6a26d459a40d7eed8ebcff01835377b3394a78de)
+
+461.	[bug]		muks
+	We now set g+w and g+s permissions (mode 02770) during
+	installation for the BIND 10 local state directory
+	($prefix/var/bind10-devel/) so that permissions to files
+	and sub-directories created in that directory are inherited.
+	(Trac #2171, git ab4d20907abdb3ce972172463dcc73405b3dee79)
+
+460.	[bug]		muks
+	SSHFP's algorithm and fingerprint type checks have been relaxed
+	such that they will accept any values in [0,255]. This is so that
+	future algorithm and fingerprint types are accomodated.
+	(Trac #2124, git 49e6644811a7ad09e1326f20dd73ab43116dfd21)
+
+459.	[func]		tomek
+	b10-dhcp6: DHCPv6 server component is now integrated into
+	BIND 10 framework. It can be started from BIND 10 (using bindctl)
+	and can receive commands. The only supported command for now
+	is 'Dhcp6 shutdown'.
+	b10-dhcp4: Command line-switch '-s' to disable msgq was added.
+	b10-dhcp6: Command line-switch '-s' to disable msgq was added.
+	(Trac #1708, git e0d7c52a71414f4de1361b09d3c70431c96daa3f)
+
+458.	[build]*		jinmei
+	BIND 10 now relies on Boost offset_ptr, which caused some new
+	portability issues.  Such issues are detected at ./configure time.
+	If ./configure stops due to this, try the following workaround:
+	- If it's about the use of mutable for a reference with clang++,
+	  upgrade Boost version to 1.44 or higher, or try a different
+	  compiler (e.g. g++ generally seems to be free from this issue)
+	- If it's about the use of "variadic templates", specify
+	  --without-werror so the warning won't be promoted to an error.
+	  Specifying BOOST_NO_USER_CONFIG in CXXFLAGS may also work
+	  (which would be the case if Boost is installed via pkgsrc)
+	(Trac #2147, git 30061d1139aad8716e97d6b620c259752fd0a3cd)
+
+457.	[build]*		muks
+	BIND 10 library names now have a "b10-" prefix. This is to avoid
+	clashes with other similarly named libraries on the system.
+	(Trac #2071, git ac20a00c28069804edc0a36050995df52f601efb)
+
+456.	[build]		muks
 	BIND 10 now compiles against log4cplus-1.1.0 (RC releases)
 	also.  Note: some older versions of log4cplus don't work any more;
 	known oldest workable version is 1.0.4.  Thanks to John Lumby for
@@ -9,7 +122,8 @@
 	The server now uses newer API for data sources. This would be an
 	internal change, however, the data sources are now configured
 	differently. Please, migrate your configuration to the top-level
-	"data_sources" module.
+	"data_sources" module.  Also the bind10 -n and --no-cache
+	and b10-auth -n options are removed.
 	(Trac #1976, git 0d4685b3e7603585afde1b587cbfefdfaf6a1bb3)
 
 454.	[bug]		jelte
@@ -26,11 +140,14 @@
 	NOTIMP instead of SERVFAIL.
 	(Trac #1986, git bd6b0a5ed3481f78fb4e5cb0b18c7b6e5920f9f8)
 
-452.	[func]*		muks
-	b10-showtech: An initial implementation of the b10-showtech tool
-	is now available. It gathers and outputs system information which
-	can be used by future tech support staff.
-	(Trac #2062, git 144e80212746f8d55e6a59edcf689fec9f32ae95)
+452.	[func]		muks, jelte
+	isc-sysinfo: An initial implementation of the isc-sysinfo
+	tool is now available for Linux, OpenBSD, FreeBSD, and Mac
+	OS X. It gathers and outputs system information which can
+	be used by future tech support staff. This includes a
+	generic Python "sysinfo" module.
+	(Trac #2062, #2121, #2122, #2172,
+	git 144e80212746f8d55e6a59edcf689fec9f32ae95)
 
 451.	[bug]		muks, jinmei
 	libdatasrc: the database-based data source now correctly returns
@@ -40,14 +157,14 @@
 	"glue"; it's the caller's responsibility.)
 	(Trac #1771, git 483f1075942965f0340291e7ff7dae7806df22af)
 
-450.	[func]*		tomek
+450.	[func]		tomek
 	b10-dhcp4: DHCPv4 server component is now integrated into
-	BIND10 framework. It can be started from BIND10 (using bindctl)
+	BIND 10 framework. It can be started from BIND 10 (using bindctl)
 	and can receive commands. The only supported command for now
 	is 'Dhcp4 shutdown'.
 	(Trac #1651, git 7e16a5a50d3311e63d10a224ec6ebcab5f25f62c)
 
-bind10-devel-20120621 released on June 21. 2012
+bind10-devel-20120621 released on June 21, 2012
 
 449.	[bug]		muks
 	b10-xfin: fixed a bug where xfrin sent the wrong notification
@@ -108,7 +225,7 @@ bind10-devel-20120621 released on June 21. 2012
 	file) was removed.
 	(Trac #1281, git 900fc8b420789a8c636bcf20fdaffc60bc1041e0)
 
-bind10-devel-20120517 released on May 17. 2012
+bind10-devel-20120517 released on May 17, 2012
 
 440.	[func]		muks
 	bindctl: improved some error messages so they will be more
@@ -687,7 +804,7 @@ bind10-devel-20120119 released on January 19, 2012
 	(Trac #1430, git b35797ba1a49c78246abc8f2387901f9690b328d)
 
 356.	[doc]		tomek
-	BIND10 Guide updated. It now describes DHCPv4 and DHCPv6
+	BIND 10 Guide updated. It now describes DHCPv4 and DHCPv6
 	components, including their overview, usage, supported standard
 	and limitations. libdhcp++ is also described.
 	(Trac #1367, git 3758ab360efe1cdf616636b76f2e0fb41f2a62a0)
@@ -1503,7 +1620,7 @@ bind10-devel-20110519 released on May 19, 2011
 	(Trac #719, git a234b20dc6617392deb8a1e00eb0eed0ff353c0a)
 
 236.	[func]		jelte
-	C++ client side of configuration now uses BIND10 logging system.
+	C++ client side of configuration now uses BIND 10 logging system.
 	It also has improved error handling when communicating with the
 	rest of the system.
 	(Trac #743, git 86632c12308c3ed099d75eb828f740c526dd7ec0)
@@ -2453,8 +2570,8 @@ bind10-devel-20100917 released on September 17, 2010
 
 86.	[func]		jerry
 	bin/zonemgr: Added zone manager module. The zone manager is one
-	of the co-operating processes of BIND10, which keeps track of
-	timers and other information necessary for BIND10 to act as a
+	of the co-operating processes of BIND 10, which keeps track of
+	timers and other information necessary for BIND 10 to act as a
 	slave. (Trac #215, svn r2737)
 
 85.	[build]*		jinmei

+ 16 - 3
configure.ac

@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.59])
-AC_INIT(bind10-devel, 20120712, bind10-dev@isc.org)
+AC_INIT(bind10-devel, 20120817, bind10-dev@isc.org)
 AC_CONFIG_SRCDIR(README)
 AM_INIT_AUTOMAKE
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])dnl be backward compatible
@@ -809,6 +809,17 @@ AC_TRY_COMPILE([
  CPPFLAGS_BOOST_THREADCONF="-DBOOST_DISABLE_THREADS=1"],
 [AC_MSG_RESULT(yes)])
 
+# Boost offset_ptr is required in one library (not optional right now), and
+# it's known it doesn't compile on some platforms, depending on boost version,
+# its local configuration, and compiler.
+AC_MSG_CHECKING([Boost offset_ptr compiles])
+AC_TRY_COMPILE([
+#include <boost/interprocess/offset_ptr.hpp>
+],,
+[AC_MSG_RESULT(yes)],
+[AC_MSG_RESULT(no)
+ AC_MSG_ERROR([Failed to compile a required header file.  Try upgrading Boost to 1.44 or higher (when using clang++) or specifying --without-werror.  See the ChangeLog entry for Trac no. 2147 for more details.])])
+
 CPPFLAGS="$CPPFLAGS_SAVES $CPPFLAGS_BOOST_THREADCONF"
 AC_SUBST(BOOST_INCLUDES)
 
@@ -1100,7 +1111,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/dhcp4/tests/Makefile
                  src/bin/resolver/Makefile
                  src/bin/resolver/tests/Makefile
-                 src/bin/showtech/Makefile
+                 src/bin/sysinfo/Makefile
                  src/bin/sockcreator/Makefile
                  src/bin/sockcreator/tests/Makefile
                  src/bin/xfrin/Makefile
@@ -1112,6 +1123,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/zonemgr/tests/Makefile
                  src/bin/stats/Makefile
                  src/bin/stats/tests/Makefile
+                 src/bin/stats/tests/testdata/Makefile
                  src/bin/usermgr/Makefile
                  src/bin/tests/Makefile
                  src/lib/Makefile
@@ -1176,6 +1188,7 @@ AC_CONFIG_FILES([Makefile
                  src/lib/datasrc/Makefile
                  src/lib/datasrc/memory/Makefile
                  src/lib/datasrc/memory/tests/Makefile
+                 src/lib/datasrc/memory/benchmarks/Makefile
                  src/lib/datasrc/tests/Makefile
                  src/lib/datasrc/tests/testdata/Makefile
                  src/lib/xfr/Makefile
@@ -1238,7 +1251,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/zonemgr/zonemgr.spec.pre
            src/bin/zonemgr/tests/zonemgr_test
            src/bin/zonemgr/run_b10-zonemgr.sh
-           src/bin/showtech/showtech.py
+           src/bin/sysinfo/sysinfo.py
            src/bin/stats/stats.py
            src/bin/stats/stats_httpd.py
            src/bin/bind10/bind10_src.py

+ 1 - 1
dns++.pc.in

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

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

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

+ 418 - 271
doc/guide/bind10-guide.xml

@@ -1302,6 +1302,232 @@ TODO
 
   </chapter>
 
+  <chapter id="common">
+    <title>Common configuration elements</title>
+
+    <para>
+      Some things are configured in the same or similar manner across
+      many modules. So we show them here in one place.
+    </para>
+
+    <section id='common-acl'>
+      <title>ACLs</title>
+
+      <para>
+        An ACL, or Access Control List, is a way to describe if a request
+        is allowed or disallowed. The principle is, there's a list of rules.
+        Each rule is a name-value mapping (a dictionary, in the JSON
+        terminology). Each rule must contain exactly one mapping called
+        "action", which describes what should happen if the rule applies.
+        There may be more mappings, calld matches, which describe the
+        conditions under which the rule applies.
+      </para>
+
+      <para>
+        When there's a query, the first rule is examined. If it matches, the
+        action in it is taken. If not, next rule is examined. If there are no
+        more rules to examine, a default action is taken.
+      </para>
+
+      <para>
+        There are three possible "action" values. The "ACCEPT" value means
+        the query is handled. If it is "REJECT", the query is not answered,
+        but a polite error message is sent back (if that makes sense in the
+        context). The "DROP" action acts like a black hole. The query is
+        not answered and no error message is sent.
+      </para>
+
+      <para>
+        If there are multiple matching conditions inside the rule, all of
+        them must be satisfied for the rule to apply. This can be used,
+        for example, to require the query to be signed by a TSIG key and
+        originate from given address.
+      </para>
+
+      <para>
+        This is encoded in form of JSON. Semi-formal description could look
+        something like this. It is described in more details below.
+<!-- FIXME: Is <screen> really the correct one?-->
+        <screen>ACL := [ RULE, RULE, ... ]
+RULE := { "action": "ACCEPT"|"REJECT"|"DROP", MATCH, MATCH, ... }
+RULE_RAW := { MATCH, MATCH, ... }
+MATCH := FROM_MATCH|KEY_MATCH|NOT_MATCH|OR_MATCH|AND_MATCH|...
+FROM_MATCH := "from": [RANGE, RANGE, RANGE, ...] | RANGE
+RANGE := "&lt;ip range&gt;"
+KEY_MATCH := "key": [KEY, KEY, KEY, ...] | KEY
+KEY := "&lt;key name&gt;"
+NOT_MATCH := "NOT": RULE_RAW
+OR_MATCH := "ANY": [ RULE_RAW, RULE_RAW, ... ]
+AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
+</screen>
+      </para>
+
+      <section>
+        <title>Matching properties</title>
+
+        <para>
+          The first thing you can check against is the source address
+          of request. The name is <varname>from</varname> and the value
+          is a string containing either a single IPv4 or IPv6 address,
+          or a range in the usual slash notation (eg. "192.0.2.0/24").
+        </para>
+
+        <para>
+          The other is TSIG key by which the message was signed. The ACL
+          contains only the name (under the name "key"), the key itself
+          must be stored in the global keyring. This property is applicable only
+          to the DNS context.
+<!-- TODO: Section for the keyring and link to it.-->
+        </para>
+
+        <para>
+          More properties to match are planned &mdash; the destination
+          address, ports, matches against the packet content.
+        </para>
+      </section>
+
+      <section>
+        <title>More complicated matches</title>
+
+        <para>
+          From time to time, you need to express something more complex
+          than just a single address or key.
+        </para>
+
+        <para>
+          You can specify a list of values instead of single value. Then
+          the property needs to match at least one of the values listed
+          &mdash; so you can say <quote>"from": ["192.0.2.0/24",
+          "2001:db8::/32"]</quote> to match any address in the ranges
+          set aside for documentation. The keys or any future properties
+          will work in a similar way.
+        </para>
+
+        <note>
+          <simpara>
+	    The list form is currently rejected due to an
+	    implementation bug.  There is a plan to fix it relatively
+	    soon, so the syntax is kept here, but note that it won't
+	    work until the bug is fixed.  To keep track of the status
+	    of the issue, see
+	    <ulink url="http://bind10.isc.org/ticket/2191">Trac #2191</ulink>.
+	    Until then, the value must be a single string.
+          </simpara>
+        </note>
+
+        <para>
+          If that is not enough, you can compose the matching conditions
+          to logical expressions. They are called "ANY", "ALL" and "NOT".
+          The "ANY" and "ALL" ones contain lists of subexpressions &mdash;
+          each subexpression is a similar dictionary, just not containing
+          the "action" element. The "NOT" contains single subexpression.
+          Their function should be obvious &mdash; "NOT" matches if and
+          only if the subexpression does not match. The "ALL" matches exactly
+          when each of the subexpressions matches and "ANY" when at least
+          one matches.
+        </para>
+      </section>
+
+      <section>
+        <title>Examples</title>
+
+        <para>
+          All the examples here is just the JSON representing the ACL,
+          nicely formatted and split across lines. They are out of any
+          surrounding context. This is similar to what you'd get from
+          <command>config show_json</command> called on the entry containing
+          the ACL.
+        </para>
+
+        <para>
+          In the first example, the ACL accepts queries from two known hosts.
+          Each host has an IP addresses (both IPv4 and IPv6) and a TSIG
+          key. Other queries are politely rejected. The last entry in the list
+          has no conditions &mdash; making it match any query.
+
+          <screen>[
+  {
+    "from": ["192.0.2.1", "2001:db8::1"],
+    "key": "first.key",
+    "action": "ACCEPT"
+  },
+  {
+    "from": ["192.0.2.2", "2001:db8::2"],
+    "key": "second.key",
+    "action": "ACCEPT"
+  },
+  {
+    "action": "REJECT"
+  }
+]</screen>
+        </para>
+
+        <para>
+          Now we show two ways to accept only the queries from private ranges.
+          This is the same as rejecting anything that is outside.
+
+          <screen>[
+  {
+    "from": [
+      "10.0.0.0/8",
+      "172.16.0.0/12",
+      "192.168.0.0/16",
+      "fc00::/7"
+    ],
+    "action": "ACCEPT"
+  },
+  {
+    "action": "REJECT"
+  }
+]</screen>
+
+          <screen>[
+  {
+    "NOT": {
+       "ANY": [
+         {"from": "10.0.0.0/8"},
+         {"from": "172.16.0.0/12"},
+         {"from": "192.168.0.0/16"},
+         {"from": "fc00::/7"}
+       ]
+    },
+    "action": "REJECT"
+  },
+  {
+    "action": "ACCEPT"
+  }
+]</screen>
+        </para>
+      </section>
+
+      <section>
+        <title>Interaction with <command>bindctl</command></title>
+
+        <para>
+          Currently, <command>bindctl</command> has hard time coping with
+          the variable nature of the ACL syntax. This technical limitation
+          makes it impossible to edit parts of the entries. You need to
+          set the whole entry at once, providing the whole JSON value.
+        </para>
+
+        <para>
+          This limitation is planned to be solved soon at least partially.
+        </para>
+
+        <para>
+          You'd do something like this to create the second example.
+          Note that the whole JSON must be on a single line.
+
+          <screen>&gt; <userinput>config add somewhere/acl</userinput>
+&gt; <userinput>config set somewhere/acl[0] { "from": [ "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "fc00::/7" ], "action": "ACCEPT" }</userinput>
+&gt; <userinput>config add somewhere/acl</userinput>
+&gt; <userinput>config set somewhere/acl[1] { "action": "REJECT" }</userinput>
+&gt; <userinput>config commit</userinput></screen>
+        </para>
+      </section>
+    </section>
+  </chapter>
+
   <chapter id="authserver">
     <title>Authoritative Server</title>
 
@@ -1407,21 +1633,6 @@ can use various data source backends.
               </simpara>
             </listitem>
           </varlistentry>
-
-          <varlistentry>
-            <term>statistics-interval</term>
-            <listitem>
-              <simpara>
-      <varname>statistics-interval</varname> is the timer interval
-      in seconds for <command>b10-auth</command> to share its
-      statistics information to
-      <citerefentry><refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-      Statistics updates can be disabled by setting this to 0.
-      The default is 60.
-              </simpara>
-            </listitem>
-          </varlistentry>
-
         </variablelist>
 
       </para>
@@ -1454,13 +1665,14 @@ can use various data source backends.
           </varlistentry>
 
           <varlistentry>
-            <term>sendstats</term>
+            <term>getstats</term>
             <listitem>
               <simpara>
-      <command>sendstats</command> tells <command>b10-auth</command>
+      <command>getstats</command> requests <command>b10-auth</command>
       to send its statistics data to
-      <citerefentry><refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-      immediately.
+      <citerefentry><refentrytitle>b10-stats</refentrytitle>
+      <manvolnum>8</manvolnum></citerefentry>
+      as a response of the command.
               </simpara>
             </listitem>
           </varlistentry>
@@ -1485,134 +1697,165 @@ can use various data source backends.
 
     </section>
 
-    <section>
+    <section id='datasrc'>
       <title>Data Source Backends</title>
 
+      <para>
+        Bind 10 has the concept of data sources. A data source is a place
+        where authoritative zone data reside and where they can be served
+        from. This can be a master file, a database or something completely
+        different.
+      </para>
+
+      <para>
+        Once a query arrives, <command>b10-auth</command> goes through a
+        configured list of data sources and finds the one containing a best
+        matching zone. From the equally good ones, the first one is taken.
+        This data source is then used to answer the query.
+      </para>
+
       <note><para>
-        For the development prototype release, <command>b10-auth</command>
-        supports a SQLite3 data source backend and in-memory data source
-        backend.
+        In the development prototype release, <command>b10-auth</command>
+        can serve data from a SQLite3 data source backend and from master
+        files.
         Upcoming versions will be able to use multiple different
         data sources, such as MySQL and Berkeley DB.
       </para></note>
 
-
       <para>
-        By default, the SQLite3 backend uses the data file located at
+        The configuration is located in data_sources/classes. Each item there
+        represents one RR class and a list used to answer queries for that
+        class. The default contains two classes. The CH class contains a static
+        data source &mdash; one that serves things like
+        <quote>AUTHORS.BIND.</quote>. The IN class contains single SQLite3
+        data source with database file located at
         <filename>/usr/local/var/bind10-devel/zone.sqlite3</filename>.
-        (The full path is what was defined at build configure time for
-        <option>--localstatedir</option>.
-        The default is <filename>/usr/local/var/</filename>.)
-	This data file location may be changed by defining the
-	<quote>database_file</quote> configuration.
       </para>
 
-      <section id="in-memory-datasource">
-	<title>In-memory Data Source</title>
-
-	<para>
-<!--	  How to configure it. -->
-	  The following commands to <command>bindctl</command>
-	  provide an example of configuring an in-memory data
-	  source containing the <quote>example.com</quote> zone
-	  with the zone file named <quote>example.com.zone</quote>:
-
-<!--
-	  <screen>&gt; <userinput> config set Auth/datasources/ [{"type": "memory", "zones": [{"origin": "example.com", "file": "example.com.zone"}]}]</userinput></screen>
--->
-
-          <screen>&gt; <userinput>config add Auth/datasources</userinput>
-&gt; <userinput>config set Auth/datasources[0]/type "<option>memory</option>"</userinput>
-&gt; <userinput>config add Auth/datasources[0]/zones</userinput>
-&gt; <userinput>config set Auth/datasources[0]/zones[0]/origin "<option>example.com</option>"</userinput>
-&gt; <userinput>config set Auth/datasources[0]/zones[0]/file "<option>example.com.zone</option>"</userinput>
-&gt; <userinput>config commit</userinput></screen>
-
-	  The authoritative server will begin serving it immediately
-	  after the zone data is loaded from the master text file.
-	</para>
-
-      </section>
-
-      <section id="in-memory-datasource-with-sqlite3-backend">
-	<title>In-memory Data Source with SQLite3 Backend</title>
-
-	<para>
-<!--	  How to configure it. -->
-	  The following commands to <command>bindctl</command>
-	  provide an example of configuring an in-memory data
-	  source containing the <quote>example.org</quote> zone
-	  with a SQLite3 backend file named <quote>example.org.sqlite3</quote>:
-
-<!--
-	  <screen>&gt; <userinput> config set Auth/datasources/ [{"type": "memory", "zones": [{"origin": "example.org", "file": "example.org.sqlite3", "filetype": "sqlite3"}]}]</userinput></screen>
--->
-
-          <screen>&gt; <userinput>config add Auth/datasources</userinput>
-&gt; <userinput>config set Auth/datasources[1]/type "<option>memory</option>"</userinput>
-&gt; <userinput>config add Auth/datasources[1]/zones</userinput>
-&gt; <userinput>config set Auth/datasources[1]/zones[0]/origin "<option>example.org</option>"</userinput>
-&gt; <userinput>config set Auth/datasources[1]/zones[0]/file "<option>example.org.sqlite3</option>"</userinput>
-&gt; <userinput>config set Auth/datasources[1]/zones[0]/filetype "<option>sqlite3</option>"</userinput>
-&gt; <userinput>config commit</userinput></screen>
-
-	  The authoritative server will begin serving it immediately
-	  after the zone data is loaded from the database file.
-	</para>
-
-      </section>
-
-      <section id="in-memory-datasource-loading">
-	<title>Reloading an In-memory Data Source</title>
-
-	<para>
-	  Use the <command>Auth loadzone</command> command in
-	  <command>bindctl</command> to reload a changed master
-	  file into memory; for example:
+      <para>
+        Each data source has several options. The first one is
+        <varname>type</varname>, which specifies the type of data source to
+        use. Valid types include the ones listed below, but bind10 uses
+        dynamically loaded modules for them, so there may be more in your
+        case. This option is mandatory.
+      </para>
 
-	  <screen>&gt; <userinput>Auth loadzone origin="example.com"</userinput>
-</screen>
+      <para>
+        Another option is <varname>params</varname>. This option is type
+        specific; it holds different data depending on the type
+        above. Also, depending on the type, it could be possible to omit it.
+      </para>
 
-	</para>
+      <para>
+        There are two options related to the so-called cache. If you enable
+        cache, zone data from the data source are loaded into memory.
+        Then, when answering a query, <command>b10-auth</command> looks
+        into the memory only instead of the data source, which speeds
+        answering up. The first option is <varname>cache-enable</varname>,
+        a boolean value turning the cache on and off (off is the default).
+        The second one, <varname>cache-zones</varname>, is a list of zone
+        origins to load into in-memory. Remember that zones in the data source
+        not listed here will not be loaded and will not be available at all.
+      </para>
 
-<!--
+      <section id='datasource-types'>
+        <title>Data source types</title>
         <para>
-          The <varname>file</varname> may be an absolute path to the
-          master zone file or it is relative to the directory BIND 10 is
-          started from.
-	</para>
--->
+          As mentioned, the type used by default is <quote>sqlite3</quote>.
+          It has single configuration option inside <varname>params</varname>
+          &mdash; <varname>database_file</varname>, which contains the path
+          to the sqlite3 file containing the data.
+        </para>
 
+        <para>
+          Another type is called <quote>MasterFiles</quote>. This one is
+          slightly special. The data are stored in RFC1034 master files.
+          Because answering directly from them would be impractical,
+          this type mandates the cache to be enabled. Also, the list of
+          zones (<varname>cache-zones</varname>) should be omitted. The
+          <varname>params</varname> is a dictionary mapping from zone
+          origins to the files they reside in.
+        </para>
       </section>
-      <section id="in-memory-datasource-disabling">
-	<title>Disabling In-memory Data Sources</title>
 
+      <section id='datasrc-examples'>
+        <title>Examples</title>
         <para>
-	By default, the memory data source is disabled; it must be
-	configured explicitly.  To disable all the in-memory zones,
-	specify a null list for <varname>Auth/datasources</varname>:
+          As this is one of the more complex configurations of Bind10,
+          we show some examples. They all assume they start with default
+          configuration.
+        </para>
 
-<!-- TODO: this assumes that Auth/datasources is for memory only -->
+        <para>
+          First, let's disable the static data source
+          (<quote>VERSION.BIND</quote> and friends). As it is the only
+          data source in the CH class, we can remove the whole class.
 
-	  <screen>&gt; <userinput>config set Auth/datasources/ []</userinput>
+          <screen>&gt; <userinput>config remove data_sources/classes CH</userinput>
 &gt; <userinput>config commit</userinput></screen>
-	</para>
+        </para>
 
-	<para>
-          The following example stops serving a specific zone:
+        <para>
+          Another one, let's say our default data source contains zones
+          <quote>example.org.</quote> and <quote>example.net.</quote>.
+          We want them to be served from memory to make the answering
+          faster.
 
-	  <screen>&gt; <userinput>config remove Auth/datasources[<option>0</option>]/zones[<option>0</option>]</userinput>
+          <screen>&gt; <userinput>config set data_sources/classes/IN[0]/cache-enable true</userinput>
+&gt; <userinput>config add data_sources/classes/IN[0]/cache-zones example.org.</userinput>
+&gt; <userinput>config add data_sources/classes/IN[0]/cache-zones example.net.</userinput>
 &gt; <userinput>config commit</userinput></screen>
 
-	  (Replace the list number(s) in
-	  <varname>datasources[<replaceable>0</replaceable>]</varname>
-	  and/or <varname>zones[<replaceable>0</replaceable>]</varname>
-	  for the relevant zone as needed.)
+          Now every time the zone in the data source is changed by the
+          operator, Bind10 needs to be told to reload it, by
+          <screen>&gt; <userinput>Auth loadzone example.org</userinput></screen>
+          You don't need to do this when the zone is modified by
+          XfrIn, it does so automatically.
+        </para>
 
-	</para>
+        <para>
+          Now, the last example is when there are master files we want to
+          serve in addition to whatever is inside the sqlite3 database.
 
+          <screen>&gt; <userinput>config add data_sources/classes/IN</userinput>
+&gt; <userinput>config set data_sources/classes/IN[1]/type MasterFiles</userinput>
+&gt; <userinput>config set data_sources/classes/IN[1]/cache-enable true</userinput>
+&gt; <userinput>config set data_sources/classes/IN[1]/params { "example.org": "/path/to/example.org", "example.com": "/path/to/example.com" }</userinput>
+&gt; <userinput>config commit</userinput></screen>
+
+          Initially, a map value has to be set, but this value may be an
+          empty map. After that, key/value pairs can be added with 'config
+          add' and keys can be removed with 'config remove'. The initial
+          value may be an empty map, but it has to be set before zones are
+          added or removed.
+
+          <screen>
+&gt; <userinput>config set data_sources/classes/IN[1]/params {}</userinput>
+&gt; <userinput>config add data_sources/classes/IN[1]/params another.example.org /path/to/another.example.org</userinput>
+&gt; <userinput>config add data_sources/classes/IN[1]/params another.example.com /path/to/another.example.com</userinput>
+&gt; <userinput>config remove data_sources/classes/IN[1]/params another.example.org</userinput>
+          </screen>
+
+          <command>bindctl</command>. To reload a zone, you the same command
+          as above.
+        </para>
       </section>
 
+      <note>
+      <para>
+        There's also <varname>Auth/database_file</varname> configuration
+        variable, pointing to a sqlite3 database file. This is no longer
+        used by <command>b10-auth</command>, but it is left in place for
+        now, since other modules use it. Once <command>b10-xfrin</command>,
+        <command>b10-xfrout</command> and <command>b10-ddns</command>
+        are ported to the new configuration, this will disappear. But for
+        now, make sure that if you use any of these modules, the new
+        and old configuration correspond. The defaults are consistent, so
+        unless you tweaked either the new or the old configuration, you're
+        good.
+      </para>
+      </note>
+
     </section>
 
     <section>
@@ -1854,7 +2097,7 @@ http://bind10.isc.org/wiki/ScalableZoneLoadDesign#a7.2UpdatingaZone
 	The administrator doesn't have to do anything for
 	<command>b10-auth</command> to serve the new version of the
 	zone, except for the configuration such as the one described in
-	<xref linkend="in-memory-datasource-with-sqlite3-backend" />.
+	<xref linkend="datasrc" />.
       </para>
     </section>
 
@@ -1883,37 +2126,17 @@ http://bind10.isc.org/wiki/ScalableZoneLoadDesign#a7.2UpdatingaZone
       can be used to control accessibility of the outbound zone
       transfer service.
       By default, <command>b10-xfrout</command> allows any clients to
-      perform zone transfers for any zones:
+      perform zone transfers for any zones.
     </para>
 
       <screen>&gt; <userinput>config show Xfrout/transfer_acl</userinput>
 Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)</screen>
 
     <para>
-      You can change this to, for example, rejecting all transfer
-      requests by default while allowing requests for the transfer
-      of zone "example.com" from 192.0.2.1 and 2001:db8::1 as follows:
-    </para>
-
-      <screen>&gt; <userinput>config set Xfrout/transfer_acl[0] {"action": "REJECT"}</userinput>
-&gt; <userinput>config add Xfrout/zone_config</userinput>
-&gt; <userinput>config set Xfrout/zone_config[0]/origin "example.com"</userinput>
-&gt; <userinput>config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1"},</userinput>
-<userinput>                                                 {"action": "ACCEPT", "from": "2001:db8::1"}]</userinput>
-&gt; <userinput>config commit</userinput></screen>
-
-    <note><simpara>
-        In the above example the lines
-        for <option>transfer_acl</option> were divided for
-        readability.  In the actual input it must be in a single line.
-    </simpara></note>
-
-    <para>
       If you want to require TSIG in access control, a system wide TSIG
       "key ring" must be configured.
-      For example, to change the previous example to allowing requests
-      from 192.0.2.1 signed by a TSIG with a key name of
-      "key.example", you'll need to do this:
+      In this example, we allow client matching both the IP address
+      and key.
     </para>
 
     <screen>&gt; <userinput>config set tsig_keys/keys ["key.example:&lt;base64-key&gt;"]</userinput>
@@ -1924,6 +2147,11 @@ Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)</screen>
       will use the system wide keyring to check
       TSIGs in the incoming messages and to sign responses.</para>
 
+    <para>
+      For further details on ACL configuration, see
+      <xref linkend="common-acl" />.
+    </para>
+
     <note><simpara>
         The way to specify zone specific configuration (ACLs, etc) is
         likely to be changed.
@@ -1965,11 +2193,11 @@ what is XfroutClient xfr_client??
       notify <command>b10-xfrout</command> so that other secondary
       servers will be notified via the DNS NOTIFY protocol.
       In addition, if <command>b10-auth</command> serves the updated
-      zone from its in-memory cache (as described in
-      <xref linkend="in-memory-datasource-with-sqlite3-backend" />),
+      zone (as described in
+      <xref linkend="datasrc" />),
       <command>b10-ddns</command> will also
       notify <command>b10-auth</command> so that <command>b10-auth</command>
-      will re-cache the updated zone content.
+      will re-cache the updated zone content if necessary.
     </para>
 
     <para>
@@ -2130,29 +2358,7 @@ what is XfroutClient xfr_client??
       </para>
 
       <para>
-        Multiple rules can be specified in the ACL, and an ACL rule
-        can consist of multiple constraints, such as a combination of
-        IP address and TSIG.
-        The following configuration sequence will add a new rule to
-        the ACL created in the above example.  This additional rule
-	allows update requests sent from a client
-        using TSIG key name of "key.example" (different from the
-        key used in the previous example) and has an IPv6 address of ::1.
-      <screen>
-&gt; <userinput>config add DDNS/zones[0]/update_acl {"action": "ACCEPT", "from": "::1", "key": "key.example"}</userinput>
-&gt; <userinput>config show DDNS/zones[0]/update_acl</userinput>
-DDNS/zones[0]/update_acl[0]     {"action": "ACCEPT", "key": "key.example.org"} any (modified)
-DDNS/zones[0]/update_acl[1]     {"action": "ACCEPT", "from": "::1", "key": "key.example"} any (modified)
-&gt; <userinput>config commit</userinput>
-</screen>
-      (Note the "add" in the first line.  Before this sequence, we
-      have had only entry in <varname>zones[0]/update_acl</varname>.
-      The <command>add</command> command with a value (rule) adds
-      a new entry and sets it to the given rule.
-
-      Due to a limitation of the current implementation, it doesn't
-      work if you first try to just add a new entry and then set it to
-      a given rule.)
+        Full description of ACLs can be found in <xref linkend="common-acl" />.
       </para>
 
       <note><simpara>
@@ -2168,21 +2374,6 @@ DDNS/zones[0]/update_acl[1]     {"action": "ACCEPT", "from": "::1", "key": "key.
       </simpara></note>
 
       <para>
-	The ACL rules will be checked in the listed order, and the
-	first matching one will apply.
-	If none of the rules matches, the default rule will apply,
-	which is rejecting any requests in the case of
-	<command>b10-ddns</command>.
-      </para>
-<!-- TODO: what are the other defaults? -->
-
-      <para>
-	Other actions than "ACCEPT", namely "REJECT" and "DROP", can be
-	used, too.
-	See <xref linkend="resolverserver"/> about their effects.
-      </para>
-
-      <para>
         Currently update ACL can only control updates per zone basis;
         it's not possible to specify access control with higher
         granularity such as for particular domain names or specific
@@ -2321,59 +2512,32 @@ DDNS/zones[0]/update_acl[1]     {"action": "ACCEPT", "from": "::1", "key": "key.
         DNS queries from the localhost (127.0.0.1 and ::1).
         The <option>Resolver/query_acl</option> configuration may
         be used to reject, drop, or allow specific IPs or networks.
-        This configuration list is first match.
-      </para>
-
-      <para>
-        The configuration's <option>action</option> item may be
-        set to <quote>ACCEPT</quote> to allow the incoming query,
-        <quote>REJECT</quote> to respond with a DNS REFUSED return
-        code, or <quote>DROP</quote> to ignore the query without
-        any response (such as a blackhole).  For more information,
-        see the respective debugging messages:  <ulink
-        url="bind10-messages.html#RESOLVER_QUERY_ACCEPTED">RESOLVER_QUERY_ACCEPTED</ulink>,
-        <ulink
-        url="bind10-messages.html#RESOLVER_QUERY_REJECTED">RESOLVER_QUERY_REJECTED</ulink>,
-        and <ulink
-url="bind10-messages.html#RESOLVER_QUERY_DROPPED">RESOLVER_QUERY_DROPPED</ulink>.
-      </para>
-
-      <para>
-        The required configuration's <option>from</option> item is set
-        to an IPv4 or IPv6 address, addresses with an network mask, or to
-        the special lowercase keywords <quote>any6</quote> (for
-        any IPv6 address) or <quote>any4</quote> (for any IPv4
-        address).
+        See <xref linkend="common-acl" />.
       </para>
 
-<!-- TODO:
-/0 is for any address in that address family
-does that need any address too?
-
-TODO: tsig
--->
-
       <para>
-        For example to allow the <replaceable>192.168.1.0/24</replaceable>
-        network to use your recursive name server, at the
-        <command>bindctl</command> prompt run:
+	The following session is an example of extending the ACL to also
+	allow queries from 192.0.2.0/24:
+        <screen>
+> <userinput>config show Resolver/query_acl</userinput>
+Resolver/query_acl[0]   {"action": "ACCEPT", "from": "127.0.0.1"}   any (default)
+Resolver/query_acl[1]   {"action": "ACCEPT", "from": "::1"} any (default)
+> <userinput>config add Resolver/query_acl</userinput>
+> <userinput>config set Resolver/query_acl[2] {"action": "ACCEPT", "from": "192.0.2.0/24"}</userinput>
+> <userinput>config add Resolver/query_acl</userinput>
+> <userinput>config show Resolver/query_acl</userinput>
+Resolver/query_acl[0]   {"action": "ACCEPT", "from": "127.0.0.1"}   any (modified)
+Resolver/query_acl[1]   {"action": "ACCEPT", "from": "::1"} any (modified)
+Resolver/query_acl[2]   {"action": "ACCEPT", "from": "192.0.2.0/24"}  any (modified)
+Resolver/query_acl[3]   {"action": "REJECT"}    any (modified)
+> <userinput>config commit</userinput></screen>
+	Note that we didn't set the value of the last final rule
+	(query_acl[3]) -- in the case of resolver, rejecting all queries is
+	the default value of a new rule.  In fact, this rule can even be
+	omitted completely, as the default, when a query falls off the list,
+	is rejection.
       </para>
 
-      <screen>
-&gt; <userinput>config add Resolver/query_acl</userinput>
-&gt; <userinput>config set Resolver/query_acl[<replaceable>2</replaceable>]/action "ACCEPT"</userinput>
-&gt; <userinput>config set Resolver/query_acl[<replaceable>2</replaceable>]/from "<replaceable>192.168.1.0/24</replaceable>"</userinput>
-&gt; <userinput>config commit</userinput>
-</screen>
-
-     <simpara>(Replace the <quote><replaceable>2</replaceable></quote>
-       as needed; run <quote><userinput>config show
-       Resolver/query_acl</userinput></quote> if needed.)</simpara>
-
-<!-- TODO: check this -->
-      <note><simpara>This prototype access control configuration
-      syntax may be changed.</simpara></note>
-
     </section>
 
     <section>
@@ -2479,7 +2643,7 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
 &gt; <userinput>config commit</userinput></screen></para>
 
       <para>
-        At start, the server will detect available network interfaces
+        During start-up the server will detect available network interfaces
         and will attempt to open UDP sockets on all interfaces that
         are up, running, are not loopback, and have IPv4 address
         assigned.
@@ -2489,17 +2653,8 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
         will respond to them with OFFER and ACK, respectively.
 
         Since the DHCPv4 server opens privileged ports, it requires root
-        access. Make sure you run this daemon as root.</para>
-
-        <note>
-          <para>
-            Integration with <command>bind10</command> is
-            planned. Ultimately, <command>b10-dhcp4</command> will not
-            be started directly, but rather via
-            <command>bind10</command>. Please be aware of this planned
-            change.
-          </para>
-        </note>
+        access. Make sure you run this daemon as root.
+      </para>
 
     </section>
 
@@ -2548,7 +2703,7 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
     </section>
 
     <section id="dhcp4-limit">
-      <title>DHCPv4 Server Limitations</title> 
+      <title>DHCPv4 Server Limitations</title>
       <para>These are the current limitations of the DHCPv4 server
       software. Most of them are reflections of the early stage of
       development and should be treated as <quote>not implemented
@@ -2664,22 +2819,25 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
       </para>
 
       <para>
-        The DHCPv6 server is implemented as <command>b10-dhcp6</command>
-        daemon. As it is not configurable yet, it is fully autonomous,
-        that is it does not interact with <command>b10-cfgmgr</command>.
-        To start DHCPv6 server, simply input:
-
-        <screen>
-#<userinput>cd src/bin/dhcp6</userinput>
-#<userinput>./b10-dhcp6</userinput>
-</screen>
+        <command>b10-dhcp6</command> is a BIND10 component and is being
+        run under BIND10 framework. To add a DHCPv6 process to the set of running
+        BIND10 services, you can use following commands in <command>bindctl</command>:
+        <screen>&gt; <userinput>config add Boss/components b10-dhcp6</userinput>
+&gt; <userinput>config set Boss/components/b10-dhcp6/kind dispensable</userinput>
+&gt; <userinput>config commit</userinput></screen>
+      </para>
 
-        Depending on your installation, <command>b10-dhcp6</command>
-        binary may reside in src/bin/dhcp6 in your source code
-        directory, in /usr/local/bin/b10-dhcp6 or other directory
-        you specified during compilation.
+       <para>
+         To shutdown running <command>b10-dhcp6</command>, please use the
+         following command:
+         <screen>&gt; <userinput>Dhcp6 shutdown</userinput></screen>
+         or
+         <screen>&gt; <userinput>config remove Boss/components b10-dhcp6</userinput>
+&gt; <userinput>config commit</userinput></screen>
+       </para>
 
-        At start, server will detect available network interfaces
+      <para>
+        During start-up the server will detect available network interfaces
         and will attempt to open UDP sockets on all interfaces that
         are up, running, are not loopback, are multicast-capable, and
         have IPv6 address assigned.
@@ -2692,16 +2850,6 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
         access. Make sure you run this daemon as root.
       </para>
 
-        <note>
-          <para>
-            Integration with <command>bind10</command> is
-            planned. Ultimately, <command>b10-dhcp6</command> will not
-            be started directly, but rather via
-            <command>bind10</command>. Please be aware of this planned
-            change.
-          </para>
-        </note>
-
     </section>
 
     <section id="dhcp6-config">
@@ -2715,7 +2863,7 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
       <para>
         At this stage of development, the only way to alter server
         configuration is to tweak its source code. To do so, please
-        edit src/bin/dhcp6/dhcp6_srv.cc file and modify following
+        edit src/bin/dhcp6/dhcp6_srv.cc file, modify the following
         parameters and recompile:
         <screen>
 const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
@@ -2865,9 +3013,8 @@ const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";</screen>
     <para>
 
        This stats daemon provides commands to identify if it is
-       running, show specified or all statistics data, show specified
-       or all statistics data schema, and set specified statistics
-       data.
+       running, show specified or all statistics data, and show specified
+       or all statistics data schema.
 
        For example, using <command>bindctl</command>:
 

+ 1 - 1
src/bin/Makefile.am

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

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

@@ -67,19 +67,19 @@ b10_auth_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
 nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
 EXTRA_DIST += auth_messages.mes
 
-b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/libdatasrc.la
-b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
-b10_auth_LDADD += $(top_builddir)/src/lib/util/libutil.la
-b10_auth_LDADD += $(top_builddir)/src/lib/util/io/libutil_io.la
-b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-b10_auth_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
-b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-b10_auth_LDADD += $(top_builddir)/src/lib/log/liblog.la
-b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-b10_auth_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-b10_auth_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
+b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
+b10_auth_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
+b10_auth_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+b10_auth_LDADD += $(top_builddir)/src/lib/util/io/libb10-util-io.la
+b10_auth_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+b10_auth_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+b10_auth_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
+b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+b10_auth_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libb10-xfr.la
+b10_auth_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
+b10_auth_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
 b10_auth_LDADD += $(SQLITE_LIBS)
 
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir

+ 2 - 7
src/bin/auth/auth.spec.pre.in

@@ -56,11 +56,6 @@
           }]
         }
       },
-      { "item_name": "statistics-interval",
-        "item_type": "integer",
-        "item_optional": true,
-        "item_default": 60
-      },
       {
         "item_name": "listen_on",
         "item_type": "list",
@@ -110,8 +105,8 @@
         ]
       },
       {
-        "command_name": "sendstats",
-        "command_description": "Send data to a statistics module at once",
+        "command_name": "getstats",
+        "command_description": "Retrieve statistics data",
         "command_args": []
       },
       {

+ 1 - 34
src/bin/auth/auth_config.cc

@@ -53,37 +53,6 @@ public:
     virtual void commit() {};
 };
 
-/// A derived \c AuthConfigParser class for the "statistics-internal"
-/// configuration identifier.
-class StatisticsIntervalConfig : public AuthConfigParser {
-public:
-    StatisticsIntervalConfig(AuthSrv& server) :
-        server_(server), interval_(0)
-    {}
-    virtual void build(ConstElementPtr config_value) {
-        const int32_t config_interval = config_value->intValue();
-        if (config_interval < 0) {
-            isc_throw(AuthConfigError, "Negative statistics interval value: "
-                      << config_interval);
-        }
-        if (config_interval > 86400) {
-            isc_throw(AuthConfigError, "Statistics interval value "
-                      << config_interval
-                      << " must be equal to or shorter than 86400");
-        }
-        interval_ = config_interval;
-    }
-    virtual void commit() {
-        // setStatisticsTimerInterval() is not 100% exception free.  But
-        // exceptions should happen only in a very rare situation, so we
-        // let them be thrown and subsequently regard them as a fatal error.
-        server_.setStatisticsTimerInterval(interval_);
-    }
-private:
-    AuthSrv& server_;
-    uint32_t interval_;
-};
-
 /// A special parser for testing: it throws from commit() despite the
 /// suggested convention of the class interface.
 class ThrowerCommitConfig : public AuthConfigParser {
@@ -155,9 +124,7 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
     // simplicity.  In future we'll probably generalize it using map-like
     // data structure, and may even provide external register interface so
     // that it can be dynamically customized.
-    if (config_id == "statistics-interval") {
-        return (new StatisticsIntervalConfig(server));
-    } else if (config_id == "listen_on") {
+    if (config_id == "listen_on") {
         return (new ListenAddressConfig(server));
     } else if (config_id == "_commit_throw") {
         // This is for testing purpose only and should not appear in the

+ 1 - 43
src/bin/auth/auth_messages.mes

@@ -122,11 +122,6 @@ a NOTIFY packet that an RR type of something other than SOA in the
 question section. (The RR type received is included in the message.) The
 server will return a FORMERR error to the sender.
 
-% AUTH_NO_STATS_SESSION session interface for statistics is not available
-The authoritative server had no session with the statistics module at the
-time it attempted to send it data: the attempt has been abandoned. This
-could be an error in configuration.
-
 % AUTH_NO_XFRIN received NOTIFY but XFRIN session is not running
 This is a debug message produced by the authoritative server when it receives
 a NOTIFY packet but the XFRIN process is not running. The packet will be
@@ -169,12 +164,6 @@ a command on the command channel.
 % AUTH_RECEIVED_NOTIFY received incoming NOTIFY for zone name %1, zone class %2
 This is a debug message reporting that an incoming NOTIFY was received.
 
-% AUTH_RECEIVED_SENDSTATS command 'sendstats' received
-This is a debug message issued when the authoritative server has received
-a command from the statistics module to send it data. The 'sendstats'
-command is handled differently to other commands, which is why the debug
-message associated with it has its own code.
-
 % AUTH_RESPONSE_FAILURE exception while building response to query: %1
 This is a debug message, generated by the authoritative server when an
 attempt to create a response to a received DNS packet has failed. The
@@ -203,7 +192,7 @@ multiple lines of text. For this reason, it is suggested that this log message
 not be routed to the syslog file, where the multiple lines could confuse
 programs that expect a format of one message per line.
 
-% AUTH_SEND_NORMAL_RESPONSE sending an error response (%1 bytes):\n%2
+% AUTH_SEND_NORMAL_RESPONSE sending a normal response (%1 bytes):\n%2
 This is a debug message recording that the authoritative server is sending
 a response to the originator of a query.
 
@@ -242,37 +231,6 @@ is not running, b10-auth will respond to UPDATE requests with rcode NOTIMP.
 When b10-ddns is running, b10-ddns will handle and respond to the UPDATE
 message.
 
-% AUTH_STATS_CHANNEL_CREATED STATS session channel created
-This is a debug message indicating that the authoritative server has
-created a channel to the statistics process.  It is issued during server
-startup is an indication that the initialization is proceeding normally.
-
-% AUTH_STATS_CHANNEL_ESTABLISHED STATS session channel established
-This is a debug message indicating that the authoritative server
-has established communication over the previously created statistics
-channel.  It is issued during server startup is an indication that the
-initialization is proceeding normally.
-
-% AUTH_STATS_COMMS communication error in sending statistics data: %1
-An error was encountered when the authoritative server tried to send data
-to the statistics daemon. The message includes additional information
-describing the reason for the failure.
-
-% AUTH_STATS_TIMEOUT timeout while sending statistics data: %1
-The authoritative server sent data to the statistics daemon but received
-no acknowledgement within the specified time. The message includes
-additional information describing the reason for the failure.
-
-% AUTH_STATS_TIMER_DISABLED statistics timer has been disabled
-This is a debug message indicating that the statistics timer has been
-disabled in the authoritative server and no statistics information is
-being produced.
-
-% AUTH_STATS_TIMER_SET statistics timer set to %1 second(s)
-This is a debug message indicating that the statistics timer has been
-enabled and that the authoritative server will produce statistics data
-at the specified interval.
-
 % AUTH_STOP_DDNS_FORWARDER DDNS UPDATE handling stopped
 This is a debug message indicating that b10-auth has received a message
 that it should stop internally forwarding UPDATE message to b10-ddns.

+ 2 - 38
src/bin/auth/auth_srv.cc

@@ -247,9 +247,6 @@ public:
     ModuleCCSession* config_session_;
     AbstractSession* xfrin_session_;
 
-    /// Interval timer for periodic submission of statistics counters.
-    IntervalTimer statistics_timer_;
-
     /// Query counters for statistics
     AuthCounters counters_;
 
@@ -320,7 +317,6 @@ AuthSrvImpl::AuthSrvImpl(AbstractXfroutClient& xfrout_client,
                          BaseSocketSessionForwarder& ddns_forwarder) :
     config_session_(NULL),
     xfrin_session_(NULL),
-    statistics_timer_(io_service_),
     counters_(),
     keyring_(NULL),
     ddns_base_forwarder_(ddns_forwarder),
@@ -479,43 +475,11 @@ AuthSrv::setConfigSession(ModuleCCSession* config_session) {
     impl_->registerStatisticsValidator();
 }
 
-void
-AuthSrv::setStatisticsSession(AbstractSession* statistics_session) {
-    impl_->counters_.setStatisticsSession(statistics_session);
-}
-
 ModuleCCSession*
 AuthSrv::getConfigSession() const {
     return (impl_->config_session_);
 }
 
-uint32_t
-AuthSrv::getStatisticsTimerInterval() const {
-    return (impl_->statistics_timer_.getInterval() / 1000);
-}
-
-void
-AuthSrv::setStatisticsTimerInterval(uint32_t interval) {
-    if (interval == impl_->statistics_timer_.getInterval()) {
-        return;
-    }
-    if (interval > 86400) {
-        // It can't occur since the value is checked in
-        // statisticsIntervalConfig::build().
-        isc_throw(InvalidParameter, "Too long interval: " << interval);
-    }
-    if (interval == 0) {
-        impl_->statistics_timer_.cancel();
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_STATS_TIMER_DISABLED);
-    } else {
-        impl_->statistics_timer_.setup(boost::bind(&AuthSrv::submitStatistics,
-                                                   this),
-                                       interval * 1000);
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_STATS_TIMER_SET)
-                  .arg(interval);
-    }
-}
-
 void
 AuthSrv::processMessage(const IOMessage& io_message, Message& message,
                         OutputBuffer& buffer, DNSServer* server)
@@ -882,8 +846,8 @@ AuthSrv::updateConfig(ConstElementPtr new_config) {
     }
 }
 
-bool AuthSrv::submitStatistics() const {
-    return (impl_->counters_.submitStatistics());
+ConstElementPtr AuthSrv::getStatistics() const {
+    return (impl_->counters_.getStatistics());
 }
 
 uint64_t

+ 6 - 50
src/bin/auth/auth_srv.h

@@ -17,7 +17,6 @@
 
 #include <string>
 
-#include <cc/data.h>
 #include <config/ccsession.h>
 #include <datasrc/factory.h>
 #include <dns/message.h>
@@ -203,64 +202,21 @@ public:
     ///
     void setXfrinSession(isc::cc::AbstractSession* xfrin_session);
 
-    /// \brief Set the communication session with Statistics.
-    ///
-    /// This function never throws an exception as far as
-    /// AuthCounters::setStatisticsSession() doesn't throw.
-    ///
-    /// Note: this interface is tentative.  We'll revisit the ASIO and
-    /// session frameworks, at which point the session will probably
-    /// be passed on construction of the server.
-    ///
-    /// \param statistics_session A Session object over which statistics
-    /// information is exchanged with statistics module.
-    /// The session must be established before setting in the server
-    /// object.
-    /// Ownership isn't transferred: the caller is responsible for keeping
-    /// this object to be valid while the server object is working and for
-    /// disconnecting the session and destroying the object when the server
-    /// is shutdown.
-    void setStatisticsSession(isc::cc::AbstractSession* statistics_session);
-
-    /// Return the interval of periodic submission of statistics in seconds.
-    ///
-    /// If the statistics submission is disabled, it returns 0.
-    ///
-    /// This method never throws an exception.
-    uint32_t getStatisticsTimerInterval() const;
-
-    /// Set the interval of periodic submission of statistics.
-    ///
-    /// If the specified value is non 0, the \c AuthSrv object will submit
-    /// its statistics to the statistics module every \c interval seconds.
-    /// If it's 0, and \c AuthSrv currently submits statistics, the submission
-    /// will be disabled. \c interval must be equal to or shorter than 86400
-    /// seconds (1 day).
-    ///
-    /// This method should normally not throw an exception; however, its
-    /// underlying library routines may involve resource allocation, and
-    /// when it fails it would result in a corresponding standard exception.
-    ///
-    /// \param interval The submission interval in seconds if non 0;
-    /// or a value of 0 to disable the submission.
-    void setStatisticsTimerInterval(uint32_t interval);
-
-    /// \brief Submit statistics counters to statistics module.
+    /// \brief Returns statistics data
     ///
     /// This function can throw an exception from
-    /// AuthCounters::submitStatistics().
+    /// AuthCounters::getStatistics().
     ///
-    /// \return true on success, false on failure (e.g. session timeout,
-    /// session error).
-    bool submitStatistics() const;
+    /// \return JSON format statistics data.
+    isc::data::ConstElementPtr getStatistics() const;
 
     /// \brief Get the value of counter in the AuthCounters.
     ///
-    /// This function calls AuthCounters::getCounter() and
+    /// This function calls AuthCounters::getStatistics() and
     /// returns its return value.
     ///
     /// This function never throws an exception as far as
-    /// AuthCounters::getCounter() doesn't throw.
+    /// AuthCounters::getStatistics() doesn't throw.
     ///
     /// Note: Currently this function is for testing purpose only.
     ///

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

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

+ 65 - 49
src/bin/auth/benchmarks/query_bench.cc

@@ -14,13 +14,6 @@
 
 #include <config.h>
 
-#include <stdlib.h>
-
-#include <iostream>
-#include <vector>
-
-#include <boost/shared_ptr.hpp>
-
 #include <bench/benchmark.h>
 #include <bench/benchmark_util.h>
 
@@ -37,11 +30,19 @@
 
 #include <auth/auth_srv.h>
 #include <auth/auth_config.h>
+#include <auth/datasrc_configurator.h>
 #include <auth/query.h>
 
 #include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 
+#include <boost/shared_ptr.hpp>
+
+#include <stdlib.h>
+
+#include <iostream>
+#include <vector>
+
 using namespace std;
 using namespace isc;
 using namespace isc::data;
@@ -124,8 +125,13 @@ public:
                           OutputBuffer& buffer) :
         QueryBenchMark(queries, query_message, buffer)
     {
-        server_->updateConfig(Element::fromJSON("{\"database_file\": \"" +
-                                                string(datasrc_file) + "\"}"));
+        DataSourceConfigurator::testReconfigure(
+            server_.get(),
+            Element::fromJSON("{\"IN\":"
+                              "  [{\"type\": \"sqlite3\","
+                              "    \"params\": {"
+                              "      \"database_file\": \"" +
+                              string(datasrc_file) + "\"}}]}"));
     }
 };
 
@@ -138,14 +144,14 @@ public:
                           OutputBuffer& buffer) :
         QueryBenchMark(queries, query_message, buffer)
     {
-        configureAuthServer(*server_,
-                            Element::fromJSON(
-                                "{\"datasources\": "
-                                " [{\"type\": \"memory\","
-                                "   \"zones\": [{\"origin\": \"" +
-                                string(zone_origin) + "\","
-                                "    \"file\": \"" +
-                                string(zone_file) + "\"}]}]}"));
+        DataSourceConfigurator::testReconfigure(
+            server_.get(),
+            Element::fromJSON("{\"IN\":"
+                              "  [{\"type\": \"MasterFiles\","
+                              "    \"cache-enable\": true, "
+                              "    \"params\": {\"" +
+                              string(zone_origin) + "\": \"" +
+                              string(zone_file) + "\"}}]}"));
     }
 };
 
@@ -187,8 +193,9 @@ enum DataSrcType {
 void
 usage() {
     cerr <<
-        "Usage: query_bench [-n iterations] [-t datasrc_type] [-o origin] "
-        "datasrc_file query_datafile\n"
+        "Usage: query_bench [-d] [-n iterations] [-t datasrc_type] [-o origin]"
+        " datasrc_file query_datafile\n"
+        "  -d Enable debug logging to stdout\n"
         "  -n Number of iterations per test case (default: "
          << ITERATION_DEFAULT << ")\n"
         "  -t Type of data source: sqlite3|memory (default: sqlite3)\n"
@@ -208,7 +215,8 @@ main(int argc, char* argv[]) {
     int iteration = ITERATION_DEFAULT;
     const char* opt_datasrc_type = "sqlite3";
     const char* origin = NULL;
-    while ((ch = getopt(argc, argv, "n:t:o:")) != -1) {
+    bool debug_log = false;
+    while ((ch = getopt(argc, argv, "dn:t:o:")) != -1) {
         switch (ch) {
         case 'n':
             iteration = atoi(optarg);
@@ -219,6 +227,9 @@ main(int argc, char* argv[]) {
         case 'o':
             origin = optarg;
             break;
+        case 'd':
+            debug_log = true;
+            break;
         case '?':
         default:
             usage();
@@ -232,9 +243,9 @@ main(int argc, char* argv[]) {
     const char* const datasrc_file = argv[0];
     const char* const query_data_file = argv[1];
 
-    // We disable logging to avoid unwanted noise. (We may eventually want to
-    // make it more configurable)
-    initLogger("query-bench", isc::log::NONE);
+    // By default disable logging to avoid unwanted noise.
+    initLogger("query-bench", debug_log ? isc::log::DEBUG : isc::log::NONE,
+               isc::log::MAX_DEBUG_LEVEL, NULL);
 
     DataSrcType datasrc_type = SQLITE3;
     if (strcmp(opt_datasrc_type, "sqlite3") == 0) {
@@ -251,34 +262,39 @@ main(int argc, char* argv[]) {
         return (1);
     }
 
-    BenchQueries queries;
-    loadQueryData(query_data_file, queries, RRClass::IN());
-    OutputBuffer buffer(4096);
-    Message message(Message::PARSE);
+    try {
+        BenchQueries queries;
+        loadQueryData(query_data_file, queries, RRClass::IN());
+        OutputBuffer buffer(4096);
+        Message message(Message::PARSE);
 
-    cout << "Parameters:" << endl;
-    cout << "  Iterations: " << iteration << endl;
-    cout << "  Data Source: type=" << opt_datasrc_type << ", file=" <<
-        datasrc_file << endl;
-    if (origin != NULL) {
-        cout << "  Origin: " << origin << endl;
-    }
-    cout << "  Query data: file=" << query_data_file << " (" << queries.size()
-         << " queries)" << endl << endl;
+        cout << "Parameters:" << endl;
+        cout << "  Iterations: " << iteration << endl;
+        cout << "  Data Source: type=" << opt_datasrc_type << ", file=" <<
+            datasrc_file << endl;
+        if (origin != NULL) {
+            cout << "  Origin: " << origin << endl;
+        }
+        cout << "  Query data: file=" << query_data_file << " ("
+             << queries.size() << " queries)" << endl << endl;
 
-    switch (datasrc_type) {
-    case SQLITE3:
-        cout << "Benchmark with SQLite3" << endl;
-        BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(datasrc_file, queries,
-                                             message, buffer));
-        break;
-    case MEMORY:
-        cout << "Benchmark with In Memory Data Source" << endl;
-        BenchMark<MemoryQueryBenchMark>(
-            iteration, MemoryQueryBenchMark(datasrc_file, origin, queries,
-                                            message, buffer));
-        break;
+        switch (datasrc_type) {
+        case SQLITE3:
+            cout << "Benchmark with SQLite3" << endl;
+            BenchMark<Sqlite3QueryBenchMark>(
+                iteration, Sqlite3QueryBenchMark(datasrc_file, queries,
+                                                 message, buffer));
+            break;
+        case MEMORY:
+            cout << "Benchmark with In Memory Data Source" << endl;
+            BenchMark<MemoryQueryBenchMark>(
+                iteration, MemoryQueryBenchMark(datasrc_file, origin, queries,
+                                                message, buffer));
+            break;
+        }
+    } catch (const std::exception& ex) {
+        cout << "Test unexpectedly failed: " << ex.what() << endl;
+        return (1);
     }
 
     return (0);

+ 34 - 18
src/bin/auth/command.cc

@@ -98,16 +98,27 @@ public:
     /// \c AuthCommandError when it encounters an internal error, such as
     /// semantics error on the command arguments.
     ///
+    /// This method should return the execution result in the form of
+    /// \c ConstElementPtr.  It will be transparently used as the return
+    /// value from the command handler called from the corresponding
+    /// \c CCSession object.  For a successful completion of the command,
+    /// it should suffice to return the return value of
+    /// \c isc::config::createAnswer() with no argument.
+    ///
     /// \param server The \c AuthSrv object on which the command is executed.
     /// \param args Command specific argument.
-    virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) = 0;
+    /// \return Command execution result.
+    virtual ConstElementPtr exec(AuthSrv& server,
+                                 isc::data::ConstElementPtr args) = 0;
 };
 
 // Handle the "shutdown" command. An optional parameter "pid" is used to
 // see if it is really for our instance.
 class ShutdownCommand : public AuthCommand {
 public:
-    virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) {
+    virtual ConstElementPtr exec(AuthSrv& server,
+                                 isc::data::ConstElementPtr args)
+    {
         // Is the pid argument provided?
         if (args && args->contains("pid")) {
             // If it is, we check it is the same as our PID
@@ -123,41 +134,47 @@ public:
                 // there are multiple instances of the server running and
                 // another instance is being shut down, we get the message
                 // too, due to the multicast nature of our message bus.
-                return;
+                return (createAnswer());
             }
         }
         LOG_DEBUG(auth_logger, DBG_AUTH_SHUT, AUTH_SHUTDOWN);
         server.stop();
+        return (createAnswer());
     }
 };
 
-// Handle the "sendstats" command.  No argument is assumed.
-class SendStatsCommand : public AuthCommand {
+// Handle the "getstats" command.  The argument is a list.
+class GetStatsCommand : public AuthCommand {
 public:
-    virtual void exec(AuthSrv& server, isc::data::ConstElementPtr) {
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_RECEIVED_SENDSTATS);
-        server.submitStatistics();
+    virtual ConstElementPtr exec(AuthSrv& server, isc::data::ConstElementPtr) {
+        return (createAnswer(0, server.getStatistics()));
     }
 };
 
 class StartDDNSForwarderCommand : public AuthCommand {
 public:
-    virtual void exec(AuthSrv& server, isc::data::ConstElementPtr) {
+    virtual ConstElementPtr exec(AuthSrv& server,
+                                 isc::data::ConstElementPtr) {
         server.createDDNSForwarder();
+        return (createAnswer());
     }
 };
 
 class StopDDNSForwarderCommand : public AuthCommand {
 public:
-    virtual void exec(AuthSrv& server, isc::data::ConstElementPtr) {
+    virtual ConstElementPtr exec(AuthSrv& server,
+                                 isc::data::ConstElementPtr) {
         server.destroyDDNSForwarder();
+        return (createAnswer());
     }
 };
 
 // Handle the "loadzone" command.
 class LoadZoneCommand : public AuthCommand {
 public:
-    virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) {
+    virtual ConstElementPtr exec(AuthSrv& server,
+                                 isc::data::ConstElementPtr args)
+    {
         if (args == NULL) {
             isc_throw(AuthCommandError, "Null argument");
         }
@@ -185,7 +202,7 @@ public:
                 // Everything worked fine.
                 LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_LOAD_ZONE)
                     .arg(zone_class).arg(origin);
-                return;
+                return (createAnswer());
             case ConfigurableClientList::ZONE_NOT_FOUND:
                 isc_throw(AuthCommandError, "Zone " << origin << "/" <<
                           zone_class << " was not found in any configured "
@@ -202,6 +219,7 @@ public:
                 isc_throw(isc::Unexpected, "Cache disabled in client list of "
                           "class " << zone_class);
         }
+        return (createAnswer());
     }
 };
 
@@ -212,8 +230,8 @@ createAuthCommand(const string& command_id) {
     // (see also createAuthConfigParser())
     if (command_id == "shutdown") {
         return (new ShutdownCommand());
-    } else if (command_id == "sendstats") {
-        return (new SendStatsCommand());
+    } else if (command_id == "getstats") {
+        return (new GetStatsCommand());
     } else if (command_id == "loadzone") {
         return (new LoadZoneCommand());
     } else if (command_id == "start_ddns_forwarder") {
@@ -238,13 +256,11 @@ execAuthServerCommand(AuthSrv& server, const string& command_id,
 {
     LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_RECEIVED_COMMAND).arg(command_id);
     try {
-        scoped_ptr<AuthCommand>(createAuthCommand(command_id))->exec(server,
-                                                                     args);
+        return (scoped_ptr<AuthCommand>(
+                    createAuthCommand(command_id))->exec(server, args));
     } catch (const isc::Exception& ex) {
         LOG_ERROR(auth_logger, AUTH_COMMAND_FAILED).arg(command_id)
                                                    .arg(ex.what());
         return (createAnswer(1, ex.what()));
     }
-
-    return (createAnswer());
 }

+ 0 - 14
src/bin/auth/main.cc

@@ -123,9 +123,7 @@ main(int argc, char* argv[]) {
     // XXX: we should eventually pass io_service here.
     Session* cc_session = NULL;
     Session* xfrin_session = NULL;
-    Session* statistics_session = NULL;
     bool xfrin_session_established = false; // XXX (see Trac #287)
-    bool statistics_session_established = false; // XXX (see Trac #287)
     ModuleCCSession* config_session = NULL;
     XfroutClient xfrout_client(getXfroutSocketPath());
     SocketSessionForwarder ddns_forwarder(getDDNSSocketPath());
@@ -173,14 +171,7 @@ main(int argc, char* argv[]) {
         xfrin_session_established = true;
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_XFRIN_CHANNEL_ESTABLISHED);
 
-        statistics_session = new Session(io_service.get_io_service());
-        LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_STATS_CHANNEL_CREATED);
-        statistics_session->establish(NULL);
-        statistics_session_established = true;
-        LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_STATS_CHANNEL_ESTABLISHED);
-
         auth_server->setXfrinSession(xfrin_session);
-        auth_server->setStatisticsSession(statistics_session);
 
         // Configure the server.  configureAuthServer() is expected to install
         // all initial configurations, but as a short term workaround we
@@ -226,16 +217,11 @@ main(int argc, char* argv[]) {
         ret = 1;
     }
 
-    if (statistics_session_established) {
-        statistics_session->disconnect();
-    }
-
     if (xfrin_session_established) {
         xfrin_session->disconnect();
     }
 
     DataSourceConfigurator::cleanup();
-    delete statistics_session;
     delete xfrin_session;
     delete config_session;
     delete cc_session;

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

@@ -57,7 +57,7 @@ namespace auth {
 void
 Query::ResponseCreator::addRRset(isc::dns::Message& message,
                                  const isc::dns::Message::Section section,
-                                 const ConstRRsetPtr& rrset, const bool dnssec)
+                                 const ConstRRsetPtr& rrset)
 {
     /// Is this RRset already in the list of RRsets added to the message?
     const std::vector<const AbstractRRset*>::const_iterator i =
@@ -68,8 +68,7 @@ Query::ResponseCreator::addRRset(isc::dns::Message& message,
         // No - add it to both the message and the list of RRsets processed.
         // The const-cast is wrong, but the message interface seems to insist.
         message.addRRset(section,
-                         boost::const_pointer_cast<AbstractRRset>(rrset),
-                         dnssec);
+                         boost::const_pointer_cast<AbstractRRset>(rrset));
         added_.push_back(rrset.get());
     }
 }
@@ -78,8 +77,7 @@ void
 Query::ResponseCreator::create(Message& response,
                                const vector<ConstRRsetPtr>& answers,
                                const vector<ConstRRsetPtr>& authorities,
-                               const vector<ConstRRsetPtr>& additionals,
-                               const bool dnssec)
+                               const vector<ConstRRsetPtr>& additionals)
 {
     // Inserter should be reset each time the query is reset, so should be
     // empty at this point.
@@ -91,13 +89,13 @@ Query::ResponseCreator::create(Message& response,
     // guarantee that if there are duplicates, the single RRset added will
     // appear in the most important section.
     BOOST_FOREACH(const ConstRRsetPtr& rrset, answers) {
-        addRRset(response, Message::SECTION_ANSWER, rrset, dnssec);
+        addRRset(response, Message::SECTION_ANSWER, rrset);
     }
     BOOST_FOREACH(const ConstRRsetPtr& rrset, authorities) {
-        addRRset(response, Message::SECTION_AUTHORITY, rrset, dnssec);
+        addRRset(response, Message::SECTION_AUTHORITY, rrset);
     }
     BOOST_FOREACH(const ConstRRsetPtr& rrset, additionals) {
-        addRRset(response, Message::SECTION_ADDITIONAL, rrset, dnssec);
+        addRRset(response, Message::SECTION_ADDITIONAL, rrset);
     }
 }
 
@@ -533,8 +531,7 @@ Query::process(datasrc::ClientList& client_list,
             break;
     }
 
-    response_creator_.create(*response_, answers_, authorities_, additionals_,
-                             dnssec_);
+    response_creator_.create(*response_, answers_, authorities_, additionals_);
 }
 
 void
@@ -592,8 +589,7 @@ Query::processDSAtChild() {
         }
     }
 
-    response_creator_.create(*response_, answers_, authorities_, additionals_,
-                             dnssec_);
+    response_creator_.create(*response_, answers_, authorities_, additionals_);
     return (true);
 }
 

+ 4 - 8
src/bin/auth/query.h

@@ -441,16 +441,13 @@ public:
         /// authority, and additional sections, and add them to their
         /// corresponding sections in the given message.  The RRsets are
         /// filtered such that a particular RRset appears only once in the
-        /// message.
-        ///
-        /// If \c dnssec is true, it tells the message to include any RRSIGs
-        /// attached to the RRsets.
+        /// message. Any RRSIGs attached to the RRsets will be included
+        /// when they are rendered.
         void create(
             isc::dns::Message& message,
             const std::vector<isc::dns::ConstRRsetPtr>& answers_,
             const std::vector<isc::dns::ConstRRsetPtr>& authorities_,
-            const std::vector<isc::dns::ConstRRsetPtr>& additionals_,
-            const bool dnssec);
+            const std::vector<isc::dns::ConstRRsetPtr>& additionals_);
 
     private:
         // \brief RRset comparison functor.
@@ -469,10 +466,9 @@ public:
         /// \param message Message to which the RRset is to be added
         /// \param section Section of the message in which the RRset is put
         /// \param rrset Pointer to RRset to be added to the message
-        /// \param dnssec Whether RRSIG records should be added as well
         void addRRset(isc::dns::Message& message,
                       const isc::dns::Message::Section section,
-                      const isc::dns::ConstRRsetPtr& rrset, const bool dnssec);
+                      const isc::dns::ConstRRsetPtr& rrset);
 
 
     private:

+ 16 - 65
src/bin/auth/statistics.cc

@@ -55,8 +55,7 @@ public:
     }
     void inc(const std::string& zone,
              const AuthCounters::PerZoneCounterType type);
-    bool submitStatistics() const;
-    void setStatisticsSession(isc::cc::AbstractSession* statistics_session);
+    isc::data::ConstElementPtr getStatistics() const;
     void registerStatisticsValidator
     (AuthCounters::validator_type validator);
     // Currently for testing purpose only
@@ -74,7 +73,6 @@ private:
     Counter rcode_counter_;
     static const size_t NUM_RCODES = 17;
     CounterDictionary per_zone_counter_;
-    isc::cc::AbstractSession* statistics_session_;
     AuthCounters::validator_type validator_;
 };
 
@@ -84,8 +82,7 @@ AuthCountersImpl::AuthCountersImpl() :
     // size of per_zone_counter_: AuthCounters::PER_ZONE_COUNTER_TYPES
     server_counter_(AuthCounters::SERVER_COUNTER_TYPES),
     opcode_counter_(NUM_OPCODES), rcode_counter_(NUM_RCODES),
-    per_zone_counter_(AuthCounters::PER_ZONE_COUNTER_TYPES),
-    statistics_session_(NULL)
+    per_zone_counter_(AuthCounters::PER_ZONE_COUNTER_TYPES)
 {
     per_zone_counter_.addElement("_SERVER_");
 }
@@ -105,25 +102,13 @@ AuthCountersImpl::inc(const std::string& zone,
     per_zone_counter_[zone].inc(type);
 }
 
-bool
-AuthCountersImpl::submitStatistics() const {
-    if (statistics_session_ == NULL) {
-        LOG_ERROR(auth_logger, AUTH_NO_STATS_SESSION);
-        return (false);
-    }
+isc::data::ConstElementPtr
+AuthCountersImpl::getStatistics() const {
     std::stringstream statistics_string;
-    // add pid in order for stats to identify which auth sends
-    // statistics in the situation that multiple auth instances are
-    // working
-    statistics_string << "{\"command\": [\"set\","
-                      <<   "{ \"owner\": \"Auth\","
-                      <<   "  \"pid\":" << getpid()
-                      <<   ", \"data\":"
-                      <<     "{ \"queries.udp\": "
-                      <<     server_counter_.get(AuthCounters::SERVER_UDP_QUERY)
-                      <<     ", \"queries.tcp\": "
-                      <<     server_counter_.get(
-                          AuthCounters::SERVER_TCP_QUERY);
+    statistics_string << "{ \"queries.udp\": "
+                      << server_counter_.get(AuthCounters::SERVER_UDP_QUERY)
+                      << ", \"queries.tcp\": "
+                      << server_counter_.get(AuthCounters::SERVER_TCP_QUERY);
     // Insert non 0 Opcode counters.
     for (int i = 0; i < NUM_OPCODES; ++i) {
         const Counter::Type counter = opcode_counter_.get(i);
@@ -150,45 +135,18 @@ AuthCountersImpl::submitStatistics() const {
                               << counter;
         }
     }
-    statistics_string <<   " }"
-                      <<   "}"
-                      << "]}";
+    statistics_string << "}";
+
     isc::data::ConstElementPtr statistics_element =
         isc::data::Element::fromJSON(statistics_string);
     // validate the statistics data before send
     if (validator_) {
-        if (!validator_(
-                statistics_element->get("command")->get(1)->get("data"))) {
+        if (!validator_(statistics_element)) {
             LOG_ERROR(auth_logger, AUTH_INVALID_STATISTICS_DATA);
-            return (false);
+            return (isc::data::ElementPtr());
         }
     }
-    try {
-        // group_{send,recv}msg() can throw an exception when encountering
-        // an error, and group_recvmsg() will throw an exception on timeout.
-        // We don't want to kill the main server just due to this, so we
-        // handle them here.
-        const int seq =
-            statistics_session_->group_sendmsg(statistics_element, "Stats");
-        isc::data::ConstElementPtr env, answer;
-        // TODO: parse and check response from statistics module
-        // currently it just returns empty message
-        statistics_session_->group_recvmsg(env, answer, false, seq);
-    } catch (const isc::cc::SessionError& ex) {
-        LOG_ERROR(auth_logger, AUTH_STATS_COMMS).arg(ex.what());
-        return (false);
-    } catch (const isc::cc::SessionTimeout& ex) {
-        LOG_ERROR(auth_logger, AUTH_STATS_TIMEOUT).arg(ex.what());
-        return (false);
-    }
-    return (true);
-}
-
-void
-AuthCountersImpl::setStatisticsSession
-    (isc::cc::AbstractSession* statistics_session)
-{
-    statistics_session_ = statistics_session;
+    return (statistics_element);
 }
 
 void
@@ -224,16 +182,9 @@ AuthCounters::inc(const Rcode rcode) {
     impl_->inc(rcode);
 }
 
-bool
-AuthCounters::submitStatistics() const {
-    return (impl_->submitStatistics());
-}
-
-void
-AuthCounters::setStatisticsSession
-    (isc::cc::AbstractSession* statistics_session)
-{
-    impl_->setStatisticsSession(statistics_session);
+isc::data::ConstElementPtr
+AuthCounters::getStatistics() const {
+    return (impl_->getStatistics());
 }
 
 uint64_t

+ 7 - 37
src/bin/auth/statistics.h

@@ -17,8 +17,9 @@
 
 #include <dns/opcode.h>
 #include <dns/rcode.h>
-
 #include <cc/session.h>
+#include <cc/data.h>
+
 #include <stdint.h>
 #include <boost/scoped_ptr.hpp>
 
@@ -34,14 +35,11 @@ class AuthCountersImpl;
 /// statistics module.
 ///
 /// This class is designed to be a part of \c AuthSrv.
-/// Call \c setStatisticsSession() to set a session to communicate with
-/// statistics module like Xfrin session.
 /// Call \c inc() to increment a counter for specific type of query in
 /// the query processing function. use \c enum \c CounterType to specify
 /// the type of query.
-/// Call \c submitStatistics() to submit statistics information to statistics
-/// module with statistics_session, periodically or at a time the command
-/// \c sendstats is received.
+/// Call \c getStatistics() to answer statistics information to statistics
+/// module with statistics_session, when the command \c getstats is received.
 ///
 /// We may eventually want to change the structure to hold values that are
 /// not counters (such as concurrent TCP connections), or seperate generic
@@ -108,43 +106,15 @@ public:
     /// \throw None
     void inc(const isc::dns::Rcode rcode);
 
-    /// \brief Submit statistics counters to statistics module.
-    ///
-    /// This method is desinged to be called periodically
-    /// with \c asio_link::StatisticsSendTimer, or arbitrary
-    /// by the command 'sendstats'.
-    ///
-    /// Note: Set the session to communicate with statistics module
-    /// by \c setStatisticsSession() before calling \c submitStatistics().
+    /// \brief Answers statistics counters to statistics module.
     ///
     /// This method is mostly exception free (error conditions are
     /// represented via the return value). But it may still throw
     /// a standard exception if memory allocation fails inside the method.
     ///
-    /// \return true on success, false on error.
-    ///
-    /// \todo Do not block message handling in auth_srv while submitting
-    /// statistics data.
-    ///
-    bool submitStatistics() const;
-
-    /// \brief Set the session to communicate with Statistics
-    /// module.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// Note: this interface is tentative.  We'll revisit the ASIO and session
-    /// frameworks, at which point the session will probably be passed on
-    /// construction of the server.
-    ///
-    /// Ownership isn't transferred: the caller is responsible for keeping
-    /// this object to be valid while the server object is working and for
-    /// disconnecting the session and destroying the object when the server
-    /// is shutdown.
-    ///
-    /// \param statistics_session A pointer to the session
+    /// \return statistics data
     ///
-    void setStatisticsSession(isc::cc::AbstractSession* statistics_session);
+    isc::data::ConstElementPtr getStatistics() const;
 
     /// \brief Get the value of a counter in the AuthCounters.
     ///

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

@@ -64,21 +64,21 @@ nodist_run_unittests_SOURCES = ../auth_messages.h ../auth_messages.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
-run_unittests_LDADD = $(top_builddir)/src/lib/testutils/libtestutils.la
-run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libdatasrc.la
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
-run_unittests_LDADD += $(top_builddir)/src/lib/util/libutil.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
-run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
-run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
-run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
-run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
+run_unittests_LDADD = $(top_builddir)/src/lib/testutils/libb10-testutils.la
+run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
+run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libb10-dns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libb10-asiodns.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libb10-xfr.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
+run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libb10-server-common.la
+run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libb10-nsas.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
-run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
+run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libb10-statistics.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/tests/libfake_session.la
 run_unittests_LDADD += $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)

+ 0 - 2
src/bin/auth/tests/auth_srv_unittest.cc

@@ -100,7 +100,6 @@ protected:
     {
         server.setDNSService(dnss_);
         server.setXfrinSession(&notify_session);
-        server.setStatisticsSession(&statistics_session);
         server.createDDNSForwarder();
     }
 
@@ -180,7 +179,6 @@ protected:
     }
 
     MockDNSService dnss_;
-    MockSession statistics_session;
     MockXfroutClient xfrout;
     MockSocketSessionForwarder ddns_forwarder;
     AuthSrv server;

+ 9 - 12
src/bin/auth/tests/command_unittest.cc

@@ -67,16 +67,13 @@ protected:
         rcode_(-1),
         expect_rcode_(0),
         itimer_(server_.getIOService())
-    {
-        server_.setStatisticsSession(&statistics_session_);
-    }
+    {}
     void checkAnswer(const int expected_code, const char* name = "") {
         SCOPED_TRACE(name);
 
         parseAnswer(rcode_, result_);
         EXPECT_EQ(expected_code, rcode_) << result_->str();
     }
-    MockSession statistics_session_;
     MockXfroutClient xfrout_;
     MockSocketSessionForwarder ddns_forwarder_;
     AuthSrv server_;
@@ -106,14 +103,6 @@ TEST_F(AuthCommandTest, DISABLED_unexpectedException) {
                  runtime_error);
 }
 
-TEST_F(AuthCommandTest, sendStatistics) {
-    result_ = execAuthServerCommand(server_, "sendstats", ConstElementPtr());
-    // Just check some message has been sent.  Detailed tests specific to
-    // statistics are done in its own tests.
-    EXPECT_EQ("Stats", statistics_session_.getMessageDest());
-    checkAnswer(0);
-}
-
 void
 AuthCommandTest::stopServer() {
     result_ = execAuthServerCommand(server_, "shutdown", param_);
@@ -425,4 +414,12 @@ TEST_F(AuthCommandTest, loadZoneInvalidParams) {
                                     Element::fromJSON("{\"origin\": 10}"));
     checkAnswer(1, "Integral name");
 }
+
+TEST_F(AuthCommandTest, getStats) {
+    result_ = execAuthServerCommand(server_, "getstats", ConstElementPtr());
+    parseAnswer(rcode_, result_);
+    // Just check the command execution succeeded.  Detailed tests specific to
+    // statistics are done in its own tests.
+    EXPECT_EQ(0, rcode_);
+}
 }

+ 18 - 54
src/bin/auth/tests/config_unittest.cc

@@ -80,17 +80,29 @@ TEST_F(AuthConfigTest, versionConfig) {
 }
 
 TEST_F(AuthConfigTest, exceptionGuarantee) {
-    server.setStatisticsTimerInterval(1234);
-    EXPECT_EQ(1234, server.getStatisticsTimerInterval());
-    // This configuration contains an invalid item, which will trigger
-    // an exception.
+    using namespace isc::server_common::portconfig;
+    AddressList a;
+    a.push_back(AddressPair("127.0.0.1", 53210));
+    server.setListenAddresses(a);
+    const AddressList b = server.getListenAddresses();
+    EXPECT_EQ(a.size(), b.size());
+    EXPECT_EQ(a.at(0).first, b.at(0).first);
+    EXPECT_EQ(a.at(0).second, b.at(0).second);
+    // The test socket request will reject the second address (192.0.2.2)
+    // with an exception
     EXPECT_THROW(configureAuthServer(
                      server,
                      Element::fromJSON(
-                         "{ \"no_such_config_var\": 1}")),
+                         "{ \"listen_on\": ["
+                           "{\"address\": \"::1\", \"port\": 53210},"
+                           "{\"address\": \"192.0.2.2\", \"port\": 53210}"
+                         "]}")),
                  AuthConfigError);
     // The server state shouldn't change
-    EXPECT_EQ(1234, server.getStatisticsTimerInterval());
+    const AddressList c = server.getListenAddresses();
+    EXPECT_EQ(a.size(), c.size());
+    EXPECT_EQ(a.at(0).first, c.at(0).first);
+    EXPECT_EQ(a.at(0).second, c.at(0).second);
 }
 
 TEST_F(AuthConfigTest, badConfig) {
@@ -131,52 +143,4 @@ TEST_F(AuthConfigTest, listenAddressConfig) {
     EXPECT_EQ(DNSService::SERVER_SYNC_OK, dnss_.getUDPFdParams().at(1).options);
 }
 
-class StatisticsIntervalConfigTest : public AuthConfigTest {
-protected:
-    StatisticsIntervalConfigTest() :
-        parser(createAuthConfigParser(server, "statistics-interval"))
-    {}
-    ~StatisticsIntervalConfigTest() {
-        delete parser;
-    }
-    AuthConfigParser* parser;
-};
-
-TEST_F(StatisticsIntervalConfigTest, setInterval) {
-    // initially the timer is not configured.
-    EXPECT_EQ(0, server.getStatisticsTimerInterval());
-
-    // initialize the timer
-    parser->build(Element::fromJSON("5"));
-    parser->commit();
-    EXPECT_EQ(5, server.getStatisticsTimerInterval());
-
-    // reset the timer with a new interval
-    delete parser;
-    parser = createAuthConfigParser(server, "statistics-interval");
-    ASSERT_NE(static_cast<void*>(NULL), parser);
-    parser->build(Element::fromJSON("10"));
-    parser->commit();
-    EXPECT_EQ(10, server.getStatisticsTimerInterval());
-
-    // disable the timer again
-    delete parser;
-    parser = createAuthConfigParser(server, "statistics-interval");
-    ASSERT_NE(static_cast<void*>(NULL), parser);
-    parser->build(Element::fromJSON("0"));
-    parser->commit();
-    EXPECT_EQ(0, server.getStatisticsTimerInterval());
-}
-
-TEST_F(StatisticsIntervalConfigTest, badInterval) {
-    EXPECT_THROW(parser->build(Element::fromJSON("\"should be integer\"")),
-                 isc::data::TypeError);
-    EXPECT_THROW(parser->build(Element::fromJSON("2.5")),
-                 isc::data::TypeError);
-    EXPECT_THROW(parser->build(Element::fromJSON("-1")), AuthConfigError);
-    // bounds check: interval value must be equal to or shorter than
-    // 86400 seconds (1 day)
-    EXPECT_NO_THROW(parser->build(Element::fromJSON("86400")));
-    EXPECT_THROW(parser->build(Element::fromJSON("86401")), AuthConfigError);
-}
 }

+ 28 - 32
src/bin/auth/tests/query_unittest.cc

@@ -211,12 +211,18 @@ const char* const nonsec_a_txt =
     "nonsec.example.com. 3600 IN A 192.0.2.0\n";
 
 // NSEC3 RRs.  You may also need to add mapping to MockZoneFinder::hash_map_.
-const char* const nsec3_apex_txt =
+const string nsec3_apex_txt =
     "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN NSEC3 1 1 12 "
     "aabbccdd 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA NSEC3PARAM RRSIG\n";
-const char* const nsec3_www_txt =
+const string nsec3_apex_rrsig_txt =
+    "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example.com. 3600 IN RRSIG NSEC3 5 3 "
+    "3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE";
+const string nsec3_www_txt =
     "q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN NSEC3 1 1 12 "
     "aabbccdd r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG\n";
+const string nsec3_www_rrsig_txt =
+    "q04jkcevqvmu85r014c7dkba38o0ji5r.example.com. 3600 IN RRSIG NSEC3 5 3 "
+    "3600 20000101000000 20000201000000 12345 example.com. FAKEFAKEFAKE";
 
 // NSEC3 for wild.example.com (used in wildcard tests, will be added on
 // demand not to confuse other tests)
@@ -479,9 +485,10 @@ protected:
                                        isc::dns::ConstRRsetPtr rrset,
                                        FindResultFlags flags = RESULT_DEFAULT)
     {
+        ConstRRsetPtr rp = stripRRsigs(rrset, options);
         return (ZoneFinderContextPtr(
                     new Context(*this, options,
-                                ResultContext(code, rrset, flags))));
+                                ResultContext(code, rp, flags))));
     }
 
 private:
@@ -594,7 +601,7 @@ MockZoneFinder::findAll(const Name& name, std::vector<ConstRRsetPtr>& target,
                  found_domain->second.begin();
                  found_rrset != found_domain->second.end(); ++found_rrset) {
                 // Insert RRs under the domain name into target
-                target.push_back(found_rrset->second);
+                target.push_back(stripRRsigs(found_rrset->second, options));
             }
             return (ZoneFinderContextPtr(
                         new Context(*this, options,
@@ -701,25 +708,8 @@ MockZoneFinder::find(const Name& name, const RRType& type,
         RRsetStore::const_iterator found_rrset =
             found_domain->second.find(type);
         if (found_rrset != found_domain->second.end()) {
-            ConstRRsetPtr rrset;
-            // Strip whatever signature there is in case DNSSEC is not required
-            // Just to make sure the Query asks for it when it is needed
-            if ((options & ZoneFinder::FIND_DNSSEC) != 0 ||
-                include_rrsig_anyway_ ||
-                !found_rrset->second->getRRsig()) {
-                rrset = found_rrset->second;
-            } else {
-                RRsetPtr noconst(new RRset(found_rrset->second->getName(),
-                                           found_rrset->second->getClass(),
-                                           found_rrset->second->getType(),
-                                           found_rrset->second->getTTL()));
-                for (RdataIteratorPtr
-                     i(found_rrset->second->getRdataIterator());
-                     !i->isLast(); i->next()) {
-                    noconst->addRdata(i->getCurrent());
-                }
-                rrset = noconst;
-            }
+            ConstRRsetPtr rrset = ZoneFinder::stripRRsigs(found_rrset->second,
+                                                          options);
             return (createContext(options, SUCCESS, rrset));
         }
 
@@ -1985,14 +1975,16 @@ TEST_F(QueryTest, findNSEC3) {
     // Apex name.  It should have a matching NSEC3
     {
         SCOPED_TRACE("apex, non recursive");
-        nsec3Check(true, expected_closest_labels, nsec3_apex_txt,
+        nsec3Check(true, expected_closest_labels,
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt,
                    mock_finder->findNSEC3(Name("example.com"), false));
     }
 
     // Recursive mode doesn't change the result in this case.
     {
         SCOPED_TRACE("apex, recursive");
-        nsec3Check(true, expected_closest_labels, nsec3_apex_txt,
+        nsec3Check(true, expected_closest_labels,
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt,
                    mock_finder->findNSEC3(Name("example.com"), true));
     }
 
@@ -2000,7 +1992,8 @@ TEST_F(QueryTest, findNSEC3) {
     // returned.
     {
         SCOPED_TRACE("nxdomain, non recursive");
-        nsec3Check(false, 4, nsec3_www_txt,
+        nsec3Check(false, 4,
+                   nsec3_www_txt + "\n" + nsec3_www_rrsig_txt,
                    mock_finder->findNSEC3(Name("nxdomain.example.com"),
                                           false));
     }
@@ -2010,7 +2003,8 @@ TEST_F(QueryTest, findNSEC3) {
     {
         SCOPED_TRACE("nxdomain, recursive");
         nsec3Check(true, expected_closest_labels,
-                   string(nsec3_apex_txt) + string(nsec3_www_txt),
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt + "\n" +
+                   nsec3_www_txt + "\n" + nsec3_www_rrsig_txt,
                    mock_finder->findNSEC3(Name("nxdomain.example.com"), true));
     }
 
@@ -2019,7 +2013,8 @@ TEST_F(QueryTest, findNSEC3) {
     {
         SCOPED_TRACE("nxdomain, next closer != qname");
         nsec3Check(true, expected_closest_labels,
-                   string(nsec3_apex_txt) + string(nsec3_www_txt),
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt + "\n" +
+                   nsec3_www_txt + "\n" + nsec3_www_rrsig_txt,
                    mock_finder->findNSEC3(Name("nx.domain.example.com"),
                                           true));
     }
@@ -2027,13 +2022,15 @@ TEST_F(QueryTest, findNSEC3) {
     // In the rest of test we check hash comparison for wrap around cases.
     {
         SCOPED_TRACE("largest");
-        nsec3Check(false, 4, nsec3_apex_txt,
+        nsec3Check(false, 4,
+                   nsec3_apex_txt + "\n" + nsec3_apex_rrsig_txt,
                    mock_finder->findNSEC3(Name("nxdomain2.example.com"),
                                           false));
     }
     {
         SCOPED_TRACE("smallest");
-        nsec3Check(false, 4, nsec3_www_txt,
+        nsec3Check(false, 4,
+                   nsec3_www_txt + "\n" + nsec3_www_rrsig_txt,
                    mock_finder->findNSEC3(Name("nxdomain3.example.com"),
                                           false));
     }
@@ -2516,8 +2513,7 @@ TEST_F(QueryTest, DuplicateNameRemoval) {
     EXPECT_EQ(0, message.getRRCount(Message::SECTION_ADDITIONAL));
 
     // ... and fill it.
-    Query::ResponseCreator().create(message, answer, authority, additional,
-                                    false);
+    Query::ResponseCreator().create(message, answer, authority, additional);
 
     // Check counts in each section.  Note that these are RR counts,
     // not RRset counts.

+ 21 - 74
src/bin/auth/tests/statistics_unittest.cc

@@ -30,7 +30,6 @@
 
 #include <dns/tests/unittest_util.h>
 
-using isc::UnitTestUtil;
 using namespace std;
 using namespace isc::cc;
 using namespace isc::dns;
@@ -77,11 +76,9 @@ private:
 
 protected:
     AuthCountersTest() : counters() {
-        counters.setStatisticsSession(&statistics_session_);
     }
     ~AuthCountersTest() {
     }
-    MockSession statistics_session_;
     AuthCounters counters;
     // no need to be inherited from the original class here.
     class MockModuleSpec {
@@ -195,25 +192,6 @@ TEST_F(AuthCountersTest, incrementRcodeCounter) {
     }
 }
 
-TEST_F(AuthCountersTest, submitStatisticsWithoutSession) {
-    // Set statistics_session to NULL and call submitStatistics().
-    // Expect to return false.
-    counters.setStatisticsSession(NULL);
-    EXPECT_FALSE(counters.submitStatistics());
-}
-
-TEST_F(AuthCountersTest, submitStatisticsWithException) {
-    // Exception SessionError and SessionTimeout will be thrown
-    // while sending statistics data.
-    // Both expect to return false.
-    statistics_session_.setThrowSessionError(true);
-    EXPECT_FALSE(counters.submitStatistics());
-    statistics_session_.setThrowSessionError(false);
-    statistics_session_.setThrowSessionTimeout(true);
-    EXPECT_FALSE(counters.submitStatistics());
-    statistics_session_.setThrowSessionTimeout(false);
-}
-
 void
 opcodeDataCheck(ConstElementPtr data, const int expected[16]) {
     const char* item_names[] = {
@@ -258,10 +236,9 @@ rcodeDataCheck(ConstElementPtr data, const int expected[17]) {
     ASSERT_EQ(static_cast<const char*>(NULL), item_names[i]);
 }
 
-
-TEST_F(AuthCountersTest, submitStatisticsWithoutValidator) {
-    // Submit statistics data.
-    // Validate if it submits correct data.
+TEST_F(AuthCountersTest, getStatisticsWithoutValidator) {
+    // Get statistics data.
+    // Validate if it answers correct data.
 
     // Counters should be initialized to 0.
     EXPECT_EQ(0, counters.getCounter(AuthCounters::SERVER_UDP_QUERY));
@@ -272,20 +249,8 @@ TEST_F(AuthCountersTest, submitStatisticsWithoutValidator) {
     counters.inc(AuthCounters::SERVER_UDP_QUERY);
     // TCP query counter is set to 1.
     counters.inc(AuthCounters::SERVER_TCP_QUERY);
-    counters.submitStatistics();
-
-    // Destination is "Stats".
-    EXPECT_EQ("Stats", statistics_session_.msg_destination);
-    // Command is "set".
-    EXPECT_EQ("set", statistics_session_.sent_msg->get("command")
-                         ->get(0)->stringValue());
-    EXPECT_EQ("Auth", statistics_session_.sent_msg->get("command")
-                         ->get(1)->get("owner")->stringValue());
-    EXPECT_EQ(statistics_session_.sent_msg->get("command")
-              ->get(1)->get("pid")->intValue(), getpid());
-    ConstElementPtr statistics_data = statistics_session_.sent_msg
-                                          ->get("command")->get(1)
-                                          ->get("data");
+    ConstElementPtr statistics_data = counters.getStatistics();
+
     // UDP query counter is 2 and TCP query counter is 1.
     EXPECT_EQ(2, statistics_data->get("queries.udp")->intValue());
     EXPECT_EQ(1, statistics_data->get("queries.tcp")->intValue());
@@ -318,61 +283,53 @@ updateRcodeCounters(AuthCounters &counters, const int expected[17]) {
     }
 }
 
-TEST_F(AuthCountersTest, submitStatisticsWithOpcodeCounters) {
+TEST_F(AuthCountersTest, getStatisticsWithOpcodeCounters) {
     // Increment some of the opcode counters.  Then they should appear in the
     // submitted data; others shouldn't
     const int opcode_results[16] = { 1, 2, 3, 0, 4, 5, 0, 0,
                                      0, 0, 0, 0, 0, 0, 0, 0 };
     updateOpcodeCounters(counters, opcode_results);
-    counters.submitStatistics();
-    ConstElementPtr statistics_data = statistics_session_.sent_msg
-        ->get("command")->get(1)->get("data");
+    ConstElementPtr statistics_data = counters.getStatistics();
     opcodeDataCheck(statistics_data, opcode_results);
 }
 
-TEST_F(AuthCountersTest, submitStatisticsWithAllOpcodeCounters) {
+TEST_F(AuthCountersTest, getStatisticsWithAllOpcodeCounters) {
     // Increment all opcode counters.  Then they should appear in the
     // submitted data.
     const int opcode_results[16] = { 1, 1, 1, 1, 1, 1, 1, 1,
                                      1, 1, 1, 1, 1, 1, 1, 1 };
     updateOpcodeCounters(counters, opcode_results);
-    counters.submitStatistics();
-    ConstElementPtr statistics_data = statistics_session_.sent_msg
-        ->get("command")->get(1)->get("data");
+    ConstElementPtr statistics_data = counters.getStatistics();
     opcodeDataCheck(statistics_data, opcode_results);
 }
 
-TEST_F(AuthCountersTest, submitStatisticsWithRcodeCounters) {
+TEST_F(AuthCountersTest, getStatisticsWithRcodeCounters) {
     // Increment some of the rcode counters.  Then they should appear in the
     // submitted data; others shouldn't
     const int rcode_results[17] = { 1, 2, 3, 4, 5, 6, 7, 8, 9,
                                     10, 0, 0, 0, 0, 0, 0, 11 };
     updateRcodeCounters(counters, rcode_results);
-    counters.submitStatistics();
-    ConstElementPtr statistics_data = statistics_session_.sent_msg
-        ->get("command")->get(1)->get("data");
+    ConstElementPtr statistics_data = counters.getStatistics();
     rcodeDataCheck(statistics_data, rcode_results);
 }
 
-TEST_F(AuthCountersTest, submitStatisticsWithAllRcodeCounters) {
+TEST_F(AuthCountersTest, getStatisticsWithAllRcodeCounters) {
     // Increment all rcode counters.  Then they should appear in the
     // submitted data.
     const int rcode_results[17] = { 1, 1, 1, 1, 1, 1, 1, 1, 1,
                                      1, 1, 1, 1, 1, 1, 1, 1 };
     updateOpcodeCounters(counters, rcode_results);
-    counters.submitStatistics();
-    ConstElementPtr statistics_data = statistics_session_.sent_msg
-        ->get("command")->get(1)->get("data");
+    ConstElementPtr statistics_data = counters.getStatistics();
     opcodeDataCheck(statistics_data, rcode_results);
 }
 
-TEST_F(AuthCountersTest, submitStatisticsWithValidator) {
+TEST_F(AuthCountersTest, getStatisticsWithValidator) {
 
     //a validator for the unittest
     AuthCounters::validator_type validator;
     ConstElementPtr el;
 
-    // Submit statistics data with correct statistics validator.
+    // Get statistics data with correct statistics validator.
     validator = boost::bind(
         &AuthCountersTest::MockModuleSpec::validateStatistics,
         &module_spec_, _1, true);
@@ -392,24 +349,14 @@ TEST_F(AuthCountersTest, submitStatisticsWithValidator) {
     // TCP query counter is set to 1.
     counters.inc(AuthCounters::SERVER_TCP_QUERY);
 
-    // checks the value returned by submitStatistics
-    EXPECT_TRUE(counters.submitStatistics());
-
-    // Destination is "Stats".
-    EXPECT_EQ("Stats", statistics_session_.msg_destination);
-    // Command is "set".
-    EXPECT_EQ("set", statistics_session_.sent_msg->get("command")
-                         ->get(0)->stringValue());
-    EXPECT_EQ("Auth", statistics_session_.sent_msg->get("command")
-                         ->get(1)->get("owner")->stringValue());
-    ConstElementPtr statistics_data = statistics_session_.sent_msg
-                                          ->get("command")->get(1)
-                                          ->get("data");
+    // checks the value returned by getStatistics
+    ConstElementPtr statistics_data = counters.getStatistics();
+
     // UDP query counter is 2 and TCP query counter is 1.
     EXPECT_EQ(2, statistics_data->get("queries.udp")->intValue());
     EXPECT_EQ(1, statistics_data->get("queries.tcp")->intValue());
 
-    // Submit statistics data with incorrect statistics validator.
+    // Get statistics data with incorrect statistics validator.
     validator = boost::bind(
         &AuthCountersTest::MockModuleSpec::validateStatistics,
         &module_spec_, _1, false);
@@ -418,7 +365,7 @@ TEST_F(AuthCountersTest, submitStatisticsWithValidator) {
 
     counters.registerStatisticsValidator(validator);
 
-    // checks the value returned by submitStatistics
-    EXPECT_FALSE(counters.submitStatistics());
+    // checks the value returned by getStatistics
+    EXPECT_FALSE(counters.getStatistics());
 }
 }

+ 4 - 9
src/bin/bind10/bind10.xml

@@ -394,7 +394,6 @@ xfrin
       daemon.
       This is an internal command and not exposed to the administrator.
 <!-- not defined in spec -->
-<!-- TODO: explain difference with sendstat -->
     </para>
 
     <para>
@@ -404,17 +403,10 @@ xfrin
     </para>
 
     <para>
-      <command>sendstats</command> tells <command>bind10</command>
-      to send its statistics data to the <command>b10-stats</command>
-      daemon immediately.
-<!-- TODO: compare with internal command getstats? -->
-    </para>
-
-    <para>
       <command>show_processes</command> lists the current processes
       managed by <command>bind10</command>.
       The output is an array in JSON format containing the process
-      ID and the name for each.
+      ID, the name for each and the address name used on each message bus.
 <!-- TODO: what is name? -->
 <!-- TODO: change to JSON object format? -->
 <!-- TODO: ticket #1406 -->
@@ -490,6 +482,9 @@ xfrin
       <citerefentry>
         <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-stats</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
     </para>
   </refsect1>

+ 6 - 24
src/bin/bind10/bind10_src.py.in

@@ -281,14 +281,13 @@ class BoB:
         pids.sort()
         process_list = [ ]
         for pid in pids:
-            process_list.append([pid, self.components[pid].name()])
+            process_list.append([pid, self.components[pid].name(),
+                                 self.components[pid].address()])
         return process_list
 
     def _get_stats_data(self):
-        return { "owner": "Boss",
-                 "data": { 'boot_time':
-                               time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
-                           }
+        return { 'boot_time':
+                     time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
                  }
 
     def command_handler(self, command, args):
@@ -301,25 +300,8 @@ class BoB:
                 self.runnable = False
                 answer = isc.config.ccsession.create_answer(0)
             elif command == "getstats":
-                answer = isc.config.ccsession.create_answer(0, self._get_stats_data())
-            elif command == "sendstats":
-                # send statistics data to the stats daemon immediately
-                stats_data = self._get_stats_data()
-                valid = self.ccs.get_module_spec().validate_statistics(
-                    True, stats_data["data"])
-                if valid:
-                    cmd = isc.config.ccsession.create_command('set', stats_data)
-                    seq = self.cc_session.group_sendmsg(cmd, 'Stats')
-                    # Consume the answer, in case it becomes a orphan message.
-                    try:
-                        self.cc_session.group_recvmsg(False, seq)
-                    except isc.cc.session.SessionTimeout:
-                        pass
-                    answer = isc.config.ccsession.create_answer(0)
-                else:
-                    logger.fatal(BIND10_INVALID_STATISTICS_DATA);
-                    answer = isc.config.ccsession.create_answer(
-                        1, "specified statistics data is invalid")
+                answer = isc.config.ccsession.create_answer(
+                    0, self._get_stats_data())
             elif command == "ping":
                 answer = isc.config.ccsession.create_answer(0, "pong")
             elif command == "show_processes":

+ 0 - 5
src/bin/bind10/bob.spec

@@ -65,11 +65,6 @@
         "command_args": []
       },
       {
-        "command_name": "sendstats",
-        "command_description": "Send data to a statistics module at once",
-        "command_args": []
-      },
-      {
         "command_name": "ping",
         "command_description": "Ping the boss process",
         "command_args": []

+ 6 - 18
src/bin/bind10/tests/bind10_test.py.in

@@ -413,20 +413,7 @@ class TestBoB(unittest.TestCase):
         # "getstats" command
         self.assertEqual(bob.command_handler("getstats", None),
                          isc.config.ccsession.create_answer(0,
-                            { "owner": "Boss",
-                              "data": {
-                                'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME)
-                            }}))
-        # "sendstats" command
-        self.assertEqual(bob.command_handler("sendstats", None),
-                         isc.config.ccsession.create_answer(0))
-        self.assertEqual(bob.cc_session.group, "Stats")
-        self.assertEqual(bob.cc_session.msg,
-                         isc.config.ccsession.create_command(
-                "set", { "owner": "Boss",
-                         "data": {
-                        "boot_time": time.strftime("%Y-%m-%dT%H:%M:%SZ", _BASETIME)
-                        }}))
+                            { 'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', _BASETIME) }))
         # "ping" command
         self.assertEqual(bob.command_handler("ping", None),
                          isc.config.ccsession.create_answer(0, "pong"))
@@ -938,9 +925,10 @@ class TestStartStopProcessesBob(unittest.TestCase):
         #self.check_started_dhcp(bob, True, True)
 
 class MockComponent:
-    def __init__(self, name, pid):
+    def __init__(self, name, pid, address=None):
         self.name = lambda: name
         self.pid = lambda: pid
+        self.address = lambda: address
 
 
 class TestBossCmd(unittest.TestCase):
@@ -966,10 +954,10 @@ class TestBossCmd(unittest.TestCase):
         """
         bob = MockBob()
         bob.register_process(1, MockComponent('first', 1))
-        bob.register_process(2, MockComponent('second', 2))
+        bob.register_process(2, MockComponent('second', 2, 'Second'))
         answer = bob.command_handler("show_processes", None)
-        processes = [[1, 'first'],
-                     [2, 'second']]
+        processes = [[1, 'first', None],
+                     [2, 'second', 'Second']]
         self.assertEqual(answer, {'result': [0, processes]})
 
 class TestParseArgs(unittest.TestCase):

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

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

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

@@ -3,7 +3,7 @@ SUBDIRS = tests
 EXTRA_DIST = README logging.spec tsig_keys.spec
 
 datasrc.spec: datasrc.spec.pre
-	$(SED) -e "s|@@PKGDATADIR@@|$(pkgdatadir)|" datasrc.spec.pre >$@
+	$(SED) -e "s|@@PKGDATADIR@@|$(pkgdatadir)|;s|@@LOCALSTATEDIR@@|$(localstatedir)|" datasrc.spec.pre >$@
 
 config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
 config_plugin_DATA = logging.spec tsig_keys.spec datasrc.spec

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

@@ -8,6 +8,14 @@
                 "item_type": "named_set",
                 "item_optional": false,
                 "item_default": {
+                    "IN": [
+                        {
+                            "type": "sqlite3",
+                            "params": {
+                                "database_file": "@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3"
+                            }
+                        }
+                    ],
                     "CH": [
                         {
                             "type": "static",

+ 5 - 4
src/bin/ddns/ddns.spec

@@ -12,8 +12,8 @@
           "item_type": "map",
           "item_optional": true,
           "item_default": {
-	    "origin": "",
-	    "class": "IN",
+          "origin": "",
+          "class": "IN",
             "update_acl": []
           },
           "map_item_spec": [
@@ -33,11 +33,12 @@
               "item_name": "update_acl",
               "item_type": "list",
               "item_optional": false,
-	      "item_default": [],
+              "item_default": [],
               "list_item_spec": {
                 "item_name": "acl_element",
                 "item_type": "any",
-                "item_optional": true
+                "item_optional": true,
+                "item_default": {"action": "REJECT"}
               }
             }
           ]

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

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

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

@@ -86,7 +86,7 @@ void ControlledDhcpv4Srv::establishSession() {
     string specfile;
     if (getenv("B10_FROM_BUILD")) {
         specfile = string(getenv("B10_FROM_BUILD")) +
-            "/src/bin/auth/dhcp4.spec";
+            "/src/bin/dhcp4/dhcp4.spec";
     } else {
         specfile = string(DHCP4_SPECFILE_LOCATION);
     }

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

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

+ 35 - 14
src/bin/dhcp4/main.cc

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 1 - 0
src/bin/loadzone/tests/correct/Makefile.am

@@ -12,6 +12,7 @@ EXTRA_DIST += ttl1.db
 EXTRA_DIST += ttl2.db
 EXTRA_DIST += ttlext.db
 EXTRA_DIST += example.db
+EXTRA_DIST += comment.db
 
 noinst_SCRIPTS = correct_test.sh
 

+ 8 - 0
src/bin/loadzone/tests/correct/comment.db

@@ -0,0 +1,8 @@
+; Test removal of comments and not removal from strings.
+; We had a bug - see #2188.
+comment.example.com.		60	IN	SOA	ns1.example.com. hostmaster.example.com. 1 43200 900 1814400 7200
+comment.example.com.		60	IN	NS	ns1.example.com.
+comment.example.com.		60	IN	TXT	"Simple text"
+comment.example.com.		60	IN	TXT	"; No comment"
+comment.example.com.		60	IN	TXT	"Also no comment here" ; But here it is a comment
+comment.example.com.		60	IN	TXT	"A combination ; see?" ; This is a "comment

+ 4 - 0
src/bin/loadzone/tests/correct/correct_test.sh.in

@@ -48,6 +48,9 @@ ${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 ttlext.db >> /
 echo "loadzone example.com. from example.db"
 ${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 example.db >> /dev/null
 
+echo "loadzone comment.example.com. from comment.db"
+${LOADZONE_PATH}/b10-loadzone -d ${TEST_OUTPUT_PATH}/zone.sqlite3 comment.db >> /dev/null
+
 echo "I:test master file \$INCLUDE semantics"
 echo "I:test master file BIND 8 compatibility TTL and \$TTL semantics"
 echo "I:test master file RFC1035 TTL and \$TTL semantics"
@@ -55,6 +58,7 @@ echo "I:test master file BIND8 compatibility and mixed \$INCLUDE with \$TTL sema
 echo "I:test master file RFC1035 TTL and mixed \$INCLUDE with \$TTL semantics"
 echo "I:test master file BIND9 extenstion of TTL"
 echo "I:test master file RFC1035 missing CLASS, TTL, NAME semantics"
+echo "I:test master file comments"
 
 ${PYTHON_EXEC} ${TEST_FILE_PATH}/get_zonedatas.py ${TEST_OUTPUT_PATH}/zone.sqlite3 > ${TEST_OUTPUT_PATH}/test.out
 echo "Compare test results."

+ 1 - 1
src/bin/loadzone/tests/correct/get_zonedatas.py

@@ -1,7 +1,7 @@
 from isc.datasrc import sqlite3_ds
 import sys
 ZONE_FILE = sys.argv[1]
-zonename_set = ["include.", "ttl1.", "ttl2.", "mix1.", "mix2.", "ttlext.", "example.com."]
+zonename_set = ["include.", "ttl1.", "ttl2.", "mix1.", "mix2.", "ttlext.", "example.com.", "comment.example.com."]
 for zone_name in zonename_set:
     for rr_data in sqlite3_ds.get_zone_datas(zone_name, ZONE_FILE):
         data_len = len(rr_data[2])

+ 6 - 0
src/bin/loadzone/tests/correct/known.test.out

@@ -77,3 +77,9 @@ ns2.example.com.		80	IN	A	1.1.1.1
 ns3.example.com.		60	IN	A	2.2.2.2
 ns4.example.com.		60	IN	A	3.3.3.3
 ns5.example.com.		90	IN	A	4.4.4.4
+comment.example.com.		60	IN	SOA	ns1.example.com. hostmaster.example.com. 1 43200 900 1814400 7200
+comment.example.com.		60	IN	NS	ns1.example.com.
+comment.example.com.		60	IN	TXT	"Simple text"
+comment.example.com.		60	IN	TXT	"; No comment"
+comment.example.com.		60	IN	TXT	"Also no comment here"
+comment.example.com.		60	IN	TXT	"A combination ; see?"

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

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

+ 17 - 31
src/bin/resolver/resolver.spec.pre.in

@@ -116,37 +116,23 @@
       },
       {
         "item_name": "query_acl",
-	"item_type": "list",
-	"item_optional": false,
-	"item_default": [
-	  {
-	    "action": "ACCEPT",
-	    "from": "127.0.0.1"
-	  },
-	  {
-	    "action": "ACCEPT",
-	    "from": "::1"
-	  }
-	],
-	"list_item_spec": {
-	  "item_name": "rule",
-	  "item_type": "map",
-	  "item_optional": false,
-	  "item_default": {},
-	  "map_item_spec": [
-	    {
-	      "item_name": "action",
-	      "item_type": "string",
-	      "item_optional": false,
-	      "item_default": ""
-	    },
-	    {
-	      "item_name": "from",
-	      "item_type": "string",
-	      "item_optional": false,
-	      "item_default": ""
-	    }
-	  ]
+        "item_type": "list",
+        "item_optional": false,
+        "item_default": [
+          {
+            "action": "ACCEPT",
+            "from": "127.0.0.1"
+          },
+          {
+            "action": "ACCEPT",
+            "from": "::1"
+          }
+        ],
+        "list_item_spec": {
+          "item_name": "rule",
+          "item_type": "any",
+          "item_optional": false,
+          "item_default": {"action": "REJECT"}
         }
       }
     ],

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

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

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

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

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

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

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

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

+ 25 - 18
src/bin/stats/b10-stats.xml

@@ -1,6 +1,6 @@
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
-	       [<!ENTITY mdash "&#8212;">]>
+               [<!ENTITY mdash "&#8212;">]>
 <!--
  - Copyright (C) 2010-2012  Internet Systems Consortium, Inc. ("ISC")
  -
@@ -59,11 +59,11 @@
       <command>bind10</command> and 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. The stats module collects data and
+      and so on. <command>b10-stats</command> periodically requests statistics
+      data from each module. The interval time can be configured
+      via <command>bindctl</command>. <command>b10-stats</command> cannot
+      accept any command from other modules for updating statistics data. The
+      stats module collects data and
       aggregates it. <command>b10-stats</command> invokes an internal
       command for <command>bind10</command> after its initial
       starting to make sure it collects statistics data from
@@ -78,9 +78,9 @@
       <varlistentry>
         <term><option>-v</option>, <option>--verbose</option></term>
         <listitem>
-	  <para>
-          This enables maximum debug logging.
-	  </para>
+          <para>
+            This enables maximum debug logging.
+          </para>
         </listitem>
       </varlistentry>
     </variablelist>
@@ -90,23 +90,30 @@
     <title>CONFIGURATION AND COMMANDS</title>
 
     <para>
-      The <command>b10-stats</command> command does not have any
-      configurable settings.
+      The only configurable setting in <filename>stats.spec</filename>
+      is:
     </para>
 
+    <variablelist>
+      <varlistentry>
+        <term><varname>poll-interval</varname></term>
+        <listitem>
+          <para>
+            is a time interval in seconds at which <command>b10-stats</command>
+            requests each module to return its statistics data. The default is 60
+            seconds. Polling can be disabled by setting it to 0. The type of the
+            value should be an unsigned integer. Negative integers are ignored.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+
 <!-- TODO: formating -->
     <para>
       The configuration commands are:
     </para>
 
     <para>
-      <command>set</command> will set new statistics data specified in
-      arguments. Statistics data to be set and the module name which owns
-      statistics data are required in argument. Pid of the module in argument
-      is optional.
-    </para>
-
-    <para>
       <command>show</command> will send the statistics data
       in JSON format.
       By default, it outputs all the statistics data it has collected.

+ 326 - 142
src/bin/stats/stats.py.in

@@ -1,6 +1,6 @@
 #!@PYTHON@
 
-# Copyright (C) 2010, 2011  Internet Systems Consortium.
+# Copyright (C) 2010, 2011, 2012  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -23,6 +23,8 @@ import sys; sys.path.append ('@@PYTHONPATH@@')
 import os
 from time import time, strftime, gmtime
 from optparse import OptionParser, OptionValueError
+import errno
+import select
 
 import isc
 import isc.util.process
@@ -92,10 +94,79 @@ def get_spec_defaults(spec):
             return spec.get(
                     "item_default",
                     dict([ (s["item_name"], _get_spec_defaults(s)) for s in spec["map_item_spec"] ]) )
+        elif item_type == "named_set":
+            # in a named_set type, it returns {} as a default value
+            return spec.get("item_default", {})
         else:
             return spec.get("item_default", None)
     return dict([ (s['item_name'], _get_spec_defaults(s)) for s in spec ])
 
+def _accum(a, b):
+    """If the first arg is dict or list type, two values
+    would be merged and accumlated. This is for internal use."""
+
+    # If both of args are dict or list type, two
+    # values are merged.
+    if type(a) is dict and type(b) is dict:
+        return dict([ (k, _accum(v, b[k])) \
+                          if k in b else (k, v) \
+                          for (k, v) in a.items() ] \
+                        + [ (k, v) \
+                                for (k, v) in b.items() \
+                                if k not in a ])
+    elif type(a) is list and type(b) is list:
+        return [ _accum(a[i], b[i]) \
+                     if len(b) > i else a[i] \
+                     for i in range(len(a)) ] \
+                     + [ b[i] \
+                             for i in range(len(b)) \
+                             if len(a) <= i ]
+    # If both of args are integer or float type, two
+    # values are added.
+    elif (type(a) is int and type(b) is int) \
+            or (type(a) is float or type(b) is float):
+        return a + b
+
+    # If both of args are string type,
+    # values are compared and bigger one is returned.
+    elif type(a) is str and type(b) is str:
+        if a < b: return b
+        return a
+
+    # If the first arg is None type, the second value is returned.
+    elif a is None:
+        return b
+
+    # Nothing matches above, the first arg is returned
+    return a
+
+def merge_oldnew(old, new):
+    """
+    Merges two arguments.  If old data contains the corresponding name
+    against new data, the value of the name is replaced with the
+    corresponding value in new data. Otherwise, the new date are added
+    at same name or same id. Both old data and new data should be same
+    data type. This method returns the merged result.
+    """
+    # If the first arg is dict or list type, two values
+    # would be merged
+    if type(old) is dict and type(new) is dict:
+        return dict([ (k, merge_oldnew(old[k], v)) \
+                          if k in old else (k, v) \
+                          for (k, v) in new.items() ] \
+                        + [ (k, v) \
+                                for (k, v) in old.items() \
+                                if k not in new ])
+    elif type(old) is list and type(new) is list:
+        return [ merge_oldnew(old[i], new[i]) \
+                     if len(old) > i else new[i] \
+                     for i in range(len(new)) ] \
+                     + [ old[i] \
+                             for i in range(len(old)) \
+                             if len(new) <= i ]
+    else:
+        return new
+
 class Callback():
     """
     A Callback handler class
@@ -129,8 +200,8 @@ class Stats:
         self.module_name = self.mccs.get_module_spec().get_module_name()
         self.modules = {}
         self.statistics_data = {}
-        # statistics data by each pid
-        self.statistics_data_bypid = {}
+        # statistics data by each mid
+        self.statistics_data_bymid = {}
         # get commands spec
         self.commands_spec = self.mccs.get_module_spec().get_commands_spec()
         # add event handler related command_handler of ModuleCCSession
@@ -144,51 +215,162 @@ class Stats:
                 self.callbacks[name] = Callback(command=callback, kwargs=kwargs)
             except AttributeError:
                 raise StatsError(STATS_UNKNOWN_COMMAND_IN_SPEC, cmd["command_name"])
+        self.config = {}
         self.mccs.start()
+        # setup my config
+        self.config = dict([
+                (itm['item_name'], self.mccs.get_value(itm['item_name'])[0])
+                for itm in self.mccs.get_module_spec().get_config_spec()
+                ])
+        # set a absolute timestamp polling at next time
+        self.next_polltime = get_timestamp() + self.get_interval()
+        # initialized Statistics data
+        self.update_modules()
+        if self.update_statistics_data(
+            self.module_name,
+            self.cc_session.lname,
+            {'lname': self.cc_session.lname,
+             'boot_time': get_datetime(_BASETIME),
+             'last_update_time': get_datetime()}):
+            logger.warn(STATS_RECEIVED_INVALID_STATISTICS_DATA,
+                        self.module_name)
+        # define the variable of the last time of polling
+        self._lasttime_poll = 0.0
+
+    def get_interval(self):
+        """return the current value of 'poll-interval'"""
+        return self.config['poll-interval']
+
+    def do_polling(self):
+        """Polls modules for statistics data. Return nothing. First
+           search multiple instances of same module. Second requests
+           each module to invoke 'getstats'. Finally updates internal
+           statistics data every time it gets from each instance."""
+
+        # It counts the number of instances of same module by
+        # examining the third value from the array result of
+        # 'show_processes' of Boss
+        seq = self.cc_session.group_sendmsg(
+            isc.config.ccsession.create_command("show_processes"),
+            'Boss')
+        (answer, env) = self.cc_session.group_recvmsg(False, seq)
+        modules = []
+        if answer:
+            (rcode, value) = isc.config.ccsession.parse_answer(answer)
+            if rcode == 0 and type(value) is list:
+                # NOTE: For example, the "show_processes" command
+                # of Boss is assumed to return the response in this
+                # format:
+                #  [
+                #  ...
+                #    [
+                #      20061,
+                #      "b10-auth",
+                #      "Auth"
+                #    ],
+                #    [
+                #      20103,
+                #      "b10-auth-2",
+                #      "Auth"
+                #    ]
+                #  ...
+                #  ]
+                # If multiple instances of the same module are
+                # running, the address names of them, which are at the
+                # third element, must be also same. Thus, the value of
+                # the third element of each outer element is read here
+                # for counting multiple instances.  This is a
+                # workaround for counting the instances. This should
+                # be fixed in another proper way in the future
+                # release.
+                modules = [ v[2] if type(v) is list and len(v) > 2 \
+                                else None for v in value ]
+        # start requesting each module to collect statistics data
+        sequences = []
+        for (module_name, data) in self.get_statistics_data().items():
+            # skip if module_name is 'Stats'
+            if module_name == self.module_name:
+                continue
+            logger.debug(DBG_STATS_MESSAGING, STATS_SEND_STATISTICS_REQUEST,
+                         module_name)
+            cmd = isc.config.ccsession.create_command(
+                "getstats", None) # no argument
+            seq = self.cc_session.group_sendmsg(cmd, module_name)
+            sequences.append((module_name, seq))
+            cnt = modules.count(module_name)
+            if cnt > 1:
+                sequences = sequences + [ (module_name, seq) \
+                                              for i in range(cnt-1) ]
+        # start receiving statistics data
+        _statistics_data = []
+        while len(sequences) > 0:
+            try:
+                (module_name, seq) = sequences.pop(0)
+                answer, env = self.cc_session.group_recvmsg(
+                    False, seq)
+                if answer:
+                    rcode, args = isc.config.ccsession.parse_answer(
+                        answer)
+                    if rcode == 0:
+                        _statistics_data.append(
+                            (module_name, env['from'], args))
+            # skip this module if SessionTimeout raised
+            except isc.cc.session.SessionTimeout:
+                pass
+
+        # update statistics data
+        self.update_modules()
+        while len(_statistics_data) > 0:
+            (_module_name, _lname, _args) = _statistics_data.pop(0)
+            if self.update_statistics_data(_module_name, _lname, _args):
+                logger.warn(
+                STATS_RECEIVED_INVALID_STATISTICS_DATA,
+                _module_name)
+            else:
+                if self.update_statistics_data(
+                    self.module_name,
+                    self.cc_session.lname,
+                    {'last_update_time': get_datetime()}):
+                    logger.warn(
+                        STATS_RECEIVED_INVALID_STATISTICS_DATA,
+                        self.module_name)
+        # if successfully done, set the last time of polling
+        self._lasttime_poll = get_timestamp()
 
     def start(self):
         """
         Start stats module
         """
-        self.running = True
         logger.info(STATS_STARTING)
 
-        # request Bob to send statistics data
-        logger.debug(DBG_STATS_MESSAGING, STATS_SEND_REQUEST_BOSS)
-        cmd = isc.config.ccsession.create_command("getstats", None)
-        seq = self.cc_session.group_sendmsg(cmd, 'Boss')
-        try:
-            answer, env = self.cc_session.group_recvmsg(False, seq)
-            if answer:
-                rcode, args = isc.config.ccsession.parse_answer(answer)
-                if rcode == 0:
-                    errors = self.update_statistics_data(
-                        args["owner"], **args["data"])
-                    if errors:
-                        raise StatsError("boss spec file is incorrect: "
-                                         + ", ".join(errors))
-                    errors = self.update_statistics_data(
-                                self.module_name,
-                                last_update_time=get_datetime())
-                    if errors:
-                        raise StatsError("stats spec file is incorrect: "
-                                         + ", ".join(errors))
-        except isc.cc.session.SessionTimeout:
-            pass
-
-        # initialized Statistics data
-        errors = self.update_statistics_data(
-            self.module_name,
-            lname=self.cc_session.lname,
-            boot_time=get_datetime(_BASETIME)
-            )
-        if errors:
-            raise StatsError("stats spec file is incorrect: "
-                             + ", ".join(errors))
+        def _check_command(nonblock=False):
+            """check invoked command by waiting for 'poll-interval'
+            seconds"""
+            # backup original timeout
+            orig_timeout = self.cc_session.get_timeout()
+            # set cc-session timeout to half of a second(500ms)
+            self.cc_session.set_timeout(500)
+            try:
+                answer, env = self.cc_session.group_recvmsg(nonblock)
+                self.mccs.check_command_without_recvmsg(answer, env)
+            except isc.cc.session.SessionTimeout:
+                pass # waited for poll-interval seconds
+            # restore timeout
+            self.cc_session.set_timeout(orig_timeout)
 
         try:
+            self.running = True
             while self.running:
-                self.mccs.check_command(False)
+                _check_command()
+                now = get_timestamp()
+                intval = self.get_interval()
+                if intval > 0 and now >= self.next_polltime:
+                    # decide the next polling timestamp
+                    self.next_polltime += intval
+                    # adjust next time
+                    if self.next_polltime < now:
+                        self.next_polltime = now
+                    self.do_polling()
         finally:
             self.mccs.send_stopping()
 
@@ -198,7 +380,21 @@ class Stats:
         """
         logger.debug(DBG_STATS_MESSAGING, STATS_RECEIVED_NEW_CONFIG,
                      new_config)
-        # do nothing currently
+        errors = []
+        if not self.mccs.get_module_spec().\
+                validate_config(False, new_config, errors):
+                return isc.config.ccsession.create_answer(
+                    1, ", ".join(errors))
+
+        if 'poll-interval' in new_config \
+                and new_config['poll-interval'] < 0:
+            return isc.config.ccsession.create_answer(
+                1, "Negative integer ignored")
+
+        self.config.update(new_config)
+        if 'poll-interval' in self.config:
+            # update next polling timestamp
+            self.next_polltime = get_timestamp() + self.get_interval()
         return isc.config.create_answer(0)
 
     def command_handler(self, command, kwargs):
@@ -248,7 +444,7 @@ class Stats:
         module. If it can't find specified statistics data, it raises
         StatsError.
         """
-        self.update_statistics_data()
+        self.update_modules()
         if owner and name:
             try:
                 return {owner:{name:self.statistics_data[owner][name]}}
@@ -267,14 +463,14 @@ class Stats:
                          + "owner: " + str(owner) + ", "
                          + "name: " + str(name))
 
-    def update_statistics_data(self, owner=None, pid=-1, **data):
+    def update_statistics_data(self, owner=None, mid=None, data=None):
         """
-        change statistics date of specified module into specified
+        change statistics data of specified module into specified
         data. It updates information of each module first, and it
         updates statistics data. If specified data is invalid for
         statistics spec of specified owner, it returns a list of error
         messages. If there is no error or if neither owner nor data is
-        specified in args, it returns None. pid is the process id of
+        specified in args, it returns None. The 'mid' argument is an identifier of
         the sender module in order for stats to identify which
         instance sends statistics data in the situation that multiple
         instances are working.
@@ -282,49 +478,32 @@ class Stats:
         # Note:
         # The fix of #1751 is for multiple instances working. It is
         # assumed here that they send different statistics data with
-        # each PID. Stats should save their statistics data by
-        # PID. The statistics data, which is the existing variable, is
-        # preserved by accumlating from statistics data by PID. This
+        # each sender module id (mid). Stats should save their statistics data by
+        # mid. The statistics data, which is the existing variable, is
+        # preserved by accumlating from statistics data by the mid. This
         # is an ad-hoc fix because administrators can not see
         # statistics by each instance via bindctl or HTTP/XML. These
         # interfaces aren't changed in this fix.
 
-        def _accum_bymodule(statistics_data_bypid):
-            # This is an internal function for the superordinate
-            # function. It accumulates statistics data of each PID by
-            # module. It returns the accumulation result.
-            def _accum(a, b):
-                # If the first arg is dict or list type, two values
-                # would be merged and accumlated.
-                if type(a) is dict:
-                    return dict([ (k, _accum(v, b[k])) \
-                                      if k in b else (k, v) \
-                                      for (k, v) in a.items() ] \
-                                    + [ (k, v) \
-                                            for (k, v) in b.items() \
-                                            if k not in a ])
-                elif type(a) is list:
-                    return [ _accum(a[i], b[i]) \
-                                 if len(b) > i else a[i] \
-                                 for i in range(len(a)) ] \
-                                 + [ b[i] \
-                                         for i in range(len(b)) \
-                                         if len(a) <= i ]
-                # If the first arg is integer or float type, two
-                # values are just added.
-                elif type(a) is int or type(a) is float:
-                    return a + b
-                # If the first arg is str or other types than above,
-                # then it just returns the first arg which is assumed
-                # to be the newer value.
-                return a
+        def _accum_bymodule(statistics_data_bymid):
+            """This is an internal method for the superordinate
+            method. It accumulates statistics data of each module id
+            by module. It returns a accumulated result."""
+            # FIXME: A issue might happen when consolidating
+            # statistics of the multiple instances. If they have
+            # different statistics data which are not for adding each
+            # other, this might happen: If these are integer or float,
+            # these are added each other. If these are string , these
+            # are compared and consolidated into bigger one.  If one
+            # of them is None type , these might be consolidated
+            # into not None-type one. Otherwise these are overwritten
+            # into one of them.
             ret = {}
-            for data in statistics_data_bypid.values():
+            for data in statistics_data_bymid.values():
                 ret.update(_accum(data, ret))
             return ret
 
         # Firstly, it gets default statistics data in each spec file.
-        self.update_modules()
         statistics_data = {}
         for (name, module) in self.modules.items():
             value = get_spec_defaults(module.get_statistics_spec())
@@ -333,62 +512,75 @@ class Stats:
         self.statistics_data = statistics_data
 
         # If the "owner" and "data" arguments in this function are
-        # specified, then the variable of statistics data of each pid
+        # specified, then the variable of statistics data of each module id
         # would be updated.
         errors = []
         if owner and data:
+            _data = self.statistics_data_bymid.copy()
             try:
-                if self.modules[owner].validate_statistics(False, data, errors):
-                    if owner in self.statistics_data_bypid:
-                        if pid in self.statistics_data_bypid[owner]:
-                            self.statistics_data_bypid[owner][pid].update(data)
+                for (_key, _val) in data.items():
+                    if self.modules[owner].validate_statistics(
+                        False, {_key: _val}, errors):
+                        if owner not in _data:
+                            _data[owner] = { mid: { _key: _val } }
+                        elif mid not in _data[owner]:
+                            _data[owner][mid] = { _key: _val }
                         else:
-                            self.statistics_data_bypid[owner][pid] = data
-                    else:
-                        self.statistics_data_bypid[owner] = { pid : data }
+                            # merge recursively old value and new
+                            # value each other
+                            _data[owner][mid] = \
+                                merge_oldnew(_data[owner][mid],
+                                             {_key: _val})
+                        continue
+                    # the key string might be a "xx/yy/zz[0]"
+                    # type. try it.
+                    if _key.find('/') >= 0 or \
+                            isc.cc.data.identifier_has_list_index(_key):
+                        # remove the last error
+                        if errors: errors.pop()
+                        # try updata and check validation in adavance
+                        __data = _data.copy()
+                        if owner not in _data:
+                            __data[owner] = {}
+                        if mid not in _data[owner]:
+                            __data[owner][mid] = {}
+                        # use the isc.cc.data.set method
+                        try:
+                            isc.cc.data.set(__data[owner][mid],
+                                            _key, _val)
+                            if self.modules[owner].validate_statistics(
+                                False, __data[owner][mid], errors):
+                                _data = __data
+                        except Exception as e:
+                            errors.append(
+                                "%s: %s" % (e.__class__.__name__, e))
             except KeyError:
                 errors.append("unknown module name: " + str(owner))
+            if not errors:
+                self.statistics_data_bymid = _data
+
+        # Just consolidate statistics data of each module without
+        # removing that of modules which have been already dead
+        mlist = [ k for k in self.statistics_data_bymid.keys() ]
+        for m in mlist:
+            if self.statistics_data_bymid[m]:
+                if m in self.statistics_data:
+                    # propagate the default values by times of
+                    # instances
+                    _len = len(self.statistics_data_bymid[m])
+                    for i in range(0, _len - 1):
+                        self.statistics_data[m] = _accum(
+                            self.statistics_data[m],
+                            self.statistics_data[m])
+                    # replace the default values with summaries of the
+                    # collected values of each module. But the default
+                    # values which are not included in collected
+                    # values are not replaced.
+                    self.statistics_data[m] = merge_oldnew(
+                        self.statistics_data[m],
+                        _accum_bymodule(
+                            self.statistics_data_bymid[m]))
 
-        # If there are inactive instances, which was actually running
-        # on the system before, their statistics data would be
-        # removed. To find inactive instances, it invokes the
-        # "show_processes" command to Boss via the cc session. Then it
-        # gets active instance list and compares its PIDs with PIDs in
-        # statistics data which it already has. If inactive instances
-        # are found, it would remove their statistics data.
-        seq = self.cc_session.group_sendmsg(
-            isc.config.ccsession.create_command("show_processes", None),
-            "Boss")
-        (answer, env) = self.cc_session.group_recvmsg(False, seq)
-        if answer:
-            (rcode, value) = isc.config.ccsession.parse_answer(answer)
-            if rcode == 0:
-                if type(value) is list and len(value) > 0 \
-                        and type(value[0]) is list and len(value[0]) > 1:
-                    mlist = [ k for k in self.statistics_data_bypid.keys() ]
-                    for m in mlist:
-                        # PID list which it has before except for -1
-                        plist1 = [ p for p in self.statistics_data_bypid[m]\
-                                       .keys() if p != -1]
-                        # PID list of active instances which is
-                        # received from Boss
-                        plist2 = [ v[0] for v in value \
-                                       if v[1].lower().find(m.lower()) \
-                                       >= 0 ]
-                        # get inactive instance list by the difference
-                        # between plist1 and plist2
-                        nplist = set(plist1).difference(set(plist2))
-                        for p in nplist:
-                            self.statistics_data_bypid[m].pop(p)
-                        if self.statistics_data_bypid[m]:
-                            if m in self.statistics_data:
-                                self.statistics_data[m].update(
-                                    _accum_bymodule(
-                                        self.statistics_data_bypid[m]))
-                        # remove statistics data of the module with no
-                        # PID
-                        else:
-                            self.statistics_data_bypid.pop(m)
         if errors: return errors
 
     def command_status(self):
@@ -413,6 +605,13 @@ class Stats:
         """
         handle show command
         """
+        # decide if polling should be done based on the the last time of
+        # polling. If more than one second has passed since the last
+        # request to each module, the stats module requests each module
+        # statistics data and then shows the latest result. Otherwise,
+        # the stats module just shows statistics data which it has.
+        if get_timestamp() - self._lasttime_poll > 1.0:
+            self.do_polling()
         if owner or name:
             logger.debug(DBG_STATS_MESSAGING,
                          STATS_RECEIVED_SHOW_NAME_COMMAND,
@@ -422,8 +621,9 @@ class Stats:
                          STATS_RECEIVED_SHOW_ALL_COMMAND)
         errors = self.update_statistics_data(
             self.module_name,
-            timestamp=get_timestamp(),
-            report_time=get_datetime()
+            self.cc_session.lname,
+            {'timestamp': get_timestamp(),
+             'report_time': get_datetime()}
             )
         if errors:
             raise StatsError("stats spec file is incorrect: "
@@ -474,22 +674,6 @@ class Stats:
                 1, "specified arguments are incorrect: " \
                     + "owner: " + str(owner) + ", name: " + str(name))
 
-    def command_set(self, owner, pid=-1, data={}):
-        """
-        handle set command
-        """
-        errors = self.update_statistics_data(owner, pid, **data)
-        if errors:
-            return isc.config.create_answer(
-                1, "errors while setting statistics data: " \
-                    + ", ".join(errors))
-        errors = self.update_statistics_data(
-            self.module_name, last_update_time=get_datetime() )
-        if errors:
-            raise StatsError("stats spec file is incorrect: "
-                             + ", ".join(errors))
-        return isc.config.create_answer(0)
-
 if __name__ == "__main__":
     try:
         parser = OptionParser()

+ 7 - 29
src/bin/stats/stats.spec

@@ -2,7 +2,13 @@
   "module_spec": {
     "module_name": "Stats",
     "module_description": "Stats daemon",
-    "config_data": [],
+    "config_data": [
+      { "item_name": "poll-interval",
+        "item_type": "integer",
+        "item_optional": true,
+        "item_default": 60
+      }
+    ],
     "commands": [
       {
         "command_name": "status",
@@ -59,34 +65,6 @@
             "item_description": "statistics item name of the owner"
           }
         ]
-      },
-      {
-        "command_name": "set",
-        "command_description": "set the value of specified name in statistics data",
-        "command_args": [
-          {
-            "item_name": "owner",
-            "item_type": "string",
-            "item_optional": false,
-            "item_default": "",
-            "item_description": "module name of the owner of the statistics data"
-          },
-	  {
-	    "item_name": "pid",
-            "item_type": "integer",
-            "item_optional": true,
-            "item_default": -1,
-            "item_description": "process id of the owner module"
-          },
-	  {
-	    "item_name": "data",
-            "item_type": "map",
-            "item_optional": false,
-            "item_default": {},
-            "item_description": "statistics data set of the owner",
-            "map_item_spec": []
-          }
-        ]
       }
     ],
     "statistics": [

+ 7 - 3
src/bin/stats/stats_messages.mes

@@ -1,4 +1,4 @@
-# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
 #
 # Permission to use, copy, modify, and/or distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -53,8 +53,12 @@ response indicating that it is running normally.
 An unknown command has been sent to the stats module. The stats module
 will respond with an error and the command will be ignored.
 
-% STATS_SEND_REQUEST_BOSS requesting boss to send statistics
-This debug message is printed when a request is sent to the boss module
+% STATS_RECEIVED_INVALID_STATISTICS_DATA received invalid statistics data from %1
+Invalid statistics data has been received from the module while
+polling and it has been discarded.
+
+% STATS_SEND_STATISTICS_REQUEST requesting %1 to send statistics
+This debug message is printed when a request is sent to the module
 to send its data to the stats module.
 
 % STATS_STARTING starting

+ 3 - 1
src/bin/stats/tests/Makefile.am

@@ -1,3 +1,5 @@
+SUBDIRS = testdata .
+
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = b10-stats_test.py b10-stats-httpd_test.py
 EXTRA_DIST = $(PYTESTS) test_utils.py
@@ -23,7 +25,7 @@ endif
 	PYTHONPATH=$(COMMON_PYTHON_PATH):$(abs_top_builddir)/src/bin/stats:$(abs_top_builddir)/src/bin/stats/tests:$(abs_top_builddir)/src/bin/msgq:$(abs_top_builddir)/src/lib/python/isc/config \
 	B10_FROM_SOURCE=$(abs_top_srcdir) \
 	BIND10_MSGQ_SOCKET_FILE=$(abs_top_builddir)/msgq_socket \
-	CONFIG_TESTDATA_PATH=$(abs_top_srcdir)/src/lib/config/tests/testdata \
+	CONFIG_TESTDATA_PATH=$(abs_top_srcdir)/src/bin/stats/tests/testdata \
 	B10_LOCKFILE_DIR_FROM_BUILD=$(abs_top_builddir) \
 	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

+ 7 - 1
src/bin/stats/tests/b10-stats-httpd_test.py

@@ -53,7 +53,13 @@ DUMMY_DATA = {
                 "zonename": "test.example",
                 "queries.tcp": 2,
                 "queries.udp": 3
-                }]
+                }],
+        "nds_queries.perzone": {
+                "test.example": {
+                    "queries.tcp": 2,
+                    "queries.udp": 3
+                  }
+                }
         },
     'Stats' : {
         "report_time": "2011-03-04T11:59:19Z",

Fichier diff supprimé car celui-ci est trop grand
+ 617 - 274
src/bin/stats/tests/b10-stats_test.py


+ 142 - 30
src/bin/stats/tests/test_utils.py

@@ -144,11 +144,71 @@ class MockBoss:
   "module_spec": {
     "module_name": "Boss",
     "module_description": "Mock Master process",
-    "config_data": [],
+    "config_data": [
+      {
+        "item_name": "components",
+        "item_type": "named_set",
+        "item_optional": false,
+        "item_default": {
+          "b10-stats": { "address": "Stats", "kind": "dispensable" },
+          "b10-cmdctl": { "special": "cmdctl", "kind": "needed" }
+        },
+        "named_set_item_spec": {
+          "item_name": "component",
+          "item_type": "map",
+          "item_optional": false,
+          "item_default": { },
+          "map_item_spec": [
+            {
+              "item_name": "special",
+              "item_optional": true,
+              "item_type": "string"
+            },
+            {
+              "item_name": "process",
+              "item_optional": true,
+              "item_type": "string"
+            },
+            {
+              "item_name": "kind",
+              "item_optional": false,
+              "item_type": "string",
+              "item_default": "dispensable"
+            },
+            {
+              "item_name": "address",
+              "item_optional": true,
+              "item_type": "string"
+            },
+            {
+              "item_name": "params",
+              "item_optional": true,
+              "item_type": "list",
+              "list_item_spec": {
+                "item_name": "param",
+                "item_optional": false,
+                "item_type": "string",
+                "item_default": ""
+              }
+            },
+            {
+              "item_name": "priority",
+              "item_optional": true,
+              "item_type": "integer"
+            }
+          ]
+        }
+      }
+    ],
     "commands": [
       {
-        "command_name": "sendstats",
-        "command_description": "Send data to a statistics module at once",
+        "command_name": "shutdown",
+        "command_description": "Shut down BIND 10",
+        "command_args": []
+      },
+      {
+        "command_name": "ping",
+        "command_description": "Ping the boss process",
         "command_args": []
       },
       {
@@ -185,10 +245,11 @@ class MockBoss:
         self.spec_file.close()
         self.cc_session = self.mccs._session
         self.got_command_name = ''
-        self.pid_list = [[ 9999, "b10-auth"   ],
-                         [ 9998, "b10-auth-2" ],
-                         [ 9997, "b10-auth-3" ],
-                         [ 9996, "b10-auth-4" ]]
+        self.pid_list = [[ 9999, "b10-auth", "Auth" ],
+                         [ 9998, "b10-auth-2", "Auth" ]]
+        self.statistics_data = {
+            'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', self._BASETIME)
+            }
 
     def run(self):
         self.mccs.start()
@@ -209,16 +270,9 @@ class MockBoss:
     def command_handler(self, command, *args, **kwargs):
         self._started.set()
         self.got_command_name = command
-        params = { "owner": "Boss",
-                   "data": {
-                'boot_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', self._BASETIME)
-                }
-                   }
-        if command == 'sendstats':
-            send_command("set", "Stats", params=params, session=self.cc_session)
-            return isc.config.create_answer(0)
-        elif command == 'getstats':
-            return isc.config.create_answer(0, params)
+        sdata = self.statistics_data
+        if command == 'getstats':
+            return isc.config.create_answer(0, sdata)
         elif command == 'show_processes':
             # Return dummy pids
             return isc.config.create_answer(
@@ -232,13 +286,7 @@ class MockAuth:
     "module_name": "Auth",
     "module_description": "Mock Authoritative service",
     "config_data": [],
-    "commands": [
-      {
-        "command_name": "sendstats",
-        "command_description": "Send data to a statistics module at once",
-        "command_args": []
-      }
-    ],
+    "commands": [],
     "statistics": [
       {
         "item_name": "queries.tcp",
@@ -306,6 +354,49 @@ class MockAuth:
             }
           ]
         }
+      },
+      {
+        "item_name": "nds_queries.perzone",
+        "item_type": "named_set",
+        "item_optional": false,
+        "item_default": {
+          "test10.example" : {
+            "queries.udp" : 1,
+            "queries.tcp" : 2
+          },
+          "test20.example" : {
+            "queries.udp" : 3,
+            "queries.tcp" : 4
+          }
+        },
+        "item_title": "Queries per zone",
+        "item_description": "Queries per zone",
+        "named_set_item_spec": {
+          "item_name": "zonename",
+          "item_type": "map",
+          "item_optional": false,
+          "item_default": {},
+          "item_title": "Zonename",
+          "item_description": "Zonename",
+          "map_item_spec": [
+            {
+              "item_name": "queries.udp",
+              "item_type": "integer",
+              "item_optional": false,
+              "item_default": 0,
+              "item_title": "Queries UDP per zone",
+              "item_description": "A number of UDP query counts per zone"
+            },
+            {
+              "item_name": "queries.tcp",
+              "item_type": "integer",
+              "item_optional": false,
+              "item_default": 0,
+              "item_title": "Queries TCP per zone",
+              "item_description": "A number of TCP query counts per zone"
+            }
+          ]
+        }
       }
     ]
   }
@@ -330,6 +421,12 @@ class MockAuth:
                 'queries.tcp': 5,
                 'queries.udp': 4
                 }]
+        self.nds_queries_per_zone = {
+            'test10.example': {
+                'queries.tcp': 5,
+                'queries.udp': 4
+                }
+            }
 
     def run(self):
         self.mccs.start()
@@ -349,12 +446,23 @@ class MockAuth:
 
     def command_handler(self, command, *args, **kwargs):
         self.got_command_name = command
-        if command == 'sendstats':
-            params = { "owner": "Auth",
-                       "data": { 'queries.tcp': self.queries_tcp,
-                                 'queries.udp': self.queries_udp,
-                                 'queries.perzone' : self.queries_per_zone } }
-            return send_command("set", "Stats", params=params, session=self.cc_session)
+        sdata = { 'queries.tcp': self.queries_tcp,
+                  'queries.udp': self.queries_udp,
+                  'queries.perzone' : self.queries_per_zone,
+                  'nds_queries.perzone' : {
+                    'test10.example': {
+                    'queries.tcp': \
+                      isc.cc.data.find(
+                        self.nds_queries_per_zone,
+                        'test10.example/queries.tcp')
+                    }
+                  },
+                  'nds_queries.perzone/test10.example/queries.udp' :
+                      isc.cc.data.find(self.nds_queries_per_zone,
+                                       'test10.example/queries.udp')
+                }
+        if command == 'getstats':
+            return isc.config.create_answer(0, sdata)
         return isc.config.create_answer(1, "Unknown Command")
 
 class MyStats(stats.Stats):
@@ -428,9 +536,13 @@ class BaseModules:
         # MockAuth
         self.auth = ThreadingServerManager(MockAuth)
         self.auth.run()
+        self.auth2 = ThreadingServerManager(MockAuth)
+        self.auth2.run()
+
 
     def shutdown(self):
         # MockAuth
+        self.auth2.shutdown()
         self.auth.shutdown()
         # MockBoss
         self.boss.shutdown()

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

@@ -0,0 +1 @@
+EXTRA_DIST = b10-config.db

+ 14 - 0
src/bin/stats/tests/testdata/b10-config.db

@@ -0,0 +1,14 @@
+{ "version": 2,
+  "Boss": {
+    "components": {
+      "b10-auth": {
+        "kind": "needed",
+        "special": "auth"
+      },
+      "b10-auth-2": {
+        "kind": "needed",
+        "special": "auth"
+      }
+    }
+  }
+}

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

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

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

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

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

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

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

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

+ 4 - 2
src/bin/xfrout/xfrout.spec.pre.in

@@ -17,7 +17,8 @@
          {
              "item_name": "acl_element",
              "item_type": "any",
-             "item_optional": true
+             "item_optional": true,
+             "item_default": {"action": "ACCEPT"}
          }
        },
        {
@@ -80,7 +81,8 @@
                    {
                        "item_name": "acl_element",
                        "item_type": "any",
-                       "item_optional": true
+                       "item_optional": true,
+                       "item_default": {"action": "ACCEPT"}
                    }
                }
              ]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 5 - 8
src/lib/cache/message_entry.cc

@@ -110,8 +110,7 @@ MessageEntry::getRRsetEntries(vector<RRsetEntryPtr>& rrset_entry_vec,
 void
 MessageEntry::addRRset(isc::dns::Message& message,
                        const vector<RRsetEntryPtr>& rrset_entry_vec,
-                       const isc::dns::Message::Section& section,
-                       bool dnssec_need)
+                       const isc::dns::Message::Section& section)
 {
     uint16_t start_index = 0;
     uint16_t end_index = answer_count_;
@@ -126,8 +125,7 @@ MessageEntry::addRRset(isc::dns::Message& message,
     }
 
     for (uint16_t index = start_index; index < end_index; ++index) {
-        message.addRRset(section, rrset_entry_vec[index]->getRRset(),
-                         dnssec_need);
+        message.addRRset(section, rrset_entry_vec[index]->getRRset());
     }
 }
 
@@ -156,10 +154,9 @@ MessageEntry::genMessage(const time_t& time_now,
         msg.setHeaderFlag(Message::HEADERFLAG_AA, false);
         msg.setHeaderFlag(Message::HEADERFLAG_TC, headerflag_tc_);
 
-        bool dnssec_need = msg.getEDNS().get();
-        addRRset(msg, rrset_entry_vec, Message::SECTION_ANSWER, dnssec_need);
-        addRRset(msg, rrset_entry_vec, Message::SECTION_AUTHORITY, dnssec_need);
-        addRRset(msg, rrset_entry_vec, Message::SECTION_ADDITIONAL, dnssec_need);
+        addRRset(msg, rrset_entry_vec, Message::SECTION_ANSWER);
+        addRRset(msg, rrset_entry_vec, Message::SECTION_AUTHORITY);
+        addRRset(msg, rrset_entry_vec, Message::SECTION_ADDITIONAL);
 
         return (true);
     }

+ 1 - 3
src/lib/cache/message_entry.h

@@ -154,11 +154,9 @@ protected:
     /// \param rrset_entry_vec vector for rrset entries in
     ///        different sections.
     /// \param section The section to add to
-    /// \param dnssec_need need dnssec records or not.
     void addRRset(isc::dns::Message& message,
                   const std::vector<RRsetEntryPtr>& rrset_entry_vec,
-                  const isc::dns::Message::Section& section,
-                  bool dnssec_need);
+                  const isc::dns::Message::Section& section);
 
     /// \brief Get the all the rrset entries for the message entry.
     ///

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

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

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

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

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

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

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

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

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

@@ -26,10 +26,10 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD =  $(GTEST_LDADD)
 run_unittests_LDADD += libfake_session.la
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
-run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/libb10-cfgclient.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/libb10-log.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 
 endif

+ 9 - 0
src/lib/config/tests/module_spec_unittests.cc

@@ -224,6 +224,15 @@ TEST(ModuleSpec, StatisticsValidation) {
     ElementPtr errors = Element::createList();
     EXPECT_FALSE(statisticsTestWithErrors(dd, "data33_2.data", errors));
     EXPECT_EQ("[ \"Format mismatch\", \"Format mismatch\", \"Format mismatch\" ]", errors->str());
+
+    dd = moduleSpecFromFile(specfile("spec41.spec"));
+
+    EXPECT_TRUE(statisticsTest(dd, "data41_1.data"));
+    EXPECT_FALSE(statisticsTest(dd, "data41_2.data"));
+
+    errors = Element::createList();
+    EXPECT_FALSE(statisticsTestWithErrors(dd, "data41_2.data", errors));
+    EXPECT_EQ("[ \"Type mismatch\" ]", errors->str());
 }
 
 TEST(ModuleSpec, CommandValidation) {

+ 3 - 0
src/lib/config/tests/testdata/Makefile.am

@@ -27,6 +27,8 @@ EXTRA_DIST += data32_2.data
 EXTRA_DIST += data32_3.data
 EXTRA_DIST += data33_1.data
 EXTRA_DIST += data33_2.data
+EXTRA_DIST += data41_1.data
+EXTRA_DIST += data41_2.data
 EXTRA_DIST += spec1.spec
 EXTRA_DIST += spec2.spec
 EXTRA_DIST += spec3.spec
@@ -67,3 +69,4 @@ EXTRA_DIST += spec37.spec
 EXTRA_DIST += spec38.spec
 EXTRA_DIST += spec39.spec
 EXTRA_DIST += spec40.spec
+EXTRA_DIST += spec41.spec

+ 0 - 0
src/lib/config/tests/testdata/data41_1.data


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff