BIND 10 trac499, updated. 87d58087b71b509d9798bd700b9ba968712e142d [trac499] Merge branch 'master' into trac499

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Mar 9 12:45:16 UTC 2011


The branch, trac499 has been updated
       via  87d58087b71b509d9798bd700b9ba968712e142d (commit)
       via  290bbf2d7c93c202b22f1f4e2638ae01038bc983 (commit)
       via  58da05cd5f8709c8f4e1824c5479a0e3cd2b4371 (commit)
       via  416fcf7eb6c7c0dc249bcc838d75504f070750a1 (commit)
       via  64978870d1b6843e94268160f5e9c7b7dfbeb755 (commit)
       via  a447b8e583551311e487816e11a171fdb0e8951a (commit)
       via  e0863720a874d75923ea66adcfbf5b2948efb10a (commit)
       via  241571157deb66f6766918b783379409e294e2f5 (commit)
       via  65a77d8fde64d464c75917a1ab9b6b3f02640ca6 (commit)
       via  9287cc8f31d6ed03cdcd95f6ca59b58ed6d695b6 (commit)
       via  34eaa7c5e831bb170f0fe8792e40df88f66ed8b9 (commit)
       via  0eefd8be74290fd9e72e3d25356c64b24c844816 (commit)
       via  2be9594e5c6cac0e01a75a06d8df31d8cef98380 (commit)
       via  17f4eab177a8d459024a5fcf2b43e6826c129891 (commit)
       via  de2d7124bd8a6bf3f2c0a6e661dc5b6b178765cc (commit)
       via  1af89c43e91b613bf3d8ece42ec5d93c19a5b225 (commit)
       via  71bcc9a5c413276bd90276c24ee28d59478a138e (commit)
       via  6ac000df85625f5921e8895a1aafff5e4be3ba9c (commit)
       via  7fef6a88c5ab2cedc5f2fa0003ae1beb7a380b9c (commit)
       via  b0c4e1599b68046bbd72455ce90433285b226ffe (commit)
       via  56f0f77fe500b6cb41cda2a950b4349f0778561e (commit)
       via  e49c4b5a038981cea80bf81613efa2c538c8b3e0 (commit)
       via  5222b51a047d8f2352bc9f92fd022baf1681ed81 (commit)
       via  ccd3fea75828ec4e0e2b20d8bba1d7b103164141 (commit)
       via  a663b567f5a57c19c033de049219e4a5eb6d936b (commit)
       via  4cf5938f86b3c1a54beac417f6723505183ddf11 (commit)
       via  977a6a742c821ed49fc7d977f917b47f23563bdb (commit)
       via  137a6934a14cf0c5b5c065e910b8b364beb0973f (commit)
       via  b23ef1cf58b0754e23e550362e7a979d5f8624ef (commit)
       via  bdc63200a7e2adcde2b0ce44aaeb8477fb059d17 (commit)
       via  5ff855e14dca375c24404eebc4573b77dba915d3 (commit)
       via  058f40e75eb59aea1d3e18ffcdfdacc8386aafa3 (commit)
       via  b9d341ecd382b44d72888899e3559d7d41baa203 (commit)
       via  e0d5584bdb3ca05b078693787c35d8f8f9228040 (commit)
       via  4596c143eadfb9d67c5395bb6fa367470976d0cb (commit)
       via  f3bd834c8e9334004994c33d0798ed6b61a7a99b (commit)
       via  860a2965d04f80fd0e90d3c5100332a8bb2ae9d8 (commit)
       via  c4f4d32eed0f4c26e4968336179a1e749e925aa7 (commit)
       via  b2d210a1ed486dc8c1083deb6f1b0bf2802e8d57 (commit)
       via  3407184a20c367a0de02b41befb4db16971c9589 (commit)
       via  26582526e20e56ea4547a447cfa93e122af0f0e1 (commit)
       via  6934390c92855d4006b727e1c8c1c89688afeb5f (commit)
       via  333edc6244dafdab42258b84a46237c6dcf936a0 (commit)
       via  8af2ccd45c7f070d2aa168763815fe8a82808e79 (commit)
       via  19f9f10fa5594bfe311688823fba5dd149e76a59 (commit)
       via  5851a6cc19356b49fcc2500f5d40e7861874561e (commit)
       via  8be2bf19228473f5d54f5015e893b44791a5c0c2 (commit)
       via  edfcbcaccbf4b8098f5cfc1bd1943fe4542b3306 (commit)
       via  7396247046ccc046d711265100aa8d46be057626 (commit)
       via  9c3f27137967b5f92c430baab6ab442258d9d692 (commit)
       via  56df4f9ab31b300b83c26fbeb1a7cf7951f8338e (commit)
       via  2298392e3ce9b5a470f4c0e3b2a22ba571f9b8ab (commit)
       via  309d02a51ee22ff4c0226784ecd7bb4394d19542 (commit)
       via  ddd7b7c3dfdebae68e3742e175e4931f0a5f6c5e (commit)
       via  a2609d0762b9dfdf2750a1bc44ea33525c634f5b (commit)
       via  de130e6d9b6dec3586126f660123a905cc9a284a (commit)
       via  53b5297513ee2320556dead019f268e79b49f77a (commit)
       via  a9211d7973042503353e61f0e16ea092c0f621bf (commit)
       via  48211526895ce56de771e65a7e6d23892c639660 (commit)
       via  ff55e63140852f4c7cf8a0404dde36442c45ff4a (commit)
       via  b723719cdad0da4db9b2099596c09f407dbdb135 (commit)
      from  827babb0d6caade8ca685e5f3e779c756f9ebe1a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 87d58087b71b509d9798bd700b9ba968712e142d
Merge: 827babb0d6caade8ca685e5f3e779c756f9ebe1a 290bbf2d7c93c202b22f1f4e2638ae01038bc983
Author: Stephen Morris <stephen at isc.org>
Date:   Wed Mar 9 12:44:59 2011 +0000

    [trac499] Merge branch 'master' into trac499
    
    Conflicts:
    	src/lib/asiolink/Makefile.am
    	src/lib/asiolink/io_fetch.cc
    	src/lib/log/Makefile.am

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |   33 +++
 Makefile.am                                        |    7 +-
 README                                             |    2 -
 configure.ac                                       |   13 ++
 doc/guide/bind10-guide.xml                         |   15 +--
 src/bin/auth/auth.spec.pre.in                      |   10 +-
 src/bin/auth/b10-auth.8                            |   16 ++-
 src/bin/auth/b10-auth.xml                          |   11 +-
 src/bin/auth/main.cc                               |    8 +-
 src/bin/bind10/bind10.py.in                        |   34 +++
 .../tests/{bind10_test.py => bind10_test.py.in}    |   51 +++++-
 src/bin/cfgmgr/b10-cfgmgr.py.in                    |   14 +-
 src/bin/resolver/b10-resolver.8                    |    2 +-
 src/bin/resolver/b10-resolver.xml                  |    5 +-
 src/bin/resolver/main.cc                           |    1 -
 src/bin/resolver/resolver.spec.pre.in              |    6 +-
 src/bin/xfrout/xfrout.py.in                        |    6 +-
 src/lib/asiolink/Makefile.am                       |    1 +
 src/lib/asiolink/io_fetch.cc                       |    6 +-
 .../root_logger_name.cc => asiolink/qid_gen.cc}    |   44 +++--
 src/lib/asiolink/qid_gen.h                         |   85 ++++++++
 src/lib/asiolink/tcp_server.cc                     |   15 ++-
 src/lib/asiolink/tests/Makefile.am                 |    1 +
 src/lib/asiolink/tests/qid_gen_unittest.cc         |   59 +++++
 src/lib/asiolink/udp_server.cc                     |    9 +
 src/lib/log/Makefile.am                            |    5 +-
 src/lib/log/{documentation.txt => README}          |  124 +++--------
 tests/Makefile.am                                  |    1 +
 tests/system/Makefile.am                           |   13 ++
 tests/system/README                                |   62 ++++++
 tests/system/cleanall.sh                           |   33 +++
 tests/system/conf.sh.in                            |   54 +++++
 tests/system/glue/auth.good                        |   15 ++
 tests/system/glue/clean.sh                         |   23 ++
 tests/system/glue/example.good                     |   19 ++
 tests/system/glue/noglue.good                      |   14 ++
 tests/system/glue/nsx1/b10-config.db.in            |    9 +
 tests/system/glue/nsx1/com.db                      |   31 +++
 tests/system/glue/nsx1/net.db                      |   32 +++
 tests/system/glue/nsx1/root-servers.nil.db         |   26 +++
 tests/system/glue/nsx1/root.db                     |   55 +++++
 tests/system/glue/setup.sh.in                      |   25 +++
 tests/system/glue/test.good                        |   19 ++
 tests/system/glue/tests.sh                         |   66 ++++++
 tests/system/ifconfig.sh                           |  226 ++++++++++++++++++++
 tests/system/run.sh                                |  125 +++++++++++
 tests/system/runall.sh                             |   44 ++++
 tests/system/start.pl                              |  226 ++++++++++++++++++++
 tests/system/stop.pl                               |  188 ++++++++++++++++
 49 files changed, 1736 insertions(+), 153 deletions(-)
 rename src/bin/bind10/tests/{bind10_test.py => bind10_test.py.in} (88%)
 copy src/lib/{log/root_logger_name.cc => asiolink/qid_gen.cc} (51%)
 create mode 100644 src/lib/asiolink/qid_gen.h
 create mode 100644 src/lib/asiolink/tests/qid_gen_unittest.cc
 rename src/lib/log/{documentation.txt => README} (75%)
 create mode 100644 tests/Makefile.am
 create mode 100644 tests/system/Makefile.am
 create mode 100644 tests/system/README
 create mode 100755 tests/system/cleanall.sh
 create mode 100755 tests/system/conf.sh.in
 create mode 100644 tests/system/glue/auth.good
 create mode 100755 tests/system/glue/clean.sh
 create mode 100644 tests/system/glue/example.good
 create mode 100644 tests/system/glue/noglue.good
 create mode 100644 tests/system/glue/nsx1/b10-config.db.in
 create mode 100644 tests/system/glue/nsx1/com.db
 create mode 100644 tests/system/glue/nsx1/net.db
 create mode 100644 tests/system/glue/nsx1/root-servers.nil.db
 create mode 100644 tests/system/glue/nsx1/root.db
 create mode 100755 tests/system/glue/setup.sh.in
 create mode 100644 tests/system/glue/test.good
 create mode 100755 tests/system/glue/tests.sh
 create mode 100755 tests/system/ifconfig.sh
 create mode 100755 tests/system/run.sh
 create mode 100755 tests/system/runall.sh
 create mode 100755 tests/system/start.pl
 create mode 100755 tests/system/stop.pl

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index b7d113a..791575e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+  194.  [bug]       vorner
+	Solved a 100% CPU usage problem after switching addresses in b10-auth
+	(and possibly, but unconfirmed, in b10-resolver). It was caused by
+	repeated reads/accepts on closed socket (the bug was in the code for a
+	long time, recent changes made it show).
+	(Trac #657, git e0863720a874d75923ea66adcfbf5b2948efb10a)
+
+  193.	[func]*		jreed
+	Listen on the IPv6 (::) and IPv4 (0.0.0.0) wildcard addresses
+	for b10-auth. This returns to previous behavior prior to
+	change #184. Document the listen_on configuration in manual.
+	(Trac #649, git 65a77d8fde64d464c75917a1ab9b6b3f02640ca6)
+
+  192.	[func]*		jreed
+	Listen on standard domain port 53 for b10-auth and
+	b10-resolver.
+	(Trac #617, #618, git 137a6934a14cf0c5b5c065e910b8b364beb0973f)
+
+  191.	[func]		jinmei
+	Imported system test framework of BIND 9.  It can be run by
+	'make systest' at the top source directory.  Notes: currently it
+	doesn't work when built in a separate tree.  It also requires
+	perl, an inherited dependency from the original framework.
+	Also, mainly for the purpose of tests, a new option "--pid-file"
+	was added to BoB, with which the boss process will dump its PID
+	to the specified file.
+	(Trac #606, git 6ac000df85625f5921e8895a1aafff5e4be3ba9c)
+
+  190.	[func]		jelte
+	Resolver now sets random qids on outgoing queries using
+	the boost::mt19937 prng.
+	(Trac #583, git 5222b51a047d8f2352bc9f92fd022baf1681ed81)
+
   189.	[bug]		jreed
 	Do not install the log message compiler.
 	(Trac #634, git eb6441aca464980d00e3ff827cbf4195c5a7afc5)
diff --git a/Makefile.am b/Makefile.am
index 9a28f20..e31a1a5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = doc src
+SUBDIRS = doc src tests
 USE_LCOV=@USE_LCOV@
 LCOV=@LCOV@
 GENHTML=@GENHTML@
@@ -77,6 +77,11 @@ cppcheck:
 		--template '{file}:{line}: check_fail: {message} ({severity},{id})' \
 		src
 
+# system tests
+systest:
+	cd tests/system; \
+	sh $(abs_srcdir)/tests/system/runall.sh
+
 #### include external sources in the distributed tarball:
 EXTRA_DIST = ext/asio/README
 EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
diff --git a/README b/README
index 5bc3154..b10d12e 100644
--- a/README
+++ b/README
@@ -164,8 +164,6 @@ source tree:
 (Which will use the modules and configurations also from the source
 tree.)
 
-The server will listen on port 5300 for DNS requests.
-
 CONFIGURATION
 
 Commands can be given through the bindctl tool.
diff --git a/configure.ac b/configure.ac
index 0f34b0d..56a5744 100644
--- a/configure.ac
+++ b/configure.ac
@@ -583,6 +583,12 @@ if test "X$ac_cv_have_devpoll" = "Xyes" -a "X$GXX" = "Xyes"; then
 	CPPFLAGS="$CPPFLAGS -DASIO_DISABLE_DEV_POLL=1"
 fi
 
+#
+# Perl is optional; it is used only by some of the system test scripts.
+#
+AC_PATH_PROGS(PERL, perl5 perl)
+AC_SUBST(PERL)
+
 AC_ARG_ENABLE(man, [AC_HELP_STRING([--enable-man],
   [regenerate man pages [default=no]])], enable_man=yes, enable_man=no)
 
@@ -683,6 +689,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/cache/tests/Makefile
                  src/lib/server_common/Makefile
                  src/lib/server_common/tests/Makefile
+                 tests/Makefile
+                 tests/system/Makefile
                ])
 AC_OUTPUT([doc/version.ent
            src/bin/cfgmgr/b10-cfgmgr.py
@@ -712,6 +720,7 @@ AC_OUTPUT([doc/version.ent
            src/bin/stats/tests/stats_test
            src/bin/bind10/bind10.py
            src/bin/bind10/tests/bind10_test
+           src/bin/bind10/tests/bind10_test.py
            src/bin/bind10/run_bind10.sh
            src/bin/bindctl/run_bindctl.sh
            src/bin/bindctl/bindctl-source.py
@@ -739,6 +748,9 @@ AC_OUTPUT([doc/version.ent
            src/lib/cc/session_config.h.pre
            src/lib/cc/tests/session_unittests_config.h
            src/lib/log/tests/run_time_init_test.sh
+           tests/system/conf.sh
+           tests/system/glue/setup.sh
+           tests/system/glue/nsx1/b10-config.db
           ], [
            chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
            chmod +x src/bin/xfrin/run_b10-xfrin.sh
@@ -763,6 +775,7 @@ AC_OUTPUT([doc/version.ent
            chmod +x src/lib/dns/gen-rdatacode.py
            chmod +x src/lib/dns/tests/testdata/gen-wiredata.py
            chmod +x src/lib/log/tests/run_time_init_test.sh
+           chmod +x tests/system/conf.sh
           ])
 AC_OUTPUT
 
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index 0935c81..bceb40c 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -336,14 +336,6 @@ var/
         </simpara>
       </note>
 
-      <note>
-        <simpara>
-          The development prototype of the b10-auth server listens on
-          0.0.0.0 (all interfaces) port 5300. (This is not the standard
-          domain service port.)
-        </simpara>
-      </note>
-
       <para>
         To quickly get started with BIND 10, follow these steps.
       </para>
@@ -397,7 +389,7 @@ var/
         <listitem>
 
          <para>Test it; for example:
-            <screen>$ <userinput>dig @127.0.0.1 -p 5300 -c CH -t TXT authors.bind</userinput></screen>
+            <screen>$ <userinput>dig @127.0.0.1 -c CH -t TXT authors.bind</userinput></screen>
          </para>
         </listitem>
 
@@ -1044,11 +1036,6 @@ TODO
       process.
     </para>
 
-    <note><simpara>
-      This development prototype release listens on all interfaces
-      and the non-standard port 5300.
-    </simpara></note>
-
     <section>
       <title>Server Configurations</title>
 
diff --git a/src/bin/auth/auth.spec.pre.in b/src/bin/auth/auth.spec.pre.in
index e95dabd..d88ffb5 100644
--- a/src/bin/auth/auth.spec.pre.in
+++ b/src/bin/auth/auth.spec.pre.in
@@ -63,12 +63,12 @@
         "item_optional": false,
         "item_default": [
           {
-            "address": "::1",
-            "port": 5300
+            "address": "::",
+            "port": 53
           },
           {
-            "address": "127.0.0.1",
-            "port": 5300
+            "address": "0.0.0.0",
+            "port": 53
           }
         ],
         "list_item_spec": {
@@ -87,7 +87,7 @@
               "item_name": "port",
               "item_type": "integer",
               "item_optional": false,
-              "item_default": 5300
+              "item_default": 53
             }
           ]
         }
diff --git a/src/bin/auth/b10-auth.8 b/src/bin/auth/b10-auth.8
index dcbe6d8..0356683 100644
--- a/src/bin/auth/b10-auth.8
+++ b/src/bin/auth/b10-auth.8
@@ -2,12 +2,12 @@
 .\"     Title: b10-auth
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: February 22, 2011
+.\"      Date: March 8, 2011
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-AUTH" "8" "February 22, 2011" "BIND10" "BIND10"
+.TH "B10\-AUTH" "8" "March 8, 2011" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -70,6 +70,18 @@ defines the path to the SQLite3 zone file when using the sqlite datasource\&. Th
 /usr/local/var/bind10\-devel/zone\&.sqlite3\&.
 .PP
 
+\fIlisten_on\fR
+is a list of addresses and ports for
+\fBb10\-auth\fR
+to listen on\&. The list items are the
+\fIaddress\fR
+string and
+\fIport\fR
+number\&. By default,
+\fBb10\-auth\fR
+listens on port 53 on the IPv6 (::) and IPv4 (0\&.0\&.0\&.0) wildcard addresses\&.
+.PP
+
 \fIdatasources\fR
 configures data sources\&. The list items include:
 \fItype\fR
diff --git a/src/bin/auth/b10-auth.xml b/src/bin/auth/b10-auth.xml
index ce80689..2b53394 100644
--- a/src/bin/auth/b10-auth.xml
+++ b/src/bin/auth/b10-auth.xml
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>February 22, 2011</date>
+    <date>March 8, 2011</date>
   </refentryinfo>
 
   <refmeta>
@@ -132,6 +132,15 @@
     </para>
 
     <para>
+      <varname>listen_on</varname> is a list of addresses and ports for
+      <command>b10-auth</command> to listen on.
+      The list items are the <varname>address</varname> string
+      and <varname>port</varname> number.
+      By default, <command>b10-auth</command> listens on port 53
+      on the IPv6 (::) and IPv4 (0.0.0.0) wildcard addresses.
+    </para>
+
+    <para>
       <varname>datasources</varname> configures data sources.
       The list items include:
       <varname>type</varname> to optionally choose the data source type
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index 275ae7d..0701b94 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -122,7 +122,13 @@ main(int argc, char* argv[]) {
     ModuleCCSession* config_session = NULL;
     string xfrout_socket_path;
     if (getenv("B10_FROM_BUILD") != NULL) {
-        xfrout_socket_path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
+        if (getenv("B10_FROM_SOURCE_LOCALSTATEDIR")) {
+            xfrout_socket_path = string("B10_FROM_SOURCE_LOCALSTATEDIR") +
+                "/auth_xfrout_conn";
+        } else {
+            xfrout_socket_path = string(getenv("B10_FROM_BUILD")) +
+                "/auth_xfrout_conn";
+        }
     } else {
         xfrout_socket_path = UNIX_SOCKET_FILE;
     }
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index 83acf1f..ce6e523 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -785,6 +785,35 @@ def process_rename(option, opt_str, value, parser):
     """Function that renames the process if it is requested by a option."""
     isc.util.process.rename(value)
 
+def dump_pid(pid_file):
+    """
+    Dump the PID of the current process to the specified file.  If the given
+    file is None this function does nothing.  If the file already exists,
+    the existing content will be removed.  If a system error happens in
+    creating or writing to the file, the corresponding exception will be
+    propagated to the caller.
+    """
+    if pid_file is None:
+        return
+    f = open(pid_file, "w")
+    f.write('%d\n' % os.getpid())
+    f.close()
+
+def unlink_pid_file(pid_file):
+    """
+    Remove the given file, which is basically expected to be the PID file
+    created by dump_pid().  The specified may or may not exist; if it
+    doesn't this function does nothing.  Other system level errors in removing
+    the file will be propagated as the corresponding exception.
+    """
+    if pid_file is None:
+        return
+    try:
+        os.unlink(pid_file)
+    except OSError as error:
+        if error.errno is not errno.ENOENT:
+            raise
+
 def main():
     global options
     global boss_of_bind
@@ -805,6 +834,9 @@ def main():
     parser.add_option("--pretty-name", type="string", action="callback",
                       callback=process_rename,
                       help="Set the process name (displayed in ps, top, ...)")
+    parser.add_option("--pid-file", dest="pid_file", type="string",
+                      default=None,
+                      help="file to dump the PID of the BIND 10 process")
     (options, args) = parser.parse_args()
     if args:
         parser.print_help()
@@ -865,6 +897,7 @@ def main():
         sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
         sys.exit(1)
     sys.stdout.write("[bind10] BIND 10 started\n")
+    dump_pid(options.pid_file)
 
     # send "bind10.boot_time" to b10-stats
     time.sleep(1) # wait a second
@@ -918,6 +951,7 @@ def main():
     signal.signal(signal.SIGCHLD, signal.SIG_DFL)
     boss_of_bind.shutdown()
     sys.stdout.write("[bind10] BIND 10 exiting\n");
+    unlink_pid_file(options.pid_file)
     sys.exit(0)
 
 if __name__ == "__main__":
diff --git a/src/bin/bind10/tests/bind10_test.py b/src/bin/bind10/tests/bind10_test.py
deleted file mode 100644
index f3fe949..0000000
--- a/src/bin/bind10/tests/bind10_test.py
+++ /dev/null
@@ -1,416 +0,0 @@
-from bind10 import ProcessInfo, BoB
-
-# XXX: environment tests are currently disabled, due to the preprocessor
-#      setup that we have now complicating the environment
-
-import unittest
-import sys
-import os
-import signal
-import socket
-from isc.net.addr import IPAddr
-
-class TestProcessInfo(unittest.TestCase):
-    def setUp(self):
-        # redirect stdout to a pipe so we can check that our
-        # process spawning is doing the right thing with stdout
-        self.old_stdout = os.dup(sys.stdout.fileno())
-        self.pipes = os.pipe()
-        os.dup2(self.pipes[1], sys.stdout.fileno())
-        os.close(self.pipes[1])
-        # note that we use dup2() to restore the original stdout
-        # to the main program ASAP in each test... this prevents
-        # hangs reading from the child process (as the pipe is only
-        # open in the child), and also insures nice pretty output
-
-    def tearDown(self):
-        # clean up our stdout munging
-        os.dup2(self.old_stdout, sys.stdout.fileno())
-        os.close(self.pipes[0])
-
-    def test_init(self):
-        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
-        os.dup2(self.old_stdout, sys.stdout.fileno())
-        self.assertEqual(pi.name, 'Test Process')
-        self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
-#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
-        self.assertEqual(pi.dev_null_stdout, False)
-        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
-        self.assertNotEqual(pi.process, None)
-        self.assertTrue(type(pi.pid) is int)
-
-#    def test_setting_env(self):
-#        pi = ProcessInfo('Test Process', [ '/bin/true' ], env={'FOO': 'BAR'})
-#        os.dup2(self.old_stdout, sys.stdout.fileno())
-#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'],
-#                                   'FOO': 'BAR' })
-
-    def test_setting_null_stdout(self):
-        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ], 
-                         dev_null_stdout=True)
-        os.dup2(self.old_stdout, sys.stdout.fileno())
-        self.assertEqual(pi.dev_null_stdout, True)
-        self.assertEqual(os.read(self.pipes[0], 100), b"")
-
-    def test_respawn(self):
-        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
-        # wait for old process to work...
-        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
-        # respawn it
-        old_pid = pi.pid
-        pi.respawn()
-        os.dup2(self.old_stdout, sys.stdout.fileno())
-        # make sure the new one started properly
-        self.assertEqual(pi.name, 'Test Process')
-        self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
-#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
-#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
-        self.assertEqual(pi.dev_null_stdout, False)
-        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
-        self.assertNotEqual(pi.process, None)
-        self.assertTrue(type(pi.pid) is int)
-        self.assertNotEqual(pi.pid, old_pid)
-
-class TestBoB(unittest.TestCase):
-    def test_init(self):
-        bob = BoB()
-        self.assertEqual(bob.verbose, False)
-        self.assertEqual(bob.msgq_socket_file, None)
-        self.assertEqual(bob.cc_session, None)
-        self.assertEqual(bob.ccs, None)
-        self.assertEqual(bob.processes, {})
-        self.assertEqual(bob.dead_processes, {})
-        self.assertEqual(bob.runnable, False)
-        self.assertEqual(bob.uid, None)
-        self.assertEqual(bob.username, None)
-        self.assertEqual(bob.nocache, False)
-        self.assertEqual(bob.cfg_start_auth, True)
-        self.assertEqual(bob.cfg_start_resolver, False)
-
-    def test_init_alternate_socket(self):
-        bob = BoB("alt_socket_file")
-        self.assertEqual(bob.verbose, False)
-        self.assertEqual(bob.msgq_socket_file, "alt_socket_file")
-        self.assertEqual(bob.cc_session, None)
-        self.assertEqual(bob.ccs, None)
-        self.assertEqual(bob.processes, {})
-        self.assertEqual(bob.dead_processes, {})
-        self.assertEqual(bob.runnable, False)
-        self.assertEqual(bob.uid, None)
-        self.assertEqual(bob.username, None)
-        self.assertEqual(bob.nocache, False)
-        self.assertEqual(bob.cfg_start_auth, True)
-        self.assertEqual(bob.cfg_start_resolver, False)
-
-# Class for testing the BoB start/stop components routines.
-#
-# Although testing that external processes start is outside the scope
-# of the unit test, by overriding the process start methods we can check
-# that the right processes are started depending on the configuration
-# options.
-class StartStopCheckBob(BoB):
-    def __init__(self):
-        BoB.__init__(self)
-
-# Set flags as to which of the overridden methods has been run.
-        self.msgq = False
-        self.cfgmgr = False
-        self.ccsession = False
-        self.auth = False
-        self.resolver = False
-        self.xfrout = False
-        self.xfrin = False
-        self.zonemgr = False
-        self.stats = False
-        self.cmdctl = False
-        self.c_channel_env = {}
-
-    def read_bind10_config(self):
-        # Configuration options are set directly
-        pass
-
-    def start_msgq(self, c_channel_env):
-        self.msgq = True
-
-    def start_cfgmgr(self, c_channel_env):
-        self.cfgmgr = True
-
-    def start_ccsession(self, c_channel_env):
-        self.ccsession = True
-
-    def start_auth(self, c_channel_env):
-        self.auth = True
-
-    def start_resolver(self, c_channel_env):
-        self.resolver = True
-
-    def start_xfrout(self, c_channel_env):
-        self.xfrout = True
-
-    def start_xfrin(self, c_channel_env):
-        self.xfrin = True
-
-    def start_zonemgr(self, c_channel_env):
-        self.zonemgr = True
-
-    def start_stats(self, c_channel_env):
-        self.stats = True
-
-    def start_cmdctl(self, c_channel_env):
-        self.cmdctl = True
-
-    # We don't really use all of these stop_ methods. But it might turn out
-    # someone would add some stop_ method to BoB and we want that one overriden
-    # in case he forgets to update the tests.
-    def stop_msgq(self):
-        self.msgq = False
-
-    def stop_cfgmgr(self):
-        self.cfgmgr = False
-
-    def stop_ccsession(self):
-        self.ccsession = False
-
-    def stop_auth(self):
-        self.auth = False
-
-    def stop_resolver(self):
-        self.resolver = False
-
-    def stop_xfrout(self):
-        self.xfrout = False
-
-    def stop_xfrin(self):
-        self.xfrin = False
-
-    def stop_zonemgr(self):
-        self.zonemgr = False
-
-    def stop_stats(self):
-        self.stats = False
-
-    def stop_cmdctl(self):
-        self.cmdctl = False
-
-class TestStartStopProcessesBob(unittest.TestCase):
-    """
-    Check that the start_all_processes method starts the right combination
-    of processes and that the right processes are started and stopped
-    according to changes in configuration.
-    """
-    def check_started(self, bob, core, auth, resolver):
-        """
-        Check that the right sets of services are started. The ones that
-        should be running are specified by the core, auth and resolver parameters
-        (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
-        and -zonemgr).
-        """
-        self.assertEqual(bob.msgq, core)
-        self.assertEqual(bob.cfgmgr, core)
-        self.assertEqual(bob.ccsession, core)
-        self.assertEqual(bob.auth, auth)
-        self.assertEqual(bob.resolver, resolver)
-        self.assertEqual(bob.xfrout, auth)
-        self.assertEqual(bob.xfrin, auth)
-        self.assertEqual(bob.zonemgr, auth)
-        self.assertEqual(bob.stats, core)
-        self.assertEqual(bob.cmdctl, core)
-
-    def check_preconditions(self, bob):
-        self.check_started(bob, False, False, False)
-
-    def check_started_none(self, bob):
-        """
-        Check that the situation is according to configuration where no servers
-        should be started. Some processes still need to be running.
-        """
-        self.check_started(bob, True, False, False)
-
-    def check_started_both(self, bob):
-        """
-        Check the situation is according to configuration where both servers
-        (auth and resolver) are enabled.
-        """
-        self.check_started(bob, True, True, True)
-
-    def check_started_auth(self, bob):
-        """
-        Check the set of processes needed to run auth only is started.
-        """
-        self.check_started(bob, True, True, False)
-
-    def check_started_resolver(self, bob):
-        """
-        Check the set of processes needed to run resolver only is started.
-        """
-        self.check_started(bob, True, False, True)
-
-    # Checks the processes started when starting neither auth nor resolver
-    # is specified.
-    def test_start_none(self):
-        # Create BoB and ensure correct initialization
-        bob = StartStopCheckBob()
-        self.check_preconditions(bob)
-
-        # Start processes and check what was started
-        bob.cfg_start_auth = False
-        bob.cfg_start_resolver = False
-
-        bob.start_all_processes()
-        self.check_started_none(bob)
-
-    # Checks the processes started when starting only the auth process
-    def test_start_auth(self):
-        # Create BoB and ensure correct initialization
-        bob = StartStopCheckBob()
-        self.check_preconditions(bob)
-
-        # Start processes and check what was started
-        bob.cfg_start_auth = True
-        bob.cfg_start_resolver = False
-
-        bob.start_all_processes()
-
-        self.check_started_auth(bob)
-
-    # Checks the processes started when starting only the resolver process
-    def test_start_resolver(self):
-        # Create BoB and ensure correct initialization
-        bob = StartStopCheckBob()
-        self.check_preconditions(bob)
-
-        # Start processes and check what was started
-        bob.cfg_start_auth = False
-        bob.cfg_start_resolver = True
-
-        bob.start_all_processes()
-
-        self.check_started_resolver(bob)
-
-    # Checks the processes started when starting both auth and resolver process
-    def test_start_both(self):
-        # Create BoB and ensure correct initialization
-        bob = StartStopCheckBob()
-        self.check_preconditions(bob)
-
-        # Start processes and check what was started
-        bob.cfg_start_auth = True
-        bob.cfg_start_resolver = True
-
-        bob.start_all_processes()
-
-        self.check_started_both(bob)
-
-    def test_config_start(self):
-        """
-        Test that the configuration starts and stops processes according
-        to configuration changes.
-        """
-
-        # Create BoB and ensure correct initialization
-        bob = StartStopCheckBob()
-        self.check_preconditions(bob)
-
-        # Start processes (nothing much should be started, as in
-        # test_start_none)
-        bob.cfg_start_auth = False
-        bob.cfg_start_resolver = False
-
-        bob.start_all_processes()
-        bob.runnable = True
-        self.check_started_none(bob)
-
-        # Enable both at once
-        bob.config_handler({'start_auth': True, 'start_resolver': True})
-        self.check_started_both(bob)
-
-        # Not touched by empty change
-        bob.config_handler({})
-        self.check_started_both(bob)
-
-        # Not touched by change to the same configuration
-        bob.config_handler({'start_auth': True, 'start_resolver': True})
-        self.check_started_both(bob)
-
-        # Turn them both off again
-        bob.config_handler({'start_auth': False, 'start_resolver': False})
-        self.check_started_none(bob)
-
-        # Not touched by empty change
-        bob.config_handler({})
-        self.check_started_none(bob)
-
-        # Not touched by change to the same configuration
-        bob.config_handler({'start_auth': False, 'start_resolver': False})
-        self.check_started_none(bob)
-
-        # Start and stop auth separately
-        bob.config_handler({'start_auth': True})
-        self.check_started_auth(bob)
-
-        bob.config_handler({'start_auth': False})
-        self.check_started_none(bob)
-
-        # Start and stop resolver separately
-        bob.config_handler({'start_resolver': True})
-        self.check_started_resolver(bob)
-
-        bob.config_handler({'start_resolver': False})
-        self.check_started_none(bob)
-
-        # Alternate
-        bob.config_handler({'start_auth': True})
-        self.check_started_auth(bob)
-
-        bob.config_handler({'start_auth': False, 'start_resolver': True})
-        self.check_started_resolver(bob)
-
-        bob.config_handler({'start_auth': True, 'start_resolver': False})
-        self.check_started_auth(bob)
-
-    def test_config_start_once(self):
-        """
-        Tests that a process is started only once.
-        """
-        # Create BoB and ensure correct initialization
-        bob = StartStopCheckBob()
-        self.check_preconditions(bob)
-
-        # Start processes (both)
-        bob.cfg_start_auth = True
-        bob.cfg_start_resolver = True
-
-        bob.start_all_processes()
-        bob.runnable = True
-        self.check_started_both(bob)
-
-        bob.start_auth = lambda: self.fail("Started auth again")
-        bob.start_xfrout = lambda: self.fail("Started xfrout again")
-        bob.start_xfrin = lambda: self.fail("Started xfrin again")
-        bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
-        bob.start_resolver = lambda: self.fail("Started resolver again")
-
-        # Send again we want to start them. Should not do it, as they are.
-        bob.config_handler({'start_auth': True})
-        bob.config_handler({'start_resolver': True})
-
-    def test_config_not_started_early(self):
-        """
-        Test that processes are not started by the config handler before
-        startup.
-        """
-        bob = StartStopCheckBob()
-        self.check_preconditions(bob)
-
-        bob.start_auth = lambda: self.fail("Started auth again")
-        bob.start_xfrout = lambda: self.fail("Started xfrout again")
-        bob.start_xfrin = lambda: self.fail("Started xfrin again")
-        bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
-        bob.start_resolver = lambda: self.fail("Started resolver again")
-
-        bob.config_handler({'start_auth': True, 'start_resolver': True})
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
new file mode 100644
index 0000000..0603443
--- /dev/null
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -0,0 +1,463 @@
+from bind10 import ProcessInfo, BoB, dump_pid, unlink_pid_file
+
+# XXX: environment tests are currently disabled, due to the preprocessor
+#      setup that we have now complicating the environment
+
+import unittest
+import sys
+import os
+import signal
+import socket
+from isc.net.addr import IPAddr
+
+class TestProcessInfo(unittest.TestCase):
+    def setUp(self):
+        # redirect stdout to a pipe so we can check that our
+        # process spawning is doing the right thing with stdout
+        self.old_stdout = os.dup(sys.stdout.fileno())
+        self.pipes = os.pipe()
+        os.dup2(self.pipes[1], sys.stdout.fileno())
+        os.close(self.pipes[1])
+        # note that we use dup2() to restore the original stdout
+        # to the main program ASAP in each test... this prevents
+        # hangs reading from the child process (as the pipe is only
+        # open in the child), and also insures nice pretty output
+
+    def tearDown(self):
+        # clean up our stdout munging
+        os.dup2(self.old_stdout, sys.stdout.fileno())
+        os.close(self.pipes[0])
+
+    def test_init(self):
+        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
+        os.dup2(self.old_stdout, sys.stdout.fileno())
+        self.assertEqual(pi.name, 'Test Process')
+        self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
+#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
+        self.assertEqual(pi.dev_null_stdout, False)
+        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+        self.assertNotEqual(pi.process, None)
+        self.assertTrue(type(pi.pid) is int)
+
+#    def test_setting_env(self):
+#        pi = ProcessInfo('Test Process', [ '/bin/true' ], env={'FOO': 'BAR'})
+#        os.dup2(self.old_stdout, sys.stdout.fileno())
+#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'],
+#                                   'FOO': 'BAR' })
+
+    def test_setting_null_stdout(self):
+        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ],
+                         dev_null_stdout=True)
+        os.dup2(self.old_stdout, sys.stdout.fileno())
+        self.assertEqual(pi.dev_null_stdout, True)
+        self.assertEqual(os.read(self.pipes[0], 100), b"")
+
+    def test_respawn(self):
+        pi = ProcessInfo('Test Process', [ '/bin/echo', 'foo' ])
+        # wait for old process to work...
+        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+        # respawn it
+        old_pid = pi.pid
+        pi.respawn()
+        os.dup2(self.old_stdout, sys.stdout.fileno())
+        # make sure the new one started properly
+        self.assertEqual(pi.name, 'Test Process')
+        self.assertEqual(pi.args, [ '/bin/echo', 'foo' ])
+#        self.assertEqual(pi.env, { 'PATH': os.environ['PATH'],
+#                                   'PYTHON_EXEC': os.environ['PYTHON_EXEC'] })
+        self.assertEqual(pi.dev_null_stdout, False)
+        self.assertEqual(os.read(self.pipes[0], 100), b"foo\n")
+        self.assertNotEqual(pi.process, None)
+        self.assertTrue(type(pi.pid) is int)
+        self.assertNotEqual(pi.pid, old_pid)
+
+class TestBoB(unittest.TestCase):
+    def test_init(self):
+        bob = BoB()
+        self.assertEqual(bob.verbose, False)
+        self.assertEqual(bob.msgq_socket_file, None)
+        self.assertEqual(bob.cc_session, None)
+        self.assertEqual(bob.ccs, None)
+        self.assertEqual(bob.processes, {})
+        self.assertEqual(bob.dead_processes, {})
+        self.assertEqual(bob.runnable, False)
+        self.assertEqual(bob.uid, None)
+        self.assertEqual(bob.username, None)
+        self.assertEqual(bob.nocache, False)
+        self.assertEqual(bob.cfg_start_auth, True)
+        self.assertEqual(bob.cfg_start_resolver, False)
+
+    def test_init_alternate_socket(self):
+        bob = BoB("alt_socket_file")
+        self.assertEqual(bob.verbose, False)
+        self.assertEqual(bob.msgq_socket_file, "alt_socket_file")
+        self.assertEqual(bob.cc_session, None)
+        self.assertEqual(bob.ccs, None)
+        self.assertEqual(bob.processes, {})
+        self.assertEqual(bob.dead_processes, {})
+        self.assertEqual(bob.runnable, False)
+        self.assertEqual(bob.uid, None)
+        self.assertEqual(bob.username, None)
+        self.assertEqual(bob.nocache, False)
+        self.assertEqual(bob.cfg_start_auth, True)
+        self.assertEqual(bob.cfg_start_resolver, False)
+
+# Class for testing the BoB start/stop components routines.
+#
+# Although testing that external processes start is outside the scope
+# of the unit test, by overriding the process start methods we can check
+# that the right processes are started depending on the configuration
+# options.
+class StartStopCheckBob(BoB):
+    def __init__(self):
+        BoB.__init__(self)
+
+# Set flags as to which of the overridden methods has been run.
+        self.msgq = False
+        self.cfgmgr = False
+        self.ccsession = False
+        self.auth = False
+        self.resolver = False
+        self.xfrout = False
+        self.xfrin = False
+        self.zonemgr = False
+        self.stats = False
+        self.cmdctl = False
+        self.c_channel_env = {}
+
+    def read_bind10_config(self):
+        # Configuration options are set directly
+        pass
+
+    def start_msgq(self, c_channel_env):
+        self.msgq = True
+
+    def start_cfgmgr(self, c_channel_env):
+        self.cfgmgr = True
+
+    def start_ccsession(self, c_channel_env):
+        self.ccsession = True
+
+    def start_auth(self, c_channel_env):
+        self.auth = True
+
+    def start_resolver(self, c_channel_env):
+        self.resolver = True
+
+    def start_xfrout(self, c_channel_env):
+        self.xfrout = True
+
+    def start_xfrin(self, c_channel_env):
+        self.xfrin = True
+
+    def start_zonemgr(self, c_channel_env):
+        self.zonemgr = True
+
+    def start_stats(self, c_channel_env):
+        self.stats = True
+
+    def start_cmdctl(self, c_channel_env):
+        self.cmdctl = True
+
+    # We don't really use all of these stop_ methods. But it might turn out
+    # someone would add some stop_ method to BoB and we want that one overriden
+    # in case he forgets to update the tests.
+    def stop_msgq(self):
+        self.msgq = False
+
+    def stop_cfgmgr(self):
+        self.cfgmgr = False
+
+    def stop_ccsession(self):
+        self.ccsession = False
+
+    def stop_auth(self):
+        self.auth = False
+
+    def stop_resolver(self):
+        self.resolver = False
+
+    def stop_xfrout(self):
+        self.xfrout = False
+
+    def stop_xfrin(self):
+        self.xfrin = False
+
+    def stop_zonemgr(self):
+        self.zonemgr = False
+
+    def stop_stats(self):
+        self.stats = False
+
+    def stop_cmdctl(self):
+        self.cmdctl = False
+
+class TestStartStopProcessesBob(unittest.TestCase):
+    """
+    Check that the start_all_processes method starts the right combination
+    of processes and that the right processes are started and stopped
+    according to changes in configuration.
+    """
+    def check_started(self, bob, core, auth, resolver):
+        """
+        Check that the right sets of services are started. The ones that
+        should be running are specified by the core, auth and resolver parameters
+        (they are groups of processes, eg. auth means b10-auth, -xfrout, -xfrin
+        and -zonemgr).
+        """
+        self.assertEqual(bob.msgq, core)
+        self.assertEqual(bob.cfgmgr, core)
+        self.assertEqual(bob.ccsession, core)
+        self.assertEqual(bob.auth, auth)
+        self.assertEqual(bob.resolver, resolver)
+        self.assertEqual(bob.xfrout, auth)
+        self.assertEqual(bob.xfrin, auth)
+        self.assertEqual(bob.zonemgr, auth)
+        self.assertEqual(bob.stats, core)
+        self.assertEqual(bob.cmdctl, core)
+
+    def check_preconditions(self, bob):
+        self.check_started(bob, False, False, False)
+
+    def check_started_none(self, bob):
+        """
+        Check that the situation is according to configuration where no servers
+        should be started. Some processes still need to be running.
+        """
+        self.check_started(bob, True, False, False)
+
+    def check_started_both(self, bob):
+        """
+        Check the situation is according to configuration where both servers
+        (auth and resolver) are enabled.
+        """
+        self.check_started(bob, True, True, True)
+
+    def check_started_auth(self, bob):
+        """
+        Check the set of processes needed to run auth only is started.
+        """
+        self.check_started(bob, True, True, False)
+
+    def check_started_resolver(self, bob):
+        """
+        Check the set of processes needed to run resolver only is started.
+        """
+        self.check_started(bob, True, False, True)
+
+    # Checks the processes started when starting neither auth nor resolver
+    # is specified.
+    def test_start_none(self):
+        # Create BoB and ensure correct initialization
+        bob = StartStopCheckBob()
+        self.check_preconditions(bob)
+
+        # Start processes and check what was started
+        bob.cfg_start_auth = False
+        bob.cfg_start_resolver = False
+
+        bob.start_all_processes()
+        self.check_started_none(bob)
+
+    # Checks the processes started when starting only the auth process
+    def test_start_auth(self):
+        # Create BoB and ensure correct initialization
+        bob = StartStopCheckBob()
+        self.check_preconditions(bob)
+
+        # Start processes and check what was started
+        bob.cfg_start_auth = True
+        bob.cfg_start_resolver = False
+
+        bob.start_all_processes()
+
+        self.check_started_auth(bob)
+
+    # Checks the processes started when starting only the resolver process
+    def test_start_resolver(self):
+        # Create BoB and ensure correct initialization
+        bob = StartStopCheckBob()
+        self.check_preconditions(bob)
+
+        # Start processes and check what was started
+        bob.cfg_start_auth = False
+        bob.cfg_start_resolver = True
+
+        bob.start_all_processes()
+
+        self.check_started_resolver(bob)
+
+    # Checks the processes started when starting both auth and resolver process
+    def test_start_both(self):
+        # Create BoB and ensure correct initialization
+        bob = StartStopCheckBob()
+        self.check_preconditions(bob)
+
+        # Start processes and check what was started
+        bob.cfg_start_auth = True
+        bob.cfg_start_resolver = True
+
+        bob.start_all_processes()
+
+        self.check_started_both(bob)
+
+    def test_config_start(self):
+        """
+        Test that the configuration starts and stops processes according
+        to configuration changes.
+        """
+
+        # Create BoB and ensure correct initialization
+        bob = StartStopCheckBob()
+        self.check_preconditions(bob)
+
+        # Start processes (nothing much should be started, as in
+        # test_start_none)
+        bob.cfg_start_auth = False
+        bob.cfg_start_resolver = False
+
+        bob.start_all_processes()
+        bob.runnable = True
+        self.check_started_none(bob)
+
+        # Enable both at once
+        bob.config_handler({'start_auth': True, 'start_resolver': True})
+        self.check_started_both(bob)
+
+        # Not touched by empty change
+        bob.config_handler({})
+        self.check_started_both(bob)
+
+        # Not touched by change to the same configuration
+        bob.config_handler({'start_auth': True, 'start_resolver': True})
+        self.check_started_both(bob)
+
+        # Turn them both off again
+        bob.config_handler({'start_auth': False, 'start_resolver': False})
+        self.check_started_none(bob)
+
+        # Not touched by empty change
+        bob.config_handler({})
+        self.check_started_none(bob)
+
+        # Not touched by change to the same configuration
+        bob.config_handler({'start_auth': False, 'start_resolver': False})
+        self.check_started_none(bob)
+
+        # Start and stop auth separately
+        bob.config_handler({'start_auth': True})
+        self.check_started_auth(bob)
+
+        bob.config_handler({'start_auth': False})
+        self.check_started_none(bob)
+
+        # Start and stop resolver separately
+        bob.config_handler({'start_resolver': True})
+        self.check_started_resolver(bob)
+
+        bob.config_handler({'start_resolver': False})
+        self.check_started_none(bob)
+
+        # Alternate
+        bob.config_handler({'start_auth': True})
+        self.check_started_auth(bob)
+
+        bob.config_handler({'start_auth': False, 'start_resolver': True})
+        self.check_started_resolver(bob)
+
+        bob.config_handler({'start_auth': True, 'start_resolver': False})
+        self.check_started_auth(bob)
+
+    def test_config_start_once(self):
+        """
+        Tests that a process is started only once.
+        """
+        # Create BoB and ensure correct initialization
+        bob = StartStopCheckBob()
+        self.check_preconditions(bob)
+
+        # Start processes (both)
+        bob.cfg_start_auth = True
+        bob.cfg_start_resolver = True
+
+        bob.start_all_processes()
+        bob.runnable = True
+        self.check_started_both(bob)
+
+        bob.start_auth = lambda: self.fail("Started auth again")
+        bob.start_xfrout = lambda: self.fail("Started xfrout again")
+        bob.start_xfrin = lambda: self.fail("Started xfrin again")
+        bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
+        bob.start_resolver = lambda: self.fail("Started resolver again")
+
+        # Send again we want to start them. Should not do it, as they are.
+        bob.config_handler({'start_auth': True})
+        bob.config_handler({'start_resolver': True})
+
+    def test_config_not_started_early(self):
+        """
+        Test that processes are not started by the config handler before
+        startup.
+        """
+        bob = StartStopCheckBob()
+        self.check_preconditions(bob)
+
+        bob.start_auth = lambda: self.fail("Started auth again")
+        bob.start_xfrout = lambda: self.fail("Started xfrout again")
+        bob.start_xfrin = lambda: self.fail("Started xfrin again")
+        bob.start_zonemgr = lambda: self.fail("Started zonemgr again")
+        bob.start_resolver = lambda: self.fail("Started resolver again")
+
+        bob.config_handler({'start_auth': True, 'start_resolver': True})
+
+class TestPIDFile(unittest.TestCase):
+    def setUp(self):
+        self.pid_file = '@builddir@' + os.sep + 'bind10.pid'
+        if os.path.exists(self.pid_file):
+            os.unlink(self.pid_file)
+
+    def tearDown(self):
+        if os.path.exists(self.pid_file):
+            os.unlink(self.pid_file)
+
+    def check_pid_file(self):
+        # dump PID to the file, and confirm the content is correct
+        dump_pid(self.pid_file)
+        my_pid = os.getpid()
+        self.assertEqual(my_pid, int(open(self.pid_file, "r").read()))
+
+    def test_dump_pid(self):
+        self.check_pid_file()
+
+        # make sure any existing content will be removed
+        open(self.pid_file, "w").write('dummy data\n')
+        self.check_pid_file()
+
+    def test_unlink_pid_file_notexist(self):
+        dummy_data = 'dummy_data\n'
+        open(self.pid_file, "w").write(dummy_data)
+        unlink_pid_file("no_such_pid_file")
+        # the file specified for unlink_pid_file doesn't exist,
+        # and the original content of the file should be intact.
+        self.assertEqual(dummy_data, open(self.pid_file, "r").read())
+
+    def test_dump_pid_with_none(self):
+        # Check the behavior of dump_pid() and unlink_pid_file() with None.
+        # This should be no-op.
+        dump_pid(None)
+        self.assertFalse(os.path.exists(self.pid_file))
+
+        dummy_data = 'dummy_data\n'
+        open(self.pid_file, "w").write(dummy_data)
+        unlink_pid_file(None)
+        self.assertEqual(dummy_data, open(self.pid_file, "r").read())
+
+    def test_dump_pid_failure(self):
+        # the attempt to open file will fail, which should result in exception.
+        self.assertRaises(IOError, dump_pid,
+                          'nonexistent_dir' + os.sep + 'bind10.pid')
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/src/bin/cfgmgr/b10-cfgmgr.py.in b/src/bin/cfgmgr/b10-cfgmgr.py.in
index 659426d..e37ec48 100755
--- a/src/bin/cfgmgr/b10-cfgmgr.py.in
+++ b/src/bin/cfgmgr/b10-cfgmgr.py.in
@@ -26,10 +26,18 @@ import os
 isc.util.process.rename()
 
 # If B10_FROM_SOURCE is set in the environment, we use data files
-# from a directory relative to that, otherwise we use the ones
-# installed on the system
+# from a directory relative to the value of that variable, or, if defined,
+# relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR.  Otherwise
+# we use the ones installed on the system.
+# B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
+# tests where we want to use variuos types of configuration within the test
+# environment.  (We may want to make it even more generic so that the path is
+# passed from the boss process)
 if "B10_FROM_SOURCE" in os.environ:
-    DATA_PATH = os.environ["B10_FROM_SOURCE"]
+    if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+        DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
+    else:
+        DATA_PATH = os.environ["B10_FROM_SOURCE"]
 else:
     PREFIX = "@prefix@"
     DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
diff --git a/src/bin/resolver/b10-resolver.8 b/src/bin/resolver/b10-resolver.8
index 3125e32..849092c 100644
--- a/src/bin/resolver/b10-resolver.8
+++ b/src/bin/resolver/b10-resolver.8
@@ -74,7 +74,7 @@ to listen on\&. The list items are the
 \fIaddress\fR
 string and
 \fIport\fR
-number\&. The defaults are address ::1 port 5300 and address 127\&.0\&.0\&.1 port 5300\&.
+number\&. The defaults are address ::1 port 53 and address 127\&.0\&.0\&.1 port 53\&.
 .PP
 
 \fIretries\fR
diff --git a/src/bin/resolver/b10-resolver.xml b/src/bin/resolver/b10-resolver.xml
index 0d395a7..bdf4f8a 100644
--- a/src/bin/resolver/b10-resolver.xml
+++ b/src/bin/resolver/b10-resolver.xml
@@ -141,8 +141,9 @@ once that is merged you can for instance do 'config add Resolver/forward_address
       <command>b10-resolver</command> to listen on.
       The list items are the <varname>address</varname> string
       and <varname>port</varname> number.
-      The defaults are address ::1 port 5300 and
-      address 127.0.0.1 port 5300.
+      The defaults are address ::1 port 53 and
+      address 127.0.0.1 port 53.
+<!-- TODO: but defaults are not used, Trac #518 -->
     </para>
 
     <para>
diff --git a/src/bin/resolver/main.cc b/src/bin/resolver/main.cc
index 03f9ab7..d987c74 100644
--- a/src/bin/resolver/main.cc
+++ b/src/bin/resolver/main.cc
@@ -56,7 +56,6 @@ using namespace asiolink;
 
 namespace {
 
-// Default port current 5300 for testing purposes
 static const string PROGRAM = "Resolver";
 
 IOService io_service;
diff --git a/src/bin/resolver/resolver.spec.pre.in b/src/bin/resolver/resolver.spec.pre.in
index bc598b0..9df1e75 100644
--- a/src/bin/resolver/resolver.spec.pre.in
+++ b/src/bin/resolver/resolver.spec.pre.in
@@ -86,11 +86,11 @@
         "item_default": [
           {
             "address": "::1",
-            "port": 5300
+            "port": 53
           },
           {
             "address": "127.0.0.1",
-            "port": 5300
+            "port": 53
           }
         ],
         "list_item_spec": {
@@ -109,7 +109,7 @@
               "item_name": "port",
               "item_type": "integer",
               "item_optional": false,
-              "item_default": 5300
+              "item_default": 53
             }
           ]
         }
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index fd1288d..f420d4b 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -50,7 +50,11 @@ isc.util.process.rename()
 if "B10_FROM_BUILD" in os.environ:
     SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/xfrout"
     AUTH_SPECFILE_PATH = os.environ["B10_FROM_BUILD"] + "/src/bin/auth"
-    UNIX_SOCKET_FILE= os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
+    if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
+        UNIX_SOCKET_FILE = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"] + \
+            "/auth_xfrout_conn"
+    else:
+        UNIX_SOCKET_FILE = os.environ["B10_FROM_BUILD"] + "/auth_xfrout_conn"
 else:
     PREFIX = "@prefix@"
     DATAROOTDIR = "@datarootdir@"
diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am
index b6133bb..b28b784 100644
--- a/src/lib/asiolink/Makefile.am
+++ b/src/lib/asiolink/Makefile.am
@@ -29,6 +29,7 @@ libasiolink_la_SOURCES += io_fetch.cc io_fetch.h
 libasiolink_la_SOURCES += io_message.h
 libasiolink_la_SOURCES += io_service.cc io_service.h
 libasiolink_la_SOURCES += io_socket.cc io_socket.h
+libasiolink_la_SOURCES += qid_gen.cc qid_gen.h
 libasiolink_la_SOURCES += recursive_query.cc recursive_query.h
 libasiolink_la_SOURCES += simple_callback.h
 libasiolink_la_SOURCES += tcp_endpoint.h
diff --git a/src/lib/asiolink/io_fetch.cc b/src/lib/asiolink/io_fetch.cc
index bc85892..3ff44c0 100644
--- a/src/lib/asiolink/io_fetch.cc
+++ b/src/lib/asiolink/io_fetch.cc
@@ -28,6 +28,8 @@
 #include <dns/rcode.h>
 #include <log/logger.h>
 
+#include <asiolink/qid_gen.h>
+
 #include <asio.hpp>
 #include <asio/deadline_timer.hpp>
 
@@ -178,9 +180,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
         /// declarations.
         {
             Message msg(Message::RENDER);
-
-            // TODO: replace with boost::random or some other suitable PRNG
-            msg.setQid(0);
+            msg.setQid(QidGenerator::getInstance().generateQid());
             msg.setOpcode(Opcode::QUERY());
             msg.setRcode(Rcode::NOERROR());
             msg.setHeaderFlag(Message::HEADERFLAG_RD);
diff --git a/src/lib/asiolink/qid_gen.cc b/src/lib/asiolink/qid_gen.cc
new file mode 100644
index 0000000..4063b39
--- /dev/null
+++ b/src/lib/asiolink/qid_gen.cc
@@ -0,0 +1,54 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// qid_gen defines a generator for query id's
+//
+// We probably want to merge this with the weighted random in the nsas
+// (and other parts where we need randomness, perhaps another thing
+// for a general libutil?)
+
+#include <asiolink/qid_gen.h>
+
+#include <sys/time.h>
+
+namespace {
+    asiolink::QidGenerator qid_generator_instance;
+}
+
+namespace asiolink {
+
+QidGenerator&
+QidGenerator::getInstance() {
+    return (qid_generator_instance);
+}
+
+QidGenerator::QidGenerator() : dist_(0, 65535),
+                               vgen_(generator_, dist_)
+{
+    seed();
+}
+
+void
+QidGenerator::seed() {
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    generator_.seed((tv.tv_sec * 1000000) + tv.tv_usec);
+}
+
+isc::dns::qid_t
+QidGenerator::generateQid() {
+    return (vgen_());
+}
+
+} // namespace asiolink
diff --git a/src/lib/asiolink/qid_gen.h b/src/lib/asiolink/qid_gen.h
new file mode 100644
index 0000000..a5caa17
--- /dev/null
+++ b/src/lib/asiolink/qid_gen.h
@@ -0,0 +1,85 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// qid_gen defines a generator for query id's
+//
+// We probably want to merge this with the weighted random in the nsas
+// (and other parts where we need randomness, perhaps another thing
+// for a general libutil?)
+
+#ifndef __QID_GEN_H
+#define __QID_GEN_H
+
+#include <dns/message.h>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/variate_generator.hpp>
+
+
+namespace asiolink {
+
+/// This class generates Qids for outgoing queries
+///
+/// It is implemented as a singleton; the public way to access it
+/// is to call getInstance()->generateQid().
+///
+/// It automatically seeds it with the current time when it is first
+/// used.
+class QidGenerator {
+public:
+    /// \brief Returns the singleton instance of the QidGenerator
+    ///
+    /// Returns a reference to the singleton instance of the generator
+    static QidGenerator& getInstance();
+
+    /// \brief Default constructor
+    ///
+    /// It is recommended that getInstance is used rather than creating
+    /// separate instances of this class.
+    ///
+    /// The constructor automatically seeds the generator with the
+    /// current time.
+    QidGenerator();
+
+    /// Generate a Qid
+    ///
+    /// \return A random Qid
+    isc::dns::qid_t generateQid();
+
+    /// \brief Seeds the QidGenerator (based on the current time)
+    ///
+    /// This is automatically called by the constructor
+    void seed();
+
+private:
+    // "Mersenne Twister: A 623-dimensionally equidistributed
+    // uniform pseudo-random number generator", Makoto Matsumoto and
+    // Takuji Nishimura, ACM Transactions on Modeling and Computer
+    // Simulation: Special Issue on Uniform Random Number Generation,
+    // Vol. 8, No. 1, January 1998, pp. 3-30.
+    //
+    // mt19937 is an implementation of one of the pseudo random
+    // generators described in this paper.
+    boost::mt19937 generator_;
+
+    // For qid's we want a uniform distribution
+    boost::uniform_int<> dist_;
+
+    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > vgen_;
+};
+
+
+} // namespace asiolink
+
+#endif // __QID_GEN_H
diff --git a/src/lib/asiolink/tcp_server.cc b/src/lib/asiolink/tcp_server.cc
index df19b00..3e0cdb4 100644
--- a/src/lib/asiolink/tcp_server.cc
+++ b/src/lib/asiolink/tcp_server.cc
@@ -17,6 +17,7 @@
 #include <netinet/in.h>
 #include <sys/socket.h>
 #include <unistd.h>             // for some IPC/network system calls
+#include <errno.h>
 
 #include <boost/shared_array.hpp>
 
@@ -83,11 +84,21 @@ TCPServer::operator()(error_code ec, size_t length) {
             /// Create a socket to listen for connections
             socket_.reset(new tcp::socket(acceptor_->get_io_service()));
 
-            /// Wait for new connections. In the event of error,
+            /// Wait for new connections. In the event of non-fatal error,
             /// try again
             do {
                 CORO_YIELD acceptor_->async_accept(*socket_, *this);
-            } while (!ec);
+                // Abort on fatal errors
+                // TODO: Log error?
+                if (ec) {
+                    using namespace asio::error;
+                    if (ec.value() != would_block && ec.value() != try_again &&
+                        ec.value() != connection_aborted &&
+                        ec.value() != interrupted) {
+                        return;
+                    }
+                }
+            } while (ec);
 
             /// Fork the coroutine by creating a copy of this one and
             /// scheduling it on the ASIO service queue.  The parent
diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am
index 075df19..3a229f3 100644
--- a/src/lib/asiolink/tests/Makefile.am
+++ b/src/lib/asiolink/tests/Makefile.am
@@ -31,6 +31,7 @@ run_unittests_SOURCES += tcp_endpoint_unittest.cc
 run_unittests_SOURCES += tcp_socket_unittest.cc
 run_unittests_SOURCES += udp_endpoint_unittest.cc
 run_unittests_SOURCES += udp_socket_unittest.cc
+run_unittests_SOURCES += qid_gen_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 
diff --git a/src/lib/asiolink/tests/qid_gen_unittest.cc b/src/lib/asiolink/tests/qid_gen_unittest.cc
new file mode 100644
index 0000000..3ad8a03
--- /dev/null
+++ b/src/lib/asiolink/tests/qid_gen_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+
+/// \brief Test of QidGenerator
+///
+
+#include <gtest/gtest.h>
+
+#include <asiolink/qid_gen.h>
+#include <dns/message.h>
+
+// Tests the operation of the Qid generator
+
+// Check that getInstance returns a singleton
+TEST(QidGenerator, singleton) {
+    asiolink::QidGenerator& g1 = asiolink::QidGenerator::getInstance();
+    asiolink::QidGenerator& g2 = asiolink::QidGenerator::getInstance();
+
+    EXPECT_TRUE(&g1 == &g2);
+}
+
+TEST(QidGenerator, generate) {
+    // We'll assume that boost's generator is 'good enough', and won't
+    // do full statistical checking here. Let's just call it the xkcd
+    // test (http://xkcd.com/221/), and check if three consecutive
+    // generates are not all the same.
+    isc::dns::qid_t one, two, three;
+    asiolink::QidGenerator& gen = asiolink::QidGenerator::getInstance();
+    one = gen.generateQid();
+    two = gen.generateQid();
+    three = gen.generateQid();
+    ASSERT_FALSE((one == two) && (one == three));
+}
diff --git a/src/lib/asiolink/udp_server.cc b/src/lib/asiolink/udp_server.cc
index 98a47c4..2c19608 100644
--- a/src/lib/asiolink/udp_server.cc
+++ b/src/lib/asiolink/udp_server.cc
@@ -15,6 +15,7 @@
 #include <netinet/in.h>
 #include <sys/socket.h>
 #include <unistd.h>             // for some IPC/network system calls
+#include <errno.h>
 
 #include <boost/shared_array.hpp>
 
@@ -195,6 +196,14 @@ UDPServer::operator()(error_code ec, size_t length) {
                 CORO_YIELD data_->socket_->async_receive_from(
                     buffer(data_->data_.get(), MAX_LENGTH), *data_->sender_,
                     *this);
+                // Abort on fatal errors
+                if (ec) {
+                    using namespace asio::error;
+                    if (ec.value() != would_block && ec.value() != try_again &&
+                        ec.value() != interrupted) {
+                        return;
+                    }
+                }
             } while (ec || length == 0);
 
             data_->bytes_ = length;
diff --git a/src/lib/log/Makefile.am b/src/lib/log/Makefile.am
index 4aaaba3..d941b01 100644
--- a/src/lib/log/Makefile.am
+++ b/src/lib/log/Makefile.am
@@ -23,7 +23,10 @@ liblog_la_SOURCES += message_types.h
 liblog_la_SOURCES += root_logger_name.cc root_logger_name.h
 liblog_la_SOURCES += strutil.h strutil.cc
 
-EXTRA_DIST = messagedef.mes
+EXTRA_DIST  = README
+EXTRA_DIST += messagedef.mes
+EXTRA_DIST += logger_impl_log4cxx.cc logger_impl_log4cxx.h
+EXTRA_DIST += xdebuglevel.cc xdebuglevel.h
 
 # Note: the ordering matters: -Wno-... must follow -Wextra (defined in
 # B10_CXXFLAGS)
diff --git a/src/lib/log/README b/src/lib/log/README
new file mode 100644
index 0000000..072649e
--- /dev/null
+++ b/src/lib/log/README
@@ -0,0 +1,376 @@
+This directory holds the first release of the logging system.
+
+Basic Ideas
+===========
+The BIND-10 logging system merges two ideas:
+
+* A hierarchical logging system similar to that used in Java (i.e. log4j)
+* Separation of message definitions and text
+
+
+Hierarchical Logging System
+===========================
+When a program writes a message to the logging system, it does so using an
+instance of the Logger class.  As well as performing the write of the message,
+the logger identifies the source of the message: different sources can write
+to different destinations and can log different severities of messages.
+For example, the "cache" logger could write messages of DEBUG severity or
+above to a file while all other components write messages of "INFO" severity
+or above to the Syslog file.
+
+The loggers are hierarchical in that each logger is the child of another
+logger.  The top of the hierarchy is the root logger, which does not have
+a parent.  The point of the hierarchy is that unless a logger is explicitly
+assigned an attribute (such as severity of message being logger), it picks
+it up from the parent.  (In BIND-10, there is the root logger (named after
+the program) and every other logger is a child of that.)  So in the example
+above, the INFO/Syslog attributes could be associated with the root logger
+while the DEBUG/file attributes are associated with the "cache" logger.
+
+
+Separation of Messages Definitions And Text
+===========================================
+The reason for this is to allow the message text to be overridden by versions
+in a local language.  To do this, each message is identified by an identifier
+e.g. "OPENIN".  Within the program, this is the symbol passed to the logging
+system.  The logger system uses the symbol as an index into a dictionary to
+retrieve the message associated with it (e.g. "unable to open %s for input").
+substitutes any message parameters (in this example, the string that is an
+invalid filename) and logs it to the destination.
+
+In the BIND-10 system, a set of default messages are linked into the
+program.  At run-time. each program reads a message file, updating the
+stored definitions; this updated text is logged.  However, to aid support,
+the message identifier so in the example above, the message finally logged
+would be something like:
+
+    OPENIN, unable to open a.txt for input
+
+
+Using The System
+================
+The steps in using the system are:
+
+1. Create a message file.  This defines messages by an identification - a
+   mnemonic for the message, typically 6-12 characters long - and a message.
+   The file is described in more detail below.
+
+   Ideally the file should have a file type of ".msg".
+
+2. Run it through the message compiler to produce the .h and .cc files.  It
+   is intended that this step be included in the build process.  However,
+   for now run the compiler (found in the "compiler" subdirectory) manually.
+   The only argument is the name of the message file: it will produce as
+   output two files, having the same name as the input file but with file
+   types of ".h" and ".cc".
+
+   The compiler is built in the "compiler" subdirectory of the "src/lib/log"
+   directory.
+
+3. Include the .h file in your source code to define message symbols, and
+   make sure that the .cc file is compiled and linked into your program -
+   static initialization will add the symbols to the global dictionary.
+
+4. Declare loggers in your code and use them to log messages.  This is
+   described in more detail below.
+
+5. To set the debug level and run-time message file, call initLogger (declared
+   in logger_support.h) in the main program unit.  This is a temporary solution
+   for Year 2, and will be replaced at a later date, the information coming
+   from the configuration database.
+
+
+Message Files
+=============
+
+File Contents and Format
+------------------------
+A message file is a file containing message definitions.  Typically there
+will be one message file for each component that declares message symbols.
+An example file could be:
+
+-- BEGIN --
+
+# Example message file
+# $ID:$
+
+$PREFIX TEST_
+$NAMESPACE isc::log
+TEST1       message %s is much too large
++ This message is a test for the general message code
+
+UNKNOWN     unknown message
++ Issued when the message is unknown.
+
+-- END --
+
+Points to note:
+* Leading and trailing space are trimmed from the line.  Although the above
+  example has every line starting at column 1, the lines could be indented
+  if desired.
+
+* Blank lines are ignored.
+
+* Lines starting with "#" are comments are are ignored.  Comments must be on
+  a line by themselves - inline comments will be interpreted as part of the
+  text of the line.
+
+* Lines starting $ are directives.  At present, two directives are recognised:
+
+  * $PREFIX, which has one argument: the string used to prefix symbols.  If
+    absent, there is no prefix to the symbols. (Prefixes are explained below.)
+  * $NAMESPACE, which has one argument: the namespace in which the symbols are
+    created.  In the absence of a $NAMESPACE directive, symbols will be put
+    in the global namespace.
+
+* Lines starting + indicate an explanation for the preceding message.  These
+  are intended to be processed by a separate program and used to generate
+  an error messages manual.  However they are treated like comments by the
+  message compiler.  As with comments, these must be on a line by themselves;
+  if inline, the text (including the leading "+") will be interpreted as
+  part of the line.
+
+* Message lines.  These comprise a symbol name and a message, which may
+  include zero or more printf-style tokens.  Symbol names will be upper-cased
+  by the compiler.
+
+
+Message Compiler
+----------------
+The message compiler is a program built in the src/log/compiler directory.
+It is invoked by the command:
+
+    message [-h] [-v] <message-file>
+
+("-v" prints the version number and exits; "-h" prints brief help text.)
+The message compiler processes the message file to produce two files:
+
+1) A C++ header file (called <message-file-name>.h) that holds lines of
+the form:
+
+   namespace <namespace> {
+   extern const isc::log::MessageID PREFIX_IDENTIFIER;
+      :
+   }
+
+The symbols define the keys in the global message dictionary.
+
+The namespace enclosing the symbols is set by the $NAMESPACE directive.
+
+The "PREFIX_" part of the symbol name is the string defined in the $PREFIX
+the argument to the directive.  So "$PREFIX MSG_" would prefix the identifer
+ABC with "MSG_" to give the symbol MSG_ABC.  Similarly "$PREFIX E" would
+prefix it with "E" to give the symbol EABC.  If no $PREFIX is given, no
+prefix appears (so the symbol in this example would be ABC).
+
+2) A C++ source file (called <message-file-name>.cc) that holds the definitions
+of the global symbols and code to insert the symbols and messages into the map.
+
+Symbols are defined to be equal to strings holding the identifier, e.g.
+
+   extern const isc::log::MessageID MSG_DUPLNS = "DUPLNS";
+
+(The implementation allows symbols to be compared.  However, use of strings
+should not be assumed - a future implementation may change this.)
+
+In addition, the file declares an array of identifiers/messages and an object
+to add them to the global dictionary:
+
+    namespace {
+    const char* values[] = {
+        identifier1, text1,
+        identifier2, text2,
+        :
+        NULL
+    };
+
+    const isc::log::MessageInitializer initializer(values);
+    }
+
+The constructor of the MessageInitializer object retrieves the singleton
+global Dictionary object (created using standard methods to avoid the
+"static initialization fiasco") and adds each identifier and text to it.
+A check is made as each is added; if the identifier already exists, it is
+added to "overflow" vector; the vector is printed to the main logging output
+when logging is finally enabled (to indicate a programming error).
+
+
+Using the Logging
+=================
+To use the current version of the logging:
+
+1. Build message header file and source file as describe above.
+
+2. In the main module of the program, declare an instance of the
+   RootLoggerName class to define the name of the program's root logger, e.g.
+
+       #include <log/root_logger_name.h>
+
+       isc::log::RootLoggerName("b10-auth");
+
+   This can be declared inside or outside an execution unit.
+
+2. In the code that needs to do logging, declare a logger with a given name,
+   e.g.
+
+       #include <log/logger.h>
+            :
+       isc::log::Logger logger("myname");   // "myname" can be anything
+
+   The above example assumes declaration outside a function.  If declaring
+   non-statically within a function, declare it as:
+
+       isc::log::Logger logger("myname", true);
+
+   (The argument is required to support a possible future implementation of
+   logging.  Currently it has no effect.)
+
+3. The main program unit should include a call to isc::log::initLogger()
+   (defined in logger_support.h) to set the logging severity, debug log level,
+   and external message file.
+
+   a) The logging severity is one of the enum defined in logger.h, i.e.
+
+        isc::log::DEBUG
+        isc::log::INFO
+        isc::log::WARN
+        isc::log::ERROR
+        isc::log::FATAL
+        isc::log::NONE
+
+   b) The debug log level is only interpreted when the severity is DEBUG and
+      is an integer ranging from 0 to 99.  0 should be used for the
+      highest-level debug messages and 99 for the lowest-level (and typically
+      more verbose) messages.
+
+   c) Name of an external message file.  This is the same as a standard message
+      file, although it should not include any directives. (A single directive
+      of a particular type will be ignored; multiple directives will cause the
+      read of the file to fail with an error.)  If a message is replaced, the
+      message should include the same printf-format directives in the same order
+      as the original message.
+
+4. Issue logging calls using methods on logger, e.g.
+
+       logger.error(DPS_NSTIMEOUT, "isc.org");
+
+   (where, in the example above we might have defined the symbol in the message
+   file with something along the lines of:
+
+       $PREFIX DPS_
+           :
+       NSTIMEOUT  queries to all nameservers for %s have timed out
+
+   At present, the only logging is to the console.
+
+
+Severity Guidelines
+===================
+When using logging, the question arises, what severity should a message be
+logged at?  The following is a suggestion - as always, the decision must be
+made in the context of which the message is logged.
+
+FATAL
+-----
+The program has encountered an error that is so severe that it cannot
+continue (or there is no point in continuing).  When a fatal error has been
+logged, the program will usually exit immediately (via a call to abort()) or
+shortly afterwards, after dumping some diagnostic information.
+
+ERROR
+-----
+Something has happened such that the program can continue but the results
+for the current (or future) operations cannot be guaranteed to be correct,
+or the results will be correct but the service is impaired.  For example,
+the program started but attempts to open one or more network interfaces failed.
+
+WARN
+----
+An unusual event  happened.  Although the program will continue working
+normally, the event was sufficiently out of the ordinary to warrant drawing
+attention to it.  For example, at program start-up a zone was loaded that
+contained no resource records,
+
+INFO
+----
+A normal but significant event has occurred that should be recorded,
+e.g. the program has started or is just about to terminate, a new zone has
+been created, etc.
+
+DEBUG
+-----
+This severity is only enabled on for debugging purposes.  A debug level is
+associated with debug messages, level 0 (the default) being for high-level
+messages and level 99 (the maximum) for the lowest level.  How the messages
+are distributed between the levels is up to the developer.  So if debugging
+the NSAS (for example), a level 0 message might record the creation of a new
+zone, a level 10 recording a timeout when trying to get a nameserver address,
+but a level 50 would record every query for an address. (And we might add
+level 51 to record every update of the RTT.)
+
+Note that like severities, levels are cumulative; so if level 25 is set as the
+debug level, all debug levels from 0 to 25 will be output.  In fact, it is
+probably easier to visualise the debug levels as part of the severity system:
+
+    FATAL                High
+    ERROR
+    WARN
+    INFO
+    DEBUG level 0
+    DEBUG level 1
+       :
+    DEBUG level 99       Low
+
+When a particular severity is set, it - and all severities and/or debug
+levels above it - will be logged.
+
+Logging Sources v Logging Severities
+------------------------------------
+When logging events, make a distinction between events related to the server
+and events related to DNS messages received.  Caution needs to be exercised
+with the latter as, if the logging is enabled in the normal course of events,
+such logging could be a denial of service vector. For example, suppose that
+the main authoritiative service logger were to log both zone loading and
+unloading as INFO and a warning message if it received an invalid packet. An
+attacker could make the INFO messages unusable by flooding the server with
+malformed packets.
+
+There are two approaches to get round this:
+
+a) Make the logging of packet-dependent events a DEBUG-severity message.
+DEBUG is not enabled by default, so these events will not be recorded unless
+DEBUG is specifically chosen.
+
+b) Record system-related and packet-related messages via different loggers
+(e.g.  in the example given, server events could be logged using the logger
+"auth" and packet-related events at that level logged using the logger
+"pkt-auth".)  As the loggers are independent and the severity levels
+independent, fine-tuning of what and what is not recorded can be achieved.
+
+
+Notes
+=====
+The message compiler is written in C++ (instead of Python) because it
+contains a component that reads the message file.  This component is used
+in both the message compiler and the server; in the server it is used when
+the server starts up (or when triggered by a command) to read in a message
+file to overwrite the internal dictionary.  Writing it in C++ means there
+is only one piece of code that does this functionality.
+
+
+Outstanding Issues
+==================
+* Ability to configure system according to configuration database.
+* Update the build procedure to create .cc and .h files from the .msg file
+  during the build process. (Requires that the message compiler is built
+  first.)
+
+
+log4cxx Issues
+==============
+Some experimental code to utilise log4cxx as an underlying implementation
+is present in the source code directory although it is not currently used.
+The files are:
+
+   logger_impl_log4cxx.{cc,h}
+   xdebuglevel.{cc,h}
diff --git a/src/lib/log/documentation.txt b/src/lib/log/documentation.txt
deleted file mode 100644
index 0501587..0000000
--- a/src/lib/log/documentation.txt
+++ /dev/null
@@ -1,434 +0,0 @@
-This directory holds the first release of the logging system.
-
-Basic Ideas
-===========
-The BIND-10 logging system merges two ideas:
-
-* A hierarchical logging system similar to that used in Java (i.e. log4j)
-* Separation of message definitions and text
-
-
-Hierarchical Logging System
-===========================
-When a program writes a message to the logging system, it does so using an
-instance of the Logger class.  As well as performing the write of the message,
-the logger identifies the source of the message: different sources can write
-to different destinations and can log different severities of messages.
-For example, the "cache" logger could write messages of DEBUG severity or
-above to a file while all other components write messages of "INFO" severity
-or above to the Syslog file.
-
-The loggers are hierarchical in that each logger is the child of another
-logger.  The top of the hierarchy is the root logger, which does not have
-a parent.  The point of the hierarchy is that unless a logger is explicitly
-assigned an attribute (such as severity of message being logger), it picks
-it up from the parent.  (In BIND-10, there is the root logger (named after
-the program) and every other logger is a child of that.)  So in the example
-above, the INFO/Syslog attributes could be associated with the root logger
-while the DEBUG/file attributes are associated with the "cache" logger.
-
-
-Separation of Messages Definitions And Text
-===========================================
-The reason for this is to allow the message text to be overridden by versions
-in a local language.  To do this, each message is identified by an identifier
-e.g. "OPENIN".  Within the program, this is the symbol passed to the logging
-system.  The logger system uses the symbol as an index into a dictionary to
-retrieve the message associated with it (e.g. "unable to open %s for input").
-substitutes any message parameters (in this example, the string that is an
-invalid filename) and logs it to the destination.
-
-In the BIND-10 system, a set of default messages are linked into the
-program.  At run-time. each program reads a message file, updating the
-stored definitions; this updated text is logged.  However, to aid support,
-the message identifier so in the example above, the message finally logged
-would be something like:
-
-    OPENIN, unable to open a.txt for input
-
-
-Using The System
-================
-The steps in using the system are:
-
-1. Create a message file.  This defines messages by an identification - a
-   mnemonic for the message, typically 6-12 characters long - and a message.
-   The file is described in more detail below.
-
-   Ideally the file should have a file type of ".msg".
-
-2. Run it through the message compiler to produce the .h and .cc files.  It
-   is intended that this step be included in the build process.  However,
-   for not run the compiler (found in the "compiler" subdirectory) manually.
-   The only argument is the name of the message file: it will produce as
-   output two files, having the same name as the input file but with file
-   types of ".h" and ".cc".
-
-   The compiler is built in the "compiler" subdirectory of the "src/lib/log"
-   directory.
-
-3. Include the .h file in your source code to define message symbols, and
-   make sure that the .cc file is compiled and linked into your program -
-   static initialization will add the symbols to the global dictionary.
-
-4. Declare loggers in your code and use them to log messages.  This is
-   described in more detail below.
-
-5. To set the debug level and run-time message file, call runTimeInit (declared
-   in logger_support.h) in the main program unit.  This is a temporary solution
-   for Year 2, and will be replaced at a later date, the information coming
-   from the configuration database.
-
-
-Message Files
-=============
-
-File Contents and Format
-------------------------
-A message file is a file containing message definitions.  Typically there
-will be one message file for each component that declares message symbols.
-An example file could be:
-
--- BEGIN --
-
-# Example message file
-# $ID:$
-
-$PREFIX TEST_
-$NAMESPACE isc::log
-TEST1       message %s is much too large
-+ This message is a test for the general message code
-
-UNKNOWN     unknown message
-+ Issued when the message is unknown.
-
--- END --
-
-Points to note:
-* Leading and trailing space are trimmed from the line.  Although the above
-  exampl,e has every line starting at column 1, the lines could be indented
-  if desired.
-
-* Blank lines are ignored.
-
-* Lines starting with "#" are comments are are ignored.  Comments must be on
-  a line by themselves - inline comments will be interpreted as part of the
-  text of the line.
-
-* Lines starting $ are directives.  At present, two directives are recognised:
-
-  * $PREFIX, which has one argument: the string used to prefix symbols.  If
-    absent, there is no prefix to the symbols. (Prefixes are explained below.)
-  * $NAMESPACE, which has one argument: the namespace in which the symbols are
-    created.  (Specifying the argument as a double colon - i.e. "$NAMESPACE
-    ::" puts the symbol definitions in the unnamed namespace.  And not
-    including a $NAMESPACE directive will result in the symbols note being
-    put in any namespace.
-
-* Lines starting + indicate an explanation for the preceding message.  These
-  are intended to be processed by a separate program and used to generate
-  an error messages manual.  However they are treated like comments by the
-  message compiler.  As with comments, these must be on a line by themselves;
-  if inline, the text (including the leading "+") will be interpreted as
-  part of the line.
-
-* Message lines.  These comprise a symbol name and a message, which may
-  include zero or more printf-style tokens.  Symbol names will be upper-cased
-  by the compiler.
-
-
-Message Compiler
-----------------
-The message compiler is a program built in the src/log/compiler directory.
-It is invoked by the command:
-
-    message [-h] [-v] <message-file>
-
-("-v" prints the version number and exits; "-h" prints brief help text.)
-The message compiler processes the message file to produce two files:
-
-1) A C++ header file (called <message-file-name>.h) that holds lines of
-the form:
-
-   namespace <namespace> {
-   isc::log::MessageID PREFIX_IDENTIFIER = "IDENTIFIER";
-      :
-   }
-
-The symbols define the keys in the global message dictionary.  At present
-they are defined as std::strings, but a future implementation could redefine
-them as numeric values.
-
-The namespace enclosing the symbols is set by the $NAMESPACE directive.
-
-The "PREFIX_" part of the symbol name is the string defined in the $PREFIX
-the argument to the directive.  So "$PREFIX MSG_" would prefix the identifer
-ABC with "MSG_" to give the symbol MSG_ABC.  Similarly "$PREFIX E" would
-prefix it with "E" to give the symbol EABC.  If no $PREFIX is given, no
-prefix appears (so the symbol in this example would be ABC).
-
-The header file also includes a couple of lines to ensure that the message
-text is included in the final program image.
-
-
-2) A C++ source file (called <message-file-name>.cc) that holds the code to
-insert the symbols and messages into the map.
-
-This file declares an array of identifiers/messages in the form:
-
-    namespace {
-    const char* values[] = {
-        identifier1, text1,
-        identifier2, text2,
-        :
-        NULL
-    };
-    }
-
-(A more complex structure to group identifiers and their messages could be
-imposed, but as the array is generated by code and will be read by code,
-it is not needed.)
-
-It then declares an object that will add information to the global dictionary:
-
-    MessageInitializer <message-file-name>_<time>(values);
-
-(Declaring the object as "static" or in the anonymous namespace runs the risk
-of it being optimised away when the module is compiled with optimisation.
-But giving it a standard name would cause a clash when multiple files are
-used, hence an attempt at disambiguation.)
-
-The constructor of the MessageInitializer object retrieves the singleton
-global Dictionary object (created using standard methods to avoid the
-"static initialization fiasco") and adds each identifier and text to it.
-A check is made as each is added; if the identifier already exists, it is
-added to "overflow" vector; the vector is printed to the main logging output
-when logging is finally enabled (to indicate a programming error).
-
-
-Using the Logging
-=================
-To use the current version of the logging:
-
-1. Build message header file and source file as describe above.
-
-2. In the main module of the program, declare an instance of the
-   RootLoggerName class to define the name of the program's root logger, e.g.
-
-       #include <log/root_logger_name.h>
-
-       isc::log::RootLoggerName("b10-auth");
-
-   This can be declared inside or outside an execution unit.
-
-2. In the code that needs to do logging, declare a logger with a given name,
-   e.g.
-
-       #include <log/logger.h>
-            :
-       isc::log::Logger logger("myname");   // "myname" can be anything
-
-   The above example assumes declaration outside a function.  If declaring
-   non-statically within a function, declare it as:
-
-       isc::log::Logger logger("myname", true);
-
-   The argument is ignored for underlying implementations other than log4cxx.
-   See below for the use of this argument.
-
-3. The main program unit should include a call to isc::log::runTimeInit()
-   (defined in logger_support.h) to set the logging severity, debug log level,
-   and external message file.
-
-   a) The logging severity is one of the enum defined in logger.h, i.e.
-
-        isc::log::DEBUG
-        isc::log::INFO
-        isc::log::WARN
-        isc::log::ERROR
-        isc::log::FATAL
-        isc::log::NONE
-
-   b) The debug log level is only interpreted when the severity is DEBUG and
-      is an integer raning from 0 to 99.  0 should be used for the highest-level
-      debug messages and 99 for the lowest-level (and typically more verbose)
-      messages.
-
-   c) Name of an external message file.  This is the same as a standard message
-      file, although it should not include the $PREFIX directive. (A single
-      $PREFIX directive will be ignored; multiple directives will cause the
-      read of the file to fail with an error.)  If a message is replaced, the
-      message should include the same printf-format directives in the same order
-      as the original message.
-
-4. Issue logging calls using methods on logger, e.g.
-
-       logger.error(DPS_NSTIMEOUT, "isc.org");
-
-   (where, in the example above we might have defined the symbol in the message
-   file with something along the lines of:
-
-       $PREFIX DPS_
-           :
-       NSTIMEOUT  queries to all nameservers for %s have timed out
-
-   At present, the only logging is to the console.
-
-
-Severity Guidelines
-===================
-When using logging, the question arises, what severity should a message be
-logged at?  The following is a suggestion - as always, the decision must be
-made in the context of which the message is logged.
-
-FATAL
------
-The program has encountered an error that is so severe that it cannot
-continue (or there is no point in continuing).  When a fatal error has been
-logged, the program will usually exit immediately (via a call to abort()) or
-shortly afterwards, after dumping some diagnostic information.
-
-ERROR
------
-Something has happened such that the program can continue but the results
-for the current (or future) operations cannot be guaranteed to be correct,
-or the results will be correct but the service is impaired.  For example,
-the program started but attempts to open one or more network interfaces failed.
-
-WARN
-----
-An unusual event  happened.  Although the program will continue working
-normally, the event was sufficiently out of the ordinary to warrant drawing
-attention to it.  For example, at program start-up a zone was loaded that
-contained no resource records,
-
-INFO
-----
-A normal but significant event has occurred that should be recorded,
-e.g. the program has started or is just about to terminate, a new zone has
-been created, etc.
-
-DEBUG
------
-This severity is only enabled on for debugging purposes.  A debug level is
-associated with debug messages, level 0 (the default) being for high-level
-messages and level 99 (the maximum) for the lowest level.  How the messages
-are distributed between the levels is up to the developer.  So if debugging
-the NSAS (for example), a level 0 message might record the creation of a new
-zone, a level 10 recording a timeout when trying to get a nameserver address,
-but a level 50 would record every query for an address. (And we might add
-level 51 to record every update of the RTT.)
-
-Note that like severities, levels are cumulative; so if level 25 is set as the
-debug level, all debug levels from 0 to 25 will be output.  In fact, it is
-probably easier to visualise the debug levels as part of the severity system:
-
-    FATAL                High
-    ERROR
-    WARN
-    INFO
-    DEBUG level 0
-    DEBUG level 1
-       :
-    DEBUG level 99       Low
-
-When a particular severity is set, it - and all severities and/or debug
-levels above it - will be logged.
-
-Logging Sources v Logging Severities
-------------------------------------
-When logging events, make a distinction between events related to the server
-and events related to DNS messages received.  Caution needs to be exercised
-with the latter as, if the logging is enabled in the normal course of events,
-such logging could be a denoial of service vector. For example, suppose that
-the main authoritiative service logger were to log both zone loading and
-unloading as INFO and a warning message if it received an invalid packet. An
-attacker could make the INFO messages unusable by flooding the server with
-malformed packets.
-
-There are two approaches to get round this:
-
-a) Make the logging of packet-dependent events a DEBUG-severity message.
-DEBUG is not enabled by default, so these events will not be recorded unless
-DEBUG is specifically chosen.
-
-b) Record system-related and packet-related messages via different loggers
-(e.g.  in the example given, sever events could be logged using the logger
-"auth" and packet-related events at that level logged using the logger
-"pkt-auth".)  As the loggers are independent and the severity levels
-independent, fine-tuning of what and what is not recorded can be achieved.
-
-
-Notes
-=====
-The message compiler is written in C++ (instead of Python) because it
-contains a component that reads the message file.  This component is used
-in both the message compiler and the server; in the server it is used when
-the server starts up (or when triggered by a command) to read in a message
-file to overwrite the internal dictionary.  Writing it in C++ means there
-is only one piece of code that does this functionality.
-
-
-Outstanding Issues
-==================
-* Ability to configure system according to configuration database.
-* Update the build procedure to create .cc and .h files from the .msg file
-  during the build process. (Requires that the message compiler is built
-  first.)
-
-
-log4cxx Issues
-==============
-
-Second Argument in Logger Constructor
--------------------------------------
-As noted above, when using log4cxx as the underlying implementation, the
-argument to the logger's constructor should be set true if declaring the
-logger within a method and set false (or omitted) if declaring the logger
-external to an execution unit.
-
-This is due to an apparent bug in the underlying log4cxx, where the deletion
-of a statically-declared object at program termination can cause a segment
-fault. (The destruction of internal memory structures can sometimes happen
-out of order.)  By default the Logger class creates the structures in
-its constructor but does not delete them in the destruction.  The default
-behavious works because instead of reclaiming memory at program run-down,
-the operating system reclaims it when the process is deleted.
-
-Setting the second argument "true" causes the Logger's destructor to delete
-the log4cxx structures.  This does not cause a problem if the program is
-not terminating.  So use the second form when declaring an automatic instance
-of isc::log::Logger on the stack.
-
-Building with log4cxx
----------------------
-Owing to issues with versions of log4cxx on different systems, log4cxx was
-temporarily disabled.  To use log4cxx on your system:
-
-* Uncomment the log4cxx lines in configure.ac
-* In src/lib/log, replace the logger_impl.{cc,h} files with their log4cxx
-  equivalents, i.e.
-
-  cp logger_impl_log4cxx.h logger_impl.h
-  cp logger_impl_log4cxx.cc logger_impl.cc
-
-* In src/lib/log/Makefile.am, uncomment the lines:
-
-  # AM_CPPFLAGS += $(LOG4CXX_INCLUDES)
-
-  # liblog_la_SOURCES += xdebuglevel.cc xdebuglevel.h
-
-  # liblog_la_LDFLAGS = $(LOG4CXX_LDFLAGS)
-
-* In src/lib/log/test, re-enable testing of the log4cxx implementation
-  class, i.e.
-
-  cp logger_impl_log4cxx_unittest.cc logger_impl_unittest.cc
-
-  ... and uncomment the following lines in Makefile.am:
-
-  # run_unittests_SOURCES += logger_impl_unittest.cc
-
-  # run_unittests_SOURCES += xdebuglevel_unittest.cc
-
-Then rebuild the system from scratch.
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..d4008c0
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = system
diff --git a/tests/system/Makefile.am b/tests/system/Makefile.am
new file mode 100644
index 0000000..efd5d7f
--- /dev/null
+++ b/tests/system/Makefile.am
@@ -0,0 +1,13 @@
+systest:
+	sh $(srcdir)/runall.sh
+
+distclean-local:
+	sh $(srcdir)/cleanall.sh
+
+# Most of the files under this directory (including test subdirectories)
+# must be listed in EXTRA_DIST.
+EXTRA_DIST = README cleanall.sh ifconfig.sh start.pl stop.pl run.sh runall.sh
+EXTRA_DIST += glue/auth.good glue/example.good glue/noglue.good glue/test.good
+EXTRA_DIST += glue/tests.sh glue/clean.sh
+EXTRA_DIST += glue/nsx1/com.db glue/nsx1/net.db glue/nsx1/root-servers.nil.db
+EXTRA_DIST += glue/nsx1/root.db
diff --git a/tests/system/README b/tests/system/README
new file mode 100644
index 0000000..080652d
--- /dev/null
+++ b/tests/system/README
@@ -0,0 +1,62 @@
+Copyright (C) 2004, 2010, 2011  Internet Systems Consortium, Inc. ("ISC")
+Copyright (C) 2000, 2001  Internet Software Consortium.
+See COPYRIGHT in the source root or http://isc.org/copyright.html for terms.
+
+This is a simple test environment for running BIND 10 system tests
+involving multiple name servers.  It was originally developed for BIND
+9, and has been ported to test BIND 10 implementations.  Ideally we
+should share the same framework for both versions, so some part of
+the original setup are kept, even though they are BIND 9 specific and
+not currently used.
+
+Also, these tests generally rely on BIND 9 programs, most commonly its
+dig, and will sometimes be its name server (named).  So, the test
+environment assumes that there's a source tree of BIND 9 where its
+programs are built, and that an environment variable "BIND9_TOP" is
+set to point to the top directory of the source tree.
+
+There are multiple test suites, each in a separate subdirectory and
+involving a different DNS setup.  They are:
+
+  glue/		Glue handling tests
+(the following tests are planned to be added soon)
+  dnssec/	DNSSEC tests
+  masterfile/	Master file parser
+  xfer/		Zone transfer tests
+
+Typically each test suite sets up 2-5 instances of BIND 10 (or BIND 9
+named) and then performs one or more tests against them.  Within the
+test suite subdirectory, each instance has a separate subdirectory
+containing its configuration data.  By convention, these
+subdirectories are named "nsx1", "nsx2", etc for BIND 10 ("x" means
+BIND 10), and "ns1", "ns2", etc. for BIND 9.
+
+The tests are completely self-contained and do not require access to
+the real DNS.  Generally, one of the test servers (ns[x]1) is set up
+as a root name server and is listed in the hints file of the others.
+
+To enable all servers to run on the same machine, they bind to
+separate virtual IP address on the loopback interface.  ns[x]1 runs on
+10.53.0.1, ns[x]2 on 10.53.0.2, etc.  Before running any tests, you
+must set up these addresses by running "ifconfig.sh up" as root.
+
+Mac OS X:
+If you wish to make the interfaces survive across reboots
+copy org.isc.bind.system and org.isc.bind.system to
+/Library/LaunchDaemons then run
+"launchctl load /Library/LaunchDaemons/org.isc.bind.system.plist" as
+root.
+
+The servers use port 53210 instead of the usual port 53, so they can be
+run without root privileges once the interfaces have been set up.
+
+The tests can be run individually like this:
+
+  sh run.sh xfer
+  sh run.sh glue
+  etc.
+
+To run all the tests, just type "make systest" either on this directory
+or on the top source directory.  Note: currently these tests cannot be
+run when built under a separate build directory.  Everything must be
+run within the original source tree.
diff --git a/tests/system/cleanall.sh b/tests/system/cleanall.sh
new file mode 100755
index 0000000..17c3d4a
--- /dev/null
+++ b/tests/system/cleanall.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Clean up after system tests.
+#
+
+find . -type f \( \
+    -name 'K*' -o -name '*~' -o -name '*.core' -o -name '*.log' \
+    -o -name '*.pid' -o -name '*.keyset' -o -name named.run \
+    -o -name bind10.run -o -name lwresd.run -o -name ans.run \) -print | \
+    xargs rm -f
+
+status=0
+
+for d in `find . -type d -maxdepth 1 -mindepth 1 -print`
+do
+   test ! -f $d/clean.sh || ( cd $d && sh clean.sh )
+done
diff --git a/tests/system/conf.sh.in b/tests/system/conf.sh.in
new file mode 100755
index 0000000..29d959a
--- /dev/null
+++ b/tests/system/conf.sh.in
@@ -0,0 +1,54 @@
+#!/bin/sh
+#
+# Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000-2003  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Common configuration data for system tests, to be sourced into
+# other shell scripts.
+#
+
+# Prerequisite check
+if [ @srcdir@ != @builddir@ ]; then
+	echo "Currently systest doesn't work for a separate build tree."
+	echo "Rebuild BIND 10 on the source tree and run the tests."
+	exit 1
+fi
+
+if [ -z $BIND9_TOP ]; then
+	echo "systest assumes there's a compiled tree of BIND 9 which can be"
+	echo "accessed via the BIND9_TOP environment variable."
+	echo "Please make sure this assumption is met."
+	exit 1
+fi
+
+# Find the top of the source tree.
+TOP=@abs_top_srcdir@
+
+RUN_BIND10=$TOP/src/bin/bind10/run_bind10.sh
+B10_LOADZONE=$TOP/src/bin/loadzone/run_loadzone.sh
+BIND9_NAMED=$BIND9_TOP/bin/named/named
+DIG=$BIND9_TOP/bin/dig/dig
+# Test tools borrowed from BIND 9's system test (without change).
+TESTSOCK=$BIND9_TOP/bin/tests/system/testsock.pl
+DIGCOMP=$BIND9_TOP/bin/tests/system/digcomp.pl
+
+SUBDIRS="glue"
+#SUBDIRS="dnssec glue masterfile xfer"
+
+# PERL will be an empty string if no perl interpreter was found.
+PERL=@PERL@
+
+export RUN_BIND10 BIND9_NAMED DIG SUBDIRS PERL TESTSOCK
diff --git a/tests/system/glue/auth.good b/tests/system/glue/auth.good
new file mode 100644
index 0000000..2c619f6
--- /dev/null
+++ b/tests/system/glue/auth.good
@@ -0,0 +1,15 @@
+
+; <<>> DiG 9.0 <<>> +norec @10.53.0.1 -p 5300 foo.bar.example.org. a
+;; global options:  printcmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41239
+;; flags: qr ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
+
+;; QUESTION SECTION:
+;foo.bar.example.org.			IN	A
+
+;; AUTHORITY SECTION:
+example.org.		172800	IN	NS	b.root-servers.nil.
+
+;; ADDITIONAL SECTION:
+b.root-servers.nil.	300	IN	A	10.53.0.2
diff --git a/tests/system/glue/clean.sh b/tests/system/glue/clean.sh
new file mode 100755
index 0000000..b2c1e02
--- /dev/null
+++ b/tests/system/glue/clean.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Clean up after glue tests.
+#
+
+rm -f dig.out.*
+rm -f */msgq_socket */zone.sqlite3
diff --git a/tests/system/glue/example.good b/tests/system/glue/example.good
new file mode 100644
index 0000000..3b7bbb8
--- /dev/null
+++ b/tests/system/glue/example.good
@@ -0,0 +1,19 @@
+
+; <<>> DiG 9.0 <<>> +norec @10.53.0.1 -p 5300 foo.bar.example. A
+;; global options:  printcmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58772
+;; flags: qr ad; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 7
+
+;; QUESTION SECTION:
+;foo.bar.example.			IN	A
+
+;; AUTHORITY SECTION:
+example.			172800	IN	NS	NS1.example.COM.
+example.			172800	IN	NS	NS.example.
+
+;; ADDITIONAL SECTION:
+NS.example.		172800	IN	A	192.0.2.1
+NS.example.		172800	IN	A	192.0.2.2
+NS1.example.COM.	172800	IN	A	192.0.2.101
+NS1.example.COM.		172800	IN	AAAA	2001:db8::1
diff --git a/tests/system/glue/noglue.good b/tests/system/glue/noglue.good
new file mode 100644
index 0000000..57a2211
--- /dev/null
+++ b/tests/system/glue/noglue.good
@@ -0,0 +1,14 @@
+
+; <<>> DiG 9.0 <<>> @10.53.0.1 -p 5300 example.net a
+;; global options:  printcmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29409
+;; flags: qr rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 0
+
+;; QUESTION SECTION:
+;example.net.			IN	A
+
+;; AUTHORITY SECTION:
+example.net.		300	IN	NS	ns2.example.info.
+example.net.		300	IN	NS	ns1.example.info.
+
diff --git a/tests/system/glue/nsx1/b10-config.db.in b/tests/system/glue/nsx1/b10-config.db.in
new file mode 100644
index 0000000..acd040c
--- /dev/null
+++ b/tests/system/glue/nsx1/b10-config.db.in
@@ -0,0 +1,9 @@
+{"version": 2,
+ "Auth": {
+   "listen_on": [{"address": "10.53.0.1", "port": 53210}],
+   "database_file": "@abs_builddir@/zone.sqlite3"
+ },
+ "Xfrout": {
+   "log_file": "@abs_builddir@/Xfrout.log"
+ }
+}
diff --git a/tests/system/glue/nsx1/com.db b/tests/system/glue/nsx1/com.db
new file mode 100644
index 0000000..c4b94e1
--- /dev/null
+++ b/tests/system/glue/nsx1/com.db
@@ -0,0 +1,31 @@
+; Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001  Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$ORIGIN com.
+$TTL 300
+@ 			IN SOA	root.example.com. a.root.servers.nil. (
+				2000042100   	; serial
+				600         	; refresh
+				600         	; retry
+				1200    	; expire
+				600       	; minimum
+				)
+@			NS	a.root-servers.nil.
+
+example.com.			NS	ns1.example.com.
+example.com.			NS	ns2.example.com.
+ns1.example.com.		172800	IN	A	192.0.2.101
+ns1.example.com.		172800	IN	AAAA	2001:db8::1
+ns2.example.com.		172800	IN	A	192.0.2.102
diff --git a/tests/system/glue/nsx1/net.db b/tests/system/glue/nsx1/net.db
new file mode 100644
index 0000000..8b66521
--- /dev/null
+++ b/tests/system/glue/nsx1/net.db
@@ -0,0 +1,32 @@
+; Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001  Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$ORIGIN net.
+$TTL 300
+@ 			IN SOA	root.example.net. a.root.servers.nil. (
+				2000042100   	; serial
+				600         	; refresh
+				600         	; retry
+				1200    	; expire
+				600       	; minimum
+				)
+@			NS	a.root-servers.nil.
+
+; Referral outside of server authority, but with glue records present.
+; Don't hand out the glue.
+example.net.			NS	ns1.example.info.
+example.net.			NS	ns2.example.info.
+ns1.example.info.	172800	IN	A	192.0.2.101
+ns2.example.info.	172800	IN	A	192.0.2.102
diff --git a/tests/system/glue/nsx1/root-servers.nil.db b/tests/system/glue/nsx1/root-servers.nil.db
new file mode 100644
index 0000000..45050a9
--- /dev/null
+++ b/tests/system/glue/nsx1/root-servers.nil.db
@@ -0,0 +1,26 @@
+; Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001  Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 300
+@			IN SOA	ns hostmaster (
+				1
+				3600
+				1800
+				1814400
+				3600
+				)
+			NS	a
+a			A	10.53.0.1
+b			A	10.53.0.2
diff --git a/tests/system/glue/nsx1/root.db b/tests/system/glue/nsx1/root.db
new file mode 100644
index 0000000..e43f2d2
--- /dev/null
+++ b/tests/system/glue/nsx1/root.db
@@ -0,0 +1,55 @@
+; Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+; Copyright (C) 2000, 2001  Internet Software Consortium.
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+$TTL 300
+. 			IN SOA	postmaster.example. a.root.servers.nil. (
+				2000042100   	; serial
+				600         	; refresh
+				600         	; retry
+				1200    	; expire
+				600       	; minimum
+				)
+.			NS	a.root-servers.nil.
+
+root-servers.nil.	NS	a.root-servers.nil.
+a.root-servers.nil.	A	10.53.0.1
+
+; Delegate some domains that contain name servers for the sample
+; ccTLDs below.
+com.			172800	IN	NS	a.root-servers.nil.
+
+;
+; A sample TLD
+;
+example.			172800	IN	NS	NS.example.
+example.			172800	IN	NS	NS1.example.COM.
+NS.example.			172800	IN	A	192.0.2.1
+NS.example.			172800	IN	A	192.0.2.2
+; this "glue" is below a zone cut for com.  BIND 9 still uses it for
+; the delegation to example.  BIND 10 (with sqlite3 data source) doesn't.
+NS1.example.COM.		172800	IN	A	192.0.2.3
+
+;
+;
+;
+test.				172800	IN	NS	ns.test.
+test.				172800	IN	NS	ns1.example.net.
+ns.test.			172800	IN	A	192.0.2.200
+ns1.example.net.		172800	IN	A	192.0.2.201
+
+;
+; A hypothetical ccTLD where we are authoritative for the NS glue.
+;
+example.org		172800  IN      NS      b.root-servers.nil.
diff --git a/tests/system/glue/setup.sh.in b/tests/system/glue/setup.sh.in
new file mode 100755
index 0000000..dc5b28a
--- /dev/null
+++ b/tests/system/glue/setup.sh.in
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+rm -f */zone.sqlite3
+${B10_LOADZONE} -o . -d @builddir@/nsx1/zone.sqlite3 @builddir@/nsx1/root.db
+${B10_LOADZONE} -o root-servers.nil -d @builddir@/nsx1/zone.sqlite3 \
+	@builddir@/nsx1/root-servers.nil.db
+${B10_LOADZONE} -o com -d @builddir@/nsx1/zone.sqlite3 @builddir@/nsx1/com.db
+${B10_LOADZONE} -o net -d @builddir@/nsx1/zone.sqlite3 @builddir@/nsx1/net.db
diff --git a/tests/system/glue/test.good b/tests/system/glue/test.good
new file mode 100644
index 0000000..b9b4719
--- /dev/null
+++ b/tests/system/glue/test.good
@@ -0,0 +1,19 @@
+
+; <<>> DiG 9.8.0 <<>> @127.0.0.1 -p 5300 foo.bar.test
+; (1 server found)
+;; global options: +cmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55069
+;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 2
+;; WARNING: recursion requested but not available
+
+;; QUESTION SECTION:
+;foo.bar.test.			IN	A
+
+;; AUTHORITY SECTION:
+test.			172800	IN	NS	ns.test.
+test.			172800	IN	NS	ns1.example.net.
+
+;; ADDITIONAL SECTION:
+ns.test.		172800	IN	A	192.0.2.200
+ns1.example.net.	172800	IN	A	192.0.2.201
diff --git a/tests/system/glue/tests.sh b/tests/system/glue/tests.sh
new file mode 100755
index 0000000..50b2330
--- /dev/null
+++ b/tests/system/glue/tests.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+#
+# Do glue tests.
+#
+
+status=0
+n=0
+
+# This query should result in a delegation with two NS; one in the delegated
+# zone and one in a so called out-of-bailiwick zone for which the auth server
+# has authority, too.  For the former, the server should return glue in the
+# parent zone.  For the latter, BIND 9 and BIND 10 behave differently; BIND 9
+# uses "glue" in the parent zone (since this is the root zone everything can
+# be considered a valid glue).  BIND 10 (using sqlite3 data source) searches
+# the other zone and uses the authoritative data in that zone (which is
+# intentionally different from the glue in the root zone).
+echo "I:testing that a TLD referral gets a full glue set from the root zone ($n)"
+$DIG +norec @10.53.0.1 -p 53210 foo.bar.example. A >dig.out.$n || status=1
+$PERL $DIGCOMP example.good dig.out.$n || status=1
+n=`expr $n + 1`
+
+echo "I:testing that we find glue A RRs we are authoritative for ($n)"
+$DIG +norec @10.53.0.1 -p 53210 foo.bar.example.org. a >dig.out.$n || status=1
+$PERL $DIGCOMP auth.good dig.out.$n || status=1
+n=`expr $n + 1`
+
+# We cannot do this test for BIND 10 because b10-auth doesn't act as a
+# recursive (caching) server (by design)
+# echo "I:testing that we find glue A/AAAA RRs in the cache ($n)"
+# $DIG +norec @10.53.0.1 -p 53210 foo.bar.yy. a >dig.out.$n || status=1
+# $PERL $DIGCOMP yy.good dig.out.$n || status=1
+# n=`expr $n + 1`
+
+echo "I:testing that we don't find out-of-zone glue ($n)"
+$DIG +norec @10.53.0.1 -p 53210 example.net. a > dig.out.$n || status=1
+$PERL $DIGCOMP noglue.good dig.out.$n || status=1
+n=`expr $n + 1`
+
+# This test currently fails (additional section will be empty, which is
+# incorrect).  See Trac ticket #646.
+#echo "I:testing that we are finding partial out-of-zone glue ($n)"
+#$DIG +norec @10.53.0.1 -p 53210 foo.bar.test. a >dig.out.$n || status=1
+#$PERL $DIGCOMP test.good dig.out.$n || status=1
+#n=`expr $n + 1`
+
+echo "I:exit status: $status"
+exit $status
diff --git a/tests/system/ifconfig.sh b/tests/system/ifconfig.sh
new file mode 100755
index 0000000..c0c365a
--- /dev/null
+++ b/tests/system/ifconfig.sh
@@ -0,0 +1,226 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007-2010  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000-2003  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Set up interface aliases for bind9 system tests.
+#
+# IPv4: 10.53.0.{1..7}				RFC 1918
+# IPv6: fd92:7065:b8e:ffff::{1..7}		ULA
+#
+
+config_guess=""
+for f in ./config.guess ../../config.guess
+do
+	if test -f $f
+	then
+		config_guess=$f
+	fi
+done
+
+if test "X$config_guess" = "X"
+then
+	cat <<EOF >&2
+$0: must be run from the top level source directory or the
+bin/tests/system directory
+EOF
+	exit 1
+fi
+
+# If running on hp-ux, don't even try to run config.guess.
+# It will try to create a temporary file in the current directory,
+# which fails when running as root with the current directory
+# on a NFS mounted disk.
+
+case `uname -a` in
+  *HP-UX*) sys=hpux ;;
+  *) sys=`sh $config_guess` ;;
+esac
+
+case "$2" in
+[0-9]|[1-9][0-9]|[1-9][0-9][0-9]) base=$2;;
+*) base=""
+esac
+
+case "$3" in
+[0-9]|[1-9][0-9]|[1-9][0-9][0-9]) base6=$2;;
+*) base6=""
+esac
+
+case "$1" in
+
+    start|up)
+	for ns in 1 2 3 4 5 6 7
+	do
+		if test -n "$base"
+		then
+			int=`expr $ns + $base - 1`
+		else
+			int=$ns
+		fi
+		if test -n "$base6"
+		then
+			int6=`expr $ns + $base6 - 1`
+		else
+			int6=$ns
+		fi
+		case "$sys" in
+		    *-pc-solaris2.5.1)
+			ifconfig lo0:$int 10.53.0.$ns netmask 0xffffffff up
+			;;
+		    *-sun-solaris2.[6-7])
+			ifconfig lo0:$int 10.53.0.$ns netmask 0xffffffff up
+			;;
+		    *-*-solaris2.[8-9]|*-*-solaris2.1[0-9])
+			/sbin/ifconfig lo0:$int plumb
+			/sbin/ifconfig lo0:$int 10.53.0.$ns up
+			if test -n "$int6"
+			then
+				/sbin/ifconfig lo0:$int6 inet6 plumb
+				/sbin/ifconfig lo0:$int6 \
+					inet6 fd92:7065:b8e:ffff::$ns up
+			fi
+			;;
+		    *-*-linux*)
+			ifconfig lo:$int 10.53.0.$ns up netmask 255.255.255.0
+			ifconfig lo inet6 add fd92:7065:b8e:ffff::$ns/64
+		        ;;
+		    *-unknown-freebsd*)
+			ifconfig lo0 10.53.0.$ns alias netmask 0xffffffff
+			ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
+			;;
+		    *-unknown-netbsd*)
+			ifconfig lo0 10.53.0.$ns alias netmask 255.255.255.0
+			ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
+			;;
+		    *-unknown-openbsd*)
+			ifconfig lo0 10.53.0.$ns alias netmask 255.255.255.0
+			ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
+			;;
+		    *-*-bsdi[3-5].*)
+			ifconfig lo0 add 10.53.0.$ns netmask 255.255.255.0
+			;;
+		    *-dec-osf[4-5].*)
+			ifconfig lo0 alias 10.53.0.$ns
+			;;
+		    *-sgi-irix6.*)
+			ifconfig lo0 alias 10.53.0.$ns
+			;;
+		    *-*-sysv5uw7*|*-*-sysv*UnixWare*|*-*-sysv*OpenUNIX*)
+			ifconfig lo0 10.53.0.$ns alias netmask 0xffffffff
+			;;
+		    *-ibm-aix4.*|*-ibm-aix5.*)
+			ifconfig lo0 alias 10.53.0.$ns
+			ifconfig lo0 inet6 alias -dad fd92:7065:b8e:ffff::$ns/64
+			;;
+		    hpux)
+			ifconfig lo0:$int 10.53.0.$ns netmask 255.255.255.0 up
+			ifconfig lo0:$int inet6 fd92:7065:b8e:ffff::$ns up
+		        ;;
+		    *-sco3.2v*)
+			ifconfig lo0 alias 10.53.0.$ns
+			;;
+		    *-darwin*)
+			ifconfig lo0 alias 10.53.0.$ns
+			ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns alias
+			;;
+	            *)
+			echo "Don't know how to set up interface.  Giving up."
+			exit 1
+		esac
+	done
+	;;
+
+    stop|down)
+	for ns in 7 6 5 4 3 2 1
+	do
+		if test -n "$base"
+		then
+			int=`expr $ns + $base - 1`
+		else
+			int=$ns
+		fi
+		case "$sys" in
+		    *-pc-solaris2.5.1)
+			ifconfig lo0:$int 0.0.0.0 down
+			;;
+		    *-sun-solaris2.[6-7])
+			ifconfig lo0:$int 10.53.0.$ns down
+			;;
+		    *-*-solaris2.[8-9]|*-*-solaris2.1[0-9])
+			ifconfig lo0:$int 10.53.0.$ns down
+			ifconfig lo0:$int 10.53.0.$ns unplumb
+			if test -n "$int6"
+			then
+				ifconfig lo0:$int6 inet6 down
+				ifconfig lo0:$int6 inet6 unplumb
+			fi
+			;;
+		    *-*-linux*)
+			ifconfig lo:$int 10.53.0.$ns down
+			ifconfig lo inet6 del fd92:7065:b8e:ffff::$ns/64
+		        ;;
+		    *-unknown-freebsd*)
+			ifconfig lo0 10.53.0.$ns delete
+			ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns delete
+			;;
+		    *-unknown-netbsd*)
+			ifconfig lo0 10.53.0.$ns delete
+			ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns delete
+			;;
+		    *-unknown-openbsd*)
+			ifconfig lo0 10.53.0.$ns delete
+			ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns delete
+			;;
+		    *-*-bsdi[3-5].*)
+			ifconfig lo0 remove 10.53.0.$ns
+			;;
+		    *-dec-osf[4-5].*)
+			ifconfig lo0 -alias 10.53.0.$ns
+			;;
+		    *-sgi-irix6.*)
+			ifconfig lo0 -alias 10.53.0.$ns
+			;;
+		    *-*-sysv5uw7*|*-*-sysv*UnixWare*|*-*-sysv*OpenUNIX*)
+			ifconfig lo0 -alias 10.53.0.$ns
+			;;
+		    *-ibm-aix4.*|*-ibm-aix5.*)
+			ifconfig lo0 delete 10.53.0.$ns
+			ifconfig lo0 delete inet6 fd92:7065:b8e:ffff::$ns/64
+			;;
+		    hpux)
+			ifconfig lo0:$int 0.0.0.0
+			ifconfig lo0:$int inet6 ::
+		        ;;
+		    *-sco3.2v*)
+			ifconfig lo0 -alias 10.53.0.$ns
+			;;
+		    *darwin*)
+			ifconfig lo0 -alias 10.53.0.$ns
+			ifconfig lo0 inet6 fd92:7065:b8e:ffff::$ns delete
+			;;
+	            *)
+			echo "Don't know how to destroy interface.  Giving up."
+			exit 1
+		esac
+	done
+
+	;;
+
+	*)
+		echo "Usage: $0 { up | down } [base]"
+		exit 1
+esac
diff --git a/tests/system/run.sh b/tests/system/run.sh
new file mode 100755
index 0000000..4f852f4
--- /dev/null
+++ b/tests/system/run.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007, 2010  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Run a system test.
+#
+
+SYSTEMTESTTOP=.
+. $SYSTEMTESTTOP/conf.sh
+
+stopservers=true
+
+case $1 in
+   --keep) stopservers=false; shift ;;
+esac
+
+test $# -gt 0 || { echo "usage: $0 [--keep] test-directory" >&2; exit 1; }
+
+test=$1
+shift
+
+test -d $test || { echo "$0: $test: no such test" >&2; exit 1; }
+
+echo "S:$test:`date`" >&2
+echo "T:$test:1:A" >&2
+echo "A:System test $test" >&2
+
+if [ x$PERL = x ]
+then
+    echo "I:Perl not available.  Skipping test." >&2
+    echo "R:UNTESTED" >&2
+    echo "E:$test:`date`" >&2
+    exit 0;
+fi
+
+$PERL $TESTSOCK || {
+    echo "I:Network interface aliases not set up.  Skipping test." >&2;
+    echo "R:UNTESTED" >&2;
+    echo "E:$test:`date`" >&2;
+    exit 0;
+}
+
+
+# Check for test-specific prerequisites.
+test ! -f $test/prereq.sh || ( cd $test && sh prereq.sh "$@" )
+result=$?
+
+if [ $result -eq 0 ]; then
+    : prereqs ok
+else
+    echo "I:Prerequisites for $test missing, skipping test." >&2
+    [ $result -eq 255 ] && echo "R:SKIPPED" || echo "R:UNTESTED"
+    echo "E:$test:`date`" >&2
+    exit 0
+fi
+
+# Check for PKCS#11 support
+if
+    test ! -f $test/usepkcs11 || sh cleanpkcs11.sh
+then
+    : pkcs11 ok
+else
+    echo "I:Need PKCS#11 for $test, skipping test." >&2
+    echo "R:PKCS11ONLY" >&2
+    echo "E:$test:`date`" >&2
+    exit 0
+fi
+
+# Set up any dynamically generated test data
+if test -f $test/setup.sh
+then
+   ( cd $test && sh setup.sh "$@" )
+fi
+
+# Start name servers running
+$PERL start.pl $test || exit 1
+
+# Run the tests
+( cd $test ; sh tests.sh )
+
+status=$?
+
+if $stopservers
+then
+    :
+else
+    exit $status
+fi
+
+# Shutdown
+$PERL stop.pl $test
+
+status=`expr $status + $?`
+
+if [ $status != 0 ]; then
+	echo "R:FAIL"
+	# Don't clean up - we need the evidence.
+	find . -name core -exec chmod 0644 '{}' \;
+else
+	echo "R:PASS"
+
+	# Clean up.
+	if test -f $test/clean.sh
+	then
+	   ( cd $test && sh clean.sh "$@" )
+	fi
+fi
+
+echo "E:$test:`date`"
+
+exit $status
diff --git a/tests/system/runall.sh b/tests/system/runall.sh
new file mode 100755
index 0000000..5d0fe9b
--- /dev/null
+++ b/tests/system/runall.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+#
+# Copyright (C) 2004, 2007, 2010  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2000, 2001  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+#
+# Run all the system tests.
+#
+
+SYSTEMTESTTOP=.
+. $SYSTEMTESTTOP/conf.sh
+
+status=0
+
+for d in $SUBDIRS
+do
+	sh run.sh $d || status=1
+done
+
+$PERL $TESTSOCK || {
+    cat <<EOF >&2
+I:
+I:NOTE: Many of the tests were skipped because they require that
+I:      the IP addresses 10.53.0.1 through 10.53.0.7 are configured
+I:	as alias addresses on the loopback interface.  Please run
+I:	"tests/system/ifconfig.sh up" as root to configure them
+I:	and rerun the tests.
+EOF
+    exit 0;
+}
+
+exit $status
diff --git a/tests/system/start.pl b/tests/system/start.pl
new file mode 100755
index 0000000..56f00c4
--- /dev/null
+++ b/tests/system/start.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2004-2008, 2010  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2001  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Framework for starting test servers.
+# Based on the type of server specified, check for port availability, remove
+# temporary files, start the server, and verify that the server is running.
+# If a server is specified, start it. Otherwise, start all servers for test.
+
+use strict;
+use Cwd 'abs_path';
+use Getopt::Long;
+
+# Option handling
+#   --noclean test [server [options]]
+#
+#   --noclean - Do not cleanup files in server directory
+#   test - name of the test directory
+#   server - name of the server directory
+#   options - alternate options for the server
+
+my $usage = "usage: $0 [--noclean] test-directory [server-directory [server-options]]";
+my $noclean;
+GetOptions('noclean' => \$noclean);
+my $test = $ARGV[0];
+my $server = $ARGV[1];
+my $options = $ARGV[2];
+
+if (!$test) {
+	print "$usage\n";
+}
+if (!-d $test) {
+	print "No test directory: \"$test\"\n";
+}
+if ($server && !-d "$test/$server") {
+	print "No server directory: \"$test/$server\"\n";
+}
+
+# Global variables
+my $topdir = abs_path("$test/..");
+my $testdir = abs_path("$test");
+my $RUN_BIND10 = $ENV{'RUN_BIND10'};
+my $NAMED = $ENV{'NAMED'};
+my $LWRESD = $ENV{'LWRESD'};
+my $DIG = $ENV{'DIG'};
+my $PERL = $ENV{'PERL'};
+my $TESTSOCK = $ENV{'TESTSOCK'};
+
+# Start the server(s)
+
+if ($server) {
+	if ($server =~ /^ns/) {
+		&check_ports($server);
+	}
+	&start_server($server, $options);
+	if ($server =~ /^ns/) {
+		&verify_server($server);
+	}
+} else {
+	# Determine which servers need to be started for this test.
+	opendir DIR, $testdir;
+	my @files = sort readdir DIR;
+	closedir DIR;
+
+	my @ns = grep /^nsx?[0-9]*$/, @files;
+	my @lwresd = grep /^lwresd[0-9]*$/, @files;
+	my @ans = grep /^ans[0-9]*$/, @files;
+
+	# Start the servers we found.
+	&check_ports();
+	foreach my $s (@ns, @lwresd, @ans) {
+		&start_server($s);
+	}
+	foreach my $s (@ns) {
+		&verify_server($s);
+	}
+}
+
+# Subroutines
+
+sub check_ports {
+	my $server = shift;
+	my $options = "";
+
+	if ($server && $server =~ /(\d+)$/) {
+		$options = "-i $1";
+	}
+
+	my $tries = 0;
+	while (1) {
+		my $return = system("$PERL $TESTSOCK -p 53210 $options");
+		last if ($return == 0);
+		if (++$tries > 4) {
+			print "$0: could not bind to server addresses, still running?\n";
+			print "I:server sockets not available\n";
+			print "R:FAIL\n";
+			system("$PERL $topdir/stop.pl $testdir"); # Is this the correct behavior?
+			exit 1;
+		}
+		print "I:Couldn't bind to socket (yet)\n";
+		sleep 2;
+	}
+}
+
+sub start_server {
+	my $server = shift;
+	my $options = shift;
+
+	my $cleanup_files;
+	my $command;
+	my $pid_file;
+
+	if ($server =~ /^nsx/) {
+		$cleanup_files = "{bind10.run}";
+		$command = "B10_FROM_SOURCE_LOCALSTATEDIR=$testdir/$server/ ";
+		$command .= "$RUN_BIND10 ";
+		if ($options) {
+			$command .= "$options";
+		} else {
+			$command .= "--msgq-socket-file=$testdir/$server/msgq_socket ";
+			$command .= "--pid-file=$testdir/$server/bind10.pid ";
+			$command .= "-v";
+		}
+		$command .= " >bind10.run 2>&1 &";
+		$pid_file = "bind10.pid";
+	} elsif ($server =~ /^ns/) {
+		$cleanup_files = "{*.jnl,*.bk,*.st,named.run}";
+		$command = "$NAMED ";
+		if ($options) {
+			$command .= "$options";
+		} else {
+			$command .= "-m record,size,mctx ";
+			$command .= "-T clienttest ";
+			$command .= "-T nosoa "
+				if (-e "$testdir/$server/named.nosoa");
+			$command .= "-T noaa "
+				if (-e "$testdir/$server/named.noaa");
+			$command .= "-c named.conf -d 99 -g";
+		}
+		$command .= " >named.run 2>&1 &";
+		$pid_file = "named.pid";
+	} elsif ($server =~ /^lwresd/) {
+		$cleanup_files = "{lwresd.run}";
+		$command = "$LWRESD ";
+		if ($options) {
+			$command .= "$options";
+		} else {
+			$command .= "-m record,size,mctx ";
+			$command .= "-T clienttest ";
+			$command .= "-C resolv.conf -d 99 -g ";
+			$command .= "-i lwresd.pid -P 9210 -p 53210";
+		}
+		$command .= " >lwresd.run 2>&1 &";
+		$pid_file = "lwresd.pid";
+	} elsif ($server =~ /^ans/) {
+		$cleanup_files = "{ans.run}";
+		$command = "$PERL ./ans.pl ";
+		if ($options) {
+			$command .= "$options";
+		} else {
+			$command .= "";
+		}
+		$command .= " >ans.run 2>&1 &";
+		$pid_file = "ans.pid";
+	} else {
+		print "I:Unknown server type $server\n";
+		print "R:FAIL\n";
+		system "$PERL $topdir/stop.pl $testdir";
+		exit 1;
+	}
+
+	#               print "I:starting server $server\n";
+
+	chdir "$testdir/$server";
+
+	unless ($noclean) {
+		unlink glob $cleanup_files;
+	}
+
+	system "$command";
+
+	my $tries = 0;
+	while (!-f $pid_file) {
+		if (++$tries > 14) {
+			print "I:Couldn't start server $server\n";
+			print "R:FAIL\n";
+			system "$PERL $topdir/stop.pl $testdir";
+			exit 1;
+		}
+		sleep 1;
+	}
+}
+
+sub verify_server {
+	my $server = shift;
+	my $n = $server;
+	$n =~ s/^nsx?//;
+
+	my $tries = 0;
+	while (1) {
+		my $return = system("$DIG +tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p 53210 version.bind. chaos txt \@10.53.0.$n > dig.out");
+		last if ($return == 0);
+		print `grep ";" dig.out`;
+		if (++$tries >= 30) {
+			print "I:no response from $server\n";
+			print "R:FAIL\n";
+			system("$PERL $topdir/stop.pl $testdir");
+			exit 1;
+		}
+		sleep 2;
+	}
+	unlink "dig.out";
+}
diff --git a/tests/system/stop.pl b/tests/system/stop.pl
new file mode 100755
index 0000000..a803f52
--- /dev/null
+++ b/tests/system/stop.pl
@@ -0,0 +1,188 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) 2001  Internet Software Consortium.
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# Framework for stopping test servers
+# Based on the type of server specified, signal the server to stop, wait
+# briefly for it to die, and then kill it if it is still alive.
+# If a server is specified, stop it. Otherwise, stop all servers for test.
+
+use strict;
+use Cwd 'abs_path';
+
+# Option handling
+#   [--use-rndc] test [server]
+#
+#   test - name of the test directory
+#   server - name of the server directory
+
+my $usage = "usage: $0 [--use-rndc] test-directory [server-directory]";
+my $use_rndc;
+
+while (@ARGV && $ARGV[0] =~ /^-/) {
+	my $opt = shift @ARGV;
+	if ($opt eq '--use-rndc') {
+		$use_rndc = 1;
+	} else {
+		die "$usage\n";
+	}
+}
+
+my $test = $ARGV[0];
+my $server = $ARGV[1];
+
+my $errors = 0;
+
+die "$usage\n" unless defined($test);
+die "No test directory: \"$test\"\n" unless (-d $test);
+die "No server directory: \"$server\"\n" if (defined($server) && !-d "$test/$server");
+
+# Global variables
+my $testdir = abs_path($test);
+my @servers;
+
+
+# Determine which servers need to be stopped.
+if (defined $server) {
+	@servers = ($server);
+} else {
+	local *DIR;
+	opendir DIR, $testdir or die "$testdir: $!\n";
+	my @files = sort readdir DIR;
+	closedir DIR;
+
+	my @ns = grep /^nsx?[0-9]*$/, @files;
+	my @lwresd = grep /^lwresd[0-9]*$/, @files;
+	my @ans = grep /^ans[0-9]*$/, @files;
+
+	push @servers, @ns, @lwresd, @ans;
+}
+
+
+# Stop the server(s), pass 1: rndc.
+if ($use_rndc) {
+	foreach my $server (grep /^ns/, @servers) {
+		stop_rndc($server);
+	}
+
+	wait_for_servers(30, grep /^ns/, @servers);
+}
+
+
+# Pass 2: SIGTERM
+foreach my $server (@servers) {
+	stop_signal($server, "TERM");
+}
+
+wait_for_servers(60, @servers);
+
+# Pass 3: SIGABRT
+foreach my $server (@servers) {
+	stop_signal($server, "ABRT");
+}
+
+exit($errors ? 1 : 0);
+
+# Subroutines
+
+# Return the full path to a given server's PID file.
+sub server_pid_file {
+	my($server) = @_;
+
+	my $pid_file;
+	if ($server =~ /^nsx/) {
+		$pid_file = "bind10.pid";
+	} elsif ($server =~ /^ns/) {
+		$pid_file = "named.pid";
+	} elsif ($server =~ /^lwresd/) {
+		$pid_file = "lwresd.pid";
+	} elsif ($server =~ /^ans/) {
+		$pid_file = "ans.pid";
+	} else {
+		print "I:Unknown server type $server\n";
+		exit 1;
+	}
+	$pid_file = "$testdir/$server/$pid_file";
+}
+
+# Read a PID.
+sub read_pid {
+	my($pid_file) = @_;
+
+	local *FH;
+	my $result = open FH, "< $pid_file";
+	if (!$result) {
+		print "I:$pid_file: $!\n";
+		unlink $pid_file;
+		return;
+	}
+
+	my $pid = <FH>;
+	chomp($pid);
+	return $pid;
+}
+
+# Stop a named process with rndc.
+sub stop_rndc {
+	my($server) = @_;
+
+	return unless ($server =~ /^ns(\d+)$/);
+	my $ip = "10.53.0.$1";
+
+	# Ugly, but should work.
+	system("$ENV{RNDC} -c $testdir/../common/rndc.conf -s $ip -p 9953 stop | sed 's/^/I:$server /'");
+	return;
+}
+
+# Stop a server by sending a signal to it.
+sub stop_signal {
+	my($server, $sig) = @_;
+
+	my $pid_file = server_pid_file($server);
+	return unless -f $pid_file;
+
+	my $pid = read_pid($pid_file);
+	return unless defined($pid);
+
+	if ($sig eq 'ABRT') {
+		print "I:$server didn't die when sent a SIGTERM\n";
+		$errors++;
+	}
+
+	my $result = kill $sig, $pid;
+	if (!$result) {
+		print "I:$server died before a SIG$sig was sent\n";
+		unlink $pid_file;
+		$errors++;
+	}
+
+	return;
+}
+
+sub wait_for_servers {
+	my($timeout, @servers) = @_;
+
+	my @pid_files = grep { defined($_) }
+	                map  { server_pid_file($_) } @servers;
+
+	while ($timeout > 0 && @pid_files > 0) {
+		@pid_files = grep { -f $_ } @pid_files;
+		sleep 1 if (@pid_files > 0);
+		$timeout--;
+	}
+
+	return;
+}




More information about the bind10-changes mailing list