Browse Source

Merge branch 'master' into trac1605

Stephen Morris 13 years ago
parent
commit
ba1bfc79c7
100 changed files with 2175 additions and 960 deletions
  1. 77 12
      ChangeLog
  2. 45 24
      configure.ac
  3. 64 60
      doc/guide/bind10-guide.html
  4. 38 20
      doc/guide/bind10-guide.txt
  5. 45 33
      doc/guide/bind10-guide.xml
  6. 111 39
      doc/guide/bind10-messages.html
  7. 208 61
      doc/guide/bind10-messages.xml
  8. 2 0
      ext/asio/asio/detail/impl/kqueue_reactor.ipp
  9. 18 18
      ext/asio/asio/detail/impl/socket_ops.ipp
  10. 9 3
      src/bin/auth/auth_srv.cc
  11. 11 7
      src/bin/auth/b10-auth.8
  12. 12 7
      src/bin/auth/b10-auth.xml
  13. 70 100
      src/bin/auth/query.cc
  14. 56 0
      src/bin/auth/query.h
  15. 1 2
      src/bin/auth/tests/auth_srv_unittest.cc
  16. 3 5
      src/bin/auth/tests/query_unittest.cc
  17. 25 27
      src/bin/bind10/bind10.8
  18. 47 28
      src/bin/bind10/bind10.xml
  19. 1 1
      src/bin/bind10/bind10_src.py.in
  20. 30 3
      src/bin/cmdctl/b10-cmdctl.8
  21. 47 3
      src/bin/cmdctl/b10-cmdctl.xml
  22. 7 5
      src/bin/ddns/b10-ddns.8
  23. 8 5
      src/bin/ddns/b10-ddns.xml
  24. 1 1
      src/bin/dhcp4/Makefile.am
  25. 1 1
      src/bin/dhcp6/Makefile.am
  26. 2 3
      src/bin/host/host.cc
  27. 6 4
      src/bin/resolver/b10-resolver.8
  28. 7 4
      src/bin/resolver/b10-resolver.xml
  29. 5 2
      src/bin/resolver/resolver.cc
  30. 1 1
      src/bin/sockcreator/main.cc
  31. 59 8
      src/bin/sockcreator/sockcreator.cc
  32. 11 10
      src/bin/sockcreator/sockcreator.h
  33. 3 2
      src/bin/sockcreator/tests/Makefile.am
  34. 68 13
      src/bin/sockcreator/tests/sockcreator_tests.cc
  35. 8 15
      src/bin/stats/b10-stats-httpd.8
  36. 10 7
      src/bin/stats/b10-stats-httpd.xml
  37. 20 18
      src/bin/stats/b10-stats.8
  38. 21 17
      src/bin/stats/b10-stats.xml
  39. 6 9
      src/bin/xfrout/b10-xfrout.8
  40. 9 46
      src/bin/xfrout/b10-xfrout.xml
  41. 35 15
      src/bin/xfrout/tests/xfrout_test.py.in
  42. 4 18
      src/bin/xfrout/xfrout.py.in
  43. 0 42
      src/bin/xfrout/xfrout.spec.pre.in
  44. 6 4
      src/bin/zonemgr/b10-zonemgr.8
  45. 7 4
      src/bin/zonemgr/b10-zonemgr.xml
  46. 16 5
      src/cppcheck-suppress.lst
  47. 1 0
      src/lib/asiodns/Makefile.am
  48. 0 16
      src/lib/asiodns/dns_server.h
  49. 5 2
      src/lib/asiodns/io_fetch.cc
  50. 215 0
      src/lib/asiodns/sync_udp_server.cc
  51. 161 0
      src/lib/asiodns/sync_udp_server.h
  52. 0 3
      src/lib/asiodns/tcp_server.h
  53. 84 35
      src/lib/asiodns/tests/dns_server_unittest.cc
  54. 17 10
      src/lib/asiodns/tests/io_fetch_unittest.cc
  55. 0 5
      src/lib/asiodns/udp_server.cc
  56. 0 10
      src/lib/asiodns/udp_server.h
  57. 4 5
      src/lib/bench/benchmark_util.cc
  58. 0 1
      src/lib/config/module_spec.cc
  59. 3 3
      src/lib/datasrc/Makefile.am
  60. 1 1
      src/lib/datasrc/datasrc_config.h.pre.in
  61. 1 1
      src/lib/datasrc/datasrc_messages.mes
  62. 34 18
      src/lib/datasrc/memory_datasrc.cc
  63. 8 0
      src/lib/datasrc/sqlite3_datasrc.cc
  64. 1 0
      src/lib/datasrc/static_datasrc.cc
  65. 1 2
      src/lib/datasrc/tests/datasrc_unittest.cc
  66. 51 7
      src/lib/datasrc/tests/memory_datasrc_unittest.cc
  67. 1 0
      src/lib/datasrc/tests/static_unittest.cc
  68. 2 2
      src/lib/dhcp/iface_mgr.cc
  69. 1 2
      src/lib/dns/benchmarks/rdatarender_bench.cc
  70. 32 1
      src/lib/dns/masterload.cc
  71. 33 7
      src/lib/dns/messagerenderer.cc
  72. 63 31
      src/lib/dns/messagerenderer.h
  73. 2 1
      src/lib/dns/python/message_python.cc
  74. 1 5
      src/lib/dns/python/messagerenderer_python.cc
  75. 2 4
      src/lib/dns/rdatafields.cc
  76. 1 3
      src/lib/dns/tests/edns_unittest.cc
  77. 98 0
      src/lib/dns/tests/masterload_unittest.cc
  78. 3 8
      src/lib/dns/tests/message_unittest.cc
  79. 64 22
      src/lib/dns/tests/messagerenderer_unittest.cc
  80. 6 7
      src/lib/dns/tests/name_unittest.cc
  81. 3 3
      src/lib/dns/tests/question_unittest.cc
  82. 1 1
      src/lib/dns/tests/rdata_afsdb_unittest.cc
  83. 2 2
      src/lib/dns/tests/rdata_cname_unittest.cc
  84. 2 2
      src/lib/dns/tests/rdata_dname_unittest.cc
  85. 2 2
      src/lib/dns/tests/rdata_dnskey_unittest.cc
  86. 2 2
      src/lib/dns/tests/rdata_ds_like_unittest.cc
  87. 3 2
      src/lib/dns/tests/rdata_hinfo_unittest.cc
  88. 1 1
      src/lib/dns/tests/rdata_in_a_unittest.cc
  89. 1 1
      src/lib/dns/tests/rdata_in_aaaa_unittest.cc
  90. 4 4
      src/lib/dns/tests/rdata_minfo_unittest.cc
  91. 3 3
      src/lib/dns/tests/rdata_mx_unittest.cc
  92. 3 2
      src/lib/dns/tests/rdata_naptr_unittest.cc
  93. 2 2
      src/lib/dns/tests/rdata_ns_unittest.cc
  94. 1 1
      src/lib/dns/tests/rdata_nsec3param_like_unittest.cc
  95. 2 2
      src/lib/dns/tests/rdata_nsec3param_unittest.cc
  96. 2 2
      src/lib/dns/tests/rdata_nsec_unittest.cc
  97. 1 1
      src/lib/dns/tests/rdata_nsecbitmap_unittest.cc
  98. 2 2
      src/lib/dns/tests/rdata_ptr_unittest.cc
  99. 1 1
      src/lib/dns/tests/rdata_rp_unittest.cc
  100. 0 0
      src/lib/dns/tests/rdata_soa_unittest.cc

+ 77 - 12
ChangeLog

@@ -1,6 +1,69 @@
-382.	[func]	jelte
+391.	[bug]*		vorner
+	The long time unused configuration options of Xfrout "log_name",
+	"log_file", "log_severity", "log_version" and "log_max_bytes" were
+	removed, as they had no effect (Xfrout uses the global logging framework).
+	However, if you have them set, you need to remove them from the
+	configuration file or the configuration will be rejected.
+	(Trac #1090, git ef1eba02e4cf550e48e7318702cff6d67c1ec82e)
+
+bind10-devel-20120301 released on March 1, 2012
+
+390.	[bug]		vorner
+	The UDP IPv6 packets are now correctly fragmented for maximum
+	guaranteed MTU, so they won't get lost because being too large
+	for some hop.
+	(Trac #1534, git ff013364643f9bfa736b2d23fec39ac35872d6ad)
+
+389.	[func]*		vorner
+	Xfrout now uses the global TSIG keyring, instead of its own. This
+	means the keys need to be set only once (in tsig_keys/keys).
+	However, the old configuration of Xfrout/tsig_keys need to be
+	removed for Xfrout to work.
+	(Trac #1643, git 5a7953933a49a0ddd4ee1feaddc908cd2285522d)
+
+388.	[func]		jreed
+	Use prefix "sockcreator-" for the private temporary directory
+	used for b10-sockcreator communication.
+	(git b98523c1260637cb33436964dc18e9763622a242)
+
+387.	[build]		muks
+	Accept a --without-werror configure switch so that some builders can
+	disable the use of -Werror in CFLAGS when building.
+	(Trac #1671, git 8684a411d7718a71ad9fb616f56b26436c4f03e5)
+
+386.	[bug]		jelte
+	Upon initial sqlite3 database creation, the 'diffs' table is now
+	always created. This already happened most of the time, but there
+	are a few cases where it was skipped, resulting in potential errors
+	in xfrout later.
+	(Trac #1717, git 30d7686cb6e2fa64866c983e0cfb7b8fabedc7a2)
+
+385.	[bug]		jinmei
+	libdns++: masterLoad() didn't accept comments placed at the end of
+	an RR.  Due to this the in-memory data source cannot load a master
+	file for a signed zone even if it's preprocessed with BIND 9's
+	named-compilezone.
+	Note: this fix is considered temporary and still only accepts some
+	limited form of such comments.  The main purpose is to allow the
+	in-memory data source to load any signed or unsigned zone files as
+	long as they are at least normalized with named-compilezone.
+	(Trac #1667, git 6f771b28eea25c693fe93a0e2379af924464a562)
+
+384.	[func]		jinmei, jelte, vorner, haikuo, kevin
+	b10-auth now supports NSEC3-signed zones in the in-memory data
+	source.
+	(Trac #1580, #1581, #1582, #1583, #1584, #1585, #1587, and
+	other related changes to the in-memory data source)
+
+383.	[build]		jinmei
+	Fixed build failure on MacOS 10.7 (Lion) due to the use of
+	IPV6_PKTINFO; the OS requires a special definition to make it
+	visible to the compiler.
+	(Trac #1633, git 19ba70c7cc3da462c70e8c4f74b321b8daad0100)
+
+382.	[func]		jelte
 	b10-auth now also experimentally supports statistics counters of
-	the rcode reponses it sends. The counters can be shown as
+	the rcode responses it sends. The counters can be shown as
 	rcode.<code name>, where code name is the lowercase textual
 	representation of the rcode (e.g. "noerror", "formerr", etc.).
 	Same note applies as for opcodes, see changelog entry 364.
@@ -50,11 +113,11 @@
 	(Trac #1570, git 2858b2098a10a8cc2d34bf87463ace0629d3670e)
 
 375.	[func]		jelte
-	Modules now inform the system when they are stopping. As a result, they
-	are removed from the 'active modules' list in bindctl, which can then
-	inform the user directly when it tries to send them a command or
-	configuration update. Previously this would result in a 'not
-	responding' error instead of 'not running'.
+	Modules now inform the system when they are stopping. As a result,
+	they are removed from the 'active modules' list in bindctl, which
+	can then inform the user directly when it tries to send them a
+	command or configuration update.  Previously this would result
+	in a 'not responding' error instead of 'not running'.
 	(Trac #640, git 17e78fa1bb1227340aa9815e91ed5c50d174425d)
 
 374.	[func]*		stephen
@@ -90,10 +153,11 @@
 	(Trac #1575, git 2c421b58e810028b303d328e4e2f5b74ea124839)
 
 369.	[func]		vorner
-	The SocketRequestor provides more information about what error happened
-	when it throws, by using subclasses of the original exception. This way
-	a user not interested in the difference can still use the original
-	exception, while it can be recognized if necessary.
+	The SocketRequestor provides more information about what error
+	happened when it throws, by using subclasses of the original
+	exception. This way a user not interested in the difference can
+	still use the original exception, while it can be recognized if
+	necessary.
 	(Trac #1542, git 2080e0316a339fa3cadea00e10b1ec4bc322ada0)
 
 368.	[func]*		jinmei
@@ -151,7 +215,8 @@ bind10-devel-20120119 released on January 19, 2012
 	configuration.  If your b10-config.db contains "setuid" for
 	Boss.components, you'll need to remove that entry by hand before
 	starting BIND 10.
-	(Trac #1508-#1510, git edc5b3c12eb45437361484c843794416ad86bb00)
+	(Trac #1508, #1509, #1510,
+	git edc5b3c12eb45437361484c843794416ad86bb00)
 
 361.	[func]		vorner,jelte,jinmei
 	The socket creator is now used to provide sockets. It means you can

+ 45 - 24
configure.ac

@@ -5,6 +5,7 @@ AC_PREREQ([2.59])
 AC_INIT(bind10-devel, 20120127, bind10-dev@isc.org)
 AC_CONFIG_SRCDIR(README)
 AM_INIT_AUTOMAKE
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])dnl be backward compatible
 AC_CONFIG_HEADERS([config.h])
 
 # Checks for programs.
@@ -108,6 +109,10 @@ case "$host" in
 	LDFLAGS="$LDFLAGS -z now"
 	;;
 *-apple-darwin*)
+	# Starting with OSX 10.7 (Lion) we must choose which IPv6 API to use
+	# (RFC2292 or RFC3542).
+	CPPFLAGS="$CPPFLAGS -D__APPLE_USE_RFC_3542"
+
 	# libtool doesn't work perfectly with Darwin: libtool embeds the
 	# final install path in dynamic libraries and our loadable python
 	# modules always refer to that path even if it's loaded within the
@@ -270,7 +275,7 @@ AC_DEFUN([BIND10_CXX_TRY_FLAG], [
   bind10_save_CXXFLAGS="$CXXFLAGS"
   CXXFLAGS="$CXXFLAGS $1"
 
-  AC_LINK_IFELSE([int main(void){ return 0;} ],
+  AC_LINK_IFELSE([int main(void){ return 0;}],
                  [bind10_cxx_flag=yes], [bind10_cxx_flag=no])
   CXXFLAGS="$bind10_save_CXXFLAGS"
 
@@ -283,8 +288,6 @@ AC_DEFUN([BIND10_CXX_TRY_FLAG], [
   AC_MSG_RESULT([$bind10_cxx_flag])
 ])
 
-werror_ok=0
-
 # SunStudio compiler requires special compiler options for boost
 # (http://blogs.sun.com/sga/entry/boost_mini_howto)
 if test "$SUNCXX" = "yes"; then
@@ -292,7 +295,7 @@ CXXFLAGS="$CXXFLAGS -library=stlport4 -features=tmplife -features=tmplrefstatic"
 MULTITHREADING_FLAG="-mt"
 fi
 
-BIND10_CXX_TRY_FLAG(-Wno-missing-field-initializers,
+BIND10_CXX_TRY_FLAG([-Wno-missing-field-initializers],
 	[WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG="-Wno-missing-field-initializers"])
 AC_SUBST(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 
@@ -310,19 +313,34 @@ case "$host" in
 	;;
 esac
 
+# Don't use -Werror if configured not to
+AC_ARG_WITH(werror,
+    AC_HELP_STRING([--with-werror], [Compile using -Werror (default=yes)]),
+    [
+     case "${withval}" in
+         yes) with_werror=1 ;;
+         no)  with_werror=0 ;;
+         *)   AC_MSG_ERROR(bad value ${withval} for --with-werror) ;;
+     esac],
+     [with_werror=1])
+
+werror_ok=0
+
 # Certain versions of gcc (g++) have a bug that incorrectly warns about
 # the use of anonymous name spaces even if they're closed in a single
 # translation unit.  For these versions we have to disable -Werror.
-CXXFLAGS_SAVED="$CXXFLAGS"
-CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
-AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
-AC_TRY_COMPILE([namespace { class Foo {}; }
-namespace isc {class Bar {Foo foo_;};} ],,
+if test $with_werror = 1; then
+   CXXFLAGS_SAVED="$CXXFLAGS"
+   CXXFLAGS="$CXXFLAGS $B10_CXXFLAGS -Werror"
+   AC_MSG_CHECKING(for in-TU anonymous namespace breakage)
+   AC_TRY_COMPILE([namespace { class Foo {}; }
+   namespace isc {class Bar {Foo foo_;};} ],,
 	[AC_MSG_RESULT(no)
 	 werror_ok=1
 	 B10_CXXFLAGS="$B10_CXXFLAGS -Werror"],
 	[AC_MSG_RESULT(yes)])
-CXXFLAGS="$CXXFLAGS_SAVED"
+   CXXFLAGS="$CXXFLAGS_SAVED"
+fi
 
 # Python 3.2 has an unused parameter in one of its headers. This
 # has been reported, but not fixed as of yet, so we check if we need
@@ -517,21 +535,22 @@ else
         AC_PATH_PROG([BOTAN_CONFIG], [botan-config])
     fi
 fi
-
-BOTAN_LIBS=`${BOTAN_CONFIG} --libs`
-BOTAN_INCLUDES=`${BOTAN_CONFIG} --cflags`
-
-# We expect botan-config --libs to contain -L<path_to_libbotan>, but
-# this is not always the case.  As a heuristics workaround we add
-# -L`botan-config --prefix/lib` in this case (if not present already).
-# Same for BOTAN_INCLUDES (but using include instead of lib) below.
-if [ $BOTAN_CONFIG --prefix >/dev/null 2>&1 ] ; then
-    echo ${BOTAN_LIBS} | grep -- -L > /dev/null || \
-        BOTAN_LIBS="-L`${BOTAN_CONFIG} --prefix`/lib ${BOTAN_LIBS}"
-    echo ${BOTAN_INCLUDES} | grep -- -I > /dev/null || \
-        BOTAN_INCLUDES="-I`${BOTAN_CONFIG} --prefix`/include ${BOTAN_INCLUDES}"
+if test "x${BOTAN_CONFIG}" != "x"
+then
+    BOTAN_LIBS=`${BOTAN_CONFIG} --libs`
+    BOTAN_INCLUDES=`${BOTAN_CONFIG} --cflags`
+
+    # We expect botan-config --libs to contain -L<path_to_libbotan>, but
+    # this is not always the case.  As a heuristics workaround we add
+    # -L`botan-config --prefix/lib` in this case (if not present already).
+    # Same for BOTAN_INCLUDES (but using include instead of lib) below.
+    if [ ${BOTAN_CONFIG} --prefix >/dev/null 2>&1 ] ; then
+        echo ${BOTAN_LIBS} | grep -- -L > /dev/null || \
+            BOTAN_LIBS="-L`${BOTAN_CONFIG} --prefix`/lib ${BOTAN_LIBS}"
+        echo ${BOTAN_INCLUDES} | grep -- -I > /dev/null || \
+            BOTAN_INCLUDES="-I`${BOTAN_CONFIG} --prefix`/include ${BOTAN_INCLUDES}"
+    fi
 fi
-
 # botan-config script (and the way we call pkg-config) returns -L and -l
 # as one string, but we need them in separate values
 BOTAN_LDFLAGS=
@@ -1001,6 +1020,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/python/isc/bind10/tests/Makefile
                  src/lib/python/isc/xfrin/Makefile
                  src/lib/python/isc/xfrin/tests/Makefile
+                 src/lib/python/isc/server_common/Makefile
+                 src/lib/python/isc/server_common/tests/Makefile
                  src/lib/config/Makefile
                  src/lib/config/tests/Makefile
                  src/lib/config/tests/testdata/Makefile

File diff suppressed because it is too large
+ 64 - 60
doc/guide/bind10-guide.html


+ 38 - 20
doc/guide/bind10-guide.txt

@@ -221,18 +221,22 @@ Chapter 1. Introduction
    processes as needed. The processes started by the bind10 command have
    names starting with "b10-", including:
 
-     o b10-msgq -- Message bus daemon. This process coordinates communication
-       between all of the other BIND 10 processes.
      o b10-auth -- Authoritative DNS server. This process serves DNS
        requests.
      o b10-cfgmgr -- Configuration manager. This process maintains all of the
        configuration for BIND 10.
      o b10-cmdctl -- Command and control service. This process allows
        external control of the BIND 10 system.
+     o b10-msgq -- Message bus daemon. This process coordinates communication
+       between all of the other BIND 10 processes.
      o b10-resolver -- Recursive name server. This process handles incoming
        queries.
+     o b10-sockcreator -- Socket creator daemon. This process creates sockets
+       used by network-listening BIND 10 processes.
      o b10-stats -- Statistics collection daemon. This process collects and
        reports statistics data.
+     o b10-stats-httpd -- HTTP server for statistics reporting. This process
+       reports statistics data in XML format over HTTP.
      o b10-xfrin -- Incoming zone transfer service. This process is used to
        transfer a new copy of a zone into BIND 10, when acting as a secondary
        server.
@@ -249,8 +253,9 @@ Chapter 1. Introduction
    Once BIND 10 is running, a few commands are used to interact directly with
    the system:
 
-     o bindctl -- interactive administration interface. This is a
-       command-line tool which allows an administrator to control BIND 10.
+     o bindctl -- interactive administration interface. This is a low-level
+       command-line tool which allows a developer or an experienced
+       administrator to control BIND 10.
      o b10-loadzone -- zone file loader. This tool will load standard
        masterfile-format zone files into BIND 10.
      o b10-cmdctl-usermgr -- user access control. This tool allows an
@@ -491,10 +496,11 @@ Chapter 3. Starting BIND10 with bind10
    b10-sockcreator will allocate sockets for the rest of the system.
 
    In its default configuration, the bind10 master process will also start up
-   b10-cmdctl for admins to communicate with the system, b10-auth for
-   authoritative DNS service, b10-stats for statistics collection, b10-xfrin
-   for inbound DNS zone transfers, b10-xfrout for outbound DNS zone
-   transfers, and b10-zonemgr for secondary service.
+   b10-cmdctl for administration tools to communicate with the system,
+   b10-auth for authoritative DNS service, b10-stats for statistics
+   collection, b10-stats-httpd for statistics reporting, b10-xfrin for
+   inbound DNS zone transfers, b10-xfrout for outbound DNS zone transfers,
+   and b10-zonemgr for secondary service.
 
 3.1. Starting BIND 10
 
@@ -600,6 +606,22 @@ Chapter 3. Starting BIND10 with bind10
 
    In short, you should think twice before disabling something here.
 
+   It is possible to start some components multiple times (currently b10-auth
+   and b10-resolzer). You might want to do that to gain more performance
+   (each one uses only single core). Just put multiple entries under
+   different names, like this, with the same config:
+
+ > config add Boss/components b10-resolver-2
+ > config set Boss/components/b10-resolver-2/special resolver
+ > config set Boss/components/b10-resolver-2/kind needed
+ > config commit
+
+   However, this is work in progress and the support is not yet complete. For
+   example, each resolver will have its own cache, each authoritative server
+   will keep its own copy of in-memory data and there could be problems with
+   locking the sqlite database, if used. The configuration might be changed
+   to something more convenient in future.
+
 Chapter 4. Command channel
 
    The BIND 10 components use the b10-msgq message routing daemon to
@@ -939,26 +961,22 @@ Chapter 10. Outbound Zone Transfers
    In the above example the lines for transfer_acl were divided for
    readability. In the actual input it must be in a single line.
 
-   If you want to require TSIG in access control, a separate TSIG "key ring"
-   must be configured specifically for b10-xfrout as well as a system wide
-   key ring, both containing a consistent set of keys. For example, to change
-   the previous example to allowing requests from 192.0.2.1 signed by a TSIG
-   with a key name of "key.example", you'll need to do this:
+   If you want to require TSIG in access control, a system wide TSIG "key
+   ring" must be configured. For example, to change the previous example to
+   allowing requests from 192.0.2.1 signed by a TSIG with a key name of
+   "key.example", you'll need to do this:
 
  > config set tsig_keys/keys ["key.example:<base64-key>"]
- > config set Xfrout/tsig_keys/keys ["key.example:<base64-key>"]
  > config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1", "key": "key.example"}]
  > config commit
 
-   The first line of configuration defines a system wide key ring. This is
-   necessary because the b10-auth server also checks TSIGs and it uses the
-   system wide configuration.
+   Both Xfrout and Auth will use the system wide keyring to check TSIGs in
+   the incomming messages and to sign responses.
 
   Note
 
-   In a future version, b10-xfrout will also use the system wide TSIG
-   configuration. The way to specify zone specific configuration (ACLs, etc)
-   is likely to be changed, too.
+   The way to specify zone specific configuration (ACLs, etc) is likely to be
+   changed.
 
 Chapter 11. Recursive Name Server
 

+ 45 - 33
doc/guide/bind10-guide.xml

@@ -172,15 +172,6 @@
 
           <listitem>
             <simpara>
-              <command>b10-msgq</command> &mdash;
-              Message bus daemon.
-              This process coordinates communication between all of the other
-              BIND 10 processes.
-            </simpara>
-          </listitem>
-
-          <listitem>
-            <simpara>
               <command>b10-auth</command> &mdash;
               Authoritative DNS server.
               This process serves DNS requests.
@@ -205,6 +196,15 @@
 
           <listitem>
             <simpara>
+              <command>b10-msgq</command> &mdash;
+              Message bus daemon.
+              This process coordinates communication between all of the other
+              BIND 10 processes.
+            </simpara>
+          </listitem>
+
+          <listitem>
+            <simpara>
               <command>b10-resolver</command> &mdash;
               Recursive name server.
               This process handles incoming queries.
@@ -214,6 +214,15 @@
 
           <listitem>
             <simpara>
+              <command>b10-sockcreator</command> &mdash;
+              Socket creator daemon.
+              This process creates sockets used by
+              network-listening BIND 10 processes.
+            </simpara>
+          </listitem>
+
+          <listitem>
+            <simpara>
               <command>b10-stats</command> &mdash;
               Statistics collection daemon.
               This process collects and reports statistics data.
@@ -222,6 +231,14 @@
 
           <listitem>
             <simpara>
+              <command>b10-stats-httpd</command> &mdash;
+              HTTP server for statistics reporting.
+              This process reports statistics data in XML format over HTTP.
+            </simpara>
+          </listitem>
+
+          <listitem>
+            <simpara>
               <command>b10-xfrin</command> &mdash;
               Incoming zone transfer service.
               This process is used to transfer a new copy
@@ -269,8 +286,9 @@
             <simpara>
               <command>bindctl</command> &mdash;
               interactive administration interface.
-              This is a command-line tool which allows an administrator
-              to control BIND 10.
+              This is a low-level command-line tool which allows
+              a developer or an experienced administrator to control
+              BIND 10.
             </simpara>
           </listitem>
           <listitem>
@@ -751,9 +769,11 @@ as a dependency earlier -->
     <para>
       In its default configuration, the <command>bind10</command>
       master process will also start up
-      <command>b10-cmdctl</command> for admins to communicate with the
-      system, <command>b10-auth</command> for authoritative DNS service,
+      <command>b10-cmdctl</command> for administration tools to
+      communicate with the system,
+      <command>b10-auth</command> for authoritative DNS service,
       <command>b10-stats</command> for statistics collection,
+      <command>b10-stats-httpd</command> for statistics reporting,
       <command>b10-xfrin</command> for inbound DNS zone transfers,
       <command>b10-xfrout</command> for outbound DNS zone transfers,
       and <command>b10-zonemgr</command> for secondary service.
@@ -889,7 +909,7 @@ address, but the usual ones don't." mean? -->
           This system allows you to start the same component multiple times
           (by including it in the configuration with different names, but the
           same process setting). However, the rest of the system doesn't expect
-          such situation, so it would probably not do what you want. Such
+          such a situation, so it would probably not do what you want. Such
           support is yet to be implemented.
         </para>
       </note>
@@ -901,10 +921,10 @@ address, but the usual ones don't." mean? -->
           <command>b10-cmdctl</command>, but then you couldn't
           change it back the usual way, as it would require it to
           be running (you would have to find and edit the configuration
-          directly).  Also, some modules might have dependencies
-          -- <command>b10-stats-httpd</command> need
+          directly).  Also, some modules might have dependencies:
+          <command>b10-stats-httpd</command> needs
           <command>b10-stats</command>, <command>b10-xfrout</command>
-          needs the <command>b10-auth</command> to be running, etc.
+          needs <command>b10-auth</command> to be running, etc.
 
 <!-- TODO: should we define dependencies? -->
 
@@ -999,7 +1019,7 @@ Unix domain sockets
 <!-- TODO -->
       <note>
         <para>
-          The development prototype release only provides the
+          The development prototype release only provides
           <command>bindctl</command> as a user interface to
           <command>b10-cmdctl</command>.
           Upcoming releases will provide another interactive command-line
@@ -1190,7 +1210,7 @@ or accounts database -->
       The port can be set by using the <option>--port</option> command line option.
       The address to listen on can be set using the <option>--address</option> command
       line argument.
-      Each HTTPS connection is stateless and timesout in 1200 seconds
+      Each HTTPS connection is stateless and times out in 1200 seconds
       by default.  This can be
       redefined by using the <option>--idle-timeout</option> command line argument.
     </para>
@@ -1629,31 +1649,23 @@ Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)</screen>
     </simpara></note>
 
     <para>
-      If you want to require TSIG in access control, a separate TSIG
-      "key ring" must be configured specifically
-      for <command>b10-xfrout</command> as well as a system wide
-      key ring, both containing a consistent set of keys.
+      If you want to require TSIG in access control, a system wide TSIG
+      "key ring" must be configured.
       For example, to change the previous example to allowing requests
       from 192.0.2.1 signed by a TSIG with a key name of
       "key.example", you'll need to do this:
     </para>
 
     <screen>&gt; <userinput>config set tsig_keys/keys ["key.example:&lt;base64-key&gt;"]</userinput>
-&gt; <userinput>config set Xfrout/tsig_keys/keys ["key.example:&lt;base64-key&gt;"]</userinput>
 &gt; <userinput>config set Xfrout/zone_config[0]/transfer_acl [{"action": "ACCEPT", "from": "192.0.2.1", "key": "key.example"}]</userinput>
 &gt; <userinput>config commit</userinput></screen>
 
-    <para>
-      The first line of configuration defines a system wide key ring.
-      This is necessary because the <command>b10-auth</command> server
-      also checks TSIGs and it uses the system wide configuration.
-    </para>
+    <para>Both Xfrout and Auth will use the system wide keyring to check
+    TSIGs in the incomming messages and to sign responses.</para>
 
     <note><simpara>
-        In a future version, <command>b10-xfrout</command> will also
-        use the system wide TSIG configuration.
         The way to specify zone specific configuration (ACLs, etc) is
-        likely to be changed, too.
+        likely to be changed.
     </simpara></note>
 
 <!--
@@ -2359,7 +2371,7 @@ eth0 fe80::21e:8cff:fe9b:7349
 
           In the Logging module, you can specify the configuration
           for zero or more loggers; any that are not specified will
-          take appropriate default values..
+          take appropriate default values.
 
         </para>
 

File diff suppressed because it is too large
+ 111 - 39
doc/guide/bind10-messages.html


+ 208 - 61
doc/guide/bind10-messages.xml

@@ -467,6 +467,14 @@ and it is entering the main loop, waiting for queries to arrive.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="AUTH_SHUTDOWN">
+<term>AUTH_SHUTDOWN asked to stop, doing so</term>
+<listitem><para>
+This is a debug message indicating the server was asked to shut down and it is
+complying to the request.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="AUTH_SQLITE3">
 <term>AUTH_SQLITE3 nothing to do for loading sqlite3</term>
 <listitem><para>
@@ -1766,6 +1774,26 @@ a bug report.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="CONFIG_CCSESSION_STOPPING">
+<term>CONFIG_CCSESSION_STOPPING error sending stopping message: %1</term>
+<listitem><para>
+There was a problem when sending a message signaling that the module using
+this CCSession is stopping. This message is sent so that the rest of the
+system is aware that the module is no longer running. Apart from logging
+this message, the error itself is ignored, and the ModuleCCSession is
+still stopped. The specific exception message is printed.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="CONFIG_CCSESSION_STOPPING_UNKNOWN">
+<term>CONFIG_CCSESSION_STOPPING_UNKNOWN unknown error sending stopping message</term>
+<listitem><para>
+Similar to CONFIG_CCSESSION_STOPPING, but in this case the exception that
+is seen is not a standard exception, and further information is unknown.
+This is a bug.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="CONFIG_GET_FAIL">
 <term>CONFIG_GET_FAIL error getting configuration from cfgmgr: %1</term>
 <listitem><para>
@@ -1873,6 +1901,28 @@ is included in the message.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="CONFIG_SESSION_STOPPING_FAILED">
+<term>CONFIG_SESSION_STOPPING_FAILED error sending stopping message: %1</term>
+<listitem><para>
+There was a problem when sending a message signaling that the module using
+this CCSession is stopping. This message is sent so that the rest of the
+system is aware that the module is no longer running. Apart from logging
+this message, the error itself is ignored, and the ModuleCCSession is
+still stopped. The specific exception message is printed.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="DATASRC_BAD_NSEC3_NAME">
+<term>DATASRC_BAD_NSEC3_NAME NSEC3 record has a bad owner name '%1'</term>
+<listitem><para>
+The software refuses to load NSEC3 records into a wildcard domain or
+the owner name has two or more labels below the zone origin.
+It isn't explicitly forbidden, but no sane zone wouldn have such names
+for NSEC3.  BIND 9 also refuses NSEC3 at wildcard, so this behavior is
+compatible with BIND 9.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DATASRC_CACHE_CREATE">
 <term>DATASRC_CACHE_CREATE creating the hotspot cache</term>
 <listitem><para>
@@ -2177,15 +2227,6 @@ its class and the database name are printed.
 </para></listitem>
 </varlistentry>
 
-<varlistentry id="DATASRC_DATABASE_UPDATER_COMMIT (1)">
-<term>DATASRC_DATABASE_UPDATER_COMMIT (1) updates committed for '%1/%2' on %3</term>
-<listitem><para>
-Debug information.  A set of updates to a zone has been successfully
-committed to the corresponding database backend.  The zone name,
-its class and the database name are printed.
-</para></listitem>
-</varlistentry>
-
 <varlistentry id="DATASRC_DATABASE_UPDATER_CREATED">
 <term>DATASRC_DATABASE_UPDATER_CREATED zone updater created for '%1/%2' on %3</term>
 <listitem><para>
@@ -2194,14 +2235,6 @@ the shown zone on the shown backend database.
 </para></listitem>
 </varlistentry>
 
-<varlistentry id="DATASRC_DATABASE_UPDATER_CREATED (1)">
-<term>DATASRC_DATABASE_UPDATER_CREATED (1) zone updater created for '%1/%2' on %3</term>
-<listitem><para>
-Debug information.  A zone updater object is created to make updates to
-the shown zone on the shown backend database.
-</para></listitem>
-</varlistentry>
-
 <varlistentry id="DATASRC_DATABASE_UPDATER_DESTROYED">
 <term>DATASRC_DATABASE_UPDATER_DESTROYED zone updater destroyed for '%1/%2' on %3</term>
 <listitem><para>
@@ -2211,15 +2244,6 @@ database.
 </para></listitem>
 </varlistentry>
 
-<varlistentry id="DATASRC_DATABASE_UPDATER_DESTROYED (1)">
-<term>DATASRC_DATABASE_UPDATER_DESTROYED (1) zone updater destroyed for '%1/%2' on %3</term>
-<listitem><para>
-Debug information.  A zone updater object is destroyed, either successfully
-or after failure of, making updates to the shown zone on the shown backend
-database.
-</para></listitem>
-</varlistentry>
-
 <varlistentry id="DATASRC_DATABASE_UPDATER_ROLLBACK">
 <term>DATASRC_DATABASE_UPDATER_ROLLBACK zone updates roll-backed for '%1/%2' on %3</term>
 <listitem><para>
@@ -2232,18 +2256,6 @@ the underlying database name are shown in the log message.
 </para></listitem>
 </varlistentry>
 
-<varlistentry id="DATASRC_DATABASE_UPDATER_ROLLBACK (1)">
-<term>DATASRC_DATABASE_UPDATER_ROLLBACK (1) zone updates roll-backed for '%1/%2' on %3</term>
-<listitem><para>
-A zone updater is being destroyed without committing the changes.
-This would typically mean the update attempt was aborted due to some
-error, but may also be a bug of the application that forgets committing
-the changes.  The intermediate changes made through the updater won't
-be applied to the underlying database.  The zone name, its class, and
-the underlying database name are shown in the log message.
-</para></listitem>
-</varlistentry>
-
 <varlistentry id="DATASRC_DATABASE_UPDATER_ROLLBACKFAIL">
 <term>DATASRC_DATABASE_UPDATER_ROLLBACKFAIL failed to roll back zone updates for '%1/%2' on %3: %4</term>
 <listitem><para>
@@ -2261,23 +2273,6 @@ database module are shown in the log message.
 </para></listitem>
 </varlistentry>
 
-<varlistentry id="DATASRC_DATABASE_UPDATER_ROLLBACKFAIL (1)">
-<term>DATASRC_DATABASE_UPDATER_ROLLBACKFAIL (1) failed to roll back zone updates for '%1/%2' on %3: %4</term>
-<listitem><para>
-A zone updater is being destroyed without committing the changes to
-the database, and attempts to rollback incomplete updates, but it
-unexpectedly fails.  The higher level implementation does not expect
-it to fail, so this means either a serious operational error in the
-underlying data source (such as a system failure of a database) or
-software bug in the underlying data source implementation.  In either
-case if this message is logged the administrator should carefully
-examine the underlying data source to see what exactly happens and
-whether the data is still valid.  The zone name, its class, and the
-underlying database name as well as the error message thrown from the
-database module are shown in the log message.
-</para></listitem>
-</varlistentry>
-
 <varlistentry id="DATASRC_DATABASE_WILDCARD_ANY">
 <term>DATASRC_DATABASE_WILDCARD_ANY search in datasource %1 resulted in wildcard match type ANY on %2</term>
 <listitem><para>
@@ -2497,6 +2492,46 @@ Debug information. A search for the requested RRset is being started.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="DATASRC_MEM_FINDNSEC3">
+<term>DATASRC_MEM_FINDNSEC3 finding NSEC3 for %1, mode %2</term>
+<listitem><para>
+Debug information. A search in an in-memory data source for NSEC3 that
+matches or covers the given name is being started.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="DATASRC_MEM_FINDNSEC3_COVER">
+<term>DATASRC_MEM_FINDNSEC3_COVER found a covering NSEC3 for %1: %2</term>
+<listitem><para>
+Debug information. An NSEC3 that covers the given name is found and
+being returned.  The found NSEC3 RRset is also displayed.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="DATASRC_MEM_FINDNSEC3_MATCH">
+<term>DATASRC_MEM_FINDNSEC3_MATCH found a matching NSEC3 for %1 at label count %2: %3</term>
+<listitem><para>
+Debug information. An NSEC3 that matches (a possibly superdomain of)
+the given name is found and being returned.  When the shown label
+count is smaller than that of the given name, the matching NSEC3 is
+for a superdomain of the given name (see DATASRC_MEM_FINDNSEC3_TRYHASH).
+The found NSEC3 RRset is also displayed.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="DATASRC_MEM_FINDNSEC3_TRYHASH">
+<term>DATASRC_MEM_FINDNSEC3_TRYHASH looking for NSEC3 for %1 at label count %2 (hash %3)</term>
+<listitem><para>
+Debug information. In an attempt of finding an NSEC3 for the give name,
+(a possibly superdomain of) the name is hashed and searched for in the
+NSEC3 name space.  When the shown label count is smaller than that of the
+shown name, the search tries the superdomain name that share the shown
+(higher) label count of the shown name (e.g., for
+www.example.com. with shown label count of 3, example.com. is being
+tried).
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DATASRC_MEM_FIND_ZONE">
 <term>DATASRC_MEM_FIND_ZONE looking for zone '%1'</term>
 <listitem><para>
@@ -2519,6 +2554,18 @@ Debug information. The requested domain does not exist.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="DATASRC_MEM_NO_NSEC3PARAM">
+<term>DATASRC_MEM_NO_NSEC3PARAM NSEC3PARAM is missing for NSEC3-signed zone %1/%2</term>
+<listitem><para>
+The in-memory data source has loaded a zone signed with NSEC3 RRs,
+but it doesn't have a NSEC3PARAM RR at the zone origin.  It's likely that
+the zone is somehow broken, but this RR is not necessarily needed for
+handling lookups with NSEC3 in this data source, so it accepts the given
+content of the zone.  Nevertheless the administrator should look into
+the integrity of the zone data.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DATASRC_MEM_NS_ENCOUNTERED">
 <term>DATASRC_MEM_NS_ENCOUNTERED encountered a NS</term>
 <listitem><para>
@@ -2570,11 +2617,13 @@ Debug information. The requested record was found.
 </varlistentry>
 
 <varlistentry id="DATASRC_MEM_SUPER_STOP">
-<term>DATASRC_MEM_SUPER_STOP stopped at superdomain '%1', domain '%2' is empty</term>
+<term>DATASRC_MEM_SUPER_STOP stopped as '%1' is superdomain of a zone node, meaning it's empty</term>
 <listitem><para>
-Debug information. The search stopped at a superdomain of the requested
-domain. The domain is an empty nonterminal, therefore it is treated  as NXRRSET
-case (eg. the domain exists, but it doesn't have the requested record type).
+Debug information. The search stopped because the requested domain was
+detected to be a superdomain of some existing node of zone (while there
+was no exact match).  This means that the domain is an empty nonterminal,
+therefore it is treated  as NXRRSET case (eg. the domain exists, but it
+doesn't have the requested record type).
 </para></listitem>
 </varlistentry>
 
@@ -2925,7 +2974,7 @@ the specific error already.
 </varlistentry>
 
 <varlistentry id="DATASRC_QUERY_RRSIG">
-<term>DATASRC_QUERY_RRSIG unable to answer RRSIG query</term>
+<term>DATASRC_QUERY_RRSIG unable to answer RRSIG query for %1</term>
 <listitem><para>
 The server is unable to answer a direct query for RRSIG type, but was asked
 to do so.
@@ -3232,6 +3281,16 @@ generated.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="DDNS_ACCEPT_FAILURE">
+<term>DDNS_ACCEPT_FAILURE error accepting a connection: %1</term>
+<listitem><para>
+There was a low-level error when we tried to accept an incoming connection
+(probably coming from b10-auth). We continue serving on whatever other
+connections we already have, but this connection is dropped. The reason
+is logged.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DDNS_CC_SESSION_ERROR">
 <term>DDNS_CC_SESSION_ERROR error reading from cc channel: %1</term>
 <listitem><para>
@@ -3257,6 +3316,17 @@ startup time.  Details of the error are included in the log message.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="DDNS_DROP_CONN">
+<term>DDNS_DROP_CONN dropping connection on file descriptor %1 because of error %2</term>
+<listitem><para>
+There was an error on a connection with the b10-auth server (or whatever
+connects to the ddns daemon). This might be OK, for example when the
+authoritative server shuts down, the connection would get closed. It also
+can mean the system is busy and can't keep up or that the other side got
+confused and sent bad data.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DDNS_MODULECC_SESSION_ERROR">
 <term>DDNS_MODULECC_SESSION_ERROR error encountered by configuration/command module: %1</term>
 <listitem><para>
@@ -3268,6 +3338,16 @@ will also be displayed.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="DDNS_NEW_CONN">
+<term>DDNS_NEW_CONN new connection on file descriptor %1 from %2</term>
+<listitem><para>
+Debug message. We received a connection and we are going to start handling
+requests from it. The file descriptor number and the address where the request
+comes from is logged. The connection is over a unix domain socket and is likely
+coming from a b10-auth process.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DDNS_RECEIVED_SHUTDOWN_COMMAND">
 <term>DDNS_RECEIVED_SHUTDOWN_COMMAND shutdown command received</term>
 <listitem><para>
@@ -3284,6 +3364,15 @@ and updates.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="DDNS_SESSION">
+<term>DDNS_SESSION session arrived on file descriptor %1</term>
+<listitem><para>
+A debug message, informing there's some activity on the given file descriptor.
+It will be either a request or the file descriptor will be closed. See
+following log messages to see what of it.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="DDNS_SHUTDOWN">
 <term>DDNS_SHUTDOWN ddns server shutting down</term>
 <listitem><para>
@@ -3826,6 +3915,32 @@ bug report.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="PYSERVER_COMMON_TSIG_KEYRING_DEINIT">
+<term>PYSERVER_COMMON_TSIG_KEYRING_DEINIT Deinitializing global TSIG keyring</term>
+<listitem><para>
+A debug message noting that the global TSIG keyring is being removed from
+memory. Most programs don't do that, they just exit, which is OK.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="PYSERVER_COMMON_TSIG_KEYRING_INIT">
+<term>PYSERVER_COMMON_TSIG_KEYRING_INIT Initializing global TSIG keyring</term>
+<listitem><para>
+A debug message noting the TSIG keyring storage is being prepared. It should
+appear at most once in the lifetime of a program. The keyring still needs
+to be loaded from configuration.
+</para></listitem>
+</varlistentry>
+
+<varlistentry id="PYSERVER_COMMON_TSIG_KEYRING_UPDATE">
+<term>PYSERVER_COMMON_TSIG_KEYRING_UPDATE Updating global TSIG keyring</term>
+<listitem><para>
+A debug message. The TSIG keyring is being (re)loaded from configuration.
+This happens at startup or when the configuration changes. The old keyring
+is removed and new one created with all the keys.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="RESLIB_ANSWER">
 <term>RESLIB_ANSWER answer received in response to query for &lt;%1&gt;</term>
 <listitem><para>
@@ -4571,6 +4686,14 @@ This informational message is output when the resolver has shut down.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="RESOLVER_SHUTDOWN (1)">
+<term>RESOLVER_SHUTDOWN (1) asked to shut down, doing so</term>
+<listitem><para>
+A debug message noting that the server was asked to terminate and is
+complying to the request.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="RESOLVER_STARTED">
 <term>RESOLVER_STARTED resolver started</term>
 <listitem><para>
@@ -4605,7 +4728,7 @@ a message to the sender with the RCODE set to NOTIMP.
 </varlistentry>
 
 <varlistentry id="SOCKETREQUESTOR_CREATED">
-<term>SOCKETREQUESTOR_CREATED Socket requestor created</term>
+<term>SOCKETREQUESTOR_CREATED Socket requestor created for application %1</term>
 <listitem><para>
 Debug message.  A socket requesor (client of the socket creator) is created
 for the corresponding application.  Normally this should happen at most
@@ -4706,6 +4829,21 @@ be hidden, as it has higher debug level.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="SRVCOMM_EXCEPTION_ALLOC">
+<term>SRVCOMM_EXCEPTION_ALLOC exception when allocating a socket: %1</term>
+<listitem><para>
+The process tried to allocate a socket using the socket creator, but an error
+occurred. But it is not one of the errors we are sure are "safe". In this case
+it is unclear if the unsuccessful communication left the process and the bind10
+process in inconsistent state, so the process is going to abort to prevent
+further problems in that area.
+</para><para>
+This is probably a bug in the code, but it could be caused by other unusual
+conditions (like insufficient memory, deleted socket file used for
+communication).
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="SRVCOMM_KEYS_DEINIT">
 <term>SRVCOMM_KEYS_DEINIT deinitializing TSIG keyring</term>
 <listitem><para>
@@ -4745,6 +4883,15 @@ different set of IP addresses and ports than before.
 </para></listitem>
 </varlistentry>
 
+<varlistentry id="SRVCOMM_UNKNOWN_EXCEPTION_ALLOC">
+<term>SRVCOMM_UNKNOWN_EXCEPTION_ALLOC unknown exception when allocating a socket</term>
+<listitem><para>
+The situation is the same as in the SRVCOMM_EXCEPTION_ALLOC case, but further
+details about the error are unknown, because it was signaled by throwing
+something not being an exception. This is definitely a bug.
+</para></listitem>
+</varlistentry>
+
 <varlistentry id="STATHTTPD_BAD_OPTION_VALUE">
 <term>STATHTTPD_BAD_OPTION_VALUE bad command line argument: %1</term>
 <listitem><para>

+ 2 - 0
ext/asio/asio/detail/impl/kqueue_reactor.ipp

@@ -301,12 +301,14 @@ void kqueue_reactor::run(bool block, op_queue<operation>& ops)
               EV_ADD | EV_ONESHOT, EV_OOBAND, 0, descriptor_data);
         else
           continue;
+        break;
       case EVFILT_WRITE:
         if (!descriptor_data->op_queue_[write_op].empty())
           ASIO_KQUEUE_EV_SET(&event, descriptor, EVFILT_WRITE,
               EV_ADD | EV_ONESHOT, 0, 0, descriptor_data);
         else
           continue;
+        break;
       default:
         break;
       }

+ 18 - 18
ext/asio/asio/detail/impl/socket_ops.ipp

@@ -282,15 +282,26 @@ int close(socket_type s, state_type& state,
   int result = 0;
   if (s != invalid_socket)
   {
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-    if ((state & non_blocking) && (state & user_set_linger))
+    if (destruction && (state & user_set_linger))
     {
-      ioctl_arg_type arg = 0;
-      ::ioctlsocket(s, FIONBIO, &arg);
-      state &= ~non_blocking;
+      ::linger opt;
+      opt.l_onoff = 0;
+      opt.l_linger = 0;
+      asio::error_code ignored_ec;
+      socket_ops::setsockopt(s, state, SOL_SOCKET,
+          SO_LINGER, &opt, sizeof(opt), ignored_ec);
     }
+
+    clear_last_error();
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+    result = error_wrapper(::closesocket(s), ec);
 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-    if (state & non_blocking)
+    result = error_wrapper(::close(s), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+    if (result != 0
+        && (ec == asio::error::would_block
+          || ec == asio::error::try_again))
     {
 #if defined(__SYMBIAN32__)
       int flags = ::fcntl(s, F_GETFL, 0);
@@ -301,18 +312,6 @@ int close(socket_type s, state_type& state,
       ::ioctl(s, FIONBIO, &arg);
 #endif // defined(__SYMBIAN32__)
       state &= ~non_blocking;
-    }
-#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
-
-    if (destruction && (state & user_set_linger))
-    {
-      ::linger opt;
-      opt.l_onoff = 0;
-      opt.l_linger = 0;
-      asio::error_code ignored_ec;
-      socket_ops::setsockopt(s, state, SOL_SOCKET,
-          SO_LINGER, &opt, sizeof(opt), ignored_ec);
-    }
 
     clear_last_error();
 #if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@@ -320,6 +319,7 @@ int close(socket_type s, state_type& state,
 #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
     result = error_wrapper(::close(s), ec);
 #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+    }
   }
 
   if (result == 0)

+ 9 - 3
src/bin/auth/auth_srv.cc

@@ -307,12 +307,14 @@ makeErrorMessage(MessagePtr message, OutputBufferPtr buffer,
     for_each(questions.begin(), questions.end(), QuestionInserter(message));
     message->setRcode(rcode);
 
-    MessageRenderer renderer(*buffer);
+    MessageRenderer renderer;
+    renderer.setBuffer(buffer.get());
     if (tsig_context.get() != NULL) {
         message->toWire(renderer, *tsig_context);
     } else {
         message->toWire(renderer);
     }
+    renderer.setBuffer(NULL);
     LOG_DEBUG(auth_logger, DBG_AUTH_MESSAGES, AUTH_SEND_ERROR_RESPONSE)
               .arg(renderer.getLength()).arg(*message);
 }
@@ -554,7 +556,8 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, MessagePtr message,
         return (true);
     }
 
-    MessageRenderer renderer(*buffer);
+    MessageRenderer renderer;
+    renderer.setBuffer(buffer.get());
     const bool udp_buffer =
         (io_message.getSocket().getProtocol() == IPPROTO_UDP);
     renderer.setLengthLimit(udp_buffer ? remote_bufsize : 65535);
@@ -563,6 +566,7 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, MessagePtr message,
     } else {
         message->toWire(renderer);
     }
+    renderer.setBuffer(NULL);
     LOG_DEBUG(auth_logger, DBG_AUTH_MESSAGES, AUTH_SEND_NORMAL_RESPONSE)
               .arg(renderer.getLength()).arg(message->toText());
 
@@ -683,12 +687,14 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, MessagePtr message,
     message->setHeaderFlag(Message::HEADERFLAG_AA);
     message->setRcode(Rcode::NOERROR());
 
-    MessageRenderer renderer(*buffer);
+    MessageRenderer renderer;
+    renderer.setBuffer(buffer.get());
     if (tsig_context.get() != NULL) {
         message->toWire(renderer, *tsig_context);
     } else {
         message->toWire(renderer);
     }
+    renderer.setBuffer(NULL);
     return (true);
 }
 

+ 11 - 7
src/bin/auth/b10-auth.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-auth
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: December 28, 2011
+.\"      Date: March 1, 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-AUTH" "8" "December 28, 2011" "BIND10" "BIND10"
+.TH "B10\-AUTH" "8" "March 1, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -154,21 +154,25 @@ immediately\&.
 
 \fBshutdown\fR
 exits
-\fBb10\-auth\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
+\fBb10\-auth\fR\&. This has an optional
+\fIpid\fR
+argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.)
 .SH "STATISTICS DATA"
 .PP
 The statistics data collected by the
 \fBb10\-stats\fR
-daemon include:
+daemon for
+\(lqAuth\(rq
+include:
 .PP
-auth\&.queries\&.tcp
+queries\&.tcp
 .RS 4
 Total count of queries received by the
 \fBb10\-auth\fR
 server over TCP since startup\&.
 .RE
 .PP
-auth\&.queries\&.udp
+queries\&.udp
 .RS 4
 Total count of queries received by the
 \fBb10\-auth\fR
@@ -198,5 +202,5 @@ The
 daemon was first coded in October 2009\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 12 - 7
src/bin/auth/b10-auth.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2010-2011  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>December 28, 2011</date>
+    <date>March 1, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2010</year>
+      <year>2010-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -188,7 +188,10 @@
 
     <para>
       <command>shutdown</command> exits <command>b10-auth</command>.
-      (Note that the BIND 10 boss process will restart this service.)
+      This has an optional <varname>pid</varname> argument to
+      select the process ID to stop.
+      (Note that the BIND 10 boss process may restart this service
+      if configured.)
     </para>
 
   </refsect1>
@@ -198,20 +201,20 @@
 
     <para>
       The statistics data collected by the <command>b10-stats</command>
-      daemon include:
+      daemon for <quote>Auth</quote> include:
     </para>
 
     <variablelist>
 
       <varlistentry>
-        <term>auth.queries.tcp</term>
+        <term>queries.tcp</term>
         <listitem><simpara>Total count of queries received by the
           <command>b10-auth</command> server over TCP since startup.
         </simpara></listitem>
       </varlistentry>
 
       <varlistentry>
-        <term>auth.queries.udp</term>
+        <term>queries.udp</term>
         <listitem><simpara>Total count of queries received by the
           <command>b10-auth</command> server over UDP since startup.
         </simpara></listitem>
@@ -219,6 +222,8 @@
 
     </variablelist>
 
+<!-- TODO: missing stats docs. See ticket #1721 -->
+
   </refsect1>
 
   <refsect1>

+ 70 - 100
src/bin/auth/query.cc

@@ -167,38 +167,65 @@ Query::addNXDOMAINProofByNSEC(ZoneFinder& finder, ConstRRsetPtr nsec) {
     }
 }
 
+uint8_t
+Query::addClosestEncloserProof(ZoneFinder& finder, const Name& name,
+                               bool exact_ok, bool add_closest)
+{
+    const ZoneFinder::FindNSEC3Result result = finder.findNSEC3(name, true);
+
+    // Validity check (see the method description).  Note that a completely
+    // broken findNSEC3 implementation could even return NULL RRset in
+    // closest_proof.  We don't explicitly check such case; addRRset() will
+    // throw an exception, and it will be converted to SERVFAIL at the caller.
+    if (!exact_ok && !result.next_proof) {
+        isc_throw(BadNSEC3, "Matching NSEC3 found for a non existent name: "
+                  << qname_);
+    }
+
+    if (add_closest) {
+        response_.addRRset(Message::SECTION_AUTHORITY,
+                           boost::const_pointer_cast<AbstractRRset>(
+                               result.closest_proof),
+                           dnssec_);
+    }
+    if (result.next_proof) {
+        response_.addRRset(Message::SECTION_AUTHORITY,
+                           boost::const_pointer_cast<AbstractRRset>(
+                               result.next_proof),
+                           dnssec_);
+    }
+    return (result.closest_labels);
+}
+
 void
-Query::addNXDOMAINProofByNSEC3(ZoneFinder& finder) {
-    // Firstly get the NSEC3 proves for Closest Encloser Proof
-    // See section 7.2.1 of RFC 5155.
-    // Since this is a Name Error case both closest and next proofs should
-    // be available (see addNXRRsetProof).
-    const ZoneFinder::FindNSEC3Result fresult1 = finder.findNSEC3(qname_,
-                                                                  true);
-    response_.addRRset(Message::SECTION_AUTHORITY,
-                       boost::const_pointer_cast<AbstractRRset>(
-                           fresult1.closest_proof),
-                       dnssec_);
+Query::addNSEC3ForName(ZoneFinder& finder, const Name& name, bool match) {
+    const ZoneFinder::FindNSEC3Result result = finder.findNSEC3(name, false);
+
+    // See the comment for addClosestEncloserProof().  We don't check a
+    // totally bogus case where closest_proof is NULL here.
+    if (match != result.matched) {
+        isc_throw(BadNSEC3, "Unexpected "
+                  << (result.matched ? "matching" : "covering")
+                  << " NSEC3 found for " << name);
+    }
     response_.addRRset(Message::SECTION_AUTHORITY,
                        boost::const_pointer_cast<AbstractRRset>(
-                       fresult1.next_proof),
+                           result.closest_proof),
                        dnssec_);
+}
+
+void
+Query::addNXDOMAINProofByNSEC3(ZoneFinder& finder) {
+    // Firstly get the NSEC3 proves for Closest Encloser Proof
+    // See Section 7.2.1 of RFC 5155.
+    const uint8_t closest_labels =
+        addClosestEncloserProof(finder, qname_, false);
 
     // Next, construct the wildcard name at the closest encloser, i.e.,
     // '*' followed by the closest encloser, and add NSEC3 for it.
     const Name wildname(Name("*").concatenate(
-               qname_.split(qname_.getLabelCount() -
-                            fresult1.closest_labels)));
-    const ZoneFinder::FindNSEC3Result fresult2 =
-        finder.findNSEC3(wildname, false);
-    if (fresult2.matched) {
-        isc_throw(BadNSEC3, "Matching NSEC3 found for nonexistent domain "
-                  << wildname);
-    }
-    response_.addRRset(Message::SECTION_AUTHORITY,
-                       boost::const_pointer_cast<AbstractRRset>(
-                           fresult2.closest_proof),
-                       dnssec_);
+               qname_.split(qname_.getLabelCount() - closest_labels)));
+    addNSEC3ForName(finder, wildname, false);
 }
 
 void
@@ -224,20 +251,13 @@ Query::addWildcardProof(ZoneFinder& finder,
                                fresult.rrset),
                            dnssec_);
     } else if (db_result.isNSEC3Signed()) {
-        // Case for RFC5155 Section 7.2.6.
+        // Case for RFC 5155 Section 7.2.6.
         //
         // Note that the closest encloser must be the immediate ancestor
-        // of the matching wildcard, so NSEC3 for its next closer is what
-        // we are expected to provided per the RFC (if this assumption isn't
-        // met the zone is broken anyway).
-        const ZoneFinder::FindNSEC3Result NSEC3Result(
-            finder.findNSEC3(qname_, true));
-        // Note that at this point next_proof must not be NULL unless it's
-        // a run time collision (or zone/findNSEC3() is broken).  The
-        // unexpected case will be caught in addRRset() and result in SERVFAIL.
-        response_.addRRset(Message::SECTION_AUTHORITY,
-                           boost::const_pointer_cast<AbstractRRset>(
-                               NSEC3Result.next_proof), dnssec_);
+        // of the matching wildcard, so NSEC3 for its next closer (and only
+        // that NSEC3) is what we are expected to provided per the RFC (if
+        // this assumption isn't met the zone is broken anyway).
+        addClosestEncloserProof(finder, qname_, false, false);
     }
 }
 
@@ -279,23 +299,8 @@ Query::addDS(ZoneFinder& finder, const Name& dname) {
         addNXRRsetProof(finder, ds_result);
     } else if (ds_result.code == ZoneFinder::NXRRSET &&
                ds_result.isNSEC3Signed()) {
-        // Add no DS proof with NSEC3 as specified in RFC5155 Section 7.2.7.
-        // Depending on whether the zone is optout or not, findNSEC3() may
-        // return non-NULL or NULL next_proof (respectively).  The Opt-Out flag
-        // must be set or cleared accordingly, but we don't check that
-        // in this level (as long as the zone signed validly and findNSEC3()
-        // is valid, the condition should be met; otherwise we'd let the
-        // validator detect the error).
-        const ZoneFinder::FindNSEC3Result nsec3_result =
-            finder.findNSEC3(dname, true);
-        response_.addRRset(Message::SECTION_AUTHORITY,
-                           boost::const_pointer_cast<AbstractRRset>(
-                               nsec3_result.closest_proof), dnssec_);
-        if (nsec3_result.next_proof) {
-            response_.addRRset(Message::SECTION_AUTHORITY,
-                               boost::const_pointer_cast<AbstractRRset>(
-                                   nsec3_result.next_proof), dnssec_);
-        }
+        // Add no DS proof with NSEC3 as specified in RFC 5155 Section 7.2.7.
+        addClosestEncloserProof(finder, dname, true);
     } else {
         // Any other case should be an error
         isc_throw(BadDS, "Unexpected result for DS lookup for delegation");
@@ -315,57 +320,22 @@ Query::addNXRRsetProof(ZoneFinder& finder,
             addWildcardNXRRSETProof(finder, db_result.rrset);
         }
     } else if (db_result.isNSEC3Signed() && !db_result.isWildcard()) {
-        // Handling depends on whether query type is DS or not
-        // (see RFC5155, 7.2.3 and 7.2.4):  If qtype == DS, do
-        // recursive search (and add next_proof, if necessary),
-        // otherwise, do non-recursive search
-        const bool qtype_ds = (qtype_ == RRType::DS());
-        ZoneFinder::FindNSEC3Result result(finder.findNSEC3(qname_, qtype_ds));
-        if (result.matched) {
-            response_.addRRset(Message::SECTION_AUTHORITY,
-                               boost::const_pointer_cast<AbstractRRset>(
-                                   result.closest_proof), dnssec_);
-            // For qtype == DS, next_proof could be set
-            // (We could check for opt-out here, but that's really the
-            // responsibility of the datasource)
-            if (qtype_ds && result.next_proof != ConstRRsetPtr()) {
-                response_.addRRset(Message::SECTION_AUTHORITY,
-                                   boost::const_pointer_cast<AbstractRRset>(
-                                       result.next_proof), dnssec_);
-            }
+        if (qtype_ == RRType::DS()) {
+            // RFC 5155, Section 7.2.4.  Add either NSEC3 for the qname or
+            // closest (provable) encloser proof in case of optout.
+            addClosestEncloserProof(finder, qname_, true);
         } else {
-            isc_throw(BadNSEC3, "No matching NSEC3 found for existing domain "
-                      << qname_);
+            // RFC 5155, Section 7.2.3.  Just add NSEC3 for the qname.
+            addNSEC3ForName(finder, qname_, true);
         }
     } else if (db_result.isNSEC3Signed() && db_result.isWildcard()) {
-        // Case for RFC5155 Section 7.2.5
-        const ZoneFinder::FindNSEC3Result result(finder.findNSEC3(qname_,
-                                                                  true));
-        // We know there's no exact match for the qname, so findNSEC3() should
-        // return both closest and next proofs.  If the latter is NULL, it
-        // means a run time collision (or the zone is broken in other way).
-        // In that case addRRset() will throw, and it will be converted to
-        // SERVFAIL.
-        response_.addRRset(Message::SECTION_AUTHORITY,
-                           boost::const_pointer_cast<AbstractRRset>(
-                               result.closest_proof), dnssec_);
-        response_.addRRset(Message::SECTION_AUTHORITY,
-                           boost::const_pointer_cast<AbstractRRset>(
-                               result.next_proof), dnssec_);
-
-        // Construct the matched wildcard name and add NSEC3 for it.
+        // Case for RFC 5155 Section 7.2.5: add closest encloser proof for the
+        // qname, construct the matched wildcard name and add NSEC3 for it.
+        const uint8_t closest_labels =
+            addClosestEncloserProof(finder, qname_, false);
         const Name wname = Name("*").concatenate(
-            qname_.split(qname_.getLabelCount() - result.closest_labels));
-        const ZoneFinder::FindNSEC3Result wresult(finder.findNSEC3(wname,
-                                                                   false));
-        if (wresult.matched) {
-            response_.addRRset(Message::SECTION_AUTHORITY,
-                               boost::const_pointer_cast<AbstractRRset>(
-                                   wresult.closest_proof), dnssec_);
-        } else {
-            isc_throw(BadNSEC3, "No matching NSEC3 found for existing domain "
-                      << wname);
-        }
+            qname_.split(qname_.getLabelCount() - closest_labels));
+        addNSEC3ForName(finder, wname, true);
     }
 }
 

+ 56 - 0
src/bin/auth/query.h

@@ -204,6 +204,62 @@ private:
     /// within this method.
     bool processDSAtChild();
 
+    /// \brief Add NSEC3 to the response for a closest encloser proof for a
+    /// given name.
+    ///
+    /// This method calls \c findNSEC3() of the given zone finder for the
+    /// given name in the recursive mode, and adds the returned NSEC3(s) to
+    /// the authority section of the response message associated with the
+    /// \c Query object.
+    ///
+    /// It returns the number of labels of the closest encloser (returned via
+    /// the \c findNSEC3() call) in case the caller needs to use that value
+    /// for subsequent processing, i.e, constructing the best possible wildcard
+    /// name that (would) match the query name.
+    ///
+    /// Unless \c exact_ok is true, \c name is expected to be non existent,
+    /// in which case findNSEC3() in the recursive mode must return both
+    /// closest and next proofs.  If the latter is NULL, it means a run time
+    /// collision (or the zone is broken in other way), and this method throws
+    /// a BadNSEC3 exception.
+    ///
+    /// If \c exact_ok is true, this method takes into account the case
+    /// where the name exists and may or may not be at a zone cut to an
+    /// optout zone.  In this case, depending on whether the zone is optout
+    /// or not, findNSEC3() may return non-NULL or NULL next_proof
+    /// (respectively).  This method adds the next proof if and only if
+    /// findNSEC3() returns non NULL value for it.  The Opt-Out flag
+    /// must be set or cleared accordingly, but this method doesn't check that
+    /// in this level (as long as the zone is signed validly and findNSEC3()
+    /// for the data source is implemented as documented, the condition
+    /// should be met; otherwise we'd let the validator detect the error).
+    ///
+    /// By default this method always adds the closest proof.
+    /// If \c add_closest is false, it only adds the next proof to the message.
+    /// This correspond to the case of "wildcard answer responses" as described
+    /// in Section 7.2.6 of RFC5155.
+    uint8_t addClosestEncloserProof(isc::datasrc::ZoneFinder& finder,
+                                    const isc::dns::Name& name, bool exact_ok,
+                                    bool add_closest = true);
+
+    /// \brief Add matching or covering NSEC3 to the response for a give name.
+    ///
+    /// This method calls \c findNSEC3() of the given zone finder for the
+    /// given name in the non recursive mode, and adds the returned NSEC3 to
+    /// the authority section of the response message associated with the
+    /// \c Query object.
+    ///
+    /// Depending on the caller's context, the returned NSEC3 is one and
+    /// only one of matching or covering NSEC3.  If \c match is true the
+    /// returned NSEC3 must be a matching one; otherwise it must be a covering
+    /// one.  If this assumption isn't met this method throws a BadNSEC3
+    /// exception (if it must be a matching NSEC3 but is not, it means a broken
+    /// zone, maybe with incorrect optout NSEC3s; if it must be a covering
+    /// NSEC3 but is not, it means a run time collision; or the \c findNSEC3()
+    /// implementation is broken for both cases.)
+    void addNSEC3ForName(isc::datasrc::ZoneFinder& finder,
+                         const isc::dns::Name& name, bool match);
+
 public:
     /// Constructor from query parameters.
     ///

+ 1 - 2
src/bin/auth/tests/auth_srv_unittest.cc

@@ -154,8 +154,7 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
     rrset_version_ns->addRdata(generic::NS(version_name));
     message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);
 
-    OutputBuffer obuffer(0);
-    MessageRenderer renderer(obuffer);
+    MessageRenderer renderer;
     message.toWire(renderer);
 
     data.clear();

+ 3 - 5
src/bin/auth/tests/query_unittest.cc

@@ -1429,7 +1429,7 @@ TEST_F(QueryTest, badWildcardNSEC3) {
 
     EXPECT_THROW(Query(memory_client, Name("www.wild.example.com"),
                        RRType::A(), response, true).process(),
-                 isc::InvalidParameter);
+                 Query::BadNSEC3);
 }
 
 TEST_F(QueryTest, badWildcardProof1) {
@@ -1540,10 +1540,9 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Collision) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    // Message::addRRset() will detect it and throw InvalidParameter.
     EXPECT_THROW(Query(memory_client, Name("www1.uwild.example.com"),
                        RRType::TXT(), response, true).process(),
-                 isc::InvalidParameter);
+                 Query::BadNSEC3);
 }
 
 TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Broken) {
@@ -2283,10 +2282,9 @@ TEST_F(QueryTest, nxdomainWithBadNextNSEC3Proof) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    // Message::addRRset() will detect it and throw InvalidParameter.
     EXPECT_THROW(Query(memory_client, Name("nxdomain.example.com"),
                        RRType::TXT(), response, true).process(),
-                 isc::InvalidParameter);
+                 Query::BadNSEC3);
 }
 
 TEST_F(QueryTest, nxdomainWithBadWildcardNSEC3Proof) {

+ 25 - 27
src/bin/bind10/bind10.8

@@ -2,12 +2,12 @@
 .\"     Title: bind10
 .\"    Author: [see the "AUTHORS" section]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: November 23, 2011
+.\"      Date: March 1, 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "BIND10" "8" "November 23, 2011" "BIND10" "BIND10"
+.TH "BIND10" "8" "March 1, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -34,9 +34,8 @@ The arguments are as follows:
 .PP
 \fB\-c\fR \fIconfig\-filename\fR, \fB\-\-config\-file\fR \fIconfig\-filename\fR
 .RS 4
-The configuration filename to use\&. Can be either absolute or relative to data path\&. In case it is absolute, value of data path is not considered\&.
-.sp
-Defaults to b10\-config\&.db\&.
+The configuration filename to use\&. Can be either absolute or relative to data path\&. In case it is absolute, value of data path is not considered\&. Defaults to
+b10\-config\&.db\&.
 .RE
 .PP
 \fB\-\-cmdctl\-port\fR \fIport\fR
@@ -50,7 +49,9 @@ for the default\&.)
 .PP
 \fB\-p\fR \fIdirectory\fR, \fB\-\-data\-path\fR \fIdirectory\fR
 .RS 4
-The path where BIND 10 programs look for various data files\&. Currently only b10\-cfgmgr uses it to locate the configuration file, but the usage might be extended for other programs and other types of files\&.
+The path where BIND 10 programs look for various data files\&. Currently only
+\fBb10-cfgmgr\fR(8)
+uses it to locate the configuration file, but the usage might be extended for other programs and other types of files\&.
 .RE
 .PP
 \fB\-m\fR \fIfile\fR, \fB\-\-msgq\-socket\-file\fR \fIfile\fR
@@ -73,7 +74,6 @@ daemon\&.
 The username for
 \fBbind10\fR
 to run as\&.
-
 \fBbind10\fR
 must be initially ran as the root user to use this option\&. The default is to run as the current user\&.
 .RE
@@ -82,7 +82,7 @@ must be initially ran as the root user to use this option\&. The default is to r
 .RS 4
 If defined, the PID of the
 \fBbind10\fR
-is stored in this file\&. This is used for testing purposes\&.
+is stored in this file\&.
 .RE
 .PP
 \fB\-\-pretty\-name \fR\fB\fIname\fR\fR
@@ -103,7 +103,9 @@ and its child processes\&.
 .PP
 \fB\-w\fR \fIwait_time\fR, \fB\-\-wait\fR \fIwait_time\fR
 .RS 4
-Sets the amount of time that BIND 10 will wait for the configuration manager (a key component of BIND 10) to initialize itself before abandoning the start up and terminating with an error\&. The wait_time is specified in seconds and has a default value of 10\&.
+Sets the amount of time that BIND 10 will wait for the configuration manager (a key component of BIND 10) to initialize itself before abandoning the start up and terminating with an error\&. The
+\fIwait_time\fR
+is specified in seconds and has a default value of 10\&.
 .RE
 .SH "CONFIGURATION AND COMMANDS"
 .PP
@@ -145,18 +147,6 @@ to manage under
 .IP \(bu 2.3
 .\}
 
-\fI/Boss/components/setuid\fR
-.RE
-.sp
-.RS 4
-.ie n \{\
-\h'-04'\(bu\h'+03'\c
-.\}
-.el \{\
-.sp -1
-.IP \(bu 2.3
-.\}
-
 \fI/Boss/components/b10\-stats\fR
 .RE
 .sp
@@ -212,11 +202,11 @@ to manage under
 \fBb10\-sockcreator\fR,
 \fBb10\-cfgmgr\fR, and
 \fBb10\-msgq\fR
-is not configurable\&. It is hardcoded and
+is not configurable\&. They are hardcoded and
 \fBbind10\fR
 will not run without them\&.)
 .PP
-These named sets (listed above) contain the following settings:
+The named sets for components contain the following settings:
 .PP
 \fIaddress\fR
 .RS 4
@@ -258,7 +248,7 @@ will use the component name instead\&.
 .PP
 \fIspecial\fR
 .RS 4
-This defines if the component is started a special way\&.
+This defines if the component is started a special, hardcoded way\&.
 .RE
 .PP
 The
@@ -307,14 +297,22 @@ will exit\&.
 .PP
 The statistics data collected by the
 \fBb10\-stats\fR
-daemon include:
+daemon for
+\(lqBoss\(rq
+include:
 .PP
-bind10\&.boot_time
+boot_time
 .RS 4
 The date and time that the
 \fBbind10\fR
 process started\&. This is represented in ISO 8601 format\&.
 .RE
+.SH "FILES"
+.PP
+sockcreator\-XXXXXX/sockcreator
+\(em the Unix Domain socket located in a temporary file directory for
+\fBb10\-sockcreator\fR
+communication\&.
 .SH "SEE ALSO"
 .PP
 
@@ -339,5 +337,5 @@ The
 daemon was initially designed by Shane Kerr of ISC\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 47 - 28
src/bin/bind10/bind10.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2010-2011  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>November 23, 2011</date>
+    <date>March 1, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2011</year>
+      <year>2010-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -97,8 +97,8 @@
         <listitem>
           <para>The configuration filename to use. Can be either absolute or
           relative to data path. In case it is absolute, value of data path is
-          not considered.</para>
-          <para>Defaults to b10-config.db.</para>
+          not considered.
+          Defaults to <filename>b10-config.db</filename>.</para>
         </listitem>
       </varlistentry>
 
@@ -123,9 +123,11 @@
         </term>
         <listitem>
           <para>The path where BIND 10 programs look for various data files.
-          Currently only b10-cfgmgr uses it to locate the configuration file,
-          but the usage might be extended for other programs and other types
-          of files.</para>
+	  Currently only
+	  <citerefentry><refentrytitle>b10-cfgmgr</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+	  uses it to locate the configuration file, but the usage
+	  might be extended for other programs and other types of
+	  files.</para>
         </listitem>
       </varlistentry>
 
@@ -155,9 +157,9 @@
 
       <varlistentry>
         <term><option>-u</option> <replaceable>user</replaceable>, <option>--user</option> <replaceable>name</replaceable></term>
+<!-- TODO: example more detail. -->
         <listitem>
           <para>The username for <command>bind10</command> to run as.
-<!-- TODO: example more detail. -->
             <command>bind10</command> must be initially ran as the
             root user to use this option.
             The default is to run as the current user.</para>
@@ -169,7 +171,6 @@
         <listitem>
           <para>If defined, the PID of the <command>bind10</command> is stored
              in this file.
-             This is used for testing purposes.
           </para>
          </listitem>
       </varlistentry>
@@ -201,11 +202,12 @@ The default is the basename of ARG 0.
       <varlistentry>
         <term><option>-w</option> <replaceable>wait_time</replaceable>, <option>--wait</option> <replaceable>wait_time</replaceable></term>
         <listitem>
-          <para>Sets the amount of time that BIND 10 will wait for
-          the configuration manager (a key component of BIND 10) to
-          initialize itself before abandoning the start up and
-          terminating with an error.  The wait_time is specified in
-          seconds and has a default value of 10.
+	  <para>Sets the amount of time that BIND 10 will wait for
+	  the configuration manager (a key component of BIND 10)
+	  to initialize itself before abandoning the start up and
+	  terminating with an error.  The
+	  <replaceable>wait_time</replaceable> is specified in
+	  seconds and has a default value of 10.
           </para>
         </listitem>
       </varlistentry>
@@ -238,10 +240,6 @@ TODO: configuration section
       </listitem>
 
       <listitem>
-        <para> <varname>/Boss/components/setuid</varname> </para>
-      </listitem>
-
-      <listitem>
         <para> <varname>/Boss/components/b10-stats</varname> </para>
       </listitem>
 
@@ -266,12 +264,12 @@ TODO: configuration section
     <para>
       (Note that the startup of <command>b10-sockcreator</command>,
       <command>b10-cfgmgr</command>, and <command>b10-msgq</command>
-      is not configurable. It is hardcoded and <command>bind10</command>
+      is not configurable. They are hardcoded and <command>bind10</command>
       will not run without them.)
     </para>
 
     <para>
-      These named sets (listed above) contain the following settings:
+      The named sets for components contain the following settings:
     </para>
 
     <variablelist>
@@ -346,7 +344,7 @@ list
           <term> <varname>special</varname> </term>
         <listitem>
           <para>
-            This defines if the component is started a special
+            This defines if the component is started a special, hardcoded
             way.
 <!--
 TODO: document this ... but maybe some of these will be removed
@@ -357,7 +355,6 @@ cfgmgr
 cmdctl
 msgq
 resolver
-setuid
 sockcreator
 xfrin
 -->
@@ -374,6 +371,22 @@ xfrin
     </para>
 <!-- TODO: let's just let bind10 be known as bind10 and not Boss -->
 
+<!-- TODO -->
+<!--
+    <para>
+      <command>drop_socket</command>
+      This is an internal command and not exposed to the administrator.
+    </para>
+-->
+
+<!-- TODO -->
+<!--
+    <para>
+      <command>get_socket</command>
+      This is an internal command and not exposed to the administrator.
+    </para>
+-->
+
     <para>
       <command>getstats</command> tells <command>bind10</command>
       to send its statistics data to the <command>b10-stats</command>
@@ -420,13 +433,13 @@ xfrin
 
     <para>
       The statistics data collected by the <command>b10-stats</command>
-      daemon include:
+      daemon for <quote>Boss</quote> include:
     </para>
 
     <variablelist>
 
       <varlistentry>
-        <term>bind10.boot_time</term>
+        <term>boot_time</term>
         <listitem><para>
           The date and time that the <command>bind10</command>
           process started.
@@ -438,13 +451,16 @@ xfrin
 
   </refsect1>
 
-<!--
   <refsect1>
     <title>FILES</title>
-    <para><filename></filename>
+    <para><filename>sockcreator-XXXXXX/sockcreator</filename>
+    &mdash;
+    the Unix Domain socket located in a temporary file directory for
+    <command>b10-sockcreator</command>
+<!--    <citerefentry><refentrytitle>b10-sockcreator</refentrytitle><manvolnum>8</manvolnum></citerefentry> -->
+    communication.
     </para>
   </refsect1>
--->
 
   <refsect1>
     <title>SEE ALSO</title>
@@ -476,6 +492,9 @@ xfrin
       <citetitle>BIND 10 Guide</citetitle>.
     </para>
   </refsect1>
+<!-- <citerefentry>
+        <refentrytitle>b10-sockcreator</refentrytitle><manvolnum>8</manvolnum>
+      </citerefentry>, -->
 
   <refsect1 id='history'><title>HISTORY</title>
     <para>The development of <command>bind10</command>

+ 1 - 1
src/bin/bind10/bind10_src.py.in

@@ -892,7 +892,7 @@ class BoB:
         # the need to find the place ourself or bother users. Also, this
         # secures the socket on some platforms, as it creates a private
         # directory.
-        self._tmpdir = tempfile.mkdtemp()
+        self._tmpdir = tempfile.mkdtemp(prefix='sockcreator-')
         # Get the name
         self._socket_path = os.path.join(self._tmpdir, "sockcreator")
         # And bind the socket to the name

+ 30 - 3
src/bin/cmdctl/b10-cmdctl.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-cmdctl
 .\"    Author: [see the "AUTHORS" section]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: March 9, 2010
+.\"      Date: February 28, 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-CMDCTL" "8" "March 9, 2010" "BIND10" "BIND10"
+.TH "B10\-CMDCTL" "8" "February 28, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -70,6 +70,33 @@ Enable verbose mode\&.
 .RS 4
 Display the version number and exit\&.
 .RE
+.SH "CONFIGURATION AND COMMANDS"
+.PP
+The configurable settings are:
+.PP
+
+\fIaccounts_file\fR
+defines the path to the user accounts database\&. The default is
+/usr/local/etc/bind10\-devel/cmdctl\-accounts\&.csv\&.
+.PP
+
+\fIcert_file\fR
+defines the path to the PEM certificate file\&. The default is
+/usr/local/etc/bind10\-devel/cmdctl\-certfile\&.pem\&.
+.PP
+
+\fIkey_file\fR
+defines the path to the PEM private key file\&. The default is
+/usr/local/etc/bind10\-devel/cmdctl\-keyfile\&.pem\&.
+.PP
+The configuration command is:
+.PP
+
+\fBshutdown\fR
+exits
+\fBb10\-cmdctl\fR\&. This has an optional
+\fIpid\fR
+argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.)
 .SH "FILES"
 .PP
 /usr/local/etc/bind10\-devel/cmdctl\-accounts\&.csv
@@ -93,5 +120,5 @@ The
 daemon was initially designed and coded by Zhang Likun of CNNIC\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 47 - 3
src/bin/cmdctl/b10-cmdctl.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>March 9, 2010</date>
+    <date>February 28, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -37,7 +37,7 @@
 
   <docinfo>
     <copyright>
-      <year>2010</year>
+      <year>2010-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -138,6 +138,50 @@
   </refsect1>
 
   <refsect1>
+    <title>CONFIGURATION AND COMMANDS</title>
+    <para>
+      The configurable settings are:
+    </para>
+
+    <para>
+      <varname>accounts_file</varname> defines the path to the
+      user accounts database.
+      The default is
+      <filename>/usr/local/etc/bind10-devel/cmdctl-accounts.csv</filename>.
+    </para>
+
+    <para>
+      <varname>cert_file</varname> defines the path to the
+      PEM certificate file.
+      The default is
+      <filename>/usr/local/etc/bind10-devel/cmdctl-certfile.pem</filename>.
+    </para>
+
+    <para>
+      <varname>key_file</varname> defines the path to the PEM private key
+      file.
+      The default is
+      <filename>/usr/local/etc/bind10-devel/cmdctl-keyfile.pem</filename>.
+    </para>
+
+<!-- TODO: formating -->
+    <para>
+      The configuration command is:
+    </para>
+
+<!-- NOTE: print_settings is not documented since I think will be removed -->
+
+    <para>
+      <command>shutdown</command> exits <command>b10-cmdctl</command>.
+      This has an optional <varname>pid</varname> argument to
+      select the process ID to stop.
+      (Note that the BIND 10 boss process may restart this service
+      if configured.)
+    </para>
+
+  </refsect1>
+
+  <refsect1>
     <title>FILES</title>
 <!-- TODO: replace /usr/local -->
 <!-- TODO: permissions -->

+ 7 - 5
src/bin/ddns/b10-ddns.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-ddns
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: December 9, 2011
+.\"      Date: February 28, 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-DDNS" "8" "December 9, 2011" "BIND10" "BIND10"
+.TH "B10\-DDNS" "8" "February 28, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -81,8 +81,10 @@ The module commands are:
 .PP
 
 \fBshutdown\fR
-Exits
-\fBb10\-ddns\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
+exits
+\fBb10\-ddns\fR\&. This has an optional
+\fIpid\fR
+argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.)
 .SH "SEE ALSO"
 .PP
 
@@ -98,5 +100,5 @@ The
 daemon was first implemented in December 2011 for the ISC BIND 10 project\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 8 - 5
src/bin/ddns/b10-ddns.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2011-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>December 9, 2011</date>
+    <date>February 28, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2011</year>
+      <year>2011-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -122,8 +122,11 @@
       The module commands are:
     </para>
     <para>
-      <command>shutdown</command> Exits <command>b10-ddns</command>.
-      (Note that the BIND 10 boss process will restart this service.)
+      <command>shutdown</command> exits <command>b10-ddns</command>.
+      This has an optional <varname>pid</varname> argument to
+      select the process ID to stop.
+      (Note that the BIND 10 boss process may restart this service
+      if configured.)
     </para>
 
   </refsect1>

+ 1 - 1
src/bin/dhcp4/Makefile.am

@@ -15,7 +15,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
 CLEANFILES = spec_config.h
 
 man_MANS = b10-dhcp4.8
-EXTRA_DIST = $(man_MANS) dhcp4.spec
+EXTRA_DIST = $(man_MANS) b10-dhcp4.xml dhcp4.spec
 
 if ENABLE_MAN
 

+ 1 - 1
src/bin/dhcp6/Makefile.am

@@ -17,7 +17,7 @@ pkglibexecdir = $(libexecdir)/@PACKAGE@
 CLEANFILES = *.gcno *.gcda spec_config.h
 
 man_MANS = b10-dhcp6.8
-EXTRA_DIST = $(man_MANS) dhcp6.spec interfaces.txt
+EXTRA_DIST = $(man_MANS) b10-dhcp6.xml dhcp6.spec interfaces.txt
 
 if ENABLE_MAN
 

+ 2 - 3
src/bin/host/host.cc

@@ -70,8 +70,7 @@ host_lookup(const char* const name, const char* const dns_class,
                              RRClass(dns_class),
                              any ? RRType::ANY() : RRType(type)));  // if NULL then:
 
-    OutputBuffer obuffer(512);
-    MessageRenderer renderer(obuffer);
+    MessageRenderer renderer;
     msg.toWire(renderer);
 
     struct addrinfo hints, *res;
@@ -111,7 +110,7 @@ host_lookup(const char* const name, const char* const dns_class,
         gettimeofday(&before_time, NULL);
     }
 
-    sendto(s, obuffer.getData(), obuffer.getLength(), 0, res->ai_addr,
+    sendto(s, renderer.getData(), renderer.getLength(), 0, res->ai_addr,
            res->ai_addrlen);
 
     struct sockaddr_storage ss;

+ 6 - 4
src/bin/resolver/b10-resolver.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-resolver
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: December 28, 2011
+.\"      Date: February 28, 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-RESOLVER" "8" "December 28, 2011" "BIND10" "BIND10"
+.TH "B10\-RESOLVER" "8" "February 28, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -118,7 +118,9 @@ The configuration command is:
 
 \fBshutdown\fR
 exits
-\fBb10\-resolver\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
+\fBb10\-resolver\fR\&. This has an optional
+\fIpid\fR
+argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.)
 .SH "SEE ALSO"
 .PP
 
@@ -134,5 +136,5 @@ The
 daemon was first coded in September 2010\&. The initial implementation only provided forwarding\&. Iteration was introduced in January 2011\&. Caching was implemented in February 2011\&. Access control was introduced in June 2011\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 7 - 4
src/bin/resolver/b10-resolver.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2010-2011  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>December 28, 2011</date>
+    <date>February 28, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2010</year>
+      <year>2010-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -201,7 +201,10 @@ once that is merged you can for instance do 'config add Resolver/forward_address
 
     <para>
       <command>shutdown</command> exits <command>b10-resolver</command>.
-      (Note that the BIND 10 boss process will restart this service.)
+      This has an optional <varname>pid</varname> argument to
+      select the process ID to stop.
+      (Note that the BIND 10 boss process may restart this service
+      if configured.)
     </para>
 
   </refsect1>

+ 5 - 2
src/bin/resolver/resolver.cc

@@ -252,7 +252,8 @@ makeErrorMessage(MessagePtr message, MessagePtr answer_message,
     }
     for_each(questions.begin(), questions.end(), QuestionInserter(message));
     message->setRcode(rcode);
-    MessageRenderer renderer(*buffer);
+    MessageRenderer renderer;
+    renderer.setBuffer(buffer.get());
     message->toWire(renderer);
 }
 
@@ -303,7 +304,8 @@ public:
 
         // Now we can clear the buffer and render the new message into it
         buffer->clear();
-        MessageRenderer renderer(*buffer);
+        MessageRenderer renderer;
+        renderer.setBuffer(buffer.get());
 
         ConstEDNSPtr edns(query_message->getEDNS());
         const bool dnssec_ok = edns && edns->getDNSSECAwareness();
@@ -327,6 +329,7 @@ public:
         }
 
         answer_message->toWire(renderer);
+        renderer.setBuffer(NULL);
 
         LOG_DEBUG(resolver_logger, RESOLVER_DBG_DETAIL,
                   RESOLVER_DNS_MESSAGE_SENT)

+ 1 - 1
src/bin/sockcreator/main.cc

@@ -24,7 +24,7 @@ main() {
      * but ability to bind ports? It would be nice.
      */
     try {
-        run(STDIN_FILENO, STDOUT_FILENO);
+        run(STDIN_FILENO, STDOUT_FILENO, getSock, isc::util::io::send_fd, close);
     } catch (const SocketCreatorError& ec) {
         return (ec.getExitCode());
     }

+ 59 - 8
src/bin/sockcreator/sockcreator.cc

@@ -18,7 +18,7 @@
 #include <util/io/sockaddr_util.h>
 
 #include <cerrno>
-#include <cstring>
+#include <string.h>
 
 #include <unistd.h>
 #include <sys/types.h>
@@ -157,7 +157,7 @@ handleRequest(const int input_fd, const int output_fd,
     }
 
     // Obtain the socket
-    const int result = get_sock(sock_type, addr, addr_len);
+    const int result = get_sock(sock_type, addr, addr_len, close_fun);
     if (result >= 0) {
         // Got the socket, send it to the client.
         writeMessage(output_fd, "S", 1);
@@ -186,6 +186,52 @@ handleRequest(const int input_fd, const int output_fd,
     }
 }
 
+// Sets the MTU related flags for IPv6 UDP sockets.
+// It is borrowed from bind-9 lib/isc/unix/socket.c and modified
+// to compile here.
+//
+// The function returns -2 if it fails or the socket file descriptor
+// on success (for convenience, so the result can be just returned).
+int
+mtu(int fd) {
+#ifdef IPV6_USE_MIN_MTU        /* RFC 3542, not too common yet*/
+    const int on(1);
+    // use minimum MTU
+    if (setsockopt(fd, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &on, sizeof(on)) < 0) {
+        return (-2);
+    }
+#else // Try the following as fallback
+#ifdef IPV6_MTU
+    // Use minimum MTU on systems that don't have the IPV6_USE_MIN_MTU
+    const int mtu = 1280;
+    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU, &mtu, sizeof(mtu)) < 0) {
+        return (-2);
+    }
+#endif
+#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
+    // Turn off Path MTU discovery on IPv6/UDP sockets.
+    const int action = IPV6_PMTUDISC_DONT;
+    if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &action,
+                   sizeof(action)) < 0) {
+
+        return (-2);
+    }
+#endif
+#endif
+    return (fd);
+}
+
+// This one closes the socket if result is negative. Used not to leak socket
+// on error.
+int maybeClose(const int result, const int socket, const close_t close_fun) {
+    if (result < 0) {
+        if (close_fun(socket) == -1) {
+            isc_throw(InternalError, "Error closing socket");
+        }
+    }
+    return (result);
+}
+
 } // Anonymous namespace
 
 namespace isc {
@@ -193,7 +239,8 @@ namespace socket_creator {
 
 // Get the socket and bind to it.
 int
-getSock(const int type, struct sockaddr* bind_addr, const socklen_t addr_len) {
+getSock(const int type, struct sockaddr* bind_addr, const socklen_t addr_len,
+        const close_t close_fun) {
     const int sock = socket(bind_addr->sa_family, type, 0);
     if (sock == -1) {
         return (-1);
@@ -201,23 +248,27 @@ getSock(const int type, struct sockaddr* bind_addr, const socklen_t addr_len) {
     const int on = 1;
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
         // This is part of the binding process, so it's a bind error
-        return (-2);
+        return (maybeClose(-2, sock, close_fun));
     }
     if (bind_addr->sa_family == AF_INET6 &&
         setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) {
         // This is part of the binding process, so it's a bind error
-        return (-2);
+        return (maybeClose(-2, sock, close_fun));
     }
     if (bind(sock, bind_addr, addr_len) == -1) {
-        return (-2);
+        return (maybeClose(-2, sock, close_fun));
+    }
+    if (type == SOCK_DGRAM && bind_addr->sa_family == AF_INET6) {
+        // Set some MTU flags on IPv6 UDP sockets.
+        return (maybeClose(mtu(sock), sock, close_fun));
     }
     return (sock);
 }
 
 // Main run loop.
 void
-run(const int input_fd, const int output_fd, const get_sock_t get_sock,
-    const send_fd_t send_fd_fun, const close_t close_fun)
+run(const int input_fd, const int output_fd, get_sock_t get_sock,
+    send_fd_t send_fd_fun, close_t close_fun)
 {
     for (;;) {
         char command;

+ 11 - 10
src/bin/sockcreator/sockcreator.h

@@ -73,6 +73,9 @@ public:
 };
 
 
+// Type of the close() function, so it can be passed as a parameter.
+// Argument is the same as that for close(2).
+typedef int (*close_t)(int);
 
 /// \short Create a socket and bind it.
 ///
@@ -82,13 +85,16 @@ public:
 /// \param type The type of socket to create (SOCK_STREAM, SOCK_DGRAM, etc).
 /// \param bind_addr The address to bind.
 /// \param addr_len The actual length of bind_addr.
+/// \param close_fun The furction used to close a socket if there's an error
+///     after the creation.
 ///
 /// \return The file descriptor of the newly created socket, if everything
 ///         goes well. A negative number is returned if an error occurs -
 ///         -1 if the socket() call fails or -2 if bind() fails. In case of
 ///         error, errno is set (or left intact from socket() or bind()).
 int
-getSock(const int type, struct sockaddr* bind_addr, const socklen_t addr_len);
+getSock(const int type, struct sockaddr* bind_addr, const socklen_t addr_len,
+        const close_t close_fun);
 
 // Define some types for functions used to perform socket-related operations.
 // These are typedefed so that alternatives can be passed through to the
@@ -96,16 +102,13 @@ getSock(const int type, struct sockaddr* bind_addr, const socklen_t addr_len);
 
 // Type of the function to get a socket and to pass it as parameter.
 // Arguments are those described above for getSock().
-typedef int (*get_sock_t)(const int, struct sockaddr *, const socklen_t);
+typedef int (*get_sock_t)(const int, struct sockaddr *, const socklen_t,
+                          const close_t close_fun);
 
 // Type of the send_fd() function, so it can be passed as a parameter.
 // Arguments are the same as those of the send_fd() function.
 typedef int (*send_fd_t)(const int, const int);
 
-// Type of the close() function, so it can be passed as a parameter.
-// Argument is the same as that for close(2).
-typedef int (*close_t)(int);
-
 
 /// \brief Infinite loop parsing commands and returning the sockets.
 ///
@@ -135,10 +138,8 @@ typedef int (*close_t)(int);
 /// \exception isc::socket_creator::ProtocolError Unrecognised command received
 /// \exception isc::socket_creator::InternalError Other error
 void
-run(const int input_fd, const int output_fd,
-    const get_sock_t get_sock_fun = getSock,
-    const send_fd_t send_fd_fun = isc::util::io::send_fd,
-    const close_t close_fun = close);
+run(const int input_fd, const int output_fd, get_sock_t get_sock_fun,
+    send_fd_t send_fd_fun, close_t close_fun);
 
 }   // namespace socket_creator
 }   // NAMESPACE ISC

+ 3 - 2
src/bin/sockcreator/tests/Makefile.am

@@ -1,7 +1,8 @@
 CLEANFILES = *.gcno *.gcda
 
-AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
-AM_CXXFLAGS = $(B10_CXXFLAGS)
+AM_CPPFLAGS  = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS  = $(B10_CXXFLAGS)
 
 if USE_STATIC_LINK
 AM_LDFLAGS = -static

+ 68 - 13
src/bin/sockcreator/tests/sockcreator_tests.cc

@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <unistd.h>
 
 #include <iostream>
@@ -105,17 +106,47 @@ typedef void (*socket_check_t)(const int);
 // The other argument is the socket descriptor number.
 
 // IPv4 check
-void addressFamilySpecificCheck(const sockaddr_in*, const int) {
+void addressFamilySpecificCheck(const sockaddr_in*, const int, const int) {
 }
 
 // IPv6 check
-void addressFamilySpecificCheck(const sockaddr_in6*, const int socknum) {
+void addressFamilySpecificCheck(const sockaddr_in6*, const int socknum,
+                                const int socket_type)
+{
     int options;
     socklen_t len = sizeof(options);
-    EXPECT_EQ(0, getsockopt(socknum, IPPROTO_IPV6, IPV6_V6ONLY, &options, &len));
+    EXPECT_EQ(0, getsockopt(socknum, IPPROTO_IPV6, IPV6_V6ONLY, &options,
+                            &len));
     EXPECT_NE(0, options);
+    if (socket_type == SOCK_DGRAM) {
+    // Some more checks for UDP - MTU
+#ifdef IPV6_USE_MIN_MTU        /* RFC 3542, not too common yet*/
+        // use minimum MTU
+        EXPECT_EQ(0, getsockopt(socknum, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+                                &options, &len)) << strerror(errno);
+        EXPECT_NE(0, options);
+#else
+        // We do not check for the IPV6_MTU, because while setting works (eg.
+        // the packets are fragmented correctly), the getting does not. If
+        // we try to getsockopt it, an error complaining it can't be accessed
+        // on unconnected socket is returned. If we try to connect it, the
+        // MTU of the interface is returned, not the one we set. So we live
+        // in belief it works because we examined the packet dump.
+#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DONT)
+        // Turned off Path MTU discovery on IPv6/UDP sockets?
+        EXPECT_EQ(0, getsockopt(socknum, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
+                                &options, &len)) << strerror(errno);
+        EXPECT_EQ(IPV6_PMTUDISC_DONT, options);
+#endif
+#endif
+    }
 }
 
+// Just ignore the fd and pretend success. We close invalid fds in the tests.
+int
+closeIgnore(int) {
+    return (0);
+}
 
 // Generic version of the socket test.  It creates the socket and checks that
 // it is a valid descriptor.  The family-specific check functions are called
@@ -133,7 +164,8 @@ void testAnyCreate(int socket_type, socket_check_t socket_check) {
     memset(&addr, 0, sizeof(addr));
     setAddressFamilyFields(&addr);
     sockaddr* addr_ptr = reinterpret_cast<sockaddr*>(&addr);
-    const int socket = getSock(socket_type, addr_ptr, sizeof(addr));
+    const int socket = getSock(socket_type, addr_ptr, sizeof(addr),
+                               closeIgnore);
     ASSERT_GE(socket, 0) << "Couldn't create socket: failed with " <<
         "return code " << socket << " and error " << strerror(errno);
 
@@ -147,7 +179,7 @@ void testAnyCreate(int socket_type, socket_check_t socket_check) {
     EXPECT_NE(0, options);
 
     // ...and the address-family specific tests.
-    addressFamilySpecificCheck(&addr, socket);
+    addressFamilySpecificCheck(&addr, socket, socket_type);
 
     // Tidy up and exit.
     EXPECT_EQ(0, close(socket));
@@ -171,12 +203,40 @@ TEST(get_sock, tcp6_create) {
     testAnyCreate<sockaddr_in6>(SOCK_STREAM, tcpCheck);
 }
 
+bool close_called(false);
+
+// You can use it as a close mockup. If you care about checking if it was really
+// called, you can use the close_called variable. But set it to false before the
+// test.
+int closeCall(int socket) {
+    close(socket);
+    close_called = true;
+    return (0);
+}
+
 // Ask the get_sock function for some nonsense and test if it is able to report
 // an error.
 TEST(get_sock, fail_with_nonsense) {
     sockaddr addr;
     memset(&addr, 0, sizeof(addr));
-    ASSERT_LT(getSock(0, &addr, sizeof addr), 0);
+    close_called = false;
+    ASSERT_EQ(-1, getSock(0, &addr, sizeof addr, closeCall));
+    ASSERT_FALSE(close_called); // The "socket" call should have failed already
+}
+
+// Bind should have failed here
+TEST(get_sock, fail_with_bind) {
+    sockaddr_in addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = 1;
+    // No host should have this address on the interface, so it should not be
+    // possible to bind it.
+    addr.sin_addr.s_addr = inet_addr("192.0.2.1");
+    close_called = false;
+    ASSERT_EQ(-2, getSock(SOCK_STREAM, reinterpret_cast<sockaddr*>(&addr),
+                          sizeof addr, closeCall));
+    ASSERT_TRUE(close_called); // The "socket" call should have failed already
 }
 
 // The main run() function in the socket creator takes three functions to
@@ -198,7 +258,8 @@ TEST(get_sock, fail_with_nonsense) {
 // -1: The simulated bind() call has failed
 // -2: The simulated socket() call has failed
 int
-getSockDummy(const int type, struct sockaddr* addr, const socklen_t) {
+getSockDummy(const int type, struct sockaddr* addr, const socklen_t,
+             const close_t) {
     int result = 0;
     int port = 0;
 
@@ -253,12 +314,6 @@ send_FdDummy(const int destination, const int what) {
     return (status ? 0 : -1);
 }
 
-// Just ignore the fd and pretend success. We close invalid fds in the tests.
-int
-closeIgnore(int) {
-    return (0);
-}
-
 // Generic test that it works, with various inputs and outputs.
 // It uses different functions to create the socket and send it and pass
 // data to it and check it returns correct data back, to see if the run()

+ 8 - 15
src/bin/stats/b10-stats-httpd.8

@@ -1,22 +1,13 @@
 '\" t
 .\"     Title: b10-stats-httpd
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
-.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
-.\"      Date: Mar 8, 2011
+.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
+.\"      Date: February 28, 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-STATS\-HTTPD" "8" "Mar 8, 2011" "BIND10" "BIND10"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el       .ds Aq '
+.TH "B10\-STATS\-HTTPD" "8" "February 28, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -110,7 +101,9 @@ with its PID\&.
 .RS 4
 exits the
 \fBb10\-stats\-httpd\fR
-process\&. (Note that the BIND 10 boss process will restart this service\&.)
+process\&. This has an optional
+\fIpid\fR
+argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.)
 .RE
 .SH "SEE ALSO"
 .PP
@@ -125,8 +118,8 @@ BIND 10 Guide\&.
 .PP
 
 \fBb10\-stats\-httpd\fR
-was designed and implemented by Naoki Kambe of JPRS in Mar 2011\&.
+was designed and implemented by Naoki Kambe of JPRS in March 2011\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2011 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2011-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 10 - 7
src/bin/stats/b10-stats-httpd.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2011-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>Mar 8, 2011</date>
+    <date>February 28, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2011</year>
+      <year>2011-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -171,9 +171,12 @@
         <term><command>shutdown</command></term>
         <listitem>
 	  <para>
-	    exits the <command>b10-stats-httpd</command> process. (Note that
-	    the BIND 10 boss process will restart this service.)
-	  </para>
+	    exits the <command>b10-stats-httpd</command> process.
+            This has an optional <varname>pid</varname> argument to
+            select the process ID to stop.
+            (Note that the BIND 10 boss process may restart this service
+            if configured.)
+          </para>
         </listitem>
       </varlistentry>
     </variablelist>
@@ -205,7 +208,7 @@
     <title>HISTORY</title>
     <para>
       <command>b10-stats-httpd</command> was designed and implemented by Naoki
-      Kambe of JPRS in Mar 2011.
+      Kambe of JPRS in March 2011.
     </para>
   </refsect1>
 </refentry><!--

+ 20 - 18
src/bin/stats/b10-stats.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-stats
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: August 11, 2011
+.\"      Date: March 1, 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-STATS" "8" "August 11, 2011" "BIND10" "BIND10"
+.TH "B10\-STATS" "8" "March 1, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -79,9 +79,9 @@ will send the statistics data in JSON format\&. By default, it outputs all the s
 \fBshutdown\fR
 will shutdown the
 \fBb10\-stats\fR
-process\&. (Note that the
-\fBbind10\fR
-parent may restart it\&.)
+process\&. This has an optional
+\fIpid\fR
+argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.)
 .PP
 
 \fBstatus\fR
@@ -90,25 +90,22 @@ simply indicates that the daemon is running\&.
 .PP
 The
 \fBb10\-stats\fR
-daemon contains these statistics:
-.PP
-report_time
-.RS 4
-The latest report date and time in ISO 8601 format\&.
-.RE
+daemon contains these
+\(lqStats\(rq
+statistics:
 .PP
-stats\&.boot_time
+boot_time
 .RS 4
 The date and time when this daemon was started in ISO 8601 format\&. This is a constant which can\'t be reset except by restarting
 \fBb10\-stats\fR\&.
 .RE
 .PP
-stats\&.last_update_time
+last_update_time
 .RS 4
 The date and time (in ISO 8601 format) when this daemon last received data from another component\&.
 .RE
 .PP
-stats\&.lname
+lname
 .RS 4
 This is the name used for the
 \fBb10\-msgq\fR
@@ -116,14 +113,19 @@ command\-control channel\&. (This is a constant which can\'t be reset except by
 \fBb10\-stats\fR\&.)
 .RE
 .PP
-stats\&.start_time
+report_time
+.RS 4
+The latest report date and time in ISO 8601 format\&.
+.RE
+.PP
+start_time
 .RS 4
 This is the date and time (in ISO 8601 format) when this daemon started collecting data\&.
 .RE
 .PP
-stats\&.timestamp
+timestamp
 .RS 4
-The current date and time represented in seconds since UNIX epoch (1970\-01\-01T0 0:00:00Z) with precision (delimited with a period) up to one hundred thousandth of second\&.
+The current date and time represented in seconds since UNIX epoch (1970\-01\-01T00:00:00Z) with precision (delimited with a period) up to one hundred thousandth of second\&.
 .RE
 .PP
 See other manual pages for explanations for their statistics that are kept track by
@@ -150,5 +152,5 @@ The
 daemon was initially designed and implemented by Naoki Kambe of JPRS in October 2010\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 21 - 17
src/bin/stats/b10-stats.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2010,2011  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>August 11, 2011</date>
+    <date>March 1, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2010</year>
+      <year>2010-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -129,7 +129,10 @@
     <para>
       <command>shutdown</command> will shutdown the
       <command>b10-stats</command> process.
-      (Note that the <command>bind10</command> parent may restart it.)
+      This has an optional <varname>pid</varname> argument to
+      select the process ID to stop.
+      (Note that the BIND 10 boss process may restart this service
+      if configured.)
     </para>
 
     <para>
@@ -143,20 +146,15 @@
     <title>STATISTICS DATA</title>
 
     <para>
-      The <command>b10-stats</command> daemon contains these statistics:
+      The <command>b10-stats</command> daemon contains these
+      <quote>Stats</quote> statistics:
     </para>
 
     <variablelist>
 
-      <varlistentry>
-        <term>report_time</term>
-<!-- TODO: why not named stats.report_time? -->
-        <listitem><simpara>The latest report date and time in
-          ISO 8601 format.</simpara></listitem>
-      </varlistentry>
 
       <varlistentry>
-        <term>stats.boot_time</term>
+        <term>boot_time</term>
         <listitem><simpara>The date and time when this daemon was
           started in ISO 8601 format.
           This is a constant which can't be reset except by restarting
@@ -165,14 +163,14 @@
       </varlistentry>
 
       <varlistentry>
-        <term>stats.last_update_time</term>
+        <term>last_update_time</term>
         <listitem><simpara>The date and time (in ISO 8601 format)
           when this daemon last received data from another component.
         </simpara></listitem>
       </varlistentry>
 
       <varlistentry>
-        <term>stats.lname</term>
+        <term>lname</term>
         <listitem><simpara>This is the name used for the
           <command>b10-msgq</command> command-control channel.
           (This is a constant which can't be reset except by restarting
@@ -181,16 +179,22 @@
       </varlistentry>
 
       <varlistentry>
-        <term>stats.start_time</term>
+        <term>report_time</term>
+        <listitem><simpara>The latest report date and time in
+          ISO 8601 format.</simpara></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>start_time</term>
         <listitem><simpara>This is the date and time (in ISO 8601 format)
           when this daemon started collecting data.
         </simpara></listitem>
       </varlistentry>
 
       <varlistentry>
-        <term>stats.timestamp</term>
+        <term>timestamp</term>
         <listitem><simpara>The current date and time represented in
-          seconds since UNIX epoch (1970-01-01T0 0:00:00Z) with
+          seconds since UNIX epoch (1970-01-01T00:00:00Z) with
           precision (delimited with a period) up to
           one hundred thousandth of second.</simpara></listitem>
       </varlistentry>

+ 6 - 9
src/bin/xfrout/b10-xfrout.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-xfrout
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: December 15, 2011
+.\"      Date: February 28. 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-XFROUT" "8" "December 15, 2011" "BIND10" "BIND10"
+.TH "B10\-XFROUT" "8" "February 28\&. 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -70,11 +70,6 @@ The configurable settings are:
 defines the maximum number of outgoing zone transfers that can run concurrently\&. The default is 10\&.
 .PP
 
-\fItsig_key_ring\fR
-A list of TSIG keys (each of which is in the form of
-\fIname:base64\-key[:algorithm]\fR) used for access control on transfer requests\&. The default is an empty list\&.
-.PP
-
 \fItransfer_acl\fR
 A list of ACL elements that apply to all transfer requests by default (unless overridden in
 \fIzone_config\fR)\&. See the
@@ -129,7 +124,9 @@ The configuration commands are:
 
 \fBshutdown\fR
 stops all outbound zone transfers and exits
-\fBb10\-xfrout\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
+\fBb10\-xfrout\fR\&. This has an optional
+\fIpid\fR
+argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.)
 .PP
 
 \fBzone_new_data_ready\fR
@@ -154,5 +151,5 @@ The
 daemon was first implemented in March 2010 by Zhang Likun of CNNIC for the ISC BIND 10 project\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2010 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 9 - 46
src/bin/xfrout/b10-xfrout.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>December 15, 2011</date>
+    <date>February 28. 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2010</year>
+      <year>2010-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -98,13 +98,6 @@
       that can run concurrently. The default is 10.
     </para>
     <para>
-      <varname>tsig_key_ring</varname>
-      A list of TSIG keys (each of which is in the form of
-      <replaceable>name:base64-key[:algorithm]</replaceable>)
-      used for access control on transfer requests.
-      The default is an empty list.
-    </para>
-    <para>
       <varname>transfer_acl</varname>
       A list of ACL elements that apply to all transfer requests by
       default (unless overridden in <varname>zone_config</varname>).
@@ -122,33 +115,6 @@
       See the <citetitle>BIND 10 Guide</citetitle> for configuration examples.
       The default is an empty list, that is, no zone specific configuration.
     </para>
-    <para>
-      <varname>log_name</varname>
-<!-- TODO -->
-    </para>
-    <para>
-      <varname>log_file</varname>
-<!-- TODO -->
-      The location of the log file if using a file channel.
-      If undefined, then the file channel is closed.
-      The default is
-      <filename>/usr/local/var/bind10-devel/log/Xfrout.log</filename>.
-    </para>
-    <para>
-      <varname>log_severity</varname>
-<!-- TODO -->
-      The default is "debug".
-    </para>
-    <para>
-      <varname>log_versions</varname>
-<!-- TODO -->
-      The default is 5.
-    </para>
-    <para>
-      <varname>log_max_bytes</varname>
-<!-- TODO -->
-      The default is 1048576.
-    </para>
 
 <!-- TODO: log configurations not documented yet in here. jreed
      has some but waiting on decisions ... -->
@@ -160,21 +126,18 @@
     </simpara></note>
 
 
-<!--
-
-tsig_key_ring list of
-tsig_key string
-
--->
-
 <!-- TODO: formating -->
     <para>
       The configuration commands are:
     </para>
+
     <para>
       <command>shutdown</command> stops all outbound zone transfers
-      and exits <command>b10-xfrout</command>. (Note that the BIND 10
-      boss process will restart this service.)
+      and exits <command>b10-xfrout</command>.
+      This has an optional <varname>pid</varname> argument to
+      select the process ID to stop.
+      (Note that the BIND 10 boss process may restart this service
+      if configured.)
     </para>
 
     <para>

+ 35 - 15
src/bin/xfrout/tests/xfrout_test.py.in

@@ -28,6 +28,7 @@ from xfrout import *
 import xfrout
 import isc.log
 import isc.acl.dns
+import isc.server_common.tsig_keyring
 
 TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
 TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
@@ -1155,6 +1156,39 @@ class TestUnixSockServer(unittest.TestCase):
         self.write_sock, self.read_sock = socket.socketpair()
         self.unix = MyUnixSockServer()
 
+    def test_tsig_keyring(self):
+        """
+        Check we use the global keyring when starting a request.
+        """
+        try:
+            # These are just so the keyring can be started
+            self.unix._cc.add_remote_config_by_name = \
+                lambda name, callback: None
+            self.unix._cc.get_remote_config_value = \
+                lambda module, name: ([], True)
+            self.unix._cc.remove_remote_config = lambda name: None
+            isc.server_common.tsig_keyring.init_keyring(self.unix._cc)
+            # These are not really interesting for the test. These are just
+            # handled over, so strings are OK.
+            self.unix._guess_remote = lambda sock: "Address"
+            self.unix._zone_config = "Zone config"
+            self.unix._acl = "acl"
+            # This would be the handler class, but we just check it is passed
+            # the right parametes, so function is enough for that.
+            keys = isc.server_common.tsig_keyring.get_keyring()
+            def handler(sock, data, server, keyring, address, acl, config):
+                self.assertEqual("sock", sock)
+                self.assertEqual("data", data)
+                self.assertEqual(self.unix, server)
+                self.assertEqual(keys, keyring)
+                self.assertEqual("Address", address)
+                self.assertEqual("acl", acl)
+                self.assertEqual("Zone config", config)
+            self.unix.RequestHandlerClass = handler
+            self.unix.finish_request("sock", "data")
+        finally:
+            isc.server_common.tsig_keyring.deinit_keyring()
+
     def test_guess_remote(self):
         """Test we can guess the remote endpoint when we have only the
            file descriptor. This is needed, because we get only that one
@@ -1214,25 +1248,12 @@ class TestUnixSockServer(unittest.TestCase):
 
     def test_update_config_data(self):
         self.check_default_ACL()
-        tsig_key_str = 'example.com:SFuWd/q99SzF8Yzd1QbB9g=='
-        tsig_key_list = [tsig_key_str]
-        bad_key_list = ['bad..example.com:SFuWd/q99SzF8Yzd1QbB9g==']
         self.unix.update_config_data({'transfers_out':10 })
         self.assertEqual(self.unix._max_transfers_out, 10)
-        self.assertTrue(self.unix.tsig_key_ring is not None)
         self.check_default_ACL()
 
-        self.unix.update_config_data({'transfers_out':9,
-                                      'tsig_key_ring':tsig_key_list})
+        self.unix.update_config_data({'transfers_out':9})
         self.assertEqual(self.unix._max_transfers_out, 9)
-        self.assertEqual(self.unix.tsig_key_ring.size(), 1)
-        self.unix.tsig_key_ring.remove(Name("example.com."))
-        self.assertEqual(self.unix.tsig_key_ring.size(), 0)
-
-        # bad tsig key
-        config_data = {'transfers_out':9, 'tsig_key_ring': bad_key_list}
-        self.assertRaises(None, self.unix.update_config_data(config_data))
-        self.assertEqual(self.unix.tsig_key_ring.size(), 0)
 
         # Load the ACL
         self.unix.update_config_data({'transfer_acl': [{'from': '127.0.0.1',
@@ -1449,7 +1470,6 @@ class TestXfroutServer(unittest.TestCase):
         self.assertTrue(self.xfrout_server._notifier.shutdown_called)
         self.assertTrue(self.xfrout_server._cc.stopped)
 
-
 if __name__== "__main__":
     isc.log.resetUnitTestRootLogger()
     unittest.main()

+ 4 - 18
src/bin/xfrout/xfrout.py.in

@@ -34,6 +34,7 @@ import select
 import errno
 from optparse import OptionParser, OptionValueError
 from isc.util import socketserver_mixin
+import isc.server_common.tsig_keyring
 
 from isc.log_messages.xfrout_messages import *
 
@@ -769,7 +770,7 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
         zone_config = self._zone_config
         self._lock.release()
         self.RequestHandlerClass(sock_fd, request_data, self,
-                                 self.tsig_key_ring,
+                                 isc.server_common.tsig_keyring.get_keyring(),
                                  self._guess_remote(sock_fd), acl, zone_config)
 
     def _remove_unused_sock_file(self, sock_file):
@@ -833,7 +834,6 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
             self._acl = new_acl
             self._zone_config = new_zone_config
             self._max_transfers_out = new_config.get('transfers_out')
-            self.set_tsig_key_ring(new_config.get('tsig_key_ring'))
         except Exception as e:
             self._lock.release()
             raise e
@@ -870,21 +870,6 @@ class UnixSockServer(socketserver_mixin.NoPollMixIn,
                                             zclass_str + ': ' + str(e))
         return new_config
 
-    def set_tsig_key_ring(self, key_list):
-        """Set the tsig_key_ring , given a TSIG key string list representation. """
-
-        # XXX add values to configure zones/tsig options
-        self.tsig_key_ring = TSIGKeyRing()
-        # If key string list is empty, create a empty tsig_key_ring
-        if not key_list:
-            return
-
-        for key_item in key_list:
-            try:
-                self.tsig_key_ring.add(TSIGKey(key_item))
-            except InvalidParameter as ipe:
-                logger.error(XFROUT_BAD_TSIG_KEY_STRING, str(key_item))
-
     def get_db_file(self):
         file, is_default = self._cc.get_remote_config_value("Auth", "database_file")
         # this too should be unnecessary, but currently the
@@ -920,7 +905,8 @@ class XfroutServer:
         self._cc = isc.config.ModuleCCSession(SPECFILE_LOCATION, self.config_handler, self.command_handler)
         self._config_data = self._cc.get_full_config()
         self._cc.start()
-        self._cc.add_remote_config(AUTH_SPECFILE_LOCATION);
+        self._cc.add_remote_config(AUTH_SPECFILE_LOCATION)
+        isc.server_common.tsig_keyring.init_keyring(self._cc)
         self._start_xfr_query_listener()
         self._start_notifier()
 

+ 0 - 42
src/bin/xfrout/xfrout.spec.pre.in

@@ -9,48 +9,6 @@
          "item_default": 10
        },
        {
-         "item_name": "log_name",
-         "item_type": "string",
-         "item_optional": false,
-         "item_default": "Xfrout"
-       },
-       {
-         "item_name": "log_file",
-         "item_type": "string",
-         "item_optional": false,
-         "item_default": "@@LOCALSTATEDIR@@/@PACKAGE@/log/Xfrout.log"
-       },
-       {
-         "item_name": "log_severity",
-         "item_type": "string",
-         "item_optional": false,
-         "item_default": "debug"
-       },
-       {
-         "item_name": "log_versions",
-         "item_type": "integer",
-         "item_optional": false,
-         "item_default": 5
-       },
-       {
-         "item_name": "log_max_bytes",
-         "item_type": "integer",
-         "item_optional": false,
-         "item_default": 1048576
-       },
-       {
-         "item_name": "tsig_key_ring",
-         "item_type": "list",
-         "item_optional": true,
-         "item_default": [],
-         "list_item_spec" :
-         {
-             "item_name": "tsig_key",
-             "item_type": "string",
-             "item_optional": true
-         }
-       },
-       {
          "item_name": "transfer_acl",
          "item_type": "list",
          "item_optional": false,

+ 6 - 4
src/bin/zonemgr/b10-zonemgr.8

@@ -2,12 +2,12 @@
 .\"     Title: b10-zonemgr
 .\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
 .\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
-.\"      Date: December 8, 2011
+.\"      Date: February 28, 2012
 .\"    Manual: BIND10
 .\"    Source: BIND10
 .\"  Language: English
 .\"
-.TH "B10\-ZONEMGR" "8" "December 8, 2011" "BIND10" "BIND10"
+.TH "B10\-ZONEMGR" "8" "February 28, 2012" "BIND10" "BIND10"
 .\" -----------------------------------------------------------------
 .\" * set default formatting
 .\" -----------------------------------------------------------------
@@ -98,7 +98,9 @@ This is an internal command and not exposed to the administrator\&.
 
 \fBshutdown\fR
 exits
-\fBb10\-zonemgr\fR\&. (Note that the BIND 10 boss process will restart this service\&.)
+\fBb10\-zonemgr\fR\&. This has an optional
+\fIpid\fR
+argument to select the process ID to stop\&. (Note that the BIND 10 boss process may restart this service if configured\&.)
 .PP
 
 \fBzone_new_data_ready\fR
@@ -128,5 +130,5 @@ The
 daemon was designed in July 2010 by CNNIC for the ISC BIND 10 project\&.
 .SH "COPYRIGHT"
 .br
-Copyright \(co 2010-2011 Internet Systems Consortium, Inc. ("ISC")
+Copyright \(co 2010-2012 Internet Systems Consortium, Inc. ("ISC")
 .br

+ 7 - 4
src/bin/zonemgr/b10-zonemgr.xml

@@ -2,7 +2,7 @@
                "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
 	       [<!ENTITY mdash "&#8212;">]>
 <!--
- - Copyright (C) 2010-2011  Internet Systems Consortium, Inc. ("ISC")
+ - Copyright (C) 2010-2012  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
@@ -20,7 +20,7 @@
 <refentry>
 
   <refentryinfo>
-    <date>December 8, 2011</date>
+    <date>February 28, 2012</date>
   </refentryinfo>
 
   <refmeta>
@@ -36,7 +36,7 @@
 
   <docinfo>
     <copyright>
-      <year>2010-2011</year>
+      <year>2010-2012</year>
       <holder>Internet Systems Consortium, Inc. ("ISC")</holder>
     </copyright>
   </docinfo>
@@ -186,7 +186,10 @@
 
     <para>
       <command>shutdown</command> exits <command>b10-zonemgr</command>.
-      (Note that the BIND 10 boss process will restart this service.)
+      This has an optional <varname>pid</varname> argument to
+      select the process ID to stop.
+      (Note that the BIND 10 boss process may restart this service
+      if configured.)
     </para>
 
     <para>

+ 16 - 5
src/cppcheck-suppress.lst

@@ -4,8 +4,19 @@ debug
 missingInclude
 // This is a template, and should be excluded from the check
 unreadVariable:src/lib/dns/rdata/template.cc:61
-// Intentional self assignment tests.  Suppress warning about them.
-selfAssignment:src/lib/dns/tests/name_unittest.cc:293
-selfAssignment:src/lib/dns/tests/rdata_unittest.cc:228
-selfAssignment:src/lib/dns/tests/tsigkey_unittest.cc:137
-selfAssignment:src/lib/dns/tests/rdata_txt_like_unittest.cc:222
+
+// Intentional self-comparisons
+duplicateExpression:src/lib/dns/tests/name_unittest.cc:569
+duplicateExpression:src/lib/dns/tests/name_unittest.cc:580
+duplicateExpression:src/lib/dns/tests/rrttl_unittest.cc:164
+duplicateExpression:src/lib/dns/tests/rrttl_unittest.cc:175
+duplicateExpression:src/lib/dns/tests/name_unittest.cc:568
+duplicateExpression:src/lib/dns/tests/name_unittest.cc:579
+
+// Intentional self-comparisons
+uselessCallsCompare:src/lib/dns/tests/rdata_dhcid_unittest.cc:96
+uselessCallsCompare:src/lib/dns/tests/rdata_in_a_unittest.cc:98
+uselessCallsCompare:src/lib/dns/tests/rdata_in_aaaa_unittest.cc:94
+uselessCallsCompare:src/lib/dns/tests/rdata_mx_unittest.cc:104
+uselessCallsCompare:src/lib/dns/tests/rdata_unittest.cc:254
+uselessCallsCompare:src/lib/dns/tests/rdata_unittest.cc:253

+ 1 - 0
src/lib/asiodns/Makefile.am

@@ -24,6 +24,7 @@ libasiodns_la_SOURCES += dns_server.h
 libasiodns_la_SOURCES += dns_service.cc dns_service.h
 libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
 libasiodns_la_SOURCES += udp_server.cc udp_server.h
+libasiodns_la_SOURCES += sync_udp_server.cc sync_udp_server.h
 libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
 libasiodns_la_SOURCES += logger.h logger.cc
 

+ 0 - 16
src/lib/asiodns/dns_server.h

@@ -88,22 +88,6 @@ public:
     ///             to return.
     virtual void resume(const bool done) { self_->resume(done); }
 
-    /// \brief Indicate whether the server is able to send an answer
-    /// to a query.
-    ///
-    /// This is presently used only for testing purposes.
-    virtual bool hasAnswer() { return (self_->hasAnswer()); }
-
-    /// \brief Returns the current value of the 'coroutine' object
-    ///
-    /// This is a temporary method, intended to be used for debugging
-    /// purposes during development and removed later.  It allows
-    /// callers from outside the coroutine object to retrieve information
-    /// about its current state.
-    ///
-    /// \return The value of the 'coroutine' object
-    virtual int value() { return (self_->value()); }
-
     /// \brief Returns a pointer to a clone of this DNSServer object.
     ///
     /// When a \c DNSServer object is copied or assigned, the result will

+ 5 - 2
src/lib/asiodns/io_fetch.cc

@@ -205,7 +205,8 @@ IOFetch::IOFetch(Protocol protocol, IOService& service,
 }
 
 void
-IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol, IOService& service,
+IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol,
+                     IOService& service,
                      const isc::dns::Question& question,
                      const IOAddress& address, uint16_t port,
                      OutputBufferPtr& buff, Callback* cb, int wait, bool edns)
@@ -225,8 +226,10 @@ IOFetch::initIOFetch(MessagePtr& query_msg, Protocol protocol, IOService& servic
         query_msg->setEDNS(edns_query);
     }
 
-    MessageRenderer renderer(*data_->msgbuf);
+    MessageRenderer renderer;
+    renderer.setBuffer(data_->msgbuf.get());
     query_msg->toWire(renderer);
+    renderer.setBuffer(NULL);
 }
 
 // Return protocol in use.

+ 215 - 0
src/lib/asiodns/sync_udp_server.cc

@@ -0,0 +1,215 @@
+// Copyright (C) 2012  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 <asio.hpp>
+#include <asio/error.hpp>
+
+#include "sync_udp_server.h"
+#include "logger.h"
+
+#include <asiolink/dummy_io_cb.h>
+#include <asiolink/udp_endpoint.h>
+#include <asiolink/udp_socket.h>
+
+#include <boost/bind.hpp>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>             // for some IPC/network system calls
+#include <errno.h>
+
+using namespace std;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+SyncUDPServer::SyncUDPServer(asio::io_service& io_service,
+                             const asio::ip::address& addr,
+                             const uint16_t port,
+                             asiolink::SimpleCallback* checkin,
+                             DNSLookup* lookup, DNSAnswer* answer) :
+    output_buffer_(new isc::util::OutputBuffer(0)),
+    query_(new isc::dns::Message(isc::dns::Message::PARSE)),
+    answer_(new isc::dns::Message(isc::dns::Message::RENDER)),
+    io_(io_service), checkin_callback_(checkin), lookup_callback_(lookup),
+    answer_callback_(answer), stopped_(false)
+{
+    // We must use different instantiations for v4 and v6;
+    // otherwise ASIO will bind to both
+    asio::ip::udp proto = addr.is_v4() ? asio::ip::udp::v4() :
+        asio::ip::udp::v6();
+    socket_.reset(new asio::ip::udp::socket(io_service, proto));
+    socket_->set_option(asio::socket_base::reuse_address(true));
+    if (addr.is_v6()) {
+        socket_->set_option(asio::ip::v6_only(true));
+    }
+    socket_->bind(asio::ip::udp::endpoint(addr, port));
+}
+
+SyncUDPServer::SyncUDPServer(asio::io_service& io_service, const int fd,
+                             const int af, asiolink::SimpleCallback* checkin,
+                             DNSLookup* lookup, DNSAnswer* answer) :
+    output_buffer_(new isc::util::OutputBuffer(0)),
+    query_(new isc::dns::Message(isc::dns::Message::PARSE)),
+    answer_(new isc::dns::Message(isc::dns::Message::RENDER)),
+    io_(io_service), checkin_callback_(checkin), lookup_callback_(lookup),
+    answer_callback_(answer), stopped_(false)
+{
+    if (af != AF_INET && af != AF_INET6) {
+        isc_throw(InvalidParameter, "Address family must be either AF_INET "
+                  "or AF_INET6, not " << af);
+    }
+    LOG_DEBUG(logger, DBGLVL_TRACE_BASIC, ASIODNS_FD_ADD_UDP).arg(fd);
+    try {
+        socket_.reset(new asio::ip::udp::socket(io_service));
+        socket_->assign(af == AF_INET6 ? asio::ip::udp::v6() :
+                        asio::ip::udp::v4(), fd);
+    } catch (const std::exception& exception) {
+        // Whatever the thing throws, it is something from ASIO and we
+        // convert it
+        isc_throw(IOError, exception.what());
+    }
+}
+
+void
+SyncUDPServer::scheduleRead() {
+    socket_->async_receive_from(asio::buffer(data_, MAX_LENGTH), sender_,
+                                boost::bind(&SyncUDPServer::handleRead, this,
+                                            _1, _2));
+}
+
+void
+SyncUDPServer::handleRead(const asio::error_code& ec, const size_t length) {
+    // Abort on fatal errors
+    if (ec) {
+        using namespace asio::error;
+        if (ec.value() != would_block && ec.value() != try_again &&
+            ec.value() != interrupted) {
+            return;
+        }
+    }
+    // Some kind of interrupt, spurious wakeup, or like that. Just try reading
+    // again.
+    if (ec || length == 0) {
+        scheduleRead();
+        return;
+    }
+    // OK, we have a real packet of data. Let's dig into it!
+
+    // XXX: This is taken (and ported) from UDPSocket class. What the hell does
+    // it really mean?
+
+    // The UDP socket class has been extended with asynchronous functions
+    // and takes as a template parameter a completion callback class.  As
+    // UDPServer does not use these extended functions (only those defined
+    // in the IOSocket base class) - but needs a UDPSocket to get hold of
+    // the underlying Boost UDP socket - DummyIOCallback is used.  This
+    // provides the appropriate operator() but is otherwise functionless.
+    UDPSocket<DummyIOCallback> socket(*socket_);
+    UDPEndpoint endpoint(sender_);
+    IOMessage message(data_, length, socket, endpoint);
+    if (checkin_callback_ != NULL) {
+        (*checkin_callback_)(message);
+        if (stopped_) {
+            return;
+        }
+    }
+
+    // If we don't have a DNS Lookup provider, there's no point in
+    // continuing; we exit the coroutine permanently.
+    if (lookup_callback_ == NULL) {
+        scheduleRead();
+        return;
+    }
+
+    // Make sure the buffers are fresh
+    output_buffer_->clear();
+    query_->clear(isc::dns::Message::PARSE);
+    answer_->clear(isc::dns::Message::RENDER);
+
+    // Mark that we don't have an answer yet.
+    done_ = false;
+    resume_called_ = false;
+
+    // Call the actual lookup
+    (*lookup_callback_)(message, query_, answer_, output_buffer_, this);
+
+    if (!resume_called_) {
+        isc_throw(isc::Unexpected,
+                  "No resume called from the lookup callback");
+    }
+
+    if (stopped_) {
+        return;
+    }
+
+    if (done_) {
+        // Good, there's an answer.
+        // Call the answer callback to render it.
+        (*answer_callback_)(message, query_, answer_, output_buffer_);
+
+        if (stopped_) {
+            return;
+        }
+
+        socket_->send_to(asio::buffer(output_buffer_->getData(),
+                                      output_buffer_->getLength()),
+                         sender_);
+    }
+
+    // And schedule handling another socket.
+    scheduleRead();
+}
+
+void
+SyncUDPServer::operator()(asio::error_code, size_t) {
+    // To start the server, we just schedule reading of data when they
+    // arrive.
+    scheduleRead();
+}
+
+/// Stop the UDPServer
+void
+SyncUDPServer::stop() {
+    /// Using close instead of cancel, because cancel
+    /// will only cancel the asynchornized event already submitted
+    /// to io service, the events post to io service after
+    /// cancel still can be scheduled by io service, if
+    /// the socket is cloesed, all the asynchronized event
+    /// for it won't be scheduled by io service not matter it is
+    /// submit to io serice before or after close call. And we will
+    //. get bad_descriptor error
+    socket_->close();
+    stopped_ = true;
+}
+
+/// 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.
+void
+SyncUDPServer::resume(const bool done) {
+    resume_called_ = true;
+    done_ = done;
+}
+
+bool
+SyncUDPServer::hasAnswer() {
+    return (done_);
+}
+
+} // namespace asiodns
+} // namespace isc

+ 161 - 0
src/lib/asiodns/sync_udp_server.h

@@ -0,0 +1,161 @@
+// Copyright (C) 2012  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 __SYNC_UDP_SERVER_H
+#define __SYNC_UDP_SERVER_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include "dns_answer.h"
+#include "dns_lookup.h"
+#include "dns_server.h"
+
+#include <dns/message.h>
+#include <asiolink/simple_callback.h>
+#include <util/buffer.h>
+#include <exceptions/exceptions.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <stdint.h>
+
+namespace isc {
+namespace asiodns {
+
+/// \brief An UDP server that doesn't asynchronous lookup handlers.
+///
+/// That means, the lookup handler must provide the answer right away.
+/// This allows for implementation with less overhead, compared with
+/// the UDPClass.
+class SyncUDPServer : public DNSServer, public boost::noncopyable {
+public:
+    /// \brief Constructor
+    /// \param io_service the asio::io_service to work with
+    /// \param addr the IP address to listen for queries on
+    /// \param port the port to listen for queries on
+    /// \param checkin the callbackprovider for non-DNS events
+    /// \param lookup the callbackprovider for DNS lookup events
+    /// \param answer the callbackprovider for DNS answer events
+    explicit SyncUDPServer(asio::io_service& io_service,
+                           const asio::ip::address& addr, const uint16_t port,
+                           isc::asiolink::SimpleCallback* checkin = NULL,
+                           DNSLookup* lookup = NULL,
+                           DNSAnswer* answer = NULL);
+
+    /// \brief Constructor
+    /// \param io_service the asio::io_service to work with
+    /// \param fd the file descriptor of opened UDP socket
+    /// \param af address family, either AF_INET or AF_INET6
+    /// \param checkin the callbackprovider for non-DNS events
+    /// \param lookup the callbackprovider for DNS lookup events
+    /// \param answer the callbackprovider for DNS answer events
+    /// \throw isc::InvalidParameter if af is neither AF_INET nor AF_INET6
+    /// \throw isc::asiolink::IOError when a low-level error happens, like the
+    ///     fd is not a valid descriptor.
+    SyncUDPServer(asio::io_service& io_service, const int fd, const int af,
+                  isc::asiolink::SimpleCallback* checkin = NULL,
+                  DNSLookup* lookup = NULL, DNSAnswer* answer = NULL);
+
+    /// \brief Start the SyncUDPServer.
+    ///
+    /// This is the function operator to keep interface with other server
+    /// classes. They need that because they're coroutines.
+    virtual void operator()(asio::error_code ec = asio::error_code(),
+                    size_t length = 0);
+
+    /// \brief Calls the lookup callback
+    virtual void asyncLookup() {
+        isc_throw(Unexpected,
+                  "SyncUDPServer doesn't support asyncLookup by design, use "
+                  "UDPServer if you need it.");
+    }
+
+    /// \brief Stop the running server
+    /// \note once the server stopped, it can't restart
+    virtual void stop();
+
+    /// \brief Resume operation
+    ///
+    /// Note that unlike other servers, this one expects it to be called
+    /// directly from the lookup callback. If it isn't, the server will
+    /// throw an Unexpected exception (probably to the event loop, which
+    /// would usually lead to termination of the program, but that's OK,
+    /// as it would be serious programmer error).
+    ///
+    /// \param done Set this to true if the lookup action is done and
+    ///        we have an answer
+    virtual void resume(const bool done);
+
+    /// \brief Check if we have an answer
+    ///
+    /// \return true if we have an answer
+    virtual bool hasAnswer();
+
+    /// \brief Clones the object
+    ///
+    /// Since cloning is for the use of coroutines, the synchronous UDP server
+    /// does not need to be cloned. Therefore supporting it would be needless
+    /// work, and trying to clone it would be a programmer error anyway, this
+    /// throws Unexpected.
+    ///
+    /// \return a newly allocated copy of this object
+    virtual DNSServer* clone() {
+        isc_throw(Unexpected, "SyncUDPServer can't be cloned.");
+    }
+private:
+    // Internal state & buffers. We don't use the PIMPL idiom, as this class
+    // isn't usually used directly anyway.
+
+    // Maximum size of incoming UDP packet
+    static const size_t MAX_LENGTH = 4096;
+    // Buffer for incoming data
+    uint8_t data_[MAX_LENGTH];
+    // The buffer to render the output to and send it.
+    // If it was OK to have just a buffer, not the wrapper class,
+    // we could reuse the data_
+    isc::util::OutputBufferPtr output_buffer_;
+    // Objects to hold the query message and the answer
+    isc::dns::MessagePtr query_, answer_;
+    // The socket used for the communication
+    std::auto_ptr<asio::ip::udp::socket> socket_;
+    // The event loop we use
+    asio::io_service& io_;
+    // Place the socket puts the sender of a packet when it is received
+    asio::ip::udp::endpoint sender_;
+    // Callbacks
+    const asiolink::SimpleCallback* checkin_callback_;
+    const DNSLookup* lookup_callback_;
+    const DNSAnswer* answer_callback_;
+    // Answers from the lookup callback (not sent directly, but signalled
+    // through resume()
+    bool resume_called_, done_;
+    // This turns true when the server stops. Allows for not sending the
+    // answer after we closed the socket.
+    bool stopped_;
+
+    // Auxiliary functions
+
+    // Schedule next read on the socket. Just a wrapper around
+    // socket_->async_read_from with the correct parameters.
+    void scheduleRead();
+    // Callback from the socket's read call (called when there's an error or
+    // when a new packet comes).
+    void handleRead(const asio::error_code& ec, const size_t length);
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __SYNC_UDP_SERVER_H

+ 0 - 3
src/lib/asiodns/tcp_server.h

@@ -62,9 +62,6 @@ public:
     void asyncLookup();
     void stop();
     void resume(const bool done);
-    bool hasAnswer() { return (done_); }
-    int value() { return (get_value()); }
-
     DNSServer* clone() {
         TCPServer* s = new TCPServer(*this);
         return (s);

+ 84 - 35
src/lib/asiodns/tests/dns_server_unittest.cc

@@ -19,6 +19,7 @@
 #include <asiolink/io_endpoint.h>
 #include <asiolink/io_error.h>
 #include <asiodns/udp_server.h>
+#include <asiodns/sync_udp_server.h>
 #include <asiodns/tcp_server.h>
 #include <asiodns/dns_answer.h>
 #include <asiodns/dns_lookup.h>
@@ -112,15 +113,22 @@ class DummyChecker : public SimpleCallback, public ServerStopper {
 
 // \brief no lookup logic at all,just provide a checkpoint to stop the server
 class DummyLookup : public DNSLookup, public ServerStopper {
-    public:
-        void operator()(const IOMessage& io_message,
-                isc::dns::MessagePtr message,
-                isc::dns::MessagePtr answer_message,
-                isc::util::OutputBufferPtr buffer,
-                DNSServer* server) const {
-            stopServer();
+public:
+    DummyLookup() :
+        allow_resume_(true)
+    { }
+    void operator()(const IOMessage& io_message,
+            isc::dns::MessagePtr message,
+            isc::dns::MessagePtr answer_message,
+            isc::util::OutputBufferPtr buffer,
+            DNSServer* server) const {
+        stopServer();
+        if (allow_resume_) {
             server->resume(true);
         }
+    }
+    // If you want it not to call resume, set this to false
+    bool allow_resume_;
 };
 
 // \brief copy the data received from user to the answer part
@@ -314,10 +322,11 @@ class TCPClient : public SimpleClient {
 // two servers, UDP client will only communicate with UDP server, same for TCP
 // client
 //
-// This is only the active part of the test. We run the test case twice, once
+// This is only the active part of the test. We run the test case four times, once
 // for each type of initialization (once when giving it the address and port,
-// once when giving the file descriptor), to ensure it works both ways exactly
-// the same.
+// once when giving the file descriptor) multiplied by once for each type of UDP
+// server (UDPServer and SyncUDPServer), to ensure it works exactly the same.
+template<class UDPServerClass>
 class DNSServerTestBase : public::testing::Test {
     protected:
         DNSServerTestBase() :
@@ -396,7 +405,7 @@ class DNSServerTestBase : public::testing::Test {
         SimpleAnswer* const answer_;
         UDPClient*    const udp_client_;
         TCPClient*    const tcp_client_;
-        UDPServer*    udp_server_;
+        UDPServerClass* udp_server_;
         TCPServer*    tcp_server_;
 
         // To access them in signal handle function, the following
@@ -406,18 +415,23 @@ class DNSServerTestBase : public::testing::Test {
 };
 
 // Initialization with name and port
-class AddrPortInit : public DNSServerTestBase {
+template<class UDPServerClass>
+class AddrPortInit : public DNSServerTestBase<UDPServerClass> {
 protected:
     AddrPortInit() {
-        udp_server_ = new UDPServer(service, server_address_, server_port,
-                                    checker_, lookup_, answer_);
-        tcp_server_ = new TCPServer(service, server_address_, server_port,
-                                    checker_, lookup_, answer_);
+        this->udp_server_ = new UDPServerClass(this->service,
+                                               this->server_address_,
+                                               server_port, this->checker_,
+                                               this->lookup_, this->answer_);
+        this->tcp_server_ = new TCPServer(this->service, this->server_address_,
+                                          server_port, this->checker_,
+                                          this->lookup_, this->answer_);
     }
 };
 
 // Initialization by the file descriptor
-class FdInit : public DNSServerTestBase {
+template<class UDPServerClass>
+class FdInit : public DNSServerTestBase<UDPServerClass> {
 private:
     // Opens the file descriptor for us
     // It uses the low-level C api, as it seems to be the easiest way to get
@@ -465,12 +479,14 @@ protected:
     void SetUp() {
         const int fdUDP(getFd(SOCK_DGRAM));
         ASSERT_NE(-1, fdUDP) << strerror(errno);
-        udp_server_ = new UDPServer(service, fdUDP, AF_INET6, checker_,
-                                    lookup_, answer_);
+        this->udp_server_ = new UDPServerClass(this->service, fdUDP, AF_INET6,
+                                               this->checker_, this->lookup_,
+                                               this->answer_);
         const int fdTCP(getFd(SOCK_STREAM));
         ASSERT_NE(-1, fdTCP) << strerror(errno);
-        tcp_server_ = new TCPServer(service, fdTCP, AF_INET6, checker_,
-                                    lookup_, answer_);
+        this->tcp_server_ = new TCPServer(this->service, fdTCP, AF_INET6,
+                                          this->checker_, this->lookup_,
+                                          this->answer_);
     }
 };
 
@@ -478,11 +494,24 @@ protected:
 template<class Parent>
 class DNSServerTest : public Parent { };
 
-typedef ::testing::Types<AddrPortInit, FdInit> ServerTypes;
+typedef ::testing::Types<AddrPortInit<UDPServer>, AddrPortInit<SyncUDPServer>,
+                         FdInit<UDPServer>, FdInit<SyncUDPServer> >
+    ServerTypes;
 TYPED_TEST_CASE(DNSServerTest, ServerTypes);
 
-bool DNSServerTestBase::io_service_is_time_out = false;
-asio::io_service* DNSServerTestBase::current_service(NULL);
+typedef ::testing::Types<UDPServer, SyncUDPServer> UDPServerTypes;
+TYPED_TEST_CASE(DNSServerTestBase, UDPServerTypes);
+
+template<class UDPServerClass>
+bool DNSServerTestBase<UDPServerClass>::io_service_is_time_out = false;
+template<class UDPServerClass>
+asio::io_service* DNSServerTestBase<UDPServerClass>::current_service(NULL);
+
+typedef ::testing::Types<AddrPortInit<SyncUDPServer>, FdInit<SyncUDPServer> >
+    SyncTypes;
+template<class Parent>
+class SyncServerTest : public Parent { };
+TYPED_TEST_CASE(SyncServerTest, SyncTypes);
 
 // Test whether server stopped successfully after client get response
 // client will send query and start to wait for response, once client
@@ -608,17 +637,20 @@ TYPED_TEST(DNSServerTest, stopTCPServeMoreThanOnce) {
 }
 
 // It raises an exception when invalid address family is passed
-TEST_F(DNSServerTestBase, invalidFamily) {
+// The parameter here doesn't mean anything
+TYPED_TEST(DNSServerTestBase, invalidFamily) {
     // We abuse DNSServerTestBase for this test, as we don't need the
     // initialization.
-    EXPECT_THROW(UDPServer(service, 0, AF_UNIX, checker_, lookup_,
-                           answer_), isc::InvalidParameter);
-    EXPECT_THROW(TCPServer(service, 0, AF_UNIX, checker_, lookup_,
-                           answer_), isc::InvalidParameter);
+    EXPECT_THROW(TypeParam(this->service, 0, AF_UNIX, this->checker_,
+                           this->lookup_, this->answer_),
+                 isc::InvalidParameter);
+    EXPECT_THROW(TCPServer(this->service, 0, AF_UNIX, this->checker_,
+                           this->lookup_, this->answer_),
+                 isc::InvalidParameter);
 }
 
 // It raises an exception when invalid address family is passed
-TEST_F(DNSServerTestBase, invalidTCPFD) {
+TYPED_TEST(DNSServerTestBase, invalidTCPFD) {
     // We abuse DNSServerTestBase for this test, as we don't need the
     // initialization.
     /*
@@ -630,11 +662,12 @@ TEST_F(DNSServerTestBase, invalidTCPFD) {
     EXPECT_THROW(UDPServer(service, -1, AF_INET, checker_, lookup_,
                            answer_), isc::asiolink::IOError);
     */
-    EXPECT_THROW(TCPServer(service, -1, AF_INET, checker_, lookup_,
-                           answer_), isc::asiolink::IOError);
+    EXPECT_THROW(TCPServer(this->service, -1, AF_INET, this->checker_,
+                           this->lookup_, this->answer_),
+                 isc::asiolink::IOError);
 }
 
-TEST_F(DNSServerTestBase, DISABLED_invalidUDPFD) {
+TYPED_TEST(DNSServerTestBase, DISABLED_invalidUDPFD) {
     /*
      FIXME: The UDP server doesn't fail reliably with an invalid FD.
      We need to find a way to trigger it reliably (it seems epoll
@@ -642,8 +675,24 @@ TEST_F(DNSServerTestBase, DISABLED_invalidUDPFD) {
      not the others, maybe we could make it run this at least on epoll-based
      systems).
     */
-    EXPECT_THROW(UDPServer(service, -1, AF_INET, checker_, lookup_,
-                           answer_), isc::asiolink::IOError);
+    EXPECT_THROW(TypeParam(this->service, -1, AF_INET, this->checker_,
+                           this->lookup_, this->answer_),
+                 isc::asiolink::IOError);
+}
+
+// Check it rejects some of the unsupported operatirons
+TYPED_TEST(SyncServerTest, unsupportedOps) {
+    EXPECT_THROW(this->udp_server_->clone(), isc::Unexpected);
+    EXPECT_THROW(this->udp_server_->asyncLookup(), isc::Unexpected);
+}
+
+// Check it rejects forgotten resume (eg. insists that it is synchronous)
+TYPED_TEST(SyncServerTest, mustResume) {
+    this->lookup_->allow_resume_ = false;
+    ASSERT_THROW(this->testStopServerByStopper(this->udp_server_,
+                                               this->udp_client_,
+                                               this->lookup_),
+                 isc::Unexpected);
 }
 
 }

+ 17 - 10
src/lib/asiodns/tests/io_fetch_unittest.cc

@@ -133,10 +133,15 @@ public:
         EDNSPtr msg_edns(new EDNS());
         msg_edns->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
         msg.setEDNS(msg_edns);
-        MessageRenderer renderer(*msgbuf_);
+
+        MessageRenderer renderer;
+        renderer.setBuffer(msgbuf_.get());
+        msg.toWire(renderer);
+        renderer.setBuffer(NULL);
+
+        renderer.setBuffer(expected_buffer_.get());
         msg.toWire(renderer);
-        MessageRenderer renderer2(*expected_buffer_);
-        msg.toWire(renderer2);
+        renderer.setBuffer(NULL);
 
         // Initialize the test data to be returned: tests will return a
         // substring of this data. (It's convenient to have this as a member of
@@ -581,20 +586,22 @@ public:
         return_data_ = "Message returned to the client";
 
         udp::endpoint remote;
-        socket.async_receive_from(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
-            remote,
-            boost::bind(&IOFetchTest::udpReceiveHandler, this, &remote, &socket,
-                        _1, _2, bad_qid, second_send));
+        socket.async_receive_from(asio::buffer(receive_buffer_,
+                                               sizeof(receive_buffer_)),
+                                  remote,
+                                  boost::bind(&IOFetchTest::udpReceiveHandler,
+                                              this, &remote, &socket,
+                                              _1, _2, bad_qid, second_send));
         service_.get_io_service().post(udp_fetch_);
         if (debug_) {
-            cout << "udpSendReceive: async_receive_from posted, waiting for callback" <<
-                    endl;
+            cout << "udpSendReceive: async_receive_from posted,"
+                "waiting for callback" << endl;
         }
         service_.run();
 
         socket.close();
 
-        EXPECT_TRUE(run_);;
+        EXPECT_TRUE(run_);
     }
 };
 

+ 0 - 5
src/lib/asiodns/udp_server.cc

@@ -343,10 +343,5 @@ UDPServer::resume(const bool done) {
     data_->io_.post(*this);
 }
 
-bool
-UDPServer::hasAnswer() {
-    return (data_->done_);
-}
-
 } // namespace asiodns
 } // namespace isc

+ 0 - 10
src/lib/asiodns/udp_server.h

@@ -83,16 +83,6 @@ public:
     ///        we have an answer
     void resume(const bool done);
 
-    /// \brief Check if we have an answer
-    ///
-    /// \return true if we have an answer
-    bool hasAnswer();
-
-    /// \brief Returns the coroutine state value
-    ///
-    /// \return the coroutine state value
-    int value() { return (get_value()); }
-
     /// \brief Clones the object
     ///
     /// \return a newly allocated copy of this object

+ 4 - 5
src/lib/bench/benchmark_util.cc

@@ -61,8 +61,7 @@ loadQueryData(istream& input, BenchQueries& queries, const RRClass& qclass,
     string line;
     unsigned int linenum = 0;
     Message query_message(Message::RENDER);
-    OutputBuffer buffer(128); // this should be sufficiently large
-    MessageRenderer renderer(buffer);
+    MessageRenderer renderer;
     while (getline(input, line), !input.eof()) {
         ++linenum;
         if (input.bad() || input.fail()) {
@@ -99,9 +98,9 @@ loadQueryData(istream& input, BenchQueries& queries, const RRClass& qclass,
             renderer.clear();
             query_message.toWire(renderer);
             vector<unsigned char> query_data(
-                static_cast<const unsigned char*>(buffer.getData()),
-                static_cast<const unsigned char*>(buffer.getData()) +
-                buffer.getLength());
+                static_cast<const unsigned char*>(renderer.getData()),
+                static_cast<const unsigned char*>(renderer.getData()) +
+                renderer.getLength());
             queries.push_back(query_data);
         } catch (const Exception&) {
             if (strict) {

+ 0 - 1
src/lib/config/module_spec.cc

@@ -466,7 +466,6 @@ ModuleSpec::validateSpecList(ConstElementPtr spec, ConstElementPtr data,
                                const bool full, ElementPtr errors) const
 {
     bool validated = true;
-    std::string cur_item_name;
     BOOST_FOREACH(ConstElementPtr cur_spec_el, spec->listValue()) {
         if (!validateSpec(cur_spec_el, data, full, errors)) {
             validated = false;

+ 3 - 3
src/lib/datasrc/Makefile.am

@@ -7,10 +7,10 @@ AM_CPPFLAGS += $(SQLITE_CFLAGS)
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
-pkglibexecdir = $(libexecdir)/@PACKAGE@/backends
+pkglibdir = $(libexecdir)/@PACKAGE@/backends
 
 datasrc_config.h: datasrc_config.h.pre
-	$(SED) -e "s|@@PKGLIBEXECDIR@@|$(pkglibexecdir)|" datasrc_config.h.pre >$@
+	$(SED) -e "s|@@PKGLIBDIR@@|$(pkglibdir)|" datasrc_config.h.pre >$@
 
 CLEANFILES = *.gcno *.gcda datasrc_messages.h datasrc_messages.cc
 CLEANFILES += datasrc_config.h
@@ -32,7 +32,7 @@ libdatasrc_la_SOURCES += database.h database.cc
 libdatasrc_la_SOURCES += factory.h factory.cc
 nodist_libdatasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
 
-pkglibexec_LTLIBRARIES =  sqlite3_ds.la memory_ds.la
+pkglib_LTLIBRARIES =  sqlite3_ds.la memory_ds.la
 
 sqlite3_ds_la_SOURCES = sqlite3_accessor.h sqlite3_accessor.cc
 sqlite3_ds_la_LDFLAGS = -module

+ 1 - 1
src/lib/datasrc/datasrc_config.h.pre.in

@@ -23,7 +23,7 @@ namespace datasrc {
 /// such as memory_ds.so and sqlite3_ds.so are found. It is used by the
 /// DataSourceClient loader if no absolute path is used and
 /// B10_FROM_BUILD is not set in the environment.
-const char* const BACKEND_LIBRARY_PATH = "@@PKGLIBEXECDIR@@/";
+const char* const BACKEND_LIBRARY_PATH = "@@PKGLIBDIR@@/";
 
 } // end namespace datasrc
 } // end namespace isc

+ 1 - 1
src/lib/datasrc/datasrc_messages.mes

@@ -585,7 +585,7 @@ The underlying data source failed to answer the query for referral information.
 1 means some error, 2 is not implemented. The data source should have logged
 the specific error already.
 
-% DATASRC_QUERY_RRSIG unable to answer RRSIG query
+% DATASRC_QUERY_RRSIG unable to answer RRSIG query for %1
 The server is unable to answer a direct query for RRSIG type, but was asked
 to do so.
 

+ 34 - 18
src/lib/datasrc/memory_datasrc.cc

@@ -611,27 +611,40 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
      *
      * If rename is false, it returns the one provided. If it is true, it
      * creates a new rrset with the same data but with provided name.
+     * In addition, if DNSSEC records are required by the original caller of
+     * find(), it also creates expanded RRSIG based on the RRSIG of the
+     * wildcard RRset.
      * It is designed for wildcard case, where we create the rrsets
      * dynamically.
      */
-    static ConstRRsetPtr prepareRRset(const Name& name, const ConstRRsetPtr&
-        rrset, bool rename)
+    static ConstRRsetPtr prepareRRset(const Name& name,
+                                      const ConstRRsetPtr& rrset,
+                                      bool rename, FindOptions options)
     {
         if (rename) {
             LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_MEM_RENAME).
                 arg(rrset->getName()).arg(name);
-            /*
-             * We lose a signature here. But it would be wrong anyway, because
-             * the name changed. This might turn out to be unimportant in
-             * future, because wildcards will probably be handled somehow
-             * by DNSSEC.
-             */
             RRsetPtr result(new RRset(name, rrset->getClass(),
-                rrset->getType(), rrset->getTTL()));
+                                      rrset->getType(), rrset->getTTL()));
             for (RdataIteratorPtr i(rrset->getRdataIterator()); !i->isLast();
-                i->next()) {
+                 i->next()) {
                 result->addRdata(i->getCurrent());
             }
+            if ((options & FIND_DNSSEC) != 0) {
+                ConstRRsetPtr sig_rrset = rrset->getRRsig();
+                if (sig_rrset) {
+                    RRsetPtr result_sig(new RRset(name, sig_rrset->getClass(),
+                                                  RRType::RRSIG(),
+                                                  sig_rrset->getTTL()));
+                    for (RdataIteratorPtr i(sig_rrset->getRdataIterator());
+                         !i->isLast();
+                         i->next())
+                    {
+                        result_sig->addRdata(i->getCurrent());
+                    }
+                    result->addRRsig(result_sig);
+                }
+            }
             return (result);
         } else {
             return (rrset);
@@ -658,7 +671,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
 
     // Implementation of InMemoryZoneFinder::find
     FindResult find(const Name& name, RRType type,
-                    std::vector<ConstRRsetPtr> *target,
+                    std::vector<ConstRRsetPtr>* target,
                     const FindOptions options) const
     {
         LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FIND).arg(name).
@@ -695,14 +708,14 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
                     // We were traversing a DNAME node (and wanted to go
                     // lower below it), so return the DNAME
                     return (FindResult(DNAME, prepareRRset(name, state.rrset_,
-                                                           false)));
+                                                           false, options)));
                 }
                 if (state.zonecut_node_ != NULL) {
                     LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_DELEG_FOUND).
                         arg(state.rrset_->getName());
                     return (FindResult(DELEGATION,
                                        prepareRRset(name, state.rrset_,
-                                                    false)));
+                                                    false, options)));
                 }
 
                 // If the RBTree search stopped at a node for a super domain
@@ -806,7 +819,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
                 LOG_DEBUG(logger, DBG_TRACE_DATA,
                           DATASRC_MEM_EXACT_DELEGATION).arg(name);
                 return (FindResult(DELEGATION,
-                                   prepareRRset(name, found->second, rename)));
+                                   prepareRRset(name, found->second, rename,
+                                                options)));
             }
         }
 
@@ -816,7 +830,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
             for (found = node->getData()->begin();
                  found != node->getData()->end(); ++found)
             {
-                target->push_back(prepareRRset(name, found->second, rename));
+                target->push_back(prepareRRset(name, found->second, rename,
+                                               options));
             }
             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
                 arg(name);
@@ -830,7 +845,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
                 arg(type);
             return (createFindResult(SUCCESS, prepareRRset(name,
                                                            found->second,
-                                                           rename), rename));
+                                                           rename, options),
+                                     rename));
         } else {
             // Next, try CNAME.
             found = node->getData()->find(RRType::CNAME());
@@ -838,7 +854,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
                 LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
                 return (createFindResult(CNAME,
                                          prepareRRset(name, found->second,
-                                                      rename), rename));
+                                                      rename, options),
+                                         rename));
             }
         }
         // No exact match or CNAME.  Return NXRRSET.
@@ -1317,7 +1334,6 @@ checkConfig(ConstElementPtr config, ElementPtr errors) {
     }
 
     return (result);
-    return true;
 }
 
 } // end anonymous namespace

+ 8 - 0
src/lib/datasrc/sqlite3_datasrc.cc

@@ -76,6 +76,14 @@ const char* const SCHEMA_LIST[] = {
     "ttl INTEGER NOT NULL, rdtype STRING NOT NULL COLLATE NOCASE, "
     "rdata STRING NOT NULL)",
     "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
+    "CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
+        "zone_id INTEGER NOT NULL, "
+        "version INTEGER NOT NULL, "
+        "operation INTEGER NOT NULL, "
+        "name STRING NOT NULL COLLATE NOCASE, "
+        "rrtype STRING NOT NULL COLLATE NOCASE, "
+        "ttl INTEGER NOT NULL, "
+        "rdata STRING NOT NULL)",
     NULL
 };
 

+ 1 - 0
src/lib/datasrc/static_datasrc.cc

@@ -73,6 +73,7 @@ StaticDataSrcImpl::StaticDataSrcImpl() :
     authors->addRdata(generic::TXT("Dmitriy Volodin"));
     authors->addRdata(generic::TXT("Evan Hunt"));
     authors->addRdata(generic::TXT("Haidong Wang")); // Ocean
+    authors->addRdata(generic::TXT("Haikuo Zhang"));
     authors->addRdata(generic::TXT("Han Feng"));
     authors->addRdata(generic::TXT("Jelte Jansen"));
     authors->addRdata(generic::TXT("Jeremy C. Reed")); 

+ 1 - 2
src/lib/datasrc/tests/datasrc_unittest.cc

@@ -58,7 +58,7 @@ ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
 
 class DataSrcTest : public ::testing::Test {
 protected:
-    DataSrcTest() : obuffer(0), renderer(obuffer), msg(Message::PARSE),
+    DataSrcTest() : msg(Message::PARSE),
                     opcodeval(Opcode::QUERY().getCode()), qid(0)
     {
         DataSrcPtr sql3_source = DataSrcPtr(new Sqlite3DataSrc); 
@@ -76,7 +76,6 @@ protected:
 
     HotCache cache;
     MetaDataSrc meta_source;
-    OutputBuffer obuffer;
     MessageRenderer renderer;
     Message msg;
     const uint16_t opcodeval;

+ 51 - 7
src/lib/datasrc/tests/memory_datasrc_unittest.cc

@@ -548,6 +548,8 @@ public:
         if (zone_finder == NULL) {
             zone_finder = &zone_finder_;
         }
+        const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
+            RRsetPtr(); // note we use the same type as of retval of getRRsig()
         // The whole block is inside, because we need to check the result and
         // we can't assign to FindResult
         EXPECT_NO_THROW({
@@ -567,6 +569,11 @@ public:
                     } else {
                         ASSERT_TRUE(find_result.rrset);
                         rrsetCheck(answer, find_result.rrset);
+                        if (answer_sig) {
+                            ASSERT_TRUE(find_result.rrset->getRRsig());
+                            rrsetCheck(answer_sig,
+                                       find_result.rrset->getRRsig());
+                        }
                     }
                 } else if (check_wild_answer) {
                     ASSERT_NE(ConstRRsetPtr(), answer) <<
@@ -584,6 +591,22 @@ public:
                         wildanswer->addRdata(expectedIt->getCurrent());
                     }
                     rrsetCheck(wildanswer, find_result.rrset);
+
+                    // Same for the RRSIG, if any.
+                    if (answer_sig) {
+                        ASSERT_TRUE(find_result.rrset->getRRsig());
+
+                        RRsetPtr wildsig(new RRset(name,
+                                                   answer_sig->getClass(),
+                                                   RRType::RRSIG(),
+                                                   answer_sig->getTTL()));
+                        RdataIteratorPtr expectedIt(
+                            answer_sig->getRdataIterator());
+                        for (; !expectedIt->isLast(); expectedIt->next()) {
+                            wildsig->addRdata(expectedIt->getCurrent());
+                        }
+                        rrsetCheck(wildsig, find_result.rrset->getRRsig());
+                    }
                 }
             });
     }
@@ -1088,6 +1111,24 @@ InMemoryZoneFinderTest::wildcardCheck(
      *                 |
      *                 *
      */
+
+    // If the zone is "signed" (detecting it by the NSEC/NSEC3 signed flags),
+    // add RRSIGs to the records.
+    ZoneFinder::FindOptions find_options = ZoneFinder::FIND_DEFAULT;
+    if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0 ||
+        (expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
+        // Convenience shortcut.  The RDATA is not really validatable, but
+        // it doesn't matter for our tests.
+        const char* const rrsig_common = "5 3 3600 "
+            "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
+
+        find_options = find_options | ZoneFinder::FIND_DNSSEC;
+        rr_wild_->addRRsig(textToRRset("*.wild.example.org. 300 IN RRSIG A " +
+                                       string(rrsig_common)));
+        rr_cnamewild_->addRRsig(textToRRset("*.cnamewild.example.org. 300 IN "
+                                            "RRSIG CNAME " +
+                                            string(rrsig_common)));
+    }
     EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
     EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cnamewild_));
     // If the zone is expected to be "signed" with NSEC3, add an NSEC3.
@@ -1101,14 +1142,15 @@ InMemoryZoneFinderTest::wildcardCheck(
     {
         SCOPED_TRACE("Search at parent");
         findTest(Name("wild.example.org"), RRType::A(), ZoneFinder::NXRRSET,
-                 true, ConstRRsetPtr(), expected_flags);
+                 true, ConstRRsetPtr(), expected_flags, NULL, find_options);
     }
 
     // Search the original name of wildcard
     {
         SCOPED_TRACE("Search directly at *");
         findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
-                 true, rr_wild_);
+                 true, rr_wild_, ZoneFinder::RESULT_DEFAULT, NULL,
+                 find_options);
     }
     // Search "created" name.
     {
@@ -1116,11 +1158,12 @@ InMemoryZoneFinderTest::wildcardCheck(
         findTest(Name("a.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
                  false, rr_wild_,
                  ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
-                 ZoneFinder::FIND_DEFAULT, true);
+                 find_options, true);
         // Wildcard match, but no data
         findTest(Name("a.wild.example.org"), RRType::AAAA(),
                  ZoneFinder::NXRRSET, true, ConstRRsetPtr(),
-                 ZoneFinder::RESULT_WILDCARD | expected_flags);
+                 ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
+                 find_options);
     }
 
     // Search name that has CNAME.
@@ -1129,7 +1172,7 @@ InMemoryZoneFinderTest::wildcardCheck(
         findTest(Name("a.cnamewild.example.org"), RRType::A(),
                  ZoneFinder::CNAME, false, rr_cnamewild_,
                  ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
-                 ZoneFinder::FIND_DEFAULT, true);
+                 find_options, true);
     }
 
     // Search another created name, this time little bit lower
@@ -1138,14 +1181,15 @@ InMemoryZoneFinderTest::wildcardCheck(
         findTest(Name("a.b.wild.example.org"), RRType::A(),
                  ZoneFinder::SUCCESS, false, rr_wild_,
                  ZoneFinder::RESULT_WILDCARD | expected_flags, NULL,
-                 ZoneFinder::FIND_DEFAULT, true);
+                 find_options, true);
     }
 
     EXPECT_EQ(SUCCESS, zone_finder_.add(rr_under_wild_));
     {
         SCOPED_TRACE("Search under non-wildcard");
         findTest(Name("bar.foo.wild.example.org"), RRType::A(),
-                 ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags);
+                 ZoneFinder::NXDOMAIN, true, ConstRRsetPtr(), expected_flags,
+                 NULL, find_options);
     }
 }
 

+ 1 - 0
src/lib/datasrc/tests/static_unittest.cc

@@ -56,6 +56,7 @@ protected:
         authors_data.push_back("Dmitriy Volodin");
         authors_data.push_back("Evan Hunt");
         authors_data.push_back("Haidong Wang");
+        authors_data.push_back("Haikuo Zhang");
         authors_data.push_back("Han Feng");
         authors_data.push_back("Jelte Jansen");
         authors_data.push_back("Jeremy C. Reed");

+ 2 - 2
src/lib/dhcp/iface_mgr.cc

@@ -130,7 +130,7 @@ IfaceMgr::IfaceMgr()
         // interface detection is implemented. Otherwise
         // it is not possible to run tests in a portable
         // way (see detectIfaces() method).
-        throw ex;
+        throw;
     }
 }
 
@@ -191,7 +191,7 @@ IfaceMgr::stubDetectIfaces() {
 
         // TODO Do LOG_FATAL here
         std::cerr << "Interface detection failed." << std::endl;
-        throw ex;
+        throw;
     }
 }
 

+ 1 - 2
src/lib/dns/benchmarks/rdatarender_bench.cc

@@ -42,7 +42,7 @@ template <typename T>
 class RdataRenderBenchMark {
 public:
     RdataRenderBenchMark(const vector<T>& dataset) :
-        dataset_(dataset), buffer_(4096), renderer_(buffer_)
+        dataset_(dataset)
     {}
     unsigned int run() {
         typename vector<T>::const_iterator data;
@@ -55,7 +55,6 @@ public:
     }
 private:
     const vector<T>& dataset_;
-    OutputBuffer buffer_;
     MessageRenderer renderer_;
 };
 

+ 32 - 1
src/lib/dns/masterload.cc

@@ -37,6 +37,29 @@ using namespace isc::dns::rdata;
 
 namespace isc {
 namespace dns {
+namespace {
+// A helper function that strips off any comment or whitespace at the end of
+// an RR.
+// This is an incomplete implementation, and cannot handle all such comments;
+// it's considered a short term workaround to deal with some real world
+// cases.
+string
+stripLine(string& s, const Exception& ex) {
+    // Find any ';' in the text data, and locate the position of the last
+    // occurrence.  Note that unless/until we support empty RDATA it
+    // shouldn't be placed at the beginning of the data.
+    const size_t pos_semicolon = s.rfind(';');
+    if (pos_semicolon == 0) {
+        throw ex;
+    } else if (pos_semicolon != string::npos) {
+        s.resize(pos_semicolon);
+    }
+    // Remove any trailing whitespace return the resulting text.
+    s.resize(s.find_last_not_of(" \t") + 1);
+    return (s);
+}
+}
+
 void
 masterLoad(const char* const filename, const Name& origin,
            const RRClass& zone_class, MasterLoadCallback callback)
@@ -116,7 +139,15 @@ masterLoad(istream& input, const Name& origin, const RRClass& zone_class,
             ttl.reset(new RRTTL(ttl_txt));
             rrclass.reset(new RRClass(rrclass_txt));
             rrtype.reset(new RRType(rrtype_txt));
-            rdata = createRdata(*rrtype, *rrclass, rdatabuf.str());
+            string rdtext = rdatabuf.str();
+            try {
+                rdata = createRdata(*rrtype, *rrclass, rdtext);
+            } catch (const Exception& ex) {
+                // If the parse for the RDATA fails, check if it has comments
+                // or whitespace at the end, and if so, retry the conversion
+                // after stripping off the comment or whitespace
+                rdata = createRdata(*rrtype, *rrclass, stripLine(rdtext, ex));
+            }
         } catch (const Exception& ex) {
             isc_throw(MasterLoadError, "Invalid RR text at line " << line_count
                       << ": " << ex.what());

+ 33 - 7
src/lib/dns/messagerenderer.cc

@@ -12,14 +12,15 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <cctype>
-#include <cassert>
-#include <set>
-
+#include <exceptions/exceptions.h>
 #include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
 
+#include <cctype>
+#include <cassert>
+#include <set>
+
 using namespace isc::util;
 
 namespace isc {
@@ -171,8 +172,8 @@ struct MessageRenderer::MessageRendererImpl {
     CompressMode compress_mode_;
 };
 
-MessageRenderer::MessageRenderer(OutputBuffer& buffer) :
-    AbstractMessageRenderer(buffer),
+MessageRenderer::MessageRenderer() :
+    AbstractMessageRenderer(),
     impl_(new MessageRendererImpl)
 {}
 
@@ -273,9 +274,34 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
     }
 }
 
+AbstractMessageRenderer::AbstractMessageRenderer() :
+    local_buffer_(0), buffer_(&local_buffer_)
+{
+}
+
+void
+AbstractMessageRenderer::setBuffer(OutputBuffer* buffer) {
+    if (buffer != NULL && buffer_->getLength() != 0) {
+        isc_throw(isc::InvalidParameter,
+                  "MessageRenderer buffer cannot be set when in use");
+    } if (buffer == NULL && buffer_ == &local_buffer_) {
+        isc_throw(isc::InvalidParameter,
+                  "Default MessageRenderer buffer cannot be reset");
+    }
+
+    if (buffer == NULL) {
+        // Reset to the default buffer, then clear other internal resources.
+        // The order is important; we need to keep the used buffer intact.
+        buffer_ = &local_buffer_;
+        clear();
+    } else {
+        buffer_ = buffer;
+    }
+}
+
 void
 AbstractMessageRenderer::clear() {
-    buffer_.clear();
+    buffer_->clear();
 }
 
 }

+ 63 - 31
src/lib/dns/messagerenderer.h

@@ -37,9 +37,15 @@ class Name;
 /// comprehensive \c Message class internally; normal applications won't have
 /// to care about details of this class.
 ///
-/// Once a renderer class object is constructed with a buffer, it is
-/// generally expected that all rendering operations are performed via that
-/// object.  If the application modifies the buffer in
+/// By default any (derived) renderer class object is associated with
+/// an internal buffer, and subsequent write operations will be performed
+/// on that buffer.  The rendering result can be retrieved via the
+/// \c getData() method.
+///
+/// If an application wants a separate buffer can be (normally temporarily)
+/// set for rendering operations via the \c setBuffer() method.  In that case,
+/// it is generally expected that all rendering operations are performed via
+/// that object.  If the application modifies the buffer in
 /// parallel with the renderer, the result will be undefined.
 ///
 /// Note to developers: we introduced a separate class for name compression
@@ -101,30 +107,30 @@ protected:
     ///
     /// This is intentionally defined as \c protected as this base class should
     /// never be instantiated (except as part of a derived class).
-    /// \param buffer The buffer where the data should be rendered into.
-    /// \todo We might want to revisit this API at some point and remove the
-    ///     buffer parameter. In that case it would create it's own buffer and
-    ///     a function to extract the data would be available instead. It seems
-    ///     like a cleaner design, but it's left undone until we would actually
-    ///     benefit from the change.
-    AbstractMessageRenderer(isc::util::OutputBuffer& buffer) :
-        buffer_(buffer)
-    {}
+    AbstractMessageRenderer();
+
 public:
     /// \brief The destructor.
     virtual ~AbstractMessageRenderer() {}
     //@}
 protected:
     /// \brief Return the output buffer we render into.
-    const isc::util::OutputBuffer& getBuffer() const { return (buffer_); }
-    isc::util::OutputBuffer& getBuffer() { return (buffer_); }
+    const isc::util::OutputBuffer& getBuffer() const { return (*buffer_); }
+    isc::util::OutputBuffer& getBuffer() { return (*buffer_); }
 private:
-    /// \short Buffer to store data
+    /// \brief Local (default) buffer to store data.
+    isc::util::OutputBuffer local_buffer_;
+
+    /// \brief Buffer to store data.
+    ///
+    /// Note that the class interface ensures this pointer is never NULL;
+    /// it either refers to \c local_buffer_ or to an application-supplied
+    /// buffer by \c setBuffer().
     ///
     /// It was decided that there's no need to have this in every subclass,
-    /// at least not now, and this reduces code size and gives compiler a better
-    /// chance to optimise.
-    isc::util::OutputBuffer& buffer_;
+    /// at least not now, and this reduces code size and gives compiler a
+    /// better chance to optimise.
+    isc::util::OutputBuffer* buffer_;
 public:
     ///
     /// \name Getter Methods
@@ -136,12 +142,12 @@ public:
     /// This method works exactly same as the same method of the \c OutputBuffer
     /// class; all notes for \c OutputBuffer apply.
     const void* getData() const {
-        return (buffer_.getData());
+        return (buffer_->getData());
     }
 
     /// \brief Return the length of data written in the internal buffer.
     size_t getLength() const {
-        return (buffer_.getLength());
+        return (buffer_->getLength());
     }
 
     /// \brief Return whether truncation has occurred while rendering.
@@ -175,6 +181,35 @@ public:
     /// \name Setter Methods
     ///
     //@{
+    /// \brief Set or reset a temporary output buffer.
+    ///
+    /// This method can be used for an application that manages an output
+    /// buffer separately from the message renderer and wants to keep reusing
+    /// the renderer.  When the renderer is associated with the default buffer
+    /// and the given pointer is non NULL, the given buffer will be
+    /// (temporarily) used for subsequent message rendering; if the renderer
+    /// is associated with a temporary buffer and the given pointer is NULL,
+    /// the renderer will be reset with the default buffer.  In the latter
+    /// case any additional resources (possibly specific to a derived renderer
+    /// class) will be cleared, but the temporary buffer is kept as the latest
+    /// state (which would normally store the rendering result).
+    ///
+    /// This method imposes some restrictions to prevent accidental misuse
+    /// that could cause disruption such as dereferencing an invalid object.
+    /// First, a temporary buffer must not be set when the associated buffer
+    /// is in use, that is, any data are stored in the buffer.  Also, the
+    /// default buffer cannot be "reset"; when NULL is specified a temporary
+    /// buffer must have been set beforehand.  If these conditions aren't met
+    /// an isc::InvalidParameter exception will be thrown.  This method is
+    /// exception free otherwise.
+    ///
+    /// \throw isc::InvalidParameter A restrictions of the method usage isn't
+    /// met.
+    ///
+    /// \param buffer A pointer to a temporary output buffer or NULL for reset
+    /// it.
+    void setBuffer(isc::util::OutputBuffer* buffer);
+
     /// \brief Mark the renderer to indicate truncation has occurred while
     /// rendering.
     ///
@@ -209,7 +244,7 @@ public:
     ///
     /// \param len The length of the gap to be inserted in bytes.
     void skip(size_t len) {
-        buffer_.skip(len);
+        buffer_->skip(len);
     }
 
     /// \brief Trim the specified length of data from the end of the internal
@@ -223,7 +258,7 @@ public:
     ///
     /// \param len The length of data that should be trimmed.
     void trim(size_t len) {
-        buffer_.trim(len);
+        buffer_->trim(len);
     }
 
     /// \brief Clear the internal buffer and other internal resources.
@@ -236,7 +271,7 @@ public:
     ///
     /// \param data The 8-bit integer to be written into the internal buffer.
     void writeUint8(const uint8_t data) {
-        buffer_.writeUint8(data);
+        buffer_->writeUint8(data);
     }
 
     /// \brief Write an unsigned 16-bit integer in host byte order into the
@@ -244,7 +279,7 @@ public:
     ///
     /// \param data The 16-bit integer to be written into the buffer.
     void writeUint16(uint16_t data) {
-        buffer_.writeUint16(data);
+        buffer_->writeUint16(data);
     }
 
     /// \brief Write an unsigned 16-bit integer in host byte order at the
@@ -259,7 +294,7 @@ public:
     /// \param data The 16-bit integer to be written into the internal buffer.
     /// \param pos The beginning position in the buffer to write the data.
     void writeUint16At(uint16_t data, size_t pos) {
-        buffer_.writeUint16At(data, pos);
+        buffer_->writeUint16At(data, pos);
     }
 
     /// \brief Write an unsigned 32-bit integer in host byte order into the
@@ -267,7 +302,7 @@ public:
     ///
     /// \param data The 32-bit integer to be written into the buffer.
     void writeUint32(uint32_t data) {
-        buffer_.writeUint32(data);
+        buffer_->writeUint32(data);
     }
 
     /// \brief Copy an arbitrary length of data into the internal buffer
@@ -278,7 +313,7 @@ public:
     /// \param data A pointer to the data to be copied into the internal buffer.
     /// \param len The length of the data in bytes.
     void writeData(const void *data, size_t len) {
-        buffer_.writeData(data, len);
+        buffer_->writeData(data, len);
     }
 
     /// \brief Write a \c Name object into the internal buffer in wire format,
@@ -316,10 +351,7 @@ public:
     using AbstractMessageRenderer::CASE_SENSITIVE;
 
     /// \brief Constructor from an output buffer.
-    ///
-    /// \param buffer An \c OutputBuffer object to which wire format data is
-    /// written.
-    MessageRenderer(isc::util::OutputBuffer& buffer);
+    MessageRenderer();
 
     virtual ~MessageRenderer();
     virtual bool isTruncated() const;

+ 2 - 1
src/lib/dns/python/message_python.cc

@@ -377,8 +377,9 @@ Message_getTSIGRecord(s_Message* self) {
 
         if (tsig_record == NULL) {
             Py_RETURN_NONE;
+        } else {
+            return (createTSIGRecordObject(*tsig_record));
         }
-        return (createTSIGRecordObject(*tsig_record));
     } catch (const InvalidMessageOperation& ex) {
         PyErr_SetString(po_InvalidMessageOperation, ex.what());
     } catch (const exception& ex) {

+ 1 - 5
src/lib/dns/python/messagerenderer_python.cc

@@ -36,7 +36,6 @@ namespace {
 class s_MessageRenderer : public PyObject {
 public:
     s_MessageRenderer();
-    isc::util::OutputBuffer* outputbuffer;
     MessageRenderer* cppobj;
 };
 
@@ -78,17 +77,14 @@ PyMethodDef MessageRenderer_methods[] = {
 
 int
 MessageRenderer_init(s_MessageRenderer* self) {
-    self->outputbuffer = new OutputBuffer(4096);
-    self->cppobj = new MessageRenderer(*self->outputbuffer);
+    self->cppobj = new MessageRenderer;
     return (0);
 }
 
 void
 MessageRenderer_destroy(s_MessageRenderer* self) {
     delete self->cppobj;
-    delete self->outputbuffer;
     self->cppobj = NULL;
-    self->outputbuffer = NULL;
     Py_TYPE(self)->tp_free(self);
 }
 

+ 2 - 4
src/lib/dns/rdatafields.cc

@@ -70,8 +70,7 @@ namespace {
 // it's hopefully an acceptable practice.
 class RdataFieldComposer : public AbstractMessageRenderer {
 public:
-    RdataFieldComposer(OutputBuffer& buffer) :
-        AbstractMessageRenderer(buffer),
+    RdataFieldComposer() :
         truncated_(false), length_limit_(65535),
         mode_(CASE_INSENSITIVE), last_data_pos_(0)
     {}
@@ -128,8 +127,7 @@ public:
 }
 
 RdataFields::RdataFields(const Rdata& rdata) {
-    OutputBuffer buffer(0);
-    RdataFieldComposer field_composer(buffer);
+    RdataFieldComposer field_composer;
     rdata.toWire(field_composer);
     nfields_ = field_composer.getFields().size();
     data_length_ = field_composer.getLength();

+ 1 - 3
src/lib/dns/tests/edns_unittest.cc

@@ -43,9 +43,7 @@ const uint8_t EDNS::SUPPORTED_VERSION;
 namespace {
 class EDNSTest : public ::testing::Test {
 protected:
-    EDNSTest() : rrtype(RRType::OPT()), buffer(NULL, 0), obuffer(0),
-                 renderer(obuffer), rcode(0)
-    {
+    EDNSTest() : rrtype(RRType::OPT()), buffer(NULL, 0), obuffer(0), rcode(0) {
         opt_rdata = ConstRdataPtr(new generic::OPT());
         edns_base.setUDPSize(4096);
     }

+ 98 - 0
src/lib/dns/tests/masterload_unittest.cc

@@ -25,6 +25,7 @@
 
 #include <dns/masterload.h>
 #include <dns/name.h>
+#include <dns/rdata.h>
 #include <dns/rrclass.h>
 #include <dns/rrset.h>
 
@@ -80,6 +81,11 @@ const char* const rrsig_rr2 =
     "www.example.com. 60 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
     "12345 example.com. FAKEFAKEFAKE\n";
 
+// Commonly used for some tests to check the constructed RR content.
+const char* const dnskey_rdata =
+    "256 3 7 AwEAAaetidLzsKWUt4swWR8yu0wPHPiUi8LUsAD0QPWU+wzt89epO6tH "
+    "zkMBVDkC7qphQO2hTY4hHn9npWFRw5BYubE=\n";
+
 TEST_F(MasterLoadTest, loadRRs) {
     // a simple case: loading 3 RRs, each consists of a single RRset.
     rr_stream << txt_rr << a_rr1 << soa_rr;
@@ -161,6 +167,98 @@ TEST_F(MasterLoadTest, loadRRsigs) {
     EXPECT_EQ(2, results.size());
 }
 
+TEST_F(MasterLoadTest, loadRRWithComment) {
+    // Comment at the end of line should be ignored and the RR should be
+    // accepted.
+    rr_stream << "example.com. 3600 IN DNSKEY	256 3 7 "
+        "AwEAAaetidLzsKWUt4swWR8yu0wPHPiUi8LUsAD0QPWU+wzt89epO6tH "
+        "zkMBVDkC7qphQO2hTY4hHn9npWFRw5BYubE=  ; key id = 40430\n";
+    masterLoad(rr_stream, origin, zclass, callback);
+    ASSERT_EQ(1, results.size());
+    EXPECT_EQ(0, results[0]->getRdataIterator()->getCurrent().compare(
+                  *rdata::createRdata(RRType::DNSKEY(), zclass,
+                                      dnskey_rdata)));
+}
+
+TEST_F(MasterLoadTest, loadRRWithCommentNoSpace) {
+    // Similar to the previous one, but there's no space before comments.
+    // It should still work.
+    rr_stream << "example.com. 3600 IN DNSKEY	256 3 7 "
+        "AwEAAaetidLzsKWUt4swWR8yu0wPHPiUi8LUsAD0QPWU+wzt89epO6tH "
+        "zkMBVDkC7qphQO2hTY4hHn9npWFRw5BYubE=; key id = 40430\n";
+    masterLoad(rr_stream, origin, zclass, callback);
+    ASSERT_EQ(1, results.size());
+    EXPECT_EQ(0, results[0]->getRdataIterator()->getCurrent().compare(
+                  *rdata::createRdata(RRType::DNSKEY(), zclass,
+                                      dnskey_rdata)));
+}
+
+TEST_F(MasterLoadTest, loadRRWithCommentEmptyComment) {
+    // Similar to the previous one, but there's no data after the ;
+    // It should still work.
+    rr_stream << "example.com. 3600 IN DNSKEY	256 3 7 "
+        "AwEAAaetidLzsKWUt4swWR8yu0wPHPiUi8LUsAD0QPWU+wzt89epO6tH "
+        "zkMBVDkC7qphQO2hTY4hHn9npWFRw5BYubE= ;\n";
+    masterLoad(rr_stream, origin, zclass, callback);
+    ASSERT_EQ(1, results.size());
+    EXPECT_EQ(0, results[0]->getRdataIterator()->getCurrent().compare(
+                  *rdata::createRdata(RRType::DNSKEY(), zclass,
+                                      dnskey_rdata)));
+}
+
+TEST_F(MasterLoadTest, loadRRWithCommentEmptyCommentNoSpace) {
+    // Similar to the previous one, but there's no space before or after ;
+    // It should still work.
+    rr_stream << "example.com. 3600 IN DNSKEY	256 3 7 "
+        "AwEAAaetidLzsKWUt4swWR8yu0wPHPiUi8LUsAD0QPWU+wzt89epO6tH "
+        "zkMBVDkC7qphQO2hTY4hHn9npWFRw5BYubE=;\n";
+    masterLoad(rr_stream, origin, zclass, callback);
+    ASSERT_EQ(1, results.size());
+    EXPECT_EQ(0, results[0]->getRdataIterator()->getCurrent().compare(
+                  *rdata::createRdata(RRType::DNSKEY(), zclass,
+                                      dnskey_rdata)));
+}
+
+TEST_F(MasterLoadTest, loadRRWithEOLWhitespace) {
+    // Test with whitespace after rdata
+    // It should still work.
+    rr_stream << "example.com. 3600 IN NSEC3PARAM 1 0 1 beef \n";
+    masterLoad(rr_stream, origin, zclass, callback);
+    ASSERT_EQ(1, results.size());
+    EXPECT_EQ(0, results[0]->getRdataIterator()->getCurrent().compare(
+                  *rdata::createRdata(RRType::NSEC3PARAM(), zclass,
+                                      "1 0 1 beef")));
+}
+
+TEST_F(MasterLoadTest, loadRRWithEOLWhitespaceTab) {
+    // Similar to the previous one, tab instead of space.
+    // It should still work.
+    rr_stream << "example.com. 3600 IN NSEC3PARAM 1 0 1 beef\t\n";
+    masterLoad(rr_stream, origin, zclass, callback);
+    ASSERT_EQ(1, results.size());
+    EXPECT_EQ(0, results[0]->getRdataIterator()->getCurrent().compare(
+                  *rdata::createRdata(RRType::NSEC3PARAM(), zclass,
+                                      "1 0 1 beef")));
+}
+
+TEST_F(MasterLoadTest, loadRRNoComment) {
+    // A semicolon in a character-string shouldn't confuse the parser.
+    rr_stream << "example.com. 3600 IN TXT \"aaa;bbb\"\n";
+    masterLoad(rr_stream, origin, zclass, callback);
+    EXPECT_EQ(1, results.size());
+    EXPECT_EQ(0, results[0]->getRdataIterator()->getCurrent().compare(
+                  *rdata::createRdata(RRType::TXT(), zclass,
+                                      "\"aaa;bbb\"")));
+}
+
+TEST_F(MasterLoadTest, loadRREmptyAndComment) {
+    // There's no RDATA (invalid in this case) but a comment.  This position
+    // shouldn't cause any disruption and should be treated as a normal error.
+    rr_stream << "example.com. 3600 IN A ;\n";
+    EXPECT_THROW(masterLoad(rr_stream, origin, zclass, callback),
+                 MasterLoadError);
+}
+
 TEST_F(MasterLoadTest, loadWithNoEOF) {
     // the input stream doesn't end with a new line (and the following blank
     // line).  It should be accepted.

+ 3 - 8
src/lib/dns/tests/message_unittest.cc

@@ -79,7 +79,6 @@ namespace {
 class MessageTest : public ::testing::Test {
 protected:
     MessageTest() : test_name("test.example.com"), obuffer(0),
-                    renderer(obuffer),
                     message_parse(Message::PARSE),
                     message_render(Message::RENDER),
                     bogus_section(static_cast<Message::Section>(
@@ -731,8 +730,8 @@ TEST_F(MessageTest, toWire) {
     message_render.toWire(renderer);
     vector<unsigned char> data;
     UnitTestUtil::readWireData("message_toWire1", data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
-                        obuffer.getLength(), &data[0], data.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
 }
 
 TEST_F(MessageTest, toWireInParseMode) {
@@ -961,9 +960,6 @@ TEST_F(MessageTest, toWireTSIGNoTruncation) {
 // rendering fail unexpectedly in the test that follows.
 class BadRenderer : public MessageRenderer {
 public:
-    BadRenderer(isc::util::OutputBuffer& buffer) :
-        MessageRenderer(buffer)
-    {}
     virtual void setLengthLimit(size_t len) {
         if (getLength() > 0) {
             MessageRenderer::setLengthLimit(getLength());
@@ -994,8 +990,7 @@ TEST_F(MessageTest, toWireTSIGLengthErrors) {
                  InvalidParameter);
 
     // Trying to render a message with TSIG using a buggy renderer.
-    obuffer.clear();
-    BadRenderer bad_renderer(obuffer);
+    BadRenderer bad_renderer;
     bad_renderer.setLengthLimit(512);
     message_render.clear(Message::RENDER);
     EXPECT_THROW(commonTSIGToWireCheck(message_render, bad_renderer, tsig_ctx,

+ 64 - 22
src/lib/dns/tests/messagerenderer_unittest.cc

@@ -12,8 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <vector>
-
+#include <exceptions/exceptions.h>
 #include <util/buffer.h>
 #include <dns/name.h>
 #include <dns/messagerenderer.h>
@@ -22,6 +21,8 @@
 
 #include <gtest/gtest.h>
 
+#include <vector>
+
 using isc::UnitTestUtil;
 using isc::dns::Name;
 using isc::dns::MessageRenderer;
@@ -30,15 +31,13 @@ using isc::util::OutputBuffer;
 namespace {
 class MessageRendererTest : public ::testing::Test {
 protected:
-    MessageRendererTest() : expected_size(0), buffer(0), renderer(buffer)
-    {
+    MessageRendererTest() : expected_size(0) {
         data16 = (2 << 8) | 3;
         data32 = (4 << 24) | (5 << 16) | (6 << 8) | 7;
     }
     size_t expected_size;
     uint16_t data16;
     uint32_t data32;
-    OutputBuffer buffer;
     MessageRenderer renderer;
     std::vector<unsigned char> data;
     static const uint8_t testdata[5];
@@ -60,21 +59,22 @@ TEST_F(MessageRendererTest, writeName) {
     renderer.writeName(Name("a.example.com."));
     renderer.writeName(Name("b.example.com."));
     renderer.writeName(Name("a.example.org."));
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
-                        buffer.getLength(), &data[0], data.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
 }
 
 TEST_F(MessageRendererTest, writeNameInLargeBuffer) {
     size_t offset = 0x3fff;
-    buffer.skip(offset);
+    renderer.skip(offset);
 
     UnitTestUtil::readWireData("name_toWire2", data);
     renderer.writeName(Name("a.example.com."));
     renderer.writeName(Name("a.example.com."));
     renderer.writeName(Name("b.example.com."));
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t*>(buffer.getData()) + offset,
-                        buffer.getLength() - offset,
+                        static_cast<const uint8_t*>(renderer.getData()) +
+                        offset,
+                        renderer.getLength() - offset,
                         &data[0], data.size());
 }
 
@@ -83,8 +83,8 @@ TEST_F(MessageRendererTest, writeNameWithUncompressed) {
     renderer.writeName(Name("a.example.com."));
     renderer.writeName(Name("b.example.com."), false);
     renderer.writeName(Name("b.example.com."));
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
-                        buffer.getLength(), &data[0], data.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
 }
 
 TEST_F(MessageRendererTest, writeNamePointerChain) {
@@ -92,8 +92,8 @@ TEST_F(MessageRendererTest, writeNamePointerChain) {
     renderer.writeName(Name("a.example.com."));
     renderer.writeName(Name("b.example.com."));
     renderer.writeName(Name("b.example.com."));
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
-                        buffer.getLength(), &data[0], data.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
 }
 
 TEST_F(MessageRendererTest, compressMode) {
@@ -120,8 +120,8 @@ TEST_F(MessageRendererTest, writeNameCaseCompress) {
     // this should match the first name in terms of compression:
     renderer.writeName(Name("b.exAmple.CoM."));
     renderer.writeName(Name("a.example.org."));
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
-                        buffer.getLength(), &data[0], data.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
 }
 
 TEST_F(MessageRendererTest, writeNameCaseSensitiveCompress) {
@@ -132,8 +132,8 @@ TEST_F(MessageRendererTest, writeNameCaseSensitiveCompress) {
     renderer.writeName(Name("a.example.com."));
     renderer.writeName(Name("b.eXample.com."));
     renderer.writeName(Name("c.eXample.com."));
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
-                        buffer.getLength(), &data[0], data.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
 }
 
 TEST_F(MessageRendererTest, writeNameMixedCaseCompress) {
@@ -147,8 +147,8 @@ TEST_F(MessageRendererTest, writeNameMixedCaseCompress) {
     // allowed in this API.
     renderer.setCompressMode(MessageRenderer::CASE_INSENSITIVE);
     renderer.writeName(Name("c.b.EXAMPLE.com."));
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, buffer.getData(),
-                        buffer.getLength(), &data[0], data.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
 }
 
 TEST_F(MessageRendererTest, writeRootName) {
@@ -164,9 +164,51 @@ TEST_F(MessageRendererTest, writeRootName) {
     renderer.writeName(Name("."));
     renderer.writeName(example_name);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t*>(buffer.getData()),
-                        buffer.getLength(),
+                        static_cast<const uint8_t*>(renderer.getData()),
+                        renderer.getLength(),
                         static_cast<const uint8_t*>(expected.getData()),
                         expected.getLength());
 }
+
+TEST_F(MessageRendererTest, setBuffer) {
+    OutputBuffer new_buffer(0);
+    renderer.setBuffer(&new_buffer);
+    EXPECT_EQ(0, new_buffer.getLength()); // the buffer should be still empty
+    renderer.writeUint32(42);
+    EXPECT_EQ(sizeof(uint32_t), new_buffer.getLength());
+    EXPECT_EQ(sizeof(uint32_t), renderer.getLength());
+
+    // Change some other internal state for the reset test below.
+    EXPECT_EQ(512, renderer.getLengthLimit());
+    renderer.setLengthLimit(4096);
+    EXPECT_EQ(4096, renderer.getLengthLimit());
+
+    // Reset the buffer to the default again.  Other internal states and
+    // resources should be cleared.  The used buffer should be intact.
+    renderer.setBuffer(NULL);
+    EXPECT_EQ(sizeof(uint32_t), new_buffer.getLength());
+    EXPECT_EQ(0, renderer.getLength());
+    EXPECT_EQ(512, renderer.getLengthLimit());
+}
+
+TEST_F(MessageRendererTest, setBufferErrors) {
+    OutputBuffer new_buffer(0);
+
+    // Buffer cannot be reset when the renderer is in use.
+    renderer.writeUint32(10);
+    EXPECT_THROW(renderer.setBuffer(&new_buffer), isc::InvalidParameter);
+
+    renderer.clear();
+    renderer.setBuffer(&new_buffer);
+    renderer.writeUint32(10);
+    EXPECT_THROW(renderer.setBuffer(&new_buffer), isc::InvalidParameter);
+
+    // Resetting the buffer isn't allowed for the default buffer.
+    renderer.setBuffer(NULL);
+    EXPECT_THROW(renderer.setBuffer(NULL), isc::InvalidParameter);
+
+    // It's okay to reset a temporary buffer without using it.
+    renderer.setBuffer(&new_buffer);
+    EXPECT_NO_THROW(renderer.setBuffer(NULL));
+}
 }

+ 6 - 7
src/lib/dns/tests/name_unittest.cc

@@ -357,13 +357,12 @@ TEST_F(NameTest, toWireBuffer) {
 //
 TEST_F(NameTest, toWireRenderer) {
     vector<unsigned char> data;
-    OutputBuffer buffer(0);
-    MessageRenderer renderer(buffer);
+    MessageRenderer renderer;
 
     UnitTestUtil::readWireData(string("01610376697803636f6d00"), data);
     Name("a.vix.com.").toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &data[0], data.size(),
-                        buffer.getData(), buffer.getLength());
+                        renderer.getData(), renderer.getLength());
 }
 
 //
@@ -524,8 +523,8 @@ TEST_F(NameTest, at) {
 
     example_name.toWire(buffer_expected);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        &data[0], data.size(),
-                        buffer_expected.getData(), buffer_expected.getLength());
+                        &data[0], data.size(), buffer_expected.getData(),
+                        buffer_expected.getLength());
 
     // Out-of-range access: should trigger an exception.
     EXPECT_THROW(example_name.at(example_name.getLength()), OutOfRange);
@@ -543,7 +542,7 @@ TEST_F(NameTest, leq) {
 
     // small <= small is true
     EXPECT_TRUE(small_name.leq(small_name));
-    EXPECT_TRUE(small_name <= small_name);
+    EXPECT_LE(small_name, small_name);
 
     // large <= small is false
     EXPECT_FALSE(large_name.leq(small_name));
@@ -555,7 +554,7 @@ TEST_F(NameTest, geq) {
     EXPECT_TRUE(large_name >= small_name);
 
     EXPECT_TRUE(large_name.geq(large_name));
-    EXPECT_TRUE(large_name >= large_name);
+    EXPECT_GE(large_name, large_name);
 
     EXPECT_FALSE(small_name.geq(large_name));
     EXPECT_FALSE(small_name >= large_name);

+ 3 - 3
src/lib/dns/tests/question_unittest.cc

@@ -37,7 +37,7 @@ using namespace isc::util;
 namespace {
 class QuestionTest : public ::testing::Test {
 protected:
-    QuestionTest() : obuffer(0), renderer(obuffer),
+    QuestionTest() : obuffer(0),
                      example_name1(Name("foo.example.com")),
                      example_name2(Name("bar.example.com")),
                      test_question1(example_name1, RRClass::IN(),
@@ -102,8 +102,8 @@ TEST_F(QuestionTest, toWireRenderer) {
     test_question1.toWire(renderer);
     test_question2.toWire(renderer);
     UnitTestUtil::readWireData("question_toWire2", wiredata);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
-                        obuffer.getLength(), &wiredata[0], wiredata.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &wiredata[0], wiredata.size());
 }
 
 TEST_F(QuestionTest, toWireTruncated) {

+ 1 - 1
src/lib/dns/tests/rdata_afsdb_unittest.cc

@@ -162,7 +162,7 @@ TEST_F(Rdata_AFSDB_Test, toWireRenderer) {
     renderer.clear();
 
     // construct actual data
-    Name("example.com.").toWire(obuffer);
+    renderer.writeName(Name("example.com."));
     rdata_afsdb2.toWire(renderer);
 
     // construct expected data

+ 2 - 2
src/lib/dns/tests/rdata_cname_unittest.cc

@@ -97,11 +97,11 @@ TEST_F(Rdata_CNAME_Test, toWireBuffer) {
 TEST_F(Rdata_CNAME_Test, toWireRenderer) {
     rdata_cname.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_cname, sizeof(wiredata_cname));
     rdata_cname2.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_cname2, sizeof(wiredata_cname2));
 }
 

+ 2 - 2
src/lib/dns/tests/rdata_dname_unittest.cc

@@ -97,11 +97,11 @@ TEST_F(Rdata_DNAME_Test, toWireBuffer) {
 TEST_F(Rdata_DNAME_Test, toWireRenderer) {
     rdata_dname.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_dname, sizeof(wiredata_dname));
     rdata_dname2.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_dname2, sizeof(wiredata_dname2));
 }
 

+ 2 - 2
src/lib/dns/tests/rdata_dnskey_unittest.cc

@@ -90,8 +90,8 @@ TEST_F(Rdata_DNSKEY_Test, toWireRenderer) {
     vector<unsigned char> data;
     UnitTestUtil::readWireData("rdata_dnskey_fromWire", data);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t *>(obuffer.getData()) + 2,
-                        obuffer.getLength() - 2, &data[2], data.size() - 2);
+                        static_cast<const uint8_t *>(renderer.getData()) + 2,
+                        renderer.getLength() - 2, &data[2], data.size() - 2);
 }
 
 TEST_F(Rdata_DNSKEY_Test, toWireBuffer) {

+ 2 - 2
src/lib/dns/tests/rdata_ds_like_unittest.cc

@@ -115,8 +115,8 @@ TYPED_TEST(Rdata_DS_LIKE_Test, toWireRenderer) {
     UnitTestUtil::readWireData("rdata_ds_fromWire", data);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
                         static_cast<const uint8_t*>
-                        (this->obuffer.getData()) + 2,
-                        this->obuffer.getLength() - 2,
+                        (this->renderer.getData()) + 2,
+                        this->renderer.getLength() - 2,
                         &data[2], data.size() - 2);
 }
 

+ 3 - 2
src/lib/dns/tests/rdata_hinfo_unittest.cc

@@ -94,8 +94,9 @@ TEST_F(Rdata_HINFO_Test, toWireRenderer) {
     HINFO hinfo(hinfo_str);
 
     hinfo.toWire(renderer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
-                        obuffer.getLength(), hinfo_rdata, sizeof(hinfo_rdata));
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), hinfo_rdata,
+                        sizeof(hinfo_rdata));
 }
 
 TEST_F(Rdata_HINFO_Test, compare) {

+ 1 - 1
src/lib/dns/tests/rdata_in_a_unittest.cc

@@ -78,7 +78,7 @@ TEST_F(Rdata_IN_A_Test, toWireBuffer) {
 TEST_F(Rdata_IN_A_Test, toWireRenderer) {
     rdata_in_a.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_in_a, sizeof(wiredata_in_a));
 }
 

+ 1 - 1
src/lib/dns/tests/rdata_in_aaaa_unittest.cc

@@ -76,7 +76,7 @@ TEST_F(Rdata_IN_AAAA_Test, toWireBuffer) {
 TEST_F(Rdata_IN_AAAA_Test, toWireRenderer) {
     rdata_in_aaaa.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_in_aaaa, sizeof(wiredata_in_aaaa));
 }
 

+ 4 - 4
src/lib/dns/tests/rdata_minfo_unittest.cc

@@ -142,15 +142,15 @@ TEST_F(Rdata_MINFO_Test, toWireRenderer) {
     vector<unsigned char> data;
     UnitTestUtil::readWireData("rdata_minfo_toWire1.wire", data);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t *>(obuffer.getData()),
-                        obuffer.getLength(), &data[0], data.size());
+                        static_cast<const uint8_t *>(renderer.getData()),
+                        renderer.getLength(), &data[0], data.size());
     renderer.clear();
     rdata_minfo2.toWire(renderer);
     vector<unsigned char> data2;
     UnitTestUtil::readWireData("rdata_minfo_toWire2.wire", data2);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t *>(obuffer.getData()),
-                        obuffer.getLength(), &data2[0], data2.size());
+                        static_cast<const uint8_t *>(renderer.getData()),
+                        renderer.getLength(), &data2[0], data2.size());
 }
 
 TEST_F(Rdata_MINFO_Test, toText) {

+ 3 - 3
src/lib/dns/tests/rdata_mx_unittest.cc

@@ -68,12 +68,12 @@ TEST_F(Rdata_MX_Test, toWireRenderer) {
 
     vector<unsigned char> data;
     UnitTestUtil::readWireData("rdata_mx_toWire1", data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
-                        obuffer.getLength(), &data[0], data.size());
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), &data[0], data.size());
 }
 
 TEST_F(Rdata_MX_Test, toWireBuffer) {
-    renderer.writeName(Name("example.com"));
+    Name("example.com").toWire(obuffer);
     rdata_mx.toWire(obuffer);
 
     vector<unsigned char> data;

+ 3 - 2
src/lib/dns/tests/rdata_naptr_unittest.cc

@@ -140,8 +140,9 @@ TEST_F(Rdata_NAPTR_Test, toWireRenderer) {
     NAPTR naptr(naptr_str);
 
     naptr.toWire(renderer);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
-                        obuffer.getLength(), naptr_rdata, sizeof(naptr_rdata));
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+                        renderer.getLength(), naptr_rdata,
+                        sizeof(naptr_rdata));
 }
 
 TEST_F(Rdata_NAPTR_Test, toText) {

+ 2 - 2
src/lib/dns/tests/rdata_ns_unittest.cc

@@ -96,11 +96,11 @@ TEST_F(Rdata_NS_Test, toWireBuffer) {
 TEST_F(Rdata_NS_Test, toWireRenderer) {
     rdata_ns.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_ns, sizeof(wiredata_ns));
     rdata_ns2.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_ns2, sizeof(wiredata_ns2));
 }
 

+ 1 - 1
src/lib/dns/tests/rdata_nsec3param_like_unittest.cc

@@ -40,7 +40,7 @@ protected:
     NSEC3PARAMLikeTest() :
         salt_txt("1 1 1 D399EAAB" + getCommonText()),
         nosalt_txt("1 1 1 -" + getCommonText()),
-        obuffer(0), renderer(obuffer)
+        obuffer(0)
     {}
 
     RDATA_TYPE fromText(const string& rdata_text) {

+ 2 - 2
src/lib/dns/tests/rdata_nsec3param_unittest.cc

@@ -94,8 +94,8 @@ TEST_F(Rdata_NSEC3PARAM_Test, toWireRenderer) {
     vector<unsigned char> data;
     UnitTestUtil::readWireData("rdata_nsec3param_fromWire1", data);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t *>(obuffer.getData()) + 2,
-                        obuffer.getLength() - 2, &data[2], data.size() - 2);
+                        static_cast<const uint8_t *>(renderer.getData()) + 2,
+                        renderer.getLength() - 2, &data[2], data.size() - 2);
 }
 
 TEST_F(Rdata_NSEC3PARAM_Test, toWireBuffer) {

+ 2 - 2
src/lib/dns/tests/rdata_nsec_unittest.cc

@@ -74,8 +74,8 @@ TEST_F(Rdata_NSEC_Test, toWireRenderer_NSEC) {
     vector<unsigned char> data;
     UnitTestUtil::readWireData("rdata_nsec_fromWire1", data);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        static_cast<const uint8_t *>(obuffer.getData()) + 2,
-                        obuffer.getLength() - 2, &data[2], data.size() - 2);
+                        static_cast<const uint8_t *>(renderer.getData()) + 2,
+                        renderer.getLength() - 2, &data[2], data.size() - 2);
 }
 
 TEST_F(Rdata_NSEC_Test, toWireBuffer_NSEC) {

+ 1 - 1
src/lib/dns/tests/rdata_nsecbitmap_unittest.cc

@@ -264,7 +264,7 @@ TEST_F(NSEC3BitmapTest, emptyMap) {
 
     // Same for MessageRenderer.
     obuffer.clear();
-    MessageRenderer renderer(obuffer);
+    MessageRenderer renderer;
     renderer.writeUint16(rdlen);
     empty_nsec3.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),

+ 2 - 2
src/lib/dns/tests/rdata_ptr_unittest.cc

@@ -100,11 +100,11 @@ TEST_F(Rdata_PTR_Test, toWireBuffer) {
 TEST_F(Rdata_PTR_Test, toWireRenderer) {
     rdata_ptr.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_ptr, sizeof(wiredata_ptr));
     rdata_ptr2.toWire(renderer);
     EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        obuffer.getData(), obuffer.getLength(),
+                        renderer.getData(), renderer.getLength(),
                         wiredata_ptr2, sizeof(wiredata_ptr2));
 }
 

+ 1 - 1
src/lib/dns/tests/rdata_rp_unittest.cc

@@ -38,7 +38,7 @@ protected:
         // this also serves as a test for "from text" constructor in a normal
         // case.
         rdata_rp("root.example.com. rp-text.example.com."),
-        obuffer(0), renderer(obuffer)
+        obuffer(0)
     {}
 
     const Name mailbox_name, text_name;

+ 0 - 0
src/lib/dns/tests/rdata_soa_unittest.cc


Some files were not shown because too many files changed in this diff