BIND 10 trac598, updated. f6556f773732939bf68129e8c1fa10e84f8f2e36 [trac658] basic qid check
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Mar 10 14:34:11 UTC 2011
The branch, trac598 has been updated
via f6556f773732939bf68129e8c1fa10e84f8f2e36 (commit)
via d6f579083977bb3a94ed1bf2ffcaa31da878e0bf (commit)
via cba9add1f69d78f1ace066e76136bcf6f0a0d3d9 (commit)
via f7d2e62980d949a74bcaf03f6079cb847d6f0f0f (commit)
via 0cd6c3812b7e7250be1381cf87140794c9fa3c42 (commit)
via a84eadd788ec9544c79b26a47f5ef34f6b34c359 (commit)
via d39787aa4305f91cfca004088c6f5ca2a3867622 (commit)
via 08d197753711038ef73a50ebc4458df5a454f648 (commit)
via 290bbf2d7c93c202b22f1f4e2638ae01038bc983 (commit)
via 86d0ba9023b4f4a23cf203d3c9bf7c2f3668315e (commit)
via 1ac4ea1a6996dd39d15d4f6cbdf0a766e8d8d569 (commit)
via 58da05cd5f8709c8f4e1824c5479a0e3cd2b4371 (commit)
via bf8ba76aed284a9f1907b3edde1f546c9a4c0a3c (commit)
via b4149e03fd8f722fe1f0fe567b34d530da005109 (commit)
via a447b8e583551311e487816e11a171fdb0e8951a (commit)
via e0863720a874d75923ea66adcfbf5b2948efb10a (commit)
via 03de120c1148775977a8cad2b0697e934e2a823a (commit)
via 9287cc8f31d6ed03cdcd95f6ca59b58ed6d695b6 (commit)
via 34eaa7c5e831bb170f0fe8792e40df88f66ed8b9 (commit)
via 1af89c43e91b613bf3d8ece42ec5d93c19a5b225 (commit)
via b23ef1cf58b0754e23e550362e7a979d5f8624ef (commit)
via 5ff855e14dca375c24404eebc4573b77dba915d3 (commit)
via b9d341ecd382b44d72888899e3559d7d41baa203 (commit)
via b2d210a1ed486dc8c1083deb6f1b0bf2802e8d57 (commit)
via 3407184a20c367a0de02b41befb4db16971c9589 (commit)
from 416fcf7eb6c7c0dc249bcc838d75504f070750a1 (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 f6556f773732939bf68129e8c1fa10e84f8f2e36
Author: Jelte Jansen <jelte at isc.org>
Date: Wed Mar 9 16:26:08 2011 +0100
[trac658] basic qid check
(temporarily) copied the readUint16 code from buffer.h (right now we're not dealing with dns/buffer. Depending on whether we move this check to a point where we do have a buffer or not, we can remove it then or abstract it the moment we decide not to (i was wondering if said code is actually right, btw)
So if a response comes in where the qid does not match, we drop it and receive again (in an 'eternal' loop; until we get the right answer or time out)
the qid generation call is now in the constructor of IOFetchData (as is the qid itself so we can check later)
also added a writeUint8At to dns/buffer, needed in one of the tests.
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 7 +
configure.ac | 3 +-
src/bin/bindctl/Makefile.am | 9 +-
src/bin/bindctl/bindcmd.py | 17 ++-
src/bin/bindctl/bindctl.xml | 21 +++-
.../{bindctl-source.py.in => bindctl_main.py.in} | 27 +++--
src/bin/bindctl/tests/Makefile.am | 2 +-
src/bin/bindctl/tests/bindctl_test.py | 62 +++++++++--
src/lib/asiolink/io_fetch.cc | 81 +++++++++----
src/lib/asiolink/io_fetch.h | 5 +-
src/lib/asiolink/tcp_server.cc | 15 ++-
src/lib/asiolink/tests/io_fetch_unittest.cc | 93 +++++++++++++--
src/lib/asiolink/udp_server.cc | 11 ++-
src/lib/dns/buffer.h | 15 +++
src/lib/dns/tests/buffer_unittest.cc | 10 ++-
src/lib/log/Makefile.am | 4 +
src/lib/log/{documentation.txt => README} | 124 +++++--------------
src/lib/server_common/tests/Makefile.am | 3 +
tests/system/Makefile.am | 3 +
tests/system/README | 1 +
tests/system/{glue => bindctl}/clean.sh | 7 +-
.../nsx1/b10-config.db.template.in} | 3 +-
tests/system/bindctl/nsx1/example-normalized.db | 3 +
.../root-servers.nil.db => bindctl/nsx1/root.db} | 17 ++--
.../system/{glue/setup.sh.in => bindctl/setup.sh} | 13 +-
tests/system/bindctl/tests.sh | 106 +++++++++++++++++
tests/system/common/default_user.csv | 1 +
tests/system/conf.sh.in | 9 +-
28 files changed, 480 insertions(+), 192 deletions(-)
rename src/bin/bindctl/{bindctl-source.py.in => bindctl_main.py.in} (86%)
mode change 100644 => 100755
rename src/lib/log/{documentation.txt => README} (75%)
copy tests/system/{glue => bindctl}/clean.sh (94%)
copy tests/system/{glue/nsx1/b10-config.db.in => bindctl/nsx1/b10-config.db.template.in} (65%)
create mode 100644 tests/system/bindctl/nsx1/example-normalized.db
copy tests/system/{glue/nsx1/root-servers.nil.db => bindctl/nsx1/root.db} (78%)
copy tests/system/{glue/setup.sh.in => bindctl/setup.sh} (69%)
create mode 100755 tests/system/bindctl/tests.sh
create mode 100644 tests/system/common/default_user.csv
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index ffa794b..791575e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+ 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
diff --git a/configure.ac b/configure.ac
index 56a5744..acc7628 100644
--- a/configure.ac
+++ b/configure.ac
@@ -723,7 +723,7 @@ AC_OUTPUT([doc/version.ent
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
+ src/bin/bindctl/bindctl_main.py
src/bin/bindctl/tests/bindctl_test
src/bin/loadzone/run_loadzone.sh
src/bin/loadzone/tests/correct/correct_test.sh
@@ -751,6 +751,7 @@ AC_OUTPUT([doc/version.ent
tests/system/conf.sh
tests/system/glue/setup.sh
tests/system/glue/nsx1/b10-config.db
+ tests/system/bindctl/nsx1/b10-config.db.template
], [
chmod +x src/bin/cmdctl/run_b10-cmdctl.sh
chmod +x src/bin/xfrin/run_b10-xfrin.sh
diff --git a/src/bin/bindctl/Makefile.am b/src/bin/bindctl/Makefile.am
index e95af78..2f412ec 100644
--- a/src/bin/bindctl/Makefile.am
+++ b/src/bin/bindctl/Makefile.am
@@ -5,12 +5,13 @@ man_MANS = bindctl.1
EXTRA_DIST = $(man_MANS) bindctl.xml
-python_PYTHON = __init__.py bindcmd.py cmdparse.py exception.py moduleinfo.py mycollections.py
+python_PYTHON = __init__.py bindcmd.py cmdparse.py exception.py moduleinfo.py \
+ mycollections.py
pythondir = $(pyexecdir)/bindctl
bindctldir = $(pkgdatadir)
-CLEANFILES = bindctl
+CLEANFILES = bindctl bindctl_main.pyc
if ENABLE_MAN
@@ -19,8 +20,8 @@ bindctl.1: bindctl.xml
endif
-bindctl: bindctl-source.py
+bindctl: bindctl_main.py
$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
-e "s|@@SYSCONFDIR@@|@sysconfdir@|" \
- -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bindctl-source.py >$@
+ -e "s|@@LIBEXECDIR@@|$(pkglibexecdir)|" bindctl_main.py >$@
chmod a+x $@
diff --git a/src/bin/bindctl/bindcmd.py b/src/bin/bindctl/bindcmd.py
index 683dda9..83dab25 100644
--- a/src/bin/bindctl/bindcmd.py
+++ b/src/bin/bindctl/bindcmd.py
@@ -87,7 +87,8 @@ class ValidatedHTTPSConnection(http.client.HTTPSConnection):
class BindCmdInterpreter(Cmd):
"""simple bindctl example."""
- def __init__(self, server_port = 'localhost:8080', pem_file = None):
+ def __init__(self, server_port='localhost:8080', pem_file=None,
+ csv_file_dir=None):
Cmd.__init__(self)
self.location = ""
self.prompt_end = '> '
@@ -103,7 +104,12 @@ class BindCmdInterpreter(Cmd):
ca_certs=pem_file)
self.session_id = self._get_session_id()
self.config_data = None
-
+ if csv_file_dir is not None:
+ self.csv_file_dir = csv_file_dir
+ else:
+ self.csv_file_dir = pwd.getpwnam(getpass.getuser()).pw_dir + \
+ os.sep + '.bind10' + os.sep
+
def _get_session_id(self):
'''Generate one session id for the connection. '''
rand = os.urandom(16)
@@ -175,9 +181,7 @@ class BindCmdInterpreter(Cmd):
time, username and password saved in 'default_user.csv' will be
used first.
'''
- csv_file_dir = pwd.getpwnam(getpass.getuser()).pw_dir
- csv_file_dir += os.sep + '.bind10' + os.sep
- users = self._get_saved_user_info(csv_file_dir, CSV_FILE_NAME)
+ users = self._get_saved_user_info(self.csv_file_dir, CSV_FILE_NAME)
for row in users:
param = {'username': row[0], 'password' : row[1]}
try:
@@ -211,7 +215,8 @@ class BindCmdInterpreter(Cmd):
raise FailToLogin()
if response.status == http.client.OK:
- self._save_user_info(username, passwd, csv_file_dir, CSV_FILE_NAME)
+ self._save_user_info(username, passwd, self.csv_file_dir,
+ CSV_FILE_NAME)
return True
def _update_commands(self):
diff --git a/src/bin/bindctl/bindctl-source.py.in b/src/bin/bindctl/bindctl-source.py.in
deleted file mode 100644
index 080c3bc..0000000
--- a/src/bin/bindctl/bindctl-source.py.in
+++ /dev/null
@@ -1,135 +0,0 @@
-#!@PYTHON@
-
-# Copyright (C) 2009 Internet Systems Consortium.
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""This is the main calling class for the bindctl configuration and
- command tool. It sets up a command interpreter and runs that."""
-
-import sys; sys.path.append ('@@PYTHONPATH@@')
-
-from bindctl.moduleinfo import *
-from bindctl.bindcmd import *
-import pprint
-from optparse import OptionParser, OptionValueError
-import isc.util.process
-
-isc.util.process.rename()
-
-# This is the version that gets displayed to the user.
-# The VERSION string consists of the module name, the module version
-# number, and the overall BIND 10 version number (set in configure.ac).
-VERSION = "bindctl 20110217 (BIND 10 @PACKAGE_VERSION@)"
-
-DEFAULT_IDENTIFIER_DESC = "The identifier specifies the config item. Child elements are separated with the '/' character. List indices can be specified with '[i]', where i is an integer specifying the index, starting with 0. Examples: 'Boss/start_auth', 'Recurse/listen_on[0]/address'. If no identifier is given, shows the item at the current location."
-
-def prepare_config_commands(tool):
- '''Prepare fixed commands for local configuration editing'''
- module = ModuleInfo(name = CONFIG_MODULE_NAME, desc = "Configuration commands.")
- cmd = CommandInfo(name = "show", desc = "Show configuration.")
- param = ParamInfo(name = "argument", type = "string", optional=True, desc = "If you specify the argument 'all' (before the identifier), recursively show all child elements for the given identifier.")
- cmd.add_param(param)
- param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
- cmd.add_param(param)
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "show_json", desc = "Show full configuration in JSON format.")
- param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
- cmd.add_param(param)
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "add", desc = "Add an entry to configuration list. If no value is given, a default value is added.")
- param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
- cmd.add_param(param)
- param = ParamInfo(name = "value", type = "string", optional=True, desc = "Specifies a value to add to the list. It must be in correct JSON format and complete.")
- cmd.add_param(param)
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "remove", desc = "Remove entry from configuration list.")
- param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
- cmd.add_param(param)
- param = ParamInfo(name = "value", type = "string", optional=True, desc = "Specifies a value to remove from the list. It must be in correct JSON format and complete.")
- cmd.add_param(param)
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "set", desc = "Set a configuration value.")
- param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
- cmd.add_param(param)
- param = ParamInfo(name = "value", type = "string", optional=False, desc = "Specifies a value to set. It must be in correct JSON format and complete.")
- cmd.add_param(param)
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "unset", desc = "Unset a configuration value (i.e. revert to the default, if any).")
- param = ParamInfo(name = "identifier", type = "string", optional=False, desc = DEFAULT_IDENTIFIER_DESC)
- cmd.add_param(param)
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "diff", desc = "Show all local changes that have not been committed.")
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "revert", desc = "Revert all local changes.")
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "commit", desc = "Commit all local changes.")
- module.add_command(cmd)
-
- cmd = CommandInfo(name = "go", desc = "Go to a specific configuration part.")
- param = ParamInfo(name = "identifier", type="string", optional=False, desc = DEFAULT_IDENTIFIER_DESC)
- cmd.add_param(param)
- module.add_command(cmd)
-
- tool.add_module_info(module)
-
-def check_port(option, opt_str, value, parser):
- if (value < 0) or (value > 65535):
- raise OptionValueError('%s requires a port number (0-65535)' % opt_str)
- parser.values.port = value
-
-def check_addr(option, opt_str, value, parser):
- ipstr = value
- ip_family = socket.AF_INET
- if (ipstr.find(':') != -1):
- ip_family = socket.AF_INET6
-
- try:
- socket.inet_pton(ip_family, ipstr)
- except:
- raise OptionValueError("%s invalid ip address" % ipstr)
-
- parser.values.addr = value
-
-def set_bindctl_options(parser):
- parser.add_option('-p', '--port', dest = 'port', type = 'int',
- action = 'callback', callback=check_port,
- default = '8080', help = 'port for cmdctl of bind10')
-
- parser.add_option('-a', '--address', dest = 'addr', type = 'string',
- action = 'callback', callback=check_addr,
- default = '127.0.0.1', help = 'IP address for cmdctl of bind10')
-
- parser.add_option('-c', '--certificate-chain', dest = 'cert_chain',
- type = 'string', action = 'store',
- help = 'PEM formatted server certificate validation chain file')
-
-if __name__ == '__main__':
- parser = OptionParser(version = VERSION)
- set_bindctl_options(parser)
- (options, args) = parser.parse_args()
- server_addr = options.addr + ':' + str(options.port)
- tool = BindCmdInterpreter(server_addr, pem_file=options.cert_chain)
- prepare_config_commands(tool)
- tool.run()
-
-
diff --git a/src/bin/bindctl/bindctl.xml b/src/bin/bindctl/bindctl.xml
index 98d65f9..eff1de2 100644
--- a/src/bin/bindctl/bindctl.xml
+++ b/src/bin/bindctl/bindctl.xml
@@ -51,6 +51,7 @@
<arg><option>--address <replaceable>address</replaceable></option></arg>
<arg><option>--help</option></arg>
<arg><option>--certificate-chain <replaceable>file</replaceable></option></arg>
+ <arg><option>--csv-file-dir<replaceable>file</replaceable></option></arg>
<arg><option>--port <replaceable>number</replaceable></option></arg>
<arg><option>--version</option></arg>
</cmdsynopsis>
@@ -110,6 +111,22 @@
</varlistentry>
<varlistentry>
+ <term>
+ <option>--csv-file-dir</option><replaceable>file</replaceable>
+ </term>
+
+ <listitem>
+ <para>
+ The directory name in which the user/password CSV file
+ is stored (see AUTHENTICATION).
+ By default this option doesn't have any value,
+ in which case the ".bind10" directory under the user's
+ home directory will be used.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-h</option>,
<option>--help</option></term>
<listitem><para>
@@ -148,8 +165,10 @@
<para>
The tool will authenticate using a username and password.
On the first successful login, it will save the details to
- <filename>~/.bind10/default_user.csv</filename>
+ a comma-separated-value (CSV) file
which will be used for later uses of <command>bindctl</command>.
+ The file name is <filename>default_user.csv</filename>
+ located under the directory specified by the --csv-file-dir option.
</para>
<!-- TODO: mention HTTPS? -->
diff --git a/src/bin/bindctl/bindctl_main.py.in b/src/bin/bindctl/bindctl_main.py.in
new file mode 100755
index 0000000..01307e9
--- /dev/null
+++ b/src/bin/bindctl/bindctl_main.py.in
@@ -0,0 +1,138 @@
+#!@PYTHON@
+
+# Copyright (C) 2009 Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+"""This is the main calling class for the bindctl configuration and
+ command tool. It sets up a command interpreter and runs that."""
+
+import sys; sys.path.append ('@@PYTHONPATH@@')
+
+from bindctl.moduleinfo import *
+from bindctl.bindcmd import *
+import pprint
+from optparse import OptionParser, OptionValueError
+import isc.util.process
+
+isc.util.process.rename()
+
+# This is the version that gets displayed to the user.
+# The VERSION string consists of the module name, the module version
+# number, and the overall BIND 10 version number (set in configure.ac).
+VERSION = "bindctl 20110217 (BIND 10 @PACKAGE_VERSION@)"
+
+DEFAULT_IDENTIFIER_DESC = "The identifier specifies the config item. Child elements are separated with the '/' character. List indices can be specified with '[i]', where i is an integer specifying the index, starting with 0. Examples: 'Boss/start_auth', 'Recurse/listen_on[0]/address'. If no identifier is given, shows the item at the current location."
+
+def prepare_config_commands(tool):
+ '''Prepare fixed commands for local configuration editing'''
+ module = ModuleInfo(name = CONFIG_MODULE_NAME, desc = "Configuration commands.")
+ cmd = CommandInfo(name = "show", desc = "Show configuration.")
+ param = ParamInfo(name = "argument", type = "string", optional=True, desc = "If you specify the argument 'all' (before the identifier), recursively show all child elements for the given identifier.")
+ cmd.add_param(param)
+ param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
+ cmd.add_param(param)
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "show_json", desc = "Show full configuration in JSON format.")
+ param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
+ cmd.add_param(param)
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "add", desc = "Add an entry to configuration list. If no value is given, a default value is added.")
+ param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
+ cmd.add_param(param)
+ param = ParamInfo(name = "value", type = "string", optional=True, desc = "Specifies a value to add to the list. It must be in correct JSON format and complete.")
+ cmd.add_param(param)
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "remove", desc = "Remove entry from configuration list.")
+ param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
+ cmd.add_param(param)
+ param = ParamInfo(name = "value", type = "string", optional=True, desc = "Specifies a value to remove from the list. It must be in correct JSON format and complete.")
+ cmd.add_param(param)
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "set", desc = "Set a configuration value.")
+ param = ParamInfo(name = "identifier", type = "string", optional=True, desc = DEFAULT_IDENTIFIER_DESC)
+ cmd.add_param(param)
+ param = ParamInfo(name = "value", type = "string", optional=False, desc = "Specifies a value to set. It must be in correct JSON format and complete.")
+ cmd.add_param(param)
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "unset", desc = "Unset a configuration value (i.e. revert to the default, if any).")
+ param = ParamInfo(name = "identifier", type = "string", optional=False, desc = DEFAULT_IDENTIFIER_DESC)
+ cmd.add_param(param)
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "diff", desc = "Show all local changes that have not been committed.")
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "revert", desc = "Revert all local changes.")
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "commit", desc = "Commit all local changes.")
+ module.add_command(cmd)
+
+ cmd = CommandInfo(name = "go", desc = "Go to a specific configuration part.")
+ param = ParamInfo(name = "identifier", type="string", optional=False, desc = DEFAULT_IDENTIFIER_DESC)
+ cmd.add_param(param)
+ module.add_command(cmd)
+
+ tool.add_module_info(module)
+
+def check_port(option, opt_str, value, parser):
+ if (value < 0) or (value > 65535):
+ raise OptionValueError('%s requires a port number (0-65535)' % opt_str)
+ parser.values.port = value
+
+def check_addr(option, opt_str, value, parser):
+ ipstr = value
+ ip_family = socket.AF_INET
+ if (ipstr.find(':') != -1):
+ ip_family = socket.AF_INET6
+
+ try:
+ socket.inet_pton(ip_family, ipstr)
+ except:
+ raise OptionValueError("%s invalid ip address" % ipstr)
+
+ parser.values.addr = value
+
+def set_bindctl_options(parser):
+ parser.add_option('-p', '--port', dest='port', type='int',
+ action='callback', callback=check_port,
+ default='8080', help='port for cmdctl of bind10')
+
+ parser.add_option('-a', '--address', dest='addr', type='string',
+ action='callback', callback=check_addr,
+ default='127.0.0.1', help='IP address for cmdctl of bind10')
+
+ parser.add_option('-c', '--certificate-chain', dest='cert_chain',
+ type='string', action='store',
+ help='PEM formatted server certificate validation chain file')
+
+ parser.add_option('--csv-file-dir', dest='csv_file_dir', type='string',
+ default=None, action='store',
+ help='Directory to store the password CSV file')
+
+if __name__ == '__main__':
+ parser = OptionParser(version = VERSION)
+ set_bindctl_options(parser)
+ (options, args) = parser.parse_args()
+ server_addr = options.addr + ':' + str(options.port)
+ tool = BindCmdInterpreter(server_addr, pem_file=options.cert_chain,
+ csv_file_dir=options.csv_file_dir)
+ prepare_config_commands(tool)
+ tool.run()
diff --git a/src/bin/bindctl/tests/Makefile.am b/src/bin/bindctl/tests/Makefile.am
index 8a7a623..d2bb90f 100644
--- a/src/bin/bindctl/tests/Makefile.am
+++ b/src/bin/bindctl/tests/Makefile.am
@@ -11,6 +11,6 @@ if ENABLE_PYTHON_COVERAGE
endif
for pytest in $(PYTESTS) ; do \
echo Running test: $$pytest ; \
- env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_srcdir)/src/bin \
+ env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/bindctl:$(abs_top_srcdir)/src/bin \
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
done
diff --git a/src/bin/bindctl/tests/bindctl_test.py b/src/bin/bindctl/tests/bindctl_test.py
index 490dd7a..dd492c1 100644
--- a/src/bin/bindctl/tests/bindctl_test.py
+++ b/src/bin/bindctl/tests/bindctl_test.py
@@ -17,8 +17,12 @@
import unittest
import isc.cc.data
import os
+import pwd
+import getpass
+from optparse import OptionParser
from isc.config.config_data import ConfigData, MultiConfigData
from isc.config.module_spec import ModuleSpec
+from bindctl_main import set_bindctl_options
from bindctl import cmdparse
from bindctl import bindcmd
from bindctl.moduleinfo import *
@@ -332,13 +336,6 @@ class TestConfigCommands(unittest.TestCase):
cmd = cmdparse.BindCmdParse("config set identifier=\"foo/a_list\" value=[1]")
self.assertRaises(isc.cc.data.DataTypeError, self.tool.apply_config_cmd, cmd)
-
-
-
-class FakeBindCmdInterpreter(bindcmd.BindCmdInterpreter):
- def __init__(self):
- pass
-
class TestBindCmdInterpreter(unittest.TestCase):
def _create_invalid_csv_file(self, csvfilename):
@@ -349,9 +346,22 @@ class TestBindCmdInterpreter(unittest.TestCase):
writer.writerow(['name2'])
csvfile.close()
+ def test_csv_file_dir(self):
+ # Checking default value
+ if "HOME" in os.environ:
+ home_dir = os.environ["HOME"]
+ else:
+ home_dir = pwd.getpwnam(getpass.getuser()).pw_dir
+ self.assertEqual(home_dir + os.sep + '.bind10' + os.sep,
+ bindcmd.BindCmdInterpreter().csv_file_dir)
+
+ new_csv_dir = '/something/different/'
+ custom_cmd = bindcmd.BindCmdInterpreter(csv_file_dir=new_csv_dir)
+ self.assertEqual(new_csv_dir, custom_cmd.csv_file_dir)
+
def test_get_saved_user_info(self):
- cmd = FakeBindCmdInterpreter()
- users = cmd._get_saved_user_info('/notexist', 'cvs_file.cvs')
+ cmd = bindcmd.BindCmdInterpreter()
+ users = cmd._get_saved_user_info('/notexist', 'csv_file.csv')
self.assertEqual([], users)
csvfilename = 'csv_file.csv'
@@ -360,6 +370,40 @@ class TestBindCmdInterpreter(unittest.TestCase):
self.assertEqual([], users)
os.remove(csvfilename)
+
+class TestCommandLineOptions(unittest.TestCase):
+ class FakeParserError(Exception):
+ """An exception thrown from FakeOptionParser on parser error.
+ """
+ pass
+
+ class FakeOptionParser(OptionParser):
+ """This fake class emulates the OptionParser class with customized
+ error handling for the convenient of tests.
+ """
+ def __init__(self):
+ OptionParser.__init__(self)
+
+ def error(self, msg):
+ raise TestCommandLineOptions.FakeParserError
+
+ def setUp(self):
+ self.parser = self.FakeOptionParser()
+ set_bindctl_options(self.parser)
+
+ def test_csv_file_dir(self):
+ # by default the option is "undefined"
+ (options, _) = self.parser.parse_args([])
+ self.assertEqual(None, options.csv_file_dir)
+
+ # specify the option, valid case.
+ (options, _) = self.parser.parse_args(['--csv-file-dir', 'some_dir'])
+ self.assertEqual('some_dir', options.csv_file_dir)
+
+ # missing option arg; should trigger parser error.
+ self.assertRaises(self.FakeParserError, self.parser.parse_args,
+ ['--csv-file-dir'])
+
if __name__== "__main__":
unittest.main()
diff --git a/src/lib/asiolink/io_fetch.cc b/src/lib/asiolink/io_fetch.cc
index a68c4c5..04993f4 100644
--- a/src/lib/asiolink/io_fetch.cc
+++ b/src/lib/asiolink/io_fetch.cc
@@ -15,6 +15,7 @@
#include <config.h>
#include <unistd.h> // for some IPC/network system calls
+#include <stdint.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -26,8 +27,6 @@
#include <dns/rcode.h>
#include <log/dummylog.h>
-#include <asiolink/qid_gen.h>
-
#include <asio.hpp>
#include <asiolink/io_fetch.h>
@@ -36,7 +35,28 @@ using namespace isc::dns;
using namespace isc::log;
using namespace std;
+namespace {
+ // Temporarily borrowed from buffer.h
+ // \brief Read an unsigned 16-bit integer in network byte order from the
+ // buffer, convert it to host byte order, and return it.
+ //
+ // If the remaining length of the buffer is smaller than 16-bit, an
+ // exception of class \c isc::dns::InvalidBufferPosition will be thrown.
+ uint16_t readUint16(const void* rb, size_t len)
+ {
+ uint16_t data;
+
+ if (sizeof(data) > len) {
+ isc_throw(InvalidBufferPosition, "read beyond end of data");
+ }
+ const uint8_t* cp = static_cast<const uint8_t*>(rb);
+ data = ((unsigned int)(cp[0])) << 8;
+ data |= ((unsigned int)(cp[1]));
+
+ return (data);
+ }
+}
namespace asiolink {
/// IOFetch Constructor - just initialize the private data
@@ -67,7 +87,7 @@ IOFetch::operator()(error_code ec, size_t length) {
{
Message msg(Message::RENDER);
- msg.setQid(QidGenerator::getInstance().generateQid());
+ msg.setQid(data_->qid);
msg.setOpcode(Opcode::QUERY());
msg.setRcode(Rcode::NOERROR());
msg.setHeaderFlag(Message::HEADERFLAG_RD);
@@ -98,27 +118,40 @@ IOFetch::operator()(error_code ec, size_t length) {
CORO_YIELD;
}
- // Begin an asynchronous send, and then yield. When the send completes
- // send completes, we will resume immediately after this point.
- CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
- data_->msgbuf->getLength(), data_->remote.get(), *this);
-
- // Now receive the response. Since TCP may not receive the entire
- // message in one operation, we need to loop until we have received
- // it. (This can't be done within the asyncReceive() method because
- // each I/O operation will be done asynchronously and between each one
- // we need to yield ... and we *really* don't want to set up another
- // coroutine within that method.) So after each receive (and yield),
- // we check if the operation is complete and if not, loop to read again.
- do {
- CORO_YIELD data_->socket->asyncReceive(data_->data.get(),
- static_cast<size_t>(MAX_LENGTH), data_->cumulative,
- data_->remote.get(), *this);
- } while (!data_->socket->receiveComplete(data_->data.get(), length,
- data_->cumulative));
-
- // The message is not rendered yet, so we can't print it easily
- dlog("Received response from " + data_->remote->getAddress().toText());
+ while (true) {
+ // Begin an asynchronous send, and then yield. When the send completes
+ // send completes, we will resume immediately after this point.
+ CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
+ data_->msgbuf->getLength(), data_->remote.get(), *this);
+
+ // Now receive the response. Since TCP may not receive the entire
+ // message in one operation, we need to loop until we have received
+ // it. (This can't be done within the asyncReceive() method because
+ // each I/O operation will be done asynchronously and between each one
+ // we need to yield ... and we *really* don't want to set up another
+ // coroutine within that method.) So after each receive (and yield),
+ // we check if the operation is complete and if not, loop to read again.
+ do {
+ CORO_YIELD data_->socket->asyncReceive(data_->data.get(),
+ static_cast<size_t>(MAX_LENGTH), data_->cumulative,
+ data_->remote.get(), *this);
+ } while (!data_->socket->receiveComplete(data_->data.get(), length,
+ data_->cumulative));
+
+ // The message is not rendered yet, so we can't print it easily
+ dlog("Received response from " + data_->remote->getAddress().toText());
+
+ // TODO: move the qid check to wherever we put demuxer (and all
+ // DNS related knowledge out of this (as well as the dupe uint16
+ // read code)
+ // This is just a quick way to check it, if we get the right ID
+ // (TODO: from the right address), break the receive-loop
+ if (readUint16(data_->data.get(), length) == data_->qid) {
+ break;
+ } else {
+ dlog("Wrong QID in response, waiting for next one");
+ }
+ }
/// Copy the answer into the response buffer. (TODO: If the
/// OutputBuffer object were made to meet the requirements of
diff --git a/src/lib/asiolink/io_fetch.h b/src/lib/asiolink/io_fetch.h
index 8158c6c..a64fc22 100644
--- a/src/lib/asiolink/io_fetch.h
+++ b/src/lib/asiolink/io_fetch.h
@@ -38,6 +38,7 @@
#include <asiolink/tcp_endpoint.h>
#include <asiolink/udp_socket.h>
#include <asiolink/udp_endpoint.h>
+#include <asiolink/qid_gen.h>
namespace asiolink {
@@ -127,6 +128,7 @@ public:
bool stopped; ///< Have we stopped running?
asio::deadline_timer timer; ///< Timer to measure timeouts
int timeout; ///< Timeout in ms
+ isc::dns::qid_t qid; ///< The QID set in the query
/// \brief Constructor
///
@@ -169,7 +171,8 @@ public:
cumulative(0),
stopped(false),
timer(service.get_io_service()),
- timeout(wait)
+ timeout(wait),
+ qid(QidGenerator::getInstance().generateQid())
{}
};
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/io_fetch_unittest.cc b/src/lib/asiolink/tests/io_fetch_unittest.cc
index 9b74ee0..832961d 100644
--- a/src/lib/asiolink/tests/io_fetch_unittest.cc
+++ b/src/lib/asiolink/tests/io_fetch_unittest.cc
@@ -59,6 +59,7 @@ public:
// The next member is the buffer iin which the "server" (implemented by the
// response handler method) receives the question sent by the fetch object.
std::vector<char> server_buff_; ///< Server buffer
+ OutputBufferPtr expected_buff_; ///< Data we expect to receive
/// \brief Constructor
IOFetchTest() :
@@ -69,7 +70,7 @@ public:
buff_(new OutputBuffer(512)),
udp_fetch_(IPPROTO_UDP, service_, question_, IOAddress(TEST_HOST),
TEST_PORT, buff_, this, 100),
- server_buff_(512)
+ server_buff_(512), expected_buff_(new OutputBuffer(512))
// tcp_fetch_(service_, question_, IOAddress(TEST_HOST), TEST_PORT,
// buff_, this, 100, IPPROTO_UDP)
{ }
@@ -86,36 +87,57 @@ public:
service_.stop(); // ... and exit run loop
}
+
/// \brief Response handler, pretending to be remote DNS server
///
/// This checks that the data sent is what we expected to receive, and
/// sends back a test answer.
+ ///
+ /// If bad_qid is true, mangle the qid in the response
+ /// If second_send is true (as well as bad_qid), send the packet
+ /// again, but with the right qid this time
void respond(udp::endpoint* remote, udp::socket* socket,
- asio::error_code ec = asio::error_code(), size_t length = 0) {
+ asio::error_code ec = asio::error_code(), size_t length = 0,
+ bool bad_qid = false, bool second_send = false) {
// Construct the data buffer for question we expect to receive.
- OutputBuffer msgbuf(512);
Message msg(Message::RENDER);
msg.setQid(0);
msg.setOpcode(Opcode::QUERY());
msg.setRcode(Rcode::NOERROR());
msg.setHeaderFlag(Message::HEADERFLAG_RD);
msg.addQuestion(question_);
- MessageRenderer renderer(msgbuf);
+ MessageRenderer renderer(*expected_buff_);
msg.toWire(renderer);
// The QID in the incoming data is random so set it to 0 for the
// data comparison check. (It was set to 0 when the buffer containing
// the expected data was constructed above.)
+ // We do store the first 2 octets for qid checks
+ uint8_t octet0 = server_buff_[0];
+ uint8_t octet1 = server_buff_[1];
server_buff_[0] = 0;
server_buff_[1] = 0;
// Check that lengths are identical.
- EXPECT_EQ(msgbuf.getLength(), length);
- EXPECT_TRUE(memcmp(msgbuf.getData(), &server_buff_[0], length) == 0);
-
- // ... and return a message back.
- socket->send_to(asio::buffer(TEST_DATA, sizeof TEST_DATA), *remote);
+ EXPECT_EQ(expected_buff_->getLength(), length);
+ EXPECT_TRUE(memcmp(expected_buff_->getData(), &server_buff_[0], length) == 0);
+
+ // ... and return a message back. (just echo what we read)
+ if (!bad_qid) {
+ expected_buff_->writeUint8At(octet0, 0);
+ expected_buff_->writeUint8At(octet1, 1);
+ } else {
+ expected_buff_->writeUint8At(octet0 + 1, 0);
+ expected_buff_->writeUint8At(octet1 + 1, 1);
+ }
+ socket->send_to(asio::buffer(expected_buff_->getData(), length), *remote);
+
+ if (bad_qid && second_send) {
+ expected_buff_->writeUint8At(octet0, 0);
+ expected_buff_->writeUint8At(octet1, 1);
+ socket->send_to(asio::buffer(expected_buff_->getData(), length), *remote);
+ }
}
};
@@ -177,15 +199,62 @@ TEST_F(IOFetchTest, UdpReceive) {
udp::endpoint remote;
socket.async_receive_from(asio::buffer(server_buff_),
remote,
- boost::bind(&IOFetchTest::respond, this, &remote, &socket, _1, _2));
+ boost::bind(&IOFetchTest::respond, this, &remote, &socket, _1, _2, false, false));
+ service_.get_io_service().post(udp_fetch_);
+ service_.run();
+
+ socket.close();
+
+ EXPECT_TRUE(run_);
+ ASSERT_EQ(expected_buff_->getLength(), buff_->getLength());
+ EXPECT_EQ(0, memcmp(expected_buff_->getData(), buff_->getData(),
+ expected_buff_->getLength()));
+}
+
+// Test that it will ignore any response that has the wrong QID
+TEST_F(IOFetchTest, UdpReceiveBadQid) {
+ expected_ = IOFetch::TIME_OUT;
+
+ udp::socket socket(service_.get_io_service(), udp::v4());
+ socket.set_option(socket_base::reuse_address(true));
+ socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
+
+ udp::endpoint remote;
+ socket.async_receive_from(asio::buffer(server_buff_),
+ remote,
+ boost::bind(&IOFetchTest::respond, this, &remote, &socket, _1, _2, true, false));
+ service_.get_io_service().post(udp_fetch_);
+ service_.run();
+
+ socket.close();
+
+ EXPECT_TRUE(run_);
+ ASSERT_EQ(0, buff_->getLength());
+}
+
+// Test that it will ignore any response that has the wrong QID, but
+// accept the one with the right QID that comes next
+TEST_F(IOFetchTest, UdpReceiveBadQid2) {
+ expected_ = IOFetch::SUCCESS;
+
+ udp::socket socket(service_.get_io_service(), udp::v4());
+ socket.set_option(socket_base::reuse_address(true));
+ socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
+
+ udp::endpoint remote;
+ socket.async_receive_from(asio::buffer(server_buff_),
+ remote,
+ boost::bind(&IOFetchTest::respond, this, &remote, &socket, _1, _2, true, true));
service_.get_io_service().post(udp_fetch_);
service_.run();
socket.close();
EXPECT_TRUE(run_);
- ASSERT_EQ(sizeof TEST_DATA, buff_->getLength());
- EXPECT_EQ(0, memcmp(TEST_DATA, buff_->getData(), sizeof TEST_DATA));
+ ASSERT_EQ(expected_buff_->getLength(), buff_->getLength());
+ EXPECT_EQ(0, memcmp(expected_buff_->getData(), buff_->getData(),
+ expected_buff_->getLength()));
}
+
} // namespace asiolink
diff --git a/src/lib/asiolink/udp_server.cc b/src/lib/asiolink/udp_server.cc
index 98a47c4..063926e 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;
@@ -257,8 +266,6 @@ UDPServer::operator()(error_code ec, size_t length) {
// this point.
CORO_YIELD data_->io_.post(AsyncLookup<UDPServer>(*this));
- dlog("[XX] got an answer");
-
// The 'done_' flag indicates whether we have an answer
// to send back. If not, exit the coroutine permanently.
if (!data_->done_) {
diff --git a/src/lib/dns/buffer.h b/src/lib/dns/buffer.h
index e100876..c824154 100644
--- a/src/lib/dns/buffer.h
+++ b/src/lib/dns/buffer.h
@@ -356,6 +356,21 @@ public:
/// \param data The 8-bit integer to be written into the buffer.
void writeUint8(uint8_t data) { data_.push_back(data); }
+ /// \brief Write an unsigned 8-bit integer into the buffer.
+ ///
+ /// The position must be lower than the size of the buffer,
+ /// otherwise an exception of class \c isc::dns::InvalidBufferPosition
+ /// will be thrown.
+ ///
+ /// \param data The 8-bit integer to be written into the buffer.
+ /// \param pos The position in the buffer to write the data.
+ void writeUint8At(uint8_t data, size_t pos) {
+ if (pos + sizeof(data) > data_.size()) {
+ isc_throw(InvalidBufferPosition, "write at invalid position");
+ }
+ data_[pos] = data;
+ }
+
/// \brief Write an unsigned 16-bit integer in host byte order into the
/// buffer in network byte order.
///
diff --git a/src/lib/dns/tests/buffer_unittest.cc b/src/lib/dns/tests/buffer_unittest.cc
index 2ac9fc5..fb4c86c 100644
--- a/src/lib/dns/tests/buffer_unittest.cc
+++ b/src/lib/dns/tests/buffer_unittest.cc
@@ -124,10 +124,16 @@ TEST_F(BufferTest, outputBufferWriteat) {
obuffer.writeUint32(data32);
expected_size += sizeof(data32);
- // overwrite 2nd and 3rd bytes
- obuffer.writeUint16At(data16, 1);
+ // overwrite 2nd byte
+ obuffer.writeUint8At(4, 1);
EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change
const uint8_t* cp = static_cast<const uint8_t*>(obuffer.getData());
+ EXPECT_EQ(4, *(cp + 1));
+
+ // overwrite 2nd and 3rd bytes again
+ obuffer.writeUint16At(data16, 1);
+ EXPECT_EQ(expected_size, obuffer.getLength()); // length shouldn't change
+ cp = static_cast<const uint8_t*>(obuffer.getData());
EXPECT_EQ(2, *(cp + 1));
EXPECT_EQ(3, *(cp + 2));
diff --git a/src/lib/log/Makefile.am b/src/lib/log/Makefile.am
index 5bcafa8..60b3f5b 100644
--- a/src/lib/log/Makefile.am
+++ b/src/lib/log/Makefile.am
@@ -23,6 +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 = README
+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)
liblog_la_CXXFLAGS = $(AM_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/src/lib/server_common/tests/Makefile.am b/src/lib/server_common/tests/Makefile.am
index 22fe104..560398f 100644
--- a/src/lib/server_common/tests/Makefile.am
+++ b/src/lib/server_common/tests/Makefile.am
@@ -33,6 +33,9 @@ run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
endif
noinst_PROGRAMS = $(TESTS)
diff --git a/tests/system/Makefile.am b/tests/system/Makefile.am
index efd5d7f..663258b 100644
--- a/tests/system/Makefile.am
+++ b/tests/system/Makefile.am
@@ -7,7 +7,10 @@ distclean-local:
# 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 += common/default_user.csv
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
+EXTRA_DIST += bindctl/tests.sh bindctl/clean.sh bindctl/setup.sh
+EXTRA_DIST += bindctl/nsx1/root.db bindctl/nsx1/example-normalized.db
diff --git a/tests/system/README b/tests/system/README
index 080652d..a43d49e 100644
--- a/tests/system/README
+++ b/tests/system/README
@@ -18,6 +18,7 @@ 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:
+ bindctl/ Some basic management operations using the bindctl tool
glue/ Glue handling tests
(the following tests are planned to be added soon)
dnssec/ DNSSEC tests
diff --git a/tests/system/bindctl/clean.sh b/tests/system/bindctl/clean.sh
new file mode 100755
index 0000000..f691512
--- /dev/null
+++ b/tests/system/bindctl/clean.sh
@@ -0,0 +1,20 @@
+#!/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.
+
+rm -f */b10-config.db
+rm -f dig.out.* bindctl.out.*
+rm -f */msgq_socket */zone.sqlite3
diff --git a/tests/system/bindctl/nsx1/b10-config.db.template.in b/tests/system/bindctl/nsx1/b10-config.db.template.in
new file mode 100644
index 0000000..162329a
--- /dev/null
+++ b/tests/system/bindctl/nsx1/b10-config.db.template.in
@@ -0,0 +1,10 @@
+{"version": 2,
+ "Auth": {
+ "listen_on": [{"address": "10.53.0.1", "port": 53210}],
+ "database_file": "@abs_builddir@/zone.sqlite3",
+ "statistics-interval": 1
+ },
+ "Xfrout": {
+ "log_file": "@abs_builddir@/Xfrout.log"
+ }
+}
diff --git a/tests/system/bindctl/nsx1/example-normalized.db b/tests/system/bindctl/nsx1/example-normalized.db
new file mode 100644
index 0000000..7129522
--- /dev/null
+++ b/tests/system/bindctl/nsx1/example-normalized.db
@@ -0,0 +1,3 @@
+com. 300 IN SOA postmaster.example. ns.example.com. 2000042100 600 600 1200 600
+com. 300 IN NS ns.example.com.
+ns.example.com. 300 IN A 192.0.2.2
diff --git a/tests/system/bindctl/nsx1/root.db b/tests/system/bindctl/nsx1/root.db
new file mode 100644
index 0000000..31293de
--- /dev/null
+++ b/tests/system/bindctl/nsx1/root.db
@@ -0,0 +1,25 @@
+; 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 ns.example.com.
+ns.example.com. A 192.0.2.1
diff --git a/tests/system/bindctl/setup.sh b/tests/system/bindctl/setup.sh
new file mode 100755
index 0000000..55afcc1
--- /dev/null
+++ b/tests/system/bindctl/setup.sh
@@ -0,0 +1,26 @@
+#!/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
+
+SUBTEST_TOP=${TEST_TOP}/bindctl
+
+cp ${SUBTEST_TOP}/nsx1/b10-config.db.template ${SUBTEST_TOP}/nsx1/b10-config.db
+
+rm -f ${SUBTEST_TOP}/*/zone.sqlite3
+${B10_LOADZONE} -o . -d ${SUBTEST_TOP}/nsx1/zone.sqlite3 \
+ ${SUBTEST_TOP}//nsx1/root.db
diff --git a/tests/system/bindctl/tests.sh b/tests/system/bindctl/tests.sh
new file mode 100755
index 0000000..354f349
--- /dev/null
+++ b/tests/system/bindctl/tests.sh
@@ -0,0 +1,106 @@
+#!/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
+
+#
+# Do bindctl tests.
+#
+
+status=0
+n=0
+
+echo "I:Checking b10-auth is working by default ($n)"
+$DIG +norec @10.53.0.1 -p 53210 ns.example.com. A >dig.out.$n || status=1
+# perform a simple check on the output (digcomp would be too much for this)
+grep 192.0.2.1 dig.out.$n > /dev/null || status=1
+if [ $status != 0 ]; then echo "I:failed"; fi
+n=`expr $n + 1`
+
+echo "I:Checking BIND 10 statistics after a pose ($n)"
+# wait for 2sec to make sure b10-stats gets the latest statistics.
+# note that we set statistics-interval to 1.
+sleep 2
+echo 'Stats show
+' | $RUN_BINDCTL \
+ --csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
+# the server should have received 1 UDP and 1 TCP queries (TCP query was
+# sent from the server startup script)
+grep "\"auth.queries.tcp\": 1," bindctl.out.$n > /dev/null || status=1
+grep "\"auth.queries.udp\": 1," bindctl.out.$n > /dev/null || status=1
+if [ $status != 0 ]; then echo "I:failed"; fi
+n=`expr $n + 1`
+
+echo "I:Stopping b10-auth and checking that ($n)"
+echo 'config set Boss/start_auth false
+config commit
+quit
+' | $RUN_BINDCTL \
+ --csv-file-dir=$BINDCTL_CSV_DIR 2>&1 > /dev/null || status=1
+# dig should exit with a failure code.
+$DIG +tcp +norec @10.53.0.1 -p 53210 ns.example.com. A && status=1
+if [ $status != 0 ]; then echo "I:failed"; fi
+n=`expr $n + 1`
+
+echo "I:Restarting b10-auth and checking that ($n)"
+echo 'config set Boss/start_auth true
+config commit
+quit
+' | $RUN_BINDCTL \
+ --csv-file-dir=$BINDCTL_CSV_DIR 2>&1 > /dev/null || status=1
+$DIG +norec @10.53.0.1 -p 53210 ns.example.com. A >dig.out.$n || status=1
+grep 192.0.2.1 dig.out.$n > /dev/null || status=1
+if [ $status != 0 ]; then echo "I:failed"; fi
+n=`expr $n + 1`
+
+echo "I:Rechecking BIND 10 statistics after a pose ($n)"
+sleep 2
+echo 'Stats show
+' | $RUN_BINDCTL \
+ --csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
+# The statistics counters should have been reset while stop/start.
+grep "\"auth.queries.tcp\": 0," bindctl.out.$n > /dev/null || status=1
+grep "\"auth.queries.udp\": 1," bindctl.out.$n > /dev/null || status=1
+if [ $status != 0 ]; then echo "I:failed"; fi
+n=`expr $n + 1`
+
+echo "I:Changing the data source from sqlite3 to in-memory ($n)"
+DATASRC_SPEC='[{"type": "memory", "zones": [{"origin": "com","file":'
+DATASRC_SPEC="${DATASRC_SPEC} \"${TEST_TOP}/bindctl/nsx1/example-normalized.db\"}]}]"
+echo "config set Auth/datasources ${DATASRC_SPEC}
+config commit
+quit
+" | $RUN_BINDCTL \
+ --csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
+$DIG +norec @10.53.0.1 -p 53210 ns.example.com. A >dig.out.$n || status=1
+grep 192.0.2.2 dig.out.$n > /dev/null || status=1
+if [ $status != 0 ]; then echo "I:failed"; fi
+n=`expr $n + 1`
+
+echo "I:Rechecking BIND 10 statistics after changing the datasource ($n)"
+sleep 2
+echo 'Stats show
+' | $RUN_BINDCTL \
+ --csv-file-dir=$BINDCTL_CSV_DIR > bindctl.out.$n || status=1
+# The statistics counters shouldn't be reset due to hot-swapping datasource.
+grep "\"auth.queries.tcp\": 0," bindctl.out.$n > /dev/null || status=1
+grep "\"auth.queries.udp\": 2," bindctl.out.$n > /dev/null || status=1
+if [ $status != 0 ]; then echo "I:failed"; fi
+n=`expr $n + 1`
+
+echo "I:exit status: $status"
+exit $status
diff --git a/tests/system/common/default_user.csv b/tests/system/common/default_user.csv
new file mode 100644
index 0000000..e13e194
--- /dev/null
+++ b/tests/system/common/default_user.csv
@@ -0,0 +1 @@
+root,bind10
diff --git a/tests/system/conf.sh.in b/tests/system/conf.sh.in
index 29d959a..66aa3f5 100755
--- a/tests/system/conf.sh.in
+++ b/tests/system/conf.sh.in
@@ -34,10 +34,13 @@ if [ -z $BIND9_TOP ]; then
exit 1
fi
-# Find the top of the source tree.
+# Find the top of the source and test trees.
TOP=@abs_top_srcdir@
+TEST_TOP=@abs_builddir@
RUN_BIND10=$TOP/src/bin/bind10/run_bind10.sh
+RUN_BINDCTL=$TOP/src/bin/bindctl/run_bindctl.sh
+BINDCTL_CSV_DIR=@abs_srcdir@/common/
B10_LOADZONE=$TOP/src/bin/loadzone/run_loadzone.sh
BIND9_NAMED=$BIND9_TOP/bin/named/named
DIG=$BIND9_TOP/bin/dig/dig
@@ -45,8 +48,8 @@ DIG=$BIND9_TOP/bin/dig/dig
TESTSOCK=$BIND9_TOP/bin/tests/system/testsock.pl
DIGCOMP=$BIND9_TOP/bin/tests/system/digcomp.pl
-SUBDIRS="glue"
-#SUBDIRS="dnssec glue masterfile xfer"
+SUBDIRS="bindctl glue"
+#SUBDIRS="dnssec masterfile xfer"
# PERL will be an empty string if no perl interpreter was found.
PERL=@PERL@
More information about the bind10-changes
mailing list