[svn] commit: r2097 - in /experiments/python-binding: ./ doc/guide/ ext/asio/ ext/boost/ src/bin/auth/ src/bin/auth/tests/ src/bin/bind10/ src/bin/bind10/tests/ src/bin/bindctl/ src/bin/bindctl/tests/ src/bin/cfgmgr/ src/bin/cmdctl/ src/bin/cmdctl/tests/ src/bin/host/ src/bin/loadzone/ src/bin/msgq/ src/bin/msgq/tests/ src/bin/xfrin/ src/bin/xfrin/tests/ src/bin/xfrout/ src/bin/xfrout/tests/ src/lib/cc/ src/lib/config/ src/lib/config/testdata/ src/lib/config/tests/ src/lib/datasrc/ src/lib/datasrc/tests/ src/lib/dns/ src/lib/dns/rdata/generic/ src/lib/dns/tests/ src/lib/exceptions/ src/lib/python/ src/lib/python/isc/cc/ src/lib/python/isc/cc/tests/ src/lib/python/isc/config/ src/lib/python/isc/config/tests/ src/lib/xfr/

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Jun 9 09:52:34 UTC 2010


Author: jelte
Date: Wed Jun  9 09:52:34 2010
New Revision: 2097

Log:
merge to sync with trunk and make later merge back easier
updated additions in tests for wrapper api
also independently came up with the fix attached in ticket #224

Added:
    experiments/python-binding/ext/asio/
      - copied from r2096, trunk/ext/asio/
    experiments/python-binding/src/bin/auth/asio_link.cc
      - copied, changed from r2096, trunk/src/bin/auth/asio_link.cc
    experiments/python-binding/src/bin/auth/asio_link.h
      - copied unchanged from r2096, trunk/src/bin/auth/asio_link.h
    experiments/python-binding/src/bin/auth/spec_config.h.pre.in
      - copied unchanged from r2096, trunk/src/bin/auth/spec_config.h.pre.in
    experiments/python-binding/src/lib/cc/session_config.h.pre.in
      - copied unchanged from r2096, trunk/src/lib/cc/session_config.h.pre.in
    experiments/python-binding/src/lib/cc/session_unittests.cc
      - copied unchanged from r2096, trunk/src/lib/cc/session_unittests.cc
    experiments/python-binding/src/lib/config/testdata/spec25.spec
      - copied unchanged from r2096, trunk/src/lib/config/testdata/spec25.spec
    experiments/python-binding/src/lib/config/testdata/spec26.spec
      - copied unchanged from r2096, trunk/src/lib/config/testdata/spec26.spec
    experiments/python-binding/src/lib/config/testdata/spec27.spec
      - copied unchanged from r2096, trunk/src/lib/config/testdata/spec27.spec
    experiments/python-binding/src/lib/python/bind10_config.py.in
      - copied unchanged from r2096, trunk/src/lib/python/bind10_config.py.in
    experiments/python-binding/src/lib/python/isc/cc/session.py
      - copied unchanged from r2096, trunk/src/lib/python/isc/cc/session.py
Removed:
    experiments/python-binding/ext/boost/
    experiments/python-binding/src/bin/auth/spec_config.h.in
Modified:
    experiments/python-binding/   (props changed)
    experiments/python-binding/ChangeLog
    experiments/python-binding/INSTALL
    experiments/python-binding/Makefile.am
    experiments/python-binding/README
    experiments/python-binding/configure.ac
    experiments/python-binding/doc/guide/bind10-guide.html
    experiments/python-binding/doc/guide/bind10-guide.xml
    experiments/python-binding/src/bin/auth/Makefile.am
    experiments/python-binding/src/bin/auth/auth.spec.pre.in
    experiments/python-binding/src/bin/auth/auth_srv.cc
    experiments/python-binding/src/bin/auth/main.cc
    experiments/python-binding/src/bin/auth/tests/Makefile.am
    experiments/python-binding/src/bin/bind10/TODO
    experiments/python-binding/src/bin/bind10/bind10.py.in
    experiments/python-binding/src/bin/bind10/bob.spec
    experiments/python-binding/src/bin/bind10/run_bind10.sh.in
    experiments/python-binding/src/bin/bind10/tests/Makefile.am
    experiments/python-binding/src/bin/bind10/tests/bind10_test.py
    experiments/python-binding/src/bin/bindctl/bindcmd.py
    experiments/python-binding/src/bin/bindctl/bindctl-source.py.in
    experiments/python-binding/src/bin/bindctl/cmdparse.py
    experiments/python-binding/src/bin/bindctl/exception.py
    experiments/python-binding/src/bin/bindctl/moduleinfo.py
    experiments/python-binding/src/bin/bindctl/run_bindctl.sh.in
    experiments/python-binding/src/bin/bindctl/tests/Makefile.am
    experiments/python-binding/src/bin/bindctl/tests/bindctl_test.py
    experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.py.in
    experiments/python-binding/src/bin/cmdctl/cmdctl.py.in
    experiments/python-binding/src/bin/cmdctl/cmdctl.spec
    experiments/python-binding/src/bin/cmdctl/tests/Makefile.am
    experiments/python-binding/src/bin/cmdctl/tests/cmdctl_test.py
    experiments/python-binding/src/bin/host/Makefile.am
    experiments/python-binding/src/bin/loadzone/b10-loadzone.py.in
    experiments/python-binding/src/bin/msgq/msgq.py.in
    experiments/python-binding/src/bin/msgq/tests/Makefile.am
    experiments/python-binding/src/bin/msgq/tests/msgq_test.py
    experiments/python-binding/src/bin/xfrin/   (props changed)
    experiments/python-binding/src/bin/xfrin/TODO
    experiments/python-binding/src/bin/xfrin/tests/xfrin_test.in
    experiments/python-binding/src/bin/xfrin/tests/xfrin_test.py   (contents, props changed)
    experiments/python-binding/src/bin/xfrin/xfrin.py.in
    experiments/python-binding/src/bin/xfrin/xfrin.spec.pre.in
    experiments/python-binding/src/bin/xfrout/tests/xfrout_test.py
    experiments/python-binding/src/bin/xfrout/xfrout.py.in
    experiments/python-binding/src/lib/cc/   (props changed)
    experiments/python-binding/src/lib/cc/Makefile.am
    experiments/python-binding/src/lib/cc/data.cc
    experiments/python-binding/src/lib/cc/session.cc
    experiments/python-binding/src/lib/cc/session.h
    experiments/python-binding/src/lib/config/Makefile.am
    experiments/python-binding/src/lib/config/ccsession.cc
    experiments/python-binding/src/lib/config/ccsession.h
    experiments/python-binding/src/lib/config/config_data.h
    experiments/python-binding/src/lib/config/module_spec.cc
    experiments/python-binding/src/lib/config/module_spec.h
    experiments/python-binding/src/lib/config/tests/Makefile.am
    experiments/python-binding/src/lib/config/tests/fake_session.cc
    experiments/python-binding/src/lib/config/tests/fake_session.h
    experiments/python-binding/src/lib/config/tests/module_spec_unittests.cc
    experiments/python-binding/src/lib/datasrc/Makefile.am
    experiments/python-binding/src/lib/datasrc/tests/Makefile.am
    experiments/python-binding/src/lib/datasrc/tests/sqlite3_unittest.cc
    experiments/python-binding/src/lib/datasrc/tests/static_unittest.cc
    experiments/python-binding/src/lib/dns/   (props changed)
    experiments/python-binding/src/lib/dns/Makefile.am
    experiments/python-binding/src/lib/dns/dnssectime.cc
    experiments/python-binding/src/lib/dns/name.cc
    experiments/python-binding/src/lib/dns/name.h
    experiments/python-binding/src/lib/dns/rdata/generic/nsec_47.cc
    experiments/python-binding/src/lib/dns/rdata/generic/rrsig_46.cc   (props changed)
    experiments/python-binding/src/lib/dns/tests/   (props changed)
    experiments/python-binding/src/lib/dns/tests/Makefile.am
    experiments/python-binding/src/lib/dns/tests/dnssectime_unittest.cc
    experiments/python-binding/src/lib/dns/tests/name_unittest.cc
    experiments/python-binding/src/lib/exceptions/Makefile.am
    experiments/python-binding/src/lib/python/Makefile.am
    experiments/python-binding/src/lib/python/isc/cc/message.py
    experiments/python-binding/src/lib/python/isc/cc/tests/Makefile.am
    experiments/python-binding/src/lib/python/isc/cc/tests/session_test.py
    experiments/python-binding/src/lib/python/isc/config/ccsession.py
    experiments/python-binding/src/lib/python/isc/config/cfgmgr.py
    experiments/python-binding/src/lib/python/isc/config/config_data.py
    experiments/python-binding/src/lib/python/isc/config/module_spec.py
    experiments/python-binding/src/lib/python/isc/config/tests/Makefile.am
    experiments/python-binding/src/lib/python/isc/config/tests/ccsession_test.py   (contents, props changed)
    experiments/python-binding/src/lib/python/isc/config/tests/cfgmgr_test.py   (contents, props changed)
    experiments/python-binding/src/lib/python/isc/config/tests/config_data_test.py   (contents, props changed)
    experiments/python-binding/src/lib/python/isc/config/tests/module_spec_test.py   (contents, props changed)
    experiments/python-binding/src/lib/xfr/Makefile.am
    experiments/python-binding/src/lib/xfr/xfrout_client.cc
    experiments/python-binding/src/lib/xfr/xfrout_client.h

Modified: experiments/python-binding/ChangeLog
==============================================================================
--- experiments/python-binding/ChangeLog (original)
+++ experiments/python-binding/ChangeLog Wed Jun  9 09:52:34 2010
@@ -1,15 +1,234 @@
-   1.	[bug]		jinmei
+  53.   [bug]      zhanglikun
+	bin/bindctl: Generate a unique session ID by using 
+	socket.gethostname() instead of socket.gethostbyname(), 
+	since the latter one could make bindctl	stall if its own 
+	host name can't be resolved.
+	(Trac #228, svn r2096)
+
+  52.   [func]      zhanglikun
+	bin/xfrout: When xfrout is launched, check whether the
+	socket file is being used by one running xfrout process, 
+	if it is, exit from python.	If the file isn't a socket file 
+	or nobody is listening, it will be removed. If it can't 
+	be removed, exit from python.
+	(Trac #151, svn r2091)
+
+bind10-devel-20100602 released on June 2, 2010
+
+  51.   [build]         jelte
+	lib/python: Add bind10_config.py module for paths and
+	possibly other configure-time variables. Allow some components
+	to find spec files in build tree when ran from source.
+	(Trac #223)
+
+  50.	[bug]		zhanglikun
+	bin/xfrin: a regression in xfrin: it can't communicate with 
+	a remote server. (Trac #218, svn r2038)
+
+  49.	[func]*		jelte
+	Use unix domain sockets for msgq. (Trac #183, svn r2009)
+
+  48.	[func]		jelte
+	bin/auth: Use asio's io_service for the msgq handling.
+	(svn r2007)
+
+  47.	[func]		zhanglikun
+	bin/cmdctl: Add value/type check for commands sent to
+	cmdctl. (Trac #201, svn r1959)
+
+  46.	[func]		zhanglikun
+	lib/cc: Fix real type data encoding/decoding. (Trac #193,
+	svn r1959)
+
+  45.	[func]		zhanglikun
+	bin/bind10: Pass verbose option to more modules. (Trac
+	#205, svn r1957)
+
+  44.   [build]         jreed
+	Install headers for libdns and libexception.  (Trac #68,
+	svn r1941)
+
+  43.   [func]          jelte
+	lib/cc: Message queuing on cc channel. (Trac #58, svn r1870)
+
+  42.   [func]          jelte
+	lib/python/isc/config:      Make temporary file with python
+	tempfile module instead of manual with fixed name.  (Trac
+	#184, svn r1859)
+
+  41.   [func]          jelte
+	Module descriptions in spec files. (Trac #90, svn r1856)
+
+  40.   [build]         jreed
+	Report detected features and configure settings at end of
+	configure output.  (svn r1836)
+
+  39.   [func]*         each
+	Renamed libauth to libdatasrc.
+
+  38.   [bug]           zhanglikun
+	(Trac #135, #151, #134, svn r1797)
+
+  37.   [build]         jinmei
+	Check for the availability of python-config.  (Trac #159,
+	svn r1794)
+
+  36.	[func]		shane
+	bin/bind10:	Miscellaneous code cleanups and improvements.
+	(Trac #40, svn r2012)
+
+  35.	[bug]		jinmei
+	bin/bindctl: fixed a bug that it didn't accept IPv6 addresses as
+	command arguments. (Trac #219, svn r2022)
+
+  34.	[bug]		jinmei
+	bin/xfrin: fixed several small bugs with many additional unit
+	tests.  Fixes include: IPv6 transport support, resource leak,
+	and non IN class support. (Trac #185, svn r2000)
+
+  33.   [bug]           each
+	bin/auth: output now prepended with "[b10-auth]" (Trac
+	#109, svn r1985)
+
+  32.	[func]*		each
+	bin/auth: removed custom query-processing code, changed
+        boost::asio code to use plain asio instead, and added asio
+        headers to the source tree.  This allows building without
+        using an external boost library. (Trac #163, svn r1983)
+
+  31.	[func]		jinmei
+	lib/dns: added a separate signature for Name::split() as a
+	convenient wrapper for common usage. (Trac #49, svn r1903)
+
+  30.	[bug]		jinmei
 	lib/dns: parameter validation of Name::split() was not sufficient,
 	and invalid parameters could cause integer overflow and make the
 	library crash. (Trac #177, svn r1806)
+
+bind10-devel-20100421 released on April 21, 2010
+
+  29.	[build]
+	Enable Python unit tests for "make check". (svn r1762)
+
+  28.	[bug]
+	Fix msgq CC test so it can find its module. (svn r1751)
+
+  27.	[build]
+	Add missing copyright license statements to various source
+	files.  (svn r1750)
+
+  26.	[func]
+	Use PACKAGE_STRING (name + version) from config.h instead
+	of hard-coded value in CH TXT version.bind replies (Trac
+	#114, svn r1749)
+
+  25.	[func]*
+	Renamed msgq to b10-msgq. (Trac #25, svn r1747, r1748)
+
+  24.	[func]
+	Support case-sensitive name compression in MessageRenderer.
+	(svn r1704)
+
+  23.	[func]
+	Support a simple name with possible compression. (svn r1701)
+
+  22.	[func]
+	b10-xfrout for AXFR-out support added. (svn r1629, r1630)
+
+  21.	[bug]
+	Make log message more readable when xfrin failed. (svn
+	r1697)
+
+  20.	[bug]
+	Keep stderr for child processes if -v is specified. (svn
+	r1690, r1698)
+
+  19.	[bug]
+	Allow bind10 boss to pass environment variables from parent.
+	(svn r1689)
+
+  18.	[bug]
+	Xfrin warn if bind10_dns load failed. (svn r1688)
+
+  17.	[bug]
+	Use sqlite3_ds.load() in xfrin module and catch Sqlite3DSError
+	explicitly. (svn r1684)
+
+  16.	[func]*
+	Removed print_message and print_settings configuration
+	commands from Xfrin. (Trac #136, svn r1682)
+
+  15.	[func]*
+	Changed zone loader/updater so trailing dot is not required.
+	(svn r1681)
+
+  14.	[bug]
+	Change shutdown to actually SIGKILL properly. (svn r1675)
+
+  13.	[bug]
+	Don't ignore other RRs than SOA even if the second SOA is
+	found. (svn r1674)
+
+  12.	[build]
+	Fix tests and testdata so can be used from a read-only
+	source directory.
+
+  11.	[build]
+	Make sure python tests scripts are included in tarball.
+	(svn r1648)
+
+  10.	[build]
+	Improve python detection for configure. (svn r1622)
+
+   9.	[build]
+	Automake the python binding of libdns. (svn r1617)
+
+   8.	[bug]
+	Fix log errors which may cause xfrin module to crash. (svn
+	r1613)
+
+   7.	[func]
+	New API for inserting zone data to sqlite3 database for
+	AXFR-in. (svn r1612, r1613)
+
+   6.	[bug]
+	More code review, miscellaneous cleanups, style guidelines,
+	and new and improved unit tests added.
+
+   5.	[doc]
+	Manual page cleanups and improvements.
+
+   4.	[bug]
+	NSEC RDATA fixes for buffer overrun lookups, incorrect
+	boundary checks, spec-non-conformant behaviors. (svn r1611)
+
+   3.	[bug]
+	Remove a re-raise of an exception that should only have
+	been included in an error answer on the cc channel. (svn
+	r1601)
+
+   2.	[bug]
+	Removed unnecessary sleep() from ccsession.cc. (svn r1528)
+
+   1.	[build]*
+	The configure --with-boostlib option changed to --with-boost-lib.
+
+bind10-devel-20100319 released on March 19, 2010
+
+For complete code revision history, see http://bind10.isc.org/browser
+Specific subversion changesets can be accessed at:
+	http://bind10.isc.org/changeset/rrrr
+Trac tickets can be accessed at: https://bind10.isc.org/ticket/nnn
 
 LEGEND
 [bug] general bug fix.  This is generally a backward compatible change,
 	unless it's deemed to be impossible or very hard to keep
 	compatibility to fix the bug.
+[build] compilation and installation infrastructure change.
 [doc] update to documentation.  This shouldn't change run time behavior.
 [func] new feature.  In some cases this may be a backward incompatible
 	change, which would require a bump of major version.
 [security] security hole fix.  This is no different than a general bug fix
 	except that it will be handled as confidential and will cause 
 	security patch releases.
+*: Backward incompatible or operational change.

Modified: experiments/python-binding/INSTALL
==============================================================================
--- experiments/python-binding/INSTALL (original)
+++ experiments/python-binding/INSTALL Wed Jun  9 09:52:34 2010
@@ -5,5 +5,5 @@
     ./configure
     make
 
-We recommend using the Boost libraries as it provides a safer TCP
-implementation in BIND 10.
+For detailed installation directions, see the guide
+at doc/guide/bind10-guide.html.

Modified: experiments/python-binding/Makefile.am
==============================================================================
--- experiments/python-binding/Makefile.am (original)
+++ experiments/python-binding/Makefile.am Wed Jun  9 09:52:34 2010
@@ -2,6 +2,8 @@
 USE_LCOV=@USE_LCOV@
 LCOV=@LCOV@
 GENHTML=@GENHTML@
+
+DISTCLEANFILES = config.report
 
 # When running distcheck target, do not install the configurations
 DISTCHECK_CONFIGURE_FLAGS = --disable-install-configurations
@@ -37,3 +39,222 @@
 	$(GENHTML) -o coverage report.info 
 
 coverage: clean-coverage perform-coverage report-coverage
+
+#### include external sources in the distributed tarball:
+# EXTRA_DIST = ext/asio/README
+EXTRA_DIST = ext/asio/asio/local/stream_protocol.hpp
+EXTRA_DIST += ext/asio/asio/local/basic_endpoint.hpp
+EXTRA_DIST += ext/asio/asio/local/datagram_protocol.hpp
+EXTRA_DIST += ext/asio/asio/local/connect_pair.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/random_access_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/random_access_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_random_access_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/overlapped_ptr.hpp
+EXTRA_DIST += ext/asio/asio/windows/stream_handle.hpp
+EXTRA_DIST += ext/asio/asio/windows/stream_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/windows/basic_stream_handle.hpp
+EXTRA_DIST += ext/asio/asio/impl/write.ipp
+EXTRA_DIST += ext/asio/asio/impl/read.ipp
+EXTRA_DIST += ext/asio/asio/impl/serial_port_base.ipp
+EXTRA_DIST += ext/asio/asio/impl/write_at.ipp
+EXTRA_DIST += ext/asio/asio/impl/read_at.ipp
+EXTRA_DIST += ext/asio/asio/impl/error_code.ipp
+EXTRA_DIST += ext/asio/asio/impl/read_until.ipp
+EXTRA_DIST += ext/asio/asio/impl/io_service.ipp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/wince_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_event.hpp
+EXTRA_DIST += ext/asio/asio/detail/descriptor_ops.hpp
+EXTRA_DIST += ext/asio/asio/detail/pipe_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/task_io_service_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/handler_alloc_helpers.hpp
+EXTRA_DIST += ext/asio/asio/detail/pop_options.hpp
+EXTRA_DIST += ext/asio/asio/detail/strand_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/buffer_resize_guard.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_scheduler.hpp
+EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/hash_map.hpp
+EXTRA_DIST += ext/asio/asio/detail/event.hpp
+EXTRA_DIST += ext/asio/asio/detail/buffered_stream_storage.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_queue_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/deadline_timer_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_registry.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/task_io_service_operation.hpp
+EXTRA_DIST += ext/asio/asio/detail/epoll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/local_free_on_block_exit.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_queue_set.hpp
+EXTRA_DIST += ext/asio/asio/detail/winsock_init.hpp
+EXTRA_DIST += ext/asio/asio/detail/signal_init.hpp
+EXTRA_DIST += ext/asio/asio/detail/call_stack.hpp
+EXTRA_DIST += ext/asio/asio/detail/operation.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_handle_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/io_control.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_ops.hpp
+EXTRA_DIST += ext/asio/asio/detail/bind_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_overlapped_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_scheduler_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/detail/consuming_buffers.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_option.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_fd_set_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_buffers_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_holder.hpp
+EXTRA_DIST += ext/asio/asio/detail/scoped_lock.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_registry_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/base_from_completion_cond.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/solaris_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/epoll_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/push_options.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_signal_blocker.hpp
+EXTRA_DIST += ext/asio/asio/detail/eventfd_select_interrupter.hpp
+EXTRA_DIST += ext/asio/asio/detail/select_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/old_win_sdk_compat.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor_op_queue.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/buffer_sequence_adapter.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_event.hpp
+EXTRA_DIST += ext/asio/asio/detail/thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/handler_invoke_helpers.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_event.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_id.hpp
+EXTRA_DIST += ext/asio/asio/detail/socket_types.hpp
+EXTRA_DIST += ext/asio/asio/detail/throw_error.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_op.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_descriptor_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/resolver_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/op_queue.hpp
+EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_thread.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_operation.hpp
+EXTRA_DIST += ext/asio/asio/detail/service_base.hpp
+EXTRA_DIST += ext/asio/asio/detail/select_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/wrapped_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/mutex.hpp
+EXTRA_DIST += ext/asio/asio/detail/completion_handler.hpp
+EXTRA_DIST += ext/asio/asio/detail/noncopyable.hpp
+EXTRA_DIST += ext/asio/asio/detail/task_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/kqueue_reactor.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_queue_base.hpp
+EXTRA_DIST += ext/asio/asio/detail/win_iocp_io_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/gcc_x86_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/posix_tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/detail/macos_fenced_block.hpp
+EXTRA_DIST += ext/asio/asio/detail/dev_poll_reactor_fwd.hpp
+EXTRA_DIST += ext/asio/asio/detail/timer_queue.hpp
+EXTRA_DIST += ext/asio/asio/detail/reactive_serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/detail/null_tss_ptr.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_stream_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_operation.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_init.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_context_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/detail/openssl_types.hpp
+EXTRA_DIST += ext/asio/asio/ssl/stream.hpp
+EXTRA_DIST += ext/asio/asio/ssl/stream_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/context_base.hpp
+EXTRA_DIST += ext/asio/asio/ssl/context.hpp
+EXTRA_DIST += ext/asio/asio/ssl/context_service.hpp
+EXTRA_DIST += ext/asio/asio/ssl/basic_context.hpp
+EXTRA_DIST += ext/asio/asio/ssl/stream_base.hpp
+EXTRA_DIST += ext/asio/asio/posix/stream_descriptor.hpp
+EXTRA_DIST += ext/asio/asio/posix/stream_descriptor_service.hpp
+EXTRA_DIST += ext/asio/asio/posix/basic_stream_descriptor.hpp
+EXTRA_DIST += ext/asio/asio/posix/basic_descriptor.hpp
+EXTRA_DIST += ext/asio/asio/posix/descriptor_base.hpp
+EXTRA_DIST += ext/asio/asio/ip/detail/socket_option.hpp
+EXTRA_DIST += ext/asio/asio/ip/v6_only.hpp
+EXTRA_DIST += ext/asio/asio/ip/address_v4.hpp
+EXTRA_DIST += ext/asio/asio/ip/address_v6.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver.hpp
+EXTRA_DIST += ext/asio/asio/ip/multicast.hpp
+EXTRA_DIST += ext/asio/asio/ip/unicast.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_iterator.hpp
+EXTRA_DIST += ext/asio/asio/ip/host_name.hpp
+EXTRA_DIST += ext/asio/asio/ip/resolver_query_base.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_endpoint.hpp
+EXTRA_DIST += ext/asio/asio/ip/resolver_service.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_entry.hpp
+EXTRA_DIST += ext/asio/asio/ip/address.hpp
+EXTRA_DIST += ext/asio/asio/ip/tcp.hpp
+EXTRA_DIST += ext/asio/asio/ip/basic_resolver_query.hpp
+EXTRA_DIST += ext/asio/asio/ip/udp.hpp
+EXTRA_DIST += ext/asio/asio/ip/icmp.hpp
+EXTRA_DIST += ext/asio/asio/error.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket.hpp
+EXTRA_DIST += ext/asio/asio/buffered_stream.hpp
+EXTRA_DIST += ext/asio/asio/system_error.hpp
+EXTRA_DIST += ext/asio/asio/basic_io_object.hpp
+EXTRA_DIST += ext/asio/asio/read_at.hpp
+EXTRA_DIST += ext/asio/asio/basic_raw_socket.hpp
+EXTRA_DIST += ext/asio/asio/serial_port_service.hpp
+EXTRA_DIST += ext/asio/asio/basic_stream_socket.hpp
+EXTRA_DIST += ext/asio/asio/placeholders.hpp
+EXTRA_DIST += ext/asio/asio/basic_deadline_timer.hpp
+EXTRA_DIST += ext/asio/asio/thread.hpp
+EXTRA_DIST += ext/asio/asio/buffered_write_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/datagram_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/handler_invoke_hook.hpp
+EXTRA_DIST += ext/asio/asio/is_read_buffered.hpp
+EXTRA_DIST += ext/asio/asio/buffer.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_acceptor.hpp
+EXTRA_DIST += ext/asio/asio/write_at.hpp
+EXTRA_DIST += ext/asio/asio/completion_condition.hpp
+EXTRA_DIST += ext/asio/asio/raw_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/socket_base.hpp
+EXTRA_DIST += ext/asio/asio/serial_port.hpp
+EXTRA_DIST += ext/asio/asio/error_code.hpp
+EXTRA_DIST += ext/asio/asio/basic_serial_port.hpp
+EXTRA_DIST += ext/asio/asio/version.hpp
+EXTRA_DIST += ext/asio/asio/deadline_timer_service.hpp
+EXTRA_DIST += ext/asio/asio/io_service.hpp
+EXTRA_DIST += ext/asio/asio/buffered_read_stream.hpp
+EXTRA_DIST += ext/asio/asio/streambuf.hpp
+EXTRA_DIST += ext/asio/asio/basic_datagram_socket.hpp
+EXTRA_DIST += ext/asio/asio/basic_streambuf.hpp
+EXTRA_DIST += ext/asio/asio/write.hpp
+EXTRA_DIST += ext/asio/asio/strand.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_iostream.hpp
+EXTRA_DIST += ext/asio/asio/buffered_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/basic_socket_streambuf.hpp
+EXTRA_DIST += ext/asio/asio/ssl.hpp
+EXTRA_DIST += ext/asio/asio/deadline_timer.hpp
+EXTRA_DIST += ext/asio/asio/buffers_iterator.hpp
+EXTRA_DIST += ext/asio/asio/handler_alloc_hook.hpp
+EXTRA_DIST += ext/asio/asio/buffered_write_stream.hpp
+EXTRA_DIST += ext/asio/asio/read.hpp
+EXTRA_DIST += ext/asio/asio/serial_port_base.hpp
+EXTRA_DIST += ext/asio/asio/stream_socket_service.hpp
+EXTRA_DIST += ext/asio/asio/time_traits.hpp
+EXTRA_DIST += ext/asio/asio/read_until.hpp
+EXTRA_DIST += ext/asio/asio/is_write_buffered.hpp
+EXTRA_DIST += ext/asio/asio/buffered_read_stream_fwd.hpp
+EXTRA_DIST += ext/asio/asio/socket_acceptor_service.hpp
+EXTRA_DIST += ext/asio/asio.hpp
+
+## include the guide in tarball, later will include the other parts there
+## but they cleanup.
+EXTRA_DIST += doc/guide/bind10-guide.css
+EXTRA_DIST += doc/guide/bind10-guide.html
+EXTRA_DIST += doc/guide/bind10-guide.xml

Modified: experiments/python-binding/README
==============================================================================
--- experiments/python-binding/README (original)
+++ experiments/python-binding/README Wed Jun  9 09:52:34 2010
@@ -13,9 +13,11 @@
 
         http://bind10.isc.org/wiki/Year1Deliverable
 
-This release includes the bind10 master process, msgq message bus,
-b10-auth authoritative DNS server, b10-cmdctl remote control daemon,
-b10-cfgmgr configuration manager, and a new libdns library.
+This release includes the bind10 master process, b10-msgq message
+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.
 
 Documentation is included and also available via the BIND 10
 website at http://bind10.isc.org/
@@ -34,12 +36,10 @@
 
         http://bind10.isc.org/
 
-See the Guide for detailed installation directions.
-
 BUILDING
 
-We recommend using the Boost libraries as it provides a safer TCP
-implementation in BIND 10.
+See the Guide for detailed installation directions at
+doc/guide/bind10-guide.html.
 
 Simple build instructions:
 

Modified: experiments/python-binding/configure.ac
==============================================================================
--- experiments/python-binding/configure.ac (original)
+++ experiments/python-binding/configure.ac Wed Jun  9 09:52:34 2010
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.59])
-AC_INIT(bind10-devel, 20100318, bind10-dev at isc.org)
+AC_INIT(bind10-devel, 20100602, bind10-dev at isc.org)
 AC_CONFIG_SRCDIR(README)
 AM_INIT_AUTOMAKE
 AC_CONFIG_HEADERS([config.h])
@@ -93,9 +93,21 @@
 
 # TODO: check for _sqlite3.py module
 
-# default compiler warning settings
+#
+# B10_CXXFLAGS is the default C++ compiler flags.  This will (and should) be
+# used as the default value for each specifc AM_CXXFLAGS:
+# AM_CXXFLAGS = $(B10_CXXFLAGS)
+# AM_CXXFLAGS += ... # add module specific flags
+# We need this so that we can disable some specific compiler warnings per
+# module basis; since AM_CXXFLAGS are placed before CXXFLAGS, and since
+# gcc's -Wno-XXX option must be specified after -Wall or -Wextra, we cannot
+# specify the default warning flags in CXXFLAGS and let specific modules
+# "override" the default.
+#
+B10_CXXFLAGS=
+
 if test "X$GCC" = "Xyes"; then
-CXXFLAGS="$CXXFLAGS -g -Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
+B10_CXXFLAGS="-g -Wall -Wextra -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare"
 UNUSED_PARAM_ATTRIBUTE='__attribute__((unused))'
 
 # Certain versions of gcc (g++) have a bug that incorrectly warns about
@@ -103,22 +115,26 @@
 # translation unit.  For these versions we have to disable -Werror.
 werror_ok=0
 CXXFLAGS_SAVED="$CXXFLAGS"
-CXXFLAGS="$CXXFLAGS -Werror"
+CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
 AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
 AC_TRY_COMPILE([namespace { class Foo {}; }
 namespace isc {class Bar {Foo foo_;};} ],,
 	[AC_MSG_RESULT(no)
-	 werror_ok=1],
+	 werror_ok=1
+	 B10_CXXFLAGS="$B10_CXXFLAGS -Werror"],
 	[AC_MSG_RESULT(yes)])
 CXXFLAGS="$CXXFLAGS_SAVED"
-fi
+fi				dnl GCC = yes
+
+AM_CONDITIONAL(GCC_WERROR_OK, test $werror_ok = 1)
 AC_DEFINE_UNQUOTED(UNUSED_PARAM, $UNUSED_PARAM_ATTRIBUTE, Define to compiler keyword indicating a function argument is intentionally unused)
-AM_CONDITIONAL(GCC_WERROR_OK, test $werror_ok = 1)
 
 # produce PIC unless we disable shared libraries. need this for python bindings.
 if test $enable_shared != "no" -a "X$GCC" = "Xyes"; then
-   CXXFLAGS="$CXXFLAGS -fPIC"
-fi
+   B10_CXXFLAGS="$B10_CXXFLAGS -fPIC"
+fi
+
+AC_SUBST(B10_CXXFLAGS)
 
 # Checks for libraries.
 
@@ -130,6 +146,8 @@
 # Checks for typedefs, structures, and compiler characteristics.
 AC_HEADER_STDBOOL
 AC_TYPE_SIZE_T
+
+
 
 AC_MSG_CHECKING(for sa_len in struct sockaddr)
 AC_TRY_COMPILE([
@@ -137,7 +155,7 @@
 #include <sys/socket.h>],
 [struct sockaddr sa; sa.sa_len = 0; return (0);],
         [AC_MSG_RESULT(yes)
-        AC_DEFINE(HAVE_SIN_LEN, 1, Define to 1 if sockaddr_in has a sin_len member)],
+        AC_DEFINE(HAVE_SA_LEN, 1, [Define to 1 if sockaddr has a sa_len member, and corresponding sin_len and sun_len])],
         AC_MSG_RESULT(no))
 
 AC_ARG_WITH(lcov,
@@ -198,52 +216,6 @@
    BOOST_LDFLAGS="-L$withval"
    fi])
 AC_SUBST(BOOST_LDFLAGS)
-
-# Check availability of the Boost System library
-
-AC_MSG_CHECKING([for boost::system library])
-AC_ARG_WITH([boost-system],
-AC_HELP_STRING([--with-boost-system],
-  [specify whether to use the boost system library]),
-  [with_boost_system="$withval"], [with_boost_system="auto"])
-
-if test "$with_boost_system" != "no"; then
-	LDFLAGS_SAVED="$LDFLAGS"
-	LIBS_SAVED="$LIBS"
-	CPPFLAGS_SAVED="$CPPFLAGS"
-	CPPFLAGS="$CPPFLAGS -Iext"
-
-	for BOOST_TRY_LIB in boost_system boost_system-mt; do
-		LDFLAGS="$LDFLAGS_SAVED ${BOOST_LDFLAGS}"
-		LIBS="$LIBS_SAVED -l${BOOST_TRY_LIB}"
-		AC_TRY_LINK([#include <boost/system/error_code.hpp>],
-			[ boost::system::error_code error_code;
-			std::string message(error_code.message());
-			return 0; ],
-			[ AC_MSG_RESULT(yes)
-			BOOST_SYSTEM_LIB="-l${BOOST_TRY_LIB}"
-			],[])
-		if test "X${BOOST_SYSTEM_LIB}" != X; then
-        		break
-		fi
-	done
-
-	LDFLAGS="$LDFLAGS_SAVED"
-	CPPFLAGS="$CPPFLAGS_SAVED"
-	LIBS="$LIBS_SAVED"
-fi
-
-if test "X${BOOST_SYSTEM_LIB}" = X; then
-	AC_MSG_RESULT(no)
-	if test "$with_boost_system" = "yes"; then
-	   AC_MSG_ERROR([boost system library is requested but not found])
-	fi
-else
-	AC_DEFINE(HAVE_BOOST_SYSTEM, 1, Define to 1 if boost system library is available)
-fi
-
-AM_CONDITIONAL(HAVE_BOOST_SYSTEM, test "X${BOOST_SYSTEM_LIB}" != X)
-AC_SUBST(BOOST_SYSTEM_LIB)
 
 # Check availability of the Boost Python library
 
@@ -298,22 +270,62 @@
 AC_SUBST(GTEST_LDFLAGS)
 AC_SUBST(GTEST_LDADD)
 
-PKG_CHECK_MODULES(SQLITE, sqlite3 >= 3.3.9)
+PKG_CHECK_MODULES(SQLITE, sqlite3 >= 3.3.9, enable_features="$enable_features SQLite3")
+
+# I can't get some of the #include <asio.hpp> right without this
+# TODO: find the real cause of asio/boost wanting pthreads
+# (this currently only occurs for src/lib/cc/session_unittests)
+PTHREAD_LDFLAGS=
+AC_CHECK_LIB(pthread, pthread_create,[ PTHREAD_LDFLAGS=-lpthread ], [])
+AC_SUBST(PTHREAD_LDFLAGS)
+
+#
+# ASIO: we extensively use it as the C++ event management module.
+#
+# Use local ASIO headers from ext
+#
+CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/ext/asio"
+#
+# kqueue portability: ASIO uses kqueue by default if it's available (it's
+# generally available in BSD variants).  Unfortunately, some public
+# implementation of kqueue forces a conversion from a pointer to an integer,
+# which is prohibited in C++ unless reinterpret_cast, C++'s most evil beast
+# (and ASIO doesn't use it anyway) is used.  This will cause build error for
+# some of our C++ files including ASIO header files.  The following check
+# detects such cases and tells ASIO not to use kqueue if so.
+AC_CHECK_FUNC(kqueue, ac_cv_have_kqueue=yes, ac_cv_have_kqueue=no)
+if test "X$ac_cv_have_kqueue" = "Xyes"; then
+	AC_MSG_CHECKING([whether kqueue EV_SET compiles in C++])
+	AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/event.h>],
+[char* udata;
+EV_SET(NULL, 0, 0, 0, 0, 0, udata);],
+	[AC_MSG_RESULT(yes)],
+	[AC_MSG_RESULT([no, disable kqueue for ASIO])
+	 CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_KQUEUE=1"
+	])
+fi
+
+# /dev/poll issue: ASIO uses /dev/poll by default if it's available (generally
+# the case with Solaris).  Unfortunately its /dev/poll specific code would
+# trigger the gcc's "missing-field-initializers" warning, which would
+# subsequently make the build fail with -Werror.  Further, older versions of
+# gcc don't provide an option to selectively suppress this warning.
+# So, for the moment, we simply disable the use of /dev/poll.  Unless we
+# implement recursive DNS server with randomized ports, we don't need the
+# scalability that /dev/poll can provide, so this decision wouldn't affect
+# run time performance.  Hpefully we can find a better solution or the ASIO
+# code will be updated by the time we really need it.
+AC_CHECK_HEADERS(sys/devpoll.h, ac_cv_have_devpoll=yes, ac_cv_have_devpoll=no)
+if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GCC" = "Xyes"; then
+	CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
+fi
 
 # Check for headers from required devel kits.
-# boost/shared_ptr.hpp is in ext in svn but not in tarball.
-CPPFLAGS_SAVED=$CPPFLAGS
-if test "X$BOOST_INCLUDES" = "X"; then
-	# abs_top_srcdir not defined yet
-	# so this is only useful to check.  We'll replace it after the check.
-	CPPFLAGS="$CPPFLAGS -Iext"
-fi
 AC_CHECK_HEADERS([boost/shared_ptr.hpp boost/foreach.hpp],,
   AC_MSG_ERROR([Missing required header files.]))
-CPPFLAGS=$CPPFLAGS_SAVED
-if test "X$BOOST_INCLUDES" = "X"; then
-	CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/ext"
-fi
 
 AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man],
   [regenerate man pages [default=no]])] ,enable_man=yes, enable_man=no)
@@ -393,13 +405,15 @@
            src/bin/msgq/tests/msgq_test
            src/bin/msgq/run_msgq.sh
            src/bin/auth/auth.spec.pre
-           src/bin/auth/spec_config.h
+           src/bin/auth/spec_config.h.pre
            src/lib/config/tests/data_def_unittests_config.h
            src/lib/python/isc/config/tests/config_test
            src/lib/python/isc/cc/tests/cc_test
            src/lib/dns/python/tests/libdns_python_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
           ], [
            chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
            chmod +x src/bin/xfrin/run_b10-xfrin.sh
@@ -419,3 +433,44 @@
            chmod +x src/lib/dns/python/tests/libdns_python_test
           ])
 AC_OUTPUT
+
+dnl Print the results
+dnl
+
+cat > config.report << END
+
+     BIND 10 source configure results:
+    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+Package:
+  Name:          $PACKAGE_NAME
+  Version:       $PACKAGE_VERSION
+
+Flags:
+  DEFS:          $DEFS
+  CPPFLAGS:      $CPPFLAGS
+  CFLAGS:        $CFLAGS
+  CXXFLAGS:      $CXXFLAGS
+  B10_CXXFLAGS:  $B10_CXXFLAGS
+dnl includes too
+  Boost Python:  $BOOST_PYTHON_LIB
+  SQLite:	 $SQLITE_CFLAGS
+                 $SQLITE_LIBS
+
+Features:
+  $enable_features
+
+Developer:
+  Google Tests:  $gtest_path
+  Code Coverage: $USE_LCOV
+  Generate Manuals:  $enable_man
+
+END
+
+cat config.report
+cat <<EOF
+
+  Now you can type "make" to build BIND 10
+
+EOF
+

Modified: experiments/python-binding/doc/guide/bind10-guide.html
==============================================================================
--- experiments/python-binding/doc/guide/bind10-guide.html (original)
+++ experiments/python-binding/doc/guide/bind10-guide.html Wed Jun  9 09:52:34 2010
@@ -2,7 +2,7 @@
         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="#id1168230328120">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="#id1168230328382">Download Tar File</a></span></dt><dt><s
 pan class="section"><a href="#id1168230328403">Retrieve from Subversion</a></span></dt><dt><span class="section"><a href="#id1168230328464">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230328600">Build</a></span></dt><dt><span class="section"><a href="#id1168230328615">Install</a></span></dt><dt><span class="section"><a href="#id1168230328645">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="#id1168230329212">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230329277">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230329307">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="#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="#id1168230328405">Download Tar File</a></span></dt><dt><s
 pan class="section"><a href="#id1168230327606">Retrieve from Subversion</a></span></dt><dt><span class="section"><a href="#id1168230327666">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230328711">Build</a></span></dt><dt><span class="section"><a href="#id1168230328726">Install</a></span></dt><dt><span class="section"><a href="#id1168230328757">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="#id1168230329323">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230329388">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230329419">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>
       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
@@ -32,7 +32,8 @@
 	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 libboost library, libpython3 library,
+	modules require the libboost library,
+        Boost Python library, 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
@@ -42,37 +43,35 @@
         </p></div></div><div class="section" title="Starting and Stopping the Server"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="starting_stopping"></a>Starting and Stopping the Server</h2></div></div></div><p>
         BIND 10 is modular.  Part of this modularity is
         accomplished using multiple cooperating processes which, together,
-        provide DNS functionality.  This is a change from the previous generation
-        of BIND software, which used a single process.
-      </p><p>
-        At first, running many different processes may seem confusing.  However,
-        these processes are started, stopped, and maintained by a single command,
-        <span class="command"><strong>bind10</strong></span>.  Additionally, the processes started by
-        the <span class="command"><strong>bind10</strong></span> command have names starting with "b10-".
-      </p><p>
-        Starting and stopping the server is performed by a single command,
-        <span class="command"><strong>bind10</strong></span>.  This command starts a master process
-        which will start other processes as needed.
-      </p><p>
-        Most of these are run automatically by a single command,
-        <span class="command"><strong>bind10</strong></span> and should not be run manually.
+	provide the server functionality.  This is a change from
+	the previous generation of BIND software, which used a
+	single process.
+      </p><p>
+	At first, running many different processes may seem confusing.
+	However, these processes are started, stopped, and maintained
+	by a single command, <span class="command"><strong>bind10</strong></span>.
+	This command starts a master process which will start other
+	processes as needed.
+	The processes started by the <span class="command"><strong>bind10</strong></span>
+	command have names starting with "b10-", including:
+      </p><p>
 
         </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem">
               <span class="command"><strong>b10-msgq</strong></span> —
-              message bus daemon.
+              Message bus daemon.
               This process coordinates communication between all of the other
               BIND 10 processes.
             </li><li class="listitem">
               <span class="command"><strong>b10-auth</strong></span> —
-              authoritative DNS server.
+              Authoritative DNS server.
               This process serves DNS requests.
             </li><li class="listitem">
               <span class="command"><strong>b10-cfgmgr</strong></span> —
-              configuration manager.
+              Configuration manager.
               This process maintains all of the configuration for BIND 10.
             </li><li class="listitem">
               <span class="command"><strong>b10-cmdctl</strong></span> —
-              command and control service.
+              Command and control service.
               This process allows external control of the BIND 10 system.
             </li><li class="listitem">
               <span class="command"><strong>b10-xfrin</strong></span> —
@@ -86,6 +85,9 @@
 	      send a local zone to a remote secondary server,
 	      when acting as a master server.
             </li></ul></div><p>
+      </p><p>
+	These are ran automatically by <span class="command"><strong>bind10</strong></span>
+	and do not need to be run manually.
       </p></div><div class="section" title="Managing BIND 10"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="managing_once_running"></a>Managing BIND 10</h2></div></div></div><p>
 	Once BIND 10 is running, a few commands are used to interact
 	directly with the system:
@@ -115,7 +117,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="#id1168230328120">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="#id1168230328382">Download Tar File</a></span></dt><dt><span class="section"><a href="#id1168230328403">Retrieve from Subversion</a></span></dt><dt><span class="section"><a href="#id1168230328464">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230328600">Build</a></span></dt><dt><span class="section"><a href="#id1168230328615">Install</a></span></dt><dt><span class="section"><a href="#id1168230328645">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="id1168230328120"></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="#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="#id1168230328405">Download Tar File</a></span></dt><dt><span class="section"><a href="#id1168230327606">Retrieve from Subversion</a></span></dt><dt><span class="section"><a href="#id1168230327666">Configure before the build</a></span></dt><dt><span class="section"><a href="#id1168230328711">Build</a></span></dt><dt><span class="section"><a href="#id1168230328726">Install</a></span></dt><dt><span class="section"><a href="#id1168230328757">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>
             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
@@ -126,26 +128,13 @@
   
   
         </p><p>
-	  The Boost Library, Boost Python library, Python Library,
+	  The Boost Library, Boost Python Library, Python Library,
 	  and Python _sqlite3 module are required to enable the
 	  Xfrout and Xfrin support.
         </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
           The Python related libraries and modules need to be built
           for Python 3.1.
         </p></div><p>
-          If the Boost System Library is detected at configure time,
-          BIND 10 will be built using an alternative method for
-          networking I/O using Boost ASIO support.  This provides
-          asynchrony support; with ASIO the Authoritative DNS server
-          can handle other queries while the processing of a TCP
-          transaction stalls.
-          This dependency is not required unless you need
-           this feature as TCP transport support is
-          provided using alternative code.
-        </p><div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
-We recommend using the Boost libraries as it provides a safer TCP
-implementation in BIND 10. 
-</p></div><p>
           Building BIND 10 also requires a C++ compiler and
           standard development headers.
           BIND 10 builds have been tested with GCC g++ 3.4.3, 4.1.2,
@@ -189,14 +178,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="id1168230328382"></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="id1168230328405"></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="id1168230328403"></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="id1168230327606"></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.
@@ -228,7 +217,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="id1168230328464"></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="id1168230327666"></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:
@@ -242,7 +231,6 @@
               </dd><dt><span class="term">--with-boost-include</span></dt><dd>Define the path to find the Boost headers.
               </dd><dt><span class="term">--with-boost-lib</span></dt><dd>Define the path to find the Boost library.
               </dd><dt><span class="term">--with-boost-python</span></dt><dd>Define to use the Boost Python library.
-              </dd><dt><span class="term">--with-boost-system</span></dt><dd>Define to use the Boost System library.
               </dd><dt><span class="term">--with-pythonpath</span></dt><dd>Define the path to Python 3.1 if it is not in the
                 standard execution path.
               </dd><dt><span class="term">--with-gtest</span></dt><dd>Enable building the C++ Unit Tests using the
@@ -251,25 +239,25 @@
               </dd></dl></div><p>
 
         </p><p>
-          For example, the following configures it to build
-    with BOOST ASIO support, find the Boost headers, find the
+          For example, the following configures it
+    build with Boost Python support (for Python DNS library),
+    find the Boost headers and library, find the
     Python interpreter, and sets the installation location:
 
           </p><pre class="screen">$ <strong class="userinput"><code>./configure --with-boost-lib=/usr/pkg/lib \
       --with-boost-include=/usr/pkg/include \
       --with-boost-python \
-      --with-boost-system \
       --with-pythonpath=/usr/pkg/bin/python3.1 \
       --prefix=/opt/bind10</code></strong></pre><p>
         </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="id1168230328600"></a>Build</h3></div></div></div><p>
+        </p></div><div class="section" title="Build"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328711"></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="id1168230328615"></a>Install</h3></div></div></div><p>
+        </p></div><div class="section" title="Install"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328726"></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>
@@ -278,7 +266,7 @@
 	  Python and Python shared libraries, you may need to
 	  configure your run-time linker to find them (such as
 	  setting LD_LIBRARY_PATH).
-        </p></div></div><div class="section" title="Install Hierarchy"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328645"></a>Install Hierarchy</h3></div></div></div><p>
+        </p></div></div><div class="section" title="Install Hierarchy"><div class="titlepage"><div><div><h3 class="title"><a name="id1168230328757"></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> —
@@ -490,7 +478,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="#id1168230329212">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230329277">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230329307">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="#id1168230329323">Server Configurations</a></span></dt><dt><span class="section"><a href="#id1168230329388">Data Source Backends</a></span></dt><dt><span class="section"><a href="#id1168230329419">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
@@ -498,7 +486,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="id1168230329212"></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="id1168230329323"></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>.
@@ -518,7 +506,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="id1168230329277"></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="id1168230329388"></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
@@ -531,7 +519,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="id1168230329307"></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="id1168230329419"></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.

Modified: experiments/python-binding/doc/guide/bind10-guide.xml
==============================================================================
--- experiments/python-binding/doc/guide/bind10-guide.xml (original)
+++ experiments/python-binding/doc/guide/bind10-guide.xml Wed Jun  9 09:52:34 2010
@@ -75,7 +75,8 @@
 	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 libboost library, libpython3 library,
+	modules require the libboost library,
+        Boost Python library, libpython3 library,
 	and the Python _sqlite3.so module.
       </para></note>
 <!-- TODO: this will change ... -->
@@ -98,32 +99,28 @@
       <para>
         BIND 10 is modular.  Part of this modularity is
         accomplished using multiple cooperating processes which, together,
-        provide DNS functionality.  This is a change from the previous generation
-        of BIND software, which used a single process.
-      </para>
-
-      <para>
-        At first, running many different processes may seem confusing.  However,
-        these processes are started, stopped, and maintained by a single command,
-        <command>bind10</command>.  Additionally, the processes started by
-        the <command>bind10</command> command have names starting with "b10-".
+	provide the server functionality.  This is a change from
+	the previous generation of BIND software, which used a
+	single process.
+      </para>
+
+      <para>
+	At first, running many different processes may seem confusing.
+	However, these processes are started, stopped, and maintained
+	by a single command, <command>bind10</command>.
+	This command starts a master process which will start other
+	processes as needed.
+	The processes started by the <command>bind10</command>
+	command have names starting with "b10-", including:
       </para>
       
       <para>
-        Starting and stopping the server is performed by a single command,
-        <command>bind10</command>.  This command starts a master process
-        which will start other processes as needed.
-      </para>
-      
-      <para>
-        Most of these are run automatically by a single command,
-        <command>bind10</command> and should not be run manually.
 
         <itemizedlist>
           <listitem>
             <simpara>
               <command>b10-msgq</command> —
-              message bus daemon.
+              Message bus daemon.
               This process coordinates communication between all of the other
               BIND 10 processes.
             </simpara>
@@ -131,21 +128,21 @@
           <listitem>
             <simpara>
               <command>b10-auth</command> —
-              authoritative DNS server.
+              Authoritative DNS server.
               This process serves DNS requests.
             </simpara>
           </listitem>
           <listitem>
             <simpara>
               <command>b10-cfgmgr</command> —
-              configuration manager.
+              Configuration manager.
               This process maintains all of the configuration for BIND 10.
             </simpara>
           </listitem>
           <listitem>
             <simpara>
               <command>b10-cmdctl</command> —
-              command and control service.
+              Command and control service.
               This process allows external control of the BIND 10 system.
             </simpara>
           </listitem>
@@ -171,6 +168,12 @@
 
         </itemizedlist>
       </para>
+
+      <para>
+	These are ran automatically by <command>bind10</command>
+	and do not need to be run manually.
+      </para>
+
     </section>
 
     <section id="managing_once_running">
@@ -269,7 +272,7 @@
         </para>
 
         <para>
-	  The Boost Library, Boost Python library, Python Library,
+	  The Boost Library, Boost Python Library, Python Library,
 	  and Python _sqlite3 module are required to enable the
 	  Xfrout and Xfrin support.
         </para>
@@ -278,23 +281,6 @@
           The Python related libraries and modules need to be built
           for Python 3.1.
         </simpara></note>
-
-        <para>
-          If the Boost System Library is detected at configure time,
-          BIND 10 will be built using an alternative method for
-          networking I/O using Boost ASIO support.  This provides
-          asynchrony support; with ASIO the Authoritative DNS server
-          can handle other queries while the processing of a TCP
-          transaction stalls.
-          This dependency is not required unless you need
-          <!-- TODO: want --> this feature as TCP transport support is
-          provided using alternative code.
-        </para>
-
-<note><simpara>
-We recommend using the Boost libraries as it provides a safer TCP
-implementation in BIND 10. 
-</simpara></note>
 
         <para>
           Building BIND 10 also requires a C++ compiler and
@@ -517,14 +503,6 @@
           </varlistentry>
 
           <varlistentry>
-            <term>--with-boost-system</term>
-            <listitem> 
-              <simpara>Define to use the Boost System library.
-              </simpara>
-            </listitem> 
-          </varlistentry>
-
-          <varlistentry>
             <term>--with-pythonpath</term>
             <listitem> 
               <simpara>Define the path to Python 3.1 if it is not in the
@@ -549,14 +527,14 @@
   <!-- TODO: lcov -->
 
         <para>
-          For example, the following configures it to build
-    with BOOST ASIO support, find the Boost headers, find the
+          For example, the following configures it
+    build with Boost Python support (for Python DNS library),
+    find the Boost headers and library, find the
     Python interpreter, and sets the installation location:
 
           <screen>$ <userinput>./configure --with-boost-lib=/usr/pkg/lib \
       --with-boost-include=/usr/pkg/include \
       --with-boost-python \
-      --with-boost-system \
       --with-pythonpath=/usr/pkg/bin/python3.1 \
       --prefix=/opt/bind10</userinput></screen>
         </para>

Modified: experiments/python-binding/src/bin/auth/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/auth/Makefile.am (original)
+++ experiments/python-binding/src/bin/auth/Makefile.am Wed Jun  9 09:52:34 2010
@@ -2,13 +2,13 @@
 
 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
-if GCC_WERROR_OK
-AM_CPPFLAGS += -Werror
-endif
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 pkglibexecdir = $(libexecdir)/@PACKAGE@
 
-CLEANFILES = *.gcno *.gcda auth.spec
+CLEANFILES = *.gcno *.gcda auth.spec spec_config.h
 
 man_MANS = b10-auth.8
 EXTRA_DIST = $(man_MANS) b10-auth.xml
@@ -23,6 +23,23 @@
 auth.spec: auth.spec.pre
 	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" auth.spec.pre >$@
 
+spec_config.h: spec_config.h.pre
+	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" spec_config.h.pre >$@
+
+# This is a wrapper library solely used for b10-auth.  The ASIO header files
+# have some code fragments that would hit gcc's unused-parameter warning,
+# which would make the build fail with -Werror (our default setting).
+# We don't want to lower the warning level for our own code just for ASIO,
+# so as a workaround we extract the ASIO related code into a separate library,
+# only for which we accept the unused-parameter warning.
+lib_LIBRARIES = libasio_link.a
+libasio_link_a_SOURCES = asio_link.cc asio_link.h
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+libasio_link_a_CXXFLAGS = $(AM_CXXFLAGS) -Wno-unused-parameter
+libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
+
+BUILT_SOURCES = spec_config.h 
 pkglibexec_PROGRAMS = b10-auth
 b10_auth_SOURCES = auth_srv.cc auth_srv.h
 b10_auth_SOURCES += common.h
@@ -32,12 +49,9 @@
 b10_auth_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
 b10_auth_LDADD += $(top_builddir)/src/lib/cc/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 += $(SQLITE_LIBS)
-if HAVE_BOOST_SYSTEM
 b10_auth_LDADD += $(top_builddir)/src/lib/xfr/.libs/libxfr.a
-endif
-b10_auth_LDFLAGS = $(AM_LDFLAGS) $(BOOST_LDFLAGS)
-b10_auth_LDADD += $(BOOST_SYSTEM_LIB)
 
 # TODO: config.h.in is wrong because doesn't honor pkgdatadir
 # and can't use @datadir@ because doesn't expand default ${prefix}

Modified: experiments/python-binding/src/bin/auth/auth.spec.pre.in
==============================================================================
--- experiments/python-binding/src/bin/auth/auth.spec.pre.in (original)
+++ experiments/python-binding/src/bin/auth/auth.spec.pre.in Wed Jun  9 09:52:34 2010
@@ -1,6 +1,7 @@
 {
   "module_spec": {
     "module_name": "Auth",
+    "module_description": "Authoritative service",
     "config_data": [
       { "item_name": "database_file",
         "item_type": "string",

Modified: experiments/python-binding/src/bin/auth/auth_srv.cc
==============================================================================
--- experiments/python-binding/src/bin/auth/auth_srv.cc (original)
+++ experiments/python-binding/src/bin/auth/auth_srv.cc Wed Jun  9 09:52:34 2010
@@ -139,7 +139,7 @@
     message.toWire(renderer);
 
     if (verbose_mode) {
-        cerr << "sending an error response (" <<
+        cerr << "[b10-auth] sending an error response (" <<
             boost::lexical_cast<string>(renderer.getLength())
              << " bytes):\n" << message.toText() << endl;
     }
@@ -179,7 +179,7 @@
         // Ignore all responses.
         if (message.getHeaderFlag(MessageFlag::QR())) {
             if (impl_->verbose_mode_) {
-                cerr << "received unexpected response, ignoring" << endl;
+                cerr << "[b10-auth] received unexpected response, ignoring" << endl;
             }
             return (false);
         }
@@ -192,7 +192,7 @@
         message.fromWire(request_buffer);
     } catch (const DNSProtocolError& error) {
         if (impl_->verbose_mode_) {
-            cerr << "returning " <<  error.getRcode().toText() << ": "
+            cerr << "[b10-auth] returning " <<  error.getRcode().toText() << ": "
                  << error.what() << endl;
         }
         makeErrorMessage(message, response_renderer, error.getRcode(),
@@ -200,7 +200,7 @@
         return (true);
     } catch (const Exception& ex) {
         if (impl_->verbose_mode_) {
-            cerr << "returning SERVFAIL: " << ex.what() << endl;
+            cerr << "[b10-auth] returning SERVFAIL: " << ex.what() << endl;
         }
         makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
                          impl_->verbose_mode_);
@@ -208,7 +208,7 @@
     } // other exceptions will be handled at a higher layer.
 
     if (impl_->verbose_mode_) {
-        cerr << "[AuthSrv] received a message:\n" << message.toText() << endl;
+        cerr << "[b10-auth] received a message:\n" << message.toText() << endl;
     }
 
     // Perform further protocol-level validation.
@@ -216,7 +216,7 @@
     // In this implementation, we only support normal queries
     if (message.getOpcode() != Opcode::QUERY()) {
         if (impl_->verbose_mode_) {
-            cerr << "unsupported opcode" << endl;
+            cerr << "[b10-auth] unsupported opcode" << endl;
         }
         makeErrorMessage(message, response_renderer, Rcode::NOTIMP(),
                          impl_->verbose_mode_);
@@ -243,7 +243,7 @@
         impl_->data_sources_.doQuery(query);
     } catch (const Exception& ex) {
         if (impl_->verbose_mode_) {
-            cerr << "Internal error, returning SERVFAIL: " << ex.what() << endl;
+            cerr << "[b10-auth] Internal error, returning SERVFAIL: " << ex.what() << endl;
         }
         makeErrorMessage(message, response_renderer, Rcode::SERVFAIL(),
                          impl_->verbose_mode_);
@@ -253,7 +253,7 @@
     response_renderer.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
     message.toWire(response_renderer);
     if (impl_->verbose_mode_) {
-        cerr << "sending a response (" <<
+        cerr << "[b10-auth] sending a response (" <<
             boost::lexical_cast<string>(response_renderer.getLength())
              << " bytes):\n" << message.toText() << endl;
     }
@@ -281,7 +281,7 @@
     }
 
     if (verbose_mode_) {
-        cerr << "[AuthSrv] Data source database file: " << db_file_ << endl;
+        cerr << "[b10-auth] Data source database file: " << db_file_ << endl;
     }
 
     // create SQL data source
@@ -313,7 +313,7 @@
         return answer;
     } catch (const isc::Exception& error) {
         if (impl_->verbose_mode_) {
-            cerr << "[AuthSrv] error: " << error.what() << endl;
+            cerr << "[b10-auth] error: " << error.what() << endl;
         }
         return isc::config::createAnswer(1, error.what());
     }

Modified: experiments/python-binding/src/bin/auth/main.cc
==============================================================================
--- experiments/python-binding/src/bin/auth/main.cc (original)
+++ experiments/python-binding/src/bin/auth/main.cc Wed Jun  9 09:52:34 2010
@@ -28,10 +28,6 @@
 #include <iostream>
 
 #include <boost/foreach.hpp>
-#ifdef HAVE_BOOST_SYSTEM
-#include <boost/bind.hpp>
-#include <boost/asio.hpp>
-#endif  // HAVE_BOOST_SYSTEM
 
 #include <exceptions/exceptions.h>
 
@@ -43,26 +39,12 @@
 #include <cc/data.h>
 #include <config/ccsession.h>
 
-#if defined(HAVE_BOOST_SYSTEM)
-#define USE_XFROUT
-#include <xfr/xfrout_client.h>
-#endif
-
 #include "spec_config.h"
 #include "common.h"
 #include "auth_srv.h"
+#include "asio_link.h"
 
 using namespace std;
-#ifdef USE_XFROUT
-using namespace isc::xfr;
-#endif
-
-#ifdef HAVE_BOOST_SYSTEM
-using namespace boost::asio;
-using ip::udp;
-using ip::tcp;
-#endif  // HAVE_BOOST_SYSTEM
-
 using namespace isc::data;
 using namespace isc::cc;
 using namespace isc::config;
@@ -79,13 +61,8 @@
  * todo: turn this around, and put handlers in the authserver
  * class itself? */
 AuthSrv *auth_server;
-#ifdef HAVE_BOOST_SYSTEM
-// TODO: this should be a property of AuthSrv, and AuthSrv needs
-// a stop() method (so the shutdown command can be handled)
-boost::asio::io_service io_service_;
-#else
-bool running;
-#endif  // HAVE_BOOST_SYSTEM
+
+asio_link::IOService* io_service;
 
 ElementPtr
 my_config_handler(ElementPtr new_config) {
@@ -101,604 +78,11 @@
         /* let's add that message to our answer as well */
         answer->get("result")->add(args);
     } else if (command == "shutdown") {
-#ifdef HAVE_BOOST_SYSTEM
-        io_service_.stop();
-#else
-        running = false;
-#endif  // HAVE_BOOST_SYSTEM
+        io_service->stop();
     }
     
     return answer;
 }
-
-#ifdef USE_XFROUT
-//TODO. The sample way for checking axfr query, the code should be merged to auth server class
-static bool
-check_axfr_query(char *msg_data, uint16_t msg_len)
-{
-    if (msg_len < 15)
-        return false;
-
-    uint16_t query_type = *(uint16_t *)(msg_data + (msg_len - 4));
-    if ( query_type == 0xFC00)
-        return true;
-    
-    return false;
-}
-
-//TODO. Send the xfr query to xfrout module, the code should be merged to auth server class
-static void
-dispatch_axfr_query(int tcp_sock, char axfr_query[], uint16_t query_len)
-{
-    std::string path;
-    if (getenv("B10_FROM_SOURCE")) {
-        path = string(getenv("B10_FROM_SOURCE")) +
-                      "/auth_xfrout_conn";
-    } else {
-        path = string(UNIX_SOCKET_FILE);
-    }
-    (void)tcp_sock;
-    (void)axfr_query;
-    (void)query_len;
-    XfroutClient xfr_client(path);
-    try {
-        xfr_client.connect();
-        xfr_client.sendXfroutRequestInfo(tcp_sock, (uint8_t *)axfr_query, query_len);
-        xfr_client.disconnect();
-    }
-    catch (const std::exception & err) {
-        //if (verbose_mode)
-            cerr << "error handle xfr query:" << err.what() << endl;
-    }
-}
-#endif
-
-#ifdef HAVE_BOOST_SYSTEM
-//
-// Helper classes for asynchronous I/O using boost::asio
-//
-class TCPClient {
-public:
-    TCPClient(io_service& io_service) :
-        socket_(io_service),
-        response_buffer_(0),
-        responselen_buffer_(TCP_MESSAGE_LENGTHSIZE),
-        response_renderer_(response_buffer_),
-        dns_message_(Message::PARSE)
-    {}
-
-    void start() {
-        async_read(socket_, boost::asio::buffer(data_, TCP_MESSAGE_LENGTHSIZE),
-                   boost::bind(&TCPClient::headerRead, this,
-                               placeholders::error,
-                               placeholders::bytes_transferred));
-    }
-
-    tcp::socket& getSocket() { return (socket_); }
-
-    void headerRead(const boost::system::error_code& error,
-                    size_t bytes_transferred)
-    {
-        if (!error) {
-            InputBuffer dnsbuffer(data_, bytes_transferred);
-
-            uint16_t msglen = dnsbuffer.readUint16();
-            async_read(socket_, boost::asio::buffer(data_, msglen),
-
-                       boost::bind(&TCPClient::requestRead, this,
-                                   placeholders::error,
-                                   placeholders::bytes_transferred));
-        } else {
-            delete this;
-        }
-    }
-
-    void requestRead(const boost::system::error_code& error,
-                     size_t bytes_transferred)
-    {
-        if (!error) {
-            InputBuffer dnsbuffer(data_, bytes_transferred);
-#ifdef USE_XFROUT
-            if (check_axfr_query(data_, bytes_transferred)) {
-                dispatch_axfr_query(socket_.native(), data_, bytes_transferred); 
-                // start to get new query ?
-                start();
-            } else {
-#endif          
-                if (auth_server->processMessage(dnsbuffer, dns_message_,
-                                                response_renderer_, false)) {
-                    responselen_buffer_.writeUint16(response_buffer_.getLength());
-                    async_write(socket_,
-                                boost::asio::buffer(
-                                    responselen_buffer_.getData(),
-                                    responselen_buffer_.getLength()),
-                                boost::bind(&TCPClient::responseWrite, this,
-                                            placeholders::error));
-                } else {
-                    delete this;
-                }
-#ifdef USE_XFROUT
-            }
-#endif
-        } else {
-            delete this;
-        }
-    }
-
-    void responseWrite(const boost::system::error_code& error) {
-        if (!error) {
-                async_write(socket_,
-                            boost::asio::buffer(response_buffer_.getData(),
-                                                response_buffer_.getLength()),
-                        boost::bind(&TCPClient::handleWrite, this,
-                                    placeholders::error));
-        } else {
-            delete this;
-        }
-    }
-
-    void handleWrite(const boost::system::error_code& error) {
-        if (!error) {
-            start();            // handle next request, if any.
-      } else {
-            delete this;
-      }
-    }
-
-private:
-    tcp::socket socket_;
-    OutputBuffer response_buffer_;
-    OutputBuffer responselen_buffer_;
-    MessageRenderer response_renderer_;
-    Message dns_message_;
-    enum { MAX_LENGTH = 65535 };
-    static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
-    char data_[MAX_LENGTH];
-};
-
-class TCPServer {
-public:
-    TCPServer(io_service& io_service, int af, short port) :
-        io_service_(io_service), acceptor_(io_service_),
-        listening_(new TCPClient(io_service_))
-    {
-        tcp::endpoint endpoint(af == AF_INET6 ? tcp::v6() : tcp::v4(), port);
-        acceptor_.open(endpoint.protocol());
-        // Set v6-only (we use a different instantiation for v4,
-        // otherwise asio will bind to both v4 and v6
-        if (af == AF_INET6) {
-            acceptor_.set_option(ip::v6_only(true));
-        }
-        acceptor_.set_option(tcp::acceptor::reuse_address(true));
-        acceptor_.bind(endpoint);
-        acceptor_.listen();
-        acceptor_.async_accept(listening_->getSocket(),
-                               boost::bind(&TCPServer::handleAccept, this,
-                                           listening_, placeholders::error));
-    }
-
-    ~TCPServer() { delete listening_; }
-
-    void handleAccept(TCPClient* new_client,
-                      const boost::system::error_code& error)
-    {
-        if (!error) {
-            assert(new_client == listening_);
-            new_client->start();
-            listening_ = new TCPClient(io_service_);
-            acceptor_.async_accept(listening_->getSocket(),
-                                   boost::bind(&TCPServer::handleAccept,
-                                               this, listening_,
-                                               placeholders::error));
-        } else {
-            delete new_client;
-        }
-    }
-
-private:
-    io_service& io_service_;
-    tcp::acceptor acceptor_;
-    TCPClient* listening_;
-};
-
-class UDPServer {
-public:
-    UDPServer(io_service& io_service, int af, short port) :
-        io_service_(io_service),
-        socket_(io_service, af == AF_INET6 ? udp::v6() : udp::v4()),
-        response_buffer_(0),
-        response_renderer_(response_buffer_),
-        dns_message_(Message::PARSE)
-    {
-        // Set v6-only (we use a different instantiation for v4,
-        // otherwise asio will bind to both v4 and v6
-        if (af == AF_INET6) {
-            socket_.set_option(boost::asio::ip::v6_only(true));
-            socket_.bind(udp::endpoint(udp::v6(), port));
-        } else {
-            socket_.bind(udp::endpoint(udp::v4(), port));
-        }
-        startReceive();
-    }
-
-    void handleRequest(const boost::system::error_code& error,
-                       size_t bytes_recvd)
-    {
-        if (!error && bytes_recvd > 0) {
-            InputBuffer request_buffer(data_, bytes_recvd);
-
-            dns_message_.clear(Message::PARSE);
-            response_renderer_.clear();
-            if (auth_server->processMessage(request_buffer, dns_message_,
-                                            response_renderer_, true)) {
-                socket_.async_send_to(
-                    boost::asio::buffer(response_buffer_.getData(),
-                                        response_buffer_.getLength()),
-                    sender_endpoint_,
-                    boost::bind(&UDPServer::sendCompleted,
-                                this,
-                                placeholders::error,
-                                placeholders::bytes_transferred));
-            } else {
-                startReceive();
-            }
-        } else {
-            startReceive();
-        }
-    }
-
-    void sendCompleted(const boost::system::error_code& error UNUSED_PARAM,
-                       size_t bytes_sent UNUSED_PARAM)
-    {
-        // Even if error occurred there's nothing to do.  Simply handle
-        // the next request.
-        startReceive();
-    }
-private:
-    void startReceive() {
-        socket_.async_receive_from(
-            boost::asio::buffer(data_, MAX_LENGTH), sender_endpoint_,
-            boost::bind(&UDPServer::handleRequest, this,
-                        placeholders::error,
-                        placeholders::bytes_transferred));
-    }
-
-private:
-    io_service& io_service_;
-    udp::socket socket_;
-    OutputBuffer response_buffer_;
-    MessageRenderer response_renderer_;
-    Message dns_message_;
-    udp::endpoint sender_endpoint_;
-    enum { MAX_LENGTH = 4096 };
-    char data_[MAX_LENGTH];
-};
-
-struct ServerSet {
-    ServerSet() : udp4_server(NULL), udp6_server(NULL),
-                  tcp4_server(NULL), tcp6_server(NULL)
-    {}
-    ~ServerSet() {
-        delete udp4_server;
-        delete udp6_server;
-        delete tcp4_server;
-        delete tcp6_server;
-    }
-    UDPServer* udp4_server;
-    UDPServer* udp6_server;
-    TCPServer* tcp4_server;
-    TCPServer* tcp6_server;
-};
-
-void
-run_server(const char* port, const bool use_ipv4, const bool use_ipv6,
-           AuthSrv* srv UNUSED_PARAM)
-{
-    ServerSet servers;
-    short portnum = atoi(port);
-
-    if (use_ipv4) {
-        servers.udp4_server = new UDPServer(io_service_, AF_INET, portnum);
-        servers.tcp4_server = new TCPServer(io_service_, AF_INET, portnum);
-    }
-    if (use_ipv6) {
-        servers.udp6_server = new UDPServer(io_service_, AF_INET6, portnum);
-        servers.tcp6_server = new TCPServer(io_service_, AF_INET6, portnum);
-    }
-
-    cout << "Server started." << endl;
-    io_service_.run();
-}
-#else  // !HAVE_BOOST_SYSTEM
-struct SocketSet {
-    SocketSet() : ups4(-1), tps4(-1), ups6(-1), tps6(-1) {}
-    ~SocketSet() {
-        if (ups4 >= 0) {
-            close(ups4);
-        }
-        if (tps4 >= 0) {
-            close(tps4);
-        }
-        if (ups6 >= 0) {
-            close(ups6);
-        }
-        if (tps4 >= 0) {
-            close(tps6);
-        }
-    }
-    int ups4, tps4, ups6, tps6;
-};
-
-int
-getUDPSocket(int af, const char* port) {
-    struct addrinfo hints, *res;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = af;
-    hints.ai_socktype = SOCK_DGRAM;
-    hints.ai_flags = AI_PASSIVE;
-    hints.ai_protocol = IPPROTO_UDP;
-
-    int error = getaddrinfo(NULL, port, &hints, &res);
-    if (error != 0) {
-        isc_throw(FatalError, "getaddrinfo failed: " << gai_strerror(error));
-    }
-
-    int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
-    if (s < 0) {
-        isc_throw(FatalError, "failed to open socket");
-    }
-
-    if (af == AF_INET6) {
-        int on = 1;
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
-            cerr << "couldn't set IPV6_V6ONLY socket option" << endl;
-            // proceed anyway
-        }
-    }
-
-    if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
-        isc_throw(FatalError, "binding socket failure");
-    }
-
-    return (s);
-}
-
-int
-getTCPSocket(int af, const char* port) {
-    struct addrinfo hints, *res;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = af;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE;
-    hints.ai_protocol = IPPROTO_TCP;
-
-    int error = getaddrinfo(NULL, port, &hints, &res);
-    if (error != 0) {
-        isc_throw(FatalError, "getaddrinfo failed: " << gai_strerror(error));
-    }
-
-    int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
-    if (s < 0) {
-        isc_throw(FatalError, "failed to open socket");
-    }
-
-    int on = 1;
-    if (af == AF_INET6) {
-        if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
-            cerr << "couldn't set IPV6_V6ONLY socket option" << endl;
-        }
-        // proceed anyway
-    }
-
-    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
-        cerr << "couldn't set SO_REUSEADDR socket option" << endl;
-    }
-
-    if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
-        isc_throw(FatalError, "binding socket failure");
-    }
-
-    if (listen(s, 100) < 0) {
-        isc_throw(FatalError, "failed to listen on a TCP socket");
-    }
-    return (s);
-}
-
-void
-processMessageUDP(const int fd, Message& dns_message,
-                  MessageRenderer& response_renderer)
-{
-    struct sockaddr_storage ss;
-    socklen_t sa_len = sizeof(ss);
-    struct sockaddr* sa = static_cast<struct sockaddr*>((void*)&ss);
-    char recvbuf[4096];
-    int cc;
-
-    dns_message.clear(Message::PARSE);
-    response_renderer.clear();
-    if ((cc = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, sa, &sa_len)) > 0) {
-        InputBuffer buffer(recvbuf, cc);
-        if (auth_server->processMessage(buffer, dns_message, response_renderer,
-                                        true)) {
-            cc = sendto(fd, response_renderer.getData(),
-                        response_renderer.getLength(), 0, sa, sa_len);
-            if (cc != response_renderer.getLength()) {
-                cerr << "UDP send error" << endl;
-            }
-        }
-    } else if (verbose_mode) {
-        cerr << "UDP receive error" << endl;
-    }
-}
-
-// XXX: this function does not handle partial reads or partial writes,
-//      and is VERY UNSAFE - will probably be removed or rewritten
-void
-processMessageTCP(const int fd, Message& dns_message,
-                  MessageRenderer& response_renderer)
-{
-    struct sockaddr_storage ss;
-    socklen_t sa_len = sizeof(ss);
-    struct sockaddr* sa = static_cast<struct sockaddr*>((void*)&ss);
-    char sizebuf[2];
-    int cc;
-
-    int ts = accept(fd, sa, &sa_len);
-    if (ts < 0) {
-        if (verbose_mode) {
-            cerr << "[XX] TCP accept failure:" << endl;
-            return;
-        }
-    }
-
-    if (verbose_mode) {
-        cerr << "[XX] process TCP" << endl;
-    }
-    cc = recv(ts, sizebuf, 2, 0);
-    if (cc < 0) {
-        if (verbose_mode) {
-            cerr << "[XX] TCP recv failure:" << endl;
-        }
-        close(ts);
-        return;
-    }
-    if (verbose_mode) {
-        cerr << "[XX] got: " << cc << endl;
-    }
-    uint16_t size, size_n;
-    memcpy(&size_n, sizebuf, 2);
-    size = ntohs(size_n);
-    if (verbose_mode) {
-        cerr << "[XX] got: " << size << endl;
-    }
-
-    vector<char> message_buffer;
-    message_buffer.reserve(size);
-    cc = 0;
-    while (cc < size) {
-        if (verbose_mode) {
-            cerr << "[XX] cc now: " << cc << " of " << size << endl;
-        }
-        const int cc0 = recv(ts, &message_buffer[0] + cc, size - cc, 0);
-        if (cc0 < 0) {
-            if (verbose_mode) {
-                cerr << "TCP receive error" << endl;
-                close(ts);
-                return;
-            }
-        }
-        if (cc0 == 0) {
-            // client closed connection
-            close(ts);
-            return;
-        }
-        cc += cc0;
-    }
-
-    InputBuffer buffer(&message_buffer[0], size);
-    dns_message.clear(Message::PARSE);
-    response_renderer.clear();
-    if (auth_server->processMessage(buffer, dns_message, response_renderer,
-                                    false)) {
-        size = response_renderer.getLength();
-        size_n = htons(size);
-        if (send(ts, &size_n, 2, 0) == 2) {
-            cc = send(ts, response_renderer.getData(),
-                      response_renderer.getLength(), 0);
-            if (cc == -1) {
-                if (verbose_mode) {
-                    cerr << "[AuthSrv] error in sending TCP response message" <<
-                        endl;
-                }
-            } else {
-                if (verbose_mode) {
-                    cerr << "[XX] sent TCP response: " << cc << " bytes"
-                         << endl;
-                }
-            }
-        } else {
-            if (verbose_mode) {
-                cerr << "TCP send error" << endl;
-            }
-        }
-    }
- 
-   // TODO: we don't check for more queries on the stream atm
-    close(ts);
-}
-
-void
-run_server(const char* port, const bool use_ipv4, const bool use_ipv6,
-           AuthSrv* srv)
-{
-    SocketSet socket_set;
-    fd_set fds_base;
-    int nfds = -1;
-
-    FD_ZERO(&fds_base);
-    if (use_ipv4) {
-        socket_set.ups4 = getUDPSocket(AF_INET, port);
-        FD_SET(socket_set.ups4, &fds_base);
-        nfds = max(nfds, socket_set.ups4);
-        socket_set.tps4 = getTCPSocket(AF_INET, port);
-        FD_SET(socket_set.tps4, &fds_base);
-        nfds = max(nfds, socket_set.tps4);
-    }
-    if (use_ipv6) {
-        socket_set.ups6 = getUDPSocket(AF_INET6, port);
-        FD_SET(socket_set.ups6, &fds_base);
-        nfds = max(nfds, socket_set.ups6);
-        socket_set.tps6 = getTCPSocket(AF_INET6, port);
-        FD_SET(socket_set.tps6, &fds_base);
-        nfds = max(nfds, socket_set.tps6);
-    }
-    ++nfds;
-
-    cout << "Server started." << endl;
-    
-    if (srv->configSession() == NULL) {
-        isc_throw(FatalError, "Config session not initalized");
-    }
-
-    int ss = srv->configSession()->getSocket();
-    Message dns_message(Message::PARSE);
-    OutputBuffer resonse_buffer(0);
-    MessageRenderer response_renderer(resonse_buffer);
-
-    running = true;
-    while (running) {
-        fd_set fds = fds_base;
-        FD_SET(ss, &fds);
-        ++nfds;
-
-        int n = select(nfds, &fds, NULL, NULL, NULL);
-        if (n < 0) {
-            if (errno != EINTR) {
-                isc_throw(FatalError, "select error");
-            }
-            continue;
-        }
-
-        if (socket_set.ups4 >= 0 && FD_ISSET(socket_set.ups4, &fds)) {
-            processMessageUDP(socket_set.ups4, dns_message, response_renderer);
-        }
-        if (socket_set.ups6 >= 0 && FD_ISSET(socket_set.ups6, &fds)) {
-            processMessageUDP(socket_set.ups6, dns_message, response_renderer);
-        }
-        if (socket_set.tps4 >= 0 && FD_ISSET(socket_set.tps4, &fds)) {
-            processMessageTCP(socket_set.tps4, dns_message, response_renderer);
-        }
-        if (socket_set.tps6 >= 0 && FD_ISSET(socket_set.tps6, &fds)) {
-            processMessageTCP(socket_set.tps6, dns_message, response_renderer);
-        }
-        if (FD_ISSET(ss, &fds)) {
-            srv->configSession()->checkCommand();
-        }
-    }
-}
-#endif // HAVE_BOOST_SYSTEM
 
 void
 usage() {
@@ -743,7 +127,7 @@
     }
 
     if (!use_ipv4 && !use_ipv6) {
-        cerr << "-4 and -6 can't coexist" << endl;
+        cerr << "[b10-auth] Error: -4 and -6 can't coexist" << endl;
         usage();
     }
 
@@ -751,8 +135,8 @@
     int ret = 0;
     try {
         string specfile;
-        if (getenv("B10_FROM_SOURCE")) {
-            specfile = string(getenv("B10_FROM_SOURCE")) +
+        if (getenv("B10_FROM_BUILD")) {
+            specfile = string(getenv("B10_FROM_BUILD")) +
                 "/src/bin/auth/auth.spec";
         } else {
             specfile = string(AUTH_SPECFILE_LOCATION);
@@ -761,22 +145,23 @@
         auth_server = new AuthSrv;
         auth_server->setVerbose(verbose_mode);
 
-#ifdef HAVE_BOOST_SYSTEM
-        ModuleCCSession cs(specfile, io_service_, my_config_handler,
-                           my_command_handler);
-#else
-        ModuleCCSession cs(specfile, my_config_handler, my_command_handler);
-#endif
+        io_service = new asio_link::IOService(auth_server, port, use_ipv4,
+                                              use_ipv6);
+
+        ModuleCCSession cs(specfile, io_service->get_io_service(), my_config_handler, my_command_handler);
 
         auth_server->setConfigSession(&cs);
         auth_server->updateConfig(ElementPtr());
 
-        run_server(port, use_ipv4, use_ipv6, auth_server);
+        
+        cout << "[b10-auth] Server started." << endl;
+        io_service->run();
     } catch (const std::exception& ex) {
-        cerr << ex.what() << endl;
+        cerr << "[b10-auth] " << ex.what() << endl;
         ret = 1;
     }
 
+    delete io_service;
     delete auth_server;
     return (ret);
 }

Modified: experiments/python-binding/src/bin/auth/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/auth/tests/Makefile.am (original)
+++ experiments/python-binding/src/bin/auth/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,6 +1,9 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 CLEANFILES = *.gcno *.gcda
 
@@ -21,10 +24,6 @@
 run_unittests_LDADD += $(top_builddir)/src/lib/config/.libs/libcfgclient.a
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
-if HAVE_BOOST_SYSTEM
-run_unittests_LDFLAGS += $(BOOST_LDFLAGS)
-run_unittests_LDADD += $(BOOST_SYSTEM_LIB)
-endif
 endif
 
 noinst_PROGRAMS = $(TESTS)

Modified: experiments/python-binding/src/bin/bind10/TODO
==============================================================================
--- experiments/python-binding/src/bin/bind10/TODO (original)
+++ experiments/python-binding/src/bin/bind10/TODO Wed Jun  9 09:52:34 2010
@@ -1,4 +1,5 @@
-- Read msgq configuration from configuration manager
+- Read msgq configuration from configuration manager (Trac #213)
+  https://bind10.isc.org/ticket/213
 - Provide more administrator options:
   - Get process list
   - Get information on a process (returns list of times started & stopped, 

Modified: experiments/python-binding/src/bin/bind10/bind10.py.in
==============================================================================
--- experiments/python-binding/src/bin/bind10/bind10.py.in (original)
+++ experiments/python-binding/src/bin/bind10/bind10.py.in Wed Jun  9 09:52:34 2010
@@ -49,8 +49,6 @@
     DATAROOTDIR = "@datarootdir@"
     SPECFILE_LOCATION = "@datadir@/@PACKAGE@/bob.spec".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
     
-# TODO: start up statistics thingy
-
 import subprocess
 import signal
 import re
@@ -63,10 +61,7 @@
 import isc.cc
 
 # This is the version that gets displayed to the user.
-__version__ = "v20100310"
-
-# Nothing at all to do with the 1990-12-10 article here:
-# http://www.subgenius.com/subg-digest/v2/0056.html
+__version__ = "v20100531"
 
 class RestartSchedule:
     """
@@ -116,7 +111,18 @@
 class ProcessInfo:
     """Information about a process"""
 
-    dev_null = open("/dev/null", "w")
+    dev_null = open(os.devnull, "w")
+
+    def __init__(self, name, args, env={}, dev_null_stdout=False,
+                 dev_null_stderr=False):
+        self.name = name 
+        self.args = args
+        self.env = env
+        self.dev_null_stdout = dev_null_stdout
+        self.dev_null_stderr = dev_null_stderr
+        self.restart_schedule = RestartSchedule()
+        self._spawn()
+
 
     def _spawn(self):
         if self.dev_null_stdout:
@@ -143,73 +149,53 @@
         self.pid = self.process.pid
         self.restart_schedule.set_run_start_time()
 
-    def __init__(self, name, args, env={}, dev_null_stdout=False,
-                 dev_null_stderr=False):
-        self.name = name 
-        self.args = args
-        self.env = env
-        self.dev_null_stdout = dev_null_stdout
-        self.dev_null_stderr = dev_null_stderr
-        self.restart_schedule = RestartSchedule()
-        self._spawn()
-
     def respawn(self):
         self._spawn()
 
 class BoB:
     """Boss of BIND class."""
-    def __init__(self, c_channel_port=9912, auth_port=5300, verbose=False):
+    
+    def __init__(self, msgq_socket_file=None, auth_port=5300, verbose=False):
         """Initialize the Boss of BIND. This is a singleton (only one
         can run).
         
-        The c_channel_port specifies the TCP/IP port that the msgq
-        process listens on. If verbose is True, then the boss reports
-        what it is doing.
+        The msgq_socket_file specifies the UNIX domain socket file
+        that the msgq process listens on.
+        If verbose is True, then the boss reports what it is doing.
         """
         self.verbose = verbose
-        self.c_channel_port = c_channel_port
+        self.msgq_socket_file = msgq_socket_file
         self.auth_port = auth_port
         self.cc_session = None
         self.ccs = None
         self.processes = {}
         self.dead_processes = {}
         self.runnable = False
-        
-        os.environ['ISC_MSGQ_PORT'] = str(self.c_channel_port)
 
     def config_handler(self, new_config):
         if self.verbose:
-            print("[bind10] handling new config:")
-            print(new_config)
+            sys.stdout.write("[bind10] handling new config:\n")
+            sys.stdout.write(new_config + "\n")
         answer = isc.config.ccsession.create_answer(0)
         return answer
         # TODO
 
     def command_handler(self, command, args):
         if self.verbose:
-            print("[bind10] Boss got command:")
-            print(command)
+            sys.stdout.write("[bind10] Boss got command:\n")
+            sys.stdout.write(command + "\n")
         answer = isc.config.ccsession.create_answer(1, "command not implemented")
         if type(command) != str:
             answer = isc.config.ccsession.create_answer(1, "bad command")
         else:
             cmd = command
             if cmd == "shutdown":
-                print("[bind10] got shutdown command")
+                sys.stdout.write("[bind10] got shutdown command\n")
                 self.runnable = False
                 answer = isc.config.ccsession.create_answer(0)
-            elif cmd == "print_message":
-                if args:
-                    print(args)
-                answer = isc.config.ccsession.create_answer(0, args)
-            elif cmd == "print_settings":
-                print("[bind10] Full Config:")
-                full_config = self.ccs.get_full_config()
-                for item in full_config:
-                    print(item + ": " + str(full_config[item]))
-                answer = isc.config.ccsession.create_answer(0)
             else:
-                answer = isc.config.ccsession.create_answer(1, "Unknown command")
+                answer = isc.config.ccsession.create_answer(1, 
+                                                            "Unknown command")
         return answer
     
     def startup(self):
@@ -220,20 +206,23 @@
         """
         # try to connect to the c-channel daemon, 
         # to see if it is already running
-        c_channel_env = { "ISC_MSGQ_PORT": str(self.c_channel_port), }
-        if self.verbose:
-            sys.stdout.write("Checking for already running b10-msgq\n")
+        c_channel_env = {}
+        if self.msgq_socket_file is not None:
+             c_channel_env["BIND10_MSGQ_SOCKET_FILE"] = self.msgq_socket_file 
+        if self.verbose:
+            sys.stdout.write("[bind10] Checking for already running b10-msgq\n")
         # try to connect, and if we can't wait a short while
         try:
-            self.cc_session = isc.cc.Session(self.c_channel_port)
-            return "b10-msgq already running, cannot start"
+            self.cc_session = isc.cc.Session(self.msgq_socket_file)
+            return "b10-msgq already running, or socket file not cleaned , cannot start"
         except isc.cc.session.SessionError:
+            # this is the case we want, where the msgq is not running
             pass
 
         # start the c-channel daemon
         if self.verbose:
-            sys.stdout.write("Starting b10-msgq using port %d\n" % 
-                             self.c_channel_port)
+            if self.msgq_socket_file:
+                sys.stdout.write("[bind10] Starting b10-msgq\n")
         try:
             c_channel = ProcessInfo("b10-msgq", ["b10-msgq"], c_channel_env,
                                     True, not self.verbose)
@@ -241,7 +230,7 @@
             return "Unable to start b10-msgq; " + str(e)
         self.processes[c_channel.pid] = c_channel
         if self.verbose:
-            sys.stdout.write("Started b10-msgq (PID %d)\n" % c_channel.pid)
+            sys.stdout.write("[bind10] Started b10-msgq (PID %d)\n" % c_channel.pid)
 
         # now connect to the c-channel
         cc_connect_start = time.time()
@@ -252,63 +241,64 @@
                 return "Unable to connect to c-channel after 5 seconds"
             # try to connect, and if we can't wait a short while
             try:
-                self.cc_session = isc.cc.Session(self.c_channel_port)
+                self.cc_session = isc.cc.Session(self.msgq_socket_file)
             except isc.cc.session.SessionError:
                 time.sleep(0.1)
-        #self.cc_session.group_subscribe("Boss", "boss")
 
         # start the configuration manager
         if self.verbose:
             sys.stdout.write("[bind10] Starting b10-cfgmgr\n")
         try:
             bind_cfgd = ProcessInfo("b10-cfgmgr", ["b10-cfgmgr"],
-                                    { 'ISC_MSGQ_PORT': str(self.c_channel_port)})
+                                    c_channel_env)
         except Exception as e:
             c_channel.process.kill()
             return "Unable to start b10-cfgmgr; " + str(e)
         self.processes[bind_cfgd.pid] = bind_cfgd
         if self.verbose:
-            sys.stdout.write("[bind10] Started b10-cfgmgr (PID %d)\n" % bind_cfgd.pid)
-
-        # TODO: once this interface is done, replace self.cc_session
-        # by this one
+            sys.stdout.write("[bind10] Started b10-cfgmgr (PID %d)\n" % 
+                             bind_cfgd.pid)
+
         # sleep until b10-cfgmgr is fully up and running, this is a good place
         # to have a (short) timeout on synchronized groupsend/receive
         # TODO: replace the sleep by a listen for ConfigManager started
         # message
         time.sleep(1)
         if self.verbose:
-            print("[bind10] starting ccsession")
-        self.ccs = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
+            sys.stdout.write("[bind10] starting ccsession\n")
+        self.ccs = isc.config.ModuleCCSession(SPECFILE_LOCATION, 
+                                      self.config_handler, self.command_handler)
         self.ccs.start()
         if self.verbose:
-            print("[bind10] ccsession started")
-
-        # start the xfrout before auth-server, to make sure every xfr-query can be
-        # processed properly.
-        if self.verbose:
-            sys.stdout.write("Starting b10-xfrout\n")
-        try:
-            xfrout = ProcessInfo("b10-xfrout", ["b10-xfrout"], 
-                                 { 'ISC_MSGQ_PORT': str(self.c_channel_port)})
+            sys.stdout.write("[bind10] ccsession started\n")
+
+        # start the xfrout before auth-server, to make sure every xfr-query can
+        # be processed properly.
+        xfrout_args = ['b10-xfrout']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-xfrout\n")
+            xfrout_args += ['-v']
+        try:
+            xfrout = ProcessInfo("b10-xfrout", xfrout_args, 
+                                 c_channel_env )
         except Exception as e:
             c_channel.process.kill()
             bind_cfgd.process.kill()
             return "Unable to start b10-xfrout; " + str(e)
         self.processes[xfrout.pid] = xfrout
         if self.verbose:
-            sys.stdout.write("Started b10-xfrout (PID %d)\n" % xfrout.pid)
+            sys.stdout.write("[bind10] Started b10-xfrout (PID %d)\n" % xfrout.pid)
 
         # start b10-auth
         # XXX: this must be read from the configuration manager in the future
         authargs = ['b10-auth', '-p', str(self.auth_port)]
         if self.verbose:
-            sys.stdout.write("Starting b10-auth using port %d\n" %
+            sys.stdout.write("[bind10] Starting b10-auth using port %d\n" %
                              self.auth_port)
             authargs += ['-v']
         try:
             auth = ProcessInfo("b10-auth", authargs,
-                               { 'ISC_MSGQ_PORT': str(self.c_channel_port)})
+                               c_channel_env)
         except Exception as e:
             c_channel.process.kill()
             bind_cfgd.process.kill()
@@ -316,14 +306,16 @@
             return "Unable to start b10-auth; " + str(e)
         self.processes[auth.pid] = auth
         if self.verbose:
-            sys.stdout.write("Started b10-auth (PID %d)\n" % auth.pid)
+            sys.stdout.write("[bind10] Started b10-auth (PID %d)\n" % auth.pid)
 
         # start b10-xfrin
-        if self.verbose:
-            sys.stdout.write("Starting b10-xfrin\n")
-        try:
-            xfrind = ProcessInfo("b10-xfrin", ['b10-xfrin'],
-                                 { 'ISC_MSGQ_PORT': str(self.c_channel_port)})
+        xfrin_args = ['b10-xfrin']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-xfrin\n")
+            xfrin_args += ['-v']
+        try:
+            xfrind = ProcessInfo("b10-xfrin", xfrin_args,
+                                 c_channel_env)
         except Exception as e:
             c_channel.process.kill()
             bind_cfgd.process.kill()
@@ -332,15 +324,17 @@
             return "Unable to start b10-xfrin; " + str(e)
         self.processes[xfrind.pid] = xfrind
         if self.verbose:
-            sys.stdout.write("Started b10-xfrin (PID %d)\n" % xfrind.pid)
+            sys.stdout.write("[bind10] Started b10-xfrin (PID %d)\n" % xfrind.pid)
 
         # start the b10-cmdctl
         # XXX: we hardcode port 8080
-        if self.verbose:
-            sys.stdout.write("Starting b10-cmdctl on port 8080\n")
-        try:
-            cmd_ctrld = ProcessInfo("b10-cmdctl", ['b10-cmdctl'],
-                                    { 'ISC_MSGQ_PORT': str(self.c_channel_port)})
+        cmdctl_args = ['b10-cmdctl']
+        if self.verbose:
+            sys.stdout.write("[bind10] Starting b10-cmdctl on port 8080\n")
+            cmdctl_args += ['-v']
+        try:
+            cmd_ctrld = ProcessInfo("b10-cmdctl", cmdctl_args,
+                                    c_channel_env)
         except Exception as e:
             c_channel.process.kill()
             bind_cfgd.process.kill()
@@ -350,7 +344,7 @@
             return "Unable to start b10-cmdctl; " + str(e)
         self.processes[cmd_ctrld.pid] = cmd_ctrld
         if self.verbose:
-            sys.stdout.write("Started b10-cmdctl (PID %d)\n" % cmd_ctrld.pid)
+            sys.stdout.write("[bind10] Started b10-cmdctl (PID %d)\n" % cmd_ctrld.pid)
 
         self.runnable = True
 
@@ -373,7 +367,7 @@
     def shutdown(self):
         """Stop the BoB instance."""
         if self.verbose:
-            sys.stdout.write("Stopping the server.\n")
+            sys.stdout.write("[bind10] Stopping the server.\n")
         # first try using the BIND 10 request to stop
         try:
             self.stop_all_processes()
@@ -386,7 +380,7 @@
         processes_to_stop = list(self.processes.values())
         for proc_info in processes_to_stop:
             if self.verbose:
-                sys.stdout.write("Sending SIGTERM to %s (PID %d).\n" % 
+                sys.stdout.write("[bind10] Sending SIGTERM to %s (PID %d).\n" % 
                                  (proc_info.name, proc_info.pid))
             try:
                 proc_info.process.terminate()
@@ -402,7 +396,7 @@
             processes_to_stop = list(self.processes.values())
             for proc_info in processes_to_stop:
                 if self.verbose:
-                    sys.stdout.write("Sending SIGKILL to %s (PID %d).\n" % 
+                    sys.stdout.write("[bind10] Sending SIGKILL to %s (PID %d).\n" % 
                                      (proc_info.name, proc_info.pid))
                 try:
                     proc_info.process.kill()
@@ -411,7 +405,7 @@
                     # finally exited)
                     pass
         if self.verbose:
-            sys.stdout.write("All processes ended, server done.\n")
+            sys.stdout.write("[bind10] All processes ended, server done.\n")
 
     def reap_children(self):
         """Check to see if any of our child processes have exited, 
@@ -430,70 +424,15 @@
                 proc_info.restart_schedule.set_run_stop_time()
                 self.dead_processes[proc_info.pid] = proc_info
                 if self.verbose:
-                    sys.stdout.write("Process %s (PID %d) died.\n" % 
+                    sys.stdout.write("[bind10] Process %s (PID %d) died.\n" % 
                                      (proc_info.name, proc_info.pid))
                 if proc_info.name == "b10-msgq":
                     if self.verbose and self.runnable:
                         sys.stdout.write(
-                                     "The b10-msgq process died, shutting down.\n")
+                                 "[bind10] The b10-msgq process died, shutting down.\n")
                     self.runnable = False
             else:
-                sys.stdout.write("Unknown child pid %d exited.\n" % pid)
-
-    # 'old' command style, uncommented for now
-    # move the handling below move to command_handler please
-    #def recv_and_process_cc_msg(self):
-        #"""Receive and process the next message on the c-channel,
-        #if any."""
-        #self.ccs.checkCommand()
-        #msg, envelope = self.cc_session.group_recvmsg(False)
-        #print(msg)
-        #if msg is None:
-        #    return
-        #if not ((type(msg) is dict) and (type(envelope) is dict)):
-        #    if self.verbose:
-        #        sys.stdout.write("Non-dictionary message\n")
-        #    return
-        #if not "command" in msg:
-        #    if self.verbose:
-        #        if "msg" in envelope:
-        #            del envelope['msg']
-        #        sys.stdout.write("Unknown message received\n")
-        #        sys.stdout.write(pprint.pformat(envelope) + "\n")
-        #        sys.stdout.write(pprint.pformat(msg) + "\n")
-        #    return
-
-        #cmd = msg['command']
-        #if not (type(cmd) is list):
-        #    if self.verbose:
-        #        sys.stdout.write("Non-list command\n")
-        #    return
-        #
-        # done checking and extracting... time to execute the command
-        #if cmd[0] == "shutdown":
-        #    if self.verbose:
-        #        sys.stdout.write("shutdown command received\n")
-        #    self.runnable = False
-        #    # XXX: reply here?
-        #elif cmd[0] == "getProcessList":
-        #    if self.verbose:
-        #        sys.stdout.write("getProcessList command received\n")
-        #    live_processes = [ ]
-        #    for proc_info in processes:
-        #        live_processes.append({ "name": proc_info.name, 
-        #                                "args": proc_info.args, 
-        #                                "pid": proc_info.pid, })
-        #    dead_processes = [ ]
-        #    for proc_info in dead_processes:
-        #        dead_processes.append({ "name": proc_info.name, 
-        #                                "args": proc_info.args, })
-        #    cc.group_reply(envelope, { "response": cmd,
-        #                               "sent": msg["sent"],
-        #                               "live_processes": live_processes,
-        #                               "dead_processes": dead_processes, })
-        #else:
-        #    if self.verbose:
-        #        sys.stdout.write("Unknown command %s\n" % str(cmd))
+                sys.stdout.write("[bind10] Unknown child pid %d exited.\n" % pid)
 
     def restart_processes(self):
         """Restart any dead processes."""
@@ -507,10 +446,6 @@
         for proc_info in self.dead_processes.values():
             restart_time = proc_info.restart_schedule.get_restart_time(now)
             if restart_time > now:
-#                if self.verbose:
-#                    sys.stdout.write("Dead %s process waiting %.1f seconds "\
-#                                     "for resurrection\n" % 
-#                                     (proc_info.name, (restart_time-now)))
                 if (next_restart is None) or (next_restart > restart_time):
                     next_restart = restart_time
                 still_dead[proc_info.pid] = proc_info
@@ -582,9 +517,9 @@
     parser.add_option("-p", "--port", dest="auth_port", type="string",
                       action="callback", callback=check_port, default="5300",
                       help="port the b10-auth daemon will use (default 5300)")
-    parser.add_option("-m", "--msgq-port", dest="msgq_port", type="string",
-                      action="callback", callback=check_port, default="9912",
-                      help="port the b10-msgq daemon will use (default 9912)")
+    parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
+                      type="string", default=None,
+                      help="UNIX domain socket file the b10-msgq daemon will use")
     (options, args) = parser.parse_args()
 
     # Announce startup.
@@ -607,11 +542,11 @@
     signal.signal(signal.SIGTERM, fatal_signal)
 
     # Go bob!
-    boss_of_bind = BoB(int(options.msgq_port), int(options.auth_port),
+    boss_of_bind = BoB(options.msgq_socket_file, int(options.auth_port),
                        options.verbose)
     startup_result = boss_of_bind.startup()
     if startup_result:
-        sys.stderr.write("Error on startup: %s\n" % startup_result)
+        sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
         sys.exit(1)
 
     # In our main loop, we check for dead processes or messages 
@@ -637,7 +572,7 @@
             if err.args[0] == errno.EINTR:
                 (rlist, wlist, xlist) = ([], [], [])
             else:
-                sys.stderr.write("Error with select(); %s\n" % err)
+                sys.stderr.write("[bind10] Error with select(); %s\n" % err)
                 break
 
         for fd in rlist + xlist:

Modified: experiments/python-binding/src/bin/bind10/bob.spec
==============================================================================
--- experiments/python-binding/src/bin/bind10/bob.spec (original)
+++ experiments/python-binding/src/bin/bind10/bob.spec Wed Jun  9 09:52:34 2010
@@ -1,36 +1,10 @@
 {
   "module_spec": {
     "module_name": "Boss",
+    "module_description": "Master process",
     "config_data": [
-      {
-        "item_name": "example_string",
-        "item_type": "string",
-        "item_optional": False,
-        "item_default": "Just an example string configuration value"
-      },
-      {
-        "item_name": "example_int",
-        "item_type": "integer",
-        "item_optional": False,
-        "item_default": 1
-      }
     ],
     "commands": [
-      {
-        "command_name": "print_message",
-        "command_description": "Print the given message to stdout",
-        "command_args": [ {
-          "item_name": "message",
-          "item_type": "string",
-          "item_optional": False,
-          "item_default": ""
-        } ]
-      },
-      {
-        "command_name": "print_settings",
-        "command_description": "Print some_string and some_int to stdout",
-        "command_args": []
-      },
       {
         "command_name": "shutdown",
         "command_description": "Shut down BIND 10",

Modified: experiments/python-binding/src/bin/bind10/run_bind10.sh.in
==============================================================================
--- experiments/python-binding/src/bin/bind10/run_bind10.sh.in (original)
+++ experiments/python-binding/src/bin/bind10/run_bind10.sh.in Wed Jun  9 09:52:34 2010
@@ -24,10 +24,19 @@
 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
 
 B10_FROM_SOURCE=@abs_top_srcdir@
 export B10_FROM_SOURCE
+# TODO: We need to do this feature based (ie. no general from_source)
+# But right now we need a second one because some spec files are
+# generated and hence end up under builddir
+B10_FROM_BUILD=@abs_top_builddir@
+export B10_FROM_BUILD
+
+BIND10_MSGQ_SOCKET_FILE=@abs_top_builddir@/msgq_socket
+export BIND10_MSGQ_SOCKET_FILE
 
 cd ${BIND10_PATH}
 exec ${PYTHON_EXEC} -O bind10 $*

Modified: experiments/python-binding/src/bin/bind10/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/bind10/tests/Makefile.am (original)
+++ experiments/python-binding/src/bin/bind10/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -7,6 +7,6 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bind10 \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

Modified: experiments/python-binding/src/bin/bind10/tests/bind10_test.py
==============================================================================
--- experiments/python-binding/src/bin/bind10/tests/bind10_test.py (original)
+++ experiments/python-binding/src/bin/bind10/tests/bind10_test.py Wed Jun  9 09:52:34 2010
@@ -75,16 +75,16 @@
     def test_init(self):
         bob = BoB()
         self.assertEqual(bob.verbose, False)
-        self.assertEqual(bob.c_channel_port, 9912)
+        self.assertEqual(bob.msgq_socket_file, None)
         self.assertEqual(bob.cc_session, None)
         self.assertEqual(bob.processes, {})
         self.assertEqual(bob.dead_processes, {})
         self.assertEqual(bob.runnable, False)
 
-    def test_init_alternate_port(self):
-        bob = BoB(2199)
+    def test_init_alternate_socket(self):
+        bob = BoB("alt_socket_file")
         self.assertEqual(bob.verbose, False)
-        self.assertEqual(bob.c_channel_port, 2199)
+        self.assertEqual(bob.msgq_socket_file, "alt_socket_file")
         self.assertEqual(bob.cc_session, None)
         self.assertEqual(bob.processes, {})
         self.assertEqual(bob.dead_processes, {})

Modified: experiments/python-binding/src/bin/bindctl/bindcmd.py
==============================================================================
--- experiments/python-binding/src/bin/bindctl/bindcmd.py (original)
+++ experiments/python-binding/src/bin/bindctl/bindcmd.py Wed Jun  9 09:52:34 2010
@@ -49,7 +49,7 @@
 except ImportError:
     my_readline = sys.stdin.readline
 
-
+CONFIG_MODULE_NAME = 'config'
 CONST_BINDCTL_HELP = """
 usage: <module name> <command name> [param1 = value1 [, param2 = value2]]
 Type Tab character to get the hint of module/command/parameters.
@@ -87,8 +87,8 @@
         '''Generate one session id for the connection. '''
         rand = os.urandom(16)
         now = time.time()
-        ip = socket.gethostbyname(socket.gethostname())
-        session_id = sha1(("%s%s%s" %(rand, now, ip)).encode())
+        session_id = sha1(("%s%s%s" %(rand, now, 
+                                      socket.gethostname())).encode())
         digest = session_id.hexdigest()
         return digest
     
@@ -180,13 +180,9 @@
 
 
     def _update_commands(self):
-        '''Get the commands of all modules. '''
-        cmd_spec = self.send_GET('/command_spec')
-        if not cmd_spec:
-            return
-
-        for module_name in cmd_spec.keys():
-            self._prepare_module_commands(module_name, cmd_spec[module_name])
+        '''Update the commands of all modules. '''
+        for module_name in self.config_data.get_config_item_list():
+            self._prepare_module_commands(self.config_data.get_module_spec(module_name))
 
     def send_GET(self, url, body = None):
         '''Send GET request to cmdctl, session id is send with the name
@@ -222,17 +218,18 @@
         self.prompt = self.location + self.prompt_end
         return stop
 
-    def _prepare_module_commands(self, module_name, module_commands):
+    def _prepare_module_commands(self, module_spec):
         '''Prepare the module commands'''
-        module = ModuleInfo(name = module_name,
-                            desc = "same here")
-        for command in module_commands:
+        module = ModuleInfo(name = module_spec.get_module_name(),
+                            desc = module_spec.get_module_description())
+        for command in module_spec.get_commands_spec():
             cmd = CommandInfo(name = command["command_name"],
                               desc = command["command_description"])
             for arg in command["command_args"]:
                 param = ParamInfo(name = arg["item_name"],
                                   type = arg["item_type"],
-                                  optional = bool(arg["item_optional"]))
+                                  optional = bool(arg["item_optional"]),
+                                  param_spec = arg)
                 if ("item_default" in arg):
                     param.default = arg["item_default"]
                 cmd.add_param(param)
@@ -305,12 +302,20 @@
                 if not name in params and not param_nr in params:
                     raise CmdMissParamSyntaxError(cmd.module, cmd.command, name)
                 param_nr += 1
-
+        
+        # Convert parameter value according parameter spec file.
+        # Ignore check for commands belongs to module 'config'
+        if cmd.module != CONFIG_MODULE_NAME:
+            for param_name in cmd.params:
+                param_spec = command_info.get_param_with_name(param_name).param_spec
+                cmd.params[param_name] = isc.config.config_data.convert_type(param_spec, cmd.params[param_name])
+
+    
     def _handle_cmd(self, cmd):
         '''Handle a command entered by the user'''
         if cmd.command == "help" or ("help" in cmd.params.keys()):
             self._handle_help(cmd)
-        elif cmd.module == "config":
+        elif cmd.module == CONFIG_MODULE_NAME:
             self.apply_config_cmd(cmd)
         else:
             self.apply_cmd(cmd)
@@ -361,7 +366,7 @@
                 else:                       
                     hints = self._get_param_startswith(cmd.module, cmd.command,
                                                        text)
-                    if cmd.module == "config":
+                    if cmd.module == CONFIG_MODULE_NAME:
                         # grm text has been stripped of slashes...
                         my_text = self.location + "/" + cur_line.rpartition(" ")[2]
                         list = self.config_data.get_config_item_list(my_text.rpartition("/")[0], True)
@@ -437,6 +442,9 @@
             self._validate_cmd(cmd)
             self._handle_cmd(cmd)
         except BindCtlException as e:
+            print("Error! ", e)
+            self._print_correct_usage(e)
+        except isc.cc.data.DataTypeError as e:
             print("Error! ", e)
             self._print_correct_usage(e)
             

Modified: experiments/python-binding/src/bin/bindctl/bindctl-source.py.in
==============================================================================
--- experiments/python-binding/src/bin/bindctl/bindctl-source.py.in (original)
+++ experiments/python-binding/src/bin/bindctl/bindctl-source.py.in Wed Jun  9 09:52:34 2010
@@ -29,7 +29,7 @@
 
 def prepare_config_commands(tool):
     '''Prepare fixed commands for local configuration editing'''
-    module = ModuleInfo(name = "config", desc = "Configuration commands")
+    module = ModuleInfo(name = CONFIG_MODULE_NAME, desc = "Configuration commands")
     cmd = CommandInfo(name = "show", desc = "Show configuration")
     param = ParamInfo(name = "identifier", type = "string", optional=True)
     cmd.add_param(param)

Modified: experiments/python-binding/src/bin/bindctl/cmdparse.py
==============================================================================
--- experiments/python-binding/src/bin/bindctl/cmdparse.py (original)
+++ experiments/python-binding/src/bin/bindctl/cmdparse.py Wed Jun  9 09:52:34 2010
@@ -24,8 +24,8 @@
     from bindctl.mycollections import OrderedDict
 
 param_name_str = "^\s*(?P<param_name>[\w]+)\s*=\s*"
-param_value_str = "(?P<param_value>[\w\./-]+)"
-param_value_with_quota_str = "[\"\'](?P<param_value>[\w\., /-]+)[\"\']"
+param_value_str = "(?P<param_value>[\w\.:/-]+)"
+param_value_with_quota_str = "[\"\'](?P<param_value>[\w\.:, /-]+)[\"\']"
 next_params_str = "(?P<blank>\s*)(?P<comma>,?)(?P<next_params>.*)$"
 
 PARAM_WITH_QUOTA_PATTERN = re.compile(param_name_str + 
@@ -116,10 +116,3 @@
                 if not groups.group('blank') and \
                    not groups.group('comma'):
                     raise CmdParamFormatError(self.module, self.command)
-                    
-                
-            
-            
-            
-    
-

Modified: experiments/python-binding/src/bin/bindctl/exception.py
==============================================================================
--- experiments/python-binding/src/bin/bindctl/exception.py (original)
+++ experiments/python-binding/src/bin/bindctl/exception.py Wed Jun  9 09:52:34 2010
@@ -62,7 +62,7 @@
         self.command = command        
 
     def __str__(self):
-        return  "Parameter format error, it should like 'key = value'"         
+        return  "Parameter format error, it should be 'key = value'"         
         
 # Begin define the exception for syntax
 
@@ -115,5 +115,3 @@
     def __str__(self):
         return str("Parameter '%s' is missed for command '%s' of module '%s'" % 
                    (self.param, self.command, self.module))
-                   
-   

Modified: experiments/python-binding/src/bin/bindctl/moduleinfo.py
==============================================================================
--- experiments/python-binding/src/bin/bindctl/moduleinfo.py (original)
+++ experiments/python-binding/src/bin/bindctl/moduleinfo.py Wed Jun  9 09:52:34 2010
@@ -33,17 +33,21 @@
 
 class ParamInfo:
     """One parameter of one command.
-    Each command parameter has four attributes:
-    parameter name, parameter type, parameter value, and parameter description
+    Each command parameter has five attributes:
+    parameter name, parameter type, parameter value,
+    parameter description and paramter's spec(got from
+    module spec file). 
     """
     def __init__(self, name, desc = '', type = STRING_TYPE, 
-                 optional = False, value = '', default_value = ''):
+                 optional = False, value = '', default_value = '', 
+                 param_spec = None):
         self.name = name
         self.type = type
         self.value = value
         self.default_value = default_value                           
         self.desc = desc
         self.is_optional = optional
+        self.param_spec = param_spec
     
     def __str__(self):        
         return str("\t%s <type: %s> \t(%s)" % (self.name, self.type, self.desc))

Modified: experiments/python-binding/src/bin/bindctl/run_bindctl.sh.in
==============================================================================
--- experiments/python-binding/src/bin/bindctl/run_bindctl.sh.in (original)
+++ experiments/python-binding/src/bin/bindctl/run_bindctl.sh.in Wed Jun  9 09:52:34 2010
@@ -18,9 +18,9 @@
 PYTHON_EXEC=${PYTHON_EXEC:- at PYTHON@}
 export PYTHON_EXEC
 
-BINDCTL_PATH=@abs_top_srcdir@/src/bin/bindctl
+BINDCTL_PATH=@abs_top_builddir@/src/bin/bindctl
 
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin
+PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python
 export PYTHONPATH
 
 B10_FROM_SOURCE=@abs_top_srcdir@

Modified: experiments/python-binding/src/bin/bindctl/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/bindctl/tests/Makefile.am (original)
+++ experiments/python-binding/src/bin/bindctl/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -7,6 +7,6 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_srcdir)/src/bin \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

Modified: experiments/python-binding/src/bin/bindctl/tests/bindctl_test.py
==============================================================================
--- experiments/python-binding/src/bin/bindctl/tests/bindctl_test.py (original)
+++ experiments/python-binding/src/bin/bindctl/tests/bindctl_test.py Wed Jun  9 09:52:34 2010
@@ -15,6 +15,7 @@
 
 
 import unittest
+import isc.cc.data
 from bindctl import cmdparse
 from bindctl import bindcmd
 from bindctl.moduleinfo import *
@@ -92,14 +93,21 @@
         """Create one bindcmd"""
         
         tool = bindcmd.BindCmdInterpreter()        
-        zone_file_param = ParamInfo(name = "zone_file")
-        zone_name = ParamInfo(name = 'zone_name')
+        string_spec = { 'item_type' : 'string',
+                       'item_optional' : False,
+                       'item_default' : ''}
+        int_spec = { 'item_type' : 'integer',
+                       'item_optional' : False,
+                       'item_default' : 10}
+        zone_file_param = ParamInfo(name = "zone_file", param_spec = string_spec)
+        zone_name = ParamInfo(name = 'zone_name', param_spec = string_spec)
         load_cmd = CommandInfo(name = "load")
         load_cmd.add_param(zone_file_param)
         load_cmd.add_param(zone_name)
         
-        param_master = ParamInfo(name = "master", optional = True)                                 
-        param_allow_update = ParamInfo(name = "allow_update", optional = True)                                           
+        param_master = ParamInfo(name = "master", optional = True, param_spec = string_spec)                                 
+        param_master = ParamInfo(name = "port", optional = True, param_spec = int_spec)                                 
+        param_allow_update = ParamInfo(name = "allow_update", optional = True, param_spec = string_spec)                                           
         set_cmd = CommandInfo(name = "set")
         set_cmd.add_param(param_master)
         set_cmd.add_param(param_allow_update)
@@ -138,6 +146,7 @@
         self.no_assert_raise("zone help help='dd' ")
         self.no_assert_raise("zone set allow_update='1.1.1.1' zone_name='cn'")
         self.no_assert_raise("zone set zone_name='cn'")
+        self.my_assert_raise(isc.cc.data.DataTypeError, "zone set zone_name ='cn', port='cn'")
         self.no_assert_raise("zone reload_all")        
         
     

Modified: experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.py.in
==============================================================================
--- experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.py.in (original)
+++ experiments/python-binding/src/bin/cfgmgr/b10-cfgmgr.py.in Wed Jun  9 09:52:34 2010
@@ -50,6 +50,6 @@
         print("[b10-cfgmgr] Error creating config manager, "
               "is the command channel daemon running?")
     except KeyboardInterrupt as kie:
-        print("Got ctrl-c, exit")
+        print("[b10-cfgmgr] Interrupted, exiting")
     if cm:
         cm.write_config()

Modified: experiments/python-binding/src/bin/cmdctl/cmdctl.py.in
==============================================================================
--- experiments/python-binding/src/bin/cmdctl/cmdctl.py.in (original)
+++ experiments/python-binding/src/bin/cmdctl/cmdctl.py.in Wed Jun  9 09:52:34 2010
@@ -219,8 +219,7 @@
         self._verbose = verbose
         self.cc = isc.cc.Session()
         self.cc.group_subscribe('Cmd-Ctrld')
-        self.command_spec = self.get_cmd_specification()
-        self.config_spec = self.get_data_specification()
+        self.module_spec = self.get_module_specification()
         self.config_data = self.get_config_data()
 
     def _parse_command_result(self, rcode, reply):
@@ -229,10 +228,6 @@
             return {}
         return reply
 
-    def get_cmd_specification(self): 
-        rcode, reply = self.send_command('ConfigManager', isc.config.ccsession.COMMAND_GET_COMMANDS_SPEC)
-        return self._parse_command_result(rcode, reply)
-
     def get_config_data(self):
         '''Get config data for all modules from configmanager '''
         rcode, reply = self.send_command('ConfigManager', isc.config.ccsession.COMMAND_GET_CONFIG)
@@ -244,7 +239,7 @@
         if module_name == 'ConfigManager' and command_name == isc.config.ccsession.COMMAND_SET_CONFIG:
             self.config_data = self.get_config_data()
 
-    def get_data_specification(self):
+    def get_module_specification(self):
         rcode, reply = self.send_command('ConfigManager', isc.config.ccsession.COMMAND_GET_MODULE_SPEC)
         return self._parse_command_result(rcode, reply)
 
@@ -253,10 +248,8 @@
         (message, env) = self.cc.group_recvmsg(True)
         command, arg = isc.config.ccsession.parse_command(message)
         while command:
-            if command == isc.config.ccsession.COMMAND_COMMANDS_UPDATE:
-                self.command_spec[arg[0]] = arg[1]
-            elif command == isc.config.ccsession.COMMAND_SPECIFICATION_UPDATE:
-                self.config_spec[arg[0]] = arg[1]
+            if command == isc.config.ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE:
+                self.module_spec[arg[0]] = arg[1]
             elif command == isc.config.ccsession.COMMAND_SHUTDOWN:
                 return False
             (message, env) = self.cc.group_recvmsg(True)
@@ -270,27 +263,20 @@
         Return rcode, dict.
         rcode = 0: dict is the correct returned value.
         rcode > 0: dict is : { 'error' : 'error reason' }
-
-        TODO. add check for parameters.
         '''
 
         # core module ConfigManager does not have a specification file
         if module_name == 'ConfigManager':
             return self.send_command(module_name, command_name, params)
 
-        if module_name not in self.command_spec.keys():
+        if module_name not in self.module_spec.keys():
             return 1, {'error' : 'unknown module'}
-
-        cmd_valid = False
-        commands = self.command_spec[module_name]
-        for cmd in commands:
-            if cmd['command_name'] == command_name:
-                cmd_valid = True
-                break
-
-        if not cmd_valid:
-            return 1, {'error' : 'unknown command'}
-
+       
+        spec_obj = isc.config.module_spec.ModuleSpec(self.module_spec[module_name], False)
+        errors = []
+        if not spec_obj.validate_command(command_name, params, errors):
+            return 1, {'error': errors[0]}
+        
         return self.send_command(module_name, command_name, params)
 
     def send_command(self, module_name, command_name, params = None):
@@ -326,7 +312,7 @@
         return 1, {'error': errstr}
     
     def log_info(self, msg):
-        sys.stdout.write(msg)
+        sys.stdout.write("[b10-cmdctl] %s\n" % str(msg))
 
 class SecureHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
     '''Make the server address can be reused.'''
@@ -383,12 +369,10 @@
         '''Currently only support the following three url GET request '''
         rcode, reply = http.client.NO_CONTENT, []        
         if not module:
-            if id == 'command_spec':
-               rcode, reply = http.client.OK, self.cmdctrl.command_spec
-            elif id == 'config_data':
+            if id == 'config_data':
                rcode, reply = http.client.OK, self.cmdctrl.config_data
-            elif id == 'config_spec':
-               rcode, reply = http.client.OK, self.cmdctrl.config_spec
+            elif id == 'module_spec':
+                rcode, reply = http.client.OK, self.cmdctrl.module_spec
         
         return rcode, reply 
 
@@ -416,7 +400,7 @@
         return self.cmdctrl.send_command_with_check(module_name, command_name, params)
    
     def log_info(self, msg):
-        sys.stdout.write(msg)
+        sys.stdout.write("[b10-cmdctl] %s\n" % str(msg))
 
 httpd = None
 

Modified: experiments/python-binding/src/bin/cmdctl/cmdctl.spec
==============================================================================
--- experiments/python-binding/src/bin/cmdctl/cmdctl.spec (original)
+++ experiments/python-binding/src/bin/cmdctl/cmdctl.spec Wed Jun  9 09:52:34 2010
@@ -1,6 +1,7 @@
 {
   "module_spec": {
     "module_name": "Cmdctl",
+    "module_description": "Interface for command and control",
     "config_data": [
       {
         "item_name": "key_file",

Modified: experiments/python-binding/src/bin/cmdctl/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/cmdctl/tests/Makefile.am (original)
+++ experiments/python-binding/src/bin/cmdctl/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -7,6 +7,6 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/bin/cmdctl \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cmdctl \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

Modified: experiments/python-binding/src/bin/cmdctl/tests/cmdctl_test.py
==============================================================================
--- experiments/python-binding/src/bin/cmdctl/tests/cmdctl_test.py (original)
+++ experiments/python-binding/src/bin/cmdctl/tests/cmdctl_test.py Wed Jun  9 09:52:34 2010
@@ -51,9 +51,8 @@
 
 class MyCommandControl(CommandControl):
     def __init__(self):
-        self.command_spec = {}
-        self.config_spec = {}
         self.config_data = {}
+        self.module_spec = {}
 
     def send_command(self, mod, cmd, param):
         return 0, {}
@@ -66,6 +65,11 @@
         self.handler.server.user_sessions = {}
         self.handler.server.user_infos = {}
         self.handler.headers = {}
+        self.handler.rfile = open("check.tmp", 'w+b')
+
+    def tearDown(self):
+        self.handler.rfile.close()
+        os.remove('check.tmp')
 
     def test_parse_request_path(self):
         self.handler.path = ''
@@ -120,7 +124,7 @@
     def test_do_GET_3(self):
         self.handler.headers['cookie'] = 12346
         self.handler.server.user_sessions[12346] = time.time() + 1000000
-        path_vec = ['command_spec', 'config_data', 'config_spec']
+        path_vec = ['config_data', 'module_spec']
         for path in path_vec:
             self.handler.path = '/' + path
             self.handler.do_GET()
@@ -145,7 +149,6 @@
         self.assertEqual(msg, ['invalid username or password'])
 
     def test_check_user_name_and_pwd_1(self):
-        self.handler.rfile = open("check.tmp", 'w+b')
         user_info = {'username':'root', 'password':'abc123'}
         len = self.handler.rfile.write(json.dumps(user_info).encode())
         self.handler.headers['Content-Length'] = len
@@ -155,11 +158,8 @@
         ret, msg = self.handler._check_user_name_and_pwd()
         self.assertTrue(ret == False)
         self.assertEqual(msg, ['password doesn\'t match'])
-        self.handler.rfile.close()
-        os.remove('check.tmp')
 
     def test_check_user_name_and_pwd_2(self):
-        self.handler.rfile = open("check.tmp", 'w+b')
         user_info = {'username':'root', 'password':'abc123'}
         len = self.handler.rfile.write(json.dumps(user_info).encode())
         self.handler.headers['Content-Length'] = len - 1
@@ -168,11 +168,8 @@
         ret, msg = self.handler._check_user_name_and_pwd()
         self.assertTrue(ret == False)
         self.assertEqual(msg, ['invalid username or password'])
-        self.handler.rfile.close()
-        os.remove('check.tmp')
 
     def test_check_user_name_and_pwd_3(self):
-        self.handler.rfile = open("check.tmp", 'w+b')
         user_info = {'usernae':'root', 'password':'abc123'}
         len = self.handler.rfile.write(json.dumps(user_info).encode())
         self.handler.headers['Content-Length'] = len
@@ -181,11 +178,8 @@
         ret, msg = self.handler._check_user_name_and_pwd()
         self.assertTrue(ret == False)
         self.assertEqual(msg, ['need user name'])
-        self.handler.rfile.close()
-        os.remove('check.tmp')
 
     def test_check_user_name_and_pwd_4(self):
-        self.handler.rfile = open("check.tmp", 'w+b')
         user_info = {'username':'root', 'pssword':'abc123'}
         len = self.handler.rfile.write(json.dumps(user_info).encode())
         self.handler.headers['Content-Length'] = len
@@ -195,11 +189,8 @@
         ret, msg = self.handler._check_user_name_and_pwd()
         self.assertTrue(ret == False)
         self.assertEqual(msg, ['need password'])
-        self.handler.rfile.close()
-        os.remove('check.tmp')
 
     def test_check_user_name_and_pwd_5(self):
-        self.handler.rfile = open("check.tmp", 'w+b')
         user_info = {'username':'root', 'password':'abc123'}
         len = self.handler.rfile.write(json.dumps(user_info).encode())
         self.handler.headers['Content-Length'] = len
@@ -208,8 +199,6 @@
         ret, msg = self.handler._check_user_name_and_pwd()
         self.assertTrue(ret == False)
         self.assertEqual(msg, ['user doesn\'t exist'])
-        self.handler.rfile.close()
-        os.remove('check.tmp')
 
     def test_do_POST(self):
         self.handler.headers = {}
@@ -235,20 +224,45 @@
         rcode, reply = self.handler._handle_post_request()
         self.assertEqual(http.client.BAD_REQUEST, rcode)
 
+    def _gen_module_spec(self):
+        spec = { 'commands': [ 
+                  { 'command_name' :'command', 
+                    'command_args': [ {
+                            'item_name' : 'param1',
+                            'item_type' : 'integer',
+                            'item_optional' : False,
+                            'item_default' : 0
+                           } ],
+                    'command_description' : 'cmd description'
+                  }
+                ] 
+               }
+        
+        return spec
+
     def test_handle_post_request_2(self):
-        self.handler.rfile = open("check.tmp", 'w+b')
-        params = {123:'param data'}
+        params = {'param1':123}
         len = self.handler.rfile.write(json.dumps(params).encode())
         self.handler.headers['Content-Length'] = len
-        self.handler.rfile.seek(0, 0)
-        self.handler.rfile.close()
-        os.remove('check.tmp')
-
+
+        self.handler.rfile.seek(0, 0)
         self.handler.path = '/module/command'
-        self.handler.server.cmdctrl.command_spec = {}
-        self.handler.server.cmdctrl.command_spec['module'] = [{'command_name':'command'}, {'command_name': ['data1']} ]
+        self.handler.server.cmdctrl.module_spec = {}
+        self.handler.server.cmdctrl.module_spec['module'] = self._gen_module_spec()
         rcode, reply = self.handler._handle_post_request()
         self.assertEqual(http.client.OK, rcode)
+
+    def test_handle_post_request_3(self):
+        params = {'param1':'abc'}
+        len = self.handler.rfile.write(json.dumps(params).encode())
+        self.handler.headers['Content-Length'] = len
+
+        self.handler.rfile.seek(0, 0)
+        self.handler.path = '/module/command'
+        self.handler.server.cmdctrl.module_spec = {}
+        self.handler.server.cmdctrl.module_spec['module'] = self._gen_module_spec()
+        rcode, reply = self.handler._handle_post_request()
+        self.assertEqual(http.client.BAD_REQUEST, rcode)
 
 if __name__== "__main__":
     unittest.main()

Modified: experiments/python-binding/src/bin/host/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/host/Makefile.am (original)
+++ experiments/python-binding/src/bin/host/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,5 +1,7 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 CLEANFILES = *.gcno *.gcda
 

Modified: experiments/python-binding/src/bin/loadzone/b10-loadzone.py.in
==============================================================================
--- experiments/python-binding/src/bin/loadzone/b10-loadzone.py.in (original)
+++ experiments/python-binding/src/bin/loadzone/b10-loadzone.py.in Wed Jun  9 09:52:34 2010
@@ -77,4 +77,4 @@
         exit(1)
 
 if __name__ == "__main__":
-    main(datasrc
+    main()

Modified: experiments/python-binding/src/bin/msgq/msgq.py.in
==============================================================================
--- experiments/python-binding/src/bin/msgq/msgq.py.in (original)
+++ experiments/python-binding/src/bin/msgq/msgq.py.in Wed Jun  9 09:52:34 2010
@@ -47,11 +47,11 @@
         """Add a subscription."""
         target = ( group, instance )
         if target in self.subscriptions:
-            print("Appending to existing target")
+            print("[b10-msgq] Appending to existing target")
             if socket not in self.subscriptions[target]:
                 self.subscriptions[target].append(socket)
         else:
-            print("Creating new target")
+            print("[b10-msgq] Creating new target")
             self.subscriptions[target] = [ socket ]
 
     def unsubscribe(self, group, instance, socket):
@@ -86,25 +86,33 @@
 
 class MsgQ:
     """Message Queue class."""
-    def __init__(self, port=0, verbose=False):
+    # did we find a better way to do this?
+    SOCKET_FILE = os.path.join("@localstatedir@",
+                               "@PACKAGE_NAME@",
+                               "msgq_socket").replace("${prefix}",
+                                                      "@prefix@")
+    
+    def __init__(self, socket_file=None, verbose=False):
         """Initialize the MsgQ master.
         
-        The port specifies the TCP/IP port that the msgq
-        process listens on. If verbose is True, then the MsgQ reports
+        The socket_file specifies the path to the UNIX domain socket
+        that the msgq process listens on. If it is None, the
+        environment variable BIND10_MSGQ_SOCKET_FILE is used. If that
+        is not set, it will default to
+        @localstatedir@/@PACKAGE_NAME@/msg_socket.
+        If verbose is True, then the MsgQ reports
         what it is doing.
         """
 
-        if port == 0:
-	        if 'ISC_MSGQ_PORT' in os.environ:
-	            port = int(os.environ["ISC_MSGQ_PORT"])
-	        else:
-	            port = 9912
-
-
-        print(port)
+        if socket_file is None:
+            if "BIND10_MSGQ_SOCKET_FILE" in os.environ:
+                self.socket_file = os.environ["BIND10_MSGQ_SOCKET_FILE"]
+            else:
+                self.socket_file = self.SOCKET_FILE
+        else:
+            self.socket_file = socket_file
 
         self.verbose = verbose
-        self.c_channel_port = port
         self.poller = None
         self.kqueue = None
         self.runnable = False
@@ -131,10 +139,19 @@
 
     def setup_listener(self):
         """Set up the listener socket.  Internal function."""
-        self.listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        self.listen_socket.bind(("127.0.0.1", self.c_channel_port))
-        self.listen_socket.listen(1024)
+        self.listen_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+        
+        if os.path.exists(self.socket_file):
+            os.remove(self.socket_file)
+        try:
+            self.listen_socket.bind(self.socket_file)
+            self.listen_socket.listen(1024)
+        except Exception as e:
+            # remove the file again if something goes wrong
+            # (note this is a catch-all, but we reraise it)
+            if os.path.exists(self.socket_file):
+                os.remove(self.socket_file)
+            raise e
 
         if self.poller:
             self.poller.register(self.listen_socket, select.POLLIN)
@@ -142,20 +159,25 @@
             self.add_kqueue_socket(self.listen_socket)
 
     def setup(self):
-        """Configure listener socket, polling, etc."""
+        """Configure listener socket, polling, etc.
+           Raises a socket.error if the socket_file cannot be
+           created.
+        """
 
         self.setup_poller()
         self.setup_listener()
 
         if self.verbose:
-            sys.stdout.write("Listening\n")
+            sys.stdout.write("[b10-msgq] Listening\n")
         
         self.runnable = True
 
     def process_accept(self):
         """Process an accept on the listening socket."""
         newsocket, ipaddr = self.listen_socket.accept()
-        sys.stderr.write("Connection\n")
+        # TODO: When we have logging, we might want
+        # to add a debug message here that a new connection
+        # was made
         self.sockets[newsocket.fileno()] = newsocket
         lname = self.newlname()
         self.lnames[lname] = newsocket
@@ -169,9 +191,9 @@
         """Process a read on a socket."""
         sock = self.sockets[fd]
         if sock == None:
-            sys.stderr.write("Got read on Strange Socket fd %d\n" % fd)
+            sys.stderr.write("[b10-msgq] Got read on Strange Socket fd %d\n" % fd)
             return
-#        sys.stderr.write("Got read on fd %d\n" %fd)
+#        sys.stderr.write("[b10-msgq] Got read on fd %d\n" %fd)
         self.process_packet(fd, sock)
 
     def kill_socket(self, fd, sock):
@@ -183,7 +205,7 @@
         del self.lnames[lname]
         sock.close()
         self.sockets[fd] = None
-        sys.stderr.write("Closing socket fd %d\n" % fd)
+        sys.stderr.write("[b10-msgq] Closing socket fd %d\n" % fd)
 
     def getbytes(self, fd, sock, length):
         """Get exactly the requested bytes, or raise an exception if
@@ -223,14 +245,14 @@
             routing, data = self.read_packet(fd, sock)
         except MsgQReceiveError as err:
             self.kill_socket(fd, sock)
-            sys.stderr.write("Receive error: %s\n" % err)
+            sys.stderr.write("[b10-msgq] Receive error: %s\n" % err)
             return
 
         try:
             routingmsg = isc.cc.message.from_wire(routing)
         except DecodeError as err:
             self.kill_socket(fd, sock)
-            sys.stderr.write("Routing decode error: %s\n" % err)
+            sys.stderr.write("[b10-msgq] Routing decode error: %s\n" % err)
             return
 
 #        sys.stdout.write("\t" + pprint.pformat(routingmsg) + "\n")
@@ -241,8 +263,9 @@
     def process_command(self, fd, sock, routing, data):
         """Process a single command.  This will split out into one of the
            other functions."""
-        print("[XX] got command: ")
-        print(routing)
+        # TODO: A print statement got removed here (one that prints the
+        # routing envelope). When we have logging with multiple levels,
+        # we might want to re-add that on a high debug verbosity.
         cmd = routing["type"]
         if cmd == 'send':
             self.process_command_send(sock, routing, data)
@@ -253,7 +276,7 @@
         elif cmd == 'getlname':
             self.process_command_getlname(sock, routing, data)
         else:
-            sys.stderr.write("Invalid command: %s\n" % cmd)
+            sys.stderr.write("[b10-msgq] Invalid command: %s\n" % cmd)
 
     def preparemsg(self, env, msg = None):
         if type(env) == dict:
@@ -338,7 +361,7 @@
                 if err.args[0] == errno.EINTR:
                     events = []
                 else:
-                    sys.stderr.write("Error with poll(): %s\n" % err)
+                    sys.stderr.write("[b10-msgq] Error with poll(): %s\n" % err)
                     break
             for (fd, event) in events:
                 if fd == self.listen_socket.fileno():
@@ -364,8 +387,10 @@
     def shutdown(self):
         """Stop the MsgQ master."""
         if self.verbose:
-            sys.stdout.write("Stopping the server.\n")
+            sys.stdout.write("[b10-msgq] Stopping the server.\n")
         self.listen_socket.close()
+        if os.path.exists(self.socket_file):
+            os.remove(self.socket_file)
 
 # can signal handling and calling a destructor be done without a
 # global variable?
@@ -389,22 +414,22 @@
     parser = OptionParser(version=__version__)
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
                       help="display more about what is going on")
-    parser.add_option("-m", "--msgq-port", dest="msgq_port", type="string",
-                      action="callback", callback=check_port, default="0",
-                      help="port the msgq daemon will use")
+    parser.add_option("-s", "--socket-file", dest="msgq_socket_file",
+                      type="string", default=None,
+                      help="UNIX domain socket file the msgq daemon will use")
     (options, args) = parser.parse_args()
 
     signal.signal(signal.SIGTERM, signal_handler)
 
     # Announce startup.
     if options.verbose:
-        sys.stdout.write("MsgQ %s\n" % __version__)
-
-    msgq = MsgQ(int(options.msgq_port), options.verbose)
+        sys.stdout.write("[b10-msgq] MsgQ %s\n" % __version__)
+
+    msgq = MsgQ(options.msgq_socket_file, options.verbose)
 
     setup_result = msgq.setup()
     if setup_result:
-        sys.stderr.write("Error on startup: %s\n" % setup_result)
+        sys.stderr.write("[b10-msgq] Error on startup: %s\n" % setup_result)
         sys.exit(1)
 
     try:

Modified: experiments/python-binding/src/bin/msgq/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/bin/msgq/tests/Makefile.am (original)
+++ experiments/python-binding/src/bin/msgq/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -7,7 +7,7 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_builddir)/src/bin/msgq:$(abs_top_srcdir)/src/lib/python \
+	env PYTHONPATH=$(abs_top_builddir)/src/bin/msgq:$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done
 

Modified: experiments/python-binding/src/bin/msgq/tests/msgq_test.py
==============================================================================
--- experiments/python-binding/src/bin/msgq/tests/msgq_test.py (original)
+++ experiments/python-binding/src/bin/msgq/tests/msgq_test.py Wed Jun  9 09:52:34 2010
@@ -1,6 +1,8 @@
 from msgq import SubscriptionManager, MsgQ
 
 import unittest
+import os
+import socket
 
 #
 # Currently only the subscription part is implemented...  I'd have to mock
@@ -58,5 +60,46 @@
         self.sm.subscribe('g1', '*', 's2')
         self.assertEqual(self.sm.find_sub("g1", "i1"), [ 's1' ])
 
+    def test_open_socket_parameter(self):
+        self.assertFalse(os.path.exists("./my_socket_file"))
+        msgq = MsgQ("./my_socket_file");
+        msgq.setup()
+        self.assertTrue(os.path.exists("./my_socket_file"))
+        msgq.shutdown();
+        self.assertFalse(os.path.exists("./my_socket_file"))
+
+    def test_open_socket_environment_variable(self):
+        self.assertFalse(os.path.exists("my_socket_file"))
+        os.environ["BIND10_MSGQ_SOCKET_FILE"] = "./my_socket_file"
+        msgq = MsgQ();
+        msgq.setup()
+        self.assertTrue(os.path.exists("./my_socket_file"))
+        msgq.shutdown();
+        self.assertFalse(os.path.exists("./my_socket_file"))
+
+    def test_open_socket_default(self):
+        env_var = None
+        if "BIND10_MSGQ_SOCKET_FILE" in os.environ:
+            env_var = os.environ["BIND10_MSGQ_SOCKET_FILE"]
+            del os.environ["BIND10_MSGQ_SOCKET_FILE"]
+        socket_file = MsgQ.SOCKET_FILE
+        self.assertFalse(os.path.exists(socket_file))
+        msgq = MsgQ();
+        try:
+            msgq.setup()
+            self.assertTrue(os.path.exists(socket_file))
+            msgq.shutdown();
+            self.assertFalse(os.path.exists(socket_file))
+        except socket.error:
+            # ok, the install path doesn't exist at all,
+            # so we can't check any further
+            pass
+        if env_var is not None:
+            os.environ["BIND10_MSGQ_SOCKET_FILE"] = env_var
+
+    def test_open_socket_bad(self):
+        msgq = MsgQ("/does/not/exist")
+        self.assertRaises(socket.error, msgq.setup)
+
 if __name__ == '__main__':
     unittest.main()

Modified: experiments/python-binding/src/bin/xfrin/TODO
==============================================================================
--- experiments/python-binding/src/bin/xfrin/TODO (original)
+++ experiments/python-binding/src/bin/xfrin/TODO Wed Jun  9 09:52:34 2010
@@ -1,1 +1,65 @@
-1. When xfrin's config data is changed, new config data should be applied.
+1. When xfrin's config data is changed, new config data should be applied.
+2. mutex on recorder is not sufficient.  race can happen if two xfrin requests
+   occur at the same time.  (but testing it would be very difficult)
+3. It wouldn't support IPv6 because of the following line:
+        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+   [FIXED in r1851]
+4. Xfrin.retransfer and refresh share most of the code.  should be unified.
+   [FIXED in r1861]
+5. class IN is hardcoded.  bad.
+        query_question = question(name(self._zone_name), rr_class.IN(), query_type)
+   [FIXED in r1889]
+   Note: we still hardcode it as the fixed default value for
+   retransfer/refresh commands.
+   we should fix this so that this is specifiable, so this TODO item is 
+   still open.
+6. QID 0 should be allowed:
+        query_id = random.randint(1, 0xFFFF)
+   [FIXED in r1880]
+7. what if xfrin fails after opening a new DB?  looks like garbage
+   (intermediate) data remains in the DB file, although it's more about
+   the data source implementation.  check it, and fix it if it's the case.
+8. Xfrin.command_handler() ignores unknown commands.  should return an error.
+   [FIXED in r1882]
+9. XfrinConnection can leak sockets. (same problem as that Jelte mentioned
+   on xfrout?)
+   [FIXED in r1908]
+10. The following line of _check_soa_serial() is incorrect.
+        soa_reply = self._get_request_response(int(data_size))
+    Unpack the data and convert it in the host by order.
+    [FIXED in r1866]
+11. if do_xfrin fails it should probably return a non "OK" value.
+    (it's currently ignored anyway, though)
+    [FIXED in r1887]
+12. XfrinConnection should probably define handle_close().  Also, the
+    following part should be revised because this can also happen when the
+    master closes the connection.
+            if self._recv_time_out:
+                raise XfrinException('receive data from socket time out.')
+13. according to the source code xfrin cannot quickly terminate on shutdown
+    if some of the xfr connections stall.  on a related note, the use of
+    threading.Event() is questionable: since no threads wait() on the event,
+    it actually just works as a global flag shared by all threads.
+    this implementation should be refactored so that a shutdown command is
+    propagate to all threads immediately, whether it's via a builtin mechanism
+    of the threading module or not (it's probably "not", see below).
+14. the current use of asyncore seems to be thread unsafe because it
+    relies on a global channel map (which is the implicit default).
+    each thread should probably use its own map:
+      asyncore.dispatcher.__init__(self, map=sock_map)
+      # where sock_map is thread specific and is passed to
+      # XfrinConnection.__init__().
+15. but in the first place, it's not clear why we need asyncore.
+    since each thread is responsible for a single xfr connection,
+    socket operations can safely block (with timeouts).  this should
+    be easily implemented using the bear socket module, and the code
+    would look like more straightforward by avoiding complicated logic
+    for asynchrony.  in fact, that simplicity should be a major
+    advantage with thread over event-driven (the model asyncore
+    implements), so this mixture of two models seems awkward to me.
+16. having said all that, asyncore may still be necessary to address
+    item #13: we'd need an explicit communication channel (e.g. a
+    pipe) between the parent thread and xfr connection thread, through
+    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.

Modified: experiments/python-binding/src/bin/xfrin/tests/xfrin_test.in
==============================================================================
--- experiments/python-binding/src/bin/xfrin/tests/xfrin_test.in (original)
+++ experiments/python-binding/src/bin/xfrin/tests/xfrin_test.in Wed Jun  9 09:52:34 2010
@@ -19,9 +19,8 @@
 export PYTHON_EXEC
 
 TEST_PATH=@abs_top_srcdir@/src/bin/xfrin/tests
-PYTHONPATH=@abs_top_srcdir@/src/bin/xfrin:@abs_top_srcdir@/src/lib/python
+PYTHONPATH=@abs_top_srcdir@/src/bin/xfrin:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/.libs
 export PYTHONPATH
 
 cd ${TEST_PATH}
 exec ${PYTHON_EXEC} -O xfrin_test.py $*
-

Modified: experiments/python-binding/src/bin/xfrin/tests/xfrin_test.py
==============================================================================
--- experiments/python-binding/src/bin/xfrin/tests/xfrin_test.py (original)
+++ experiments/python-binding/src/bin/xfrin/tests/xfrin_test.py Wed Jun  9 09:52:34 2010
@@ -13,99 +13,533 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+# $Id$
 
 import unittest
 import socket
 from xfrin import *
 
-# An axfr response of the simple zone "example.com(without soa record at the end)."
-axfr_response1 = b'\x84\x00\x00\x01\x00\x06\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01\xc0\x0c\x00\x06\x00\x01\x00\x00\x0e\x10\x00$\x05dns01\xc0\x0c\x05admin\xc0\x0c\x00\x00\x04\xd2\x00\x00\x0e\x10\x00\x00\x07\x08\x00$\xea\x00\x00\x00\x1c \xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x02\xc0)\xc0)\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\xc0\xa8\x02\x02\x04sql1\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x02\xc0)\x04sql2\xc0\x0c\x00\x02\x00\x01\x00\x00\x0e\x10\x00\x02\xc0)\x03ns1\x07subzone\xc0\x0c\x00\x01\x00\x01\x00\x00\x0e\x10\x00\x04\xc0\xa8\x03\x01'
-
-# The second axfr response with only the end soa record.
-axfr_response2 = b'\x84\x00\x00\x00\x00\x01\x00\x00\x00\x00\x07example\x03com\x00\x00\x06\x00\x01\x00\x00\x0e\x10\x00$\x05dns01\xc0\x0c\x05admin\xc0\x0c\x00\x00\x04\xd2\x00\x00\x0e\x10\x00\x00\x07\x08\x00$\xea\x00\x00\x00\x1c '
-
-DB_FILE = 'db_file'
-# Rewrite the class for unittest.
-class MyXfrin(Xfrin):
-    def __init__(self):
+#
+# Commonly used (mostly constant) test parameters
+#
+TEST_ZONE_NAME = "example.com"
+TEST_RRCLASS = RRClass.IN()
+TEST_DB_FILE = 'db_file'
+TEST_MASTER_IPV4_ADDRESS = '127.0.0.1'
+TEST_MASTER_IPV4_ADDRINFO = (socket.AF_INET, socket.SOCK_STREAM,
+                             socket.IPPROTO_TCP, '',
+                             (TEST_MASTER_IPV4_ADDRESS, 53))
+TEST_MASTER_IPV6_ADDRESS = '::1'
+TEST_MASTER_IPV6_ADDRINFO = (socket.AF_INET6, socket.SOCK_STREAM,
+                             socket.IPPROTO_TCP, '',
+                             (TEST_MASTER_IPV6_ADDRESS, 53))
+# XXX: This should be a non priviledge port that is unlikely to be used.
+# If some other process uses this port test will fail.
+TEST_MASTER_PORT = '53535'
+
+soa_rdata = Rdata(RRType.SOA(), TEST_RRCLASS,
+                  'master.example.com. admin.example.com ' +
+                  '1234 3600 1800 2419200 7200')
+soa_rrset = RRset(Name(TEST_ZONE_NAME), TEST_RRCLASS, RRType.SOA(),
+                  RRTTL(3600))
+soa_rrset.add_rdata(soa_rdata)
+example_axfr_question = Question(Name(TEST_ZONE_NAME), TEST_RRCLASS,
+                                 RRType.AXFR())
+example_soa_question = Question(Name(TEST_ZONE_NAME), TEST_RRCLASS,
+                                 RRType.SOA())
+default_questions = [example_axfr_question]
+default_answers = [soa_rrset]
+
+class XfrinTestException(Exception):
+    pass
+
+class MockXfrin(Xfrin):
+    # This is a class attribute of a callable object that specifies a non
+    # default behavior triggered in _cc_check_command().  Specific test methods
+    # are expected to explicitly set this attribute before creating a
+    # MockXfrin object (when it needs a non default behavior).
+    # See the TestMain class.
+    check_command_hook = None
+
+    def _cc_setup(self):
         pass
-
-class MyXfrinConnection(XfrinConnection):
-    query_data = b''
-    eply_data = b''
-
-    def _handle_xfrin_response(self):
-        for rr in super()._handle_xfrin_response():
-            pass
-
-    def _get_request_response(self, size):
-        ret = self.reply_data[:size]
+    
+    def _cc_check_command(self):
+        self._shutdown_event.set()
+        if MockXfrin.check_command_hook:
+            MockXfrin.check_command_hook()
+
+class MockXfrinConnection(XfrinConnection):
+    def __init__(self, sock_map, zone_name, rrclass, db_file, shutdown_event,
+                 master_addr):
+        super().__init__(sock_map, zone_name, rrclass, db_file, shutdown_event,
+                         master_addr)
+        self.query_data = b''
+        self.reply_data = b''
+        self.force_time_out = False
+        self.force_close = False
+        self.qlen = None
+        self.qid = None
+        self.response_generator = None
+
+    def _asyncore_loop(self):
+        if self.force_close:
+            self.handle_close()
+        elif not self.force_time_out:
+            self.handle_read()
+
+    def connect_to_master(self):
+        return True
+
+    def recv(self, size):
+        data = self.reply_data[:size]
         self.reply_data = self.reply_data[size:]
-        if (len(ret) < size):
-            raise XfrinException('cannot get reply data')
-        return ret
+        if len(data) < size:
+            raise XfrinTestException('cannot get reply data')
+        return data
 
     def send(self, data):
+        if self.qlen != None and len(self.query_data) >= self.qlen:
+            # This is a new query.  reset the internal state.
+            self.qlen = None
+            self.qid = None
+            self.query_data = b''
         self.query_data += data
+
+        # when the outgoing data is sufficiently large to contain the length
+        # and the QID fields (4 octets or more), extract these fields.
+        # The length will be reset the internal query data to support multiple
+        # queries in a single test.
+        # The QID will be used to construct a matching response.
+        if len(self.query_data) >= 4 and self.qid == None:
+            self.qlen = socket.htons(struct.unpack('H',
+                                                   self.query_data[0:2])[0])
+            self.qid = socket.htons(struct.unpack('H', self.query_data[2:4])[0])
+            # if the response generator method is specified, invoke it now.
+            if self.response_generator != None:
+                self.response_generator()
         return len(data)
 
-    def create_response_data(self, data):
-        reply_data = self.query_data[2:4] + data
-        size = socket.htons(len(reply_data))
-        reply_data = struct.pack('H', size) + reply_data
+    def create_response_data(self, response = True, bad_qid = False,
+                             rcode = Rcode.NOERROR(),
+                             questions = default_questions,
+                             answers = default_answers):
+        resp = Message(Message.RENDER)
+        qid = self.qid
+        if bad_qid:
+            qid += 1
+        resp.set_qid(qid)
+        resp.set_opcode(Opcode.QUERY())
+        resp.set_rcode(rcode)
+        if response:
+            resp.set_header_flag(MessageFlag.QR())
+        [resp.add_question(q) for q in questions]
+        [resp.add_rrset(Section.ANSWER(), a) for a in answers]
+
+        renderer = MessageRenderer()
+        resp.to_wire(renderer)
+        reply_data = struct.pack('H', socket.htons(renderer.get_length()))
+        reply_data += renderer.get_data()
+
         return reply_data
-
 
 class TestXfrinConnection(unittest.TestCase):
     def setUp(self):
-        self.conn = MyXfrinConnection('example.com.', DB_FILE, threading.Event(), '1.1.1.1')
+        if os.path.exists(TEST_DB_FILE):
+            os.remove(TEST_DB_FILE)
+        self.sock_map = {}
+        self.conn = MockXfrinConnection(self.sock_map, 'example.com.',
+                                        TEST_RRCLASS, TEST_DB_FILE,
+                                        threading.Event(),
+                                        TEST_MASTER_IPV4_ADDRINFO)
+        self.axfr_after_soa = False
+        self.soa_response_params = {
+            'questions': [example_soa_question],
+            'bad_qid': False,
+            'response': True,
+            'rcode': Rcode.NOERROR(),
+            'axfr_after_soa': self._create_normal_response_data
+            }
+
+    def tearDown(self):
+        self.conn.close()
+        if os.path.exists(TEST_DB_FILE):
+            os.remove(TEST_DB_FILE)
+
+    def test_close(self):
+        # we shouldn't be using the global asyncore map.
+        self.assertEqual(len(asyncore.socket_map), 0)
+        # there should be exactly one entry in our local map
+        self.assertEqual(len(self.sock_map), 1)
+        # once closing the dispatch the map should become empty
+        self.conn.close()
+        self.assertEqual(len(self.sock_map), 0)
+
+    def test_init_ip6(self):
+        # This test simply creates a new XfrinConnection object with an
+        # IPv6 address, tries to bind it to an IPv6 wildcard address/port
+        # to confirm an AF_INET6 socket has been created.  A naive application
+        # tends to assume it's IPv4 only and hardcode AF_INET.  This test
+        # uncovers such a bug.
+        c = MockXfrinConnection({}, 'example.com.', TEST_RRCLASS, TEST_DB_FILE,
+                                threading.Event(),
+                                TEST_MASTER_IPV6_ADDRINFO)
+        c.bind(('::', 0))
+        c.close()
+
+    def test_init_chclass(self):
+        c = XfrinConnection({}, 'example.com.', RRClass.CH(), TEST_DB_FILE,
+                            threading.Event(), TEST_MASTER_IPV4_ADDRINFO)
+        axfrmsg = c._create_query(RRType.AXFR())
+        self.assertEqual(axfrmsg.get_question()[0].get_class(),
+                         RRClass.CH())
+        c.close()
 
     def test_response_with_invalid_msg(self):
-        self.conn.data_exchange = b'aaaxxxx'
-        self.assertRaises(Exception, self.conn._handle_xfrin_response)
+        self.conn.reply_data = b'aaaxxxx'
+        self.assertRaises(XfrinTestException, self._handle_xfrin_response)
 
     def test_response_without_end_soa(self):
         self.conn._send_query(RRType.AXFR())
-        self.conn.reply_data = self.conn.create_response_data(axfr_response1) 
-        self.assertRaises(XfrinException, self.conn._handle_xfrin_response)
+        self.conn.reply_data = self.conn.create_response_data()
+        self.assertRaises(XfrinTestException, self._handle_xfrin_response)
+
+    def test_response_bad_qid(self):
+        self.conn._send_query(RRType.AXFR())
+        self.conn.reply_data = self.conn.create_response_data(bad_qid = True)
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_response_non_response(self):
+        self.conn._send_query(RRType.AXFR())
+        self.conn.reply_data = self.conn.create_response_data(response = False)
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_response_error_code(self):
+        self.conn._send_query(RRType.AXFR())
+        self.conn.reply_data = self.conn.create_response_data(
+            rcode=Rcode.SERVFAIL())
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_response_multi_question(self):
+        self.conn._send_query(RRType.AXFR())
+        self.conn.reply_data = self.conn.create_response_data(
+            questions=[example_axfr_question, example_axfr_question])
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_response_empty_answer(self):
+        self.conn._send_query(RRType.AXFR())
+        self.conn.reply_data = self.conn.create_response_data(answers=[])
+        # Should an empty answer trigger an exception?  Even though it's very
+        # unusual it's not necessarily invalid.  Need to revisit.
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_response_non_response(self):
+        self.conn._send_query(RRType.AXFR())
+        self.conn.reply_data = self.conn.create_response_data(response = False)
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_soacheck(self):
+        # we need to defer the creation until we know the QID, which is
+        # determined in _check_soa_serial(), so we use response_generator.
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertEqual(self.conn._check_soa_serial(), XFRIN_OK)
+
+    def test_soacheck_with_bad_response(self):
+        self.conn.response_generator = self._create_broken_response_data
+        self.assertRaises(MessageTooShort, self.conn._check_soa_serial)
+
+    def test_soacheck_badqid(self):
+        self.soa_response_params['bad_qid'] = True
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertRaises(XfrinException, self.conn._check_soa_serial)
+
+    def test_soacheck_non_response(self):
+        self.soa_response_params['response'] = False
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertRaises(XfrinException, self.conn._check_soa_serial)
+
+    def test_soacheck_error_code(self):
+        self.soa_response_params['rcode'] = Rcode.SERVFAIL()
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertRaises(XfrinException, self.conn._check_soa_serial)
+
+    def test_response_shutdown(self):
+        self.conn.response_generator = self._create_normal_response_data
+        self.conn._shutdown_event.set()
+        self.conn._send_query(RRType.AXFR())
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_response_timeout(self):
+        self.conn.response_generator = self._create_normal_response_data
+        self.conn.force_time_out = True
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_response_remote_close(self):
+        self.conn.response_generator = self._create_normal_response_data
+        self.conn.force_close = True
+        self.assertRaises(XfrinException, self._handle_xfrin_response)
+
+    def test_response_bad_message(self):
+        self.conn.response_generator = self._create_broken_response_data
+        self.conn._send_query(RRType.AXFR())
+        self.assertRaises(Exception, self._handle_xfrin_response)
 
     def test_response(self):
-        self.conn._send_query(RRType.AXFR())
-        self.conn.reply_data = self.conn.create_response_data(axfr_response1) 
-        self.conn.reply_data += self.conn.create_response_data(axfr_response2) 
-        self.conn._handle_xfrin_response()
+        # normal case.
+        self.conn.response_generator = self._create_normal_response_data
+        self.conn._send_query(RRType.AXFR())
+        # two SOAs, and only these have been transfered.  the 2nd SOA is just
+        # a marker, so only 1 RR has been provided in the iteration.
+        self.assertEqual(self._handle_xfrin_response(), 1)
+
+    def test_do_xfrin(self):
+        self.conn.response_generator = self._create_normal_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_OK)
+
+    def test_do_xfrin_empty_response(self):
+        # skipping the creation of response data, so the transfer will fail.
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+
+    def test_do_xfrin_bad_response(self):
+        self.conn.response_generator = self._create_broken_response_data
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+
+    def test_do_xfrin_dberror(self):
+        # DB file is under a non existent directory, so its creation will fail,
+        # which will make the transfer fail.
+        self.conn._db_file = "not_existent/" + TEST_DB_FILE
+        self.assertEqual(self.conn.do_xfrin(False), XFRIN_FAIL)
+
+    def test_do_soacheck_and_xfrin(self):
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertEqual(self.conn.do_xfrin(True), XFRIN_OK)
+
+    def test_do_soacheck_broken_response(self):
+        self.conn.response_generator = self._create_broken_response_data
+        # XXX: TODO: this test failed here, should xfr not raise an
+        # exception but simply drop and return FAIL?
+        #self.assertEqual(self.conn.do_xfrin(True), XFRIN_FAIL)
+        self.assertRaises(MessageTooShort, self.conn.do_xfrin, True)
+
+    def test_do_soacheck_badqid(self):
+        # the QID mismatch would internally trigger a XfrinException exception,
+        # and covers part of the code that other tests can't.
+        self.soa_response_params['bad_qid'] = True
+        self.conn.response_generator = self._create_soa_response_data
+        self.assertEqual(self.conn.do_xfrin(True), XFRIN_FAIL)
+
+    def _handle_xfrin_response(self):
+        # This helper methods iterates over all RRs (excluding the ending SOA)
+        # transferred, and simply returns the number of RRs.  The return value
+        # may be used an assertion value for test cases.
+        rrs = 0
+        for rr in self.conn._handle_xfrin_response():
+            rrs += 1
+        return rrs
+
+    def _create_normal_response_data(self):
+        # This helper method creates a simple sequence of DNS messages that
+        # forms a valid XFR transaction.  It consists of two messages, each
+        # containing just a single SOA RR.
+        self.conn.reply_data = self.conn.create_response_data()
+        self.conn.reply_data += self.conn.create_response_data()
+
+    def _create_soa_response_data(self):
+        # This helper method creates a DNS message that is supposed to be
+        # used a valid response to SOA queries prior to XFR.
+        # If axfr_after_soa is True, it resets the response_generator so that
+        # a valid XFR messages will follow.
+        self.conn.reply_data = self.conn.create_response_data(
+            bad_qid=self.soa_response_params['bad_qid'],
+            response=self.soa_response_params['response'],
+            rcode=self.soa_response_params['rcode'],
+            questions=self.soa_response_params['questions'])
+        if self.soa_response_params['axfr_after_soa'] != None:
+            self.conn.response_generator = self.soa_response_params['axfr_after_soa']
+
+    def _create_broken_response_data(self):
+        # This helper method creates a bogus "DNS message" that only contains
+        # 4 octets of data.  The DNS message parser will raise an exception.
+        bogus_data = b'xxxx'
+        self.conn.reply_data = struct.pack('H', socket.htons(len(bogus_data)))
+        self.conn.reply_data += bogus_data
+
+class TestXfrinRecorder(unittest.TestCase):
+    def setUp(self):
+        self.recorder = XfrinRecorder()
+
+    def test_increment(self):
+        self.assertEqual(self.recorder.count(), 0)
+        self.recorder.increment(TEST_ZONE_NAME)
+        self.assertEqual(self.recorder.count(), 1)
+        # duplicate "increment" should probably be rejected.  but it's not
+        # checked at this moment
+        self.recorder.increment(TEST_ZONE_NAME)
+        self.assertEqual(self.recorder.count(), 2)
+
+    def test_decrement(self):
+        self.assertEqual(self.recorder.count(), 0)
+        self.recorder.increment(TEST_ZONE_NAME)
+        self.assertEqual(self.recorder.count(), 1)
+        self.recorder.decrement(TEST_ZONE_NAME)
+        self.assertEqual(self.recorder.count(), 0)
+
+    def test_decrement_from_empty(self):
+        self.assertEqual(self.recorder.count(), 0)
+        self.recorder.decrement(TEST_ZONE_NAME)
+        self.assertEqual(self.recorder.count(), 0)
+
+    def test_inprogress(self):
+        self.assertEqual(self.recorder.count(), 0)
+        self.recorder.increment(TEST_ZONE_NAME)
+        self.assertEqual(self.recorder.xfrin_in_progress(TEST_ZONE_NAME), True)
+        self.recorder.decrement(TEST_ZONE_NAME)
+        self.assertEqual(self.recorder.xfrin_in_progress(TEST_ZONE_NAME), False)
 
 class TestXfrin(unittest.TestCase):
+    def setUp(self):
+        self.xfr = MockXfrin()
+        self.args = {}
+        self.args['zone_name'] = TEST_ZONE_NAME
+        self.args['port'] = TEST_MASTER_PORT
+        self.args['master'] = TEST_MASTER_IPV4_ADDRESS
+        self.args['db_file'] = TEST_DB_FILE
+
+    def tearDown(self):
+        self.xfr.shutdown()
+
+    def _do_parse(self):
+        return self.xfr._parse_cmd_params(self.args)
+
     def test_parse_cmd_params(self):
-        xfr = MyXfrin()
-        args = {}
-        args['zone_name'] = 'sd.cn.'
-        args['port'] = '12345'
-        args['master'] = '218.241.108.122'
-        args['db_file'] = '/home/tt'
-
-        name, master, port, db_file = xfr._parse_cmd_params(args)
-        self.assertEqual(port, 12345)
-        self.assertEqual(name, 'sd.cn.')
-        self.assertEqual(master, '218.241.108.122')
-        self.assertEqual(db_file, '/home/tt')
-
-    def test_parse_cmd_params_1(self):
-        xfr = MyXfrin()
-        args = {}
-        args['port'] = '12345'
-        args['master'] = '218.241.108.122'
-        args['db_file'] = '/home/tt'
-
-        self.assertRaises(XfrinException, xfr._parse_cmd_params, args)
-        self.assertRaises(XfrinException, xfr._parse_cmd_params, {'zone_name':'ds.cn.', 'master':'3.3.3'})
-        self.assertRaises(XfrinException, xfr._parse_cmd_params, {'zone_name':'ds.cn.'})
-        self.assertRaises(XfrinException, xfr._parse_cmd_params, {'master':'ds.cn.'})
+        name, master_addrinfo, db_file = self._do_parse()
+        self.assertEqual(master_addrinfo[4][1], int(TEST_MASTER_PORT))
+        self.assertEqual(name, TEST_ZONE_NAME)
+        self.assertEqual(master_addrinfo[4][0], TEST_MASTER_IPV4_ADDRESS)
+        self.assertEqual(db_file, TEST_DB_FILE)
+
+    def test_parse_cmd_params_default_port(self):
+        del self.args['port']
+        master_addrinfo = self._do_parse()[1]
+        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()[1]
+        self.assertEqual(master_addrinfo[4][0], TEST_MASTER_IPV6_ADDRESS)
+
+    def test_parse_cmd_params_nozone(self):
+        # zone name is mandatory.
+        del self.args['zone_name']
+        self.assertRaises(XfrinException, self._do_parse)
+
+    def test_parse_cmd_params_nomaster(self):
+        # master address is mandatory.
+        del self.args['master']
+        self.assertRaises(XfrinException, self._do_parse)
+
+    def test_parse_cmd_params_bad_ip4(self):
+        self.args['master'] = '3.3.3.3.3'
+        self.assertRaises(XfrinException, self._do_parse)
+
+    def test_parse_cmd_params_bad_ip6(self):
+        self.args['master'] = '1::1::1'
+        self.assertRaises(XfrinException, self._do_parse)
+
+    def test_parse_cmd_params_bad_port(self):
+        self.args['port'] = '-1'
+        self.assertRaises(XfrinException, self._do_parse)
+
+        self.args['port'] = '65536'
+        self.assertRaises(XfrinException, self._do_parse)
+
+        self.args['port'] = 'http'
+        self.assertRaises(XfrinException, self._do_parse)
+
+    def test_command_handler_shutdown(self):
+        self.assertEqual(self.xfr.command_handler("shutdown",
+                                                  None)['result'][0], 0)
+        # shutdown command doesn't expect an argument, but accepts it if any.
+        self.assertEqual(self.xfr.command_handler("shutdown",
+                                                  "unused")['result'][0], 0)
+
+    def test_command_handler_retransfer(self):
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  self.args)['result'][0], 0)
+
+    def test_command_handler_retransfer_badcommand(self):
+        self.args['master'] = 'invalid'
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  self.args)['result'][0], 1)
+
+    def test_command_handler_retransfer_quota(self):
+        for i in range(self.xfr._max_transfers_in - 1):
+            self.xfr.recorder.increment(str(i) + TEST_ZONE_NAME)
+        # there can be one more outstanding transfer.
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  self.args)['result'][0], 0)
+        # make sure the # xfrs would excceed the quota
+        self.xfr.recorder.increment(str(self.xfr._max_transfers_in) + TEST_ZONE_NAME)
+        # this one should fail
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  self.args)['result'][0], 1)
+
+    def test_command_handler_retransfer_inprogress(self):
+        self.xfr.recorder.increment(TEST_ZONE_NAME)
+        self.assertEqual(self.xfr.command_handler("retransfer",
+                                                  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']
+        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
+
+    def test_command_handler_refresh(self):
+        # at this level, refresh is no different than retransfer.
+        # just confirm the successful case with a different family of address.
+        self.args['master'] = TEST_MASTER_IPV6_ADDRESS
+        self.assertEqual(self.xfr.command_handler("refresh",
+                                                  self.args)['result'][0], 0)
+
+    def test_command_handler_unknown(self):
+        self.assertEqual(self.xfr.command_handler("xxx", None)['result'][0], 1)
+
+def raise_interrupt():
+    raise KeyboardInterrupt()
+
+def raise_ccerror():
+    raise isc.cc.session.SessionError('test error')
+
+def raise_excpetion():
+    raise Exception('test exception')
+
+class TestMain(unittest.TestCase):
+    def setUp(self):
+        MockXfrin.check_command_hook = None
+
+    def tearDown(self):
+        MockXfrin.check_command_hook = None
+
+    def test_startup(self):
+        main(MockXfrin, False)
+
+    def test_startup_interrupt(self):
+        MockXfrin.check_command_hook = raise_interrupt
+        main(MockXfrin, False)
+
+    def test_startup_ccerror(self):
+        MockXfrin.check_command_hook = raise_ccerror
+        main(MockXfrin, False)
+
+    def test_startup_generalerror(self):
+        MockXfrin.check_command_hook = raise_excpetion
+        main(MockXfrin, False)
 
 if __name__== "__main__":
     try:
         unittest.main()
-        os.remove(DB_FILE)
     except KeyboardInterrupt as e:
         print(e)
-

Modified: experiments/python-binding/src/bin/xfrin/xfrin.py.in
==============================================================================
--- experiments/python-binding/src/bin/xfrin/xfrin.py.in (original)
+++ experiments/python-binding/src/bin/xfrin/xfrin.py.in Wed Jun  9 09:52:34 2010
@@ -35,11 +35,11 @@
     # must keep running, so we warn about it and move forward.
     sys.stderr.write('[b10-xfrin] failed to import DNS module: %s\n' % str(e))
 
-# If B10_FROM_SOURCE is set in the environment, we use data files
+# If B10_FROM_BUILD is set in the environment, we use data files
 # from a directory relative to that, otherwise we use the ones
 # installed on the system
-if "B10_FROM_SOURCE" in os.environ:
-    SPECFILE_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/xfrin"
+if "B10_FROM_BUILD" in os.environ:
+    SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrin"
 else:
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
@@ -50,11 +50,12 @@
 __version__ = 'BIND10'
 # define xfrin rcode
 XFRIN_OK = 0
+XFRIN_FAIL = 1
+
+DEFAULT_MASTER_PORT = '53'
 
 def log_error(msg):
-    sys.stderr.write("[b10-xfrin] ")
-    sys.stderr.write(str(msg))
-    sys.stderr.write('\n')
+    sys.stderr.write("[b10-xfrin] %s\n" % str(msg))
 
 class XfrinException(Exception): 
     pass
@@ -62,50 +63,49 @@
 class XfrinConnection(asyncore.dispatcher):
     '''Do xfrin in this class. '''    
 
-    def __init__(self, 
-                 zone_name, db_file, shutdown_event, master_addr, 
-                 port = 53, verbose = False, idle_timeout = 60): 
+    def __init__(self,
+                 sock_map, zone_name, rrclass, db_file, shutdown_event,
+                 master_addrinfo, verbose = False, idle_timeout = 60): 
         ''' idle_timeout: max idle time for read data from socket.
             db_file: specify the data source file.
             check_soa: when it's true, check soa first before sending xfr query
         '''
 
-        asyncore.dispatcher.__init__(self)
-        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+        asyncore.dispatcher.__init__(self, map=sock_map)
+        self.create_socket(master_addrinfo[0], master_addrinfo[1])
         self._zone_name = zone_name
+        self._sock_map = sock_map
+        self._rrclass = rrclass
         self._db_file = db_file
         self._soa_rr_count = 0
         self._idle_timeout = idle_timeout
         self.setblocking(1)
         self._shutdown_event = shutdown_event
         self._verbose = verbose
-        self._master_addr = master_addr
-        self._port = port
+        self._master_address = master_addrinfo[4]
 
     def connect_to_master(self):
         '''Connect to master in TCP.'''
 
         try:
-            self.connect((self._master_addr, self._port))
+            self.connect(self._master_address)
             return True
         except socket.error as e:
-            self.log_msg('Failed to connect:(%s:%d), %s' % (self._master_addr, self._port, str(e)))
+            self.log_msg('Failed to connect:(%s), %s' % (self._master_address,
+                                                            str(e)))
             return False
 
     def _create_query(self, query_type):
         '''Create dns query message. '''
 
         msg = Message(Message.RENDER)
-        query_id = random.randint(1, 0xFFFF)
+        query_id = random.randint(0, 0xFFFF)
         self._query_id = query_id
         msg.set_qid(query_id)
         msg.set_opcode(Opcode.QUERY())
         msg.set_rcode(Rcode.NOERROR())
-        query_question = Question(Name(self._zone_name), RRClass("IN"), query_type)
-        try:
-            msg.add_question(query_question)
-        except Exception as err:
-            raise err
+        query_question = Question(Name(self._zone_name), self._rrclass, query_type)
+        msg.add_question(query_question)
         return msg
 
     def _send_data(self, data):
@@ -125,6 +125,13 @@
 
         self._send_data(header_len)
         self._send_data(render.get_data())
+
+    def _asyncore_loop(self):
+        '''
+        This method is a trivial wrapper for asyncore.loop().  It's extracted from
+        _get_request_response so that we can test the rest of the code without
+        involving actual communication with a remote server.'''
+        asyncore.loop(self._idle_timeout, map=self._sock_map, count=1)
     
     def _get_request_response(self, size):
         recv_size = 0
@@ -132,7 +139,7 @@
         while recv_size < size:
             self._recv_time_out = True
             self._need_recv_size = size - recv_size
-            asyncore.loop(self._idle_timeout, count = 1)
+            self._asyncore_loop()
             if self._recv_time_out:
                 raise XfrinException('receive data from socket time out.')
 
@@ -149,10 +156,19 @@
         '''
 
         self._send_query(RRType("SOA"))
-        data_size = self._get_request_response(2)
-        soa_reply = self._get_request_response(int(data_size))
-        #TODO, need select soa record from data source then compare the two 
-        #serial, current just return OK, since this function hasn't been used now 
+        data_len = self._get_request_response(2)
+        msg_len = socket.htons(struct.unpack('H', data_len)[0])
+        soa_response = self._get_request_response(msg_len)
+        msg = Message(Message.PARSE)
+        msg.from_wire(soa_response)
+
+        # perform some minimal level validation.  It's an open issue how
+        # strict we should be (see the comment in _check_response_header())
+        self._check_response_header(msg)
+
+        # TODO, need select soa record from data source then compare the two 
+        # serial, current just return OK, since this function hasn't been used
+        # now.
         return XFRIN_OK
 
     def do_xfrin(self, check_soa, ixfr_first = False):
@@ -161,6 +177,7 @@
         try:
             ret = XFRIN_OK
             if check_soa:
+                logstr = 'SOA check for \'%s\' ' % self._zone_name
                 ret =  self._check_soa_serial()
 
             logstr = 'transfer of \'%s\': AXFR ' % self._zone_name
@@ -172,23 +189,41 @@
                                             self._handle_xfrin_response)
 
                 self.log_msg(logstr + 'succeeded')
+                ret = XFRIN_OK
 
         except XfrinException as e:
             self.log_msg(e)
             self.log_msg(logstr + 'failed')
+            ret = XFRIN_FAIL
             #TODO, recover data source.
         except isc.datasrc.sqlite3_ds.Sqlite3DSError as e:
             self.log_msg(e)
             self.log_msg(logstr + 'failed')
+            ret = XFRIN_FAIL
+        except UserWarning as e:
+            # XXX: this is an exception from our C++ library via the
+            # Boost.Python binding.  It would be better to have more more
+            # specific exceptions, but at this moment this is the finest
+            # granularity.
+            self.log_msg(e)
+            self.log_msg(logstr + 'failed')
+            ret = XFRIN_FAIL
         finally:
            self.close()
 
         return ret
-    
-    def _check_response_status(self, msg):
-        '''Check validation of xfr response. '''
-
-        #TODO, check more?
+
+    def _check_response_header(self, msg):
+        '''Perform minimal validation on responses'''
+
+        # It's not clear how strict we should be about response validation.
+        # BIND 9 ignores some cases where it would normally be considered a
+        # bogus response.  For example, it accepts a response even if its
+        # opcode doesn't match that of the corresponding request.
+        # According to an original developer of BIND 9 some of the missing
+        # checks are deliberate to be kind to old implementations that would
+        # cause interoperability trouble with stricter checks.
+
         msg_rcode = msg.get_rcode()
         if msg_rcode != Rcode.NOERROR():
             raise XfrinException('error response: %s' % msg_rcode.to_text())
@@ -198,6 +233,11 @@
 
         if msg.get_qid() != self._query_id:
             raise XfrinException('bad query id')
+
+    def _check_response_status(self, msg):
+        '''Check validation of xfr response. '''
+
+        self._check_response_header(msg)
 
         if msg.get_rr_count(Section.ANSWER()) == 0:
             raise XfrinException('answer section is empty')
@@ -270,24 +310,22 @@
 
     def log_msg(self, msg):
         if self._verbose:
-            sys.stdout.write('[b10-xfrin] ')
-            sys.stdout.write(str(msg))
-            sys.stdout.write('\n')
-
-
-def process_xfrin(xfrin_recorder, zone_name, db_file, 
-                  shutdown_event, master_addr, port, check_soa, verbose):
-    port = int(port)
+            sys.stdout.write('[b10-xfrin] %s\n' % str(msg))
+
+
+def process_xfrin(xfrin_recorder, zone_name, rrclass, db_file, 
+                  shutdown_event, master_addrinfo, check_soa, verbose):
     xfrin_recorder.increment(zone_name)
-    conn = XfrinConnection(zone_name, db_file, shutdown_event, 
-                           master_addr, port, verbose)
+    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)
 
     xfrin_recorder.decrement(zone_name)
 
 
-class XfrinRecorder():
+class XfrinRecorder:
     def __init__(self):
         self._lock = threading.Lock()
         self._zones = []
@@ -315,15 +353,31 @@
         self._lock.release()
         return ret
 
-class Xfrin():
+class Xfrin:
     def __init__(self, verbose = False):
-        self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
-        self._cc.start()
+        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,
+                                              self.config_handler,
+                                              self.command_handler)
+        self._cc.start()
+
+    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()
 
     def config_handler(self, new_config):
         # TODO, process new config data
@@ -343,20 +397,20 @@
 
     def command_handler(self, command, args):
         answer = create_answer(0)
-        cmd = command
         try:
-            if cmd == 'shutdown':
+            if command == 'shutdown':
                 self._shutdown_event.set()
-
-            elif cmd == 'retransfer':
-                zone_name, master, port, db_file = self._parse_cmd_params(args)
-                ret = self.xfrin_start(zone_name, db_file, master, port, False)
+            elif command == 'retransfer' or command == 'refresh':
+                # The default RR class is IN.  We should fix this so that
+                # the class is passed in the command arg (where we specify
+                # the default)
+                rrclass = RRClass.IN()
+                zone_name, master_addr, db_file = self._parse_cmd_params(args)
+                ret = self.xfrin_start(zone_name, rrclass, db_file, master_addr,
+                                   False if command == 'retransfer' else True)
                 answer = create_answer(ret[0], ret[1])
-
-            elif cmd == 'refresh':
-                zone_name, master, port, db_file = self._parse_cmd_params(args)
-                ret = self.xfrin_start(zone_name, db_file, master, port)
-                answer = create_answer(ret[0], ret[1])
+            else:
+                answer = create_answer(1, 'unknown command: ' + command)
 
         except XfrinException as err:
             answer = create_answer(1, str(err))
@@ -372,28 +426,23 @@
         if not master:
             raise XfrinException('master address should be provided')
 
-        check_addr(master)
-        port = 53
         port_str = args.get('port')
-        if port_str:
-            port = int(port_str)
-            check_port(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
             db_file = '@@LOCALSTATEDIR@@/@PACKAGE@/zone.sqlite3'
 
-        return (zone_name, master, port, db_file)
-            
+        return (zone_name, master_addrinfo, db_file)
 
     def startup(self):
         while not self._shutdown_event.is_set():
-            self._cc.check_command()
-
-
-    def xfrin_start(self, zone_name, db_file, master_addr, 
-                    port = 53, 
+            self._cc_check_command()
+
+    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'")
@@ -407,12 +456,12 @@
 
         xfrin_thread = threading.Thread(target = process_xfrin,
                                         args = (self.recorder,
-                                                zone_name,
+                                                zone_name, rrclass,
                                                 db_file,
                                                 self._shutdown_event,
-                                                master_addr,
-                                                port, check_soa, self._verbose))
-                                                
+                                                master_addrinfo, check_soa,
+                                                self._verbose))
+
         xfrin_thread.start()
         return (0, 'zone xfrin is started')
 
@@ -428,34 +477,53 @@
     signal.signal(signal.SIGTERM, signal_handler)
     signal.signal(signal.SIGINT, signal_handler)
 
-def check_port(value):
-    if (value < 0) or (value > 65535):
-        raise XfrinException('requires a port number (0-65535)')
-
-def check_addr(ipstr):
-    ip_family = socket.AF_INET
-    if (ipstr.find(':') != -1):
-        ip_family = socket.AF_INET6
-
+def check_addr_port(addrstr, portstr):
+    # XXX: Linux (glibc)'s getaddrinfo incorrectly accepts numeric port
+    # string larger than 65535.  So we need to explicit validate it separately.
     try:
-        socket.inet_pton(ip_family, ipstr)
-    except:
-        raise XfrinException("%s invalid ip address" % ipstr)
-
+        portnum = int(portstr)
+        if portnum < 0 or portnum > 65535:
+            raise ValueError("invalid port number (out of range): " + portstr)
+    except ValueError as err:
+        raise XfrinException("failed to resolve master address/port=%s/%s: %s" %
+                             (addrstr, portstr, str(err)))
+
+    try:
+        addrinfo = socket.getaddrinfo(addrstr, portstr, socket.AF_UNSPEC,
+                                      socket.SOCK_STREAM, socket.IPPROTO_TCP,
+                                      socket.AI_NUMERICHOST|
+                                      socket.AI_NUMERICSERV)
+    except socket.gaierror as err:
+        raise XfrinException("failed to resolve master address/port=%s/%s: %s" %
+                             (addrstr, portstr, str(err)))
+    if len(addrinfo) != 1:
+        # with the parameters above the result must be uniquely determined.
+        errmsg = "unexpected result for address/port resolution for %s:%s"
+        raise XfrinException(errmsg % (addrstr, portstr))
+    return addrinfo[0]
 
 def set_cmd_options(parser):
     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
             help="display more about what is going on")
 
-    
-if __name__ == '__main__':
+def main(xfrin_class, use_signal = True):
+    """The main loop of the Xfrin daemon.
+
+    @param xfrin_class: A class of the Xfrin object.  This is normally Xfrin,
+    but can be a subclass of it for customization.
+    @param use_signal: True if this process should catch signals.  This is
+    normally True, but may be disabled when this function is called in a
+    testing context."""
+    global xfrind
+
     try:
         parser = OptionParser(version = __version__)
         set_cmd_options(parser)
         (options, args) = parser.parse_args()
 
-        set_signal_handler()
-        xfrind = Xfrin(verbose = options.verbose)
+        if use_signal:
+            set_signal_handler()
+        xfrind = xfrin_class(verbose = options.verbose)
         xfrind.startup()
     except KeyboardInterrupt:
         log_error("exit b10-xfrin")
@@ -467,3 +535,6 @@
 
     if xfrind:
         xfrind.shutdown()
+
+if __name__ == '__main__':
+    main(Xfrin)

Modified: experiments/python-binding/src/bin/xfrin/xfrin.spec.pre.in
==============================================================================
--- experiments/python-binding/src/bin/xfrin/xfrin.spec.pre.in (original)
+++ experiments/python-binding/src/bin/xfrin/xfrin.spec.pre.in Wed Jun  9 09:52:34 2010
@@ -1,6 +1,7 @@
 {
   "module_spec": {
     "module_name": "Xfrin",
+    "module_description": "XFR in daemon",
     "config_data": [
       {
         "item_name": "transfers_in",
@@ -47,5 +48,3 @@
     ]
   }
 }
-
-

Modified: experiments/python-binding/src/bin/xfrout/tests/xfrout_test.py
==============================================================================
--- experiments/python-binding/src/bin/xfrout/tests/xfrout_test.py (original)
+++ experiments/python-binding/src/bin/xfrout/tests/xfrout_test.py Wed Jun  9 09:52:34 2010
@@ -276,6 +276,70 @@
         self.unix.decrease_transfers_counter()
         self.assertEqual(count - 1, self.unix._transfers_counter)
 
+    def _remove_file(self, sock_file):
+        try:
+            os.remove(sock_file)
+        except OSError:
+            pass
+ 
+    def test_sock_file_in_use_file_exist(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self.assertFalse(os.path.exists(sock_file))
+
+    def test_sock_file_in_use_file_not_exist(self):
+        self.assertFalse(self.unix._sock_file_in_use('temp.sock.file'))
+
+    def _start_unix_sock_server(self, sock_file):
+        serv = ThreadingUnixStreamServer(sock_file, BaseRequestHandler)
+        serv_thread = threading.Thread(target=serv.serve_forever)
+        serv_thread.setDaemon(True)
+        serv_thread.start()
+
+    def test_sock_file_in_use(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self._start_unix_sock_server(sock_file)
+
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        self.assertTrue(self.unix._sock_file_in_use(sock_file))
+        sys.stdout = old_stdout
+
+    def test_remove_unused_sock_file_in_use(self):
+        sock_file = 'temp.sock.file'
+        self._remove_file(sock_file)
+        self.assertFalse(self.unix._sock_file_in_use(sock_file))
+        self._start_unix_sock_server(sock_file)
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        try:
+            self.unix._remove_unused_sock_file(sock_file)
+        except SystemExit:
+            pass
+        else:
+            # This should never happen
+            self.assertTrue(False)
+
+        sys.stdout = old_stdout
+
+    def test_remove_unused_sock_file_dir(self):
+        import tempfile
+        dir_name = tempfile.mkdtemp()
+        old_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+        try:
+            self.unix._remove_unused_sock_file(dir_name)
+        except SystemExit:
+            pass
+        else:
+            # This should never happen
+            self.assertTrue(False)
+
+        sys.stdout = old_stdout
+        os.rmdir(dir_name)
 
 if __name__== "__main__":
     unittest.main()

Modified: experiments/python-binding/src/bin/xfrout/xfrout.py.in
==============================================================================
--- experiments/python-binding/src/bin/xfrout/xfrout.py.in (original)
+++ experiments/python-binding/src/bin/xfrout/xfrout.py.in Wed Jun  9 09:52:34 2010
@@ -28,6 +28,7 @@
 from isc.config.ccsession import *
 from isc.cc import SessionError
 import socket
+import errno
 from optparse import OptionParser, OptionValueError
 try:
     from libxfr_python import *
@@ -37,14 +38,14 @@
     # must keep running, so we warn about it and move forward.
     sys.stderr.write('[b10-xfrout] failed to import DNS or XFR module: %s\n' % str(e))
 
-if "B10_FROM_SOURCE" in os.environ:
-    SPECFILE_PATH = os.environ["B10_FROM_SOURCE"] + "/src/bin/xfrout"
+if "B10_FROM_BUILD" in os.environ:
+    SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
     UNIX_SOCKET_FILE = os.environ["B10_FROM_SOURCE"] + "/auth_xfrout_conn"
 else:
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
     SPECFILE_PATH = "@datadir@/@PACKAGE@".replace("${datarootdir}", DATAROOTDIR).replace("${prefix}", PREFIX)
-    UNIX_SOCKET_FILE = "@localstatedir@".replace("${prefix}", PREFIX) + "/auth_xfrout_conn"
+    UNIX_SOCKET_FILE = "@@LOCALSTATEDIR@@/auth_xfrout_conn"
 SPECFILE_LOCATION = SPECFILE_PATH + "/xfrout.spec"
 
 MAX_TRANSFERS_OUT = 10
@@ -59,7 +60,13 @@
         fd = recv_fd(self.request.fileno())
         
         if fd < 0:
-            raise XfroutException("failed to receive the FD for XFR connection")
+            # This may happen when one xfrout process try to connect to
+            # xfrout unix socket server, to check whether there is another
+            # xfrout running. 
+            print("[b10-xfrout] Failed to receive the FD for XFR connection, "
+                  "maybe because another xfrout process was started.")
+            return
+
         data_len = self.request.recv(2)
         msg_len = struct.unpack('!H', data_len)[0]
         msgdata = self.request.recv(msg_len)
@@ -182,7 +189,7 @@
                 self.log_msg("transfer of '%s/IN': AXFR end" % zone_name)
         except TmpException as err:
             if verbose_mode:
-                sys.stderr.write(str(err))
+                sys.stderr.write("[b10-xfrout] %s\n" % str(err))
 
         self.server.decrease_transfers_counter()
         return    
@@ -282,18 +289,44 @@
     '''The unix domain socket server which accept xfr query sent from auth server.'''
 
     def __init__(self, sock_file, handle_class, shutdown_event, config_data):
-        try:
-            os.unlink(sock_file)
-        except:
-            pass
- 
+        self._remove_unused_sock_file(sock_file)
         self._sock_file = sock_file
         ThreadingUnixStreamServer.__init__(self, sock_file, handle_class)
         self._lock = threading.Lock()
         self._transfers_counter = 0
         self._shutdown_event = shutdown_event
         self.update_config_data(config_data)
-    
+
+    def _remove_unused_sock_file(self, sock_file):
+        '''Try to remove the socket file. If the file is being used 
+        by one running xfrout process, exit from python. 
+        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.exit(0)
+        else:
+            if not os.path.exists(sock_file):
+                return
+
+            try:
+                os.unlink(sock_file)
+            except OSError as err:
+                print('[b10-xfrout] Fail to remove file ' + sock_file, err)
+                sys.exit(0)
+   
+    def _sock_file_in_use(self, sock_file):
+        '''Check whether the socket file 'sock_file' exists and 
+        is being used by one running xfrout process. If it is, 
+        return True, or else return False. '''
+        try:
+            sock = socket.socket(socket.AF_UNIX)
+            sock.connect(sock_file)
+        except socket.error as err:
+            return False
+        else:
+            return True 
 
     def shutdown(self):
         ThreadingUnixStreamServer.shutdown(self)
@@ -396,7 +429,7 @@
     def command_handler(self, cmd, args):
         if cmd == "shutdown":
             if verbose_mode:
-                log_msg("Received shutdown command")
+                print("[b10-xfrout] Received shutdown command")
             self.shutdown()
             answer = create_answer(0)
         else: 

Modified: experiments/python-binding/src/lib/cc/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/cc/Makefile.am (original)
+++ experiments/python-binding/src/lib/cc/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,19 +1,36 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+# ASIO header files used in session.cc will trigger "unused-parameter"
+# error.  Unfortunately there doesn't seem to be an easy way to selectively
+# avoid the error.  As a short term workaround we suppress this warning
+# for the entire this module.  See also src/bin/auth/Makefile.am.
+AM_CXXFLAGS += -Wno-unused-parameter
 
 lib_LIBRARIES = libcc.a
 libcc_a_SOURCES = data.cc data.h session.cc session.h
 
-CLEANFILES = *.gcno *.gcda
+CLEANFILES = *.gcno *.gcda session_config.h
+
+session_config.h: session_config.h.pre
+	$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" session_config.h.pre >$@
+
+BUILT_SOURCES = session_config.h 
 
 TESTS =
 if HAVE_GTEST
 TESTS += run_unittests
-run_unittests_SOURCES = data_unittests.cc run_unittests.cc
+# (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)
-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 = libcc.a $(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: experiments/python-binding/src/lib/cc/data.cc
==============================================================================
--- experiments/python-binding/src/lib/cc/data.cc (original)
+++ experiments/python-binding/src/lib/cc/data.cc Wed Jun  9 09:52:34 2010
@@ -204,47 +204,27 @@
 //
 ElementPtr
 Element::create(const int i) {
-    try {
-        return ElementPtr(new IntElement(i));
-    } catch (std::bad_alloc) {
-        return ElementPtr();
-    }
+    return ElementPtr(new IntElement(i));
 }
 
 ElementPtr
 Element::create(const double d) {
-    try {
-        return ElementPtr(new DoubleElement(d));
-    } catch (std::bad_alloc) {
-        return ElementPtr();
-    }
+    return ElementPtr(new DoubleElement(d));
 }
 
 ElementPtr
 Element::create(const std::string& s) {
-    try {
-        return ElementPtr(new StringElement(s));
-    } catch (std::bad_alloc) {
-        return ElementPtr();
-    }
+    return ElementPtr(new StringElement(s));
 }
 
 ElementPtr
 Element::create(const bool b) {
-    try {
-        return ElementPtr(new BoolElement(b));
-    } catch (std::bad_alloc) {
-        return ElementPtr();
-    }
+    return ElementPtr(new BoolElement(b));
 }
 
 ElementPtr
 Element::create(const std::vector<ElementPtr>& v) {
-    try {
-        return ElementPtr(new ListElement(v));
-    } catch (std::bad_alloc) {
-        return ElementPtr();
-    }
+    return ElementPtr(new ListElement(v));
 }
 
 ElementPtr
@@ -255,11 +235,7 @@
             isc_throw(TypeError, "Map tag is too long");
         }
     }
-    try {
-        return ElementPtr(new MapElement(m));
-    } catch (std::bad_alloc) {
-        return ElementPtr();
-    }
+    return ElementPtr(new MapElement(m));
 }
 
 

Modified: experiments/python-binding/src/lib/cc/session.cc
==============================================================================
--- experiments/python-binding/src/lib/cc/session.cc (original)
+++ experiments/python-binding/src/lib/cc/session.cc Wed Jun  9 09:52:34 2010
@@ -14,7 +14,8 @@
 
 // $Id$
 
-#include "config.h"
+#include <config.h>
+#include "session_config.h"
 
 #include <stdint.h>
 
@@ -23,11 +24,14 @@
 #include <iostream>
 #include <sstream>
 
-#ifdef HAVE_BOOST_SYSTEM
+#include <sys/un.h>
+
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
-#include <boost/asio.hpp>
-#endif
+
+#include <asio.hpp>
+#include <asio/error_code.hpp>
+#include <asio/system_error.hpp>
 
 #include <exceptions/exceptions.h>
 
@@ -38,12 +42,10 @@
 using namespace isc::cc;
 using namespace isc::data;
 
-#ifdef HAVE_BOOST_SYSTEM
-// some of the boost::asio names conflict with socket API system calls
-// (e.g. write(2)) so we don't import the entire boost::asio namespace.
-using boost::asio::io_service;
-using boost::asio::ip::tcp;
-#endif
+// some of the asio names conflict with socket API system calls
+// (e.g. write(2)) so we don't import the entire asio namespace.
+using asio::io_service;
+using asio::ip::tcp;
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -54,27 +56,27 @@
 
 class SessionImpl {
 public:
-    SessionImpl() : sequence_(-1) {}
+    SessionImpl() : sequence_(-1) { queue_ = Element::createFromString("[]"); }
     virtual ~SessionImpl() {}
-    virtual void establish() = 0; 
+    virtual void establish(const char& socket_file) = 0;
     virtual int getSocket() = 0;
     virtual void disconnect() = 0;
     virtual void writeData(const void* data, size_t datalen) = 0;
     virtual size_t readDataLength() = 0;
     virtual void readData(void* data, size_t datalen) = 0;
     virtual void startRead(boost::function<void()> user_handler) = 0;
-
+    
     int sequence_; // the next sequence number to use
     std::string lname_;
+    ElementPtr queue_;
 };
 
-#ifdef HAVE_BOOST_SYSTEM
 class ASIOSession : public SessionImpl {
 public:
     ASIOSession(io_service& io_service) :
         io_service_(io_service), socket_(io_service_), data_length_(0)
     {}
-    virtual void establish();
+    virtual void establish(const char& socket_file);
     virtual void disconnect();
     virtual int getSocket() { return (socket_.native()); }
     virtual void writeData(const void* data, size_t datalen);
@@ -82,23 +84,28 @@
     virtual void readData(void* data, size_t datalen);
     virtual void startRead(boost::function<void()> user_handler);
 private:
-    void internalRead(const boost::system::error_code& error,
+    void internalRead(const asio::error_code& error,
                       size_t bytes_transferred);
 
 private:
     io_service& io_service_;
-    tcp::socket socket_;
+    asio::local::stream_protocol::socket socket_;
     uint32_t data_length_;
     boost::function<void()> user_handler_;
-    boost::system::error_code error_;
+    asio::error_code error_;
 };
 
-void
-ASIOSession::establish() {
-    socket_.connect(tcp::endpoint(boost::asio::ip::address_v4::loopback(),
-                                  9912), error_);
+
+
+void
+ASIOSession::establish(const char& socket_file) {
+    try {
+        socket_.connect(asio::local::stream_protocol::endpoint(&socket_file), error_);
+    } catch (asio::system_error& se) {
+        isc_throw(SessionError, se.what());
+    }
     if (error_) {
-        isc_throw(SessionError, "Unable to connect to message queue");
+        isc_throw(SessionError, "Unable to connect to message queue.");
     }
 }
 
@@ -111,9 +118,9 @@
 void
 ASIOSession::writeData(const void* data, size_t datalen) {
     try {
-        boost::asio::write(socket_, boost::asio::buffer(data, datalen));
-    } catch (const boost::system::system_error& boost_ex) {
-        isc_throw(SessionError, "ASIO write failed: " << boost_ex.what());
+        asio::write(socket_, asio::buffer(data, datalen));
+    } catch (const asio::system_error& asio_ex) {
+        isc_throw(SessionError, "ASIO write failed: " << asio_ex.what());
     }
 }
 
@@ -136,11 +143,11 @@
 void
 ASIOSession::readData(void* data, size_t datalen) {
     try {
-        boost::asio::read(socket_, boost::asio::buffer(data, datalen));
-    } catch (const boost::system::system_error& boost_ex) {
+        asio::read(socket_, asio::buffer(data, datalen));
+    } catch (const asio::system_error& asio_ex) {
         // to hide boost specific exceptions, we catch them explicitly
         // and convert it to SessionError.
-        isc_throw(SessionError, "ASIO read failed: " << boost_ex.what());
+        isc_throw(SessionError, "ASIO read failed: " << asio_ex.what());
     }
 }
 
@@ -148,15 +155,15 @@
 ASIOSession::startRead(boost::function<void()> user_handler) {
     data_length_ = 0;
     user_handler_ = user_handler;
-    async_read(socket_, boost::asio::buffer(&data_length_,
+    async_read(socket_, asio::buffer(&data_length_,
                                             sizeof(data_length_)),
                boost::bind(&ASIOSession::internalRead, this,
-                           boost::asio::placeholders::error,
-                           boost::asio::placeholders::bytes_transferred));
-}
-
-void
-ASIOSession::internalRead(const boost::system::error_code& error,
+                           asio::placeholders::error,
+                           asio::placeholders::bytes_transferred));
+}
+
+void
+ASIOSession::internalRead(const asio::error_code& error,
                           size_t bytes_transferred)
 {
     if (!error) {
@@ -170,14 +177,13 @@
         isc_throw(SessionError, "asynchronous read failed");
     }
 }
-#endif
 
 class SocketSession : public SessionImpl {
 public:
     SocketSession() : sock_(-1) {}
     virtual ~SocketSession() { disconnect(); }
     virtual int getSocket() { return (sock_); }
-    void establish();
+    void establish(const char& socket_file);
     virtual void disconnect()
     {
         if (sock_ >= 0) {
@@ -212,29 +218,25 @@
 }
 
 void
-SocketSession::establish() {
-    int s;
-    struct sockaddr_in sin;
-
-    s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+SocketSession::establish(const char& socket_file) {
+    struct sockaddr_un s_un;
+#ifdef HAVE_SA_LEN
+    s_un.sun_len = sizeof(struct sockaddr_un);
+#endif
+
+    if (strlen(&socket_file) >= sizeof(s_un.sun_path)) {
+        isc_throw(SessionError, "Unable to connect to message queue; "
+                  "socket file path too long: " << socket_file);
+    }
+    s_un.sun_family = AF_UNIX;
+    strncpy(s_un.sun_path, &socket_file, sizeof(s_un.sun_path) - 1);
+
+    int s = socket(AF_UNIX, SOCK_STREAM, 0);
     if (s < 0) {
         isc_throw(SessionError, "socket() failed");
     }
-    
-    int port = atoi(getenv("ISC_MSGQ_PORT"));
-    if (port == 0) {
-        port = 9912;
-    }
-
-    sin.sin_family = AF_INET;
-    sin.sin_port = htons(port);
-    sin.sin_addr.s_addr = INADDR_ANY;
-
-#ifdef HAVE_SIN_LEN
-    sin.sin_len = sizeof(struct sockaddr_in);
-#endif
-
-    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+
+    if (connect(s, (struct sockaddr *)&s_un, sizeof(s_un)) < 0) {
         close(s);
         isc_throw(SessionError, "Unable to connect to message queue");
     }
@@ -270,10 +272,8 @@
 Session::Session() : impl_(new SocketSession)
 {}
 
-#ifdef HAVE_BOOST_SYSTEM
 Session::Session(io_service& io_service) : impl_(new ASIOSession(io_service))
 {}
-#endif
 
 Session::~Session() {
     delete impl_;
@@ -295,8 +295,15 @@
 }
 
 void
-Session::establish() {
-    impl_->establish();
+Session::establish(const char* socket_file) {
+    if (socket_file == NULL) {
+        socket_file = getenv("BIND10_MSGQ_SOCKET_FILE");
+    }
+    if (socket_file == NULL) {
+        socket_file = BIND10_MSGQ_SOCKET_FILE;
+    }
+
+    impl_->establish(*socket_file);
 
     // once established, encapsulate the implementation object so that we
     // can safely release the internal resource when exception happens
@@ -314,7 +321,6 @@
     recvmsg(routing, msg, false);
 
     impl_->lname_ = msg->get("lname")->stringValue();
-    cout << "My local name is:  " << impl_->lname_ << endl;
 
     // At this point there's no risk of resource leak.
     session_holder.clear();
@@ -352,35 +358,35 @@
 }
 
 bool
-Session::recvmsg(ElementPtr& msg, bool nonblock UNUSED_PARAM) {
+Session::recvmsg(ElementPtr& msg, bool nonblock, int seq) {
+    ElementPtr l_env;
+    return recvmsg(l_env, msg, nonblock, seq);
+}
+
+bool
+Session::recvmsg(ElementPtr& env, ElementPtr& msg,
+                 bool nonblock, int seq) {
     size_t length = impl_->readDataLength();
-
-    unsigned short header_length_net;
-    impl_->readData(&header_length_net, sizeof(header_length_net));
-
-    unsigned short header_length = ntohs(header_length_net);
-    if (header_length != length) {
-        isc_throw(SessionError, "Length parameters invalid: total=" << length
-                  << ", header=" << header_length);
-    }
-
-    std::vector<char> buffer(length);
-    impl_->readData(&buffer[0], length);
-
-    std::string wire = std::string(&buffer[0], length);
-    std::stringstream wire_stream;
-    wire_stream << wire;
-
-    msg = Element::fromWire(wire_stream, length);
-
-    return (true);
-    // XXXMLG handle non-block here, and return false for short reads
-}
-
-bool
-Session::recvmsg(ElementPtr& env, ElementPtr& msg, bool nonblock UNUSED_PARAM) {
-    size_t length = impl_->readDataLength();
-
+    ElementPtr l_env, l_msg;
+    if (hasQueuedMsgs()) {
+        ElementPtr q_el;
+        for (int i = 0; i < impl_->queue_->size(); i++) {
+            q_el = impl_->queue_->get(i);
+            if (( seq == -1 &&
+                  !q_el->get(0)->contains("reply")
+                ) || (
+                  q_el->get(0)->contains("reply") &&
+                  q_el->get(0)->get("reply")->intValue() == seq
+                )
+               ) {
+                   env = q_el->get(0);
+                   msg = q_el->get(1);
+                   impl_->queue_->remove(i);
+                   return true;
+            }
+        }
+    }
+    
     unsigned short header_length_net;
     impl_->readData(&header_length_net, sizeof(header_length_net));
 
@@ -400,13 +406,28 @@
                                         length - header_length);
     std::stringstream header_wire_stream;
     header_wire_stream << header_wire;
-    env = Element::fromWire(header_wire_stream, header_length);
+    l_env = Element::fromWire(header_wire_stream, header_length);
     
     std::stringstream body_wire_stream;
     body_wire_stream << body_wire;
-    msg = Element::fromWire(body_wire_stream, length - header_length);
-
-    return (true);
+    l_msg = Element::fromWire(body_wire_stream, length - header_length);
+    if ((seq == -1 &&
+         !l_env->contains("reply")
+        ) || (
+         l_env->contains("reply") &&
+         l_env->get("reply")->intValue() == seq
+        )
+       ) {
+        env = l_env;
+        msg = l_msg;
+        return true;
+    } else {
+        ElementPtr q_el = Element::createFromString("[]");
+        q_el->add(l_env);
+        q_el->add(l_msg);
+        impl_->queue_->add(q_el);
+        return recvmsg(env, msg, nonblock, seq);
+    }
     // XXXMLG handle non-block here, and return false for short reads
 }
 
@@ -432,47 +453,55 @@
     sendmsg(env);
 }
 
-unsigned int
+int
 Session::group_sendmsg(ElementPtr msg, std::string group,
                        std::string instance, std::string to)
 {
     ElementPtr env = Element::create(std::map<std::string, ElementPtr>());
-
+    int nseq = ++impl_->sequence_;
+    
     env->set("type", Element::create("send"));
     env->set("from", Element::create(impl_->lname_));
     env->set("to", Element::create(to));
     env->set("group", Element::create(group));
     env->set("instance", Element::create(instance));
-    env->set("seq", Element::create(impl_->sequence_));
+    env->set("seq", Element::create(nseq));
     //env->set("msg", Element::create(msg->toWire()));
 
     sendmsg(env, msg);
-
-    return (++impl_->sequence_);
+    return nseq;
 }
 
 bool
 Session::group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
-                       bool nonblock)
+                       bool nonblock, int seq)
 {
-    return (recvmsg(envelope, msg, nonblock));
-}
-
-unsigned int
+    return (recvmsg(envelope, msg, nonblock, seq));
+}
+
+int
 Session::reply(ElementPtr& envelope, ElementPtr& newmsg) {
     ElementPtr env = Element::create(std::map<std::string, ElementPtr>());
-
+    int nseq = ++impl_->sequence_;
+    
     env->set("type", Element::create("send"));
     env->set("from", Element::create(impl_->lname_));
     env->set("to", Element::create(envelope->get("from")->stringValue()));
     env->set("group", Element::create(envelope->get("group")->stringValue()));
     env->set("instance", Element::create(envelope->get("instance")->stringValue()));
-    env->set("seq", Element::create(impl_->sequence_));
+    env->set("seq", Element::create(nseq));
     env->set("reply", Element::create(envelope->get("seq")->intValue()));
 
     sendmsg(env, newmsg);
 
-    return (++impl_->sequence_);
-}
-}
-}
+    return nseq;
+}
+
+bool
+Session::hasQueuedMsgs()
+{
+    return (impl_->queue_->size() > 0);
+}
+
+}
+}

Modified: experiments/python-binding/src/lib/cc/session.h
==============================================================================
--- experiments/python-binding/src/lib/cc/session.h (original)
+++ experiments/python-binding/src/lib/cc/session.h Wed Jun  9 09:52:34 2010
@@ -24,11 +24,10 @@
 #include <exceptions/exceptions.h>
 
 #include "data.h"
+#include "session_config.h"
 
-namespace boost {
 namespace asio {
 class io_service;
-}
 }
 
 namespace isc {
@@ -51,7 +50,7 @@
 
         public:
             Session();
-            Session(boost::asio::io_service& ioservice);
+            Session(asio::io_service& ioservice);
             ~Session();
 
             // XXX: quick hack to allow the user to watch the socket directly.
@@ -59,29 +58,33 @@
 
             void startRead(boost::function<void()> read_callback);
 
-            void establish();
+            void establish(const char* socket_file = NULL);
             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);
+                         bool nonblock = true,
+                         int seq = -1);
             bool recvmsg(isc::data::ElementPtr& env,
                          isc::data::ElementPtr& msg,
-                         bool nonblock = true);
+                         bool nonblock = true,
+                         int seq = -1);
             void subscribe(std::string group,
                            std::string instance = "*");
             void unsubscribe(std::string group,
                              std::string instance = "*");
-            unsigned int group_sendmsg(isc::data::ElementPtr msg,
+            int group_sendmsg(isc::data::ElementPtr msg,
                                        std::string group,
                                        std::string instance = "*",
                                        std::string to = "*");
             bool group_recvmsg(isc::data::ElementPtr& envelope,
                                isc::data::ElementPtr& msg,
-                               bool nonblock = true);
-            unsigned int reply(isc::data::ElementPtr& envelope,
+                               bool nonblock = true,
+                               int seq = -1);
+            int reply(isc::data::ElementPtr& envelope,
                                isc::data::ElementPtr& newmsg);
+            bool hasQueuedMsgs();
         };
     } // namespace cc
 } // namespace isc

Modified: experiments/python-binding/src/lib/config/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/config/Makefile.am (original)
+++ experiments/python-binding/src/lib/config/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,4 +1,6 @@
-AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib -Wno-strict-aliasing
+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
 
 lib_LTLIBRARIES = libcfgclient.la
 libcfgclient_la_SOURCES = config_data.h config_data.cc module_spec.h module_spec.cc ccsession.cc ccsession.h
@@ -46,3 +48,6 @@
 EXTRA_DIST += testdata/spec22.spec
 EXTRA_DIST += testdata/spec23.spec
 EXTRA_DIST += testdata/spec24.spec
+EXTRA_DIST += testdata/spec25.spec
+EXTRA_DIST += testdata/spec26.spec
+EXTRA_DIST += testdata/spec27.spec

Modified: experiments/python-binding/src/lib/config/ccsession.cc
==============================================================================
--- experiments/python-binding/src/lib/config/ccsession.cc (original)
+++ experiments/python-binding/src/lib/config/ccsession.cc Wed Jun  9 09:52:34 2010
@@ -32,9 +32,7 @@
 #include <sstream>
 #include <cerrno>
 
-#ifdef HAVE_BOOST_SYSTEM
 #include <boost/bind.hpp>
-#endif
 #include <boost/foreach.hpp>
 
 #include <cc/data.h>
@@ -188,7 +186,6 @@
     return module_spec;
 }
 
-#ifdef HAVE_BOOST_SYSTEM
 void
 ModuleCCSession::startCheck() {
     // data available on the command channel.  process it in the synchronous
@@ -201,7 +198,7 @@
 
 ModuleCCSession::ModuleCCSession(
     std::string spec_file_name,
-    boost::asio::io_service& io_service,
+    asio::io_service& io_service,
     isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config),
     isc::data::ElementPtr(*command_handler)(
         const std::string& command, const isc::data::ElementPtr args)
@@ -213,7 +210,6 @@
     // register callback for asynchronous read
     session_.startRead(boost::bind(&ModuleCCSession::startCheck, this));
 }
-#endif
 
 ModuleCCSession::ModuleCCSession(
     std::string spec_file_name,
@@ -248,8 +244,8 @@
     //session_.subscribe("statistics", "*");
     // send the data specification
     ElementPtr spec_msg = createCommand("module_spec", module_specification_.getFullSpec());
-    session_.group_sendmsg(spec_msg, "ConfigManager");
-    session_.group_recvmsg(env, answer, false);
+    unsigned int seq = session_.group_sendmsg(spec_msg, "ConfigManager");
+    session_.group_recvmsg(env, answer, false, seq);
     int rcode;
     ElementPtr err = parseAnswer(rcode, answer);
     if (rcode != 0) {
@@ -260,8 +256,8 @@
     // get any stored configuration from the manager
     if (config_handler_) {
         ElementPtr cmd = Element::createFromString("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
-        session_.group_sendmsg(cmd, "ConfigManager");
-        session_.group_recvmsg(env, answer, false);
+        seq = session_.group_sendmsg(cmd, "ConfigManager");
+        session_.group_recvmsg(env, answer, false, seq);
         ElementPtr new_config = parseAnswer(rcode, answer);
         if (rcode == 0) {
             handleConfigUpdate(new_config);
@@ -308,6 +304,12 @@
 ModuleCCSession::getSocket()
 {
     return (session_.getSocket());
+}
+
+bool
+ModuleCCSession::hasQueuedMsgs()
+{
+    return (session_.hasQueuedMsgs());
 }
 
 int
@@ -365,8 +367,8 @@
     ElementPtr env, answer;
     int rcode;
     
-    session_.group_sendmsg(cmd, "ConfigManager");
-    session_.group_recvmsg(env, answer, false);
+    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);

Modified: experiments/python-binding/src/lib/config/ccsession.h
==============================================================================
--- experiments/python-binding/src/lib/config/ccsession.h (original)
+++ experiments/python-binding/src/lib/config/ccsession.h Wed Jun  9 09:52:34 2010
@@ -24,10 +24,8 @@
 #include <cc/session.h>
 #include <cc/data.h>
 
-namespace boost {
 namespace asio {
 class io_service;
-}
 }
 
 namespace isc {
@@ -133,7 +131,7 @@
                     isc::data::ElementPtr(*command_handler)(const std::string& command, const isc::data::ElementPtr args) = NULL
                     ) throw (isc::cc::SessionError);
     ModuleCCSession(std::string spec_file_name,
-                    boost::asio::io_service& io_service,
+                    asio::io_service& io_service,
                     isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config) = NULL,
                     isc::data::ElementPtr(*command_handler)(const std::string& command, const isc::data::ElementPtr args) = NULL
                     ) throw (isc::cc::SessionError);
@@ -148,6 +146,16 @@
      *         channel.
      */
     int getSocket();
+
+    /**
+     * Optional optimization for checkCommand loop; returns true
+     * if there are unhandled queued messages in the cc session.
+     * (if either this is true or there is data on the socket found
+     * by the select() call on getSocket(), run checkCommand())
+     * 
+     * @return true if there are unhandled queued messages
+     */
+    bool hasQueuedMsgs();
 
     /**
      * Check if there is a command or config change on the command

Modified: experiments/python-binding/src/lib/config/config_data.h
==============================================================================
--- experiments/python-binding/src/lib/config/config_data.h (original)
+++ experiments/python-binding/src/lib/config/config_data.h Wed Jun  9 09:52:34 2010
@@ -40,6 +40,7 @@
     /// Constructs a ConfigData option with no specification and an
     /// empty configuration.
     ConfigData() { _config = Element::createFromString("{}"); };
+    
     /// Constructs a ConfigData option with the given specification
     /// and an empty configuration.
     /// \param module_spec A ModuleSpec for the relevant module
@@ -70,17 +71,21 @@
 
     /// Returns the ModuleSpec associated with this ConfigData object
     const ModuleSpec getModuleSpec() { 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; }
+    
     /// Returns a list of all possible configuration options as specified
     ///         by the ModuleSpec.
     /// \param identifier If given, show the items at the given identifier
@@ -92,6 +97,7 @@
     ///         location (or all possible identifiers if identifier==""
     ///         and recurse==false)
     ElementPtr getItemList(const std::string& identifier = "", bool recurse = false);
+    
     /// 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

Modified: experiments/python-binding/src/lib/config/module_spec.cc
==============================================================================
--- experiments/python-binding/src/lib/config/module_spec.cc (original)
+++ experiments/python-binding/src/lib/config/module_spec.cc Wed Jun  9 09:52:34 2010
@@ -145,6 +145,7 @@
 static void
 check_data_specification(const ElementPtr& 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
     // commands and have no config
     if (spec->contains("config_data")) {
@@ -202,6 +203,16 @@
 ModuleSpec::getModuleName() const
 {
     return module_specification->get("module_name")->stringValue();
+}
+
+const std::string
+ModuleSpec::getModuleDescription() const
+{
+    if (module_specification->contains("module_description")) {
+        return module_specification->get("module_description")->stringValue();
+    } else {
+        return std::string("");
+    }
 }
 
 bool

Modified: experiments/python-binding/src/lib/config/module_spec.h
==============================================================================
--- experiments/python-binding/src/lib/config/module_spec.h (original)
+++ experiments/python-binding/src/lib/config/module_spec.h Wed Jun  9 09:52:34 2010
@@ -77,6 +77,10 @@
         /// Returns the module name as specified by the specification
         const std::string getModuleName() const;
         
+        /// Returns the module description as specified by the specification
+        /// returns an empty string if there is no description
+        const std::string getModuleDescription() const;
+        
         // returns true if the given element conforms to this data
         // configuration specification
         /// Validates the given configuration data for this specification.

Modified: experiments/python-binding/src/lib/config/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/config/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/config/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,4 +1,8 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+# see src/lib/cc/Makefile.am for -Wno-unused-parameter
+AM_CXXFLAGS += -Wno-unused-parameter
 
 CLEANFILES = *.gcno *.gcda
 
@@ -14,14 +18,9 @@
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD =  $(GTEST_LDADD)
 run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += libfake_session.la
 run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
 run_unittests_LDADD += $(top_builddir)/src/lib/cc/data.o
-run_unittests_LDADD += libfake_session.la
-
-if HAVE_BOOST_SYSTEM
-run_unittests_LDFLAGS += $(AM_LDFLAGS) $(BOOST_LDFLAGS)
-run_unittests_LDADD += $(BOOST_SYSTEM_LIB)
-endif
 
 endif
 

Modified: experiments/python-binding/src/lib/config/tests/fake_session.cc
==============================================================================
--- experiments/python-binding/src/lib/config/tests/fake_session.cc (original)
+++ experiments/python-binding/src/lib/config/tests/fake_session.cc Wed Jun  9 09:52:34 2010
@@ -23,12 +23,6 @@
 #include <iostream>
 #include <sstream>
 
-#ifdef HAVE_BOOST_SYSTEM
-#include <boost/bind.hpp>
-#include <boost/function.hpp>
-#include <boost/asio.hpp>
-#endif
-
 #include <boost/foreach.hpp>
 
 #include <exceptions/exceptions.h>
@@ -39,13 +33,6 @@
 using namespace std;
 using namespace isc::cc;
 using namespace isc::data;
-
-#ifdef HAVE_BOOST_SYSTEM
-// some of the boost::asio names conflict with socket API system calls
-// (e.g. write(2)) so we don't import the entire boost::asio namespace.
-using boost::asio::io_service;
-using boost::asio::ip::tcp;
-#endif
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -144,13 +131,16 @@
 {
 }
 
-#ifdef HAVE_BOOST_SYSTEM
-Session::Session(io_service& io_service UNUSED_PARAM)
-{
-}
-#endif
+Session::Session(asio::io_service& io_service UNUSED_PARAM)
+{
+}
 
 Session::~Session() {
+}
+
+bool
+Session::connect() {
+    return true;
 }
 
 void
@@ -167,7 +157,7 @@
 }
 
 void
-Session::establish() {
+Session::establish(const char* socket_file) {
 }
 
 //
@@ -188,7 +178,7 @@
 }
 
 bool
-Session::recvmsg(ElementPtr& msg, bool nonblock UNUSED_PARAM) {
+Session::recvmsg(ElementPtr& msg, bool nonblock UNUSED_PARAM, int seq UNUSED_PARAM) {
     //cout << "[XX] client asks for message " << endl;
     if (initial_messages &&
         initial_messages->getType() == Element::list &&
@@ -202,7 +192,7 @@
 }
 
 bool
-Session::recvmsg(ElementPtr& env, ElementPtr& msg, bool nonblock UNUSED_PARAM) {
+Session::recvmsg(ElementPtr& env, ElementPtr& msg, bool nonblock UNUSED_PARAM, int seq UNUSED_PARAM) {
     //cout << "[XX] client asks for message and env" << endl;
     env = ElementPtr();
     if (initial_messages &&
@@ -269,9 +259,9 @@
 
 bool
 Session::group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
-                       bool nonblock)
-{
-    return (recvmsg(envelope, msg, nonblock));
+                       bool nonblock, int seq)
+{
+    return (recvmsg(envelope, msg, nonblock, seq));
 }
 
 unsigned int
@@ -282,5 +272,10 @@
     return 1;
 }
 
-}
-}
+bool
+Session::hasQueuedMsgs() {
+    return false;
+}
+
+}
+}

Modified: experiments/python-binding/src/lib/config/tests/fake_session.h
==============================================================================
--- experiments/python-binding/src/lib/config/tests/fake_session.h (original)
+++ experiments/python-binding/src/lib/config/tests/fake_session.h Wed Jun  9 09:52:34 2010
@@ -25,10 +25,8 @@
 
 #include <cc/data.h>
 
-namespace boost {
 namespace asio {
 class io_service;
-}
 }
 
 // global variables so tests can insert
@@ -65,7 +63,7 @@
             // public so tests can inspect them
         
             Session();
-            Session(boost::asio::io_service& ioservice);
+            Session(asio::io_service& ioservice);
             ~Session();
 
             // XXX: quick hack to allow the user to watch the socket directly.
@@ -73,16 +71,17 @@
 
             void startRead(boost::function<void()> read_callback);
 
-            void establish();
+            void establish(const char* socket_file = NULL);
+            bool connect();
             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);
+                         bool nonblock = true, int seq = -1);
             bool recvmsg(isc::data::ElementPtr& env,
                          isc::data::ElementPtr& msg,
-                         bool nonblock = true);
+                         bool nonblock = true, int seq = -1);
             void subscribe(std::string group,
                            std::string instance = "*");
             void unsubscribe(std::string group,
@@ -93,9 +92,11 @@
                                        std::string to = "*");
             bool group_recvmsg(isc::data::ElementPtr& envelope,
                                isc::data::ElementPtr& msg,
-                               bool nonblock = true);
+                               bool nonblock = true,
+                               int seq = -1);
             unsigned int reply(isc::data::ElementPtr& envelope,
                                isc::data::ElementPtr& newmsg);
+            bool hasQueuedMsgs();
 
         };
     } // namespace cc

Modified: experiments/python-binding/src/lib/config/tests/module_spec_unittests.cc
==============================================================================
--- experiments/python-binding/src/lib/config/tests/module_spec_unittests.cc (original)
+++ experiments/python-binding/src/lib/config/tests/module_spec_unittests.cc Wed Jun  9 09:52:34 2010
@@ -60,6 +60,12 @@
     dd = moduleSpecFromFile(specfile("spec2.spec"));
     EXPECT_EQ("[ {\"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\"} ]", dd.getCommandsSpec()->str());
     EXPECT_EQ("Spec2", dd.getModuleName());
+    EXPECT_EQ("", dd.getModuleDescription());
+
+    dd = moduleSpecFromFile(specfile("spec25.spec"));
+    EXPECT_EQ("Spec25", dd.getModuleName());
+    EXPECT_EQ("Just an empty module", dd.getModuleDescription());
+    EXPECT_THROW(moduleSpecFromFile(specfile("spec26.spec")), ModuleSpecError);
 
     std::ifstream file;
     file.open(specfile("spec1.spec").c_str());

Modified: experiments/python-binding/src/lib/datasrc/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/datasrc/Makefile.am (original)
+++ experiments/python-binding/src/lib/datasrc/Makefile.am Wed Jun  9 09:52:34 2010
@@ -3,6 +3,8 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 AM_CPPFLAGS += $(SQLITE_CFLAGS)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 CLEANFILES = *.gcno *.gcda
 

Modified: experiments/python-binding/src/lib/datasrc/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/datasrc/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/datasrc/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,6 +1,8 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 CLEANFILES = *.gcno *.gcda
 

Modified: experiments/python-binding/src/lib/datasrc/tests/sqlite3_unittest.cc
==============================================================================
--- experiments/python-binding/src/lib/datasrc/tests/sqlite3_unittest.cc (original)
+++ experiments/python-binding/src/lib/datasrc/tests/sqlite3_unittest.cc Wed Jun  9 09:52:34 2010
@@ -376,8 +376,10 @@
 
     NameMatch name_match(www_name);
     data_source.findClosestEnclosure(name_match, rrclass);
-    EXPECT_EQ(NULL, name_match.closestName());
-    EXPECT_EQ(NULL, name_match.bestDataSrc());
+    // XXX: some deviant compilers seem to fail to recognize a NULL as a
+    // pointer type.  This explicit cast works around such compilers.
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.closestName());
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.bestDataSrc());
 }
 
 TEST_F(Sqlite3DataSourceTest, openFail) {
@@ -441,15 +443,15 @@
 TEST_F(Sqlite3DataSourceTest, findClosestEnclosureNoMatch) {
     NameMatch name_match(nomatch_name);
     data_source.findClosestEnclosure(name_match, rrclass);
-    EXPECT_EQ(NULL, name_match.closestName());
-    EXPECT_EQ(NULL, name_match.bestDataSrc());
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.closestName());
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.bestDataSrc());
 }
 
 TEST_F(Sqlite3DataSourceTest, findClosestClassMismatch) {
     NameMatch name_match(www_name);
     data_source.findClosestEnclosure(name_match, rrclass_notmatch);
-    EXPECT_EQ(NULL, name_match.closestName());
-    EXPECT_EQ(NULL, name_match.bestDataSrc());
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.closestName());
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.bestDataSrc());
 }
 
 // If the query class is ANY, the result should be the same as the case where

Modified: experiments/python-binding/src/lib/datasrc/tests/static_unittest.cc
==============================================================================
--- experiments/python-binding/src/lib/datasrc/tests/static_unittest.cc (original)
+++ experiments/python-binding/src/lib/datasrc/tests/static_unittest.cc Wed Jun  9 09:52:34 2010
@@ -214,8 +214,9 @@
 TEST_F(StaticDataSourceTest, findClosestEnclosureForVersionClassMismatch) {
     NameMatch name_match(version_name);
     data_source.findClosestEnclosure(name_match, RRClass::IN());
-    EXPECT_EQ(NULL, name_match.closestName());
-    EXPECT_EQ(NULL, name_match.bestDataSrc());
+    // XXX: see sqlite3_unittest.cc about the cast.
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.closestName());
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.bestDataSrc());
 }
 
 TEST_F(StaticDataSourceTest, findClosestEnclosureForVersionPartial) {
@@ -242,8 +243,8 @@
 TEST_F(StaticDataSourceTest, findClosestEnclosureNoMatch) {
     NameMatch name_match(nomatch_name);
     data_source.findClosestEnclosure(name_match, rrclass);
-    EXPECT_EQ(NULL, name_match.closestName());
-    EXPECT_EQ(NULL, name_match.bestDataSrc());
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.closestName());
+    EXPECT_EQ(static_cast<void*>(NULL), name_match.bestDataSrc());
 }
 
 TEST_F(StaticDataSourceTest, findRRsetVersionTXT) {

Modified: experiments/python-binding/src/lib/dns/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/dns/Makefile.am (original)
+++ experiments/python-binding/src/lib/dns/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,9 +1,7 @@
 SUBDIRS = . tests python
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
-if GCC_WERROR_OK
-AM_CPPFLAGS += -Werror
-endif
+AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 CLEANFILES = *.gcno *.gcda
 CLEANFILES += rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc
@@ -79,6 +77,7 @@
 libdns_la_SOURCES += sha1.h sha1.cc
 libdns_la_SOURCES += tsig.h tsig.cc
 
+
 #if HAVE_BOOST_PYTHON
 ## This is a loadable module for python scripts, so we use the prefix "pyexec"
 ## to make sure the object files will be installed in the appropriate place
@@ -86,10 +85,11 @@
 #pyexec_LTLIBRARIES = bind10_dns.la
 #bind10_dns_la_SOURCES = python_dns.cc
 #bind10_dns_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
+#bind10_dns_la_CXXFLAGS = $(AM_CXXFLAGS) $(B10_CXXFLAGS)
 #if GCC_WERROR_OK
 ## XXX: Boost.Python triggers strict aliasing violation, so if we use -Werror
 ## we need to suppress the warnings.
-#bind10_dns_la_CPPFLAGS += -fno-strict-aliasing
+#bind10_dns_la_CXXFLAGS += -fno-strict-aliasing
 #endif
 #bind10_dns_la_LDFLAGS = $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
 ## Python prefers .so, while some OSes (specifically MacOS) use a different
@@ -107,3 +107,29 @@
 rrparamregistry.cc: rrparamregistry-placeholder.cc
 rrclass.h rrtype.h rrparamregistry.cc rdataclass.h rdataclass.cc: Makefile
 	./gen-rdatacode.py
+
+libdns_includedir = $(includedir)/dns
+libdns_include_HEADERS = \
+	buffer.h \
+	dnssectime.h \
+	exceptions.h \
+	message.h \
+	messagerenderer.h \
+	name.h \
+	question.h \
+	rdata.h \
+	rdataclass.h \
+	rrclass.h \
+	rrparamregistry.h \
+	rrset.h \
+	rrsetlist.h \
+	rrttl.h \
+	rrtype.h \
+	tsig.h
+# Purposely not installing these headers:
+# base32.h # used only internally, and not actually DNS specific
+# base64.h # used only internally, and not actually DNS specific
+# hex.h # used only internally, and not actually DNS specific
+# sha1.h # used only internally, and not actually DNS specific
+# rrclass-placeholder.h
+# rrtype-placeholder.h

Modified: experiments/python-binding/src/lib/dns/dnssectime.cc
==============================================================================
--- experiments/python-binding/src/lib/dns/dnssectime.cc (original)
+++ experiments/python-binding/src/lib/dns/dnssectime.cc Wed Jun  9 09:52:34 2010
@@ -18,21 +18,12 @@
 #include <iomanip>
 #include <iostream>
 #include <sstream>
-#include <vector>
 
 #include <stdio.h>
 #include <time.h>
 
 #include <exceptions/exceptions.h>
 
-#include <dns/base64.h>
-#include <dns/buffer.h>
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
 #include <dns/dnssectime.h>
 
 using namespace std;

Modified: experiments/python-binding/src/lib/dns/name.cc
==============================================================================
--- experiments/python-binding/src/lib/dns/name.cc (original)
+++ experiments/python-binding/src/lib/dns/name.cc Wed Jun  9 09:52:34 2010
@@ -666,7 +666,7 @@
 }
 
 Name
-Name::split(unsigned int first, unsigned int n) const {
+Name::split(const unsigned int first, const unsigned int n) const {
     if (n == 0 || n > labelcount_ || first > labelcount_ - n) {
         isc_throw(OutOfRange, "Name::split: invalid split range");
     }
@@ -700,6 +700,16 @@
     assert(retname.labelcount_ == newlabels);
 
     return (retname);
+}
+
+Name
+Name::split(const unsigned level) const {
+    if (level >= getLabelCount()) {
+        isc_throw(OutOfRange, "invalid level for name split (" << level
+                  << ") for name " << *this);
+    }
+
+    return (split(level, getLabelCount() - level));
 }
 
 Name&

Modified: experiments/python-binding/src/lib/dns/name.h
==============================================================================
--- experiments/python-binding/src/lib/dns/name.h (original)
+++ experiments/python-binding/src/lib/dns/name.h Wed Jun  9 09:52:34 2010
@@ -84,7 +84,7 @@
 
 ///
 /// \brief A standard DNS module exception that is thrown if the name parser
-/// finds the input (string or wire-format data) is incomplete.
+/// finds the input (string or wire-format %data) is incomplete.
 ///
 /// An attempt of constructing a name from an empty string will trigger this
 /// exception.
@@ -168,13 +168,13 @@
 ///
 /// The \c Name class encapsulates DNS names.
 ///
-/// It provides interfaces to construct a name from string or wire-format data,
-/// transform a name into a string or wire-format data, compare two names, get
+/// It provides interfaces to construct a name from string or wire-format %data,
+/// transform a name into a string or wire-format %data, compare two names, get
 /// access to various properties of a name, etc.
 ///
-/// Notes to developers: Internally, a name object maintains the name data
+/// Notes to developers: Internally, a name object maintains the name %data
 /// in wire format as an instance of \c std::string.  Since many string
-/// implementations adopt copy-on-write data sharing, we expect this approach
+/// implementations adopt copy-on-write %data sharing, we expect this approach
 /// will make copying a name less expensive in typical cases.  If this is
 /// found to be a significant performance bottleneck later, we may reconsider
 /// the internal representation or perhaps the API.
@@ -187,9 +187,9 @@
 /// included.  In the BIND9 DNS library from which this implementation is
 /// derived, the offsets are optional, probably due to performance
 /// considerations (in fact, offsets can always be calculated from the name
-/// data, and in that sense are redundant).  In our implementation, however,
+/// %data, and in that sense are redundant).  In our implementation, however,
 /// we always build and maintain the offsets.  We believe we need more low
-/// level, specialized data structure and interface where we really need to
+/// level, specialized %data structure and interface where we really need to
 /// pursue performance, and would rather keep this generic API and
 /// implementation simpler.
 ///
@@ -233,21 +233,21 @@
     /// \param namestr A string representation of the name to be constructed.
     /// \param downcase Whether to convert upper case alphabets to lower case.
     explicit Name(const std::string& namestr, bool downcase = false);
-    /// Constructor from wire-format data.
+    /// Constructor from wire-format %data.
     ///
     /// The \c buffer parameter normally stores a complete DNS message
     /// containing the name to be constructed.  The current read position of
     /// the buffer points to the head of the name.
     ///
-    /// The input data may or may not be compressed; if it's compressed, this
+    /// The input %data may or may not be compressed; if it's compressed, this
     /// method will automatically decompress it.
     ///
-    /// If the given data does not represent a valid DNS name, an exception
+    /// If the given %data does not represent a valid DNS name, an exception
     /// of class \c DNSMessageFORMERR will be thrown.
     /// In addition, if resource allocation for the new name fails, a
     /// corresponding standard exception will be thrown.
     ///
-    /// \param buffer A buffer storing the wire format data.
+    /// \param buffer A buffer storing the wire format %data.
     /// \param downcase Whether to convert upper case alphabets to lower case.
     explicit Name(InputBuffer& buffer, bool downcase = false);
     ///
@@ -260,35 +260,35 @@
     /// \name Getter Methods
     ///
     //@{
-    /// \brief Provides one-byte name data in wire format at the specified
+    /// \brief Provides one-byte name %data in wire format at the specified
     /// position.
     ///
     /// This method returns the unsigned 8-bit value of wire-format \c Name
-    /// data at the given position from the head.
+    /// %data at the given position from the head.
     ///
     /// For example, if \c n is a \c Name object for "example.com",
     /// \c n.at(3) would return \c 'a', and \c n.at(7) would return \c 'e'.
     /// Note that \c n.at(0) would be 7 (decimal), the label length of
-    /// "example", instead of \c 'e', because it returns a data portion
+    /// "example", instead of \c 'e', because it returns a %data portion
     /// in wire-format.  Likewise, \c n.at(8) would return 3 (decimal)
     /// instead of <code>'.'</code>
     ///
     /// This method would be useful for an application to examine the
-    /// wire-format name data without dumping the data into a buffer,
-    /// which would involve data copies and would be less efficient.
+    /// wire-format name %data without dumping the %data into a buffer,
+    /// which would involve %data copies and would be less efficient.
     /// One common usage of this method would be something like this:
     /// \code for (size_t i = 0; i < name.getLength(); ++i) {
     ///     uint8_t c = name.at(i);
     ///     // do something with c
     /// } \endcode
     ///
-    /// Parameter \c pos must be in the valid range of the name data, that is,
+    /// Parameter \c pos must be in the valid range of the name %data, that is,
     /// must be less than \c Name.getLength().  Otherwise, an exception of
     /// class \c OutOfRange will be thrown.
     /// This method never throws an exception in other ways.
     ///
-    /// \param pos The position in the wire format name data to be returned.
-    /// \return An unsigned 8-bit integer corresponding to the name data
+    /// \param pos The position in the wire format name %data to be returned.
+    /// \return An unsigned 8-bit integer corresponding to the name %data
     /// at the position of \c pos.
     uint8_t at(size_t pos) const
     {
@@ -360,7 +360,7 @@
     /// <code>buffer.getCapacity() - buffer.getLength() >= Name::MAX_WIRE</code>
     /// then this method should not throw an exception.
     ///
-    /// \param buffer An output buffer to store the wire data.
+    /// \param buffer An output buffer to store the wire %data.
     void toWire(OutputBuffer& buffer) const;
     //@}
 
@@ -502,6 +502,72 @@
     /// labels including and following the <code>first</code> label.  
     Name split(unsigned int first, unsigned int n) const;
 
+    /// \brief Extract a specified super domain name of Name.
+    ///
+    /// This function constructs a new \c Name object that is a super domain
+    /// of \c this name.
+    /// The new name is \c level labels upper than \c this name.
+    /// For example, when \c name is www.example.com,
+    /// <code>name.split(1)</code> will return a \c Name object for example.com.
+    /// \c level can be 0, in which case this method returns a copy of
+    /// \c this name.
+    /// The possible maximum value for \c level is
+    /// <code>this->getLabelCount()-1</code>, in which case this method
+    /// returns a root name.
+    ///
+    /// One common expected usage of this method is to iterate over super
+    /// domains of a given name, label by label, as shown in the following
+    /// sample code:
+    /// \code // if name is www.example.com...
+    /// for (int i = 0; i < name.getLabelCount(); ++i) {
+    ///     Name upper_name(name.split(i));
+    ///     // upper_name'll be www.example.com., example.com., com., and then .
+    /// }
+    /// \endcode
+    ///
+    /// \c level must be smaller than the number of labels of \c this name;
+    /// otherwise an exception of class \c OutOfRange will be thrown.
+    /// In addition, if resource allocation for the new name fails, a
+    /// corresponding standard exception will be thrown.
+    ///
+    /// Note to developers: probably as easily imagined, this method is a
+    /// simple wrapper to one usage of the other
+    /// <code>split(unsigned int, unsigned int) const</code> method and is
+    /// redundant in some sense.
+    /// We provide the "redundant" method for convenience, however, because
+    /// the expected usage shown above seems to be common, and the parameters
+    /// to the other \c split(unsigned int, unsigned int) const to implement
+    /// it may not be very intuitive.
+    ///
+    /// We are also aware that it is generally discouraged to add a public
+    /// member function that could be implemented using other member functions.
+    /// We considered making it a non member function, but we could not come
+    /// up with an intuitive function name to represent the specific service.
+    /// Some other BIND 10 developers argued, probably partly because of the
+    /// counter intuitive function name, a different signature of \c split
+    /// would be better to improve code readability.
+    /// While that may be a matter of personal preference, we accepted the
+    /// argument.  One major goal of public APIs like this is wider acceptance
+    /// from internal/external developers, so unless there is a clear advantage
+    /// it would be better to respect the preference of the API users.
+    ///
+    /// Since this method doesn't have to be a member function in other way,
+    /// it is intentionally implemented only using public interfaces of the
+    /// \c Name class; it doesn't refer to private members of the class even if
+    /// it could.
+    /// This way we hope we can avoid damaging the class encapsulation,
+    /// which is a major drawback of public member functions.
+    /// As such if and when this "method" has to be extended, it should be
+    /// implemented without the privilege of being a member function unless
+    /// there is a very strong reason to do so.  In particular a minor
+    /// performance advantage shouldn't justify that approach.
+    ///
+    /// \param level The number of labels to be removed from \c this name to
+    /// create the super domain name.
+    /// (0 <= \c level < <code>this->getLabelCount()</code>)
+    /// \return A new \c Name object to be created.
+    Name split(unsigned int level) const;
+
     /// \brief Reverse the labels of a name
     ///
     /// This method reverses the labels of a name.  For example, if

Modified: experiments/python-binding/src/lib/dns/rdata/generic/nsec_47.cc
==============================================================================
--- experiments/python-binding/src/lib/dns/rdata/generic/nsec_47.cc (original)
+++ experiments/python-binding/src/lib/dns/rdata/generic/nsec_47.cc Wed Jun  9 09:52:34 2010
@@ -112,7 +112,7 @@
     for (int i = 0; i < rdata_len; i += len) {
         if (i + 2 > rdata_len) {
             isc_throw(DNSMessageFORMERR, "NSEC RDATA from wire: "
-                      "incomplete bit map filed");
+                      "incomplete bit map field");
         }
         block = typebits[i];
         len = typebits[i + 1];
@@ -182,7 +182,7 @@
         assert(i + 2 <= impl_->typebits_.size());
         const int block = impl_->typebits_.at(i);
         len = impl_->typebits_.at(i + 1);
-        assert(len >= 0 && len <= 32);
+        assert(len > 0 && len <= 32);
         i += 2;
         for (int j = 0; j < len; j++) {
             if (impl_->typebits_.at(i + j) == 0) {

Modified: experiments/python-binding/src/lib/dns/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/dns/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/dns/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,6 +1,7 @@
 AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
 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)
 
 CLEANFILES = *.gcno *.gcda
 

Modified: experiments/python-binding/src/lib/dns/tests/dnssectime_unittest.cc
==============================================================================
--- experiments/python-binding/src/lib/dns/tests/dnssectime_unittest.cc (original)
+++ experiments/python-binding/src/lib/dns/tests/dnssectime_unittest.cc Wed Jun  9 09:52:34 2010
@@ -64,7 +64,8 @@
 TEST(DNSSECTimeTest, overflow) {
     // Jan 1, Year 10,000.
     if (sizeof(time_t) > 4) {
-        EXPECT_THROW(timeToText(253402300800LL), InvalidTime);
+        EXPECT_THROW(timeToText(static_cast<time_t>(253402300800LL)),
+                     InvalidTime);
     }
 }
 

Modified: experiments/python-binding/src/lib/dns/tests/name_unittest.cc
==============================================================================
--- experiments/python-binding/src/lib/dns/tests/name_unittest.cc (original)
+++ experiments/python-binding/src/lib/dns/tests/name_unittest.cc Wed Jun  9 09:52:34 2010
@@ -500,6 +500,18 @@
                  OutOfRange);
 }
 
+TEST_F(NameTest, split_for_suffix) {
+    EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(1),
+                        Name("example.com"));
+    EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(0),
+                        example_name);
+    EXPECT_PRED_FORMAT2(UnitTestUtil::matchName, example_name.split(3),
+                        Name("."));
+
+    // Invalid case: the level must be less than the original label count.
+    EXPECT_THROW(example_name.split(4), OutOfRange);
+}
+
 TEST_F(NameTest, downcase) {
     // usual case: all-upper case name to all-lower case
     compareInWireFormat(example_name_upper.downcase(), example_name);

Modified: experiments/python-binding/src/lib/exceptions/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/exceptions/Makefile.am (original)
+++ experiments/python-binding/src/lib/exceptions/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,3 +1,4 @@
+AM_CXXFLAGS=$(B10_CXXFLAGS)
 
 lib_LTLIBRARIES = libexceptions.la
 libexceptions_la_SOURCES = exceptions.h exceptions.cc
@@ -15,3 +16,6 @@
 endif
 
 noinst_PROGRAMS = $(TESTS)
+
+libexceptions_includedir = $(includedir)/exceptions
+libexceptions_include_HEADERS = exceptions.h

Modified: experiments/python-binding/src/lib/python/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/python/Makefile.am (original)
+++ experiments/python-binding/src/lib/python/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,1 +1,12 @@
 SUBDIRS = isc
+
+python_PYTHON =	bind10_config.py
+
+# Explicitly define DIST_COMMON so ${python_PYTHON} is not included
+# as we don't want the generated file included in distributed tarfile.
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in bind10_config.py.in
+
+# When setting DIST_COMMON, then need to add the .in file too.
+EXTRA_DIST =  bind10_config.py.in
+
+CLEANFILES = bind10_config.pyc

Modified: experiments/python-binding/src/lib/python/isc/cc/message.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/cc/message.py (original)
+++ experiments/python-binding/src/lib/python/isc/cc/message.py Wed Jun  9 09:52:34 2010
@@ -26,6 +26,7 @@
 _ITEM_NULL = 0x04
 _ITEM_BOOL = 0x05
 _ITEM_INT  = 0x06
+_ITEM_REAL = 0x07
 _ITEM_UTF8 = 0x08
 _ITEM_MASK = 0x0f
 
@@ -77,6 +78,10 @@
     """Pack an integer and its type/length prefix."""
     return (_encode_length_and_type(bytes(str(item), 'utf-8'), _ITEM_INT))
 
+def _pack_real(item):
+    """Pack an integer and its type/length prefix."""
+    return (_encode_length_and_type(bytes(str(item), 'utf-8'), _ITEM_REAL))
+
 def _pack_array(item):
     """Pack a list (array) and its type/length prefix."""
     return (_encode_length_and_type(_encode_array(item), _ITEM_LIST))
@@ -98,6 +103,8 @@
         return (_pack_bool(item))
     elif type(item) == int:
         return (_pack_int(item))
+    elif type(item) == float:
+        return (_pack_real(item))
     elif type(item) == dict:
         return (_pack_hash(item))
     elif type(item) == list:
@@ -186,6 +193,8 @@
         value = _decode_bool(item)
     elif item_type == _ITEM_INT:
         value = _decode_int(item)
+    elif item_type == _ITEM_REAL:
+        value = _decode_real(item)
     elif item_type == _ITEM_UTF8:
         value = str(item, 'utf-8')
     elif item_type == _ITEM_HASH:
@@ -205,6 +214,9 @@
 def _decode_int(data):
     return int(str(data, 'utf-8'))
 
+def _decode_real(data):
+    return float(str(data, 'utf-8'))
+
 def _decode_hash(data):
     ret = {}
     while len(data) > 0:

Modified: experiments/python-binding/src/lib/python/isc/cc/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/python/isc/cc/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/python/isc/cc/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -10,6 +10,6 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python \
+	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python \
 	$(PYCOVERAGE) $(abs_srcdir)/$$pytest ; \
 	done

Modified: experiments/python-binding/src/lib/python/isc/cc/tests/session_test.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/cc/tests/session_test.py (original)
+++ experiments/python-binding/src/lib/python/isc/cc/tests/session_test.py Wed Jun  9 09:52:34 2010
@@ -98,6 +98,7 @@
         self._sequence = 1
         self._closed = False
         self._queue = []
+        self._lock = threading.RLock()
 
         try:
             self._socket = MySocket(socket.AF_INET, socket.SOCK_STREAM)
@@ -178,66 +179,78 @@
         # sending message {'to': 'someone', 'reply': 1}, {"hello": "a"}
         #print("sending message {'to': 'someone', 'reply': 1}, {'hello': 'a'}")
 
-        # simply get the message without asking for a specific sequence number reply
+        # get no message without asking for a specific sequence number reply
+        self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv(b'\x00\x00\x00(\x00\x19Skan\x02to(\x07someone\x05reply&\x011Skan\x05hello(\x01a')
         env, msg = sess.recvmsg(False)
+        self.assertEqual(None, env)
+        self.assertTrue(sess.has_queued_msgs())
+        env, msg = sess.recvmsg(False, 1)
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
-
-        # simply get the message, asking for a specific sequence number reply
-        sess._socket.addrecv(b'\x00\x00\x00(\x00\x19Skan\x02to(\x07someone\x05reply&\x011Skan\x05hello(\x01a')
-        env, msg = sess.recvmsg(False, 1)
-        self.assertEqual({'to': 'someone', 'reply': 1}, env)
-        self.assertEqual({"hello": "a"}, msg)
+        self.assertFalse(sess.has_queued_msgs())
         
         # ask for a differe sequence number reply (that doesn't exist)
         # then ask for the one that is there
+        self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv(b'\x00\x00\x00(\x00\x19Skan\x02to(\x07someone\x05reply&\x011Skan\x05hello(\x01a')
         env, msg = sess.recvmsg(False, 2)
         self.assertEqual(None, env)
         self.assertEqual(None, msg)
+        self.assertTrue(sess.has_queued_msgs())
         env, msg = sess.recvmsg(False, 1)
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
+        self.assertFalse(sess.has_queued_msgs())
         
         # ask for a differe sequence number reply (that doesn't exist)
         # then ask for any message
+        self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv(b'\x00\x00\x00(\x00\x19Skan\x02to(\x07someone\x05reply&\x011Skan\x05hello(\x01a')
         env, msg = sess.recvmsg(False, 2)
         self.assertEqual(None, env)
         self.assertEqual(None, msg)
-        env, msg = sess.recvmsg(False)
+        self.assertTrue(sess.has_queued_msgs())
+        env, msg = sess.recvmsg(False, 1)
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
+        self.assertFalse(sess.has_queued_msgs())
         
         #print("sending message {'to': 'someone', 'reply': 1}, {'hello': 'a'}")
 
         # ask for a differe sequence number reply (that doesn't exist)
-        # send a new message, ask for any message (get the first)
+        # send a new message, ask for specific message (get the first)
         # then ask for any message (get the second)
+        self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv(b'\x00\x00\x00(\x00\x19Skan\x02to(\x07someone\x05reply&\x011Skan\x05hello(\x01a')
         env, msg = sess.recvmsg(False, 2)
         self.assertEqual(None, env)
         self.assertEqual(None, msg)
+        self.assertTrue(sess.has_queued_msgs())
         sess._socket.addrecv(b'\x00\x00\x00\x1f\x00\x10Skan\x02to(\x07someoneSkan\x05hello(\x01b')
-        env, msg = sess.recvmsg(False)
-        self.assertEqual({'to': 'someone', 'reply': 1}, env)
-        self.assertEqual({"hello": "a"}, msg)
+        env, msg = sess.recvmsg(False, 1)
+        self.assertEqual({'to': 'someone', 'reply': 1 }, env)
+        self.assertEqual({"hello": "a"}, msg)
+        self.assertFalse(sess.has_queued_msgs())
         env, msg = sess.recvmsg(False)
         self.assertEqual({'to': 'someone'}, env)
         self.assertEqual({"hello": "b"}, msg)
+        self.assertFalse(sess.has_queued_msgs())
         
         # send a message, then one with specific reply value
         # ask for that specific message (get the second)
         # then ask for any message (get the first)
+        self.assertFalse(sess.has_queued_msgs())
         sess._socket.addrecv(b'\x00\x00\x00\x1f\x00\x10Skan\x02to(\x07someoneSkan\x05hello(\x01b')
         sess._socket.addrecv(b'\x00\x00\x00(\x00\x19Skan\x02to(\x07someone\x05reply&\x011Skan\x05hello(\x01a')
         env, msg = sess.recvmsg(False, 1)
         self.assertEqual({'to': 'someone', 'reply': 1}, env)
         self.assertEqual({"hello": "a"}, msg)
+        self.assertTrue(sess.has_queued_msgs())
         env, msg = sess.recvmsg(False)
         self.assertEqual({'to': 'someone'}, env)
         self.assertEqual({"hello": "b"}, msg)
+        self.assertFalse(sess.has_queued_msgs())
 
     def test_next_sequence(self):
         sess = MySession()

Modified: experiments/python-binding/src/lib/python/isc/config/ccsession.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/ccsession.py (original)
+++ experiments/python-binding/src/lib/python/isc/config/ccsession.py Wed Jun  9 09:52:34 2010
@@ -81,8 +81,7 @@
 # 'fixed' commands
 """Fixed names for command and configuration messages"""
 COMMAND_CONFIG_UPDATE = "config_update"
-COMMAND_COMMANDS_UPDATE = "commands_update"
-COMMAND_SPECIFICATION_UPDATE = "specification_update"
+COMMAND_MODULE_SPECIFICATION_UPDATE = "module_specification_update"
 
 COMMAND_GET_COMMANDS_SPEC = "get_commands_spec"
 COMMAND_GET_CONFIG = "get_config"
@@ -314,16 +313,9 @@
         # this step should be unnecessary but is the current way cmdctl returns stuff
         # so changes are needed there to make this clean (we need a command to simply get the
         # full specs for everything, including commands etc, not separate gets for that)
-        specs = self._conn.send_GET('/config_spec')
-        commands = self._conn.send_GET('/commands')
+        specs = self._conn.send_GET('/module_spec')
         for module in specs.keys():
-            cur_spec = { 'module_name': module }
-            if module in specs and specs[module]:
-                cur_spec['config_data'] = specs[module]
-            if module in commands and commands[module]:
-                cur_spec['commands'] = commands[module]
-            
-            self.set_specification(isc.config.ModuleSpec(cur_spec))
+            self.set_specification(isc.config.ModuleSpec(specs[module]))
 
     def request_current_config(self):
         """Requests the current configuration from the configuration

Modified: experiments/python-binding/src/lib/python/isc/config/cfgmgr.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/cfgmgr.py (original)
+++ experiments/python-binding/src/lib/python/isc/config/cfgmgr.py Wed Jun  9 09:52:34 2010
@@ -25,7 +25,9 @@
 import pprint
 import os
 import copy
+import tempfile
 from isc.cc import data
+from isc.config import ccsession
 
 class ConfigManagerDataReadError(Exception):
     """This exception is thrown when there is an error while reading
@@ -84,24 +86,35 @@
         """Writes the current configuration data to a file. If
            output_file_name is not specified, the file used in
            read_from_file is used."""
+        filename = None
         try:
-            tmp_filename = self.db_filename + ".tmp"
-            file = open(tmp_filename, 'w');
+            file = tempfile.NamedTemporaryFile(mode='w',
+                                               prefix="b10-config.db.",
+                                               dir=self.data_path,
+                                               delete=False)
+            filename = file.name
             pp = pprint.PrettyPrinter(indent=4)
             s = pp.pformat(self.data)
             file.write(s)
             file.write("\n")
             file.close()
             if output_file_name:
-                os.rename(tmp_filename, output_file_name)
-            else:
-                os.rename(tmp_filename, self.db_filename)
+                os.rename(filename, output_file_name)
+            else:
+                os.rename(filename, self.db_filename)
         except IOError as ioe:
             # TODO: log this (level critical)
             print("[b10-cfgmgr] Unable to write config file; configuration not stored: " + str(ioe))
+            # TODO: debug option to keep file?
         except OSError as ose:
             # TODO: log this (level critical)
             print("[b10-cfgmgr] Unable to write config file; configuration not stored: " + str(ose))
+        try:
+            if filename and os.path.exists(filename):
+                os.remove(filename)
+        except OSError:
+            # Ok if we really can't delete it anymore, leave it
+            pass
 
     def __eq__(self, other):
         """Returns True if the data contained is equal. data_path and
@@ -148,11 +161,23 @@
         if module_name in self.module_specs:
             del self.module_specs[module_name]
 
-    def get_module_spec(self, module_name):
+    def get_module_spec(self, module_name = None):
         """Returns the full ModuleSpec for the module with the given
-           module_name"""
-        if module_name in self.module_specs:
-            return self.module_specs[module_name]
+           module_name. If no module name is given, a dict will
+           be returned with 'name': module_spec values. If the
+           module name is given, but does not exist, an empty dict
+           is returned"""
+        if module_name:
+            if module_name in self.module_specs:
+                return self.module_specs[module_name]
+            else:
+                # TODO: log error?
+                return {}
+        else:
+            result = {}
+            for module in self.module_specs:
+                result[module] = self.module_specs[module].get_full_spec()
+            return result
 
     def get_config_spec(self, name = None):
         """Returns a dict containing 'module_name': config_spec for
@@ -201,95 +226,112 @@
             if type(cmd) == dict:
                 if 'module_name' in cmd and cmd['module_name'] != '':
                     module_name = cmd['module_name']
-                    answer = isc.config.ccsession.create_answer(0, self.get_config_spec(module_name))
+                    answer = ccsession.create_answer(0, self.get_module_spec(module_name))
                 else:
-                    answer = isc.config.ccsession.create_answer(1, "Bad module_name in get_module_spec command")
-            else:
-                answer = isc.config.ccsession.create_answer(1, "Bad get_module_spec command, argument not a dict")
-        else:
-            answer = isc.config.ccsession.create_answer(0, self.get_config_spec())
+                    answer = ccsession.create_answer(1, "Bad module_name in get_module_spec command")
+            else:
+                answer = ccsession.create_answer(1, "Bad get_module_spec command, argument not a dict")
+        else:
+            answer = ccsession.create_answer(0, self.get_module_spec())
         return answer
+
+    def _handle_get_config_dict(self, cmd):
+        """Private function that handles the 'get_config' command
+           where the command has been checked to be a dict"""
+        if 'module_name' in cmd and cmd['module_name'] != '':
+            module_name = cmd['module_name']
+            try:
+                return ccsession.create_answer(0, data.find(self.config.data, module_name))
+            except data.DataNotFoundError as dnfe:
+                # no data is ok, that means we have nothing that
+                # deviates from default values
+                return ccsession.create_answer(0, { 'version': self.config.CONFIG_VERSION })
+        else:
+            return ccsession.create_answer(1, "Bad module_name in get_config command")
 
     def _handle_get_config(self, cmd):
         """Private function that handles the 'get_config' command"""
-        answer = {}
         if cmd != None:
             if type(cmd) == dict:
-                if 'module_name' in cmd and cmd['module_name'] != '':
-                    module_name = cmd['module_name']
-                    try:
-                        answer = isc.config.ccsession.create_answer(0, data.find(self.config.data, module_name))
-                    except data.DataNotFoundError as dnfe:
-                        # no data is ok, that means we have nothing that
-                        # deviates from default values
-                        answer = isc.config.ccsession.create_answer(0, { 'version': self.config.CONFIG_VERSION })
+                return self._handle_get_config_dict(cmd)
+            else:
+                return ccsession.create_answer(1, "Bad get_config command, argument not a dict")
+        else:
+            return ccsession.create_answer(0, self.config.data)
+
+    def _handle_set_config_module(self, cmd):
+        # the answer comes (or does not come) from the relevant module
+        # so we need a variable to see if we got it
+        answer = None
+        # todo: use api (and check the data against the definition?)
+        old_data = copy.deepcopy(self.config.data)
+        module_name = cmd[0]
+        conf_part = data.find_no_exc(self.config.data, module_name)
+        if conf_part:
+            data.merge(conf_part, cmd[1])
+            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)
+        else:
+            conf_part = data.set(self.config.data, module_name, {})
+            data.merge(conf_part[module_name], cmd[1])
+            # send out changed info
+            update_cmd = ccsession.create_command(ccsession.COMMAND_CONFIG_UPDATE,
+                                                  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)
+        if answer:
+            rcode, val = ccsession.parse_answer(answer)
+            if rcode == 0:
+                self.write_config()
+            else:
+                self.config.data = old_data
+        return answer
+
+    def _handle_set_config_all(self, cmd):
+        old_data = copy.deepcopy(self.config.data)
+        data.merge(self.config.data, cmd[0])
+        # send out changed info
+        got_error = False
+        err_list = []
+        for module in self.config.data:
+            if module != "version" and \
+               (module not in old_data or self.config.data[module] != old_data[module]):
+                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:
+                    got_error = True
+                    err_list.append("No answer message from " + module)
                 else:
-                    answer = isc.config.ccsession.create_answer(1, "Bad module_name in get_config command")
-            else:
-                answer = isc.config.ccsession.create_answer(1, "Bad get_config command, argument not a dict")
-        else:
-            answer = isc.config.ccsession.create_answer(0, self.config.data)
-        return answer
+                    rcode, val = ccsession.parse_answer(answer)
+                    if rcode != 0:
+                        got_error = True
+                        err_list.append(val)
+        if not got_error:
+            self.write_config()
+            return ccsession.create_answer(0)
+        else:
+            # TODO rollback changes that did get through, should we re-send update?
+            self.config.data = old_data
+            return ccsession.create_answer(1, " ".join(err_list))
 
     def _handle_set_config(self, cmd):
         """Private function that handles the 'set_config' command"""
         answer = None
         if cmd == None:
-            return isc.config.ccsession.create_answer(1, "Wrong number of arguments")
+            return ccsession.create_answer(1, "Wrong number of arguments")
         if len(cmd) == 2:
-            # todo: use api (and check the data against the definition?)
-            old_data = copy.deepcopy(self.config.data)
-            module_name = cmd[0]
-            conf_part = data.find_no_exc(self.config.data, module_name)
-            if conf_part:
-                data.merge(conf_part, cmd[1])
-                update_cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, conf_part)
-                seq = self.cc.group_sendmsg(update_cmd, module_name)
-                answer, env = self.cc.group_recvmsg(False, seq)
-            else:
-                conf_part = data.set(self.config.data, module_name, {})
-                data.merge(conf_part[module_name], cmd[1])
-                # send out changed info
-                update_cmd = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_CONFIG_UPDATE, 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)
-            if answer:
-                rcode, val = isc.config.ccsession.parse_answer(answer)
-                if rcode == 0:
-                    self.write_config()
-                else:
-                    self.config.data = old_data
+            answer = self._handle_set_config_module(cmd)
         elif len(cmd) == 1:
-            old_data = copy.deepcopy(self.config.data)
-            data.merge(self.config.data, cmd[0])
-            # send out changed info
-            got_error = False
-            err_list = []
-            for module in self.config.data:
-                if module != "version" and (module not in old_data or self.config.data[module] != old_data[module]):
-                    update_cmd = isc.config.ccsession.create_command(isc.config.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:
-                        got_error = True
-                        err_list.append("No answer message from " + module)
-                    else:
-                        rcode, val = isc.config.ccsession.parse_answer(answer)
-                        if rcode != 0:
-                            got_error = True
-                            err_list.append(val)
-            if not got_error:
-                self.write_config()
-                answer = isc.config.ccsession.create_answer(0)
-            else:
-                # TODO rollback changes that did get through, should we re-send update?
-                self.config.data = old_data
-                answer = isc.config.ccsession.create_answer(1, " ".join(err_list))
-        else:
-            answer = isc.config.ccsession.create_answer(1, "Wrong number of arguments")
+            answer = self._handle_set_config_all(cmd)
+        else:
+            answer = ccsession.create_answer(1, "Wrong number of arguments")
         if not answer:
-            answer = isc.config.ccsession.create_answer(1, "No answer message from " + cmd[0])
+            answer = ccsession.create_answer(1, "No answer message from " + cmd[0])
             
         return answer
 
@@ -303,42 +345,38 @@
         
         # We should make one general 'spec update for module' that
         # passes both specification and commands at once
-        spec_update = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_SPECIFICATION_UPDATE,
-                                                          [ spec.get_module_name(), spec.get_config_spec() ])
+        spec_update = ccsession.create_command(ccsession.COMMAND_MODULE_SPECIFICATION_UPDATE,
+                                               [ spec.get_module_name(), spec.get_full_spec() ])
         self.cc.group_sendmsg(spec_update, "Cmd-Ctrld")
-        cmds_update = isc.config.ccsession.create_command(isc.config.ccsession.COMMAND_COMMANDS_UPDATE,
-                                                          [ spec.get_module_name(), spec.get_commands_spec() ])
-        self.cc.group_sendmsg(cmds_update, "Cmd-Ctrld")
-        answer = isc.config.ccsession.create_answer(0)
-        return answer
+        return ccsession.create_answer(0)
 
     def handle_msg(self, msg):
         """Handle a command from the cc channel to the configuration manager"""
         answer = {}
-        cmd, arg = isc.config.ccsession.parse_command(msg)
+        cmd, arg = ccsession.parse_command(msg)
         if cmd:
-            if cmd == isc.config.ccsession.COMMAND_GET_COMMANDS_SPEC:
-                answer = isc.config.ccsession.create_answer(0, self.get_commands_spec())
-            elif cmd == isc.config.ccsession.COMMAND_GET_MODULE_SPEC:
+            if cmd == ccsession.COMMAND_GET_COMMANDS_SPEC:
+                answer = ccsession.create_answer(0, self.get_commands_spec())
+            elif cmd == ccsession.COMMAND_GET_MODULE_SPEC:
                 answer = self._handle_get_module_spec(arg)
-            elif cmd == isc.config.ccsession.COMMAND_GET_CONFIG:
+            elif cmd == ccsession.COMMAND_GET_CONFIG:
                 answer = self._handle_get_config(arg)
-            elif cmd == isc.config.ccsession.COMMAND_SET_CONFIG:
+            elif cmd == ccsession.COMMAND_SET_CONFIG:
                 answer = self._handle_set_config(arg)
-            elif cmd == isc.config.ccsession.COMMAND_SHUTDOWN:
+            elif cmd == ccsession.COMMAND_SHUTDOWN:
                 # TODO: logging
                 #print("[b10-cfgmgr] Received shutdown command")
                 self.running = False
-                answer = isc.config.ccsession.create_answer(0)
-            elif cmd == isc.config.ccsession.COMMAND_MODULE_SPEC:
+                answer = ccsession.create_answer(0)
+            elif cmd == ccsession.COMMAND_MODULE_SPEC:
                 try:
                     answer = self._handle_module_spec(isc.config.ModuleSpec(arg))
                 except isc.config.ModuleSpecError as dde:
-                    answer = isc.config.ccsession.create_answer(1, "Error in data definition: " + str(dde))
-            else:
-                answer = isc.config.ccsession.create_answer(1, "Unknown command: " + str(cmd))
-        else:
-            answer = isc.config.ccsession.create_answer(1, "Unknown message format: " + str(msg))
+                    answer = ccsession.create_answer(1, "Error in data definition: " + str(dde))
+            else:
+                answer = ccsession.create_answer(1, "Unknown command: " + str(cmd))
+        else:
+            answer = ccsession.create_answer(1, "Unknown message format: " + str(msg))
         return answer
         
     def run(self):

Modified: experiments/python-binding/src/lib/python/isc/config/config_data.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/config_data.py (original)
+++ experiments/python-binding/src/lib/python/isc/config/config_data.py Wed Jun  9 09:52:34 2010
@@ -52,6 +52,51 @@
     elif data_type == "map" and type(value) != dict:
         # todo: check types of map contents too
         raise isc.cc.data.DataTypeError(str(value) + " is not a map")
+
+def convert_type(spec_part, value):
+    """Convert the give value(type is string) according specification 
+    part relevant for the value. Raises an isc.cc.data.DataTypeError 
+    exception if conversion failed.
+    """
+    if type(spec_part) == dict and 'item_type' in spec_part:
+        data_type = spec_part['item_type']
+    else:
+        raise isc.cc.data.DataTypeError(str("Incorrect specification part for type convering"))
+   
+    try:
+        if data_type == "integer":
+            return int(value)
+        elif data_type == "real":
+            return float(value)
+        elif data_type == "boolean":
+            return str.lower(str(value)) != 'false'
+        elif data_type == "string":
+            return str(value)
+        elif data_type == "list":
+            ret = []
+            if type(value) == list:
+                for item in value:    
+                    ret.append(convert_type(spec_part['list_item_spec'], item))
+            elif type(value) == str:    
+                value = value.split(',')
+                for item in value:    
+                    sub_value = item.split()
+                    for sub_item in sub_value:
+                        ret.append(convert_type(spec_part['list_item_spec'], sub_item))
+
+            if ret == []:
+                raise isc.cc.data.DataTypeError(str(value) + " is not a list")
+
+            return ret
+        elif data_type == "map":
+            return dict(value)
+            # todo: check types of map contents too
+        else:
+            return value
+    except ValueError as err:
+        raise isc.cc.data.DataTypeError(str(err))
+    except TypeError as err:
+        raise isc.cc.data.DataTypeError(str(err))
 
 def find_spec_part(element, identifier):
     """find the data definition for the given identifier
@@ -382,7 +427,6 @@
                         else:
                             entry['default'] = False
                         result.append(entry)
-            #print(spec)
         return result
 
     def set_value(self, identifier, value):

Modified: experiments/python-binding/src/lib/python/isc/config/module_spec.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/module_spec.py (original)
+++ experiments/python-binding/src/lib/python/isc/config/module_spec.py Wed Jun  9 09:52:34 2010
@@ -80,14 +80,46 @@
             return _validate_spec_list(data_def, full, data, errors)
         else:
             # no spec, always bad
-            errors.append("No config_data specification")
+            if errors != None:
+                errors.append("No config_data specification")
             return False
 
+    def validate_command(self, cmd_name, cmd_params, errors = None):
+        '''Check whether the given piece of command conforms to this 
+        command definition. If so, it reutrns True. If not, it will 
+        return False. If errors is given, and is an array, a string
+        describing the error will be appended to it. The current version
+        stops as soon as there is one error.
+           cmd_name is command name to be validated, cmd_params includes 
+        command's parameters needs to be validated. cmd_params must 
+        be a map, with the format like:
+        {param1_name: param1_value, param2_name: param2_value}
+        '''
+        cmd_spec = self.get_commands_spec()
+        if not cmd_spec:
+            return False
+
+        for cmd in cmd_spec:
+            if cmd['command_name'] != cmd_name:
+                continue
+            return _validate_spec_list(cmd['command_args'], True, cmd_params, errors)
+
+        return False
 
     def get_module_name(self):
         """Returns a string containing the name of the module as
-           specified by the specification given at __init__"""
+           specified by the specification given at __init__()"""
         return self._module_spec['module_name']
+
+    def get_module_description(self):
+        """Returns a string containing the description of the module as
+           specified by the specification given at __init__().
+           Returns an empty string if there is no description.
+        """
+        if 'module_description' in self._module_spec:
+            return self._module_spec['module_description']
+        else:
+            return ""
 
     def get_full_spec(self):
         """Returns a dict representation of the full module specification"""
@@ -123,6 +155,9 @@
         raise ModuleSpecError("data specification not a dict")
     if "module_name" not in module_spec:
         raise ModuleSpecError("no module_name in module_spec")
+    if "module_description" in module_spec and \
+       type(module_spec["module_description"]) != str:
+        raise ModuleSpecError("module_description is not a string")
     if "config_data" in module_spec:
         _check_config_spec(module_spec["config_data"])
     if "commands" in module_spec:

Modified: experiments/python-binding/src/lib/python/isc/config/tests/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/tests/Makefile.am (original)
+++ experiments/python-binding/src/lib/python/isc/config/tests/Makefile.am Wed Jun  9 09:52:34 2010
@@ -9,7 +9,7 @@
 check-local:
 	for pytest in $(PYTESTS) ; do \
 	echo Running test: $$pytest ; \
-	env PYTHONPATH=$(abs_top_srcdir)/src/lib/python \
+	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 ; \
 	done

Modified: experiments/python-binding/src/lib/python/isc/config/tests/ccsession_test.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/tests/ccsession_test.py (original)
+++ experiments/python-binding/src/lib/python/isc/config/tests/ccsession_test.py Wed Jun  9 09:52:34 2010
@@ -13,6 +13,8 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+# $Id$
+
 #
 # Tests for the ConfigData and MultiConfigData classes
 #
@@ -375,7 +377,7 @@
         if name in self.get_answers:
             return self.get_answers[name]
         else:
-            return None
+            return {}
     
     def send_POST(self, name, arg = None):
         if name in self.post_answers:
@@ -396,23 +398,20 @@
         
     def create_uccs2(self, fake_conn):
         module_spec = isc.config.module_spec_from_file(self.spec_file("spec2.spec"))
-        fake_conn.set_get_answer('/config_spec', { module_spec.get_module_name(): module_spec.get_config_spec()})
-        fake_conn.set_get_answer('/commands', { module_spec.get_module_name(): module_spec.get_commands_spec()})
+        fake_conn.set_get_answer('/module_spec', { module_spec.get_module_name(): module_spec.get_full_spec()})
         fake_conn.set_get_answer('/config_data', { 'version': 1 })
         return UIModuleCCSession(fake_conn)
 
     def test_init(self):
         fake_conn = fakeUIConn()
-        fake_conn.set_get_answer('/config_spec', {})
-        fake_conn.set_get_answer('/commands', {})
+        fake_conn.set_get_answer('/module_spec', {})
         fake_conn.set_get_answer('/config_data', { 'version': 1 })
         uccs = UIModuleCCSession(fake_conn)
         self.assertEqual({}, uccs._specifications)
         self.assertEqual({ 'version': 1}, uccs._current_config)
 
         module_spec = isc.config.module_spec_from_file(self.spec_file("spec2.spec"))
-        fake_conn.set_get_answer('/config_spec', { module_spec.get_module_name(): module_spec.get_config_spec()})
-        fake_conn.set_get_answer('/commands', { module_spec.get_module_name(): module_spec.get_commands_spec()})
+        fake_conn.set_get_answer('/module_spec', { module_spec.get_module_name(): module_spec.get_full_spec()})
         fake_conn.set_get_answer('/config_data', { 'version': 1 })
         uccs = UIModuleCCSession(fake_conn)
         self.assertEqual(module_spec._module_spec, uccs._specifications['Spec2']._module_spec)

Modified: experiments/python-binding/src/lib/python/isc/config/tests/cfgmgr_test.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/tests/cfgmgr_test.py (original)
+++ experiments/python-binding/src/lib/python/isc/config/tests/cfgmgr_test.py Wed Jun  9 09:52:34 2010
@@ -12,6 +12,8 @@
 # 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$
 
 #
 # Tests for the configuration manager module
@@ -262,7 +264,7 @@
                                 {'result': [0]})
         self._handle_msg_helper({ "command": [ "module_spec", { 'foo': 1 } ] },
                                 {'result': [1, 'Error in data definition: no module_name in module_spec']})
-        self._handle_msg_helper({ "command": [ "get_module_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_config_spec() } ]})
+        self._handle_msg_helper({ "command": [ "get_module_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_full_spec() } ]})
         self._handle_msg_helper({ "command": [ "get_commands_spec" ] }, { 'result': [ 0, { self.spec.get_module_name(): self.spec.get_commands_spec() } ]})
         # re-add this once we have new way to propagate spec changes (1 instead of the current 2 messages)
         #self.assertEqual(len(self.fake_session.message_queue), 2)

Modified: experiments/python-binding/src/lib/python/isc/config/tests/config_data_test.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/tests/config_data_test.py (original)
+++ experiments/python-binding/src/lib/python/isc/config/tests/config_data_test.py Wed Jun  9 09:52:34 2010
@@ -13,6 +13,8 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+# $Id$
+
 #
 # Tests for the ConfigData and MultiConfigData classes
 #
@@ -92,6 +94,71 @@
         #self.assertRaises(isc.cc.data.DataTypeError, check_type, spec_part, { "value1": 1 })
 
         self.assertRaises(isc.cc.data.DataTypeError, check_type, config_spec, 1)
+
+    def test_convert_type(self):
+        config_spec = isc.config.module_spec_from_file(self.data_path + os.sep + "spec22.spec").get_config_spec()
+        spec_part = find_spec_part(config_spec, "value1")
+        self.assertEqual(1, convert_type(spec_part, '1'))
+        self.assertEqual(2, convert_type(spec_part, 2.1))
+        self.assertEqual(2, convert_type(spec_part, '2'))
+        self.assertEqual(3, convert_type(spec_part, '3'))
+        self.assertEqual(1, convert_type(spec_part, True))
+
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, "a")
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, [ 1, 2 ])
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, { "a": 1 })
+        
+        spec_part = find_spec_part(config_spec, "value2")
+        self.assertEqual(1.1, convert_type(spec_part, '1.1'))
+        self.assertEqual(123.0, convert_type(spec_part, '123'))
+        self.assertEqual(1.0, convert_type(spec_part, True))
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, "a")
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, [ 1, 2 ])
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, { "a": 1 })
+
+        spec_part = find_spec_part(config_spec, "value3")
+        self.assertEqual(True, convert_type(spec_part, 'True'))
+        self.assertEqual(False, convert_type(spec_part, 'False'))
+        self.assertEqual(True, convert_type(spec_part, 1))
+        self.assertEqual(True, convert_type(spec_part, 1.1))
+        self.assertEqual(True, convert_type(spec_part, 'a'))
+        self.assertEqual(True, convert_type(spec_part, [1, 2]))
+        self.assertEqual(True, convert_type(spec_part, {'a' : 1}))
+
+        spec_part = find_spec_part(config_spec, "value4")
+        self.assertEqual('asdf', convert_type(spec_part, "asdf"))
+        self.assertEqual('1', convert_type(spec_part, 1))
+        self.assertEqual('1.1', convert_type(spec_part, 1.1))
+        self.assertEqual('True', convert_type(spec_part, True))
+        
+        spec_part = find_spec_part(config_spec, "value5")
+        self.assertEqual([1, 2], convert_type(spec_part, '1, 2'))
+        self.assertEqual([1, 2, 3], convert_type(spec_part, '1 2  3'))
+        self.assertEqual([1, 2, 3,4], convert_type(spec_part, '1 2  3, 4'))
+        self.assertEqual([1], convert_type(spec_part, [1,]))
+        self.assertEqual([1,2], convert_type(spec_part, [1,2]))
+        self.assertEqual([1,2], convert_type(spec_part, ['1', '2']))
+
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, 1.1)
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, True)
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, "a")
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, [ "a", "b" ])
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, [ "1", "b" ])
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, { "a": 1 })
+
+        spec_part = find_spec_part(config_spec, "value7")
+        self.assertEqual(['1', '2'], convert_type(spec_part, '1, 2'))
+        self.assertEqual(['1', '2', '3'], convert_type(spec_part, '1 2  3'))
+        self.assertEqual(['1', '2', '3','4'], convert_type(spec_part, '1 2  3, 4'))
+        self.assertEqual([1], convert_type(spec_part, [1,]))
+        self.assertEqual([1,2], convert_type(spec_part, [1,2]))
+        self.assertEqual(['1','2'], convert_type(spec_part, ['1', '2']))
+
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, 1.1)
+        self.assertRaises(isc.cc.data.DataTypeError, convert_type, spec_part, True)
+        self.assertEqual(['a'], convert_type(spec_part, "a"))
+        self.assertEqual(['a', 'b'], convert_type(spec_part, ["a", "b" ]))
+        self.assertEqual([1, 'b'], convert_type(spec_part, [1, "b" ]))
 
     def test_find_spec_part(self):
         config_spec = self.cd.get_module_spec().get_config_spec()

Modified: experiments/python-binding/src/lib/python/isc/config/tests/module_spec_test.py
==============================================================================
--- experiments/python-binding/src/lib/python/isc/config/tests/module_spec_test.py (original)
+++ experiments/python-binding/src/lib/python/isc/config/tests/module_spec_test.py Wed Jun  9 09:52:34 2010
@@ -12,6 +12,8 @@
 # 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$
 
 #
 # Tests for the module_spec module
@@ -73,6 +75,7 @@
         self.assertRaises(ModuleSpecError, self.read_spec_file, "spec19.spec")
         self.assertRaises(ModuleSpecError, self.read_spec_file, "spec20.spec")
         self.assertRaises(ModuleSpecError, self.read_spec_file, "spec21.spec")
+        self.assertRaises(ModuleSpecError, self.read_spec_file, "spec26.spec")
 
     def validate_data(self, specfile_name, datafile_name):
         dd = self.read_spec_file(specfile_name);
@@ -91,10 +94,32 @@
         self.assertEqual(True, self.validate_data("spec22.spec", "data22_7.data"))
         self.assertEqual(False, self.validate_data("spec22.spec", "data22_8.data"))
 
+    def validate_command_params(self, specfile_name, datafile_name, cmd_name):
+        dd = self.read_spec_file(specfile_name);
+        data_file = open(self.spec_file(datafile_name))
+        data_str = data_file.read()
+        params = isc.cc.data.parse_value_str(data_str)
+        return dd.validate_command(cmd_name, params)
+
+    def test_command_validation(self):
+        self.assertEqual(True, self.validate_command_params("spec27.spec", "data22_1.data", 'cmd1'))
+        self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_2.data",'cmd1'))
+        self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_3.data", 'cmd1'))
+        self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_4.data", 'cmd1'))
+        self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_5.data", 'cmd1'))
+        self.assertEqual(True, self.validate_command_params("spec27.spec", "data22_6.data", 'cmd1'))
+        self.assertEqual(True, self.validate_command_params("spec27.spec", "data22_7.data", 'cmd1'))
+        self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_8.data", 'cmd1'))
+        self.assertEqual(False, self.validate_command_params("spec27.spec", "data22_8.data", 'cmd2'))
+
     def test_init(self):
         self.assertRaises(ModuleSpecError, ModuleSpec, 1)
         module_spec = isc.config.module_spec_from_file(self.spec_file("spec1.spec"), False)
         self.spec1(module_spec)
+
+        module_spec = isc.config.module_spec_from_file(self.spec_file("spec25.spec"), True)
+        self.assertEqual("Spec25", module_spec.get_module_name())
+        self.assertEqual("Just an empty module", module_spec.get_module_description())
 
     def test_str(self):
         module_spec = isc.config.module_spec_from_file(self.spec_file("spec1.spec"), False)

Modified: experiments/python-binding/src/lib/xfr/Makefile.am
==============================================================================
--- experiments/python-binding/src/lib/xfr/Makefile.am (original)
+++ experiments/python-binding/src/lib/xfr/Makefile.am Wed Jun  9 09:52:34 2010
@@ -1,12 +1,8 @@
-SUBDIRS = . 
-
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
-AM_CPPFLAGS += -I$(top_srcdir)/ext -Wno-strict-aliasing
 
-if GCC_WERROR_OK
-AM_CPPFLAGS += -Werror
-endif
+AM_CXXFLAGS = $(B10_CXXFLAGS) -Wno-strict-aliasing
+AM_CXXFLAGS += -Wno-unused-parameter # see src/lib/cc/Makefile.am
 
 CLEANFILES = *.gcno *.gcda
 
@@ -15,28 +11,12 @@
 libxfr_la_SOURCES += fd_share.h fd_share.cc
 
 pyexec_LTLIBRARIES = libxfr_python.la
-libxfr_python_la_SOURCES = fdshare_python.cc
+libxfr_python_la_SOURCES = fdshare_python.cc fd_share.cc fd_share.h
 libxfr_python_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-libxfr_python_la_LDFLAGS = $(PYTHON_LDFLAGS)
-# (still need boost for asio)
-libxfr_python_la_LDFLAGS += $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
-libxfr_python_la_LDFLAGS += -module
+libxfr_python_la_CXXFLAGS = $(AM_CXXFLAGS)
 
-libxfr_python_la_LIBADD = $(top_builddir)/src/lib/xfr/libxfr.la
-libxfr_python_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
-libxfr_python_la_LIBADD += $(BOOST_SYSTEM_LIB) $(PYTHON_LIB)
-libxfr_python_la_LIBADD += $(PYTHON_LIB)
+#bind10_xfr_la_LDFLAGS = $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
 
-#if HAVE_BOOST_PYTHON
-#pyexec_LTLIBRARIES += bind10_xfr.la
-#bind10_xfr_la_SOURCES = python_xfr.cc fd_share.cc fd_share.h
-#bind10_xfr_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
-#if GCC_WERROR_OK
-# XXX: Boost.Python triggers strict aliasing violation, so if we use -Werror
-# we need to suppress the warnings.
-#bind10_xfr_la_CPPFLAGS += -fno-strict-aliasing
-#endif
-#bind10_xfr_la_LDFLAGS = $(BOOST_LDFLAGS) $(PYTHON_LDFLAGS)
 # Python prefers .so, while some OSes (specifically MacOS) use a different
 # suffix for dynamic objects.  -module is necessary to work this around.
 #bind10_xfr_la_LDFLAGS += -module

Modified: experiments/python-binding/src/lib/xfr/xfrout_client.cc
==============================================================================
--- experiments/python-binding/src/lib/xfr/xfrout_client.cc (original)
+++ experiments/python-binding/src/lib/xfr/xfrout_client.cc Wed Jun  9 09:52:34 2010
@@ -17,46 +17,72 @@
 #include <cstdlib>
 #include <cstring>
 #include <iostream>
+
+#include <asio.hpp>
+
 #include "fd_share.h"
 #include "xfrout_client.h"
 
-using boost::asio::local::stream_protocol;
+using namespace std;
+using asio::local::stream_protocol;
 
 namespace isc {
 namespace xfr {
 
+struct XfroutClientImpl {
+    XfroutClientImpl(const string& file);
+    const std::string file_path_;
+    asio::io_service io_service_;
+    // The socket used to communicate with the xfrout server.
+    stream_protocol::socket socket_;
+};
+
+XfroutClientImpl::XfroutClientImpl(const string& file) :
+    file_path_(file), socket_(io_service_)
+{}
+
+XfroutClient::XfroutClient(const string& file) :
+    impl_(new XfroutClientImpl(file))
+{}
+
+XfroutClient::~XfroutClient()
+{
+    delete impl_;
+}
+
 void
 XfroutClient::connect() {
-    socket_.connect(stream_protocol::endpoint(file_path_));
+    impl_->socket_.connect(stream_protocol::endpoint(impl_->file_path_));
 }
 
 void
 XfroutClient::disconnect() {
-    socket_.close();
+    impl_->socket_.close();
 }
 
 int 
 XfroutClient::sendXfroutRequestInfo(const int tcp_sock, uint8_t* msg_data,
                                     const uint16_t msg_len)
 {
-    if (-1 == send_fd(socket_.native(), tcp_sock)) {
+    if (-1 == send_fd(impl_->socket_.native(), tcp_sock)) {
         isc_throw(XfroutError,
                   "Fail to send socket descriptor to xfrout module");
     }
 
     // XXX: this shouldn't be blocking send, even though it's unlikely to block.
     const uint8_t lenbuf[2] = { msg_len >> 8, msg_len & 0xff };
-    if (send(socket_.native(), lenbuf, sizeof(lenbuf), 0) != sizeof(lenbuf)) {
+    if (send(impl_->socket_.native(), lenbuf, sizeof(lenbuf), 0) !=
+        sizeof(lenbuf)) {
         isc_throw(XfroutError,
                   "failed to send XFR request length to xfrout module");
     }
-    if (send(socket_.native(), msg_data, msg_len, 0) != msg_len) {
+    if (send(impl_->socket_.native(), msg_data, msg_len, 0) != msg_len) {
         isc_throw(XfroutError,
                   "failed to send XFR request data to xfrout module");
     }
     
     int databuf = 0;
-    if (recv(socket_.native(), &databuf, sizeof(int), 0) != 0) {
+    if (recv(impl_->socket_.native(), &databuf, sizeof(int), 0) != 0) {
         isc_throw(XfroutError,
                   "xfr query hasn't been processed properly by xfrout module");
     }

Modified: experiments/python-binding/src/lib/xfr/xfrout_client.h
==============================================================================
--- experiments/python-binding/src/lib/xfr/xfrout_client.h (original)
+++ experiments/python-binding/src/lib/xfr/xfrout_client.h Wed Jun  9 09:52:34 2010
@@ -17,13 +17,16 @@
 #ifndef _XFROUT_CLIENT_H
 #define _XFROUT_CLIENT_H
 
+#include <stdint.h>
+
 #include <string>
 
-#include <boost/asio.hpp>
 #include <exceptions/exceptions.h>
 
 namespace isc {
 namespace xfr {
+
+struct XfroutClientImpl;
 
 class XfroutError: public Exception {
 public:
@@ -31,22 +34,21 @@
         isc::Exception(file, line, what) {}
 };
 
-using boost::asio::local::stream_protocol;
 class XfroutClient {
 public:
-    XfroutClient(const std::string& file):
-        socket_(io_service_), file_path_(file) {}
-
+    XfroutClient(const std::string& file);
+    ~XfroutClient();
+private:
+    // make this class non copyable
+    XfroutClient(const XfroutClient& source);
+    XfroutClient& operator=(const XfroutClient& source);
+public:
     void connect();
     void disconnect();
     int sendXfroutRequestInfo(int tcp_sock, uint8_t* msg_data,
                               uint16_t msg_len);
-
 private:
-    boost::asio::io_service io_service_;
-    // The socket used to communicate with the xfrout server.
-    stream_protocol::socket socket_;
-    const std::string file_path_;
+    XfroutClientImpl* impl_;
 };
 
 } // End for namespace xfr




More information about the bind10-changes mailing list