Browse Source

sync with trunk

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac311@3018 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 14 years ago
parent
commit
31d34a20f7
100 changed files with 2017 additions and 936 deletions
  1. 48 0
      ChangeLog
  2. 2 1
      README
  3. 26 6
      configure.ac
  4. 46 25
      doc/guide/bind10-guide.html
  5. 46 10
      doc/guide/bind10-guide.xml
  6. 2 2
      src/bin/auth/Makefile.am
  7. 1 1
      src/bin/auth/asio_link.cc
  8. 1 1
      src/bin/auth/asio_link.h
  9. 23 17
      src/bin/auth/auth_srv.cc
  10. 21 1
      src/bin/auth/auth_srv.h
  11. 1 0
      src/bin/auth/b10-auth.8
  12. 3 0
      src/bin/auth/b10-auth.xml
  13. 20 0
      src/bin/auth/benchmarks/Makefile.am
  14. 179 0
      src/bin/auth/benchmarks/query_bench.cc
  15. 6 6
      src/bin/auth/main.cc
  16. 30 17
      src/bin/auth/tests/auth_srv_unittest.cc
  17. 1 1
      src/bin/bind10/Makefile.am
  18. 2 0
      src/bin/bind10/bind10.8
  19. 12 5
      src/bin/bind10/bind10.py.in
  20. 6 0
      src/bin/bind10/bind10.xml
  21. 1 1
      src/bin/bind10/tests/Makefile.am
  22. 1 1
      src/bin/bindctl/Makefile.am
  23. 0 1
      src/bin/bindctl/bindcmd.py
  24. 1 1
      src/bin/bindctl/tests/Makefile.am
  25. 1 1
      src/bin/cfgmgr/Makefile.am
  26. 1 1
      src/bin/cfgmgr/tests/Makefile.am
  27. 1 1
      src/bin/cmdctl/Makefile.am
  28. 8 2
      src/bin/cmdctl/cmdctl.py.in
  29. 1 1
      src/bin/cmdctl/tests/Makefile.am
  30. 1 2
      src/bin/loadzone/Makefile.am
  31. 1 1
      src/bin/loadzone/tests/correct/Makefile.am
  32. 1 1
      src/bin/loadzone/tests/error/Makefile.am
  33. 1 1
      src/bin/msgq/Makefile.am
  34. 1 1
      src/bin/msgq/tests/Makefile.am
  35. 1 1
      src/bin/xfrin/Makefile.am
  36. 5 0
      src/bin/xfrin/TODO
  37. 45 10
      src/bin/xfrin/b10-xfrin.8
  38. 62 17
      src/bin/xfrin/b10-xfrin.xml
  39. 1 1
      src/bin/xfrin/tests/Makefile.am
  40. 3 3
      src/bin/xfrin/tests/xfrin_test.py
  41. 3 4
      src/bin/xfrin/xfrin.py.in
  42. 1 1
      src/bin/xfrout/Makefile.am
  43. 2 1
      src/bin/xfrout/TODO
  44. 18 9
      src/bin/xfrout/b10-xfrout.8
  45. 27 9
      src/bin/xfrout/b10-xfrout.xml
  46. 1 1
      src/bin/xfrout/tests/Makefile.am
  47. 53 7
      src/bin/xfrout/tests/xfrout_test.py
  48. 43 45
      src/bin/xfrout/xfrout.py.in
  49. 11 1
      src/bin/zonemgr/Makefile.am
  50. 5 0
      src/bin/zonemgr/TODO
  51. 91 0
      src/bin/zonemgr/b10-zonemgr.8
  52. 205 0
      src/bin/zonemgr/b10-zonemgr.xml
  53. 1 1
      src/bin/zonemgr/tests/Makefile.am
  54. 13 10
      src/bin/zonemgr/zonemgr.py.in
  55. 1 1
      src/lib/bench/tests/benchmark_unittest.cc
  56. 112 84
      src/lib/cc/data.cc
  57. 106 68
      src/lib/cc/data.h
  58. 18 16
      src/lib/cc/session.cc
  59. 18 18
      src/lib/cc/session.h
  60. 141 92
      src/lib/cc/tests/data_unittests.cc
  61. 2 2
      src/lib/cc/tests/session_unittests.cc
  62. 68 57
      src/lib/config/ccsession.cc
  63. 33 20
      src/lib/config/ccsession.h
  64. 28 26
      src/lib/config/config_data.cc
  65. 11 5
      src/lib/config/config_data.h
  66. 1 1
      src/lib/config/documentation.txt
  67. 51 42
      src/lib/config/module_spec.cc
  68. 22 13
      src/lib/config/module_spec.h
  69. 3 5
      src/lib/config/tests/Makefile.am
  70. 16 16
      src/lib/config/tests/ccsession_unittests.cc
  71. 25 46
      src/lib/config/tests/fake_session.cc
  72. 19 21
      src/lib/config/tests/fake_session.h
  73. 5 4
      src/lib/config/tests/module_spec_unittests.cc
  74. 6 1
      src/lib/datasrc/data_source.cc
  75. 2 2
      src/lib/datasrc/data_source.h
  76. 1 1
      src/lib/datasrc/sqlite3_datasrc.cc
  77. 1 1
      src/lib/datasrc/sqlite3_datasrc.h
  78. 1 1
      src/lib/datasrc/static_datasrc.cc
  79. 1 1
      src/lib/datasrc/static_datasrc.h
  80. 19 1
      src/lib/datasrc/tests/datasrc_unittest.cc
  81. 6 6
      src/lib/datasrc/tests/sqlite3_unittest.cc
  82. 1 2
      src/lib/datasrc/tests/test_datasrc.cc
  83. 1 1
      src/lib/datasrc/tests/test_datasrc.h
  84. 2 2
      src/lib/dns/Makefile.am
  85. 0 71
      src/lib/dns/message_test.py
  86. 1 1
      src/lib/dns/messagerenderer.h
  87. 7 8
      src/lib/dns/name.cc
  88. 10 21
      src/lib/dns/python/Makefile.am
  89. 6 6
      src/lib/dns/python/README
  90. 12 10
      src/lib/dns/python/message_python.cc
  91. 1 1
      src/lib/dns/python/messagerenderer_python.cc
  92. 14 14
      src/lib/dns/python/name_python.cc
  93. 141 0
      src/lib/dns/python/pydnspp.cc
  94. 1 1
      src/lib/dns/python/libdns_python_common.cc
  95. 0 0
      src/lib/dns/python/pydnspp_common.h
  96. 2 3
      src/lib/dns/python/question_python.cc
  97. 5 5
      src/lib/dns/python/rdata_python.cc
  98. 6 6
      src/lib/dns/python/rrclass_python.cc
  99. 3 3
      src/lib/dns/python/rrset_python.cc
  100. 0 0
      src/lib/dns/python/rrttl_python.cc

+ 48 - 0
ChangeLog

@@ -1,3 +1,51 @@
+  98.	[build]		jinmei
+	The ./configure script now tries to search some common include
+	paths for boost header files to minimize the need for explicit
+	configuration with --with-boost-include. (Trac #323, svn r3006)
+
+  97.	[func]		jinmei
+	Added a micro benchmark test for query processing of b10-auth.
+	(Trac #308, svn r2982)
+
+  96.	[bug]		jinmei
+	Fixed two small issues with configure: Do not set CXXFLAGS so that
+	it can be customized; Make sure --disable-static works.
+	(Trac #325, r2976)
+
+bind10-devel-20100917 released on September 17, 2010 
+
+  95.	[doc]		jreed
+	Add b10-zonemgr manual page. Update other docs to introduce
+	this secondary manager. (Trac #341, svn r2951)
+
+  95.	[bug]		jreed
+	bin/xfrout and bin/zonemgr: Fixed some stderr output.
+	(Trac #342, svn r2949)
+
+  94.	[bug]		jelte
+  	bin/xfrout:  Fixed a problem in xfrout where only 2 or 3 RRs
+	were used per DNS message in the xfrout stream.
+	(Trac #334, r2931)
+
+  93.	[bug]		jinmei
+	lib/datasrc: A DS query could crash the library (and therefore,
+	e.g. the authoritative server) if some RR of the same apex name
+	is stored in the hot spot cache.  (Trac #307, svn r2923)
+
+  92.	[func]*		jelte
+	libdns_python (the python wrappers for libdns++) has been renamed
+	to pydnspp (Python DNS++). Programs and libraries that used
+	'import libdns_python' now need to use 'import pydnspp'.
+	(Trac #314, r2902)
+
+  91.	[func]*		jinmei
+	lib/cc: Use const pointers and const member functions for the API
+	as much as possible for safer operations.  Basically this does not
+	change the observable behavior, but some of the API were changed
+	in a backward incompatible manner.  This change also involves more
+	copies, but at this moment the overhead is deemed acceptable.
+	(Trac #310, r2803)
+
   90.	[build]		jinmei
   90.	[build]		jinmei
 	(Darwin/Mac OS X specific) Specify DYLD_LIBRARY_PATH for tests and
 	(Darwin/Mac OS X specific) Specify DYLD_LIBRARY_PATH for tests and
 	experimental run under the source tree.  Without this loadable
 	experimental run under the source tree.  Without this loadable

+ 2 - 1
README

@@ -17,7 +17,8 @@ This release includes the bind10 master process, b10-msgq message
 bus, b10-auth authoritative DNS server (with SQLite3 backend),
 bus, b10-auth authoritative DNS server (with SQLite3 backend),
 b10-cmdctl remote control daemon, b10-cfgmgr configuration manager,
 b10-cmdctl remote control daemon, b10-cfgmgr configuration manager,
 b10-xfrin AXFR inbound service, b10-xfrout outgoing AXFR service,
 b10-xfrin AXFR inbound service, b10-xfrout outgoing AXFR service,
-and a new libdns++ library for C++ with a python wrapper.
+b10-zonemgr secondary manager, and a new libdns++ library for C++
+with a python wrapper.
 
 
 Documentation is included and also available via the BIND 10
 Documentation is included and also available via the BIND 10
 website at http://bind10.isc.org/
 website at http://bind10.isc.org/

+ 26 - 6
configure.ac

@@ -40,6 +40,14 @@ AC_HELP_STRING([--enable-static-link],
   [enable_static_link=yes], [enable_static_link=no])
   [enable_static_link=yes], [enable_static_link=no])
 AM_CONDITIONAL(USE_STATIC_LINK, test $enable_static_link = yes)
 AM_CONDITIONAL(USE_STATIC_LINK, test $enable_static_link = yes)
 
 
+# Check validity about some libtool options
+if test $enable_static_link = yes -a $enable_static = no; then
+	AC_MSG_ERROR([--enable-static-link requires --enable-static])
+fi
+if test $enable_shared = no; then
+	AC_MSG_ERROR([BIND 10 requires shared libraries to be built])
+fi
+
 # OS dependent configuration
 # OS dependent configuration
 SET_ENV_LIBRARY_PATH=no
 SET_ENV_LIBRARY_PATH=no
 ENV_LIBRARY_PATH=LD_LIBRARY_PATH
 ENV_LIBRARY_PATH=LD_LIBRARY_PATH
@@ -167,7 +175,6 @@ LDFLAGS=$LDFLAGS_SAVED
 # specify the default warning flags in CXXFLAGS and let specific modules
 # specify the default warning flags in CXXFLAGS and let specific modules
 # "override" the default.
 # "override" the default.
 
 
-CXXFLAGS=-g
 werror_ok=0
 werror_ok=0
 
 
 # SunStudio compiler requires special compiler options for boost
 # SunStudio compiler requires special compiler options for boost
@@ -270,14 +277,31 @@ if test "$lcov" != "no"; then
 fi
 fi
 AC_SUBST(USE_LCOV)
 AC_SUBST(USE_LCOV)
 
 
+#
+# Configure Boost header path
+#
+# If explicitly specified, use it.
 AC_ARG_WITH([boost-include],
 AC_ARG_WITH([boost-include],
   AC_HELP_STRING([--with-boost-include=PATH],
   AC_HELP_STRING([--with-boost-include=PATH],
     [specify exact directory for Boost headers]),
     [specify exact directory for Boost headers]),
     [boost_include_path="$withval"])
     [boost_include_path="$withval"])
+# If not specified, try some common paths.
+if test -z "$with_boost_include"; then
+	boostdirs="/usr/local /usr/pkg /opt /opt/local"
+	for d in $boostdirs
+	do
+		if test -f $d/include/boost/shared_ptr.hpp; then
+			boost_include_path=$d/include
+			break
+		fi
+	done
+fi
 if test "${boost_include_path}" ; then
 if test "${boost_include_path}" ; then
 	BOOST_INCLUDES="-I${boost_include_path}"
 	BOOST_INCLUDES="-I${boost_include_path}"
 	CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES"
 	CPPFLAGS="$CPPFLAGS $BOOST_INCLUDES"
 fi
 fi
+AC_CHECK_HEADERS([boost/shared_ptr.hpp boost/foreach.hpp],,
+  AC_MSG_ERROR([Missing required header files.]))
 AC_SUBST(BOOST_INCLUDES)
 AC_SUBST(BOOST_INCLUDES)
 
 
 #
 #
@@ -389,10 +413,6 @@ if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GXX" = "Xyes"; then
 	CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
 	CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
 fi
 fi
 
 
-# Check for headers from required devel kits.
-AC_CHECK_HEADERS([boost/shared_ptr.hpp boost/foreach.hpp],,
-  AC_MSG_ERROR([Missing required header files.]))
-
 AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man],
 AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man],
   [regenerate man pages [default=no]])] ,enable_man=yes, enable_man=no)
   [regenerate man pages [default=no]])] ,enable_man=yes, enable_man=no)
 
 
@@ -423,6 +443,7 @@ AC_CONFIG_FILES([Makefile
                  src/bin/msgq/tests/Makefile
                  src/bin/msgq/tests/Makefile
                  src/bin/auth/Makefile
                  src/bin/auth/Makefile
                  src/bin/auth/tests/Makefile
                  src/bin/auth/tests/Makefile
+                 src/bin/auth/benchmarks/Makefile
                  src/bin/xfrin/Makefile
                  src/bin/xfrin/Makefile
                  src/bin/xfrin/tests/Makefile
                  src/bin/xfrin/tests/Makefile
                  src/bin/xfrout/Makefile
                  src/bin/xfrout/Makefile
@@ -544,7 +565,6 @@ Package:
 Flags:
 Flags:
   DEFS:          $DEFS
   DEFS:          $DEFS
   CPPFLAGS:      $CPPFLAGS
   CPPFLAGS:      $CPPFLAGS
-  CFLAGS:        $CFLAGS
   CXXFLAGS:      $CXXFLAGS
   CXXFLAGS:      $CXXFLAGS
   B10_CXXFLAGS:  $B10_CXXFLAGS
   B10_CXXFLAGS:  $B10_CXXFLAGS
 dnl includes too
 dnl includes too

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


+ 46 - 10
doc/guide/bind10-guide.xml

@@ -42,7 +42,7 @@
 
 
     <note>
     <note>
       <para>
       <para>
-        BIND 10, at this time, does not provide an recursive
+        BIND 10, at this time, does not provide a recursive
         DNS server. It does provide a EDNS0- and DNSSEC-capable
         DNS server. It does provide a EDNS0- and DNSSEC-capable
         authoritative DNS server.
         authoritative DNS server.
       </para>
       </para>
@@ -74,9 +74,9 @@
 	For this development prototype release, the only supported
 	For this development prototype release, the only supported
 	data source backend is SQLite3. The authoritative server
 	data source backend is SQLite3. The authoritative server
 	requires SQLite 3.3.9 or newer.
 	requires SQLite 3.3.9 or newer.
-        The <command>b10-xfrin</command> and <command>b10-xfrout</command>
+	The <command>b10-xfrin</command>, <command>b10-xfrout</command>,
-        modules require the libpython3 library and the Python
+	and <command>b10-zonemgr</command> modules require the
-        _sqlite3.so module.
+	libpython3 library and the Python _sqlite3.so module.
       </para></note>
       </para></note>
 <!-- TODO: this will change ... -->
 <!-- TODO: this will change ... -->
 
 
@@ -165,6 +165,15 @@
             </simpara>
             </simpara>
           </listitem>
           </listitem>
 
 
+          <listitem>
+            <simpara>
+              <command>b10-zonemgr</command> &mdash;
+              Secondary manager.
+	      This process keeps track of timers and other
+              necessary information for BIND 10 to act as a slave server.
+            </simpara>
+          </listitem>
+
         </itemizedlist>
         </itemizedlist>
       </para>
       </para>
 
 
@@ -650,8 +659,9 @@ var/
       The <command>bind10</command> master process will also start up
       The <command>bind10</command> master process will also start up
       <command>b10-cmdctl</command> for admins to communicate with the
       <command>b10-cmdctl</command> for admins to communicate with the
       system, <command>b10-auth</command> for Authoritative DNS service,
       system, <command>b10-auth</command> for Authoritative DNS service,
-      <command>b10-xfrin</command> for inbound DNS zone transfers.
+      <command>b10-xfrin</command> for inbound DNS zone transfers,
-      and <command>b10-xfrout</command> for outbound DNS zone transfers.
+      <command>b10-xfrout</command> for outbound DNS zone transfers,
+      and <command>b10-zonemgr</command> for secondary service.
     </para>
     </para>
 
 
     <section id="start">
     <section id="start">
@@ -1173,14 +1183,14 @@ TODO
       transfer. When received, it is stored in the BIND 10
       transfer. When received, it is stored in the BIND 10
       data store, and its records can be served by
       data store, and its records can be served by
       <command>b10-auth</command>.
       <command>b10-auth</command>.
-      This allows the BIND 10 server to provide
+      In combination with <command>b10-zonemgr</command> (for
-      <quote>secondary</quote> service.
+      automated SOA checks), this allows the BIND 10 server to
+      provide <quote>secondary</quote> service.
     </para>
     </para>
 
 
     <note><simpara>
     <note><simpara>
      The current development release of BIND 10 only supports
      The current development release of BIND 10 only supports
      AXFR. (IXFR is not supported.) 
      AXFR. (IXFR is not supported.) 
-     It also does not yet support automated SOA checks.
     </simpara></note>
     </simpara></note>
 
 
     <para>
     <para>
@@ -1204,12 +1214,13 @@ TODO
       sends the zone.
       sends the zone.
       This is used to provide master DNS service to share zones
       This is used to provide master DNS service to share zones
       to secondary name servers.
       to secondary name servers.
+      The <command>b10-xfrout</command> is also used to send
+      NOTIFY messages to slaves.
     </para>
     </para>
 
 
     <note><simpara>
     <note><simpara>
      The current development release of BIND 10 only supports
      The current development release of BIND 10 only supports
      AXFR. (IXFR is not supported.) 
      AXFR. (IXFR is not supported.) 
-     It also does not yet support NOTIFY.
      Access control is not yet provided.
      Access control is not yet provided.
     </simpara></note>
     </simpara></note>
 
 
@@ -1226,6 +1237,31 @@ what is XfroutClient xfr_client??
 
 
   </chapter>
   </chapter>
 
 
+  <chapter id="zonemgr">
+    <title>Secondary Manager</title>
+
+    <para>
+      The <command>b10-zonemgr</command> process is started by
+      <command>bind10</command>.
+      It keeps track of SOA refresh, retry, and expire timers
+      and other details for BIND 10 to perform as a slave.
+      When the <command>b10-auth</command> authoritative DNS server
+      receives a NOTIFY message, <command>b10-zonemgr</command>
+      may tell <command>b10-xfrin</command> to do a refresh
+      to start an inbound zone transfer.
+      The secondary manager resets its counters when a new zone is
+      transferred in.
+    </para>
+
+    <note><simpara>
+     Access control (such as allowing notifies) is not yet provided.
+     The primary/secondary service is not yet complete.
+    </simpara></note>
+
+<!-- TODO: lots to describe for zonemgr -->
+
+  </chapter>
+
 <!-- TODO: how to help: run unit tests, join lists, review trac tickets -->
 <!-- TODO: how to help: run unit tests, join lists, review trac tickets -->
 
 
   <!-- <index>    <title>Index</title> </index> -->
   <!-- <index>    <title>Index</title> </index> -->

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

@@ -1,4 +1,4 @@
-SUBDIRS = . tests
+SUBDIRS = . tests benchmarks
 
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
@@ -59,7 +59,7 @@ b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
 b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.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/cc/libcc.la
 b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-b10_auth_LDADD += $(top_builddir)/src/bin/auth/libasio_link.a
+b10_auth_LDADD += libasio_link.a
 b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
 b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
 b10_auth_LDADD += $(SQLITE_LIBS)
 b10_auth_LDADD += $(SQLITE_LIBS)
 
 

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

@@ -67,7 +67,7 @@ IOAddress::toText() const {
 // Note: this implementation is optimized for the case where this object
 // Note: this implementation is optimized for the case where this object
 // is created from an ASIO endpoint object in a receiving code path
 // is created from an ASIO endpoint object in a receiving code path
 // by avoiding to make a copy of the base endpoint.  For TCP it may not be
 // by avoiding to make a copy of the base endpoint.  For TCP it may not be
-// a bug deal, but when we receive UDP packets at a high rate, the copy
+// a big deal, but when we receive UDP packets at a high rate, the copy
 // overhead might be significant.
 // overhead might be significant.
 class TCPEndpoint : public IOEndpoint {
 class TCPEndpoint : public IOEndpoint {
 public:
 public:

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

@@ -207,7 +207,7 @@ public:
     /// will be thrown.
     /// will be thrown.
     ///
     ///
     /// Memory for the created object will be dynamically allocated.  It's
     /// Memory for the created object will be dynamically allocated.  It's
-    /// caller's responsibility to \c delete it later.
+    /// the caller's responsibility to \c delete it later.
     /// If resource allocation for the new object fails, a corresponding
     /// If resource allocation for the new object fails, a corresponding
     /// standard exception will be thrown.
     /// standard exception will be thrown.
     ///
     ///

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

@@ -69,7 +69,7 @@ private:
 public:
 public:
     AuthSrvImpl(const bool use_cache, AbstractXfroutClient& xfrout_client);
     AuthSrvImpl(const bool use_cache, AbstractXfroutClient& xfrout_client);
     ~AuthSrvImpl();
     ~AuthSrvImpl();
-    isc::data::ElementPtr setDbFile(const isc::data::ElementPtr config);
+    isc::data::ConstElementPtr setDbFile(isc::data::ConstElementPtr config);
 
 
     bool processNormalQuery(const IOMessage& io_message, Message& message,
     bool processNormalQuery(const IOMessage& io_message, Message& message,
                             MessageRenderer& response_renderer);
                             MessageRenderer& response_renderer);
@@ -193,6 +193,16 @@ AuthSrv::getVerbose() const {
 }
 }
 
 
 void
 void
+AuthSrv::setCacheSlots(const size_t slots) {
+    impl_->cache_.setSlots(slots);
+}
+
+size_t
+AuthSrv::getCacheSlots() const {
+    return (impl_->cache_.getSlots());
+}
+
+void
 AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
 AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
     impl_->xfrin_session_ = xfrin_session;
     impl_->xfrin_session_ = xfrin_session;
 }
 }
@@ -433,7 +443,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
     static const string command_template_end = "\"}]}";
     static const string command_template_end = "\"}]}";
 
 
     try {
     try {
-        ElementPtr notify_command = Element::fromJSON(
+        ConstElementPtr notify_command = Element::fromJSON(
                 command_template_start + question->getName().toText() + 
                 command_template_start + question->getName().toText() + 
                 command_template_master + remote_ip_address +
                 command_template_master + remote_ip_address +
                 command_template_rrclass + question->getClass().toText() +
                 command_template_rrclass + question->getClass().toText() +
@@ -441,7 +451,7 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
         const unsigned int seq =
         const unsigned int seq =
             xfrin_session_->group_sendmsg(notify_command, "Zonemgr",
             xfrin_session_->group_sendmsg(notify_command, "Zonemgr",
                                           "*", "*");
                                           "*", "*");
-        ElementPtr env, answer, parsed_answer;
+        ConstElementPtr env, answer, parsed_answer;
         xfrin_session_->group_recvmsg(env, answer, false, seq);
         xfrin_session_->group_recvmsg(env, answer, false, seq);
         int rcode;
         int rcode;
         parsed_answer = parseAnswer(rcode, answer);
         parsed_answer = parseAnswer(rcode, answer);
@@ -466,19 +476,17 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
     return (true);
     return (true);
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-AuthSrvImpl::setDbFile(const isc::data::ElementPtr config) {
+AuthSrvImpl::setDbFile(ConstElementPtr config) {
-    ElementPtr answer = isc::config::createAnswer();
+    ConstElementPtr answer = isc::config::createAnswer();
-    ElementPtr final;
 
 
     if (config && config->contains("database_file")) {
     if (config && config->contains("database_file")) {
         db_file_ = config->get("database_file")->stringValue();
         db_file_ = config->get("database_file")->stringValue();
-        final = config;
     } else if (config_session_ != NULL) {
     } else if (config_session_ != NULL) {
         bool is_default;
         bool is_default;
         string item("database_file");
         string item("database_file");
-        ElementPtr value = config_session_->getValue(is_default, item);
+        ConstElementPtr value = config_session_->getValue(is_default, item);
-        final = Element::createMap();
+        ElementPtr final = Element::createMap();
 
 
         // If the value is the default, and we are running from
         // If the value is the default, and we are running from
         // a specific directory ('from build'), we need to use
         // a specific directory ('from build'), we need to use
@@ -492,6 +500,7 @@ AuthSrvImpl::setDbFile(const isc::data::ElementPtr config) {
                                     "/bind10_zones.sqlite3");
                                     "/bind10_zones.sqlite3");
         }
         }
         final->set(item, value);
         final->set(item, value);
+        config = final;
 
 
         db_file_ = value->stringValue();
         db_file_ = value->stringValue();
     } else {
     } else {
@@ -508,7 +517,7 @@ AuthSrvImpl::setDbFile(const isc::data::ElementPtr config) {
     // fail, while acquiring resources in the RAII manner.  We then perform
     // fail, while acquiring resources in the RAII manner.  We then perform
     // delete and swap operations which should not fail.
     // delete and swap operations which should not fail.
     DataSrcPtr datasrc_ptr(DataSrcPtr(new Sqlite3DataSrc));
     DataSrcPtr datasrc_ptr(DataSrcPtr(new Sqlite3DataSrc));
-    datasrc_ptr->init(final);
+    datasrc_ptr->init(config);
     data_sources_.addDataSrc(datasrc_ptr);
     data_sources_.addDataSrc(datasrc_ptr);
 
 
     // The following code should be exception free.
     // The following code should be exception free.
@@ -520,15 +529,12 @@ AuthSrvImpl::setDbFile(const isc::data::ElementPtr config) {
     return (answer);
     return (answer);
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-AuthSrv::updateConfig(isc::data::ElementPtr new_config) {
+AuthSrv::updateConfig(ConstElementPtr new_config) {
     try {
     try {
         // the ModuleCCSession has already checked if we have
         // the ModuleCCSession has already checked if we have
         // the correct ElementPtr type as specified in our .spec file
         // the correct ElementPtr type as specified in our .spec file
-        ElementPtr answer = isc::config::createAnswer();
+        return (impl_->setDbFile(new_config));
-        answer = impl_->setDbFile(new_config);
-
-        return (answer);
     } catch (const isc::Exception& error) {
     } catch (const isc::Exception& error) {
         if (impl_->verbose_mode_) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-auth] error: " << error.what() << endl;
             cerr << "[b10-auth] error: " << error.what() << endl;

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

@@ -69,10 +69,30 @@ public:
                         isc::dns::MessageRenderer& response_renderer);
                         isc::dns::MessageRenderer& response_renderer);
     void setVerbose(bool on);
     void setVerbose(bool on);
     bool getVerbose() const;
     bool getVerbose() const;
-    isc::data::ElementPtr updateConfig(isc::data::ElementPtr config);
+    isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
     isc::config::ModuleCCSession* configSession() const;
     isc::config::ModuleCCSession* configSession() const;
     void setConfigSession(isc::config::ModuleCCSession* config_session);
     void setConfigSession(isc::config::ModuleCCSession* config_session);
 
 
+    /// \brief Set or update the size (number of slots) of hot spot cache.
+    ///
+    /// If the specified size is 0, it means the size will be unlimited.
+    /// The specified size is recorded even if the cache is disabled; the
+    /// new size will be effective when the cache is enabled.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param slots The number of cache slots.
+    void setCacheSlots(const size_t slots);
+
+    /// \brief Get the current size (number of slots) of hot spot cache.
+    ///
+    /// It always returns the recorded size regardless of the cache is enabled.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \return The current number of cache slots.
+    size_t getCacheSlots() const;
+
     ///
     ///
     /// Note: this interface is tentative.  We'll revisit the ASIO and session
     /// Note: this interface is tentative.  We'll revisit the ASIO and session
     /// frameworks, at which point the session will probably be passed on
     /// frameworks, at which point the session will probably be passed on

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

@@ -137,6 +137,7 @@ configuration is not defined\&.
 \fBb10-cmdctl\fR(8),
 \fBb10-cmdctl\fR(8),
 \fBb10-loadzone\fR(8),
 \fBb10-loadzone\fR(8),
 \fBb10-msgq\fR(8),
 \fBb10-msgq\fR(8),
+\fBb10-zonemgr\fR(8),
 \fBbind10\fR(8),
 \fBbind10\fR(8),
 BIND 10 Guide\&.
 BIND 10 Guide\&.
 .SH "HISTORY"
 .SH "HISTORY"

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

@@ -201,6 +201,9 @@
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       </citerefentry>,
       <citerefentry>
       <citerefentry>
+        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
       <citetitle>BIND 10 Guide</citetitle>.

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

@@ -0,0 +1,20 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+CLEANFILES = *.gcno *.gcda
+
+noinst_PROGRAMS = query_bench
+query_bench_SOURCES = query_bench.cc
+query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
+
+query_bench_LDADD = $(top_builddir)/src/lib/dns/libdns++.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/bin/auth/libasio_link.a
+query_bench_LDADD += $(SQLITE_LIBS)

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

@@ -0,0 +1,179 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <stdlib.h>
+
+#include <iostream>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+#include <bench/benchmark.h>
+#include <bench/benchmark_util.h>
+
+#include <dns/buffer.h>
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/question.h>
+#include <dns/rrclass.h>
+
+#include <xfr/xfrout_client.h>
+
+#include <auth/auth_srv.h>
+#include <auth/asio_link.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+using namespace isc::xfr;
+using namespace isc::bench;
+using namespace asio_link;
+
+namespace {
+// Commonly used constant:
+XfroutClient xfrout_client("dummy_path"); // path doesn't matter
+
+class QueryBenchMark {
+private:
+    // Maintain dynamically generated objects via shared pointers because
+    // QueryBenchMark objects will be copied.
+    typedef boost::shared_ptr<AuthSrv> AuthSrvPtr;
+    typedef boost::shared_ptr<const IOEndpoint> IOEndpointPtr;
+public:
+    QueryBenchMark(const int cache_slots, const char* const datasrc_file,
+                   const BenchQueries& queries, Message& query_message,
+                   MessageRenderer& renderer) :
+        server_(new AuthSrv(cache_slots >= 0 ? true : false, xfrout_client)),
+        queries_(queries),
+        query_message_(query_message),
+        renderer_(renderer),
+        dummy_socket(IOSocket::getDummyUDPSocket()),
+        dummy_endpoint(IOEndpointPtr(IOEndpoint::create(IPPROTO_UDP,
+                                                        IOAddress("192.0.2.1"),
+                                                        5300)))
+    {
+        if (cache_slots >= 0) {
+            server_->setCacheSlots(cache_slots);
+        }
+        server_->updateConfig(Element::fromJSON("{\"database_file\": \"" +
+                                                string(datasrc_file) + "\"}"));
+    }
+    unsigned int run() {
+        BenchQueries::const_iterator query;
+        const BenchQueries::const_iterator query_end = queries_.end();
+        for (query = queries_.begin(); query != query_end; ++query) {
+            IOMessage io_message(&(*query)[0], (*query).size(), dummy_socket,
+                                 *dummy_endpoint);
+            query_message_.clear(Message::PARSE);
+            renderer_.clear();
+            server_->processMessage(io_message, query_message_, renderer_);
+        }
+
+        return (queries_.size());
+    }
+private:
+    AuthSrvPtr server_;
+    const BenchQueries& queries_;
+    Message& query_message_;
+    MessageRenderer& renderer_;
+    IOSocket& dummy_socket;
+    IOEndpointPtr dummy_endpoint;
+};
+}
+
+namespace isc {
+namespace bench {
+template<>
+void
+BenchMark<QueryBenchMark>::printResult() const {
+    cout.precision(6);
+    cout << "Processed " << getIteration() << " queries in "
+         << fixed << getDuration() << "s";
+    cout.precision(2);
+    cout << " (" << fixed << getIterationPerSecond() << "qps)" << endl;
+}
+}
+}
+
+namespace {
+void
+usage() {
+    cerr << "Usage: query_bench [-n iterations] datasrc_file query_datafile"
+         << endl;
+    exit (1);
+}
+}
+
+int
+main(int argc, char* argv[]) {
+    int ch;
+    int iteration = 1;
+    while ((ch = getopt(argc, argv, "n:")) != -1) {
+        switch (ch) {
+        case 'n':
+            iteration = atoi(optarg);
+            break;
+        case '?':
+        default:
+            usage();
+        }
+    }
+    argc -= optind;
+    argv += optind;
+    if (argc < 2) {
+        usage();
+    }
+    const char* const datasrc_file = argv[0];
+    const char* const query_data_file = argv[1];
+
+    BenchQueries queries;
+    loadQueryData(query_data_file, queries, RRClass::IN());
+    OutputBuffer buffer(4096);
+    MessageRenderer renderer(buffer);
+    Message message(Message::PARSE);
+
+    cout << "Parameters:" << endl;
+    cout << "  Iterations: " << iteration << endl;
+    cout << "  Data Source: " << datasrc_file << endl;
+    cout << "  Query data: file=" << query_data_file << " (" << queries.size()
+         << " queries)" << endl << endl;
+
+    cout << "Benchmark enabling Hot Spot Cache with unlimited slots "
+         << endl;
+    BenchMark<QueryBenchMark>(iteration,
+                              QueryBenchMark(0, datasrc_file, queries, message,
+                                             renderer));
+
+    cout << "Benchmark enabling Hot Spot Cache with 10*#queries slots "
+         << endl;
+    BenchMark<QueryBenchMark>(iteration,
+                              QueryBenchMark(10 * queries.size(), datasrc_file,
+                                             queries, message, renderer));
+
+    cout << "Benchmark enabling Hot Spot Cache with #queries/2 slots "
+         << endl;
+    BenchMark<QueryBenchMark>(iteration,
+                              QueryBenchMark(queries.size() / 2, datasrc_file,
+                                             queries, message, renderer));
+
+    cout << "Benchmark disabling Hot Spot Cache" << endl;
+    BenchMark<QueryBenchMark>(iteration,
+                              QueryBenchMark(-1, datasrc_file, queries,
+                                             message, renderer));    
+
+    return (0);
+}

+ 6 - 6
src/bin/auth/main.cc

@@ -66,19 +66,19 @@ AuthSrv *auth_server;
 
 
 asio_link::IOService* io_service;
 asio_link::IOService* io_service;
 
 
-ElementPtr
+ConstElementPtr
-my_config_handler(ElementPtr new_config) {
+my_config_handler(ConstElementPtr new_config) {
     return (auth_server->updateConfig(new_config));
     return (auth_server->updateConfig(new_config));
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-my_command_handler(const string& command, const ElementPtr args) {
+my_command_handler(const string& command, ConstElementPtr args) {
-    ElementPtr answer = createAnswer();
+    ConstElementPtr answer = createAnswer();
 
 
     if (command == "print_message") {
     if (command == "print_message") {
         cout << args << endl;
         cout << args << endl;
         /* let's add that message to our answer as well */
         /* let's add that message to our answer as well */
-        answer->get("result")->add(args);
+        answer = createAnswer(0, args);
     } else if (command == "shutdown") {
     } else if (command == "shutdown") {
         io_service->stop();
         io_service->stop();
     }
     }

+ 30 - 17
src/bin/auth/tests/auth_srv_unittest.cc

@@ -85,26 +85,27 @@ private:
         {}
         {}
         virtual void establish(const char* socket_file);
         virtual void establish(const char* socket_file);
         virtual void disconnect();
         virtual void disconnect();
-        virtual int group_sendmsg(ElementPtr msg, string group,
+        virtual int group_sendmsg(ConstElementPtr msg, string group,
                                   string instance, string to);
                                   string instance, string to);
-        virtual bool group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+        virtual bool group_recvmsg(ConstElementPtr& envelope,
+                                   ConstElementPtr& msg,
                                    bool nonblock, int seq);
                                    bool nonblock, int seq);
         virtual void subscribe(string group, string instance);
         virtual void subscribe(string group, string instance);
         virtual void unsubscribe(string group, string instance);
         virtual void unsubscribe(string group, string instance);
         virtual void startRead(boost::function<void()> read_callback);
         virtual void startRead(boost::function<void()> read_callback);
-        virtual int reply(ElementPtr& envelope, ElementPtr& newmsg);
+        virtual int reply(ConstElementPtr envelope, ConstElementPtr newmsg);
-        virtual bool hasQueuedMsgs();
+        virtual bool hasQueuedMsgs() const;
         virtual void setTimeout(size_t timeout UNUSED_PARAM) {};
         virtual void setTimeout(size_t timeout UNUSED_PARAM) {};
         virtual size_t getTimeout() const { return 0; };
         virtual size_t getTimeout() const { return 0; };
 
 
-        void setMessage(ElementPtr msg) { msg_ = msg; }
+        void setMessage(ConstElementPtr msg) { msg_ = msg; }
         void disableSend() { send_ok_ = false; }
         void disableSend() { send_ok_ = false; }
         void disableReceive() { receive_ok_ = false; }
         void disableReceive() { receive_ok_ = false; }
 
 
-        ElementPtr sent_msg;
+        ConstElementPtr sent_msg;
         string msg_destination;
         string msg_destination;
     private:
     private:
-        ElementPtr msg_;
+        ConstElementPtr msg_;
         bool send_ok_;
         bool send_ok_;
         bool receive_ok_;
         bool receive_ok_;
     };
     };
@@ -174,19 +175,19 @@ AuthSrvTest::MockSession::startRead(
 {}
 {}
 
 
 int
 int
-AuthSrvTest::MockSession::reply(ElementPtr& envelope UNUSED_PARAM,
+AuthSrvTest::MockSession::reply(ConstElementPtr envelope UNUSED_PARAM,
-                                ElementPtr& newmsg UNUSED_PARAM)
+                                ConstElementPtr newmsg UNUSED_PARAM)
 {
 {
     return (-1);
     return (-1);
 }
 }
 
 
 bool
 bool
-AuthSrvTest::MockSession::hasQueuedMsgs() {
+AuthSrvTest::MockSession::hasQueuedMsgs() const {
     return (false);
     return (false);
 }
 }
 
 
 int
 int
-AuthSrvTest::MockSession::group_sendmsg(ElementPtr msg, string group,
+AuthSrvTest::MockSession::group_sendmsg(ConstElementPtr msg, string group,
                                         string instance UNUSED_PARAM,
                                         string instance UNUSED_PARAM,
                                         string to UNUSED_PARAM)
                                         string to UNUSED_PARAM)
 {
 {
@@ -200,8 +201,8 @@ AuthSrvTest::MockSession::group_sendmsg(ElementPtr msg, string group,
 }
 }
 
 
 bool
 bool
-AuthSrvTest::MockSession::group_recvmsg(ElementPtr& envelope UNUSED_PARAM,
+AuthSrvTest::MockSession::group_recvmsg(ConstElementPtr& envelope UNUSED_PARAM,
-                                        ElementPtr& msg,
+                                        ConstElementPtr& msg,
                                         bool nonblock UNUSED_PARAM,
                                         bool nonblock UNUSED_PARAM,
                                         int seq UNUSED_PARAM)
                                         int seq UNUSED_PARAM)
 {
 {
@@ -546,7 +547,8 @@ TEST_F(AuthSrvTest, notify) {
     EXPECT_EQ("Zonemgr", notify_session.msg_destination);
     EXPECT_EQ("Zonemgr", notify_session.msg_destination);
     EXPECT_EQ("notify",
     EXPECT_EQ("notify",
               notify_session.sent_msg->get("command")->get(0)->stringValue());
               notify_session.sent_msg->get("command")->get(0)->stringValue());
-    ElementPtr notify_args = notify_session.sent_msg->get("command")->get(1);
+    ConstElementPtr notify_args =
+        notify_session.sent_msg->get("command")->get(1);
     EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
     EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
     EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
     EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
               notify_args->get("master")->stringValue());
               notify_args->get("master")->stringValue());
@@ -574,7 +576,8 @@ TEST_F(AuthSrvTest, notifyForCHClass) {
 
 
     // Other conditions should be the same, so simply confirm the RR class is
     // Other conditions should be the same, so simply confirm the RR class is
     // set correctly.
     // set correctly.
-    ElementPtr notify_args = notify_session.sent_msg->get("command")->get(1);
+    ConstElementPtr notify_args =
+        notify_session.sent_msg->get("command")->get(1);
     EXPECT_EQ("CH", notify_args->get("zone_class")->stringValue());
     EXPECT_EQ("CH", notify_args->get("zone_class")->stringValue());
 }
 }
 
 
@@ -702,12 +705,12 @@ void
 updateConfig(AuthSrv* server, const char* const dbfile,
 updateConfig(AuthSrv* server, const char* const dbfile,
              const bool expect_success)
              const bool expect_success)
 {
 {
-    const ElementPtr config_answer =
+    ConstElementPtr config_answer =
         server->updateConfig(Element::fromJSON(dbfile));
         server->updateConfig(Element::fromJSON(dbfile));
     EXPECT_EQ(Element::map, config_answer->getType());
     EXPECT_EQ(Element::map, config_answer->getType());
     EXPECT_TRUE(config_answer->contains("result"));
     EXPECT_TRUE(config_answer->contains("result"));
 
 
-    const ElementPtr result = config_answer->get("result");
+    ConstElementPtr result = config_answer->get("result");
     EXPECT_EQ(Element::list, result->getType());
     EXPECT_EQ(Element::list, result->getType());
     EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
     EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
 }
 }
@@ -754,4 +757,14 @@ TEST_F(AuthSrvTest, updateConfigFail) {
     headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
     headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 }
+
+TEST_F(AuthSrvTest, cacheSlots) {
+    // simple check for the get/set operations
+    server.setCacheSlots(10);    // 10 = arbitrary choice
+    EXPECT_EQ(10, server.getCacheSlots());
+
+    // 0 is a valid size
+    server.setCacheSlots(0);
+    EXPECT_EQ(00, server.getCacheSlots());
+}
 }
 }

+ 1 - 1
src/bin/bind10/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 sbin_SCRIPTS = bind10
 sbin_SCRIPTS = bind10
 CLEANFILES = bind10 bind10.pyc
 CLEANFILES = bind10 bind10.pyc

+ 2 - 0
src/bin/bind10/bind10.8

@@ -101,6 +101,8 @@ and its child processes\&.
 \fBb10-cmdctl\fR(8),
 \fBb10-cmdctl\fR(8),
 \fBb10-msgq\fR(8),
 \fBb10-msgq\fR(8),
 \fBb10-xfrin\fR(8),
 \fBb10-xfrin\fR(8),
+\fBb10-xfrout\fR(8),
+\fBb10-zonemgr\fR(8),
 BIND 10 Guide\&.
 BIND 10 Guide\&.
 .SH "HISTORY"
 .SH "HISTORY"
 .PP
 .PP

+ 12 - 5
src/bin/bind10/bind10.py.in

@@ -18,7 +18,7 @@
 """\
 """\
 This file implements the Boss of Bind (BoB, or bob) program.
 This file implements the Boss of Bind (BoB, or bob) program.
 
 
-It's purpose is to start up the BIND 10 system, and then manage the
+Its purpose is to start up the BIND 10 system, and then manage the
 processes, by starting and stopping processes, plus restarting
 processes, by starting and stopping processes, plus restarting
 processes that exit.
 processes that exit.
 
 
@@ -65,7 +65,9 @@ import posix
 import isc.cc
 import isc.cc
 
 
 # This is the version that gets displayed to the user.
 # This is the version that gets displayed to the user.
-__version__ = "v20100531"
+# The VERSION string consists of the module name, the module version
+# number, and the overall BIND 10 version number (set in configure.ac).
+VERSION = "bind10 20100916 (BIND 10 @PACKAGE_VERSION@)"
 
 
 class RestartSchedule:
 class RestartSchedule:
     """
     """
@@ -627,7 +629,7 @@ def main():
 
 
 
 
     # Parse any command-line options.
     # Parse any command-line options.
-    parser = OptionParser(version=__version__)
+    parser = OptionParser(version=VERSION)
     parser.add_option("-a", "--address", dest="address", type="string",
     parser.add_option("-a", "--address", dest="address", type="string",
                       action="callback", callback=check_addr, default='',
                       action="callback", callback=check_addr, default='',
                       help="address the b10-auth daemon will use (default: listen on all addresses)")
                       help="address the b10-auth daemon will use (default: listen on all addresses)")
@@ -680,7 +682,7 @@ def main():
 
 
     # Announce startup.
     # Announce startup.
     if options.verbose:
     if options.verbose:
-        sys.stdout.write("BIND 10 %s\n" % __version__)
+        sys.stdout.write("%s\n" % VERSION)
 
 
     # TODO: set process name, perhaps by:
     # TODO: set process name, perhaps by:
     #       http://code.google.com/p/procname/
     #       http://code.google.com/p/procname/
@@ -735,7 +737,12 @@ def main():
 
 
         for fd in rlist + xlist:
         for fd in rlist + xlist:
             if fd == ccs_fd:
             if fd == ccs_fd:
-                boss_of_bind.ccs.check_command()
+                try:
+                    boss_of_bind.ccs.check_command()
+                except isc.cc.session.ProtocolError:
+                    if options.verbose:
+                        sys.stderr.write("[bind10] msgq channel disappeared.\n")
+                    break
             elif fd == wakeup_fd:
             elif fd == wakeup_fd:
                 os.read(wakeup_fd, 32)
                 os.read(wakeup_fd, 32)
 
 

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

@@ -189,6 +189,12 @@
       <citerefentry>
       <citerefentry>
         <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
         <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-xfrout</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
       <citetitle>BIND 10 Guide</citetitle>.
     </para>
     </para>
   </refsect1>
   </refsect1>

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

@@ -8,5 +8,5 @@ check-local:
 	for pytest in $(PYTESTS) ; do \
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done
 	done

+ 1 - 1
src/bin/bindctl/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 bin_SCRIPTS = bindctl
 bin_SCRIPTS = bindctl
 man_MANS = bindctl.1
 man_MANS = bindctl.1

+ 0 - 1
src/bin/bindctl/bindcmd.py

@@ -35,7 +35,6 @@ import os, time, random, re
 import getpass
 import getpass
 from hashlib import sha1
 from hashlib import sha1
 import csv
 import csv
-import json
 import pwd
 import pwd
 import getpass
 import getpass
 
 

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

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

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

@@ -1,4 +1,4 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 

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

@@ -9,5 +9,5 @@ check-local:
 	for pytest in $(PYTESTS) ; do \
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr \
-	$(PYCOVERAGE) $(abs_builddir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_builddir)/$$pytest || exit ; \
 	done
 	done

+ 1 - 1
src/bin/cmdctl/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 

+ 8 - 2
src/bin/cmdctl/cmdctl.py.in

@@ -380,6 +380,7 @@ class CommandControl():
     def send_command(self, module_name, command_name, params = None):
     def send_command(self, module_name, command_name, params = None):
         '''Send the command from bindctl to proper module. '''
         '''Send the command from bindctl to proper module. '''
         errstr = 'unknown error'
         errstr = 'unknown error'
+        answer = None
         if self._verbose:
         if self._verbose:
             self.log_info("Begin send command '%s' to module '%s'" %(command_name, module_name))
             self.log_info("Begin send command '%s' to module '%s'" %(command_name, module_name))
 
 
@@ -390,7 +391,10 @@ class CommandControl():
             msg = ccsession.create_command(command_name, params)
             msg = ccsession.create_command(command_name, params)
             seq = self._cc.group_sendmsg(msg, module_name)
             seq = self._cc.group_sendmsg(msg, module_name)
             #TODO, it may be blocked, msqg need to add a new interface waiting in timeout.
             #TODO, it may be blocked, msqg need to add a new interface waiting in timeout.
-            answer, env = self._cc.group_recvmsg(False, seq)
+            try:
+                answer, env = self._cc.group_recvmsg(False, seq)
+            except isc.cc.session.SessionTimeout:
+                errstr = "Module '%s' not responding" % module_name
 
 
         if self._verbose:
         if self._verbose:
             self.log_info("Finish send command '%s' to module '%s'" % (command_name, module_name))
             self.log_info("Finish send command '%s' to module '%s'" % (command_name, module_name))
@@ -410,7 +414,6 @@ class CommandControl():
             except ccsession.ModuleCCSessionError as mcse:
             except ccsession.ModuleCCSessionError as mcse:
                 errstr = str("Error in ccsession answer:") + str(mcse)
                 errstr = str("Error in ccsession answer:") + str(mcse)
                 self.log_info(errstr)
                 self.log_info(errstr)
-        
         return 1, {'error': errstr}
         return 1, {'error': errstr}
     
     
     def log_info(self, msg):
     def log_info(self, msg):
@@ -602,6 +605,9 @@ if __name__ == '__main__':
     except isc.cc.SessionError as err:
     except isc.cc.SessionError as err:
         sys.stderr.write("[b10-cmdctl] Error creating b10-cmdctl, "
         sys.stderr.write("[b10-cmdctl] Error creating b10-cmdctl, "
                          "is the command channel daemon running?\n")        
                          "is the command channel daemon running?\n")        
+    except isc.cc.SessionTimeout:
+        sys.stderr.write("[b10-cmdctl] Error creating b10-cmdctl, "
+                         "is the configuration manager running?\n")        
     except KeyboardInterrupt:
     except KeyboardInterrupt:
         sys.stderr.write("[b10-cmdctl] exit from Cmdctl\n")
         sys.stderr.write("[b10-cmdctl] exit from Cmdctl\n")
     except CmdctlException as err:
     except CmdctlException as err:

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

@@ -10,5 +10,5 @@ check-local:
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cmdctl \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cmdctl \
 	CMDCTL_SPEC_PATH=$(abs_top_builddir)/src/bin/cmdctl \
 	CMDCTL_SPEC_PATH=$(abs_top_builddir)/src/bin/cmdctl \
 	CMDCTL_SRC_PATH=$(abs_top_srcdir)/src/bin/cmdctl \
 	CMDCTL_SRC_PATH=$(abs_top_srcdir)/src/bin/cmdctl \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done
 	done

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

@@ -1,5 +1,4 @@
-SUBDIRS = tests/correct
+SUBDIRS = . tests/correct tests/error
-SUBDIRS += tests/error
 bin_SCRIPTS = b10-loadzone
 bin_SCRIPTS = b10-loadzone
 
 
 CLEANFILES = b10-loadzone
 CLEANFILES = b10-loadzone

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

@@ -21,5 +21,5 @@ check-local:
 	for pytest in $(PYTESTS) ; do \
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
-	$(SHELL) $(abs_builddir)/$$pytest ; \
+	$(SHELL) $(abs_builddir)/$$pytest || exit ; \
 	done
 	done

+ 1 - 1
src/bin/loadzone/tests/error/Makefile.am

@@ -21,5 +21,5 @@ check-local:
 	for pytest in $(PYTESTS) ; do \
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
-	$(SHELL) $(abs_builddir)/$$pytest ; \
+	$(SHELL) $(abs_builddir)/$$pytest || exit ; \
 	done
 	done

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

@@ -1,4 +1,4 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 pkglibexecdir = $(libexecdir)/@PACKAGE@
  
  

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

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

+ 1 - 1
src/bin/xfrin/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 

+ 5 - 0
src/bin/xfrin/TODO

@@ -63,3 +63,8 @@
     which a shutdown notification would be sent to the child.  With
     which a shutdown notification would be sent to the child.  With
     this approach each thread needs to watch at least two channels,
     this approach each thread needs to watch at least two channels,
     and then it would need some asynchronous communication mechanism.
     and then it would need some asynchronous communication mechanism.
+17. Do zone transfer from notifyfrom address first, if it's one master of the zone.
+18. Check soa serial first when doing zone refreshment.
+19. Add configuration items to seperate zone, including ACL, multiple masters, etc.
+20. Be able to cancel the ongoing zone transfer, and be able to disable zone transfer.
+

+ 45 - 10
src/bin/xfrin/b10-xfrin.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-xfrin
 .\"     Title: b10-xfrin
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: March 17, 2010
+.\"      Date: September 8, 2010
 .\"    Manual: BIND10
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"  Language: English
 .\"
 .\"
-.TH "B10\-XFRIN" "8" "March 17, 2010" "BIND10" "BIND10"
+.TH "B10\-XFRIN" "8" "September 8, 2010" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
@@ -47,7 +47,6 @@ The Y1 prototype release only supports AXFR\&. IXFR is not implemented\&.
 .sp .5v
 .sp .5v
 .RE
 .RE
 .PP
 .PP
-
 This daemon communicates with BIND 10 over a
 This daemon communicates with BIND 10 over a
 \fBb10-msgq\fR(8)
 \fBb10-msgq\fR(8)
 C\-Channel connection\&. If this connection is not established,
 C\-Channel connection\&. If this connection is not established,
@@ -60,24 +59,59 @@ receives its configurations from
 \fBb10-cfgmgr\fR(8)\&.
 \fBb10-cfgmgr\fR(8)\&.
 .SH "CONFIGURATION AND COMMANDS"
 .SH "CONFIGURATION AND COMMANDS"
 .PP
 .PP
-The configurable setting is
+The configurable settings are:
+.PP
+\fImaster_addr\fR
+The default is 127\&.0\&.0\&.1\&.
+.PP
+\fImaster_port\fR
+The default is 53\&.
+.PP
 \fItransfers\-in\fR
 \fItransfers\-in\fR
-which defines the maximum number of inbound zone transfers that can run concurrently\&. The default is 10\&.
+defines the maximum number of inbound zone transfers that can run concurrently\&. The default is 10\&.
 .PP
 .PP
 The configuration commands are:
 The configuration commands are:
 .PP
 .PP
 
 
-\fBshutdown\fR
+\fBnotify\fR
-stops all incoming zone transfers and exits
+is sent by
-\fBb10\-xfrin\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
+\fBb10-zonemgr\fR(8)
+when a DNS NOTIFY message is received to initiate a zone transfer\&.
+This is an internal command and not exposed to the administrator\&.
+.PP
+
+\fBrefresh\fR
+triggers the transfer in for a single zone\&. It is the same as
+\fBretransfer\fR
+except it checks the SOA serial first\&.
+This is an internal command and not exposed to the administrator\&.
+
+.PP
+
+\fBrefresh_from_zonemgr\fR
+is sent by
+\fBb10-zonemgr\fR(8)
+according to the SOA\'s REFRESH time to tell
+\fBb10\-xfrin\fR
+that the zone needs to do a zone refresh\&. This is an internal command and not exposed to the administrator\&.
 .PP
 .PP
 
 
 \fBretransfer\fR
 \fBretransfer\fR
 triggers the transfer in for a single zone without checking the zone\'s serial number\&. It has the following arguments:
 triggers the transfer in for a single zone without checking the zone\'s serial number\&. It has the following arguments:
 \fIzone_name\fR
 \fIzone_name\fR
-to define the zone to request and
+to define the zone to request,
+\fIzone_class\fR
+to define the class (defaults to
+\(lqIN\(rq),
 \fImaster\fR
 \fImaster\fR
-to define the IP address of the authoritative server to transfer from\&.
+to define the IP address of the authoritative server to transfer from, and
+\fIport\fR
+to define the port number on the authoritative server (defaults to 53)\&.
+.PP
+
+\fBshutdown\fR
+stops all incoming zone transfers and exits
+\fBb10\-xfrin\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
 .if n \{\
 .if n \{\
 .sp
 .sp
 .\}
 .\}
@@ -99,6 +133,7 @@ This prototype version uses SQLite3 as its data source backend\&. Future version
 
 
 \fBb10-cfgmgr\fR(8),
 \fBb10-cfgmgr\fR(8),
 \fBb10-msgq\fR(8),
 \fBb10-msgq\fR(8),
+\fBb10-zonemgr\fR(8),
 \fBbind10\fR(8),
 \fBbind10\fR(8),
 BIND 10 Guide\&.
 BIND 10 Guide\&.
 .SH "HISTORY"
 .SH "HISTORY"

+ 62 - 17
src/bin/xfrin/b10-xfrin.xml

@@ -21,7 +21,7 @@
 <refentry>
 <refentry>
 
 
   <refentryinfo>
   <refentryinfo>
-    <date>March 17, 2010</date>
+    <date>September 8, 2010</date>
   </refentryinfo>
   </refentryinfo>
 
 
   <refmeta>
   <refmeta>
@@ -68,7 +68,6 @@
     </simpara></note>
     </simpara></note>
 
 
     <para>
     <para>
-<!-- TODO: does it really use msgq? what for? -->
       This daemon communicates with BIND 10 over a
       This daemon communicates with BIND 10 over a
       <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       C-Channel connection.  If this connection is not established,
       C-Channel connection.  If this connection is not established,
@@ -85,42 +84,85 @@
   <refsect1>
   <refsect1>
     <title>CONFIGURATION AND COMMANDS</title>
     <title>CONFIGURATION AND COMMANDS</title>
     <para>
     <para>
-      The configurable setting is <varname>transfers-in</varname>
+      The configurable settings are:
-      which defines the maximum number of inbound zone transfers
+    </para>
+
+    <para><varname>master_addr</varname>
+<!-- TODO: how can there be a single setting for this? -->
+       The default is 127.0.0.1.
+    </para>
+
+    <para><varname>master_port</varname>
+<!-- TODO: what if custom is needed per zone? -->
+      The default is 53.
+    </para>
+
+    <para><varname>transfers-in</varname>
+      defines the maximum number of inbound zone transfers
       that can run concurrently. The default is 10.
       that can run concurrently. The default is 10.
     </para>
     </para>
 
 
 <!-- TODO: formating -->
 <!-- TODO: formating -->
-<!-- TODO: refresh is code but not in spec -->
-<!-- schedule immediate maintenance for a zone(check soa serial ) -->
     <para>
     <para>
       The configuration commands are:
       The configuration commands are:
     </para>
     </para>
+
+    <para>
+      <command>notify</command> is sent by
+      <citerefentry><refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      when a DNS NOTIFY message is received to initiate a zone
+      transfer.
+<!-- TODO: document that zonemgr or xfrin checks if it needs to or not -->
+      This is an internal command and not exposed to the administrator.
+<!-- not defined in spec -->
+    </para>
+
     <para>
     <para>
-      <command>shutdown</command> stops all incoming zone transfers
+      <command>refresh</command> triggers the transfer in for
-      and exits <command>b10-xfrin</command>. (Note that the BIND 10
+      a single zone.
-      boss process will restart this service.)
+      It is the same as <command>retransfer</command> except it
+      checks the SOA serial first.
+<!-- TODO more detail -->
+      This is an internal command and not exposed to the administrator.
+<!-- not defined in spec -->
+<!-- TODO: refresh is code but not in spec, see trac ticket #328 -->
     </para>
     </para>
+
+    <para>
+      <command>refresh_from_zonemgr</command> is sent by
+      <citerefentry><refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      according to the SOA's REFRESH time
+      to tell <command>b10-xfrin</command> that the zone needs to do
+      a zone refresh.
+      This is an internal command and not exposed to the administrator. 
+<!-- not defined in spec -->
+    </para>
+
     <para>
     <para>
       <command>retransfer</command> triggers the transfer in for
       <command>retransfer</command> triggers the transfer in for
       a single zone without checking the zone's serial number.
       a single zone without checking the zone's serial number.
       It has the following arguments: <varname>zone_name</varname>
       It has the following arguments: <varname>zone_name</varname>
-      to define the zone to request and <varname>master</varname>
+      to define the zone to request,
-      to define the IP address of the authoritative server to
+      <varname>zone_class</varname> to define the class (defaults to
-      transfer from.
+      <quote>IN</quote>),
+      <varname>master</varname> to define the IP address of
+      the authoritative server to transfer from,
+      and <varname>port</varname> to define the port number on the
+      authoritative server (defaults to 53).
+<!-- TODO: note: not documenting db_file since that will be removed. -->
      </para>
      </para>
 <!-- TODO: later hostname for master? -->
 <!-- TODO: later hostname for master? -->
 
 
+    <para>
+      <command>shutdown</command> stops all incoming zone transfers
+      and exits <command>b10-xfrin</command>. (Note that the BIND 10
+      boss process will restart this service.)
+    </para>
 <!-- TODO:
 <!-- TODO:
 add a usage example of xfrin -->
 add a usage example of xfrin -->
 
 
 <!-- TODO:
 <!-- TODO:
 
 
-port (defaults to 53)
-db_file (defaults to zone.sqlite3) --> <!-- TODO: fix this -->
-
-<!-- TODO:
-
  later it will can be triggered by :
  later it will can be triggered by :
 1.  Notify message from auth server.
 1.  Notify message from auth server.
 2.  Schedule zone transfer (determined by Refresh/Expire time in SOA record)
 2.  Schedule zone transfer (determined by Refresh/Expire time in SOA record)
@@ -182,6 +224,9 @@ operation
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       </citerefentry>,
       <citerefentry>
       <citerefentry>
+        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
       <citetitle>BIND 10 Guide</citetitle>.

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

@@ -16,5 +16,5 @@ check-local:
 	echo Running test: $$pytest ; \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	$(LIBRARY_PATH_PLACEHOLDER) \
 	$(LIBRARY_PATH_PLACEHOLDER) \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done
 	done

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

@@ -508,12 +508,12 @@ class TestXfrin(unittest.TestCase):
                                                   self.args)['result'][0], 1)
                                                   self.args)['result'][0], 1)
 
 
     def test_command_handler_retransfer_nomodule(self):
     def test_command_handler_retransfer_nomodule(self):
-        dns_module = sys.modules['libdns_python'] # this must exist
+        dns_module = sys.modules['pydnspp'] # this must exist
-        del sys.modules['libdns_python']
+        del sys.modules['pydnspp']
         self.assertEqual(self.xfr.command_handler("retransfer",
         self.assertEqual(self.xfr.command_handler("retransfer",
                                                   self.args)['result'][0], 1)
                                                   self.args)['result'][0], 1)
         # sys.modules is global, so we must recover it
         # sys.modules is global, so we must recover it
-        sys.modules['libdns_python'] = dns_module
+        sys.modules['pydnspp'] = dns_module
 
 
     def test_command_handler_refresh(self):
     def test_command_handler_refresh(self):
         # at this level, refresh is no different than retransfer.
         # at this level, refresh is no different than retransfer.

+ 3 - 4
src/bin/xfrin/xfrin.py.in

@@ -30,7 +30,7 @@ from optparse import OptionParser, OptionValueError
 from isc.config.ccsession import *
 from isc.config.ccsession import *
 from isc.notify import notify_out
 from isc.notify import notify_out
 try:
 try:
-    from libdns_python import *
+    from pydnspp import *
 except ImportError as e:
 except ImportError as e:
     # C++ loadable module may not be installed; even so the xfrin process
     # C++ loadable module may not be installed; even so the xfrin process
     # must keep running, so we warn about it and move forward.
     # must keep running, so we warn about it and move forward.
@@ -197,7 +197,6 @@ class XfrinConnection(asyncore.dispatcher):
                                             self._handle_xfrin_response)
                                             self._handle_xfrin_response)
 
 
                 self.log_msg(logstr + 'succeeded')
                 self.log_msg(logstr + 'succeeded')
-                ret = XFRIN_OK
 
 
         except XfrinException as e:
         except XfrinException as e:
             self.log_msg(e)
             self.log_msg(e)
@@ -523,8 +522,8 @@ class Xfrin:
 
 
     def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo,
     def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo,
                     check_soa = True):
                     check_soa = True):
-        if "libdns_python" not in sys.modules:
+        if "pydnspp" not in sys.modules:
-            return (1, "xfrin failed, can't load dns message python library: 'libdns_python'")
+            return (1, "xfrin failed, can't load dns message python library: 'pydnspp'")
 
 
         # check max_transfer_in, else return quota error
         # check max_transfer_in, else return quota error
         if self.recorder.count() >= self._max_transfers_in:
         if self.recorder.count() >= self._max_transfers_in:

+ 1 - 1
src/bin/xfrout/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 

+ 2 - 1
src/bin/xfrout/TODO

@@ -1 +1,2 @@
-Add unittest code.
+Add unittest code.
+Be able to cancel the outgoing zone transfer, and also be able to disable outgoing zone transfer.

+ 18 - 9
src/bin/xfrout/b10-xfrout.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-xfrout
 .\"     Title: b10-xfrout
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: April 20, 2010
+.\"      Date: September 8, 2010
 .\"    Manual: BIND10
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"  Language: English
 .\"
 .\"
-.TH "B10\-XFROUT" "8" "April 20, 2010" "BIND10" "BIND10"
+.TH "B10\-XFROUT" "8" "September 8, 2010" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" * set default formatting
 .\" -----------------------------------------------------------------
 .\" -----------------------------------------------------------------
@@ -27,7 +27,7 @@ b10-xfrout \- Outbound DNS zone transfer service
 .PP
 .PP
 The
 The
 \fBb10\-xfrout\fR
 \fBb10\-xfrout\fR
-daemon provides the BIND 10 outgoing DNS zone transfer service\&. Normally it is started by the
+daemon provides the BIND 10 outgoing DNS zone transfer service\&. It is also used to send outgoing NOTIFY messages\&. Normally it is started by the
 \fBbind10\fR(8)
 \fBbind10\fR(8)
 boss process\&. When the
 boss process\&. When the
 \fBb10\-auth\fR
 \fBb10\-auth\fR
@@ -67,13 +67,13 @@ receives its configurations from
 The configurable settings are:
 The configurable settings are:
 .PP
 .PP
 
 
-\fItransfers\-out\fR
-defines the maximum number of outgoing zone transfers that can run concurrently\&. The default is 10\&.
-.PP
-
 \fIdb_file\fR
 \fIdb_file\fR
 defines the path to the SQLite3 data store file\&. The default is
 defines the path to the SQLite3 data store file\&. The default is
 /usr/local/var/bind10\-devel/zone\&.sqlite3\&.
 /usr/local/var/bind10\-devel/zone\&.sqlite3\&.
+.PP
+
+\fItransfers_out\fR
+defines the maximum number of outgoing zone transfers that can run concurrently\&. The default is 10\&.
 .if n \{\
 .if n \{\
 .sp
 .sp
 .\}
 .\}
@@ -91,25 +91,34 @@ This prototype version uses SQLite3 as its data source backend\&. Future version
 .sp .5v
 .sp .5v
 .RE
 .RE
 .PP
 .PP
-The configuration command is:
+The configuration commands are:
 .PP
 .PP
 
 
 \fBshutdown\fR
 \fBshutdown\fR
 stops all outbound zone transfers and exits
 stops all outbound zone transfers and exits
 \fBb10\-xfrout\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
 \fBb10\-xfrout\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
+.PP
+
+\fBzone_new_data_ready\fR
+is sent from
+\fBb10-xfrin\fR(8)
+to indicate that the zone transferred in successfully\&. This triggers
+\fBb10\-xfrout\fR
+to send NOTIFY message(s)\&. This is an internal command and not exposed to the administrator\&.
 .SH "SEE ALSO"
 .SH "SEE ALSO"
 .PP
 .PP
 
 
 \fBb10-auth\fR(8),
 \fBb10-auth\fR(8),
 \fBb10-cfgmgr\fR(8),
 \fBb10-cfgmgr\fR(8),
 \fBb10-msgq\fR(8),
 \fBb10-msgq\fR(8),
+\fBb10-xfrin\fR(8),
 \fBbind10\fR(8),
 \fBbind10\fR(8),
 BIND 10 Guide\&.
 BIND 10 Guide\&.
 .SH "HISTORY"
 .SH "HISTORY"
 .PP
 .PP
 The
 The
 \fBb10\-xfrout\fR
 \fBb10\-xfrout\fR
-daemon was implemented in March 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project\&.
+daemon was first implemented in March 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project\&.
 .SH "COPYRIGHT"
 .SH "COPYRIGHT"
 .br
 .br
 Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
 Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")

+ 27 - 9
src/bin/xfrout/b10-xfrout.xml

@@ -21,7 +21,7 @@
 <refentry>
 <refentry>
 
 
   <refentryinfo>
   <refentryinfo>
-    <date>April 20, 2010</date>
+    <date>September 8, 2010</date>
   </refentryinfo>
   </refentryinfo>
 
 
   <refmeta>
   <refmeta>
@@ -54,6 +54,7 @@
     <title>DESCRIPTION</title>
     <title>DESCRIPTION</title>
     <para>The <command>b10-xfrout</command> daemon provides the BIND 10
     <para>The <command>b10-xfrout</command> daemon provides the BIND 10
       outgoing DNS zone transfer service.
       outgoing DNS zone transfer service.
+      It is also used to send outgoing NOTIFY messages.
       Normally it is started by the
       Normally it is started by the
       <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       boss process.
       boss process.
@@ -93,17 +94,21 @@
       The configurable settings are:
       The configurable settings are:
     </para>
     </para>
     <para>
     <para>
-      <varname>transfers-out</varname>
-      defines the maximum number of outgoing zone transfers
-      that can run concurrently. The default is 10.
-    </para>
-    <para>
       <varname>db_file</varname>
       <varname>db_file</varname>
       defines the path to the SQLite3 data store file.
       defines the path to the SQLite3 data store file.
       The default is
       The default is
       <filename>/usr/local/var/bind10-devel/zone.sqlite3</filename>.
       <filename>/usr/local/var/bind10-devel/zone.sqlite3</filename>.
+<!-- TODO: db_file will be removed -->
+    </para>
+    <para>
+      <varname>transfers_out</varname>
+      defines the maximum number of outgoing zone transfers
+      that can run concurrently. The default is 10.
     </para>
     </para>
 
 
+<!-- TODO: log configurations not documented yet in here. jreed
+     has some but waiting on decisions ... -->
+
     <note><simpara>
     <note><simpara>
       This prototype version uses SQLite3 as its data source backend.
       This prototype version uses SQLite3 as its data source backend.
       Future versions will be configurable, supporting multiple
       Future versions will be configurable, supporting multiple
@@ -112,7 +117,7 @@
 
 
 <!-- TODO: formating -->
 <!-- TODO: formating -->
     <para>
     <para>
-      The configuration command is:
+      The configuration commands are:
     </para>
     </para>
     <para>
     <para>
       <command>shutdown</command> stops all outbound zone transfers
       <command>shutdown</command> stops all outbound zone transfers
@@ -120,6 +125,16 @@
       boss process will restart this service.)
       boss process will restart this service.)
     </para>
     </para>
 
 
+    <para>
+      <command>zone_new_data_ready</command> is sent from
+      <citerefentry><refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      to indicate that the zone transferred in successfully.
+      This triggers <command>b10-xfrout</command> to send NOTIFY
+      message(s).
+      This is an internal command and not exposed to the administrator.
+<!-- not defined in spec -->
+    </para>
+
   </refsect1>
   </refsect1>
 
 
 <!--
 <!--
@@ -161,6 +176,9 @@
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       </citerefentry>,
       <citerefentry>
       <citerefentry>
+        <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
       <citetitle>BIND 10 Guide</citetitle>.
@@ -170,8 +188,8 @@
   <refsect1>
   <refsect1>
     <title>HISTORY</title>
     <title>HISTORY</title>
     <para>
     <para>
-      The <command>b10-xfrout</command> daemon was implemented in March 2010
+      The <command>b10-xfrout</command> daemon was first implemented
-      by Zhang Likun of CNNIC for the ISC BIND 10 project.
+      in March 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project.
     </para>
     </para>
   </refsect1>
   </refsect1>
 </refentry><!--
 </refentry><!--

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

@@ -16,5 +16,5 @@ check-local:
 	echo Running test: $$pytest ; \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
 	$(LIBRARY_PATH_PLACEHOLDER) \
 	$(LIBRARY_PATH_PLACEHOLDER) \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done
 	done

+ 53 - 7
src/bin/xfrout/tests/xfrout_test.py

@@ -19,7 +19,7 @@
 import unittest
 import unittest
 import os
 import os
 from isc.cc.session import *
 from isc.cc.session import *
-from libdns_python import *
+from pydnspp import *
 from xfrout import *
 from xfrout import *
 
 
 # our fake socket, where we can read and insert messages
 # our fake socket, where we can read and insert messages
@@ -40,8 +40,12 @@ class MySocket():
         return len(data)
         return len(data)
 
 
     def readsent(self):
     def readsent(self):
-        result = self.sendqueue[:]
+        if len(self.sendqueue) >= 2:
-        del self.sendqueue[:]
+            size = 2 + struct.unpack("!H", self.sendqueue[:2])[0]
+        else:
+            size = 0
+        result = self.sendqueue[:size]
+        self.sendqueue = self.sendqueue[size:]
         return result
         return result
     
     
     def read_msg(self):
     def read_msg(self):
@@ -133,7 +137,7 @@ class TestXfroutSession(unittest.TestCase):
 
 
         msg = self.getmsg()
         msg = self.getmsg()
         msg.make_response()
         msg.make_response()
-        self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa)
+        self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 0)
         get_msg = self.sock.read_msg()
         get_msg = self.sock.read_msg()
 
 
         self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 1)
         self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 1)
@@ -148,10 +152,52 @@ class TestXfroutSession(unittest.TestCase):
         rdata = answer.get_rdata()
         rdata = answer.get_rdata()
         self.assertEqual(rdata[0].to_text(), self.soa_record[7])
         self.assertEqual(rdata[0].to_text(), self.soa_record[7])
 
 
-    def test_get_message_len(self):
+    def test_trigger_send_message_with_last_soa(self):
+        rrset_a = RRset(Name("example.com"), RRClass.IN(), RRType.A(), RRTTL(3600))
+        rrset_a.add_rdata(Rdata(RRType.A(), RRClass.IN(), "192.0.2.1"))
+        rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
+
         msg = self.getmsg()
         msg = self.getmsg()
-        msg.make_response()  
+        msg.make_response()
-        self.assertEqual(self.xfrsess._get_message_len(msg), 29)
+
+        msg.add_rrset(Section.ANSWER(), rrset_a)
+        # give the function a value that is larger than MAX-len(rrset)
+        self.xfrsess._send_message_with_last_soa(msg, self.sock, rrset_soa, 65520)
+
+        # this should have triggered the sending of two messages
+        # (1 with the rrset we added manually, and 1 that triggered
+        # the sending in _with_last_soa)
+        get_msg = self.sock.read_msg()
+        self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 1)
+        self.assertEqual(get_msg.get_rr_count(Section.ANSWER()), 1)
+        self.assertEqual(get_msg.get_rr_count(Section.AUTHORITY()), 0)
+
+        answer = get_msg.get_section(Section.ANSWER())[0]
+        self.assertEqual(answer.get_name().to_text(), "example.com.")
+        self.assertEqual(answer.get_class(), RRClass("IN"))
+        self.assertEqual(answer.get_type().to_text(), "A")
+        rdata = answer.get_rdata()
+        self.assertEqual(rdata[0].to_text(), "192.0.2.1")
+
+        get_msg = self.sock.read_msg()
+        self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 0)
+        self.assertEqual(get_msg.get_rr_count(Section.ANSWER()), 1)
+        self.assertEqual(get_msg.get_rr_count(Section.AUTHORITY()), 0)
+
+        #answer_rrset_iter = section_iter(get_msg, section.ANSWER())
+        answer = get_msg.get_section(Section.ANSWER())[0]
+        self.assertEqual(answer.get_name().to_text(), "example.com.")
+        self.assertEqual(answer.get_class(), RRClass("IN"))
+        self.assertEqual(answer.get_type().to_text(), "SOA")
+        rdata = answer.get_rdata()
+        self.assertEqual(rdata[0].to_text(), self.soa_record[7])
+
+        # and it should not have sent anything else
+        self.assertEqual(0, len(self.sock.sendqueue))
+
+    def test_get_rrset_len(self):
+        rrset_soa = self.xfrsess._create_rrset_from_db_record(self.soa_record)
+        self.assertEqual(82, get_rrset_len(rrset_soa))
 
 
     def test_zone_is_empty(self):
     def test_zone_is_empty(self):
         global sqlite3_ds
         global sqlite3_ds

+ 43 - 45
src/bin/xfrout/xfrout.py.in

@@ -27,7 +27,7 @@ from socketserver import *
 import os
 import os
 from isc.config.ccsession import *
 from isc.config.ccsession import *
 from isc.log.log import *
 from isc.log.log import *
-from isc.cc import SessionError
+from isc.cc import SessionError, SessionTimeout
 from isc.notify import notify_out
 from isc.notify import notify_out
 import socket
 import socket
 import select
 import select
@@ -35,7 +35,7 @@ import errno
 from optparse import OptionParser, OptionValueError
 from optparse import OptionParser, OptionValueError
 try:
 try:
     from libxfr_python import *
     from libxfr_python import *
-    from libdns_python import *
+    from pydnspp import *
 except ImportError as e:
 except ImportError as e:
     # C++ loadable module may not be installed; even so the xfrout process
     # C++ loadable module may not be installed; even so the xfrout process
     # must keep running, so we warn about it and move forward.
     # must keep running, so we warn about it and move forward.
@@ -57,6 +57,15 @@ AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + os.sep + "auth.spec"
 MAX_TRANSFERS_OUT = 10
 MAX_TRANSFERS_OUT = 10
 VERBOSE_MODE = False
 VERBOSE_MODE = False
 
 
+XFROUT_MAX_MESSAGE_SIZE = 65535
+
+def get_rrset_len(rrset):
+    """Returns the wire length of the given RRset"""
+    bytes = bytearray()
+    rrset.to_wire(bytes)
+    return len(bytes)
+
+
 class XfroutSession(BaseRequestHandler):
 class XfroutSession(BaseRequestHandler):
     def __init__(self, request, client_address, server, log):
     def __init__(self, request, client_address, server, log):
         # The initializer for the superclass may call functions
         # The initializer for the superclass may call functions
@@ -121,10 +130,8 @@ class XfroutSession(BaseRequestHandler):
 
 
 
 
     def _send_message(self, sock, msg):
     def _send_message(self, sock, msg):
-        #obuf = output_buffer(0)
-        #render = message_render(obuf)
         render = MessageRenderer()
         render = MessageRenderer()
-        render.set_length_limit(65535)
+        render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
         msg.to_wire(render)
         msg.to_wire(render)
         header_len = struct.pack('H', socket.htons(render.get_length()))
         header_len = struct.pack('H', socket.htons(render.get_length()))
         self._send_data(sock, header_len)
         self._send_data(sock, header_len)
@@ -227,34 +234,20 @@ class XfroutSession(BaseRequestHandler):
         rrset_.add_rdata(rdata_)
         rrset_.add_rdata(rdata_)
         return rrset_
         return rrset_
          
          
-    def _send_message_with_last_soa(self, msg, sock, rrset_soa):
+    def _send_message_with_last_soa(self, msg, sock, rrset_soa, message_upper_len):
         '''Add the SOA record to the end of message. If it can't be
         '''Add the SOA record to the end of message. If it can't be
         added, a new message should be created to send out the last soa .
         added, a new message should be created to send out the last soa .
         '''
         '''
+        rrset_len = get_rrset_len(rrset_soa)
 
 
-        render = MessageRenderer()
+        if message_upper_len + rrset_len < XFROUT_MAX_MESSAGE_SIZE:
-        msg.to_wire(render)
+            msg.add_rrset(Section.ANSWER(), rrset_soa)
-        old_message_len = render.get_length()
-        msg.add_rrset(Section.ANSWER(), rrset_soa)
-
-        msg.to_wire(render)
-        message_len = render.get_length()
-
-        if message_len != old_message_len:
-            self._send_message(sock, msg)
         else:
         else:
+            self._send_message(sock, msg)
             msg = self._clear_message(msg)
             msg = self._clear_message(msg)
             msg.add_rrset(Section.ANSWER(), rrset_soa)
             msg.add_rrset(Section.ANSWER(), rrset_soa)
-            self._send_message(sock, msg)
-
-    def _get_message_len(self, msg):
-        '''Get message length, every time need do like this? Actually there should be 
-        a better way, I need check with jinmei later.
-        '''
 
 
-        render = MessageRenderer()
+        self._send_message(sock, msg)
-        msg.to_wire(render)
-        return render.get_length()
 
 
 
 
     def _reply_xfrout_query(self, msg, sock, zone_name):
     def _reply_xfrout_query(self, msg, sock, zone_name):
@@ -265,9 +258,8 @@ class XfroutSession(BaseRequestHandler):
         rrset_soa = self._create_rrset_from_db_record(soa_record)
         rrset_soa = self._create_rrset_from_db_record(soa_record)
         msg.add_rrset(Section.ANSWER(), rrset_soa)
         msg.add_rrset(Section.ANSWER(), rrset_soa)
 
 
-        old_message_len = 0
+        message_upper_len = get_rrset_len(rrset_soa)
-        # TODO, Since add_rrset() return nothing when rrset can't be added, so I have to compare
+
-        # the message length to know if the rrset has been added sucessfully.
         for rr_data in sqlite3_ds.get_zone_datas(zone_name, self.server.get_db_file()):
         for rr_data in sqlite3_ds.get_zone_datas(zone_name, self.server.get_db_file()):
             if  self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
             if  self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
                 self._log.log_message("error", "shutdown!")
                 self._log.log_message("error", "shutdown!")
@@ -277,19 +269,22 @@ class XfroutSession(BaseRequestHandler):
                 continue
                 continue
 
 
             rrset_ = self._create_rrset_from_db_record(rr_data)
             rrset_ = self._create_rrset_from_db_record(rr_data)
-            msg.add_rrset(Section.ANSWER(), rrset_)
+
-            message_len = self._get_message_len(msg)
+            # We calculate the maximum size of the RRset (i.e. the
-            if message_len != old_message_len:
+            # size without compression) and use that to see if we
-                old_message_len = message_len
+            # may have reached the limit
+            rrset_len = get_rrset_len(rrset_)
+            if message_upper_len + rrset_len < XFROUT_MAX_MESSAGE_SIZE:
+                msg.add_rrset(Section.ANSWER(), rrset_)
+                message_upper_len += rrset_len
                 continue
                 continue
 
 
             self._send_message(sock, msg)
             self._send_message(sock, msg)
             msg = self._clear_message(msg)
             msg = self._clear_message(msg)
             msg.add_rrset(Section.ANSWER(), rrset_) # Add the rrset to the new message
             msg.add_rrset(Section.ANSWER(), rrset_) # Add the rrset to the new message
-            old_message_len = 0
+            message_upper_len = rrset_len
-
-        self._send_message_with_last_soa(msg, sock, rrset_soa)
 
 
+        self._send_message_with_last_soa(msg, sock, rrset_soa, message_upper_len)
 
 
 class UnixSockServer(ThreadingUnixStreamServer):
 class UnixSockServer(ThreadingUnixStreamServer):
     '''The unix domain socket server which accept xfr query sent from auth server.'''
     '''The unix domain socket server which accept xfr query sent from auth server.'''
@@ -315,8 +310,8 @@ class UnixSockServer(ThreadingUnixStreamServer):
         If it's not a socket file or nobody is listening
         If it's not a socket file or nobody is listening
         , it will be removed. If it can't be removed, exit from python. '''
         , it will be removed. If it can't be removed, exit from python. '''
         if self._sock_file_in_use(sock_file):
         if self._sock_file_in_use(sock_file):
-            print("[b10-xfrout] Fail to start xfrout process, unix socket" 
+            sys.stderr.write("[b10-xfrout] Fail to start xfrout process, unix socket" 
-                  " file '%s' is being used by another xfrout process" % sock_file)
+                  " file '%s' is being used by another xfrout process\n" % sock_file)
             sys.exit(0)
             sys.exit(0)
         else:
         else:
             if not os.path.exists(sock_file):
             if not os.path.exists(sock_file):
@@ -325,7 +320,7 @@ class UnixSockServer(ThreadingUnixStreamServer):
             try:
             try:
                 os.unlink(sock_file)
                 os.unlink(sock_file)
             except OSError as err:
             except OSError as err:
-                print('[b10-xfrout] Fail to remove file ' + sock_file, err)
+                sys.stderr.write('[b10-xfrout] Fail to remove file %s: %s\n' % (sock_file, err))
                 sys.exit(0)
                 sys.exit(0)
    
    
     def _sock_file_in_use(self, sock_file):
     def _sock_file_in_use(self, sock_file):
@@ -409,9 +404,9 @@ class XfroutServer:
         self._listen_sock_file = UNIX_SOCKET_FILE 
         self._listen_sock_file = UNIX_SOCKET_FILE 
         self._shutdown_event = threading.Event()
         self._shutdown_event = threading.Event()
         self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
         self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
-        self._cc.add_remote_config(AUTH_SPECFILE_LOCATION);
         self._config_data = self._cc.get_full_config()
         self._config_data = self._cc.get_full_config()
         self._cc.start()
         self._cc.start()
+        self._cc.add_remote_config(AUTH_SPECFILE_LOCATION);
         self._log = isc.log.NSLogger(self._config_data.get('log_name'), self._config_data.get('log_file'),
         self._log = isc.log.NSLogger(self._config_data.get('log_name'), self._config_data.get('log_file'),
                                 self._config_data.get('log_severity'), self._config_data.get('log_versions'),
                                 self._config_data.get('log_severity'), self._config_data.get('log_versions'),
                                 self._config_data.get('log_max_bytes'), True)
                                 self._config_data.get('log_max_bytes'), True)
@@ -481,8 +476,8 @@ class XfroutServer:
             zone_name = args.get('zone_name')
             zone_name = args.get('zone_name')
             zone_class = args.get('zone_class')
             zone_class = args.get('zone_class')
             if zone_name and zone_class:
             if zone_name and zone_class:
-                self._log.log_message("info", "Receive notify command for zone:'%s/%s'" \
+                self._log.log_message("info", "zone '%s/%s': receive notify others command" \
-                                     % (zone_name, zone_class))
+                                       % (zone_name, zone_class))
                 self.send_notify(zone_name, zone_class)
                 self.send_notify(zone_name, zone_class)
                 answer = create_answer(0)
                 answer = create_answer(0)
             else:
             else:
@@ -525,12 +520,15 @@ if '__main__' == __name__:
         xfrout_server = XfroutServer()
         xfrout_server = XfroutServer()
         xfrout_server.run()
         xfrout_server.run()
     except KeyboardInterrupt:
     except KeyboardInterrupt:
-        sys.stderr.write("[b10-xfrout] exit xfrout process")
+        sys.stderr.write("[b10-xfrout] exit xfrout process\n")
     except SessionError as e:
     except SessionError as e:
-        sys.stderr.write("[b10-xfrout] Error creating xfrout," 
+        sys.stderr.write("[b10-xfrout] Error creating xfrout, "
-                           "is the command channel daemon running?")
+                           "is the command channel daemon running?\n")
+    except SessionTimeout as e:
+        sys.stderr.write("[b10-xfrout] Error creating xfrout, " 
+                           "is the configuration manager running?\n")
     except ModuleCCSessionError as e:
     except ModuleCCSessionError as e:
-        sys.stderr.write("info", '[b10-xfrout] exit xfrout process:', e)
+        sys.stderr.write("[b10-xfrout] exit xfrout process:%s\n" % str(e))
 
 
     if xfrout_server:
     if xfrout_server:
         xfrout_server.shutdown()
         xfrout_server.shutdown()

+ 11 - 1
src/bin/zonemgr/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
 
@@ -9,6 +9,16 @@ b10_zonemgr_DATA = zonemgr.spec
 
 
 CLEANFILES = b10-zonemgr zonemgr.pyc zonemgr.spec
 CLEANFILES = b10-zonemgr zonemgr.pyc zonemgr.spec
 
 
+man_MANS = b10-zonemgr.8
+EXTRA_DIST = $(man_MANS) b10-zonemgr.xml
+
+if ENABLE_MAN
+
+b10-zonemgr.8: b10-zonemgr.xml
+	xsltproc --novalid --xinclude --nonet -o $@ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $(srcdir)/b10-zonemgr.xml
+
+endif
+
 zonemgr.spec: zonemgr.spec.pre
 zonemgr.spec: zonemgr.spec.pre
 	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" zonemgr.spec.pre >$@
 	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" zonemgr.spec.pre >$@
 
 

+ 5 - 0
src/bin/zonemgr/TODO

@@ -1 +1,6 @@
 1. Zonemgr should support adding/deleting zones dynamically.
 1. Zonemgr should support adding/deleting zones dynamically.
+2. Make zonemgr  has customizable configurations for LOWERBOUND_REFRESH, LOWERBOUND_RETRY, MAX_TRANSFER_TIMEOUT, REFRESH_OFFSET, RETRY_OFFSET, EXPIRED_OFFSET, and/or jitter?
+3. There should be one way to see the current counters/timers and other data for each zone managed by zonemgr.
+4. There should be one way to turn off zonemgr.(Does user really need it? not sure what's the purpose of user)
+
+

+ 91 - 0
src/bin/zonemgr/b10-zonemgr.8

@@ -0,0 +1,91 @@
+'\" t
+.\"     Title: b10-zonemgr
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: September 8, 2010
+.\"    Manual: BIND10
+.\"    Source: BIND10
+.\"  Language: English
+.\"
+.TH "B10\-ZONEMGR" "8" "September 8, 2010" "BIND10" "BIND10"
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+b10-zonemgr \- BIND 10 Secondary zone manager
+.SH "SYNOPSIS"
+.HP \w'\fBb10\-zonemgr\fR\ 'u
+\fBb10\-zonemgr\fR [\fB\-v\fR] [\fB\-\-verbose\fR]
+.SH "DESCRIPTION"
+.PP
+The
+\fBb10\-zonemgr\fR
+daemon, also known as the BIND 10 secondary manager, keeps track of timers and other information necessary for BIND 10 to act as a DNS slave\&. Normally it is started by the
+\fBbind10\fR(8)
+boss process\&.
+.PP
+This daemon communicates with BIND 10 over a
+\fBb10-msgq\fR(8)
+C\-Channel connection\&. If this connection is not established,
+\fBb10\-zonemgr\fR
+will exit\&.
+.PP
+
+\fBb10\-zonemgr\fR
+receives its configurations from
+\fBb10-cfgmgr\fR(8)\&.
+.SH "CONFIGURATION AND COMMANDS"
+.PP
+The configuration commands are:
+.PP
+
+\fBnotify\fR
+(sent by
+\fBb10-auth\fR(8)) tells
+\fBb10\-zonemgr\fR
+the zone name and class, and the IP address for the master (source of the NOTIFY message)\&. This will set the zone\'s refresh time to now\&.
+This is an internal command and not exposed to the administrator\&.
+.PP
+
+\fBshutdown\fR
+exits
+\fBb10\-zonemgr\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
+.PP
+
+\fBzone_new_data_ready\fR
+is sent from
+\fBb10-xfrin\fR(8)
+to indicate that the zone transferred in successfully\&. This is an internal command and not exposed to the administrator\&.
+.PP
+
+\fBzone_xfrin_failed\fR
+is sent from
+\fBb10-xfrin\fR(8)
+to indicate a failure (such as a transfer\-in was incomplete)\&. The refresh timer for the zone is reset\&.
+This is an internal command and not exposed to the administrator\&.
+.SH "SEE ALSO"
+.PP
+
+\fBb10-auth\fR(8),
+\fBb10-cfgmgr\fR(8),
+\fBb10-msgq\fR(8),
+\fBb10-xfrin\fR(8),
+\fBb10-xfrout\fR(8),
+\fBbind10\fR(8),
+BIND 10 Guide\&.
+.SH "HISTORY"
+.PP
+The
+\fBb10\-zonemgr\fR
+daemon was designed in July 2010 by CNNIC for the ISC BIND 10 project\&.
+.SH "COPYRIGHT"
+.br
+Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+.br

+ 205 - 0
src/bin/zonemgr/b10-zonemgr.xml

@@ -0,0 +1,205 @@
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+               "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
+	       [<!ENTITY mdash "&#8212;">]>
+<!--
+ - Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+ -
+ - Permission to use, copy, modify, and/or distribute this software for any
+ - purpose with or without fee is hereby granted, provided that the above
+ - copyright notice and this permission notice appear in all copies.
+ -
+ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ - PERFORMANCE OF THIS SOFTWARE.
+-->
+
+<!-- $Id$ -->
+<refentry>
+
+  <refentryinfo>
+    <date>September 8, 2010</date>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>b10-zonemgr</refentrytitle>
+    <manvolnum>8</manvolnum>
+    <refmiscinfo>BIND10</refmiscinfo>
+  </refmeta>
+
+  <refnamediv>
+    <refname>b10-zonemgr</refname>
+    <refpurpose>BIND 10 Secondary zone manager</refpurpose>
+  </refnamediv>
+
+  <docinfo>
+    <copyright>
+      <year>2010</year>
+      <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
+    </copyright>
+  </docinfo>
+
+  <refsynopsisdiv>
+    <cmdsynopsis>
+      <command>b10-zonemgr</command>
+      <arg><option>-v</option></arg>
+      <arg><option>--verbose</option></arg>
+    </cmdsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>DESCRIPTION</title>
+    <para>The <command>b10-zonemgr</command> daemon, also known
+      as the BIND 10 secondary manager, keeps track of timers
+      and other information necessary for BIND 10 to act as a DNS slave.
+      Normally it is started by the
+      <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      boss process.
+    </para>
+
+    <para>
+      This daemon communicates with BIND 10 over a
+      <citerefentry><refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      C-Channel connection.  If this connection is not established,
+      <command>b10-zonemgr</command> will exit.
+<!-- TODO what if connection closes later, will b10-zonemgr exit? -->
+    </para>
+
+    <para>
+     <command>b10-zonemgr</command> receives its configurations from
+<citerefentry><refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+    </para>
+
+<!--
+
+            self._send_command(XFRIN_MODULE_NAME, ZONE_NOTIFY_COMMAND, param) 
+            self._clear_zone_notifier_master(zone_name_class)
+        # Send refresh command to xfrin module
+        else:
+            param = {"zone_name" : zone_name_class[0],
+                     "zone_class" : zone_name_class[1]
+                    }
+            self._send_command(XFRIN_MODULE_NAME, ZONE_REFRESH_COMMAND, param)
+
+-->
+
+  </refsect1>
+
+  <refsect1>
+    <title>CONFIGURATION AND COMMANDS</title>
+<!--
+    <para>
+      The configurable settings are:
+    </para>
+-->
+
+<!-- TODO: formating -->
+    <para>
+      The configuration commands are:
+    </para>
+    <para>
+      <command>notify</command> (sent by
+      <citerefentry><refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum></citerefentry>)
+      tells <command>b10-zonemgr</command>
+      the zone name and class, and the IP address for the master
+      (source of the NOTIFY message).
+      This will set the zone's refresh time to now.
+<!-- TODO reword this -->
+      This is an internal command and not exposed to the administrator.
+<!-- not defined in spec -->
+    </para>
+
+    <para>
+      <command>shutdown</command> exits <command>b10-zonemgr</command>.
+      (Note that the BIND 10 boss process will restart this service.)
+    </para>
+
+    <para>
+      <command>zone_new_data_ready</command> is sent from
+      <citerefentry><refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      to indicate that the zone transferred in successfully.
+      This is an internal command and not exposed to the administrator.
+<!-- not defined in spec -->
+    </para>
+
+    <para>
+      <command>zone_xfrin_failed</command> is sent from
+      <citerefentry><refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      to indicate a failure (such as a transfer-in was incomplete).
+      The refresh timer for the zone is reset.
+<!--
+        """Set zone next refresh time after zone refresh fail.
+           now + retry*3/4 <= next_refresh_time <= now + retry
+-->
+      This is an internal command and not exposed to the administrator.
+<!-- not defined in spec -->
+    </para>
+
+  </refsect1>
+
+<!--
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <para>The arguments are as follows:</para>
+
+    <variablelist>
+      <varlistentry>
+        <term><option></option></term>
+        <listitem><para>
+        </para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+  </refsect1>
+-->
+<!--
+  <refsect1>
+    <title>FILES</title>
+    <para>
+    <filename>/tmp/auth_xfrout_conn</filename>
+    </para>
+  </refsect1>
+-->
+
+  <refsect1>
+    <title>SEE ALSO</title>
+    <para>
+      <citerefentry>
+        <refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-xfrout</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citetitle>BIND 10 Guide</citetitle>.
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>HISTORY</title>
+    <para>
+      The <command>b10-zonemgr</command> daemon was designed in July 2010
+      by CNNIC for the ISC BIND 10 project.
+    </para>
+  </refsect1>
+</refentry><!--
+ - Local variables:
+ - mode: sgml
+ - End:
+-->

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

@@ -8,5 +8,5 @@ check-local:
 	for pytest in $(PYTESTS) ; do \
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/zonemgr:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
 	env PYTHONPATH=$(abs_top_builddir)/src/bin/zonemgr:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/lib/xfr/.libs \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done
 	done

+ 13 - 10
src/bin/zonemgr/zonemgr.py.in

@@ -153,8 +153,8 @@ class ZonemgrRefresh:
     def zone_refresh_success(self, zone_name_class):
     def zone_refresh_success(self, zone_name_class):
         """Update zone info after zone refresh success"""
         """Update zone info after zone refresh success"""
         if (self._zone_not_exist(zone_name_class)):
         if (self._zone_not_exist(zone_name_class)):
-            raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't \
+            raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
-                                    belong to zonemgr" % zone_name_class)
+                                   "belong to zonemgr" % zone_name_class)
             return
             return
         self.zonemgr_reload_zone(zone_name_class)
         self.zonemgr_reload_zone(zone_name_class)
         self._set_zone_refresh_timer(zone_name_class)
         self._set_zone_refresh_timer(zone_name_class)
@@ -164,8 +164,8 @@ class ZonemgrRefresh:
     def zone_refresh_fail(self, zone_name_class):
     def zone_refresh_fail(self, zone_name_class):
         """Update zone info after zone refresh fail"""
         """Update zone info after zone refresh fail"""
         if (self._zone_not_exist(zone_name_class)):
         if (self._zone_not_exist(zone_name_class)):
-            raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't \
+            raise ZonemgrException("[b10-zonemgr] Zone (%s, %s) doesn't "
-                                    belong to zonemgr" % zone_name_class)
+                                   "belong to zonemgr" % zone_name_class)
             return
             return
         self._set_zone_state(zone_name_class, ZONE_OK)
         self._set_zone_state(zone_name_class, ZONE_OK)
         self._set_zone_retry_timer(zone_name_class)
         self._set_zone_retry_timer(zone_name_class)
@@ -173,8 +173,8 @@ class ZonemgrRefresh:
     def zone_handle_notify(self, zone_name_class, master):
     def zone_handle_notify(self, zone_name_class, master):
         """Handle zone notify"""
         """Handle zone notify"""
         if (self._zone_not_exist(zone_name_class)):
         if (self._zone_not_exist(zone_name_class)):
-            raise ZonemgrException("[b10-zonemgr] Notified zone (%s, %s) doesn't \
+            raise ZonemgrException("[b10-zonemgr] Notified zone (%s, %s) "
-                                    belong to zonemgr" % zone_name_class)
+                                   "doesn't belong to zonemgr" % zone_name_class)
             return
             return
         self._set_zone_notifier_master(zone_name_class, master)
         self._set_zone_notifier_master(zone_name_class, master)
         self._set_zone_notify_timer(zone_name_class)
         self._set_zone_notify_timer(zone_name_class)
@@ -513,12 +513,15 @@ if '__main__' == __name__:
         zonemgrd = Zonemgr()
         zonemgrd = Zonemgr()
         zonemgrd.run()
         zonemgrd.run()
     except KeyboardInterrupt:
     except KeyboardInterrupt:
-        sys.stderr.write("[b10-zonemgr] exit zonemgr process")
+        sys.stderr.write("[b10-zonemgr] exit zonemgr process\n")
     except isc.cc.session.SessionError as e:
     except isc.cc.session.SessionError as e:
-        sys.stderr.write("[b10-zonemgr] Error creating ,zonemgr" 
+        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
-                           "is the command channel daemon running?")
+                           "is the command channel daemon running?\n")
+    except isc.cc.session.SessionTimeout as e:
+        sys.stderr.write("[b10-zonemgr] Error creating zonemgr, " 
+                           "is the configuration manager running?\n")
     except isc.config.ModuleCCSessionError as e:
     except isc.config.ModuleCCSessionError as e:
-        sys.stderr.write("info", "[b10-zonemgr] exit zonemgr process:", e)
+        sys.stderr.write("[b10-zonemgr] exit zonemgr process: %s\n" % str(e))
 
 
     if zonemgrd:
     if zonemgrd:
         zonemgrd.shutdown()
         zonemgrd.shutdown()

+ 1 - 1
src/lib/bench/tests/benchmark_unittest.cc

@@ -58,7 +58,7 @@ BenchMark<TestBenchMark>::tearDown() {
 };
 };
 
 
 // XXX: some compilers cannot find class static constants used in
 // XXX: some compilers cannot find class static constants used in
-// EXPECT_xxx macross, for which we need an explicit definition.
+// EXPECT_xxx macros, for which we need an explicit definition.
 template <typename T>
 template <typename T>
 const int BenchMark<T>::TIME_FAILURE;
 const int BenchMark<T>::TIME_FAILURE;
 }
 }

+ 112 - 84
src/lib/cc/data.cc

@@ -20,6 +20,7 @@
 
 
 #include <cassert>
 #include <cassert>
 #include <climits>
 #include <climits>
+#include <map>
 #include <cstdio>
 #include <cstdio>
 #include <iostream>
 #include <iostream>
 #include <string>
 #include <string>
@@ -35,21 +36,21 @@ namespace isc {
 namespace data {
 namespace data {
 
 
 std::string
 std::string
-Element::str() {
+Element::str() const {
     std::stringstream ss;
     std::stringstream ss;
     toJSON(ss);
     toJSON(ss);
     return (ss.str());
     return (ss.str());
 }
 }
 
 
 std::string
 std::string
-Element::toWire() {
+Element::toWire() const {
     std::stringstream ss;
     std::stringstream ss;
     toJSON(ss);
     toJSON(ss);
     return (ss.str());
     return (ss.str());
 }
 }
 
 
 void
 void
-Element::toWire(std::ostream& ss) {
+Element::toWire(std::ostream& ss) const {
     toJSON(ss);
     toJSON(ss);
 }
 }
 
 
@@ -81,12 +82,12 @@ Element::getValue(std::string& t UNUSED_PARAM) {
 }
 }
 
 
 bool
 bool
-Element::getValue(std::vector<ElementPtr>& t UNUSED_PARAM) {
+Element::getValue(std::vector<ConstElementPtr>& t UNUSED_PARAM) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::getValue(std::map<std::string, ElementPtr>& t UNUSED_PARAM) {
+Element::getValue(std::map<std::string, ConstElementPtr>& t UNUSED_PARAM) {
     return (false);
     return (false);
 }
 }
 
 
@@ -111,27 +112,29 @@ Element::setValue(const std::string& v UNUSED_PARAM) {
 }
 }
 
 
 bool
 bool
-Element::setValue(const std::vector<ElementPtr>& v UNUSED_PARAM) {
+Element::setValue(const std::vector<ConstElementPtr>& v UNUSED_PARAM) {
     return (false);
     return (false);
 }
 }
 
 
 bool
 bool
-Element::setValue(const std::map<std::string, ElementPtr>& v UNUSED_PARAM) {
+Element::setValue(const std::map<std::string,
+                  ConstElementPtr>& v UNUSED_PARAM)
+{
     return (false);
     return (false);
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-Element::get(const int i UNUSED_PARAM) {
+Element::get(const int i UNUSED_PARAM) const {
     isc_throw(TypeError, "get(int) called on a non-list Element");
     isc_throw(TypeError, "get(int) called on a non-list Element");
 }
 }
 
 
 void
 void
-Element::set(const size_t i UNUSED_PARAM, ElementPtr element UNUSED_PARAM) {
+Element::set(const size_t i UNUSED_PARAM, ConstElementPtr element UNUSED_PARAM) {
     isc_throw(TypeError, "set(int, element) called on a non-list Element");
     isc_throw(TypeError, "set(int, element) called on a non-list Element");
 }
 }
 
 
 void
 void
-Element::add(ElementPtr element UNUSED_PARAM) {
+Element::add(ConstElementPtr element UNUSED_PARAM) {
     isc_throw(TypeError, "add() called on a non-list Element");
     isc_throw(TypeError, "add() called on a non-list Element");
 }
 }
 
 
@@ -141,18 +144,18 @@ Element::remove(const int i UNUSED_PARAM) {
 }
 }
 
 
 size_t
 size_t
-Element::size() {
+Element::size() const {
     isc_throw(TypeError, "size() called on a non-list Element");
     isc_throw(TypeError, "size() called on a non-list Element");
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-Element::get(const std::string& name UNUSED_PARAM) {
+Element::get(const std::string& name UNUSED_PARAM) const {
     isc_throw(TypeError, "get(string) called on a non-map Element");
     isc_throw(TypeError, "get(string) called on a non-map Element");
 }
 }
 
 
 void
 void
 Element::set(const std::string& name UNUSED_PARAM,
 Element::set(const std::string& name UNUSED_PARAM,
-             ElementPtr element UNUSED_PARAM)
+             ConstElementPtr element UNUSED_PARAM)
 {
 {
     isc_throw(TypeError, "set(name, element) called on a non-map Element");
     isc_throw(TypeError, "set(name, element) called on a non-map Element");
 }
 }
@@ -163,18 +166,18 @@ Element::remove(const std::string& name UNUSED_PARAM) {
 }
 }
 
 
 bool
 bool
-Element::contains(const std::string& name UNUSED_PARAM) {
+Element::contains(const std::string& name UNUSED_PARAM) const {
     isc_throw(TypeError, "contains(string) called on a non-map Element");
     isc_throw(TypeError, "contains(string) called on a non-map Element");
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-Element::find(const std::string& identifier UNUSED_PARAM) {
+Element::find(const std::string& identifier UNUSED_PARAM) const {
     isc_throw(TypeError, "find(string) called on a non-map Element");
     isc_throw(TypeError, "find(string) called on a non-map Element");
 }
 }
 
 
 bool
 bool
 Element::find(const std::string& identifier UNUSED_PARAM,
 Element::find(const std::string& identifier UNUSED_PARAM,
-              ElementPtr& t UNUSED_PARAM)
+              ConstElementPtr t UNUSED_PARAM) const
 {
 {
     return (false);
     return (false);
 }
 }
@@ -189,12 +192,18 @@ throwJSONError(const std::string& error, const std::string& file, int line, int
 }
 }
 }
 }
 
 
-std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
+std::ostream&
-    return (out << e->str());
+operator<<(std::ostream &out, const Element& e) {
+    return (out << e.str());
 }
 }
 
 
-bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) {
+bool
-    return (a->equals(b));
+operator==(const Element& a, const Element& b) {
+    return (a.equals(b));
+}
+
+bool operator!=(const Element& a, const Element& b) {
+    return (!a.equals(b));
 };
 };
 
 
 //
 //
@@ -428,7 +437,7 @@ from_stringstream_list(std::istream &in, const std::string& file, int& line, int
 {
 {
     char c = 0;
     char c = 0;
     ElementPtr list = Element::createList();
     ElementPtr list = Element::createList();
-    ElementPtr cur_list_element;
+    ConstElementPtr cur_list_element;
 
 
     skip_chars(in, " \t\n", line, pos);
     skip_chars(in, " \t\n", line, pos);
     while (c != EOF && c != ']') {
     while (c != EOF && c != ']') {
@@ -462,7 +471,7 @@ from_stringstream_map(std::istream &in, const std::string& file, int& line,
             in.get();
             in.get();
             pos++;
             pos++;
 
 
-            ElementPtr value = Element::fromJSON(in, file, line, pos);
+            ConstElementPtr value = Element::fromJSON(in, file, line, pos);
             map->set(key, value);
             map->set(key, value);
             
             
             skip_to(in, file, line, pos, ",}", " \t\n");
             skip_to(in, file, line, pos, ",}", " \t\n");
@@ -614,20 +623,17 @@ Element::fromJSON(const std::string &in) {
 // to JSON format
 // to JSON format
 
 
 void
 void
-IntElement::toJSON(std::ostream& ss)
+IntElement::toJSON(std::ostream& ss) const {
-{
     ss << intValue();
     ss << intValue();
 }
 }
 
 
 void
 void
-DoubleElement::toJSON(std::ostream& ss)
+DoubleElement::toJSON(std::ostream& ss) const {
-{
     ss << doubleValue();
     ss << doubleValue();
 }
 }
 
 
 void
 void
-BoolElement::toJSON(std::ostream& ss)
+BoolElement::toJSON(std::ostream& ss) const {
-{
     if (boolValue()) {
     if (boolValue()) {
         ss << "true";
         ss << "true";
     } else {
     } else {
@@ -636,26 +642,23 @@ BoolElement::toJSON(std::ostream& ss)
 }
 }
 
 
 void
 void
-NullElement::toJSON(std::ostream& ss)
+NullElement::toJSON(std::ostream& ss) const {
-{
     ss << "null";
     ss << "null";
 }
 }
 
 
 void
 void
-StringElement::toJSON(std::ostream& ss)
+StringElement::toJSON(std::ostream& ss) const {
-{
     ss << "\"";
     ss << "\"";
     ss << stringValue();
     ss << stringValue();
     ss << "\"";
     ss << "\"";
 }
 }
 
 
 void
 void
-ListElement::toJSON(std::ostream& ss)
+ListElement::toJSON(std::ostream& ss) const {
-{
     ss << "[ ";
     ss << "[ ";
 
 
-    const std::vector<ElementPtr>& v = listValue();
+    const std::vector<ConstElementPtr>& v = listValue();
-    for (std::vector<ElementPtr>::const_iterator it = v.begin();
+    for (std::vector<ConstElementPtr>::const_iterator it = v.begin();
          it != v.end(); ++it) {
          it != v.end(); ++it) {
         if (it != v.begin()) {
         if (it != v.begin()) {
             ss << ", ";
             ss << ", ";
@@ -666,12 +669,11 @@ ListElement::toJSON(std::ostream& ss)
 }
 }
 
 
 void
 void
-MapElement::toJSON(std::ostream& ss)
+MapElement::toJSON(std::ostream& ss) const {
-{
     ss << "{ ";
     ss << "{ ";
 
 
-    const std::map<std::string, ElementPtr>& m = mapValue();
+    const std::map<std::string, ConstElementPtr>& m = mapValue();
-    for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+    for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
          it != m.end(); ++it) {
          it != m.end(); ++it) {
         if (it != m.begin()) {
         if (it != m.begin()) {
             ss << ", ";
             ss << ", ";
@@ -690,13 +692,13 @@ MapElement::toJSON(std::ostream& ss)
 // we're looking for) is not a MapElement
 // we're looking for) is not a MapElement
 // returns 0 if it could simply not be found
 // returns 0 if it could simply not be found
 // should that also be an exception?
 // should that also be an exception?
-ElementPtr
+ConstElementPtr
-MapElement::find(const std::string& id) {
+MapElement::find(const std::string& id) const {
     const size_t sep = id.find('/');
     const size_t sep = id.find('/');
     if (sep == std::string::npos) {
     if (sep == std::string::npos) {
         return (get(id));
         return (get(id));
     } else {
     } else {
-        ElementPtr ce = get(id.substr(0, sep));
+        ConstElementPtr ce = get(id.substr(0, sep));
         if (ce) {
         if (ce) {
             // ignore trailing slash
             // ignore trailing slash
             if  (sep + 1 != id.size()) {
             if  (sep + 1 != id.size()) {
@@ -735,14 +737,14 @@ Element::fromWire(std::stringstream& in, int length) {
 }
 }
 
 
 void
 void
-MapElement::set(const std::string& key, ElementPtr value) {
+MapElement::set(const std::string& key, ConstElementPtr value) {
     m[key] = value;
     m[key] = value;
 }
 }
 
 
 bool
 bool
-MapElement::find(const std::string& id, ElementPtr& t) {
+MapElement::find(const std::string& id, ConstElementPtr t) const {
     try {
     try {
-        ElementPtr p = find(id);
+        ConstElementPtr p = find(id);
         if (p) {
         if (p) {
             t = p;
             t = p;
             return (true);
             return (true);
@@ -754,43 +756,43 @@ MapElement::find(const std::string& id, ElementPtr& t) {
 }
 }
 
 
 bool
 bool
-IntElement::equals(ElementPtr other) {
+IntElement::equals(const Element& other) const {
-    return (other->getType() == Element::integer) &&
+    return (other.getType() == Element::integer) &&
-           (i == other->intValue());
+           (i == other.intValue());
 }
 }
 
 
 bool
 bool
-DoubleElement::equals(ElementPtr other) {
+DoubleElement::equals(const Element& other) const {
-    return (other->getType() == Element::real) &&
+    return (other.getType() == Element::real) &&
-           (d == other->doubleValue());
+           (d == other.doubleValue());
 }
 }
 
 
 bool
 bool
-BoolElement::equals(ElementPtr other) {
+BoolElement::equals(const Element& other) const {
-    return (other->getType() == Element::boolean) &&
+    return (other.getType() == Element::boolean) &&
-           (b == other->boolValue());
+           (b == other.boolValue());
 }
 }
 
 
 bool
 bool
-NullElement::equals(ElementPtr other) {
+NullElement::equals(const Element& other) const {
-    return (other->getType() == Element::null);
+    return (other.getType() == Element::null);
 }
 }
 
 
 bool
 bool
-StringElement::equals(ElementPtr other) {
+StringElement::equals(const Element& other) const {
-    return (other->getType() == Element::string) &&
+    return (other.getType() == Element::string) &&
-           (s == other->stringValue());
+           (s == other.stringValue());
 }
 }
 
 
 bool
 bool
-ListElement::equals(ElementPtr other) {
+ListElement::equals(const Element& other) const {
-    if (other->getType() == Element::list) {
+    if (other.getType() == Element::list) {
         const int s = size();
         const int s = size();
-        if (s != other->size()) {
+        if (s != other.size()) {
             return (false);
             return (false);
         }
         }
         for (int i = 0; i < s; ++i) {
         for (int i = 0; i < s; ++i) {
-            if (!get(i)->equals(other->get(i))) {
+            if (!get(i)->equals(*other.get(i))) {
                 return (false);
                 return (false);
             }
             }
         }
         }
@@ -801,13 +803,14 @@ ListElement::equals(ElementPtr other) {
 }
 }
 
 
 bool
 bool
-MapElement::equals(ElementPtr other) {
+MapElement::equals(const Element& other) const {
-    if (other->getType() == Element::map) {
+    if (other.getType() == Element::map) {
-        std::map<std::string, ElementPtr> m = mapValue();
+        const std::map<std::string, ConstElementPtr>& m = mapValue();
-        for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+        for (std::map<std::string, ConstElementPtr>::const_iterator it =
+                 m.begin();
              it != m.end() ; ++it) {
              it != m.end() ; ++it) {
-            if (other->contains((*it).first)) {
+            if (other.contains((*it).first)) {
-                if (!get((*it).first)->equals(other->get((*it).first))) {
+                if (!get((*it).first)->equals(*other.get((*it).first))) {
                     return (false);
                     return (false);
                 }
                 }
             } else {
             } else {
@@ -819,9 +822,10 @@ MapElement::equals(ElementPtr other) {
         // compare those elements; if one of them is missing we
         // compare those elements; if one of them is missing we
         // differ (and if it's not missing the loop above has checked
         // differ (and if it's not missing the loop above has checked
         // it)
         // it)
-        m = other->mapValue();
+        std::map<std::string, ConstElementPtr>::const_iterator it;
-        for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+        for (it = other.mapValue().begin();
-             it != m.end() ; ++it) {
+             it != other.mapValue().end();
+             ++it) {
             if (!contains((*it).first)) {
             if (!contains((*it).first)) {
                 return (false);
                 return (false);
             }
             }
@@ -833,12 +837,12 @@ MapElement::equals(ElementPtr other) {
 }
 }
 
 
 bool
 bool
-isNull(ElementPtr p) {
+isNull(ConstElementPtr p) {
     return (!p);
     return (!p);
 }
 }
 
 
 void
 void
-removeIdentical(ElementPtr a, const ElementPtr b) {
+removeIdentical(ElementPtr a, ConstElementPtr b) {
     if (!b) {
     if (!b) {
         return;
         return;
     }
     }
@@ -846,26 +850,50 @@ removeIdentical(ElementPtr a, const ElementPtr b) {
         isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
         isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
     }
     }
 
 
-    std::map<std::string, ElementPtr> m = a->mapValue();
+    const std::map<std::string, ConstElementPtr>& m = a->mapValue();
-    for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+    for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
          it != m.end() ; ++it) {
          it != m.end() ; ++it) {
         if (b->contains((*it).first)) {
         if (b->contains((*it).first)) {
-            if (a->get((*it).first)->equals(b->get((*it).first))) {
+            if (a->get((*it).first)->equals(*b->get((*it).first))) {
                 a->remove((*it).first);
                 a->remove((*it).first);
             }
             }
         }
         }
     }
     }
 }
 }
 
 
+ConstElementPtr
+removeIdentical(ConstElementPtr a, ConstElementPtr b) {
+    ElementPtr result = Element::createMap();
+
+    if (!b) {
+        return (result);
+    }
+    
+    if (a->getType() != Element::map || b->getType() != Element::map) {
+        isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
+    }
+
+    const std::map<std::string, ConstElementPtr>& m = a->mapValue();
+    for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
+         it != m.end() ; ++it) {
+        if (!b->contains((*it).first) ||
+            !a->get((*it).first)->equals(*b->get((*it).first))) {
+            result->set((*it).first, (*it).second);
+        }
+    }
+
+    return (result);
+}
+
 void
 void
-merge(ElementPtr element, const ElementPtr other) {
+merge(ElementPtr element, ConstElementPtr other) {
     if (element->getType() != Element::map ||
     if (element->getType() != Element::map ||
         other->getType() != Element::map) {
         other->getType() != Element::map) {
         isc_throw(TypeError, "merge arguments not MapElements");
         isc_throw(TypeError, "merge arguments not MapElements");
     }
     }
     
     
-    std::map<std::string, ElementPtr> m = other->mapValue();
+    std::map<std::string, ConstElementPtr> m = other->mapValue();
-    for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+    for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
          it != m.end() ; ++it) {
          it != m.end() ; ++it) {
         if ((*it).second && (*it).second->getType() != Element::null) {
         if ((*it).second && (*it).second->getType() != Element::null) {
             element->set((*it).first, (*it).second);
             element->set((*it).first, (*it).second);

+ 106 - 68
src/lib/cc/data.h

@@ -29,6 +29,7 @@ namespace isc { namespace data {
 class Element;
 class Element;
 // todo: describe the rationale behind ElementPtr?
 // todo: describe the rationale behind ElementPtr?
 typedef boost::shared_ptr<Element> ElementPtr;
 typedef boost::shared_ptr<Element> ElementPtr;
+typedef boost::shared_ptr<const Element> ConstElementPtr;
 
 
 ///
 ///
 /// \brief A standard Data module exception that is thrown if a function
 /// \brief A standard Data module exception that is thrown if a function
@@ -90,7 +91,7 @@ public:
     virtual ~Element() {};
     virtual ~Element() {};
 
 
     /// \return the type of this element
     /// \return the type of this element
-    int getType() { return (type); }
+    int getType() const { return (type); }
 
 
     /// Returns a string representing the Element and all its
     /// Returns a string representing the Element and all its
     /// child elements; note that this is different from stringValue(),
     /// child elements; note that this is different from stringValue(),
@@ -99,24 +100,24 @@ public:
     /// The resulting string will contain the Element in JSON format.
     /// The resulting string will contain the Element in JSON format.
     ///
     ///
     /// \return std::string containing the string representation
     /// \return std::string containing the string representation
-    std::string str();
+    std::string str() const;
 
 
     /// Returns the wireformat for the Element and all its child
     /// Returns the wireformat for the Element and all its child
     /// elements.
     /// elements.
     ///
     ///
     /// \return std::string containing the element in wire format
     /// \return std::string containing the element in wire format
-    std::string toWire();
+    std::string toWire() const;
-    void toWire(std::ostream& out);
+    void toWire(std::ostream& out) const;
 
 
     /// \name pure virtuals, every derived class must implement these
     /// \name pure virtuals, every derived class must implement these
 
 
     /// \returns true if the other ElementPtr has the same type and
     /// \returns true if the other ElementPtr has the same type and
     ///          value
     ///          value
-    virtual bool equals(ElementPtr other) = 0;
+    virtual bool equals(const Element& other) const = 0;
     
     
     /// Converts the Element to JSON format and appends it to
     /// Converts the Element to JSON format and appends it to
     /// the given stringstream.
     /// the given stringstream.
-    virtual void toJSON(std::ostream& ss) = 0;
+    virtual void toJSON(std::ostream& ss) const = 0;
 
 
     /// \name Type-specific getters
     /// \name Type-specific getters
     ///
     ///
@@ -126,12 +127,22 @@ public:
     /// If you want an exception-safe getter method, use
     /// If you want an exception-safe getter method, use
     /// getValue() below
     /// getValue() below
     //@{
     //@{
-    virtual long int intValue() { isc_throw(TypeError, "intValue() called on non-integer Element"); };
+    virtual long int intValue() const
-    virtual double doubleValue() { isc_throw(TypeError, "doubleValue() called on non-double Element"); };
+    { isc_throw(TypeError, "intValue() called on non-integer Element"); };
-    virtual bool boolValue() { isc_throw(TypeError, "boolValue() called on non-Bool Element"); };
+    virtual double doubleValue() const
-    virtual std::string stringValue() { isc_throw(TypeError, "stringValue() called on non-string Element"); };
+    { isc_throw(TypeError, "doubleValue() called on non-double Element"); };
-    virtual const std::vector<boost::shared_ptr<Element> >& listValue() { isc_throw(TypeError, "listValue() called on non-list Element"); }; // replace with real exception or empty vector?
+    virtual bool boolValue() const
-    virtual const std::map<std::string, boost::shared_ptr<Element> >& mapValue() { isc_throw(TypeError, "mapValue() called on non-map Element"); }; // replace with real exception or empty map?
+    { isc_throw(TypeError, "boolValue() called on non-Bool Element"); };
+    virtual std::string stringValue() const
+    { isc_throw(TypeError, "stringValue() called on non-string Element"); };
+    virtual const std::vector<ConstElementPtr>& listValue() const {
+        // replace with real exception or empty vector?
+        isc_throw(TypeError, "listValue() called on non-list Element");
+    };
+    virtual const std::map<std::string, ConstElementPtr>& mapValue() const {
+        // replace with real exception or empty map?
+        isc_throw(TypeError, "mapValue() called on non-map Element");
+    };
     //@}
     //@}
 
 
     /// \name Exception-safe getters
     /// \name Exception-safe getters
@@ -147,8 +158,8 @@ public:
     virtual bool getValue(double& t);
     virtual bool getValue(double& t);
     virtual bool getValue(bool& t);
     virtual bool getValue(bool& t);
     virtual bool getValue(std::string& t);
     virtual bool getValue(std::string& t);
-    virtual bool getValue(std::vector<ElementPtr>& t);
+    virtual bool getValue(std::vector<ConstElementPtr>& t);
-    virtual bool getValue(std::map<std::string, ElementPtr>& t);
+    virtual bool getValue(std::map<std::string, ConstElementPtr>& t);
     //@}
     //@}
 
 
     ///
     ///
@@ -163,8 +174,8 @@ public:
     virtual bool setValue(const double v);
     virtual bool setValue(const double v);
     virtual bool setValue(const bool t);
     virtual bool setValue(const bool t);
     virtual bool setValue(const std::string& v);
     virtual bool setValue(const std::string& v);
-    virtual bool setValue(const std::vector<ElementPtr>& v);
+    virtual bool setValue(const std::vector<ConstElementPtr>& v);
-    virtual bool setValue(const std::map<std::string, ElementPtr>& v);
+    virtual bool setValue(const std::map<std::string, ConstElementPtr>& v);
     //@}
     //@}
 
 
 
 
@@ -179,17 +190,17 @@ public:
     /// Returns the ElementPtr at the given index. If the index is out
     /// Returns the ElementPtr at the given index. If the index is out
     /// of bounds, this function throws an std::out_of_range exception.
     /// of bounds, this function throws an std::out_of_range exception.
     /// \param i The position of the ElementPtr to return
     /// \param i The position of the ElementPtr to return
-    virtual ElementPtr get(const int i);
+    virtual ConstElementPtr get(const int i) const;
 
 
     /// Sets the ElementPtr at the given index. If the index is out
     /// Sets the ElementPtr at the given index. If the index is out
     /// of bounds, this function throws an std::out_of_range exception.
     /// of bounds, this function throws an std::out_of_range exception.
     /// \param i The position of the ElementPtr to set
     /// \param i The position of the ElementPtr to set
     /// \param element The ElementPtr to set at the position
     /// \param element The ElementPtr to set at the position
-    virtual void set(const size_t i, ElementPtr element);
+    virtual void set(const size_t i, ConstElementPtr element);
 
 
     /// Adds an ElementPtr to the list
     /// Adds an ElementPtr to the list
     /// \param element The ElementPtr to add
     /// \param element The ElementPtr to add
-    virtual void add(ElementPtr element);
+    virtual void add(ConstElementPtr element);
 
 
     /// Removes the element at the given position. If the index is out
     /// Removes the element at the given position. If the index is out
     /// of nothing happens.
     /// of nothing happens.
@@ -197,7 +208,7 @@ public:
     virtual void remove(const int i);
     virtual void remove(const int i);
 
 
     /// Returns the number of elements in the list.
     /// Returns the number of elements in the list.
-    virtual size_t size();
+    virtual size_t size() const;
     //@}
     //@}
 
 
     
     
@@ -209,11 +220,11 @@ public:
     /// Returns the ElementPtr at the given key
     /// Returns the ElementPtr at the given key
     /// \param name The key of the Element to return
     /// \param name The key of the Element to return
     /// \return The ElementPtr at the given key
     /// \return The ElementPtr at the given key
-    virtual ElementPtr get(const std::string& name);
+    virtual ConstElementPtr get(const std::string& name) const;
 
 
     /// Sets the ElementPtr at the given key
     /// Sets the ElementPtr at the given key
     /// \param name The key of the Element to set
     /// \param name The key of the Element to set
-    virtual void set(const std::string& name, ElementPtr element);
+    virtual void set(const std::string& name, ConstElementPtr element);
 
 
     /// Remove the ElementPtr at the given key
     /// Remove the ElementPtr at the given key
     /// \param name The key of the Element to remove
     /// \param name The key of the Element to remove
@@ -222,7 +233,7 @@ public:
     /// Checks if there is data at the given key
     /// Checks if there is data at the given key
     /// \param name The key of the Element to remove
     /// \param name The key of the Element to remove
     /// \return true if there is data at the key, false if not.
     /// \return true if there is data at the key, false if not.
-    virtual bool contains(const std::string& name);
+    virtual bool contains(const std::string& name) const;
 
 
     /// Recursively finds any data at the given identifier. The
     /// Recursively finds any data at the given identifier. The
     /// identifier is a /-separated list of names of nested maps, with
     /// identifier is a /-separated list of names of nested maps, with
@@ -237,13 +248,13 @@ public:
     /// \return The ElementPtr at the given identifier. Returns a
     /// \return The ElementPtr at the given identifier. Returns a
     /// null ElementPtr if it is not found, which can be checked with
     /// null ElementPtr if it is not found, which can be checked with
     /// Element::is_null(ElementPtr e).
     /// Element::is_null(ElementPtr e).
-    virtual ElementPtr find(const std::string& identifier);
+    virtual ConstElementPtr find(const std::string& identifier) const;
 
 
     /// See \c Element::find()
     /// See \c Element::find()
     /// \param identifier The identifier of the element to find
     /// \param identifier The identifier of the element to find
     /// \param t Reference to store the resulting ElementPtr, if found.
     /// \param t Reference to store the resulting ElementPtr, if found.
     /// \return true if the element was found, false if not.
     /// \return true if the element was found, false if not.
-    virtual bool find(const std::string& identifier, ElementPtr& t);
+    virtual bool find(const std::string& identifier, ConstElementPtr t) const;
     //@}
     //@}
 
 
 
 
@@ -365,13 +376,13 @@ class IntElement : public Element {
 
 
 public:
 public:
     IntElement(long int v) : Element(integer), i(v) { }
     IntElement(long int v) : Element(integer), i(v) { }
-    long int intValue() { return (i); }
+    long int intValue() const { return (i); }
     using Element::getValue;
     using Element::getValue;
     bool getValue(long int& t) { t = i; return (true); }
     bool getValue(long int& t) { t = i; return (true); }
     using Element::setValue;
     using Element::setValue;
     bool setValue(const long int v) { i = v; return (true); }
     bool setValue(const long int v) { i = v; return (true); }
-    void toJSON(std::ostream& ss);
+    void toJSON(std::ostream& ss) const;
-    bool equals(ElementPtr other);
+    bool equals(const Element& other) const;
 };
 };
 
 
 class DoubleElement : public Element {
 class DoubleElement : public Element {
@@ -379,13 +390,13 @@ class DoubleElement : public Element {
 
 
 public:
 public:
     DoubleElement(double v) : Element(real), d(v) {};
     DoubleElement(double v) : Element(real), d(v) {};
-    double doubleValue() { return (d); }
+    double doubleValue() const { return (d); }
     using Element::getValue;
     using Element::getValue;
     bool getValue(double& t) { t = d; return (true); }
     bool getValue(double& t) { t = d; return (true); }
     using Element::setValue;
     using Element::setValue;
     bool setValue(const double v) { d = v; return (true); }
     bool setValue(const double v) { d = v; return (true); }
-    void toJSON(std::ostream& ss);
+    void toJSON(std::ostream& ss) const;
-    bool equals(ElementPtr other);
+    bool equals(const Element& other) const;
 };
 };
 
 
 class BoolElement : public Element {
 class BoolElement : public Element {
@@ -393,20 +404,20 @@ class BoolElement : public Element {
 
 
 public:
 public:
     BoolElement(const bool v) : Element(boolean), b(v) {};
     BoolElement(const bool v) : Element(boolean), b(v) {};
-    bool boolValue() { return (b); }
+    bool boolValue() const { return (b); }
     using Element::getValue;
     using Element::getValue;
     bool getValue(bool& t) { t = b; return (true); }
     bool getValue(bool& t) { t = b; return (true); }
     using Element::setValue;
     using Element::setValue;
     bool setValue(const bool v) { b = v; return (true); }
     bool setValue(const bool v) { b = v; return (true); }
-    void toJSON(std::ostream& ss);
+    void toJSON(std::ostream& ss) const;
-    bool equals(ElementPtr other);
+    bool equals(const Element& other) const;
 };
 };
 
 
 class NullElement : public Element {
 class NullElement : public Element {
 public:
 public:
     NullElement() : Element(null) {};
     NullElement() : Element(null) {};
-    void toJSON(std::ostream& ss);
+    void toJSON(std::ostream& ss) const;
-    bool equals(ElementPtr other);
+    bool equals(const Element& other) const;
 };
 };
 
 
 class StringElement : public Element {
 class StringElement : public Element {
@@ -414,77 +425,97 @@ class StringElement : public Element {
 
 
 public:
 public:
     StringElement(std::string v) : Element(string), s(v) {};
     StringElement(std::string v) : Element(string), s(v) {};
-    std::string stringValue() { return (s); }
+    std::string stringValue() const { return (s); }
     using Element::getValue;
     using Element::getValue;
     bool getValue(std::string& t) { t = s; return (true); }
     bool getValue(std::string& t) { t = s; return (true); }
     using Element::setValue;
     using Element::setValue;
     bool setValue(const std::string& v) { s = v; return (true); }
     bool setValue(const std::string& v) { s = v; return (true); }
-    void toJSON(std::ostream& ss);
+    void toJSON(std::ostream& ss) const;
-    bool equals(ElementPtr other);
+    bool equals(const Element& other) const;
 };
 };
 
 
 class ListElement : public Element {
 class ListElement : public Element {
-    std::vector<ElementPtr> l;
+    std::vector<ConstElementPtr> l;
 
 
 public:
 public:
-    ListElement() : Element(list), l(std::vector<ElementPtr>()) {};
+    ListElement() : Element(list) {}
-    const std::vector<ElementPtr>& listValue() { return (l); }
+    const std::vector<ConstElementPtr>& listValue() const { return (l); }
     using Element::getValue;
     using Element::getValue;
-    bool getValue(std::vector<ElementPtr>& t) { t = l; return (true); }
+    bool getValue(std::vector<ConstElementPtr>& t) {
+        t = l;
+        return (true);
+    }
     using Element::setValue;
     using Element::setValue;
-    bool setValue(const std::vector<ElementPtr>& v) { l = v; return (true); }
+    bool setValue(const std::vector<ConstElementPtr>& v) {
+        l = v;
+        return (true);
+    }
     using Element::get;
     using Element::get;
-    ElementPtr get(int i) { return (l.at(i)); }
+    ConstElementPtr get(int i) const { return (l.at(i)); }
     using Element::set;
     using Element::set;
-    void set(size_t i, ElementPtr e) { if (i <= l.size()) {l[i] = e;} else { throw std::out_of_range("vector::_M_range_check"); } };
+    void set(size_t i, ConstElementPtr e) {
-    void add(ElementPtr e) { l.push_back(e); };
+        l.at(i) = e;
+    }
+    void add(ConstElementPtr e) { l.push_back(e); };
     using Element::remove;
     using Element::remove;
     void remove(int i) { l.erase(l.begin() + i); };
     void remove(int i) { l.erase(l.begin() + i); };
-    void toJSON(std::ostream& ss);
+    void toJSON(std::ostream& ss) const;
-    size_t size() { return (l.size()); }
+    size_t size() const { return (l.size()); }
-    bool equals(ElementPtr other);
+    bool equals(const Element& other) const;
 };
 };
 
 
 class MapElement : public Element {
 class MapElement : public Element {
-    std::map<std::string, ElementPtr> m;
+    std::map<std::string, ConstElementPtr> m;
 
 
 public:
 public:
-    MapElement() : Element(map), m(std::map<std::string, ElementPtr>()) {};
+    MapElement() : Element(map) {}
     // TODO: should we have direct iterators instead of exposing the std::map here?
     // TODO: should we have direct iterators instead of exposing the std::map here?
-    const std::map<std::string, ElementPtr>& mapValue() { return (m); }
+    const std::map<std::string, ConstElementPtr>& mapValue() const {
+        return (m);
+    }
     using Element::getValue;
     using Element::getValue;
-    bool getValue(std::map<std::string, ElementPtr>& t) { t = m; return (true); }
+    bool getValue(std::map<std::string, ConstElementPtr>& t) {
+        t = m;
+        return (true);
+    }
     using Element::setValue;
     using Element::setValue;
-    bool setValue(std::map<std::string, ElementPtr>& v) { m = v; return (true); }
+    bool setValue(std::map<std::string, ConstElementPtr>& v) {
+        m = v;
+        return (true);
+    }
     using Element::get;
     using Element::get;
-    ElementPtr get(const std::string& s) { if (contains(s)) { return (m[s]); } else { return (ElementPtr());} }
+    ConstElementPtr get(const std::string& s) const {
+        return (contains(s) ? m.find(s)->second : ConstElementPtr());
+    }
     using Element::set;
     using Element::set;
-    void set(const std::string& key, ElementPtr value);
+    void set(const std::string& key, ConstElementPtr value);
     using Element::remove;
     using Element::remove;
     void remove(const std::string& s) { m.erase(s); }
     void remove(const std::string& s) { m.erase(s); }
-    bool contains(const std::string& s) { return (m.find(s) != m.end()); }
+    bool contains(const std::string& s) const {
-    void toJSON(std::ostream& ss);
+        return (m.find(s) != m.end());
+    }
+    void toJSON(std::ostream& ss) const;
     
     
     // we should name the two finds better...
     // we should name the two finds better...
     // find the element at id; raises TypeError if one of the
     // find the element at id; raises TypeError if one of the
     // elements at path except the one we're looking for is not a
     // elements at path except the one we're looking for is not a
     // mapelement.
     // mapelement.
     // returns an empty element if the item could not be found
     // returns an empty element if the item could not be found
-    ElementPtr find(const std::string& id);
+    ConstElementPtr find(const std::string& id) const;
 
 
     // find the Element at 'id', and store the element pointer in t
     // find the Element at 'id', and store the element pointer in t
     // returns true if found, or false if not found (either because
     // returns true if found, or false if not found (either because
     // it doesnt exist or one of the elements in the path is not
     // it doesnt exist or one of the elements in the path is not
     // a MapElement)
     // a MapElement)
-    bool find(const std::string& id, ElementPtr& t);
+    bool find(const std::string& id, ConstElementPtr t) const;
 
 
-    bool equals(ElementPtr other);
+    bool equals(const Element& other) const;
 };
 };
 
 
 /// Checks whether the given ElementPtr is a NULL pointer
 /// Checks whether the given ElementPtr is a NULL pointer
 /// \param p The ElementPtr to check
 /// \param p The ElementPtr to check
 /// \return true if it is NULL, false if not.
 /// \return true if it is NULL, false if not.
-bool isNull(ElementPtr p);
+bool isNull(ConstElementPtr p);
 
 
 ///
 ///
 /// \brief Remove all values from the first ElementPtr that are
 /// \brief Remove all values from the first ElementPtr that are
@@ -493,7 +524,14 @@ bool isNull(ElementPtr p);
 /// only contains new and changed values (for ModuleCCSession and
 /// only contains new and changed values (for ModuleCCSession and
 /// configuration update handlers)
 /// configuration update handlers)
 /// Raises a TypeError if a or b are not MapElements
 /// Raises a TypeError if a or b are not MapElements
-void removeIdentical(ElementPtr a, const ElementPtr b);
+void removeIdentical(ElementPtr a, ConstElementPtr b);
+
+/// \brief Create a new ElementPtr from the first ElementPtr, removing all
+/// values that are equal in the second. Both ElementPtrs MUST be MapElements.
+/// The returned ElementPtr will be a MapElement that only contains new and
+/// changed values (for ModuleCCSession and configuration update handlers).
+/// Raises a TypeError if a or b are not MapElements
+ConstElementPtr removeIdentical(ConstElementPtr a, ConstElementPtr b);
 
 
 /// \brief Merges the data from other into element.
 /// \brief Merges the data from other into element.
 /// (on the first level). Both elements must be
 /// (on the first level). Both elements must be
@@ -507,7 +545,7 @@ void removeIdentical(ElementPtr a, const ElementPtr b);
 /// configuration data (which would then result in reverting back
 /// configuration data (which would then result in reverting back
 /// to the default).
 /// to the default).
 /// Raises a TypeError if either ElementPtr is not a MapElement
 /// Raises a TypeError if either ElementPtr is not a MapElement
-void merge(ElementPtr element, const ElementPtr other);
+void merge(ElementPtr element, ConstElementPtr other);
 
 
 ///
 ///
 /// \brief Insert the Element as a string into stream.
 /// \brief Insert the Element as a string into stream.
@@ -524,11 +562,11 @@ void merge(ElementPtr element, const ElementPtr other);
 /// \param e The \c ElementPtr object to insert.
 /// \param e The \c ElementPtr object to insert.
 /// \return A reference to the same \c std::ostream object referenced by
 /// \return A reference to the same \c std::ostream object referenced by
 /// parameter \c os after the insertion operation.
 /// parameter \c os after the insertion operation.
-std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e);
+std::ostream& operator<<(std::ostream& out, const Element& e);
 
 
-bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b);
+bool operator==(const Element& a, const Element& b);
+bool operator!=(const Element& a, const Element& b);
 } }
 } }
-
 #endif // _ISC_DATA_H
 #endif // _ISC_DATA_H
 
 
 // Local Variables: 
 // Local Variables: 

+ 18 - 16
src/lib/cc/session.cc

@@ -296,11 +296,11 @@ Session::establish(const char* socket_file) {
     //
     //
     // send a request for our local name, and wait for a response
     // send a request for our local name, and wait for a response
     //
     //
-    ElementPtr get_lname_msg =
+    ConstElementPtr get_lname_msg =
         Element::fromJSON("{ \"type\": \"getlname\" }");
         Element::fromJSON("{ \"type\": \"getlname\" }");
     sendmsg(get_lname_msg);
     sendmsg(get_lname_msg);
 
 
-    ElementPtr routing, msg;
+    ConstElementPtr routing, msg;
     recvmsg(routing, msg, false);
     recvmsg(routing, msg, false);
 
 
     impl_->lname_ = msg->get("lname")->stringValue();
     impl_->lname_ = msg->get("lname")->stringValue();
@@ -314,7 +314,7 @@ Session::establish(const char* socket_file) {
 // prefix.
 // prefix.
 //
 //
 void
 void
-Session::sendmsg(ElementPtr& msg) {
+Session::sendmsg(ConstElementPtr msg) {
     std::string header_wire = msg->toWire();
     std::string header_wire = msg->toWire();
     unsigned int length = 2 + header_wire.length();
     unsigned int length = 2 + header_wire.length();
     unsigned int length_net = htonl(length);
     unsigned int length_net = htonl(length);
@@ -327,7 +327,7 @@ Session::sendmsg(ElementPtr& msg) {
 }
 }
 
 
 void
 void
-Session::sendmsg(ElementPtr& env, ElementPtr& msg) {
+Session::sendmsg(ConstElementPtr env, ConstElementPtr msg) {
     std::string header_wire = env->toWire();
     std::string header_wire = env->toWire();
     std::string body_wire = msg->toWire();
     std::string body_wire = msg->toWire();
     unsigned int length = 2 + header_wire.length() + body_wire.length();
     unsigned int length = 2 + header_wire.length() + body_wire.length();
@@ -342,18 +342,18 @@ Session::sendmsg(ElementPtr& env, ElementPtr& msg) {
 }
 }
 
 
 bool
 bool
-Session::recvmsg(ElementPtr& msg, bool nonblock, int seq) {
+Session::recvmsg(ConstElementPtr& msg, bool nonblock, int seq) {
-    ElementPtr l_env;
+    ConstElementPtr l_env;
     return (recvmsg(l_env, msg, nonblock, seq));
     return (recvmsg(l_env, msg, nonblock, seq));
 }
 }
 
 
 bool
 bool
-Session::recvmsg(ElementPtr& env, ElementPtr& msg,
+Session::recvmsg(ConstElementPtr& env, ConstElementPtr& msg,
-                 bool nonblock, int seq) {
+                 bool nonblock, int seq)
+{
     size_t length = impl_->readDataLength();
     size_t length = impl_->readDataLength();
-    ElementPtr l_env, l_msg;
     if (hasQueuedMsgs()) {
     if (hasQueuedMsgs()) {
-        ElementPtr q_el;
+        ConstElementPtr q_el;
         for (int i = 0; i < impl_->queue_->size(); i++) {
         for (int i = 0; i < impl_->queue_->size(); i++) {
             q_el = impl_->queue_->get(i);
             q_el = impl_->queue_->get(i);
             if (( seq == -1 &&
             if (( seq == -1 &&
@@ -390,11 +390,13 @@ Session::recvmsg(ElementPtr& env, ElementPtr& msg,
                                         length - header_length);
                                         length - header_length);
     std::stringstream header_wire_stream;
     std::stringstream header_wire_stream;
     header_wire_stream << header_wire;
     header_wire_stream << header_wire;
-    l_env = Element::fromWire(header_wire_stream, header_length);
+    ConstElementPtr l_env =
+        Element::fromWire(header_wire_stream, header_length);
     
     
     std::stringstream body_wire_stream;
     std::stringstream body_wire_stream;
     body_wire_stream << body_wire;
     body_wire_stream << body_wire;
-    l_msg = Element::fromWire(body_wire_stream, length - header_length);
+    ConstElementPtr l_msg =
+        Element::fromWire(body_wire_stream, length - header_length);
     if ((seq == -1 &&
     if ((seq == -1 &&
          !l_env->contains("reply")
          !l_env->contains("reply")
         ) || (
         ) || (
@@ -438,7 +440,7 @@ Session::unsubscribe(std::string group, std::string instance) {
 }
 }
 
 
 int
 int
-Session::group_sendmsg(ElementPtr msg, std::string group,
+Session::group_sendmsg(ConstElementPtr msg, std::string group,
                        std::string instance, std::string to)
                        std::string instance, std::string to)
 {
 {
     ElementPtr env = Element::createMap();
     ElementPtr env = Element::createMap();
@@ -457,14 +459,14 @@ Session::group_sendmsg(ElementPtr msg, std::string group,
 }
 }
 
 
 bool
 bool
-Session::group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+Session::group_recvmsg(ConstElementPtr& envelope, ConstElementPtr& msg,
                        bool nonblock, int seq)
                        bool nonblock, int seq)
 {
 {
     return (recvmsg(envelope, msg, nonblock, seq));
     return (recvmsg(envelope, msg, nonblock, seq));
 }
 }
 
 
 int
 int
-Session::reply(ElementPtr& envelope, ElementPtr& newmsg) {
+Session::reply(ConstElementPtr envelope, ConstElementPtr newmsg) {
     ElementPtr env = Element::createMap();
     ElementPtr env = Element::createMap();
     long int nseq = ++impl_->sequence_;
     long int nseq = ++impl_->sequence_;
     
     
@@ -482,7 +484,7 @@ Session::reply(ElementPtr& envelope, ElementPtr& newmsg) {
 }
 }
 
 
 bool
 bool
-Session::hasQueuedMsgs() {
+Session::hasQueuedMsgs() const {
     return (impl_->queue_->size() > 0);
     return (impl_->queue_->size() > 0);
 }
 }
 
 

+ 18 - 18
src/lib/cc/session.h

@@ -81,12 +81,12 @@ namespace isc {
             //@}
             //@}
             virtual void establish(const char* socket_file) = 0;
             virtual void establish(const char* socket_file) = 0;
             virtual void disconnect() = 0;
             virtual void disconnect() = 0;
-            virtual int group_sendmsg(isc::data::ElementPtr msg,
+            virtual int group_sendmsg(isc::data::ConstElementPtr msg,
                                       std::string group,
                                       std::string group,
                                       std::string instance = "*",
                                       std::string instance = "*",
                                       std::string to = "*") = 0;
                                       std::string to = "*") = 0;
-            virtual bool group_recvmsg(isc::data::ElementPtr& envelope,
+            virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
-                                       isc::data::ElementPtr& msg,
+                                       isc::data::ConstElementPtr& msg,
                                        bool nonblock = true,
                                        bool nonblock = true,
                                        int seq = -1) = 0;
                                        int seq = -1) = 0;
             virtual void subscribe(std::string group,
             virtual void subscribe(std::string group,
@@ -94,9 +94,9 @@ namespace isc {
             virtual void unsubscribe(std::string group,
             virtual void unsubscribe(std::string group,
                              std::string instance = "*") = 0;
                              std::string instance = "*") = 0;
             virtual void startRead(boost::function<void()> read_callback) = 0;
             virtual void startRead(boost::function<void()> read_callback) = 0;
-            virtual int reply(isc::data::ElementPtr& envelope,
+            virtual int reply(isc::data::ConstElementPtr envelope,
-                               isc::data::ElementPtr& newmsg) = 0;
+                               isc::data::ConstElementPtr newmsg) = 0;
-            virtual bool hasQueuedMsgs() = 0;
+            virtual bool hasQueuedMsgs() const = 0;
 
 
             /// \brief Sets the default timeout for blocking reads
             /// \brief Sets the default timeout for blocking reads
             ///        in this session to the given number of milliseconds
             ///        in this session to the given number of milliseconds
@@ -130,28 +130,28 @@ namespace isc {
                                    std::string instance = "*");
                                    std::string instance = "*");
             virtual void unsubscribe(std::string group,
             virtual void unsubscribe(std::string group,
                              std::string instance = "*");
                              std::string instance = "*");
-            virtual int group_sendmsg(isc::data::ElementPtr msg,
+            virtual int group_sendmsg(isc::data::ConstElementPtr msg,
                                       std::string group,
                                       std::string group,
                                       std::string instance = "*",
                                       std::string instance = "*",
                                       std::string to = "*");
                                       std::string to = "*");
-            virtual bool group_recvmsg(isc::data::ElementPtr& envelope,
+            virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
-                                       isc::data::ElementPtr& msg,
+                                       isc::data::ConstElementPtr& msg,
                                        bool nonblock = true,
                                        bool nonblock = true,
                                        int seq = -1);
                                        int seq = -1);
-            virtual int reply(isc::data::ElementPtr& envelope,
+            virtual int reply(isc::data::ConstElementPtr envelope,
-                              isc::data::ElementPtr& newmsg);
+                              isc::data::ConstElementPtr newmsg);
-            virtual bool hasQueuedMsgs();
+            virtual bool hasQueuedMsgs() const;
             virtual void setTimeout(size_t milliseconds);
             virtual void setTimeout(size_t milliseconds);
             virtual size_t getTimeout() const;
             virtual size_t getTimeout() const;
     private:
     private:
-            void sendmsg(isc::data::ElementPtr& msg);
+            void sendmsg(isc::data::ConstElementPtr msg);
-            void sendmsg(isc::data::ElementPtr& env,
+            void sendmsg(isc::data::ConstElementPtr env,
-                         isc::data::ElementPtr& msg);
+                         isc::data::ConstElementPtr msg);
-            bool recvmsg(isc::data::ElementPtr& msg,
+            bool recvmsg(isc::data::ConstElementPtr& msg,
                          bool nonblock = true,
                          bool nonblock = true,
                          int seq = -1);
                          int seq = -1);
-            bool recvmsg(isc::data::ElementPtr& env,
+            bool recvmsg(isc::data::ConstElementPtr& env,
-                         isc::data::ElementPtr& msg,
+                         isc::data::ConstElementPtr& msg,
                          bool nonblock = true,
                          bool nonblock = true,
                          int seq = -1);
                          int seq = -1);
         };
         };

+ 141 - 92
src/lib/cc/tests/data_unittests.cc

@@ -29,6 +29,7 @@ using std::setfill;
 using std::setw;
 using std::setw;
 using std::string;
 using std::string;
 
 
+namespace {
 TEST(Element, type) {
 TEST(Element, type) {
     // this tests checks whether the getType() function returns the
     // this tests checks whether the getType() function returns the
     // correct type
     // correct type
@@ -73,7 +74,7 @@ TEST(Element, from_and_to_json) {
     // a set of inputs that are the same when converted to json and
     // a set of inputs that are the same when converted to json and
     // back to a string (tests for inputs that have equivalent, but
     // back to a string (tests for inputs that have equivalent, but
     // different string representations when converted back are below)
     // different string representations when converted back are below)
-    ElementPtr el;
+    ConstElementPtr el;
     std::vector<std::string> sv;
     std::vector<std::string> sv;
 
 
     sv.push_back("12");
     sv.push_back("12");
@@ -92,25 +93,25 @@ TEST(Element, from_and_to_json) {
     sv.push_back("-1.234");
     sv.push_back("-1.234");
     sv.push_back("-123.456");
     sv.push_back("-123.456");
     
     
-    BOOST_FOREACH(std::string s, sv) {
+    BOOST_FOREACH(const std::string& s, sv) {
         // test << operator, which uses Element::str()
         // test << operator, which uses Element::str()
         std::ostringstream stream;
         std::ostringstream stream;
         el = Element::fromJSON(s);
         el = Element::fromJSON(s);
-        stream << el;
+        stream << *el;
-        EXPECT_EQ(stream.str(), s);
+        EXPECT_EQ(s, stream.str());
 
 
         // test toWire(ostream), which should also be the same now
         // test toWire(ostream), which should also be the same now
         std::ostringstream wire_stream;
         std::ostringstream wire_stream;
         el->toWire(wire_stream);
         el->toWire(wire_stream);
-        EXPECT_EQ(wire_stream.str(), s);
+        EXPECT_EQ(s, wire_stream.str());
     }
     }
 
 
     // some parse errors
     // some parse errors
     try {
     try {
         Element::fromJSON("{1}");
         Element::fromJSON("{1}");
-    } catch (isc::data::JSONError pe) {
+    } catch (const isc::data::JSONError& pe) {
         std::string s = std::string(pe.what());
         std::string s = std::string(pe.what());
-        EXPECT_EQ(s, "String expected in <string>:1:3");
+        EXPECT_EQ("String expected in <string>:1:3", s);
     }
     }
     
     
     sv.clear();
     sv.clear();
@@ -169,9 +170,8 @@ TEST(Element, create_and_value_throws) {
     double d;
     double d;
     bool b;
     bool b;
     std::string s("asdf");
     std::string s("asdf");
-    std::vector<ElementPtr> v;
+    std::vector<ConstElementPtr> v;
-    std::map<std::string, ElementPtr> m;
+    std::map<std::string, ConstElementPtr> m;
-    
 
 
     el = Element::create(1);
     el = Element::create(1);
     EXPECT_NO_THROW(el->intValue());
     EXPECT_NO_THROW(el->intValue());
@@ -204,7 +204,7 @@ TEST(Element, create_and_value_throws) {
     EXPECT_THROW(el->set("foo", el), TypeError);
     EXPECT_THROW(el->set("foo", el), TypeError);
     EXPECT_THROW(el->remove("foo"), TypeError);
     EXPECT_THROW(el->remove("foo"), TypeError);
     EXPECT_THROW(el->contains("foo"), TypeError);
     EXPECT_THROW(el->contains("foo"), TypeError);
-    ElementPtr tmp;
+    ConstElementPtr tmp;
     EXPECT_FALSE(el->find("foo", tmp));
     EXPECT_FALSE(el->find("foo", tmp));
     
     
 
 
@@ -322,13 +322,19 @@ TEST(Element, ListElement) {
     EXPECT_ANY_THROW(el->get(3));
     EXPECT_ANY_THROW(el->get(3));
 
 
     el->add(Element::create(32));
     el->add(Element::create(32));
-    EXPECT_EQ(el->get(2)->intValue(), 32);
+    EXPECT_EQ(32, el->get(2)->intValue());
+
+    // boundary condition tests for set()
+    el->set(2, Element::create(0)); // update the last entry of the list
+    EXPECT_EQ(0, el->get(2)->intValue());
+    // attempt of set beyond the range of list should trigger an exception.
+    EXPECT_ANY_THROW(el->set(3, Element::create(0)));
 }
 }
 
 
 TEST(Element, MapElement) {
 TEST(Element, MapElement) {
     // this function checks the specific functions for ListElements
     // this function checks the specific functions for ListElements
     ElementPtr el = Element::fromJSON("{ \"name\": \"foo\", \"value1\": \"bar\", \"value2\": { \"number\": 42 } }");
     ElementPtr el = Element::fromJSON("{ \"name\": \"foo\", \"value1\": \"bar\", \"value2\": { \"number\": 42 } }");
-    ElementPtr el2;
+    ConstElementPtr el2;
     
     
     EXPECT_EQ(el->get("name")->stringValue(), "foo");
     EXPECT_EQ(el->get("name")->stringValue(), "foo");
     EXPECT_EQ(el->get("value2")->getType(), Element::map);
     EXPECT_EQ(el->get("value2")->getType(), Element::map);
@@ -376,7 +382,6 @@ TEST(Element, MapElement) {
 
 
 TEST(Element, to_and_from_wire) {
 TEST(Element, to_and_from_wire) {
     // Wire format is now plain JSON.
     // Wire format is now plain JSON.
-    ElementPtr el;
     EXPECT_EQ("1", Element::create(1)->toWire());
     EXPECT_EQ("1", Element::create(1)->toWire());
     EXPECT_EQ("1.1", Element::create(1.1)->toWire());
     EXPECT_EQ("1.1", Element::create(1.1)->toWire());
     EXPECT_EQ("true", Element::create(true)->toWire());
     EXPECT_EQ("true", Element::create(true)->toWire());
@@ -398,124 +403,167 @@ TEST(Element, to_and_from_wire) {
     EXPECT_THROW(Element::fromJSON("[ 1, 2, }"), isc::data::JSONError);
     EXPECT_THROW(Element::fromJSON("[ 1, 2, }"), isc::data::JSONError);
 }
 }
 
 
-static ElementPtr
+ConstElementPtr
 efs(const std::string& str) {
 efs(const std::string& str) {
     return (Element::fromJSON(str));
     return (Element::fromJSON(str));
 }
 }
 
 
 TEST(Element, equals) {
 TEST(Element, equals) {
-    // why does EXPECT_EQ not work?
+    EXPECT_EQ(*efs("1"), *efs("1"));
-    EXPECT_EQ(efs("1"), efs("1"));
+    EXPECT_NE(*efs("1"), *efs("2"));
-    EXPECT_NE(efs("1"), efs("2"));
+    EXPECT_NE(*efs("1"), *efs("\"1\""));
-    EXPECT_NE(efs("1"), efs("\"1\""));
+    EXPECT_NE(*efs("1"), *efs("[]"));
-    EXPECT_NE(efs("1"), efs("[]"));
+    EXPECT_NE(*efs("1"), *efs("True"));
-    EXPECT_NE(efs("1"), efs("True"));
+    EXPECT_NE(*efs("1"), *efs("{}"));
-    EXPECT_NE(efs("1"), efs("{}"));
+
-
+    EXPECT_EQ(*efs("1.1"), *efs("1.1"));
-    EXPECT_EQ(efs("1.1"), efs("1.1"));
+    EXPECT_NE(*efs("1.0"), *efs("1"));
-    EXPECT_NE(efs("1.0"), efs("1"));
+    EXPECT_NE(*efs("1.1"), *efs("\"1\""));
-    EXPECT_NE(efs("1.1"), efs("\"1\""));
+    EXPECT_NE(*efs("1.1"), *efs("[]"));
-    EXPECT_NE(efs("1.1"), efs("[]"));
+    EXPECT_NE(*efs("1.1"), *efs("True"));
-    EXPECT_NE(efs("1.1"), efs("True"));
+    EXPECT_NE(*efs("1.1"), *efs("{}"));
-    EXPECT_NE(efs("1.1"), efs("{}"));
+
-
+    EXPECT_EQ(*efs("True"), *efs("True"));
-    EXPECT_EQ(efs("True"), efs("True"));
+    EXPECT_NE(*efs("True"), *efs("False"));
-    EXPECT_NE(efs("True"), efs("False"));
+    EXPECT_NE(*efs("True"), *efs("1"));
-    EXPECT_NE(efs("True"), efs("1"));
+    EXPECT_NE(*efs("True"), *efs("\"1\""));
-    EXPECT_NE(efs("True"), efs("\"1\""));
+    EXPECT_NE(*efs("True"), *efs("[]"));
-    EXPECT_NE(efs("True"), efs("[]"));
+    EXPECT_NE(*efs("True"), *efs("{}"));
-    EXPECT_NE(efs("True"), efs("{}"));
+
-
+    EXPECT_EQ(*efs("\"foo\""), *efs("\"foo\""));
-    EXPECT_EQ(efs("\"foo\""), efs("\"foo\""));
+    EXPECT_NE(*efs("\"foo\""), *efs("\"bar\""));
-    EXPECT_NE(efs("\"foo\""), efs("\"bar\""));
+    EXPECT_NE(*efs("\"foo\""), *efs("1"));
-    EXPECT_NE(efs("\"foo\""), efs("1"));
+    EXPECT_NE(*efs("\"foo\""), *efs("\"1\""));
-    EXPECT_NE(efs("\"foo\""), efs("\"1\""));
+    EXPECT_NE(*efs("\"foo\""), *efs("True"));
-    EXPECT_NE(efs("\"foo\""), efs("True"));
+    EXPECT_NE(*efs("\"foo\""), *efs("[]"));
-    EXPECT_NE(efs("\"foo\""), efs("[]"));
+    EXPECT_NE(*efs("\"foo\""), *efs("{}"));
-    EXPECT_NE(efs("\"foo\""), efs("{}"));
+
-
+    EXPECT_EQ(*efs("[]"), *efs("[]"));
-    EXPECT_EQ(efs("[]"), efs("[]"));
+    EXPECT_EQ(*efs("[ 1, 2, 3 ]"), *efs("[ 1, 2, 3 ]"));
-    EXPECT_EQ(efs("[ 1, 2, 3 ]"), efs("[ 1, 2, 3 ]"));
+    EXPECT_EQ(*efs("[ \"a\", [ True, 1], 2.2 ]"), *efs("[ \"a\", [ True, 1], 2.2 ]"));
-    EXPECT_EQ(efs("[ \"a\", [ True, 1], 2.2 ]"), efs("[ \"a\", [ True, 1], 2.2 ]"));
+    EXPECT_NE(*efs("[ \"a\", [ True, 1], 2.2 ]"), *efs("[ \"a\", [ True, 2], 2.2 ]"));
-    EXPECT_NE(efs("[ \"a\", [ True, 1], 2.2 ]"), efs("[ \"a\", [ True, 2], 2.2 ]"));
+    EXPECT_NE(*efs("[]"), *efs("[1]"));
-    EXPECT_NE(efs("[]"), efs("[1]"));
+    EXPECT_NE(*efs("[]"), *efs("1"));
-    EXPECT_NE(efs("[]"), efs("1"));
+    EXPECT_NE(*efs("[]"), *efs("\"1\""));
-    EXPECT_NE(efs("[]"), efs("\"1\""));
+    EXPECT_NE(*efs("[]"), *efs("{}"));
-    EXPECT_NE(efs("[]"), efs("{}"));
+
-
+    EXPECT_EQ(*efs("{}"), *efs("{}"));
-    EXPECT_EQ(efs("{}"), efs("{}"));
+    EXPECT_EQ(*efs("{ \"foo\": \"bar\" }"), *efs("{ \"foo\": \"bar\" }"));
-    EXPECT_EQ(efs("{ \"foo\": \"bar\" }"), efs("{ \"foo\": \"bar\" }"));
+    EXPECT_EQ(*efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), *efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"));
-    EXPECT_EQ(efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"));
+    EXPECT_NE(*efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), *efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar2\" } }"));
-    EXPECT_NE(efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar2\" } }"));
+    EXPECT_NE(*efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), *efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\", 1 ], \"item3\": { \"foo\": \"bar\" } }"));
-    EXPECT_NE(efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\" ], \"item3\": { \"foo\": \"bar\" } }"), efs("{ \"item1\": 1, \"item2\": [ \"a\", \"list\", 1 ], \"item3\": { \"foo\": \"bar\" } }"));
+    EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("1"));
-    EXPECT_NE(efs("{ \"foo\": \"bar\" }"), efs("1"));
+    EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("\"1\""));
-    EXPECT_NE(efs("{ \"foo\": \"bar\" }"), efs("\"1\""));
+    EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("[]"));
-    EXPECT_NE(efs("{ \"foo\": \"bar\" }"), efs("[]"));
+    EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("{}"));
-    EXPECT_NE(efs("{ \"foo\": \"bar\" }"), efs("{}"));
+    EXPECT_NE(*efs("{ \"foo\": \"bar\" }"), *efs("{ \"something\": \"different\" }"));
-    EXPECT_NE(efs("{ \"foo\": \"bar\" }"), efs("{ \"something\": \"different\" }"));
+
-
+    EXPECT_EQ(*efs("null"), *Element::create());
-    EXPECT_EQ(efs("null"), Element::create());
 }
 }
 
 
 TEST(Element, removeIdentical) {
 TEST(Element, removeIdentical) {
     ElementPtr a = Element::createMap();
     ElementPtr a = Element::createMap();
-    ElementPtr b = Element::createMap();
+    ConstElementPtr b = Element::createMap();
-    ElementPtr c = Element::createMap();
+    ConstElementPtr c = Element::createMap();
     removeIdentical(a, b);
     removeIdentical(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1 }");
     a = Element::fromJSON("{ \"a\": 1 }");
     b = Element::fromJSON("{ \"a\": 1 }");
     b = Element::fromJSON("{ \"a\": 1 }");
     c = Element::createMap();
     c = Element::createMap();
     removeIdentical(a, b);
     removeIdentical(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     b = Element::createMap();
     b = Element::createMap();
     c = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     c = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     removeIdentical(a, b);
     removeIdentical(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     c = Element::createMap();
     c = Element::createMap();
     removeIdentical(a, b);
     removeIdentical(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 3 ] }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 3 ] }");
     c = Element::fromJSON("{ \"b\": [ 1, 2 ] }");
     c = Element::fromJSON("{ \"b\": [ 1, 2 ] }");
     removeIdentical(a, b);
     removeIdentical(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     b = Element::createMap();
     b = Element::createMap();
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     removeIdentical(a, b);
     removeIdentical(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     b = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     b = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     c = Element::createMap();
     c = Element::createMap();
     removeIdentical(a, b);
     removeIdentical(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
     b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     removeIdentical(a, b);
     removeIdentical(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     EXPECT_THROW(removeIdentical(Element::create(1), Element::create(2)), TypeError);
     EXPECT_THROW(removeIdentical(Element::create(1), Element::create(2)), TypeError);
 }
 }
 
 
-TEST(Element, merge)
+TEST(Element, constRemoveIdentical) {
-{
+    ConstElementPtr a = Element::createMap();
+    ConstElementPtr b = Element::createMap();
+    ConstElementPtr c = Element::createMap();
+    EXPECT_EQ(*removeIdentical(a, b), *c);
+
+    a = Element::fromJSON("{ \"a\": 1 }");
+    b = Element::fromJSON("{ \"a\": 1 }");
+    c = Element::createMap();
+    EXPECT_EQ(*removeIdentical(a, b), *c);
+
+    a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    b = Element::createMap();
+    c = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    EXPECT_EQ(*removeIdentical(a, b), *c);
+
+    a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    c = Element::createMap();
+    EXPECT_EQ(*removeIdentical(a, b), *c);
+
+    a = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 2 ] }");
+    b = Element::fromJSON("{ \"a\": 1, \"b\": [ 1, 3 ] }");
+    c = Element::fromJSON("{ \"b\": [ 1, 2 ] }");
+    EXPECT_EQ(*removeIdentical(a, b), *c);
+
+    a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
+    b = Element::createMap();
+    c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
+    EXPECT_EQ(*removeIdentical(a, b), *c);
+
+    a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
+    b = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
+    c = Element::createMap();
+    EXPECT_EQ(*removeIdentical(a, b), *c);
+
+    a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
+    b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
+    c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
+    EXPECT_EQ(*removeIdentical(a, b), *c);
+
+    EXPECT_THROW(removeIdentical(Element::create(1), Element::create(2)),
+                 TypeError);
+}
+
+TEST(Element, merge) {
     ElementPtr a = Element::createMap();
     ElementPtr a = Element::createMap();
     ElementPtr b = Element::createMap();
     ElementPtr b = Element::createMap();
-    ElementPtr c = Element::createMap();
+    ConstElementPtr c = Element::createMap();
     merge(a, b);
     merge(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("1");
     a = Element::fromJSON("1");
     b = Element::createMap();
     b = Element::createMap();
@@ -525,73 +573,74 @@ TEST(Element, merge)
     b = Element::fromJSON("{ \"a\": 1 }");
     b = Element::fromJSON("{ \"a\": 1 }");
     c = Element::fromJSON("{ \"a\": 1 }");
     c = Element::fromJSON("{ \"a\": 1 }");
     merge(a, b);
     merge(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::createMap();
     a = Element::createMap();
     b = Element::fromJSON("{ \"a\": 1 }");
     b = Element::fromJSON("{ \"a\": 1 }");
     c = Element::fromJSON("{ \"a\": 1 }");
     c = Element::fromJSON("{ \"a\": 1 }");
     merge(b, a);
     merge(b, a);
-    EXPECT_EQ(b, c);
+    EXPECT_EQ(*b, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1 }");
     a = Element::fromJSON("{ \"a\": 1 }");
     b = Element::fromJSON("{ \"a\": 2 }");
     b = Element::fromJSON("{ \"a\": 2 }");
     c = Element::fromJSON("{ \"a\": 2 }");
     c = Element::fromJSON("{ \"a\": 2 }");
     merge(a, b);
     merge(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1 }");
     a = Element::fromJSON("{ \"a\": 1 }");
     b = Element::fromJSON("{ \"a\": 2 }");
     b = Element::fromJSON("{ \"a\": 2 }");
     c = Element::fromJSON("{ \"a\": 1 }");
     c = Element::fromJSON("{ \"a\": 1 }");
     merge(b, a);
     merge(b, a);
-    EXPECT_EQ(b, c);
+    EXPECT_EQ(*b, *c);
 
 
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
     b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
     merge(a, b);
     merge(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
     b = Element::fromJSON("{ \"a\": { \"b\": \"d\" } }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     merge(b, a);
     merge(b, a);
-    EXPECT_EQ(b, c);
+    EXPECT_EQ(*b, *c);
 
 
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     b = Element::fromJSON("{ \"a\": null }");
     b = Element::fromJSON("{ \"a\": null }");
     c = Element::fromJSON("{  }");
     c = Element::fromJSON("{  }");
     merge(a, b);
     merge(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     a = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     b = Element::fromJSON("{ \"a\": null }");
     b = Element::fromJSON("{ \"a\": null }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     c = Element::fromJSON("{ \"a\": { \"b\": \"c\" } }");
     merge(b, a);
     merge(b, a);
-    EXPECT_EQ(b, c);
+    EXPECT_EQ(*b, *c);
     
     
     // And some tests with multiple values
     // And some tests with multiple values
     a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }");
     a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }");
     c = Element::fromJSON("{ \"a\": 1, \"c\": \"a string\" }");
     c = Element::fromJSON("{ \"a\": 1, \"c\": \"a string\" }");
     merge(a, b);
     merge(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }");
     a = Element::fromJSON("{ \"a\": 1, \"b\": true, \"c\": null }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }");
     b = Element::fromJSON("{ \"a\": 1, \"b\": null, \"c\": \"a string\" }");
     c = Element::fromJSON("{ \"a\": 1, \"b\": true }");
     c = Element::fromJSON("{ \"a\": 1, \"b\": true }");
     merge(b, a);
     merge(b, a);
-    EXPECT_EQ(b, c);
+    EXPECT_EQ(*b, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
     a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
     b = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
     b = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
     c = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
     c = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
     merge(a, b);
     merge(a, b);
-    EXPECT_EQ(a, c);
+    EXPECT_EQ(*a, *c);
 
 
     a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
     a = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
     b = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
     b = Element::fromJSON("{ \"a\": 3, \"b\": 2, \"c\": 1 }");
     c = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
     c = Element::fromJSON("{ \"a\": 1, \"b\": 2, \"c\": 3 }");
     merge(b, a);
     merge(b, a);
-    EXPECT_EQ(b, c);
+    EXPECT_EQ(*b, *c);
 
 
 }
 }
+}

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

@@ -140,7 +140,7 @@ public:
     // If this message is { "command": "stop" } it'll tell the
     // If this message is { "command": "stop" } it'll tell the
     // io_service it is done. Otherwise it'll re-register this handler
     // io_service it is done. Otherwise it'll re-register this handler
     void someHandler() {
     void someHandler() {
-        isc::data::ElementPtr env, msg;
+        isc::data::ConstElementPtr env, msg;
         sess.group_recvmsg(env, msg, false, -1);
         sess.group_recvmsg(env, msg, false, -1);
 
 
         sess.group_recvmsg(env, msg, false, -1);
         sess.group_recvmsg(env, msg, false, -1);
@@ -188,7 +188,7 @@ TEST_F(SessionTest, connect_ok_connection_reset) {
     // Close the session again, so the next recv() should throw
     // Close the session again, so the next recv() should throw
     sess.disconnect();
     sess.disconnect();
 
 
-    isc::data::ElementPtr env, msg;
+    isc::data::ConstElementPtr env, msg;
     EXPECT_THROW(sess.group_recvmsg(env, msg, false, -1), SessionError);
     EXPECT_THROW(sess.group_recvmsg(env, msg, false, -1), SessionError);
 }
 }
 
 

+ 68 - 57
src/lib/config/ccsession.cc

@@ -52,41 +52,47 @@ namespace isc {
 namespace config {
 namespace config {
 
 
 /// Creates a standard config/command protocol answer message
 /// Creates a standard config/command protocol answer message
-ElementPtr
+ConstElementPtr
 createAnswer() {
 createAnswer() {
     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
-    ElementPtr answer_content = answer->get("result");
+    ElementPtr answer_content = Element::createList();
     answer_content->add(Element::create(0));
     answer_content->add(Element::create(0));
+    answer->set("result", answer_content);
+
     return (answer);
     return (answer);
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-createAnswer(const int rcode, const ElementPtr arg) {
+createAnswer(const int rcode, ConstElementPtr arg) {
     if (rcode != 0 && (!arg || arg->getType() != Element::string)) {
     if (rcode != 0 && (!arg || arg->getType() != Element::string)) {
         isc_throw(CCSessionError, "Bad or no argument for rcode != 0");
         isc_throw(CCSessionError, "Bad or no argument for rcode != 0");
     }
     }
     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
-    ElementPtr answer_content = answer->get("result");
+    ElementPtr answer_content = Element::createList();
     answer_content->add(Element::create(rcode));
     answer_content->add(Element::create(rcode));
     answer_content->add(arg);
     answer_content->add(arg);
+    answer->set("result", answer_content);
+
     return (answer);
     return (answer);
 }
 }
 
 
-ElementPtr
+ConstElementPtr
 createAnswer(const int rcode, const std::string& arg) {
 createAnswer(const int rcode, const std::string& arg) {
     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
-    ElementPtr answer_content = answer->get("result");
+    ElementPtr answer_content = Element::createList();
     answer_content->add(Element::create(rcode));
     answer_content->add(Element::create(rcode));
     answer_content->add(Element::create(arg));
     answer_content->add(Element::create(arg));
+    answer->set("result", answer_content);
+
     return (answer);
     return (answer);
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-parseAnswer(int &rcode, const ElementPtr msg) {
+parseAnswer(int &rcode, ConstElementPtr msg) {
     if (msg &&
     if (msg &&
         msg->getType() == Element::map &&
         msg->getType() == Element::map &&
         msg->contains("result")) {
         msg->contains("result")) {
-        ElementPtr result = msg->get("result");
+        ConstElementPtr result = msg->get("result");
         if (result->getType() != Element::list) {
         if (result->getType() != Element::list) {
             isc_throw(CCSessionError, "Result element in answer message is not a list");
             isc_throw(CCSessionError, "Result element in answer message is not a list");
         } else if (result->get(0)->getType() != Element::integer) {
         } else if (result->get(0)->getType() != Element::integer) {
@@ -111,13 +117,13 @@ parseAnswer(int &rcode, const ElementPtr msg) {
     }
     }
 }
 }
 
 
-ElementPtr
+ConstElementPtr
 createCommand(const std::string& command) {
 createCommand(const std::string& command) {
     return (createCommand(command, ElementPtr()));
     return (createCommand(command, ElementPtr()));
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-createCommand(const std::string& command, ElementPtr arg) {
+createCommand(const std::string& command, ConstElementPtr arg) {
     ElementPtr cmd = Element::createMap();
     ElementPtr cmd = Element::createMap();
     ElementPtr cmd_parts = Element::createList();
     ElementPtr cmd_parts = Element::createList();
     cmd_parts->add(Element::create(command));
     cmd_parts->add(Element::create(command));
@@ -130,13 +136,12 @@ createCommand(const std::string& command, ElementPtr arg) {
 
 
 /// Returns "" and empty ElementPtr() if this does not
 /// Returns "" and empty ElementPtr() if this does not
 /// look like a command
 /// look like a command
-const std::string
+std::string
-parseCommand(ElementPtr& arg, const ElementPtr command)
+parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
-{
     if (command &&
     if (command &&
         command->getType() == Element::map &&
         command->getType() == Element::map &&
         command->contains("command")) {
         command->contains("command")) {
-        ElementPtr cmd = command->get("command");
+        ConstElementPtr cmd = command->get("command");
         if (cmd->getType() == Element::list &&
         if (cmd->getType() == Element::list &&
             cmd->size() > 0 &&
             cmd->size() > 0 &&
             cmd->get(0)->getType() == Element::string) {
             cmd->get(0)->getType() == Element::string) {
@@ -192,9 +197,10 @@ ModuleCCSession::startCheck() {
 ModuleCCSession::ModuleCCSession(
 ModuleCCSession::ModuleCCSession(
     const std::string& spec_file_name,
     const std::string& spec_file_name,
     isc::cc::AbstractSession& session,
     isc::cc::AbstractSession& session,
-    isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config),
+    isc::data::ConstElementPtr(*config_handler)(
-    isc::data::ElementPtr(*command_handler)(
+        isc::data::ConstElementPtr new_config),
-        const std::string& command, const isc::data::ElementPtr args)
+    isc::data::ConstElementPtr(*command_handler)(
+        const std::string& command, isc::data::ConstElementPtr args)
     ) :
     ) :
     session_(session)
     session_(session)
 {
 {
@@ -205,18 +211,20 @@ ModuleCCSession::ModuleCCSession(
     config_handler_ = config_handler;
     config_handler_ = config_handler;
     command_handler_ = command_handler;
     command_handler_ = command_handler;
 
 
-    ElementPtr answer, env;
-
     session_.establish(NULL);
     session_.establish(NULL);
     session_.subscribe(module_name_, "*");
     session_.subscribe(module_name_, "*");
     //session_.subscribe("Boss", "*");
     //session_.subscribe("Boss", "*");
     //session_.subscribe("statistics", "*");
     //session_.subscribe("statistics", "*");
     // send the data specification
     // send the data specification
-    ElementPtr spec_msg = createCommand("module_spec", module_specification_.getFullSpec());
+
+    ConstElementPtr spec_msg = createCommand("module_spec",
+                                             module_specification_.getFullSpec());
     unsigned int seq = session_.group_sendmsg(spec_msg, "ConfigManager");
     unsigned int seq = session_.group_sendmsg(spec_msg, "ConfigManager");
+
+    ConstElementPtr answer, env;
     session_.group_recvmsg(env, answer, false, seq);
     session_.group_recvmsg(env, answer, false, seq);
     int rcode;
     int rcode;
-    ElementPtr err = parseAnswer(rcode, answer);
+    ConstElementPtr err = parseAnswer(rcode, answer);
     if (rcode != 0) {
     if (rcode != 0) {
         std::cerr << "[" << module_name_ << "] Error in specification: " << answer << std::endl;
         std::cerr << "[" << module_name_ << "] Error in specification: " << answer << std::endl;
     }
     }
@@ -224,10 +232,10 @@ ModuleCCSession::ModuleCCSession(
     setLocalConfig(Element::fromJSON("{}"));
     setLocalConfig(Element::fromJSON("{}"));
     // get any stored configuration from the manager
     // get any stored configuration from the manager
     if (config_handler_) {
     if (config_handler_) {
-        ElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
+        ConstElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
         seq = session_.group_sendmsg(cmd, "ConfigManager");
         seq = session_.group_sendmsg(cmd, "ConfigManager");
         session_.group_recvmsg(env, answer, false, seq);
         session_.group_recvmsg(env, answer, false, seq);
-        ElementPtr new_config = parseAnswer(rcode, answer);
+        ConstElementPtr new_config = parseAnswer(rcode, answer);
         if (rcode == 0) {
         if (rcode == 0) {
             handleConfigUpdate(new_config);
             handleConfigUpdate(new_config);
         } else {
         } else {
@@ -242,30 +250,30 @@ ModuleCCSession::ModuleCCSession(
 /// Validates the new config values, if they are correct,
 /// Validates the new config values, if they are correct,
 /// call the config handler with the values that have changed
 /// call the config handler with the values that have changed
 /// If that results in success, store the new config
 /// If that results in success, store the new config
-ElementPtr
+ConstElementPtr
-ModuleCCSession::handleConfigUpdate(ElementPtr new_config)
+ModuleCCSession::handleConfigUpdate(ConstElementPtr new_config) {
-{
+    ConstElementPtr answer;
-    ElementPtr answer;
     ElementPtr errors = Element::createList();
     ElementPtr errors = Element::createList();
     if (!config_handler_) {
     if (!config_handler_) {
         answer = createAnswer(1, module_name_ + " does not have a config handler");
         answer = createAnswer(1, module_name_ + " does not have a config handler");
-    } else if (!module_specification_.validate_config(new_config, false, errors)) {
+    } else if (!module_specification_.validate_config(new_config, false,
+                                                      errors)) {
         std::stringstream ss;
         std::stringstream ss;
         ss << "Error in config validation: ";
         ss << "Error in config validation: ";
-        BOOST_FOREACH(ElementPtr error, errors->listValue()) {
+        BOOST_FOREACH(ConstElementPtr error, errors->listValue()) {
             ss << error->stringValue();
             ss << error->stringValue();
         }
         }
         answer = createAnswer(2, ss.str());
         answer = createAnswer(2, ss.str());
     } else {
     } else {
         // remove the values that have not changed
         // remove the values that have not changed
-        isc::data::removeIdentical(new_config, getLocalConfig());
+        ConstElementPtr diff = removeIdentical(new_config, getLocalConfig());
         // handle config update
         // handle config update
-        answer = config_handler_(new_config);
+        answer = config_handler_(diff);
         int rcode;
         int rcode;
         parseAnswer(rcode, answer);
         parseAnswer(rcode, answer);
         if (rcode == 0) {
         if (rcode == 0) {
             ElementPtr local_config = getLocalConfig();
             ElementPtr local_config = getLocalConfig();
-            isc::data::merge(local_config, new_config);
+            isc::data::merge(local_config, diff);
             setLocalConfig(local_config);
             setLocalConfig(local_config);
         }
         }
     }
     }
@@ -273,15 +281,13 @@ ModuleCCSession::handleConfigUpdate(ElementPtr new_config)
 }
 }
 
 
 bool
 bool
-ModuleCCSession::hasQueuedMsgs()
+ModuleCCSession::hasQueuedMsgs() const {
-{
     return (session_.hasQueuedMsgs());
     return (session_.hasQueuedMsgs());
 }
 }
 
 
 int
 int
-ModuleCCSession::checkCommand()
+ModuleCCSession::checkCommand() {
-{
+    ConstElementPtr cmd, routing, data;
-    ElementPtr cmd, routing, data;
     if (session_.group_recvmsg(routing, data, true)) {
     if (session_.group_recvmsg(routing, data, true)) {
         
         
         /* ignore result messages (in case we're out of sync, to prevent
         /* ignore result messages (in case we're out of sync, to prevent
@@ -289,8 +295,8 @@ ModuleCCSession::checkCommand()
         if (data->getType() != Element::map || data->contains("result")) {
         if (data->getType() != Element::map || data->contains("result")) {
             return (0);
             return (0);
         }
         }
-        ElementPtr arg;
+        ConstElementPtr arg;
-        ElementPtr answer;
+        ConstElementPtr answer;
         try {
         try {
             std::string cmd_str = parseCommand(arg, data);
             std::string cmd_str = parseCommand(arg, data);
             std::string target_module = routing->get("group")->stringValue();
             std::string target_module = routing->get("group")->stringValue();
@@ -313,7 +319,7 @@ ModuleCCSession::checkCommand()
                     }
                     }
                 }
                 }
             }
             }
-        } catch (CCSessionError re) {
+        } catch (const CCSessionError& re) {
             // TODO: Once we have logging and timeouts, we should not
             // TODO: Once we have logging and timeouts, we should not
             // answer here (potential interference)
             // answer here (potential interference)
             answer = createAnswer(1, re.what());
             answer = createAnswer(1, re.what());
@@ -335,15 +341,17 @@ ModuleCCSession::addRemoteConfig(const std::string& spec_file_name)
     session_.subscribe(module_name);
     session_.subscribe(module_name);
 
 
     // Get the current configuration values for that module
     // Get the current configuration values for that module
-    ElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name + "\"} ] }");
+    ConstElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name + "\"} ] }");
-    ElementPtr env, answer;
-    int rcode;
-    
     unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
     unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
+
+    ConstElementPtr env, answer;
     session_.group_recvmsg(env, answer, false, seq);
     session_.group_recvmsg(env, answer, false, seq);
-    ElementPtr new_config = parseAnswer(rcode, answer);
+    int rcode;
-    if (rcode == 0) {
+    ConstElementPtr new_config = parseAnswer(rcode, answer);
-        rmod_config.setLocalConfig(new_config);
+    if (rcode == 0 && new_config) {
+        ElementPtr local_config = rmod_config.getLocalConfig();
+        isc::data::merge(local_config, new_config);
+        rmod_config.setLocalConfig(local_config);
     } else {
     } else {
         isc_throw(CCSessionError, "Error getting config for " + module_name + ": " + answer->str());
         isc_throw(CCSessionError, "Error getting config for " + module_name + ": " + answer->str());
     }
     }
@@ -365,21 +373,24 @@ ModuleCCSession::removeRemoteConfig(const std::string& module_name)
     }
     }
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-ModuleCCSession::getRemoteConfigValue(const std::string& module_name, const std::string& identifier)
+ModuleCCSession::getRemoteConfigValue(const std::string& module_name,
+                                      const std::string& identifier) const
 {
 {
-    std::map<std::string, ConfigData>::iterator it;
+    std::map<std::string, ConfigData>::const_iterator it =
+        remote_module_configs_.find(module_name);
 
 
-    it = remote_module_configs_.find(module_name);
     if (it != remote_module_configs_.end()) {
     if (it != remote_module_configs_.end()) {
-        return (remote_module_configs_[module_name].getValue(identifier));
+        return ((*it).second.getValue(identifier));
     } else {
     } else {
-        isc_throw(CCSessionError, "Remote module " + module_name + " not found.");
+        isc_throw(CCSessionError,
+                  "Remote module " + module_name + " not found.");
     }
     }
 }
 }
 
 
 void
 void
-ModuleCCSession::updateRemoteConfig(const std::string& module_name, ElementPtr new_config)
+ModuleCCSession::updateRemoteConfig(const std::string& module_name,
+                                    ConstElementPtr new_config)
 {
 {
     std::map<std::string, ConfigData>::iterator it;
     std::map<std::string, ConfigData>::iterator it;
 
 

+ 33 - 20
src/lib/config/ccsession.h

@@ -31,7 +31,7 @@ namespace config {
 /// \brief Creates a standard config/command level success answer message
 /// \brief Creates a standard config/command level success answer message
 ///        (i.e. of the form { "result": [ 0 ] }
 ///        (i.e. of the form { "result": [ 0 ] }
 /// \return Standard command/config success answer message
 /// \return Standard command/config success answer message
-ElementPtr createAnswer();
+ConstElementPtr createAnswer();
 
 
 ///
 ///
 /// \brief Creates a standard config/command level answer message
 /// \brief Creates a standard config/command level answer message
@@ -43,7 +43,7 @@ ElementPtr createAnswer();
 ///            Element type. For rcode == 1, this argument is mandatory,
 ///            Element type. For rcode == 1, this argument is mandatory,
 ///            and must be a StringElement containing an error description
 ///            and must be a StringElement containing an error description
 /// \return Standard command/config answer message
 /// \return Standard command/config answer message
-ElementPtr createAnswer(const int rcode, const ElementPtr arg);
+ConstElementPtr createAnswer(const int rcode, ConstElementPtr arg);
 
 
 ///
 ///
 /// \brief Creates a standard config/command level answer message
 /// \brief Creates a standard config/command level answer message
@@ -52,7 +52,7 @@ ElementPtr createAnswer(const int rcode, const ElementPtr arg);
 /// \param rcode The return code (0 for success)
 /// \param rcode The return code (0 for success)
 /// \param arg A string to put into the StringElement argument
 /// \param arg A string to put into the StringElement argument
 /// \return Standard command/config answer message
 /// \return Standard command/config answer message
-ElementPtr createAnswer(const int rcode, const std::string& arg);
+ConstElementPtr createAnswer(const int rcode, const std::string& arg);
 
 
 ///
 ///
 /// Parses a standard config/command level answer message
 /// Parses a standard config/command level answer message
@@ -63,8 +63,7 @@ ElementPtr createAnswer(const int rcode, const std::string& arg);
 /// \return The optional argument in the message, or an empty ElementPtr
 /// \return The optional argument in the message, or an empty ElementPtr
 ///         if there was no argument. If rcode != 0, this contains a
 ///         if there was no argument. If rcode != 0, this contains a
 ///         StringElement with the error description.
 ///         StringElement with the error description.
-ElementPtr parseAnswer(int &rcode, const ElementPtr msg);
+ConstElementPtr parseAnswer(int &rcode, ConstElementPtr msg);
-
 
 
 ///
 ///
 /// \brief Creates a standard config/command command message with no
 /// \brief Creates a standard config/command command message with no
@@ -72,7 +71,7 @@ ElementPtr parseAnswer(int &rcode, const ElementPtr msg);
 /// 
 /// 
 /// \param command The command string
 /// \param command The command string
 /// \return The created message
 /// \return The created message
-ElementPtr createCommand(const std::string& command);
+ConstElementPtr createCommand(const std::string& command);
 
 
 ///
 ///
 /// \brief Creates a standard config/command command message with the
 /// \brief Creates a standard config/command command message with the
@@ -82,7 +81,7 @@ ElementPtr createCommand(const std::string& command);
 /// \param arg The optional argument for the command. This can be of 
 /// \param arg The optional argument for the command. This can be of 
 ///        any Element type, but it should conform to the .spec file.
 ///        any Element type, but it should conform to the .spec file.
 /// \return The created message
 /// \return The created message
-ElementPtr createCommand(const std::string& command, ElementPtr arg);
+ConstElementPtr createCommand(const std::string& command, ConstElementPtr arg);
 
 
 ///
 ///
 /// \brief Parses the given command into a string containing the actual
 /// \brief Parses the given command into a string containing the actual
@@ -93,7 +92,7 @@ ElementPtr createCommand(const std::string& command, ElementPtr arg);
 /// \param command The command message containing the command (as made
 /// \param command The command message containing the command (as made
 ///        by createCommand()
 ///        by createCommand()
 /// \return The command string
 /// \return The command string
-const std::string parseCommand(ElementPtr& arg, const ElementPtr command);
+std::string parseCommand(ConstElementPtr& arg, ConstElementPtr command);
 
 
 
 
 ///
 ///
@@ -133,11 +132,11 @@ public:
      */
      */
     ModuleCCSession(const std::string& spec_file_name,
     ModuleCCSession(const std::string& spec_file_name,
                     isc::cc::AbstractSession& session,
                     isc::cc::AbstractSession& session,
-                    isc::data::ElementPtr(*config_handler)(
+                    isc::data::ConstElementPtr(*config_handler)(
-                        isc::data::ElementPtr new_config) = NULL,
+                        isc::data::ConstElementPtr new_config) = NULL,
-                    isc::data::ElementPtr(*command_handler)(
+                    isc::data::ConstElementPtr(*command_handler)(
                         const std::string& command,
                         const std::string& command,
-                        const isc::data::ElementPtr args) = NULL
+                        isc::data::ConstElementPtr args) = NULL
                     );
                     );
 
 
     /**
     /**
@@ -148,7 +147,7 @@ public:
      * 
      * 
      * @return true if there are unhandled queued messages
      * @return true if there are unhandled queued messages
      */
      */
-    bool hasQueuedMsgs();
+    bool hasQueuedMsgs() const;
 
 
     /**
     /**
      * Check if there is a command or config change on the command
      * Check if there is a command or config change on the command
@@ -167,7 +166,11 @@ public:
      * 100000 zones, where the whole list is passed every time a single
      * 100000 zones, where the whole list is passed every time a single
      * thing changes)
      * thing changes)
      */
      */
-    void setConfigHandler(isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config)) { config_handler_ = config_handler; };
+    void setConfigHandler(isc::data::ConstElementPtr(*config_handler)(
+                              isc::data::ConstElementPtr new_config))
+    {
+        config_handler_ = config_handler;
+    }
 
 
     /**
     /**
      * Set a command handler; the function that is passed takes an
      * Set a command handler; the function that is passed takes an
@@ -179,7 +182,12 @@ public:
      *
      *
      * This protocol is very likely to change.
      * This protocol is very likely to change.
      */
      */
-    void setCommandHandler(isc::data::ElementPtr(*command_handler)(const std::string& command, const isc::data::ElementPtr args)) { command_handler_ = command_handler; };
+    void setCommandHandler(isc::data::ConstElementPtr(*command_handler)(
+                               const std::string& command,
+                               isc::data::ConstElementPtr args))
+    {
+        command_handler_ = command_handler;
+    }
 
 
     /**
     /**
      * Gives access to the configuration values of a different module
      * Gives access to the configuration values of a different module
@@ -217,7 +225,8 @@ public:
      * \param identifier The identifier of the config value
      * \param identifier The identifier of the config value
      * \return The configuration setting at the given identifier
      * \return The configuration setting at the given identifier
      */
      */
-    ElementPtr getRemoteConfigValue(const std::string& module_name, const std::string& identifier);
+    ConstElementPtr getRemoteConfigValue(const std::string& module_name,
+                                         const std::string& identifier) const;
     
     
 private:
 private:
     ModuleSpec readModuleSpecification(const std::string& filename);
     ModuleSpec readModuleSpecification(const std::string& filename);
@@ -226,13 +235,17 @@ private:
     std::string module_name_;
     std::string module_name_;
     isc::cc::AbstractSession& session_;
     isc::cc::AbstractSession& session_;
     ModuleSpec module_specification_;
     ModuleSpec module_specification_;
-    ElementPtr handleConfigUpdate(ElementPtr new_config);
+    ConstElementPtr handleConfigUpdate(ConstElementPtr new_config);
 
 
-    isc::data::ElementPtr(*config_handler_)(isc::data::ElementPtr new_config);
+    isc::data::ConstElementPtr(*config_handler_)(
-    isc::data::ElementPtr(*command_handler_)(const std::string& command, const isc::data::ElementPtr args);
+        isc::data::ConstElementPtr new_config);
+    isc::data::ConstElementPtr(*command_handler_)(
+        const std::string& command,
+        isc::data::ConstElementPtr args);
 
 
     std::map<std::string, ConfigData> remote_module_configs_;
     std::map<std::string, ConfigData> remote_module_configs_;
-    void updateRemoteConfig(const std::string& module_name, ElementPtr new_config);
+    void updateRemoteConfig(const std::string& module_name,
+                            ConstElementPtr new_config);
 };
 };
 
 
 }
 }

+ 28 - 26
src/lib/config/config_data.cc

@@ -36,15 +36,14 @@ namespace config {
 // If it is a map, we search through the list contained in its
 // If it is a map, we search through the list contained in its
 // 'map_item_spec' value. This code assumes the data has been
 // 'map_item_spec' value. This code assumes the data has been
 // validated and conforms to the specification.
 // validated and conforms to the specification.
-static ElementPtr
+static ConstElementPtr
-find_spec_part(ElementPtr spec, const std::string& identifier)
+find_spec_part(ConstElementPtr spec, const std::string& identifier) {
-{
     //std::cout << "[XX] find_spec_part for " << identifier << std::endl;
     //std::cout << "[XX] find_spec_part for " << identifier << std::endl;
     if (!spec) {
     if (!spec) {
         isc_throw(DataNotFoundError, "Empty specification");
         isc_throw(DataNotFoundError, "Empty specification");
     }
     }
     //std::cout << "in: " << std::endl << spec << std::endl;
     //std::cout << "in: " << std::endl << spec << std::endl;
-    ElementPtr spec_part = spec;
+    ConstElementPtr spec_part = spec;
     if (identifier == "") {
     if (identifier == "") {
         isc_throw(DataNotFoundError, "Empty identifier");
         isc_throw(DataNotFoundError, "Empty identifier");
     }
     }
@@ -55,7 +54,7 @@ find_spec_part(ElementPtr spec, const std::string& identifier)
         //std::cout << "[XX] id part: " << part << std::endl;
         //std::cout << "[XX] id part: " << part << std::endl;
         if (spec_part->getType() == Element::list) {
         if (spec_part->getType() == Element::list) {
             bool found = false;
             bool found = false;
-            BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
+            BOOST_FOREACH(ConstElementPtr list_el, spec_part->listValue()) {
                 if (list_el->getType() == Element::map &&
                 if (list_el->getType() == Element::map &&
                     list_el->contains("item_name") &&
                     list_el->contains("item_name") &&
                     list_el->get("item_name")->stringValue() == part) {
                     list_el->get("item_name")->stringValue() == part) {
@@ -73,7 +72,7 @@ find_spec_part(ElementPtr spec, const std::string& identifier)
     if (id != "" && id != "/") {
     if (id != "" && id != "/") {
         if (spec_part->getType() == Element::list) {
         if (spec_part->getType() == Element::list) {
             bool found = false;
             bool found = false;
-            BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
+            BOOST_FOREACH(ConstElementPtr list_el, spec_part->listValue()) {
                 if (list_el->getType() == Element::map &&
                 if (list_el->getType() == Element::map &&
                     list_el->contains("item_name") &&
                     list_el->contains("item_name") &&
                     list_el->get("item_name")->stringValue() == id) {
                     list_el->get("item_name")->stringValue() == id) {
@@ -87,7 +86,8 @@ find_spec_part(ElementPtr spec, const std::string& identifier)
         } else if (spec_part->getType() == Element::map) {
         } else if (spec_part->getType() == Element::map) {
             if (spec_part->contains("map_item_spec")) {
             if (spec_part->contains("map_item_spec")) {
                 bool found = false;
                 bool found = false;
-                BOOST_FOREACH(ElementPtr list_el, spec_part->get("map_item_spec")->listValue()) {
+                BOOST_FOREACH(ConstElementPtr list_el,
+                              spec_part->get("map_item_spec")->listValue()) {
                     if (list_el->getType() == Element::map &&
                     if (list_el->getType() == Element::map &&
                         list_el->contains("item_name") &&
                         list_el->contains("item_name") &&
                         list_el->get("item_name")->stringValue() == id) {
                         list_el->get("item_name")->stringValue() == id) {
@@ -113,10 +113,11 @@ find_spec_part(ElementPtr spec, const std::string& identifier)
 // Result must be a ListElement
 // Result must be a ListElement
 //
 //
 static void
 static void
-spec_name_list(ElementPtr result, ElementPtr spec_part, std::string prefix, bool recurse = false)
+spec_name_list(ElementPtr result, ConstElementPtr spec_part,
+               const std::string& prefix, bool recurse = false)
 {
 {
     if (spec_part->getType() == Element::list) {
     if (spec_part->getType() == Element::list) {
-        BOOST_FOREACH(ElementPtr list_el, spec_part->listValue()) {
+        BOOST_FOREACH(ConstElementPtr list_el, spec_part->listValue()) {
             if (list_el->getType() == Element::map &&
             if (list_el->getType() == Element::map &&
                 list_el->contains("item_name")) {
                 list_el->contains("item_name")) {
                 std::string new_prefix = prefix;
                 std::string new_prefix = prefix;
@@ -136,26 +137,29 @@ spec_name_list(ElementPtr result, ElementPtr spec_part, std::string prefix, bool
                 }
                 }
             }
             }
         }
         }
-    } else if (spec_part->getType() == Element::map && spec_part->contains("map_item_spec")) {
+    } else if (spec_part->getType() == Element::map &&
-        spec_name_list(result, spec_part->get("map_item_spec"), prefix, recurse);
+               spec_part->contains("map_item_spec")) {
+        spec_name_list(result, spec_part->get("map_item_spec"), prefix,
+                       recurse);
     }
     }
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-ConfigData::getValue(const std::string& identifier) {
+ConfigData::getValue(const std::string& identifier) const {
     // 'fake' is set, but dropped by this function and
     // 'fake' is set, but dropped by this function and
     // serves no further purpose.
     // serves no further purpose.
     bool fake;
     bool fake;
     return (getValue(fake, identifier));
     return (getValue(fake, identifier));
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-ConfigData::getValue(bool& is_default, const std::string& identifier) {
+ConfigData::getValue(bool& is_default, const std::string& identifier) const {
-    ElementPtr value = _config->find(identifier);
+    ConstElementPtr value = _config->find(identifier);
     if (value) {
     if (value) {
         is_default = false;
         is_default = false;
     } else {
     } else {
-        ElementPtr spec_part = find_spec_part(_module_spec.getConfigSpec(), identifier);
+        ConstElementPtr spec_part =
+            find_spec_part(_module_spec.getConfigSpec(), identifier);
         if (spec_part->contains("item_default")) {
         if (spec_part->contains("item_default")) {
             value = spec_part->get("item_default");
             value = spec_part->get("item_default");
             is_default = true;
             is_default = true;
@@ -170,11 +174,10 @@ ConfigData::getValue(bool& is_default, const std::string& identifier) {
 /// Returns an ElementPtr pointing to a ListElement containing
 /// Returns an ElementPtr pointing to a ListElement containing
 /// StringElements with the names of the options at the given
 /// StringElements with the names of the options at the given
 /// identifier. If recurse is true, maps will be expanded as well
 /// identifier. If recurse is true, maps will be expanded as well
-ElementPtr
+ConstElementPtr
-ConfigData::getItemList(const std::string& identifier, bool recurse)
+ConfigData::getItemList(const std::string& identifier, bool recurse) const {
-{
     ElementPtr result = Element::createList();
     ElementPtr result = Element::createList();
-    ElementPtr spec_part = getModuleSpec().getConfigSpec();
+    ConstElementPtr spec_part = getModuleSpec().getConfigSpec();
     if (identifier != "" && identifier != "/") {
     if (identifier != "" && identifier != "/") {
         spec_part = find_spec_part(spec_part, identifier);
         spec_part = find_spec_part(spec_part, identifier);
     }
     }
@@ -184,12 +187,11 @@ ConfigData::getItemList(const std::string& identifier, bool recurse)
 
 
 /// Returns an ElementPtr containing a MapElement with identifier->value
 /// Returns an ElementPtr containing a MapElement with identifier->value
 /// pairs.
 /// pairs.
-ElementPtr
+ConstElementPtr
-ConfigData::getFullConfig()
+ConfigData::getFullConfig() const {
-{
     ElementPtr result = Element::createMap();
     ElementPtr result = Element::createMap();
-    ElementPtr items = getItemList("", true);
+    ConstElementPtr items = getItemList("", true);
-    BOOST_FOREACH(ElementPtr item, items->listValue()) {
+    BOOST_FOREACH(ConstElementPtr item, items->listValue()) {
         result->set(item->stringValue(), getValue(item->stringValue()));
         result->set(item->stringValue(), getValue(item->stringValue()));
     }
     }
     return (result);
     return (result);

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

@@ -55,7 +55,7 @@ public:
     /// Raises a DataNotFoundError if the identifier is bad.
     /// Raises a DataNotFoundError if the identifier is bad.
     /// \param identifier The identifier pointing to the configuration
     /// \param identifier The identifier pointing to the configuration
     ///        value that is to be returned
     ///        value that is to be returned
-    ElementPtr getValue(const std::string& identifier);
+    ConstElementPtr getValue(const std::string& identifier) const;
 
 
     /// Returns the value currently set for the given identifier
     /// Returns the value currently set for the given identifier
     /// If no value is set, the default value (as specified by the
     /// If no value is set, the default value (as specified by the
@@ -67,10 +67,11 @@ public:
     ///                   false otherwise
     ///                   false otherwise
     /// \param identifier The identifier pointing to the configuration
     /// \param identifier The identifier pointing to the configuration
     ///        value that is to be returned
     ///        value that is to be returned
-    ElementPtr getValue(bool &is_default, const std::string& identifier);
+    ConstElementPtr getValue(bool& is_default,
+                             const std::string& identifier) const;
 
 
     /// Returns the ModuleSpec associated with this ConfigData object
     /// Returns the ModuleSpec associated with this ConfigData object
-    const ModuleSpec getModuleSpec() { return (_module_spec); }
+    const ModuleSpec& getModuleSpec() const { return (_module_spec); }
 
 
     /// Set the ModuleSpec associated with this ConfigData object
     /// Set the ModuleSpec associated with this ConfigData object
     void setModuleSpec(ModuleSpec module_spec) { _module_spec = module_spec; };
     void setModuleSpec(ModuleSpec module_spec) { _module_spec = module_spec; };
@@ -96,14 +97,15 @@ public:
     ///         StringElements that specify the identifiers at the given
     ///         StringElements that specify the identifiers at the given
     ///         location (or all possible identifiers if identifier==""
     ///         location (or all possible identifiers if identifier==""
     ///         and recurse==false)
     ///         and recurse==false)
-    ElementPtr getItemList(const std::string& identifier = "", bool recurse = false);
+    ConstElementPtr getItemList(const std::string& identifier = "",
+                                bool recurse = false) const;
 
 
     /// Returns all current configuration settings (both non-default and default).
     /// Returns all current configuration settings (both non-default and default).
     /// \return An ElementPtr pointing to a MapElement containing
     /// \return An ElementPtr pointing to a MapElement containing
     ///         string->value elements, where the string is the
     ///         string->value elements, where the string is the
     ///         full identifier of the configuration option and the
     ///         full identifier of the configuration option and the
     ///         value is an ElementPtr with the value.
     ///         value is an ElementPtr with the value.
-    ElementPtr getFullConfig();
+    ConstElementPtr getFullConfig() const;
 
 
 private:
 private:
     ElementPtr _config;
     ElementPtr _config;
@@ -113,3 +115,7 @@ private:
 }
 }
 }
 }
 #endif
 #endif
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 1 - 1
src/lib/config/documentation.txt

@@ -53,7 +53,7 @@ isc::data::ElementPtr my_config_handler(isc::data::ElementPtr new_config);
 
 
 The new_config is a ElementPtr pointing to a MapElement containing data in the form as specified by the specification file. It only contains values that were changed.
 The new_config is a ElementPtr pointing to a MapElement containing data in the form as specified by the specification file. It only contains values that were changed.
 
 
-The module can walk through this set and alter it's behaviour accordingly if necessary. It can also simply check them and return success (see below) and reference the needed configuration values directly when necessary by calling get_config_value(std::string identifier).
+The module can walk through this set and alter its behaviour accordingly if necessary. It can also simply check them and return success (see below) and reference the needed configuration values directly when necessary by calling get_config_value(std::string identifier).
 
 
 The callback function must return an answer message, which is created with isc::config::createAnswer(). For successful handling of the configuration, it should return the result of createAnswer(0) (0 being the result code for success). If there is a problem, the function can return the result of createAnswer(non-zero, "string_with_error_message"). In this case, the new configuration is not stored, and the error is fed back to the configuration manager.
 The callback function must return an answer message, which is created with isc::config::createAnswer(). For successful handling of the configuration, it should return the result of createAnswer(0) (0 being the result code for success). If there is a problem, the function can return the result of createAnswer(non-zero, "string_with_error_message"). In this case, the new configuration is not stored, and the error is fed back to the configuration manager.
 
 

+ 51 - 42
src/lib/config/module_spec.cc

@@ -24,15 +24,16 @@
 
 
 // todo: add more context to thrown ModuleSpecErrors?
 // todo: add more context to thrown ModuleSpecErrors?
 
 
-namespace isc {
+using namespace isc::config;
-namespace config {
 
 
+namespace {
 //
 //
-// static functions
+// Private functions
 //
 //
 
 
-static void
+void
-check_leaf_item(const ElementPtr& spec, const std::string& name, Element::types type, bool mandatory)
+check_leaf_item(ConstElementPtr spec, const std::string& name,
+                Element::types type, bool mandatory)
 {
 {
     if (spec->contains(name)) {
     if (spec->contains(name)) {
         if (spec->get(name)->getType() == type) {
         if (spec->get(name)->getType() == type) {
@@ -48,10 +49,10 @@ check_leaf_item(const ElementPtr& spec, const std::string& name, Element::types
     }
     }
 }
 }
 
 
-static void check_config_item_list(const ElementPtr& spec);
+void check_config_item_list(ConstElementPtr spec);
 
 
-static void
+void
-check_config_item(const ElementPtr& spec) {
+check_config_item(ConstElementPtr spec) {
     check_leaf_item(spec, "item_name", Element::string, true);
     check_leaf_item(spec, "item_name", Element::string, true);
     check_leaf_item(spec, "item_type", Element::string, true);
     check_leaf_item(spec, "item_type", Element::string, true);
     check_leaf_item(spec, "item_optional", Element::boolean, true);
     check_leaf_item(spec, "item_optional", Element::boolean, true);
@@ -72,35 +73,35 @@ check_config_item(const ElementPtr& spec) {
     }
     }
 }
 }
 
 
-static void
+void
-check_config_item_list(const ElementPtr& spec) {
+check_config_item_list(ConstElementPtr spec) {
     if (spec->getType() != Element::list) {
     if (spec->getType() != Element::list) {
         throw ModuleSpecError("config_data is not a list of elements");
         throw ModuleSpecError("config_data is not a list of elements");
     }
     }
-    BOOST_FOREACH(ElementPtr item, spec->listValue()) {
+    BOOST_FOREACH(ConstElementPtr item, spec->listValue()) {
         check_config_item(item);
         check_config_item(item);
     }
     }
 }
 }
 
 
-static void
+void
-check_command(const ElementPtr& spec) {
+check_command(ConstElementPtr spec) {
     check_leaf_item(spec, "command_name", Element::string, true);
     check_leaf_item(spec, "command_name", Element::string, true);
     check_leaf_item(spec, "command_args", Element::list, true);
     check_leaf_item(spec, "command_args", Element::list, true);
     check_config_item_list(spec->get("command_args"));
     check_config_item_list(spec->get("command_args"));
 }
 }
 
 
-static void
+void
-check_command_list(const ElementPtr& spec) {
+check_command_list(ConstElementPtr spec) {
     if (spec->getType() != Element::list) {
     if (spec->getType() != Element::list) {
         throw ModuleSpecError("commands is not a list of elements");
         throw ModuleSpecError("commands is not a list of elements");
     }
     }
-    BOOST_FOREACH(ElementPtr item, spec->listValue()) {
+    BOOST_FOREACH(ConstElementPtr item, spec->listValue()) {
         check_command(item);
         check_command(item);
     }
     }
 }
 }
 
 
-static void
+void
-check_data_specification(const ElementPtr& spec) {
+check_data_specification(ConstElementPtr spec) {
     check_leaf_item(spec, "module_name", Element::string, true);
     check_leaf_item(spec, "module_name", Element::string, true);
     check_leaf_item(spec, "module_description", Element::string, false);
     check_leaf_item(spec, "module_description", Element::string, false);
     // config_data is not mandatory; module could just define
     // config_data is not mandatory; module could just define
@@ -115,21 +116,23 @@ check_data_specification(const ElementPtr& spec) {
 
 
 // checks whether the given element is a valid module specification
 // checks whether the given element is a valid module specification
 // throws a ModuleSpecError if the specification is bad
 // throws a ModuleSpecError if the specification is bad
-static void
+void
-check_module_specification(const ElementPtr& def)
+check_module_specification(ConstElementPtr def) {
-{
     try {
     try {
         check_data_specification(def);
         check_data_specification(def);
     } catch (TypeError te) {
     } catch (TypeError te) {
         throw ModuleSpecError(te.what());
         throw ModuleSpecError(te.what());
     }
     }
 }
 }
+}
 
 
+namespace isc {
+namespace config {
 //
 //
 // Public functions
 // Public functions
 //
 //
 
 
-ModuleSpec::ModuleSpec(ElementPtr module_spec_element,
+ModuleSpec::ModuleSpec(ConstElementPtr module_spec_element,
                        const bool check)
                        const bool check)
                        throw(ModuleSpecError)
                        throw(ModuleSpecError)
                        
                        
@@ -140,7 +143,7 @@ ModuleSpec::ModuleSpec(ElementPtr module_spec_element,
     }
     }
 }
 }
 
 
-const ElementPtr
+ConstElementPtr
 ModuleSpec::getCommandsSpec() const {
 ModuleSpec::getCommandsSpec() const {
     if (module_specification->contains("commands")) {
     if (module_specification->contains("commands")) {
         return (module_specification->get("commands"));
         return (module_specification->get("commands"));
@@ -149,7 +152,7 @@ ModuleSpec::getCommandsSpec() const {
     }
     }
 }
 }
 
 
-const ElementPtr
+ConstElementPtr
 ModuleSpec::getConfigSpec() const {
 ModuleSpec::getConfigSpec() const {
     if (module_specification->contains("config_data")) {
     if (module_specification->contains("config_data")) {
         return (module_specification->get("config_data"));
         return (module_specification->get("config_data"));
@@ -173,16 +176,16 @@ ModuleSpec::getModuleDescription() const {
 }
 }
 
 
 bool
 bool
-ModuleSpec::validate_config(const ElementPtr data, const bool full) {
+ModuleSpec::validate_config(ConstElementPtr data, const bool full) const {
-    ElementPtr spec = module_specification->find("config_data");
+    ConstElementPtr spec = module_specification->find("config_data");
     return (validate_spec_list(spec, data, full, ElementPtr()));
     return (validate_spec_list(spec, data, full, ElementPtr()));
 }
 }
 
 
 bool
 bool
-ModuleSpec::validate_config(const ElementPtr data, const bool full,
+ModuleSpec::validate_config(ConstElementPtr data, const bool full,
-                            ElementPtr errors)
+                            ElementPtr errors) const
 {
 {
-    ElementPtr spec = module_specification->find("config_data");
+    ConstElementPtr spec = module_specification->find("config_data");
     return (validate_spec_list(spec, data, full, errors));
     return (validate_spec_list(spec, data, full, errors));
 }
 }
 
 
@@ -199,7 +202,7 @@ moduleSpecFromFile(const std::string& file_name, const bool check)
         throw ModuleSpecError(errs.str());
         throw ModuleSpecError(errs.str());
     }
     }
 
 
-    ElementPtr module_spec_element = Element::fromJSON(file, file_name);
+    ConstElementPtr module_spec_element = Element::fromJSON(file, file_name);
     if (module_spec_element->contains("module_spec")) {
     if (module_spec_element->contains("module_spec")) {
         return (ModuleSpec(module_spec_element->get("module_spec"), check));
         return (ModuleSpec(module_spec_element->get("module_spec"), check));
     } else {
     } else {
@@ -211,7 +214,7 @@ ModuleSpec
 moduleSpecFromFile(std::ifstream& in, const bool check)
 moduleSpecFromFile(std::ifstream& in, const bool check)
                    throw(JSONError, ModuleSpecError)
                    throw(JSONError, ModuleSpecError)
 {
 {
-    ElementPtr module_spec_element = Element::fromJSON(in);
+    ConstElementPtr module_spec_element = Element::fromJSON(in);
     if (module_spec_element->contains("module_spec")) {
     if (module_spec_element->contains("module_spec")) {
         return (ModuleSpec(module_spec_element->get("module_spec"), check));
         return (ModuleSpec(module_spec_element->get("module_spec"), check));
     } else {
     } else {
@@ -220,6 +223,7 @@ moduleSpecFromFile(std::ifstream& in, const bool check)
 }
 }
 
 
 
 
+namespace {
 //
 //
 // private functions
 // private functions
 //
 //
@@ -227,9 +231,8 @@ moduleSpecFromFile(std::ifstream& in, const bool check)
 //
 //
 // helper functions for validation
 // helper functions for validation
 //
 //
-static bool
+bool
-check_type(ElementPtr spec, ElementPtr element)
+check_type(ConstElementPtr spec, ConstElementPtr element) {
-{
     std::string cur_item_type;
     std::string cur_item_type;
     cur_item_type = spec->get("item_type")->stringValue();
     cur_item_type = spec->get("item_type")->stringValue();
     if (cur_item_type == "any") {
     if (cur_item_type == "any") {
@@ -257,9 +260,12 @@ check_type(ElementPtr spec, ElementPtr element)
     }
     }
     return (false);
     return (false);
 }
 }
+}
 
 
 bool
 bool
-ModuleSpec::validate_item(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors) {
+ModuleSpec::validate_item(ConstElementPtr spec, ConstElementPtr data,
+                          const bool full, ElementPtr errors) const
+{
     if (!check_type(spec, data)) {
     if (!check_type(spec, data)) {
         // we should do some proper error feedback here
         // we should do some proper error feedback here
         // std::cout << "type mismatch; not " << spec->get("item_type") << ": " << data << std::endl;
         // std::cout << "type mismatch; not " << spec->get("item_type") << ": " << data << std::endl;
@@ -270,8 +276,8 @@ ModuleSpec::validate_item(const ElementPtr spec, const ElementPtr data, const bo
         return (false);
         return (false);
     }
     }
     if (data->getType() == Element::list) {
     if (data->getType() == Element::list) {
-        ElementPtr list_spec = spec->get("list_item_spec");
+        ConstElementPtr list_spec = spec->get("list_item_spec");
-        BOOST_FOREACH(ElementPtr list_el, data->listValue()) {
+        BOOST_FOREACH(ConstElementPtr list_el, data->listValue()) {
             if (!check_type(list_spec, list_el)) {
             if (!check_type(list_spec, list_el)) {
                 if (errors) {
                 if (errors) {
                     errors->add(Element::create("Type mismatch"));
                     errors->add(Element::create("Type mismatch"));
@@ -295,10 +301,12 @@ ModuleSpec::validate_item(const ElementPtr spec, const ElementPtr data, const bo
 
 
 // spec is a map with item_name etc, data is a map
 // spec is a map with item_name etc, data is a map
 bool
 bool
-ModuleSpec::validate_spec(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors) {
+ModuleSpec::validate_spec(ConstElementPtr spec, ConstElementPtr data,
+                          const bool full, ElementPtr errors) const
+{
     std::string item_name = spec->get("item_name")->stringValue();
     std::string item_name = spec->get("item_name")->stringValue();
     bool optional = spec->get("item_optional")->boolValue();
     bool optional = spec->get("item_optional")->boolValue();
-    ElementPtr data_el;
+    ConstElementPtr data_el;
     data_el = data->get(item_name);
     data_el = data->get(item_name);
     
     
     if (data_el) {
     if (data_el) {
@@ -318,10 +326,11 @@ ModuleSpec::validate_spec(const ElementPtr spec, const ElementPtr data, const bo
 
 
 // spec is a list of maps, data is a map
 // spec is a list of maps, data is a map
 bool
 bool
-ModuleSpec::validate_spec_list(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors) {
+ModuleSpec::validate_spec_list(ConstElementPtr spec, ConstElementPtr data,
-    ElementPtr cur_data_el;
+                               const bool full, ElementPtr errors) const
+{
     std::string cur_item_name;
     std::string cur_item_name;
-    BOOST_FOREACH(ElementPtr cur_spec_el, spec->listValue()) {
+    BOOST_FOREACH(ConstElementPtr cur_spec_el, spec->listValue()) {
         if (!validate_spec(cur_spec_el, data, full, errors)) {
         if (!validate_spec(cur_spec_el, data, full, errors)) {
             return (false);
             return (false);
         }
         }

+ 22 - 13
src/lib/config/module_spec.h

@@ -51,28 +51,28 @@ namespace isc { namespace config {
     ///
     ///
     class ModuleSpec {
     class ModuleSpec {
     public:
     public:
-        explicit ModuleSpec() {};
+        ModuleSpec() {};
         /// Create a \c ModuleSpec instance with the given data as
         /// Create a \c ModuleSpec instance with the given data as
         /// the specification
         /// the specification
         /// \param e The Element containing the data specification
         /// \param e The Element containing the data specification
-        explicit ModuleSpec(ElementPtr e, const bool check = true)
+        explicit ModuleSpec(ConstElementPtr e, const bool check = true)
-                            throw(ModuleSpecError);
+            throw(ModuleSpecError);
 
 
         /// Returns the commands part of the specification as an
         /// Returns the commands part of the specification as an
         /// ElementPtr, returns an empty ElementPtr if there is none
         /// ElementPtr, returns an empty ElementPtr if there is none
         /// \return ElementPtr Shared pointer to the commands
         /// \return ElementPtr Shared pointer to the commands
         ///                    part of the specification
         ///                    part of the specification
-        const ElementPtr getCommandsSpec() const;
+        ConstElementPtr getCommandsSpec() const;
 
 
         /// Returns the configuration part of the specification as an
         /// Returns the configuration part of the specification as an
         /// ElementPtr
         /// ElementPtr
         /// \return ElementPtr Shared pointer to the configuration
         /// \return ElementPtr Shared pointer to the configuration
         ///                    part of the specification
         ///                    part of the specification
-        const ElementPtr getConfigSpec() const;
+        ConstElementPtr getConfigSpec() const;
 
 
         /// Returns the full module specification as an ElementPtr
         /// Returns the full module specification as an ElementPtr
         /// \return ElementPtr Shared pointer to the specification
         /// \return ElementPtr Shared pointer to the specification
-        const ElementPtr getFullSpec() const { return (module_specification); }
+        ConstElementPtr getFullSpec() const { return module_specification; }
 
 
         /// Returns the module name as specified by the specification
         /// Returns the module name as specified by the specification
         const std::string getModuleName() const;
         const std::string getModuleName() const;
@@ -87,17 +87,22 @@ namespace isc { namespace config {
         /// \param data The base \c Element of the data to check
         /// \param data The base \c Element of the data to check
         /// \return true if the data conforms to the specification,
         /// \return true if the data conforms to the specification,
         /// false otherwise.
         /// false otherwise.
-        bool validate_config(const ElementPtr data, const bool full = false);
+        bool validate_config(ConstElementPtr data,
+                             const bool full = false) const;
 
 
         /// errors must be of type ListElement
         /// errors must be of type ListElement
-        bool validate_config(const ElementPtr data, const bool full, ElementPtr errors);
+        bool validate_config(ConstElementPtr data, const bool full,
+                             ElementPtr errors) const;
 
 
     private:
     private:
-        bool validate_item(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors);
+        bool validate_item(ConstElementPtr spec, ConstElementPtr data,
-        bool validate_spec(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors);
+                           const bool full, ElementPtr errors) const;
-        bool validate_spec_list(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors);
+        bool validate_spec(ConstElementPtr spec, ConstElementPtr data,
-
+                           const bool full, ElementPtr errors) const;
-        ElementPtr module_specification;
+        bool validate_spec_list(ConstElementPtr spec, ConstElementPtr data,
+                                const bool full, ElementPtr errors) const;
+
+        ConstElementPtr module_specification;
     };
     };
 
 
     /// Creates a \c ModuleSpec instance from the contents
     /// Creates a \c ModuleSpec instance from the contents
@@ -126,3 +131,7 @@ namespace isc { namespace config {
 } }
 } }
 
 
 #endif // _DATA_DEF_H
 #endif // _DATA_DEF_H
+
+// Local Variables: 
+// mode: c++
+// End: 

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

@@ -21,15 +21,13 @@ TESTS += run_unittests
 run_unittests_SOURCES = ccsession_unittests.cc module_spec_unittests.cc config_data_unittests.cc run_unittests.cc
 run_unittests_SOURCES = ccsession_unittests.cc module_spec_unittests.cc config_data_unittests.cc run_unittests.cc
 
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
-run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+# TODO: remove PTHREAD_LDFLAGS (and from configure too)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) $(PTHREAD_LDFLAGS)
 run_unittests_LDADD =  $(GTEST_LDADD)
 run_unittests_LDADD =  $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 run_unittests_LDADD += libfake_session.la
 run_unittests_LDADD += libfake_session.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
-# link *only* to data.o from lib/cc (more importantly, don't link in
-# the session class provided there, since we use our own fake_session
-# here)
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/data.o
 
 
 endif
 endif
 
 

File diff suppressed because it is too large
+ 16 - 16
src/lib/config/tests/ccsession_unittests.cc


+ 25 - 46
src/lib/config/tests/fake_session.cc

@@ -40,12 +40,12 @@ using namespace isc::data;
 
 
 // ok i want these in cc/data 
 // ok i want these in cc/data 
 bool
 bool
-listContains(ElementPtr list, ElementPtr el) {
+listContains(ConstElementPtr list, ConstElementPtr el) {
     if (!list) {
     if (!list) {
         return (false);
         return (false);
     }
     }
-    BOOST_FOREACH(ElementPtr l_el, list->listValue()) {
+    BOOST_FOREACH(ConstElementPtr l_el, list->listValue()) {
-        if (l_el == el) {
+        if (*l_el == *el) {
             return (true);
             return (true);
         }
         }
     }
     }
@@ -53,10 +53,10 @@ listContains(ElementPtr list, ElementPtr el) {
 }
 }
 
 
 void
 void
-listRemove(ElementPtr list, ElementPtr el) {
+listRemove(ElementPtr list, ConstElementPtr el) {
     int i = -1;
     int i = -1;
-    BOOST_FOREACH(ElementPtr s_el, list->listValue()) {
+    BOOST_FOREACH(ConstElementPtr s_el, list->listValue()) {
-        if (el == s_el) {
+        if (*el == *s_el) {
             i = 0;
             i = 0;
         }
         }
         i++;
         i++;
@@ -82,11 +82,6 @@ FakeSession::FakeSession(isc::data::ElementPtr initial_messages,
 FakeSession::~FakeSession() {
 FakeSession::~FakeSession() {
 }
 }
 
 
-bool
-FakeSession::connect() {
-    return (true);
-}
-
 void
 void
 FakeSession::disconnect() {
 FakeSession::disconnect() {
 }
 }
@@ -99,25 +94,8 @@ void
 FakeSession::establish(const char* socket_file) {
 FakeSession::establish(const char* socket_file) {
 }
 }
 
 
-//
-// Convert to wire format and send this on the TCP stream with its length prefix
-//
-void
-FakeSession::sendmsg(ElementPtr& msg) {
-    //cout << "[XX] client sends message: " << msg << endl;
-    // err, to where?
-    addMessage(msg, "*", "*");
-}
-
-void
-FakeSession::sendmsg(ElementPtr& env, ElementPtr& msg) {
-    //cout << "[XX] client sends message: " << msg << endl;
-    //cout << "[XX] env: " << env << endl;
-    addMessage(msg, env->get("group")->stringValue(), env->get("to")->stringValue());
-}
-
 bool
 bool
-FakeSession::recvmsg(ElementPtr& msg, bool nonblock UNUSED_PARAM,
+FakeSession::recvmsg(ConstElementPtr& msg, bool nonblock UNUSED_PARAM,
                      int seq UNUSED_PARAM)
                      int seq UNUSED_PARAM)
 {
 {
     //cout << "[XX] client asks for message " << endl;
     //cout << "[XX] client asks for message " << endl;
@@ -133,7 +111,7 @@ FakeSession::recvmsg(ElementPtr& msg, bool nonblock UNUSED_PARAM,
 }
 }
 
 
 bool
 bool
-FakeSession::recvmsg(ElementPtr& env, ElementPtr& msg,
+FakeSession::recvmsg(ConstElementPtr& env, ConstElementPtr& msg,
                      bool nonblock UNUSED_PARAM,
                      bool nonblock UNUSED_PARAM,
                      int seq UNUSED_PARAM)
                      int seq UNUSED_PARAM)
 {
 {
@@ -147,12 +125,13 @@ FakeSession::recvmsg(ElementPtr& env, ElementPtr& msg,
         messages_->remove(0);
         messages_->remove(0);
         return (true);
         return (true);
     } else if (msg_queue_) {
     } else if (msg_queue_) {
-        BOOST_FOREACH(ElementPtr c_m, msg_queue_->listValue()) {
+        BOOST_FOREACH(ConstElementPtr c_m, msg_queue_->listValue()) {
-            ElementPtr to_remove = ElementPtr();
+            ConstElementPtr to_remove = ElementPtr();
             if (haveSubscription(c_m->get(0), c_m->get(1))) {
             if (haveSubscription(c_m->get(0), c_m->get(1))) {
-                env = Element::createMap();
+                ElementPtr new_env = Element::createMap();
-                env->set("group", c_m->get(0));
+                new_env->set("group", c_m->get(0));
-                env->set("to", c_m->get(1));
+                new_env->set("to", c_m->get(1));
+                env = new_env;
                 msg = c_m->get(2);
                 msg = c_m->get(2);
                 to_remove = c_m;
                 to_remove = c_m;
             }
             }
@@ -192,7 +171,7 @@ FakeSession::unsubscribe(std::string group, std::string instance) {
 }
 }
 
 
 int
 int
-FakeSession::group_sendmsg(ElementPtr msg, std::string group,
+FakeSession::group_sendmsg(ConstElementPtr msg, std::string group,
                            std::string to, std::string instance UNUSED_PARAM)
                            std::string to, std::string instance UNUSED_PARAM)
 {
 {
     //cout << "[XX] client sends message: " << msg << endl;
     //cout << "[XX] client sends message: " << msg << endl;
@@ -202,28 +181,29 @@ FakeSession::group_sendmsg(ElementPtr msg, std::string group,
 }
 }
 
 
 bool
 bool
-FakeSession::group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+FakeSession::group_recvmsg(ConstElementPtr& envelope, ConstElementPtr& msg,
                            bool nonblock, int seq)
                            bool nonblock, int seq)
 {
 {
     return (recvmsg(envelope, msg, nonblock, seq));
     return (recvmsg(envelope, msg, nonblock, seq));
 }
 }
 
 
 int
 int
-FakeSession::reply(ElementPtr& envelope, ElementPtr& newmsg) {
+FakeSession::reply(ConstElementPtr envelope, ConstElementPtr newmsg) {
     //cout << "[XX] client sends reply: " << newmsg << endl;
     //cout << "[XX] client sends reply: " << newmsg << endl;
     //cout << "[XX] env: " << envelope << endl;
     //cout << "[XX] env: " << envelope << endl;
-    addMessage(newmsg, envelope->get("group")->stringValue(), envelope->get("to")->stringValue());
+    addMessage(newmsg, envelope->get("group")->stringValue(),
+               envelope->get("to")->stringValue());
     return (1);
     return (1);
 }
 }
 
 
 bool
 bool
-FakeSession::hasQueuedMsgs() {
+FakeSession::hasQueuedMsgs() const {
     return (false);
     return (false);
 }
 }
 
 
-ElementPtr
+ConstElementPtr
-FakeSession::getFirstMessage(std::string& group, std::string& to) {
+FakeSession::getFirstMessage(std::string& group, std::string& to) const {
-    ElementPtr el;
+    ConstElementPtr el;
     if (msg_queue_ && msg_queue_->size() > 0) {
     if (msg_queue_ && msg_queue_->size() > 0) {
         el = msg_queue_->get(0);
         el = msg_queue_->get(0);
         msg_queue_->remove(0);
         msg_queue_->remove(0);
@@ -238,7 +218,7 @@ FakeSession::getFirstMessage(std::string& group, std::string& to) {
 }
 }
 
 
 void
 void
-FakeSession::addMessage(ElementPtr msg, const std::string& group,
+FakeSession::addMessage(ConstElementPtr msg, const std::string& group,
                         const std::string& to)
                         const std::string& to)
 {
 {
     ElementPtr m_el = Element::createList();
     ElementPtr m_el = Element::createList();
@@ -270,8 +250,7 @@ FakeSession::haveSubscription(const std::string& group,
 }
 }
 
 
 bool
 bool
-FakeSession::haveSubscription(const ElementPtr group,
+FakeSession::haveSubscription(ConstElementPtr group, ConstElementPtr instance)
-                              const ElementPtr instance)
 {
 {
     return (haveSubscription(group->stringValue(), instance->stringValue()));
     return (haveSubscription(group->stringValue(), instance->stringValue()));
 }
 }

+ 19 - 21
src/lib/config/tests/fake_session.h

@@ -47,40 +47,32 @@ public:
     virtual void startRead(boost::function<void()> read_callback);
     virtual void startRead(boost::function<void()> read_callback);
 
 
     virtual void establish(const char* socket_file = NULL);
     virtual void establish(const char* socket_file = NULL);
-    bool connect();
     virtual void disconnect();
     virtual void disconnect();
-    void sendmsg(isc::data::ElementPtr& msg);
-    void sendmsg(isc::data::ElementPtr& env,
-                 isc::data::ElementPtr& msg);
-    bool recvmsg(isc::data::ElementPtr& msg,
-                 bool nonblock = true, int seq = -1);
-    bool recvmsg(isc::data::ElementPtr& env,
-                 isc::data::ElementPtr& msg,
-                 bool nonblock = true, int seq = -1);
     virtual void subscribe(std::string group,
     virtual void subscribe(std::string group,
                            std::string instance = "*");
                            std::string instance = "*");
     virtual void unsubscribe(std::string group,
     virtual void unsubscribe(std::string group,
                              std::string instance = "*");
                              std::string instance = "*");
-    virtual int group_sendmsg(isc::data::ElementPtr msg,
+    virtual int group_sendmsg(isc::data::ConstElementPtr msg,
                               std::string group,
                               std::string group,
                               std::string instance = "*",
                               std::string instance = "*",
                               std::string to = "*");
                               std::string to = "*");
-    virtual bool group_recvmsg(isc::data::ElementPtr& envelope,
+    virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
-                               isc::data::ElementPtr& msg,
+                               isc::data::ConstElementPtr& msg,
                                bool nonblock = true,
                                bool nonblock = true,
                                int seq = -1);
                                int seq = -1);
-    virtual int reply(isc::data::ElementPtr& envelope,
+    virtual int reply(isc::data::ConstElementPtr envelope,
-                      isc::data::ElementPtr& newmsg);
+                      isc::data::ConstElementPtr newmsg);
-    virtual bool hasQueuedMsgs();
+    virtual bool hasQueuedMsgs() const;
-    virtual void setTimeout(size_t milliseconds) {};
+    virtual void setTimeout(size_t milliseconds) {}
-    virtual size_t getTimeout() const { return 0; };
+    virtual size_t getTimeout() const { return (0); }
-    isc::data::ElementPtr getFirstMessage(std::string& group, std::string& to);
+    isc::data::ConstElementPtr getFirstMessage(std::string& group,
-    void addMessage(isc::data::ElementPtr, const std::string& group,
+                                               std::string& to) const;
+    void addMessage(isc::data::ConstElementPtr, const std::string& group,
                     const std::string& to);
                     const std::string& to);
     bool haveSubscription(const std::string& group,
     bool haveSubscription(const std::string& group,
                           const std::string& instance);
                           const std::string& instance);
-    bool haveSubscription(const isc::data::ElementPtr group,
+    bool haveSubscription(const isc::data::ConstElementPtr group,
-                          const isc::data::ElementPtr instance);
+                          const isc::data::ConstElementPtr instance);
 
 
     // For the convenience of tests, we share these internal members
     // For the convenience of tests, we share these internal members
     // with the tester.  The test code may insert update and check,
     // with the tester.  The test code may insert update and check,
@@ -90,6 +82,12 @@ public:
     isc::data::ElementPtr getMsgQueue() { return (msg_queue_); }
     isc::data::ElementPtr getMsgQueue() { return (msg_queue_); }
 
 
 private:
 private:
+    bool recvmsg(isc::data::ConstElementPtr& msg,
+                 bool nonblock = true, int seq = -1);
+    bool recvmsg(isc::data::ConstElementPtr& env,
+                 isc::data::ConstElementPtr& msg,
+                 bool nonblock = true, int seq = -1);
+
     const isc::data::ElementPtr messages_;
     const isc::data::ElementPtr messages_;
     isc::data::ElementPtr subscriptions_;
     isc::data::ElementPtr subscriptions_;
     isc::data::ElementPtr msg_queue_;
     isc::data::ElementPtr msg_queue_;

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

@@ -134,23 +134,24 @@ TEST(ModuleSpec, SpecfileCommands)
 }
 }
 
 
 bool
 bool
-data_test(ModuleSpec dd, const std::string& data_file_name) {
+data_test(const ModuleSpec& dd, const std::string& data_file_name) {
     std::ifstream data_file;
     std::ifstream data_file;
 
 
     data_file.open(specfile(data_file_name).c_str());
     data_file.open(specfile(data_file_name).c_str());
-    ElementPtr data = Element::fromJSON(data_file, data_file_name);
+    ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
     data_file.close();
     data_file.close();
 
 
     return (dd.validate_config(data));
     return (dd.validate_config(data));
 }
 }
 
 
 bool
 bool
-data_test_with_errors(ModuleSpec dd, const std::string& data_file_name, ElementPtr errors)
+data_test_with_errors(const ModuleSpec& dd, const std::string& data_file_name,
+                      ElementPtr errors)
 {
 {
     std::ifstream data_file;
     std::ifstream data_file;
 
 
     data_file.open(specfile(data_file_name).c_str());
     data_file.open(specfile(data_file_name).c_str());
-    ElementPtr data = Element::fromJSON(data_file, data_file_name);
+    ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
     data_file.close();
     data_file.close();
 
 
     return (dd.validate_config(data, true, errors));
     return (dd.validate_config(data, true, errors));

+ 6 - 1
src/lib/datasrc/data_source.cc

@@ -206,6 +206,11 @@ checkCache(QueryTask& task, RRsetList& target) {
         if (!hit || !rrset || (flags & DataSrc::CNAME_FOUND) != 0) {
         if (!hit || !rrset || (flags & DataSrc::CNAME_FOUND) != 0) {
             hit = cache.retrieve(task.qname, task.qclass, RRType::CNAME(),
             hit = cache.retrieve(task.qname, task.qclass, RRType::CNAME(),
                                  rrset, flags);
                                  rrset, flags);
+            if (!rrset) {
+                // If we don't have a positive cache, forget it; otherwise the
+                // intermediate result may confuse the subsequent processing.
+                hit = false;
+            }
         }
         }
 
 
         if (hit) {
         if (hit) {
@@ -1245,7 +1250,7 @@ Nsec3Param::getHash(const Name& name) const {
 // installed files we define the methods here.
 // installed files we define the methods here.
 //
 //
 DataSrc::Result
 DataSrc::Result
-DataSrc::init(const isc::data::ElementPtr config UNUSED_PARAM) {
+DataSrc::init(isc::data::ConstElementPtr config UNUSED_PARAM) {
     return (NOT_IMPLEMENTED);
     return (NOT_IMPLEMENTED);
 }
 }
 
 

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

@@ -115,7 +115,7 @@ public:
     // Optional 'low-level' methods.  These will have stub implementations
     // Optional 'low-level' methods.  These will have stub implementations
     // in the general DataSrc class but MAY be overwritten by subclasses
     // in the general DataSrc class but MAY be overwritten by subclasses
     virtual Result init() = 0;
     virtual Result init() = 0;
-    virtual Result init(const isc::data::ElementPtr config) = 0;
+    virtual Result init(isc::data::ConstElementPtr config) = 0;
     virtual Result close() = 0;
     virtual Result close() = 0;
 
 
     // Mandatory 'low-level' methods: These will NOT be implemented by
     // Mandatory 'low-level' methods: These will NOT be implemented by
@@ -187,7 +187,7 @@ public:
     void setClass(const isc::dns::RRClass& c) { rrclass = c; }
     void setClass(const isc::dns::RRClass& c) { rrclass = c; }
 
 
     Result init() { return (NOT_IMPLEMENTED); }
     Result init() { return (NOT_IMPLEMENTED); }
-    Result init(const isc::data::ElementPtr config);
+    Result init(isc::data::ConstElementPtr config);
     Result close() { return (NOT_IMPLEMENTED); }
     Result close() { return (NOT_IMPLEMENTED); }
 
 
     virtual Result findRRset(const isc::dns::Name& qname,
     virtual Result findRRset(const isc::dns::Name& qname,

+ 1 - 1
src/lib/datasrc/sqlite3_datasrc.cc

@@ -558,7 +558,7 @@ Sqlite3DataSrc::~Sqlite3DataSrc() {
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-Sqlite3DataSrc::init(const isc::data::ElementPtr config) {
+Sqlite3DataSrc::init(isc::data::ConstElementPtr config) {
     if (config && config->contains("database_file")) {
     if (config && config->contains("database_file")) {
         open(config->get("database_file")->stringValue());
         open(config->get("database_file")->stringValue());
     } else {
     } else {

+ 1 - 1
src/lib/datasrc/sqlite3_datasrc.h

@@ -95,7 +95,7 @@ public:
                              isc::dns::RRsetList& target) const;
                              isc::dns::RRsetList& target) const;
 
 
     Result init() { return (init(isc::data::ElementPtr())); }
     Result init() { return (init(isc::data::ElementPtr())); }
-    Result init(const isc::data::ElementPtr config);
+    Result init(const isc::data::ConstElementPtr config);
     Result close();
     Result close();
 
 
 private:
 private:

+ 1 - 1
src/lib/datasrc/static_datasrc.cc

@@ -260,7 +260,7 @@ StaticDataSrc::init() {
 // Static data source is "configuration less", so the \c config parameter
 // Static data source is "configuration less", so the \c config parameter
 // is intentionally ignored.
 // is intentionally ignored.
 DataSrc::Result
 DataSrc::Result
-StaticDataSrc::init(const isc::data::ElementPtr config UNUSED_PARAM) {
+StaticDataSrc::init(isc::data::ConstElementPtr config UNUSED_PARAM) {
     return (init());
     return (init());
 }
 }
 
 

+ 1 - 1
src/lib/datasrc/static_datasrc.h

@@ -81,7 +81,7 @@ public:
                             isc::dns::RRsetList& target) const;
                             isc::dns::RRsetList& target) const;
 
 
     Result init();
     Result init();
-    Result init(const isc::data::ElementPtr config);
+    Result init(isc::data::ConstElementPtr config);
     Result close();
     Result close();
 private:
 private:
     StaticDataSrcImpl* impl_;
     StaticDataSrcImpl* impl_;

+ 19 - 1
src/lib/datasrc/tests/datasrc_unittest.cc

@@ -49,7 +49,7 @@ using namespace isc::datasrc;
 using namespace isc::data;
 using namespace isc::data;
 
 
 namespace {
 namespace {
-const ElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
     "{ \"database_file\": \"" TEST_DATA_DIR "/example.org.sqlite3\"}");
     "{ \"database_file\": \"" TEST_DATA_DIR "/example.org.sqlite3\"}");
 
 
 class DataSrcTest : public ::testing::Test {
 class DataSrcTest : public ::testing::Test {
@@ -915,6 +915,24 @@ TEST_F(DataSrcTest, RootDSQuery) {
     headerCheck(msg, Rcode::REFUSED(), true, false, true, 0, 0, 0);
     headerCheck(msg, Rcode::REFUSED(), true, false, true, 0, 0, 0);
 }
 }
 
 
+TEST_F(DataSrcTest, DSQueryFromCache) {
+    // explicitly enable hot spot cache
+    cache.setEnabled(true);
+
+    // The first query will create a negative cache for example.org/CNAME
+    createAndProcessQuery(Name("example.org"), RRClass::IN(), RRType::SOA());
+
+    // the cached CNAME shouldn't confuse subsequent query.
+    // there may be several different possible cases that could trigger a bug,
+    // but DS query is the only known example.
+    msg.clear(Message::PARSE);
+    createAndProcessQuery(Name("example.org"), RRClass::IN(), RRType::DS());
+
+    // returning refused is probably a bad behavior, but it's a different
+    // issue -- see Trac Ticket #306.
+    headerCheck(msg, Rcode::REFUSED(), true, false, true, 0, 0, 0);
+}
+
 // Non-existent name in the "static" data source.  The purpose of this test
 // Non-existent name in the "static" data source.  The purpose of this test
 // is to check a corner case behavior when atypical RRClass (CH in this case)
 // is to check a corner case behavior when atypical RRClass (CH in this case)
 // is specified.
 // is specified.

+ 6 - 6
src/lib/datasrc/tests/sqlite3_unittest.cc

@@ -43,22 +43,22 @@ using namespace isc::datasrc;
 using namespace isc::data;
 using namespace isc::data;
 
 
 namespace {
 namespace {
-ElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
     "{ \"database_file\": \"" TEST_DATA_DIR "/test.sqlite3\"}");
     "{ \"database_file\": \"" TEST_DATA_DIR "/test.sqlite3\"}");
-ElementPtr SQLITE_DBFILE_EXAMPLE2 = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_EXAMPLE2 = Element::fromJSON(
     "{ \"database_file\": \"" TEST_DATA_DIR "/example2.com.sqlite3\"}");
     "{ \"database_file\": \"" TEST_DATA_DIR "/example2.com.sqlite3\"}");
-ElementPtr SQLITE_DBFILE_EXAMPLE_ROOT = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_EXAMPLE_ROOT = Element::fromJSON(
     "{ \"database_file\": \"" TEST_DATA_DIR "/test-root.sqlite3\"}");
     "{ \"database_file\": \"" TEST_DATA_DIR "/test-root.sqlite3\"}");
-ElementPtr SQLITE_DBFILE_BROKENDB = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_BROKENDB = Element::fromJSON(
     "{ \"database_file\": \"" TEST_DATA_DIR "/brokendb.sqlite3\"}");
     "{ \"database_file\": \"" TEST_DATA_DIR "/brokendb.sqlite3\"}");
-ElementPtr SQLITE_DBFILE_MEMORY = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_MEMORY = Element::fromJSON(
     "{ \"database_file\": \":memory:\"}");
     "{ \"database_file\": \":memory:\"}");
 
 
 // The following file must be non existent and must be non"creatable";
 // The following file must be non existent and must be non"creatable";
 // the sqlite3 library will try to create a new DB file if it doesn't exist,
 // the sqlite3 library will try to create a new DB file if it doesn't exist,
 // so to test a failure case the create operation should also fail.
 // so to test a failure case the create operation should also fail.
 // The "nodir", a non existent directory, is inserted for this purpose.
 // The "nodir", a non existent directory, is inserted for this purpose.
-ElementPtr SQLITE_DBFILE_NOTEXIST = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_NOTEXIST = Element::fromJSON(
     "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}");
     "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}");
 
 
 const string sigdata_common(" 20100322084538 20100220084538 "
 const string sigdata_common(" 20100322084538 20100220084538 "

+ 1 - 2
src/lib/datasrc/tests/test_datasrc.cc

@@ -307,8 +307,7 @@ vector<Zone> zones;
 }
 }
 
 
 DataSrc::Result
 DataSrc::Result
-TestDataSrc::init(const isc::data::ElementPtr config UNUSED_PARAM)
+TestDataSrc::init(isc::data::ConstElementPtr config UNUSED_PARAM) {
-{
     return (init());
     return (init());
 }
 }
 
 

+ 1 - 1
src/lib/datasrc/tests/test_datasrc.h

@@ -85,7 +85,7 @@ public:
                              isc::dns::RRsetList& target) const;
                              isc::dns::RRsetList& target) const;
 
 
     Result init();
     Result init();
-    Result init(const isc::data::ElementPtr config);
+    Result init(isc::data::ConstElementPtr config);
     Result close() { return (SUCCESS); }
     Result close() { return (SUCCESS); }
 
 
 private:
 private:

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

@@ -89,8 +89,8 @@ rrparamregistry.cc: rrparamregistry-placeholder.cc
 rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 	./gen-rdatacode.py
 	./gen-rdatacode.py
 
 
-libdns++_includedir = $(includedir)/dns
+libdns___includedir = $(includedir)/dns
-libdns++_include_HEADERS = \
+libdns___include_HEADERS = \
 	buffer.h \
 	buffer.h \
 	dnssectime.h \
 	dnssectime.h \
 	exceptions.h \
 	exceptions.h \

+ 0 - 71
src/lib/dns/message_test.py

@@ -1,71 +0,0 @@
-from bind10_dns import *
-from struct import *
-
-id = ["10","35"]
-flags = ["85", "00"]
-sections = ["00","01","00","02","00","00","00","00"]
-query_raw_name = ["04","74","65","73","74","07","65","78","61","6d","70","6c","65","03","63","6f","6d","00"]
-query_type_class = ["00","01","00","01"]
-answer_compress = ["c0","0c"]
-answer1_ttl_type_class_rdlen_rdata = ["00","01","00","01","00","00","0e","10","00","04","c0","00","02","01"]
-answer2_ttl_type_class_rdlen_rdata = ["00","01","00","01","00","00","1c","20","00","04","c0","00","02","02"]
-
-bytes = pack("B" * len(query_raw_name), *[int(i,16) for i in query_raw_name])
-query_name = name(input_buffer(bytes))
-print("query name is ", query_name.to_text())
-
-message_raw_data = id + flags + sections + query_raw_name + query_type_class + answer_compress + answer1_ttl_type_class_rdlen_rdata + answer_compress + \
-        answer2_ttl_type_class_rdlen_rdata
-
-m = message(message_mode.PARSE)
-message_bytes = pack("B" * len(message_raw_data), *[int(i,16) for i in message_raw_data])
-m.from_wire(input_buffer(message_bytes))
-if m.get_qid() == int("1035", 16):
-    print("id is correct")
-
-if m.get_opcode() == op_code.QUERY():
-    print("opcode is correct")
-
-if m.get_rcode() == rcode.NOERROR():
-    print("rcode is correct")
-
-if m.get_header_flag(message_flag.QR()):
-    print("qr is correct")
-
-if m.get_header_flag(message_flag.RD()):
-    print("rd is correct")
-
-if m.get_header_flag(message_flag.AA()):
-    print("aa is correct")
-
-if m.get_rr_count(section.QUESTION()) == 1:
-    print("qustion rr count is correct")
-
-if m.get_rr_count(section.ANSWER()) == 2:
-    print("answer rr count is ok")
-
-if m.get_rr_count(section.AUTHORITY()) == 0 and m.get_rr_count(section.ADDITIONAL()) == 0:
-    print("authority and additional rr count is ok")
-
-question_iter = question_iter(m)
-question = question_iter.get_question()
-print("question name is ", question.get_name().to_text())
-if question.get_type() == rr_type.A():
-    print("question rr type is A")
-if question.get_class() == rr_class.IN():
-    print("question rr class is IN")
-
-answer_rrset_iter = section_iter(m, section.ANSWER())
-answer = answer_rrset_iter.get_rrset()
-print("answer part name is ", answer.get_name().to_text())
-if answer.get_type() == rr_type.A() and answer.get_class() == rr_class.IN():
-    print("answer part is A record and class IN")
-
-rdata_iter = answer.get_rdata_iterator()
-rdata_iter.first()
-print("first part of rdata is ", rdata_iter.get_current().to_text())
-rdata_iter.next()
-print("second part of rdata is", rdata_iter.get_current().to_text())
-rdata_iter.next()
-if rdata_iter.is_last():
-    print("answer part has two rr")

+ 1 - 1
src/lib/dns/messagerenderer.h

@@ -109,7 +109,7 @@ public:
     /// The destructor does nothing on the given \c buffer on construction;
     /// The destructor does nothing on the given \c buffer on construction;
     /// in fact, it is expected that the user will use the resulting buffer
     /// in fact, it is expected that the user will use the resulting buffer
     /// for some post rendering purposes (e.g., send the data to the network).
     /// for some post rendering purposes (e.g., send the data to the network).
-    /// It's user's responsibility to do any necessary cleanup for the
+    /// It's the user's responsibility to do any necessary cleanup for the
     /// \c buffer.
     /// \c buffer.
     ~MessageRenderer();
     ~MessageRenderer();
     //@}
     //@}

+ 7 - 8
src/lib/dns/name.cc

@@ -601,17 +601,17 @@ Name::isWildcard() const {
 
 
 Name
 Name
 Name::concatenate(const Name& suffix) const {
 Name::concatenate(const Name& suffix) const {
-    assert(this->length_ > 0 && suffix.length_ > 0);
+    assert(length_ > 0 && suffix.length_ > 0);
-    assert(this->labelcount_ > 0 && suffix.labelcount_ > 0);
+    assert(labelcount_ > 0 && suffix.labelcount_ > 0);
 
 
-    unsigned int length = this->length_ + suffix.length_ - 1;
+    unsigned int length = length_ + suffix.length_ - 1;
     if (length > Name::MAX_WIRE) {
     if (length > Name::MAX_WIRE) {
         isc_throw(TooLongName, "names are too long to concatenate");
         isc_throw(TooLongName, "names are too long to concatenate");
     }
     }
 
 
     Name retname;
     Name retname;
     retname.ndata_.reserve(length);
     retname.ndata_.reserve(length);
-    retname.ndata_.assign(this->ndata_, 0, this->length_ - 1);
+    retname.ndata_.assign(ndata_, 0, length_ - 1);
     retname.ndata_.insert(retname.ndata_.end(),
     retname.ndata_.insert(retname.ndata_.end(),
                           suffix.ndata_.begin(), suffix.ndata_.end());
                           suffix.ndata_.begin(), suffix.ndata_.end());
     assert(retname.ndata_.size() == length);
     assert(retname.ndata_.size() == length);
@@ -622,14 +622,13 @@ Name::concatenate(const Name& suffix) const {
     // excluding that for the trailing dot, and append the offsets of the
     // excluding that for the trailing dot, and append the offsets of the
     // suffix name with the additional offset of the length of the prefix.
     // suffix name with the additional offset of the length of the prefix.
     //
     //
-    unsigned int labels = this->labelcount_ + suffix.labelcount_ - 1;
+    unsigned int labels = labelcount_ + suffix.labelcount_ - 1;
     assert(labels <= Name::MAX_LABELS);
     assert(labels <= Name::MAX_LABELS);
     retname.offsets_.reserve(labels);
     retname.offsets_.reserve(labels);
-    retname.offsets_.assign(&this->offsets_[0],
+    retname.offsets_.assign(&offsets_[0], &offsets_[0] + labelcount_ - 1);
-                            &this->offsets_[0] + this->labelcount_ - 1);
     transform(suffix.offsets_.begin(), suffix.offsets_.end(),
     transform(suffix.offsets_.begin(), suffix.offsets_.end(),
               back_inserter(retname.offsets_),
               back_inserter(retname.offsets_),
-              bind2nd(plus<char>(), this->length_ - 1));
+              bind2nd(plus<char>(), length_ - 1));
     assert(retname.offsets_.size() == labels);
     assert(retname.offsets_.size() == labels);
     retname.labelcount_ = labels;
     retname.labelcount_ = labels;
 
 

+ 10 - 21
src/lib/dns/python/Makefile.am

@@ -1,27 +1,16 @@
-SUBDIRS = tests
+SUBDIRS = . tests
 
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
-
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 
-if USE_GXX
+pyexec_LTLIBRARIES = pydnspp.la
-AM_CXXFLAGS += -Wno-write-strings
+pydnspp_la_SOURCES = pydnspp.cc pydnspp_common.cc
-endif
+pydnspp_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-
+pydnspp_la_LDFLAGS = $(PYTHON_LDFLAGS)
-#lib_LTLIBRARIES = libdns_python_name.la libdns_python_rrset.la
-#libdns_python_name_la_SOURCES = name_python.cc
-#libdns_python_name_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-#libdns_python_name_la_LDFLAGS = $(PYTHON_LDFLAGS)
-
-#lib_LTLIBRARIES = libdns_python_name.la libdns_python_rrset.la
-pyexec_LTLIBRARIES = libdns_python.la
-libdns_python_la_SOURCES = libdns_python.cc libdns_python_common.cc
-libdns_python_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-libdns_python_la_LDFLAGS = $(PYTHON_LDFLAGS)
 
 
 # directly included from source files, so these don't have their own
 # directly included from source files, so these don't have their own
 # rules
 # rules
-EXTRA_DIST = libdns_python_common.h
+EXTRA_DIST = pydnspp_common.h
 EXTRA_DIST += edns_python.h
 EXTRA_DIST += edns_python.h
 EXTRA_DIST += messagerenderer_python.cc
 EXTRA_DIST += messagerenderer_python.cc
 EXTRA_DIST += message_python.cc
 EXTRA_DIST += message_python.cc
@@ -35,7 +24,7 @@ EXTRA_DIST += rrtype_python.cc
 
 
 # Python prefers .so, while some OSes (specifically MacOS) use a different
 # Python prefers .so, while some OSes (specifically MacOS) use a different
 # suffix for dynamic objects.  -module is necessary to work this around.
 # suffix for dynamic objects.  -module is necessary to work this around.
-libdns_python_la_LDFLAGS += -module
+pydnspp_la_LDFLAGS += -module
-libdns_python_la_LIBADD = $(top_builddir)/src/lib/dns/libdns++.la
+pydnspp_la_LIBADD = $(top_builddir)/src/lib/dns/libdns++.la
-libdns_python_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+pydnspp_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-libdns_python_la_LIBADD += $(PYTHON_LIB)
+pydnspp_la_LIBADD += $(PYTHON_LIB)

+ 6 - 6
src/lib/dns/python/README

@@ -1,14 +1,14 @@
 
 
 This is an implementation of the python wrappers for isc::dns.
 This is an implementation of the python wrappers for isc::dns.
 
 
-Currently, when compiled the module is called libdns_python. If we
+When compiled the module is called pydnspp. If we
 decide to always need it we can add a default import under
 decide to always need it we can add a default import under
 lib/python/isc.
 lib/python/isc.
 
 
 To use it from the source tree, you must add src/lib/dns/python/.libs
 To use it from the source tree, you must add src/lib/dns/python/.libs
 to your PYTHONPATH environment variable. Within python you can then use
 to your PYTHONPATH environment variable. Within python you can then use
-> import libdns_python
+> import pydnspp
-> rrc = libdns_python.RRClass("IN")
+> rrc = pydnspp.RRClass("IN")
 etc.
 etc.
 
 
 Notes:
 Notes:
@@ -26,8 +26,8 @@ specific Rdata types.
 If you have specific functionality you do need, please ask for it and we
 If you have specific functionality you do need, please ask for it and we
 will add it.
 will add it.
 
 
-The 'main' module is defined in libdns_python.cc.
+The 'main' module is defined in pydnspp.cc.
-There is a libdns_python_common.[cc|h] for helper functions.
+There is a pydnspp_common.[cc|h] for helper functions.
 
 
 Implementation notes:
 Implementation notes:
 
 
@@ -87,7 +87,7 @@ This is repeated for every class we export.
 
 
 Finally we define the function to add the class, constants, exceptions,
 Finally we define the function to add the class, constants, exceptions,
 and enums to the module. This function is called from the init function
 and enums to the module. This function is called from the init function
-in libdns_python.cc, has the name
+in pydnspp.cc, has the name
 initModulePart_<c++ class name>, returns a boolean
 initModulePart_<c++ class name>, returns a boolean
 (true on success, false on failure), and takes the module as a
 (true on success, false on failure), and takes the module as a
 PyObject*. There is a convenience function called addClassVariable to
 PyObject*. There is a convenience function called addClassVariable to

+ 12 - 10
src/lib/dns/python/message_python.cc

@@ -70,7 +70,7 @@ static PyMethodDef MessageFlag_methods[] = {
 
 
 static PyTypeObject messageflag_type = {
 static PyTypeObject messageflag_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.MessageFlag",
+    "pydnspp.MessageFlag",
     sizeof(s_MessageFlag),              // tp_basicsize
     sizeof(s_MessageFlag),              // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)MessageFlag_destroy,    // tp_dealloc
     (destructor)MessageFlag_destroy,    // tp_dealloc
@@ -246,7 +246,7 @@ static PyMethodDef Opcode_methods[] = {
 
 
 static PyTypeObject opcode_type = {
 static PyTypeObject opcode_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Opcode",
+    "pydnspp.Opcode",
     sizeof(s_Opcode),                   // tp_basicsize
     sizeof(s_Opcode),                   // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)Opcode_destroy,         // tp_dealloc
     (destructor)Opcode_destroy,         // tp_dealloc
@@ -534,7 +534,7 @@ static PyMethodDef Rcode_methods[] = {
 
 
 static PyTypeObject rcode_type = {
 static PyTypeObject rcode_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Rcode",
+    "pydnspp.Rcode",
     sizeof(s_Rcode),                    // tp_basicsize
     sizeof(s_Rcode),                    // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)Rcode_destroy,          // tp_dealloc
     (destructor)Rcode_destroy,          // tp_dealloc
@@ -809,7 +809,7 @@ static PyMethodDef Section_methods[] = {
 
 
 static PyTypeObject section_type = {
 static PyTypeObject section_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Section",
+    "pydnspp.Section",
     sizeof(s_Section),                  // tp_basicsize
     sizeof(s_Section),                  // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)Section_destroy,        // tp_dealloc
     (destructor)Section_destroy,        // tp_dealloc
@@ -1099,7 +1099,7 @@ static PyMethodDef Message_methods[] = {
 // Most of the functions are not actually implemented and NULL here.
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject message_type = {
 static PyTypeObject message_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Message",
+    "pydnspp.Message",
     sizeof(s_Message),                  // tp_basicsize
     sizeof(s_Message),                  // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)Message_destroy,        // tp_dealloc
     (destructor)Message_destroy,        // tp_dealloc
@@ -1501,7 +1501,7 @@ static PyObject*
 Message_toWire(s_Message* self, PyObject* args) {
 Message_toWire(s_Message* self, PyObject* args) {
     s_MessageRenderer* mr;
     s_MessageRenderer* mr;
     
     
-    if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, (PyObject**) &mr)) {
+    if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
         try {
         try {
             self->message->toWire(*mr->messagerenderer);
             self->message->toWire(*mr->messagerenderer);
             // If we return NULL it is seen as an error, so use this for
             // If we return NULL it is seen as an error, so use this for
@@ -1593,14 +1593,16 @@ initModulePart_Message(PyObject* mod) {
     addClassVariable(message_type, "DEFAULT_MAX_UDPSIZE", Py_BuildValue("I", Message::DEFAULT_MAX_UDPSIZE));
     addClassVariable(message_type, "DEFAULT_MAX_UDPSIZE", Py_BuildValue("I", Message::DEFAULT_MAX_UDPSIZE));
 
 
     /* Class-specific exceptions */
     /* Class-specific exceptions */
-    po_MessageTooShort = PyErr_NewException("libdns_python.MessageTooShort", NULL, NULL);
+    po_MessageTooShort = PyErr_NewException("pydnspp.MessageTooShort", NULL, NULL);
     PyModule_AddObject(mod, "MessageTooShort", po_MessageTooShort);
     PyModule_AddObject(mod, "MessageTooShort", po_MessageTooShort);
-    po_InvalidMessageSection = PyErr_NewException("libdns_python.InvalidMessageSection", NULL, NULL);
+    po_InvalidMessageSection = PyErr_NewException("pydnspp.InvalidMessageSection", NULL, NULL);
     PyModule_AddObject(mod, "InvalidMessageSection", po_InvalidMessageSection);
     PyModule_AddObject(mod, "InvalidMessageSection", po_InvalidMessageSection);
-    po_InvalidMessageOperation = PyErr_NewException("libdns_python.InvalidMessageOperation", NULL, NULL);
+    po_InvalidMessageOperation = PyErr_NewException("pydnspp.InvalidMessageOperation", NULL, NULL);
     PyModule_AddObject(mod, "InvalidMessageOperation", po_InvalidMessageOperation);
     PyModule_AddObject(mod, "InvalidMessageOperation", po_InvalidMessageOperation);
-    po_InvalidMessageUDPSize = PyErr_NewException("libdns_python.InvalidMessageUDPSize", NULL, NULL);
+    po_InvalidMessageUDPSize = PyErr_NewException("pydnspp.InvalidMessageUDPSize", NULL, NULL);
     PyModule_AddObject(mod, "InvalidMessageUDPSize", po_InvalidMessageUDPSize);
     PyModule_AddObject(mod, "InvalidMessageUDPSize", po_InvalidMessageUDPSize);
+    po_DNSMessageBADVERS = PyErr_NewException("pydnspp.DNSMessageBADVERS", NULL, NULL);
+    PyModule_AddObject(mod, "DNSMessageBADVERS", po_DNSMessageBADVERS);
 
 
     Py_INCREF(&message_type);
     Py_INCREF(&message_type);
     PyModule_AddObject(mod, "Message",
     PyModule_AddObject(mod, "Message",

+ 1 - 1
src/lib/dns/python/messagerenderer_python.cc

@@ -65,7 +65,7 @@ static PyMethodDef MessageRenderer_methods[] = {
 
 
 static PyTypeObject messagerenderer_type = {
 static PyTypeObject messagerenderer_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.MessageRenderer",
+    "pydnspp.MessageRenderer",
     sizeof(s_MessageRenderer),          // tp_basicsize
     sizeof(s_MessageRenderer),          // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)MessageRenderer_destroy,// tp_dealloc
     (destructor)MessageRenderer_destroy,// tp_dealloc

+ 14 - 14
src/lib/dns/python/name_python.cc

@@ -68,7 +68,7 @@ static PyMethodDef NameComparisonResult_methods[] = {
 
 
 static PyTypeObject name_comparison_result_type = {
 static PyTypeObject name_comparison_result_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.NameComparisonResult",
+    "pydnspp.NameComparisonResult",
     sizeof(s_NameComparisonResult),           // tp_basicsize
     sizeof(s_NameComparisonResult),           // tp_basicsize
     0,                                        // tp_itemsize
     0,                                        // tp_itemsize
     (destructor)NameComparisonResult_destroy, // tp_dealloc
     (destructor)NameComparisonResult_destroy, // tp_dealloc
@@ -222,7 +222,7 @@ static PyMethodDef Name_methods[] = {
 
 
 static PyTypeObject name_type = {
 static PyTypeObject name_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Name",
+    "pydnspp.Name",
     sizeof(s_Name),                     // tp_basicsize
     sizeof(s_Name),                     // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)Name_destroy,           // tp_dealloc
     (destructor)Name_destroy,           // tp_dealloc
@@ -421,7 +421,7 @@ Name_toWire(s_Name* self, PyObject* args) {
         // to prevent memory leak
         // to prevent memory leak
         Py_DECREF(name_bytes);
         Py_DECREF(name_bytes);
         return (result);
         return (result);
-    } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, (PyObject**) &mr)) {
+    } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
         self->name->toWire(*mr->messagerenderer);
         self->name->toWire(*mr->messagerenderer);
         // If we return NULL it is seen as an error, so use this for
         // If we return NULL it is seen as an error, so use this for
         // None returns
         // None returns
@@ -437,7 +437,7 @@ static PyObject*
 Name_compare(s_Name* self, PyObject* args) {
 Name_compare(s_Name* self, PyObject* args) {
     s_Name* other;
     s_Name* other;
 
 
-    if (!PyArg_ParseTuple(args, "O!", &name_type, (PyObject* *) &other))
+    if (!PyArg_ParseTuple(args, "O!", &name_type, &other))
         return (NULL);
         return (NULL);
 
 
     s_NameComparisonResult* ret = PyObject_New(s_NameComparisonResult, &name_comparison_result_type);
     s_NameComparisonResult* ret = PyObject_New(s_NameComparisonResult, &name_comparison_result_type);
@@ -452,7 +452,7 @@ static PyObject*
 Name_equals(s_Name* self, PyObject* args) {
 Name_equals(s_Name* self, PyObject* args) {
     s_Name* other;
     s_Name* other;
 
 
-    if (!PyArg_ParseTuple(args, "O!", &name_type, (PyObject* *) &other))
+    if (!PyArg_ParseTuple(args, "O!", &name_type, &other))
         return (NULL);
         return (NULL);
 
 
     if (self->name->equals(*other->name))
     if (self->name->equals(*other->name))
@@ -565,7 +565,7 @@ static PyObject*
 Name_concatenate(s_Name* self, PyObject* args) {
 Name_concatenate(s_Name* self, PyObject* args) {
     s_Name* other;
     s_Name* other;
 
 
-    if (!PyArg_ParseTuple(args, "O!", &name_type, (PyObject**) &other))
+    if (!PyArg_ParseTuple(args, "O!", &name_type, &other))
         return (NULL);
         return (NULL);
 
 
     s_Name* ret = PyObject_New(s_Name, &name_type);
     s_Name* ret = PyObject_New(s_Name, &name_type);
@@ -651,30 +651,30 @@ initModulePart_Name(PyObject* mod) {
     
     
 
 
     // Add the exceptions to the module
     // Add the exceptions to the module
-    po_EmptyLabel = PyErr_NewException("libdns_python.EmptyLabel", NULL, NULL);
+    po_EmptyLabel = PyErr_NewException("pydnspp.EmptyLabel", NULL, NULL);
     PyModule_AddObject(mod, "EmptyLabel", po_EmptyLabel);
     PyModule_AddObject(mod, "EmptyLabel", po_EmptyLabel);
 
 
-    po_TooLongName = PyErr_NewException("libdns_python.TooLongName", NULL, NULL);
+    po_TooLongName = PyErr_NewException("pydnspp.TooLongName", NULL, NULL);
     PyModule_AddObject(mod, "TooLongName", po_TooLongName);
     PyModule_AddObject(mod, "TooLongName", po_TooLongName);
 
 
-    po_TooLongLabel = PyErr_NewException("libdns_python.TooLongLabel", NULL, NULL);
+    po_TooLongLabel = PyErr_NewException("pydnspp.TooLongLabel", NULL, NULL);
     PyModule_AddObject(mod, "TooLongLabel", po_TooLongLabel);
     PyModule_AddObject(mod, "TooLongLabel", po_TooLongLabel);
 
 
-    po_BadLabelType = PyErr_NewException("libdns_python.BadLabelType", NULL, NULL);
+    po_BadLabelType = PyErr_NewException("pydnspp.BadLabelType", NULL, NULL);
     PyModule_AddObject(mod, "BadLabelType", po_BadLabelType);
     PyModule_AddObject(mod, "BadLabelType", po_BadLabelType);
 
 
-    po_BadEscape = PyErr_NewException("libdns_python.BadEscape", NULL, NULL);
+    po_BadEscape = PyErr_NewException("pydnspp.BadEscape", NULL, NULL);
     PyModule_AddObject(mod, "BadEscape", po_BadEscape);
     PyModule_AddObject(mod, "BadEscape", po_BadEscape);
 
 
-    po_IncompleteName = PyErr_NewException("libdns_python.IncompleteName", NULL, NULL);
+    po_IncompleteName = PyErr_NewException("pydnspp.IncompleteName", NULL, NULL);
     PyModule_AddObject(mod, "IncompleteName", po_IncompleteName);
     PyModule_AddObject(mod, "IncompleteName", po_IncompleteName);
 
 
-    po_InvalidBufferPosition = PyErr_NewException("libdns_python.InvalidBufferPosition", NULL, NULL);
+    po_InvalidBufferPosition = PyErr_NewException("pydnspp.InvalidBufferPosition", NULL, NULL);
     PyModule_AddObject(mod, "InvalidBufferPosition", po_InvalidBufferPosition);
     PyModule_AddObject(mod, "InvalidBufferPosition", po_InvalidBufferPosition);
 
 
     // This one could have gone into the message_python.cc file, but is
     // This one could have gone into the message_python.cc file, but is
     // already needed here.
     // already needed here.
-    po_DNSMessageFORMERR = PyErr_NewException("libdns_python.DNSMessageFORMERR", NULL, NULL);
+    po_DNSMessageFORMERR = PyErr_NewException("pydnspp.DNSMessageFORMERR", NULL, NULL);
     PyModule_AddObject(mod, "DNSMessageFORMERR", po_DNSMessageFORMERR);
     PyModule_AddObject(mod, "DNSMessageFORMERR", po_DNSMessageFORMERR);
 
 
     return (true);
     return (true);

+ 141 - 0
src/lib/dns/python/pydnspp.cc

@@ -0,0 +1,141 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+
+// We want a lot of different parts of the DNS API in the python
+// module, but not one big 10000-line file.
+// So we split it up in several 'mini-modules'
+// These would be the same as a single module, except for
+// the init function, which has to be modified to a unique
+// name initModulePart_<name>, and return true/false instead of
+// NULL/*mod
+//
+// And of course care has to be taken that all identifiers be unique
+
+// $Id$
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <structmember.h>
+
+#include <config.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/buffer.h>
+#include <dns/exceptions.h>
+#include <dns/name.h>
+#include <dns/messagerenderer.h>
+
+#include <dns/python/pydnspp_common.h>
+
+// For our 'general' isc::Exceptions
+static PyObject* po_IscException;
+static PyObject* po_InvalidParameter;
+
+// For our own isc::dns::Exception
+static PyObject* po_DNSMessageBADVERS;
+
+// order is important here!
+#include <dns/python/messagerenderer_python.cc>
+#include <dns/python/name_python.cc>           // needs Messagerenderer
+#include <dns/python/rrclass_python.cc>        // needs Messagerenderer
+#include <dns/python/rrtype_python.cc>         // needs Messagerenderer
+#include <dns/python/rrttl_python.cc>          // needs Messagerenderer
+#include <dns/python/rdata_python.cc>          // needs Type, Class
+#include <dns/python/rrset_python.cc>          // needs Rdata, RRTTL
+#include <dns/python/question_python.cc>       // needs RRClass, RRType, RRTTL,
+                                               // Name
+#include <dns/python/edns_python.cc>           // needs Messagerenderer, Rcode
+#include <dns/python/message_python.cc>        // needs RRset, Question
+
+//
+// Definition of the module
+//
+static PyModuleDef pydnspp = {
+    { PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
+    "pydnspp",
+    "Python bindings for the classes in the isc::dns namespace.\n\n"
+    "These bindings match the original C++ API as closely as possible, "
+    "but are not complete. Some classes are unnecessary (InputBuffer "
+    "and OutputBuffer for instance), and others may be necessary, but "
+    "were not up to now.",
+    -1,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+PyMODINIT_FUNC
+PyInit_pydnspp(void) {
+    PyObject *mod = PyModule_Create(&pydnspp);
+    if (mod == NULL) {
+        return (NULL);
+    }
+
+    // Add the exceptions to the class
+    po_IscException = PyErr_NewException("pydnspp.IscException", NULL, NULL);
+    PyModule_AddObject(mod, "IscException", po_IscException);
+
+    po_InvalidParameter = PyErr_NewException("pydnspp.InvalidParameter",
+                                             NULL, NULL);
+    PyModule_AddObject(mod, "InvalidParameter", po_InvalidParameter);
+
+    // for each part included above, we call its specific initializer
+
+    if (!initModulePart_Name(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_MessageRenderer(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_RRClass(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_RRType(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_RRTTL(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_Rdata(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_RRset(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_Question(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_Message(mod)) {
+        return (NULL);
+    }
+
+    if (!initModulePart_EDNS(mod)) {
+        return (NULL);
+    }
+
+    return (mod);
+}
+

+ 1 - 1
src/lib/dns/python/libdns_python_common.cc

@@ -15,7 +15,7 @@
 // $Id$
 // $Id$
 
 
 #include <Python.h>
 #include <Python.h>
-#include <libdns_python_common.h>
+#include <pydnspp_common.h>
 
 
 int
 int
 readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence) {
 readDataFromSequence(uint8_t *data, size_t len, PyObject* sequence) {

src/lib/dns/python/libdns_python_common.h → src/lib/dns/python/pydnspp_common.h


+ 2 - 3
src/lib/dns/python/question_python.cc

@@ -76,7 +76,7 @@ static PyMethodDef Question_methods[] = {
 // Most of the functions are not actually implemented and NULL here.
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject question_type = {
 static PyTypeObject question_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Question",
+    "pydnspp.Question",
     sizeof(s_Question),                 // tp_basicsize
     sizeof(s_Question),                 // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)Question_destroy,       // tp_dealloc
     (destructor)Question_destroy,       // tp_dealloc
@@ -254,8 +254,7 @@ Question_toWire(s_Question* self, PyObject* args) {
         // to prevent memory leak
         // to prevent memory leak
         Py_DECREF(n);
         Py_DECREF(n);
         return (result);
         return (result);
-    } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type,
+    } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
-                                reinterpret_cast<PyObject**>(&mr))) {
         self->question->toWire(*mr->messagerenderer);
         self->question->toWire(*mr->messagerenderer);
         // If we return NULL it is seen as an error, so use this for
         // If we return NULL it is seen as an error, so use this for
         // None returns
         // None returns

+ 5 - 5
src/lib/dns/python/rdata_python.cc

@@ -92,7 +92,7 @@ static PyMethodDef Rdata_methods[] = {
 // Most of the functions are not actually implemented and NULL here.
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject rdata_type = {
 static PyTypeObject rdata_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Rdata",
+    "pydnspp.Rdata",
     sizeof(s_Rdata),                    // tp_basicsize
     sizeof(s_Rdata),                    // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)Rdata_destroy,          // tp_dealloc
     (destructor)Rdata_destroy,          // tp_dealloc
@@ -204,7 +204,7 @@ Rdata_toWire(s_Rdata* self, PyObject* args) {
         // to prevent memory leak
         // to prevent memory leak
         Py_DECREF(rd_bytes);
         Py_DECREF(rd_bytes);
         return (result);
         return (result);
-    } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, (PyObject**) &mr)) {
+    } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
         self->rdata->toWire(*mr->messagerenderer);
         self->rdata->toWire(*mr->messagerenderer);
         // If we return NULL it is seen as an error, so use this for
         // If we return NULL it is seen as an error, so use this for
         // None returns
         // None returns
@@ -276,13 +276,13 @@ initModulePart_Rdata(PyObject* mod) {
                        reinterpret_cast<PyObject*>(&rdata_type));
                        reinterpret_cast<PyObject*>(&rdata_type));
 
 
     // Add the exceptions to the class
     // Add the exceptions to the class
-    po_InvalidRdataLength = PyErr_NewException("libdns_python.InvalidRdataLength", NULL, NULL);
+    po_InvalidRdataLength = PyErr_NewException("pydnspp.InvalidRdataLength", NULL, NULL);
     PyModule_AddObject(mod, "InvalidRdataLength", po_InvalidRdataLength);
     PyModule_AddObject(mod, "InvalidRdataLength", po_InvalidRdataLength);
 
 
-    po_InvalidRdataText = PyErr_NewException("libdns_python.InvalidRdataText", NULL, NULL);
+    po_InvalidRdataText = PyErr_NewException("pydnspp.InvalidRdataText", NULL, NULL);
     PyModule_AddObject(mod, "InvalidRdataText", po_InvalidRdataText);
     PyModule_AddObject(mod, "InvalidRdataText", po_InvalidRdataText);
 
 
-    po_CharStringTooLong = PyErr_NewException("libdns_python.CharStringTooLong", NULL, NULL);
+    po_CharStringTooLong = PyErr_NewException("pydnspp.CharStringTooLong", NULL, NULL);
     PyModule_AddObject(mod, "CharStringTooLong", po_CharStringTooLong);
     PyModule_AddObject(mod, "CharStringTooLong", po_CharStringTooLong);
 
 
     
     

+ 6 - 6
src/lib/dns/python/rrclass_python.cc

@@ -100,7 +100,7 @@ static PyMethodDef RRClass_methods[] = {
 // Most of the functions are not actually implemented and NULL here.
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject rrclass_type = {
 static PyTypeObject rrclass_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.RRClass",
+    "pydnspp.RRClass",
     sizeof(s_RRClass),                  // tp_basicsize
     sizeof(s_RRClass),                  // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)RRClass_destroy,        // tp_dealloc
     (destructor)RRClass_destroy,        // tp_dealloc
@@ -157,7 +157,7 @@ RRClass_init(s_RRClass* self, PyObject* args) {
     unsigned int i;
     unsigned int i;
     PyObject* bytes = NULL;
     PyObject* bytes = NULL;
     // The constructor argument can be a string ("IN"), an integer (1),
     // The constructor argument can be a string ("IN"), an integer (1),
-    // or a sequence of numbers between 0 and 255 (wire code)
+    // or a sequence of numbers between 0 and 65535 (wire code)
 
 
     // Note that PyArg_ParseType can set PyError, and we need to clear
     // Note that PyArg_ParseType can set PyError, and we need to clear
     // that if we try several like here. Otherwise the *next* python
     // that if we try several like here. Otherwise the *next* python
@@ -170,7 +170,7 @@ RRClass_init(s_RRClass* self, PyObject* args) {
         } else if (PyArg_ParseTuple(args, "I", &i)) {
         } else if (PyArg_ParseTuple(args, "I", &i)) {
             PyErr_Clear();
             PyErr_Clear();
             if (i > 65535) {
             if (i > 65535) {
-                PyErr_SetString(po_InvalidRRClass, "Class number too high");
+                PyErr_SetString(po_InvalidRRClass, "RR class number too high");
                 return (-1);
                 return (-1);
             }
             }
             self->rrclass = new RRClass(i);
             self->rrclass = new RRClass(i);
@@ -236,7 +236,7 @@ RRClass_toWire(s_RRClass* self, PyObject* args) {
         // to prevent memory leak
         // to prevent memory leak
         Py_DECREF(n);
         Py_DECREF(n);
         return (result);
         return (result);
-    } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, (PyObject**) &mr)) {
+    } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
         self->rrclass->toWire(*mr->messagerenderer);
         self->rrclass->toWire(*mr->messagerenderer);
         // If we return NULL it is seen as an error, so use this for
         // If we return NULL it is seen as an error, so use this for
         // None returns
         // None returns
@@ -332,10 +332,10 @@ static PyObject* RRClass_ANY(s_RRClass *self UNUSED_PARAM) {
 bool
 bool
 initModulePart_RRClass(PyObject* mod) {
 initModulePart_RRClass(PyObject* mod) {
     // Add the exceptions to the module
     // Add the exceptions to the module
-    po_InvalidRRClass = PyErr_NewException("libdns_python.InvalidRRClass", NULL, NULL);
+    po_InvalidRRClass = PyErr_NewException("pydnspp.InvalidRRClass", NULL, NULL);
     Py_INCREF(po_InvalidRRClass);
     Py_INCREF(po_InvalidRRClass);
     PyModule_AddObject(mod, "InvalidRRClass", po_InvalidRRClass);
     PyModule_AddObject(mod, "InvalidRRClass", po_InvalidRRClass);
-    po_IncompleteRRClass = PyErr_NewException("libdns_python.IncompleteRRClass", NULL, NULL);
+    po_IncompleteRRClass = PyErr_NewException("pydnspp.IncompleteRRClass", NULL, NULL);
     Py_INCREF(po_IncompleteRRClass);
     Py_INCREF(po_IncompleteRRClass);
     PyModule_AddObject(mod, "IncompleteRRClass", po_IncompleteRRClass);
     PyModule_AddObject(mod, "IncompleteRRClass", po_IncompleteRRClass);
 
 

+ 3 - 3
src/lib/dns/python/rrset_python.cc

@@ -94,7 +94,7 @@ static PyMethodDef RRset_methods[] = {
 
 
 static PyTypeObject rrset_type = {
 static PyTypeObject rrset_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.RRset",
+    "pydnspp.RRset",
     sizeof(s_RRset),                    // tp_basicsize
     sizeof(s_RRset),                    // tp_basicsize
     0,                                  // tp_itemsize
     0,                                  // tp_itemsize
     (destructor)RRset_destroy,          // tp_dealloc
     (destructor)RRset_destroy,          // tp_dealloc
@@ -315,7 +315,7 @@ RRset_toWire(s_RRset* self, PyObject* args) {
             // to prevent memory leak
             // to prevent memory leak
             Py_DECREF(n);
             Py_DECREF(n);
             return (result);
             return (result);
-        } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, (PyObject**) &mr)) {
+        } else if (PyArg_ParseTuple(args, "O!", &messagerenderer_type, &mr)) {
             self->rrset->toWire(*mr->messagerenderer);
             self->rrset->toWire(*mr->messagerenderer);
             // If we return NULL it is seen as an error, so use this for
             // If we return NULL it is seen as an error, so use this for
             // None returns
             // None returns
@@ -379,7 +379,7 @@ RRset_getRdata(s_RRset* self) {
 bool
 bool
 initModulePart_RRset(PyObject* mod) {
 initModulePart_RRset(PyObject* mod) {
     // Add the exceptions to the module
     // Add the exceptions to the module
-    po_EmptyRRset = PyErr_NewException("libdns_python.EmptyRRset", NULL, NULL);
+    po_EmptyRRset = PyErr_NewException("pydnspp.EmptyRRset", NULL, NULL);
     PyModule_AddObject(mod, "EmptyRRset", po_EmptyRRset);
     PyModule_AddObject(mod, "EmptyRRset", po_EmptyRRset);
 
 
     // Add the enums to the module
     // Add the enums to the module

+ 0 - 0
src/lib/dns/python/rrttl_python.cc


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