Browse Source

Merge branch 'master' into trac2025_2

Mukund Sivaraman 13 years ago
parent
commit
2498f05b7a
56 changed files with 1094 additions and 463 deletions
  1. 15 0
      ChangeLog
  2. 42 6
      doc/devel/02-dhcp.dox
  3. 3 0
      doc/devel/mainpage.dox
  4. 60 81
      doc/guide/bind10-guide.html
  5. 207 201
      doc/guide/bind10-guide.xml
  6. 1 1
      src/bin/auth/tests/Makefile.am
  7. 4 0
      src/bin/dhcp4/Makefile.am
  8. 159 0
      src/bin/dhcp4/ctrl_dhcp4_srv.cc
  9. 123 0
      src/bin/dhcp4/ctrl_dhcp4_srv.h
  10. 14 2
      src/bin/dhcp4/dhcp4.spec
  11. 10 2
      src/bin/dhcp4/dhcp4_srv.cc
  12. 10 0
      src/bin/dhcp4/dhcp4_srv.h
  13. 27 44
      src/bin/dhcp4/main.cc
  14. 5 2
      src/bin/dhcp4/tests/Makefile.am
  15. 85 0
      src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc
  16. 1 1
      src/bin/dhcp6/tests/Makefile.am
  17. 1 7
      src/bin/msgq/msgq.xml
  18. 1 1
      src/bin/resolver/tests/Makefile.am
  19. 1 1
      src/bin/sockcreator/tests/Makefile.am
  20. 1 1
      src/lib/acl/tests/Makefile.am
  21. 1 1
      src/lib/asiodns/tests/Makefile.am
  22. 1 1
      src/lib/asiolink/tests/Makefile.am
  23. 1 1
      src/lib/bench/tests/Makefile.am
  24. 1 1
      src/lib/cache/tests/Makefile.am
  25. 16 0
      src/lib/cc/session.cc
  26. 5 0
      src/lib/cc/session.h
  27. 1 1
      src/lib/cc/tests/Makefile.am
  28. 13 0
      src/lib/cc/tests/session_unittests.cc
  29. 1 1
      src/lib/config/tests/Makefile.am
  30. 1 1
      src/lib/cryptolink/tests/Makefile.am
  31. 22 35
      src/lib/datasrc/database.cc
  32. 6 9
      src/lib/datasrc/database.h
  33. 1 1
      src/lib/datasrc/tests/Makefile.am
  34. 24 13
      src/lib/datasrc/tests/database_unittest.cc
  35. 0 13
      src/lib/datasrc/tests/zone_finder_context_unittest.cc
  36. 10 0
      src/lib/datasrc/zone.h
  37. 82 12
      src/lib/dhcp/iface_mgr.cc
  38. 25 5
      src/lib/dhcp/iface_mgr.h
  39. 1 1
      src/lib/dhcp/tests/Makefile.am
  40. 51 2
      src/lib/dhcp/tests/iface_mgr_unittest.cc
  41. 1 1
      src/lib/dns/tests/Makefile.am
  42. 1 1
      src/lib/exceptions/tests/Makefile.am
  43. 1 1
      src/lib/log/tests/Makefile.am
  44. 1 1
      src/lib/nsas/tests/Makefile.am
  45. 1 1
      src/lib/resolve/tests/Makefile.am
  46. 1 1
      src/lib/server_common/tests/Makefile.am
  47. 1 1
      src/lib/statistics/tests/Makefile.am
  48. 1 1
      src/lib/util/tests/Makefile.am
  49. 1 1
      src/lib/xfr/tests/Makefile.am
  50. 6 0
      tests/lettuce/configurations/DO_NOT_USE_127.0.0.1:47807
  51. 0 4
      tests/lettuce/configurations/NOTES
  52. 1 0
      tests/lettuce/data/example.org
  53. 25 0
      tests/lettuce/features/queries.feature
  54. 1 1
      tests/tools/badpacket/tests/Makefile.am
  55. 18 0
      tests/tools/perfdhcp/command_options.cc
  56. 1 1
      tests/tools/perfdhcp/tests/Makefile.am

+ 15 - 0
ChangeLog

@@ -1,3 +1,18 @@
+451.	[bug]		muks, jinmei
+	libdatasrc: the database-based data source now correctly returns
+	glue records on (not under) a zone cut, such as in the case where
+	the NS name of an NS record is identical to its owner name. (Note:
+	libdatasrc itself doesn't judge what kind of record type can be a
+	"glue"; it's the caller's responsibility.)
+	(Trac #1771, git 483f1075942965f0340291e7ff7dae7806df22af)
+
+450.	[func]*		tomek
+	b10-dhcp4: DHCPv4 server component is now integrated into
+	BIND10 framework. It can be started from BIND10 (using bindctl)
+	and can receive commands. The only supported command for now
+	is 'Dhcp4 shutdown'.
+	(Trac #1651, git 7e16a5a50d3311e63d10a224ec6ebcab5f25f62c)
+
 bind10-devel-20120621 released on June 21. 2012
 bind10-devel-20120621 released on June 21. 2012
 
 
 449.	[bug]		muks
 449.	[bug]		muks

+ 42 - 6
doc/devel/02-dhcp.dox

@@ -15,11 +15,47 @@
  * only), as support for transmission to hosts without IPv4 address
  * only), as support for transmission to hosts without IPv4 address
  * assigned is not implemented in IfaceMgr yet.
  * assigned is not implemented in IfaceMgr yet.
  *
  *
- * DHCPv4 server component does not listen to BIND10 message queue.
- *
  * DHCPv4 server component does not use BIND10 logging yet.
  * DHCPv4 server component does not use BIND10 logging yet.
  *
  *
- * DHCPv4 server component is not integrated with boss yet.
+ * @section dhcpv4Session BIND10 message queue integration
+ *
+ * DHCPv4 server component is now integrated with BIND10 message queue.
+ * The integration is performed by establishSession() and disconnectSession()
+ * functions in isc::dhcp::ControlledDhcpv4Srv class. main() method deifined
+ * in the src/bin/dhcp4/main.cc file instantiates isc::dhcp::ControlledDhcpv4Srv
+ * class that establishes connection with msgq and install necessary handlers
+ * for receiving commands and configuration updates. It is derived from
+ * a base isc::dhcp::Dhcpv4Srv class that implements DHCPv4 server functionality,
+ * without any controlling mechanisms.
+ *
+ * ControlledDhcpv4Srv instantiates several components to make management
+ * session possible. In particular, isc::cc::Session cc_session
+ * object uses ASIO for establishing connection. It registers its socket
+ * in isc::asiolink::IOService io_service object. Typically, other components
+ * (e.g. auth or resolver) that use ASIO for their communication, register their
+ * other sockets in the
+ * same io_service and then just call io_service.run() method that does
+ * not return, until one of the callback decides that it is time to shut down
+ * the whole component cal calls io_service.stop(). DHCPv4 works in a
+ * different way. It does receive messages using select()
+ * (see isc::dhcp::IfaceMgr::receive4()), which is incompatible with ASIO.
+ * To solve this problem, socket descriptor is extracted from cc_session
+ * object and is passed to IfaceMgr by using isc::dhcp::IfaceMgr::set_session_socket().
+ * IfaceMgr then uses this socket in its select() call. If there is some
+ * data to be read, it calls registered callback that is supposed to
+ * read and process incoming data.
+ *
+ * This somewhat complicated approach is needed for a simple reason. In
+ * embedded deployments there will be no message queue. Not referring directly
+ * to anything related to message queue in isc::dhcp::Dhcpv4Srv and
+ * isc::dhcp::IfaceMgr classes brings in two benefits. First, the can
+ * be used with and without message queue. Second benefit is related to the
+ * first one: \ref libdhcp is supposed to be simple and robust and not require
+ * many dependencies. One notable example of a use case that benefits from
+ * this approach is a perfdhcp tool. Finally, the idea is that it should be
+ * possible to instantiate Dhcpv4Srv object directly, thus getting a server
+ * that does not support msgq. That is useful for embedded environments.
+ * It may also be useful in validation.
  *
  *
  * @page dhcpv6 DHCPv6 Server Component
  * @page dhcpv6 DHCPv6 Server Component
  *
  *
@@ -42,9 +78,9 @@
  *
  *
  * DHCPv6 server component is not integrated with boss yet.
  * DHCPv6 server component is not integrated with boss yet.
  *
  *
- * @page libdhcp libdhcp++ library
+ * @page libdhcp libdhcp++
  *
  *
- * @section libdhcpIntro Libdhcp++ Introduction
+ * @section libdhcpIntro Libdhcp++ Library Introduction
  *
  *
  * libdhcp++ is an all-purpose DHCP-manipulation library, written in
  * libdhcp++ is an all-purpose DHCP-manipulation library, written in
  * C++. It offers packet parsing and assembly, DHCPv4 and DHCPv6
  * C++. It offers packet parsing and assembly, DHCPv4 and DHCPv6
@@ -82,7 +118,7 @@
  * isc::dhcp::Option::delOption(), isc::dhcp::Option::getOption() can be used
  * isc::dhcp::Option::delOption(), isc::dhcp::Option::getOption() can be used
  * for that purpose.
  * for that purpose.
  *
  *
- * @section lidhcpIfaceMgr Interface Manager
+ * @section libdhcpIfaceMgr Interface Manager
  *
  *
  * Interface Manager (or IfaceMgr) is an abstraction layer about low-level
  * Interface Manager (or IfaceMgr) is an abstraction layer about low-level
  * network operations. In particlar, it provides information about existing
  * network operations. In particlar, it provides information about existing

+ 3 - 0
doc/devel/mainpage.dox

@@ -19,8 +19,11 @@
  *
  *
  * @section DHCP
  * @section DHCP
  * - @subpage dhcpv4
  * - @subpage dhcpv4
+ *   - @subpage dhcpv4Session
  * - @subpage dhcpv6
  * - @subpage dhcpv6
  * - @subpage libdhcp
  * - @subpage libdhcp
+ *   - @subpage libdhcpIntro
+ *   - @subpage libdhcpIfaceMgr
  *
  *
  * @section misc Miscellaneous topics
  * @section misc Miscellaneous topics
  * - @subpage LoggingApi
  * - @subpage LoggingApi

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


+ 207 - 201
doc/guide/bind10-guide.xml

@@ -36,8 +36,8 @@
     <abstract>
     <abstract>
       <para>BIND 10 is a framework that features Domain Name System
       <para>BIND 10 is a framework that features Domain Name System
       (DNS) suite and Dynamic Host Configuration Protocol (DHCP)
       (DNS) suite and Dynamic Host Configuration Protocol (DHCP)
-      servers managed by Internet Systems Consortium (ISC). It
-      includes DNS libraries, modular components for controlling
+      servers with development managed by Internet Systems Consortium (ISC).
+      It includes DNS libraries, modular components for controlling
       authoritative and recursive DNS servers, and experimental DHCPv4
       authoritative and recursive DNS servers, and experimental DHCPv4
       and DHCPv6 servers.
       and DHCPv6 servers.
       </para>
       </para>
@@ -59,6 +59,8 @@
     <section id="acknowledgements">
     <section id="acknowledgements">
       <title>Acknowledgements</title>
       <title>Acknowledgements</title>
 
 
+<!-- TODO: acknowledge all sponsors and CNNIC and CZNIC too -->
+
       <para>ISC would like to acknowledge generous support for
       <para>ISC would like to acknowledge generous support for
       BIND 10 development of DHCPv4 and DHCPv6 components provided
       BIND 10 development of DHCPv4 and DHCPv6 components provided
       by <ulink url="http://www.comcast.com/">Comcast</ulink>.</para>
       by <ulink url="http://www.comcast.com/">Comcast</ulink>.</para>
@@ -72,11 +74,13 @@
     <para>
     <para>
       BIND is the popular implementation of a DNS server, developer
       BIND is the popular implementation of a DNS server, developer
       interfaces, and DNS tools.
       interfaces, and DNS tools.
-      BIND 10 is a rewrite of BIND 9.  BIND 10 is written in C++ and Python
-      and provides a modular environment for serving and maintaining DNS.
+      BIND 10 is a rewrite of BIND 9 and ISC DHCP.
+      BIND 10 is written in C++ and Python and provides a modular
+      environment for serving, maintaining, and developing DNS and DHCP.
       BIND 10 provides a EDNS0- and DNSSEC-capable authoritative
       BIND 10 provides a EDNS0- and DNSSEC-capable authoritative
       DNS server and a caching recursive name server which also
       DNS server and a caching recursive name server which also
       provides forwarding.
       provides forwarding.
+      It also provides experimental DHCPv4 and DHCPv6 servers.
     </para>
     </para>
 
 
     <para>
     <para>
@@ -105,7 +109,7 @@
       <para>
       <para>
         BIND 10 requires at least Python 3.1
         BIND 10 requires at least Python 3.1
         (<ulink url="http://www.python.org/"/>).
         (<ulink url="http://www.python.org/"/>).
-        It has also been tested with Python 3.2.
+        It also works with Python 3.2.
       </para>
       </para>
 
 
       <para>
       <para>
@@ -118,6 +122,7 @@
         BIND 10 uses the log4cplus C++ logging library
         BIND 10 uses the log4cplus C++ logging library
         (<ulink url="http://log4cplus.sourceforge.net/"/>).
         (<ulink url="http://log4cplus.sourceforge.net/"/>).
         It requires at least log4cplus version 1.0.3.
         It requires at least log4cplus version 1.0.3.
+<!-- TODO: It is recommended to use at least version .... -->
       </para>
       </para>
 
 
       <para>
       <para>
@@ -132,9 +137,7 @@
         <command>b10-xfrout</command>, and <command>b10-zonemgr</command>
         <command>b10-xfrout</command>, and <command>b10-zonemgr</command>
         components require the libpython3 library and the Python
         components require the libpython3 library and the Python
         _sqlite3.so module (which is included with Python).
         _sqlite3.so module (which is included with Python).
-        The <command>b10-stats-httpd</command> component uses the
-        Python pyexpat.so module.
-        The Python modules need to be built for the corresponding Python 3.
+        Python modules need to be built for the corresponding Python 3.
       </para>
       </para>
 <!-- TODO: this will change ... -->
 <!-- TODO: this will change ... -->
 
 
@@ -220,8 +223,8 @@
             <simpara>
             <simpara>
               <command>b10-resolver</command> &mdash;
               <command>b10-resolver</command> &mdash;
               Recursive name server.
               Recursive name server.
-              This process handles incoming queries.
-<!-- TODO: -->
+              This process handles incoming DNS queries and provides
+              answers from its cache or by recursively doing remote lookups.
             </simpara>
             </simpara>
           </listitem>
           </listitem>
 
 
@@ -264,15 +267,14 @@
               <command>b10-xfrout</command> &mdash;
               <command>b10-xfrout</command> &mdash;
               Outgoing zone transfer service.
               Outgoing zone transfer service.
               This process is used to handle transfer requests to
               This process is used to handle transfer requests to
-              send a local zone to a remote secondary server,
-              when acting as a master server.
+              send a local zone to a remote secondary server.
             </simpara>
             </simpara>
           </listitem>
           </listitem>
 
 
           <listitem>
           <listitem>
             <simpara>
             <simpara>
               <command>b10-zonemgr</command> &mdash;
               <command>b10-zonemgr</command> &mdash;
-              Secondary manager.
+              Secondary zone manager.
               This process keeps track of timers and other
               This process keeps track of timers and other
               necessary information for BIND 10 to act as a slave server.
               necessary information for BIND 10 to act as a slave server.
             </simpara>
             </simpara>
@@ -282,8 +284,8 @@
       </para>
       </para>
 
 
       <para>
       <para>
-        These are ran automatically by <command>bind10</command>
-        and do not need to be run manually.
+        These are ran by <command>bind10</command>
+        and do not need to be manually started independently.
       </para>
       </para>
 
 
     </section>
     </section>
@@ -298,7 +300,7 @@
           <listitem>
           <listitem>
             <simpara>
             <simpara>
               <command>bindctl</command> &mdash;
               <command>bindctl</command> &mdash;
-              interactive administration interface.
+              Interactive administration interface.
               This is a low-level command-line tool which allows
               This is a low-level command-line tool which allows
               a developer or an experienced administrator to control
               a developer or an experienced administrator to control
               BIND 10.
               BIND 10.
@@ -307,7 +309,7 @@
           <listitem>
           <listitem>
             <simpara>
             <simpara>
               <command>b10-loadzone</command> &mdash;
               <command>b10-loadzone</command> &mdash;
-              zone file loader.
+              Zone file loader.
               This tool will load standard masterfile-format zone files into
               This tool will load standard masterfile-format zone files into
               BIND 10.
               BIND 10.
             </simpara>
             </simpara>
@@ -315,7 +317,7 @@
           <listitem>
           <listitem>
             <simpara>
             <simpara>
               <command>b10-cmdctl-usermgr</command> &mdash;
               <command>b10-cmdctl-usermgr</command> &mdash;
-              user access control.
+              User access control.
               This tool allows an administrator to authorize additional users
               This tool allows an administrator to authorize additional users
               to manage BIND 10.
               to manage BIND 10.
             </simpara>
             </simpara>
@@ -358,6 +360,7 @@ var/
       for C++ and Python for the message bus, configuration backend,
       for C++ and Python for the message bus, configuration backend,
       and, of course, DNS. These include detailed developer
       and, of course, DNS. These include detailed developer
       documentation and code examples.
       documentation and code examples.
+<!-- TODO: DHCP also but no Python yet. -->
 <!-- TODO point to this -->
 <!-- TODO point to this -->
     </para>
     </para>
 
 
@@ -366,12 +369,100 @@ var/
   <chapter id="installation">
   <chapter id="installation">
     <title>Installation</title>
     <title>Installation</title>
 
 
+    <section id="packages">
+      <title>Packages</title>
+
+      <para>
+        Some operating systems or softare package vendors may
+        provide ready-to-use, pre-built software packages for
+        the BIND 10 suite.
+        Installing a pre-built package means you do not need to
+        install build-only prerequisites and do not need to
+        <emphasis>make</emphasis> the software.
+      </para>
+
+      <para>
+        FreeBSD ports, NetBSD pkgsrc, and Debian
+        <emphasis>testing</emphasis> package collections provide
+        all the prerequisite packages.
+      </para>
+    </section>
+
+    <section id="install-hierarchy">
+      <title>Install Hierarchy</title>
+      <para>
+        The following is the standard, common layout of the
+        complete BIND 10 installation:
+        <itemizedlist>
+          <listitem>
+           <simpara>
+              <filename>bin/</filename> &mdash;
+              general tools and diagnostic clients.
+            </simpara>
+          </listitem>
+          <listitem>
+          <simpara>
+            <filename>etc/bind10-devel/</filename> &mdash;
+            configuration files.
+          </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>lib/</filename> &mdash;
+              libraries and python modules.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>libexec/bind10-devel/</filename> &mdash;
+              executables that a user wouldn't normally run directly and
+              are not run independently.
+              These are the BIND 10 modules which are daemons started by
+              the <command>bind10</command> tool.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>sbin/</filename> &mdash;
+              commands used by the system administrator.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>share/bind10-devel/</filename> &mdash;
+              configuration specifications.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>share/doc/bind10-devel/</filename> &mdash;
+              this guide and other supplementary documentation.
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>share/man/</filename> &mdash;
+              manual pages (online documentation).
+            </simpara>
+          </listitem>
+          <listitem>
+            <simpara>
+              <filename>var/bind10-devel/</filename> &mdash;
+              data source and configuration databases.
+            </simpara>
+          </listitem>
+        </itemizedlist>
+      </para>
+    </section>
+
     <section id="build-requirements">
     <section id="build-requirements">
       <title>Building Requirements</title>
       <title>Building Requirements</title>
 
 
         <para>
         <para>
-          In addition to the run-time requirements, building BIND 10
-          from source code requires various development include headers.
+          In addition to the run-time requirements (listed in
+          <xref linkend="required-software"/>), building BIND 10
+          from source code requires various development include headers and
+          program development tools.
         </para>
         </para>
 
 
         <note>
         <note>
@@ -415,7 +506,7 @@ as a dependency earlier -->
         </para>
         </para>
 
 
         <para>
         <para>
-          Visit the wiki at <ulink
+          Visit the user-contributed wiki at <ulink
           url="http://bind10.isc.org/wiki/SystemSpecificNotes" />
           url="http://bind10.isc.org/wiki/SystemSpecificNotes" />
           for system-specific installation tips.
           for system-specific installation tips.
         </para>
         </para>
@@ -484,7 +575,7 @@ as a dependency earlier -->
         </listitem>
         </listitem>
 
 
         <listitem>
         <listitem>
-
+<!-- TODO: this is wrong; b10-auth is not started by default any more -->
          <para>Test it; for example:
          <para>Test it; for example:
             <screen>$ <userinput>dig @127.0.0.1 -c CH -t TXT authors.bind</userinput></screen>
             <screen>$ <userinput>dig @127.0.0.1 -c CH -t TXT authors.bind</userinput></screen>
          </para>
          </para>
@@ -510,10 +601,10 @@ as a dependency earlier -->
       <title>Installation from source</title>
       <title>Installation from source</title>
       <para>
       <para>
         BIND 10 is open source software written in C++ and Python.
         BIND 10 is open source software written in C++ and Python.
-        It is freely available in source code form from ISC via
-        the Git code revision control system or as a downloadable
-        tar file. It may also be available in pre-compiled ready-to-use
-        packages from operating system vendors.
+        It is freely available in source code form from ISC as a
+        downloadable tar file or via BIND 10's Git code revision control
+        service. (It may also be available in pre-compiled ready-to-use
+        packages from operating system vendors.)
       </para>
       </para>
 
 
       <section>
       <section>
@@ -541,7 +632,7 @@ as a dependency earlier -->
 
 
         <note>
         <note>
           <para>
           <para>
-            When using source code retrieved via Git additional
+            When using source code retrieved via Git, additional
             software will be required:  automake (v1.11 or newer),
             software will be required:  automake (v1.11 or newer),
             libtoolize, and autoconf (2.59 or newer).
             libtoolize, and autoconf (2.59 or newer).
             These may need to be installed.
             These may need to be installed.
@@ -549,11 +640,12 @@ as a dependency earlier -->
         </note>
         </note>
 
 
         <para>
         <para>
-          The latest development code, including temporary experiments
-          and un-reviewed code, is available via the BIND 10 code revision
+          The latest development code (and temporary experiments
+          and un-reviewed code) is available via the BIND 10 code revision
           control system. This is powered by Git and all the BIND 10
           control system. This is powered by Git and all the BIND 10
           development is public.
           development is public.
-          The leading development is done in the <quote>master</quote>.
+          The leading development is done in the <quote>master</quote>
+          branch.
         </para>
         </para>
         <para>
         <para>
           The code can be checked out from
           The code can be checked out from
@@ -566,8 +658,8 @@ as a dependency earlier -->
         <para>
         <para>
           When checking out the code from
           When checking out the code from
           the code version control system, it doesn't include the
           the code version control system, it doesn't include the
-          generated configure script, Makefile.in files, nor the
-          related configure files.
+          generated configure script, Makefile.in files, nor their
+          related build files.
           They can be created by running <command>autoreconf</command>
           They can be created by running <command>autoreconf</command>
           with the <option>--install</option> switch.
           with the <option>--install</option> switch.
           This will run <command>autoconf</command>,
           This will run <command>autoconf</command>,
@@ -591,7 +683,7 @@ as a dependency earlier -->
         </para>
         </para>
         <para>
         <para>
           Run <command>./configure</command> with the <option>--help</option>
           Run <command>./configure</command> with the <option>--help</option>
-          switch to view the different options. The commonly-used options are:
+          switch to view the different options. Some commonly-used options are:
 
 
           <variablelist>
           <variablelist>
 
 
@@ -679,65 +771,6 @@ as a dependency earlier -->
 
 
   <!-- TODO: tests -->
   <!-- TODO: tests -->
 
 
-      <section>
-        <title>Install Hierarchy</title>
-        <para>
-          The following is the layout of the complete BIND 10 installation:
-          <itemizedlist>
-            <listitem>
-              <simpara>
-                <filename>bin/</filename> &mdash;
-                general tools and diagnostic clients.
-              </simpara>
-            </listitem>
-            <listitem>
-            <simpara>
-              <filename>etc/bind10-devel/</filename> &mdash;
-              configuration files.
-            </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>lib/</filename> &mdash;
-                libraries and python modules.
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>libexec/bind10-devel/</filename> &mdash;
-                executables that a user wouldn't normally run directly and
-                are not run independently.
-                These are the BIND 10 modules which are daemons started by
-                the <command>bind10</command> tool.
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>sbin/</filename> &mdash;
-                commands used by the system administrator.
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>share/bind10-devel/</filename> &mdash;
-                configuration specifications.
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>share/man/</filename> &mdash;
-                manual pages (online documentation).
-              </simpara>
-            </listitem>
-            <listitem>
-              <simpara>
-                <filename>var/bind10-devel/</filename> &mdash;
-                data source and configuration databases.
-              </simpara>
-            </listitem>
-          </itemizedlist>
-        </para>
-      </section>
     </section>
     </section>
 
 
   <!--
   <!--
@@ -775,8 +808,9 @@ as a dependency earlier -->
       The <command>b10-cfgmgr</command> daemon is always needed by every
       The <command>b10-cfgmgr</command> daemon is always needed by every
       module, if only to send information about themselves somewhere,
       module, if only to send information about themselves somewhere,
       but more importantly to ask about their own settings, and
       but more importantly to ask about their own settings, and
-      about other modules. The <command>b10-sockcreator</command> will
-      allocate sockets for the rest of the system.
+      about other modules. The <command>b10-sockcreator</command> daemon
+      helps allocate Internet addresses and ports as needed for BIND 10
+      network services.
     </para>
     </para>
 
 
     <para>
     <para>
@@ -807,23 +841,22 @@ as a dependency earlier -->
 
 
     </section>
     </section>
     <section id="bind10.config">
     <section id="bind10.config">
-      <title>Configuration of started processes</title>
-      <para>
-        The processes to be started can be configured, with the exception
-        of the <command>b10-sockcreator</command>, <command>b10-msgq</command>
-        and <command>b10-cfgmgr</command>.
-      </para>
+      <title>Configuration to start processes</title>
 
 
       <para>
       <para>
-        The configuration is in the Boss/components section. Each element
-        represents one component, which is an abstraction of a process
-        (currently there's also one component which doesn't represent
-        a process).
+	The processes to be used can be configured for
+	<command>bind10</command> to start, with the exception
+	of the required <command>b10-sockcreator</command>,
+	<command>b10-msgq</command> and <command>b10-cfgmgr</command>
+	components.
+	The configuration is in the <varname>Boss/components</varname>
+	section. Each element represents one component, which is
+	an abstraction of a process.
       </para>
       </para>
 
 
       <para>
       <para>
-        To add a process to the set, let's say the resolver (which not started
-        by default), you would do this:
+	To add a process to the set, let's say the resolver (which
+	is not started by default), you would do this:
         <screen>&gt; <userinput>config add Boss/components b10-resolver</userinput>
         <screen>&gt; <userinput>config add Boss/components b10-resolver</userinput>
 &gt; <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
 &gt; <userinput>config set Boss/components/b10-resolver/special resolver</userinput>
 &gt; <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
 &gt; <userinput>config set Boss/components/b10-resolver/kind needed</userinput>
@@ -831,27 +864,32 @@ as a dependency earlier -->
 &gt; <userinput>config commit</userinput></screen></para>
 &gt; <userinput>config commit</userinput></screen></para>
 
 
       <para>
       <para>
-        Now, what it means. We add an entry called b10-resolver. It is both a
-        name used to reference this component in the configuration and the
-        name of the process to start. Then we set some parameters on how to
-        start it.
+	Now, what it means. We add an entry called
+	<quote>b10-resolver</quote>. It is both a name used to
+	reference this component in the configuration and the name
+	of the process to start. Then we set some parameters on
+	how to start it.
       </para>
       </para>
 
 
       <para>
       <para>
-        The special one is for components that need some kind of special care
-        during startup or shutdown. Unless specified, the component is started
-        in usual way. This is the list of components that need to be started
-        in a special way, with the value of special used for them:
+	The <varname>special</varname> setting is for components
+	that need some kind of special care during startup or
+	shutdown. Unless specified, the component is started in a
+	usual way. This is the list of components that need to be
+	started in a special way, with the value of special used
+	for them:
+<!-- TODO: this still doesn't explain why they are special -->
         <table>
         <table>
+          <title>Special startup components</title>
           <tgroup cols='3' align='left'>
           <tgroup cols='3' align='left'>
           <colspec colname='component'/>
           <colspec colname='component'/>
           <colspec colname='special'/>
           <colspec colname='special'/>
           <colspec colname='description'/>
           <colspec colname='description'/>
           <thead><row><entry>Component</entry><entry>Special</entry><entry>Description</entry></row></thead>
           <thead><row><entry>Component</entry><entry>Special</entry><entry>Description</entry></row></thead>
           <tbody>
           <tbody>
-            <row><entry>b10-auth</entry><entry>auth</entry><entry>Authoritative server</entry></row>
-            <row><entry>b10-resolver</entry><entry>resolver</entry><entry>The resolver</entry></row>
-            <row><entry>b10-cmdctl</entry><entry>cmdctl</entry><entry>The command control (remote control interface)</entry></row>
+            <row><entry>b10-auth</entry><entry>auth</entry><entry>Authoritative DNS server</entry></row>
+            <row><entry>b10-resolver</entry><entry>resolver</entry><entry>DNS resolver</entry></row>
+            <row><entry>b10-cmdctl</entry><entry>cmdctl</entry><entry>Command control (remote control interface)</entry></row>
             <!-- TODO Either add xfrin and xfrout as well or clean up the workarounds in boss before the release -->
             <!-- TODO Either add xfrin and xfrout as well or clean up the workarounds in boss before the release -->
           </tbody>
           </tbody>
           </tgroup>
           </tgroup>
@@ -859,32 +897,34 @@ as a dependency earlier -->
       </para>
       </para>
 
 
       <para>
       <para>
-        The kind specifies how a failure of the component should
-        be handled.  If it is set to <quote>dispensable</quote>
-        (the default unless you set something else), it will get
-        started again if it fails. If it is set to <quote>needed</quote>
-        and it fails at startup, the whole <command>bind10</command>
-        shuts down and exits with error exit code. But if it fails
-        some time later, it is just started again. If you set it
-        to <quote>core</quote>, you indicate that the system is
-        not usable without the component and if such component
-        fails, the system shuts down no matter when the failure
-        happened.  This is the behaviour of the core components
-        (the ones you can't turn off), but you can declare any
-        other components as core as well if you wish (but you can
-        turn these off, they just can't fail).
+	The <varname>kind</varname> specifies how a failure of the
+	component should be handled.  If it is set to
+	<quote>dispensable</quote> (the default unless you set
+	something else), it will get started again if it fails. If
+	it is set to <quote>needed</quote> and it fails at startup,
+	the whole <command>bind10</command> shuts down and exits
+	with an error exit code. But if it fails some time later, it
+	is just started again. If you set it to <quote>core</quote>,
+	you indicate that the system is not usable without the
+	component and if such component fails, the system shuts
+	down no matter when the failure happened.  This is the
+	behaviour of the core components (the ones you can't turn
+	off), but you can declare any other components as core as
+	well if you wish (but you can turn these off, they just
+	can't fail).
       </para>
       </para>
 
 
       <para>
       <para>
-        The priority defines order in which the components should start.
-        The ones with higher number are started sooner than the ones with
-        lower ones. If you don't set it, 0 (zero) is used as the priority.
-        Usually, leaving it at the default is enough.
+	The <varname>priority</varname> defines order in which the
+	components should start.  The ones with higher numbers are
+	started sooner than the ones with lower ones. If you don't
+	set it, 0 (zero) is used as the priority.  Usually, leaving
+	it at the default is enough.
       </para>
       </para>
 
 
       <para>
       <para>
         There are other parameters we didn't use in our example.
         There are other parameters we didn't use in our example.
-        One of them is <quote>address</quote>. It is the address
+        One of them is <varname>address</varname>. It is the address
         used by the component on the <command>b10-msgq</command>
         used by the component on the <command>b10-msgq</command>
         message bus. The special components already know their
         message bus. The special components already know their
         address, but the usual ones don't. The address is by
         address, but the usual ones don't. The address is by
@@ -900,25 +940,17 @@ address, but the usual ones don't." mean? -->
 <!-- TODO: document params when is enabled -->
 <!-- TODO: document params when is enabled -->
 
 
       <para>
       <para>
-        The last one is process. It is the name of the process to be started.
-        It defaults to the name of the component if not set, but you can use
-        this to override it.
+	The last one is <varname>process</varname>. It is the name
+	of the process to be started.  It defaults to the name of
+	the component if not set, but you can use this to override
+	it. (The special components also already know their
+        executable name.)
       </para>
       </para>
 
 
       <!-- TODO Add parameters when they work, not implemented yet-->
       <!-- TODO Add parameters when they work, not implemented yet-->
 
 
       <note>
       <note>
         <para>
         <para>
-          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 a situation, so it would probably not do what you want. Such
-          support is yet to be implemented.
-        </para>
-      </note>
-
-      <note>
-        <para>
           The configuration is quite powerful, but that includes
           The configuration is quite powerful, but that includes
           a lot of space for mistakes. You could turn off the
           a lot of space for mistakes. You could turn off the
           <command>b10-cmdctl</command>, but then you couldn't
           <command>b10-cmdctl</command>, but then you couldn't
@@ -938,7 +970,7 @@ address, but the usual ones don't." mean? -->
       </note>
       </note>
       <para>
       <para>
         It is possible to start some components multiple times (currently
         It is possible to start some components multiple times (currently
-        <command>b10-auth</command> and <command>b10-resolzer</command>).
+        <command>b10-auth</command> and <command>b10-resolver</command>).
         You might want to do that to gain more performance (each one uses only
         You might want to do that to gain more performance (each one uses only
         single core). Just put multiple entries under different names, like
         single core). Just put multiple entries under different names, like
         this, with the same config:
         this, with the same config:
@@ -953,6 +985,9 @@ address, but the usual ones don't." mean? -->
         server will keep its own copy of in-memory data and there could be
         server will keep its own copy of in-memory data and there could be
         problems with locking the sqlite database, if used. The configuration
         problems with locking the sqlite database, if used. The configuration
         might be changed to something more convenient in future.
         might be changed to something more convenient in future.
+	Other components don't expect such a situation, so it would
+	probably not do what you want. Such support is yet to be
+	implemented.
       </para>
       </para>
     </section>
     </section>
 
 
@@ -977,23 +1012,11 @@ address, but the usual ones don't." mean? -->
       <para>
       <para>
         Administrators do not communicate directly with the
         Administrators do not communicate directly with the
         <command>b10-msgq</command> daemon.
         <command>b10-msgq</command> daemon.
-        By default, BIND 10 uses port 9912 for the
-        <command>b10-msgq</command> service.
-        It listens on 127.0.0.1.
+        By default, BIND 10 uses a UNIX domain socket file named
+        <filename>/usr/local/var/bind10-devel/msg_socket</filename>
+        for this interprocess communication.
       </para>
       </para>
 
 
-<!-- TODO: this is broken, see Trac #111
-      <para>
-        To select an alternate port for the <command>b10-msgq</command> to
-        use, run <command>bind10</command> specifying the option:
-        <screen> $ <userinput>bind10 -TODO-msgq-port 9912</userinput></screen>
-      </para>
--->
-
-<!-- TODO: upcoming plans:
-Unix domain sockets
--->
-
   </chapter>
   </chapter>
 
 
   <chapter id="cfgmgr">
   <chapter id="cfgmgr">
@@ -2439,21 +2462,22 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
       </para>
       </para>
 
 
       <para>
       <para>
-        The DHCPv4 server is implemented as <command>b10-dhcp4</command>
-        daemon. As it is not configurable yet, it is fully autonomous,
-        that is it does not interact with <command>b10-cfgmgr</command>.
-        To start DHCPv4 server, simply input:
-
-        <screen>
-#<userinput>cd src/bin/dhcp4</userinput>
-#<userinput>./b10-dhcp4</userinput>
-</screen>
+        <command>b10-dhcp4</command> is a BIND10 component and is being
+        run under BIND10 framework. To add a DHCPv4 process to the set of running
+        BIND10 services, you can use following commands in <command>bindctl</command>:
+        <screen>&gt; <userinput>config add Boss/components b10-dhcp4</userinput>
+&gt; <userinput>config set Boss/components/b10-dhcp4/kind dispensable</userinput>
+&gt; <userinput>config commit</userinput></screen></para>
 
 
-        Depending on your installation, <command>b10-dhcp4</command>
-        binary may reside in src/bin/dhcp4 in your source code
-        directory, in /usr/local/bin/b10-dhcp4 or other directory
-        you specified during compilation.
+       <para>
+         To shutdown running <command>b10-dhcp4</command>, please use the
+         following command:
+         <screen>&gt; <userinput>Dhcp4 shutdown</userinput></screen>
+         or
+         <screen>&gt; <userinput>config remove Boss/components b10-dhcp4</userinput>
+&gt; <userinput>config commit</userinput></screen></para>
 
 
+      <para>
         At start, the server will detect available network interfaces
         At start, the server will detect available network interfaces
         and will attempt to open UDP sockets on all interfaces that
         and will attempt to open UDP sockets on all interfaces that
         are up, running, are not loopback, and have IPv4 address
         are up, running, are not loopback, and have IPv4 address
@@ -2555,13 +2579,7 @@ const std::string HARDCODED_SERVER_ID = "192.0.2.1";</screen>
           <listitem>
           <listitem>
             <simpara>Upon start, the server will open sockets on all
             <simpara>Upon start, the server will open sockets on all
             interfaces that are not loopback, are up and running and
             interfaces that are not loopback, are up and running and
-            have IPv4 address.  Support for multiple interfaces is not
-            coded in reception routines yet, so if you are running
-            this code on a machine that has many interfaces and
-            <command>b10-dhcp4</command> happens to listen on wrong
-            interface, the easiest way to work around this problem is
-            to turn down other interfaces. This limitation will be
-            fixed shortly.</simpara>
+            have IPv4 address.</simpara>
           </listitem>
           </listitem>
           <listitem>
           <listitem>
             <simpara>PRL (Parameter Request List, a list of options
             <simpara>PRL (Parameter Request List, a list of options
@@ -2819,22 +2837,10 @@ const std::string HARDCODED_DNS_SERVER = "2001:db8:1::1";</screen>
       currently only supported on Linux systems.</para>
       currently only supported on Linux systems.</para>
 
 
       <para>For non-Linux systems, there is currently stub
       <para>For non-Linux systems, there is currently stub
-      implementation provided. As DHCP servers need to know available
-      addresses, there is a simple mechanism implemented to provide
-      that information. User is expected to create interfaces.txt
-      file. Format of this file is simple. It contains list of
-      interfaces along with available address on each interface. This
-      mechanism is temporary and is going to be removed as soon as
-      interface detection becomes available on non-Linux
-      systems. Here is an example of the interfaces.txt file:
-      <screen>
-# For DHCPv6, please specify link-local address (starts with fe80::)
-# If in doubt, check output of 'ifconfig -a' command.
-eth0 fe80::21e:8cff:fe9b:7349
-
-# For DHCPv4, please use following format:
-#eth0 192.0.2.5</screen>
-      </para>
+      implementation provided. Interface manager detects loopback
+      interfaces only as their name (lo or lo0) can be easily predicted.
+      Please contact BIND10 development team if you are interested
+      in running DHCP components on systems other than Linux.</para>
     </section>
     </section>
 
 
     <section id="packet-handling">
     <section id="packet-handling">

+ 1 - 1
src/bin/auth/tests/Makefile.am

@@ -20,7 +20,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 # Do not define global tests, use check-local so
 # Do not define global tests, use check-local so
 # environment can be set (needed for dynamic loading)
 # environment can be set (needed for dynamic loading)

+ 4 - 0
src/bin/dhcp4/Makefile.am

@@ -31,6 +31,7 @@ BUILT_SOURCES = spec_config.h
 pkglibexec_PROGRAMS = b10-dhcp4
 pkglibexec_PROGRAMS = b10-dhcp4
 
 
 b10_dhcp4_SOURCES = main.cc dhcp4_srv.cc dhcp4_srv.h
 b10_dhcp4_SOURCES = main.cc dhcp4_srv.cc dhcp4_srv.h
+b10_dhcp4_SOURCES += ctrl_dhcp4_srv.cc ctrl_dhcp4_srv.h
 
 
 if USE_CLANGPP
 if USE_CLANGPP
 # Disable unused parameter warning caused by some of the
 # Disable unused parameter warning caused by some of the
@@ -42,6 +43,9 @@ b10_dhcp4_LDADD = $(top_builddir)/src/lib/dhcp/libdhcp++.la
 b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 b10_dhcp4_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 b10_dhcp4_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 b10_dhcp4_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 b10_dhcp4_LDADD += $(top_builddir)/src/lib/log/liblog.la
 b10_dhcp4_LDADD += $(top_builddir)/src/lib/log/liblog.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+b10_dhcp4_LDADD += $(top_builddir)/src/lib/cc/libcc.la
+
 
 
 b10_dhcp4dir = $(pkgdatadir)
 b10_dhcp4dir = $(pkgdatadir)
 b10_dhcp4_DATA = dhcp4.spec
 b10_dhcp4_DATA = dhcp4.spec

+ 159 - 0
src/bin/dhcp4/ctrl_dhcp4_srv.cc

@@ -0,0 +1,159 @@
+// 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 <cassert>
+#include <iostream>
+
+#include <cc/session.h>
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
+#include <cc/session.h>
+#include <config/ccsession.h>
+#include <util/buffer.h>
+#include <dhcp4/spec_config.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
+#include <dhcp/iface_mgr.h>
+#include <asiolink/asiolink.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::dhcp;
+using namespace isc::util;
+using namespace isc::data;
+using namespace isc::cc;
+using namespace isc::config;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+
+ControlledDhcpv4Srv* ControlledDhcpv4Srv::server_ = NULL;
+
+ConstElementPtr
+ControlledDhcpv4Srv::dhcp4ConfigHandler(ConstElementPtr new_config) {
+    cout << "b10-dhcp4: Received new config:" << new_config->str() << endl;
+    ConstElementPtr answer = isc::config::createAnswer(0,
+                             "Thank you for sending config.");
+    return (answer);
+}
+
+ConstElementPtr
+ControlledDhcpv4Srv::dhcp4CommandHandler(const string& command, ConstElementPtr args) {
+    cout << "b10-dhcp4: Received new command: [" << command << "], args="
+         << args->str() << endl;
+    if (command == "shutdown") {
+        if (ControlledDhcpv4Srv::server_) {
+            ControlledDhcpv4Srv::server_->shutdown();
+        } else {
+            cout << "Server not initialized yet or already shut down." << endl;
+            ConstElementPtr answer = isc::config::createAnswer(1,
+                                     "Shutdown failure.");
+            return (answer);
+        }
+        ConstElementPtr answer = isc::config::createAnswer(0,
+                                 "Shutting down.");
+        return (answer);
+    }
+
+    ConstElementPtr answer = isc::config::createAnswer(1,
+                             "Unrecognized command.");
+
+    return (answer);
+}
+
+void ControlledDhcpv4Srv::sessionReader(void) {
+    // Process one asio event. If there are more events, iface_mgr will call
+    // this callback more than once.
+    if (server_) {
+        server_->io_service_.run_one();
+    }
+}
+
+void ControlledDhcpv4Srv::establishSession() {
+    
+    string specfile;
+    if (getenv("B10_FROM_BUILD")) {
+        specfile = string(getenv("B10_FROM_BUILD")) +
+            "/src/bin/auth/dhcp4.spec";
+    } else {
+        specfile = string(DHCP4_SPECFILE_LOCATION);
+    }
+
+    /// @todo: Check if session is not established already. Throw, if it is.
+    
+    cout << "b10-dhcp4: my specfile is " << specfile << endl;
+    
+    cc_session_ = new Session(io_service_.get_io_service());
+
+    config_session_ = new ModuleCCSession(specfile, *cc_session_,
+                                          dhcp4ConfigHandler,
+                                          dhcp4CommandHandler, false);
+    config_session_->start();
+
+    /// Integrate the asynchronous I/O model of BIND 10 configuration
+    /// control with the "select" model of the DHCP server.  This is
+    /// fully explained in \ref dhcpv4Session.
+    int ctrl_socket = cc_session_->getSocketDesc();
+    cout << "b10-dhcp4: Control session started, socket="
+         << ctrl_socket << endl;
+    IfaceMgr::instance().set_session_socket(ctrl_socket, sessionReader);
+}
+
+void ControlledDhcpv4Srv::disconnectSession() {
+    if (config_session_) {
+        delete config_session_;
+        config_session_ = NULL;
+    }
+    if (cc_session_) {
+        cc_session_->disconnect();
+        delete cc_session_;
+        cc_session_ = NULL;
+    }
+
+    // deregister session socket
+    IfaceMgr::instance().set_session_socket(IfaceMgr::INVALID_SOCKET, NULL);
+}
+
+ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
+    :Dhcpv4Srv(port), cc_session_(NULL), config_session_(NULL) {
+    server_ = this; // remember this instance for use in callback
+}
+
+void ControlledDhcpv4Srv::shutdown() {
+    io_service_.stop(); // Stop ASIO transmissions
+    Dhcpv4Srv::shutdown(); // Initiate DHCPv4 shutdown procedure.
+}
+
+ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
+    disconnectSession();
+
+    server_ = NULL; // forget this instance. There should be no callback anymore
+                    // at this stage anyway.
+}
+
+isc::data::ConstElementPtr
+ControlledDhcpv4Srv::execDhcpv4ServerCommand(const std::string& command_id,
+                                             isc::data::ConstElementPtr args) {
+    try {
+        return (dhcp4CommandHandler(command_id, args));
+    } catch (const Exception& ex) {
+        ConstElementPtr answer = isc::config::createAnswer(1, ex.what());
+        return (answer);
+    }
+}
+
+
+};
+};

+ 123 - 0
src/bin/dhcp4/ctrl_dhcp4_srv.h

@@ -0,0 +1,123 @@
+// 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 CTRL_DHCPV4_SRV_H
+#define CTRL_DHCPV4_SRV_H
+
+#include <dhcp4/dhcp4_srv.h>
+#include <asiolink/asiolink.h>
+#include <cc/session.h>
+#include <config/ccsession.h>
+#include <cc/data.h>
+
+namespace isc {
+namespace dhcp {
+
+/// @brief Controlled version of the DHCPv4 server
+///
+/// This is a class that is responsible for establishing connection
+/// with msqg (receving commands and configuration). This is an extended
+/// version of Dhcpv4Srv class that is purely a DHCPv4 server, without
+/// external control. ControlledDhcpv4Srv should be used in typical BIND10
+/// (i.e. featuring msgq) environment, while Dhcpv4Srv should be used in
+/// embedded environments.
+///
+/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
+/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
+class ControlledDhcpv4Srv : public isc::dhcp::Dhcpv4Srv {
+public:
+
+    /// @brief Constructor
+    ///
+    /// @param port UDP port to be opened for DHCP traffic
+    ControlledDhcpv4Srv(uint16_t port = DHCP4_SERVER_PORT);
+
+    /// @brief Destructor.
+    ~ControlledDhcpv4Srv();
+
+    /// @brief Establishes msgq session.
+    ///
+    /// Creates session that will be used to receive commands and updated
+    /// configuration from boss (or indirectly from user via bindctl).
+    void establishSession();
+
+    /// @brief Terminates existing msgq session.
+    ///
+    /// This method terminates existing session with msgq. After calling
+    /// it, no further messages over msgq (commands or configuration updates)
+    /// may be received.
+    ///
+    /// It is ok to call this method when session is disconnected already.
+    void disconnectSession();
+
+    /// @brief Initiates shutdown procedure for the whole DHCPv4 server.
+    void shutdown();
+
+    /// @brief Session callback, processes received commands.
+    ///
+    /// @param command_id text represenation of the command (e.g. "shutdown")
+    /// @param args optional parameters
+    ///
+    /// @return status of the command
+    static isc::data::ConstElementPtr
+    execDhcpv4ServerCommand(const std::string& command,
+                            isc::data::ConstElementPtr args);
+
+protected:
+    /// @brief Static pointer to the sole instance of the DHCP server.
+    ///
+    /// This is required for config and command handlers to gain access to
+    /// the server
+    static ControlledDhcpv4Srv* server_;
+
+    /// @brief A callback for handling incoming configuration updates.
+    ///
+    /// As pointer to this method is used a callback in ASIO used in
+    /// ModuleCCSession, it has to be static.
+    ///
+    /// @param new_config textual representation of the new configuration
+    ///
+    /// @return status of the config update
+    static isc::data::ConstElementPtr
+    dhcp4ConfigHandler(isc::data::ConstElementPtr new_config);
+
+    /// @brief A callback for handling incoming commands.
+    ///
+    /// @param command textual representation of the command
+    /// @param args parameters of the command
+    ///
+    /// @return status of the processed command
+    static isc::data::ConstElementPtr
+    dhcp4CommandHandler(const std::string& command, isc::data::ConstElementPtr args);
+
+    /// @brief Callback that will be called from iface_mgr when command/config arrives.
+    ///
+    /// This static callback method is called from IfaceMgr::receive4() method,
+    /// when there is a new command or configuration sent over msgq.
+    static void sessionReader(void);
+
+    /// @brief IOService object, used for all ASIO operations.
+    isc::asiolink::IOService io_service_;
+
+    /// @brief Helper session object that represents raw connection to msgq.
+    isc::cc::Session* cc_session_;
+
+    /// @brief Session that receives configuation and commands
+    isc::config::ModuleCCSession* config_session_;
+};
+
+}; // namespace isc::dhcp
+}; // namespace isc
+
+#endif

+ 14 - 2
src/bin/dhcp4/dhcp4.spec

@@ -1,6 +1,6 @@
 {
 {
   "module_spec": {
   "module_spec": {
-    "module_name": "dhcp4",
+    "module_name": "Dhcp4",
     "module_description": "DHCPv4 server daemon",
     "module_description": "DHCPv4 server daemon",
     "config_data": [
     "config_data": [
       { "item_name": "interface",
       { "item_name": "interface",
@@ -9,6 +9,18 @@
         "item_default": "eth0"
         "item_default": "eth0"
       }
       }
     ],
     ],
-    "commands": []
+    "commands": [
+        {
+            "command_name": "shutdown",
+            "command_description": "Shuts down DHCPv4 server.",
+            "command_args": [
+                {
+                    "item_name": "pid",
+                    "item_type": "integer",
+                    "item_optional": true
+                }
+            ]
+        }
+    ]
   }
   }
 }
 }

+ 10 - 2
src/bin/dhcp4/dhcp4_srv.cc

@@ -52,15 +52,23 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port) {
 }
 }
 
 
 Dhcpv4Srv::~Dhcpv4Srv() {
 Dhcpv4Srv::~Dhcpv4Srv() {
-    cout << "DHCPv4 server shutdown." << endl;
+    cout << "b10-dhcp4: DHCPv4 server terminating." << endl;
     IfaceMgr::instance().closeSockets();
     IfaceMgr::instance().closeSockets();
 }
 }
 
 
+void Dhcpv4Srv::shutdown() {
+    cout << "b10-dhcp4: DHCPv4 server shutdown." << endl;
+    shutdown_ = true;
+}
+
 bool
 bool
 Dhcpv4Srv::run() {
 Dhcpv4Srv::run() {
     while (!shutdown_) {
     while (!shutdown_) {
+        /// @todo: calculate actual timeout once we have lease database
+        int timeout = 1000;
+
         // client's message and server's response
         // client's message and server's response
-        Pkt4Ptr query = IfaceMgr::instance().receive4();
+        Pkt4Ptr query = IfaceMgr::instance().receive4(timeout);
         Pkt4Ptr rsp;
         Pkt4Ptr rsp;
 
 
         if (query) {
         if (query) {

+ 10 - 0
src/bin/dhcp4/dhcp4_srv.h

@@ -32,6 +32,13 @@ namespace dhcp {
 /// that is going to be used as server-identifier, receives incoming
 /// that is going to be used as server-identifier, receives incoming
 /// packets, processes them, manages leases assignment and generates
 /// packets, processes them, manages leases assignment and generates
 /// appropriate responses.
 /// appropriate responses.
+///
+/// This class does not support any controlling mechanisms directly.
+/// See derived \ref ControlledDhcv4Srv class for support for
+/// command and configuration updates over msgq.
+///
+/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
+/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
 class Dhcpv4Srv : public boost::noncopyable {
 class Dhcpv4Srv : public boost::noncopyable {
 
 
     public:
     public:
@@ -60,6 +67,9 @@ class Dhcpv4Srv : public boost::noncopyable {
     ///         critical error.
     ///         critical error.
     bool run();
     bool run();
 
 
+    /// @brief Instructs the server to shut down.
+    void shutdown();
+
 protected:
 protected:
     /// @brief Processes incoming DISCOVER and returns response.
     /// @brief Processes incoming DISCOVER and returns response.
     ///
     ///

+ 27 - 44
src/bin/dhcp4/main.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2009-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
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -13,41 +13,31 @@
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
 #include <config.h>
 #include <config.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/select.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <cassert>
 #include <iostream>
 #include <iostream>
-
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
-#if 0
-// TODO cc is not used yet. It should be eventually
-#include <cc/session.h>
-#include <config/ccsession.h>
-#endif
-
-#include <util/buffer.h>
 #include <log/dummylog.h>
 #include <log/dummylog.h>
-
-#include <dhcp4/spec_config.h>
+#include <log/logger_support.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <dhcp4/dhcp4_srv.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp/dhcp4.h>
 
 
 using namespace std;
 using namespace std;
-using namespace isc::util;
-
-using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp;
 
 
+
+
+/// This file contains entry point (main() function) for standard DHCPv4 server
+/// component for BIND10 framework. It parses command-line arguments and
+/// instantiates ControlledDhcpv4Srv class that is responsible for establishing
+/// connection with msgq (receiving commands and configuration) and also
+/// creating Dhcpv4 server object as well.
+///
+/// For detailed explanation or relations between main(), ControlledDhcpv4Srv,
+/// Dhcpv4Srv and other classes, see \ref dhcpv4Session.
+
 namespace {
 namespace {
 
 
-bool verbose_mode = false;
+const char* const DHCP4_NAME = "b10-dhcp4";
 
 
 void
 void
 usage() {
 usage() {
@@ -62,6 +52,7 @@ usage() {
 int
 int
 main(int argc, char* argv[]) {
 main(int argc, char* argv[]) {
     int ch;
     int ch;
+    bool verbose_mode = false; // should server be verbose?
     int port_number = DHCP4_SERVER_PORT; // The default. any other values are
     int port_number = DHCP4_SERVER_PORT; // The default. any other values are
                                          // useful for testing only.
                                          // useful for testing only.
 
 
@@ -85,8 +76,13 @@ main(int argc, char* argv[]) {
         }
         }
     }
     }
 
 
-    cout << "My pid=" << getpid() << ", binding to port " << port_number
-         << ", verbose " << (verbose_mode?"yes":"no") << endl;
+    // Initialize logging.  If verbose, we'll use maximum verbosity.
+    isc::log::initLogger(DHCP4_NAME,
+                         (verbose_mode ? isc::log::DEBUG : isc::log::INFO),
+                         isc::log::MAX_DEBUG_LEVEL, NULL);
+
+    cout << "b10-dhcp4: My pid=" << getpid() << ", binding to port " 
+         << port_number << ", verbose " << (verbose_mode?"yes":"no") << endl;
 
 
     if (argc - optind > 0) {
     if (argc - optind > 0) {
         usage();
         usage();
@@ -94,27 +90,14 @@ main(int argc, char* argv[]) {
 
 
     int ret = EXIT_SUCCESS;
     int ret = EXIT_SUCCESS;
 
 
-    // TODO remainder of auth to dhcp4 code copy. We need to enable this in
-    //      dhcp4 eventually
-#if 0
-    Session* cc_session = NULL;
-    Session* statistics_session = NULL;
-    ModuleCCSession* config_session = NULL;
-#endif
     try {
     try {
-        string specfile;
-        if (getenv("B10_FROM_BUILD")) {
-            specfile = string(getenv("B10_FROM_BUILD")) +
-                "/src/bin/auth/dhcp4.spec";
-        } else {
-            specfile = string(DHCP4_SPECFILE_LOCATION);
-        }
 
 
         cout << "[b10-dhcp4] Initiating DHCPv4 server operation." << endl;
         cout << "[b10-dhcp4] Initiating DHCPv4 server operation." << endl;
 
 
-        Dhcpv4Srv* srv = new Dhcpv4Srv(port_number);
-
-        srv->run();
+        ControlledDhcpv4Srv* server = new ControlledDhcpv4Srv(port_number);
+        server->run();
+        delete server;
+        server = NULL;
 
 
     } catch (const std::exception& ex) {
     } catch (const std::exception& ex) {
         cerr << "[b10-dhcp4] Server failed: " << ex.what() << endl;
         cerr << "[b10-dhcp4] Server failed: " << ex.what() << endl;

+ 5 - 2
src/bin/dhcp4/tests/Makefile.am

@@ -39,16 +39,17 @@ AM_LDFLAGS = -static
 endif
 endif
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST
 
 
 TESTS += dhcp4_unittests
 TESTS += dhcp4_unittests
 
 
-dhcp4_unittests_SOURCES = ../dhcp4_srv.h ../dhcp4_srv.cc
+dhcp4_unittests_SOURCES = ../dhcp4_srv.h ../dhcp4_srv.cc ../ctrl_dhcp4_srv.cc
 dhcp4_unittests_SOURCES += dhcp4_unittests.cc
 dhcp4_unittests_SOURCES += dhcp4_unittests.cc
 dhcp4_unittests_SOURCES += dhcp4_srv_unittest.cc
 dhcp4_unittests_SOURCES += dhcp4_srv_unittest.cc
+dhcp4_unittests_SOURCES += ctrl_dhcp4_srv_unittest.cc
 
 
 if USE_CLANGPP
 if USE_CLANGPP
 # Disable unused parameter warning caused by some of the
 # Disable unused parameter warning caused by some of the
@@ -64,6 +65,8 @@ dhcp4_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libdhcp++.la
 dhcp4_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 dhcp4_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 dhcp4_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
 dhcp4_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
 dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
 dhcp4_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+dhcp4_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
 endif
 endif
 
 
 noinst_PROGRAMS = $(TESTS)
 noinst_PROGRAMS = $(TESTS)

+ 85 - 0
src/bin/dhcp4/tests/ctrl_dhcp4_srv_unittest.cc

@@ -0,0 +1,85 @@
+// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include <arpa/inet.h>
+#include <gtest/gtest.h>
+
+#include <dhcp/dhcp4.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
+#include <config/ccsession.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::data;
+using namespace isc::config;
+
+namespace {
+
+class NakedControlledDhcpv4Srv: public ControlledDhcpv4Srv {
+    // "naked" DHCPv4 server, exposes internal fields
+public:
+    NakedControlledDhcpv4Srv():ControlledDhcpv4Srv(DHCP4_SERVER_PORT + 10000) { }
+};
+
+class CtrlDhcpv4SrvTest : public ::testing::Test {
+public:
+    CtrlDhcpv4SrvTest() {
+    }
+
+    ~CtrlDhcpv4SrvTest() {
+    };
+};
+
+TEST_F(CtrlDhcpv4SrvTest, commands) {
+
+    ControlledDhcpv4Srv* srv = NULL;
+    ASSERT_NO_THROW({
+        srv = new ControlledDhcpv4Srv(DHCP4_SERVER_PORT + 10000);
+    });
+
+    // use empty parameters list
+    ElementPtr params(new isc::data::MapElement());
+    int rcode = -1;
+
+    // case 1: send bogus command
+    ConstElementPtr result = ControlledDhcpv4Srv::execDhcpv4ServerCommand("blah", params);
+    ConstElementPtr comment = parseAnswer(rcode, result);
+    EXPECT_EQ(1, rcode); // expect failure (no such command as blah)
+
+    // case 1: send shutdown command without any parameters
+    result = ControlledDhcpv4Srv::execDhcpv4ServerCommand("shutdown", params);
+    comment = parseAnswer(rcode, result);
+    EXPECT_EQ(0, rcode); // expect success
+
+    const pid_t pid(getpid());
+    ConstElementPtr x(new isc::data::IntElement(pid));
+    params->set("pid", x);
+
+    // case 2: send shutdown command with 1 parameter: pid
+    result = ControlledDhcpv4Srv::execDhcpv4ServerCommand("shutdown", params);
+    comment = parseAnswer(rcode, result);
+    EXPECT_EQ(0, rcode); // expect success
+
+
+    delete srv;
+}
+
+} // end of anonymous namespace

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

@@ -35,7 +35,7 @@ AM_LDFLAGS = -static
 endif
 endif
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 7
src/bin/msgq/msgq.xml

@@ -20,7 +20,7 @@
 <refentry>
 <refentry>
 
 
   <refentryinfo>
   <refentryinfo>
-    <date>August 4, 2010</date>
+    <date>June 25, 2012</date>
   </refentryinfo>
   </refentryinfo>
 
 
   <refmeta>
   <refmeta>
@@ -92,10 +92,6 @@
     </para>
     </para>
 
 
     <para>
     <para>
-      It listens on 127.0.0.1.
-    </para>
-
-    <para>
       The <command>b10-msgq</command> daemon may be cleanly stopped by
       The <command>b10-msgq</command> daemon may be cleanly stopped by
       sending the SIGTERM signal to the process.
       sending the SIGTERM signal to the process.
       This shutdown does not notify the subscribers.
       This shutdown does not notify the subscribers.
@@ -168,5 +164,3 @@
  - End:
  - End:
 -->
 -->
 
 
-
-

+ 1 - 1
src/bin/resolver/tests/Makefile.am

@@ -15,7 +15,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/bin/sockcreator/tests/Makefile.am

@@ -9,7 +9,7 @@ AM_LDFLAGS = -static
 endif
 endif
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/acl/tests/Makefile.am

@@ -9,7 +9,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

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

@@ -13,7 +13,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/asiolink/tests/Makefile.am

@@ -19,7 +19,7 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/bench/tests/Makefile.am

@@ -6,7 +6,7 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/cache/tests/Makefile.am

@@ -29,7 +29,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 16 - 0
src/lib/cc/session.cc

@@ -88,6 +88,7 @@ public:
     void startRead(boost::function<void()> user_handler);
     void startRead(boost::function<void()> user_handler);
     void setTimeout(size_t seconds) { timeout_ = seconds; };
     void setTimeout(size_t seconds) { timeout_ = seconds; };
     size_t getTimeout() const { return timeout_; };
     size_t getTimeout() const { return timeout_; };
+    int getSocketDesc();
 
 
     long int sequence_; // the next sequence number to use
     long int sequence_; // the next sequence number to use
     std::string lname_;
     std::string lname_;
@@ -254,6 +255,16 @@ SessionImpl::internalRead(const asio::error_code& error,
     }
     }
 }
 }
 
 
+int
+SessionImpl::getSocketDesc() {
+    /// @todo boost 1.42 uses native() method, but it is deprecated
+    /// in 1.49 and native_handle() is recommended instead
+    if (!socket_.is_open()) {
+        isc_throw(InvalidOperation, "Can't return socket desciptor: no socket opened.");
+    }
+    return socket_.native();
+}
+
 Session::Session(asio::io_service& io_service) :
 Session::Session(asio::io_service& io_service) :
     impl_(new SessionImpl(io_service))
     impl_(new SessionImpl(io_service))
 {}
 {}
@@ -273,6 +284,11 @@ Session::startRead(boost::function<void()> read_callback) {
     impl_->startRead(read_callback);
     impl_->startRead(read_callback);
 }
 }
 
 
+int
+Session::getSocketDesc() const {
+    return impl_->getSocketDesc();
+}
+
 namespace {                     // maybe unnecessary.
 namespace {                     // maybe unnecessary.
 // This is a helper class to make the establish() method (below) exception-safe
 // This is a helper class to make the establish() method (below) exception-safe
 // with the RAII approach.
 // with the RAII approach.

+ 5 - 0
src/lib/cc/session.h

@@ -141,6 +141,11 @@ namespace isc {
             virtual bool hasQueuedMsgs() const;
             virtual bool hasQueuedMsgs() const;
             virtual void setTimeout(size_t milliseconds);
             virtual void setTimeout(size_t milliseconds);
             virtual size_t getTimeout() const;
             virtual size_t getTimeout() const;
+
+            /// @brief returns socket descriptor from underlying socket connection
+            ///
+            /// @param returns socket descriptor used for session connection
+            virtual int getSocketDesc() const;
     private:
     private:
             void sendmsg(isc::data::ConstElementPtr msg);
             void sendmsg(isc::data::ConstElementPtr msg);
             void sendmsg(isc::data::ConstElementPtr env,
             void sendmsg(isc::data::ConstElementPtr env,

+ 1 - 1
src/lib/cc/tests/Makefile.am

@@ -17,7 +17,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 13 - 0
src/lib/cc/tests/session_unittests.cc

@@ -34,6 +34,9 @@ TEST(AsioSession, establish) {
     asio::io_service io_service_;
     asio::io_service io_service_;
     Session sess(io_service_);
     Session sess(io_service_);
 
 
+    // can't return socket desciptor before session is established
+    EXPECT_THROW(sess.getSocketDesc(), isc::InvalidOperation);
+
     EXPECT_THROW(
     EXPECT_THROW(
         sess.establish("/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
         sess.establish("/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
                        "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
                        "/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/aaaaaaaaaa/"
@@ -235,4 +238,14 @@ TEST_F(SessionTest, run_with_handler_timeout) {
     ASSERT_THROW(my_io_service.run(), SessionTimeout);
     ASSERT_THROW(my_io_service.run(), SessionTimeout);
 }
 }
 
 
+TEST_F(SessionTest, get_socket_descr) {
+    tds->setSendLname();
+    sess.establish(BIND10_TEST_SOCKET_FILE);
 
 
+    int socket = 0;
+    // session is established, so getSocketDesc() should work
+    EXPECT_NO_THROW(socket = sess.getSocketDesc());
+
+    // expect actual socket handle to be returned, not 0
+    EXPECT_LT(0, socket);
+}

+ 1 - 1
src/lib/config/tests/Makefile.am

@@ -15,7 +15,7 @@ noinst_LTLIBRARIES = libfake_session.la
 libfake_session_la_SOURCES = fake_session.h fake_session.cc
 libfake_session_la_SOURCES = fake_session.h fake_session.cc
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/cryptolink/tests/Makefile.am

@@ -11,7 +11,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 22 - 35
src/lib/datasrc/database.cc

@@ -179,8 +179,7 @@ private:
 
 
 DatabaseClient::Finder::FoundRRsets
 DatabaseClient::Finder::FoundRRsets
 DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
 DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
-                                  bool check_ns, const string* construct_name,
-                                  bool any,
+                                  const string* construct_name, bool any,
                                   DatabaseAccessor::IteratorContextPtr context)
                                   DatabaseAccessor::IteratorContextPtr context)
 {
 {
     RRsigStore sig_store;
     RRsigStore sig_store;
@@ -204,9 +203,7 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
     const Name construct_name_object(*construct_name);
     const Name construct_name_object(*construct_name);
 
 
     bool seen_cname(false);
     bool seen_cname(false);
-    bool seen_ds(false);
     bool seen_other(false);
     bool seen_other(false);
-    bool seen_ns(false);
 
 
     while (context->getNext(columns)) {
     while (context->getNext(columns)) {
         // The domain is not empty
         // The domain is not empty
@@ -249,16 +246,12 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
 
 
             if (cur_type == RRType::CNAME()) {
             if (cur_type == RRType::CNAME()) {
                 seen_cname = true;
                 seen_cname = true;
-            } else if (cur_type == RRType::NS()) {
-                seen_ns = true;
-            } else if (cur_type == RRType::DS()) {
-                seen_ds = true;
             } else if (cur_type != RRType::RRSIG() &&
             } else if (cur_type != RRType::RRSIG() &&
                        cur_type != RRType::NSEC3() &&
                        cur_type != RRType::NSEC3() &&
                        cur_type != RRType::NSEC()) {
                        cur_type != RRType::NSEC()) {
                 // NSEC and RRSIG can coexist with anything, otherwise
                 // NSEC and RRSIG can coexist with anything, otherwise
                 // we've seen something that can't live together with potential
                 // we've seen something that can't live together with potential
-                // CNAME or NS
+                // CNAME.
                 //
                 //
                 // NSEC3 lives in separate namespace from everything, therefore
                 // NSEC3 lives in separate namespace from everything, therefore
                 // we just ignore it here for these checks as well.
                 // we just ignore it here for these checks as well.
@@ -278,14 +271,10 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
                       RDATA_COLUMN]);
                       RDATA_COLUMN]);
         }
         }
     }
     }
-    if (seen_cname && (seen_other || seen_ns || seen_ds)) {
+    if (seen_cname && seen_other) {
         isc_throw(DataSourceError, "CNAME shares domain " << name <<
         isc_throw(DataSourceError, "CNAME shares domain " << name <<
                   " with something else");
                   " with something else");
     }
     }
-    if (check_ns && seen_ns && seen_other) {
-        isc_throw(DataSourceError, "NS shares domain " << name <<
-                  " with something else");
-    }
     // Add signatures to all found RRsets
     // Add signatures to all found RRsets
     for (std::map<RRType, RRsetPtr>::iterator i(result.begin());
     for (std::map<RRType, RRsetPtr>::iterator i(result.begin());
          i != result.end(); ++ i) {
          i != result.end(); ++ i) {
@@ -455,20 +444,20 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
     for (int i = remove_labels; i > 0; --i) {
     for (int i = remove_labels; i > 0; --i) {
         const Name superdomain(name.split(i));
         const Name superdomain(name.split(i));
 
 
-        // Note if this is the origin. (We don't count NS records at the origin
-        // as a delegation so this controls whether NS RRs are included in
-        // the results of some searches.)
-        const bool not_origin = (i != remove_labels);
-
         // Look if there's NS or DNAME at this point of the tree, but ignore
         // Look if there's NS or DNAME at this point of the tree, but ignore
         // the NS RRs at the apex of the zone.
         // the NS RRs at the apex of the zone.
         const FoundRRsets found = getRRsets(superdomain.toText(),
         const FoundRRsets found = getRRsets(superdomain.toText(),
-                                            DELEGATION_TYPES(), not_origin);
+                                            DELEGATION_TYPES());
         if (found.first) {
         if (found.first) {
             // This node contains either NS or DNAME RRs so it does exist.
             // This node contains either NS or DNAME RRs so it does exist.
             const FoundIterator nsi(found.second.find(RRType::NS()));
             const FoundIterator nsi(found.second.find(RRType::NS()));
             const FoundIterator dni(found.second.find(RRType::DNAME()));
             const FoundIterator dni(found.second.find(RRType::DNAME()));
 
 
+            // Note if this is the origin. (We don't count NS records at the
+            // origin as a delegation so this controls whether NS RRs are
+            // included in the results of some searches.)
+            const bool not_origin = (i != remove_labels);
+
             // An optimisation.  We know that there is an exact match for
             // An optimisation.  We know that there is an exact match for
             // something at this point in the tree so remember it.  If we have
             // something at this point in the tree so remember it.  If we have
             // to do a wildcard search, as we search upwards through the tree
             // to do a wildcard search, as we search upwards through the tree
@@ -477,7 +466,7 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
             last_known = superdomain.getLabelCount();
             last_known = superdomain.getLabelCount();
 
 
             if (glue_ok && !first_ns && not_origin &&
             if (glue_ok && !first_ns && not_origin &&
-                    nsi != found.second.end()) {
+                nsi != found.second.end()) {
                 // If we are searching for glue ("glue OK" mode), store the
                 // If we are searching for glue ("glue OK" mode), store the
                 // highest NS record that we find that is not the apex.  This
                 // highest NS record that we find that is not the apex.  This
                 // is another optimisation for later, where we need the
                 // is another optimisation for later, where we need the
@@ -590,8 +579,9 @@ DatabaseClient::Finder::findWildcardMatch(
         // TODO Add a check for DNAME, as DNAME wildcards are discouraged (see
         // TODO Add a check for DNAME, as DNAME wildcards are discouraged (see
         // RFC 4592 section 4.4).
         // RFC 4592 section 4.4).
         // Search for a match.  The types are the same as with original query.
         // Search for a match.  The types are the same as with original query.
-        FoundRRsets found = getRRsets(wildcard, final_types, true,
-                                      &construct_name, type == RRType::ANY());
+        const FoundRRsets found = getRRsets(wildcard, final_types,
+                                            &construct_name,
+                                            type == RRType::ANY());
         if (found.first) {
         if (found.first) {
             // Found something - but what?
             // Found something - but what?
 
 
@@ -694,7 +684,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
             // such cases).
             // such cases).
             const string origin = finder_.getOrigin().toText();
             const string origin = finder_.getOrigin().toText();
             const FoundRRsets nsec3_found =
             const FoundRRsets nsec3_found =
-                finder_.getRRsets(origin, NSEC3PARAM_TYPES(), false);
+                finder_.getRRsets(origin, NSEC3PARAM_TYPES());
             const FoundIterator nfi=
             const FoundIterator nfi=
                 nsec3_found.second.find(RRType::NSEC3PARAM());
                 nsec3_found.second.find(RRType::NSEC3PARAM());
             is_nsec3_ = (nfi != nsec3_found.second.end());
             is_nsec3_ = (nfi != nsec3_found.second.end());
@@ -705,7 +695,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
             // described in Section 10.4 of RFC 5155.
             // described in Section 10.4 of RFC 5155.
             if (!is_nsec3_) {
             if (!is_nsec3_) {
                 const FoundRRsets nsec_found =
                 const FoundRRsets nsec_found =
-                    finder_.getRRsets(origin, NSEC_TYPES(), false);
+                    finder_.getRRsets(origin, NSEC_TYPES());
                 const FoundIterator nfi =
                 const FoundIterator nfi =
                     nsec_found.second.find(RRType::NSEC());
                     nsec_found.second.find(RRType::NSEC());
                 is_nsec_ = (nfi != nsec_found.second.end());
                 is_nsec_ = (nfi != nsec_found.second.end());
@@ -757,10 +747,8 @@ DatabaseClient::Finder::FindDNSSECContext::getDNSSECRRset(const Name &name,
     try {
     try {
         const Name& nsec_name =
         const Name& nsec_name =
             covering ? finder_.findPreviousName(name) : name;
             covering ? finder_.findPreviousName(name) : name;
-        const bool need_nscheck = (nsec_name != finder_.getOrigin());
         const FoundRRsets found = finder_.getRRsets(nsec_name.toText(),
         const FoundRRsets found = finder_.getRRsets(nsec_name.toText(),
-                                                    NSEC_TYPES(),
-                                                    need_nscheck);
+                                                    NSEC_TYPES());
         const FoundIterator nci = found.second.find(RRType::NSEC());
         const FoundIterator nci = found.second.find(RRType::NSEC());
         if (nci != found.second.end()) {
         if (nci != found.second.end()) {
             return (nci->second);
             return (nci->second);
@@ -984,16 +972,15 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
     // - Requested name is a delegation point (NS only but not at the zone
     // - Requested name is a delegation point (NS only but not at the zone
     //   apex - DNAME is ignored here as it redirects DNS names subordinate to
     //   apex - DNAME is ignored here as it redirects DNS names subordinate to
     //   the owner name - the owner name itself is not redirected.)
     //   the owner name - the owner name itself is not redirected.)
-    const bool is_origin = (name == getOrigin());
     WantedTypes final_types(FINAL_TYPES());
     WantedTypes final_types(FINAL_TYPES());
     final_types.insert(type);
     final_types.insert(type);
     const FoundRRsets found = getRRsets(name.toText(), final_types,
     const FoundRRsets found = getRRsets(name.toText(), final_types,
-                                        !is_origin, NULL,
-                                        type == RRType::ANY());
+                                        NULL, type == RRType::ANY());
     FindDNSSECContext dnssec_ctx(*this, options);
     FindDNSSECContext dnssec_ctx(*this, options);
     if (found.first) {
     if (found.first) {
         // Something found at the domain name.  Look into it further to get
         // Something found at the domain name.  Look into it further to get
         // the final result.
         // the final result.
+        const bool is_origin = (name == getOrigin());
         return (findOnNameResult(name, type, options, is_origin, found, NULL,
         return (findOnNameResult(name, type, options, is_origin, found, NULL,
                                  target, dnssec_ctx));
                                  target, dnssec_ctx));
     } else {
     } else {
@@ -1021,7 +1008,7 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
     // Now, we need to get the NSEC3 params from the apex and create the hash
     // Now, we need to get the NSEC3 params from the apex and create the hash
     // creator for it.
     // creator for it.
     const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
     const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
-                                 NSEC3PARAM_TYPES(), false));
+                                           NSEC3PARAM_TYPES()));
     const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
     const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
     if (!nsec3param.first || param == nsec3param.second.end()) {
     if (!nsec3param.first || param == nsec3param.second.end()) {
         // No NSEC3 params? :-(
         // No NSEC3 params? :-(
@@ -1061,7 +1048,7 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
         }
         }
 
 
         const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
         const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
-                                          false, NULL, false, context));
+                                          NULL, false, context));
 
 
         if (nsec3.first) {
         if (nsec3.first) {
             // We found an exact match against the current label.
             // We found an exact match against the current label.
@@ -1086,8 +1073,8 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
                 arg(labels).arg(prevHash);
                 arg(labels).arg(prevHash);
             context = accessor_->getNSEC3Records(prevHash, zone_id_);
             context = accessor_->getNSEC3Records(prevHash, zone_id_);
             const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
             const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
-                                                   NSEC3_TYPES(), false, NULL,
-                                                   false, context));
+                                                   NSEC3_TYPES(), NULL, false,
+                                                   context));
 
 
             if (!prev_nsec3.first) {
             if (!prev_nsec3.first) {
                 isc_throw(DataSourceError, "Hash " + prevHash + " returned "
                 isc_throw(DataSourceError, "Hash " + prevHash + " returned "

+ 6 - 9
src/lib/datasrc/database.h

@@ -963,17 +963,14 @@ public:
         ///
         ///
         /// \param name Which domain name should be scanned.
         /// \param name Which domain name should be scanned.
         /// \param types List of types the caller is interested in.
         /// \param types List of types the caller is interested in.
-        /// \param check_ns If this is set to true, it checks nothing lives
-        ///     together with NS record (with few little exceptions, like RRSIG
-        ///     or NSEC). This check is meant for non-apex NS records.
         /// \param construct_name If this is NULL, the resulting RRsets have
         /// \param construct_name If this is NULL, the resulting RRsets have
-        ///     their name set to name. If it is not NULL, it overrides the name
-        ///     and uses this one (this can be used for wildcard synthesized
-        ///     records).
+        ///     their name set to name. If it is not NULL, it overrides the
+        ///     name and uses this one (this can be used for wildcard
+        ///     synthesized records).
         /// \param any If this is true, it records all the types, not only the
         /// \param any If this is true, it records all the types, not only the
         ///     ones requested by types. It also puts a NULL pointer under the
         ///     ones requested by types. It also puts a NULL pointer under the
-        ///     ANY type into the result, if it finds any RRs at all, to easy the
-        ///     identification of success.
+        ///     ANY type into the result, if it finds any RRs at all, to easy
+        ///     the identification of success.
         /// \param srcContext This can be set to non-NULL value to override the
         /// \param srcContext This can be set to non-NULL value to override the
         ///     iterator context used for obtaining the data. This can be used,
         ///     iterator context used for obtaining the data. This can be used,
         ///     for example, to get data from the NSEC3 namespace.
         ///     for example, to get data from the NSEC3 namespace.
@@ -986,7 +983,7 @@ public:
         /// \throw DataSourceError If there's a low-level error with the
         /// \throw DataSourceError If there's a low-level error with the
         ///     database or the database contains bad data.
         ///     database or the database contains bad data.
         FoundRRsets getRRsets(const std::string& name,
         FoundRRsets getRRsets(const std::string& name,
-                              const WantedTypes& types, bool check_ns,
+                              const WantedTypes& types,
                               const std::string* construct_name = NULL,
                               const std::string* construct_name = NULL,
                               bool any = false,
                               bool any = false,
                               DatabaseAccessor::IteratorContextPtr srcContext =
                               DatabaseAccessor::IteratorContextPtr srcContext =

+ 1 - 1
src/lib/datasrc/tests/Makefile.am

@@ -18,7 +18,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 noinst_PROGRAMS =
 noinst_PROGRAMS =

+ 24 - 13
src/lib/datasrc/tests/database_unittest.cc

@@ -168,13 +168,16 @@ const char* const TEST_RECORDS[][5] = {
     {"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
     {"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
      "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
      "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
 
 
-    // Broken NS
+    // Delegation NS and other ordinary type of RR coexist at the same
+    // name.  This is deviant (except for some special cases like the other
+    // RR could be used for addressing the NS name), but as long as the
+    // other records are hidden behind the delegation for normal queries
+    // it's not necessarily harmful. (so "broken" may be too strong, but we
+    // keep the name since it could be in a chain of sorted names for DNSSEC
+    // processing and renaming them may have other bad effects for tests).
     {"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
     {"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
     {"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
     {"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
 
 
-    {"brokenns2.example.org.", "NS", "3600", "", "ns.example.com."},
-    {"brokenns2.example.org.", "A", "3600", "", "192.0.2.1"},
-
     // Now double DNAME, to test failure mode
     // Now double DNAME, to test failure mode
     {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
     {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
     {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
     {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
@@ -2202,15 +2205,23 @@ TYPED_TEST(DatabaseClientTest, findDelegation) {
                               ZoneFinder::FIND_DEFAULT),
                               ZoneFinder::FIND_DEFAULT),
                  DataSourceError);
                  DataSourceError);
 
 
-    // Broken NS - it lives together with something else
-    EXPECT_THROW(finder->find(isc::dns::Name("brokenns1.example.org."),
-                              this->qtype_,
-                              ZoneFinder::FIND_DEFAULT),
-                 DataSourceError);
-    EXPECT_THROW(finder->find(isc::dns::Name("brokenns2.example.org."),
-                              this->qtype_,
-                              ZoneFinder::FIND_DEFAULT),
-                 DataSourceError);
+    // NS and other type coexist: deviant and not necessarily harmful.
+    // It should normally just result in DELEGATION; if GLUE_OK is specified,
+    // the other RR should be visible.
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back("ns.example.com");
+    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
+               RRType::NS(), this->rrttl_, ZoneFinder::DELEGATION,
+               this->expected_rdatas_, this->empty_rdatas_,
+               ZoneFinder::RESULT_DEFAULT);
+
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back("192.0.2.1");
+    doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
+               this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
+               this->expected_rdatas_, this->empty_rdatas_,
+               ZoneFinder::RESULT_DEFAULT, Name("brokenns1.example.org"),
+               ZoneFinder::FIND_GLUE_OK);
 }
 }
 
 
 TYPED_TEST(DatabaseClientTest, findDS) {
 TYPED_TEST(DatabaseClientTest, findDS) {

+ 0 - 13
src/lib/datasrc/tests/zone_finder_context_unittest.cc

@@ -208,13 +208,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegation) {
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationAtZoneCut) {
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationAtZoneCut) {
     // Similar to the previous case, but one of the NS addresses is at the
     // Similar to the previous case, but one of the NS addresses is at the
     // zone cut.
     // zone cut.
-
-    // XXX: the current database-based data source incorrectly rejects this
-    // setup (see #1771)
-    if (GetParam() == createSQLite3Client) {
-        return;
-    }
-
     ZoneFinderContextPtr ctx = finder_->find(Name("www.b.example.org"),
     ZoneFinderContextPtr ctx = finder_->find(Name("www.b.example.org"),
                                              RRType::SOA());
                                              RRType::SOA());
     EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
     EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
@@ -316,12 +309,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalMX) {
 }
 }
 
 
 TEST_P(ZoneFinderContextTest, getAdditionalMXAtZoneCut) {
 TEST_P(ZoneFinderContextTest, getAdditionalMXAtZoneCut) {
-    // XXX: the current database-based data source incorrectly rejects this
-    // setup (see #1771)
-    if (GetParam() == createSQLite3Client) {
-        return;
-    }
-
     ZoneFinderContextPtr ctx = finder_->find(Name("mxatcut.example.org."),
     ZoneFinderContextPtr ctx = finder_->find(Name("mxatcut.example.org."),
                                              RRType::MX());
                                              RRType::MX());
     EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
     EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);

+ 10 - 0
src/lib/datasrc/zone.h

@@ -376,6 +376,16 @@ public:
     ///   RRsets for that name are searched just like the normal case;
     ///   RRsets for that name are searched just like the normal case;
     ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
     ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
     ///   with the information of the highest zone cut will be returned.
     ///   with the information of the highest zone cut will be returned.
+    ///   Note: the term "glue" in the DNS protocol standard may sometimes
+    ///   cause confusion: some people use this term strictly for an address
+    ///   record (type AAAA or A) for the name used in the RDATA of an NS RR;
+    ///   some others seem to give it broader flexibility.  Nevertheless,
+    ///   in this API the "GLUE OK" simply means the search by find() can
+    ///   continue beyond a zone cut; the derived class implementation does
+    ///   not have to, and should not, check whether the type is an address
+    ///   record or whether the query name is pointed by some NS RR.
+    ///   It's up to the caller with which definition of "glue" the search
+    ///   result with this option should be used.
     /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
     /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
     ///   returned with the answer. It is allowed for the data source to
     ///   returned with the answer. It is allowed for the data source to
     ///   include them even when not requested.
     ///   include them even when not requested.

+ 82 - 12
src/lib/dhcp/iface_mgr.cc

@@ -18,6 +18,7 @@
 #include <string.h>
 #include <string.h>
 #include <netinet/in.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <arpa/inet.h>
+#include <sys/select.h>
 
 
 #include <dhcp/dhcp4.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/dhcp6.h>
@@ -121,7 +122,8 @@ bool IfaceMgr::Iface::delSocket(uint16_t sockfd) {
 
 
 IfaceMgr::IfaceMgr()
 IfaceMgr::IfaceMgr()
     :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
     :control_buf_len_(CMSG_SPACE(sizeof(struct in6_pktinfo))),
-     control_buf_(new char[control_buf_len_])
+     control_buf_(new char[control_buf_len_]),
+     session_socket_(INVALID_SOCKET), session_callback_(NULL)
 {
 {
 
 
     cout << "IfaceMgr initialization." << endl;
     cout << "IfaceMgr initialization." << endl;
@@ -230,11 +232,13 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
          iface!=ifaces_.end();
          iface!=ifaces_.end();
          ++iface) {
          ++iface) {
 
 
-        cout << "Trying interface " << iface->getFullName() << endl;
+        cout << "Trying opening socket on interface " << iface->getFullName() << endl;
 
 
         if (iface->flag_loopback_ ||
         if (iface->flag_loopback_ ||
             !iface->flag_up_ ||
             !iface->flag_up_ ||
             !iface->flag_running_) {
             !iface->flag_running_) {
+            cout << "Interface " << iface->getFullName()
+                 << " not suitable: is loopback, is down or not running" << endl;
             continue;
             continue;
         }
         }
 
 
@@ -685,35 +689,101 @@ IfaceMgr::send(const Pkt4Ptr& pkt)
 
 
 
 
 boost::shared_ptr<Pkt4>
 boost::shared_ptr<Pkt4>
-IfaceMgr::receive4() {
+IfaceMgr::receive4(uint32_t timeout) {
 
 
     const SocketInfo* candidate = 0;
     const SocketInfo* candidate = 0;
     IfaceCollection::const_iterator iface;
     IfaceCollection::const_iterator iface;
+
+    fd_set sockets;
+    FD_ZERO(&sockets);
+    int maxfd = 0;
+
+    stringstream names;
+
+    /// @todo: marginal performance optimization. We could create the set once
+    /// and then use its copy for select(). Please note that select() modifies
+    /// provided set to indicated which sockets have something to read.
     for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
     for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
 
 
-        /// @todo: rewrite this as part of #1555
         for (SocketCollection::const_iterator s = iface->sockets_.begin();
         for (SocketCollection::const_iterator s = iface->sockets_.begin();
              s != iface->sockets_.end(); ++s) {
              s != iface->sockets_.end(); ++s) {
 
 
-            // We don't want IPv6 addresses here.
-            if (s->addr_.getFamily() != AF_INET) {
-                continue;
+            // Only deal with IPv4 addresses.
+            if (s->addr_.getFamily() == AF_INET) {
+                names << s->sockfd_ << "(" << iface->getName() << ") ";
+
+                // Add this socket to listening set
+                FD_SET(s->sockfd_, &sockets);
+                if (maxfd < s->sockfd_) {
+                    maxfd = s->sockfd_;
+                }
             }
             }
+        }
+    }
 
 
-            // This address looks good.
-            if (!candidate) {
+    // if there is session socket registered...
+    if (session_socket_ != INVALID_SOCKET) {
+        // at it to the set as well
+        FD_SET(session_socket_, &sockets);
+        if (maxfd < session_socket_)
+            maxfd = session_socket_;
+        names << session_socket_ << "(session)";
+    }
+
+    /// @todo: implement sub-second precision one day
+    struct timeval select_timeout;
+    select_timeout.tv_sec = timeout;
+    select_timeout.tv_usec = 0;
+
+    cout << "Trying to receive data on sockets: " << names.str()
+         << ". Timeout is " << timeout << " seconds." << endl;
+    int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
+    cout << "select returned " << result << endl;
+
+    if (result == 0) {
+        // nothing received and timeout has been reached
+        return (Pkt4Ptr()); // NULL
+    } else if (result < 0) {
+        cout << "Socket read error: " << strerror(errno) << endl;
+
+        /// @todo: perhaps throw here?
+        return (Pkt4Ptr()); // NULL
+    }
+
+    // Let's find out which socket has the data
+    if ((session_socket_ != INVALID_SOCKET) && (FD_ISSET(session_socket_, &sockets))) {
+        // something received over session socket
+        cout << "BIND10 command or config available over session socket." << endl;
+
+        if (session_callback_) {
+            // in theory we could call io_service.run_one() here, instead of
+            // implementing callback mechanism, but that would introduce
+            // asiolink dependency to libdhcp++ and that is something we want
+            // to avoid (see CPE market and out long term plans for minimalistic
+            // implementations.
+            session_callback_();
+        }
+
+        return (Pkt4Ptr()); // NULL
+    }
+
+    // Let's find out which interface/socket has the data
+    for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
+        for (SocketCollection::const_iterator s = iface->sockets_.begin();
+             s != iface->sockets_.end(); ++s) {
+            if (FD_ISSET(s->sockfd_, &sockets)) {
                 candidate = &(*s);
                 candidate = &(*s);
                 break;
                 break;
             }
             }
         }
         }
-
         if (candidate) {
         if (candidate) {
             break;
             break;
         }
         }
     }
     }
 
 
     if (!candidate) {
     if (!candidate) {
-        isc_throw(Unexpected, "Failed to find any suitable sockets on all interfaces.");
+        cout << "Received data over unknown socket." << endl;
+        return (Pkt4Ptr()); // NULL
     }
     }
 
 
     cout << "Trying to receive over UDP4 socket " << candidate->sockfd_ << " bound to "
     cout << "Trying to receive over UDP4 socket " << candidate->sockfd_ << " bound to "
@@ -750,7 +820,7 @@ IfaceMgr::receive4() {
     m.msg_control = &control_buf_[0];
     m.msg_control = &control_buf_[0];
     m.msg_controllen = control_buf_len_;
     m.msg_controllen = control_buf_len_;
 
 
-    int result = recvmsg(candidate->sockfd_, &m, 0);
+    result = recvmsg(candidate->sockfd_, &m, 0);
     if (result < 0) {
     if (result < 0) {
         cout << "Failed to receive UDP4 data." << endl;
         cout << "Failed to receive UDP4 data." << endl;
         return (Pkt4Ptr()); // NULL
         return (Pkt4Ptr()); // NULL

+ 25 - 5
src/lib/dhcp/iface_mgr.h

@@ -39,6 +39,9 @@ public:
     /// type that defines list of addresses
     /// type that defines list of addresses
     typedef std::vector<isc::asiolink::IOAddress> AddressCollection;
     typedef std::vector<isc::asiolink::IOAddress> AddressCollection;
 
 
+    /// defines callback used when commands are received over control session
+    typedef void (*SessionCallback) (void);
+
     /// maximum MAC address length (Infiniband uses 20 bytes)
     /// maximum MAC address length (Infiniband uses 20 bytes)
     static const unsigned int MAX_MAC_LEN = 20;
     static const unsigned int MAX_MAC_LEN = 20;
 
 
@@ -351,12 +354,10 @@ public:
     /// If reception is successful and all information about its sender
     /// If reception is successful and all information about its sender
     /// are obtained, Pkt4 object is created and returned.
     /// are obtained, Pkt4 object is created and returned.
     ///
     ///
-    /// TODO Start using select() and add timeout to be able
-    /// to not wait infinitely, but rather do something useful
-    /// (e.g. remove expired leases)
+    /// @param timeout specifies timeout (in seconds)
     ///
     ///
     /// @return Pkt4 object representing received packet (or NULL)
     /// @return Pkt4 object representing received packet (or NULL)
-    Pkt4Ptr receive4();
+    Pkt4Ptr receive4(uint32_t timeout);
 
 
     /// Opens UDP/IP socket and binds it to address, interface and port.
     /// Opens UDP/IP socket and binds it to address, interface and port.
     ///
     ///
@@ -401,6 +402,21 @@ public:
     /// @return number of detected interfaces
     /// @return number of detected interfaces
     uint16_t countIfaces() { return ifaces_.size(); }
     uint16_t countIfaces() { return ifaces_.size(); }
 
 
+    /// @brief Sets session socket and a callback
+    ///
+    /// Specifies session socket and a callback that will be called
+    /// when data will be received over that socket.
+    ///
+    /// @param socketfd socket descriptor
+    /// @param callback callback function
+    void set_session_socket(int socketfd, SessionCallback callback) {
+        session_socket_ = socketfd;
+        session_callback_ = callback;
+    }
+
+    /// A value of socket descriptor representing "not specified" state.
+    static const int INVALID_SOCKET = -1;
+
     // don't use private, we need derived classes in tests
     // don't use private, we need derived classes in tests
 protected:
 protected:
 
 
@@ -487,7 +503,6 @@ protected:
     /// control-buffer, used in transmission and reception
     /// control-buffer, used in transmission and reception
     boost::scoped_array<char> control_buf_;
     boost::scoped_array<char> control_buf_;
 
 
-
     /// @brief A wrapper for OS-specific operations before sending IPv4 packet
     /// @brief A wrapper for OS-specific operations before sending IPv4 packet
     ///
     ///
     /// @param m message header (will be later used for sendmsg() call)
     /// @param m message header (will be later used for sendmsg() call)
@@ -505,6 +520,11 @@ protected:
     /// @return true if successful, false otherwise
     /// @return true if successful, false otherwise
     bool os_receive4(struct msghdr& m, Pkt4Ptr& pkt);
     bool os_receive4(struct msghdr& m, Pkt4Ptr& pkt);
 
 
+    /// socket descriptor of the session socket
+    int session_socket_;
+
+    /// a callback that will be called when data arrives over session_socket_
+    SessionCallback session_callback_;
 private:
 private:
 
 
     /// @brief Creates a single instance of this class (a singleton implementation)
     /// @brief Creates a single instance of this class (a singleton implementation)

+ 1 - 1
src/lib/dhcp/tests/Makefile.am

@@ -20,7 +20,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 51 - 2
src/lib/dhcp/tests/iface_mgr_unittest.cc

@@ -7,7 +7,7 @@
 // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 // 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
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
@@ -17,6 +17,7 @@
 #include <fstream>
 #include <fstream>
 #include <sstream>
 #include <sstream>
 
 
+#include <unistd.h>
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
@@ -381,7 +382,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
 
 
     EXPECT_EQ(true, ifacemgr->send(sendPkt));
     EXPECT_EQ(true, ifacemgr->send(sendPkt));
 
 
-    rcvPkt = ifacemgr->receive4();
+    rcvPkt = ifacemgr->receive4(10);
 
 
     ASSERT_TRUE(rcvPkt); // received our own packet
     ASSERT_TRUE(rcvPkt); // received our own packet
 
 
@@ -899,4 +900,52 @@ TEST_F(IfaceMgrTest, DISABLED_detectIfaces_linux) {
 }
 }
 #endif
 #endif
 
 
+volatile bool callback_ok;
+
+void my_callback(void) {
+    cout << "Callback triggered." << endl;
+    callback_ok = true;
+}
+
+TEST_F(IfaceMgrTest, controlSession) {
+    // tests if extra control socket and its callback can be passed and
+    // it is supported properly by receive4() method.
+
+    callback_ok = false;
+
+    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+
+    // create pipe and register it as extra socket
+    int pipefd[2];
+    EXPECT_TRUE(pipe(pipefd) == 0);
+    EXPECT_NO_THROW(ifacemgr->set_session_socket(pipefd[0], my_callback));
+
+    Pkt4Ptr pkt4;
+    pkt4 = ifacemgr->receive4(1);
+
+    // Our callback should not be called this time (there was no data)
+    EXPECT_FALSE(callback_ok);
+
+    // IfaceMgr should not process control socket data as incoming packets
+    EXPECT_FALSE(pkt4);
+
+    // Now, send some data over pipe (38 bytes)
+    EXPECT_EQ(38, write(pipefd[1], "Hi, this is a message sent over a pipe", 38));
+
+    // ... and repeat
+    pkt4 = ifacemgr->receive4(1);
+
+    // IfaceMgr should not process control socket data as incoming packets
+    EXPECT_FALSE(pkt4);
+
+    // There was some data, so this time callback should be called
+    EXPECT_TRUE(callback_ok);
+
+    delete ifacemgr;
+
+    // close both pipe ends
+    close(pipefd[1]);
+    close(pipefd[0]);
+}
+
 }
 }

+ 1 - 1
src/lib/dns/tests/Makefile.am

@@ -15,7 +15,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/exceptions/tests/Makefile.am

@@ -10,7 +10,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/log/tests/Makefile.am

@@ -48,7 +48,7 @@ logger_lock_test_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
 logger_lock_test_LDADD += $(AM_LDADD) $(LOG4CPLUS_LIBS)
 logger_lock_test_LDADD += $(AM_LDADD) $(LOG4CPLUS_LIBS)
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 if HAVE_GTEST
 if HAVE_GTEST
 TESTS =
 TESTS =

+ 1 - 1
src/lib/nsas/tests/Makefile.am

@@ -26,7 +26,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-	libtool --mode=execute $(VALGRIND_COMMAND)
+	$(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/resolve/tests/Makefile.am

@@ -9,7 +9,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/server_common/tests/Makefile.am

@@ -23,7 +23,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/statistics/tests/Makefile.am

@@ -16,7 +16,7 @@ AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/util/tests/Makefile.am

@@ -16,7 +16,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 1 - 1
src/lib/xfr/tests/Makefile.am

@@ -9,7 +9,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 6 - 0
tests/lettuce/configurations/DO_NOT_USE_127.0.0.1:47807

@@ -0,0 +1,6 @@
+Note well:
+
+In some configuration we intentionally use an IPv6 address (::1) with
+port 47807.  DO NOT CHANGE THAT; at least do not change it to
+127.0.0.1:47807.  See git e3f4b290d17a68db728166cdffcbe93517966e8b
+for why.

+ 0 - 4
tests/lettuce/configurations/NOTES

@@ -1,4 +0,0 @@
-- In some configuration we intentionally use an IPv6 address (::1) with
-  port 47807.  DO NOT CHANGE THAT; at least do not change it to
-  127.0.0.1:47807.  See git e3f4b290d17a68db728166cdffcbe93517966e8b
-  for why.

+ 1 - 0
tests/lettuce/data/example.org

@@ -10,3 +10,4 @@ dname.example.org.	3600	IN	DNAME	dname.example.info.
 dname2.foo.example.org.	3600	IN	DNAME	dname2.example.info.
 dname2.foo.example.org.	3600	IN	DNAME	dname2.example.info.
 ns1.example.org.	3600	IN	A	192.0.2.3
 ns1.example.org.	3600	IN	A	192.0.2.3
 ns2.example.org.	3600	IN	A	192.0.2.4
 ns2.example.org.	3600	IN	A	192.0.2.4
+shell.example.org.	3600	IN	SSHFP	2 1 123456789abcdef67890123456789abcdef67890

+ 25 - 0
tests/lettuce/features/queries.feature

@@ -103,6 +103,7 @@ Feature: Querying feature
         ns2.example.org.        3600    IN      A       192.0.2.4
         ns2.example.org.        3600    IN      A       192.0.2.4
         mail.example.org.       3600    IN      A       192.0.2.10
         mail.example.org.       3600    IN      A       192.0.2.10
         """
         """
+
     Scenario: Delegation query for unsigned child zone
     Scenario: Delegation query for unsigned child zone
         Given I have bind10 running with configuration example.org.inmem.config
         Given I have bind10 running with configuration example.org.inmem.config
         And wait for bind10 stderr message BIND10_STARTED_CC
         And wait for bind10 stderr message BIND10_STARTED_CC
@@ -122,3 +123,27 @@ Feature: Querying feature
         """
         """
         ns.sub.example.org.	3600	IN	A	192.0.2.101
         ns.sub.example.org.	3600	IN	A	192.0.2.101
         """
         """
+
+    Scenario: SSHFP query
+        # We are testing one more RR type for a normal successful case
+        Given I have bind10 running with configuration example.org.inmem.config
+        And wait for bind10 stderr message BIND10_STARTED_CC
+        And wait for bind10 stderr message CMDCTL_STARTED
+        And wait for bind10 stderr message AUTH_SERVER_STARTED
+
+        bind10 module Auth should be running
+        And bind10 module Resolver should not be running
+        And bind10 module Xfrout should not be running
+        And bind10 module Zonemgr should not be running
+        And bind10 module Xfrin should not be running
+        And bind10 module Stats should not be running
+        And bind10 module StatsHttpd should not be running
+
+        A query for example.org type SSHFP should have rcode NOERROR
+        The last query response should have ancount 0
+        A query for shell.example.org type SSHFP should have rcode NOERROR
+        The last query response should have ancount 1
+        The answer section of the last query response should be
+        """
+        shell.example.org.      3600    IN      SSHFP   2 1 123456789abcdef67890123456789abcdef67890
+        """

+ 1 - 1
tests/tools/badpacket/tests/Makefile.am

@@ -11,7 +11,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST

+ 18 - 0
tests/tools/perfdhcp/command_options.cc

@@ -88,7 +88,25 @@ CommandOptions::parse(int argc, char** const argv) {
     // Reset internal variables used by getopt
     // Reset internal variables used by getopt
     // to eliminate undefined behavior when
     // to eliminate undefined behavior when
     // parsing different command lines multiple times
     // parsing different command lines multiple times
+
+#ifdef __GLIBC__
+    // Warning: non-portable code. This is due to a bug in glibc's
+    // getopt() which keeps internal state about an old argument vector
+    // (argc, argv) from last call and tries to scan them when a new
+    // argument vector (argc, argv) is passed. As the old vector may not
+    // be main()'s arguments, but heap allocated and may have been freed
+    // since, this becomes a use after free and results in random
+    // behavior. According to the NOTES section in glibc getopt()'s
+    // manpage, setting optind=0 resets getopt()'s state. Though this is
+    // not required in our usage of getopt(), the bug still happens
+    // unless we set optind=0.
+    //
+    // Setting optind=0 is non-portable code.
+    optind = 0;
+#else
     optind = 1;
     optind = 1;
+#endif
+
     opterr = 0;
     opterr = 0;
 
 
     // Reset values of class members
     // Reset values of class members

+ 1 - 1
tests/tools/perfdhcp/tests/Makefile.am

@@ -11,7 +11,7 @@ endif
 CLEANFILES = *.gcno *.gcda
 CLEANFILES = *.gcno *.gcda
 
 
 TESTS_ENVIRONMENT = \
 TESTS_ENVIRONMENT = \
-        libtool --mode=execute $(VALGRIND_COMMAND)
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
 
 
 TESTS =
 TESTS =
 if HAVE_GTEST
 if HAVE_GTEST