[svn] commit: r2981 - in /branches/trac308: ./ doc/guide/ src/bin/ src/bin/auth/ src/bin/auth/tests/ src/bin/bind10/ src/bin/bind10/tests/ src/bin/bindctl/ src/bin/bindctl/tests/ src/bin/cfgmgr/tests/ src/bin/cmdctl/ src/bin/cmdctl/tests/ src/bin/host/ src/bin/loadzone/tests/correct/ src/bin/loadzone/tests/error/ src/bin/msgq/ src/bin/msgq/tests/ src/bin/xfrin/ src/bin/xfrin/tests/ src/bin/xfrout/ src/bin/xfrout/tests/ src/bin/zonemgr/ src/lib/bench/ src/lib/bench/tests/ src/lib/cc/ src/lib/cc/tests/ src/lib/config/ src/lib/config/testdata/ src/lib/config/tests/ src/lib/datasrc/ src/lib/datasrc/tests/ src/lib/dns/ src/lib/dns/python/ src/lib/dns/python/tests/ src/lib/dns/rdata/generic/ src/lib/dns/tests/ src/lib/dns/util/ src/lib/exceptions/ src/lib/exceptions/tests/ src/lib/python/isc/ src/lib/python/isc/cc/ src/lib/python/isc/cc/tests/ src/lib/python/isc/config/ src/lib/python/isc/config/tests/ src/lib/python/isc/datasrc/ src/lib/python/isc/dns/ src/lib/python/isc/log/tests/ src/lib/python/isc/notify/ src/lib/xfr/

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Sep 20 11:07:55 UTC 2010


Author: jinmei
Date: Mon Sep 20 11:07:54 2010
New Revision: 2981

Log:
sync with trunk

Added:
    branches/trac308/src/bin/zonemgr/
      - copied from r2979, trunk/src/bin/zonemgr/
    branches/trac308/src/lib/cc/tests/
      - copied from r2979, trunk/src/lib/cc/tests/
    branches/trac308/src/lib/config/testdata/Makefile.am
      - copied unchanged from r2979, trunk/src/lib/config/testdata/Makefile.am
    branches/trac308/src/lib/config/testdata/b10-config.db.master
      - copied unchanged from r2979, trunk/src/lib/config/testdata/b10-config.db.master
    branches/trac308/src/lib/dns/python/pydnspp.cc
      - copied unchanged from r2979, trunk/src/lib/dns/python/pydnspp.cc
    branches/trac308/src/lib/dns/python/pydnspp_common.cc
      - copied unchanged from r2979, trunk/src/lib/dns/python/pydnspp_common.cc
    branches/trac308/src/lib/dns/python/pydnspp_common.h
      - copied unchanged from r2979, trunk/src/lib/dns/python/pydnspp_common.h
    branches/trac308/src/lib/exceptions/tests/
      - copied from r2979, trunk/src/lib/exceptions/tests/
    branches/trac308/src/lib/python/isc/notify/
      - copied from r2979, trunk/src/lib/python/isc/notify/
Removed:
    branches/trac308/src/lib/cc/data_unittests.cc
    branches/trac308/src/lib/cc/run_unittests.cc
    branches/trac308/src/lib/cc/session_unittests.cc
    branches/trac308/src/lib/config/testdata/b10-config.db
    branches/trac308/src/lib/dns/message_test.py
    branches/trac308/src/lib/dns/python/libdns_python.cc
    branches/trac308/src/lib/dns/python/libdns_python_common.cc
    branches/trac308/src/lib/dns/python/libdns_python_common.h
    branches/trac308/src/lib/dns/python/tests/test.py
    branches/trac308/src/lib/exceptions/exceptions_unittest.cc
    branches/trac308/src/lib/exceptions/run_unittests.cc
Modified:
    branches/trac308/   (props changed)
    branches/trac308/ChangeLog
    branches/trac308/Makefile.am
    branches/trac308/README
    branches/trac308/configure.ac
    branches/trac308/doc/guide/bind10-guide.html
    branches/trac308/doc/guide/bind10-guide.xml
    branches/trac308/src/bin/Makefile.am
    branches/trac308/src/bin/auth/Makefile.am
    branches/trac308/src/bin/auth/asio_link.cc
    branches/trac308/src/bin/auth/asio_link.h
    branches/trac308/src/bin/auth/auth_srv.cc
    branches/trac308/src/bin/auth/auth_srv.h
    branches/trac308/src/bin/auth/b10-auth.8
    branches/trac308/src/bin/auth/b10-auth.xml
    branches/trac308/src/bin/auth/main.cc
    branches/trac308/src/bin/auth/tests/Makefile.am
    branches/trac308/src/bin/auth/tests/auth_srv_unittest.cc
    branches/trac308/src/bin/bind10/bind10.8
    branches/trac308/src/bin/bind10/bind10.py.in
    branches/trac308/src/bin/bind10/bind10.xml
    branches/trac308/src/bin/bind10/run_bind10.sh.in
    branches/trac308/src/bin/bind10/tests/Makefile.am
    branches/trac308/src/bin/bindctl/bindcmd.py
    branches/trac308/src/bin/bindctl/tests/Makefile.am
    branches/trac308/src/bin/cfgmgr/tests/Makefile.am
    branches/trac308/src/bin/cmdctl/cmdctl.py.in
    branches/trac308/src/bin/cmdctl/tests/Makefile.am
    branches/trac308/src/bin/host/Makefile.am
    branches/trac308/src/bin/loadzone/tests/correct/Makefile.am
    branches/trac308/src/bin/loadzone/tests/error/Makefile.am
    branches/trac308/src/bin/msgq/msgq.py.in
    branches/trac308/src/bin/msgq/tests/Makefile.am
    branches/trac308/src/bin/xfrin/   (props changed)
    branches/trac308/src/bin/xfrin/TODO
    branches/trac308/src/bin/xfrin/b10-xfrin.8
    branches/trac308/src/bin/xfrin/b10-xfrin.xml
    branches/trac308/src/bin/xfrin/tests/Makefile.am
    branches/trac308/src/bin/xfrin/tests/xfrin_test.py
    branches/trac308/src/bin/xfrin/xfrin.py.in
    branches/trac308/src/bin/xfrin/xfrin.spec.pre.in
    branches/trac308/src/bin/xfrout/b10-xfrout.8
    branches/trac308/src/bin/xfrout/b10-xfrout.xml
    branches/trac308/src/bin/xfrout/tests/Makefile.am
    branches/trac308/src/bin/xfrout/tests/xfrout_test.py
    branches/trac308/src/bin/xfrout/xfrout.py.in
    branches/trac308/src/lib/bench/   (props changed)
    branches/trac308/src/lib/bench/tests/benchmark_unittest.cc
    branches/trac308/src/lib/cc/   (props changed)
    branches/trac308/src/lib/cc/Makefile.am
    branches/trac308/src/lib/cc/data.cc
    branches/trac308/src/lib/cc/data.h
    branches/trac308/src/lib/cc/session.cc
    branches/trac308/src/lib/cc/session.h
    branches/trac308/src/lib/config/Makefile.am
    branches/trac308/src/lib/config/ccsession.cc
    branches/trac308/src/lib/config/ccsession.h
    branches/trac308/src/lib/config/config_data.cc
    branches/trac308/src/lib/config/config_data.h
    branches/trac308/src/lib/config/documentation.txt
    branches/trac308/src/lib/config/module_spec.cc
    branches/trac308/src/lib/config/module_spec.h
    branches/trac308/src/lib/config/tests/Makefile.am
    branches/trac308/src/lib/config/tests/ccsession_unittests.cc
    branches/trac308/src/lib/config/tests/config_data_unittests.cc
    branches/trac308/src/lib/config/tests/fake_session.cc
    branches/trac308/src/lib/config/tests/fake_session.h
    branches/trac308/src/lib/config/tests/module_spec_unittests.cc
    branches/trac308/src/lib/datasrc/   (props changed)
    branches/trac308/src/lib/datasrc/data_source.cc
    branches/trac308/src/lib/datasrc/data_source.h
    branches/trac308/src/lib/datasrc/sqlite3_datasrc.cc
    branches/trac308/src/lib/datasrc/sqlite3_datasrc.h
    branches/trac308/src/lib/datasrc/static_datasrc.cc
    branches/trac308/src/lib/datasrc/static_datasrc.h
    branches/trac308/src/lib/datasrc/tests/Makefile.am
    branches/trac308/src/lib/datasrc/tests/datasrc_unittest.cc
    branches/trac308/src/lib/datasrc/tests/sqlite3_unittest.cc
    branches/trac308/src/lib/datasrc/tests/test_datasrc.cc
    branches/trac308/src/lib/datasrc/tests/test_datasrc.h
    branches/trac308/src/lib/dns/   (props changed)
    branches/trac308/src/lib/dns/Makefile.am
    branches/trac308/src/lib/dns/messagerenderer.h
    branches/trac308/src/lib/dns/name.cc
    branches/trac308/src/lib/dns/name.h
    branches/trac308/src/lib/dns/python/Makefile.am
    branches/trac308/src/lib/dns/python/README
    branches/trac308/src/lib/dns/python/message_python.cc   (contents, props changed)
    branches/trac308/src/lib/dns/python/messagerenderer_python.cc
    branches/trac308/src/lib/dns/python/name_python.cc
    branches/trac308/src/lib/dns/python/question_python.cc
    branches/trac308/src/lib/dns/python/rdata_python.cc
    branches/trac308/src/lib/dns/python/rrclass_python.cc
    branches/trac308/src/lib/dns/python/rrset_python.cc
    branches/trac308/src/lib/dns/python/rrttl_python.cc
    branches/trac308/src/lib/dns/python/rrtype_python.cc
    branches/trac308/src/lib/dns/python/tests/Makefile.am
    branches/trac308/src/lib/dns/python/tests/message_python_test.py
    branches/trac308/src/lib/dns/python/tests/messagerenderer_python_test.py
    branches/trac308/src/lib/dns/python/tests/name_python_test.py
    branches/trac308/src/lib/dns/python/tests/question_python_test.py
    branches/trac308/src/lib/dns/python/tests/rdata_python_test.py
    branches/trac308/src/lib/dns/python/tests/rrclass_python_test.py
    branches/trac308/src/lib/dns/python/tests/rrset_python_test.py
    branches/trac308/src/lib/dns/python/tests/rrttl_python_test.py
    branches/trac308/src/lib/dns/python/tests/rrtype_python_test.py
    branches/trac308/src/lib/dns/rdata/generic/ds_43.cc
    branches/trac308/src/lib/dns/rdata/generic/nsec3_50.cc
    branches/trac308/src/lib/dns/rdata/generic/rrsig_46.cc   (props changed)
    branches/trac308/src/lib/dns/rrsetlist.cc
    branches/trac308/src/lib/dns/rrtype-placeholder.h
    branches/trac308/src/lib/dns/tests/   (props changed)
    branches/trac308/src/lib/dns/tests/Makefile.am
    branches/trac308/src/lib/dns/tests/rrparamregistry_unittest.cc
    branches/trac308/src/lib/dns/tests/unittest_util.cc
    branches/trac308/src/lib/dns/util/base16_from_binary.h
    branches/trac308/src/lib/dns/util/base32hex_from_binary.h
    branches/trac308/src/lib/dns/util/binary_from_base16.h
    branches/trac308/src/lib/dns/util/binary_from_base32hex.h
    branches/trac308/src/lib/dns/util/sha1.cc
    branches/trac308/src/lib/exceptions/Makefile.am
    branches/trac308/src/lib/python/isc/Makefile.am
    branches/trac308/src/lib/python/isc/cc/session.py
    branches/trac308/src/lib/python/isc/cc/tests/Makefile.am
    branches/trac308/src/lib/python/isc/cc/tests/session_test.py
    branches/trac308/src/lib/python/isc/config/ccsession.py
    branches/trac308/src/lib/python/isc/config/cfgmgr.py
    branches/trac308/src/lib/python/isc/config/tests/Makefile.am
    branches/trac308/src/lib/python/isc/config/tests/cfgmgr_test.py
    branches/trac308/src/lib/python/isc/config/tests/unittest_fakesession.py   (contents, props changed)
    branches/trac308/src/lib/python/isc/datasrc/sqlite3_ds.py
    branches/trac308/src/lib/python/isc/dns/__init__.py
    branches/trac308/src/lib/python/isc/log/tests/Makefile.am
    branches/trac308/src/lib/python/isc/log/tests/log_test.py
    branches/trac308/src/lib/xfr/fdshare_python.cc
    branches/trac308/src/lib/xfr/xfrout_client.cc

Modified: branches/trac308/ChangeLog
==============================================================================
--- branches/trac308/ChangeLog (original)
+++ branches/trac308/ChangeLog Mon Sep 20 11:07:54 2010
@@ -1,16 +1,91 @@
+96.	[bug]		jinmei
+	Fixed two small issues with configure: Do not set CXXFLAGS so that
+	it can be customized; Made 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
+	(Darwin/Mac OS X specific) Specify DYLD_LIBRARY_PATH for tests and
+	experimental run under the source tree.  Without this loadable
+	python modules refer to installation paths, which may confuse the
+	operation due to version mismatch or even trigger run time errors
+	due to missing libraries. (Trac #313, r2782)
+
+  89.	[build]		jinmei
+	Generate b10-config.db for tests at build time so that the source
+	tree does not have to be writable. (Trac #315, r2776)
+
+  88.   [func]		jelte
+	Blocking reads on the msgq command channel now have a timeout
+	(defaults to 4 seconds, modifiable as needed by modules).
+	Because of this, modules will no longer block indefinitely
+	if they are waiting for a message that is not sent for whatever
+	reason. (Trac #296, r2761)
+
+  87.   [func]		zhanglikun
+	lib/python/isc/notifyout: Add the feature of notify-out, when 
+	zone axfr/ixfr finishing, the server will notify its slaves.
+	(Trac #289, svn r2737)
+
+  86.   [func]		jerry
+    	bin/zonemgr: Added zone manager module. The zone manager is one 
+	of the co-operating processes of BIND10, which keeps track of 
+	timers and other information necessary for BIND10 to act as a 
+	slave. (Trac #215, svn r2737)
+
+  85.	[build]*	jinmei
+	Build programs using dynamic link by default.  A new configure
+	option --enable-static-link is provided to force static link for
+	executable programs.  Statically linked programs can be run on a
+	debugger more easily and would be convenient for developers.
+	(Trac #309, svn r2723)
+
 bind10-devel-20100812 released on August 12, 2010
 
-  84.   [bug]       jinmei, jerry
+  84.	[bug]		jinmei, jerry
 	This is a quick fix patch for the issue: AXFR fails half the 
 	time because of connection problems. xfrout client will make
 	a new connection every time. (Trac #299, svn r2697)
 
-  83.	[build]*
+  83.	[build]*	jreed
 	The configure --with-boost-lib option is removed. It was not
 	used since the build included ASIO. (svn r2684)
 
   82.	[func]		jinmei
-	bin/auth: Added -u option to allow the effective process user
+	bin/auth: Added -u option to change the effective process user
 	of the authoritative server after invocation.  The same option to
 	the boss process will be propagated to b10-auth, too.
 	(Trac #268, svn r2675)

Modified: branches/trac308/Makefile.am
==============================================================================
--- branches/trac308/Makefile.am (original)
+++ branches/trac308/Makefile.am Mon Sep 20 11:07:54 2010
@@ -28,6 +28,7 @@
 			c++/4.4\*/ext/\* \
 			c++/4.4\*/\*-\*/bits/\* \
 			boost/\* \
+			ext/asio/\* \
 			gtest/\* \
 			usr/include/\* \
 			tests/\* \

Modified: branches/trac308/README
==============================================================================
--- branches/trac308/README (original)
+++ branches/trac308/README Mon Sep 20 11:07:54 2010
@@ -17,7 +17,8 @@
 bus, b10-auth authoritative DNS server (with SQLite3 backend),
 b10-cmdctl remote control daemon, b10-cfgmgr configuration manager,
 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
 website at http://bind10.isc.org/

Modified: branches/trac308/configure.ac
==============================================================================
--- branches/trac308/configure.ac (original)
+++ branches/trac308/configure.ac Mon Sep 20 11:07:54 2010
@@ -32,14 +32,46 @@
 	])
 LDFLAGS=$LDFLAGS_SAVED
 
-# OS dependent compiler flags
+# allow building programs with static link.  we need to make it selective
+# because loadable modules cannot be statically linked.
+AC_ARG_ENABLE([static-link],
+AC_HELP_STRING([--enable-static-link],
+  [build programs with static link [[default=no]]]),
+  [enable_static_link=yes], [enable_static_link=no])
+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
+SET_ENV_LIBRARY_PATH=no
+ENV_LIBRARY_PATH=LD_LIBRARY_PATH
+
 case "$host" in
 *-solaris*)
 	# Solaris requires special definitions to get some standard libraries
 	# (e.g. getopt(3)) available with common used header files.
 	CPPFLAGS="$CPPFLAGS -D_XPG4_2 -D__EXTENSIONS__"
 	;;
+*-apple-darwin*)
+	# libtool doesn't work pefectly with Darwin: libtool embeds the
+	# final install path in dynamic libraries and our loadable python
+	# modules always refer to that path even if it's loaded within the
+	# source tree.  This prevents pre-install tests from working.
+	# To work around this problem we explicitly specify paths to dynamic
+	# libraries when we use them in the source tree.
+	SET_ENV_LIBRARY_PATH=yes
+	ENV_LIBRARY_PATH=DYLD_LIBRARY_PATH
+	;;
 esac
+AM_CONDITIONAL(SET_ENV_LIBRARY_PATH, test $SET_ENV_LIBRARY_PATH = yes)
+AC_SUBST(SET_ENV_LIBRARY_PATH)
+AC_SUBST(ENV_LIBRARY_PATH)
 
 m4_define([_AM_PYTHON_INTERPRETER_LIST], [python python3 python3.1])
 AC_ARG_WITH([pythonpath],
@@ -143,7 +175,6 @@
 # specify the default warning flags in CXXFLAGS and let specific modules
 # "override" the default.
 
-CXXFLAGS=-g
 werror_ok=0
 
 # SunStudio compiler requires special compiler options for boost
@@ -404,12 +435,15 @@
                  src/bin/xfrin/tests/Makefile
                  src/bin/xfrout/Makefile
                  src/bin/xfrout/tests/Makefile
+                 src/bin/zonemgr/Makefile
+                 src/bin/zonemgr/tests/Makefile
                  src/bin/usermgr/Makefile
                  src/lib/Makefile
                  src/lib/bench/Makefile
                  src/lib/bench/example/Makefile
                  src/lib/bench/tests/Makefile
                  src/lib/cc/Makefile
+                 src/lib/cc/tests/Makefile
                  src/lib/python/Makefile
                  src/lib/python/isc/Makefile
                  src/lib/python/isc/datasrc/Makefile
@@ -419,13 +453,17 @@
                  src/lib/python/isc/config/tests/Makefile
                  src/lib/python/isc/log/Makefile
                  src/lib/python/isc/log/tests/Makefile
+                 src/lib/python/isc/notify/Makefile
+                 src/lib/python/isc/notify/tests/Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
+                 src/lib/config/testdata/Makefile
                  src/lib/dns/Makefile
                  src/lib/dns/tests/Makefile
                  src/lib/dns/python/Makefile
                  src/lib/dns/python/tests/Makefile
                  src/lib/exceptions/Makefile
+                 src/lib/exceptions/tests/Makefile
                  src/lib/datasrc/Makefile
                  src/lib/datasrc/tests/Makefile
                  src/lib/xfr/Makefile
@@ -444,6 +482,10 @@
            src/bin/xfrout/xfrout.spec.pre
            src/bin/xfrout/tests/xfrout_test
            src/bin/xfrout/run_b10-xfrout.sh
+           src/bin/zonemgr/zonemgr.py
+           src/bin/zonemgr/zonemgr.spec.pre
+           src/bin/zonemgr/tests/zonemgr_test
+           src/bin/zonemgr/run_b10-zonemgr.sh
            src/bin/bind10/bind10.py
            src/bin/bind10/tests/bind10_test
            src/bin/bind10/run_bind10.sh
@@ -465,18 +507,22 @@
            src/lib/python/isc/config/tests/config_test
            src/lib/python/isc/cc/tests/cc_test
            src/lib/python/isc/log/tests/log_test
+           src/lib/python/isc/notify/tests/notify_out_test
            src/lib/dns/gen-rdatacode.py
            src/lib/python/bind10_config.py
            src/lib/dns/tests/testdata/gen-wiredata.py
            src/lib/cc/session_config.h.pre
+           src/lib/cc/tests/session_unittests_config.h
           ], [
            chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
            chmod +x src/bin/xfrin/run_b10-xfrin.sh
            chmod +x src/bin/xfrout/run_b10-xfrout.sh
+           chmod +x src/bin/zonemgr/run_b10-zonemgr.sh
            chmod +x src/bin/bind10/run_bind10.sh
            chmod +x src/bin/cmdctl/tests/cmdctl_test
            chmod +x src/bin/xfrin/tests/xfrin_test
            chmod +x src/bin/xfrout/tests/xfrout_test
+           chmod +x src/bin/zonemgr/tests/zonemgr_test
            chmod +x src/bin/bindctl/tests/bindctl_test
            chmod +x src/bin/bindctl/run_bindctl.sh
            chmod +x src/bin/loadzone/run_loadzone.sh
@@ -505,7 +551,6 @@
 Flags:
   DEFS:          $DEFS
   CPPFLAGS:      $CPPFLAGS
-  CFLAGS:        $CFLAGS
   CXXFLAGS:      $CXXFLAGS
   B10_CXXFLAGS:  $B10_CXXFLAGS
 dnl includes too

Modified: branches/trac308/doc/guide/bind10-guide.html
==============================================================================
--- branches/trac308/doc/guide/bind10-guide.html (original)
+++ branches/trac308/doc/guide/bind10-guide.html Mon Sep 20 11:07:54 2010
@@ -1,8 +1,8 @@
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>BIND 10 Guide</title><link rel="stylesheet" href="bind10-guide.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><meta name="description" content="This is the reference guide for BIND 10. The most up-to-date version of this document, along with other documents for BIND 10, can be found at ."></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" title="BIND 10 Guide"><div class="titlepage"><div><div><h1 class="title"><a name="id1168230342594"></a>BIND 10 Guide</h1></div><div><h2 class="subtitle">Administrator Reference for BIND 10</h2></div><div><p class="copyright">Copyright © 2010 Internet Systems Consortium, Inc.</p></div><div><div class="abstract" title="Abstract"><p class="title"><b>Abstract</b></p><p>This is the reference guide for BIND 10.</p><p>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>BIND 10 Guide</title><link rel="stylesheet" href="bind10-guide.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.75.2"><meta name="description" content="This is the reference guide for BIND 10. The most up-to-date version of this document, along with other documents for BIND 10, can be found at ."></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="book" title="BIND 10 Guide"><div class="titlepage"><div><div><h1 class="title"><a name="id1168230298903"></a>BIND 10 Guide</h1></div><div><h2 class="subtitle">Administrator Reference for BIND 10</h2></div><div><p class="copyright">Copyright © 2010 Internet Systems Consortium, Inc.</p></div><div><div class="abstract" title="Abstract"><p class="title"><b>Abstract</b></p><p>This is the reference guide for BIND 10.</p><p>
         The most up-to-date version of this document, along with other documents
         for BIND 10, can be found at
         <a class="ulink" href="http://bind10.isc.org/docs" target="_top">http://bind10.isc.org/docs</a>.
-      </p></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="#intro">1. Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230342718">Supported Platforms</a></span></dt><dt><span class="section"><a href="#id1168230342746">Required Software</a></span></dt><dt><span class="section"><a href="#starting_stopping">Starting and Stopping the Server</a></span></dt><dt><span class="section"><a href="#managing_once_running">Managing BIND 10</a></span></dt></dl></dd><dt><span class="chapter"><a href="#installation">2. Installation</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230328220">Building Requirements</a></span></dt><dt><span class="section"><a href="#quickstart">Quick start</a></span></dt><dt><span class="section"><a href="#install">Installation from source</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230328406">Download Tar File</a></span></dt><dt><s
 pan class="section"><a href="#id1168230328426">Retrieve from Subversion</a></span></dt><dt><span class="section"><a href="#id1168230328486">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230328584">Build</a></span></dt><dt><span class="section"><a href="#id1168230328599">Install</a></span></dt><dt><span class="section"><a href="#id1168230328622">Install Hierarchy</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#bind10">3. Starting BIND10 with <span class="command"><strong>bind10</strong></span></a></span></dt><dd><dl><dt><span class="section"><a href="#start">Starting BIND 10</a></span></dt></dl></dd><dt><span class="chapter"><a href="#msgq">4. Command channel</a></span></dt><dt><span class="chapter"><a href="#cfgmgr">5. Configuration manager</a></span></dt><dt><span class="chapter"><a href="#cmdctl">6. Remote control daemon</a></span></dt><dd><dl><dt><span class="section"><a href="#cmdctl.spec">Configuration specifi
 cation for b10-cmdctl</a></span></dt></dl></dd><dt><span class="chapter"><a href="#bindctl">7. Control and configure user interface</a></span></dt><dt><span class="chapter"><a href="#authserver">8. Authoritative Server</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230329190">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230329255">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230329285">Loading Master Zones Files</a></span></dt></dl></dd><dt><span class="chapter"><a href="#xfrin">9. Incoming Zone Transfers</a></span></dt><dt><span class="chapter"><a href="#xfrout">10. Outbound Zone Transfers</a></span></dt></dl></div><div class="chapter" title="Chapter 1. Introduction"><div class="titlepage"><div><div><h2 class="title"><a name="intro"></a>Chapter 1. Introduction</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230342718">S
 upported Platforms</a></span></dt><dt><span class="section"><a href="#id1168230342746">Required Software</a></span></dt><dt><span class="section"><a href="#starting_stopping">Starting and Stopping the Server</a></span></dt><dt><span class="section"><a href="#managing_once_running">Managing BIND 10</a></span></dt></dl></div><p>
+      </p></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter"><a href="#intro">1. Introduction</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230299028">Supported Platforms</a></span></dt><dt><span class="section"><a href="#id1168230299056">Required Software</a></span></dt><dt><span class="section"><a href="#starting_stopping">Starting and Stopping the Server</a></span></dt><dt><span class="section"><a href="#managing_once_running">Managing BIND 10</a></span></dt></dl></dd><dt><span class="chapter"><a href="#installation">2. Installation</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230284542">Building Requirements</a></span></dt><dt><span class="section"><a href="#quickstart">Quick start</a></span></dt><dt><span class="section"><a href="#install">Installation from source</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230284728">Download Tar File</a></span></dt><dt><s
 pan class="section"><a href="#id1168230284748">Retrieve from Subversion</a></span></dt><dt><span class="section"><a href="#id1168230284809">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230284906">Build</a></span></dt><dt><span class="section"><a href="#id1168230284921">Install</a></span></dt><dt><span class="section"><a href="#id1168230284946">Install Hierarchy</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#bind10">3. Starting BIND10 with <span class="command"><strong>bind10</strong></span></a></span></dt><dd><dl><dt><span class="section"><a href="#start">Starting BIND 10</a></span></dt></dl></dd><dt><span class="chapter"><a href="#msgq">4. Command channel</a></span></dt><dt><span class="chapter"><a href="#cfgmgr">5. Configuration manager</a></span></dt><dt><span class="chapter"><a href="#cmdctl">6. Remote control daemon</a></span></dt><dd><dl><dt><span class="section"><a href="#cmdctl.spec">Configuration specifi
 cation for b10-cmdctl</a></span></dt></dl></dd><dt><span class="chapter"><a href="#bindctl">7. Control and configure user interface</a></span></dt><dt><span class="chapter"><a href="#authserver">8. Authoritative Server</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230285515">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230285580">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230285610">Loading Master Zones Files</a></span></dt></dl></dd><dt><span class="chapter"><a href="#xfrin">9. Incoming Zone Transfers</a></span></dt><dt><span class="chapter"><a href="#xfrout">10. Outbound Zone Transfers</a></span></dt><dt><span class="chapter"><a href="#zonemgr">11. Secondary Manager</a></span></dt></dl></div><div class="chapter" title="Chapter 1. Introduction"><div class="titlepage"><div><div><h2 class="title"><a name="intro"></a>Chapter 1. Introduction</h2></div></div></div><div class="toc"><p><b>T
 able of Contents</b></p><dl><dt><span class="section"><a href="#id1168230299028">Supported Platforms</a></span></dt><dt><span class="section"><a href="#id1168230299056">Required Software</a></span></dt><dt><span class="section"><a href="#starting_stopping">Starting and Stopping the Server</a></span></dt><dt><span class="section"><a href="#managing_once_running">Managing BIND 10</a></span></dt></dl></div><p>
       BIND is the popular implementation of a DNS server, developer
       interfaces, and DNS tools.
       BIND 10 is a rewrite of BIND 9.  BIND 10 is written in C++ and Python
@@ -11,10 +11,10 @@
         This guide covers the experimental prototype version of
         BIND 10.
       </p></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
-        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
         authoritative DNS server.
-      </p></div><div class="section" title="Supported Platforms"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230342718"></a>Supported Platforms</h2></div></div></div><p>
+      </p></div><div class="section" title="Supported Platforms"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230299028"></a>Supported Platforms</h2></div></div></div><p>
   BIND 10 builds have been tested on Debian GNU/Linux 5,
   Ubuntu 9.10, NetBSD 5, Solaris 10, FreeBSD 7, and CentOS
   Linux 5.3.
@@ -24,16 +24,16 @@
 
         It is planned for BIND 10 to build, install and run on
         Windows and standard Unix-type platforms.
-      </p></div><div class="section" title="Required Software"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230342746"></a>Required Software</h2></div></div></div><p>
+      </p></div><div class="section" title="Required Software"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230299056"></a>Required Software</h2></div></div></div><p>
         BIND 10 requires Python 3.1.  Later versions may work, but Python
         3.1 is the minimum version which will work.
       </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
 	For this development prototype release, the only supported
 	data source backend is SQLite3. The authoritative server
 	requires SQLite 3.3.9 or newer.
-        The <span class="command"><strong>b10-xfrin</strong></span> and <span class="command"><strong>b10-xfrout</strong></span>
-        modules require the libpython3 library and the Python
-        _sqlite3.so module.
+	The <span class="command"><strong>b10-xfrin</strong></span>, <span class="command"><strong>b10-xfrout</strong></span>,
+	and <span class="command"><strong>b10-zonemgr</strong></span> modules require the
+	libpython3 library and the Python _sqlite3.so module.
       </p></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
           Some operating systems do not provide these dependencies
           in their default installation nor standard packages
@@ -83,6 +83,11 @@
 	      This process is used to handle transfer requests to
 	      send a local zone to a remote secondary server,
 	      when acting as a master server.
+            </li><li class="listitem">
+              <span class="command"><strong>b10-zonemgr</strong></span> —
+              Secondary manager.
+	      This process keeps track of timers and other
+              necessary information for BIND 10 to act as a slave server.
             </li></ul></div><p>
       </p><p>
 	These are ran automatically by <span class="command"><strong>bind10</strong></span>
@@ -116,7 +121,7 @@
       and, of course, DNS. These include detailed developer
       documentation and code examples.
 
-    </p></div><div class="chapter" title="Chapter 2. Installation"><div class="titlepage"><div><div><h2 class="title"><a name="installation"></a>Chapter 2. Installation</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230328220">Building Requirements</a></span></dt><dt><span class="section"><a href="#quickstart">Quick start</a></span></dt><dt><span class="section"><a href="#install">Installation from source</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230328406">Download Tar File</a></span></dt><dt><span class="section"><a href="#id1168230328426">Retrieve from Subversion</a></span></dt><dt><span class="section"><a href="#id1168230328486">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230328584">Build</a></span></dt><dt><span class="section"><a href="#id1168230328599">Install</a></span></dt><dt><span class="section"><a href="#id1168230328622">Install
  Hierarchy</a></span></dt></dl></dd></dl></div><div class="section" title="Building Requirements"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230328220"></a>Building Requirements</h2></div></div></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+    </p></div><div class="chapter" title="Chapter 2. Installation"><div class="titlepage"><div><div><h2 class="title"><a name="installation"></a>Chapter 2. Installation</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230284542">Building Requirements</a></span></dt><dt><span class="section"><a href="#quickstart">Quick start</a></span></dt><dt><span class="section"><a href="#install">Installation from source</a></span></dt><dd><dl><dt><span class="section"><a href="#id1168230284728">Download Tar File</a></span></dt><dt><span class="section"><a href="#id1168230284748">Retrieve from Subversion</a></span></dt><dt><span class="section"><a href="#id1168230284809">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230284906">Build</a></span></dt><dt><span class="section"><a href="#id1168230284921">Install</a></span></dt><dt><span class="section"><a href="#id1168230284946">Install
  Hierarchy</a></span></dt></dl></dd></dl></div><div class="section" title="Building Requirements"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230284542"></a>Building Requirements</h2></div></div></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
             Some operating systems have split their distribution packages into
             a run-time and a development package.  You will need to install
             the development package versions, which include header files and
@@ -176,14 +181,14 @@
         the Subversion code revision control system or as a downloadable
         tar file. It may also be available in pre-compiled ready-to-use
         packages from operating system vendors.
-      </p><div class="section" title="Download Tar File"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328406"></a>Download Tar File</h3></div></div></div><p>
+      </p><div class="section" title="Download Tar File"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230284728"></a>Download Tar File</h3></div></div></div><p>
           Downloading a release tar file is the recommended method to
           obtain the source code.
         </p><p>
           The BIND 10 releases are available as tar file downloads from
           <a class="ulink" href="ftp://ftp.isc.org/isc/bind10/" target="_top">ftp://ftp.isc.org/isc/bind10/</a>.
           Periodic development snapshots may also be available.
-        </p></div><div class="section" title="Retrieve from Subversion"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328426"></a>Retrieve from Subversion</h3></div></div></div><p>
+        </p></div><div class="section" title="Retrieve from Subversion"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230284748"></a>Retrieve from Subversion</h3></div></div></div><p>
           Downloading this "bleeding edge" code is recommended only for
           developers or advanced users.  Using development code in a production
           environment is not recommended.
@@ -215,7 +220,7 @@
           <span class="command"><strong>autoheader</strong></span>,
           <span class="command"><strong>automake</strong></span>,
           and related commands.
-        </p></div><div class="section" title="Configure before the build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328486"></a>Configure before the build</h3></div></div></div><p>
+        </p></div><div class="section" title="Configure before the build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230284809"></a>Configure before the build</h3></div></div></div><p>
           BIND 10 uses the GNU Build System to discover build environment
           details.
           To generate the makefiles using the defaults, simply run:
@@ -246,16 +251,16 @@
         </p><p>
           If the configure fails, it may be due to missing or old
           dependencies.
-        </p></div><div class="section" title="Build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328584"></a>Build</h3></div></div></div><p>
+        </p></div><div class="section" title="Build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230284906"></a>Build</h3></div></div></div><p>
     After the configure step is complete, to build the executables
     from the C++ code and prepare the Python scripts, run:
 
           </p><pre class="screen">$ <strong class="userinput"><code>make</code></strong></pre><p>
-        </p></div><div class="section" title="Install"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328599"></a>Install</h3></div></div></div><p>
+        </p></div><div class="section" title="Install"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230284921"></a>Install</h3></div></div></div><p>
           To install the BIND 10 executables, support files,
           and documentation, run:
           </p><pre class="screen">$ <strong class="userinput"><code>make install</code></strong></pre><p>
-        </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The install step may require superuser privileges.</p></div></div><div class="section" title="Install Hierarchy"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328622"></a>Install Hierarchy</h3></div></div></div><p>
+        </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>The install step may require superuser privileges.</p></div></div><div class="section" title="Install Hierarchy"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230284946"></a>Install Hierarchy</h3></div></div></div><p>
           The following is the layout of the complete BIND 10 installation:
           </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
                 <code class="filename">bin/</code> —
@@ -307,8 +312,9 @@
       The <span class="command"><strong>bind10</strong></span> master process will also start up
       <span class="command"><strong>b10-cmdctl</strong></span> for admins to communicate with the
       system, <span class="command"><strong>b10-auth</strong></span> for Authoritative DNS service,
-      <span class="command"><strong>b10-xfrin</strong></span> for inbound DNS zone transfers.
-      and <span class="command"><strong>b10-xfrout</strong></span> for outbound DNS zone transfers.
+      <span class="command"><strong>b10-xfrin</strong></span> for inbound DNS zone transfers,
+      <span class="command"><strong>b10-xfrout</strong></span> for outbound DNS zone transfers,
+      and <span class="command"><strong>b10-zonemgr</strong></span> for secondary service.
     </p><div class="section" title="Starting BIND 10"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="start"></a>Starting BIND 10</h2></div></div></div><p>
         To start the BIND 10 service, simply run <span class="command"><strong>bind10</strong></span>.
         Run it with the <code class="option">--verbose</code> switch to
@@ -467,7 +473,7 @@
       the details and relays (over a <span class="command"><strong>b10-msgq</strong></span> command
       channel) the configuration on to the specified module.
     </p><p>
-    </p></div><div class="chapter" title="Chapter 8. Authoritative Server"><div class="titlepage"><div><div><h2 class="title"><a name="authserver"></a>Chapter 8. Authoritative Server</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230329190">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230329255">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230329285">Loading Master Zones Files</a></span></dt></dl></div><p>
+    </p></div><div class="chapter" title="Chapter 8. Authoritative Server"><div class="titlepage"><div><div><h2 class="title"><a name="authserver"></a>Chapter 8. Authoritative Server</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="#id1168230285515">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230285580">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230285610">Loading Master Zones Files</a></span></dt></dl></div><p>
       The <span class="command"><strong>b10-auth</strong></span> is the authoritative DNS server.
       It supports EDNS0 and DNSSEC. It supports IPv6.
       Normally it is started by the <span class="command"><strong>bind10</strong></span> master
@@ -475,7 +481,7 @@
     </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
       This development prototype release listens on all interfaces
       and the non-standard port 5300.
-    </p></div><div class="section" title="Server Configurations"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230329190"></a>Server Configurations</h2></div></div></div><p>
+    </p></div><div class="section" title="Server Configurations"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285515"></a>Server Configurations</h2></div></div></div><p>
         <span class="command"><strong>b10-auth</strong></span> is configured via the
         <span class="command"><strong>b10-cfgmgr</strong></span> configuration manager.
         The module name is <span class="quote">“<span class="quote">Auth</span>”</span>.
@@ -495,7 +501,7 @@
         </p><div class="variablelist"><dl><dt><span class="term">shutdown</span></dt><dd>Stop the authoritative DNS server.
               </dd></dl></div><p>
 
-      </p></div><div class="section" title="Data Source Backends"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230329255"></a>Data Source Backends</h2></div></div></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+      </p></div><div class="section" title="Data Source Backends"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285580"></a>Data Source Backends</h2></div></div></div><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
         For the development prototype release, <span class="command"><strong>b10-auth</strong></span>
         only supports the SQLite3 data source backend.
         Upcoming versions will be able to use multiple different
@@ -508,7 +514,7 @@
         The default is <code class="filename">/usr/local/var/</code>.)
   This data file location may be changed by defining the
   <span class="quote">“<span class="quote">database_file</span>”</span> configuration.
-      </p></div><div class="section" title="Loading Master Zones Files"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230329285"></a>Loading Master Zones Files</h2></div></div></div><p>
+      </p></div><div class="section" title="Loading Master Zones Files"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="id1168230285610"></a>Loading Master Zones Files</h2></div></div></div><p>
         RFC 1035 style DNS master zone files may imported
         into a BIND 10 data source by using the
         <span class="command"><strong>b10-loadzone</strong></span> utility.
@@ -544,12 +550,12 @@
       transfer. When received, it is stored in the BIND 10
       data store, and its records can be served by
       <span class="command"><strong>b10-auth</strong></span>.
-      This allows the BIND 10 server to provide
-      <span class="quote">“<span class="quote">secondary</span>”</span> service.
+      In combination with <span class="command"><strong>b10-zonemgr</strong></span> (for
+      automated SOA checks), this allows the BIND 10 server to
+      provide <span class="quote">“<span class="quote">secondary</span>”</span> service.
     </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
      The current development release of BIND 10 only supports
      AXFR. (IXFR is not supported.) 
-     It also does not yet support automated SOA checks.
     </p></div><p>
        To manually trigger a zone transfer to retrieve a remote zone,
        you may use the <span class="command"><strong>bindctl</strong></span> utility.
@@ -564,9 +570,24 @@
       sends the zone.
       This is used to provide master DNS service to share zones
       to secondary name servers.
+      The <span class="command"><strong>b10-xfrout</strong></span> is also used to send
+      NOTIFY messages to slaves.
     </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
      The current development release of BIND 10 only supports
      AXFR. (IXFR is not supported.) 
-     It also does not yet support NOTIFY.
      Access control is not yet provided.
+    </p></div></div><div class="chapter" title="Chapter 11. Secondary Manager"><div class="titlepage"><div><div><h2 class="title"><a name="zonemgr"></a>Chapter 11. Secondary Manager</h2></div></div></div><p>
+      The <span class="command"><strong>b10-zonemgr</strong></span> process is started by
+      <span class="command"><strong>bind10</strong></span>.
+      It keeps track of SOA refresh, retry, and expire timers
+      and other details for BIND 10 to perform as a slave.
+      When the <span class="command"><strong>b10-auth</strong></span> authoritative DNS server
+      receives a NOTIFY message, <span class="command"><strong>b10-zonemgr</strong></span>
+      may tell <span class="command"><strong>b10-xfrin</strong></span> to do a refresh
+      to start an inbound zone transfer.
+      The secondary manager resets its counters when a new zone is
+      transferred in.
+    </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
+     Access control (such as allowing notifies) is not yet provided.
+     The primary/secondary service is not yet complete.
     </p></div></div></div></body></html>

Modified: branches/trac308/doc/guide/bind10-guide.xml
==============================================================================
--- branches/trac308/doc/guide/bind10-guide.xml (original)
+++ branches/trac308/doc/guide/bind10-guide.xml Mon Sep 20 11:07:54 2010
@@ -42,7 +42,7 @@
 
     <note>
       <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
         authoritative DNS server.
       </para>
@@ -74,9 +74,9 @@
 	For this development prototype release, the only supported
 	data source backend is SQLite3. The authoritative server
 	requires SQLite 3.3.9 or newer.
-        The <command>b10-xfrin</command> and <command>b10-xfrout</command>
-        modules require the libpython3 library and the Python
-        _sqlite3.so module.
+	The <command>b10-xfrin</command>, <command>b10-xfrout</command>,
+	and <command>b10-zonemgr</command> modules require the
+	libpython3 library and the Python _sqlite3.so module.
       </para></note>
 <!-- TODO: this will change ... -->
 
@@ -165,6 +165,15 @@
             </simpara>
           </listitem>
 
+          <listitem>
+            <simpara>
+              <command>b10-zonemgr</command> —
+              Secondary manager.
+	      This process keeps track of timers and other
+              necessary information for BIND 10 to act as a slave server.
+            </simpara>
+          </listitem>
+
         </itemizedlist>
       </para>
 
@@ -650,8 +659,9 @@
       The <command>bind10</command> master process will also start up
       <command>b10-cmdctl</command> for admins to communicate with the
       system, <command>b10-auth</command> for Authoritative DNS service,
-      <command>b10-xfrin</command> for inbound DNS zone transfers.
-      and <command>b10-xfrout</command> for outbound DNS zone transfers.
+      <command>b10-xfrin</command> for inbound DNS zone transfers,
+      <command>b10-xfrout</command> for outbound DNS zone transfers,
+      and <command>b10-zonemgr</command> for secondary service.
     </para>
 
     <section id="start">
@@ -1173,14 +1183,14 @@
       transfer. When received, it is stored in the BIND 10
       data store, and its records can be served by
       <command>b10-auth</command>.
-      This allows the BIND 10 server to provide
-      <quote>secondary</quote> service.
+      In combination with <command>b10-zonemgr</command> (for
+      automated SOA checks), this allows the BIND 10 server to
+      provide <quote>secondary</quote> service.
     </para>
 
     <note><simpara>
      The current development release of BIND 10 only supports
      AXFR. (IXFR is not supported.) 
-     It also does not yet support automated SOA checks.
     </simpara></note>
 
     <para>
@@ -1204,12 +1214,13 @@
       sends the zone.
       This is used to provide master DNS service to share zones
       to secondary name servers.
+      The <command>b10-xfrout</command> is also used to send
+      NOTIFY messages to slaves.
     </para>
 
     <note><simpara>
      The current development release of BIND 10 only supports
      AXFR. (IXFR is not supported.) 
-     It also does not yet support NOTIFY.
      Access control is not yet provided.
     </simpara></note>
 
@@ -1226,6 +1237,31 @@
 
   </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 -->
 
   <!-- <index>    <title>Index</title> </index> -->

Modified: branches/trac308/src/bin/Makefile.am
==============================================================================
--- branches/trac308/src/bin/Makefile.am (original)
+++ branches/trac308/src/bin/Makefile.am Mon Sep 20 11:07:54 2010
@@ -1,1 +1,1 @@
-SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout usermgr
+SUBDIRS = bind10 bindctl cfgmgr loadzone msgq host cmdctl auth xfrin xfrout usermgr zonemgr

Modified: branches/trac308/src/bin/auth/Makefile.am
==============================================================================
--- branches/trac308/src/bin/auth/Makefile.am (original)
+++ branches/trac308/src/bin/auth/Makefile.am Mon Sep 20 11:07:54 2010
@@ -7,6 +7,10 @@
 AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
@@ -50,13 +54,13 @@
 b10_auth_SOURCES += change_user.cc change_user.h
 b10_auth_SOURCES += common.h
 b10_auth_SOURCES += main.cc
-b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-b10_auth_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
-b10_auth_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
-b10_auth_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
-b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
-b10_auth_LDADD += $(top_builddir)/src/bin/auth/libasio_link.a
-b10_auth_LDADD += $(top_builddir)/src/lib/xfr/.libs/libxfr.a
+b10_auth_LDADD =  $(top_builddir)/src/lib/datasrc/libdatasrc.la
+b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+b10_auth_LDADD += libasio_link.a
+b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
 b10_auth_LDADD += $(SQLITE_LIBS)
 
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir

Modified: branches/trac308/src/bin/auth/asio_link.cc
==============================================================================
--- branches/trac308/src/bin/auth/asio_link.cc (original)
+++ branches/trac308/src/bin/auth/asio_link.cc Mon Sep 20 11:07:54 2010
@@ -67,7 +67,7 @@
 // Note: this implementation is optimized for the case where this object
 // 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
-// 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.
 class TCPEndpoint : public IOEndpoint {
 public:
@@ -563,7 +563,7 @@
 
 asio::io_service&
 IOService::get_io_service() {
-    return impl_->io_service_;
+    return (impl_->io_service_);
 }
 
 void

Modified: branches/trac308/src/bin/auth/asio_link.h
==============================================================================
--- branches/trac308/src/bin/auth/asio_link.h (original)
+++ branches/trac308/src/bin/auth/asio_link.h Mon Sep 20 11:07:54 2010
@@ -207,7 +207,7 @@
     /// will be thrown.
     ///
     /// 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
     /// standard exception will be thrown.
     ///

Modified: branches/trac308/src/bin/auth/auth_srv.cc
==============================================================================
--- branches/trac308/src/bin/auth/auth_srv.cc (original)
+++ branches/trac308/src/bin/auth/auth_srv.cc Mon Sep 20 11:07:54 2010
@@ -68,7 +68,7 @@
 public:
     AuthSrvImpl(const bool use_cache, AbstractXfroutClient& xfrout_client);
     ~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,
                             MessageRenderer& response_renderer);
@@ -336,7 +336,6 @@
 
     return (true);
 }
-
 
 bool
 AuthSrvImpl::processAxfrQuery(const IOMessage& io_message, Message& message,
@@ -433,32 +432,32 @@
     static const string command_template_start =
         "{\"command\": [\"notify\", {\"zone_name\" : \"";
     static const string command_template_master = "\", \"master\" : \"";
-    static const string command_template_rrclass = "\", \"rrclass\" : \"";
+    static const string command_template_rrclass = "\", \"zone_class\" : \"";
     static const string command_template_end = "\"}]}";
 
     try {
-        ElementPtr notify_command = Element::fromJSON(
+        ConstElementPtr notify_command = Element::fromJSON(
                 command_template_start + question->getName().toText() + 
                 command_template_master + remote_ip_address +
                 command_template_rrclass + question->getClass().toText() +
                 command_template_end);
         const unsigned int seq =
-            xfrin_session_->group_sendmsg(notify_command, "Xfrin",
+            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);
         int rcode;
         parsed_answer = parseAnswer(rcode, answer);
         if (rcode != 0) {
             if (verbose_mode_) {
-                cerr << "[b10-auth] failed to notify Xfrin: "
+                cerr << "[b10-auth] failed to notify Zonemgr: "
                      << parsed_answer->str() << endl; 
             }
             return (false);
         }
     } catch (const Exception& ex) {
         if (verbose_mode_) {
-            cerr << "[b10-auth] failed to notify Xfrin: " << ex.what() << endl;
+            cerr << "[b10-auth] failed to notify Zonemgr: " << ex.what() << endl;
         }
         return (false);
     }
@@ -470,19 +469,17 @@
     return (true);
 }
 
-ElementPtr
-AuthSrvImpl::setDbFile(const isc::data::ElementPtr config) {
-    ElementPtr answer = isc::config::createAnswer();
-    ElementPtr final;
+ConstElementPtr
+AuthSrvImpl::setDbFile(ConstElementPtr config) {
+    ConstElementPtr answer = isc::config::createAnswer();
 
     if (config && config->contains("database_file")) {
         db_file_ = config->get("database_file")->stringValue();
-        final = config;
     } else if (config_session_ != NULL) {
         bool is_default;
         string item("database_file");
-        ElementPtr value = config_session_->getValue(is_default, item);
-        final = Element::createMap();
+        ConstElementPtr value = config_session_->getValue(is_default, item);
+        ElementPtr final = Element::createMap();
 
         // If the value is the default, and we are running from
         // a specific directory ('from build'), we need to use
@@ -496,6 +493,7 @@
                                     "/bind10_zones.sqlite3");
         }
         final->set(item, value);
+        config = final;
 
         db_file_ = value->stringValue();
     } else {
@@ -512,7 +510,7 @@
     // fail, while acquiring resources in the RAII manner.  We then perform
     // delete and swap operations which should not fail.
     DataSrcPtr datasrc_ptr(DataSrcPtr(new Sqlite3DataSrc));
-    datasrc_ptr->init(final);
+    datasrc_ptr->init(config);
     data_sources_.addDataSrc(datasrc_ptr);
 
     // The following code should be exception free.
@@ -524,19 +522,16 @@
     return (answer);
 }
 
-ElementPtr
-AuthSrv::updateConfig(isc::data::ElementPtr new_config) {
+ConstElementPtr
+AuthSrv::updateConfig(ConstElementPtr new_config) {
     try {
         // the ModuleCCSession has already checked if we have
         // the correct ElementPtr type as specified in our .spec file
-        ElementPtr answer = isc::config::createAnswer();
-        answer = impl_->setDbFile(new_config);
-
-        return answer;
+        return (impl_->setDbFile(new_config));
     } catch (const isc::Exception& error) {
         if (impl_->verbose_mode_) {
             cerr << "[b10-auth] error: " << error.what() << endl;
         }
-        return isc::config::createAnswer(1, error.what());
-    }
-}
+        return (isc::config::createAnswer(1, error.what()));
+    }
+}

Modified: branches/trac308/src/bin/auth/auth_srv.h
==============================================================================
--- branches/trac308/src/bin/auth/auth_srv.h (original)
+++ branches/trac308/src/bin/auth/auth_srv.h Mon Sep 20 11:07:54 2010
@@ -69,7 +69,7 @@
                         isc::dns::MessageRenderer& response_renderer);
     void setVerbose(bool on);
     bool getVerbose() const;
-    isc::data::ElementPtr updateConfig(isc::data::ElementPtr config);
+    isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
     isc::config::ModuleCCSession* configSession() const;
     void setConfigSession(isc::config::ModuleCCSession* config_session);
 

Modified: branches/trac308/src/bin/auth/b10-auth.8
==============================================================================
--- branches/trac308/src/bin/auth/b10-auth.8 (original)
+++ branches/trac308/src/bin/auth/b10-auth.8 Mon Sep 20 11:07:54 2010
@@ -137,6 +137,7 @@
 \fBb10-cmdctl\fR(8),
 \fBb10-loadzone\fR(8),
 \fBb10-msgq\fR(8),
+\fBb10-zonemgr\fR(8),
 \fBbind10\fR(8),
 BIND 10 Guide\&.
 .SH "HISTORY"

Modified: branches/trac308/src/bin/auth/b10-auth.xml
==============================================================================
--- branches/trac308/src/bin/auth/b10-auth.xml (original)
+++ branches/trac308/src/bin/auth/b10-auth.xml Mon Sep 20 11:07:54 2010
@@ -201,6 +201,9 @@
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
+        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.

Modified: branches/trac308/src/bin/auth/main.cc
==============================================================================
--- branches/trac308/src/bin/auth/main.cc (original)
+++ branches/trac308/src/bin/auth/main.cc Mon Sep 20 11:07:54 2010
@@ -66,24 +66,24 @@
 
 asio_link::IOService* io_service;
 
-ElementPtr
-my_config_handler(ElementPtr new_config) {
-    return auth_server->updateConfig(new_config);
-}
-
-ElementPtr
-my_command_handler(const string& command, const ElementPtr args) {
-    ElementPtr answer = createAnswer();
+ConstElementPtr
+my_config_handler(ConstElementPtr new_config) {
+    return (auth_server->updateConfig(new_config));
+}
+
+ConstElementPtr
+my_command_handler(const string& command, ConstElementPtr args) {
+    ConstElementPtr answer = createAnswer();
 
     if (command == "print_message") {
         cout << args << endl;
         /* let's add that message to our answer as well */
-        answer->get("result")->add(args);
+        answer = createAnswer(0, args);
     } else if (command == "shutdown") {
         io_service->stop();
     }
     
-    return answer;
+    return (answer);
 }
 
 void

Modified: branches/trac308/src/bin/auth/tests/Makefile.am
==============================================================================
--- branches/trac308/src/bin/auth/tests/Makefile.am (original)
+++ branches/trac308/src/bin/auth/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -4,6 +4,10 @@
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
 
 CLEANFILES = *.gcno *.gcda
 
@@ -22,13 +26,13 @@
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
-run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns++.a
-run_unittests_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
+run_unittests_LDADD +=  $(top_builddir)/src/lib/datasrc/libdatasrc.la
+run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 run_unittests_LDADD += $(top_builddir)/src/bin/auth/libasio_link.a
-run_unittests_LDADD += $(top_builddir)/src/lib/xfr/.libs/libxfr.a
+run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
 endif
 
 noinst_PROGRAMS = $(TESTS)

Modified: branches/trac308/src/bin/auth/tests/auth_srv_unittest.cc
==============================================================================
--- branches/trac308/src/bin/auth/tests/auth_srv_unittest.cc (original)
+++ branches/trac308/src/bin/auth/tests/auth_srv_unittest.cc Mon Sep 20 11:07:54 2010
@@ -85,24 +85,27 @@
         {}
         virtual void establish(const char* socket_file);
         virtual void disconnect();
-        virtual int group_sendmsg(ElementPtr msg, string group,
+        virtual int group_sendmsg(ConstElementPtr msg, string group,
                                   string instance, string to);
-        virtual bool group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+        virtual bool group_recvmsg(ConstElementPtr& envelope,
+                                   ConstElementPtr& msg,
                                    bool nonblock, int seq);
         virtual void subscribe(string group, string instance);
         virtual void unsubscribe(string group, string instance);
         virtual void startRead(boost::function<void()> read_callback);
-        virtual int reply(ElementPtr& envelope, ElementPtr& newmsg);
-        virtual bool hasQueuedMsgs();
-
-        void setMessage(ElementPtr msg) { msg_ = msg; }
+        virtual int reply(ConstElementPtr envelope, ConstElementPtr newmsg);
+        virtual bool hasQueuedMsgs() const;
+        virtual void setTimeout(size_t timeout UNUSED_PARAM) {};
+        virtual size_t getTimeout() const { return 0; };
+
+        void setMessage(ConstElementPtr msg) { msg_ = msg; }
         void disableSend() { send_ok_ = false; }
         void disableReceive() { receive_ok_ = false; }
 
-        ElementPtr sent_msg;
+        ConstElementPtr sent_msg;
         string msg_destination;
     private:
-        ElementPtr msg_;
+        ConstElementPtr msg_;
         bool send_ok_;
         bool receive_ok_;
     };
@@ -172,19 +175,19 @@
 {}
 
 int
-AuthSrvTest::MockSession::reply(ElementPtr& envelope UNUSED_PARAM,
-                                ElementPtr& newmsg UNUSED_PARAM)
+AuthSrvTest::MockSession::reply(ConstElementPtr envelope UNUSED_PARAM,
+                                ConstElementPtr newmsg UNUSED_PARAM)
 {
     return (-1);
 }
 
 bool
-AuthSrvTest::MockSession::hasQueuedMsgs() {
+AuthSrvTest::MockSession::hasQueuedMsgs() const {
     return (false);
 }
 
 int
-AuthSrvTest::MockSession::group_sendmsg(ElementPtr msg, string group,
+AuthSrvTest::MockSession::group_sendmsg(ConstElementPtr msg, string group,
                                         string instance UNUSED_PARAM,
                                         string to UNUSED_PARAM)
 {
@@ -198,8 +201,8 @@
 }
 
 bool
-AuthSrvTest::MockSession::group_recvmsg(ElementPtr& envelope UNUSED_PARAM,
-                                        ElementPtr& msg,
+AuthSrvTest::MockSession::group_recvmsg(ConstElementPtr& envelope UNUSED_PARAM,
+                                        ConstElementPtr& msg,
                                         bool nonblock UNUSED_PARAM,
                                         int seq UNUSED_PARAM)
 {
@@ -534,14 +537,15 @@
 
     // An internal command message should have been created and sent to an
     // external module.  Check them.
-    EXPECT_EQ("Xfrin", notify_session.msg_destination);
+    EXPECT_EQ("Zonemgr", notify_session.msg_destination);
     EXPECT_EQ("notify",
               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(DEFAULT_REMOTE_ADDRESS,
               notify_args->get("master")->stringValue());
-    EXPECT_EQ("IN", notify_args->get("rrclass")->stringValue());
+    EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
 
     // On success, the server should return a response to the notify.
     headerCheck(parse_message, default_qid, Rcode::NOERROR(),
@@ -565,8 +569,9 @@
 
     // Other conditions should be the same, so simply confirm the RR class is
     // set correctly.
-    ElementPtr notify_args = notify_session.sent_msg->get("command")->get(1);
-    EXPECT_EQ("CH", notify_args->get("rrclass")->stringValue());
+    ConstElementPtr notify_args =
+        notify_session.sent_msg->get("command")->get(1);
+    EXPECT_EQ("CH", notify_args->get("zone_class")->stringValue());
 }
 
 TEST_F(AuthSrvTest, notifyEmptyQuestion) {
@@ -693,12 +698,12 @@
 updateConfig(AuthSrv* server, const char* const dbfile,
              const bool expect_success)
 {
-    const ElementPtr config_answer =
+    ConstElementPtr config_answer =
         server->updateConfig(Element::fromJSON(dbfile));
     EXPECT_EQ(Element::map, config_answer->getType());
     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(expect_success ? 0 : 1, result->get(0)->intValue());
 }

Modified: branches/trac308/src/bin/bind10/bind10.8
==============================================================================
--- branches/trac308/src/bin/bind10/bind10.8 (original)
+++ branches/trac308/src/bin/bind10/bind10.8 Mon Sep 20 11:07:54 2010
@@ -101,6 +101,8 @@
 \fBb10-cmdctl\fR(8),
 \fBb10-msgq\fR(8),
 \fBb10-xfrin\fR(8),
+\fBb10-xfrout\fR(8),
+\fBb10-zonemgr\fR(8),
 BIND 10 Guide\&.
 .SH "HISTORY"
 .PP

Modified: branches/trac308/src/bin/bind10/bind10.py.in
==============================================================================
--- branches/trac308/src/bin/bind10/bind10.py.in (original)
+++ branches/trac308/src/bin/bind10/bind10.py.in Mon Sep 20 11:07:54 2010
@@ -18,7 +18,7 @@
 """\
 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 that exit.
 
@@ -65,7 +65,9 @@
 import isc.cc
 
 # 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:
     """
@@ -398,6 +400,26 @@
             sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % 
                              xfrind.pid)
 
+        # start b10-zonemgr
+        zonemgr_args = ['b10-zonemgr']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-zonemgr\n")
+            zonemgr_args += ['-v']
+        try:
+            zonemgr = ProcessInfo("b10-zonemgr", zonemgr_args,
+                                 c_channel_env)
+        except Exception as e:
+            c_channel.process.kill()
+            bind_cfgd.process.kill()
+            xfrout.process.kill()
+            auth.process.kill()
+            xfrind.process.kill()
+            return "Unable to start b10-zonemgr; " + str(e)
+        self.processes[zonemgr.pid] = zonemgr 
+        if self.verbose:
+            sys.stdout.write("[bind10] Started b10-zonemgr(PID %d)\n" % 
+                             zonemgr.pid)
+
         # start the b10-cmdctl
         # XXX: we hardcode port 8080
         cmdctl_args = ['b10-cmdctl']
@@ -413,6 +435,7 @@
             xfrout.process.kill()
             auth.process.kill()
             xfrind.process.kill()
+            zonemgr.process.kill()
             return "Unable to start b10-cmdctl; " + str(e)
         self.processes[cmd_ctrld.pid] = cmd_ctrld
         if self.verbose:
@@ -431,6 +454,7 @@
         self.cc_session.group_sendmsg(cmd, "Boss", "Auth")
         self.cc_session.group_sendmsg(cmd, "Boss", "Xfrout")
         self.cc_session.group_sendmsg(cmd, "Boss", "Xfrin")
+        self.cc_session.group_sendmsg(cmd, "Boss", "Zonemgr")
 
     def stop_process(self, process):
         """Stop the given process, friendly-like."""
@@ -605,7 +629,7 @@
 
 
     # Parse any command-line options.
-    parser = OptionParser(version=__version__)
+    parser = OptionParser(version=VERSION)
     parser.add_option("-a", "--address", dest="address", type="string",
                       action="callback", callback=check_addr, default='',
                       help="address the b10-auth daemon will use (default: listen on all addresses)")
@@ -658,7 +682,7 @@
 
     # Announce startup.
     if options.verbose:
-        sys.stdout.write("BIND 10 %s\n" % __version__)
+        sys.stdout.write("%s\n" % VERSION)
 
     # TODO: set process name, perhaps by:
     #       http://code.google.com/p/procname/
@@ -713,7 +737,12 @@
 
         for fd in rlist + xlist:
             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:
                 os.read(wakeup_fd, 32)
 

Modified: branches/trac308/src/bin/bind10/bind10.xml
==============================================================================
--- branches/trac308/src/bin/bind10/bind10.xml (original)
+++ branches/trac308/src/bin/bind10/bind10.xml Mon Sep 20 11:07:54 2010
@@ -189,6 +189,12 @@
       <citerefentry>
         <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-xfrout</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
+        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
     </para>
   </refsect1>

Modified: branches/trac308/src/bin/bind10/run_bind10.sh.in
==============================================================================
--- branches/trac308/src/bin/bind10/run_bind10.sh.in (original)
+++ branches/trac308/src/bin/bind10/run_bind10.sh.in Mon Sep 20 11:07:54 2010
@@ -20,12 +20,19 @@
 
 BIND10_PATH=@abs_top_builddir@/src/bin/bind10
 
-PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:$PATH
+PATH=@abs_top_builddir@/src/bin/msgq:@abs_top_builddir@/src/bin/auth:@abs_top_builddir@/src/bin/cfgmgr:@abs_top_builddir@/src/bin/cmdctl:@abs_top_builddir@/src/bin/xfrin:@abs_top_builddir@/src/bin/xfrout:@abs_top_builddir@/src/bin/zonemgr:$PATH
 export PATH
 
 PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs:@abs_top_builddir@/src/lib/xfr/.libs
-#PYTHONPATH=@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/xfr/.libs
 export PYTHONPATH
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+SET_ENV_LIBRARY_PATH=@SET_ENV_LIBRARY_PATH@
+if test $SET_ENV_LIBRARY_PATH = yes; then
+	@ENV_LIBRARY_PATH@=@abs_top_builddir@/src/lib/dns/.libs:@abs_top_builddir@/src/lib/exceptions/.libs:$@ENV_LIBRARY_PATH@
+	export @ENV_LIBRARY_PATH@
+fi
 
 B10_FROM_SOURCE=@abs_top_srcdir@
 export B10_FROM_SOURCE

Modified: branches/trac308/src/bin/bind10/tests/Makefile.am
==============================================================================
--- branches/trac308/src/bin/bind10/tests/Makefile.am (original)
+++ branches/trac308/src/bin/bind10/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -8,5 +8,5 @@
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/bin/bindctl/bindcmd.py
==============================================================================
--- branches/trac308/src/bin/bindctl/bindcmd.py (original)
+++ branches/trac308/src/bin/bindctl/bindcmd.py Mon Sep 20 11:07:54 2010
@@ -35,7 +35,6 @@
 import getpass
 from hashlib import sha1
 import csv
-import json
 import pwd
 import getpass
 

Modified: branches/trac308/src/bin/bindctl/tests/Makefile.am
==============================================================================
--- branches/trac308/src/bin/bindctl/tests/Makefile.am (original)
+++ branches/trac308/src/bin/bindctl/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -8,5 +8,5 @@
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/bin/cfgmgr/tests/Makefile.am
==============================================================================
--- branches/trac308/src/bin/cfgmgr/tests/Makefile.am (original)
+++ branches/trac308/src/bin/cfgmgr/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -9,5 +9,5 @@
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr \
-	$(PYCOVERAGE) $(abs_builddir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_builddir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/bin/cmdctl/cmdctl.py.in
==============================================================================
--- branches/trac308/src/bin/cmdctl/cmdctl.py.in (original)
+++ branches/trac308/src/bin/cmdctl/cmdctl.py.in Mon Sep 20 11:07:54 2010
@@ -380,6 +380,7 @@
     def send_command(self, module_name, command_name, params = None):
         '''Send the command from bindctl to proper module. '''
         errstr = 'unknown error'
+        answer = None
         if self._verbose:
             self.log_info("Begin send command '%s' to module '%s'" %(command_name, module_name))
 
@@ -390,7 +391,10 @@
             msg = ccsession.create_command(command_name, params)
             seq = self._cc.group_sendmsg(msg, module_name)
             #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:
             self.log_info("Finish send command '%s' to module '%s'" % (command_name, module_name))
@@ -410,7 +414,6 @@
             except ccsession.ModuleCCSessionError as mcse:
                 errstr = str("Error in ccsession answer:") + str(mcse)
                 self.log_info(errstr)
-        
         return 1, {'error': errstr}
     
     def log_info(self, msg):
@@ -602,6 +605,9 @@
     except isc.cc.SessionError as err:
         sys.stderr.write("[b10-cmdctl] Error creating b10-cmdctl, "
                          "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:
         sys.stderr.write("[b10-cmdctl] exit from Cmdctl\n")
     except CmdctlException as err:

Modified: branches/trac308/src/bin/cmdctl/tests/Makefile.am
==============================================================================
--- branches/trac308/src/bin/cmdctl/tests/Makefile.am (original)
+++ branches/trac308/src/bin/cmdctl/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -10,5 +10,5 @@
 	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_SRC_PATH=$(abs_top_srcdir)/src/bin/cmdctl \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/bin/host/Makefile.am
==============================================================================
--- branches/trac308/src/bin/host/Makefile.am (original)
+++ branches/trac308/src/bin/host/Makefile.am Mon Sep 20 11:07:54 2010
@@ -3,12 +3,16 @@
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
 CLEANFILES = *.gcno *.gcda
 
 bin_PROGRAMS = host
 host_SOURCES = host.cc
-host_LDADD = $(top_builddir)/src/lib/dns/.libs/libdns++.a
-host_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
+host_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
+host_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 
 #man_MANS = host.1
 #EXTRA_DIST = $(man_MANS) host.xml

Modified: branches/trac308/src/bin/loadzone/tests/correct/Makefile.am
==============================================================================
--- branches/trac308/src/bin/loadzone/tests/correct/Makefile.am (original)
+++ branches/trac308/src/bin/loadzone/tests/correct/Makefile.am Mon Sep 20 11:07:54 2010
@@ -21,5 +21,5 @@
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
-	$(SHELL) $(abs_builddir)/$$pytest ; \
+	$(SHELL) $(abs_builddir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/bin/loadzone/tests/error/Makefile.am
==============================================================================
--- branches/trac308/src/bin/loadzone/tests/error/Makefile.am (original)
+++ branches/trac308/src/bin/loadzone/tests/error/Makefile.am Mon Sep 20 11:07:54 2010
@@ -21,5 +21,5 @@
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/bin/loadzone \
-	$(SHELL) $(abs_builddir)/$$pytest ; \
+	$(SHELL) $(abs_builddir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/bin/msgq/msgq.py.in
==============================================================================
--- branches/trac308/src/bin/msgq/msgq.py.in (original)
+++ branches/trac308/src/bin/msgq/msgq.py.in Mon Sep 20 11:07:54 2010
@@ -212,7 +212,10 @@
            EOF."""
         received = b''
         while len(received) < length:
-            data = sock.recv(length - len(received))
+            try:
+                data = sock.recv(length - len(received))
+            except socket.error:
+                raise MsgQReceiveError(socket.error)
             if len(data) == 0:
                 raise MsgQReceiveError("EOF")
             received += data

Modified: branches/trac308/src/bin/msgq/tests/Makefile.am
==============================================================================
--- branches/trac308/src/bin/msgq/tests/Makefile.am (original)
+++ branches/trac308/src/bin/msgq/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -8,6 +8,6 @@
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	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
 

Modified: branches/trac308/src/bin/xfrin/TODO
==============================================================================
--- branches/trac308/src/bin/xfrin/TODO (original)
+++ branches/trac308/src/bin/xfrin/TODO Mon Sep 20 11:07:54 2010
@@ -63,3 +63,7 @@
     which a shutdown notification would be sent to the child.  With
     this approach each thread needs to watch at least two channels,
     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.
+

Modified: branches/trac308/src/bin/xfrin/b10-xfrin.8
==============================================================================
--- branches/trac308/src/bin/xfrin/b10-xfrin.8 (original)
+++ branches/trac308/src/bin/xfrin/b10-xfrin.8 Mon Sep 20 11:07:54 2010
@@ -2,12 +2,12 @@
 .\"     Title: b10-xfrin
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: March 17, 2010
+.\"      Date: September 8, 2010
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-XFRIN" "8" "March 17, 2010" "BIND10" "BIND10"
+.TH "B10\-XFRIN" "8" "September 8, 2010" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -47,7 +47,6 @@
 .sp .5v
 .RE
 .PP
-
 This daemon communicates with BIND 10 over a
 \fBb10-msgq\fR(8)
 C\-Channel connection\&. If this connection is not established,
@@ -60,24 +59,59 @@
 \fBb10-cfgmgr\fR(8)\&.
 .SH "CONFIGURATION AND COMMANDS"
 .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
-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
 The configuration commands are:
+.PP
+
+\fBnotify\fR
+is sent by
+\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
+
+\fBretransfer\fR
+triggers the transfer in for a single zone without checking the zone\'s serial number\&. It has the following arguments:
+\fIzone_name\fR
+to define the zone to request,
+\fIzone_class\fR
+to define the class (defaults to
+\(lqIN\(rq),
+\fImaster\fR
+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\&.)
-.PP
-
-\fBretransfer\fR
-triggers the transfer in for a single zone without checking the zone\'s serial number\&. It has the following arguments:
-\fIzone_name\fR
-to define the zone to request and
-\fImaster\fR
-to define the IP address of the authoritative server to transfer from\&.
 .if n \{\
 .sp
 .\}
@@ -99,6 +133,7 @@
 
 \fBb10-cfgmgr\fR(8),
 \fBb10-msgq\fR(8),
+\fBb10-zonemgr\fR(8),
 \fBbind10\fR(8),
 BIND 10 Guide\&.
 .SH "HISTORY"

Modified: branches/trac308/src/bin/xfrin/b10-xfrin.xml
==============================================================================
--- branches/trac308/src/bin/xfrin/b10-xfrin.xml (original)
+++ branches/trac308/src/bin/xfrin/b10-xfrin.xml Mon Sep 20 11:07:54 2010
@@ -21,7 +21,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>March 17, 2010</date>
+    <date>September 8, 2010</date>
   </refentryinfo>
 
   <refmeta>
@@ -68,7 +68,6 @@
     </simpara></note>
 
     <para>
-<!-- TODO: does it really use msgq? what for? -->
       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,
@@ -85,39 +84,82 @@
   <refsect1>
     <title>CONFIGURATION AND COMMANDS</title>
     <para>
-      The configurable setting is <varname>transfers-in</varname>
-      which defines the maximum number of inbound zone transfers
+      The configurable settings are:
+    </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.
     </para>
 
 <!-- TODO: formating -->
-<!-- TODO: refresh is code but not in spec -->
-<!-- schedule immediate maintenance for a zone(check soa serial ) -->
     <para>
       The configuration commands are:
     </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>
+      <command>refresh</command> triggers the transfer in for
+      a single zone.
+      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>
+      <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>
+      <command>retransfer</command> triggers the transfer in for
+      a single zone without checking the zone's serial number.
+      It has the following arguments: <varname>zone_name</varname>
+      to define the zone to request,
+      <varname>zone_class</varname> to define the class (defaults to
+      <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>
+<!-- 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>
-    <para>
-      <command>retransfer</command> triggers the transfer in for
-      a single zone without checking the zone's serial number.
-      It has the following arguments: <varname>zone_name</varname>
-      to define the zone to request and <varname>master</varname>
-      to define the IP address of the authoritative server to
-      transfer from.
-     </para>
-<!-- TODO: later hostname for master? -->
-
 <!-- TODO:
 add a usage example of xfrin -->
-
-<!-- TODO:
-
-port (defaults to 53)
-db_file (defaults to zone.sqlite3) --> <!-- TODO: fix this -->
 
 <!-- TODO:
 
@@ -182,6 +224,9 @@
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
+        <refentrytitle>b10-zonemgr</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.

Modified: branches/trac308/src/bin/xfrin/tests/Makefile.am
==============================================================================
--- branches/trac308/src/bin/xfrin/tests/Makefile.am (original)
+++ branches/trac308/src/bin/xfrin/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -1,5 +1,12 @@
 PYTESTS = xfrin_test.py
 EXTRA_DIST = $(PYTESTS)
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+LIBRARY_PATH_PLACEHOLDER =
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
+endif
 
 # later will have configure option to choose this, like: coverage run --branch
 PYCOVERAGE = $(PYTHON)
@@ -7,6 +14,7 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/dns/python/.libs:$(abs_top_builddir)/src/bin/xfrin:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
-	$(PYCOVERAGE) $(abs_srcdir)/$$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 \
+	$(LIBRARY_PATH_PLACEHOLDER) \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/bin/xfrin/tests/xfrin_test.py
==============================================================================
--- branches/trac308/src/bin/xfrin/tests/xfrin_test.py (original)
+++ branches/trac308/src/bin/xfrin/tests/xfrin_test.py Mon Sep 20 11:07:54 2010
@@ -63,6 +63,9 @@
 
     def _cc_setup(self):
         pass
+
+    def _get_db_file(self):
+        pass
     
     def _cc_check_command(self):
         self._shutdown_event.set()
@@ -408,11 +411,16 @@
     def tearDown(self):
         self.xfr.shutdown()
 
-    def _do_parse(self):
-        return self.xfr._parse_cmd_params(self.args)
+    def _do_parse_zone_name_class(self):
+        return self.xfr._parse_zone_name_and_class(self.args)
+
+    def _do_parse_master_port(self):
+        return self.xfr._parse_master_and_port(self.args)
 
     def test_parse_cmd_params(self):
-        name, rrclass, master_addrinfo, db_file = self._do_parse()
+        name, rrclass = self._do_parse_zone_name_class()
+        master_addrinfo = self._do_parse_master_port()
+        db_file = self.args.get('db_file')
         self.assertEqual(master_addrinfo[4][1], int(TEST_MASTER_PORT))
         self.assertEqual(name, TEST_ZONE_NAME)
         self.assertEqual(rrclass, TEST_RRCLASS)
@@ -421,49 +429,50 @@
 
     def test_parse_cmd_params_default_port(self):
         del self.args['port']
-        master_addrinfo = self._do_parse()[2]
+        master_addrinfo = self._do_parse_master_port()
         self.assertEqual(master_addrinfo[4][1], 53)
 
     def test_parse_cmd_params_ip6master(self):
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
-        master_addrinfo = self._do_parse()[2]
+        master_addrinfo = self._do_parse_master_port()
         self.assertEqual(master_addrinfo[4][0], TEST_MASTER_IPV6_ADDRESS)
 
     def test_parse_cmd_params_chclass(self):
-        self.args['rrclass'] = 'CH'
-        self.assertEqual(self._do_parse()[1], RRClass.CH())
+        self.args['zone_class'] = 'CH'
+        self.assertEqual(self._do_parse_zone_name_class()[1], RRClass.CH())
 
     def test_parse_cmd_params_bogusclass(self):
-        self.args['rrclass'] = 'XXX'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.args['zone_class'] = 'XXX'
+        self.assertRaises(XfrinException, self._do_parse_zone_name_class)
 
     def test_parse_cmd_params_nozone(self):
         # zone name is mandatory.
         del self.args['zone_name']
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_zone_name_class)
 
     def test_parse_cmd_params_nomaster(self):
         # master address is mandatory.
         del self.args['master']
-        self.assertRaises(XfrinException, self._do_parse)
+        master_addrinfo = self._do_parse_master_port()
+        self.assertEqual(master_addrinfo[4][0], DEFAULT_MASTER)
 
     def test_parse_cmd_params_bad_ip4(self):
         self.args['master'] = '3.3.3.3.3'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
     def test_parse_cmd_params_bad_ip6(self):
         self.args['master'] = '1::1::1'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
     def test_parse_cmd_params_bad_port(self):
         self.args['port'] = '-1'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
         self.args['port'] = '65536'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
         self.args['port'] = 'http'
-        self.assertRaises(XfrinException, self._do_parse)
+        self.assertRaises(XfrinException, self._do_parse_master_port)
 
     def test_command_handler_shutdown(self):
         self.assertEqual(self.xfr.command_handler("shutdown",
@@ -499,12 +508,12 @@
                                                   self.args)['result'][0], 1)
 
     def test_command_handler_retransfer_nomodule(self):
-        dns_module = sys.modules['libdns_python'] # this must exist
-        del sys.modules['libdns_python']
+        dns_module = sys.modules['pydnspp'] # this must exist
+        del sys.modules['pydnspp']
         self.assertEqual(self.xfr.command_handler("retransfer",
                                                   self.args)['result'][0], 1)
         # 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):
         # at this level, refresh is no different than retransfer.
@@ -518,18 +527,39 @@
         self.args['master'] = TEST_MASTER_IPV6_ADDRESS
         # ...but right now we disable the feature due to security concerns.
         self.assertEqual(self.xfr.command_handler("notify",
-                                                  self.args)['result'][0], 1)
+                                                  self.args)['result'][0], 0)
 
     def test_command_handler_unknown(self):
         self.assertEqual(self.xfr.command_handler("xxx", None)['result'][0], 1)
 
+    def test_command_handler_transfers_in(self):
+        self.assertEqual(self.xfr.config_handler({})['result'][0], 0)
+        self.assertEqual(self.xfr.config_handler({'transfers_in': 3})['result'][0], 0)
+        self.assertEqual(self.xfr._max_transfers_in, 3)
+
+    def test_command_handler_masters(self):
+        master_info = {'master_addr': '1.1.1.1', 'master_port':53}
+        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 0)
+
+        master_info = {'master_addr': '1111.1.1.1', 'master_port':53 }
+        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 1)
+
+        master_info = {'master_addr': '2.2.2.2', 'master_port':530000 }
+        self.assertEqual(self.xfr.config_handler(master_info)['result'][0], 1)
+
+        master_info = {'master_addr': '2.2.2.2', 'master_port':53 } 
+        self.xfr.config_handler(master_info)
+        self.assertEqual(self.xfr._master_addr, '2.2.2.2')
+        self.assertEqual(self.xfr._master_port, 53)
+
+
 def raise_interrupt():
     raise KeyboardInterrupt()
 
 def raise_ccerror():
     raise isc.cc.session.SessionError('test error')
 
-def raise_excpetion():
+def raise_exception():
     raise Exception('test exception')
 
 class TestMain(unittest.TestCase):
@@ -551,7 +581,7 @@
         main(MockXfrin, False)
 
     def test_startup_generalerror(self):
-        MockXfrin.check_command_hook = raise_excpetion
+        MockXfrin.check_command_hook = raise_exception
         main(MockXfrin, False)
 
 if __name__== "__main__":

Modified: branches/trac308/src/bin/xfrin/xfrin.py.in
==============================================================================
--- branches/trac308/src/bin/xfrin/xfrin.py.in (original)
+++ branches/trac308/src/bin/xfrin/xfrin.py.in Mon Sep 20 11:07:54 2010
@@ -28,8 +28,9 @@
 import random
 from optparse import OptionParser, OptionValueError
 from isc.config.ccsession import *
+from isc.notify import notify_out
 try:
-    from libdns_python import *
+    from pydnspp import *
 except ImportError as e:
     # C++ loadable module may not be installed; even so the xfrin process
     # must keep running, so we warn about it and move forward.
@@ -49,13 +50,17 @@
 SPECFILE_LOCATION = SPECFILE_PATH + "/xfrin.spec"
 AUTH_SPECFILE_LOCATION = AUTH_SPECFILE_PATH + "/auth.spec"
 
-
+XFROUT_MODULE_NAME = 'Xfrout'
+ZONE_MANAGER_MODULE_NAME = 'Zonemgr'
+REFRESH_FROM_ZONEMGR = 'refresh_from_zonemgr'
+ZONE_XFRIN_FAILED = 'zone_xfrin_failed'
 __version__ = 'BIND10'
 # define xfrin rcode
 XFRIN_OK = 0
 XFRIN_FAIL = 1
 
 DEFAULT_MASTER_PORT = '53'
+DEFAULT_MASTER = '127.0.0.1'
 
 def log_error(msg):
     sys.stderr.write("[b10-xfrin] %s\n" % str(msg))
@@ -192,7 +197,6 @@
                                             self._handle_xfrin_response)
 
                 self.log_msg(logstr + 'succeeded')
-                ret = XFRIN_OK
 
         except XfrinException as e:
             self.log_msg(e)
@@ -316,14 +320,15 @@
             sys.stdout.write('[b10-xfrin] %s\n' % str(msg))
 
 
-def process_xfrin(xfrin_recorder, zone_name, rrclass, db_file, 
+def process_xfrin(server, xfrin_recorder, zone_name, rrclass, db_file, 
                   shutdown_event, master_addrinfo, check_soa, verbose):
     xfrin_recorder.increment(zone_name)
     sock_map = {}
     conn = XfrinConnection(sock_map, zone_name, rrclass, db_file,
                            shutdown_event, master_addrinfo, verbose)
     if conn.connect_to_master():
-        conn.do_xfrin(check_soa)
+        ret = conn.do_xfrin(check_soa)
+        server.publish_xfrin_news(zone_name, rrclass, ret)
 
     xfrin_recorder.decrement(zone_name)
 
@@ -358,32 +363,54 @@
 
 class Xfrin:
     def __init__(self, verbose = False):
+        self._max_transfers_in = 10
+        #TODO, this is the temp way to set the zone's master.
+        self._master_addr = DEFAULT_MASTER
+        self._master_port = DEFAULT_MASTER_PORT
         self._cc_setup()
-        self._max_transfers_in = 10
         self.recorder = XfrinRecorder()
         self._shutdown_event = threading.Event()
         self._verbose = verbose
 
     def _cc_setup(self):
-        '''
-This method is used only as part of initialization, but is implemented
-separately for convenience of unit tests; by letting the test code override
-this method we can test most of this class without requiring a command channel.
-'''
-        self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
+        '''This method is used only as part of initialization, but is 
+        implemented separately for convenience of unit tests; by letting 
+        the test code override this method we can test most of this class 
+        without requiring a command channel.'''
+        # Create one session for sending command to other modules, because the 
+        # listening session will block the send operation.
+        self._send_cc_session = isc.cc.Session()
+        self._module_cc = isc.config.ModuleCCSession(SPECFILE_LOCATION,
                                               self.config_handler,
                                               self.command_handler)
-        self._cc.start()
+        self._module_cc.start()
+        config_data = self._module_cc.get_full_config()
+        self._max_transfers_in = config_data.get("transfers_in")
+        self._master_addr = config_data.get('master_addr') or self._master_addr
+        self._master_port = config_data.get('master_port') or self._master_port
 
     def _cc_check_command(self):
-        '''
-This is a straightforward wrapper for cc.check_command, but provided as
-a separate method for the convenience of unit tests.
-'''
-        self._cc.check_command()
+        '''This is a straightforward wrapper for cc.check_command, 
+        but provided as a separate method for the convenience 
+        of unit tests.'''
+        self._module_cc.check_command()
 
     def config_handler(self, new_config):
-        # TODO, process new config data
+        self._max_transfers_in = new_config.get("transfers_in") or self._max_transfers_in
+        if ('master_addr' in new_config) or ('master_port' in new_config):
+            # Check if the new master is valid, there should be library for check it.
+            # and user should change the port and address together.
+            try:
+                addr = new_config.get('master_addr') or self._master_addr
+                port = new_config.get('master_port') or self._master_port
+                check_addr_port(addr, port)
+                self._master_addr = addr
+                self._master_port = port
+            except:
+                errmsg = "bad format for zone's master: " + str(new_config)
+                log_error(errmsg)
+                return create_answer(1, errmsg)
+
         return create_answer(0)
 
     def shutdown(self):
@@ -397,95 +424,97 @@
                 continue
             th.join()
 
-
     def command_handler(self, command, args):
         answer = create_answer(0)
         try:
             if command == 'shutdown':
                 self._shutdown_event.set()
+            elif command == 'notify' or command == REFRESH_FROM_ZONEMGR:
+                # Xfrin receives the refresh/notify command from zone manager. 
+                # notify command maybe has the parameters which 
+                # specify the notifyfrom address and port, according the RFC1996, zone
+                # transfer should starts first from the notifyfrom, but now, let 'TODO' it.
+                (zone_name, rrclass) = self._parse_zone_name_and_class(args)
+                (master_addr) = check_addr_port(self._master_addr, self._master_port)
+                ret = self.xfrin_start(zone_name, 
+                                       rrclass, 
+                                       self._get_db_file(),
+                                       master_addr,
+                                       True)
+                answer = create_answer(ret[0], ret[1])
+
             elif command == 'retransfer' or command == 'refresh':
-                (zone_name, rrclass,
-                 master_addr, db_file) = self._parse_cmd_params(args)
-                ret = self.xfrin_start(zone_name, rrclass, db_file,
+                # Xfrin receives the retransfer/refresh from cmdctl(sent by bindctl).
+                # If the command has specified master address, do transfer from the 
+                # master address, or else do transfer from the configured masters.                
+                (zone_name, rrclass) = self._parse_zone_name_and_class(args)
+                master_addr = self._parse_master_and_port(args)
+                db_file = args.get('db_file') or self._get_db_file()
+                ret = self.xfrin_start(zone_name, 
+                                       rrclass, 
+                                       db_file, 
                                        master_addr,
-                                   False if command == 'retransfer' else True)
+                                       (False if command == 'retransfer' else True))
                 answer = create_answer(ret[0], ret[1])
-            elif command == 'notify':
-                # This is the temporary implementation for notify.
-                # actually the notfiy command should be sent to the
-                # Zone Manager module.  Being temporary, we separate this case
-                # from refresh/retransfer while we could (and should otherwise)
-                # share the code.
-                (zone_name, rrclass,
-                 master_addr, db_file) = self._parse_cmd_params(args)
-
-                # XXX: master_addr is the sender of the notify message.
-                # It's very dangerous to naively trust it as the source of
-                # subsequent zone transfer; any remote node can easily exploit
-                # it to mount zone poisoning or DoS attacks.  We should
-                # locally identify the appropriate set of master servers.
-                # For now, we disable the code below.
-                master_is_valid = False
-
-                if master_is_valid:
-                    ret = self.xfrin_start(zone_name, rrclass, db_file,
-                                           master_addr, True)
-                else:
-                    errmsg = 'Failed to validate the master address ('
-                    errmsg += args['master'] + '), ignoring notify'
-                    ret = [1, errmsg]
-                answer = create_answer(ret[0], ret[1])
+
             else:
                 answer = create_answer(1, 'unknown command: ' + command)
-
         except XfrinException as err:
+            log_error('error happened for command: %s, %s' % (command, str(err)) )
             answer = create_answer(1, str(err))
-
         return answer
 
-    def _parse_cmd_params(self, args):
+    def _parse_zone_name_and_class(self, args):
         zone_name = args.get('zone_name')
         if not zone_name:
             raise XfrinException('zone name should be provided')
 
-        rrclass = args.get('rrclass')
+        rrclass = args.get('zone_class')
         if not rrclass:
-            # The default RR class is IN.  We should fix this so that
-            # the class is always passed in the command arg (where we specify
-            # the default)
             rrclass = RRClass.IN()
         else:
             try:
                 rrclass = RRClass(rrclass)
             except InvalidRRClass as e:
                 raise XfrinException('invalid RRClass: ' + rrclass)
-
-        master = args.get('master')
-        if not master:
-            raise XfrinException('master address should be provided')
-
-        port_str = args.get('port')
-        if not port_str:
-            port_str = DEFAULT_MASTER_PORT
-        master_addrinfo = check_addr_port(master, port_str)
-
-        db_file = args.get('db_file')
-        if not db_file:
-            #TODO, the db file path should be got in auth server's configuration
-            # if we need access to this configuration more often, we
-            # should add it on start, and not remove it here
-            # (or, if we have writable ds, we might not need this in
-            # the first place)
-            self._cc.add_remote_config(AUTH_SPECFILE_LOCATION)
-            db_file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
-            if is_default and "B10_FROM_BUILD" in os.environ:
-                # this too should be unnecessary, but currently the
-                # 'from build' override isn't stored in the config
-                # (and we don't have writable datasources yet)
-                db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
-            self._cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
-
-        return (zone_name, rrclass, master_addrinfo, db_file)
+        
+        return zone_name, rrclass
+
+    def _parse_master_and_port(self, args):
+        port = args.get('port') or self._master_port
+        master = args.get('master') or self._master_addr
+        return check_addr_port(master, port)
+ 
+    def _get_db_file(self):
+        #TODO, the db file path should be got in auth server's configuration
+        # if we need access to this configuration more often, we
+        # should add it on start, and not remove it here
+        # (or, if we have writable ds, we might not need this in
+        # the first place)
+        self._module_cc.add_remote_config(AUTH_SPECFILE_LOCATION)
+        db_file, is_default = self._module_cc.get_remote_config_value("Auth", "database_file")
+        if is_default and "B10_FROM_BUILD" in os.environ:
+            # this too should be unnecessary, but currently the
+            # 'from build' override isn't stored in the config
+            # (and we don't have writable datasources yet)
+            db_file = os.environ["B10_FROM_BUILD"] + os.sep + "bind10_zones.sqlite3"
+        self._module_cc.remove_remote_config(AUTH_SPECFILE_LOCATION)
+        return db_file
+       
+    def publish_xfrin_news(self, zone_name, zone_class,  xfr_result):
+        '''Send command to xfrout/zone manager module.
+        If xfrin has finished successfully for one zone, tell the good 
+        news(command: zone_new_data_ready) to zone manager and xfrout.
+        if xfrin failed, just tell the bad news to zone manager, so that 
+        it can reset the refresh timer for that zone. '''
+        param = {'zone_name': zone_name, 'zone_class': zone_class.to_text()}
+        if xfr_result == XFRIN_OK:
+            msg = create_command(notify_out.ZONE_NEW_DATA_READY_CMD, param)
+            self._send_cc_session.group_sendmsg(msg, XFROUT_MODULE_NAME)
+            self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
+        else:
+            msg = create_command(ZONE_XFRIN_FAILED, param)
+            self._send_cc_session.group_sendmsg(msg, ZONE_MANAGER_MODULE_NAME)
 
     def startup(self):
         while not self._shutdown_event.is_set():
@@ -493,8 +522,8 @@
 
     def xfrin_start(self, zone_name, rrclass, db_file, master_addrinfo,
                     check_soa = True):
-        if "libdns_python" not in sys.modules:
-            return (1, "xfrin failed, can't load dns message python library: 'libdns_python'")
+        if "pydnspp" not in sys.modules:
+            return (1, "xfrin failed, can't load dns message python library: 'pydnspp'")
 
         # check max_transfer_in, else return quota error
         if self.recorder.count() >= self._max_transfers_in:
@@ -504,7 +533,8 @@
             return (1, 'zone xfrin is in progress')
 
         xfrin_thread = threading.Thread(target = process_xfrin,
-                                        args = (self.recorder,
+                                        args = (self,
+                                                self.recorder,
                                                 zone_name, rrclass,
                                                 db_file,
                                                 self._shutdown_event,

Modified: branches/trac308/src/bin/xfrin/xfrin.spec.pre.in
==============================================================================
--- branches/trac308/src/bin/xfrin/xfrin.spec.pre.in (original)
+++ branches/trac308/src/bin/xfrin/xfrin.spec.pre.in Mon Sep 20 11:07:54 2010
@@ -8,6 +8,17 @@
         "item_type": "integer",
         "item_optional": false,
         "item_default": 10
+      },
+      {
+        "item_name": "master_addr",
+        "item_type": "string",
+        "item_optional": false,
+        "item_default": ""
+      },
+      { "item_name": "master_port",
+        "item_type": "integer",
+        "item_optional": false,
+        "item_default": 53
       }
     ],
     "commands": [
@@ -21,9 +32,15 @@
             "item_default": ""
           },
           {
+            "item_name": "zone_class",
+            "item_type": "string",
+            "item_optional": true,
+            "item_default": "IN"
+          },
+          {
             "item_name": "master",
             "item_type": "string",
-            "item_optional": false,
+            "item_optional": true,
             "item_default": ""
           },
           {

Modified: branches/trac308/src/bin/xfrout/b10-xfrout.8
==============================================================================
--- branches/trac308/src/bin/xfrout/b10-xfrout.8 (original)
+++ branches/trac308/src/bin/xfrout/b10-xfrout.8 Mon Sep 20 11:07:54 2010
@@ -2,12 +2,12 @@
 .\"     Title: b10-xfrout
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: April 20, 2010
+.\"      Date: September 8, 2010
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-XFROUT" "8" "April 20, 2010" "BIND10" "BIND10"
+.TH "B10\-XFROUT" "8" "September 8, 2010" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -27,7 +27,7 @@
 .PP
 The
 \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)
 boss process\&. When the
 \fBb10\-auth\fR
@@ -67,13 +67,13 @@
 The configurable settings are:
 .PP
 
-\fItransfers\-out\fR
-defines the maximum number of outgoing zone transfers that can run concurrently\&. The default is 10\&.
-.PP
-
 \fIdb_file\fR
 defines the path to the SQLite3 data store file\&. The default is
 /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 \{\
 .sp
 .\}
@@ -91,25 +91,34 @@
 .sp .5v
 .RE
 .PP
-The configuration command is:
+The configuration commands are:
 .PP
 
 \fBshutdown\fR
 stops all outbound zone transfers and exits
 \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"
 .PP
 
 \fBb10-auth\fR(8),
 \fBb10-cfgmgr\fR(8),
 \fBb10-msgq\fR(8),
+\fBb10-xfrin\fR(8),
 \fBbind10\fR(8),
 BIND 10 Guide\&.
 .SH "HISTORY"
 .PP
 The
 \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"
 .br
 Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")

Modified: branches/trac308/src/bin/xfrout/b10-xfrout.xml
==============================================================================
--- branches/trac308/src/bin/xfrout/b10-xfrout.xml (original)
+++ branches/trac308/src/bin/xfrout/b10-xfrout.xml Mon Sep 20 11:07:54 2010
@@ -21,7 +21,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>April 20, 2010</date>
+    <date>September 8, 2010</date>
   </refentryinfo>
 
   <refmeta>
@@ -54,6 +54,7 @@
     <title>DESCRIPTION</title>
     <para>The <command>b10-xfrout</command> 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
       <citerefentry><refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       boss process.
@@ -93,16 +94,20 @@
       The configurable settings are:
     </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>
       defines the path to the SQLite3 data store file.
       The default is
       <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>
+
+<!-- TODO: log configurations not documented yet in here. jreed
+     has some but waiting on decisions ... -->
 
     <note><simpara>
       This prototype version uses SQLite3 as its data source backend.
@@ -112,12 +117,22 @@
 
 <!-- TODO: formating -->
     <para>
-      The configuration command is:
+      The configuration commands are:
     </para>
     <para>
       <command>shutdown</command> stops all outbound zone transfers
       and exits <command>b10-xfrout</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 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>
@@ -161,6 +176,9 @@
         <refentrytitle>b10-msgq</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citerefentry>
+        <refentrytitle>b10-xfrin</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>,
+      <citerefentry>
         <refentrytitle>bind10</refentrytitle><manvolnum>8</manvolnum>
       </citerefentry>,
       <citetitle>BIND 10 Guide</citetitle>.
@@ -170,8 +188,8 @@
   <refsect1>
     <title>HISTORY</title>
     <para>
-      The <command>b10-xfrout</command> daemon was implemented in March 2010
-      by Zhang Likun of CNNIC for the ISC BIND 10 project.
+      The <command>b10-xfrout</command> daemon was first implemented
+      in March 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project.
     </para>
   </refsect1>
 </refentry><!--

Modified: branches/trac308/src/bin/xfrout/tests/Makefile.am
==============================================================================
--- branches/trac308/src/bin/xfrout/tests/Makefile.am (original)
+++ branches/trac308/src/bin/xfrout/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -1,5 +1,12 @@
 PYTESTS = xfrout_test.py
 EXTRA_DIST = $(PYTESTS)
+
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+LIBRARY_PATH_PLACEHOLDER =
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$(abs_top_builddir)/src/lib/xfr/.libs:$$$(ENV_LIBRARY_PATH)
+endif
 
 # later will have configure option to choose this, like: coverage run --branch
 PYCOVERAGE = $(PYTHON)
@@ -7,6 +14,7 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_builddir)/src/bin/xfrout:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/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 ; \
+	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) \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/bin/xfrout/tests/xfrout_test.py
==============================================================================
--- branches/trac308/src/bin/xfrout/tests/xfrout_test.py (original)
+++ branches/trac308/src/bin/xfrout/tests/xfrout_test.py Mon Sep 20 11:07:54 2010
@@ -19,7 +19,7 @@
 import unittest
 import os
 from isc.cc.session import *
-from libdns_python import *
+from pydnspp import *
 from xfrout import *
 
 # our fake socket, where we can read and insert messages
@@ -40,8 +40,12 @@
         return len(data)
 
     def readsent(self):
-        result = self.sendqueue[:]
-        del self.sendqueue[:]
+        if len(self.sendqueue) >= 2:
+            size = 2 + struct.unpack("!H", self.sendqueue[:2])[0]
+        else:
+            size = 0
+        result = self.sendqueue[:size]
+        self.sendqueue = self.sendqueue[size:]
         return result
     
     def read_msg(self):
@@ -133,7 +137,7 @@
 
         msg = self.getmsg()
         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()
 
         self.assertEqual(get_msg.get_rr_count(Section.QUESTION()), 1)
@@ -148,10 +152,52 @@
         rdata = answer.get_rdata()
         self.assertEqual(rdata[0].to_text(), self.soa_record[7])
 
-    def test_get_message_len(self):
-        msg = self.getmsg()
-        msg.make_response()  
-        self.assertEqual(self.xfrsess._get_message_len(msg), 29)
+    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.make_response()
+
+        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):
         global sqlite3_ds

Modified: branches/trac308/src/bin/xfrout/xfrout.py.in
==============================================================================
--- branches/trac308/src/bin/xfrout/xfrout.py.in (original)
+++ branches/trac308/src/bin/xfrout/xfrout.py.in Mon Sep 20 11:07:54 2010
@@ -27,14 +27,15 @@
 import os
 from isc.config.ccsession import *
 from isc.log.log import *
-from isc.cc import SessionError
+from isc.cc import SessionError, SessionTimeout
+from isc.notify import notify_out
 import socket
 import select
 import errno
 from optparse import OptionParser, OptionValueError
 try:
     from libxfr_python import *
-    from libdns_python import *
+    from pydnspp import *
 except ImportError as e:
     # C++ loadable module may not be installed; even so the xfrout process
     # must keep running, so we warn about it and move forward.
@@ -56,6 +57,15 @@
 MAX_TRANSFERS_OUT = 10
 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):
     def __init__(self, request, client_address, server, log):
         # The initializer for the superclass may call functions
@@ -120,10 +130,8 @@
 
 
     def _send_message(self, sock, msg):
-        #obuf = output_buffer(0)
-        #render = message_render(obuf)
         render = MessageRenderer()
-        render.set_length_limit(65535)
+        render.set_length_limit(XFROUT_MAX_MESSAGE_SIZE)
         msg.to_wire(render)
         header_len = struct.pack('H', socket.htons(render.get_length()))
         self._send_data(sock, header_len)
@@ -226,34 +234,20 @@
         rrset_.add_rdata(rdata_)
         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
         added, a new message should be created to send out the last soa .
         '''
-
-        render = MessageRenderer()
-        msg.to_wire(render)
-        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:
+        rrset_len = get_rrset_len(rrset_soa)
+
+        if message_upper_len + rrset_len < XFROUT_MAX_MESSAGE_SIZE:
+            msg.add_rrset(Section.ANSWER(), rrset_soa)
+        else:
             self._send_message(sock, msg)
-        else:
             msg = self._clear_message(msg)
             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()
-        msg.to_wire(render)
-        return render.get_length()
+
+        self._send_message(sock, msg)
 
 
     def _reply_xfrout_query(self, msg, sock, zone_name):
@@ -264,9 +258,8 @@
         rrset_soa = self._create_rrset_from_db_record(soa_record)
         msg.add_rrset(Section.ANSWER(), rrset_soa)
 
-        old_message_len = 0
-        # 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.
+        message_upper_len = get_rrset_len(rrset_soa)
+
         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
                 self._log.log_message("error", "shutdown!")
@@ -276,19 +269,22 @@
                 continue
 
             rrset_ = self._create_rrset_from_db_record(rr_data)
-            msg.add_rrset(Section.ANSWER(), rrset_)
-            message_len = self._get_message_len(msg)
-            if message_len != old_message_len:
-                old_message_len = message_len
+
+            # We calculate the maximum size of the RRset (i.e. the
+            # size without compression) and use that to see if we
+            # 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
 
             self._send_message(sock, msg)
             msg = self._clear_message(msg)
             msg.add_rrset(Section.ANSWER(), rrset_) # Add the rrset to the new message
-            old_message_len = 0
-
-        self._send_message_with_last_soa(msg, sock, rrset_soa)
-
+            message_upper_len = rrset_len
+
+        self._send_message_with_last_soa(msg, sock, rrset_soa, message_upper_len)
 
 class UnixSockServer(ThreadingUnixStreamServer):
     '''The unix domain socket server which accept xfr query sent from auth server.'''
@@ -303,7 +299,7 @@
         self._log = log
         self.update_config_data(config_data)
         self._cc = cc
-
+        
     def finish_request(self, request, client_address):
         '''Finish one request by instantiating RequestHandlerClass.'''
         self.RequestHandlerClass(request, client_address, self, self._log)
@@ -314,8 +310,8 @@
         If it's not a socket file or nobody is listening
         , it will be removed. If it can't be removed, exit from python. '''
         if self._sock_file_in_use(sock_file):
-            print("[b10-xfrout] Fail to start xfrout process, unix socket" 
-                  " file '%s' is being used by another xfrout process" % sock_file)
+            sys.stderr.write("[b10-xfrout] Fail to start xfrout process, unix socket" 
+                  " file '%s' is being used by another xfrout process\n" % sock_file)
             sys.exit(0)
         else:
             if not os.path.exists(sock_file):
@@ -324,7 +320,7 @@
             try:
                 os.unlink(sock_file)
             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)
    
     def _sock_file_in_use(self, sock_file):
@@ -408,23 +404,32 @@
         self._listen_sock_file = UNIX_SOCKET_FILE 
         self._shutdown_event = threading.Event()
         self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
-        self._cc.add_remote_config(AUTH_SPECFILE_LOCATION);
         self._config_data = self._cc.get_full_config()
         self._cc.start()
+        self._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._config_data.get('log_severity'), self._config_data.get('log_versions'),
                                 self._config_data.get('log_max_bytes'), True)
         self._start_xfr_query_listener()
+        self._start_notifier()
 
     def _start_xfr_query_listener(self):
         '''Start a new thread to accept xfr query. '''
-    
         self._unix_socket_server = UnixSockServer(self._listen_sock_file, XfroutSession, 
                                                   self._shutdown_event, self._config_data,
                                                   self._cc, self._log);
         listener = threading.Thread(target = listen_on_xfr_query, args = (self._unix_socket_server,))
         listener.start()
-
+        
+    def _start_notifier(self):
+        datasrc = self._unix_socket_server.get_db_file()
+        self._notifier = notify_out.NotifyOut(datasrc, self._log)
+        td = threading.Thread(target = notify_out.dispatcher, args = (self._notifier,))
+        td.daemon = True
+        td.start()
+
+    def send_notify(self, zone_name, zone_class):
+        self._notifier.send_notify(zone_name, zone_class)
 
     def config_handler(self, new_config):
         '''Update config data. TODO. Do error check'''
@@ -466,11 +471,22 @@
             self._log.log_message("info", "Received shutdown command.")
             self.shutdown()
             answer = create_answer(0)
+        
+        elif cmd == notify_out.ZONE_NEW_DATA_READY_CMD:
+            zone_name = args.get('zone_name')
+            zone_class = args.get('zone_class')
+            if zone_name and zone_class:
+                self._log.log_message("info", "zone '%s/%s': receive notify others command" \
+                                       % (zone_name, zone_class))
+                self.send_notify(zone_name, zone_class)
+                answer = create_answer(0)
+            else:
+                answer = create_answer(1, "Bad command parameter:" + str(args))
+
         else: 
             answer = create_answer(1, "Unknown command:" + str(cmd))
 
         return answer    
- 
 
     def run(self):
         '''Get and process all commands sent from cfgmgr or other modules. '''
@@ -504,12 +520,15 @@
         xfrout_server = XfroutServer()
         xfrout_server.run()
     except KeyboardInterrupt:
-        sys.stderr.write("[b10-xfrout] exit xfrout process")
+        sys.stderr.write("[b10-xfrout] exit xfrout process\n")
     except SessionError as e:
-        sys.stderr.write("[b10-xfrout] Error creating xfrout," 
-                           "is the command channel daemon running?")
+        sys.stderr.write("[b10-xfrout] Error creating xfrout, "
+                           "is the command channel daemon running?\n")
+    except SessionTimeout as e:
+        sys.stderr.write("[b10-xfrout] Error creating xfrout, " 
+                           "is the configuration manager running?\n")
     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:
         xfrout_server.shutdown()

Modified: branches/trac308/src/lib/bench/tests/benchmark_unittest.cc
==============================================================================
--- branches/trac308/src/lib/bench/tests/benchmark_unittest.cc (original)
+++ branches/trac308/src/lib/bench/tests/benchmark_unittest.cc Mon Sep 20 11:07:54 2010
@@ -58,7 +58,7 @@
 };
 
 // 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>
 const int BenchMark<T>::TIME_FAILURE;
 }

Modified: branches/trac308/src/lib/cc/Makefile.am
==============================================================================
--- branches/trac308/src/lib/cc/Makefile.am (original)
+++ branches/trac308/src/lib/cc/Makefile.am Mon Sep 20 11:07:54 2010
@@ -1,3 +1,5 @@
+SUBDIRS = . tests
+
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 
@@ -19,20 +21,3 @@
 	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" session_config.h.pre >$@
 
 BUILT_SOURCES = session_config.h 
-
-TESTS =
-if HAVE_GTEST
-TESTS += run_unittests
-# (TODO: these need to be completed and moved to tests/)
-run_unittests_SOURCES = data_unittests.cc session_unittests.cc run_unittests.cc
-run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
-# TODO: remove PTHREAD_LDFLAGS (and from configure too)
-run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) $(PTHREAD_LDFLAGS)
-
-run_unittests_LDADD = libcc.la $(GTEST_LDADD)
-run_unittests_LDADD +=  $(top_builddir)/src/lib/dns/.libs/libdns++.a
-run_unittests_LDADD +=  $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
-
-endif
-
-noinst_PROGRAMS = $(TESTS)

Modified: branches/trac308/src/lib/cc/data.cc
==============================================================================
--- branches/trac308/src/lib/cc/data.cc (original)
+++ branches/trac308/src/lib/cc/data.cc Mon Sep 20 11:07:54 2010
@@ -20,6 +20,7 @@
 
 #include <cassert>
 #include <climits>
+#include <map>
 #include <cstdio>
 #include <iostream>
 #include <string>
@@ -35,24 +36,21 @@
 namespace data {
 
 std::string
-Element::str()
-{
+Element::str() const {
     std::stringstream ss;
     toJSON(ss);
-    return ss.str();
+    return (ss.str());
 }
 
 std::string
-Element::toWire()
-{
+Element::toWire() const {
     std::stringstream ss;
     toJSON(ss);
-    return ss.str();
-}
-
-void
-Element::toWire(std::ostream& ss)
-{
+    return (ss.str());
+}
+
+void
+Element::toWire(std::ostream& ss) const {
     toJSON(ss);
 }
 
@@ -65,77 +63,78 @@
 //
 bool
 Element::getValue(long int& t UNUSED_PARAM) {
-    return false;
+    return (false);
 }
 
 bool
 Element::getValue(double& t UNUSED_PARAM) {
-    return false;
+    return (false);
 }
 
 bool
 Element::getValue(bool& t UNUSED_PARAM) {
-    return false;
+    return (false);
 }
 
 bool
 Element::getValue(std::string& t UNUSED_PARAM) {
-    return false;
-}
-
-bool
-Element::getValue(std::vector<ElementPtr>& t UNUSED_PARAM) {
-    return false;
-}
-
-bool
-Element::getValue(std::map<std::string, ElementPtr>& t UNUSED_PARAM) {
-    return false;
+    return (false);
+}
+
+bool
+Element::getValue(std::vector<ConstElementPtr>& t UNUSED_PARAM) {
+    return (false);
+}
+
+bool
+Element::getValue(std::map<std::string, ConstElementPtr>& t UNUSED_PARAM) {
+    return (false);
 }
 
 bool
 Element::setValue(const long int v UNUSED_PARAM) {
-    return false;
+    return (false);
 }
 
 bool
 Element::setValue(const double v UNUSED_PARAM) {
-    return false;
+    return (false);
 }
 
 bool
 Element::setValue(const bool t UNUSED_PARAM) {
-    return false;
+    return (false);
 }
 
 bool
 Element::setValue(const std::string& v UNUSED_PARAM) {
-    return false;
-}
-
-bool
-Element::setValue(const std::vector<ElementPtr>& v UNUSED_PARAM) {
-    return false;
-}
-
-bool
-Element::setValue(const std::map<std::string, ElementPtr>& v UNUSED_PARAM)
-{
-    return false;
-}
-
-ElementPtr
-Element::get(const int i UNUSED_PARAM) {
+    return (false);
+}
+
+bool
+Element::setValue(const std::vector<ConstElementPtr>& v UNUSED_PARAM) {
+    return (false);
+}
+
+bool
+Element::setValue(const std::map<std::string,
+                  ConstElementPtr>& v UNUSED_PARAM)
+{
+    return (false);
+}
+
+ConstElementPtr
+Element::get(const int i UNUSED_PARAM) const {
     isc_throw(TypeError, "get(int) called on a non-list Element");
 }
 
 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");
 }
 
 void
-Element::add(ElementPtr element UNUSED_PARAM) {
+Element::add(ConstElementPtr element UNUSED_PARAM) {
     isc_throw(TypeError, "add() called on a non-list Element");
 }
 
@@ -145,18 +144,18 @@
 }
 
 size_t
-Element::size() {
+Element::size() const {
     isc_throw(TypeError, "size() called on a non-list Element");
 }
 
-ElementPtr
-Element::get(const std::string& name UNUSED_PARAM) {
+ConstElementPtr
+Element::get(const std::string& name UNUSED_PARAM) const {
     isc_throw(TypeError, "get(string) called on a non-map Element");
 }
 
 void
 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");
 }
@@ -167,20 +166,20 @@
 }
 
 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");
 }
 
-ElementPtr
-Element::find(const std::string& identifier UNUSED_PARAM) {
+ConstElementPtr
+Element::find(const std::string& identifier UNUSED_PARAM) const {
     isc_throw(TypeError, "find(string) called on a non-map Element");
 }
 
 bool
 Element::find(const std::string& identifier UNUSED_PARAM,
-              ElementPtr& t UNUSED_PARAM)
-{
-    return false;
+              ConstElementPtr t UNUSED_PARAM) const
+{
+    return (false);
 }
 
 namespace {
@@ -193,12 +192,18 @@
 }
 }
 
-std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e) {
-    return out << e->str();
-}
-
-bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b) {
-    return a->equals(b);
+std::ostream&
+operator<<(std::ostream &out, const Element& e) {
+    return (out << e.str());
+}
+
+bool
+operator==(const Element& a, const Element& b) {
+    return (a.equals(b));
+}
+
+bool operator!=(const Element& a, const Element& b) {
+    return (!a.equals(b));
 };
 
 //
@@ -206,37 +211,37 @@
 //
 ElementPtr
 Element::create() {
-    return ElementPtr(new NullElement());
+    return (ElementPtr(new NullElement()));
 }
 
 ElementPtr
 Element::create(const long int i) {
-    return ElementPtr(new IntElement(i));
+    return (ElementPtr(new IntElement(i)));
 }
 
 ElementPtr
 Element::create(const double d) {
-    return ElementPtr(new DoubleElement(d));
+    return (ElementPtr(new DoubleElement(d)));
 }
 
 ElementPtr
 Element::create(const std::string& s) {
-    return ElementPtr(new StringElement(s));
+    return (ElementPtr(new StringElement(s)));
 }
 
 ElementPtr
 Element::create(const bool b) {
-    return ElementPtr(new BoolElement(b));
+    return (ElementPtr(new BoolElement(b)));
 }
 
 ElementPtr
 Element::createList() {
-    return ElementPtr(new ListElement());
+    return (ElementPtr(new ListElement()));
 }
 
 ElementPtr
 Element::createMap() {
-    return ElementPtr(new MapElement());
+    return (ElementPtr(new MapElement()));
 }
 
 
@@ -248,10 +253,10 @@
 char_in(const char c, const char *chars) {
     for (size_t i = 0; i < strlen(chars); ++i) {
         if (chars[i] == c) {
-            return true;
-        }
-    }
-    return false;
+            return (true);
+        }
+    }
+    return (false);
 }
 
 void
@@ -332,7 +337,7 @@
         c = in.get();
         ++pos;
     }
-    return ss.str();
+    return (ss.str());
 }
 
 std::string
@@ -342,7 +347,7 @@
         ss << (char) in.get();
     }
     pos += ss.str().size();
-    return ss.str();
+    return (ss.str());
 }
 
 static std::string
@@ -353,7 +358,7 @@
         ss << (char) in.get();
     }
     pos += ss.str().size();
-    return ss.str();
+    return (ss.str());
 }
 
 // Should we change from IntElement and DoubleElement to NumberElement
@@ -386,9 +391,9 @@
     }
     
     if (is_double) {
-        return Element::create(d);
-    } else {
-        return Element::create(i);
+        return (Element::create(d));
+    } else {
+        return (Element::create(i));
     }
 }
 
@@ -398,13 +403,13 @@
 {
     const std::string word = word_from_stringstream(in, pos);
     if (boost::iequals(word, "True")) {
-        return Element::create(true);
+        return (Element::create(true));
     } else if (boost::iequals(word, "False")) {
-        return Element::create(false);
+        return (Element::create(false));
     } else {
         throwJSONError(std::string("Bad boolean value: ") + word, file, line, pos);
         // above is a throw shortcurt, return empty is never reached
-        return ElementPtr();
+        return (ElementPtr());
     }
 }
 
@@ -414,17 +419,17 @@
 {
     const std::string word = word_from_stringstream(in, pos);
     if (boost::iequals(word, "null")) {
-        return Element::create();
+        return (Element::create());
     } else {
         throwJSONError(std::string("Bad null value: ") + word, file, line, pos);
-        return ElementPtr();
+        return (ElementPtr());
     }
 }
 
 ElementPtr
 from_stringstream_string(std::istream& in, const std::string& file, int& line, int& pos)
 {
-    return Element::create(str_from_stringstream(in, file, line, pos));
+    return (Element::create(str_from_stringstream(in, file, line, pos)));
 }
 
 ElementPtr
@@ -432,7 +437,7 @@
 {
     char c = 0;
     ElementPtr list = Element::createList();
-    ElementPtr cur_list_element;
+    ConstElementPtr cur_list_element;
 
     skip_chars(in, " \t\n", line, pos);
     while (c != EOF && c != ']') {
@@ -444,7 +449,7 @@
         c = in.get();
         pos++;
     }
-    return list;
+    return (list);
 }
 
 ElementPtr
@@ -466,7 +471,7 @@
             in.get();
             pos++;
 
-            ElementPtr value = Element::fromJSON(in, file, line, pos);
+            ConstElementPtr value = Element::fromJSON(in, file, line, pos);
             map->set(key, value);
             
             skip_to(in, file, line, pos, ",}", " \t\n");
@@ -474,53 +479,53 @@
             pos++;
         }
     }
-    return map;
+    return (map);
 }
 }
 
 std::string
 Element::typeToName(Element::types type)
 {
-    switch(type) {
+    switch (type) {
     case Element::integer:
-        return std::string("integer");
+        return (std::string("integer"));
     case Element::real:
-        return std::string("real");
+        return (std::string("real"));
     case Element::boolean:
-        return std::string("boolean");
+        return (std::string("boolean"));
     case Element::string:
-        return std::string("string");
+        return (std::string("string"));
     case Element::list:
-        return std::string("list");
+        return (std::string("list"));
     case Element::map:
-        return std::string("map");
+        return (std::string("map"));
     case Element::null:
-        return std::string("null");
+        return (std::string("null"));
     case Element::any:
-        return std::string("any");
+        return (std::string("any"));
     default:
-        return std::string("unknown");
+        return (std::string("unknown"));
     }
 }
 
 Element::types
 Element::nameToType(const std::string& type_name) {
     if (type_name == "integer") {
-        return Element::integer;
+        return (Element::integer);
     } else if (type_name == "real") {
-        return Element::real;
+        return (Element::real);
     } else if (type_name == "boolean") {
-        return Element::boolean;
+        return (Element::boolean);
     } else if (type_name == "string") {
-        return Element::string;
+        return (Element::string);
     } else if (type_name == "list") {
-        return Element::list;
+        return (Element::list);
     } else if (type_name == "map") {
-        return Element::map;
+        return (Element::map);
     } else if (type_name == "null") {
-        return Element::null;
+        return (Element::null);
     } else if (type_name == "any") {
-        return Element::any;
+        return (Element::any);
     } else {
         isc_throw(TypeError, type_name + " is not a valid type name");
     }
@@ -529,14 +534,14 @@
 ElementPtr
 Element::fromJSON(std::istream& in) throw(JSONError) {
     int line = 1, pos = 1;
-    return fromJSON(in, "<istream>", line, pos);
+    return (fromJSON(in, "<istream>", line, pos));
 }
 
 ElementPtr
 Element::fromJSON(std::istream& in, const std::string& file_name) throw(JSONError)
 {
     int line = 1, pos = 1;
-    return fromJSON(in, file_name, line, pos);
+    return (fromJSON(in, file_name, line, pos));
 }
 
 ElementPtr
@@ -602,7 +607,7 @@
         }
     }
     if (el_read) {
-        return element;
+        return (element);
     } else {
         isc_throw(JSONError, "nothing read");
     }
@@ -612,26 +617,23 @@
 Element::fromJSON(const std::string &in) {
     std::stringstream ss;
     ss << in;
-    return fromJSON(ss, "<string>");
+    return (fromJSON(ss, "<string>"));
 }
 
 // to JSON format
 
 void
-IntElement::toJSON(std::ostream& ss)
-{
+IntElement::toJSON(std::ostream& ss) const {
     ss << intValue();
 }
 
 void
-DoubleElement::toJSON(std::ostream& ss)
-{
+DoubleElement::toJSON(std::ostream& ss) const {
     ss << doubleValue();
 }
 
 void
-BoolElement::toJSON(std::ostream& ss)
-{
+BoolElement::toJSON(std::ostream& ss) const {
     if (boolValue()) {
         ss << "true";
     } else {
@@ -640,26 +642,23 @@
 }
 
 void
-NullElement::toJSON(std::ostream& ss)
-{
+NullElement::toJSON(std::ostream& ss) const {
     ss << "null";
 }
 
 void
-StringElement::toJSON(std::ostream& ss)
-{
+StringElement::toJSON(std::ostream& ss) const {
     ss << "\"";
     ss << stringValue();
     ss << "\"";
 }
 
 void
-ListElement::toJSON(std::ostream& ss)
-{
+ListElement::toJSON(std::ostream& ss) const {
     ss << "[ ";
 
-    const std::vector<ElementPtr>& v = listValue();
-    for (std::vector<ElementPtr>::const_iterator it = v.begin();
+    const std::vector<ConstElementPtr>& v = listValue();
+    for (std::vector<ConstElementPtr>::const_iterator it = v.begin();
          it != v.end(); ++it) {
         if (it != v.begin()) {
             ss << ", ";
@@ -670,12 +669,11 @@
 }
 
 void
-MapElement::toJSON(std::ostream& ss)
-{
+MapElement::toJSON(std::ostream& ss) const {
     ss << "{ ";
 
-    const std::map<std::string, ElementPtr>& m = mapValue();
-    for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+    const std::map<std::string, ConstElementPtr>& m = mapValue();
+    for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
          it != m.end(); ++it) {
         if (it != m.begin()) {
             ss << ", ";
@@ -694,22 +692,22 @@
 // we're looking for) is not a MapElement
 // returns 0 if it could simply not be found
 // should that also be an exception?
-ElementPtr
-MapElement::find(const std::string& id) {
+ConstElementPtr
+MapElement::find(const std::string& id) const {
     const size_t sep = id.find('/');
     if (sep == std::string::npos) {
-        return get(id);
-    } else {
-        ElementPtr ce = get(id.substr(0, sep));
+        return (get(id));
+    } else {
+        ConstElementPtr ce = get(id.substr(0, sep));
         if (ce) {
             // ignore trailing slash
             if  (sep + 1 != id.size()) {
-                return ce->find(id.substr(sep + 1));
+                return (ce->find(id.substr(sep + 1)));
             } else {
-                return ce;
+                return (ce);
             }
         } else {
-            return ElementPtr();
+            return (ElementPtr());
         }
     }
 }
@@ -719,7 +717,7 @@
     std::stringstream ss;
     ss << s;
     int line = 0, pos = 0;
-    return fromJSON(ss, "<wire>", line, pos);
+    return (fromJSON(ss, "<wire>", line, pos));
 }
 
 ElementPtr
@@ -735,87 +733,88 @@
     //}
     //length -= 4;
     int line = 0, pos = 0;
-    return fromJSON(in, "<wire>", line, pos);
-}
-
-void
-MapElement::set(const std::string& key, ElementPtr value) {
+    return (fromJSON(in, "<wire>", line, pos));
+}
+
+void
+MapElement::set(const std::string& key, ConstElementPtr value) {
     m[key] = value;
 }
 
 bool
-MapElement::find(const std::string& id, ElementPtr& t) {
+MapElement::find(const std::string& id, ConstElementPtr t) const {
     try {
-        ElementPtr p = find(id);
+        ConstElementPtr p = find(id);
         if (p) {
             t = p;
-            return true;
+            return (true);
         }
     } catch (const TypeError& e) {
         // ignore
     }
-    return false;
-}
-
-bool
-IntElement::equals(ElementPtr other) {
-    return (other->getType() == Element::integer) &&
-           (i == other->intValue());
-}
-
-bool
-DoubleElement::equals(ElementPtr other) {
-    return (other->getType() == Element::real) &&
-           (d == other->doubleValue());
-}
-
-bool
-BoolElement::equals(ElementPtr other) {
-    return (other->getType() == Element::boolean) &&
-           (b == other->boolValue());
-}
-
-bool
-NullElement::equals(ElementPtr other) {
-    return other->getType() == Element::null;
-}
-
-bool
-StringElement::equals(ElementPtr other) {
-    return (other->getType() == Element::string) &&
-           (s == other->stringValue());
-}
-
-bool
-ListElement::equals(ElementPtr other) {
-    if (other->getType() == Element::list) {
+    return (false);
+}
+
+bool
+IntElement::equals(const Element& other) const {
+    return (other.getType() == Element::integer) &&
+           (i == other.intValue());
+}
+
+bool
+DoubleElement::equals(const Element& other) const {
+    return (other.getType() == Element::real) &&
+           (d == other.doubleValue());
+}
+
+bool
+BoolElement::equals(const Element& other) const {
+    return (other.getType() == Element::boolean) &&
+           (b == other.boolValue());
+}
+
+bool
+NullElement::equals(const Element& other) const {
+    return (other.getType() == Element::null);
+}
+
+bool
+StringElement::equals(const Element& other) const {
+    return (other.getType() == Element::string) &&
+           (s == other.stringValue());
+}
+
+bool
+ListElement::equals(const Element& other) const {
+    if (other.getType() == Element::list) {
         const int s = size();
-        if (s != other->size()) {
-            return false;
+        if (s != other.size()) {
+            return (false);
         }
         for (int i = 0; i < s; ++i) {
-            if (!get(i)->equals(other->get(i))) {
-                return false;
+            if (!get(i)->equals(*other.get(i))) {
+                return (false);
             }
         }
-        return true;
-    } else {
-        return false;
-    }
-}
-
-bool
-MapElement::equals(ElementPtr other) {
-    if (other->getType() == Element::map) {
-        std::map<std::string, ElementPtr> m = mapValue();
-        for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+        return (true);
+    } else {
+        return (false);
+    }
+}
+
+bool
+MapElement::equals(const Element& other) const {
+    if (other.getType() == Element::map) {
+        const std::map<std::string, ConstElementPtr>& m = mapValue();
+        for (std::map<std::string, ConstElementPtr>::const_iterator it =
+                 m.begin();
              it != m.end() ; ++it) {
-            if (other->contains((*it).first)) {
-                if (!get((*it).first)->equals(other->get((*it).first))) {
-                    return false;
+            if (other.contains((*it).first)) {
+                if (!get((*it).first)->equals(*other.get((*it).first))) {
+                    return (false);
                 }
             } else {
-                return false;
+                return (false);
             }
         }
         // quickly walk through the other map too, to see if there's
@@ -823,26 +822,27 @@
         // compare those elements; if one of them is missing we
         // differ (and if it's not missing the loop above has checked
         // it)
-        m = other->mapValue();
-        for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
-             it != m.end() ; ++it) {
+        std::map<std::string, ConstElementPtr>::const_iterator it;
+        for (it = other.mapValue().begin();
+             it != other.mapValue().end();
+             ++it) {
             if (!contains((*it).first)) {
-                return false;
+                return (false);
             }
         }
-        return true;
-    } else {
-        return false;
-    }
-}
-
-bool
-isNull(ElementPtr p) {
-    return !p;
-}
-
-void
-removeIdentical(ElementPtr a, const ElementPtr b) {
+        return (true);
+    } else {
+        return (false);
+    }
+}
+
+bool
+isNull(ConstElementPtr p) {
+    return (!p);
+}
+
+void
+removeIdentical(ElementPtr a, ConstElementPtr b) {
     if (!b) {
         return;
     }
@@ -850,26 +850,50 @@
         isc_throw(TypeError, "Non-map Elements passed to removeIdentical");
     }
 
-    std::map<std::string, ElementPtr> m = a->mapValue();
-    for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+    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)) {
-            if (a->get((*it).first)->equals(b->get((*it).first))) {
+            if (a->get((*it).first)->equals(*b->get((*it).first))) {
                 a->remove((*it).first);
             }
         }
     }
 }
 
-void
-merge(ElementPtr element, const ElementPtr other) {
+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
+merge(ElementPtr element, ConstElementPtr other) {
     if (element->getType() != Element::map ||
         other->getType() != Element::map) {
         isc_throw(TypeError, "merge arguments not MapElements");
     }
     
-    std::map<std::string, ElementPtr> m = other->mapValue();
-    for (std::map<std::string, ElementPtr>::const_iterator it = m.begin();
+    std::map<std::string, ConstElementPtr> m = other->mapValue();
+    for (std::map<std::string, ConstElementPtr>::const_iterator it = m.begin();
          it != m.end() ; ++it) {
         if ((*it).second && (*it).second->getType() != Element::null) {
             element->set((*it).first, (*it).second);

Modified: branches/trac308/src/lib/cc/data.h
==============================================================================
--- branches/trac308/src/lib/cc/data.h (original)
+++ branches/trac308/src/lib/cc/data.h Mon Sep 20 11:07:54 2010
@@ -29,6 +29,7 @@
 class Element;
 // todo: describe the rationale behind 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
@@ -90,7 +91,7 @@
     virtual ~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
     /// child elements; note that this is different from stringValue(),
@@ -99,24 +100,24 @@
     /// The resulting string will contain the Element in JSON format.
     ///
     /// \return std::string containing the string representation
-    std::string str();
+    std::string str() const;
 
     /// Returns the wireformat for the Element and all its child
     /// elements.
     ///
     /// \return std::string containing the element in wire format
-    std::string toWire();
-    void toWire(std::ostream& out);
+    std::string toWire() const;
+    void toWire(std::ostream& out) const;
 
     /// \name pure virtuals, every derived class must implement these
 
     /// \returns true if the other ElementPtr has the same type and
     ///          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
     /// the given stringstream.
-    virtual void toJSON(std::ostream& ss) = 0;
+    virtual void toJSON(std::ostream& ss) const = 0;
 
     /// \name Type-specific getters
     ///
@@ -126,12 +127,22 @@
     /// If you want an exception-safe getter method, use
     /// getValue() below
     //@{
-    virtual long int intValue() { isc_throw(TypeError, "intValue() called on non-integer Element"); };
-    virtual double doubleValue() { isc_throw(TypeError, "doubleValue() called on non-double Element"); };
-    virtual bool boolValue() { isc_throw(TypeError, "boolValue() called on non-Bool Element"); };
-    virtual std::string stringValue() { isc_throw(TypeError, "stringValue() called on non-string 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 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?
+    virtual long int intValue() const
+    { isc_throw(TypeError, "intValue() called on non-integer Element"); };
+    virtual double doubleValue() const
+    { isc_throw(TypeError, "doubleValue() called on non-double Element"); };
+    virtual bool boolValue() const
+    { 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
@@ -147,8 +158,8 @@
     virtual bool getValue(double& t);
     virtual bool getValue(bool& t);
     virtual bool getValue(std::string& t);
-    virtual bool getValue(std::vector<ElementPtr>& t);
-    virtual bool getValue(std::map<std::string, ElementPtr>& t);
+    virtual bool getValue(std::vector<ConstElementPtr>& t);
+    virtual bool getValue(std::map<std::string, ConstElementPtr>& t);
     //@}
 
     ///
@@ -163,8 +174,8 @@
     virtual bool setValue(const double v);
     virtual bool setValue(const bool t);
     virtual bool setValue(const std::string& v);
-    virtual bool setValue(const std::vector<ElementPtr>& v);
-    virtual bool setValue(const std::map<std::string, ElementPtr>& v);
+    virtual bool setValue(const std::vector<ConstElementPtr>& v);
+    virtual bool setValue(const std::map<std::string, ConstElementPtr>& v);
     //@}
 
 
@@ -179,17 +190,17 @@
     /// Returns the ElementPtr at the given index. If the index is out
     /// of bounds, this function throws an std::out_of_range exception.
     /// \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
     /// of bounds, this function throws an std::out_of_range exception.
     /// \param i The position of the ElementPtr to set
     /// \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
     /// \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
     /// of nothing happens.
@@ -197,7 +208,7 @@
     virtual void remove(const int i);
 
     /// Returns the number of elements in the list.
-    virtual size_t size();
+    virtual size_t size() const;
     //@}
 
     
@@ -209,11 +220,11 @@
     /// Returns the ElementPtr at the given key
     /// \param name The key of the Element to return
     /// \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
     /// \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
     /// \param name The key of the Element to remove
@@ -222,7 +233,7 @@
     /// Checks if there is data at the given key
     /// \param name The key of the Element to remove
     /// \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
     /// identifier is a /-separated list of names of nested maps, with
@@ -237,13 +248,13 @@
     /// \return The ElementPtr at the given identifier. Returns a
     /// null ElementPtr if it is not found, which can be checked with
     /// Element::is_null(ElementPtr e).
-    virtual ElementPtr find(const std::string& identifier);
+    virtual ConstElementPtr find(const std::string& identifier) const;
 
     /// See \c Element::find()
     /// \param identifier The identifier of the element to find
     /// \param t Reference to store the resulting ElementPtr, if found.
     /// \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;
     //@}
 
 
@@ -265,13 +276,13 @@
     //@{
     static ElementPtr create();
     static ElementPtr create(const long int i);
-    static ElementPtr create(const int i) { return create(static_cast<long int>(i)); };
+    static ElementPtr create(const int i) { return (create(static_cast<long int>(i))); };
     static ElementPtr create(const double d);
     static ElementPtr create(const bool b);
     static ElementPtr create(const std::string& s);
     // need both std:string and char *, since c++ will match
     // bool before std::string when you pass it a char *
-    static ElementPtr create(const char *s) { return create(std::string(s)); };
+    static ElementPtr create(const char *s) { return (create(std::string(s))); }
 
     /// \brief Creates an empty ListElement type ElementPtr.
     static ElementPtr createList();
@@ -364,14 +375,14 @@
     long int i;
 
 public:
-    IntElement(long int v) : Element(integer), i(v) { };
-    long int intValue() { return i; }
+    IntElement(long int v) : Element(integer), i(v) { }
+    long int intValue() const { return (i); }
     using Element::getValue;
-    bool getValue(long int& t) { t = i; return true; };
+    bool getValue(long int& t) { t = i; return (true); }
     using Element::setValue;
-    bool setValue(const long int v) { i = v; return true; };
-    void toJSON(std::ostream& ss);
-    bool equals(ElementPtr other);
+    bool setValue(const long int v) { i = v; return (true); }
+    void toJSON(std::ostream& ss) const;
+    bool equals(const Element& other) const;
 };
 
 class DoubleElement : public Element {
@@ -379,13 +390,13 @@
 
 public:
     DoubleElement(double v) : Element(real), d(v) {};
-    double doubleValue() { return d; }
+    double doubleValue() const { return (d); }
     using Element::getValue;
-    bool getValue(double& t) { t = d; return true; };
+    bool getValue(double& t) { t = d; return (true); }
     using Element::setValue;
-    bool setValue(const double v) { d = v; return true; };
-    void toJSON(std::ostream& ss);
-    bool equals(ElementPtr other);
+    bool setValue(const double v) { d = v; return (true); }
+    void toJSON(std::ostream& ss) const;
+    bool equals(const Element& other) const;
 };
 
 class BoolElement : public Element {
@@ -393,20 +404,20 @@
 
 public:
     BoolElement(const bool v) : Element(boolean), b(v) {};
-    bool boolValue() { return b; }
+    bool boolValue() const { return (b); }
     using Element::getValue;
-    bool getValue(bool& t) { t = b; return true; };
+    bool getValue(bool& t) { t = b; return (true); }
     using Element::setValue;
-    bool setValue(const bool v) { b = v; return true; };
-    void toJSON(std::ostream& ss);
-    bool equals(ElementPtr other);
+    bool setValue(const bool v) { b = v; return (true); }
+    void toJSON(std::ostream& ss) const;
+    bool equals(const Element& other) const;
 };
 
 class NullElement : public Element {
 public:
     NullElement() : Element(null) {};
-    void toJSON(std::ostream& ss);
-    bool equals(ElementPtr other);
+    void toJSON(std::ostream& ss) const;
+    bool equals(const Element& other) const;
 };
 
 class StringElement : public Element {
@@ -414,77 +425,97 @@
 
 public:
     StringElement(std::string v) : Element(string), s(v) {};
-    std::string stringValue() { return s; };
+    std::string stringValue() const { return (s); }
     using Element::getValue;
-    bool getValue(std::string& t) { t = s; return true; };
+    bool getValue(std::string& t) { t = s; return (true); }
     using Element::setValue;
-    bool setValue(const std::string& v) { s = v; return true; };
-    void toJSON(std::ostream& ss);
-    bool equals(ElementPtr other);
+    bool setValue(const std::string& v) { s = v; return (true); }
+    void toJSON(std::ostream& ss) const;
+    bool equals(const Element& other) const;
 };
 
 class ListElement : public Element {
-    std::vector<ElementPtr> l;
-
-public:
-    ListElement() : Element(list), l(std::vector<ElementPtr>()) {};
-    const std::vector<ElementPtr>& listValue() { return l; }
+    std::vector<ConstElementPtr> l;
+
+public:
+    ListElement() : Element(list) {}
+    const std::vector<ConstElementPtr>& listValue() const { return (l); }
     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;
-    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;
-    ElementPtr get(int i) { return l.at(i); };
+    ConstElementPtr get(int i) const { return (l.at(i)); }
     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 add(ElementPtr e) { l.push_back(e); };
+    void set(size_t i, ConstElementPtr e) {
+        l.at(i) = e;
+    }
+    void add(ConstElementPtr e) { l.push_back(e); };
     using Element::remove;
     void remove(int i) { l.erase(l.begin() + i); };
-    void toJSON(std::ostream& ss);
-    size_t size() { return l.size(); }
-    bool equals(ElementPtr other);
+    void toJSON(std::ostream& ss) const;
+    size_t size() const { return (l.size()); }
+    bool equals(const Element& other) const;
 };
 
 class MapElement : public Element {
-    std::map<std::string, ElementPtr> m;
-
-public:
-    MapElement() : Element(map), m(std::map<std::string, ElementPtr>()) {};
+    std::map<std::string, ConstElementPtr> m;
+
+public:
+    MapElement() : Element(map) {}
     // 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;
-    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;
-    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;
-    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;
-    void set(const std::string& key, ElementPtr value);
+    void set(const std::string& key, ConstElementPtr value);
     using Element::remove;
     void remove(const std::string& s) { m.erase(s); }
-    bool contains(const std::string& s) { return m.find(s) != m.end(); }
-    void toJSON(std::ostream& ss);
+    bool contains(const std::string& s) const {
+        return (m.find(s) != m.end());
+    }
+    void toJSON(std::ostream& ss) const;
     
     // we should name the two finds better...
     // find the element at id; raises TypeError if one of the
     // elements at path except the one we're looking for is not a
     // mapelement.
     // 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
     // returns true if found, or false if not found (either because
     // it doesnt exist or one of the elements in the path is not
     // a MapElement)
-    bool find(const std::string& id, ElementPtr& t);
-
-    bool equals(ElementPtr other);
+    bool find(const std::string& id, ConstElementPtr t) const;
+
+    bool equals(const Element& other) const;
 };
 
 /// Checks whether the given ElementPtr is a NULL pointer
 /// \param p The ElementPtr to check
 /// \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
@@ -493,7 +524,14 @@
 /// only contains new and changed values (for ModuleCCSession and
 /// configuration update handlers)
 /// 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.
 /// (on the first level). Both elements must be
@@ -507,7 +545,7 @@
 /// configuration data (which would then result in reverting back
 /// to the default).
 /// 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.
@@ -524,11 +562,11 @@
 /// \param e The \c ElementPtr object to insert.
 /// \return A reference to the same \c std::ostream object referenced by
 /// parameter \c os after the insertion operation.
-std::ostream& operator <<(std::ostream &out, const isc::data::ElementPtr& e);
-
-bool operator==(const isc::data::ElementPtr a, const isc::data::ElementPtr b);
+std::ostream& operator<<(std::ostream& out, const Element& e);
+
+bool operator==(const Element& a, const Element& b);
+bool operator!=(const Element& a, const Element& b);
 } }
-
 #endif // _ISC_DATA_H
 
 // Local Variables: 

Modified: branches/trac308/src/lib/cc/session.cc
==============================================================================
--- branches/trac308/src/lib/cc/session.cc (original)
+++ branches/trac308/src/lib/cc/session.cc Mon Sep 20 11:07:54 2010
@@ -28,6 +28,7 @@
 #include <unistd.h>             // for some IPC/network system calls
 #include <asio.hpp>
 #include <asio/error_code.hpp>
+#include <asio/deadline_timer.hpp>
 #include <asio/system_error.hpp>
 
 #include <cstdio>
@@ -38,7 +39,9 @@
 #include <sys/un.h>
 
 #include <boost/bind.hpp>
+#include <boost/optional.hpp>
 #include <boost/function.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
 
 #include <exceptions/exceptions.h>
 
@@ -53,20 +56,39 @@
 // (e.g. write(2)) so we don't import the entire asio namespace.
 using asio::io_service;
 
+namespace {
+/// \brief Sets the given Optional 'result' to the given error code
+/// Used as a callback for emulating sync reads with async calls
+/// \param result Pointer to the optional to set
+/// \param err The error code to set it to
+void
+setResult(boost::optional<asio::error_code>* result,
+          const asio::error_code& err)
+{
+    result->reset(err);
+}
+}
+
 namespace isc {
 namespace cc {
+
 class SessionImpl {
 public:
     SessionImpl(io_service& io_service) :
         sequence_(-1), queue_(Element::createList()),
-        io_service_(io_service), socket_(io_service_), data_length_(0)
+        io_service_(io_service), socket_(io_service_), data_length_(0),
+        timeout_(MSGQ_DEFAULT_TIMEOUT)
     {}
     void establish(const char& socket_file);
     void disconnect();
     void writeData(const void* data, size_t datalen);
     size_t readDataLength();
+    // Blocking read. Will throw a SessionTimeout if the timeout value
+    // (in seconds) is thrown. If timeout is 0 it will block forever
     void readData(void* data, size_t datalen);
     void startRead(boost::function<void()> user_handler);
+    void setTimeout(size_t seconds) { timeout_ = seconds; };
+    size_t getTimeout() const { return timeout_; };
 
     long int sequence_; // the next sequence number to use
     std::string lname_;
@@ -82,6 +104,17 @@
     uint32_t data_length_;
     boost::function<void()> user_handler_;
     asio::error_code error_;
+    size_t timeout_;
+
+    // By default, unless changed or disabled, blocking reads on
+    // the msgq channel will time out after 4 seconds in this
+    // implementation.
+    // This number is chosen to be low enough so that whatever
+    // component is blocking does not seem to be hanging, but
+    // still gives enough time for other modules to respond if they
+    // are busy. If this choice turns out to be a bad one, we can
+    // change it later.
+    static const size_t MSGQ_DEFAULT_TIMEOUT = 4000;
 };
 
 void
@@ -131,10 +164,53 @@
 
 void
 SessionImpl::readData(void* data, size_t datalen) {
+    boost::optional<asio::error_code> read_result;
+    boost::optional<asio::error_code> timer_result;
+
     try {
-        asio::read(socket_, asio::buffer(data, datalen));
+        asio::async_read(socket_, asio::buffer(data, datalen),
+                         boost::bind(&setResult, &read_result, _1));
+        asio::deadline_timer timer(socket_.io_service());
+    
+        if (getTimeout() != 0) {
+            timer.expires_from_now(boost::posix_time::milliseconds(getTimeout()));
+            timer.async_wait(boost::bind(&setResult, &timer_result, _1));
+        }
+
+        // wait until either we have read the data we want, the
+        // timer expires, or one of the two is triggered with an error.
+        // When one of them has a result, cancel the other, and wait
+        // until the cancel is processed before we continue
+        while (!read_result && !timer_result) {
+            socket_.io_service().run_one();
+
+            // Don't cancel the timer if we haven't set it
+            if (read_result && getTimeout() != 0) {
+                timer.cancel();
+                while (!timer_result) {
+                    socket_.io_service().run_one();
+                }
+            } else if (timer_result) {
+                socket_.cancel();
+                while (!read_result) {
+                    socket_.io_service().run_one();
+                }
+            }
+        }
+
+        // asio::error_code evaluates to false if there was no error
+        if (*read_result) {
+            if (*read_result == asio::error::operation_aborted) {
+                isc_throw(SessionTimeout,
+                          "Timeout while reading data from cc session");
+            } else {
+                isc_throw(SessionError,
+                          "Error while reading data from cc session: " <<
+                          read_result->message());
+            }
+        }
     } catch (const asio::system_error& asio_ex) {
-        // to hide boost specific exceptions, we catch them explicitly
+        // to hide ASIO specific exceptions, we catch them explicitly
         // and convert it to SessionError.
         isc_throw(SessionError, "ASIO read failed: " << asio_ex.what());
     }
@@ -144,11 +220,11 @@
 SessionImpl::startRead(boost::function<void()> user_handler) {
     data_length_ = 0;
     user_handler_ = user_handler;
-    async_read(socket_, asio::buffer(&data_length_,
-                                            sizeof(data_length_)),
-               boost::bind(&SessionImpl::internalRead, this,
-                           asio::placeholders::error,
-                           asio::placeholders::bytes_transferred));
+    asio::async_read(socket_, asio::buffer(&data_length_,
+                                           sizeof(data_length_)),
+                     boost::bind(&SessionImpl::internalRead, this,
+                                 asio::placeholders::error,
+                                 asio::placeholders::bytes_transferred));
 }
 
 void
@@ -220,11 +296,11 @@
     //
     // send a request for our local name, and wait for a response
     //
-    ElementPtr get_lname_msg =
+    ConstElementPtr get_lname_msg =
         Element::fromJSON("{ \"type\": \"getlname\" }");
     sendmsg(get_lname_msg);
 
-    ElementPtr routing, msg;
+    ConstElementPtr routing, msg;
     recvmsg(routing, msg, false);
 
     impl_->lname_ = msg->get("lname")->stringValue();
@@ -238,7 +314,7 @@
 // prefix.
 //
 void
-Session::sendmsg(ElementPtr& msg) {
+Session::sendmsg(ConstElementPtr msg) {
     std::string header_wire = msg->toWire();
     unsigned int length = 2 + header_wire.length();
     unsigned int length_net = htonl(length);
@@ -251,7 +327,7 @@
 }
 
 void
-Session::sendmsg(ElementPtr& env, ElementPtr& msg) {
+Session::sendmsg(ConstElementPtr env, ConstElementPtr msg) {
     std::string header_wire = env->toWire();
     std::string body_wire = msg->toWire();
     unsigned int length = 2 + header_wire.length() + body_wire.length();
@@ -266,18 +342,18 @@
 }
 
 bool
-Session::recvmsg(ElementPtr& msg, bool nonblock, int seq) {
-    ElementPtr l_env;
-    return recvmsg(l_env, msg, nonblock, seq);
+Session::recvmsg(ConstElementPtr& msg, bool nonblock, int seq) {
+    ConstElementPtr l_env;
+    return (recvmsg(l_env, msg, nonblock, seq));
 }
 
 bool
-Session::recvmsg(ElementPtr& env, ElementPtr& msg,
-                 bool nonblock, int seq) {
+Session::recvmsg(ConstElementPtr& env, ConstElementPtr& msg,
+                 bool nonblock, int seq)
+{
     size_t length = impl_->readDataLength();
-    ElementPtr l_env, l_msg;
     if (hasQueuedMsgs()) {
-        ElementPtr q_el;
+        ConstElementPtr q_el;
         for (int i = 0; i < impl_->queue_->size(); i++) {
             q_el = impl_->queue_->get(i);
             if (( seq == -1 &&
@@ -290,7 +366,7 @@
                    env = q_el->get(0);
                    msg = q_el->get(1);
                    impl_->queue_->remove(i);
-                   return true;
+                   return (true);
             }
         }
     }
@@ -314,11 +390,13 @@
                                         length - header_length);
     std::stringstream header_wire_stream;
     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;
     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 &&
          !l_env->contains("reply")
         ) || (
@@ -328,13 +406,13 @@
        ) {
         env = l_env;
         msg = l_msg;
-        return true;
+        return (true);
     } else {
         ElementPtr q_el = Element::createList();
         q_el->add(l_env);
         q_el->add(l_msg);
         impl_->queue_->add(q_el);
-        return recvmsg(env, msg, nonblock, seq);
+        return (recvmsg(env, msg, nonblock, seq));
     }
     // XXXMLG handle non-block here, and return false for short reads
 }
@@ -362,7 +440,7 @@
 }
 
 int
-Session::group_sendmsg(ElementPtr msg, std::string group,
+Session::group_sendmsg(ConstElementPtr msg, std::string group,
                        std::string instance, std::string to)
 {
     ElementPtr env = Element::createMap();
@@ -377,18 +455,18 @@
     //env->set("msg", Element::create(msg->toWire()));
 
     sendmsg(env, msg);
-    return nseq;
+    return (nseq);
 }
 
 bool
-Session::group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+Session::group_recvmsg(ConstElementPtr& envelope, ConstElementPtr& msg,
                        bool nonblock, int seq)
 {
     return (recvmsg(envelope, msg, nonblock, seq));
 }
 
 int
-Session::reply(ElementPtr& envelope, ElementPtr& newmsg) {
+Session::reply(ConstElementPtr envelope, ConstElementPtr newmsg) {
     ElementPtr env = Element::createMap();
     long int nseq = ++impl_->sequence_;
     
@@ -402,14 +480,22 @@
 
     sendmsg(env, newmsg);
 
-    return nseq;
+    return (nseq);
 }
 
 bool
-Session::hasQueuedMsgs()
-{
+Session::hasQueuedMsgs() const {
     return (impl_->queue_->size() > 0);
 }
 
-}
-}
+void
+Session::setTimeout(size_t milliseconds) {
+    impl_->setTimeout(milliseconds);
+}
+
+size_t
+Session::getTimeout() const {
+    return (impl_->getTimeout());
+}
+}
+}

Modified: branches/trac308/src/lib/cc/session.h
==============================================================================
--- branches/trac308/src/lib/cc/session.h (original)
+++ branches/trac308/src/lib/cc/session.h Mon Sep 20 11:07:54 2010
@@ -40,6 +40,15 @@
                 isc::Exception(file, line, what) {}
         };
 
+        /// \brief A standard Exception class that is thrown when a
+        /// blocking readData call does not read the given number of
+        /// bytes before the timeout expires
+        class SessionTimeout : public isc::Exception {
+        public:
+            SessionTimeout(const char* file, size_t line, const char* what) :
+                isc::Exception(file, line, what) {}
+        };
+
         /// \brief The AbstractSession class is an abstract base class that
         /// defines the interfaces of Session.
         /// The intended primary usage of abstraction is to allow tests for the
@@ -72,12 +81,12 @@
             //@}
             virtual void establish(const char* socket_file) = 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 instance = "*",
                                       std::string to = "*") = 0;
-            virtual bool group_recvmsg(isc::data::ElementPtr& envelope,
-                                       isc::data::ElementPtr& msg,
+            virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
+                                       isc::data::ConstElementPtr& msg,
                                        bool nonblock = true,
                                        int seq = -1) = 0;
             virtual void subscribe(std::string group,
@@ -85,9 +94,20 @@
             virtual void unsubscribe(std::string group,
                              std::string instance = "*") = 0;
             virtual void startRead(boost::function<void()> read_callback) = 0;
-            virtual int reply(isc::data::ElementPtr& envelope,
-                               isc::data::ElementPtr& newmsg) = 0;
-            virtual bool hasQueuedMsgs() = 0;
+            virtual int reply(isc::data::ConstElementPtr envelope,
+                               isc::data::ConstElementPtr newmsg) = 0;
+            virtual bool hasQueuedMsgs() const = 0;
+
+            /// \brief Sets the default timeout for blocking reads
+            ///        in this session to the given number of milliseconds
+            /// \param milliseconds the timeout for blocking reads in
+            ///        milliseconds, if this is set to 0, reads will block
+            ///        forever.
+            virtual void setTimeout(size_t milliseconds) = 0;
+
+            /// \brief Returns the current timeout for blocking reads
+            /// \return The timeout (in milliseconds)
+            virtual size_t getTimeout() const = 0;
         };
 
     class Session : public AbstractSession {
@@ -110,26 +130,28 @@
                                    std::string instance = "*");
             virtual void unsubscribe(std::string group,
                              std::string instance = "*");
-            virtual int group_sendmsg(isc::data::ElementPtr msg,
+            virtual int group_sendmsg(isc::data::ConstElementPtr msg,
                                       std::string group,
                                       std::string instance = "*",
                                       std::string to = "*");
-            virtual bool group_recvmsg(isc::data::ElementPtr& envelope,
-                                       isc::data::ElementPtr& msg,
+            virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
+                                       isc::data::ConstElementPtr& msg,
                                        bool nonblock = true,
                                        int seq = -1);
-            virtual int reply(isc::data::ElementPtr& envelope,
-                              isc::data::ElementPtr& newmsg);
-            virtual bool hasQueuedMsgs();
+            virtual int reply(isc::data::ConstElementPtr envelope,
+                              isc::data::ConstElementPtr newmsg);
+            virtual bool hasQueuedMsgs() const;
+            virtual void setTimeout(size_t milliseconds);
+            virtual size_t getTimeout() const;
     private:
-            void sendmsg(isc::data::ElementPtr& msg);
-            void sendmsg(isc::data::ElementPtr& env,
-                         isc::data::ElementPtr& msg);
-            bool recvmsg(isc::data::ElementPtr& msg,
+            void sendmsg(isc::data::ConstElementPtr msg);
+            void sendmsg(isc::data::ConstElementPtr env,
+                         isc::data::ConstElementPtr msg);
+            bool recvmsg(isc::data::ConstElementPtr& msg,
                          bool nonblock = true,
                          int seq = -1);
-            bool recvmsg(isc::data::ElementPtr& env,
-                         isc::data::ElementPtr& msg,
+            bool recvmsg(isc::data::ConstElementPtr& env,
+                         isc::data::ConstElementPtr& msg,
                          bool nonblock = true,
                          int seq = -1);
         };

Modified: branches/trac308/src/lib/config/Makefile.am
==============================================================================
--- branches/trac308/src/lib/config/Makefile.am (original)
+++ branches/trac308/src/lib/config/Makefile.am Mon Sep 20 11:07:54 2010
@@ -1,3 +1,5 @@
+SUBDIRS = . testdata tests
+
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CXXFLAGS = $(B10_CXXFLAGS) -Wno-strict-aliasing
@@ -7,16 +9,11 @@
 
 CLEANFILES = *.gcno *.gcda
 
-TESTS =
-if HAVE_GTEST
-SUBDIRS = . tests
-endif
-
 EXTRA_DIST =  testdata/b10-config-bad1.db
 EXTRA_DIST += testdata/b10-config-bad2.db
 EXTRA_DIST += testdata/b10-config-bad3.db
 EXTRA_DIST += testdata/b10-config-bad4.db
-EXTRA_DIST += testdata/b10-config.db
+EXTRA_DIST += testdata/b10-config.db.master #.db will be auto-generated
 EXTRA_DIST += testdata/data22_1.data
 EXTRA_DIST += testdata/data22_2.data
 EXTRA_DIST += testdata/data22_3.data

Modified: branches/trac308/src/lib/config/ccsession.cc
==============================================================================
--- branches/trac308/src/lib/config/ccsession.cc (original)
+++ branches/trac308/src/lib/config/ccsession.cc Mon Sep 20 11:07:54 2010
@@ -52,45 +52,47 @@
 namespace config {
 
 /// Creates a standard config/command protocol answer message
-ElementPtr
-createAnswer()
-{
+ConstElementPtr
+createAnswer() {
     ElementPtr answer = Element::fromJSON("{\"result\": [] }");
-    ElementPtr answer_content = answer->get("result");
+    ElementPtr answer_content = Element::createList();
     answer_content->add(Element::create(0));
-    return answer;
-}
-
-ElementPtr
-createAnswer(const int rcode, const ElementPtr arg)
-{
+    answer->set("result", answer_content);
+
+    return (answer);
+}
+
+ConstElementPtr
+createAnswer(const int rcode, ConstElementPtr arg) {
     if (rcode != 0 && (!arg || arg->getType() != Element::string)) {
         isc_throw(CCSessionError, "Bad or no argument for rcode != 0");
     }
     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(arg);
-    return answer;
-}
-
-ElementPtr
-createAnswer(const int rcode, const std::string& arg)
-{
+    answer->set("result", answer_content);
+
+    return (answer);
+}
+
+ConstElementPtr
+createAnswer(const int rcode, const std::string& arg) {
     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(arg));
-    return answer;
-}
-
-ElementPtr
-parseAnswer(int &rcode, const ElementPtr msg)
-{
+    answer->set("result", answer_content);
+
+    return (answer);
+}
+
+ConstElementPtr
+parseAnswer(int &rcode, ConstElementPtr msg) {
     if (msg &&
         msg->getType() == Element::map &&
         msg->contains("result")) {
-        ElementPtr result = msg->get("result");
+        ConstElementPtr result = msg->get("result");
         if (result->getType() != Element::list) {
             isc_throw(CCSessionError, "Result element in answer message is not a list");
         } else if (result->get(0)->getType() != Element::integer) {
@@ -99,13 +101,13 @@
         rcode = result->get(0)->intValue();
         if (result->size() > 1) {
             if (rcode == 0 || result->get(1)->getType() == Element::string) {
-                return result->get(1);
+                return (result->get(1));
             } else {
                 isc_throw(CCSessionError, "Error description in result with rcode != 0 is not a string");
             }
         } else {
             if (rcode == 0) {
-                return ElementPtr();
+                return (ElementPtr());
             } else {
                 isc_throw(CCSessionError, "Result with rcode != 0 does not have an error description");
             }
@@ -115,15 +117,13 @@
     }
 }
 
-ElementPtr
-createCommand(const std::string& command)
-{
-    return createCommand(command, ElementPtr());
-}
-
-ElementPtr
-createCommand(const std::string& command, ElementPtr arg)
-{
+ConstElementPtr
+createCommand(const std::string& command) {
+    return (createCommand(command, ElementPtr()));
+}
+
+ConstElementPtr
+createCommand(const std::string& command, ConstElementPtr arg) {
     ElementPtr cmd = Element::createMap();
     ElementPtr cmd_parts = Element::createList();
     cmd_parts->add(Element::create(command));
@@ -131,18 +131,17 @@
         cmd_parts->add(arg);
     }
     cmd->set("command", cmd_parts);
-    return cmd;
+    return (cmd);
 }
 
 /// Returns "" and empty ElementPtr() if this does not
 /// look like a command
-const std::string
-parseCommand(ElementPtr& arg, const ElementPtr command)
-{
+std::string
+parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
     if (command &&
         command->getType() == Element::map &&
         command->contains("command")) {
-        ElementPtr cmd = command->get("command");
+        ConstElementPtr cmd = command->get("command");
         if (cmd->getType() == Element::list &&
             cmd->size() > 0 &&
             cmd->get(0)->getType() == Element::string) {
@@ -151,7 +150,7 @@
             } else {
                 arg = ElementPtr();
             }
-            return cmd->get(0)->stringValue();
+            return (cmd->get(0)->stringValue());
         } else {
             isc_throw(CCSessionError, "Command part in command message missing, empty, or not a list");
         }
@@ -182,7 +181,7 @@
         exit(1);
     }
     file.close();
-    return module_spec;
+    return (module_spec);
 }
 
 void
@@ -198,10 +197,11 @@
 ModuleCCSession::ModuleCCSession(
     const std::string& spec_file_name,
     isc::cc::AbstractSession& session,
-    isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config),
-    isc::data::ElementPtr(*command_handler)(
-        const std::string& command, const isc::data::ElementPtr args)
-    ) throw (isc::cc::SessionError) :
+    isc::data::ConstElementPtr(*config_handler)(
+        isc::data::ConstElementPtr new_config),
+    isc::data::ConstElementPtr(*command_handler)(
+        const std::string& command, isc::data::ConstElementPtr args)
+    ) :
     session_(session)
 {
     module_specification_ = readModuleSpecification(spec_file_name);
@@ -210,19 +210,21 @@
     module_name_ = module_specification_.getFullSpec()->get("module_name")->stringValue();
     config_handler_ = config_handler;
     command_handler_ = command_handler;
-
-    ElementPtr answer, env;
 
     session_.establish(NULL);
     session_.subscribe(module_name_, "*");
     //session_.subscribe("Boss", "*");
     //session_.subscribe("statistics", "*");
     // 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");
+
+    ConstElementPtr answer, env;
     session_.group_recvmsg(env, answer, false, seq);
     int rcode;
-    ElementPtr err = parseAnswer(rcode, answer);
+    ConstElementPtr err = parseAnswer(rcode, answer);
     if (rcode != 0) {
         std::cerr << "[" << module_name_ << "] Error in specification: " << answer << std::endl;
     }
@@ -230,10 +232,10 @@
     setLocalConfig(Element::fromJSON("{}"));
     // get any stored configuration from the manager
     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");
         session_.group_recvmsg(env, answer, false, seq);
-        ElementPtr new_config = parseAnswer(rcode, answer);
+        ConstElementPtr new_config = parseAnswer(rcode, answer);
         if (rcode == 0) {
             handleConfigUpdate(new_config);
         } else {
@@ -248,55 +250,53 @@
 /// Validates the new config values, if they are correct,
 /// call the config handler with the values that have changed
 /// If that results in success, store the new config
-ElementPtr
-ModuleCCSession::handleConfigUpdate(ElementPtr new_config)
-{
-    ElementPtr answer;
+ConstElementPtr
+ModuleCCSession::handleConfigUpdate(ConstElementPtr new_config) {
+    ConstElementPtr answer;
     ElementPtr errors = Element::createList();
     if (!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;
         ss << "Error in config validation: ";
-        BOOST_FOREACH(ElementPtr error, errors->listValue()) {
+        BOOST_FOREACH(ConstElementPtr error, errors->listValue()) {
             ss << error->stringValue();
         }
         answer = createAnswer(2, ss.str());
     } else {
         // remove the values that have not changed
-        isc::data::removeIdentical(new_config, getLocalConfig());
+        ConstElementPtr diff = removeIdentical(new_config, getLocalConfig());
         // handle config update
-        answer = config_handler_(new_config);
+        answer = config_handler_(diff);
         int rcode;
         parseAnswer(rcode, answer);
         if (rcode == 0) {
             ElementPtr local_config = getLocalConfig();
-            isc::data::merge(local_config, new_config);
+            isc::data::merge(local_config, diff);
             setLocalConfig(local_config);
         }
     }
-    return answer;
+    return (answer);
 }
 
 bool
-ModuleCCSession::hasQueuedMsgs()
-{
+ModuleCCSession::hasQueuedMsgs() const {
     return (session_.hasQueuedMsgs());
 }
 
 int
-ModuleCCSession::checkCommand()
-{
-    ElementPtr cmd, routing, data;
+ModuleCCSession::checkCommand() {
+    ConstElementPtr cmd, routing, data;
     if (session_.group_recvmsg(routing, data, true)) {
         
         /* ignore result messages (in case we're out of sync, to prevent
          * pingpongs */
         if (data->getType() != Element::map || data->contains("result")) {
-            return 0;
-        }
-        ElementPtr arg;
-        ElementPtr answer;
+            return (0);
+        }
+        ConstElementPtr arg;
+        ConstElementPtr answer;
         try {
             std::string cmd_str = parseCommand(arg, data);
             std::string target_module = routing->get("group")->stringValue();
@@ -308,7 +308,7 @@
                     // in our remote config list, update that
                     updateRemoteConfig(target_module, arg);
                     // we're not supposed to answer to this, so return
-                    return 0;
+                    return (0);
                 }
             } else {
                 if (target_module == module_name_) {
@@ -319,7 +319,7 @@
                     }
                 }
             }
-        } catch (CCSessionError re) {
+        } catch (const CCSessionError& re) {
             // TODO: Once we have logging and timeouts, we should not
             // answer here (potential interference)
             answer = createAnswer(1, re.what());
@@ -329,7 +329,7 @@
         }
     }
     
-    return 0;
+    return (0);
 }
 
 std::string
@@ -341,22 +341,24 @@
     session_.subscribe(module_name);
 
     // Get the current configuration values for that module
-    ElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name + "\"} ] }");
-    ElementPtr env, answer;
+    ConstElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name + "\"} ] }");
+    unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
+
+    ConstElementPtr env, answer;
+    session_.group_recvmsg(env, answer, false, seq);
     int rcode;
-    
-    unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
-    session_.group_recvmsg(env, answer, false, seq);
-    ElementPtr new_config = parseAnswer(rcode, answer);
-    if (rcode == 0) {
-        rmod_config.setLocalConfig(new_config);
+    ConstElementPtr new_config = parseAnswer(rcode, answer);
+    if (rcode == 0 && new_config) {
+        ElementPtr local_config = rmod_config.getLocalConfig();
+        isc::data::merge(local_config, new_config);
+        rmod_config.setLocalConfig(local_config);
     } else {
         isc_throw(CCSessionError, "Error getting config for " + module_name + ": " + answer->str());
     }
 
     // all ok, add it
     remote_module_configs_[module_name] = rmod_config;
-    return module_name;
+    return (module_name);
 }
 
 void
@@ -371,21 +373,24 @@
     }
 }
 
-ElementPtr
-ModuleCCSession::getRemoteConfigValue(const std::string& module_name, const std::string& identifier)
+ConstElementPtr
+ModuleCCSession::getRemoteConfigValue(const std::string& module_name,
+                                      const std::string& identifier) const
 {
-    std::map<std::string, ConfigData>::iterator it;
-
-    it = remote_module_configs_.find(module_name);
+    std::map<std::string, ConfigData>::const_iterator it =
+        remote_module_configs_.find(module_name);
+
     if (it != remote_module_configs_.end()) {
-        return remote_module_configs_[module_name].getValue(identifier);
+        return ((*it).second.getValue(identifier));
     } else {
-        isc_throw(CCSessionError, "Remote module " + module_name + " not found.");
+        isc_throw(CCSessionError,
+                  "Remote module " + module_name + " not found.");
     }
 }
 
 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;
 

Modified: branches/trac308/src/lib/config/ccsession.h
==============================================================================
--- branches/trac308/src/lib/config/ccsession.h (original)
+++ branches/trac308/src/lib/config/ccsession.h Mon Sep 20 11:07:54 2010
@@ -31,7 +31,7 @@
 /// \brief Creates a standard config/command level success answer message
 ///        (i.e. of the form { "result": [ 0 ] }
 /// \return Standard command/config success answer message
-ElementPtr createAnswer();
+ConstElementPtr createAnswer();
 
 ///
 /// \brief Creates a standard config/command level answer message
@@ -43,7 +43,7 @@
 ///            Element type. For rcode == 1, this argument is mandatory,
 ///            and must be a StringElement containing an error description
 /// \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
@@ -52,7 +52,7 @@
 /// \param rcode The return code (0 for success)
 /// \param arg A string to put into the StringElement argument
 /// \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
@@ -63,8 +63,7 @@
 /// \return The optional argument in the message, or an empty ElementPtr
 ///         if there was no argument. If rcode != 0, this contains a
 ///         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
@@ -72,7 +71,7 @@
 /// 
 /// \param command The command string
 /// \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
@@ -82,7 +81,7 @@
 /// \param arg The optional argument for the command. This can be of 
 ///        any Element type, but it should conform to the .spec file.
 /// \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
@@ -93,7 +92,7 @@
 /// \param command The command message containing the command (as made
 ///        by createCommand()
 /// \return The command string
-const std::string parseCommand(ElementPtr& arg, const ElementPtr command);
+std::string parseCommand(ConstElementPtr& arg, ConstElementPtr command);
 
 
 ///
@@ -133,12 +132,12 @@
      */
     ModuleCCSession(const std::string& spec_file_name,
                     isc::cc::AbstractSession& session,
-                    isc::data::ElementPtr(*config_handler)(
-                        isc::data::ElementPtr new_config) = NULL,
-                    isc::data::ElementPtr(*command_handler)(
+                    isc::data::ConstElementPtr(*config_handler)(
+                        isc::data::ConstElementPtr new_config) = NULL,
+                    isc::data::ConstElementPtr(*command_handler)(
                         const std::string& command,
-                        const isc::data::ElementPtr args) = NULL
-                    ) throw (isc::cc::SessionError);
+                        isc::data::ConstElementPtr args) = NULL
+                    );
 
     /**
      * Optional optimization for checkCommand loop; returns true
@@ -148,7 +147,7 @@
      * 
      * @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
@@ -167,7 +166,11 @@
      * 100000 zones, where the whole list is passed every time a single
      * 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
@@ -179,7 +182,12 @@
      *
      * 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
@@ -217,7 +225,8 @@
      * \param identifier The identifier of the config value
      * \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:
     ModuleSpec readModuleSpecification(const std::string& filename);
@@ -226,13 +235,17 @@
     std::string module_name_;
     isc::cc::AbstractSession& session_;
     ModuleSpec module_specification_;
-    ElementPtr handleConfigUpdate(ElementPtr new_config);
-
-    isc::data::ElementPtr(*config_handler_)(isc::data::ElementPtr new_config);
-    isc::data::ElementPtr(*command_handler_)(const std::string& command, const isc::data::ElementPtr args);
+    ConstElementPtr handleConfigUpdate(ConstElementPtr new_config);
+
+    isc::data::ConstElementPtr(*config_handler_)(
+        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_;
-    void updateRemoteConfig(const std::string& module_name, ElementPtr new_config);
+    void updateRemoteConfig(const std::string& module_name,
+                            ConstElementPtr new_config);
 };
 
 }

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

Modified: branches/trac308/src/lib/config/config_data.h
==============================================================================
--- branches/trac308/src/lib/config/config_data.h (original)
+++ branches/trac308/src/lib/config/config_data.h Mon Sep 20 11:07:54 2010
@@ -40,7 +40,7 @@
     /// Constructs a ConfigData option with no specification and an
     /// empty configuration.
     ConfigData() { _config = Element::createMap(); };
-    
+
     /// Constructs a ConfigData option with the given specification
     /// and an empty configuration.
     /// \param module_spec A ModuleSpec for the relevant module
@@ -55,7 +55,7 @@
     /// Raises a DataNotFoundError if the identifier is bad.
     /// \param identifier The identifier pointing to the configuration
     ///        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
     /// If no value is set, the default value (as specified by the
@@ -67,25 +67,26 @@
     ///                   false otherwise
     /// \param identifier The identifier pointing to the configuration
     ///        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
-    const ModuleSpec getModuleSpec() { return _module_spec; };
-    
+    const ModuleSpec& getModuleSpec() const { return (_module_spec); }
+
     /// Set the ModuleSpec associated with this ConfigData object
     void setModuleSpec(ModuleSpec module_spec) { _module_spec = module_spec; };
-    
+
     /// Set the local configuration (i.e. all non-default values)
     /// \param config An ElementPtr pointing to a MapElement containing
     ///        *all* non-default configuration values. Existing values
     ///        will be removed.
     void setLocalConfig(ElementPtr config) { _config = config; }
-    
+
     /// Returns the local (i.e. non-default) configuration.
     /// \returns An ElementPtr pointing to a MapElement containing all
     ///          non-default configuration options.
-    ElementPtr getLocalConfig() { return _config; }
-    
+    ElementPtr getLocalConfig() { return (_config); }
+
     /// Returns a list of all possible configuration options as specified
     ///         by the ModuleSpec.
     /// \param identifier If given, show the items at the given identifier
@@ -96,14 +97,15 @@
     ///         StringElements that specify the identifiers at the given
     ///         location (or all possible identifiers if identifier==""
     ///         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).
     /// \return An ElementPtr pointing to a MapElement containing
     ///         string->value elements, where the string is the
     ///         full identifier of the configuration option and the
     ///         value is an ElementPtr with the value.
-    ElementPtr getFullConfig();
+    ConstElementPtr getFullConfig() const;
 
 private:
     ElementPtr _config;
@@ -113,3 +115,7 @@
 }
 }
 #endif
+
+// Local Variables: 
+// mode: c++
+// End: 

Modified: branches/trac308/src/lib/config/documentation.txt
==============================================================================
--- branches/trac308/src/lib/config/documentation.txt (original)
+++ branches/trac308/src/lib/config/documentation.txt Mon Sep 20 11:07:54 2010
@@ -53,7 +53,7 @@
 
 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.
 

Modified: branches/trac308/src/lib/config/module_spec.cc
==============================================================================
--- branches/trac308/src/lib/config/module_spec.cc (original)
+++ branches/trac308/src/lib/config/module_spec.cc Mon Sep 20 11:07:54 2010
@@ -24,15 +24,16 @@
 
 // todo: add more context to thrown ModuleSpecErrors?
 
-namespace isc {
-namespace config {
-
-//
-// static functions
-//
-
-static void
-check_leaf_item(const ElementPtr& spec, const std::string& name, Element::types type, bool mandatory)
+using namespace isc::config;
+
+namespace {
+//
+// Private functions
+//
+
+void
+check_leaf_item(ConstElementPtr spec, const std::string& name,
+                Element::types type, bool mandatory)
 {
     if (spec->contains(name)) {
         if (spec->get(name)->getType() == type) {
@@ -48,10 +49,10 @@
     }
 }
 
-static void check_config_item_list(const ElementPtr& spec);
-
-static void
-check_config_item(const ElementPtr& spec) {
+void check_config_item_list(ConstElementPtr spec);
+
+void
+check_config_item(ConstElementPtr spec) {
     check_leaf_item(spec, "item_name", Element::string, true);
     check_leaf_item(spec, "item_type", Element::string, true);
     check_leaf_item(spec, "item_optional", Element::boolean, true);
@@ -72,35 +73,35 @@
     }
 }
 
-static void
-check_config_item_list(const ElementPtr& spec) {
+void
+check_config_item_list(ConstElementPtr spec) {
     if (spec->getType() != Element::list) {
         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);
     }
 }
 
-static void
-check_command(const ElementPtr& spec) {
+void
+check_command(ConstElementPtr spec) {
     check_leaf_item(spec, "command_name", Element::string, true);
     check_leaf_item(spec, "command_args", Element::list, true);
     check_config_item_list(spec->get("command_args"));
 }
 
-static void
-check_command_list(const ElementPtr& spec) {
+void
+check_command_list(ConstElementPtr spec) {
     if (spec->getType() != Element::list) {
         throw ModuleSpecError("commands is not a list of elements");
     }
-    BOOST_FOREACH(ElementPtr item, spec->listValue()) {
+    BOOST_FOREACH(ConstElementPtr item, spec->listValue()) {
         check_command(item);
     }
 }
 
-static void
-check_data_specification(const ElementPtr& spec) {
+void
+check_data_specification(ConstElementPtr spec) {
     check_leaf_item(spec, "module_name", Element::string, true);
     check_leaf_item(spec, "module_description", Element::string, false);
     // config_data is not mandatory; module could just define
@@ -115,21 +116,23 @@
 
 // checks whether the given element is a valid module specification
 // throws a ModuleSpecError if the specification is bad
-static void
-check_module_specification(const ElementPtr& def)
-{
+void
+check_module_specification(ConstElementPtr def) {
     try {
         check_data_specification(def);
     } catch (TypeError te) {
         throw ModuleSpecError(te.what());
     }
 }
-
+}
+
+namespace isc {
+namespace config {
 //
 // Public functions
 //
 
-ModuleSpec::ModuleSpec(ElementPtr module_spec_element,
+ModuleSpec::ModuleSpec(ConstElementPtr module_spec_element,
                        const bool check)
                        throw(ModuleSpecError)
                        
@@ -140,54 +143,50 @@
     }
 }
 
-const ElementPtr
-ModuleSpec::getCommandsSpec() const
-{
+ConstElementPtr
+ModuleSpec::getCommandsSpec() const {
     if (module_specification->contains("commands")) {
-        return module_specification->get("commands");
-    } else {
-        return ElementPtr();
-    }
-}
-
-const ElementPtr
-ModuleSpec::getConfigSpec() const
-{
+        return (module_specification->get("commands"));
+    } else {
+        return (ElementPtr());
+    }
+}
+
+ConstElementPtr
+ModuleSpec::getConfigSpec() const {
     if (module_specification->contains("config_data")) {
-        return module_specification->get("config_data");
-    } else {
-        return ElementPtr();
+        return (module_specification->get("config_data"));
+    } else {
+        return (ElementPtr());
     }
 }
 
 const std::string
-ModuleSpec::getModuleName() const
-{
-    return module_specification->get("module_name")->stringValue();
+ModuleSpec::getModuleName() const {
+    return (module_specification->get("module_name")->stringValue());
 }
 
 const std::string
-ModuleSpec::getModuleDescription() const
-{
+ModuleSpec::getModuleDescription() const {
     if (module_specification->contains("module_description")) {
-        return module_specification->get("module_description")->stringValue();
-    } else {
-        return std::string("");
-    }
-}
-
-bool
-ModuleSpec::validate_config(const ElementPtr data, const bool full)
-{
-    ElementPtr spec = module_specification->find("config_data");
-    return validate_spec_list(spec, data, full, ElementPtr());
-}
-
-bool
-ModuleSpec::validate_config(const ElementPtr data, const bool full, ElementPtr errors)
-{
-    ElementPtr spec = module_specification->find("config_data");
-    return validate_spec_list(spec, data, full, errors);
+        return (module_specification->get("module_description")->stringValue());
+    } else {
+        return (std::string(""));
+    }
+}
+
+bool
+ModuleSpec::validate_config(ConstElementPtr data, const bool full) const {
+    ConstElementPtr spec = module_specification->find("config_data");
+    return (validate_spec_list(spec, data, full, ElementPtr()));
+}
+
+bool
+ModuleSpec::validate_config(ConstElementPtr data, const bool full,
+                            ElementPtr errors) const
+{
+    ConstElementPtr spec = module_specification->find("config_data");
+    return (validate_spec_list(spec, data, full, errors));
 }
 
 ModuleSpec
@@ -203,9 +202,9 @@
         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")) {
-        return ModuleSpec(module_spec_element->get("module_spec"), check);
+        return (ModuleSpec(module_spec_element->get("module_spec"), check));
     } else {
         throw ModuleSpecError("No module_spec in specification");
     }
@@ -213,16 +212,18 @@
 
 ModuleSpec
 moduleSpecFromFile(std::ifstream& in, const bool check)
-                   throw(JSONError, ModuleSpecError) {
-    ElementPtr module_spec_element = Element::fromJSON(in);
+                   throw(JSONError, ModuleSpecError)
+{
+    ConstElementPtr module_spec_element = Element::fromJSON(in);
     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 {
         throw ModuleSpecError("No module_spec in specification");
     }
 }
 
 
+namespace {
 //
 // private functions
 //
@@ -230,39 +231,41 @@
 //
 // helper functions for validation
 //
-static bool
-check_type(ElementPtr spec, ElementPtr element)
-{
+bool
+check_type(ConstElementPtr spec, ConstElementPtr element) {
     std::string cur_item_type;
     cur_item_type = spec->get("item_type")->stringValue();
     if (cur_item_type == "any") {
-        return true;
+        return (true);
     }
     switch (element->getType()) {
         case Element::integer:
-            return cur_item_type == "integer";
+            return (cur_item_type == "integer");
             break;
         case Element::real:
-            return cur_item_type == "real";
+            return (cur_item_type == "real");
             break;
         case Element::boolean:
-            return cur_item_type == "boolean";
+            return (cur_item_type == "boolean");
             break;
         case Element::string:
-            return cur_item_type == "string";
+            return (cur_item_type == "string");
             break;
         case Element::list:
-            return cur_item_type == "list";
+            return (cur_item_type == "list");
             break;
         case Element::map:
-            return cur_item_type == "map";
-            break;
-    }
-    return false;
-}
-
-bool
-ModuleSpec::validate_item(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors) {
+            return (cur_item_type == "map");
+            break;
+    }
+    return (false);
+}
+}
+
+bool
+ModuleSpec::validate_item(ConstElementPtr spec, ConstElementPtr data,
+                          const bool full, ElementPtr errors) const
+{
     if (!check_type(spec, data)) {
         // we should do some proper error feedback here
         // std::cout << "type mismatch; not " << spec->get("item_type") << ": " << data << std::endl;
@@ -270,67 +273,70 @@
         if (errors) {
             errors->add(Element::create("Type mismatch"));
         }
-        return false;
+        return (false);
     }
     if (data->getType() == Element::list) {
-        ElementPtr list_spec = spec->get("list_item_spec");
-        BOOST_FOREACH(ElementPtr list_el, data->listValue()) {
+        ConstElementPtr list_spec = spec->get("list_item_spec");
+        BOOST_FOREACH(ConstElementPtr list_el, data->listValue()) {
             if (!check_type(list_spec, list_el)) {
                 if (errors) {
                     errors->add(Element::create("Type mismatch"));
                 }
-                return false;
+                return (false);
             }
             if (list_spec->get("item_type")->stringValue() == "map") {
                 if (!validate_item(list_spec, list_el, full, errors)) {
-                    return false;
+                    return (false);
                 }
             }
         }
     }
     if (data->getType() == Element::map) {
         if (!validate_spec_list(spec->get("map_item_spec"), data, full, errors)) {
-            return false;
-        }
-    }
-    return true;
+            return (false);
+        }
+    }
+    return (true);
 }
 
 // spec is a map with item_name etc, data is a map
 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();
     bool optional = spec->get("item_optional")->boolValue();
-    ElementPtr data_el;
+    ConstElementPtr data_el;
     data_el = data->get(item_name);
     
     if (data_el) {
         if (!validate_item(spec, data_el, full, errors)) {
-            return false;
+            return (false);
         }
     } else {
         if (!optional && full) {
             if (errors) {
                 errors->add(Element::create("Non-optional value missing"));
             }
-            return false;
-        }
-    }
-    return true;
+            return (false);
+        }
+    }
+    return (true);
 }
 
 // spec is a list of maps, data is a map
 bool
-ModuleSpec::validate_spec_list(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors) {
-    ElementPtr cur_data_el;
+ModuleSpec::validate_spec_list(ConstElementPtr spec, ConstElementPtr data,
+                               const bool full, ElementPtr errors) const
+{
     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)) {
-            return false;
-        }
-    }
-    return true;
-}
-
-}
-}
+            return (false);
+        }
+    }
+    return (true);
+}
+
+}
+}

Modified: branches/trac308/src/lib/config/module_spec.h
==============================================================================
--- branches/trac308/src/lib/config/module_spec.h (original)
+++ branches/trac308/src/lib/config/module_spec.h Mon Sep 20 11:07:54 2010
@@ -34,7 +34,7 @@
     public:
         ModuleSpecError(std::string m = "Module specification is invalid") : msg(m) {}
         ~ModuleSpecError() throw() {}
-        const char* what() const throw() { return msg.c_str(); }
+        const char* what() const throw() { return (msg.c_str()); }
     private:
         std::string msg;
     };
@@ -51,28 +51,28 @@
     ///
     class ModuleSpec {
     public:
-        explicit ModuleSpec() {};
+        ModuleSpec() {};
         /// Create a \c ModuleSpec instance with the given data as
         /// the specification
         /// \param e The Element containing the data specification
-        explicit ModuleSpec(ElementPtr e, const bool check = true)
-                            throw(ModuleSpecError);
+        explicit ModuleSpec(ConstElementPtr e, const bool check = true)
+            throw(ModuleSpecError);
 
         /// Returns the commands part of the specification as an
         /// ElementPtr, returns an empty ElementPtr if there is none
         /// \return ElementPtr Shared pointer to the commands
         ///                    part of the specification
-        const ElementPtr getCommandsSpec() const;
+        ConstElementPtr getCommandsSpec() const;
 
         /// Returns the configuration part of the specification as an
         /// ElementPtr
         /// \return ElementPtr Shared pointer to the configuration
         ///                    part of the specification
-        const ElementPtr getConfigSpec() const;
+        ConstElementPtr getConfigSpec() const;
 
         /// Returns the full module specification as an ElementPtr
         /// \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
         const std::string getModuleName() const;
@@ -87,17 +87,22 @@
         /// \param data The base \c Element of the data to check
         /// \return true if the data conforms to the specification,
         /// 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
-        bool validate_config(const ElementPtr data, const bool full, ElementPtr errors);
+        bool validate_config(ConstElementPtr data, const bool full,
+                             ElementPtr errors) const;
 
     private:
-        bool validate_item(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors);
-        bool validate_spec(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors);
-        bool validate_spec_list(const ElementPtr spec, const ElementPtr data, const bool full, ElementPtr errors);
+        bool validate_item(ConstElementPtr spec, ConstElementPtr data,
+                           const bool full, ElementPtr errors) const;
+        bool validate_spec(ConstElementPtr spec, ConstElementPtr data,
+                           const bool full, ElementPtr errors) const;
+        bool validate_spec_list(ConstElementPtr spec, ConstElementPtr data,
+                                const bool full, ElementPtr errors) const;
 
-        ElementPtr module_specification;
+        ConstElementPtr module_specification;
     };
 
     /// Creates a \c ModuleSpec instance from the contents
@@ -126,3 +131,7 @@
 } }
 
 #endif // _DATA_DEF_H
+
+// Local Variables: 
+// mode: c++
+// End: 

Modified: branches/trac308/src/lib/config/tests/Makefile.am
==============================================================================
--- branches/trac308/src/lib/config/tests/Makefile.am (original)
+++ branches/trac308/src/lib/config/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -4,6 +4,10 @@
 # see src/lib/cc/Makefile.am for -Wno-unused-parameter
 if USE_GXX
 AM_CXXFLAGS += -Wno-unused-parameter
+endif
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
 endif
 
 CLEANFILES = *.gcno *.gcda
@@ -17,15 +21,13 @@
 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_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 += $(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 += $(top_builddir)/src/lib/config/libcfgclient.la
-# link *only* to data.o from lib/cc (more importantly, don't link in
-# the session class provided there, since we use our own fake_session
-# here)
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/data.o
 
 endif
 

Modified: branches/trac308/src/lib/config/tests/ccsession_unittests.cc
==============================================================================
--- branches/trac308/src/lib/config/tests/ccsession_unittests.cc (original)
+++ branches/trac308/src/lib/config/tests/ccsession_unittests.cc Mon Sep 20 11:07:54 2010
@@ -34,12 +34,12 @@
 namespace {
 std::string
 ccspecfile(const std::string name) {
-    return std::string(TEST_DATA_PATH) + "/" + name;
+    return (std::string(TEST_DATA_PATH) + "/" + name);
 }
 
 ElementPtr
 el(const std::string& str) {
-    return Element::fromJSON(str);
+    return (Element::fromJSON(str));
 }
 
 class CCSessionTest : public ::testing::Test {
@@ -57,7 +57,7 @@
 };
 
 TEST_F(CCSessionTest, createAnswer) {
-    ElementPtr answer;
+    ConstElementPtr answer;
     answer = createAnswer();
     EXPECT_EQ("{ \"result\": [ 0 ] }", answer->str());
     answer = createAnswer(1, "error");
@@ -66,14 +66,14 @@
     EXPECT_THROW(createAnswer(1, ElementPtr()), CCSessionError);
     EXPECT_THROW(createAnswer(1, Element::create(1)), CCSessionError);
 
-    ElementPtr arg = el("[ \"just\", \"some\", \"data\" ]");
+    ConstElementPtr arg = el("[ \"just\", \"some\", \"data\" ]");
     answer = createAnswer(0, arg);
     EXPECT_EQ("{ \"result\": [ 0, [ \"just\", \"some\", \"data\" ] ] }", answer->str());
 }
 
 TEST_F(CCSessionTest, parseAnswer) {
-    ElementPtr answer;
-    ElementPtr arg;
+    ConstElementPtr answer;
+    ConstElementPtr arg;
     int rcode;
 
     EXPECT_THROW(parseAnswer(rcode, ElementPtr()), CCSessionError);
@@ -103,8 +103,8 @@
 }
 
 TEST_F(CCSessionTest, createCommand) {
-    ElementPtr command;
-    ElementPtr arg;
+    ConstElementPtr command;
+    ConstElementPtr arg;
 
     command = createCommand("my_command");
     ASSERT_EQ("{ \"command\": [ \"my_command\" ] }", command->str());
@@ -123,7 +123,7 @@
 }
 
 TEST_F(CCSessionTest, parseCommand) {
-    ElementPtr arg;
+    ConstElementPtr arg;
     std::string cmd;
 
     // should throw
@@ -155,7 +155,7 @@
     EXPECT_EQ(true, session.haveSubscription("Spec1", "*"));
 
     EXPECT_EQ(1, session.getMsgQueue()->size());
-    ElementPtr msg;
+    ConstElementPtr msg;
     std::string group, to;
     msg = session.getFirstMessage(group, to);
     EXPECT_EQ("{ \"command\": [ \"module_spec\", { \"module_name\": \"Spec1\" } ] }", msg->str());
@@ -171,7 +171,7 @@
     EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
 
     EXPECT_EQ(1, session.getMsgQueue()->size());
-    ElementPtr msg;
+    ConstElementPtr msg;
     std::string group, to;
     msg = session.getFirstMessage(group, to);
     EXPECT_EQ("{ \"command\": [ \"module_spec\", { \"commands\": [ { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }, { \"command_args\": [  ], \"command_description\": \"Shut down BIND 10\", \"command_name\": \"shutdown\" } ], \"config_data\": [ { \"item_default\": 1, \"item_name\": \"item1\", \"item_optional\": false, \"item_type\": \"integer\" }, { \"item_default\": 1.1, \"item_name\": \"item2\", \"item_optional\": false, \"item_type\": \"real\" }, { \"item_default\": true, \"item_name\": \"item3\", \"item_optional\": false, \"item_type\": \"boolean\" }, { \"item_default\": \"test\", \"item_name\": \"item4\", \"item_optional\": false, \"item_type\": \"string\" }, { \"item_default\": [ \"a\", \"b\" ], \"item_name\": \"item5\", \"item_optional\": false, \"item_type\": \"list\", \"list_item_sp
 ec\": { \"item_default\": \"\", \"item_name\": \"list_element\", \"item_optional\": false, \"item_type\": \"string\" } }, { \"item_default\": {  }, \"item_name\": \"item6\", \"item_optional\": false, \"item_type\": \"map\", \"map_item_spec\": [ { \"item_default\": \"default\", \"item_name\": \"value1\", \"item_optional\": true, \"item_type\": \"string\" }, { \"item_name\": \"value2\", \"item_optional\": true, \"item_type\": \"integer\" } ] } ], \"module_name\": \"Spec2\" } ] }", msg->str());
@@ -180,31 +180,31 @@
     EXPECT_EQ(0, session.getMsgQueue()->size());
 }
 
-ElementPtr my_config_handler(ElementPtr new_config) {
+ConstElementPtr my_config_handler(ConstElementPtr new_config) {
     if (new_config && new_config->contains("item1") &&
         new_config->get("item1")->intValue() == 5) {
-        return createAnswer(6, "I do not like the number 5");
+        return (createAnswer(6, "I do not like the number 5"));
     }
-    return createAnswer();
-}
-
-ElementPtr my_command_handler(const std::string& command,
-                              ElementPtr arg UNUSED_PARAM)
+    return (createAnswer());
+}
+
+ConstElementPtr my_command_handler(const std::string& command,
+                                   ConstElementPtr arg UNUSED_PARAM)
 {
     if (command == "good_command") {
-        return createAnswer();
+        return (createAnswer());
     } else if (command == "command_with_arg") {
         if (arg) {
             if (arg->getType() == Element::integer) {
-                return createAnswer(0, el("2"));
+                return (createAnswer(0, el("2")));
             } else {
-                return createAnswer(1, "arg bad type");
+                return (createAnswer(1, "arg bad type"));
             }
         } else {
-            return createAnswer(1, "arg missing");
+            return (createAnswer(1, "arg missing"));
         }
     } else {
-        return createAnswer(1, "bad command");
+        return (createAnswer(1, "bad command"));
     }
 }
 
@@ -218,7 +218,7 @@
     EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
 
     EXPECT_EQ(2, session.getMsgQueue()->size());
-    ElementPtr msg;
+    ConstElementPtr msg;
     std::string group, to;
     msg = session.getFirstMessage(group, to);
     EXPECT_EQ("{ \"command\": [ \"module_spec\", { \"commands\": [ { \"command_args\": [ { \"item_default\": \"\", \"item_name\": \"message\", \"item_optional\": false, \"item_type\": \"string\" } ], \"command_description\": \"Print the given message to stdout\", \"command_name\": \"print_message\" }, { \"command_args\": [  ], \"command_description\": \"Shut down BIND 10\", \"command_name\": \"shutdown\" } ], \"config_data\": [ { \"item_default\": 1, \"item_name\": \"item1\", \"item_optional\": false, \"item_type\": \"integer\" }, { \"item_default\": 1.1, \"item_name\": \"item2\", \"item_optional\": false, \"item_type\": \"real\" }, { \"item_default\": true, \"item_name\": \"item3\", \"item_optional\": false, \"item_type\": \"boolean\" }, { \"item_default\": \"test\", \"item_name\": \"item4\", \"item_optional\": false, \"item_type\": \"string\" }, { \"item_default\": [ \"a\", \"b\" ], \"item_name\": \"item5\", \"item_optional\": false, \"item_type\": \"list\", \"list_item_sp
 ec\": { \"item_default\": \"\", \"item_name\": \"list_element\", \"item_optional\": false, \"item_type\": \"string\" } }, { \"item_default\": {  }, \"item_name\": \"item6\", \"item_optional\": false, \"item_type\": \"map\", \"map_item_spec\": [ { \"item_default\": \"default\", \"item_name\": \"value1\", \"item_optional\": true, \"item_type\": \"string\" }, { \"item_name\": \"value2\", \"item_optional\": true, \"item_type\": \"integer\" } ] } ], \"module_name\": \"Spec2\" } ] }", msg->str());
@@ -242,7 +242,7 @@
     EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
 
     EXPECT_EQ(2, session.getMsgQueue()->size());
-    ElementPtr msg;
+    ConstElementPtr msg;
     std::string group, to;
     // checked above, drop em
     msg = session.getFirstMessage(group, to);
@@ -381,7 +381,7 @@
     EXPECT_THROW(mccs.addRemoteConfig(ccspecfile("spec2.spec")), CCSessionError);
     
     session.getMessages()->add(createAnswer());
-    mccs.addRemoteConfig(ccspecfile("spec2.spec"));
+    EXPECT_THROW(mccs.addRemoteConfig(ccspecfile("spec2.spec")), CCSessionError);
 }
 
 TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
@@ -393,7 +393,7 @@
     EXPECT_EQ(true, session.haveSubscription("Spec2", "*"));
 
     EXPECT_EQ(2, session.getMsgQueue()->size());
-    ElementPtr msg;
+    ConstElementPtr msg;
     std::string group, to;
     // drop the module_spec and config commands
     session.getFirstMessage(group, to);

Modified: branches/trac308/src/lib/config/tests/config_data_unittests.cc
==============================================================================
--- branches/trac308/src/lib/config/tests/config_data_unittests.cc (original)
+++ branches/trac308/src/lib/config/tests/config_data_unittests.cc Mon Sep 20 11:07:54 2010
@@ -26,10 +26,9 @@
 using namespace isc::config;
 
 ConfigData
-setupSpec2()
-{
+setupSpec2() {
     ModuleSpec spec2 = moduleSpecFromFile(std::string(TEST_DATA_PATH) + "/spec22.spec");
-    return ConfigData(spec2);
+    return (ConfigData(spec2));
 }
 
 TEST(ConfigData, Creation) {

Modified: branches/trac308/src/lib/config/tests/fake_session.cc
==============================================================================
--- branches/trac308/src/lib/config/tests/fake_session.cc (original)
+++ branches/trac308/src/lib/config/tests/fake_session.cc Mon Sep 20 11:07:54 2010
@@ -40,12 +40,12 @@
 
 // ok i want these in cc/data 
 bool
-listContains(ElementPtr list, ElementPtr el) {
+listContains(ConstElementPtr list, ConstElementPtr el) {
     if (!list) {
         return (false);
     }
-    BOOST_FOREACH(ElementPtr l_el, list->listValue()) {
-        if (l_el == el) {
+    BOOST_FOREACH(ConstElementPtr l_el, list->listValue()) {
+        if (*l_el == *el) {
             return (true);
         }
     }
@@ -53,10 +53,10 @@
 }
 
 void
-listRemove(ElementPtr list, ElementPtr el) {
+listRemove(ElementPtr list, ConstElementPtr el) {
     int i = -1;
-    BOOST_FOREACH(ElementPtr s_el, list->listValue()) {
-        if (el == s_el) {
+    BOOST_FOREACH(ConstElementPtr s_el, list->listValue()) {
+        if (*el == *s_el) {
             i = 0;
         }
         i++;
@@ -82,11 +82,6 @@
 FakeSession::~FakeSession() {
 }
 
-bool
-FakeSession::connect() {
-    return (true);
-}
-
 void
 FakeSession::disconnect() {
 }
@@ -99,25 +94,8 @@
 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
-FakeSession::recvmsg(ElementPtr& msg, bool nonblock UNUSED_PARAM,
+bool
+FakeSession::recvmsg(ConstElementPtr& msg, bool nonblock UNUSED_PARAM,
                      int seq UNUSED_PARAM)
 {
     //cout << "[XX] client asks for message " << endl;
@@ -133,7 +111,7 @@
 }
 
 bool
-FakeSession::recvmsg(ElementPtr& env, ElementPtr& msg,
+FakeSession::recvmsg(ConstElementPtr& env, ConstElementPtr& msg,
                      bool nonblock UNUSED_PARAM,
                      int seq UNUSED_PARAM)
 {
@@ -145,26 +123,27 @@
         // do we need initial message to have env[group] and [to] too?
         msg = messages_->get(0);
         messages_->remove(0);
-        return true;
+        return (true);
     } else if (msg_queue_) {
-        BOOST_FOREACH(ElementPtr c_m, msg_queue_->listValue()) {
-            ElementPtr to_remove = ElementPtr();
+        BOOST_FOREACH(ConstElementPtr c_m, msg_queue_->listValue()) {
+            ConstElementPtr to_remove = ElementPtr();
             if (haveSubscription(c_m->get(0), c_m->get(1))) {
-                env = Element::createMap();
-                env->set("group", c_m->get(0));
-                env->set("to", c_m->get(1));
+                ElementPtr new_env = Element::createMap();
+                new_env->set("group", c_m->get(0));
+                new_env->set("to", c_m->get(1));
+                env = new_env;
                 msg = c_m->get(2);
                 to_remove = c_m;
             }
             if (to_remove) {
                 listRemove(msg_queue_, to_remove);
-                return true;
+                return (true);
             }
         }
     }
     msg = ElementPtr();
     env = ElementPtr();
-    return false;
+    return (false);
 }
 
 void
@@ -192,44 +171,45 @@
 }
 
 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)
 {
     //cout << "[XX] client sends message: " << msg << endl;
     //cout << "[XX] to: " << group << " . " << instance << "." << to << endl;
     addMessage(msg, group, to);
-    return 1;
-}
-
-bool
-FakeSession::group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+    return (1);
+}
+
+bool
+FakeSession::group_recvmsg(ConstElementPtr& envelope, ConstElementPtr& msg,
                            bool nonblock, int seq)
 {
     return (recvmsg(envelope, msg, nonblock, seq));
 }
 
 int
-FakeSession::reply(ElementPtr& envelope, ElementPtr& newmsg) {
+FakeSession::reply(ConstElementPtr envelope, ConstElementPtr newmsg) {
     //cout << "[XX] client sends reply: " << newmsg << endl;
     //cout << "[XX] env: " << envelope << endl;
-    addMessage(newmsg, envelope->get("group")->stringValue(), envelope->get("to")->stringValue());
-    return 1;
-}
-
-bool
-FakeSession::hasQueuedMsgs() {
-    return false;
-}
-
-ElementPtr
-FakeSession::getFirstMessage(std::string& group, std::string& to) {
-    ElementPtr el;
+    addMessage(newmsg, envelope->get("group")->stringValue(),
+               envelope->get("to")->stringValue());
+    return (1);
+}
+
+bool
+FakeSession::hasQueuedMsgs() const {
+    return (false);
+}
+
+ConstElementPtr
+FakeSession::getFirstMessage(std::string& group, std::string& to) const {
+    ConstElementPtr el;
     if (msg_queue_ && msg_queue_->size() > 0) {
         el = msg_queue_->get(0);
         msg_queue_->remove(0);
         group = el->get(0)->stringValue();
         to = el->get(1)->stringValue();
-        return el->get(2);
+        return (el->get(2));
     } else {
         group = "";
         to = "";
@@ -238,7 +218,7 @@
 }
 
 void
-FakeSession::addMessage(ElementPtr msg, const std::string& group,
+FakeSession::addMessage(ConstElementPtr msg, const std::string& group,
                         const std::string& to)
 {
     ElementPtr m_el = Element::createList();
@@ -270,8 +250,7 @@
 }
 
 bool
-FakeSession::haveSubscription(const ElementPtr group,
-                              const ElementPtr instance)
+FakeSession::haveSubscription(ConstElementPtr group, ConstElementPtr instance)
 {
     return (haveSubscription(group->stringValue(), instance->stringValue()));
 }

Modified: branches/trac308/src/lib/config/tests/fake_session.h
==============================================================================
--- branches/trac308/src/lib/config/tests/fake_session.h (original)
+++ branches/trac308/src/lib/config/tests/fake_session.h Mon Sep 20 11:07:54 2010
@@ -47,38 +47,32 @@
     virtual void startRead(boost::function<void()> read_callback);
 
     virtual void establish(const char* socket_file = NULL);
-    bool connect();
     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,
                            std::string instance = "*");
     virtual void unsubscribe(std::string group,
                              std::string instance = "*");
-    virtual int group_sendmsg(isc::data::ElementPtr msg,
+    virtual int group_sendmsg(isc::data::ConstElementPtr msg,
                               std::string group,
                               std::string instance = "*",
                               std::string to = "*");
-    virtual bool group_recvmsg(isc::data::ElementPtr& envelope,
-                               isc::data::ElementPtr& msg,
+    virtual bool group_recvmsg(isc::data::ConstElementPtr& envelope,
+                               isc::data::ConstElementPtr& msg,
                                bool nonblock = true,
                                int seq = -1);
-    virtual int reply(isc::data::ElementPtr& envelope,
-                      isc::data::ElementPtr& newmsg);
-    virtual bool hasQueuedMsgs();
-    isc::data::ElementPtr getFirstMessage(std::string& group, std::string& to);
-    void addMessage(isc::data::ElementPtr, const std::string& group,
+    virtual int reply(isc::data::ConstElementPtr envelope,
+                      isc::data::ConstElementPtr newmsg);
+    virtual bool hasQueuedMsgs() const;
+    virtual void setTimeout(size_t milliseconds) {}
+    virtual size_t getTimeout() const { return (0); }
+    isc::data::ConstElementPtr getFirstMessage(std::string& group,
+                                               std::string& to) const;
+    void addMessage(isc::data::ConstElementPtr, const std::string& group,
                     const std::string& to);
     bool haveSubscription(const std::string& group,
                           const std::string& instance);
-    bool haveSubscription(const isc::data::ElementPtr group,
-                          const isc::data::ElementPtr instance);
+    bool haveSubscription(const isc::data::ConstElementPtr group,
+                          const isc::data::ConstElementPtr instance);
 
     // For the convenience of tests, we share these internal members
     // with the tester.  The test code may insert update and check,
@@ -88,6 +82,12 @@
     isc::data::ElementPtr getMsgQueue() { return (msg_queue_); }
 
 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_;
     isc::data::ElementPtr subscriptions_;
     isc::data::ElementPtr msg_queue_;

Modified: branches/trac308/src/lib/config/tests/module_spec_unittests.cc
==============================================================================
--- branches/trac308/src/lib/config/tests/module_spec_unittests.cc (original)
+++ branches/trac308/src/lib/config/tests/module_spec_unittests.cc Mon Sep 20 11:07:54 2010
@@ -26,7 +26,7 @@
 using namespace isc::config;
 
 std::string specfile(const std::string name) {
-    return std::string(TEST_DATA_PATH) + "/" + name;
+    return (std::string(TEST_DATA_PATH) + "/" + name);
 }
 
 void
@@ -134,27 +134,27 @@
 }
 
 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;
+
+    data_file.open(specfile(data_file_name).c_str());
+    ConstElementPtr data = Element::fromJSON(data_file, data_file_name);
+    data_file.close();
+
+    return (dd.validate_config(data));
+}
+
+bool
+data_test_with_errors(const ModuleSpec& dd, const std::string& data_file_name,
+                      ElementPtr errors)
 {
     std::ifstream data_file;
 
     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();
 
-    return dd.validate_config(data);
-}
-
-bool
-data_test_with_errors(ModuleSpec dd, const std::string& data_file_name, ElementPtr errors)
-{
-    std::ifstream data_file;
-
-    data_file.open(specfile(data_file_name).c_str());
-    ElementPtr data = Element::fromJSON(data_file, data_file_name);
-    data_file.close();
-
-    return dd.validate_config(data, true, errors);
+    return (dd.validate_config(data, true, errors));
 }
 
 TEST(ModuleSpec, DataValidation) {

Modified: branches/trac308/src/lib/datasrc/data_source.cc
==============================================================================
--- branches/trac308/src/lib/datasrc/data_source.cc (original)
+++ branches/trac308/src/lib/datasrc/data_source.cc Mon Sep 20 11:07:54 2010
@@ -206,6 +206,11 @@
         if (!hit || !rrset || (flags & DataSrc::CNAME_FOUND) != 0) {
             hit = cache.retrieve(task.qname, task.qclass, RRType::CNAME(),
                                  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) {
@@ -1245,8 +1250,8 @@
 // installed files we define the methods here.
 //
 DataSrc::Result
-DataSrc::init(const isc::data::ElementPtr config UNUSED_PARAM) {
-    return NOT_IMPLEMENTED;
+DataSrc::init(isc::data::ConstElementPtr config UNUSED_PARAM) {
+    return (NOT_IMPLEMENTED);
 }
 
 DataSrc::Result

Modified: branches/trac308/src/lib/datasrc/data_source.h
==============================================================================
--- branches/trac308/src/lib/datasrc/data_source.h (original)
+++ branches/trac308/src/lib/datasrc/data_source.h Mon Sep 20 11:07:54 2010
@@ -115,7 +115,7 @@
     // Optional 'low-level' methods.  These will have stub implementations
     // in the general DataSrc class but MAY be overwritten by subclasses
     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;
 
     // Mandatory 'low-level' methods: These will NOT be implemented by
@@ -182,13 +182,13 @@
 
     virtual void findClosestEnclosure(DataSrcMatch& match) const = 0;
 
-    const isc::dns::RRClass& getClass() const { return rrclass; }
+    const isc::dns::RRClass& getClass() const { return (rrclass); }
     void setClass(isc::dns::RRClass& c) { rrclass = c; }
     void setClass(const isc::dns::RRClass& c) { rrclass = c; }
 
-    Result init() { return NOT_IMPLEMENTED; }
-    Result init(const isc::data::ElementPtr config);
-    Result close() { return NOT_IMPLEMENTED; }
+    Result init() { return (NOT_IMPLEMENTED); }
+    Result init(isc::data::ConstElementPtr config);
+    Result close() { return (NOT_IMPLEMENTED); }
 
     virtual Result findRRset(const isc::dns::Name& qname,
                              const isc::dns::RRClass& qclass,
@@ -247,7 +247,7 @@
 
     void addDataSrc(ConstDataSrcPtr data_src);
     void removeDataSrc(ConstDataSrcPtr data_src);
-    size_t dataSrcCount() { return data_sources.size(); };
+    size_t dataSrcCount() { return (data_sources.size()); }
     
     void findClosestEnclosure(DataSrcMatch& match) const;
 

Modified: branches/trac308/src/lib/datasrc/sqlite3_datasrc.cc
==============================================================================
--- branches/trac308/src/lib/datasrc/sqlite3_datasrc.cc (original)
+++ branches/trac308/src/lib/datasrc/sqlite3_datasrc.cc Mon Sep 20 11:07:54 2010
@@ -558,7 +558,7 @@
 }
 
 DataSrc::Result
-Sqlite3DataSrc::init(const isc::data::ElementPtr config) {
+Sqlite3DataSrc::init(isc::data::ConstElementPtr config) {
     if (config && config->contains("database_file")) {
         open(config->get("database_file")->stringValue());
     } else {

Modified: branches/trac308/src/lib/datasrc/sqlite3_datasrc.h
==============================================================================
--- branches/trac308/src/lib/datasrc/sqlite3_datasrc.h (original)
+++ branches/trac308/src/lib/datasrc/sqlite3_datasrc.h Mon Sep 20 11:07:54 2010
@@ -94,8 +94,8 @@
                              std::string& hash,
                              isc::dns::RRsetList& target) const;
 
-    Result init() { return init(isc::data::ElementPtr()); };
-    Result init(const isc::data::ElementPtr config);
+    Result init() { return (init(isc::data::ElementPtr())); }
+    Result init(const isc::data::ConstElementPtr config);
     Result close();
 
 private:

Modified: branches/trac308/src/lib/datasrc/static_datasrc.cc
==============================================================================
--- branches/trac308/src/lib/datasrc/static_datasrc.cc (original)
+++ branches/trac308/src/lib/datasrc/static_datasrc.cc Mon Sep 20 11:07:54 2010
@@ -260,8 +260,8 @@
 // Static data source is "configuration less", so the \c config parameter
 // is intentionally ignored.
 DataSrc::Result
-StaticDataSrc::init(const isc::data::ElementPtr config UNUSED_PARAM) {
-    return init();
+StaticDataSrc::init(isc::data::ConstElementPtr config UNUSED_PARAM) {
+    return (init());
 }
 
 DataSrc::Result

Modified: branches/trac308/src/lib/datasrc/static_datasrc.h
==============================================================================
--- branches/trac308/src/lib/datasrc/static_datasrc.h (original)
+++ branches/trac308/src/lib/datasrc/static_datasrc.h Mon Sep 20 11:07:54 2010
@@ -81,7 +81,7 @@
                             isc::dns::RRsetList& target) const;
 
     Result init();
-    Result init(const isc::data::ElementPtr config);
+    Result init(isc::data::ConstElementPtr config);
     Result close();
 private:
     StaticDataSrcImpl* impl_;

Modified: branches/trac308/src/lib/datasrc/tests/Makefile.am
==============================================================================
--- branches/trac308/src/lib/datasrc/tests/Makefile.am (original)
+++ branches/trac308/src/lib/datasrc/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -3,6 +3,10 @@
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
 
 CLEANFILES = *.gcno *.gcda
 
@@ -22,10 +26,10 @@
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
-run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/.libs/libdatasrc.a 
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a 
-run_unittests_LDADD += $(top_builddir)/src/lib/cc/.libs/libcc.a
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
+run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la 
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 endif
 
 noinst_PROGRAMS = $(TESTS)

Modified: branches/trac308/src/lib/datasrc/tests/datasrc_unittest.cc
==============================================================================
--- branches/trac308/src/lib/datasrc/tests/datasrc_unittest.cc (original)
+++ branches/trac308/src/lib/datasrc/tests/datasrc_unittest.cc Mon Sep 20 11:07:54 2010
@@ -49,7 +49,7 @@
 using namespace isc::data;
 
 namespace {
-const ElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
     "{ \"database_file\": \"" TEST_DATA_DIR "/example.org.sqlite3\"}");
 
 class DataSrcTest : public ::testing::Test {
@@ -915,6 +915,24 @@
     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
 // is to check a corner case behavior when atypical RRClass (CH in this case)
 // is specified.

Modified: branches/trac308/src/lib/datasrc/tests/sqlite3_unittest.cc
==============================================================================
--- branches/trac308/src/lib/datasrc/tests/sqlite3_unittest.cc (original)
+++ branches/trac308/src/lib/datasrc/tests/sqlite3_unittest.cc Mon Sep 20 11:07:54 2010
@@ -43,22 +43,22 @@
 using namespace isc::data;
 
 namespace {
-ElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
     "{ \"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\"}");
-ElementPtr SQLITE_DBFILE_EXAMPLE_ROOT = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_EXAMPLE_ROOT = Element::fromJSON(
     "{ \"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\"}");
-ElementPtr SQLITE_DBFILE_MEMORY = Element::fromJSON(
+ConstElementPtr SQLITE_DBFILE_MEMORY = Element::fromJSON(
     "{ \"database_file\": \":memory:\"}");
 
 // 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,
 // so to test a failure case the create operation should also fail.
 // 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\"}");
 
 const string sigdata_common(" 20100322084538 20100220084538 "

Modified: branches/trac308/src/lib/datasrc/tests/test_datasrc.cc
==============================================================================
--- branches/trac308/src/lib/datasrc/tests/test_datasrc.cc (original)
+++ branches/trac308/src/lib/datasrc/tests/test_datasrc.cc Mon Sep 20 11:07:54 2010
@@ -307,9 +307,8 @@
 }
 
 DataSrc::Result
-TestDataSrc::init(const isc::data::ElementPtr config UNUSED_PARAM)
-{
-    return init();
+TestDataSrc::init(isc::data::ConstElementPtr config UNUSED_PARAM) {
+    return (init());
 }
 
 void

Modified: branches/trac308/src/lib/datasrc/tests/test_datasrc.h
==============================================================================
--- branches/trac308/src/lib/datasrc/tests/test_datasrc.h (original)
+++ branches/trac308/src/lib/datasrc/tests/test_datasrc.h Mon Sep 20 11:07:54 2010
@@ -85,7 +85,7 @@
                              isc::dns::RRsetList& target) const;
 
     Result init();
-    Result init(const isc::data::ElementPtr config);
+    Result init(isc::data::ConstElementPtr config);
     Result close() { return (SUCCESS); }
 
 private:

Modified: branches/trac308/src/lib/dns/Makefile.am
==============================================================================
--- branches/trac308/src/lib/dns/Makefile.am (original)
+++ branches/trac308/src/lib/dns/Makefile.am Mon Sep 20 11:07:54 2010
@@ -88,8 +88,8 @@
 rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 	./gen-rdatacode.py
 
-libdns++_includedir = $(includedir)/dns
-libdns++_include_HEADERS = \
+libdns___includedir = $(includedir)/dns
+libdns___include_HEADERS = \
 	buffer.h \
 	dnssectime.h \
 	exceptions.h \

Modified: branches/trac308/src/lib/dns/messagerenderer.h
==============================================================================
--- branches/trac308/src/lib/dns/messagerenderer.h (original)
+++ branches/trac308/src/lib/dns/messagerenderer.h Mon Sep 20 11:07:54 2010
@@ -109,7 +109,7 @@
     /// The destructor does nothing on the given \c buffer on construction;
     /// 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).
-    /// 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.
     ~MessageRenderer();
     //@}

Modified: branches/trac308/src/lib/dns/name.cc
==============================================================================
--- branches/trac308/src/lib/dns/name.cc (original)
+++ branches/trac308/src/lib/dns/name.cc Mon Sep 20 11:07:54 2010
@@ -601,17 +601,17 @@
 
 Name
 Name::concatenate(const Name& suffix) const {
-    assert(this->length_ > 0 && suffix.length_ > 0);
-    assert(this->labelcount_ > 0 && suffix.labelcount_ > 0);
-
-    unsigned int length = this->length_ + suffix.length_ - 1;
+    assert(length_ > 0 && suffix.length_ > 0);
+    assert(labelcount_ > 0 && suffix.labelcount_ > 0);
+
+    unsigned int length = length_ + suffix.length_ - 1;
     if (length > Name::MAX_WIRE) {
         isc_throw(TooLongName, "names are too long to concatenate");
     }
 
     Name retname;
     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(),
                           suffix.ndata_.begin(), suffix.ndata_.end());
     assert(retname.ndata_.size() == length);
@@ -622,14 +622,13 @@
     // excluding that for the trailing dot, and append the offsets of the
     // 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);
     retname.offsets_.reserve(labels);
-    retname.offsets_.assign(&this->offsets_[0],
-                            &this->offsets_[0] + this->labelcount_ - 1);
+    retname.offsets_.assign(&offsets_[0], &offsets_[0] + labelcount_ - 1);
     transform(suffix.offsets_.begin(), suffix.offsets_.end(),
               back_inserter(retname.offsets_),
-              bind2nd(plus<char>(), this->length_ - 1));
+              bind2nd(plus<char>(), length_ - 1));
     assert(retname.offsets_.size() == labels);
     retname.labelcount_ = labels;
 

Modified: branches/trac308/src/lib/dns/name.h
==============================================================================
--- branches/trac308/src/lib/dns/name.h (original)
+++ branches/trac308/src/lib/dns/name.h Mon Sep 20 11:07:54 2010
@@ -406,7 +406,7 @@
     /// This method simply negates the result of \c equal() method, and in that
     /// sense it's redundant.  The separate method is provided just for
     /// convenience.
-    bool nequals(const Name& other) const { return !(equals(other)); }
+    bool nequals(const Name& other) const { return (!(equals(other))); }
 
     /// Same as nequals()
     bool operator!=(const Name& other) const { return (nequals(other)); }

Modified: branches/trac308/src/lib/dns/python/Makefile.am
==============================================================================
--- branches/trac308/src/lib/dns/python/Makefile.am (original)
+++ branches/trac308/src/lib/dns/python/Makefile.am Mon Sep 20 11:07:54 2010
@@ -1,24 +1,16 @@
 SUBDIRS = tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
-if USE_GXX
-AM_CPPFLAGS += -Wno-write-strings
-endif
+AM_CXXFLAGS = $(B10_CXXFLAGS)
 
-#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)
+pyexec_LTLIBRARIES = pydnspp.la
+pydnspp_la_SOURCES = pydnspp.cc pydnspp_common.cc
+pydnspp_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
+pydnspp_la_LDFLAGS = $(PYTHON_LDFLAGS)
 
 # directly included from source files, so these don't have their own
 # rules
-EXTRA_DIST = libdns_python_common.h
+EXTRA_DIST = pydnspp_common.h
 EXTRA_DIST += messagerenderer_python.cc
 EXTRA_DIST += message_python.cc
 EXTRA_DIST += rrclass_python.cc
@@ -31,7 +23,7 @@
 
 # Python prefers .so, while some OSes (specifically MacOS) use a different
 # suffix for dynamic objects.  -module is necessary to work this around.
-libdns_python_la_LDFLAGS += -module
-libdns_python_la_LIBADD = $(top_builddir)/src/lib/dns/libdns++.la
-libdns_python_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-libdns_python_la_LIBADD += $(PYTHON_LIB)
+pydnspp_la_LDFLAGS += -module
+pydnspp_la_LIBADD = $(top_builddir)/src/lib/dns/libdns++.la
+pydnspp_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+pydnspp_la_LIBADD += $(PYTHON_LIB)

Modified: branches/trac308/src/lib/dns/python/README
==============================================================================
--- branches/trac308/src/lib/dns/python/README (original)
+++ branches/trac308/src/lib/dns/python/README Mon Sep 20 11:07:54 2010
@@ -1,14 +1,14 @@
 
 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
 lib/python/isc.
 
 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
-> import libdns_python
-> rrc = libdns_python.RRClass("IN")
+> import pydnspp
+> rrc = pydnspp.RRClass("IN")
 etc.
 
 Notes:
@@ -26,8 +26,8 @@
 If you have specific functionality you do need, please ask for it and we
 will add it.
 
-The 'main' module is defined in libdns_python.cc.
-There is a libdns_python_common.[cc|h] for helper functions.
+The 'main' module is defined in pydnspp.cc.
+There is a pydnspp_common.[cc|h] for helper functions.
 
 Implementation notes:
 
@@ -87,7 +87,7 @@
 
 Finally we define the function to add the class, constants, exceptions,
 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
 (true on success, false on failure), and takes the module as a
 PyObject*. There is a convenience function called addClassVariable to

Modified: branches/trac308/src/lib/dns/python/message_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/message_python.cc (original)
+++ branches/trac308/src/lib/dns/python/message_python.cc Mon Sep 20 11:07:54 2010
@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-// $Id: message_python.cc 1711 2010-04-14 15:14:53Z jelte $
+// $Id$
 
 #include <dns/message.h>
 using namespace isc::dns;
@@ -71,7 +71,7 @@
 
 static PyTypeObject messageflag_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.MessageFlag",
+    "pydnspp.MessageFlag",
     sizeof(s_MessageFlag),              // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)MessageFlag_destroy,    // tp_dealloc
@@ -248,7 +248,7 @@
 
 static PyTypeObject opcode_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Opcode",
+    "pydnspp.Opcode",
     sizeof(s_Opcode),                   // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)Opcode_destroy,         // tp_dealloc
@@ -326,9 +326,9 @@
 static PyObject*
 Opcode_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -532,7 +532,7 @@
 
 static PyTypeObject rcode_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Rcode",
+    "pydnspp.Rcode",
     sizeof(s_Rcode),                    // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)Rcode_destroy,          // tp_dealloc
@@ -589,7 +589,7 @@
         try {
             self->rcode = new Rcode(code);
             self->static_code = false;
-        } catch (isc::OutOfRange) {
+        } catch (const isc::OutOfRange&) {
             PyErr_SetString(PyExc_OverflowError,
                             "rcode out of range");
             return (-1);
@@ -624,9 +624,9 @@
 static PyObject*
 Rcode_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -802,7 +802,7 @@
 
 static PyTypeObject section_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Section",
+    "pydnspp.Section",
     sizeof(s_Section),                  // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)Section_destroy,        // tp_dealloc
@@ -886,22 +886,22 @@
 
 static PyObject*
 Section_QUESTION(s_Section* self UNUSED_PARAM) {
-    return Section_createStatic(Section::QUESTION());
+    return (Section_createStatic(Section::QUESTION()));
 }
 
 static PyObject*
 Section_ANSWER(s_Section* self UNUSED_PARAM) {
-    return Section_createStatic(Section::ANSWER());
+    return (Section_createStatic(Section::ANSWER()));
 }
 
 static PyObject*
 Section_AUTHORITY(s_Section* self UNUSED_PARAM) {
-    return Section_createStatic(Section::AUTHORITY());
+    return (Section_createStatic(Section::AUTHORITY()));
 }
 
 static PyObject*
 Section_ADDITIONAL(s_Section* self UNUSED_PARAM) {
-    return Section_createStatic(Section::ADDITIONAL());
+    return (Section_createStatic(Section::ADDITIONAL()));
 }
 
 static PyObject* 
@@ -1117,7 +1117,7 @@
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject message_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Message",
+    "pydnspp.Message",
     sizeof(s_Message),                  // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)Message_destroy,        // tp_dealloc
@@ -1221,7 +1221,7 @@
     try {
         self->message->setHeaderFlag(*messageflag->messageflag);
         Py_RETURN_NONE;
-    } catch (isc::dns::InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_Clear();
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
@@ -1238,7 +1238,7 @@
     try {
         self->message->clearHeaderFlag(*messageflag->messageflag);
         Py_RETURN_NONE;
-    } catch (isc::dns::InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_Clear();
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
@@ -1269,7 +1269,7 @@
             self->message->setDNSSECSupported(false);
         }
         Py_RETURN_NONE;
-    } catch (isc::dns::InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
     }
@@ -1289,10 +1289,10 @@
     try {
         self->message->setUDPSize(size);
         Py_RETURN_NONE;
-    } catch (isc::dns::InvalidMessageUDPSize imus) {
+    } catch (const InvalidMessageUDPSize& imus) {
         PyErr_SetString(po_InvalidMessageUDPSize, imus.what());
         return (NULL);
-    } catch (isc::dns::InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
     }
@@ -1312,7 +1312,7 @@
     try {
         self->message->setQid(id);
         Py_RETURN_NONE;
-    } catch (InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
     }
@@ -1344,7 +1344,7 @@
     try {
         self->message->setRcode(*rcode->rcode);
         Py_RETURN_NONE;
-    } catch (InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
     }
@@ -1379,7 +1379,7 @@
     try {
         self->message->setOpcode(*opcode->opcode);
         Py_RETURN_NONE;
-    } catch (InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
     }
@@ -1482,7 +1482,7 @@
             self->message->addRRset(*section->section, rrset->rrset, false);
         }
         Py_RETURN_NONE;
-    } catch (InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
     }
@@ -1526,9 +1526,9 @@
 static PyObject*
 Message_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -1541,7 +1541,7 @@
             // If we return NULL it is seen as an error, so use this for
             // None returns
             Py_RETURN_NONE;
-        } catch (isc::dns::InvalidMessageOperation imo) {
+        } catch (const InvalidMessageOperation& imo) {
             PyErr_Clear();
             PyErr_SetString(po_InvalidMessageOperation, imo.what());
             return (NULL);
@@ -1565,16 +1565,16 @@
     try {
         self->message->fromWire(inbuf);
         Py_RETURN_NONE;
-    } catch (isc::dns::InvalidMessageOperation imo) {
+    } catch (const InvalidMessageOperation& imo) {
         PyErr_SetString(po_InvalidMessageOperation, imo.what());
         return (NULL);
-    } catch (isc::dns::DNSMessageFORMERR dmfe) {
+    } catch (const DNSMessageFORMERR& dmfe) {
         PyErr_SetString(po_DNSMessageFORMERR, dmfe.what());
         return (NULL);
-    } catch (isc::dns::DNSMessageBADVERS dmfe) {
+    } catch (const DNSMessageBADVERS& dmfe) {
         PyErr_SetString(po_DNSMessageBADVERS, dmfe.what());
         return (NULL);
-    } catch (isc::dns::MessageTooShort mts) {
+    } catch (const MessageTooShort& mts) {
         PyErr_SetString(po_MessageTooShort, mts.what());
         return (NULL);
     }
@@ -1627,15 +1627,15 @@
     addClassVariable(message_type, "DEFAULT_MAX_UDPSIZE", Py_BuildValue("I", Message::DEFAULT_MAX_UDPSIZE));
 
     /* 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);
-    po_InvalidMessageSection = PyErr_NewException("libdns_python.InvalidMessageSection", NULL, NULL);
+    po_InvalidMessageSection = PyErr_NewException("pydnspp.InvalidMessageSection", NULL, NULL);
     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);
-    po_InvalidMessageUDPSize = PyErr_NewException("libdns_python.InvalidMessageUDPSize", NULL, NULL);
+    po_InvalidMessageUDPSize = PyErr_NewException("pydnspp.InvalidMessageUDPSize", NULL, NULL);
     PyModule_AddObject(mod, "InvalidMessageUDPSize", po_InvalidMessageUDPSize);
-    po_DNSMessageBADVERS = PyErr_NewException("libdns_python.DNSMessageBADVERS", NULL, NULL);
+    po_DNSMessageBADVERS = PyErr_NewException("pydnspp.DNSMessageBADVERS", NULL, NULL);
     PyModule_AddObject(mod, "DNSMessageBADVERS", po_DNSMessageBADVERS);
 
     Py_INCREF(&message_type);

Modified: branches/trac308/src/lib/dns/python/messagerenderer_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/messagerenderer_python.cc (original)
+++ branches/trac308/src/lib/dns/python/messagerenderer_python.cc Mon Sep 20 11:07:54 2010
@@ -62,7 +62,7 @@
 
 static PyTypeObject messagerenderer_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.MessageRenderer",
+    "pydnspp.MessageRenderer",
     sizeof(s_MessageRenderer),          // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)MessageRenderer_destroy,// tp_dealloc
@@ -133,9 +133,9 @@
 
 static PyObject*
 MessageRenderer_getData(s_MessageRenderer* self) {
-    return Py_BuildValue("y#",
+    return (Py_BuildValue("y#",
                          self->messagerenderer->getData(),
-                         self->messagerenderer->getLength());
+                          self->messagerenderer->getLength()));
 }
 
 static PyObject*

Modified: branches/trac308/src/lib/dns/python/name_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/name_python.cc (original)
+++ branches/trac308/src/lib/dns/python/name_python.cc Mon Sep 20 11:07:54 2010
@@ -68,7 +68,7 @@
 
 static PyTypeObject name_comparison_result_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.NameComparisonResult",
+    "pydnspp.NameComparisonResult",
     sizeof(s_NameComparisonResult),           // tp_basicsize
     0,                                        // tp_itemsize
     (destructor)NameComparisonResult_destroy, // tp_dealloc
@@ -222,7 +222,7 @@
 
 static PyTypeObject name_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Name",
+    "pydnspp.Name",
     sizeof(s_Name),                     // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)Name_destroy,           // tp_dealloc
@@ -291,26 +291,26 @@
 
             self->name = new Name(n, downcase == Py_True);
             self->position = 0;
-        } catch (EmptyLabel) {
+        } catch (const EmptyLabel&) {
             PyErr_SetString(po_EmptyLabel, "EmptyLabel");
             return (-1);
-        } catch (TooLongLabel) {
+        } catch (const TooLongLabel&) {
             PyErr_SetString(po_TooLongLabel, "TooLongLabel");
             return (-1);
-        } catch (BadLabelType) {
+        } catch (const BadLabelType&) {
             PyErr_SetString(po_BadLabelType, "BadLabelType");
             return (-1);
-        } catch (BadEscape) {
+        } catch (const BadEscape&) {
             PyErr_SetString(po_BadEscape, "BadEscape");
             return (-1);
-        } catch (TooLongName) {
+        } catch (const TooLongName&) {
             PyErr_SetString(po_TooLongName, "TooLongName");
             return (-1);
-        } catch (IncompleteName) {
+        } catch (const IncompleteName&) {
             PyErr_SetString(po_IncompleteName, "IncompleteName");
             return (-1);
 #ifdef CATCHMEMERR
-        } catch (std::bad_alloc) {
+        } catch (const std::bad_alloc&) {
             PyErr_NoMemory();
             return (-1);
 #endif
@@ -338,11 +338,11 @@
             buffer.setPosition(position);
             self->name = new Name(buffer, downcase == Py_True);
             self->position = buffer.getPosition();
-        } catch (InvalidBufferPosition) {
+        } catch (const InvalidBufferPosition&) {
             PyErr_SetString(po_InvalidBufferPosition,
                             "InvalidBufferPosition");
             return (-1);
-        } catch (DNSMessageFORMERR) {
+        } catch (const DNSMessageFORMERR&) {
             PyErr_SetString(po_DNSMessageFORMERR, "DNSMessageFORMERR");
             return (-1);
         } catch (...) {
@@ -373,7 +373,7 @@
     }
     try {
         return (Py_BuildValue("I", self->name->at(pos)));
-    } catch (isc::OutOfRange oor) {
+    } catch (const isc::OutOfRange&) {
         PyErr_SetString(PyExc_IndexError,
                         "name index out of range");
         return (NULL);
@@ -400,9 +400,9 @@
     // Simply call the to_text method we already defined
     // str() is not defined in the c++ version, only to_text
     // and we already have a wrapper for that one.
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -472,7 +472,7 @@
             ret->name = NULL;
             try {
                 ret->name = new Name(self->name->split(first, n));
-            } catch(isc::OutOfRange oor) {
+            } catch(const isc::OutOfRange& oor) {
                 PyErr_SetString(PyExc_IndexError, oor.what());
                 ret->name = NULL;
             }
@@ -487,7 +487,7 @@
             ret->name = NULL;
             try {
                 ret->name = new Name(self->name->split(n));
-            } catch(isc::OutOfRange oor) {
+            } catch(const isc::OutOfRange& oor) {
                 PyErr_SetString(PyExc_IndexError, oor.what());
                 ret->name = NULL;
             }
@@ -572,7 +572,7 @@
     if (ret != NULL) {
         try {
             ret->name = new Name(self->name->concatenate(*other->name));
-        } catch (isc::dns::TooLongName tln) {
+        } catch (const TooLongName& tln) {
             PyErr_SetString(po_TooLongName, tln.what());
             return (NULL);
         }
@@ -651,30 +651,30 @@
     
 
     // 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);
 
-    po_TooLongName = PyErr_NewException("libdns_python.TooLongName", NULL, NULL);
+    po_TooLongName = PyErr_NewException("pydnspp.TooLongName", NULL, NULL);
     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);
 
-    po_BadLabelType = PyErr_NewException("libdns_python.BadLabelType", NULL, NULL);
+    po_BadLabelType = PyErr_NewException("pydnspp.BadLabelType", NULL, NULL);
     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);
 
-    po_IncompleteName = PyErr_NewException("libdns_python.IncompleteName", NULL, NULL);
+    po_IncompleteName = PyErr_NewException("pydnspp.IncompleteName", NULL, NULL);
     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);
 
     // This one could have gone into the message_python.cc file, but is
     // 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);
 
     return (true);

Modified: branches/trac308/src/lib/dns/python/question_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/question_python.cc (original)
+++ branches/trac308/src/lib/dns/python/question_python.cc Mon Sep 20 11:07:54 2010
@@ -76,7 +76,7 @@
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject question_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Question",
+    "pydnspp.Question",
     sizeof(s_Question),                 // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)Question_destroy,       // tp_dealloc
@@ -156,15 +156,15 @@
             self->question = QuestionPtr(new Question(inbuf));
             return (0);
         }
-    } catch (isc::dns::DNSMessageFORMERR dmfe) {
+    } catch (const DNSMessageFORMERR& dmfe) {
         PyErr_Clear();
         PyErr_SetString(po_DNSMessageFORMERR, dmfe.what());
         return (-1);
-    } catch (isc::dns::IncompleteRRClass irc) {
+    } catch (const IncompleteRRClass& irc) {
         PyErr_Clear();
         PyErr_SetString(po_IncompleteRRClass, irc.what());
         return (-1);
-    } catch (isc::dns::IncompleteRRType irt) {
+    } catch (const IncompleteRRType& irt) {
         PyErr_Clear();
         PyErr_SetString(po_IncompleteRRType, irt.what());
         return (-1);
@@ -231,9 +231,9 @@
 static PyObject*
 Question_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*

Modified: branches/trac308/src/lib/dns/python/rdata_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/rdata_python.cc (original)
+++ branches/trac308/src/lib/dns/python/rdata_python.cc Mon Sep 20 11:07:54 2010
@@ -92,7 +92,7 @@
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject rdata_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.Rdata",
+    "pydnspp.Rdata",
     sizeof(s_Rdata),                    // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)Rdata_destroy,          // tp_dealloc
@@ -174,9 +174,9 @@
 static PyObject*
 Rdata_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -267,13 +267,13 @@
                        reinterpret_cast<PyObject*>(&rdata_type));
 
     // 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);
 
-    po_InvalidRdataText = PyErr_NewException("libdns_python.InvalidRdataText", NULL, NULL);
+    po_InvalidRdataText = PyErr_NewException("pydnspp.InvalidRdataText", NULL, NULL);
     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);
 
     

Modified: branches/trac308/src/lib/dns/python/rrclass_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/rrclass_python.cc (original)
+++ branches/trac308/src/lib/dns/python/rrclass_python.cc Mon Sep 20 11:07:54 2010
@@ -100,7 +100,7 @@
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject rrclass_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.RRClass",
+    "pydnspp.RRClass",
     sizeof(s_RRClass),                  // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)RRClass_destroy,        // tp_dealloc
@@ -157,7 +157,7 @@
     unsigned int i;
     PyObject* bytes = NULL;
     // 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
     // that if we try several like here. Otherwise the *next* python
@@ -170,7 +170,7 @@
         } else if (PyArg_ParseTuple(args, "I", &i)) {
             PyErr_Clear();
             if (i > 65535) {
-                PyErr_SetString(po_InvalidRRClass, "Class number too high");
+                PyErr_SetString(po_InvalidRRClass, "RR class number too high");
                 return (-1);
             }
             self->rrclass = new RRClass(i);
@@ -188,7 +188,7 @@
         }
     // Incomplete is never thrown, a type error would have already been raised
     //when we try to read the 2 bytes above
-    } catch (InvalidRRClass ic) {
+    } catch (const InvalidRRClass& ic) {
         PyErr_Clear();
         PyErr_SetString(po_InvalidRRClass, ic.what());
         return (-1);
@@ -215,9 +215,9 @@
 static PyObject*
 RRClass_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -332,10 +332,10 @@
 bool
 initModulePart_RRClass(PyObject* mod) {
     // 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);
     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);
     PyModule_AddObject(mod, "IncompleteRRClass", po_IncompleteRRClass);
 

Modified: branches/trac308/src/lib/dns/python/rrset_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/rrset_python.cc (original)
+++ branches/trac308/src/lib/dns/python/rrset_python.cc Mon Sep 20 11:07:54 2010
@@ -94,7 +94,7 @@
 
 static PyTypeObject rrset_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.RRset",
+    "pydnspp.RRset",
     sizeof(s_RRset),                    // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)RRset_destroy,          // tp_dealloc
@@ -284,7 +284,7 @@
 RRset_toText(s_RRset* self) {
     try {
         return (Py_BuildValue("s", self->rrset->toText().c_str()));
-    } catch (EmptyRRset ers) {
+    } catch (const EmptyRRset& ers) {
         PyErr_SetString(po_EmptyRRset, ers.what());
         return (NULL);
     }
@@ -293,9 +293,9 @@
 static PyObject*
 RRset_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -321,7 +321,7 @@
             // None returns
             Py_RETURN_NONE;
         }
-    } catch (EmptyRRset ers) {
+    } catch (const EmptyRRset& ers) {
         PyErr_Clear();
         PyErr_SetString(po_EmptyRRset, ers.what());
         return (NULL);
@@ -341,7 +341,7 @@
     try {
         self->rrset->addRdata(*rdata->rdata);
         Py_RETURN_NONE;
-    } catch (std::bad_cast) {
+    } catch (const std::bad_cast&) {
         PyErr_Clear();
         PyErr_SetString(PyExc_TypeError,
                         "Rdata type to add must match type of RRset");
@@ -379,7 +379,7 @@
 bool
 initModulePart_RRset(PyObject* mod) {
     // 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);
 
     // Add the enums to the module

Modified: branches/trac308/src/lib/dns/python/rrttl_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/rrttl_python.cc (original)
+++ branches/trac308/src/lib/dns/python/rrttl_python.cc Mon Sep 20 11:07:54 2010
@@ -91,7 +91,7 @@
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject rrttl_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.RRTTL",
+    "pydnspp.RRTTL",
     sizeof(s_RRTTL),                    // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)RRTTL_destroy,          // tp_dealloc
@@ -177,7 +177,7 @@
             PyErr_Clear();
             return (0);
         }
-    } catch (IncompleteRRTTL icc) {
+    } catch (const IncompleteRRTTL& icc) {
         // Ok so one of our functions has thrown a C++ exception.
         // We need to translate that to a Python Exception
         // First clear any existing error that was set
@@ -186,7 +186,7 @@
         PyErr_SetString(po_IncompleteRRTTL, icc.what());
         // And return negative
         return (-1);
-    } catch (InvalidRRTTL ic) {
+    } catch (const InvalidRRTTL& ic) {
         PyErr_Clear();
         PyErr_SetString(po_InvalidRRTTL, ic.what());
         return (-1);
@@ -213,9 +213,9 @@
 static PyObject*
 RRTTL_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self,
+    return (PyObject_CallMethod(self,
                                const_cast<char*>("to_text"),
-                               const_cast<char*>(""));
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -296,9 +296,9 @@
 bool
 initModulePart_RRTTL(PyObject* mod) {
     // Add the exceptions to the module
-    po_InvalidRRTTL = PyErr_NewException("libdns_python.InvalidRRTTL", NULL, NULL);
+    po_InvalidRRTTL = PyErr_NewException("pydnspp.InvalidRRTTL", NULL, NULL);
     PyModule_AddObject(mod, "InvalidRRTTL", po_InvalidRRTTL);
-    po_IncompleteRRTTL = PyErr_NewException("libdns_python.IncompleteRRTTL", NULL, NULL);
+    po_IncompleteRRTTL = PyErr_NewException("pydnspp.IncompleteRRTTL", NULL, NULL);
     PyModule_AddObject(mod, "IncompleteRRTTL", po_IncompleteRRTTL);
 
     // We initialize the static description object with PyType_Ready(),

Modified: branches/trac308/src/lib/dns/python/rrtype_python.cc
==============================================================================
--- branches/trac308/src/lib/dns/python/rrtype_python.cc (original)
+++ branches/trac308/src/lib/dns/python/rrtype_python.cc Mon Sep 20 11:07:54 2010
@@ -130,7 +130,7 @@
 // Most of the functions are not actually implemented and NULL here.
 static PyTypeObject rrtype_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
-    "libdns_python.RRType",
+    "pydnspp.RRType",
     sizeof(s_RRType),                   // tp_basicsize
     0,                                  // tp_itemsize
     (destructor)RRType_destroy,         // tp_dealloc
@@ -186,8 +186,8 @@
     const char* s;
     unsigned int i;
     PyObject* bytes = NULL;
-    // The constructor argument can be a string ("IN"), an integer (1),
-    // or a sequence of numbers between 0 and 255 (wire code)
+    // The constructor argument can be a string ("A"), an integer (1),
+    // or a sequence of numbers between 0 and 65535 (wire code)
 
     // Note that PyArg_ParseType can set PyError, and we need to clear
     // that if we try several like here. Otherwise the *next* python
@@ -200,7 +200,7 @@
         } else if (PyArg_ParseTuple(args, "I", &i)) {
             PyErr_Clear();
             if (i > 65535) {
-                PyErr_SetString(po_InvalidRRType, "Class number too high");
+                PyErr_SetString(po_InvalidRRType, "RR Type number too high");
                 return (-1);
             }
             self->rrtype = new RRType(i);
@@ -217,7 +217,7 @@
             PyErr_Clear();
             return (0);
         }
-    } catch (IncompleteRRType icc) {
+    } catch (const IncompleteRRType& icc) {
         // Ok so one of our functions has thrown a C++ exception.
         // We need to translate that to a Python Exception
         // First clear any existing error that was set
@@ -226,7 +226,7 @@
         PyErr_SetString(po_IncompleteRRType, icc.what());
         // And return negative
         return (-1);
-    } catch (InvalidRRType ic) {
+    } catch (const InvalidRRType& ic) {
         PyErr_Clear();
         PyErr_SetString(po_InvalidRRType, ic.what());
         return (-1);
@@ -253,8 +253,8 @@
 static PyObject*
 RRType_str(PyObject* self) {
     // Simply call the to_text method we already defined
-    return PyObject_CallMethod(self, const_cast<char*>("to_text"),
-                                     const_cast<char*>(""));
+    return (PyObject_CallMethod(self, const_cast<char*>("to_text"),
+                                const_cast<char*>("")));
 }
 
 static PyObject*
@@ -446,9 +446,9 @@
 bool
 initModulePart_RRType(PyObject* mod) {
     // Add the exceptions to the module
-    po_InvalidRRType = PyErr_NewException("libdns_python.InvalidRRType", NULL, NULL);
+    po_InvalidRRType = PyErr_NewException("pydnspp.InvalidRRType", NULL, NULL);
     PyModule_AddObject(mod, "InvalidRRType", po_InvalidRRType);
-    po_IncompleteRRType = PyErr_NewException("libdns_python.IncompleteRRType", NULL, NULL);
+    po_IncompleteRRType = PyErr_NewException("pydnspp.IncompleteRRType", NULL, NULL);
     PyModule_AddObject(mod, "IncompleteRRType", po_IncompleteRRType);
 
     // We initialize the static description object with PyType_Ready(),

Modified: branches/trac308/src/lib/dns/python/tests/Makefile.am
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/Makefile.am (original)
+++ branches/trac308/src/lib/dns/python/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -10,6 +10,13 @@
 
 EXTRA_DIST = $(PYTESTS)
 
+# If necessary (rare cases), explicitly specify paths to dynamic libraries
+# required by loadable python modules.
+LIBRARY_PATH_PLACEHOLDER =
+if SET_ENV_LIBRARY_PATH
+LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
+endif
+
 # later will have configure option to choose this, like: coverage run --branch
 PYCOVERAGE = $(PYTHON)
 # test using command-line arguments, so use check-local target instead of TESTS
@@ -18,5 +25,6 @@
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/dns/python/.libs \
 	TESTDATA_PATH=$(abs_top_srcdir)/src/lib/dns/tests/testdata \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(LIBRARY_PATH_PLACEHOLDER) \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/lib/dns/python/tests/message_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/message_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/message_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the message part of the libdns_python module
+# Tests for the message part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 
 class MessageFlagTest(unittest.TestCase):

Modified: branches/trac308/src/lib/dns/python/tests/messagerenderer_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/messagerenderer_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/messagerenderer_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the messagerenderer part of the libdns_python module
+# Tests for the messagerenderer part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 class MessageRendererTest(unittest.TestCase):
 

Modified: branches/trac308/src/lib/dns/python/tests/name_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/name_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/name_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the messagerenderer part of the libdns_python module
+# Tests for the messagerenderer part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 class NameComparisonTest(unittest.TestCase):
     def setUp(self):

Modified: branches/trac308/src/lib/dns/python/tests/question_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/question_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/question_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the rrtype part of the libdns_python module
+# Tests for the rrtype part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 if "TESTDATA_PATH" in os.environ:
     testdata_path = os.environ["TESTDATA_PATH"]

Modified: branches/trac308/src/lib/dns/python/tests/rdata_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/rdata_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/rdata_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the rdata part of the libdns_python module
+# Tests for the rdata part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 class RdataTest(unittest.TestCase):
     def setUp(self):

Modified: branches/trac308/src/lib/dns/python/tests/rrclass_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/rrclass_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/rrclass_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the rrclass part of the libdns_python module
+# Tests for the rrclass part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 class RRClassTest(unittest.TestCase):
     def setUp(self):

Modified: branches/trac308/src/lib/dns/python/tests/rrset_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/rrset_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/rrset_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the rrtype part of the libdns_python module
+# Tests for the rrtype part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 class TestModuleSpec(unittest.TestCase):
     

Modified: branches/trac308/src/lib/dns/python/tests/rrttl_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/rrttl_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/rrttl_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the rrttl part of the libdns_python module
+# Tests for the rrttl part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 class RRTTLTest(unittest.TestCase):
     def setUp(self):

Modified: branches/trac308/src/lib/dns/python/tests/rrtype_python_test.py
==============================================================================
--- branches/trac308/src/lib/dns/python/tests/rrtype_python_test.py (original)
+++ branches/trac308/src/lib/dns/python/tests/rrtype_python_test.py Mon Sep 20 11:07:54 2010
@@ -14,12 +14,12 @@
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 #
-# Tests for the rrtype part of the libdns_python module
+# Tests for the rrtype part of the pydnspp module
 #
 
 import unittest
 import os
-from libdns_python import *
+from pydnspp import *
 
 class TestModuleSpec(unittest.TestCase):
     

Modified: branches/trac308/src/lib/dns/rdata/generic/ds_43.cc
==============================================================================
--- branches/trac308/src/lib/dns/rdata/generic/ds_43.cc (original)
+++ branches/trac308/src/lib/dns/rdata/generic/ds_43.cc Mon Sep 20 11:07:54 2010
@@ -173,7 +173,7 @@
 
 uint16_t
 DS::getTag() const {
-    return impl_->tag_;
+    return (impl_->tag_);
 }
 
 // END_RDATA_NAMESPACE

Modified: branches/trac308/src/lib/dns/rdata/generic/nsec3_50.cc
==============================================================================
--- branches/trac308/src/lib/dns/rdata/generic/nsec3_50.cc (original)
+++ branches/trac308/src/lib/dns/rdata/generic/nsec3_50.cc Mon Sep 20 11:07:54 2010
@@ -323,22 +323,22 @@
 
 uint8_t
 NSEC3::getHashalg() const {
-    return impl_->hashalg_;
+    return (impl_->hashalg_);
 }
 
 uint8_t
 NSEC3::getFlags() const {
-    return impl_->flags_;
+    return (impl_->flags_);
 }
 
 uint16_t
 NSEC3::getIterations() const {
-    return impl_->iterations_;
+    return (impl_->iterations_);
 }
 
 vector<uint8_t>&
 NSEC3::getSalt() const {
-    return impl_->salt_;
+    return (impl_->salt_);
 }
 
 // END_RDATA_NAMESPACE

Modified: branches/trac308/src/lib/dns/rrsetlist.cc
==============================================================================
--- branches/trac308/src/lib/dns/rrsetlist.cc (original)
+++ branches/trac308/src/lib/dns/rrsetlist.cc Mon Sep 20 11:07:54 2010
@@ -53,10 +53,10 @@
     BOOST_FOREACH(RRsetPtr rrsetptr, rrsets_) {
         if ((rrsetptr->getClass() == rrclass) &&
             (rrsetptr->getType() == rrtype)) {
-            return rrsetptr;
+            return (rrsetptr);
         }
     }
-    return RRsetPtr();
+    return (RRsetPtr());
 }
 
 }

Modified: branches/trac308/src/lib/dns/rrtype-placeholder.h
==============================================================================
--- branches/trac308/src/lib/dns/rrtype-placeholder.h (original)
+++ branches/trac308/src/lib/dns/rrtype-placeholder.h Mon Sep 20 11:07:54 2010
@@ -221,7 +221,7 @@
     bool equals(const RRType& other) const
     { return (typecode_ == other.typecode_); }
     /// \brief Same as \c equals().
-    bool operator==(const RRType& other) const { return equals(other); }
+    bool operator==(const RRType& other) const { return (equals(other)); }
 
     /// \brief Return true iff two RRTypes are equal.
     ///
@@ -232,7 +232,7 @@
     bool nequals(const RRType& other) const 
     { return (typecode_ != other.typecode_); }
     /// \brief Same as \c nequals().
-    bool operator!=(const RRType& other) const { return nequals(other); }
+    bool operator!=(const RRType& other) const { return (nequals(other)); }
  
     /// \brief Less-than comparison for RRType against \c other
     ///

Modified: branches/trac308/src/lib/dns/tests/Makefile.am
==============================================================================
--- branches/trac308/src/lib/dns/tests/Makefile.am (original)
+++ branches/trac308/src/lib/dns/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -2,6 +2,10 @@
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
 AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
 
 CLEANFILES = *.gcno *.gcda
 
@@ -40,8 +44,8 @@
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
-run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns++.a
-run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 endif
 
 noinst_PROGRAMS = $(TESTS)

Modified: branches/trac308/src/lib/dns/tests/rrparamregistry_unittest.cc
==============================================================================
--- branches/trac308/src/lib/dns/tests/rrparamregistry_unittest.cc (original)
+++ branches/trac308/src/lib/dns/tests/rrparamregistry_unittest.cc Mon Sep 20 11:07:54 2010
@@ -107,11 +107,11 @@
 class TestRdataFactory : public AbstractRdataFactory {
 public:
     virtual RdataPtr create(const string& rdata_str) const
-    { return RdataPtr(new in::A(rdata_str)); }
+    { return (RdataPtr(new in::A(rdata_str))); }
     virtual RdataPtr create(InputBuffer& buffer, size_t rdata_len) const
-    { return RdataPtr(new in::A(buffer, rdata_len)); }
+    { return (RdataPtr(new in::A(buffer, rdata_len))); }
     virtual RdataPtr create(const Rdata& source) const
-    { return RdataPtr(new in::A(dynamic_cast<const in::A&>(source))); }
+    { return (RdataPtr(new in::A(dynamic_cast<const in::A&>(source)))); }
 };
 
 TEST_F(RRParamRegistryTest, addRemoveFactory)

Modified: branches/trac308/src/lib/dns/tests/unittest_util.cc
==============================================================================
--- branches/trac308/src/lib/dns/tests/unittest_util.cc (original)
+++ branches/trac308/src/lib/dns/tests/unittest_util.cc Mon Sep 20 11:07:54 2010
@@ -158,7 +158,7 @@
             << "Expected: " << len2 << "\n";
         return (::testing::AssertionFailure(msg));
     }
-    return ::testing::AssertionSuccess();
+    return (::testing::AssertionSuccess());
 }
 
 ::testing::AssertionResult
@@ -177,5 +177,5 @@
             << "Other: " << name2 << "\n";
         return (::testing::AssertionFailure(msg));
     }
-    return ::testing::AssertionSuccess();
+    return (::testing::AssertionSuccess());
 }

Modified: branches/trac308/src/lib/dns/util/base16_from_binary.h
==============================================================================
--- branches/trac308/src/lib/dns/util/base16_from_binary.h (original)
+++ branches/trac308/src/lib/dns/util/base16_from_binary.h Mon Sep 20 11:07:54 2010
@@ -46,7 +46,7 @@
             "0123456789"
             "ABCDEF";
         assert(t < 16);
-        return lookup_table[static_cast<size_t>(t)];
+        return (lookup_table[static_cast<size_t>(t)]);
     }
 };
 

Modified: branches/trac308/src/lib/dns/util/base32hex_from_binary.h
==============================================================================
--- branches/trac308/src/lib/dns/util/base32hex_from_binary.h (original)
+++ branches/trac308/src/lib/dns/util/base32hex_from_binary.h Mon Sep 20 11:07:54 2010
@@ -48,7 +48,7 @@
             "0123456789"
             "ABCDEFGHIJKLMNOPQRSTUV";
         assert(t < 32);
-        return lookup_table[static_cast<size_t>(t)];
+        return (lookup_table[static_cast<size_t>(t)]);
     }
 };
 

Modified: branches/trac308/src/lib/dns/util/binary_from_base16.h
==============================================================================
--- branches/trac308/src/lib/dns/util/binary_from_base16.h (original)
+++ branches/trac308/src/lib/dns/util/binary_from_base16.h Mon Sep 20 11:07:54 2010
@@ -56,7 +56,7 @@
             isc_throw(isc::BadValue,
                       "attempt to decode a value not in base16 char set");
         }
-        return value;
+        return (value);
     }
 };
 

Modified: branches/trac308/src/lib/dns/util/binary_from_base32hex.h
==============================================================================
--- branches/trac308/src/lib/dns/util/binary_from_base32hex.h (original)
+++ branches/trac308/src/lib/dns/util/binary_from_base32hex.h Mon Sep 20 11:07:54 2010
@@ -59,7 +59,7 @@
             isc_throw(isc::BadValue,
                       "attempt to decode a value not in base32hex char set");
         }
-        return value;
+        return (value);
     }
 };
 

Modified: branches/trac308/src/lib/dns/util/sha1.cc
==============================================================================
--- branches/trac308/src/lib/dns/util/sha1.cc (original)
+++ branches/trac308/src/lib/dns/util/sha1.cc Mon Sep 20 11:07:54 2010
@@ -85,9 +85,9 @@
     uint32_t addTemp = context->Length_Low;
     context->Length_Low += length;
     if (context->Length_Low < addTemp && ++context->Length_High == 0) {
-        return true;
+        return (true);
     } else {
-        return false;
+        return (false);
     }
 }
 

Modified: branches/trac308/src/lib/exceptions/Makefile.am
==============================================================================
--- branches/trac308/src/lib/exceptions/Makefile.am (original)
+++ branches/trac308/src/lib/exceptions/Makefile.am Mon Sep 20 11:07:54 2010
@@ -1,3 +1,5 @@
+SUBDIRS = . tests
+
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CXXFLAGS=$(B10_CXXFLAGS)
 
@@ -6,17 +8,5 @@
 
 CLEANFILES = *.gcno *.gcda
 
-TESTS =
-if HAVE_GTEST
-TESTS += run_unittests
-run_unittests_SOURCES = run_unittests.cc
-run_unittests_SOURCES += exceptions_unittest.cc
-run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
-run_unittests_LDFLAGS = $(GTEST_LDFLAGS)
-run_unittests_LDADD = .libs/libexceptions.a $(GTEST_LDADD)
-endif
-
-noinst_PROGRAMS = $(TESTS)
-
 libexceptions_includedir = $(includedir)/exceptions
 libexceptions_include_HEADERS = exceptions.h

Modified: branches/trac308/src/lib/python/isc/Makefile.am
==============================================================================
--- branches/trac308/src/lib/python/isc/Makefile.am (original)
+++ branches/trac308/src/lib/python/isc/Makefile.am Mon Sep 20 11:07:54 2010
@@ -1,4 +1,4 @@
-SUBDIRS = datasrc cc config log # Util
+SUBDIRS = datasrc cc config log notify # Util
 
 python_PYTHON = __init__.py
 

Modified: branches/trac308/src/lib/python/isc/cc/session.py
==============================================================================
--- branches/trac308/src/lib/python/isc/cc/session.py (original)
+++ branches/trac308/src/lib/python/isc/cc/session.py Mon Sep 20 11:07:54 2010
@@ -16,6 +16,7 @@
 import sys
 import socket
 import struct
+import errno
 import os
 import threading
 import bind10_config
@@ -25,17 +26,21 @@
 class ProtocolError(Exception): pass
 class NetworkError(Exception): pass
 class SessionError(Exception): pass
+class SessionTimeout(Exception): pass
 
 class Session:
+    MSGQ_DEFAULT_TIMEOUT = 4000
+    
     def __init__(self, socket_file=None):
         self._socket = None
         self._lname = None
-        self._recvbuffer = bytearray()
-        self._recvlength = 0
         self._sequence = 1
         self._closed = False
         self._queue = []
         self._lock = threading.RLock()
+        self.set_timeout(self.MSGQ_DEFAULT_TIMEOUT);
+        self._recv_len_size = 0
+        self._recv_size = 0
 
         if socket_file is None:
             if "BIND10_MSGQ_SOCKET_FILE" in os.environ:
@@ -44,7 +49,6 @@
                 self.socket_file = bind10_config.BIND10_MSGQ_SOCKET_FILE
         else:
             self.socket_file = socket_file
-        
 
         try:
             self._socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -118,41 +122,94 @@
                     return isc.cc.message.from_wire(data[2:header_length+2]), None
             return None, None
 
+    def _receive_bytes(self, size):
+        """Try to get size bytes of data from the socket.
+           Raises a ProtocolError if the size is 0.
+           Raises any error from recv().
+           Returns whatever data was available (if >0 bytes).
+           """
+        data = self._socket.recv(size)
+        if len(data) == 0: # server closed connection
+            raise ProtocolError("Read of 0 bytes: connection closed")
+        return data
+        
+    def _receive_len_data(self):
+        """Reads self._recv_len_size bytes of data from the socket into
+           self._recv_len_data
+           This is done through class variables so in the case of
+           an EAGAIN we can continue on a subsequent call.
+           Raises a ProtocolError, a socket.error (which may be
+           timeout or eagain), or reads until we have all data we need.
+           """
+        while self._recv_len_size > 0:
+            new_data = self._receive_bytes(self._recv_len_size)
+            self._recv_len_data += new_data
+            self._recv_len_size -= len(new_data)
+
+    def _receive_data(self):
+        """Reads self._recv_size bytes of data from the socket into
+           self._recv_data.
+           This is done through class variables so in the case of
+           an EAGAIN we can continue on a subsequent call.
+           Raises a ProtocolError, a socket.error (which may be
+           timeout or eagain), or reads until we have all data we need.
+        """
+        while self._recv_size > 0:
+            new_data = self._receive_bytes(self._recv_size)
+            self._recv_data += new_data
+            self._recv_size -= len(new_data)
+
     def _receive_full_buffer(self, nonblock):
         if nonblock:
             self._socket.setblocking(0)
         else:
             self._socket.setblocking(1)
-
-        if self._recvlength == 0:
-            length = 4
-            length -= len(self._recvbuffer)
-            try:
-                data = self._socket.recv(length)
-            except:
+            if self._socket_timeout == 0.0:
+                self._socket.settimeout(None)
+            else:
+                self._socket.settimeout(self._socket_timeout)
+
+        try:
+            # we might be in a call following an EAGAIN, in which case
+            # we simply continue. In the first case, either
+            # recv_size or recv_len size are not zero
+            # they may never both be non-zero (we are either starting
+            # a full read, or continuing one of the reads
+            assert self._recv_size == 0 or self._recv_len_size == 0
+            
+            if self._recv_size == 0:
+                if self._recv_len_size == 0:
+                    # both zero, start a new full read
+                    self._recv_len_size = 4
+                    self._recv_len_data = bytearray()
+                self._receive_len_data()
+
+                self._recv_size = struct.unpack('>I', self._recv_len_data)[0]
+                self._recv_data = bytearray()
+            self._receive_data()
+
+            # no EAGAIN, so copy data and reset internal counters
+            data = self._recv_data
+
+            self._recv_len_size = 0
+            self._recv_size = 0
+
+            return (data)
+
+        except socket.timeout:
+            raise SessionTimeout("recv() on cc session timed out")
+        except socket.error as se:
+            # Only keep data in case of EAGAIN
+            if se.errno == errno.EAGAIN:
                 return None
-            if data == "": # server closed connection
-                raise ProtocolError("Read of 0 bytes: connection closed")
-            self._recvbuffer += data
-            if len(self._recvbuffer) < 4:
+            # unknown state otherwise, best to drop data
+            self._recv_len_size = 0
+            self._recv_size = 0
+            # ctrl-c can result in EINTR, return None to prevent
+            # stacktrace output
+            if se.errno == errno.EINTR:
                 return None
-            self._recvlength = struct.unpack('>I', self._recvbuffer)[0]
-            self._recvbuffer = bytearray()
-
-        length = self._recvlength - len(self._recvbuffer)
-        while (length > 0):
-            try:
-                data = self._socket.recv(length)
-            except:
-                return None
-            if data == "": # server closed connection
-                raise ProtocolError("Read of 0 bytes: connection closed")
-            self._recvbuffer += data
-            length -= len(data)
-        data = self._recvbuffer
-        self._recvbuffer = bytearray()
-        self._recvlength = 0
-        return (data)
+            raise se
 
     def _next_sequence(self):
         self._sequence += 1
@@ -208,6 +265,15 @@
         }, isc.cc.message.to_wire(msg))
         return seq
 
+    def set_timeout(self, milliseconds):
+        """Sets the socket timeout for blocking reads to the given
+           number of milliseconds"""
+        self._socket_timeout = milliseconds / 1000.0
+
+    def get_timeout(self):
+        """Returns the current timeout for blocking reads (in milliseconds)"""
+        return self._socket_timeout * 1000.0
+
 if __name__ == "__main__":
     import doctest
     doctest.testmod()

Modified: branches/trac308/src/lib/python/isc/cc/tests/Makefile.am
==============================================================================
--- branches/trac308/src/lib/python/isc/cc/tests/Makefile.am (original)
+++ branches/trac308/src/lib/python/isc/cc/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -11,5 +11,6 @@
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	BIND10_TEST_SOCKET_FILE=$(builddir)/test_socket.sock \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/lib/python/isc/cc/tests/session_test.py
==============================================================================
--- branches/trac308/src/lib/python/isc/cc/tests/session_test.py (original)
+++ branches/trac308/src/lib/python/isc/cc/tests/session_test.py Mon Sep 20 11:07:54 2010
@@ -28,6 +28,7 @@
         self.type = type
         self.recvqueue = bytearray()
         self.sendqueue = bytearray()
+        self._blocking = True
 
     def connect(self, to):
         pass
@@ -36,7 +37,7 @@
         pass
 
     def setblocking(self, val):
-        pass
+        self._blocking = val
 
     def send(self, data):
         self.sendqueue.extend(data);
@@ -67,6 +68,11 @@
         return result
 
     def recv(self, length):
+        if len(self.recvqueue) == 0:
+            if self._blocking:
+                return bytes()
+            else:
+                raise socket.error(errno.EAGAIN, "Resource temporarily unavailable")
         if length > len(self.recvqueue):
             raise Exception("Buffer underrun in test, does the test provide the right data?")
         result = self.recvqueue[:length]
@@ -89,28 +95,39 @@
         if msg:
             self.recvqueue.extend(msg)
 
+    def settimeout(self, val):
+        pass
+
+    def gettimeout(self):
+        return 0
+
 #
 # We subclass the Session class we're testing here, only
 # to override the __init__() method, which wants a socket,
 # and we need to use our fake socket
 class MySession(Session):
-    def __init__(self, port=9912):
+    def __init__(self, port=9912, s=None):
         self._socket = None
+        self._socket_timeout = 1
         self._lname = None
         self._recvbuffer = bytearray()
-        self._recvlength = 0
+        self._recv_len_size = 0
+        self._recv_size = 0
         self._sequence = 1
         self._closed = False
         self._queue = []
         self._lock = threading.RLock()
 
-        try:
-            self._socket = MySocket(socket.AF_INET, socket.SOCK_STREAM)
-            self._socket.connect(tuple(['127.0.0.1', port]))
-            self._lname = "test_name"
-            # testing getlname here isn't useful, code removed
-        except socket.error as se:
-                raise SessionError(se)
+        if s is not None:
+            self._socket = s
+        else:
+            try:
+                self._socket = MySocket(socket.AF_INET, socket.SOCK_STREAM)
+                self._socket.connect(tuple(['127.0.0.1', port]))
+                self._lname = "test_name"
+                # testing getlname here isn't useful, code removed
+            except socket.error as se:
+                    raise SessionError(se)
 
 class testSession(unittest.TestCase):
 
@@ -182,10 +199,10 @@
         # get no message without asking for a specific sequence number reply
         self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv({'to': 'someone', 'reply': 1}, {"hello": "a"})
-        env, msg = sess.recvmsg(False)
+        env, msg = sess.recvmsg(True)
         self.assertEqual(None, env)
         self.assertTrue(sess.has_queued_msgs())
-        env, msg = sess.recvmsg(False, 1)
+        env, msg = sess.recvmsg(True, 1)
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
         self.assertFalse(sess.has_queued_msgs())
@@ -194,11 +211,11 @@
         # then ask for the one that is there
         self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv({'to': 'someone', 'reply': 1}, {"hello": "a"})
-        env, msg = sess.recvmsg(False, 2)
+        env, msg = sess.recvmsg(True, 2)
         self.assertEqual(None, env)
         self.assertEqual(None, msg)
         self.assertTrue(sess.has_queued_msgs())
-        env, msg = sess.recvmsg(False, 1)
+        env, msg = sess.recvmsg(True, 1)
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
         self.assertFalse(sess.has_queued_msgs())
@@ -207,11 +224,11 @@
         # then ask for any message
         self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv({'to': 'someone', 'reply': 1}, {"hello": "a"})
-        env, msg = sess.recvmsg(False, 2)
+        env, msg = sess.recvmsg(True, 2)
         self.assertEqual(None, env)
         self.assertEqual(None, msg)
         self.assertTrue(sess.has_queued_msgs())
-        env, msg = sess.recvmsg(False, 1)
+        env, msg = sess.recvmsg(True, 1)
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
         self.assertFalse(sess.has_queued_msgs())
@@ -223,16 +240,16 @@
         # then ask for any message (get the second)
         self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv({'to': 'someone', 'reply': 1}, {'hello': 'a'})
-        env, msg = sess.recvmsg(False, 2)
+        env, msg = sess.recvmsg(True, 2)
         self.assertEqual(None, env)
         self.assertEqual(None, msg)
         self.assertTrue(sess.has_queued_msgs())
         sess._socket.addrecv({'to': 'someone' }, {'hello': 'b'})
-        env, msg = sess.recvmsg(False, 1)
+        env, msg = sess.recvmsg(True, 1)
         self.assertEqual({'to': 'someone', 'reply': 1 }, env)
         self.assertEqual({"hello": "a"}, msg)
         self.assertFalse(sess.has_queued_msgs())
-        env, msg = sess.recvmsg(False)
+        env, msg = sess.recvmsg(True)
         self.assertEqual({'to': 'someone'}, env)
         self.assertEqual({"hello": "b"}, msg)
         self.assertFalse(sess.has_queued_msgs())
@@ -243,11 +260,11 @@
         self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv({'to': 'someone' }, {'hello': 'b'})
         sess._socket.addrecv({'to': 'someone', 'reply': 1}, {'hello': 'a'})
-        env, msg = sess.recvmsg(False, 1)
+        env, msg = sess.recvmsg(True, 1)
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
         self.assertTrue(sess.has_queued_msgs())
-        env, msg = sess.recvmsg(False)
+        env, msg = sess.recvmsg(True)
         self.assertEqual({'to': 'someone'}, env)
         self.assertEqual({"hello": "b"}, msg)
         self.assertFalse(sess.has_queued_msgs())
@@ -323,8 +340,30 @@
         sess.group_reply({ 'from': 'me', 'group': 'our_group', 'instance': 'other_instance', 'seq': 9}, {"hello": "a"})
         sent = sess._socket.readsentmsg();
         self.assertEqual(sent, b'\x00\x00\x00\x8b\x00{{"from": "test_name", "seq": 3, "to": "me", "instance": "other_instance", "reply": 9, "group": "our_group", "type": "send"}{"hello": "a"}')
-        
-        
+
+    def test_timeout(self):
+        if "BIND10_TEST_SOCKET_FILE" not in os.environ:
+            self.assertEqual("", "This test can only run if the value BIND10_TEST_SOCKET_FILE is set in the environment")
+        TEST_SOCKET_FILE = os.environ["BIND10_TEST_SOCKET_FILE"]
+
+        # create a read domain socket to pass into the session
+        s1 = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        if os.path.exists(TEST_SOCKET_FILE):
+            os.remove(TEST_SOCKET_FILE)
+        s1.bind(TEST_SOCKET_FILE)
+
+        try:
+            s1.listen(1)
+
+            s2 = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            s2.connect(TEST_SOCKET_FILE)
+            sess = MySession(1, s2)
+            # set timeout to 100 msec, so test does not take too long
+            sess.set_timeout(100)
+            self.assertRaises(SessionTimeout, sess.group_recvmsg, False)
+        finally:
+            os.remove(TEST_SOCKET_FILE)
+
 if __name__ == "__main__":
     unittest.main()
 

Modified: branches/trac308/src/lib/python/isc/config/ccsession.py
==============================================================================
--- branches/trac308/src/lib/python/isc/config/ccsession.py (original)
+++ branches/trac308/src/lib/python/isc/config/ccsession.py Mon Sep 20 11:07:54 2010
@@ -177,10 +177,14 @@
     def check_command(self):
         """Check whether there is a command or configuration update
            on the channel. Call the corresponding callback function if
-           there is."""
-        msg, env = self._session.group_recvmsg(False)
+           there is. This function does a non-blocking read on the
+           cc session, and returns nothing. It will respond to any
+           command by either an error or the answer message returned
+           by the callback, unless the latter is None."""
+        msg, env = self._session.group_recvmsg(True)
+        
         # should we default to an answer? success-by-default? unhandled error?
-        if msg and not 'result' in msg:
+        if msg is not None and not 'result' in msg:
             answer = None
             try:
                 module_name = env['group']
@@ -244,6 +248,8 @@
            also subscribes to the channel of the remote module name
            to receive the relevant updates. It is not possible to
            specify your own handler for this right now.
+           start() must have been called on this CCSession
+           prior to the call to this method.
            Returns the name of the module."""
         module_spec = isc.config.module_spec_from_file(spec_file_name)
         module_cfg = ConfigData(module_spec)
@@ -252,7 +258,13 @@
 
         # Get the current config for that module now
         seq = self._session.group_sendmsg(create_command(COMMAND_GET_CONFIG, { "module_name": module_name }), "ConfigManager")
-        answer, env = self._session.group_recvmsg(False, seq)
+
+        try:
+            answer, env = self._session.group_recvmsg(False, seq)
+        except isc.cc.SessionTimeout:
+            raise ModuleCCSessionError("No answer from ConfigManager when "
+                                       "asking about Remote module " +
+                                       module_name)
         if answer:
             rcode, value = parse_answer(answer)
             if rcode == 0:
@@ -283,25 +295,32 @@
         """Sends the data specification to the configuration manager"""
         msg = create_command(COMMAND_MODULE_SPEC, self.get_module_spec().get_full_spec())
         seq = self._session.group_sendmsg(msg, "ConfigManager")
-        answer, env = self._session.group_recvmsg(False, seq)
+        try:
+            answer, env = self._session.group_recvmsg(False, seq)
+        except isc.cc.SessionTimeout:
+            # TODO: log an error?
+            pass
         
     def __request_config(self):
         """Asks the configuration manager for the current configuration, and call the config handler if set.
            Raises a ModuleCCSessionError if there is no answer from the configuration manager"""
         seq = self._session.group_sendmsg(create_command(COMMAND_GET_CONFIG, { "module_name": self._module_name }), "ConfigManager")
-        answer, env = self._session.group_recvmsg(False, seq)
-        if answer:
-            rcode, value = parse_answer(answer)
-            if rcode == 0:
-                if value != None and self.get_module_spec().validate_config(False, value):
-                    self.set_local_config(value);
-                    if self._config_handler:
-                        self._config_handler(value)
+        try:
+            answer, env = self._session.group_recvmsg(False, seq)
+            if answer:
+                rcode, value = parse_answer(answer)
+                if rcode == 0:
+                    if value != None and self.get_module_spec().validate_config(False, value):
+                        self.set_local_config(value);
+                        if self._config_handler:
+                            self._config_handler(value)
+                else:
+                    # log error
+                    print("[" + self._module_name + "] Error requesting configuration: " + value)
             else:
-                # log error
-                print("[" + self._module_name + "] Error requesting configuration: " + value)
-        else:
-            raise ModuleCCSessionError("No answer from configuration manager")
+                raise ModuleCCSessionError("No answer from configuration manager")
+        except isc.cc.SessionTimeout:
+            raise ModuleCCSessionError("CC Session timeout waiting for configuration manager")
 
 
 class UIModuleCCSession(MultiConfigData):

Modified: branches/trac308/src/lib/python/isc/config/cfgmgr.py
==============================================================================
--- branches/trac308/src/lib/python/isc/config/cfgmgr.py (original)
+++ branches/trac308/src/lib/python/isc/config/cfgmgr.py Mon Sep 20 11:07:54 2010
@@ -283,7 +283,10 @@
             update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
                                                   conf_part)
             seq = self.cc.group_sendmsg(update_cmd, module_name)
-            answer, env = self.cc.group_recvmsg(False, seq)
+            try:
+                answer, env = self.cc.group_recvmsg(False, seq)
+            except isc.cc.SessionTimeout:
+                answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name)
         else:
             conf_part = data.set(self.config.data, module_name, {})
             data.merge(conf_part[module_name], cmd[1])
@@ -292,7 +295,10 @@
                                                   conf_part[module_name])
             seq = self.cc.group_sendmsg(update_cmd, module_name)
             # replace 'our' answer with that of the module
-            answer, env = self.cc.group_recvmsg(False, seq)
+            try:
+                answer, env = self.cc.group_recvmsg(False, seq)
+            except isc.cc.SessionTimeout:
+                answer = ccsession.create_answer(1, "Timeout waiting for answer from " + module_name)
         if answer:
             rcode, val = ccsession.parse_answer(answer)
             if rcode == 0:
@@ -313,15 +319,19 @@
                 update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
                                                       self.config.data[module])
                 seq = self.cc.group_sendmsg(update_cmd, module)
-                answer, env = self.cc.group_recvmsg(False, seq)
-                if answer == None:
+                try:
+                    answer, env = self.cc.group_recvmsg(False, seq)
+                    if answer == None:
+                        got_error = True
+                        err_list.append("No answer message from " + module)
+                    else:
+                        rcode, val = ccsession.parse_answer(answer)
+                        if rcode != 0:
+                            got_error = True
+                            err_list.append(val)
+                except isc.cc.SessionTimeout:
                     got_error = True
-                    err_list.append("No answer message from " + module)
-                else:
-                    rcode, val = ccsession.parse_answer(answer)
-                    if rcode != 0:
-                        got_error = True
-                        err_list.append(val)
+                    err_list.append("CC Timeout waiting on answer message from " + module)
         if not got_error:
             self.write_config()
             return ccsession.create_answer(0)
@@ -394,9 +404,15 @@
         """Runs the configuration manager."""
         self.running = True
         while (self.running):
+            # we just wait eternally for any command here, so disable
+            # timeouts for this specific recv
+            self.cc.set_timeout(0)
             msg, env = self.cc.group_recvmsg(False)
-            if msg and not 'result' in msg:
+            # and set it back to whatever we default to
+            self.cc.set_timeout(isc.cc.Session.MSGQ_DEFAULT_TIMEOUT)
+            # ignore 'None' value (even though they should not occur)
+            # and messages that are answers to questions we did
+            # not ask
+            if msg is not None and not 'result' in msg:
                 answer = self.handle_msg(msg);
                 self.cc.group_reply(env, answer)
-            else:
-                self.running = False

Modified: branches/trac308/src/lib/python/isc/config/tests/Makefile.am
==============================================================================
--- branches/trac308/src/lib/python/isc/config/tests/Makefile.am (original)
+++ branches/trac308/src/lib/python/isc/config/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -11,5 +11,6 @@
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	CONFIG_TESTDATA_PATH=$(abs_top_srcdir)/src/lib/config/testdata \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	CONFIG_WR_TESTDATA_PATH=$(abs_top_builddir)/src/lib/config/testdata \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/lib/python/isc/config/tests/cfgmgr_test.py
==============================================================================
--- branches/trac308/src/lib/python/isc/config/tests/cfgmgr_test.py (original)
+++ branches/trac308/src/lib/python/isc/config/tests/cfgmgr_test.py Mon Sep 20 11:07:54 2010
@@ -28,19 +28,20 @@
 class TestConfigManagerData(unittest.TestCase):
     def setUp(self):
         self.data_path = os.environ['CONFIG_TESTDATA_PATH']
-        self.config_manager_data = ConfigManagerData(self.data_path)
+        self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
+        self.config_manager_data = ConfigManagerData(self.writable_data_path)
         self.assert_(self.config_manager_data)
 
     def test_init(self):
         self.assertEqual(self.config_manager_data.data['version'],
                          config_data.BIND10_CONFIG_DATA_VERSION)
         self.assertEqual(self.config_manager_data.data_path,
-                         self.data_path)
+                         self.writable_data_path)
         self.assertEqual(self.config_manager_data.db_filename,
-                         self.data_path + os.sep + "b10-config.db")
+                         self.writable_data_path + os.sep + "b10-config.db")
 
     def test_read_from_file(self):
-        ConfigManagerData.read_from_file(self.data_path)
+        ConfigManagerData.read_from_file(self.writable_data_path)
         self.assertRaises(ConfigManagerDataEmpty,
                           ConfigManagerData.read_from_file,
                           "doesnotexist")
@@ -58,10 +59,11 @@
                           self.data_path, "b10-config-bad4.db")
 
     def test_write_to_file(self):
-        output_file_name = "b10-config-write-test";
+        output_file_name = "b10-config-write-test"
         self.config_manager_data.write_to_file(output_file_name)
         new_config = ConfigManagerData(self.data_path, output_file_name)
         self.assertEqual(self.config_manager_data, new_config)
+        os.remove(output_file_name)
 
     def test_equality(self):
         # tests the __eq__ function. Equality is only defined
@@ -83,14 +85,15 @@
 
     def setUp(self):
         self.data_path = os.environ['CONFIG_TESTDATA_PATH']
+        self.writable_data_path = os.environ['CONFIG_WR_TESTDATA_PATH']
         self.fake_session = FakeModuleCCSession()
-        self.cm = ConfigManager(self.data_path, self.fake_session)
+        self.cm = ConfigManager(self.writable_data_path, self.fake_session)
         self.name = "TestModule"
         self.spec = isc.config.module_spec_from_file(self.data_path + os.sep + "/spec2.spec")
     
     def test_init(self):
         self.assert_(self.cm.module_specs == {})
-        self.assert_(self.cm.data_path == self.data_path)
+        self.assert_(self.cm.data_path == self.writable_data_path)
         self.assert_(self.cm.config != None)
         self.assert_(self.fake_session.has_subscription("ConfigManager"))
         self.assert_(self.fake_session.has_subscription("Boss", "ConfigManager"))
@@ -286,13 +289,14 @@
 
     def test_run(self):
         self.fake_session.group_sendmsg({ "command": [ "get_commands_spec" ] }, "ConfigManager")
+        self.fake_session.group_sendmsg({ "command": [ "shutdown" ] }, "ConfigManager")
         self.cm.run()
         pass
 
 
 if __name__ == '__main__':
-    if not 'CONFIG_TESTDATA_PATH' in os.environ:
-        print("You need to set the environment variable CONFIG_TESTDATA_PATH to point to the directory containing the test data files")
+    if not 'CONFIG_TESTDATA_PATH' in os.environ or not 'CONFIG_WR_TESTDATA_PATH' in os.environ:
+        print("You need to set the environment variable CONFIG_TESTDATA_PATH and CONFIG_WR_TESTDATA_PATH to point to the directory containing the test data files")
         exit(1)
     unittest.main()
 

Modified: branches/trac308/src/lib/python/isc/config/tests/unittest_fakesession.py
==============================================================================
--- branches/trac308/src/lib/python/isc/config/tests/unittest_fakesession.py (original)
+++ branches/trac308/src/lib/python/isc/config/tests/unittest_fakesession.py Mon Sep 20 11:07:54 2010
@@ -1,4 +1,21 @@
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+# $Id$
+
+import isc
 
 #
 # We can probably use a more general version of this
@@ -9,6 +26,10 @@
         # each entry is of the form [ channel, instance, message ]
         self.message_queue = []
         self._socket = "ok we just need something not-None here atm"
+        # if self.timeout is set to anything other than 0, and
+        # the message_queue is empty when receive is called, throw
+        # a SessionTimeout
+        self._timeout = 0
 
     def group_subscribe(self, group_name, instance_name = None):
         if not group_name in self.subscriptions:
@@ -48,7 +69,11 @@
             if qm[0] in self.subscriptions and (qm[1] == None or qm[1] in self.subscriptions[qm[0]]):
                 self.message_queue.remove(qm)
                 return qm[2], {'group': qm[0], 'from': qm[1]}
-        return None, None
+        if self._timeout == 0:
+            return None, None
+        else:
+            raise isc.cc.SessionTimeout("Timeout set but no data to "
+                                 "return to group_recvmsg()")
 
     def get_message(self, channel, target = None):
         for qm in self.message_queue:
@@ -60,4 +85,6 @@
     def close(self):
         # need to pass along somehow that this function has been called,
         self._socket = "closed"
-        pass
+
+    def set_timeout(self, timeout):
+        self._timeout = timeout

Modified: branches/trac308/src/lib/python/isc/datasrc/sqlite3_ds.py
==============================================================================
--- branches/trac308/src/lib/python/isc/datasrc/sqlite3_ds.py (original)
+++ branches/trac308/src/lib/python/isc/datasrc/sqlite3_ds.py Mon Sep 20 11:07:54 2010
@@ -17,6 +17,13 @@
 
 import sqlite3, re, random
 import isc
+
+
+#define the index of different part of one record
+RR_TYPE_INDEX = 5
+RR_NAME_INDEX = 2
+RR_TTL_INDEX = 4
+RR_RDATA_INDEX = 7
 
 #########################################################################
 # define exceptions
@@ -86,10 +93,10 @@
 
     return conn, cur
 
-
 #########################################################################
 # get_zone_datas
-#   returns all the records for one zone with the given zone name. 
+#   a generator function producing an iterable set of 
+#   the records in the zone with the given zone name.
 #########################################################################
 def get_zone_datas(zonename, dbfile):
     conn, cur = open(dbfile)
@@ -119,6 +126,39 @@
     conn.close()
 
     return datas
+
+
+#########################################################################
+# get_zone_rrset
+#   returns the rrset of the zone with the given zone name, rrset name 
+#   and given rd type. 
+#   If the zone doesn't exist or rd type doesn't exist, return an empty list. 
+#########################################################################
+def get_zone_rrset(zonename, rr_name, rdtype, dbfile):
+    conn, cur = open(dbfile)
+    id = get_zoneid(zonename, cur)
+    cur.execute("SELECT * FROM records WHERE name = ? and zone_id = ? and rdtype = ?", 
+                [rr_name, id, rdtype])
+    datas = cur.fetchall()
+    cur.close()
+    conn.close()
+    return datas
+
+
+#########################################################################
+# get_zones_info:
+#   returns all the zones' information.
+#########################################################################
+def get_zones_info(db_file):
+    conn, cur = open(db_file)
+    cur.execute("SELECT name, rdclass FROM zones")
+    info = cur.fetchone()
+    while info:
+        yield info
+        info = cur.fetchone()
+
+    cur.close()
+    conn.close()
 
 #########################################################################
 # get_zoneid:
@@ -132,7 +172,7 @@
         return row[0]
     else:
         return ''
-
+    
 #########################################################################
 # reverse_name:
 #   reverse the labels of a DNS name.  (for example,

Modified: branches/trac308/src/lib/python/isc/dns/__init__.py
==============================================================================
--- branches/trac308/src/lib/python/isc/dns/__init__.py (original)
+++ branches/trac308/src/lib/python/isc/dns/__init__.py Mon Sep 20 11:07:54 2010
@@ -1,1 +1,1 @@
-from libdns_python_name import *
+from pydnspp import *

Modified: branches/trac308/src/lib/python/isc/log/tests/Makefile.am
==============================================================================
--- branches/trac308/src/lib/python/isc/log/tests/Makefile.am (original)
+++ branches/trac308/src/lib/python/isc/log/tests/Makefile.am Mon Sep 20 11:07:54 2010
@@ -8,5 +8,5 @@
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
 	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/lib/python/isc/log \
-	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
+	$(PYCOVERAGE) $(abs_srcdir)/$$pytest || exit ; \
 	done

Modified: branches/trac308/src/lib/python/isc/log/tests/log_test.py
==============================================================================
--- branches/trac308/src/lib/python/isc/log/tests/log_test.py (original)
+++ branches/trac308/src/lib/python/isc/log/tests/log_test.py Mon Sep 20 11:07:54 2010
@@ -1,3 +1,22 @@
+# Copyright (C) 2010  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Tests for the python logging module
+#
+
 from isc.log.log import *
 import unittest
 import os

Modified: branches/trac308/src/lib/xfr/fdshare_python.cc
==============================================================================
--- branches/trac308/src/lib/xfr/fdshare_python.cc (original)
+++ branches/trac308/src/lib/xfr/fdshare_python.cc Mon Sep 20 11:07:54 2010
@@ -23,25 +23,23 @@
 #include <xfr/fd_share.h>
 
 static PyObject*
-fdshare_recv_fd(PyObject *self UNUSED_PARAM, PyObject *args)
-{
+fdshare_recv_fd(PyObject *self UNUSED_PARAM, PyObject *args) {
     int sock, fd;
     if (!PyArg_ParseTuple(args, "i", &sock)) {
-        return NULL;
+        return (NULL);
     }
     fd = isc::xfr::recv_fd(sock);
-    return Py_BuildValue("i", fd);
+    return (Py_BuildValue("i", fd));
 }
 
 static PyObject*
-fdshare_send_fd(PyObject *self UNUSED_PARAM, PyObject *args)
-{
+fdshare_send_fd(PyObject *self UNUSED_PARAM, PyObject *args) {
     int sock, fd, result;
     if (!PyArg_ParseTuple(args, "ii", &sock, &fd)) {
-        return NULL;
+        return (NULL);
     }
     result = isc::xfr::send_fd(sock, fd);
-    return Py_BuildValue("i", result);
+    return (Py_BuildValue("i", result));
 }
 
 static PyMethodDef fdshare_Methods[] = {
@@ -64,13 +62,12 @@
 };
 
 PyMODINIT_FUNC
-PyInit_libxfr_python(void)
-{
+PyInit_libxfr_python(void) {
     PyObject *mod = PyModule_Create(&bind10_fdshare_python);
     if (mod == NULL) {
-        return NULL;
+        return (NULL);
     }
 
-    return mod;
+    return (mod);
 }
 

Modified: branches/trac308/src/lib/xfr/xfrout_client.cc
==============================================================================
--- branches/trac308/src/lib/xfr/xfrout_client.cc (original)
+++ branches/trac308/src/lib/xfr/xfrout_client.cc Mon Sep 20 11:07:54 2010
@@ -81,8 +81,9 @@
                   "to xfrout module");
     }
 
-    // XXX: this shouldn't be blocking send, even though it's unlikely to
+    // TODO: this shouldn't be blocking send, even though it's unlikely to
     // block.
+    // converting the 16-bit word to network byte order.
     const uint8_t lenbuf[2] = { msg_len >> 8, msg_len & 0xff };
     if (send(impl_->socket_.native(), lenbuf, sizeof(lenbuf), 0) !=
         sizeof(lenbuf)) {
@@ -100,7 +101,7 @@
                   "xfr query hasn't been processed properly by xfrout module");
     }
 
-    return 0;
+    return (0);
 }
 
 } // End for xfr




More information about the bind10-changes mailing list