BIND 10 trac595, updated. fa64874fe02ff6ab8a782e0ede0d70ff2c95783e Merge branch 'master' into trac595
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Mar 7 05:36:26 UTC 2011
The branch, trac595 has been updated
via fa64874fe02ff6ab8a782e0ede0d70ff2c95783e (commit)
via 44bf7654cb3ce85fe63fa47c7b39f48bb041d4de (commit)
via 1c8557996bdd428c9a3bf0935c30bf42fb167f35 (commit)
via dfbeea4eb3f414dcb66d2447e59216c23dade515 (commit)
via 54e61304131965c4a1d88c9151f8697dcbb3ce12 (commit)
via 242cb68113bd4d2c0a3ea3b61cc56e143a42b38e (commit)
via 3ffa099e0969468d0f16f00c503b8936b895a2d4 (commit)
via fa83bb99518bd8c4dede832769fe4f7a6405ea62 (commit)
via 0ca10e6357d7a41bc308f90183848ce41582adf8 (commit)
via 25a5f4ec755bc09b54410fcdff22691283147f32 (commit)
via 2275e0d7afa15b69bd7511616a6ebae0b9de0d22 (commit)
via 301da7d26d41e64d87c0cf72727f3347aa61fb40 (commit)
via eeacd1d5adeb27ee536fb04296cc20ffa898cdab (commit)
via 33cf7e5a182bc98cd168928fa8b5c775581fe90a (commit)
via 87829d23b5d698611c94ee92f758558d8ad95468 (commit)
via 5cde27560e4b8e3cd098daae572ca4d0124358de (commit)
via 1fd5547c170550880268ba0eb83a374231be348b (commit)
via f06ce638877acf6f8e1994962bf2dbfbab029edf (commit)
via 8053d85447560fa3c64f276881496513c66f4ba0 (commit)
via 5d246e92aef87505e9392274cacbabbd20478d3e (commit)
via ae0b20c57c48c4932b9aff2146f5d76f9eff5a90 (commit)
via 0047c74393959975ffd9f75a687a60f1f1c42a9c (commit)
via 1d60afb59e9606f312caef352ecb2fe488c4e751 (commit)
via 9c22af762d0cb6cdcb0bcbcea2b302b1165a0f66 (commit)
via f9152fae80f751adc95c894b872204e98504dcb8 (commit)
via 40f87a0aa5e6b2e8f86346f181b5e1d785c36e67 (commit)
via 3d69f66a688c09a20083a52f2a64b9327ede70c6 (commit)
via 76843dc3d8538f932d58e55ab6189091cd709f48 (commit)
via 451fdd5e7209a31420d2a61df99d66d2abfe34ca (commit)
via 34066d5d8486b9d3dad08e0b13269db14a8d8aae (commit)
via 543f406610c4fc2c0236f8f9c7fdc37014937fb6 (commit)
via 42d9589eb5c3fb6dd9f1a73206510d01bb29bedc (commit)
via bb8d9d376a1e2caadfdc3631c221cb7ca118f60f (commit)
via fa05a534849c2e3ba68d6fdc4c5ddc6531948fc3 (commit)
via e55ec73b0bdcc2b7d6286c6a18886de194280947 (commit)
via 2f0de2e7a8d594fd40c4fb2449232bb5cd64efa9 (commit)
via dadeedb633df1f3793c32fa283c82f22fcdb7ff4 (commit)
via 0a9ce967a515894bd7c46cf86a6ff4bc3d856b3a (commit)
via db2594e846ccf340ed9820f049b9839231a4832b (commit)
via b973f67520682b63ef38b1451d309be9f4f4b218 (commit)
via 0de367c06c8e4c730729de446cc5c54b7cee9ea4 (commit)
via a4a2b5aba9b2b16c4aa2cc8af01c19a4b9b61aea (commit)
via be8886364d3e7466a0a5007a75df797b6839004c (commit)
via 25747d9b65fccbe5e37b4c49377382381edf1e78 (commit)
via 9186edcad7735f16c835bd845572e74f8069f2d3 (commit)
via 8c7144c6aef7eb26215f045ee95551ed7a6fe307 (commit)
via a2dbc20364f13ddd393e51e711db7e5e3bd2551f (commit)
via 529119357642023c02dc40fd3c07bd2797062ba9 (commit)
via 09191932190ac8a64a4b77def3877fc5801d8aeb (commit)
via f79cea1f5a7ce45498a7a94cb5ed9aae6dfe1a7f (commit)
via 9e7943a5c72c19247d6ae7e7c264ef37e11d3561 (commit)
via 96c47a07bb44b6667816e576d8907fc223d1d771 (commit)
via 6458b98ea487620fd4c47b0de5b5bc2e5fe97794 (commit)
via 910df2cc9298c1c7697f6f38c303b26169e62305 (commit)
via 2bd3a99bb2580fa3c783058f490eb1c8130c65ab (commit)
via ba727c17d3517232a3c40fa3a30c6924a30ed7dc (commit)
via 91193e42d664fbb494a15cdf5b01a0c5da19d0b7 (commit)
via ab86095a11e912123c40f6b41879dfa634e491a8 (commit)
via d1a73e27eb7d3c133e871809efeea5174b01a2ee (commit)
via 1022129fcea6743037ed7ae2b363b0af082afd30 (commit)
via da0e644a1c4826da8587bee6fe1902a6f28e5931 (commit)
via 8f6657a13b4e6e140e3c5a52201fd4c998ee9560 (commit)
via e5e62873bcc14a7aba87bf0bdc7d2d354aba331b (commit)
via a42df8e3040bc9cfa52aca8d45d09ef016810862 (commit)
via 5ac67ede03892a5eacf42ce3ace1e4e376164c9f (commit)
via a9e9a2b26fbe93fda5174e4482c9c13e05287539 (commit)
via f54d8505d8ac997fca63d2cd82485b19c248a804 (commit)
via 950fc0ab5f04dc55c41ad93179cc188f8695f335 (commit)
via b229aa1c060b0d3a21b3173b97c835ff10dc3b17 (commit)
via ba66913e80236f8b33afd055317fc0356580970e (commit)
via 4fa3cf5c5f623d24c357aac1d689a068528c73ce (commit)
via 923a47079606a6ba9368d94007b3c24aaa4ca7e5 (commit)
via ddd04eed61f4945303400569629d66cf685833d2 (commit)
via c3d81863bc201dc1fab9690565158b8f09d61061 (commit)
via 199599a979e331026ec5dc8ff07f1bb08f3228e9 (commit)
via d7ec12be1f1e87ca0cc4675165f126f8d010b6b3 (commit)
via b7d8ac6afdd51bb18fcb0c1c0f7389d4975f7c54 (commit)
via 40f74edaaf73a8a5a7798fd79646e2279b82b5cc (commit)
via 24ef7a16425e696fbb794605a89ff8d7bdd7172c (commit)
via 59455cd6b9de13d63c2b6cf17eb7e8c88c8a99cc (commit)
via 8a47d8d2b9123df707aebfa14141a5c11c5a6228 (commit)
via 6bdfcf31fed84b413714a0ef446578ebbb3002a9 (commit)
via 33deff727f64139d15f45173679fd0e73531e7da (commit)
via 354ca192db138bdd942734ff985b6e21c8445a82 (commit)
via 8f331c78a07959b413f4a00e3b3f7a935cd42b2f (commit)
via 6df94e2db856c1adc020f658cc77da5edc967555 (commit)
via c6b5e0f57cb473f7e2731d8ca1d3619139263a12 (commit)
via 239114f5e894111f47dca785429a9180f2cb1598 (commit)
via 477b53cb86a431a7c38655db3972a554b412e700 (commit)
via 8ffbcda5bbf9729b9ab09d89531520c9f94618ee (commit)
via 77a02471ef75d226a6dbf7e962491fedfef6d6d9 (commit)
via 09b70f9b0f93da5c7034b02837987fc03a675472 (commit)
via de89048d524aef36e88ce770f3f953401e3a24a8 (commit)
via 94b5025336f509832addd712ed2f9f4fce48bfa4 (commit)
via 8578607b1c73c76e16a4eabd4ed45539260e0c74 (commit)
via 0503f4a60a6873d63bb1d9352c6b50a7a40130f9 (commit)
via 71c4e3cb8c0f6c4e51a8afd24928ee10710a49a2 (commit)
via bba7327c68c2242882dcaadbcae4b2db0aabedd3 (commit)
via 783c0a87b919e9d39ab271de6203bb4277758e2d (commit)
via f9be171869937e52f960568773c45cfda28baa3a (commit)
via 9abd2de988dbd33bac4149e0d2cb1e4fec55413e (commit)
via 4548257a1d70b64890433443d156d62a27fcc32a (commit)
via 06fdc8c5bff48e8cd0fa093dce018af40bdaa668 (commit)
from 996e2593c867478eec8f2b3700aa52776528394b (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 fa64874fe02ff6ab8a782e0ede0d70ff2c95783e
Merge: 996e2593c867478eec8f2b3700aa52776528394b 44bf7654cb3ce85fe63fa47c7b39f48bb041d4de
Author: zhanglikun <zhanglikun at cnnic.cn>
Date: Mon Mar 7 13:35:46 2011 +0800
Merge branch 'master' into trac595
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 49 +++++
Makefile.am | 7 +
configure.ac | 15 ++-
doc/Doxyfile | 2 +-
src/bin/auth/Makefile.am | 3 +-
src/bin/auth/auth.spec.pre.in | 35 ++++
src/bin/auth/auth_srv.cc | 19 ++
src/bin/auth/auth_srv.h | 14 ++
src/bin/auth/b10-auth.xml | 47 -----
src/bin/auth/benchmarks/Makefile.am | 1 +
src/bin/auth/benchmarks/query_bench.cc | 2 +-
src/bin/auth/config.cc | 61 ++++++-
src/bin/auth/main.cc | 65 +------
src/bin/auth/tests/Makefile.am | 1 +
src/bin/auth/tests/auth_srv_unittest.cc | 20 ++-
src/bin/auth/tests/config_unittest.cc | 22 +++-
src/bin/bind10/Makefile.am | 3 +-
src/bin/bind10/bind10.py.in | 45 +----
src/bin/bind10/bind10.xml | 37 +----
src/bin/bind10/tests/bind10_test.py | 38 ----
src/bin/bindctl/Makefile.am | 2 +-
src/bin/cfgmgr/Makefile.am | 1 -
src/bin/cmdctl/Makefile.am | 3 +-
src/bin/host/host.cc | 7 +-
src/bin/msgq/Makefile.am | 1 -
src/bin/resolver/Makefile.am | 3 +-
src/bin/resolver/resolver.cc | 154 +++++-----------
src/bin/resolver/resolver.spec.pre.in | 34 ++--
src/bin/resolver/tests/Makefile.am | 1 +
src/bin/resolver/tests/resolver_config_unittest.cc | 116 +++----------
src/bin/resolver/tests/resolver_unittest.cc | 21 +++
src/bin/stats/Makefile.am | 3 +-
src/bin/usermgr/Makefile.am | 3 +-
src/bin/xfrin/Makefile.am | 3 +-
src/bin/xfrout/Makefile.am | 3 +-
src/bin/xfrout/tests/xfrout_test.py | 29 ++--
src/bin/xfrout/xfrout.py.in | 183 +++++++++++--------
src/bin/zonemgr/Makefile.am | 2 +-
src/cppcheck-suppress.lst | 15 ++
src/lib/Makefile.am | 2 +-
src/lib/asiolink/dns_server.h | 3 +
src/lib/asiolink/dns_service.cc | 10 +-
src/lib/asiolink/tcp_server.cc | 23 ++-
src/lib/asiolink/tcp_server.h | 4 +
src/lib/asiolink/tests/interval_timer_unittest.cc | 7 +-
src/lib/asiolink/tests/io_endpoint_unittest.cc | 6 +-
src/lib/asiolink/tests/io_fetch_unittest.cc | 13 +-
src/lib/asiolink/tests/io_service_unittest.cc | 2 +-
src/lib/asiolink/tests/recursive_query_unittest.cc | 8 +-
src/lib/asiolink/tests/udp_socket_unittest.cc | 6 +-
src/lib/asiolink/udp_server.cc | 27 +++-
src/lib/asiolink/udp_server.h | 4 +
src/lib/bench/tests/benchmark_unittest.cc | 19 ++-
src/lib/bench/tests/loadquery_unittest.cc | 2 +-
src/lib/cache/message_cache.cc | 2 +
src/lib/cache/message_cache.h | 5 +
src/lib/cache/message_entry.cc | 2 +-
src/lib/cache/rrset_cache.cc | 2 +
src/lib/cache/rrset_cache.h | 7 +-
src/lib/cache/tests/message_cache_unittest.cc | 31 +++-
src/lib/cc/tests/session_unittests.cc | 2 +-
src/lib/config/ccsession.cc | 4 +-
src/lib/config/module_spec.cc | 2 +-
src/lib/config/tests/ccsession_unittests.cc | 2 +-
src/lib/config/tests/module_spec_unittests.cc | 4 +-
src/lib/datasrc/memory_datasrc.cc | 2 +-
src/lib/datasrc/tests/rbtree_unittest.cc | 2 +-
src/lib/dns/message.cc | 4 +-
src/lib/dns/rdata/generic/nsec3_50.cc | 3 +-
src/lib/dns/rdata/generic/nsec_47.cc | 3 +-
src/lib/dns/tests/name_unittest.cc | 2 +-
src/lib/log/strutil.cc | 2 +-
src/lib/log/strutil.h | 2 +-
src/lib/nsas/asiolink.h | 2 +-
src/lib/nsas/nameserver_entry.h | 9 +-
src/lib/python/isc/util/socketserver_mixin.py | 6 +-
.../isc/util/tests/socketserver_mixin_test.py | 2 +-
src/lib/python/isc/utils/Makefile.am | 5 -
src/lib/python/isc/utils/process.py | 37 ----
src/lib/python/isc/utils/tests/Makefile.am | 16 --
src/lib/python/isc/utils/tests/process_test.py | 39 ----
src/lib/server_common/Makefile.am | 26 +++
src/lib/server_common/portconfig.cc | 119 ++++++++++++
src/lib/server_common/portconfig.h | 121 +++++++++++++
src/lib/server_common/tests/Makefile.am | 38 ++++
src/lib/server_common/tests/portconfig_unittest.cc | 182 +++++++++++++++++++
.../{log => server_common}/tests/run_unittests.cc | 5 +
src/lib/testutils/Makefile.am | 2 +
src/lib/testutils/portconfig.h | 189 ++++++++++++++++++++
src/lib/testutils/srv_test.cc | 4 +-
tools/README | 5 +-
tools/import_boost.sh | 74 --------
tools/tests_in_valgrind.sh | 75 ++++++++
tools/valgrind_test_cleaner.pl | 64 +++++++
94 files changed, 1512 insertions(+), 797 deletions(-)
create mode 100644 src/cppcheck-suppress.lst
delete mode 100644 src/lib/python/isc/utils/Makefile.am
delete mode 100644 src/lib/python/isc/utils/__init__.py
delete mode 100644 src/lib/python/isc/utils/process.py
delete mode 100644 src/lib/python/isc/utils/tests/Makefile.am
delete mode 100644 src/lib/python/isc/utils/tests/process_test.py
create mode 100644 src/lib/server_common/Makefile.am
create mode 100644 src/lib/server_common/portconfig.cc
create mode 100644 src/lib/server_common/portconfig.h
create mode 100644 src/lib/server_common/tests/Makefile.am
create mode 100644 src/lib/server_common/tests/portconfig_unittest.cc
copy src/lib/{log => server_common}/tests/run_unittests.cc (93%)
create mode 100644 src/lib/testutils/portconfig.h
delete mode 100755 tools/import_boost.sh
create mode 100755 tools/tests_in_valgrind.sh
create mode 100755 tools/valgrind_test_cleaner.pl
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 85783f7..7d140ec 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,52 @@
+ 187. [bug] zhang likun
+ Fix the assert error in class isc::cache::RRsetCache by adding the
+ check for empty pointer and test case for it.
+ (Trac #638, git 54e61304131965c4a1d88c9151f8697dcbb3ce12)
+
+ 186. [bug] jelte
+ b10-resolver could stop with an assertion failure on certain kinds
+ of messages (there was a problem in error message creation). This
+ fixes that.
+ (Trac #607, git 25a5f4ec755bc09b54410fcdff22691283147f32)
+
+ 185. [bug] vorner
+ Tests use port from private range (53210), lowering chance of
+ a conflict with something else (eg. running bind 10).
+ (Trac #523, git 301da7d26d41e64d87c0cf72727f3347aa61fb40)
+
+ 184. [func]* vorner
+ Listening address and port configuration of b10-auth is the same as
+ for b10-resolver now. That means, it is configured through bindctl
+ at runtime, in the Auth/listen_on list, not through command line
+ arguments.
+ (Trac #575, #576, git f06ce638877acf6f8e1994962bf2dbfbab029edf)
+
+ 183. [bug] jerry
+ src/bin/xfrout: Enable parallel sessions between xfrout server and
+ muti-Auth. The session needs to be created only on the first time
+ or if an error occur.
+ (Trac #419, git 1d60afb59e9606f312caef352ecb2fe488c4e751)
+
+ 182. [func] jinmei
+ Support cppcheck for static code check on C++ code. If cppcheck
+ is available, 'make cppcheck' on the top source directory will run
+ the checker and should cleanly complete with an exit code of 0
+ (at least with cppcheck 1.47).
+ Note: the suppression list isn't included in the final
+ distributions. It should be created by hand or retrieved from
+ the git repository.
+ (Trac #613, git b973f67520682b63ef38b1451d309be9f4f4b218)
+
+ 181. [func] feng
+ Add stop interface into dns server, so we can stop each running
+ server individually. With it, user can reconfigure her running server
+ with different ip address or port.
+ (Trac #388, git 6df94e2db856c1adc020f658cc77da5edc967555)
+
+ 180. [build] jreed
+ Fix custom DESTDIR for make install. Patch from Jan Engelhardt.
+ (Trac #629, git 5ac67ede03892a5eacf42ce3ace1e4e376164c9f)
+
bind10-devel-20110224 released on February 24, 2011
179. [func] vorner
diff --git a/Makefile.am b/Makefile.am
index 68a41d6..9a28f20 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -70,6 +70,13 @@ clean-coverage: clean-cpp-coverage clean-python-coverage
report-coverage: report-cpp-coverage report-python-coverage
+# for static C++ check using cppcheck (when available)
+cppcheck:
+ cppcheck --enable=all --suppressions src/cppcheck-suppress.lst \
+ --quiet --error-exitcode=1 \
+ --template '{file}:{line}: check_fail: {message} ({severity},{id})' \
+ src
+
#### include external sources in the distributed tarball:
EXTRA_DIST = ext/asio/README
EXTRA_DIST += ext/asio/asio/local/stream_protocol.hpp
diff --git a/configure.ac b/configure.ac
index d6b9376..0f34b0d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,18 +14,22 @@ AC_PROG_CXX
#
# On FreeBSD (and probably some others), clang++ does not meet an autoconf
# assumption in identifying libtool configuration regarding shared library:
-# the configure script will execute "$CC -shared $CFLAGS -v -o" and expect
-# the output contains -Lxxx or -Ryyy. This is the case for g++, but not for
-# clang++, and, as a result, it will cause various errors in linking programs
-# or running them with a shared object (such as some of our python scripts).
+# the configure script will execute "$CC -shared $CFLAGS/$CXXFLAGS -v" and
+# expect the output contains -Lxxx or -Ryyy. This is the case for g++, but
+# not for clang++, and, as a result, it will cause various errors in linking
+# programs or running them with a shared object (such as some of our python
+# scripts).
# To work around this problem we define a temporary variable
# "CXX_LIBTOOL_LDFLAGS". It's expected to be defined as, e.g, "-L/usr/lib"
# to temporarily fake the output so that it will be compatible with that of
# g++.
CFLAGS_SAVED=$CFLAGS
+CXXFLAGS_SAVED=$CXXFLAGS
CFLAGS="$CFLAGS $CXX_LIBTOOL_LDFLAGS"
+CXXFLAGS="$CXXFLAGS $CXX_LIBTOOL_LDFLAGS"
AC_PROG_LIBTOOL
CFLAGS=$CFLAGS_SAVED
+CXXFLAGS=$CXXFLAGS_SAVED
# Use C++ language
AC_LANG([C++])
@@ -291,6 +295,7 @@ AC_SUBST(B10_CXXFLAGS)
AC_SEARCH_LIBS(inet_pton, [nsl])
AC_SEARCH_LIBS(recvfrom, [socket])
+AC_SEARCH_LIBS(nanosleep, [rt])
# Checks for header files.
@@ -676,6 +681,8 @@ AC_CONFIG_FILES([Makefile
src/lib/nsas/tests/Makefile
src/lib/cache/Makefile
src/lib/cache/tests/Makefile
+ src/lib/server_common/Makefile
+ src/lib/server_common/tests/Makefile
])
AC_OUTPUT([doc/version.ent
src/bin/cfgmgr/b10-cfgmgr.py
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 34ec3d8..46aa178 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -568,7 +568,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache
+INPUT = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache ../src/lib/server_common/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index 36de53d..cdfc55e 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -52,10 +52,11 @@ b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
b10_auth_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
+b10_auth_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
b10_auth_LDADD += $(SQLITE_LIBS)
# TODO: config.h.in is wrong because doesn't honor pkgdatadir
# and can't use @datadir@ because doesn't expand default ${prefix}
-b10_authdir = $(DESTDIR)$(pkgdatadir)
+b10_authdir = $(pkgdatadir)
b10_auth_DATA = auth.spec
diff --git a/src/bin/auth/auth.spec.pre.in b/src/bin/auth/auth.spec.pre.in
index 7cb571c..e95dabd 100644
--- a/src/bin/auth/auth.spec.pre.in
+++ b/src/bin/auth/auth.spec.pre.in
@@ -56,6 +56,41 @@
"item_type": "integer",
"item_optional": true,
"item_default": 60
+ },
+ {
+ "item_name": "listen_on",
+ "item_type": "list",
+ "item_optional": false,
+ "item_default": [
+ {
+ "address": "::1",
+ "port": 5300
+ },
+ {
+ "address": "127.0.0.1",
+ "port": 5300
+ }
+ ],
+ "list_item_spec": {
+ "item_name": "address",
+ "item_type": "map",
+ "item_optional": false,
+ "item_default": {},
+ "map_item_spec": [
+ {
+ "item_name": "address",
+ "item_type": "string",
+ "item_optional": false,
+ "item_default": "::1"
+ },
+ {
+ "item_name": "port",
+ "item_type": "integer",
+ "item_optional": false,
+ "item_default": 5300
+ }
+ ]
+ }
}
],
"commands": [
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index 045fe7f..f46752a 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -69,6 +69,7 @@ using namespace isc::data;
using namespace isc::config;
using namespace isc::xfr;
using namespace asiolink;
+using namespace isc::server_common::portconfig;
class AuthSrvImpl {
private:
@@ -109,6 +110,9 @@ public:
/// Query counters for statistics
AuthCounters counters_;
+
+ /// Addresses we listen on
+ AddressList listen_addresses_;
private:
std::string db_file_;
@@ -750,3 +754,18 @@ uint64_t
AuthSrv::getCounter(const AuthCounters::CounterType type) const {
return (impl_->counters_.getCounter(type));
}
+
+const AddressList&
+AuthSrv::getListenAddresses() const {
+ return (impl_->listen_addresses_);
+}
+
+void
+AuthSrv::setListenAddresses(const AddressList& addresses) {
+ installListenAddresses(addresses, impl_->listen_addresses_, *dnss_);
+}
+
+void
+AuthSrv::setDNSService(asiolink::DNSService& dnss) {
+ dnss_ = &dnss;
+}
diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h
index 4772a02..8253c85 100644
--- a/src/bin/auth/auth_srv.h
+++ b/src/bin/auth/auth_srv.h
@@ -25,6 +25,7 @@
#include <config/ccsession.h>
#include <asiolink/asiolink.h>
+#include <server_common/portconfig.h>
#include <auth/statistics.h>
namespace isc {
@@ -353,11 +354,24 @@ public:
/// \return the value of the counter.
uint64_t getCounter(const AuthCounters::CounterType type) const;
+ /**
+ * \brief Set and get the addresses we listen on.
+ */
+ void setListenAddresses(const isc::server_common::portconfig::AddressList&
+ addreses);
+ const isc::server_common::portconfig::AddressList& getListenAddresses()
+ const;
+
+ /// \brief Assign an ASIO DNS Service queue to this Auth object
+ void setDNSService(asiolink::DNSService& dnss);
+
+
private:
AuthSrvImpl* impl_;
asiolink::SimpleCallback* checkin_;
asiolink::DNSLookup* dns_lookup_;
asiolink::DNSAnswer* dns_answer_;
+ asiolink::DNSService* dnss_;
};
#endif // __AUTH_SRV_H
diff --git a/src/bin/auth/b10-auth.xml b/src/bin/auth/b10-auth.xml
index b22d24d..c9e935a 100644
--- a/src/bin/auth/b10-auth.xml
+++ b/src/bin/auth/b10-auth.xml
@@ -44,11 +44,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>b10-auth</command>
- <arg><option>-4</option></arg>
- <arg><option>-6</option></arg>
- <arg><option>-a <replaceable>address</replaceable></option></arg>
<arg><option>-n</option></arg>
- <arg><option>-p <replaceable>number</replaceable></option></arg>
<arg><option>-u <replaceable>username</replaceable></option></arg>
<arg><option>-v</option></arg>
</cmdsynopsis>
@@ -85,39 +81,6 @@
<variablelist>
<varlistentry>
- <term><option>-4</option></term>
- <listitem><para>
- Enables IPv4 only mode.
- This switch may not be used with <option>-6</option> nor
- <option>-a</option>.
- By default, it listens on both IPv4 and IPv6 (if capable).
- </para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><option>-6</option></term>
- <listitem><para>
- Enables IPv6 only mode.
- This switch may not be used with <option>-4</option> nor
- <option>-a</option>.
- By default, it listens on both IPv4 and IPv6 (if capable).
- </para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><option>-a <replaceable>address</replaceable></option></term>
-
- <listitem>
- <para>The IPv4 or IPv6 address to listen on.
- This switch may not be used with <option>-4</option> nor
- <option>-6</option>.
- The default is to listen on all addresses.
- (This is a short term workaround. This argument may change.)
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term><option>-n</option></term>
<listitem><para>
Do not cache answers in memory.
@@ -130,16 +93,6 @@
</varlistentry>
<varlistentry>
- <term><option>-p <replaceable>number</replaceable></option></term>
- <listitem><para>
- The port number it listens on.
- The default is 5300.</para>
- <note><simpara>This prototype runs on all interfaces
- and on this nonstandard port.</simpara></note>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term><option>-u <replaceable>username</replaceable></option></term>
<listitem>
<para>
diff --git a/src/bin/auth/benchmarks/Makefile.am b/src/bin/auth/benchmarks/Makefile.am
index 653d502..3078dd5 100644
--- a/src/bin/auth/benchmarks/Makefile.am
+++ b/src/bin/auth/benchmarks/Makefile.am
@@ -23,4 +23,5 @@ query_bench_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
query_bench_LDADD += $(top_builddir)/src/lib/log/liblog.la
query_bench_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+query_bench_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
query_bench_LDADD += $(SQLITE_LIBS)
diff --git a/src/bin/auth/benchmarks/query_bench.cc b/src/bin/auth/benchmarks/query_bench.cc
index 7f643f3..5e69134 100644
--- a/src/bin/auth/benchmarks/query_bench.cc
+++ b/src/bin/auth/benchmarks/query_bench.cc
@@ -77,7 +77,7 @@ protected:
dummy_socket(IOSocket::getDummyUDPSocket()),
dummy_endpoint(IOEndpointPtr(IOEndpoint::create(IPPROTO_UDP,
IOAddress("192.0.2.1"),
- 5300)))
+ 53210)))
{}
public:
unsigned int run() {
diff --git a/src/bin/auth/config.cc b/src/bin/auth/config.cc
index 5befc6e..f289ca0 100644
--- a/src/bin/auth/config.cc
+++ b/src/bin/auth/config.cc
@@ -32,11 +32,14 @@
#include <auth/config.h>
#include <auth/common.h>
+#include <server_common/portconfig.h>
+
using namespace std;
using boost::shared_ptr;
using namespace isc::dns;
using namespace isc::data;
using namespace isc::datasrc;
+using namespace isc::server_common::portconfig;
namespace {
// Forward declaration
@@ -210,6 +213,60 @@ public:
}
};
+/**
+ * \brief Configuration parser for listen_on.
+ *
+ * It parses and sets the listening addresses of the server.
+ *
+ * It acts in unusual way. Since actually binding (changing) the sockets
+ * is an operation that is expected to throw often, it shouldn't happen
+ * in commit. Thefere we do it in build. But if the config is not committed
+ * then, we would have it wrong. So we store the old addresses and if
+ * commit is not called before destruction of the object, we return the
+ * old addresses (which is the same kind of dangerous operation, but it is
+ * expected that if we just managed to bind some and had the old ones binded
+ * before, it should work).
+ *
+ * We might do something better in future (like open only the ports that are
+ * extra, put them in in commit and close the old ones), but that's left out
+ * for now.
+ */
+class ListenAddressConfig : public AuthConfigParser {
+public:
+ ListenAddressConfig(AuthSrv& server) :
+ server_(server)
+ { }
+ ~ ListenAddressConfig() {
+ if (rollbackAddresses_.get() != NULL) {
+ server_.setListenAddresses(*rollbackAddresses_);
+ }
+ }
+private:
+ typedef auto_ptr<AddressList> AddrListPtr;
+public:
+ virtual void build(ConstElementPtr config) {
+ AddressList newAddresses = parseAddresses(config, "listen_on");
+ AddrListPtr old(new AddressList(server_.getListenAddresses()));
+ server_.setListenAddresses(newAddresses);
+ /*
+ * Set the rollback addresses only after successful setting of the
+ * new addresses, so we don't try to rollback if the setup is
+ * unsuccessful (the above can easily throw).
+ */
+ rollbackAddresses_ = old;
+ }
+ virtual void commit() {
+ rollbackAddresses_.release();
+ }
+private:
+ AuthSrv& server_;
+ /**
+ * This is the old address list, if we expect to roll back. When we commit,
+ * this is set to NULL.
+ */
+ AddrListPtr rollbackAddresses_;
+};
+
// This is a generalized version of create function that can create
// an AuthConfigParser object for "internal" use.
AuthConfigParser*
@@ -226,6 +283,8 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id,
return (new StatisticsIntervalConfig(server));
} else if (internal && config_id == "datasources/memory") {
return (new MemoryDatasourceConfig(server));
+ } else if (config_id == "listen_on") {
+ return (new ListenAddressConfig(server));
} else if (config_id == "_commit_throw") {
// This is for testing purpose only and should not appear in the
// actual configuration syntax. While this could crash the caller
@@ -271,7 +330,7 @@ configureAuthServer(AuthSrv& server, ConstElementPtr config_set) {
parsers.push_back(parser);
}
} catch (const AuthConfigError& ex) {
- throw ex; // simply rethrowing it
+ throw; // simply rethrowing it
} catch (const isc::Exception& ex) {
isc_throw(AuthConfigError, "Server configuration failed: " <<
ex.what());
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index 10e1194..275ae7d 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -42,6 +42,7 @@
#include <auth/change_user.h>
#include <auth/auth_srv.h>
#include <asiolink/asiolink.h>
+#include <log/dummylog.h>
using namespace std;
using namespace isc::data;
@@ -55,9 +56,6 @@ namespace {
bool verbose_mode = false;
-// Default port current 5300 for testing purposes
-const char* DNSPORT = "5300";
-
/* need global var for config/command handlers.
* todo: turn this around, and put handlers in the authserver
* class itself? */
@@ -76,13 +74,8 @@ my_command_handler(const string& command, ConstElementPtr args) {
void
usage() {
- cerr << "Usage: b10-auth [-a address] [-p port] [-u user] [-4|-6] [-nv]"
- << endl;
- cerr << "\t-a: specify the address to listen on (default: all) " << endl;
- cerr << "\t-p: specify the port to listen on (default: " << DNSPORT << ")"
+ cerr << "Usage: b10-auth [-u user] [-nv]"
<< endl;
- cerr << "\t-4: listen on all IPv4 addresses (incompatible with -a)" << endl;
- cerr << "\t-6: listen on all IPv6 addresses (incompatible with -a)" << endl;
cerr << "\t-n: do not cache answers in memory" << endl;
cerr << "\t-u: change process UID to the specified user" << endl;
cerr << "\t-v: verbose output" << endl;
@@ -93,38 +86,20 @@ usage() {
int
main(int argc, char* argv[]) {
int ch;
- const char* port = DNSPORT;
- const char* address = NULL;
const char* uid = NULL;
- bool use_ipv4 = true, use_ipv6 = true, cache = true;
+ bool cache = true;
- while ((ch = getopt(argc, argv, "46a:np:u:v")) != -1) {
+ while ((ch = getopt(argc, argv, ":nu:v")) != -1) {
switch (ch) {
- case '4':
- // Note that -4 means "ipv4 only", we need to set "use_ipv6" here,
- // not "use_ipv4". We could use something like "ipv4_only", but
- // we found the negatively named variable could confuse the code
- // logic.
- use_ipv6 = false;
- break;
- case '6':
- // The same note as -4 applies.
- use_ipv4 = false;
- break;
case 'n':
cache = false;
break;
- case 'a':
- address = optarg;
- break;
- case 'p':
- port = optarg;
- break;
case 'u':
uid = optarg;
break;
case 'v':
verbose_mode = true;
+ isc::log::denabled = true;
break;
case '?':
default:
@@ -136,18 +111,6 @@ main(int argc, char* argv[]) {
usage();
}
- if (!use_ipv4 && !use_ipv6) {
- cerr << "[b10-auth] Error: Cannot specify both -4 and -6 "
- << "at the same time" << endl;
- usage();
- }
-
- if ((!use_ipv4 || !use_ipv6) && address != NULL) {
- cerr << "[b10-auth] Error: Cannot specify -4 or -6 "
- << "at the same time as -a" << endl;
- usage();
- }
-
int ret = 0;
// XXX: we should eventually pass io_service here.
@@ -182,21 +145,8 @@ main(int argc, char* argv[]) {
DNSLookup* lookup = auth_server->getDNSLookupProvider();
DNSAnswer* answer = auth_server->getDNSAnswerProvider();
- DNSService* dns_service;
- if (address != NULL) {
- // XXX: we can only specify at most one explicit address.
- // This also means the server cannot run in the dual address
- // family mode if explicit addresses need to be specified.
- // We don't bother to fix this problem, however. The -a option
- // is a short term workaround until we support dynamic listening
- // port allocation.
- dns_service = new DNSService(io_service, *port, *address,
- checkin, lookup, answer);
- } else {
- dns_service = new DNSService(io_service, *port, use_ipv4,
- use_ipv6, checkin, lookup,
- answer);
- }
+ DNSService dns_service(io_service, checkin, lookup, answer);
+ auth_server->setDNSService(dns_service);
cout << "[b10-auth] DNSServices created." << endl;
cc_session = new Session(io_service.get_io_service());
@@ -237,7 +187,6 @@ main(int argc, char* argv[]) {
cout << "[b10-auth] Server started." << endl;
io_service.run();
- delete dns_service;
} catch (const std::exception& ex) {
cerr << "[b10-auth] Server failed: " << ex.what() << endl;
ret = 1;
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index def99b0..7d489a1 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -45,6 +45,7 @@ run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
endif
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index 576799c..379342e 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -26,6 +26,8 @@
#include <dns/rrttl.h>
#include <dns/rdataclass.h>
+#include <server_common/portconfig.h>
+
#include <datasrc/memory_datasrc.h>
#include <auth/auth_srv.h>
#include <auth/common.h>
@@ -34,6 +36,7 @@
#include <dns/tests/unittest_util.h>
#include <testutils/dnsmessage_test.h>
#include <testutils/srv_test.h>
+#include <testutils/portconfig.h>
using namespace std;
using namespace isc::cc;
@@ -43,6 +46,7 @@ using namespace isc::data;
using namespace isc::xfr;
using namespace asiolink;
using namespace isc::testutils;
+using namespace isc::server_common::portconfig;
using isc::UnitTestUtil;
namespace {
@@ -55,7 +59,12 @@ const char* const BADCONFIG_TESTDB =
class AuthSrvTest : public SrvTestBase {
protected:
- AuthSrvTest() : server(true, xfrout), rrclass(RRClass::IN()) {
+ AuthSrvTest() :
+ dnss_(ios_, NULL, NULL, NULL),
+ server(true, xfrout),
+ rrclass(RRClass::IN())
+ {
+ server.setDNSService(dnss_);
server.setXfrinSession(¬ify_session);
server.setStatisticsSession(&statistics_session);
}
@@ -63,6 +72,8 @@ protected:
server.processMessage(*io_message, parse_message, response_obuffer,
&dnsserv);
}
+ IOService ios_;
+ DNSService dnss_;
MockSession statistics_session;
MockXfroutClient xfrout;
AuthSrv server;
@@ -633,7 +644,7 @@ TEST_F(AuthSrvTest, queryCounterUnexpected) {
// Modify the message.
delete io_message;
endpoint = IOEndpoint::create(IPPROTO_UDP,
- IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
+ IOAddress(DEFAULT_REMOTE_ADDRESS), 53210);
io_message = new IOMessage(request_renderer.getData(),
request_renderer.getLength(),
getDummyUnknownSocket(), *endpoint);
@@ -650,4 +661,9 @@ TEST_F(AuthSrvTest, stop) {
// If/when the interval timer has finer granularity we'll probably add
// our own tests here, so we keep this empty test case.
}
+
+TEST_F(AuthSrvTest, listenAddresses) {
+ isc::testutils::portconfig::listenAddresses(server);
+}
+
}
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index b8b379e..8cce0af 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -30,6 +30,7 @@
#include <auth/common.h>
#include <testutils/mockups.h>
+#include <testutils/portconfig.h>
using namespace isc::dns;
using namespace isc::data;
@@ -39,7 +40,15 @@ using namespace asiolink;
namespace {
class AuthConfigTest : public ::testing::Test {
protected:
- AuthConfigTest() : rrclass(RRClass::IN()), server(true, xfrout) {}
+ AuthConfigTest() :
+ dnss_(ios_, NULL, NULL, NULL),
+ rrclass(RRClass::IN()),
+ server(true, xfrout)
+ {
+ server.setDNSService(dnss_);
+ }
+ IOService ios_;
+ DNSService dnss_;
const RRClass rrclass;
MockXfroutClient xfrout;
AuthSrv server;
@@ -112,6 +121,17 @@ TEST_F(AuthConfigTest, exceptionFromCommit) {
FatalError);
}
+// Test invalid address configs are rejected
+TEST_F(AuthConfigTest, invalidListenAddressConfig) {
+ // This currently passes simply because the config doesn't know listen_on
+ isc::testutils::portconfig::invalidListenAddressConfig(server);
+}
+
+// Try setting addresses trough config
+TEST_F(AuthConfigTest, listenAddressConfig) {
+ isc::testutils::portconfig::listenAddressConfig(server);
+}
+
class MemoryDatasrcConfigTest : public AuthConfigTest {
protected:
MemoryDatasrcConfigTest() :
diff --git a/src/bin/bind10/Makefile.am b/src/bin/bind10/Makefile.am
index 1445b95..254875f 100644
--- a/src/bin/bind10/Makefile.am
+++ b/src/bin/bind10/Makefile.am
@@ -5,7 +5,7 @@ CLEANFILES = bind10 bind10.pyc
pkglibexecdir = $(libexecdir)/@PACKAGE@
-bind10dir = $(DESTDIR)$(pkgdatadir)
+bind10dir = $(pkgdatadir)
bind10_DATA = bob.spec
EXTRA_DIST = bob.spec
@@ -19,7 +19,6 @@ bind10.8: bind10.xml
endif
-# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
bind10: bind10.py
$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
diff --git a/src/bin/bind10/bind10.py.in b/src/bin/bind10/bind10.py.in
index 5a4ba4a..83acf1f 100755
--- a/src/bin/bind10/bind10.py.in
+++ b/src/bin/bind10/bind10.py.in
@@ -194,8 +194,8 @@ class CChannelConnectError(Exception): pass
class BoB:
"""Boss of BIND class."""
- def __init__(self, msgq_socket_file=None, dns_port=5300, address=None,
- nocache=False, verbose=False, setuid=None, username=None):
+ def __init__(self, msgq_socket_file=None, nocache=False, verbose=False,
+ setuid=None, username=None):
"""
Initialize the Boss of BIND. This is a singleton (only one can run).
@@ -203,8 +203,6 @@ class BoB:
msgq process listens on. If verbose is True, then the boss reports
what it is doing.
"""
- self.address = address
- self.dns_port = dns_port
self.cc_session = None
self.ccs = None
self.cfg_start_auth = True
@@ -462,9 +460,6 @@ class BoB:
Start the Authoritative server
"""
authargs = ['b10-auth']
- authargs += ['-p', str(self.dns_port)]
- if self.address:
- authargs += ['-a', str(self.address)]
if self.nocache:
authargs += ['-n']
if self.uid:
@@ -473,8 +468,7 @@ class BoB:
authargs += ['-v']
# ... and start
- self.start_process("b10-auth", authargs, c_channel_env,
- self.dns_port, self.address)
+ self.start_process("b10-auth", authargs, c_channel_env)
def start_resolver(self, c_channel_env):
"""
@@ -787,28 +781,6 @@ def fatal_signal(signal_number, stack_frame):
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
boss_of_bind.runnable = False
-def check_port(option, opt_str, value, parser):
- """Function to insure that the port we are passed is actually
- a valid port number. Used by OptionParser() on startup."""
- try:
- if opt_str in ['-p', '--port']:
- parser.values.dns_port = isc.net.parse.port_parse(value)
- else:
- raise OptionValueError("Unknown option " + opt_str)
- except ValueError as e:
- raise OptionValueError(str(e))
-
-def check_addr(option, opt_str, value, parser):
- """Function to insure that the address we are passed is actually
- a valid address. Used by OptionParser() on startup."""
- try:
- if opt_str in ['-a', '--address']:
- parser.values.address = isc.net.parse.addr_parse(value)
- else:
- raise OptionValueError("Unknown option " + opt_str)
- except ValueError:
- raise OptionValueError("%s requires a valid IPv4 or IPv6 address" % opt_str)
-
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)
@@ -821,17 +793,11 @@ def main():
# Parse any command-line options.
parser = OptionParser(version=VERSION)
- parser.add_option("-a", "--address", dest="address", type="string",
- action="callback", callback=check_addr, default=None,
- help="address the DNS server will use (default: listen on all addresses)")
parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
type="string", default=None,
help="UNIX domain socket file the b10-msgq daemon will use")
parser.add_option("-n", "--no-cache", action="store_true", dest="nocache",
default=False, help="disable hot-spot cache in authoritative DNS server")
- parser.add_option("-p", "--port", dest="dns_port", type="int",
- action="callback", callback=check_port, default=5300,
- help="port the DNS server will use (default 5300)")
parser.add_option("-u", "--user", dest="user", type="string", default=None,
help="Change user after startup (must run as root)")
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
@@ -892,9 +858,8 @@ def main():
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
# Go bob!
- boss_of_bind = BoB(options.msgq_socket_file, options.dns_port,
- options.address, options.nocache, options.verbose,
- setuid, username)
+ boss_of_bind = BoB(options.msgq_socket_file, options.nocache,
+ options.verbose, setuid, username)
startup_result = boss_of_bind.startup()
if startup_result:
sys.stderr.write("[bind10] Error on startup: %s\n" % startup_result)
diff --git a/src/bin/bind10/bind10.xml b/src/bin/bind10/bind10.xml
index dd8daf9..f3964a6 100644
--- a/src/bin/bind10/bind10.xml
+++ b/src/bin/bind10/bind10.xml
@@ -20,7 +20,7 @@
<refentry>
<refentryinfo>
- <date>July 29, 2010</date>
+ <date>February 22, 2011</date>
</refentryinfo>
<refmeta>
@@ -36,24 +36,20 @@
<docinfo>
<copyright>
- <year>2010</year>
+ <year>2011</year>
<holder>Internet Systems Consortium, Inc. ("ISC")</holder>
</copyright>
</docinfo>
<refsynopsisdiv>
<cmdsynopsis>
- <command>bind10</command>
- <arg><option>-a <replaceable>address</replaceable></option></arg>
+ <command>bind10</command>
<arg><option>-m <replaceable>file</replaceable></option></arg>
<arg><option>-n</option></arg>
- <arg><option>-p <replaceable>number</replaceable></option></arg>
<arg><option>-u <replaceable>user</replaceable></option></arg>
<arg><option>-v</option></arg>
- <arg><option>--address <replaceable>address</replaceable></option></arg>
<arg><option>--msgq-socket-file <replaceable>file</replaceable></option></arg>
<arg><option>--no-cache</option></arg>
- <arg><option>--port <replaceable>number</replaceable></option></arg>
<arg><option>--user <replaceable>user</replaceable></option></arg>
<arg><option>--pretty-name <replaceable>name</replaceable></option></arg>
<arg><option>--verbose</option></arg>
@@ -86,19 +82,6 @@
<variablelist>
<varlistentry>
- <term><option>-a</option> <replaceable>address</replaceable>, <option>--address</option> <replaceable>address</replaceable></term>
-
- <listitem>
- <para>The IPv4 or IPv6 address for the
- <citerefentry><refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- daemon to listen on.
- The default is to listen on all addresses.
- (This is a short term workaround. This argument may change.)
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term><option>-m</option> <replaceable>file</replaceable>,
<option>--msgq-socket-file</option> <replaceable>file</replaceable></term>
@@ -123,20 +106,6 @@
</varlistentry>
<varlistentry>
- <term><option>-p</option> <replaceable>number</replaceable>, <option>--port</option> <replaceable>number</replaceable></term>
-
- <listitem>
- <para>The port number for the
- <citerefentry><refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- daemon to listen on.
- The default is 5300.</para>
-<!-- TODO: -->
- <note><simpara>This prototype release uses a non-default
- port for domain service.</simpara></note>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term><option>-u</option> <replaceable>user</replaceable>, <option>--user</option> <replaceable>name</replaceable></term>
<listitem>
diff --git a/src/bin/bind10/tests/bind10_test.py b/src/bin/bind10/tests/bind10_test.py
index ffa06bc..f3fe949 100644
--- a/src/bin/bind10/tests/bind10_test.py
+++ b/src/bin/bind10/tests/bind10_test.py
@@ -78,8 +78,6 @@ class TestBoB(unittest.TestCase):
bob = BoB()
self.assertEqual(bob.verbose, False)
self.assertEqual(bob.msgq_socket_file, None)
- self.assertEqual(bob.dns_port, 5300)
- self.assertEqual(bob.address, None)
self.assertEqual(bob.cc_session, None)
self.assertEqual(bob.ccs, None)
self.assertEqual(bob.processes, {})
@@ -95,42 +93,6 @@ class TestBoB(unittest.TestCase):
bob = BoB("alt_socket_file")
self.assertEqual(bob.verbose, False)
self.assertEqual(bob.msgq_socket_file, "alt_socket_file")
- self.assertEqual(bob.address, None)
- self.assertEqual(bob.dns_port, 5300)
- 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_dns_port(self):
- bob = BoB(None, 9999)
- self.assertEqual(bob.verbose, False)
- self.assertEqual(bob.msgq_socket_file, None)
- self.assertEqual(bob.dns_port, 9999)
- self.assertEqual(bob.address, 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_address(self):
- bob = BoB(None, 1234, IPAddr('127.127.127.127'))
- self.assertEqual(bob.verbose, False)
- self.assertEqual(bob.msgq_socket_file, None)
- self.assertEqual(bob.dns_port, 1234)
- self.assertEqual(bob.address.addr, socket.inet_aton('127.127.127.127'))
self.assertEqual(bob.cc_session, None)
self.assertEqual(bob.ccs, None)
self.assertEqual(bob.processes, {})
diff --git a/src/bin/bindctl/Makefile.am b/src/bin/bindctl/Makefile.am
index da9b63d..e95af78 100644
--- a/src/bin/bindctl/Makefile.am
+++ b/src/bin/bindctl/Makefile.am
@@ -8,7 +8,7 @@ EXTRA_DIST = $(man_MANS) bindctl.xml
python_PYTHON = __init__.py bindcmd.py cmdparse.py exception.py moduleinfo.py mycollections.py
pythondir = $(pyexecdir)/bindctl
-bindctldir = $(DESTDIR)$(pkgdatadir)
+bindctldir = $(pkgdatadir)
CLEANFILES = bindctl
diff --git a/src/bin/cfgmgr/Makefile.am b/src/bin/cfgmgr/Makefile.am
index e092070..a41448b 100644
--- a/src/bin/cfgmgr/Makefile.am
+++ b/src/bin/cfgmgr/Makefile.am
@@ -19,7 +19,6 @@ b10-cfgmgr.8: b10-cfgmgr.xml
endif
-# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
b10-cfgmgr: b10-cfgmgr.py
$(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" b10-cfgmgr.py >$@
diff --git a/src/bin/cmdctl/Makefile.am b/src/bin/cmdctl/Makefile.am
index 76572ab..04cf5e2 100644
--- a/src/bin/cmdctl/Makefile.am
+++ b/src/bin/cmdctl/Makefile.am
@@ -4,7 +4,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
pkglibexec_SCRIPTS = b10-cmdctl
-b10_cmdctldir = $(DESTDIR)$(pkgdatadir)
+b10_cmdctldir = $(pkgdatadir)
# NOTE: this will overwrite on install
# So these generic copies are placed in share/bind10 instead of to etc
@@ -33,7 +33,6 @@ endif
cmdctl.spec: cmdctl.spec.pre
$(SED) -e "s|@@SYSCONFDIR@@|$(sysconfdir)|" cmdctl.spec.pre >$@
-# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
b10-cmdctl: cmdctl.py
$(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" cmdctl.py >$@
diff --git a/src/bin/host/host.cc b/src/bin/host/host.cc
index 477586d..c513b5a 100644
--- a/src/bin/host/host.cc
+++ b/src/bin/host/host.cc
@@ -70,12 +70,15 @@ host_lookup(const char* const name, const char* const type) {
msg.toWire(renderer);
struct addrinfo hints, *res;
- int e;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0; // not using AI_NUMERICHOST in case to bootstrap
- e = getaddrinfo(server, server_port, &hints, &res);
+ if (getaddrinfo(server, server_port, &hints, &res) != 0) {
+ cerr << "address/port conversion for " << server << ":"
+ << server_port << " failed" << endl;
+ return (1);
+ }
if (verbose) {
cout << "Trying \"" << name << "\"\n";
diff --git a/src/bin/msgq/Makefile.am b/src/bin/msgq/Makefile.am
index 9ed4717..61d4f23 100644
--- a/src/bin/msgq/Makefile.am
+++ b/src/bin/msgq/Makefile.am
@@ -16,7 +16,6 @@ b10-msgq.8: msgq.xml
endif
-# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
b10-msgq: msgq.py
$(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" msgq.py >$@
diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am
index 75d6249..36b8551 100644
--- a/src/bin/resolver/Makefile.am
+++ b/src/bin/resolver/Makefile.am
@@ -48,6 +48,7 @@ b10_resolver_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
b10_resolver_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
b10_resolver_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
b10_resolver_LDADD += $(top_builddir)/src/lib/log/liblog.la
+b10_resolver_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
b10_resolver_LDADD += $(top_builddir)/src/lib/cache/libcache.la
b10_resolver_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
b10_resolver_LDADD += $(top_builddir)/src/bin/auth/change_user.o
@@ -55,6 +56,6 @@ b10_resolver_LDFLAGS = -pthread
# TODO: config.h.in is wrong because doesn't honor pkgdatadir
# and can't use @datadir@ because doesn't expand default ${prefix}
-b10_resolverdir = $(DESTDIR)$(pkgdatadir)
+b10_resolverdir = $(pkgdatadir)
b10_resolver_DATA = resolver.spec
diff --git a/src/bin/resolver/resolver.cc b/src/bin/resolver/resolver.cc
index 95a417d..84df9d2 100644
--- a/src/bin/resolver/resolver.cc
+++ b/src/bin/resolver/resolver.cc
@@ -39,6 +39,7 @@
#include <dns/rrttl.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
+#include <server_common/portconfig.h>
#include <log/dummylog.h>
@@ -52,8 +53,7 @@ using namespace isc::data;
using namespace isc::config;
using isc::log::dlog;
using namespace asiolink;
-
-typedef pair<string, uint16_t> addr_t;
+using namespace isc::server_common::portconfig;
class ResolverImpl {
private:
@@ -96,14 +96,14 @@ public:
}
}
- void setForwardAddresses(const vector<addr_t>& upstream,
+ void setForwardAddresses(const AddressList& upstream,
DNSService *dnss)
{
upstream_ = upstream;
if (dnss) {
if (!upstream_.empty()) {
dlog("Setting forward addresses:");
- BOOST_FOREACH(const addr_t& address, upstream) {
+ BOOST_FOREACH(const AddressPair& address, upstream) {
dlog(" " + address.first + ":" +
boost::lexical_cast<string>(address.second));
}
@@ -113,14 +113,14 @@ public:
}
}
- void setRootAddresses(const vector<addr_t>& upstream_root,
+ void setRootAddresses(const AddressList& upstream_root,
DNSService *dnss)
{
upstream_root_ = upstream_root;
if (dnss) {
if (!upstream_root_.empty()) {
dlog("Setting root addresses:");
- BOOST_FOREACH(const addr_t& address, upstream_root) {
+ BOOST_FOREACH(const AddressPair& address, upstream_root) {
dlog(" " + address.first + ":" +
boost::lexical_cast<string>(address.second));
}
@@ -144,11 +144,11 @@ public:
/// These members are public because Resolver accesses them directly.
ModuleCCSession* config_session_;
/// Addresses of the root nameserver(s)
- vector<addr_t> upstream_root_;
+ AddressList upstream_root_;
/// Addresses of the forward nameserver
- vector<addr_t> upstream_;
+ AddressList upstream_;
/// Addresses we listen on
- vector<addr_t> listen_;
+ AddressList listen_;
/// Timeout for outgoing queries in milliseconds
int query_timeout_;
@@ -185,8 +185,8 @@ public:
// TODO: REMOVE, USE isc::resolve::MakeErrorMessage?
void
-makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
- const Rcode& rcode)
+makeErrorMessage(MessagePtr message, MessagePtr answer_message,
+ OutputBufferPtr buffer, const Rcode& rcode)
{
// extract the parameters that should be kept.
// XXX: with the current implementation, it's not easy to set EDNS0
@@ -197,6 +197,12 @@ makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
const Opcode& opcode = message->getOpcode();
vector<QuestionPtr> questions;
+ // answer_message is actually ignored right now,
+ // see the comment in #607
+ answer_message->setRcode(rcode);
+ answer_message->setOpcode(opcode);
+ answer_message->setQid(qid);
+
// If this is an error to a query or notify, we should also copy the
// question section.
if (opcode == Opcode::QUERY() || opcode == Opcode::NOTIFY()) {
@@ -385,12 +391,14 @@ Resolver::processMessage(const IOMessage& io_message,
} catch (const DNSProtocolError& error) {
dlog(string("returning ") + error.getRcode().toText() + ": " +
error.what());
- makeErrorMessage(query_message, buffer, error.getRcode());
+ makeErrorMessage(query_message, answer_message,
+ buffer, error.getRcode());
server->resume(true);
return;
} catch (const Exception& ex) {
dlog(string("returning SERVFAIL: ") + ex.what());
- makeErrorMessage(query_message, buffer, Rcode::SERVFAIL());
+ makeErrorMessage(query_message, answer_message,
+ buffer, Rcode::SERVFAIL());
server->resume(true);
return;
} // other exceptions will be handled at a higher layer.
@@ -400,28 +408,34 @@ Resolver::processMessage(const IOMessage& io_message,
// Perform further protocol-level validation.
bool sendAnswer = true;
if (query_message->getOpcode() == Opcode::NOTIFY()) {
- makeErrorMessage(query_message, buffer, Rcode::NOTAUTH());
+ makeErrorMessage(query_message, answer_message,
+ buffer, Rcode::NOTAUTH());
dlog("Notify arrived, but we are not authoritative");
} else if (query_message->getOpcode() != Opcode::QUERY()) {
dlog("Unsupported opcode (got: " + query_message->getOpcode().toText() +
", expected: " + Opcode::QUERY().toText());
- makeErrorMessage(query_message, buffer, Rcode::NOTIMP());
+ makeErrorMessage(query_message, answer_message,
+ buffer, Rcode::NOTIMP());
} else if (query_message->getRRCount(Message::SECTION_QUESTION) != 1) {
dlog("The query contained " +
boost::lexical_cast<string>(query_message->getRRCount(
Message::SECTION_QUESTION) + " questions, exactly one expected"));
- makeErrorMessage(query_message, buffer, Rcode::FORMERR());
+ makeErrorMessage(query_message, answer_message,
+ buffer, Rcode::FORMERR());
} else {
ConstQuestionPtr question = *query_message->beginQuestion();
const RRType &qtype = question->getType();
if (qtype == RRType::AXFR()) {
if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
- makeErrorMessage(query_message, buffer, Rcode::FORMERR());
+ makeErrorMessage(query_message, answer_message,
+ buffer, Rcode::FORMERR());
} else {
- makeErrorMessage(query_message, buffer, Rcode::NOTIMP());
+ makeErrorMessage(query_message, answer_message,
+ buffer, Rcode::NOTIMP());
}
} else if (qtype == RRType::IXFR()) {
- makeErrorMessage(query_message, buffer, Rcode::NOTIMP());
+ makeErrorMessage(query_message, answer_message,
+ buffer, Rcode::NOTIMP());
} else {
// The RecursiveQuery object will post the "resume" event to the
// DNSServer when an answer arrives, so we don't have to do it now.
@@ -453,46 +467,6 @@ ResolverImpl::processNormalQuery(const Question& question,
rec_query_->resolve(question, answer_message, buffer, server);
}
-namespace {
-
-vector<addr_t>
-parseAddresses(ConstElementPtr addresses) {
- vector<addr_t> result;
- if (addresses) {
- if (addresses->getType() == Element::list) {
- for (size_t i(0); i < addresses->size(); ++ i) {
- ConstElementPtr addrPair(addresses->get(i));
- ConstElementPtr addr(addrPair->get("address"));
- ConstElementPtr port(addrPair->get("port"));
- if (!addr || ! port) {
- isc_throw(BadValue, "Address must contain both the IP"
- "address and port");
- }
- try {
- IOAddress(addr->stringValue());
- if (port->intValue() < 0 ||
- port->intValue() > 0xffff) {
- isc_throw(BadValue, "Bad port value (" <<
- port->intValue() << ")");
- }
- result.push_back(addr_t(addr->stringValue(),
- port->intValue()));
- }
- catch (const TypeError &e) { // Better error message
- isc_throw(TypeError,
- "Address must be a string and port an integer");
- }
- }
- } else if (addresses->getType() != Element::null) {
- isc_throw(TypeError,
- "root_addresses, forward_addresses, and listen_on config element must be a list");
- }
- }
- return (result);
-}
-
-}
-
ConstElementPtr
Resolver::updateConfig(ConstElementPtr config) {
dlog("New config comes: " + config->toWire());
@@ -500,11 +474,14 @@ Resolver::updateConfig(ConstElementPtr config) {
try {
// Parse forward_addresses
ConstElementPtr rootAddressesE(config->get("root_addresses"));
- vector<addr_t> rootAddresses(parseAddresses(rootAddressesE));
+ AddressList rootAddresses(parseAddresses(rootAddressesE,
+ "root_addresses"));
ConstElementPtr forwardAddressesE(config->get("forward_addresses"));
- vector<addr_t> forwardAddresses(parseAddresses(forwardAddressesE));
+ AddressList forwardAddresses(parseAddresses(forwardAddressesE,
+ "forward_addresses"));
ConstElementPtr listenAddressesE(config->get("listen_on"));
- vector<addr_t> listenAddresses(parseAddresses(listenAddressesE));
+ AddressList listenAddresses(parseAddresses(listenAddressesE,
+ "listen_on"));
bool set_timeouts(false);
int qtimeout = impl_->query_timeout_;
int ctimeout = impl_->client_timeout_;
@@ -577,13 +554,13 @@ Resolver::updateConfig(ConstElementPtr config) {
}
void
-Resolver::setForwardAddresses(const vector<addr_t>& addresses)
+Resolver::setForwardAddresses(const AddressList& addresses)
{
impl_->setForwardAddresses(addresses, dnss_);
}
void
-Resolver::setRootAddresses(const vector<addr_t>& addresses)
+Resolver::setRootAddresses(const AddressList& addresses)
{
impl_->setRootAddresses(addresses, dnss_);
}
@@ -593,58 +570,19 @@ Resolver::isForwarding() const {
return (!impl_->upstream_.empty());
}
-vector<addr_t>
+AddressList
Resolver::getForwardAddresses() const {
return (impl_->upstream_);
}
-vector<addr_t>
+AddressList
Resolver::getRootAddresses() const {
return (impl_->upstream_root_);
}
-namespace {
-
void
-setAddresses(DNSService *service, const vector<addr_t>& addresses) {
- service->clearServers();
- BOOST_FOREACH(const addr_t &address, addresses) {
- service->addServer(address.second, address.first);
- }
-}
-
-}
-
-void
-Resolver::setListenAddresses(const vector<addr_t>& addresses) {
- try {
- dlog("Setting listen addresses:");
- BOOST_FOREACH(const addr_t& addr, addresses) {
- dlog(" " + addr.first + ":" +
- boost::lexical_cast<string>(addr.second));
- }
- setAddresses(dnss_, addresses);
- impl_->listen_ = addresses;
- }
- catch (const exception& e) {
- /*
- * We couldn't set it. So return it back. If that fails as well,
- * we have a problem.
- *
- * If that fails, bad luck, but we are useless anyway, so just die
- * and let boss start us again.
- */
- dlog(string("Unable to set new address: ") + e.what(),true);
- try {
- setAddresses(dnss_, impl_->listen_);
- }
- catch (const exception& e2) {
- dlog(string("Unable to recover from error;"),true);
- dlog(string("Rollback failed with: ") + e2.what(),true);
- abort();
- }
- throw e; // Let it fly a little bit further
- }
+Resolver::setListenAddresses(const AddressList& addresses) {
+ installListenAddresses(addresses, impl_->listen_, *dnss_);
}
void
@@ -680,7 +618,7 @@ Resolver::getRetries() const {
return impl_->retries_;
}
-vector<addr_t>
+AddressList
Resolver::getListenAddresses() const {
return (impl_->listen_);
}
diff --git a/src/bin/resolver/resolver.spec.pre.in b/src/bin/resolver/resolver.spec.pre.in
index 48e1eb6..bc598b0 100644
--- a/src/bin/resolver/resolver.spec.pre.in
+++ b/src/bin/resolver/resolver.spec.pre.in
@@ -6,48 +6,48 @@
{
"item_name": "timeout_query",
"item_type": "integer",
- "item_optional": False,
+ "item_optional": false,
"item_default": 2000
},
{
"item_name": "timeout_client",
"item_type": "integer",
- "item_optional": False,
+ "item_optional": false,
"item_default": 4000
},
{
"item_name": "timeout_lookup",
"item_type": "integer",
- "item_optional": False,
+ "item_optional": false,
"item_default": 30000
},
{
"item_name": "retries",
"item_type": "integer",
- "item_optional": False,
+ "item_optional": false,
"item_default": 3
},
{
"item_name": "forward_addresses",
"item_type": "list",
- "item_optional": True,
+ "item_optional": true,
"item_default": [],
"list_item_spec" : {
"item_name": "address",
"item_type": "map",
- "item_optional": False,
+ "item_optional": false,
"item_default": {},
"map_item_spec": [
{
"item_name": "address",
"item_type": "string",
- "item_optional": False,
+ "item_optional": false,
"item_default": "::1"
},
{
"item_name": "port",
"item_type": "integer",
- "item_optional": False,
+ "item_optional": false,
"item_default": 53
}
]
@@ -56,24 +56,24 @@
{
"item_name": "root_addresses",
"item_type": "list",
- "item_optional": True,
+ "item_optional": true,
"item_default": [],
"list_item_spec" : {
"item_name": "address",
"item_type": "map",
- "item_optional": False,
+ "item_optional": false,
"item_default": {},
"map_item_spec": [
{
"item_name": "address",
"item_type": "string",
- "item_optional": False,
+ "item_optional": false,
"item_default": "::1"
},
{
"item_name": "port",
"item_type": "integer",
- "item_optional": False,
+ "item_optional": false,
"item_default": 53
}
]
@@ -82,7 +82,7 @@
{
"item_name": "listen_on",
"item_type": "list",
- "item_optional": False,
+ "item_optional": false,
"item_default": [
{
"address": "::1",
@@ -91,24 +91,24 @@
{
"address": "127.0.0.1",
"port": 5300
- },
+ }
],
"list_item_spec": {
"item_name": "address",
"item_type": "map",
- "item_optional": False,
+ "item_optional": false,
"item_default": {},
"map_item_spec": [
{
"item_name": "address",
"item_type": "string",
- "item_optional": False,
+ "item_optional": false,
"item_default": "::1"
},
{
"item_name": "port",
"item_type": "integer",
- "item_optional": False,
+ "item_optional": false,
"item_default": 5300
}
]
diff --git a/src/bin/resolver/tests/Makefile.am b/src/bin/resolver/tests/Makefile.am
index 3dc6b3b..eb7e3e1 100644
--- a/src/bin/resolver/tests/Makefile.am
+++ b/src/bin/resolver/tests/Makefile.am
@@ -37,6 +37,7 @@ run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la
run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
diff --git a/src/bin/resolver/tests/resolver_config_unittest.cc b/src/bin/resolver/tests/resolver_config_unittest.cc
index 916396a..1d6415b 100644
--- a/src/bin/resolver/tests/resolver_config_unittest.cc
+++ b/src/bin/resolver/tests/resolver_config_unittest.cc
@@ -24,6 +24,7 @@
#include <dns/tests/unittest_util.h>
#include <testutils/srv_test.h>
+#include <testutils/portconfig.h>
using namespace std;
using namespace isc::data;
@@ -42,7 +43,7 @@ class ResolverConfig : public ::testing::Test {
{
server.setDNSService(dnss);
}
- void invalidTest(const string &JOSN);
+ void invalidTest(const string &JSON, const string& name);
};
TEST_F(ResolverConfig, forwardAddresses) {
@@ -122,117 +123,48 @@ TEST_F(ResolverConfig, rootAddressConfig) {
}
void
-ResolverConfig::invalidTest(const string &JOSN) {
- ElementPtr config(Element::fromJSON(JOSN));
- EXPECT_FALSE(server.updateConfig(config)->equals(
- *isc::config::createAnswer())) << "Accepted config " << JOSN << endl;
+ResolverConfig::invalidTest(const string &JSON, const string& name) {
+ isc::testutils::portconfig::configRejected(server, JSON, name);
}
TEST_F(ResolverConfig, invalidForwardAddresses) {
// Try torturing it with some invalid inputs
invalidTest("{"
"\"forward_addresses\": \"error\""
- "}");
+ "}", "Invalid type");
invalidTest("{"
"\"forward_addresses\": [{}]"
- "}");
+ "}", "Empty element");
invalidTest("{"
"\"forward_addresses\": [{"
" \"port\": 1.5,"
" \"address\": \"192.0.2.1\""
- "}]}");
+ "}]}", "Float port");
invalidTest("{"
"\"forward_addresses\": [{"
" \"port\": -5,"
" \"address\": \"192.0.2.1\""
- "}]}");
+ "}]}", "Negative port");
invalidTest("{"
"\"forward_addresses\": [{"
" \"port\": 53,"
" \"address\": \"bad_address\""
- "}]}");
+ "}]}", "Bad address");
}
+// Try setting the addresses directly
TEST_F(ResolverConfig, listenAddresses) {
- // Default value should be fully recursive
- EXPECT_TRUE(server.getListenAddresses().empty());
-
- // Try putting there some addresses
- vector<pair<string, uint16_t> > addresses;
- addresses.push_back(pair<string, uint16_t>("127.0.0.1", 5321));
- addresses.push_back(pair<string, uint16_t>("::1", 5321));
- server.setListenAddresses(addresses);
- EXPECT_EQ(2, server.getListenAddresses().size());
- EXPECT_EQ("::1", server.getListenAddresses()[1].first);
-
- // Is it independent from what we do with the vector later?
- addresses.clear();
- EXPECT_EQ(2, server.getListenAddresses().size());
-
- // Did it return to fully recursive?
- server.setListenAddresses(addresses);
- EXPECT_TRUE(server.getListenAddresses().empty());
+ isc::testutils::portconfig::listenAddresses(server);
}
-TEST_F(ResolverConfig, DISABLED_listenAddressConfig) {
- // Try putting there some address
- ElementPtr config(Element::fromJSON("{"
- "\"listen_on\": ["
- " {"
- " \"address\": \"127.0.0.1\","
- " \"port\": 5321"
- " }"
- "]"
- "}"));
- ConstElementPtr result(server.updateConfig(config));
- EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
- ASSERT_EQ(1, server.getListenAddresses().size());
- EXPECT_EQ("127.0.0.1", server.getListenAddresses()[0].first);
- EXPECT_EQ(5321, server.getListenAddresses()[0].second);
-
- // As this is example address, the machine should not have it on
- // any interface
- // FIXME: This test aborts, because it tries to rollback and
- // it is impossible, since the sockets are not closed.
- // Once #388 is solved, enable this test.
- config = Element::fromJSON("{"
- "\"listen_on\": ["
- " {"
- " \"address\": \"192.0.2.0\","
- " \"port\": 5321"
- " }"
- "]"
- "}");
- result = server.updateConfig(config);
- EXPECT_FALSE(result->equals(*isc::config::createAnswer()));
- ASSERT_EQ(1, server.getListenAddresses().size());
- EXPECT_EQ("127.0.0.1", server.getListenAddresses()[0].first);
- EXPECT_EQ(5321, server.getListenAddresses()[0].second);
+// Try setting some addresses and a rollback
+TEST_F(ResolverConfig, listenAddressConfig) {
+ isc::testutils::portconfig::listenAddressConfig(server);
}
+// Try some invalid configs are rejected
TEST_F(ResolverConfig, invalidListenAddresses) {
- // Try torturing it with some invalid inputs
- invalidTest("{"
- "\"listen_on\": \"error\""
- "}");
- invalidTest("{"
- "\"listen_on\": [{}]"
- "}");
- invalidTest("{"
- "\"listen_on\": [{"
- " \"port\": 1.5,"
- " \"address\": \"192.0.2.1\""
- "}]}");
- invalidTest("{"
- "\"listen_on\": [{"
- " \"port\": -5,"
- " \"address\": \"192.0.2.1\""
- "}]}");
- invalidTest("{"
- "\"listen_on\": [{"
- " \"port\": 53,"
- " \"address\": \"bad_address\""
- "}]}");
+ isc::testutils::portconfig::invalidListenAddressConfig(server);
}
// Just test it sets and gets the values correctly
@@ -267,28 +199,28 @@ TEST_F(ResolverConfig, timeoutsConfig) {
TEST_F(ResolverConfig, invalidTimeoutsConfig) {
invalidTest("{"
"\"timeout_query\": \"error\""
- "}");
+ "}", "Wrong query element type");
invalidTest("{"
"\"timeout_query\": -2"
- "}");
+ "}", "Negative query timeout");
invalidTest("{"
"\"timeout_client\": \"error\""
- "}");
+ "}", "Wrong client element type");
invalidTest("{"
"\"timeout_client\": -2"
- "}");
+ "}", "Negative client timeout");
invalidTest("{"
"\"timeout_lookup\": \"error\""
- "}");
+ "}", "Wrong lookup element type");
invalidTest("{"
"\"timeout_lookup\": -2"
- "}");
+ "}", "Negative lookup timeout");
invalidTest("{"
"\"retries\": \"error\""
- "}");
+ "}", "Wrong retries element type");
invalidTest("{"
"\"retries\": -1"
- "}");
+ "}", "Negative number of retries");
}
}
diff --git a/src/bin/resolver/tests/resolver_unittest.cc b/src/bin/resolver/tests/resolver_unittest.cc
index a4f11f5..97edf12 100644
--- a/src/bin/resolver/tests/resolver_unittest.cc
+++ b/src/bin/resolver/tests/resolver_unittest.cc
@@ -96,6 +96,27 @@ TEST_F(ResolverTest, AXFRFail) {
QR_FLAG, 1, 0, 0, 0);
}
+TEST_F(ResolverTest, IXFRFail) {
+ UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
+ Name("example.com"), RRClass::IN(),
+ RRType::IXFR());
+ createRequestPacket(request_message, IPPROTO_TCP);
+ // IXFR is not implemented and should always send NOTIMP.
+ server.processMessage(*io_message,
+ parse_message,
+ response_message,
+ response_obuffer,
+ &dnsserv);
+ EXPECT_TRUE(dnsserv.hasAnswer());
+ // the second check is what we'll need in the end (with the values
+ // from the first one), but right now the first one is for what
+ // will actually be returned to the client
+ headerCheck(*parse_message, default_qid, Rcode::NOTIMP(), opcode.getCode(),
+ QR_FLAG, 1, 0, 0, 0);
+ headerCheck(*response_message, default_qid, Rcode::NOTIMP(), opcode.getCode(),
+ 0, 0, 0, 0, 0);
+}
+
TEST_F(ResolverTest, notifyFail) {
// Notify should always return NOTAUTH
request_message.clear(Message::RENDER);
diff --git a/src/bin/stats/Makefile.am b/src/bin/stats/Makefile.am
index b267479..b173813 100644
--- a/src/bin/stats/Makefile.am
+++ b/src/bin/stats/Makefile.am
@@ -5,7 +5,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
pkglibexec_SCRIPTS = b10-stats
noinst_SCRIPTS = b10-stats_stub
-b10_statsdir = $(DESTDIR)$(pkgdatadir)
+b10_statsdir = $(pkgdatadir)
b10_stats_DATA = stats.spec
CLEANFILES = stats.spec b10-stats stats.pyc stats.pyo b10-stats_stub stats_stub.pyc stats_stub.pyo
@@ -23,7 +23,6 @@ endif
stats.spec: stats.spec.pre
$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" stats.spec.pre >$@
-# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
b10-stats: stats.py
$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
diff --git a/src/bin/usermgr/Makefile.am b/src/bin/usermgr/Makefile.am
index f830aad..7ebb1cd 100644
--- a/src/bin/usermgr/Makefile.am
+++ b/src/bin/usermgr/Makefile.am
@@ -1,6 +1,6 @@
sbin_SCRIPTS = b10-cmdctl-usermgr
-b10_cmdctl_usermgrdir = $(DESTDIR)$(pkgdatadir)
+b10_cmdctl_usermgrdir = $(pkgdatadir)
CLEANFILES= b10-cmdctl-usermgr
@@ -14,7 +14,6 @@ b10-cmdctl-usermgr.8: b10-cmdctl-usermgr.xml
endif
-# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
b10-cmdctl-usermgr: b10-cmdctl-usermgr.py
$(SED) "s|@@PYTHONPATH@@|@pyexecdir@|" b10-cmdctl-usermgr.py >$@
diff --git a/src/bin/xfrin/Makefile.am b/src/bin/xfrin/Makefile.am
index 7ed41e2..ee8505e 100644
--- a/src/bin/xfrin/Makefile.am
+++ b/src/bin/xfrin/Makefile.am
@@ -4,7 +4,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
pkglibexec_SCRIPTS = b10-xfrin
-b10_xfrindir = $(DESTDIR)$(pkgdatadir)
+b10_xfrindir = $(pkgdatadir)
b10_xfrin_DATA = xfrin.spec
CLEANFILES = b10-xfrin xfrin.pyc
@@ -20,7 +20,6 @@ b10-xfrin.8: b10-xfrin.xml
endif
-# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
b10-xfrin: xfrin.py
$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
diff --git a/src/bin/xfrout/Makefile.am b/src/bin/xfrout/Makefile.am
index 4955b7a..d4f021e 100644
--- a/src/bin/xfrout/Makefile.am
+++ b/src/bin/xfrout/Makefile.am
@@ -4,7 +4,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
pkglibexec_SCRIPTS = b10-xfrout
-b10_xfroutdir = $(DESTDIR)$(pkgdatadir)
+b10_xfroutdir = $(pkgdatadir)
b10_xfrout_DATA = xfrout.spec
CLEANFILES= b10-xfrout xfrout.pyc xfrout.spec
@@ -23,7 +23,6 @@ endif
xfrout.spec: xfrout.spec.pre
$(SED) -e "s|@@LOCALSTATEDIR@@|$(localstatedir)|" xfrout.spec.pre >$@
-# TODO: does this need $$(DESTDIR) also?
# this is done here since configure.ac AC_OUTPUT doesn't expand exec_prefix
b10-xfrout: xfrout.py
$(SED) -e "s|@@PYTHONPATH@@|@pyexecdir@|" \
diff --git a/src/bin/xfrout/tests/xfrout_test.py b/src/bin/xfrout/tests/xfrout_test.py
index 55a2e52..5aec072 100644
--- a/src/bin/xfrout/tests/xfrout_test.py
+++ b/src/bin/xfrout/tests/xfrout_test.py
@@ -85,23 +85,12 @@ class TestXfroutSession(unittest.TestCase):
return msg
def setUp(self):
- request = MySocket(socket.AF_INET,socket.SOCK_STREAM)
+ self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
self.log = isc.log.NSLogger('xfrout', '', severity = 'critical', log_to_console = False )
- (self.write_sock, self.read_sock) = socket.socketpair()
- self.xfrsess = MyXfroutSession(request, None, None, self.log, self.read_sock)
- self.xfrsess.server = Dbserver()
+ self.xfrsess = MyXfroutSession(self.sock, None, Dbserver(), self.log)
self.mdata = bytes(b'\xd6=\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\xfc\x00\x01')
- self.sock = MySocket(socket.AF_INET,socket.SOCK_STREAM)
self.soa_record = (4, 3, 'example.com.', 'com.example.', 3600, 'SOA', None, 'master.example.com. admin.example.com. 1234 3600 1800 2419200 7200')
- def test_receive_query_message(self):
- send_msg = b"\xd6=\x00\x00\x00\x01\x00"
- msg_len = struct.pack('H', socket.htons(len(send_msg)))
- self.write_sock.send(msg_len)
- self.write_sock.send(send_msg)
- recv_msg = self.xfrsess._receive_query_message(self.read_sock)
- self.assertEqual(recv_msg, send_msg)
-
def test_parse_query_message(self):
[get_rcode, get_msg] = self.xfrsess._parse_query_message(self.mdata)
self.assertEqual(get_rcode.to_text(), "NOERROR")
@@ -157,7 +146,6 @@ class TestXfroutSession(unittest.TestCase):
self.assertTrue(msg.get_header_flag(Message.HEADERFLAG_AA))
def test_reply_query_with_format_error(self):
-
msg = self.getmsg()
self.xfrsess._reply_query_with_format_error(msg, self.sock)
get_msg = self.sock.read_msg()
@@ -272,11 +260,11 @@ class TestXfroutSession(unittest.TestCase):
self.xfrsess._zone_has_soa = zone_empty
def false_func():
return False
- self.xfrsess.server.increase_transfers_counter = false_func
+ self.xfrsess._server.increase_transfers_counter = false_func
self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "REFUSED")
def true_func():
return True
- self.xfrsess.server.increase_transfers_counter = true_func
+ self.xfrsess._server.increase_transfers_counter = true_func
self.assertEqual(self.xfrsess._check_xfrout_available(True).to_text(), "NOERROR")
def test_dns_xfrout_start_formerror(self):
@@ -346,8 +334,17 @@ class MyUnixSockServer(UnixSockServer):
class TestUnixSockServer(unittest.TestCase):
def setUp(self):
+ self.write_sock, self.read_sock = socket.socketpair()
self.unix = MyUnixSockServer()
+ def test_receive_query_message(self):
+ send_msg = b"\xd6=\x00\x00\x00\x01\x00"
+ msg_len = struct.pack('H', socket.htons(len(send_msg)))
+ self.write_sock.send(msg_len)
+ self.write_sock.send(send_msg)
+ recv_msg = self.unix._receive_query_message(self.read_sock)
+ self.assertEqual(recv_msg, send_msg)
+
def test_updata_config_data(self):
self.unix.update_config_data({'transfers_out':10 })
self.assertEqual(self.unix._max_transfers_out, 10)
diff --git a/src/bin/xfrout/xfrout.py.in b/src/bin/xfrout/xfrout.py.in
index a819640..fd1288d 100755
--- a/src/bin/xfrout/xfrout.py.in
+++ b/src/bin/xfrout/xfrout.py.in
@@ -73,75 +73,25 @@ def get_rrset_len(rrset):
return len(bytes)
-class XfroutSession(BaseRequestHandler):
- def __init__(self, request, client_address, server, log, sock):
+class XfroutSession():
+ def __init__(self, sock_fd, request_data, server, log):
# The initializer for the superclass may call functions
# that need _log to be set, so we set it first
+ self._sock_fd = sock_fd
+ self._request_data = request_data
+ self._server = server
self._log = log
- self._shutdown_sock = sock
- BaseRequestHandler.__init__(self, request, client_address, server)
+ self.handle()
def handle(self):
- '''Handle a request until shutdown or xfrout client is closed.'''
- # check self.server._shutdown_event to ensure the real shutdown comes.
- # Linux could trigger a spurious readable event on the _shutdown_sock
- # due to a bug, so we need perform a double check.
- while not self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
- try:
- (rlist, wlist, xlist) = select.select([self._shutdown_sock, self.request], [], [])
- except select.error as e:
- if e.args[0] == errno.EINTR:
- (rlist, wlist, xlist) = ([], [], [])
- continue
- else:
- self._log.log_message("error", "Error with select(): %s" %e)
- break
- # self.server._shutdown_evnet will be set by now, if it is not a false
- # alarm
- if self._shutdown_sock in rlist:
- continue
-
- sock_fd = recv_fd(self.request.fileno())
-
- if sock_fd < 0:
- # This may happen when one xfrout process try to connect to
- # xfrout unix socket server, to check whether there is another
- # xfrout running.
- if sock_fd == XFR_FD_RECEIVE_FAIL:
- self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
- break
-
- # receive query msg
- msgdata = self._receive_query_message(self.request)
- if not msgdata:
- break
-
- try:
- self.dns_xfrout_start(sock_fd, msgdata)
- #TODO, avoid catching all exceptions
- except Exception as e:
- self._log.log_message("error", str(e))
-
- os.close(sock_fd)
-
- def _receive_query_message(self, sock):
- ''' receive query message from sock'''
- # receive data length
- data_len = sock.recv(2)
- if not data_len:
- return None
- msg_len = struct.unpack('!H', data_len)[0]
- # receive data
- recv_size = 0
- msgdata = b''
- while recv_size < msg_len:
- data = sock.recv(msg_len - recv_size)
- if not data:
- return None
- recv_size += len(data)
- msgdata += data
+ ''' Handle a xfrout query, send xfrout response '''
+ try:
+ self.dns_xfrout_start(self._sock_fd, self._request_data)
+ #TODO, avoid catching all exceptions
+ except Exception as e:
+ self._log.log_message("error", str(e))
- return msgdata
+ os.close(self._sock_fd)
def _parse_query_message(self, mdata):
''' parse query message to [socket,message]'''
@@ -195,7 +145,6 @@ class XfroutSession(BaseRequestHandler):
msg.set_rcode(Rcode.FORMERR())
self._send_message(sock_fd, msg)
-
def _zone_has_soa(self, zone):
'''Judge if the zone has an SOA record.'''
# In some sense, the SOA defines a zone.
@@ -203,7 +152,7 @@ class XfroutSession(BaseRequestHandler):
# specific zone, we need to judge if the zone has an SOA record;
# if not, we consider the zone has incomplete data, so xfrout can't
# serve for it.
- if sqlite3_ds.get_zone_soa(zone, self.server.get_db_file()):
+ if sqlite3_ds.get_zone_soa(zone, self._server.get_db_file()):
return True
return False
@@ -215,7 +164,7 @@ class XfroutSession(BaseRequestHandler):
# authority for the specific zone.
# TODO: should get zone's configuration from cfgmgr or other place
# in future.
- return sqlite3_ds.zone_exist(zonename, self.server.get_db_file())
+ return sqlite3_ds.zone_exist(zonename, self._server.get_db_file())
def _check_xfrout_available(self, zone_name):
'''Check if xfr request can be responsed.
@@ -234,7 +183,7 @@ class XfroutSession(BaseRequestHandler):
return Rcode.SERVFAIL()
#TODO, check allow_transfer
- if not self.server.increase_transfers_counter():
+ if not self._server.increase_transfers_counter():
return Rcode.REFUSED()
return Rcode.NOERROR()
@@ -260,7 +209,7 @@ class XfroutSession(BaseRequestHandler):
except Exception as err:
self._log.log_message("error", str(err))
- self.server.decrease_transfers_counter()
+ self._server.decrease_transfers_counter()
return
@@ -307,14 +256,14 @@ class XfroutSession(BaseRequestHandler):
#TODO, there should be a better way to insert rrset.
msg.make_response()
msg.set_header_flag(Message.HEADERFLAG_AA)
- soa_record = sqlite3_ds.get_zone_soa(zone_name, self.server.get_db_file())
+ soa_record = sqlite3_ds.get_zone_soa(zone_name, self._server.get_db_file())
rrset_soa = self._create_rrset_from_db_record(soa_record)
msg.add_rrset(Message.SECTION_ANSWER, rrset_soa)
message_upper_len = get_rrset_len(rrset_soa)
- for rr_data in sqlite3_ds.get_zone_datas(zone_name, self.server.get_db_file()):
- if self.server._shutdown_event.is_set(): # Check if xfrout is shutdown
+ for rr_data in sqlite3_ds.get_zone_datas(zone_name, self._server.get_db_file()):
+ if self._server._shutdown_event.is_set(): # Check if xfrout is shutdown
self._log.log_message("info", "xfrout process is being shutdown")
return
@@ -356,9 +305,93 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer):
self.update_config_data(config_data)
self._cc = cc
- def finish_request(self, request, client_address):
+ def _receive_query_message(self, sock):
+ ''' receive request message from sock'''
+ # receive data length
+ data_len = sock.recv(2)
+ if not data_len:
+ return None
+ msg_len = struct.unpack('!H', data_len)[0]
+ # receive data
+ recv_size = 0
+ msgdata = b''
+ while recv_size < msg_len:
+ data = sock.recv(msg_len - recv_size)
+ if not data:
+ return None
+ recv_size += len(data)
+ msgdata += data
+
+ return msgdata
+
+ def handle_request(self):
+ ''' Enable server handle a request until shutdown or auth is closed.'''
+ try:
+ request, client_address = self.get_request()
+ except socket.error:
+ self._log.log_message("error", "Failed to fetch request")
+ return
+
+ # Check self._shutdown_event to ensure the real shutdown comes.
+ # Linux could trigger a spurious readable event on the _read_sock
+ # due to a bug, so we need perform a double check.
+ while not self._shutdown_event.is_set(): # Check if xfrout is shutdown
+ try:
+ (rlist, wlist, xlist) = select.select([self._read_sock, request], [], [])
+ except select.error as e:
+ if e.args[0] == errno.EINTR:
+ (rlist, wlist, xlist) = ([], [], [])
+ continue
+ else:
+ self._log.log_message("error", "Error with select(): %s" %e)
+ break
+
+ # self.server._shutdown_event will be set by now, if it is not a false
+ # alarm
+ if self._read_sock in rlist:
+ continue
+
+ try:
+ self.process_request(request)
+ except:
+ self._log.log_message("error", "Exception happened during processing of %s"
+ % str(client_address))
+ break
+
+ def _handle_request_noblock(self):
+ """Override the function _handle_request_noblock(), it creates a new
+ thread to handle requests for each auth"""
+ td = threading.Thread(target=self.handle_request)
+ td.setDaemon(True)
+ td.start()
+
+ def process_request(self, request):
+ """Receive socket fd and query message from auth, then
+ start a new thread to process the request."""
+ sock_fd = recv_fd(request.fileno())
+ if sock_fd < 0:
+ # This may happen when one xfrout process try to connect to
+ # xfrout unix socket server, to check whether there is another
+ # xfrout running.
+ if sock_fd == XFR_FD_RECEIVE_FAIL:
+ self._log.log_message("error", "Failed to receive the file descriptor for XFR connection")
+ return
+
+ # receive request msg
+ request_data = self._receive_query_message(request)
+ if not request_data:
+ return
+
+ t = threading.Thread(target = self.finish_request,
+ args = (sock_fd, request_data))
+ if self.daemon_threads:
+ t.daemon = True
+ t.start()
+
+
+ def finish_request(self, sock_fd, request_data):
'''Finish one request by instantiating RequestHandlerClass.'''
- self.RequestHandlerClass(request, client_address, self, self._log, self._read_sock)
+ self.RequestHandlerClass(sock_fd, request_data, self, self._log)
def _remove_unused_sock_file(self, sock_file):
'''Try to remove the socket file. If the file is being used
@@ -376,7 +409,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer):
try:
os.unlink(sock_file)
except OSError as err:
- self._log.log_message("error", '[b10-xfrout] Fail to remove file %s: %s\n' % (sock_file, err))
+ self._log.log_message("error", "[b10-xfrout] Fail to remove file %s: %s\n" % (sock_file, err))
sys.exit(0)
def _sock_file_in_use(self, sock_file):
@@ -397,7 +430,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn, ThreadingUnixStreamServer):
try:
os.unlink(self._sock_file)
except Exception as e:
- self._log.log_message("error", str(e))
+ self._log.log_message('error', str(e))
def update_config_data(self, new_config):
'''Apply the new config setting of xfrout module. '''
diff --git a/src/bin/zonemgr/Makefile.am b/src/bin/zonemgr/Makefile.am
index dd3e67a..410279a 100644
--- a/src/bin/zonemgr/Makefile.am
+++ b/src/bin/zonemgr/Makefile.am
@@ -4,7 +4,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
pkglibexec_SCRIPTS = b10-zonemgr
-b10_zonemgrdir = $(DESTDIR)$(pkgdatadir)
+b10_zonemgrdir = $(pkgdatadir)
b10_zonemgr_DATA = zonemgr.spec
CLEANFILES = b10-zonemgr zonemgr.pyc zonemgr.spec
diff --git a/src/cppcheck-suppress.lst b/src/cppcheck-suppress.lst
new file mode 100644
index 0000000..3e4dcd6
--- /dev/null
+++ b/src/cppcheck-suppress.lst
@@ -0,0 +1,15 @@
+// On some systems cppcheck produces false alarms about 'missing includes'.
+// the following two will suppress, depending on the cppcheck version
+debug
+missingInclude
+// This is a template, and should be excluded from the check
+unreadVariable:src/lib/dns/rdata/template.cc:59
+// These three trigger warnings due to the incomplete implementation. This is
+// our problem, but we need to suppress the warnings for now.
+functionConst:src/lib/cache/resolver_cache.h
+functionConst:src/lib/cache/message_cache.h
+functionConst:src/lib/cache/rrset_cache.h
+// Intentional self assignment tests. Suppress warning about them.
+selfAssignment:src/lib/dns/tests/name_unittest.cc:292
+selfAssignment:src/lib/dns/tests/rdata_unittest.cc:227
+selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:104
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index d5486a0..27d9b8b 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,2 +1,2 @@
SUBDIRS = exceptions dns cc config datasrc python xfr bench log \
- resolve nsas cache asiolink testutils
+ resolve nsas cache asiolink testutils server_common
diff --git a/src/lib/asiolink/dns_server.h b/src/lib/asiolink/dns_server.h
index 6545275..352ea8e 100644
--- a/src/lib/asiolink/dns_server.h
+++ b/src/lib/asiolink/dns_server.h
@@ -75,6 +75,9 @@ public:
(*self_)(ec, length);
}
+ /// \brief Stop current running server
+ virtual void stop() { self_->stop();}
+
/// \brief Resume processing of the server coroutine after an
/// asynchronous call (e.g., to the DNS Lookup provider) has completed.
///
diff --git a/src/lib/asiolink/dns_service.cc b/src/lib/asiolink/dns_service.cc
index e9688c7..f17bb44 100644
--- a/src/lib/asiolink/dns_service.cc
+++ b/src/lib/asiolink/dns_service.cc
@@ -29,6 +29,11 @@
#include <asiolink/tcp_server.h>
#include <asiolink/udp_server.h>
+#include <log/dummylog.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+
using isc::log::dlog;
namespace asiolink {
@@ -184,8 +189,9 @@ DNSService::addServer(uint16_t port, const std::string& address) {
void
DNSService::clearServers() {
- // FIXME: This does not work, it does not close the socket.
- // How is it done?
+ BOOST_FOREACH(const DNSServiceImpl::DNSServerPtr& s, impl_->servers_) {
+ s->stop();
+ }
impl_->servers_.clear();
}
diff --git a/src/lib/asiolink/tcp_server.cc b/src/lib/asiolink/tcp_server.cc
index 414cdc7..df19b00 100644
--- a/src/lib/asiolink/tcp_server.cc
+++ b/src/lib/asiolink/tcp_server.cc
@@ -46,7 +46,7 @@ TCPServer::TCPServer(io_service& io_service,
const SimpleCallback* checkin,
const DNSLookup* lookup,
const DNSAnswer* answer) :
- io_(io_service), done_(false),
+ io_(io_service), done_(false), stopped_by_hand_(false),
checkin_callback_(checkin), lookup_callback_(lookup),
answer_callback_(answer)
{
@@ -65,9 +65,16 @@ TCPServer::TCPServer(io_service& io_service,
void
TCPServer::operator()(error_code ec, size_t length) {
- /// Because the coroutine reeentry block is implemented as
+ /// Because the coroutine reentry block is implemented as
/// a switch statement, inline variable declarations are not
/// permitted. Certain variables used below can be declared here.
+
+ /// If user has stopped the server, we won't enter the
+ /// coroutine body, just return
+ if (stopped_by_hand_) {
+ return;
+ }
+
boost::array<const_buffer,2> bufs;
OutputBuffer lenbuf(TCP_MESSAGE_LENGTHSIZE);
@@ -103,7 +110,7 @@ TCPServer::operator()(error_code ec, size_t length) {
/// Now read the message itself. (This is done in a different scope
/// to allow inline variable declarations.)
CORO_YIELD {
- InputBuffer dnsbuffer((const void *) data_.get(), length);
+ InputBuffer dnsbuffer(data_.get(), length);
uint16_t msglen = dnsbuffer.readUint16();
async_read(*socket_, asio::buffer(data_.get(), msglen), *this);
}
@@ -188,6 +195,16 @@ TCPServer::asyncLookup() {
answer_message_, respbuf_, this);
}
+void TCPServer::stop() {
+ // server should not be stopped twice
+ if (stopped_by_hand_) {
+ return;
+ }
+
+ stopped_by_hand_ = true;
+ acceptor_->close();
+ socket_->close();
+}
/// Post this coroutine on the ASIO service queue so that it will
/// resume processing where it left off. The 'done' parameter indicates
/// whether there is an answer to return to the client.
diff --git a/src/lib/asiolink/tcp_server.h b/src/lib/asiolink/tcp_server.h
index 9b985ce..9df335d 100644
--- a/src/lib/asiolink/tcp_server.h
+++ b/src/lib/asiolink/tcp_server.h
@@ -43,6 +43,7 @@ public:
void operator()(asio::error_code ec = asio::error_code(),
size_t length = 0);
void asyncLookup();
+ void stop();
void resume(const bool done);
bool hasAnswer() { return (done_); }
int value() { return (get_value()); }
@@ -106,6 +107,9 @@ private:
size_t bytes_;
bool done_;
+ // whether user has stopped the server
+ bool stopped_by_hand_;
+
// Callback functions provided by the caller
const SimpleCallback* checkin_callback_;
const DNSLookup* lookup_callback_;
diff --git a/src/lib/asiolink/tests/interval_timer_unittest.cc b/src/lib/asiolink/tests/interval_timer_unittest.cc
index a6793bf..7e0e7bc 100644
--- a/src/lib/asiolink/tests/interval_timer_unittest.cc
+++ b/src/lib/asiolink/tests/interval_timer_unittest.cc
@@ -33,7 +33,9 @@ using namespace asiolink;
// or not.
class IntervalTimerTest : public ::testing::Test {
protected:
- IntervalTimerTest() : io_service_() {}
+ IntervalTimerTest() :
+ io_service_(), timer_called_(false), timer_cancel_success_(false)
+ {}
~IntervalTimerTest() {}
class TimerCallBack : public std::unary_function<void, void> {
public:
@@ -64,7 +66,8 @@ protected:
TimerCallBackCancelDeleter(IntervalTimerTest* test_obj,
IntervalTimer* timer,
TimerCallBackCounter& counter)
- : test_obj_(test_obj), timer_(timer), counter_(counter), count_(0)
+ : test_obj_(test_obj), timer_(timer), counter_(counter), count_(0),
+ prev_counter_(-1)
{}
void operator()() {
++count_;
diff --git a/src/lib/asiolink/tests/io_endpoint_unittest.cc b/src/lib/asiolink/tests/io_endpoint_unittest.cc
index 534850a..6101473 100644
--- a/src/lib/asiolink/tests/io_endpoint_unittest.cc
+++ b/src/lib/asiolink/tests/io_endpoint_unittest.cc
@@ -22,9 +22,9 @@ using namespace asiolink;
TEST(IOEndpointTest, createUDPv4) {
const IOEndpoint* ep;
- ep = IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5300);
+ ep = IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 53210);
EXPECT_EQ("192.0.2.1", ep->getAddress().toText());
- EXPECT_EQ(5300, ep->getPort());
+ EXPECT_EQ(53210, ep->getPort());
EXPECT_EQ(AF_INET, ep->getFamily());
EXPECT_EQ(AF_INET, ep->getAddress().getFamily());
EXPECT_EQ(IPPROTO_UDP, ep->getProtocol());
@@ -62,7 +62,7 @@ TEST(IOEndpointTest, createTCPv6) {
TEST(IOEndpointTest, createIPProto) {
EXPECT_THROW(IOEndpoint::create(IPPROTO_IP, IOAddress("192.0.2.1"),
- 5300)->getAddress().toText(),
+ 53210)->getAddress().toText(),
IOError);
}
diff --git a/src/lib/asiolink/tests/io_fetch_unittest.cc b/src/lib/asiolink/tests/io_fetch_unittest.cc
index 57f61b2..9b74ee0 100644
--- a/src/lib/asiolink/tests/io_fetch_unittest.cc
+++ b/src/lib/asiolink/tests/io_fetch_unittest.cc
@@ -16,6 +16,7 @@
#include <boost/bind.hpp>
#include <cstdlib>
#include <string>
+#include <vector>
#include <string.h>
@@ -57,7 +58,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.
- char server_buff_[512]; ///< Server buffer
+ std::vector<char> server_buff_; ///< Server buffer
/// \brief Constructor
IOFetchTest() :
@@ -67,7 +68,8 @@ public:
question_(Name("example.net"), RRClass::IN(), RRType::A()),
buff_(new OutputBuffer(512)),
udp_fetch_(IPPROTO_UDP, service_, question_, IOAddress(TEST_HOST),
- TEST_PORT, buff_, this, 100)
+ TEST_PORT, buff_, this, 100),
+ server_buff_(512)
// tcp_fetch_(service_, question_, IOAddress(TEST_HOST), TEST_PORT,
// buff_, this, 100, IPPROTO_UDP)
{ }
@@ -105,11 +107,12 @@ public:
// 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.)
- server_buff_[0] = server_buff_[1] = 0;
+ 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_, length) == 0);
+ 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);
@@ -172,7 +175,7 @@ TEST_F(IOFetchTest, UdpReceive) {
socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
udp::endpoint remote;
- socket.async_receive_from(asio::buffer(server_buff_, sizeof(server_buff_)),
+ socket.async_receive_from(asio::buffer(server_buff_),
remote,
boost::bind(&IOFetchTest::respond, this, &remote, &socket, _1, _2));
service_.get_io_service().post(udp_fetch_);
diff --git a/src/lib/asiolink/tests/io_service_unittest.cc b/src/lib/asiolink/tests/io_service_unittest.cc
index 28924d4..779d03e 100644
--- a/src/lib/asiolink/tests/io_service_unittest.cc
+++ b/src/lib/asiolink/tests/io_service_unittest.cc
@@ -28,7 +28,7 @@ const char* const TEST_IPV4_ADDR = "127.0.0.1";
TEST(IOServiceTest, badPort) {
IOService io_service;
EXPECT_THROW(DNSService(io_service, *"65536", true, false, NULL, NULL, NULL), IOError);
- EXPECT_THROW(DNSService(io_service, *"5300.0", true, false, NULL, NULL, NULL), IOError);
+ EXPECT_THROW(DNSService(io_service, *"53210.0", true, false, NULL, NULL, NULL), IOError);
EXPECT_THROW(DNSService(io_service, *"-1", true, false, NULL, NULL, NULL), IOError);
EXPECT_THROW(DNSService(io_service, *"domain", true, false, NULL, NULL, NULL), IOError);
}
diff --git a/src/lib/asiolink/tests/recursive_query_unittest.cc b/src/lib/asiolink/tests/recursive_query_unittest.cc
index dd18024..f4fc2ac 100644
--- a/src/lib/asiolink/tests/recursive_query_unittest.cc
+++ b/src/lib/asiolink/tests/recursive_query_unittest.cc
@@ -279,6 +279,7 @@ protected:
DNSLookup* lookup = NULL,
DNSAnswer* answer = NULL) :
io_(io_service),
+ done_(false),
message_(new Message(Message::PARSE)),
answer_message_(new Message(Message::RENDER)),
respbuf_(new OutputBuffer(0)),
@@ -412,7 +413,8 @@ protected:
};
RecursiveQueryTest::RecursiveQueryTest() :
- dns_service_(NULL), callback_(NULL), sock_(-1), res_(NULL)
+ dns_service_(NULL), callback_(NULL), callback_protocol_(0),
+ callback_native_(-1), sock_(-1), res_(NULL)
{
io_service_ = new IOService();
setDNSService(true, true);
@@ -485,9 +487,7 @@ TEST_F(RecursiveQueryTest, v4AddServer) {
EXPECT_THROW(sendTCP(AF_INET6), IOError);
}
-TEST_F(RecursiveQueryTest, DISABLED_clearServers) {
- // FIXME: Enable when clearServers actually close the sockets
- // See #388
+TEST_F(RecursiveQueryTest, clearServers) {
setDNSService();
dns_service_->clearServers();
diff --git a/src/lib/asiolink/tests/udp_socket_unittest.cc b/src/lib/asiolink/tests/udp_socket_unittest.cc
index 3033857..bb79b88 100644
--- a/src/lib/asiolink/tests/udp_socket_unittest.cc
+++ b/src/lib/asiolink/tests/udp_socket_unittest.cc
@@ -138,7 +138,7 @@ public:
}
/// \brief Get number of bytes transferred in I/O
- size_t getLength() {
+ size_t getLength() const {
return (ptr_->length_);
}
@@ -150,7 +150,7 @@ public:
}
/// \brief Get flag to say when callback was called
- bool getCalled() {
+ bool getCalled() const {
return (ptr_->called_);
}
@@ -162,7 +162,7 @@ public:
}
/// \brief Return instance of callback name
- std::string getName() {
+ std::string getName() const {
return (ptr_->name_);
}
diff --git a/src/lib/asiolink/udp_server.cc b/src/lib/asiolink/udp_server.cc
index 9a5f00e..98a47c4 100644
--- a/src/lib/asiolink/udp_server.cc
+++ b/src/lib/asiolink/udp_server.cc
@@ -55,8 +55,9 @@ struct UDPServer::Data {
*/
Data(io_service& io_service, const ip::address& addr, const uint16_t port,
SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
- io_(io_service), done_(false), checkin_callback_(checkin),
- lookup_callback_(lookup), answer_callback_(answer)
+ io_(io_service), done_(false), stopped_by_hand_(false),
+ checkin_callback_(checkin),lookup_callback_(lookup),
+ answer_callback_(answer)
{
// We must use different instantiations for v4 and v6;
// otherwise ASIO will bind to both
@@ -78,6 +79,7 @@ struct UDPServer::Data {
*/
Data(const Data& other) :
io_(other.io_), socket_(other.socket_), done_(false),
+ stopped_by_hand_(false),
checkin_callback_(other.checkin_callback_),
lookup_callback_(other.lookup_callback_),
answer_callback_(other.answer_callback_)
@@ -141,6 +143,9 @@ struct UDPServer::Data {
size_t bytes_;
bool done_;
+ //whether user explicitly stop the server
+ bool stopped_by_hand_;
+
// Callback functions provided by the caller
const SimpleCallback* checkin_callback_;
const DNSLookup* lookup_callback_;
@@ -164,10 +169,16 @@ UDPServer::UDPServer(io_service& io_service, const ip::address& addr,
/// pattern; see internal/coroutine.h for details.
void
UDPServer::operator()(error_code ec, size_t length) {
- /// Because the coroutine reeentry block is implemented as
+ /// Because the coroutine reentry block is implemented as
/// a switch statement, inline variable declarations are not
/// permitted. Certain variables used below can be declared here.
+ /// if user stopped the server, we won't enter the coroutine body
+ /// just return
+ if (data_->stopped_by_hand_) {
+ return;
+ }
+
CORO_REENTER (this) {
do {
/*
@@ -277,6 +288,16 @@ UDPServer::asyncLookup() {
data_->query_message_, data_->answer_message_, data_->respbuf_, this);
}
+/// Stop the UDPServer
+void
+UDPServer::stop() {
+ //server should not be stopped twice
+ if (data_->stopped_by_hand_)
+ return;
+ data_->stopped_by_hand_ = true;
+ data_->socket_->close();
+}
+
/// Post this coroutine on the ASIO service queue so that it will
/// resume processing where it left off. The 'done' parameter indicates
/// whether there is an answer to return to the client.
diff --git a/src/lib/asiolink/udp_server.h b/src/lib/asiolink/udp_server.h
index 16a03dd..1d37471 100644
--- a/src/lib/asiolink/udp_server.h
+++ b/src/lib/asiolink/udp_server.h
@@ -58,6 +58,10 @@ public:
/// \brief Calls the lookup callback
void asyncLookup();
+ /// \brief Stop the running server
+ /// \note once the server stopped, it can't restart
+ void stop();
+
/// \brief Resume operation
///
/// \param done Set this to true if the lookup action is done and
diff --git a/src/lib/bench/tests/benchmark_unittest.cc b/src/lib/bench/tests/benchmark_unittest.cc
index f16b47d..7bb8a60 100644
--- a/src/lib/bench/tests/benchmark_unittest.cc
+++ b/src/lib/bench/tests/benchmark_unittest.cc
@@ -12,7 +12,7 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <unistd.h> // for usleep
+#include <time.h> // for nanosleep
#include <bench/benchmark.h>
@@ -26,16 +26,17 @@ namespace {
// number of iterations.
class TestBenchMark {
public:
- TestBenchMark(const int sub_iterations, const int sleep_time) :
+ TestBenchMark(const int sub_iterations,
+ const struct timespec& sleep_time) :
sub_iterations_(sub_iterations), sleep_time_(sleep_time),
setup_completed_(false), teardown_completed_(false)
{}
unsigned int run() {
- usleep(sleep_time_);
+ nanosleep(&sleep_time_, NULL);
return (sub_iterations_);
}
const int sub_iterations_;
- const int sleep_time_;
+ const struct timespec sleep_time_;
bool setup_completed_;
bool teardown_completed_;
};
@@ -67,6 +68,7 @@ TEST(BenchMarkTest, run) {
// use some uncommon iterations for testing purpose:
const int sub_iterations = 23;
const int sleep_time = 50000; // will sleep for 50ms
+ const struct timespec sleep_timespec = { 0, sleep_time * 1000 };
// we cannot expect particular accuracy on the measured duration, so
// we'll include some conservative margin (25%) and perform range
// comparison below.
@@ -75,12 +77,12 @@ TEST(BenchMarkTest, run) {
// Prerequisite check: since the tests in this case may depend on subtle
// timing, it may result in false positives. There are reportedly systems
- // where usleep() doesn't work as this test expects. So we check the
+ // where sleeping doesn't work as this test expects. So we check the
// conditions before the tests, and if it fails skip the tests at the
// risk of overlooking possible bugs.
struct timeval check_begin, check_end;
gettimeofday(&check_begin, NULL);
- usleep(sleep_time);
+ nanosleep(&sleep_timespec, 0);
gettimeofday(&check_end, NULL);
check_end.tv_sec -= check_begin.tv_sec;
if (check_end.tv_usec >= check_begin.tv_usec) {
@@ -97,7 +99,7 @@ TEST(BenchMarkTest, run) {
return;
}
- TestBenchMark test_bench(sub_iterations, sleep_time);
+ TestBenchMark test_bench(sub_iterations, sleep_timespec);
BenchMark<TestBenchMark> bench(1, test_bench, false);
// Check pre-test conditions.
EXPECT_FALSE(test_bench.setup_completed_);
@@ -130,7 +132,8 @@ TEST(BenchMarkTest, run) {
TEST(BenchMarkTest, runWithNoIteration) {
// we'll lie on the number of iteration (0). it will result in
// meaningless result, but at least it shouldn't crash.
- TestBenchMark test_bench(0, 0);
+ const struct timespec null_timespec = { 0, 0 };
+ TestBenchMark test_bench(0, null_timespec);
BenchMark<TestBenchMark> bench(1, test_bench, false);
bench.run();
EXPECT_EQ(0, bench.getIteration());
diff --git a/src/lib/bench/tests/loadquery_unittest.cc b/src/lib/bench/tests/loadquery_unittest.cc
index 3ac352a..a53e191 100644
--- a/src/lib/bench/tests/loadquery_unittest.cc
+++ b/src/lib/bench/tests/loadquery_unittest.cc
@@ -55,7 +55,7 @@ const char* const LoadQueryTest::DATA_DIR = TEST_DATA_DIR;
class QueryInserter {
public:
QueryInserter(stringstream& stream) : stream_(stream) {}
- void operator()(const QueryParam& query) {
+ void operator()(const QueryParam& query) const {
stream_ << query.first << " " << query.second << endl;
}
private:
diff --git a/src/lib/cache/message_cache.cc b/src/lib/cache/message_cache.cc
index 70e7c67..f1334a2 100644
--- a/src/lib/cache/message_cache.cc
+++ b/src/lib/cache/message_cache.cc
@@ -74,6 +74,7 @@ MessageCache::update(const Message& msg) {
return (message_table_.add(msg_entry, entry_key, true));
}
+#if 0
void
MessageCache::dump(const std::string&) {
//TODO
@@ -89,6 +90,7 @@ MessageCache::resize(uint32_t) {
//TODO
return (true);
}
+#endif
} // namespace cache
} // namespace isc
diff --git a/src/lib/cache/message_cache.h b/src/lib/cache/message_cache.h
index 3a684c8..65c7381 100644
--- a/src/lib/cache/message_cache.h
+++ b/src/lib/cache/message_cache.h
@@ -41,6 +41,9 @@ public:
MessageCache(boost::shared_ptr<RRsetCache> rrset_cache_,
uint32_t cache_size, uint16_t message_class);
+ /// \brief Destructor function
+ virtual ~MessageCache() {}
+
/// \brief Look up message in cache.
/// \param message generated response message if the message entry
/// can be found.
@@ -57,6 +60,7 @@ public:
/// directly.
bool update(const isc::dns::Message& msg);
+#if 0
/// \brief Dump the message cache to specified file.
/// \todo It should can be dumped to one configured database.
void dump(const std::string& file_name);
@@ -67,6 +71,7 @@ public:
/// \brief Resize the size of message cache in runtime.
bool resize(uint32_t size);
+#endif
protected:
/// \brief Get the hash key for the message entry in the cache.
diff --git a/src/lib/cache/message_entry.cc b/src/lib/cache/message_entry.cc
index de684a0..6396167 100644
--- a/src/lib/cache/message_entry.cc
+++ b/src/lib/cache/message_entry.cc
@@ -76,7 +76,7 @@ MessageEntry::getRRsetEntries(vector<RRsetEntryPtr>& rrset_entry_vec,
for (int index = 0; index < entry_count; ++index) {
RRsetEntryPtr rrset_entry = rrset_cache_->lookup(rrsets_[index].name_,
rrsets_[index].type_);
- if (time_now < rrset_entry->getExpireTime()) {
+ if (rrset_entry && time_now < rrset_entry->getExpireTime()) {
rrset_entry_vec.push_back(rrset_entry);
} else {
return (false);
diff --git a/src/lib/cache/rrset_cache.cc b/src/lib/cache/rrset_cache.cc
index 0a2957c..7dab3b5 100644
--- a/src/lib/cache/rrset_cache.cc
+++ b/src/lib/cache/rrset_cache.cc
@@ -83,6 +83,7 @@ RRsetCache::update(const isc::dns::RRset& rrset, const RRsetTrustLevel& level) {
}
}
+#if 0
void
RRsetCache::dump(const std::string&) {
//TODO
@@ -98,6 +99,7 @@ RRsetCache::resize(uint32_t) {
//TODO
return (true);
}
+#endif
} // namespace cache
} // namespace isc
diff --git a/src/lib/cache/rrset_cache.h b/src/lib/cache/rrset_cache.h
index 15084c9..5bf2730 100644
--- a/src/lib/cache/rrset_cache.h
+++ b/src/lib/cache/rrset_cache.h
@@ -45,7 +45,7 @@ public:
/// \param cache_size the size of rrset cache.
/// \param rrset_class the class of rrset cache.
RRsetCache(uint32_t cache_size, uint16_t rrset_class);
- ~RRsetCache() {}
+ virtual ~RRsetCache() {}
//@}
/// \brief Look up rrset in cache.
@@ -70,6 +70,7 @@ public:
RRsetEntryPtr update(const isc::dns::RRset& rrset,
const RRsetTrustLevel& level);
+#if 0
/// \brief Dump the rrset cache to specified file.
///
/// \param file_name The file to write to
@@ -89,8 +90,10 @@ public:
/// \param The size to resize to
/// \return true
bool resize(uint32_t size);
+#endif
-private:
+ /// \short Protected memebers, so they can be accessed by tests.
+protected:
uint16_t class_; // The class of the rrset cache.
isc::nsas::HashTable<RRsetEntry> rrset_table_;
isc::nsas::LruList<RRsetEntry> rrset_lru_;
diff --git a/src/lib/cache/tests/message_cache_unittest.cc b/src/lib/cache/tests/message_cache_unittest.cc
index e7184bd..b2c0cd3 100644
--- a/src/lib/cache/tests/message_cache_unittest.cc
+++ b/src/lib/cache/tests/message_cache_unittest.cc
@@ -43,20 +43,40 @@ public:
}
};
+/// \brief Derived from base class to make it easy to test
+/// its internals.
+class DerivedRRsetCache: public RRsetCache {
+public:
+ DerivedRRsetCache(uint32_t cache_size, uint16_t rrset_class):
+ RRsetCache(cache_size, rrset_class)
+ {}
+
+ /// \brief Remove one rrset entry from rrset cache.
+ void removeRRsetEntry(Name& name, const RRType& type) {
+ const string entry_name = genCacheEntryName(name, type);
+ HashKey entry_key = HashKey(entry_name, RRClass(class_));
+ RRsetEntryPtr rrset_entry = rrset_table_.get(entry_key);
+ if (rrset_entry) {
+ rrset_lru_.remove(rrset_entry);
+ rrset_table_.remove(entry_key);
+ }
+ }
+};
+
class MessageCacheTest: public testing::Test {
public:
MessageCacheTest(): message_parse(Message::PARSE),
message_render(Message::RENDER)
{
uint16_t class_ = RRClass::IN().getCode();
- rrset_cache_.reset(new RRsetCache(RRSET_CACHE_DEFAULT_SIZE, class_));
- message_cache_.reset(new DerivedMessageCache(rrset_cache_,
+ rrset_cache_.reset(new DerivedRRsetCache(RRSET_CACHE_DEFAULT_SIZE, class_));
+ message_cache_.reset(new DerivedMessageCache(rrset_cache_,
MESSAGE_CACHE_DEFAULT_SIZE, class_ ));
}
protected:
boost::shared_ptr<DerivedMessageCache> message_cache_;
- RRsetCachePtr rrset_cache_;
+ boost::shared_ptr<DerivedRRsetCache> rrset_cache_;
Message message_parse;
Message message_render;
};
@@ -75,6 +95,11 @@ TEST_F(MessageCacheTest, testLookup) {
Name qname1("test.example.net.");
EXPECT_TRUE(message_cache_->lookup(qname1, RRType::A(), message_render));
+
+ // Test looking up message which has expired rrsets.
+ // Remove one
+ rrset_cache_->removeRRsetEntry(qname1, RRType::A());
+ EXPECT_FALSE(message_cache_->lookup(qname1, RRType::A(), message_render));
}
TEST_F(MessageCacheTest, testUpdate) {
diff --git a/src/lib/cc/tests/session_unittests.cc b/src/lib/cc/tests/session_unittests.cc
index d61cbd3..5f6e595 100644
--- a/src/lib/cc/tests/session_unittests.cc
+++ b/src/lib/cc/tests/session_unittests.cc
@@ -74,7 +74,7 @@ public:
}
void
- acceptHandler(const asio::error_code&) {
+ acceptHandler(const asio::error_code&) const {
}
void
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index 7049565..69621a4 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -170,10 +170,10 @@ ModuleCCSession::readModuleSpecification(const std::string& filename) {
try {
module_spec = moduleSpecFromFile(file, true);
- } catch (JSONError pe) {
+ } catch (const JSONError& pe) {
cout << "Error parsing module specification file: " << pe.what() << endl;
exit(1);
- } catch (ModuleSpecError dde) {
+ } catch (const ModuleSpecError& dde) {
cout << "Error reading module specification file: " << dde.what() << endl;
exit(1);
}
diff --git a/src/lib/config/module_spec.cc b/src/lib/config/module_spec.cc
index ad40689..fd07dde 100644
--- a/src/lib/config/module_spec.cc
+++ b/src/lib/config/module_spec.cc
@@ -121,7 +121,7 @@ void
check_module_specification(ConstElementPtr def) {
try {
check_data_specification(def);
- } catch (TypeError te) {
+ } catch (const TypeError& te) {
throw ModuleSpecError(te.what());
}
}
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index 4ed3ce2..43663bd 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -31,7 +31,7 @@ using namespace std;
namespace {
std::string
-ccspecfile(const std::string name) {
+ccspecfile(const std::string& name) {
return (std::string(TEST_DATA_PATH) + "/" + name);
}
diff --git a/src/lib/config/tests/module_spec_unittests.cc b/src/lib/config/tests/module_spec_unittests.cc
index 8490aa0..59f5459 100644
--- a/src/lib/config/tests/module_spec_unittests.cc
+++ b/src/lib/config/tests/module_spec_unittests.cc
@@ -23,7 +23,7 @@
using namespace isc::data;
using namespace isc::config;
-std::string specfile(const std::string name) {
+std::string specfile(const std::string& name) {
return (std::string(TEST_DATA_PATH) + "/" + name);
}
@@ -36,7 +36,7 @@ moduleSpecError(const std::string& file,
EXPECT_THROW(moduleSpecFromFile(specfile(file)), ModuleSpecError);
try {
ModuleSpec dd = moduleSpecFromFile(specfile(file));
- } catch (ModuleSpecError dde) {
+ } catch (const ModuleSpecError& dde) {
std::string ddew = dde.what();
EXPECT_EQ(error1 + error2 + error3, ddew);
}
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index bf3c8ca..5230ced 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -472,7 +472,7 @@ struct MemoryZone::MemoryZoneImpl {
* Otherwise, why would the DOMAINFLAG_WILD be there if
* there was no wildcard under it?
*/
- assert(result = DomainTree::EXACTMATCH);
+ assert(result == DomainTree::EXACTMATCH);
/*
* We have the wildcard node now. Jump below the switch,
* where handling of the common (exact-match) case is.
diff --git a/src/lib/datasrc/tests/rbtree_unittest.cc b/src/lib/datasrc/tests/rbtree_unittest.cc
index 82eed63..23b25f4 100644
--- a/src/lib/datasrc/tests/rbtree_unittest.cc
+++ b/src/lib/datasrc/tests/rbtree_unittest.cc
@@ -56,7 +56,7 @@ const size_t Name::MAX_LABELS;
namespace {
class RBTreeTest : public::testing::Test {
protected:
- RBTreeTest() : rbtree_expose_empty_node(true) {
+ RBTreeTest() : rbtree_expose_empty_node(true), crbtnode(NULL) {
const char* const domain_names[] = {
"c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
"j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f"};
diff --git a/src/lib/dns/message.cc b/src/lib/dns/message.cc
index c966116..9eae605 100644
--- a/src/lib/dns/message.cc
+++ b/src/lib/dns/message.cc
@@ -113,10 +113,8 @@ public:
vector<RRsetPtr> rrsets_[NUM_SECTIONS];
ConstEDNSPtr edns_;
-#ifdef notyet
// tsig/sig0: TODO
- RRsetsSorter* sorter_;
-#endif
+ // RRsetsSorter* sorter_; : TODO
void init();
void setOpcode(const Opcode& opcode);
diff --git a/src/lib/dns/rdata/generic/nsec3_50.cc b/src/lib/dns/rdata/generic/nsec3_50.cc
index 01ffefa..fbe6612 100644
--- a/src/lib/dns/rdata/generic/nsec3_50.cc
+++ b/src/lib/dns/rdata/generic/nsec3_50.cc
@@ -117,11 +117,10 @@ NSEC3::NSEC3(const string& nsec3_str) :
memset(bitmap, 0, sizeof(bitmap));
do {
string type;
- int code;
iss >> type;
if (type.length() != 0) {
try {
- code = RRType(type).getCode();
+ const int code = RRType(type).getCode();
bitmap[code / 8] |= (0x80 >> (code % 8));
} catch (...) {
isc_throw(InvalidRdataText, "Invalid RRtype in NSEC3");
diff --git a/src/lib/dns/rdata/generic/nsec_47.cc b/src/lib/dns/rdata/generic/nsec_47.cc
index 5d92528..72eb946 100644
--- a/src/lib/dns/rdata/generic/nsec_47.cc
+++ b/src/lib/dns/rdata/generic/nsec_47.cc
@@ -63,10 +63,9 @@ NSEC::NSEC(const string& nsec_str) :
memset(bitmap, 0, sizeof(bitmap));
do {
string type;
- int code;
iss >> type;
try {
- code = RRType(type).getCode();
+ const int code = RRType(type).getCode();
bitmap[code / 8] |= (0x80 >> (code % 8));
} catch (...) {
isc_throw(InvalidRdataText, "Invalid RRtype in NSEC");
diff --git a/src/lib/dns/tests/name_unittest.cc b/src/lib/dns/tests/name_unittest.cc
index b79fd74..5daba9c 100644
--- a/src/lib/dns/tests/name_unittest.cc
+++ b/src/lib/dns/tests/name_unittest.cc
@@ -290,7 +290,7 @@ TEST_F(NameTest, assignment) {
// Self assignment
copy = copy;
- EXPECT_EQ(copy, example_name);
+ EXPECT_EQ(example_name, copy);
}
TEST_F(NameTest, toText) {
diff --git a/src/lib/log/strutil.cc b/src/lib/log/strutil.cc
index 8ed6c27..65fb0cd 100644
--- a/src/lib/log/strutil.cc
+++ b/src/lib/log/strutil.cc
@@ -62,7 +62,7 @@ trim(const string& instring) {
// another dependency on a Boost library.
vector<string>
-tokens(const std::string text, const std::string& delim) {
+tokens(const std::string& text, const std::string& delim) {
vector<string> result;
// Search for the first non-delimiter character
diff --git a/src/lib/log/strutil.h b/src/lib/log/strutil.h
index 87c0153..f44b0d0 100644
--- a/src/lib/log/strutil.h
+++ b/src/lib/log/strutil.h
@@ -71,7 +71,7 @@ std::string trim(const std::string& instring);
/// \param delim Delimiter characters
///
/// \return Vector of tokens.
-std::vector<std::string> tokens(const std::string text,
+std::vector<std::string> tokens(const std::string& text,
const std::string& delim = std::string(" \t\n"));
diff --git a/src/lib/nsas/asiolink.h b/src/lib/nsas/asiolink.h
index b99ddb3..f5af192 100644
--- a/src/lib/nsas/asiolink.h
+++ b/src/lib/nsas/asiolink.h
@@ -46,7 +46,7 @@ public:
}
/// \return true if two addresses are equal
- bool equal(const IOAddress& address)
+ bool equal(const IOAddress& address) const
{return (toText() == address.toText());}
private:
diff --git a/src/lib/nsas/nameserver_entry.h b/src/lib/nsas/nameserver_entry.h
index c3ddcd4..f6c2e8c 100644
--- a/src/lib/nsas/nameserver_entry.h
+++ b/src/lib/nsas/nameserver_entry.h
@@ -105,7 +105,14 @@ public:
name_(name),
classCode_(class_code),
expiration_(0)
- {}
+ {
+ has_address_[V4_ONLY] = false;
+ has_address_[V6_ONLY] = false;
+ has_address_[ANY_OK] = false;
+ expect_address_[V4_ONLY] = false;
+ expect_address_[V6_ONLY] = false;
+ expect_address_[ANY_OK] = false;
+ }
/*
* \brief Return Address
diff --git a/src/lib/python/isc/util/socketserver_mixin.py b/src/lib/python/isc/util/socketserver_mixin.py
index fb5f9a2..e954fe1 100644
--- a/src/lib/python/isc/util/socketserver_mixin.py
+++ b/src/lib/python/isc/util/socketserver_mixin.py
@@ -64,7 +64,7 @@ class NoPollMixIn:
called in anther thread. Note, parameter 'poll_interval' is
just used for interface compatibility; it's never used in this
function.
- '''
+ '''
while True:
# block until the self.socket or self.__read_sock is readable
try:
@@ -74,11 +74,11 @@ class NoPollMixIn:
continue
else:
break
-
+
if self.__read_sock in r:
break
else:
- self._handle_request_noblock()
+ self._handle_request_noblock();
self._is_shut_down.set()
diff --git a/src/lib/python/isc/util/tests/socketserver_mixin_test.py b/src/lib/python/isc/util/tests/socketserver_mixin_test.py
index 61bc248..a6686d8 100644
--- a/src/lib/python/isc/util/tests/socketserver_mixin_test.py
+++ b/src/lib/python/isc/util/tests/socketserver_mixin_test.py
@@ -25,7 +25,7 @@ class MyHandler(socketserver.BaseRequestHandler):
data = self.request.recv(20)
self.request.send(data)
-class MyServer(NoPollMixIn,
+class MyServer(NoPollMixIn,
socketserver.ThreadingMixIn,
socketserver.TCPServer):
diff --git a/src/lib/python/isc/utils/Makefile.am b/src/lib/python/isc/utils/Makefile.am
deleted file mode 100644
index 65a39ad..0000000
--- a/src/lib/python/isc/utils/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-SUBDIRS = tests
-
-python_PYTHON = __init__.py process.py
-
-pythondir = $(pyexecdir)/isc/utils
diff --git a/src/lib/python/isc/utils/__init__.py b/src/lib/python/isc/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/lib/python/isc/utils/process.py b/src/lib/python/isc/utils/process.py
deleted file mode 100644
index 25775af..0000000
--- a/src/lib/python/isc/utils/process.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) 2010 CZ NIC
-#
-# 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.
-
-"""
-Module to manipulate the python processes.
-
-It contains only function to rename the process, which is currently
-wrapper around setproctitle library. Does not fail if the setproctitle
-module is missing, but does nothing in that case.
-"""
-try:
- from setproctitle import setproctitle
-except ImportError:
- def setproctitle(_): pass
-import sys
-import os.path
-
-"""
-Rename the current process to given name (so it can be found in ps).
-If name is None, use zero'th command line argument.
-"""
-def rename(name=None):
- if name is None:
- name = os.path.basename(sys.argv[0])
- setproctitle(name)
diff --git a/src/lib/python/isc/utils/tests/Makefile.am b/src/lib/python/isc/utils/tests/Makefile.am
deleted file mode 100644
index e58b5b6..0000000
--- a/src/lib/python/isc/utils/tests/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-PYTESTS = process_test.py
-EXTRA_DIST = $(PYTESTS)
-
-# test using command-line arguments, so use check-local target instead of TESTS
-check-local:
-if ENABLE_PYTHON_COVERAGE
- touch $(abs_top_srcdir)/.coverage
- rm -f .coverage
- ${LN_S} $(abs_top_srcdir)/.coverage .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_builddir)/src/lib/dns/python/.libs \
- $(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
- done
diff --git a/src/lib/python/isc/utils/tests/process_test.py b/src/lib/python/isc/utils/tests/process_test.py
deleted file mode 100644
index 0e7c8b1..0000000
--- a/src/lib/python/isc/utils/tests/process_test.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2010 CZ NIC
-#
-# Permission to use, copy, modify, and distribute this software for any
-# purpose with or without fee is hereby granted, provided that the above
-# copyright notice and this permission notice appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
-# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
-# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
-# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Tests for isc.utils.process."""
-import unittest
-import isc.utils.process
-run_tests = True
-try:
- import setproctitle
-except ImportError:
- run_tests = False
-
-class TestRename(unittest.TestCase):
- """Testcase for isc.process.rename."""
- def __get_self_name(self):
- return setproctitle.getproctitle()
-
- @unittest.skipIf(not run_tests, "Setproctitle not installed, not testing")
- def test_rename(self):
- """Test if the renaming function works."""
- isc.utils.process.rename("rename-test")
- self.assertEqual("rename-test", self.__get_self_name())
- isc.utils.process.rename()
- self.assertEqual("process_test.py", self.__get_self_name())
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/src/lib/server_common/Makefile.am b/src/lib/server_common/Makefile.am
new file mode 100644
index 0000000..dfb3014
--- /dev/null
+++ b/src/lib/server_common/Makefile.am
@@ -0,0 +1,26 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+if USE_CLANGPP
+# clang++ complains about unused function parameters in some boost header
+# files.
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
+
+lib_LTLIBRARIES = libserver_common.la
+libserver_common_la_SOURCES = portconfig.h portconfig.cc
+libserver_common_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
+libserver_common_la_LIBADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+libserver_common_la_LIBADD += $(top_builddir)/src/lib/cc/libcc.la
+libserver_common_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
+
+CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/server_common/portconfig.cc b/src/lib/server_common/portconfig.cc
new file mode 100644
index 0000000..3765f52
--- /dev/null
+++ b/src/lib/server_common/portconfig.cc
@@ -0,0 +1,119 @@
+// 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.
+
+#include <server_common/portconfig.h>
+
+#include <asiolink/io_address.h>
+#include <asiolink/dns_service.h>
+#include <log/dummylog.h>
+
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+
+using namespace std;
+using namespace isc::data;
+using namespace asiolink;
+using isc::log::dlog;
+
+namespace isc {
+namespace server_common {
+namespace portconfig {
+
+AddressList
+parseAddresses(isc::data::ConstElementPtr addresses,
+ const std::string& elemName)
+{
+ AddressList result;
+ if (addresses) {
+ if (addresses->getType() == Element::list) {
+ for (size_t i(0); i < addresses->size(); ++ i) {
+ ConstElementPtr addrPair(addresses->get(i));
+ ConstElementPtr addr(addrPair->get("address"));
+ ConstElementPtr port(addrPair->get("port"));
+ if (!addr || ! port) {
+ isc_throw(BadValue, "Address must contain both the IP"
+ "address and port");
+ }
+ try {
+ IOAddress(addr->stringValue());
+ if (port->intValue() < 0 ||
+ port->intValue() > 0xffff) {
+ isc_throw(BadValue, "Bad port value (" <<
+ port->intValue() << ")");
+ }
+ result.push_back(AddressPair(addr->stringValue(),
+ port->intValue()));
+ }
+ catch (const TypeError &e) { // Better error message
+ isc_throw(TypeError,
+ "Address must be a string and port an integer");
+ }
+ }
+ } else if (addresses->getType() != Element::null) {
+ isc_throw(TypeError, elemName + " config element must be a list");
+ }
+ }
+ return (result);
+}
+
+namespace {
+
+void
+setAddresses(DNSService& service, const AddressList& addresses) {
+ service.clearServers();
+ BOOST_FOREACH(const AddressPair &address, addresses) {
+ service.addServer(address.second, address.first);
+ }
+}
+
+}
+
+void
+installListenAddresses(const AddressList& newAddresses,
+ AddressList& addressStore,
+ asiolink::DNSService& service)
+{
+ try {
+ dlog("Setting listen addresses:");
+ BOOST_FOREACH(const AddressPair& addr, newAddresses) {
+ dlog(" " + addr.first + ":" +
+ boost::lexical_cast<string>(addr.second));
+ }
+ setAddresses(service, newAddresses);
+ addressStore = newAddresses;
+ }
+ catch (const exception& e) {
+ /*
+ * We couldn't set it. So return it back. If that fails as well,
+ * we have a problem.
+ *
+ * If that fails, bad luck, but we are useless anyway, so just die
+ * and let boss start us again.
+ */
+ dlog(string("Unable to set new address: ") + e.what(), true);
+ try {
+ setAddresses(service, addressStore);
+ }
+ catch (const exception& e2) {
+ dlog("Unable to recover from error;", true);
+ dlog(string("Rollback failed with: ") + e2.what(), true);
+ abort();
+ }
+ throw; // Let it fly a little bit further
+ }
+}
+
+}
+}
+}
diff --git a/src/lib/server_common/portconfig.h b/src/lib/server_common/portconfig.h
new file mode 100644
index 0000000..bcb8528
--- /dev/null
+++ b/src/lib/server_common/portconfig.h
@@ -0,0 +1,121 @@
+// 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.
+
+#ifndef ISC_SERVER_COMMON_PORTCONFIG_H
+#define ISC_SERVER_COMMON_PORTCONFIG_H
+
+#include <utility>
+#include <string>
+#include <stdint.h>
+#include <vector>
+
+#include <cc/data.h>
+
+/*
+ * Some forward declarations.
+ */
+namespace asiolink {
+class DNSService;
+}
+
+namespace isc {
+namespace server_common {
+/**
+ * \brief Utilities to configure ports and addresses.
+ *
+ * Here are some utilities to help a server to parse configuration of addresses
+ * and ports and install the configuration.
+ */
+namespace portconfig {
+
+/**
+ * \brief An address-port pair.
+ *
+ * It is just a pair of string for an address and unsigned integer for port
+ * number. Anything more fancy would be an overkill, it is used only to pass
+ * the addresses and ports around as intermediate results.
+ */
+typedef std::pair<std::string, uint16_t> AddressPair;
+
+/// \brief Bunch of address pairs
+typedef std::vector<AddressPair> AddressList;
+
+/**
+ * \brief
+ *
+ * This parses a list of address-port configurations and returns them. The
+ * configuration looks like this:
+ *
+ * \verbatim
+[
+ {
+ "address": "192.0.2.1",
+ "port": 13
+ },
+ {
+ "address": "::",
+ "port": 80
+ }
+]
+ * \endverbatim
+ * \param addresses The configuration element to parse (the list). Empty list,
+ * null element and null pointer all mean empty list of addresses.
+ * \param elemName The name of the element, used to create descriptions for
+ * exceptions.
+ * \return Vector of parsed address-port pairs found in the configuration.
+ * \throw isc::data::TypeError if something in the configuration is of a wrong
+ * type (string passed to a port, element in the list that isn't hash,
+ * etc).
+ * \throw asiolink::IOError if the provided address string can't be parsed.
+ * \throw BadValue for other invalid configurations (missing port or address
+ * element in the hash, port number out of range).
+ * \throw std::bad_alloc when allocation fails.
+ */
+AddressList
+parseAddresses(isc::data::ConstElementPtr addresses,
+ const std::string& elemName);
+
+/**
+ * \brief Changes current listening addresses and ports.
+ *
+ * Removes all sockets we currently listen on and starts listening on the
+ * addresses and ports requested in newAddresses.
+ *
+ * If it fails to set up the new addresses, it attempts to roll back to the
+ * previous addresses (but it still propagates the exception). If the rollback
+ * fails as well, it aborts the application (it assumes if it can't listen
+ * on the new addresses nor on the old ones, the application is useless anyway
+ * and should be restarted by Boss, not to mention that the internal state is
+ * probably broken).
+ *
+ * \param newAddresses are the addresses you want to listen on.
+ * \param addressStore is the place you store your current addresses. It is
+ * used when there's a need for rollback. The newAddresses are copied here
+ * when the change is successful.
+ * \param dnsService is the DNSService object we use now. The requests from
+ * the new sockets are handled using this dnsService (and all current
+ * sockets on the service are closed first).
+ * \throw asiolink::IOError when initialization or closing of socket fails.
+ * \throw std::bad_alloc when allocation fails.
+ */
+void
+installListenAddresses(const AddressList& newAddresses,
+ AddressList& addressStore,
+ asiolink::DNSService& dnsService);
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/server_common/tests/Makefile.am b/src/lib/server_common/tests/Makefile.am
new file mode 100644
index 0000000..22fe104
--- /dev/null
+++ b/src/lib/server_common/tests/Makefile.am
@@ -0,0 +1,38 @@
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/server_common
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/server_common
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+AM_LDFLAGS =
+if USE_STATIC_LINK
+AM_LDFLAGS += -static
+endif
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+if USE_CLANGPP
+# see ../Makefile.am
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += portconfig_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+
+run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/server_common/tests/portconfig_unittest.cc b/src/lib/server_common/tests/portconfig_unittest.cc
new file mode 100644
index 0000000..fabdfa2
--- /dev/null
+++ b/src/lib/server_common/tests/portconfig_unittest.cc
@@ -0,0 +1,182 @@
+// 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.
+
+#include <server_common/portconfig.h>
+
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
+#include <asiolink/asiolink.h>
+
+#include <gtest/gtest.h>
+#include <string>
+
+using namespace isc::server_common::portconfig;
+using namespace isc::data;
+using namespace isc;
+using namespace std;
+using namespace asiolink;
+
+namespace {
+
+/// Testcase for parseAddresses call (struct, nobody cares about private here)
+struct ParseAddresses : public ::testing::Test {
+ AddressList result_;
+ void empty(ElementPtr config, const string& name) {
+ SCOPED_TRACE(name);
+ EXPECT_NO_THROW(result_ = parseAddresses(config, "test"));
+ EXPECT_TRUE(result_.empty());
+ }
+ template<class Exception>
+ void invalidTest(const string& json, const string& name) {
+ SCOPED_TRACE(name);
+ ElementPtr config(Element::fromJSON(json));
+ EXPECT_THROW(parseAddresses(config, "test"), Exception) <<
+ "Should throw " << typeid(Exception).name();
+ }
+};
+
+// Parse valid IPv4 address
+TEST_F(ParseAddresses, ipv4) {
+ ElementPtr config(Element::fromJSON("["
+ " {"
+ " \"address\": \"192.0.2.1\","
+ " \"port\": 53"
+ " }"
+ "]"));
+ EXPECT_NO_THROW(result_ = parseAddresses(config, "test"));
+ ASSERT_EQ(1, result_.size());
+ EXPECT_EQ("192.0.2.1", result_[0].first);
+ EXPECT_EQ(53, result_[0].second);
+}
+
+// Parse valid IPv6 address
+TEST_F(ParseAddresses, ipv6) {
+ ElementPtr config(Element::fromJSON("["
+ " {"
+ " \"address\": \"2001:db8::1\","
+ " \"port\": 53"
+ " }"
+ "]"));
+ EXPECT_NO_THROW(result_ = parseAddresses(config, "test"));
+ ASSERT_EQ(1, result_.size());
+ EXPECT_EQ("2001:db8::1", result_[0].first);
+ EXPECT_EQ(53, result_[0].second);
+}
+
+// Parse multiple addresses at once
+// (even the ports are different to see they are not mistaken)
+TEST_F(ParseAddresses, multi) {
+ ElementPtr config(Element::fromJSON("["
+ " {"
+ " \"address\": \"2001:db8::1\","
+ " \"port\": 53"
+ " },"
+ " {"
+ " \"address\": \"192.0.2.1\","
+ " \"port\": 54"
+ " }"
+ "]"));
+ EXPECT_NO_THROW(result_ = parseAddresses(config, "test"));
+ ASSERT_EQ(2, result_.size());
+ EXPECT_EQ("2001:db8::1", result_[0].first);
+ EXPECT_EQ(53, result_[0].second);
+ EXPECT_EQ("192.0.2.1", result_[1].first);
+ EXPECT_EQ(54, result_[1].second);
+}
+
+// Parse various versions of empty list
+TEST_F(ParseAddresses, empty) {
+ empty(Element::fromJSON("[]"), "Empty list");
+ empty(ElementPtr(new NullElement), "Null element");
+ empty(ElementPtr(), "Null pointer");
+}
+
+// Reject invalid configs
+TEST_F(ParseAddresses, invalid) {
+ invalidTest<TypeError>("{}", "Not a list");
+ invalidTest<BadValue>("[{}]", "Empty element");
+ invalidTest<TypeError>("[{"
+ " \"port\": 1.5,"
+ " \"address\": \"192.0.2.1\""
+ "}]", "Float port");
+ invalidTest<BadValue>("[{"
+ " \"port\": -5,"
+ " \"address\": \"192.0.2.1\""
+ "}]", "Negative port");
+ invalidTest<BadValue>("[{"
+ " \"port\": 1000000,"
+ " \"address\": \"192.0.2.1\""
+ "}]", "Port too big");
+ invalidTest<IOError>("[{"
+ " \"port\": 53,"
+ " \"address\": \"bad_address\""
+ "}]", "Bad address");
+}
+
+// Test fixture for installListenAddresses
+struct InstallListenAddresses : public ::testing::Test {
+ InstallListenAddresses() :
+ dnss_(ios_, NULL, NULL, NULL)
+ {
+ valid_.push_back(AddressPair("127.0.0.1", 5288));
+ valid_.push_back(AddressPair("::1", 5288));
+ invalid_.push_back(AddressPair("192.0.2.2", 1));
+ }
+ IOService ios_;
+ DNSService dnss_;
+ AddressList store_;
+ // We should be able to bind to these addresses
+ AddressList valid_;
+ // But this shouldn't work
+ AddressList invalid_;
+ // Check that the store_ addresses are the same as expected
+ void checkAddresses(const AddressList& expected, const string& name) {
+ SCOPED_TRACE(name);
+
+ ASSERT_EQ(expected.size(), store_.size()) <<
+ "Different amount of elements, not checking content";
+ // Run in parallel trough the vectors
+ for (AddressList::const_iterator ei(expected.begin()),
+ si(store_.begin()); ei != expected.end(); ++ei, ++si) {
+ EXPECT_EQ(ei->first, si->first);
+ EXPECT_EQ(ei->second, si->second);
+ }
+ }
+};
+
+// Try switching valid addresses
+TEST_F(InstallListenAddresses, valid) {
+ // First, bind to the valid addresses
+ EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_));
+ checkAddresses(valid_, "Valid addresses");
+ // TODO Maybe some test to actually connect to them
+ // Try setting it back to nothing
+ EXPECT_NO_THROW(installListenAddresses(AddressList(), store_, dnss_));
+ checkAddresses(AddressList(), "No addresses");
+ // Try switching back again
+ EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_));
+ checkAddresses(valid_, "Valid addresses");
+}
+
+// Try if rollback works
+TEST_F(InstallListenAddresses, rollback) {
+ // Set some addresses
+ EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_));
+ checkAddresses(valid_, "Before rollback");
+ // This should not bind them, but should leave the original addresses
+ EXPECT_THROW(installListenAddresses(invalid_, store_, dnss_), IOError);
+ checkAddresses(valid_, "After rollback");
+}
+
+}
diff --git a/src/lib/server_common/tests/run_unittests.cc b/src/lib/server_common/tests/run_unittests.cc
new file mode 100644
index 0000000..7ebc985
--- /dev/null
+++ b/src/lib/server_common/tests/run_unittests.cc
@@ -0,0 +1,26 @@
+// 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.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/testutils/Makefile.am b/src/lib/testutils/Makefile.am
index d0467ea..e5cb46b 100644
--- a/src/lib/testutils/Makefile.am
+++ b/src/lib/testutils/Makefile.am
@@ -12,3 +12,5 @@ libtestutils_la_SOURCES += dnsmessage_test.h dnsmessage_test.cc
libtestutils_la_SOURCES += mockups.h
libtestutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
endif
+
+EXTRA_DIST = portconfig.h
diff --git a/src/lib/testutils/portconfig.h b/src/lib/testutils/portconfig.h
new file mode 100644
index 0000000..8e61ffc
--- /dev/null
+++ b/src/lib/testutils/portconfig.h
@@ -0,0 +1,189 @@
+// 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.
+
+#ifndef TESTUTILS_PORTCONFIG_H
+#define TESTUTILS_PORTCONFIG_H
+
+#include <gtest/gtest.h>
+#include <cc/data.h>
+#include <server_common/portconfig.h>
+
+namespace isc {
+namespace testutils {
+/**
+ * \brief Bits of tests for server port configuration.
+ *
+ * These are bits of tests that can be reused by server classes to check if
+ * configuration of the listening addresses work.
+ *
+ * You can put any of these functions into a TEST_F test and pass the server
+ * to it.
+ *
+ * \todo There's quite a lot of common code in the basic server handling.
+ * We should refactor it, so both Resolver server and Auth server have
+ * a common base class. When this is done, the common parts would be put
+ * there and the tests would be at the base class, not here.
+ */
+namespace portconfig {
+
+/**
+ * \brief Check setting of the listening addresses directly (as a list) works.
+ *
+ * \param server The server to test against.
+ */
+template<class Server>
+void
+listenAddresses(Server& server) {
+ using namespace isc::server_common::portconfig;
+ // Default value should be fully recursive
+ EXPECT_TRUE(server.getListenAddresses().empty());
+
+ // Try putting there some addresses
+ AddressList addresses;
+ addresses.push_back(AddressPair("127.0.0.1", 53210));
+ addresses.push_back(AddressPair("::1", 53210));
+ server.setListenAddresses(addresses);
+ EXPECT_EQ(2, server.getListenAddresses().size());
+ EXPECT_EQ("::1", server.getListenAddresses()[1].first);
+
+ // Is it independent from what we do with the vector later?
+ addresses.clear();
+ EXPECT_EQ(2, server.getListenAddresses().size());
+
+ // Did it return to fully recursive?
+ server.setListenAddresses(addresses);
+ EXPECT_TRUE(server.getListenAddresses().empty());
+}
+
+/**
+ * \brief Check setting of the addresses by config value.
+ *
+ * This passes an listen_on element to the server's updateConfig function.
+ * It tries little bit of switching around. It tries both setting a presumably
+ * valid addresses and then setting something that cant be bound, rolling back
+ * back to original.
+ *
+ * \param server The server object to test against.
+ */
+template<class Server>
+void
+listenAddressConfig(Server& server) {
+ using namespace isc::data;
+ // Try putting there some address
+ ElementPtr config(Element::fromJSON("{"
+ "\"listen_on\": ["
+ " {"
+ " \"address\": \"127.0.0.1\","
+ " \"port\": 53210"
+ " }"
+ "]"
+ "}"));
+ ConstElementPtr result(server.updateConfig(config));
+ EXPECT_EQ(result->toWire(), isc::config::createAnswer()->toWire());
+ ASSERT_EQ(1, server.getListenAddresses().size());
+ EXPECT_EQ("127.0.0.1", server.getListenAddresses()[0].first);
+ EXPECT_EQ(53210, server.getListenAddresses()[0].second);
+
+ // As this is example address, the machine should not have it on
+ // any interface
+ config = Element::fromJSON("{"
+ "\"listen_on\": ["
+ " {"
+ " \"address\": \"192.0.2.0\","
+ " \"port\": 53210"
+ " }"
+ "]"
+ "}");
+ result = server.updateConfig(config);
+ EXPECT_FALSE(result->equals(*isc::config::createAnswer()));
+ ASSERT_EQ(1, server.getListenAddresses().size());
+ EXPECT_EQ("127.0.0.1", server.getListenAddresses()[0].first);
+ EXPECT_EQ(53210, server.getListenAddresses()[0].second);
+
+}
+
+/**
+ * \brief Check that given config is rejected.
+ *
+ * Try if given config is considered invalid by the server and is rejected.
+ * The value is converted from JSON to the data elements and passed to server's
+ * updateConfig method. It should not crash, but return a negative answer.
+ *
+ * It is used internally by invalidListenAddressConfig, but you can use it
+ * to test any other invalid configs.
+ *
+ * \todo It might be better to put it to some other namespace, as this is more
+ * generic. But right now it is used only here, so until something else
+ * needs it, it might as well stay here.
+ * \param server The server to test against.
+ * \param JSON Config to use.
+ * \param name It is used in the output if the test fails.
+ */
+template<class Server>
+void
+configRejected(Server& server, const std::string& JSON,
+ const std::string& name)
+{
+ SCOPED_TRACE(name);
+
+ using namespace isc::data;
+ ElementPtr config(Element::fromJSON(JSON));
+ EXPECT_FALSE(server.updateConfig(config)->
+ equals(*isc::config::createAnswer())) <<
+ "Accepted invalid config " << JSON;
+}
+
+/**
+ * \brief Check some invalid address configs.
+ *
+ * It tries a series of invalid listen_on configs against the server and checks
+ * it is rejected.
+ * \param server The server to check against.
+ */
+template<class Server>
+void
+invalidListenAddressConfig(Server& server) {
+ configRejected(server, "{"
+ "\"listen_on\": \"error\""
+ "}", "Wrong element type");
+ configRejected(server, "{"
+ "\"listen_on\": [{}]"
+ "}", "Empty address element");
+ configRejected(server, "{"
+ "\"listen_on\": [{"
+ " \"port\": 1.5,"
+ " \"address\": \"192.0.2.1\""
+ "}]}", "Float port");
+ configRejected(server, "{"
+ "\"listen_on\": [{"
+ " \"port\": -5,"
+ " \"address\": \"192.0.2.1\""
+ "}]}", "Negative port");
+ configRejected(server, "{"
+ "\"listen_on\": [{"
+ " \"port\": 1000000,"
+ " \"address\": \"192.0.2.1\""
+ "}]}", "Huge port");
+ configRejected(server, "{"
+ "\"listen_on\": [{"
+ " \"port\": 53,"
+ " \"address\": \"bad_address\""
+ "}]}", "Bad address");
+}
+
+}
+}
+}
+
+#endif
diff --git a/src/lib/testutils/srv_test.cc b/src/lib/testutils/srv_test.cc
index c0d6e0f..4fec4ca 100644
--- a/src/lib/testutils/srv_test.cc
+++ b/src/lib/testutils/srv_test.cc
@@ -60,7 +60,7 @@ SrvTestBase::createDataFromFile(const char* const datafile,
delete endpoint;
endpoint = IOEndpoint::create(protocol,
- IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
+ IOAddress(DEFAULT_REMOTE_ADDRESS), 53210);
UnitTestUtil::readWireData(datafile, data);
io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
&IOSocket::getDummyTCPSocket();
@@ -76,7 +76,7 @@ SrvTestBase::createRequestPacket(Message& message,
delete io_message;
endpoint = IOEndpoint::create(protocol,
- IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
+ IOAddress(DEFAULT_REMOTE_ADDRESS), 53210);
io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
&IOSocket::getDummyTCPSocket();
io_message = new IOMessage(request_renderer.getData(),
diff --git a/tools/README b/tools/README
index a18b38a..ce8ddea 100644
--- a/tools/README
+++ b/tools/README
@@ -1,3 +1,4 @@
The "tools" directory contains scripts for helping the BIND 10
-developers maintain the source tree. These are not intended
-to be built nor installed by the build system.
+developers with various tasks, eg. maintaining the source tree,
+running some tests. These are not intended to be built nor
+installed by the build system.
diff --git a/tools/import_boost.sh b/tools/import_boost.sh
deleted file mode 100755
index 07abe8c..0000000
--- a/tools/import_boost.sh
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-
-# given a directory, copy all needed parts from boost into the
-# current branch
-
-# only run this to update boost! (i.e. almost never)
-
-# usage example:
-# cd /tmp
-# tar xzvf /location/of/boost/tarball
-# cd /home/user/svn/bind10/trunk
-# tools/import_boost.sh /tmp/boost-version
-# svn commit
-
-# need new boost stuff?
-# TODO: LICENSE_1_0.txt
-# add files to list 'ere
-FILES="
-boost/*.hpp
-boost/algorithm
-boost/asio
-boost/assign/list_inserter.hpp
-boost/assign/std/vector.hpp
-boost/bind
-boost/config
-boost/concept
-boost/detail
-boost/exception
-boost/function
-boost/iterator
-boost/mpl
-boost/preprocessor
-boost/python
-boost/range
-boost/smart_ptr
-boost/type_traits
-boost/utility
-"
-
-TARGET="ext"
-
-if [ $# -ne 1 ]
-then
- echo "Usage: boost_import.sh <boost directory>"
- exit
-fi
-
-if [ ! -d $TARGET/boost ]
-then
- echo "This does not appear to be the main trunk/branch directory"
- exit
-fi
-
-
-DIR=$1
-
-do_cmd()
-{
- echo $@
- $@
-}
-
-
-#echo "cp ${DIR}/boost/shared_ptr.hpp boost/"
-for FILE in ${FILES}
-do
-TGT=`echo ${FILE} | sed 's/[^\/]*$//'`
-cmd="mkdir -p ${TARGET}/${TGT}"
-do_cmd ${cmd}
-cmd="cp -r ${DIR}/${FILE} ${TARGET}/${TGT}"
-do_cmd ${cmd}
-done
-
-
diff --git a/tools/tests_in_valgrind.sh b/tools/tests_in_valgrind.sh
new file mode 100755
index 0000000..14e91ba
--- /dev/null
+++ b/tools/tests_in_valgrind.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+###########################################
+# This script runs all tests in valgrind. Configure and compile bind the way
+# you want it to be tested (you should use --with-gtest, however, or you get
+# no tests). Then run this script from the top build directory.
+#
+# Note that the test isn't what you would call "production quality" (it is
+# expected to be used by the bind10 developers, not end user) and might break,
+# some ways of breaking it are known.
+#
+# There are two variables that modify it's behaviour.
+# * VALGRIND_FLAGS are the flag passed to valgrind. There are some, hopefully
+# reasonable defaults which you can overwrite. Note that the variable is
+# used unmodified inside a sed pattern with # as a modifier, which can
+# easily break it. There was no motivation to fix this.
+# * VALGRIND_FILE is the file to store the output into. Default is valgrind.log
+###########################################
+
+# First, make sure the tests are up to date
+make
+
+if [ $? = 2 ] ; then
+ echo "Did you run configure? Or maybe you're running the script from the tools directory? (you need to run it from the top bind10 build directory)"
+ exit 1
+fi
+
+set -e
+
+# Some configuration
+# TODO Escape for sed, this might break
+LOGFILE="${VALGRIND_FILE:-`pwd`/valgrind.log}"
+FLAGS="${VALGRIND_FLAGS:---leak-check=full --track-fds=yes}"
+FLAGS="$FLAGS --log-file=$LOGFILE.%p"
+
+FOUND_ANY=false
+FAILED=
+
+# Find all the tests (yes, doing it by a name is a nasty hack)
+# Since the while runs in a subprocess, we need to get the assignments out, done by the eval
+eval $(find . -type f -name run_unittests -print | grep -v '\.libs/run_unittests$' | while read testname ; do
+ sed -e 's#exec "#exec valgrind '"$FLAGS"' "#' "$testname" > "$testname.valgrind"
+ chmod +x "$testname.valgrind"
+ echo "$testname" >>"$LOGFILE"
+ echo "===============" >>"$LOGFILE"
+ OLDDIR="`pwd`"
+ cd $(dirname "$testname")
+ ./run_unittests.valgrind >&2 &
+ PID="$!"
+ set +e
+ wait "$PID"
+ CODE="$?"
+ set -e
+ cd "$OLDDIR"
+ if [ "$CODE" != 0 ] ; then
+ echo 'FAILED="$FAILED
+'"$testname"'"'
+ fi
+ NAME="$LOGFILE.$PID"
+ rm "$testname.valgrind"
+ # Remove the ones from death tests
+ grep "==$PID==" "$NAME" >>"$LOGFILE"
+ rm "$NAME"
+ echo 'FOUND_ANY=true'
+done)
+
+if test -n "$FAILED"; then
+ echo "These tests failed:" >&2
+ echo "$FAILED" >&2
+fi
+
+if ! $FOUND_ANY ; then
+ echo "No test was found. It is possible you configured without --with-gtest or you run it from wrong directory" >&2
+ exit 1
+fi
diff --git a/tools/valgrind_test_cleaner.pl b/tools/valgrind_test_cleaner.pl
new file mode 100755
index 0000000..9928e9f
--- /dev/null
+++ b/tools/valgrind_test_cleaner.pl
@@ -0,0 +1,64 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+# This script can be used on a valgrind output of the tests (from
+# tests_in_valgrind.sh) to remove some uninteresting error reports.
+# Since we care about the tested application not leaking/crashing, not
+# the tests itself, memory leaks that are caused only by the tests
+# (eg. unreleased test data), we don't want to have logs full of them.
+#
+# This script does some heuristics to eliminate some of such error
+# reports. Currently, the memory lost reports whose stack contains
+# no call from the real application are suppressed.
+#
+# Of course, the rest still can contain many uninteresting entries.
+
+# Yes, it's perl even when we use python. I wrote it for myself when
+# I needed to clean the outputs and after it proved useful to me, I
+# thought it might be for others too, so I just included it. It's not
+# that we would be switching to perl. If it should grow in future to
+# include more heuristics and do something more fancy, we should probably
+# rewrite it in python instead.
+
+my ($block, $blockOK);
+
+sub endBlock(_) {
+ return unless $block;
+ if ($blockOK) {
+ print @$block;
+ }
+ undef $block;
+ undef $blockOK;
+}
+
+sub startBlock(_) {
+ $block = [@_];
+}
+
+sub addToBlock(_) {
+ my ($line) = @_;
+ push @$block, $line;
+ return unless $line =~ /^==\d+==\s+(at|by) 0x[0-9A-F]+: (.*) \(.+:\d+\)$/;
+ $_ = $2;
+ return $blockOK = 1 if /^isc::/;
+ return $blockOK = 1 if /^asiolink:/;
+ return if /^main \(/;
+ return if /^testing::/;
+ return if /^\(anonymous namespace\)::/;
+ $blockOK = 1;
+}
+
+while(<>) {
+ if (/^==\d+==\s*$/) {
+ print;
+ endBlock;
+ } elsif (/^==\d+==\s+\d+bytes.*lost in loss record/) {
+ startBlock;
+ } elsif ($block) {
+ addToBlock;
+ } else {
+ print;
+ }
+}
+endBlock;
More information about the bind10-changes
mailing list