Browse Source

[master]Merge branch 'master' of ssh://git.bind10.isc.org//var/bind10/git/bind10

Jeremy C. Reed 12 years ago
parent
commit
07d2d30929
100 changed files with 1594 additions and 8759 deletions
  1. 24 1
      ChangeLog
  2. 2 2
      configure.ac
  3. 91 19
      doc/guide/bind10-guide.xml
  4. 0 6
      src/bin/auth/Makefile.am
  5. 0 3
      src/bin/auth/auth_srv.cc
  6. 0 6
      src/bin/auth/benchmarks/Makefile.am
  7. 0 7
      src/bin/auth/tests/Makefile.am
  8. 7 3
      src/bin/auth/tests/auth_srv_unittest.cc
  9. 10 0
      src/bin/dhcp4/dhcp4_messages.mes
  10. 12 2
      src/bin/dhcp4/dhcp4_srv.cc
  11. 10 0
      src/bin/dhcp6/dhcp6_messages.mes
  12. 12 2
      src/bin/dhcp6/dhcp6_srv.cc
  13. 0 4
      src/lib/acl/dns.h
  14. 13 1
      src/lib/acl/tests/dns_test.cc
  15. 3 6
      src/lib/datasrc/Makefile.am
  16. 0 396
      src/lib/datasrc/cache.cc
  17. 0 223
      src/lib/datasrc/cache.h
  18. 45 22
      src/lib/datasrc/client_list.cc
  19. 43 15
      src/lib/datasrc/client_list.h
  20. 0 1434
      src/lib/datasrc/data_source.cc
  21. 0 362
      src/lib/datasrc/data_source.h
  22. 1 1
      src/lib/datasrc/memory/Makefile.am
  23. 95 21
      src/lib/datasrc/memory/domaintree.h
  24. 32 24
      src/lib/datasrc/memory/memory_client.cc
  25. 11 12
      src/lib/datasrc/memory/memory_client.h
  26. 22 17
      src/lib/datasrc/memory/treenode_rrset.cc
  27. 0 2
      src/lib/datasrc/memory/treenode_rrset.h
  28. 421 59
      src/lib/datasrc/memory/zone_finder.cc
  29. 10 28
      src/lib/datasrc/memory/zone_finder.h
  30. 0 116
      src/lib/datasrc/query.cc
  31. 0 255
      src/lib/datasrc/query.h
  32. 0 917
      src/lib/datasrc/sqlite3_datasrc.cc
  33. 0 130
      src/lib/datasrc/sqlite3_datasrc.h
  34. 0 275
      src/lib/datasrc/static_datasrc.cc
  35. 0 95
      src/lib/datasrc/static_datasrc.h
  36. 1 18
      src/lib/datasrc/tests/Makefile.am
  37. 0 340
      src/lib/datasrc/tests/cache_unittest.cc
  38. 91 60
      src/lib/datasrc/tests/client_list_unittest.cc
  39. 0 1209
      src/lib/datasrc/tests/datasrc_unittest.cc
  40. 17 0
      src/lib/datasrc/tests/faked_nsec3.cc
  41. 4 0
      src/lib/datasrc/tests/faked_nsec3.h
  42. 0 0
      src/lib/datasrc/tests/memory/.gitignore
  43. 1 2
      src/lib/datasrc/memory/tests/Makefile.am
  44. 62 0
      src/lib/datasrc/memory/tests/domaintree_unittest.cc
  45. 43 33
      src/lib/datasrc/memory/tests/memory_client_unittest.cc
  46. 0 0
      src/lib/datasrc/tests/memory/memory_segment_test.h
  47. 1 1
      src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc
  48. 0 0
      src/lib/datasrc/tests/memory/rdataset_unittest.cc
  49. 0 0
      src/lib/datasrc/tests/memory/run_unittests.cc
  50. 0 0
      src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc
  51. 1 0
      src/lib/datasrc/memory/tests/testdata/Makefile.am
  52. 0 0
      src/lib/datasrc/tests/memory/testdata/empty.zone
  53. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-broken1.zone
  54. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-broken2.zone
  55. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-1.zone
  56. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-2.zone
  57. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-1.zone
  58. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-2.zone
  59. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-1.zone
  60. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-2.zone
  61. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type-bad.zone
  62. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone
  63. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-empty.zone
  64. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-multiple-cname.zone
  65. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-multiple-dname.zone
  66. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3.zone
  67. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3param.zone
  68. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone
  69. 14 0
      src/lib/datasrc/tests/memory/testdata/example.org-nsec3-empty-salt.zone
  70. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-nsec3-fewer-labels.zone
  71. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-nsec3-more-labels.zone
  72. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed-no-param.zone
  73. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed.zone
  74. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-out-of-zone.zone
  75. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone
  76. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone
  77. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-wildcard-dname.zone
  78. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-wildcard-ns.zone
  79. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org-wildcard-nsec3.zone
  80. 0 0
      src/lib/datasrc/tests/memory/testdata/example.org.zone
  81. 49 9
      src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc
  82. 0 0
      src/lib/datasrc/tests/memory/zone_data_unittest.cc
  83. 236 113
      src/lib/datasrc/memory/tests/zone_finder_unittest.cc
  84. 0 0
      src/lib/datasrc/tests/memory/zone_table_unittest.cc
  85. 0 66
      src/lib/datasrc/tests/memory_datasrc_unittest.cc
  86. 0 71
      src/lib/datasrc/tests/query_unittest.cc
  87. 0 950
      src/lib/datasrc/tests/sqlite3_unittest.cc
  88. 0 422
      src/lib/datasrc/tests/static_unittest.cc
  89. 0 657
      src/lib/datasrc/tests/test_datasrc.cc
  90. 0 111
      src/lib/datasrc/tests/test_datasrc.h
  91. 4 1
      src/lib/datasrc/tests/testdata/contexttest.zone
  92. 27 12
      src/lib/datasrc/tests/zone_finder_context_unittest.cc
  93. 64 170
      src/lib/dhcp/iface_mgr.cc
  94. 40 0
      src/lib/dhcp/iface_mgr.h
  95. 1 8
      src/lib/dhcp/iface_mgr_linux.cc
  96. 4 13
      src/lib/dhcp/libdhcp++.cc
  97. 0 2
      src/lib/dhcp/pkt4.cc
  98. 4 6
      src/lib/dhcp/pkt6.cc
  99. 66 19
      src/lib/dhcp/tests/iface_mgr_unittest.cc
  100. 0 0
      src/lib/dns/labelsequence.cc

+ 24 - 1
ChangeLog

@@ -1,7 +1,30 @@
+482.	[func]		team
+	Memory footprint of the in-memory data source has been
+	substantially improved.  For example, b10-auth now requires much
+	less memory than BIND 9 named for loading and serving the same
+	zone in-memory.  This is a transparent change in terms of user
+	operation; there's no need to update or change the configuration
+	to enable this feature.
+	Notes: multiple instances of b10-auth still make separate copies
+	of the memory image.  Also, loading zones in memory still suspends
+	query processing, so manual reloading or reloading after incoming
+	transfer may cause service disruption for huge zones.
+	(Multiple Trac tickets)
+
+481.	[bug]		vorner
+	The abbreviated form of IP addresses in ACLs is accepted
+	(eg. "from": ["127.0.01", "::1"] now works).
+	(Trac #2191, git 48b6e91386b46eed383126ad98dddfafc9f7e75e)
+
+480.	[doc]		vorner
+	Added documentation about global TSIG key ring to the Guide.
+	(Trac #2189, git 52177bb31f5fb8e134aecb9fd039c368684ad2df)
+
 479.	[func]		marcin
 	Refactored perfdhcp tool to C++, added missing unit tests and removed
 	the old code. The new code uses libdhcp++ (src/lib/dhcp) for DHCP
-	packet management, network interface management and packet transmission.
+	packet management, network interface management and packet
+	transmission.
 	(Trac #1954, git 8d56105742f3043ed4b561f26241f3e4331f51dc)
 	(Trac #1955, git 6f914bb2c388eb4dd3e5c55297f8988ab9529b3f)
 	(Trac #1956, git 6f914bb2c388eb4dd3e5c55297f8988ab9529b3f)

+ 2 - 2
configure.ac

@@ -1193,11 +1193,11 @@ AC_CONFIG_FILES([Makefile
                  src/lib/exceptions/tests/Makefile
                  src/lib/datasrc/Makefile
                  src/lib/datasrc/memory/Makefile
-                 src/lib/datasrc/memory/tests/Makefile
-                 src/lib/datasrc/memory/tests/testdata/Makefile
                  src/lib/datasrc/memory/benchmarks/Makefile
                  src/lib/datasrc/tests/Makefile
                  src/lib/datasrc/tests/testdata/Makefile
+                 src/lib/datasrc/tests/memory/Makefile
+                 src/lib/datasrc/tests/memory/testdata/Makefile
                  src/lib/xfr/Makefile
                  src/lib/xfr/tests/Makefile
                  src/lib/log/Makefile

+ 91 - 19
doc/guide/bind10-guide.xml

@@ -1310,6 +1310,89 @@ TODO
       many modules. So we show them here in one place.
     </para>
 
+    <section id='common-tsig'>
+      <title>TSIG keys</title>
+
+      <para>
+        TSIG is a way to sign requests and responses in DNS. It is defined in
+        RFC 2845 and uses symmetric cryptography to sign the DNS messages. If
+        you want to make any use of TSIG (to authenticate transfers or DDNS,
+        for example), you need to set up shared secrets between the endpoints.
+      </para>
+
+      <para>
+        BIND 10 uses a global key ring for the secrets. It doesn't currently
+        mean they would be stored differently, they are just in one place of
+        the configuration.
+      </para>
+
+      <section id='tsig-key-syntax'>
+        <title>Key anatomy and syntax</title>
+
+        <para>
+          Each key has three attributes. One is a name by which it is referred
+          both in DNS packets and the rest of the configuration. Another is the
+          algorithm used to compute the signature. And the last part is a
+          base64 encoded secret, which might be any blob of data.
+        </para>
+
+        <para>
+          The parts are written into a string, concatenated together by colons.
+          So if you wanted to have a key called "example.key", used as a
+          HMAC-MD5 key with secret "secret", you'd write it as:
+<screen>"example.key.:c2VjcmV0:hmac-md5"</screen>
+        </para>
+
+        <para>
+          The HMAC-MD5 algorithm is the default, so you can omit it. You could
+          write the same key as:
+<screen>"example.key.:c2VjcmV0"</screen>
+        </para>
+
+        <para>
+          You can also use these algorithms (which may not be omitted from the
+          key definition if used):
+          <itemizedlist>
+            <listitem>hmac-sha1</listitem>
+            <listitem>hmac-sha224</listitem>
+            <listitem>hmac-sha256</listitem>
+            <listitem>hmac-sha384</listitem>
+            <listitem>hmac-sha512</listitem>
+          </itemizedlist>
+        </para>
+
+        <para>
+          The name of the key must be a valid DNS name.
+        </para>
+      </section>
+
+      <section id='tsig-key-ring'>
+        <title>Key ring</title>
+        <para>
+          The key ring lives in the configuration in "tsig_keys/keys". Most of
+          the system uses the keys from there &mdash; ACLs, authoritative server to
+          sign responses to signed queries, and <command>b10-xfrout</command>
+          to sign transfers. The <command>b10-xfrin</command> uses its own
+          configuration for keys, but that will be fixed in Trac ticket
+          <ulink url="http://bind10.isc.org/ticket/1351">#1351</ulink>.
+        </para>
+
+        <para>
+          The key ring is just a list of strings, each describing one key. So,
+          to add a new key, you can do this:
+          <screen>&gt; <userinput>config add tsig_keys/keys "example.key.:c2VjcmV0"</userinput>
+&gt; <userinput>config show tsig_keys/keys</userinput>
+tsig_keys/keys[0]   "example.key.:c2VjcmV0" string  (modified)
+&gt; <userinput>config commit</userinput></screen>
+        </para>
+
+        <para>
+          You can keep as many keys as you want in the key ring, but each must
+          have a different name.
+        </para>
+      </section>
+    </section>
+
     <section id='common-acl'>
       <title>ACLs</title>
 
@@ -1375,9 +1458,9 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
         <para>
           The other is TSIG key by which the message was signed. The ACL
           contains only the name (under the name "key"), the key itself
-          must be stored in the global keyring. This property is applicable only
-          to the DNS context.
-<!-- TODO: Section for the keyring and link to it.-->
+	  must be stored in the global key ring (see <xref
+	  linkend="tsig-key-ring"/>).
+          This property is applicable only to the DNS context.
         </para>
 
         <para>
@@ -1403,18 +1486,6 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
           will work in a similar way.
         </para>
 
-        <note>
-          <simpara>
-	    The list form is currently rejected due to an
-	    implementation bug.  There is a plan to fix it relatively
-	    soon, so the syntax is kept here, but note that it won't
-	    work until the bug is fixed.  To keep track of the status
-	    of the issue, see
-	    <ulink url="http://bind10.isc.org/ticket/2191">Trac #2191</ulink>.
-	    Until then, the value must be a single string.
-          </simpara>
-        </note>
-
         <para>
           If that is not enough, you can compose the matching conditions
           to logical expressions. They are called "ANY", "ALL" and "NOT".
@@ -2151,7 +2222,7 @@ Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)</screen>
 
     <para>
       If you want to require TSIG in access control, a system wide TSIG
-      "key ring" must be configured.
+      key ring must be configured (see <xref linkend="tsig-key-ring"/>).
       In this example, we allow client matching both the IP address
       and key.
     </para>
@@ -2161,7 +2232,7 @@ Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)</screen>
 &gt; <userinput>config commit</userinput></screen>
 
     <para>Both <command>b10-xfrout</command> and <command>b10-auth</command>
-      will use the system wide keyring to check
+      will use the system wide key ring to check
       TSIGs in the incoming messages and to sign responses.</para>
 
     <para>
@@ -2371,11 +2442,12 @@ what is XfroutClient xfr_client??
 &gt; <userinput>config commit</userinput>
 </screen>
       The TSIG key must be configured system wide
-      (see <xref linkend="xfrout"/>.)
+      (see <xref linkend="common-tsig"/>).
       </para>
 
       <para>
-        Full description of ACLs can be found in <xref linkend="common-acl" />.
+	The full description of ACLs can be found in <xref
+	linkend="common-acl" />.
       </para>
 
       <note><simpara>

+ 0 - 6
src/bin/auth/Makefile.am

@@ -57,12 +57,6 @@ b10_auth_SOURCES += common.h common.cc
 b10_auth_SOURCES += statistics.cc statistics.h
 b10_auth_SOURCES += datasrc_configurator.h
 b10_auth_SOURCES += main.cc
-# This is a temporary workaround for #1206, where the InMemoryClient has been
-# moved to an ldopened library. We could add that library to LDADD, but that
-# is nonportable. This should've been moot after #1207, but there is still
-# one dependency; the in-memory-specific zone loader call is still in
-# auth.
-b10_auth_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
 
 nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
 EXTRA_DIST += auth_messages.mes

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

@@ -41,10 +41,7 @@
 
 #include <asiodns/dns_service.h>
 
-#include <datasrc/query.h>
 #include <datasrc/data_source.h>
-#include <datasrc/static_datasrc.h>
-#include <datasrc/sqlite3_datasrc.h>
 #include <datasrc/client_list.h>
 
 #include <xfr/xfrout_client.h>

+ 0 - 6
src/bin/auth/benchmarks/Makefile.am

@@ -17,12 +17,6 @@ query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
 query_bench_SOURCES += ../auth_config.h ../auth_config.cc
 query_bench_SOURCES += ../statistics.h ../statistics.cc
 query_bench_SOURCES += ../auth_log.h ../auth_log.cc
-# This is a temporary workaround for #1206, where the InMemoryClient has been
-# moved to an ldopened library. We could add that library to LDADD, but that
-# is nonportable. When #1207 is done this becomes moot anyway, and the
-# specific workaround is not needed anymore, so we can then remove this
-# line again.
-query_bench_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
 
 nodist_query_bench_SOURCES = ../auth_messages.h ../auth_messages.cc
 

+ 0 - 7
src/bin/auth/tests/Makefile.am

@@ -52,13 +52,6 @@ run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += statistics_unittest.cc
 run_unittests_SOURCES += datasrc_configurator_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
-# This is a temporary workaround for #1206, where the InMemoryClient has been
-# moved to an ldopened library. We could add that library to LDADD, but that
-# is nonportable. This should've been moot after #1207, but there is still
-# one dependency; the in-memory-specific zone loader call is still in
-# auth.
-run_unittests_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
-
 
 nodist_run_unittests_SOURCES = ../auth_messages.h ../auth_messages.cc
 

+ 7 - 3
src/bin/auth/tests/auth_srv_unittest.cc

@@ -15,6 +15,7 @@
 #include <config.h>
 
 #include <util/io/sockaddr_util.h>
+#include <util/memory_segment_local.h>
 
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
@@ -1393,16 +1394,19 @@ public:
              const isc::datasrc::DataSourceClientPtr
                  client(new FakeClient(info.data_src_client_ != NULL ?
                                        info.data_src_client_ :
-                                       info.cache_.get(),
+                                       info.getCacheClient(),
                                        throw_when, isc_exception, fake_rrset));
              clients_.push_back(client);
-             data_sources_.push_back(DataSourceInfo(client.get(),
-                 isc::datasrc::DataSourceClientContainerPtr(), false));
+             data_sources_.push_back(
+                 DataSourceInfo(client.get(),
+                                isc::datasrc::DataSourceClientContainerPtr(),
+                                false, RRClass::IN(), mem_sgmt_));
         }
     }
 private:
     const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
     vector<isc::datasrc::DataSourceClientPtr> clients_;
+    MemorySegmentLocal mem_sgmt_;
 };
 
 } // end anonymous namespace for throwing proxy classes

+ 10 - 0
src/bin/dhcp4/dhcp4_messages.mes

@@ -42,12 +42,22 @@ server is about to open sockets on the specified port.
 The IPv4 DHCP server has received a packet that it is unable to
 interpret. The reason why the packet is invalid is included in the message.
 
+% DHCP4_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
+The IPv4 DHCP server tried to receive a packet but an error
+occured during this attempt. The reason for the error is included in
+the message.
+
 % DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3
 A debug message noting that the server has received the specified type of
 packet on the specified interface.  Note that a packet marked as UNKNOWN
 may well be a valid DHCP packet, just a type not expected by the server
 (e.g. it will report a received OFFER packet as UNKNOWN).
 
+% DHCP4_PACKET_SEND_FAIL failed to send DHCPv4 packet: %1
+This error is output if the IPv4 DHCP server fails to send an assembled
+DHCP message to a client. The reason for the error is included in the
+message.
+
 % DHCP4_PACK_FAIL failed to assemble response correctly
 This error is output if the server failed to assemble the data to be
 returned to the client into a valid packet.  The cause is most likely

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

@@ -73,9 +73,15 @@ Dhcpv4Srv::run() {
         int timeout = 1000;
 
         // client's message and server's response
-        Pkt4Ptr query = IfaceMgr::instance().receive4(timeout);
+        Pkt4Ptr query;
         Pkt4Ptr rsp;
 
+        try {
+            query = IfaceMgr::instance().receive4(timeout);
+        } catch (const std::exception& e) {
+            LOG_ERROR(dhcp4_logger, DHCP4_PACKET_RECEIVE_FAIL).arg(e.what());
+        }
+
         if (query) {
             try {
                 query->unpack();
@@ -141,7 +147,11 @@ Dhcpv4Srv::run() {
                           .arg(rsp->getType()).arg(rsp->toText());
 
                 if (rsp->pack()) {
-                    IfaceMgr::instance().send(rsp);
+                    try {
+                        IfaceMgr::instance().send(rsp);
+                    } catch (const std::exception& e) {
+                        LOG_ERROR(dhcp4_logger, DHCP4_PACKET_SEND_FAIL).arg(e.what());
+                    }
                 } else {
                     LOG_ERROR(dhcp4_logger, DHCP4_PACK_FAIL);
                 }

+ 10 - 0
src/bin/dhcp6/dhcp6_messages.mes

@@ -45,12 +45,22 @@ server is about to open sockets on the specified port.
 % DHCP6_PACKET_PARSE_FAIL failed to parse incoming packet
 The IPv6 DHCP server has received a packet that it is unable to interpret.
 
+% DHCP6_PACKET_RECEIVE_FAIL error on attempt to receive packet: %1
+The IPv6 DHCP server tried to receive a packet but an error
+occured during this attempt. The reason for the error is included in
+the message.
+
 % DHCP6_PACKET_RECEIVED %1 (type %2) packet received
 A debug message noting that the server has received the specified type
 of packet.  Note that a packet marked as UNKNOWN may well be a valid
 DHCP packet, just a type not expected by the server (e.g. it will report
 a received OFFER packet as UNKNOWN).
 
+% DHCP6_PACKET_SEND_FAIL failed to send DHCPv6 packet: %1
+This error is output if the IPv6 DHCP server fails to send an assembled
+DHCP message to a client. The reason for the error is included in the
+message.
+
 % DHCP6_PACK_FAIL failed to assemble response correctly
 This error is output if the server failed to assemble the data to be
 returned to the client into a valid packet.  The reason is most likely

+ 12 - 2
src/bin/dhcp6/dhcp6_srv.cc

@@ -84,9 +84,15 @@ bool Dhcpv6Srv::run() {
         int timeout = 1000;
 
         // client's message and server's response
-        Pkt6Ptr query = IfaceMgr::instance().receive6(timeout);
+        Pkt6Ptr query;
         Pkt6Ptr rsp;
 
+        try {
+            query = IfaceMgr::instance().receive6(timeout);
+        } catch (const std::exception& e) {
+            LOG_ERROR(dhcp6_logger, DHCP6_PACKET_RECEIVE_FAIL).arg(e.what());
+        }
+
         if (query) {
             if (!query->unpack()) {
                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
@@ -154,7 +160,11 @@ bool Dhcpv6Srv::run() {
                           .arg(rsp->getType()).arg(rsp->toText());
 
                 if (rsp->pack()) {
-                    IfaceMgr::instance().send(rsp);
+                    try {
+                        IfaceMgr::instance().send(rsp);
+                    } catch (const std::exception& e) {
+                        LOG_ERROR(dhcp6_logger, DHCP6_PACKET_SEND_FAIL).arg(e.what());
+                    }
                 } else {
                     LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL);
                 }

+ 0 - 4
src/lib/acl/dns.h

@@ -136,10 +136,6 @@ public:
     virtual boost::shared_ptr<RequestCheck>
     create(const std::string& name, isc::data::ConstElementPtr definition,
            const acl::Loader<RequestContext>& loader);
-
-    /// Until we are sure how the various rules work for this case, we won't
-    /// allow unexpected special interpretation for list definitions.
-    virtual bool allowListAbbreviation() const { return (false); }
 };
 } // end of namespace "internal"
 

+ 13 - 1
src/lib/acl/tests/dns_test.cc

@@ -62,6 +62,18 @@ TEST(DNSACL, getRequestLoader) {
                                               "  \"from\": \"192.0.2.1\"}]")));
 }
 
+// Check we can abbreviate the IP address lists and TSIG keys
+TEST(DNSACL, abbreviated) {
+    dns::RequestLoader* l(&getRequestLoader());
+
+    EXPECT_NO_THROW(l->load(Element::fromJSON("[{\"action\": \"DROP\","
+                                              "  \"from\": [\"127.0.0.1\","
+                                              "             \"::1\"]}]")));
+    EXPECT_NO_THROW(l->load(Element::fromJSON("[{\"action\": \"DROP\","
+                                              "  \"key\": [\"key.example.\","
+                                              "            \"other.\"]}]")));
+}
+
 class RequestCheckCreatorTest : public ::testing::Test {
 protected:
     dns::internal::RequestCheckCreator creator_;
@@ -78,7 +90,7 @@ TEST_F(RequestCheckCreatorTest, names) {
 }
 
 TEST_F(RequestCheckCreatorTest, allowListAbbreviation) {
-    EXPECT_FALSE(creator_.allowListAbbreviation());
+    EXPECT_TRUE(creator_.allowListAbbreviation());
 }
 
 // The following two tests check the creator for the form of

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

@@ -1,4 +1,4 @@
-SUBDIRS = . memory tests
+SUBDIRS = memory . tests
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
@@ -21,11 +21,7 @@ CLEANFILES += datasrc_config.h
 CLEANFILES += static.zone
 
 lib_LTLIBRARIES = libb10-datasrc.la
-libb10_datasrc_la_SOURCES = data_source.h data_source.cc
-libb10_datasrc_la_SOURCES += static_datasrc.h static_datasrc.cc
-libb10_datasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
-libb10_datasrc_la_SOURCES += query.h query.cc
-libb10_datasrc_la_SOURCES += cache.h cache.cc
+libb10_datasrc_la_SOURCES = data_source.h
 libb10_datasrc_la_SOURCES += rbnode_rrset.h
 libb10_datasrc_la_SOURCES += rbtree.h
 libb10_datasrc_la_SOURCES += zonetable.h zonetable.cc
@@ -64,6 +60,7 @@ libb10_datasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/cc/libb10-cc.la
+libb10_datasrc_la_LIBADD += $(builddir)/memory/libdatasrc_memory.la
 libb10_datasrc_la_LIBADD += $(SQLITE_LIBS)
 
 BUILT_SOURCES = datasrc_config.h datasrc_messages.h datasrc_messages.cc

+ 0 - 396
src/lib/datasrc/cache.cc

@@ -1,396 +0,0 @@
-// Copyright (C) 2010  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 <stdint.h>
-
-#include <map>
-
-#include <dns/question.h>
-#include <dns/rrclass.h>
-#include <dns/rrset.h>
-#include <dns/rrtype.h>
-
-#include <list>
-
-#include <datasrc/cache.h>
-#include <datasrc/logger.h>
-
-using namespace std;
-using namespace isc::dns;
-
-namespace isc {
-namespace datasrc {
-
-/// \brief A \c CacheEntry object contains the data stored with
-/// each \c CacheNode: a pointer to the cached RRset (empty in
-/// the case of a negative cache entry), and a copy of the
-/// query-response flags that were returned when the RRset
-/// was originally looked up in the low-level data source.
-class CacheEntry {
-private:
-    /// The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    CacheEntry(const CacheEntry& source);
-    CacheEntry& operator=(const CacheEntry& source);
-
-public:
-    CacheEntry(RRsetPtr r, uint32_t f) : rrset(r), flags(f) {};
-
-    RRsetPtr rrset;
-    uint32_t flags;
-};
-
-typedef boost::shared_ptr<CacheEntry> CacheEntryPtr;
-
-/// \brief A \c CacheNode is a node in the \c HotCache LRU queue.  It
-/// contains a pointer to a \c CacheEntry, a reference to the \c Question
-/// that we are answering, a lifespan during which this entry remains
-/// valid, and pointers to the next and previous entries in the list.
-class CacheNode {
-private:
-    /// \name Constructors and Assignment Operator
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    //@{
-    CacheNode(const CacheNode& source);
-    CacheNode& operator=(const CacheNode& source);
-
-public:
-    /// \brief Constructor for positive cache entry.
-    ///
-    /// \param rrset The \c RRset to cache.
-    /// \param flags The query response flags returned from the low-level
-    /// data source when this \c RRset was looked up.
-    /// \param lifespan How long the cache node is to be considered valid.
-    CacheNode(const RRsetPtr rrset, uint32_t flags, time_t lifespan);
-
-    /// \brief Constructor for negative cache entry.
-    ///
-    /// \param name Query name
-    /// \param rrclass Query class
-    /// \param rrtype Query type
-    /// \param flags Query response flags returned from the low-level
-    /// data source, indicating why this lookup failed (name not found,
-    /// type not found, etc).
-    /// \param lifespan How long the cache node is to be considered valid.
-    CacheNode(const Name& name,
-              const RRClass& rrclass,
-              const RRType& rrtype,
-              uint32_t flags,
-              time_t lifespan);
-    //@}
-
-    /// \name Getter and Setter Methods
-    //@{
-    /// \brief Returns a pointer to the cached RRset (or an empty
-    /// RRsetPtr for negative cache entries).
-
-    /// \return \c RRsetPtr
-    RRsetPtr getRRset() const { return (entry->rrset); }
-
-    /// \brief Returns name associated with cached node
-    ///
-    /// This is the name associated with the RRset if it is a positive
-    /// entry, and the associated question name if the RRSet is NULL
-    /// and this is a negative entry (together with an indication that
-    /// this is a negative entry).
-    string getNodeName() const {
-        if (getRRset()) {
-            return (getRRset()->getName().toText());
-        }
-        return (std::string("negative entry for ") + question.toText());
-    }
-
-    /// \brief Returns the query response flags associated with the data.
-    ///
-    /// \return \c uint32_t
-    uint32_t getFlags() const { return (entry->flags); }
-
-    /// \brief Is this record still valid?
-    ///
-    /// \return True if the expiration time has not yet passed,
-    /// or false if it has.
-    bool isValid() const;
-    //@}
-
-    // An iterator referencing this entry in the LRU list. This
-    // permits unit-time removal using list::erase().
-    list<CacheNodePtr>::iterator lru_entry_;
-
-    /// The \c Question (name/rrclass/rrtype) answered by this cache node
-    const isc::dns::Question question;
-
-private:
-    // The cached RRset data
-    CacheEntryPtr entry;
-
-    // When this record should be discarded
-    time_t expiry;
-};
-
-// CacheNode constructor for a positive cache entry
-CacheNode::CacheNode(const RRsetPtr rrset, const uint32_t flags,
-                     const time_t lifespan) :
-    question(Question(rrset->getName(), rrset->getClass(), rrset->getType()))
-{
-    const time_t now = time(NULL);
-    expiry = now + lifespan;
-
-    entry = CacheEntryPtr(new CacheEntry(rrset, flags));
-}
-
-// CacheNode constructor for a negative cache entry
-CacheNode::CacheNode(const Name& name,
-                     const RRClass& rrclass,
-                     const RRType& rrtype,
-                     const uint32_t flags,
-                     const time_t lifespan) :
-    question(Question(name, rrclass, rrtype))
-{
-    const time_t now = time(NULL);
-    expiry = now + lifespan;
-
-    entry = CacheEntryPtr(new CacheEntry(RRsetPtr(), flags));
-}
-// Returns true if the node has not yet expired.
-bool
-CacheNode::isValid() const {
-    const time_t now = time(NULL);
-    return (now < expiry);
-}
-
-/// This class abstracts the implementation details for \c HotCache.
-///
-/// Each node inserted into the cache is placed at the head of a
-/// doubly-linked list.  Whenever that node is retrieved from the cache,
-/// it is again moved to the head of the list.  When the configured
-/// number of slots in the cache has been exceeded, the least recently
-/// used nodes will be removed from the tail of the list.
-///
-/// A pointer to each cache node is also placed in a \c std::map object,
-/// keyed by \c isc::dns::Question.  This allows retrieval of data in
-/// (usually) logarithmic time.  (Possible TODO item: replace this with a
-/// hash table instead.)
-class HotCacheImpl {
-public:
-    HotCacheImpl(int slots, bool enabled);
-
-    // The LRU list
-    list<CacheNodePtr> lru_;
-
-    // Flag to indicate whether the cache is enabled
-    bool enabled_;
-
-    // The number of available slots in the LRU list.  (If zero,
-    // then the list is unbounded; otherwise, items are removed
-    // from the tail of the list whenever it grows past slots_.)
-    int slots_;
-
-    // The number of items currently in the list.
-    int count_;
-
-    // Map from query tuple to cache node pointer, allowing fast retrieval
-    // of data without a linear search of the LRU list
-    std::map<Question, CacheNodePtr> map_;
-
-    // Move a node to the front of the LRU list.
-    void promote(CacheNodePtr node);
-
-    // Remove a node from the cache.
-    void remove(ConstCacheNodePtr node);
-
-    // Insert a node into the cache (called by both cache() and ncache())
-    void insert(CacheNodePtr node);
-};
-
-// HotCacheImpl constructor
-HotCacheImpl::HotCacheImpl(int slots, bool enabled) :
-    enabled_(enabled), slots_(slots), count_(0)
-{
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_CREATE);
-}
-
-// Insert a cache node into the cache
-inline void
-HotCacheImpl::insert(const CacheNodePtr node) {
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_INSERT).
-        arg(node->getNodeName());
-    std::map<Question, CacheNodePtr>::const_iterator iter;
-    iter = map_.find(node->question);
-    if (iter != map_.end()) {
-        CacheNodePtr old = iter->second;
-        if (old && old->isValid()) {
-            LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_OLD_FOUND)
-                      .arg(node->getNodeName());
-            remove(old);
-        }
-    }
-
-    lru_.push_front(node);
-    node->lru_entry_ = lru_.begin();
-
-    map_[node->question] = node;
-    ++count_;
-
-    if (slots_ != 0 && count_ > slots_) {
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FULL);
-        remove(lru_.back());
-    }
-}
-
-// Promote a node to the head of the LRU list
-void
-HotCacheImpl::promote(CacheNodePtr node) {
-    if (!node) {
-        return;
-    }
-    if (node->lru_entry_ == lru_.begin()) {
-        return;
-    }
-    lru_.splice(lru_.begin(), lru_, node->lru_entry_); // move node to front
-    node->lru_entry_ = lru_.begin();
-}
-
-// Remove a node from the LRU list and the map
-void
-HotCacheImpl::remove(ConstCacheNodePtr node) {
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_REMOVE).
-        arg(node->getNodeName());
-    lru_.erase(node->lru_entry_);
-    map_.erase(node->question);
-    --count_;
-}
-
-// HotCache constructor
-HotCache::HotCache(const int slots) {
-    impl_ = new HotCacheImpl(slots, true);
-}
-
-// HotCache destructor
-HotCache::~HotCache() {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_CACHE_DESTROY);
-    delete impl_;
-}
-
-// Add a positive entry to the cache
-void
-HotCache::addPositive(RRsetPtr rrset, const uint32_t flags,
-                      const time_t lifespan)
-{
-    if (!impl_->enabled_) {
-        return;
-    }
-
-    impl_->insert(CacheNodePtr(new CacheNode(rrset, flags, lifespan)));
-}
-
-// Add a negative entry to the cache
-void
-HotCache::addNegative(const Name& name, const RRClass &rrclass,
-                      const RRType& rrtype, const uint32_t flags,
-                      const time_t lifespan)
-{
-    if (!impl_->enabled_) {
-        return;
-    }
-
-    if (rrtype == RRType::ANY() || rrclass == RRClass::ANY()) {
-        return;
-    }
-
-    impl_->insert(CacheNodePtr(new CacheNode(name, rrclass, rrtype,
-                                             flags, lifespan)));
-}
-
-// Try to retrieve an entry from the cache, returning true if
-// it was found and valid.
-bool
-HotCache::retrieve(const Name& n, const RRClass& c, const RRType& t,
-                   RRsetPtr& rrset, uint32_t& flags)
-{
-    if (!impl_->enabled_) {
-        return (false);
-    }
-
-    std::map<Question, CacheNodePtr>::const_iterator iter;
-    iter = impl_->map_.find(Question(n, c, t));
-    if (iter == impl_->map_.end()) {
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_NOT_FOUND).arg(n);
-        return (false);
-    }
-
-    CacheNodePtr node = iter->second;
-
-    if (node->isValid()) {
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_FOUND).arg(n);
-        impl_->promote(node);
-        rrset = node->getRRset();
-        flags = node->getFlags();
-        return (true);
-    }
-
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_CACHE_EXPIRED).arg(n);
-    impl_->remove(node);
-    return (false);
-}
-
-// Set the number of slots in the cache.
-void
-HotCache::setSlots(const int slots) {
-    impl_->slots_ = slots;
-
-    if (!impl_->enabled_) {
-        return;
-    }
-
-    logger.info(DATASRC_CACHE_SLOTS).arg(slots).arg(max(0, impl_->count_ -
-                                                        slots));
-
-    while (impl_->slots_ != 0 && impl_->count_ > impl_->slots_) {
-        impl_->remove(impl_->lru_.back());
-    }
-}
-
-// Return the number of slots in the cache
-int
-HotCache::getSlots() const {
-    return (impl_->slots_);
-}
-
-/// Enable or disable the cache
-void
-HotCache::setEnabled(const bool e) {
-    impl_->enabled_ = e;
-    if (e) {
-        logger.info(DATASRC_CACHE_ENABLE);
-    } else {
-        logger.info(DATASRC_CACHE_DISABLE);
-    }
-}
-
-/// Indicate whether the cache is enabled
-bool
-HotCache::getEnabled() const {
-    return (impl_->enabled_);
-}
-
-// Return the number of entries in the cache
-int
-HotCache::getCount() const {
-    return (impl_->count_);
-}
-
-}
-}

+ 0 - 223
src/lib/datasrc/cache.h

@@ -1,223 +0,0 @@
-// Copyright (C) 2010  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 __CACHE_H
-#define __CACHE_H
-
-#include <time.h>
-
-#include <boost/shared_ptr.hpp>
-
-#include <dns/rrset.h>
-
-namespace isc {
-namespace dns {
-class Name;
-class RRClass;
-class RRType;
-}
-
-namespace datasrc {
-
-class CacheNode;
-typedef boost::shared_ptr<CacheNode> CacheNodePtr;
-typedef boost::shared_ptr<const CacheNode> ConstCacheNodePtr;
-
-class HotCacheImpl;
-
-/// \brief A \c HotCache is a hot-spot cache for one or more data sources.
-///
-/// A \c HotCache must be instantiated prior to creating a \c Query.
-/// The same instance should be passed to the constructor for all queries,
-/// so that all of them will be using the same cache.
-///
-/// The cache may contain positive or negative entries, indicating
-/// whether the data does or does not exist in the underlying data
-/// source.  Entries have a fixed and limited lifespan (currently
-/// set to 30 seconds, see LIFESPAN_ below).  If a cache entry is
-/// found which has exceeded its lifespan, it will not be returned
-/// to the caller--exactly as if it had not been found.
-/// 
-/// The current 30 second cache entry lifespan is experimental.  A longer
-/// lifespan would improve performance somewhat; however, longer-lived
-/// cache entries are more likely to be incorrect in the event that
-/// the underlying data source had been updated.  Depending on the
-/// frequency of queries and the frequency of updates, longer or
-/// shorter lifespans may be desirable -- it's even possible
-/// we may want the lifespan to be set differently depending on
-/// the zone or the data source (i.e., with an infinite lifespan
-/// for cached data from a static data source).  Additional benchmarking
-/// and analysis will be needed for this.
-/// 
-/// The cache may be configured with a number of available slots for
-/// for entries.  When set to a nonzero value, no more than that number
-/// of entries can exist in the cache.  If more entries are inserted,
-/// old entries will be dropped in "least recently used" order.  If
-/// set to zero, the cache size is unlimited.  The current default is
-/// based on one thousand queries per second, times the number of seconds
-/// in the cache lifespan: 30,000 slots.
-///
-/// Notes to developers: The current implementation of HotCache uses
-/// a std::map (keyed by isc::dns::Question) to locate nodes, so access
-/// will generally be in O(log n) time.  (XXX: This might be faster if a
-/// hash table were used instead.)
-///
-/// A linked list is also maintained to keep track of recent accesses
-/// to cache entries; each time an entry is accessed, it is moved to the
-/// head of the list; when entries need to be removed, they are taken
-/// from the tail of the list.  This operation is not locked.  BIND 10
-/// does not currently use threads, but if it ever does (or if libdatasrc
-/// is ever used by a threaded application), this will need to be
-/// revisited.
-class HotCache {
-private:
-    /// \name Static definitions
-    //@{
-    /// \brief Default validity period for cache entries
-    static const int LIFESPAN_ = 30;
-
-    /// \brief Default number of slots in cache
-    static const int SLOTS_ = 1000 * LIFESPAN_;
-    //@}
-
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    //@{
-    HotCache(const HotCache& source);
-    HotCache& operator=(const HotCache& source);
-
-public:
-    /// \brief Constructor for HotCache
-    ///
-    /// \param slots The number of slots available in the cache.
-    HotCache(const int slots = SLOTS_);
-
-    /// \brief Destructor for HotCache
-    ~HotCache();
-    //@}
-
-    /// \name Cache Manipulation Methods
-    //@{
-    /// \brief Enter a positive cache entry.
-    ///
-    /// If an entry already exists in the cache which matches the
-    /// name/class/type of the RRset being cached, then the old entry
-    /// is removed before the the new one is inserted.  (XXX: This is
-    /// currently slightly inefficient; it would be quicker to keep the
-    /// existing node and simply update the rrset, flags, and lifespan.)
-    ///
-    /// \param rrset The \c RRset to cache.
-    /// \param flags The query response flags returned from the low-level
-    /// data source when this \c RRset was looked up.
-    /// \param lifespan How long the cache node is to be considered valid;
-    /// defaulting to 30 seconds.
-    void addPositive(isc::dns::RRsetPtr rrset,
-                     uint32_t flags,
-                     time_t lifespan = LIFESPAN_);
-
-    /// \brief Enter a negative cache entry.
-    ///
-    /// In the case of a negative cache entry there is no \c RRset to
-    /// cache, so instead a null \c RRsetPtr will be stored.  Since the
-    /// name, class, and type cannot be retrieved from an \c RRset, they
-    /// must be specified in the parameters.
-    ///
-    /// If an entry already exists in the cache which matches the
-    /// specified name/class/type, then the old entry is removed
-    /// before the the new one is inserted.  (XXX: As noted in the comments
-    /// for addPositive(), this is currently slightly inefficient.)
-    /// 
-    /// \param name Query name
-    /// \param rrclass Query class
-    /// \param rrtype Query type
-    /// \param flags Query response flags returned from the low-level
-    /// data source, indicating why this lookup failed (name not found,
-    /// type not found, etc).
-    /// \param lifespan How long the cache node is to be considered valid;
-    /// defaulting to 30 seconds.
-    ///
-    /// Note: 'rrclass' and 'rrtype' must refer to a specific class and
-    /// type; it is not meaningful to cache type or class ANY.  Currently,
-    /// this condition is silently ignored.
-    void addNegative(const isc::dns::Name& name,
-                     const isc::dns::RRClass& rrclass,
-                     const isc::dns::RRType& rrtype,
-                     uint32_t flags,
-                     time_t lifespan = LIFESPAN_);
-
-    /// \brief Retrieve (and promote) a record from the cache
-    ///
-    /// Retrieves a record from the cache matching the given 
-    /// query-tuple.  Returns true if one is found.  If it is a
-    /// positive cache entry, then 'rrset' is set to the cached
-    /// RRset.  For both positive and negative cache entries, 'flags'
-    /// is set to the query response flags.  The cache entry is 
-    /// then promoted to the head of the LRU queue.  (NOTE: Because
-    /// of this, "retrieve" cannot be implemented as a const method.)
-    ///
-    /// \param qname The query name
-    /// \param qclass The query class
-    /// \param qtype The query type
-    /// \param rrset Returns the RRset found, if any, to the caller
-    /// \param flags Returns the flags, if any, to the caller
-    ///
-    /// \return \c bool, true if data was found in the cache, false if not.
-    bool retrieve(const isc::dns::Name& qname,
-                  const isc::dns::RRClass& qclass,
-                  const isc::dns::RRType& qtype,
-                  isc::dns::RRsetPtr& rrset,
-                  uint32_t& flags);
-    //@}
-
-    /// \name Getter and Setter Methods
-    //@{
-    /// \brief Sets the number of slots in the cache.
-    ///
-    /// If slots is set to zero, the cache can grow without any imposed
-    /// limit.  If slots is to set a lower number than the cache currently
-    /// contains, then the least recently used records will be purged from
-    /// the cache until the total number of items in the cache equals slots.
-    void setSlots(int slots);
-
-    /// \brief Returns the number of slots in the cache.
-    int getSlots() const;
-
-    /// \brief Enable or disable the cache
-    void setEnabled(bool e);
-
-    /// \brief Indicate whether the cache is enabled
-    bool getEnabled() const;
-
-    /// \brief Returns the number of nodes currently stored in the cache.
-    ///
-    /// Note that this doesn't indicate how many nodes are still valid;
-    /// some may have expired.
-    int getCount() const;
-    //@}
-
-private:
-    /// \brief Hidden implementation details
-    HotCacheImpl* impl_;
-};
-
-}
-}
-
-#endif
-
-// Local Variables: 
-// mode: c++
-// End: 

+ 45 - 22
src/lib/datasrc/client_list.cc

@@ -12,10 +12,12 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <util/memory_segment_local.h>
+
 #include "client_list.h"
 #include "client.h"
 #include "factory.h"
-#include "memory_datasrc.h"
+#include "memory/memory_client.h"
 #include "logger.h"
 #include <dns/masterload.h>
 
@@ -25,32 +27,58 @@
 using namespace isc::data;
 using namespace isc::dns;
 using namespace std;
+using isc::util::MemorySegment;
 using boost::lexical_cast;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
+using isc::datasrc::memory::InMemoryClient;
 
 namespace isc {
 namespace datasrc {
 
 ConfigurableClientList::DataSourceInfo::DataSourceInfo(
     DataSourceClient* data_src_client,
-    const DataSourceClientContainerPtr& container, bool has_cache) :
+    const DataSourceClientContainerPtr& container, bool has_cache,
+    const RRClass& rrclass, MemorySegment& mem_sgmt) :
     data_src_client_(data_src_client),
     container_(container)
 {
     if (has_cache) {
-        cache_.reset(new InMemoryClient);
+        cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
     }
 }
 
-ConfigurableClientList::DataSourceInfo::DataSourceInfo(bool has_cache) :
+ConfigurableClientList::DataSourceInfo::DataSourceInfo(
+    const RRClass& rrclass, MemorySegment& mem_sgmt, bool has_cache) :
     data_src_client_(NULL)
 {
     if (has_cache) {
-        cache_.reset(new InMemoryClient);
+        cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
     }
 }
 
+const DataSourceClient*
+ConfigurableClientList::DataSourceInfo::getCacheClient() const {
+    return (cache_.get());
+}
+
+ConfigurableClientList::ConfigurableClientList(const RRClass& rrclass) :
+    rrclass_(rrclass),
+    mem_sgmt_(new util::MemorySegmentLocal),
+    configuration_(new isc::data::ListElement),
+    allow_cache_(false)
+{}
+
+ConfigurableClientList::~ConfigurableClientList() {
+    // Explicitly clear the contained data source clients, and check memory
+    // leak.  assert() (with abort on failure) may be too harsh, but
+    // it's probably better to find more leaks initially.  Once it's stabilized
+    // we should probably revisit it.
+
+    data_sources_.clear();
+    assert(mem_sgmt_->allMemoryDeallocated());
+}
+
 void
 ConfigurableClientList::configure(const ConstElementPtr& config,
                                   bool allow_cache)
@@ -98,14 +126,16 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                     isc_throw(ConfigurationError, "The cache must be enabled "
                               "for the MasterFiles type");
                 }
-                new_data_sources.push_back(DataSourceInfo(true));
+                new_data_sources.push_back(DataSourceInfo(rrclass_, *mem_sgmt_,
+                                                          true));
             } else {
                 // Ask the factory to create the data source for us
                 const DataSourcePair ds(this->getDataSourceClient(type,
                                                                   paramConf));
                 // And put it into the vector
                 new_data_sources.push_back(DataSourceInfo(ds.first, ds.second,
-                                                          want_cache));
+                                                          want_cache, rrclass_,
+                                                          *mem_sgmt_));
             }
 
             if (want_cache) {
@@ -141,13 +171,10 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                 for (vector<string>::const_iterator it(zones_origins.begin());
                      it != zones_origins.end(); ++it) {
                     const Name origin(*it);
-                    shared_ptr<InMemoryZoneFinder>
-                        finder(new
-                            InMemoryZoneFinder(rrclass_, origin));
                     if (type == "MasterFiles") {
                         try {
-                            finder->load(paramConf->get(*it)->stringValue());
-                            cache->addZone(finder);
+                            cache->load(origin,
+                                        paramConf->get(*it)->stringValue());
                         } catch (const isc::dns::MasterLoadError& mle) {
                             LOG_ERROR(logger, DATASRC_MASTERLOAD_ERROR)
                                 .arg(mle.what());
@@ -165,8 +192,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                             isc_throw(isc::Unexpected, "Got NULL iterator "
                                       "for zone " << origin);
                         }
-                        finder->load(*iterator);
-                        cache->addZone(finder);
+                        cache->load(origin, *iterator);
                     }
                 }
             }
@@ -324,14 +350,11 @@ ConfigurableClientList::reload(const Name& name) {
     }
     // Try to convert the finder to in-memory one. If it is the cache,
     // it should work.
-    shared_ptr<InMemoryZoneFinder>
-        finder(dynamic_pointer_cast<InMemoryZoneFinder>(result.finder));
-    const DataSourceInfo* info(result.info);
     // It is of a different type or there's no cache.
-    if (!info->cache_ || !finder) {
+    if (!result.info->cache_) {
         return (ZONE_NOT_CACHED);
     }
-    DataSourceClient* client(info->data_src_client_);
+    DataSourceClient* client(result.info->data_src_client_);
     if (client) {
         // Now do the final reload. If it does not exist in client,
         // DataSourceError is thrown, which is exactly the result what we
@@ -340,15 +363,15 @@ ConfigurableClientList::reload(const Name& name) {
         if (!iterator) {
             isc_throw(isc::Unexpected, "Null iterator from " << name);
         }
-        finder->load(*iterator);
+        result.info->cache_->load(name, *iterator);
     } else {
         // The MasterFiles special case
-        const string filename(finder->getFileName());
+        const string filename(result.info->cache_->getFileName(name));
         if (filename.empty()) {
             isc_throw(isc::Unexpected, "Confused about missing both filename "
                       "and data source");
         }
-        finder->load(filename);
+        result.info->cache_->load(name, filename);
     }
     return (ZONE_RELOADED);
 }

+ 43 - 15
src/lib/datasrc/client_list.h

@@ -15,6 +15,8 @@
 #ifndef DATASRC_CONTAINER_H
 #define DATASRC_CONTAINER_H
 
+#include <util/memory_segment.h>
+
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <cc/data.h>
@@ -22,6 +24,7 @@
 
 #include <vector>
 #include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
 #include <boost/noncopyable.hpp>
 
 namespace isc {
@@ -34,7 +37,13 @@ typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
 class DataSourceClientContainer;
 typedef boost::shared_ptr<DataSourceClientContainer>
     DataSourceClientContainerPtr;
+
+// XXX: it's better to even hide the existence of the "memory" namespace.
+// We should probably consider pimpl for details of ConfigurableClientList
+// and hide real definitions except for itself and tests.
+namespace memory {
 class InMemoryClient;
+}
 
 /// \brief The list of data source clients.
 ///
@@ -209,11 +218,11 @@ public:
     /// \brief Constructor
     ///
     /// \param rrclass For which class the list should work.
-    ConfigurableClientList(const isc::dns::RRClass &rrclass) :
-        rrclass_(rrclass),
-        configuration_(new isc::data::ListElement),
-        allow_cache_(false)
-    {}
+    ConfigurableClientList(const isc::dns::RRClass& rrclass);
+
+    /// \brief Destructor
+    virtual ~ConfigurableClientList();
+
     /// \brief Exception thrown when there's an error in configuration.
     class ConfigurationError : public Exception {
     public:
@@ -290,24 +299,27 @@ public:
     /// \todo The content yet to be defined.
     struct DataSourceInfo {
         // Plays a role of default constructor too (for vector)
-        DataSourceInfo(bool has_cache = false);
+        DataSourceInfo(const dns::RRClass& rrclass,
+                       util::MemorySegment& mem_sgmt,
+                       bool has_cache = false);
         DataSourceInfo(DataSourceClient* data_src_client,
                        const DataSourceClientContainerPtr& container,
-                       bool has_cache);
+                       bool has_cache, const dns::RRClass& rrclass,
+                       util::MemorySegment& mem_sgmt);
         DataSourceClient* data_src_client_;
         DataSourceClientContainerPtr container_;
-        boost::shared_ptr<InMemoryClient> cache_;
+
+        // Accessor to cache_ in the form of DataSourceClient, hiding
+        // the existence of InMemoryClient as much as possible.  We should
+        // really consider cleaner abstraction, but for now it works.
+        // This is also only intended to be used in auth unit tests right now.
+        // No other applications or tests may use it.
+        const DataSourceClient* getCacheClient() const;
+        boost::shared_ptr<memory::InMemoryClient> cache_;
     };
 
     /// \brief The collection of data sources.
     typedef std::vector<DataSourceInfo> DataSources;
-protected:
-    /// \brief The data sources held here.
-    ///
-    /// All our data sources are stored here. It is protected to let the
-    /// tests in. You should consider it private if you ever want to
-    /// derive this class (which is not really recommended anyway).
-    DataSources data_sources_;
 
     /// \brief Convenience type alias.
     ///
@@ -357,10 +369,26 @@ private:
     void findInternal(MutableResult& result, const dns::Name& name,
                       bool want_exact_match, bool want_finder) const;
     const isc::dns::RRClass rrclass_;
+
+    /// \brief Memory segment for in-memory cache.
+    ///
+    /// Note that this must be placed before data_sources_ so it won't be
+    /// destroyed before the built objects in the destructor.
+    boost::scoped_ptr<util::MemorySegment> mem_sgmt_;
+
     /// \brief Currently active configuration.
     isc::data::ConstElementPtr configuration_;
+
     /// \brief The last set value of allow_cache.
     bool allow_cache_;
+
+protected:
+    /// \brief The data sources held here.
+    ///
+    /// All our data sources are stored here. It is protected to let the
+    /// tests in. You should consider it private if you ever want to
+    /// derive this class (which is not really recommended anyway).
+    DataSources data_sources_;
 };
 
 } // namespace datasrc

File diff suppressed because it is too large
+ 0 - 1434
src/lib/datasrc/data_source.cc


+ 0 - 362
src/lib/datasrc/data_source.h

@@ -38,13 +38,6 @@ class RRsetList;
 
 namespace datasrc {
 
-class DataSrcMatch;
-class Query;
-
-class DataSrc;
-typedef boost::shared_ptr<DataSrc> DataSrcPtr;
-typedef boost::shared_ptr<const DataSrc> ConstDataSrcPtr;
-
 /// This exception represents Backend-independent errors relating to
 /// data source operations.
 class DataSourceError : public Exception {
@@ -65,361 +58,6 @@ public:
         DataSourceError(file, line, what) {}
 };
 
-
-class AbstractDataSrc {
-    ///
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private to make it explicit that this is a pure base class.
-private:
-    AbstractDataSrc(const AbstractDataSrc& source);
-    AbstractDataSrc& operator=(const AbstractDataSrc& source);
-protected:
-    /// \brief The default constructor.
-    ///
-    /// This is intentionally defined as \c protected as this base class should
-    /// never be instantiated (except as part of a derived class).
-    AbstractDataSrc() {}
-public:
-    /// \brief The destructor.
-    virtual ~AbstractDataSrc() {};
-    //@}
-
-    enum Result {
-        SUCCESS,
-        ERROR,
-        NOT_IMPLEMENTED
-    };
-
-    // These flags indicate conditions encountered while processing a query.
-    //
-    // REFERRAL:       The node contains an NS record
-    // CNAME_FOUND:    The node contains a CNAME record
-    // NAME_NOT_FOUND: The node does not exist in the data source.
-    // TYPE_NOT_FOUND: The node does not contain the requested RRType
-    // NO_SUCH_ZONE:   The zone does not exist in this data source.
-    //
-    // DATA_NOT_FOUND: A combination of the last three, for coding convenience
-    enum QueryResponseFlags {
-        REFERRAL = 0x01,
-        CNAME_FOUND = 0x02,
-        NAME_NOT_FOUND = 0x04,
-        TYPE_NOT_FOUND = 0x08,
-        NO_SUCH_ZONE = 0x10,
-        DATA_NOT_FOUND = (NAME_NOT_FOUND|TYPE_NOT_FOUND|NO_SUCH_ZONE)
-    };
-
-    // 'High-level' methods.  These will be implemented by the
-    // general DataSrc class, and SHOULD NOT be overwritten by subclasses.
-    virtual void doQuery(Query& query) = 0;
-
-    // XXX: High-level methods to be implemented later:
-    // virtual void doUpdate(Update update) = 0;
-    // virtual void doXfr(Query query) = 0;
-
-    // 'Medium-level' methods.  This will be implemented by the general
-    // DataSrc class but MAY be overwritten by subclasses.
-    virtual void findClosestEnclosure(DataSrcMatch& match) const = 0;
-
-    // Optional 'low-level' methods.  These will have stub implementations
-    // in the general DataSrc class but MAY be overwritten by subclasses
-    virtual Result init() = 0;
-    virtual Result init(isc::data::ConstElementPtr config) = 0;
-    virtual Result close() = 0;
-
-    // Mandatory 'low-level' methods: These will NOT be implemented by
-    // the general DataSrc class; subclasses MUST implement them.
-    virtual Result findRRset(const isc::dns::Name& qname,
-                             const isc::dns::RRClass& qclass,
-                             const isc::dns::RRType& qtype,
-                             isc::dns::RRsetList& target,
-                             uint32_t& flags,
-                             const isc::dns::Name* zonename) const = 0;
-
-    virtual Result findExactRRset(const isc::dns::Name& qname,
-                                  const isc::dns::RRClass& qclass,
-                                  const isc::dns::RRType& qtype,
-                                  isc::dns::RRsetList& target,
-                                  uint32_t& flags,
-                                  const isc::dns::Name* zonename) const = 0;
-
-    // These will have dumb implementations in the general DataSrc
-    // class, and SHOULD be overwritten by subclasses.
-    virtual Result findAddrs(const isc::dns::Name& qname,
-                             const isc::dns::RRClass& qclass,
-                             isc::dns::RRsetList& target,
-                             uint32_t& flags,
-                             const isc::dns::Name* zonename) const = 0;
-
-     virtual Result findReferral(const isc::dns::Name& qname,
-                                 const isc::dns::RRClass& qclass,
-                                 isc::dns::RRsetList& target,
-                                 uint32_t& flags,
-                                 const isc::dns::Name* zonename) const = 0;
-
-    // This MUST be implemented by concrete data sources which support
-    // DNSSEC, but is optional for others (e.g., the static data source).
-    virtual Result findPreviousName(const isc::dns::Name& qname,
-                                    isc::dns::Name& target,
-                                    const isc::dns::Name* zonename) const = 0;
-
-   // This MUST be implemented by concrete data sources which support
-   // NSEC3, but is optional for others
-   virtual Result findCoveringNSEC3(const isc::dns::Name& zonename,
-                                    std::string& hash,
-                                    isc::dns::RRsetList& target) const = 0;
-};
-
-// Base class for a DNS Data Source
-class DataSrc : public AbstractDataSrc {
-    ///
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-private:
-    DataSrc(const DataSrc& source);
-    DataSrc& operator=(const DataSrc& source);
-public:
-    DataSrc() : rrclass(isc::dns::RRClass::IN()) {}
-    DataSrc(const isc::dns::RRClass& c) : rrclass(c) {}
-    /// \brief The destructor.
-    virtual ~DataSrc() {};
-    //@}
-
-    virtual void doQuery(Query& q);
-
-    virtual void findClosestEnclosure(DataSrcMatch& match) const = 0;
-
-    const isc::dns::RRClass& getClass() const { return (rrclass); }
-    void setClass(isc::dns::RRClass& c) { rrclass = c; }
-    void setClass(const isc::dns::RRClass& c) { rrclass = c; }
-
-    virtual Result init() { return (NOT_IMPLEMENTED); }
-    virtual Result init(isc::data::ConstElementPtr config);
-    virtual Result close() { return (NOT_IMPLEMENTED); }
-
-    virtual Result findRRset(const isc::dns::Name& qname,
-                             const isc::dns::RRClass& qclass,
-                             const isc::dns::RRType& qtype,
-                             isc::dns::RRsetList& target,
-                             uint32_t& flags,
-                             const isc::dns::Name* zonename) const = 0;
-
-    virtual Result findExactRRset(const isc::dns::Name& qname,
-                                  const isc::dns::RRClass& qclass,
-                                  const isc::dns::RRType& qtype,
-                                  isc::dns::RRsetList& target,
-                                  uint32_t& flags,
-                                  const isc::dns::Name* zonename) const = 0;
-
-    virtual Result findAddrs(const isc::dns::Name& qname,
-                             const isc::dns::RRClass& qclass,
-                             isc::dns::RRsetList& target,
-                             uint32_t& flags,
-                             const isc::dns::Name* zonename) const;
-
-    virtual Result findReferral(const isc::dns::Name& qname,
-                                const isc::dns::RRClass& qclass,
-                                isc::dns::RRsetList& target,
-                                uint32_t& flags,
-                                const isc::dns::Name* zonename) const;
-
-    virtual Result findPreviousName(const isc::dns::Name& qname,
-                                    isc::dns::Name& target,
-                                    const isc::dns::Name* zonename) const = 0;
-
-   virtual Result findCoveringNSEC3(const isc::dns::Name& zonename,
-                                    std::string& hash,
-                                    isc::dns::RRsetList& target) const = 0;
-
-private:
-    isc::dns::RRClass rrclass;
-};
-
-class MetaDataSrc : public DataSrc {
-    ///
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    //@{
-private:
-    MetaDataSrc(const MetaDataSrc& source);
-    MetaDataSrc& operator=(const MetaDataSrc& source);
-public:
-    MetaDataSrc() : DataSrc(isc::dns::RRClass::ANY()) {}
-    MetaDataSrc(const isc::dns::RRClass& c) : DataSrc(c) {}
-    /// \brief The destructor.
-    virtual ~MetaDataSrc() {}
-    //@}
-
-    void addDataSrc(ConstDataSrcPtr data_src);
-    void removeDataSrc(ConstDataSrcPtr data_src);
-    size_t dataSrcCount() { return (data_sources.size()); }
-
-    void findClosestEnclosure(DataSrcMatch& match) const;
-
-    // Actual queries for data should not be sent to a MetaDataSrc object,
-    // so we return NOT_IMPLEMENTED if we receive any.
-    //
-    // The proper way to use the MetaDataSrc is to run findClosestEnclosure()
-    // to get a pointer to the best concrete data source for the specified
-    // zone, then send all queries directly to that data source.
-
-    Result findRRset(const isc::dns::Name& qname,
-                     const isc::dns::RRClass& qclass,
-                     const isc::dns::RRType& qtype,
-                     isc::dns::RRsetList& target,
-                     uint32_t& flags,
-                     const isc::dns::Name* zonename) const;
-
-    Result findExactRRset(const isc::dns::Name& qname,
-                          const isc::dns::RRClass& qclass,
-                          const isc::dns::RRType& qtype,
-                          isc::dns::RRsetList& target,
-                          uint32_t& flags,
-                          const isc::dns::Name* zonename) const;
-
-    Result findAddrs(const isc::dns::Name& qname,
-                     const isc::dns::RRClass& qclass,
-                     isc::dns::RRsetList& target,
-                     uint32_t& flags,
-                     const isc::dns::Name* zonename) const;
-
-    Result findReferral(const isc::dns::Name& qname,
-                        const isc::dns::RRClass& qclass,
-                        isc::dns::RRsetList& target,
-                        uint32_t& flags,
-                        const isc::dns::Name* zonename) const;
-
-    virtual Result findPreviousName(const isc::dns::Name& qname,
-                                    isc::dns::Name& target,
-                                    const isc::dns::Name* zonename) const;
-
-   virtual Result findCoveringNSEC3(const isc::dns::Name& zonename,
-                                    std::string& hash,
-                                    isc::dns::RRsetList& target) const;
-
-private:
-    std::vector<ConstDataSrcPtr> data_sources;
-};
-
-/// \brief Information about the zone along with the %data source that best
-/// matches a give name and RR class.
-///
-/// A \c DataSrcMatch object is created with a domain name and RR class to
-/// hold the search state of looking for the zone and the %data source that
-/// stores the zone that best match the given name and RR class.
-/// The application of this class passes an object of \c DataSrcMatch to
-/// one or more ^data sources via their \c findClosestEnclosure() method.
-/// The %data source searches its content for the given key, and update
-/// the state if it finds a better zone than the currently recorded one.
-///
-/// The state of a \c DataSrcMatch object should be updated if and only if:
-///  - The specified RR class and the RR class of the %data source are the
-//     same, or the specified RR class is ANY; and
-///  - There is no matching %data source and name found (which is probably
-///    wrong, see below), or the given enclosing name gives a longer match
-///    than the currently stored enclosing name against the specified name.
-class DataSrcMatch {
-    ///
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are
-    /// intentionally defined as private.
-    //@{
-private:
-    DataSrcMatch(const DataSrcMatch& source);
-    DataSrcMatch& operator=(const DataSrcMatch& source);
-public:
-    /// \brief The constructor.
-    ///
-    /// This constructor normally doesn't throw an exception.  However,
-    /// it creates a copy of the given name object, which may require memory
-    /// allocation, and if it fails the corresponding standard exception will
-    /// be thrown.
-    ///
-    /// \param name The domain name to be matched.
-    /// \param rrclass The RR class to be matched
-    DataSrcMatch(const isc::dns::Name& name,
-                 const isc::dns::RRClass& rrclass) :
-        closest_name_(NULL), best_source_(NULL),
-        name_(name), rrclass_(rrclass)
-    {}
-    ~DataSrcMatch();
-    //@}
-
-    /// \name Getter and Setter Methods
-    //@{
-    /// \brief Returns the name to be matched.
-    const isc::dns::Name& getName() const { return (name_); }
-
-    /// \brief Returns the RR class to be matched.
-    ///
-    /// This method never throws an exception.
-    const isc::dns::RRClass& getClass() const { return (rrclass_); }
-
-    /// \brief Returns the best enclosing zone name found for the given
-    // name and RR class so far.
-    ///
-    /// \return A pointer to the zone apex \c Name, NULL if none found yet.
-    ///
-    /// This method never throws an exception.
-    const isc::dns::Name* getEnclosingZone() const { return (closest_name_); }
-
-    /// \brief Returns the best %data source found for the given name and
-    /// RR class so far.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \return A pointer to a concrete %data source, NULL if none found yet.
-    const DataSrc* getDataSource() const { return (best_source_); }
-    //@}
-
-    /// \brief Update the object state with better information if possible.
-    ///
-    /// This method is intended to be called by a concrete %data source's
-    /// \c findClosestEnclosure() method to store the best match for
-    /// the given name and class that has been found so far.
-    ///
-    /// It compares the best name (if found) and \c container, and if the
-    /// latter gives a longer match, it will install the given %data source
-    /// and the enclosing name as the best match;
-    /// if there is no known pair of %data source and enclosing name,
-    /// this method will install the given pair unconditionally.
-    /// (which is probably BAD);
-    /// otherwise this method does nothing.
-    ///
-    /// In any case, if a new pair of %data source and enclosing name are
-    /// installed, a new name object will be internally allocated.
-    /// And, if memory allocation fails the corresponding standard exception
-    /// will be thrown.
-    ///
-    /// \param new_source A candidate %data source that gives a better match.
-    /// \param container The enclosing name of the matching zone in
-    /// \c new_source.
-    void update(const DataSrc& new_source, const isc::dns::Name& container);
-
-private:
-    isc::dns::Name* closest_name_;
-    const DataSrc* best_source_;
-    const isc::dns::Name name_;
-    const isc::dns::RRClass& rrclass_;
-};
-
-class Nsec3Param {
-public:
-    Nsec3Param(uint8_t a, uint8_t f, uint16_t i, const std::vector<uint8_t>& s);
-    std::string getHash(const isc::dns::Name& name) const;
-private:
-    const uint8_t algorithm_;
-    const uint8_t flags_;
-    const uint16_t iterations_;
-    const std::vector<uint8_t> salt_;
-};
-
 }
 }
 

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

@@ -1,4 +1,4 @@
-SUBDIRS = . tests benchmarks
+SUBDIRS = . benchmarks
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns

+ 95 - 21
src/lib/datasrc/memory/domaintree.h

@@ -373,10 +373,23 @@ private:
         }
     }
 
+    /// \brief returns if the node is a subtree's root node
+    ///
+    /// This method takes a node and returns \c true if it is the root
+    /// node of the subtree it belongs to.
+    ///
+    /// This method never throws an exception.
     bool isSubTreeRoot() const {
         return ((flags_ & FLAG_SUBTREE_ROOT) != 0);
     }
 
+    /// \brief returns the root of its subtree
+    ///
+    /// This method takes a node and returns the root of its subtree.
+    ///
+    /// This method never throws an exception.
+    const DomainTreeNode<T>* getSubTreeRoot() const;
+
 public:
     /// \brief returns the parent of the root of its subtree
     ///
@@ -388,7 +401,6 @@ public:
     /// This method never throws an exception.
     const DomainTreeNode<T>* getUpperNode() const;
 
-private:
     /// \brief return the next node which is bigger than current node
     /// in the same subtree
     ///
@@ -423,6 +435,7 @@ private:
     /// This method never throws an exception.
     const DomainTreeNode<T>* predecessor() const;
 
+private:
     /// \brief private shared implementation of successor and predecessor
     ///
     /// As the two mentioned functions are merely mirror images of each other,
@@ -538,7 +551,7 @@ DomainTreeNode<T>::~DomainTreeNode() {
 
 template <typename T>
 const DomainTreeNode<T>*
-DomainTreeNode<T>::getUpperNode() const {
+DomainTreeNode<T>::getSubTreeRoot() const {
     const DomainTreeNode<T>* current = this;
 
     // current would never be equal to NULL here (in a correct tree
@@ -547,7 +560,13 @@ DomainTreeNode<T>::getUpperNode() const {
         current = current->getParent();
     }
 
-    return (current->getParent());
+    return (current);
+}
+
+template <typename T>
+const DomainTreeNode<T>*
+DomainTreeNode<T>::getUpperNode() const {
+    return (getSubTreeRoot()->getParent());
 }
 
 template <typename T>
@@ -555,7 +574,17 @@ isc::dns::LabelSequence
 DomainTreeNode<T>::getAbsoluteLabels(
     uint8_t buf[isc::dns::LabelSequence::MAX_SERIALIZED_LENGTH]) const
 {
-    isc::dns::LabelSequence result(getLabels(), buf);
+    // If the current node already has absolute labels, just return it.
+    // This should normally be the case for the origin node if this tree
+    // is used to represent a single DNS zone.
+    const isc::dns::LabelSequence cur_labels(getLabels());
+    if (cur_labels.isAbsolute()) {
+        return (cur_labels);
+    }
+
+    // Otherwise, build the absolute sequence traversing the tree of tree
+    // toward the top root.
+    isc::dns::LabelSequence result(cur_labels, buf);
     const DomainTreeNode<T>* upper = getUpperNode();
     while (upper != NULL) {
         result.extend(upper->getLabels(), buf);
@@ -672,14 +701,26 @@ public:
     /// The default constructor.
     ///
     /// \exception None
-    DomainTreeNodeChain() : node_count_(0), last_compared_(NULL),
+    DomainTreeNodeChain() : level_count_(0), last_compared_(NULL),
                         // XXX: meaningless initial values:
                         last_comparison_(0, 0,
                                          isc::dns::NameComparisonResult::EQUAL)
     {}
 
+    /// \brief Copy constructor.
+    ///
+    /// \exception None
+    DomainTreeNodeChain(const DomainTreeNodeChain<T>& other) :
+        level_count_(other.level_count_),
+        last_compared_(other.last_compared_),
+        last_comparison_(other.last_comparison_)
+    {
+        for (size_t i = 0; i < level_count_; i++) {
+            nodes_[i] = other.nodes_[i];
+        }
+    }
+
 private:
-    DomainTreeNodeChain(const DomainTreeNodeChain<T>&);
     DomainTreeNodeChain<T>& operator=(const DomainTreeNodeChain<T>&);
     //@}
 
@@ -691,7 +732,7 @@ public:
     ///
     /// \exception None
     void clear() {
-        node_count_ = 0;
+        level_count_ = 0;
         last_compared_ = NULL;
     }
 
@@ -732,7 +773,7 @@ public:
     /// chain, 0 will be returned.
     ///
     /// \exception None
-    unsigned int getLevelCount() const { return (node_count_); }
+    size_t getLevelCount() const { return (level_count_); }
 
     /// \brief return the absolute name for the node which this
     /// \c DomainTreeNodeChain currently refers to.
@@ -750,11 +791,11 @@ public:
 
         const DomainTreeNode<T>* top_node = top();
         isc::dns::Name absolute_name = top_node->getName();
-        int node_count = node_count_ - 1;
-        while (node_count > 0) {
-            top_node = nodes_[node_count - 1];
+        size_t level = level_count_ - 1;
+        while (level > 0) {
+            top_node = nodes_[level - 1];
             absolute_name = absolute_name.concatenate(top_node->getName());
-            --node_count;
+            --level;
         }
         return (absolute_name);
     }
@@ -768,7 +809,7 @@ private:
     /// \brief return whether node chain has node in it.
     ///
     /// \exception None
-    bool isEmpty() const { return (node_count_ == 0); }
+    bool isEmpty() const { return (level_count_ == 0); }
 
     /// \brief return the top node for the node chain
     ///
@@ -778,7 +819,7 @@ private:
     /// \exception None
     const DomainTreeNode<T>* top() const {
         assert(!isEmpty());
-        return (nodes_[node_count_ - 1]);
+        return (nodes_[level_count_ - 1]);
     }
 
     /// \brief pop the top node from the node chain
@@ -789,7 +830,7 @@ private:
     /// \exception None
     void pop() {
         assert(!isEmpty());
-        --node_count_;
+        --level_count_;
     }
 
     /// \brief add the node into the node chain
@@ -800,8 +841,8 @@ private:
     ///
     /// \exception None
     void push(const DomainTreeNode<T>* node) {
-        assert(node_count_ < RBT_MAX_LEVEL);
-        nodes_[node_count_++] = node;
+        assert(level_count_ < RBT_MAX_LEVEL);
+        nodes_[level_count_++] = node;
     }
 
 private:
@@ -810,7 +851,7 @@ private:
     // it's also equal to the possible maximum level.
     const static int RBT_MAX_LEVEL = isc::dns::Name::MAX_LABELS;
 
-    int node_count_;
+    size_t level_count_;
     const DomainTreeNode<T>* nodes_[RBT_MAX_LEVEL];
     const DomainTreeNode<T>* last_compared_;
     isc::dns::NameComparisonResult last_comparison_;
@@ -1265,12 +1306,20 @@ public:
     const DomainTreeNode<T>*
     previousNode(DomainTreeNodeChain<T>& node_path) const;
 
+    /// \brief return the largest node in the tree of trees.
+    ///
+    /// \throw none
+    ///
+    /// \return A \c DomainTreeNode that is the largest node in the
+    /// tree. If there are no nodes, then \c NULL is returned.
+    const DomainTreeNode<T>* largestNode() const;
+
     /// \brief Get the total number of nodes in the tree
     ///
     /// It includes nodes internally created as a result of adding a domain
     /// name that is a subdomain of an existing node of the tree.
     /// This function is mainly intended to be used for debugging.
-    int getNodeCount() const { return (node_count_); }
+    uint32_t getNodeCount() const { return (node_count_); }
 
     /// \name Debug function
     //@{
@@ -1402,8 +1451,15 @@ private:
     //@}
 
     typename DomainTreeNode<T>::DomainTreeNodePtr root_;
-    /// the node count of current tree
-    unsigned int node_count_;
+
+    /// the node count of current tree.
+    ///
+    /// Note: uint32_t may look awkward, but we intentionally choose it so
+    /// that needsReturnEmptyNode_ below won't make cause extra padding
+    /// in 64-bit machines (and we can minimize the total size of this class).
+    /// 2^32 - 1 should be a reasonable max of possible number of nodes.
+    uint32_t node_count_;
+
     /// search policy for domaintree
     const bool needsReturnEmptyNode_;
 };
@@ -1710,6 +1766,24 @@ DomainTree<T>::previousNode(DomainTreeNodeChain<T>& node_path) const {
 }
 
 template <typename T>
+const DomainTreeNode<T>*
+DomainTree<T>::largestNode() const {
+    const DomainTreeNode<T>* node = root_.get();
+    while (node != NULL) {
+        // We go right first, then down.
+        if (node->getRight() != NULL) {
+            node = node->getRight();
+        } else if (node->getDown() != NULL) {
+            node = node->getDown();
+        } else {
+            break;
+        }
+    }
+
+    return (node);
+}
+
+template <typename T>
 typename DomainTree<T>::Result
 DomainTree<T>::insert(util::MemorySegment& mem_sgmt,
                       const isc::dns::Name& target_name,

+ 32 - 24
src/lib/datasrc/memory/memory_client.cc

@@ -22,6 +22,7 @@
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/segment_object_holder.h>
 #include <datasrc/memory/treenode_rrset.h>
+#include <datasrc/memory/zone_finder.h>
 
 #include <util/memory_segment_local.h>
 
@@ -100,9 +101,6 @@ public:
         FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
 
         ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
-
-        // see above for the assert().
-        assert(mem_sgmt_.allMemoryDeallocated());
     }
 
     util::MemorySegment& mem_sgmt_;
@@ -326,6 +324,7 @@ public:
         if (nsec3_data == NULL) {
             nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
             zone_data.setNSEC3Data(nsec3_data);
+            zone_data.setSigned(true);
         } else {
             size_t salt_len = nsec3_data->getSaltLen();
             const uint8_t* salt_data = nsec3_data->getSaltData();
@@ -333,7 +332,12 @@ public:
 
             if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
                 (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
-                (salt_data_2.size() != salt_len) ||
+                (salt_data_2.size() != salt_len)) {
+                isc_throw(AddError,
+                          "NSEC3 with inconsistent parameters: " <<
+                          rrset->toText());
+            }
+            if ((salt_len > 0) &&
                 (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
                 isc_throw(AddError,
                           "NSEC3 with inconsistent parameters: " <<
@@ -341,17 +345,10 @@ public:
             }
         }
 
-        string fst_label = rrset->getName().split(0, 1).toText(true);
-        transform(fst_label.begin(), fst_label.end(), fst_label.begin(),
-                  ::toupper);
-
         ZoneNode* node;
-        nsec3_data->insertName(mem_sgmt_, Name(fst_label), &node);
+        nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
 
         RdataEncoder encoder;
-
-        // We assume that rrsig has already been checked to match rrset
-        // by the caller.
         RdataSet* set = RdataSet::create(mem_sgmt_, encoder, rrset, rrsig);
         RdataSet* old_set = node->setData(set);
         if (old_set != NULL) {
@@ -416,6 +413,7 @@ public:
                 if (nsec3_data == NULL) {
                     nsec3_data = NSEC3Data::create(mem_sgmt_, param);
                     zone_data.setNSEC3Data(nsec3_data);
+                    zone_data.setSigned(true);
                 } else {
                     size_t salt_len = nsec3_data->getSaltLen();
                     const uint8_t* salt_data = nsec3_data->getSaltData();
@@ -423,7 +421,13 @@ public:
 
                     if ((param.getHashalg() != nsec3_data->hashalg) ||
                         (param.getIterations() != nsec3_data->iterations) ||
-                        (salt_data_2.size() != salt_len) ||
+                        (salt_data_2.size() != salt_len)) {
+                        isc_throw(AddError,
+                                  "NSEC3PARAM with inconsistent parameters: "
+                                  << rrset->toText());
+                    }
+
+                    if ((salt_len > 0) &&
                         (std::memcmp(&salt_data_2[0],
                                      salt_data, salt_len) != 0)) {
                         isc_throw(AddError,
@@ -606,7 +610,7 @@ InMemoryClient::InMemoryClientImpl::load(
     }
 
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
-        arg(zone_name).arg(rrclass_.toText());
+        arg(zone_name).arg(rrclass_);
 
     // Set the filename in file_name_tree_ now, so that getFileName()
     // can use it (during zone reloading).
@@ -686,21 +690,25 @@ InMemoryClient::getZoneCount() const {
     return (impl_->zone_count_);
 }
 
-isc::datasrc::memory::ZoneTable::FindResult
-InMemoryClient::findZone2(const isc::dns::Name& zone_name) const {
+isc::datasrc::DataSourceClient::FindResult
+InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
     LOG_DEBUG(logger, DBG_TRACE_DATA,
               DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
+
     ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
-    return (result);
+
+    ZoneFinderPtr finder;
+    if (result.code != result::NOTFOUND) {
+        finder.reset(new InMemoryZoneFinder(*result.zone_data, getClass()));
+    }
+
+    return (DataSourceClient::FindResult(result.code, finder));
 }
 
-isc::datasrc::DataSourceClient::FindResult
-InMemoryClient::findZone(const isc::dns::Name&) const {
-    // This variant of findZone() is not implemented and should be
-    // removed eventually. It currently throws an exception. It is
-    // required right now to derive from DataSourceClient.
-    isc_throw(isc::NotImplemented,
-              "This variant of findZone() is not implemented.");
+const ZoneData*
+InMemoryClient::findZoneData(const isc::dns::Name& zone_name) {
+    ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+    return (result.zone_data);
 }
 
 result::Result

+ 11 - 12
src/lib/datasrc/memory/memory_client.h

@@ -20,11 +20,7 @@
 #include <datasrc/iterator.h>
 #include <datasrc/client.h>
 #include <datasrc/memory/zone_table.h>
-
-// for isc::datasrc::ZoneTable::FindResult returned by findZone(). This
-// variant of findZone() is not implemented and should be removed
-// eventually.
-#include <datasrc/zonetable.h>
+#include <datasrc/memory/zone_data.h>
 
 #include <string>
 
@@ -206,19 +202,22 @@ public:
         { }
     };
 
-    /// Returns a \c ZoneTable result that best matches the given name.
+    /// Returns a \c ZoneFinder result that best matches the given name.
     ///
     /// This derived version of the method never throws an exception.
     /// For other details see \c DataSourceClient::findZone().
-    virtual isc::datasrc::memory::ZoneTable::FindResult
-    findZone2(const isc::dns::Name& name) const;
-
-    // This variant of findZone() is not implemented and should be
-    // removed eventually. It currently throws an exception. It is
-    // required right now to derive from DataSourceClient.
     virtual isc::datasrc::DataSourceClient::FindResult
     findZone(const isc::dns::Name& name) const;
 
+    /// Returns a \c ZoneData in the result that best matches the given
+    /// name.
+    ///
+    /// This is mainly intended for use in unit tests and should not be
+    /// used in other code.
+    ///
+    /// \throws none
+    const ZoneData* findZoneData(const isc::dns::Name& name);
+
     /// \brief Implementation of the getIterator method
     virtual isc::datasrc::ZoneIteratorPtr
     getIterator(const isc::dns::Name& name, bool separate_rrs = false) const;

+ 22 - 17
src/lib/datasrc/memory/treenode_rrset.cc

@@ -79,10 +79,6 @@ TreeNodeRRset::setTTL(const RRTTL&) {
 
 std::string
 TreeNodeRRset::toText() const {
-    // Create TTL from internal data
-    util::InputBuffer ttl_buffer(rdataset_->getTTLData(), sizeof(uint32_t));
-    const RRTTL ttl(ttl_buffer);
-
     // Dump the main RRset, if not empty
     std::string ret;
     RRsetPtr tmp_rrset;
@@ -92,7 +88,7 @@ TreeNodeRRset::toText() const {
     {
         if (!tmp_rrset) {
             tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_, getType(),
-                                           ttl));
+                                           getTTL()));
         }
         tmp_rrset->addRdata(rit->getCurrent());
     }
@@ -101,17 +97,7 @@ TreeNodeRRset::toText() const {
     }
 
     // Dump any RRSIGs
-    tmp_rrset.reset();
-    for (RdataIteratorPtr rit = getSigRdataIterator();
-         !rit->isLast();
-         rit->next())
-    {
-        if (!tmp_rrset) {
-            tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_,
-                                           RRType::RRSIG(), ttl));
-        }
-        tmp_rrset->addRdata(rit->getCurrent());
-    }
+    tmp_rrset = getRRsig();
     if (tmp_rrset) {
         ret += tmp_rrset->toText();
     }
@@ -292,7 +278,26 @@ TreeNodeRRset::getSigRdataIterator() const {
 
 RRsetPtr
 TreeNodeRRset::getRRsig() const {
-    isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
+    // Shortcut: if DNSSEC is disabled for the RRset, simply return NULL.
+    // The generic code below provides the same behavior, but with much more
+    // overhead.
+    if (!dnssec_ok_) {
+        return (RRsetPtr());
+    }
+
+    RRsetPtr tmp_rrset;
+    for (RdataIteratorPtr rit = getSigRdataIterator();
+         !rit->isLast();
+         rit->next())
+    {
+        if (!tmp_rrset) {
+            tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_,
+                                           RRType::RRSIG(), getTTL()));
+        }
+        tmp_rrset->addRdata(rit->getCurrent());
+    }
+
+    return (tmp_rrset);
 }
 
 void

+ 0 - 2
src/lib/datasrc/memory/treenode_rrset.h

@@ -190,8 +190,6 @@ public:
     virtual dns::RdataIteratorPtr getRdataIterator() const;
 
     /// \brief Specialized version of \c getRRsig() for \c TreeNodeRRset.
-    ///
-    /// It throws \c isc::Unexpected unconditionally.
     virtual dns::RRsetPtr getRRsig() const;
 
     virtual unsigned int getRRsigDataCount() const {

+ 421 - 59
src/lib/datasrc/memory/zone_finder.cc

@@ -15,6 +15,7 @@
 #include <datasrc/memory/zone_finder.h>
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/treenode_rrset.h>
+#include <datasrc/memory/rdata_serialization.h>
 
 #include <datasrc/zone.h>
 #include <datasrc/data_source.h>
@@ -22,9 +23,16 @@
 #include <dns/name.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
+#include <dns/nsec3hash.h>
 
 #include <datasrc/logger.h>
 
+#include <boost/scoped_ptr.hpp>
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <vector>
+
 using namespace isc::dns;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc;
@@ -33,6 +41,37 @@ namespace isc {
 namespace datasrc {
 namespace memory {
 
+namespace internal {
+
+// Specialized version of ZoneFinder::ResultContext, which  holds objects
+// related to find() results using internal representations of the in-memory
+// data source implementation.
+class ZoneFinderResultContext {
+public:
+    /// \brief Constructor
+    ///
+    /// The first three parameters correspond to those of
+    /// ZoneFinder::ResultContext.  If node is non NULL, it specifies the
+    /// found ZoneNode in the search.
+    ZoneFinderResultContext(ZoneFinder::Result code_param,
+                            TreeNodeRRsetPtr rrset_param,
+                            ZoneFinder::FindResultFlags flags_param,
+                            const ZoneData& zone_data_param,
+                            const ZoneNode* node, const RdataSet* rdset) :
+        code(code_param), rrset(rrset_param), flags(flags_param),
+        zone_data(&zone_data_param), found_node(node), found_rdset(rdset)
+    {}
+
+    const ZoneFinder::Result code;
+    const TreeNodeRRsetPtr rrset;
+    const ZoneFinder::FindResultFlags flags;
+    const ZoneData* const zone_data;
+    const ZoneNode* const found_node;
+    const RdataSet* const found_rdset;
+};
+}
+using internal::ZoneFinderResultContext;
+
 namespace {
 /// Creates a TreeNodeRRsetPtr for the given RdataSet at the given Node, for
 /// the given RRClass
@@ -51,18 +90,21 @@ TreeNodeRRsetPtr
 createTreeNodeRRset(const ZoneNode* node,
                     const RdataSet* rdataset,
                     const RRClass& rrclass,
+                    ZoneFinder::FindOptions options,
                     const Name* realname = NULL)
 {
+    const bool dnssec = ((options & ZoneFinder::FIND_DNSSEC) != 0);
     if (node != NULL && rdataset != NULL) {
         if (realname != NULL) {
-            return TreeNodeRRsetPtr(new TreeNodeRRset(*realname, rrclass, node,
-                                                      rdataset, true));
+            return (TreeNodeRRsetPtr(new TreeNodeRRset(*realname, rrclass,
+                                                       node, rdataset,
+                                                       dnssec)));
         } else {
-            return TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node,
-                                                      rdataset, true));
+            return (TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node, rdataset,
+                                                       dnssec)));
         }
     } else {
-        return TreeNodeRRsetPtr();
+        return (TreeNodeRRsetPtr());
     }
 }
 
@@ -145,6 +187,27 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
     return (false);
 }
 
+/// Creates a NSEC3 ConstRRsetPtr for the given ZoneNode inside the
+/// NSEC3 tree, for the given RRClass.
+///
+/// It asserts that the node contains data (RdataSet) and is of type
+/// NSEC3.
+///
+/// \param node The ZoneNode inside the NSEC3 tree
+/// \param rrclass The RRClass as passed by the client
+ConstRRsetPtr
+createNSEC3RRset(const ZoneNode* node, const RRClass& rrclass) {
+     const RdataSet* rdataset = node->getData();
+     // Only NSEC3 ZoneNodes are allowed to be passed to this method. We
+     // assert that these have data, and also are of type NSEC3.
+     assert(rdataset != NULL);
+     assert(rdataset->type == RRType::NSEC3());
+
+    // Create the RRset.  Note the DNSSEC flag: NSEC3 implies DNSSEC.
+    return (createTreeNodeRRset(node, rdataset, rrclass,
+                                ZoneFinder::FIND_DNSSEC));
+}
+
 // convenience function to fill in the final details
 //
 // Set up ZoneFinderResultContext object as a return value of find(),
@@ -158,14 +221,16 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
 // if wild is true, the RESULT_WILDCARD flag will be set.
 // If qname is not NULL, this is the query name, to be used in wildcard
 // substitution instead of the Node's name).
-isc::datasrc::memory::ZoneFinderResultContext
+ZoneFinderResultContext
 createFindResult(const RRClass& rrclass,
                  const ZoneData& zone_data,
                  ZoneFinder::Result code,
-                 const RdataSet* rrset,
+                 const RdataSet* rdset,
                  const ZoneNode* node,
+                 ZoneFinder::FindOptions options,
                  bool wild = false,
-                 const Name* qname = NULL) {
+                 const Name* qname = NULL)
+{
     ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
     const Name* rename = NULL;
 
@@ -182,9 +247,10 @@ createFindResult(const RRClass& rrclass,
         }
     }
 
-    return (ZoneFinderResultContext(code, createTreeNodeRRset(node, rrset,
-                                                              rrclass, rename),
-                                    flags, node));
+    return (ZoneFinderResultContext(code, createTreeNodeRRset(node, rdset,
+                                                              rrclass, options,
+                                                              rename),
+                                    flags, zone_data, node, rdset));
 }
 
 // A helper function for NSEC-signed zones.  It searches the zone for
@@ -341,19 +407,22 @@ public:
 // caught above.
 //
 // If none of the above succeeds, we conclude the name doesn't exist in
-// the zone, and throw an OutOfZone exception.
+// the zone, and throw an OutOfZone exception by default.  If the optional
+// out_of_zone_ok is true, it returns an NXDOMAIN result with NULL data so
+// the caller can take an action to it (technically it's not "NXDOMAIN",
+// but the caller is assumed not to rely on the difference.)
 FindNodeResult findNode(const ZoneData& zone_data,
-                        const Name& name,
+                        const LabelSequence& name_labels,
                         ZoneChain& node_path,
-                        ZoneFinder::FindOptions options)
+                        ZoneFinder::FindOptions options,
+                        bool out_of_zone_ok = false)
 {
     ZoneNode* node = NULL;
     FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
 
     const ZoneTree& tree(zone_data.getZoneTree());
-    ZoneTree::Result result = tree.find(isc::dns::LabelSequence(name),
-                                        &node, node_path, cutCallback,
-                                        &state);
+    const ZoneTree::Result result = tree.find(name_labels, &node, node_path,
+                                              cutCallback, &state);
     const unsigned int zonecut_flag =
         (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
     if (result == ZoneTree::EXACTMATCH) {
@@ -377,7 +446,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
         if (node_path.getLastComparisonResult().getRelation() ==
             NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
             LOG_DEBUG(logger, DBG_TRACE_DATA,
-                      DATASRC_MEM_SUPER_STOP).arg(name);
+                      DATASRC_MEM_SUPER_STOP).arg(name_labels);
             const ZoneNode* nsec_node;
             const RdataSet* nsec_rds = getClosestNSEC(zone_data,
                                                       node_path,
@@ -398,7 +467,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
                 // baz.foo.wild.example. The common ancestor, foo.wild.example,
                 // should cancel wildcard.  Treat it as NXDOMAIN.
                 LOG_DEBUG(logger, DBG_TRACE_DATA,
-                          DATASRC_MEM_WILDCARD_CANCEL).arg(name);
+                          DATASRC_MEM_WILDCARD_CANCEL).arg(name_labels);
                     const ZoneNode* nsec_node;
                     const RdataSet* nsec_rds = getClosestNSEC(zone_data,
                                                               node_path,
@@ -431,53 +500,198 @@ FindNodeResult findNode(const ZoneData& zone_data,
                         FindNodeResult::FIND_WILDCARD | zonecut_flag));
         }
 
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).arg(name);
+        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_NOT_FOUND).
+            arg(name_labels);
         const ZoneNode* nsec_node;
         const RdataSet* nsec_rds = getClosestNSEC(zone_data, node_path,
                                                   &nsec_node, options);
         return (FindNodeResult(ZoneFinder::NXDOMAIN, nsec_node, nsec_rds));
     } else {
         // If the name is neither an exact or partial match, it is
-        // out of bailiwick, which is considered an error.
-        isc_throw(OutOfZone, name.toText() << " not in " <<
+        // out of bailiwick, which is considered an error, unless the caller
+        // is willing to accept it.
+        if (out_of_zone_ok) {
+            return (FindNodeResult(ZoneFinder::NXDOMAIN, NULL, NULL));
+        }
+        isc_throw(OutOfZone, name_labels << " not in " <<
                              zone_data.getOriginNode()->getName());
     }
 }
 
 } // end anonymous namespace
 
-// Specialization of the ZoneFinder::Context for the in-memory finder.
+
+/// \brief Specialization of the ZoneFinder::Context for the in-memory finder.
+///
+/// Note that we don't have a specific constructor for the findAll() case.
+/// For (successful) type ANY query, found_node points to the
+/// corresponding zone node, which is recorded within this specialized
+/// context.
 class InMemoryZoneFinder::Context : public ZoneFinder::Context {
 public:
-    /// \brief Constructor.
-    ///
-    /// Note that we don't have a specific constructor for the findAll() case.
-    /// For (successful) type ANY query, found_node points to the
-    /// corresponding RB node, which is recorded within this specialized
-    /// context.
     Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
-            ZoneFinderResultContext result) :
+            const RRClass& rrclass, const ZoneFinderResultContext& result) :
         ZoneFinder::Context(finder, options,
                             ResultContext(result.code, result.rrset,
                                           result.flags)),
-        rrset_(result.rrset), found_node_(result.found_node)
+        rrclass_(rrclass), zone_data_(result.zone_data),
+        found_node_(result.found_node),
+        found_rdset_(result.found_rdset)
     {}
 
+protected:
+    virtual void getAdditionalImpl(const std::vector<RRType>& requested_types,
+                                   std::vector<ConstRRsetPtr>& result)
+    {
+        if (found_rdset_ != NULL) {
+            // Normal query with successful result.
+            getAdditionalForRdataset(found_rdset_, requested_types, result,
+                                     options_);
+        } else if (found_node_ != NULL) {
+            // Successful type ANY query result.  Call
+            // getAdditionalForRdataset for each RdataSet of the node.
+            for (const RdataSet* rdset = found_node_->getData();
+                 rdset != NULL;
+                 rdset = rdset->getNext())
+            {
+                getAdditionalForRdataset(rdset, requested_types, result,
+                                         options_);
+            }
+        }
+    }
+
 private:
-    const TreeNodeRRsetPtr rrset_;
+    // Main subroutine of getAdditionalImpl, iterate over Rdata fields
+    // find, create, and insert necessary additional RRsets.
+    void
+    getAdditionalForRdataset(const RdataSet* rdset,
+                             const std::vector<RRType>& requested_types,
+                             std::vector<ConstRRsetPtr>& result,
+                             ZoneFinder::FindOptions orig_options) const
+    {
+        ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT;
+        if ((orig_options & ZoneFinder::FIND_DNSSEC) != 0) {
+            options = options | ZoneFinder::FIND_DNSSEC;
+        }
+        if (rdset->type == RRType::NS()) {
+            options = options | ZoneFinder::FIND_GLUE_OK;
+        }
+
+        RdataReader(rrclass_, rdset->type, rdset->getDataBuf(),
+                    rdset->getRdataCount(), rdset->getSigRdataCount(),
+                    boost::bind(&Context::findAdditional, this,
+                                &requested_types, &result, options, _1, _2),
+                    &RdataReader::emptyDataAction).iterate();
+    }
+
+    // RdataReader callback for additional section processing.
+    void
+    findAdditional(const std::vector<RRType>* requested_types,
+                   std::vector<ConstRRsetPtr>* result,
+                   ZoneFinder::FindOptions options,
+                   const LabelSequence& name_labels,
+                   RdataNameAttributes attr) const;
+
+    // Subroutine for findAdditional() to unify the normal and wildcard match
+    // cases.
+    void
+    findAdditionalHelper(const std::vector<RRType>* requested_types,
+                         std::vector<ConstRRsetPtr>* result,
+                         const ZoneNode* node,
+                         ZoneFinder::FindOptions options,
+                         const Name* real_name) const
+    {
+        const std::vector<RRType>::const_iterator type_beg =
+            requested_types->begin();
+        const std::vector<RRType>::const_iterator type_end =
+            requested_types->end();
+        for (const RdataSet* rdset = node->getData();
+             rdset != NULL;
+             rdset = rdset->getNext())
+        {
+            // Checking all types for all RdataSets could be suboptimal.
+            // This can be a bit more optimized, but unless we have many
+            // requested types the effect is probably marginal.  For now we
+            // keep it simple.
+            if (std::find(type_beg, type_end, rdset->type) != type_end) {
+                result->push_back(createTreeNodeRRset(node, rdset, rrclass_,
+                                                      options, real_name));
+            }
+        }
+    }
+
+private:
+    const RRClass rrclass_;
+    const ZoneData* const zone_data_;
     const ZoneNode* const found_node_;
+    const RdataSet* const found_rdset_;
 };
 
+void
+InMemoryZoneFinder::Context::findAdditional(
+    const std::vector<RRType>* requested_types,
+    std::vector<ConstRRsetPtr>* result,
+    ZoneFinder::FindOptions options,
+    const LabelSequence& name_labels,
+    RdataNameAttributes attr) const
+{
+    // Ignore name data that don't need additional processing.
+    if ((attr & NAMEATTR_ADDITIONAL) == 0) {
+        return;
+    }
+
+    // Find the zone node for the additional name.  By passing true as the
+    // last parameter of findNode() we ignore out-of-zone names.
+    ZoneChain node_path;
+    const FindNodeResult node_result =
+        findNode(*zone_data_, name_labels, node_path, options, true);
+    // we only need non-empty exact match
+    if (node_result.code != SUCCESS) {
+        return;
+    }
+
+    // Ignore data at a zone cut (due to subdomain delegation) unless glue is
+    // allowed.  Checking the node callback flag is a cheap way to detect
+    // zone cuts, but it includes DNAME delegation, in which case we should
+    // keep finding the additional records regardless of the 'GLUE_OK' flag.
+    // The last two conditions limit the case to delegation NS, i.e, the node
+    // has an NS and it's not the zone origin.
+    const ZoneNode* node = node_result.node;
+    if ((options & ZoneFinder::FIND_GLUE_OK) == 0 &&
+        node->getFlag(ZoneNode::FLAG_CALLBACK) &&
+        node != zone_data_->getOriginNode() &&
+        RdataSet::find(node->getData(), RRType::NS()) != NULL) {
+        return;
+    }
+
+    // Examine RdataSets of the node, and create and insert requested types
+    // of RRsets as we find them.
+    if ((node_result.flags & FindNodeResult::FIND_WILDCARD) == 0) {
+        // normal case
+        findAdditionalHelper(requested_types, result, node, options, NULL);
+    } else {
+        // if the additional name is subject to wildcard substitution, we need
+        // to create a name object for the "real" (after substitution) name.
+        // This is expensive, but in the additional processing this should be
+        // very rare cases and acceptable.
+        size_t data_len;
+        const uint8_t* data;
+        data = name_labels.getData(&data_len);
+        util::InputBuffer buffer(data, data_len);
+        const Name real_name(buffer);
+        findAdditionalHelper(requested_types, result, node, options,
+                             &real_name);
+    }
+}
+
 boost::shared_ptr<ZoneFinder::Context>
 InMemoryZoneFinder::find(const isc::dns::Name& name,
                 const isc::dns::RRType& type,
                 const FindOptions options)
 {
-    return ZoneFinderContextPtr(new Context(*this, options,
-                                            find_internal(name,
-                                                          type,
-                                                          NULL,
-                                                          options)));
+    return (ZoneFinderContextPtr(new Context(*this, options, rrclass_,
+                                             find_internal(name, type,
+                                                           NULL, options))));
 }
 
 boost::shared_ptr<ZoneFinder::Context>
@@ -485,11 +699,11 @@ InMemoryZoneFinder::findAll(const isc::dns::Name& name,
         std::vector<isc::dns::ConstRRsetPtr>& target,
         const FindOptions options)
 {
-    return ZoneFinderContextPtr(new Context(*this, options,
-                                            find_internal(name,
-                                                          RRType::ANY(),
-                                                          &target,
-                                                          options)));
+    return (ZoneFinderContextPtr(new Context(*this, options, rrclass_,
+                                             find_internal(name,
+                                                           RRType::ANY(),
+                                                           &target,
+                                                           options))));
 }
 
 ZoneFinderResultContext
@@ -502,10 +716,11 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
     // in findNode().  We simply construct a result structure and return.
     ZoneChain node_path;
     const FindNodeResult node_result =
-        findNode(zone_data_, name, node_path, options);
+        findNode(zone_data_, LabelSequence(name), node_path, options);
     if (node_result.code != SUCCESS) {
         return (createFindResult(rrclass_, zone_data_, node_result.code,
-                                 node_result.rrset, node_result.node));
+                                 node_result.rrset, node_result.node,
+                                 options));
     }
 
     const ZoneNode* node = node_result.node;
@@ -524,25 +739,26 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
         const RdataSet* nsec_rds = getClosestNSEC(zone_data_, node_path,
                                                   &nsec_node, options);
         return (createFindResult(rrclass_, zone_data_, NXRRSET,
-                                 nsec_rds,
-                                 nsec_node,
-                                 wild));
+                                 nsec_rds, nsec_node, options, wild));
     }
 
     const RdataSet* found;
 
     // If the node callback is enabled, this may be a zone cut.  If it
     // has a NS RR, we should return a delegation, but not in the apex.
-    // There is one exception: the case for DS query, which should always
-    // be considered in-zone lookup.
+    // There are two exceptions:
+    // - the case for DS query, which should always be considered in-zone
+    //   lookup.
+    // - when we are looking for glue records (FIND_GLUE_OK)
     if (node->getFlag(ZoneNode::FLAG_CALLBACK) &&
-            node != zone_data_.getOriginNode() && type != RRType::DS()) {
+        (options & FIND_GLUE_OK) == 0 &&
+        node != zone_data_.getOriginNode() && type != RRType::DS()) {
         found = RdataSet::find(node->getData(), RRType::NS());
         if (found != NULL) {
             LOG_DEBUG(logger, DBG_TRACE_DATA,
                       DATASRC_MEM_EXACT_DELEGATION).arg(name);
             return (createFindResult(rrclass_, zone_data_, DELEGATION,
-                                     found, node, wild, &name));
+                                     found, node, options, wild, &name));
         }
     }
 
@@ -552,13 +768,13 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
         const RdataSet* cur_rds = node->getData();
         while (cur_rds != NULL) {
             target->push_back(createTreeNodeRRset(node, cur_rds, rrclass_,
-                                                  &name));
+                                                  options, &name));
             cur_rds = cur_rds->getNext();
         }
         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
             arg(name);
         return (createFindResult(rrclass_, zone_data_, SUCCESS, NULL, node,
-                                 wild, &name));
+                                 options, wild, &name));
     }
 
     found = RdataSet::find(node->getData(), type);
@@ -567,7 +783,7 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
             arg(type);
         return (createFindResult(rrclass_, zone_data_, SUCCESS, found, node,
-                                 wild, &name));
+                                 options, wild, &name));
     } else {
         // Next, try CNAME.
         found = RdataSet::find(node->getData(), RRType::CNAME());
@@ -575,20 +791,166 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
 
             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
             return (createFindResult(rrclass_, zone_data_, CNAME, found, node,
-                                     wild, &name));
+                                     options, wild, &name));
         }
     }
     // No exact match or CNAME.  Get NSEC if necessary and return NXRRSET.
     return (createFindResult(rrclass_, zone_data_, NXRRSET,
                              getNSECForNXRRSET(zone_data_, options, node),
-                             node, wild, &name));
+                             node, options, wild, &name));
 }
 
 isc::datasrc::ZoneFinder::FindNSEC3Result
 InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
-    (void)name;
-    (void)recursive;
-    isc_throw(isc::NotImplemented, "not completed yet! please implement me");
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3).arg(name).
+        arg(recursive ? "recursive" : "non-recursive");
+
+    uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    const LabelSequence origin_ls(zone_data_.getOriginNode()->
+                                  getAbsoluteLabels(labels_buf));
+    const LabelSequence name_ls(name);
+
+    if (!zone_data_.isNSEC3Signed()) {
+        isc_throw(DataSourceError,
+                  "findNSEC3 attempt for non NSEC3 signed zone: " <<
+                  origin_ls << "/" << getClass());
+    }
+
+    const NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+    // This would be a programming mistake, as ZoneData::isNSEC3Signed()
+    // should check this.
+    assert(nsec3_data != NULL);
+
+    const ZoneTree& tree = nsec3_data->getNSEC3Tree();
+    if (tree.getNodeCount() == 0) {
+        isc_throw(DataSourceError,
+                  "findNSEC3 attempt but zone has no NSEC3 RRs: " <<
+                  origin_ls << "/" << getClass());
+    }
+
+    const NameComparisonResult cmp_result = name_ls.compare(origin_ls);
+    if (cmp_result.getRelation() != NameComparisonResult::EQUAL &&
+        cmp_result.getRelation() != NameComparisonResult::SUBDOMAIN) {
+        isc_throw(OutOfZone, "findNSEC3 attempt for out-of-zone name: "
+                  << name_ls << ", zone: " << origin_ls << "/"
+                  << getClass());
+    }
+
+    // Convenient shortcuts
+    const unsigned int olabels = origin_ls.getLabelCount();
+    const unsigned int qlabels = name.getLabelCount();
+    // placeholder of the next closer proof
+    const ZoneNode* covering_node(NULL);
+
+    // Now we'll first look up the origin node and initialize orig_chain
+    // with it.
+    ZoneChain orig_chain;
+    const ZoneNode* node(NULL);
+    ZoneTree::Result result =
+         tree.find<void*>(origin_ls, &node, orig_chain, NULL, NULL);
+    if (result != ZoneTree::EXACTMATCH) {
+        // If the origin node doesn't exist, simply fail.
+        isc_throw(DataSourceError,
+                  "findNSEC3 attempt but zone has no NSEC3 RRs: " <<
+                  origin_ls << "/" << getClass());
+    }
+
+    const boost::scoped_ptr<NSEC3Hash> hash
+        (NSEC3Hash::create(nsec3_data->hashalg,
+                           nsec3_data->iterations,
+                           nsec3_data->getSaltData(),
+                           nsec3_data->getSaltLen()));
+
+    // Examine all names from the query name to the origin name, stripping
+    // the deepest label one by one, until we find a name that has a matching
+    // NSEC3 hash.
+    for (unsigned int labels = qlabels; labels >= olabels; --labels) {
+        const Name& hname = (labels == qlabels ?
+                             name : name.split(qlabels - labels, labels));
+        const std::string hlabel = hash->calculate(hname);
+
+        LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_FINDNSEC3_TRYHASH).
+            arg(name).arg(labels).arg(hlabel);
+
+        node = NULL;
+        ZoneChain chain(orig_chain);
+
+        // Now, make a label sequence relative to the origin.
+        const Name hlabel_name(hlabel);
+        LabelSequence hlabel_ls(hlabel_name);
+        // Remove trailing '.' making it relative
+        hlabel_ls.stripRight(1);
+
+        // Find hlabel relative to the orig_chain.
+        result = tree.find<void*>(hlabel_ls, &node, chain, NULL, NULL);
+        if (result == ZoneTree::EXACTMATCH) {
+            // We found an exact match.
+            ConstRRsetPtr closest = createNSEC3RRset(node, getClass());
+            ConstRRsetPtr next;
+            if (covering_node != NULL) {
+                next = createNSEC3RRset(covering_node, getClass());
+            }
+
+            LOG_DEBUG(logger, DBG_TRACE_BASIC,
+                      DATASRC_MEM_FINDNSEC3_MATCH).arg(name).arg(labels).
+                arg(*closest);
+
+            return (FindNSEC3Result(true, labels, closest, next));
+        } else {
+            while ((covering_node = tree.previousNode(chain)) != NULL &&
+                   covering_node->isEmpty()) {
+                ;
+            }
+            if (covering_node == NULL) {
+                covering_node = tree.largestNode();
+            }
+
+            if (!recursive) {   // in non recursive mode, we are done.
+                ConstRRsetPtr closest;
+                if (covering_node != NULL) {
+                    closest = createNSEC3RRset(covering_node, getClass());
+
+                    LOG_DEBUG(logger, DBG_TRACE_BASIC,
+                              DATASRC_MEM_FINDNSEC3_COVER).
+                        arg(name).arg(*closest);
+                }
+
+                return (FindNSEC3Result(false, labels,
+                                        closest, ConstRRsetPtr()));
+            }
+        }
+    }
+
+    isc_throw(DataSourceError, "recursive findNSEC3 mode didn't stop, likely "
+              "a broken NSEC3 zone: " << getOrigin() << "/"
+              << getClass());
+}
+
+Name
+InMemoryZoneFinder::getOrigin() const {
+    size_t data_len;
+    const uint8_t* data;
+
+    // Normally the label sequence of the origin node should be absolute,
+    // in which case we can simply generate the origin name from the labels.
+    const LabelSequence node_labels = zone_data_.getOriginNode()->getLabels();
+    if (node_labels.isAbsolute()) {
+        data = node_labels.getData(&data_len);
+    } else {
+        // In future we may allow adding out-of-zone names in the zone tree.
+        // For example, to hold out-of-zone NS names so we can establish a
+        // shortcut link to them as an optimization.  If and when that happens
+        // the origin node may not have an absolute label (consider the zone
+        // is example.org and we add ns.noexample.org).  In that case
+        // we first need to construct the absolute label sequence and then
+        // construct the name.
+        uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+        const LabelSequence name_labels =
+            zone_data_.getOriginNode()->getAbsoluteLabels(labels_buf);
+        data = name_labels.getData(&data_len);
+    }
+    util::InputBuffer buffer(data, data_len);
+    return (Name(buffer));
 }
 
 } // namespace memory

+ 10 - 28
src/lib/datasrc/memory/zone_finder.h

@@ -23,30 +23,15 @@
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 
+#include <string>
+
 namespace isc {
 namespace datasrc {
 namespace memory {
-
-class ZoneFinderResultContext {
-public:
-    /// \brief Constructor
-    ///
-    /// The first three parameters correspond to those of
-    /// ZoneFinder::ResultContext.  If node is non NULL, it specifies the
-    /// found RBNode in the search.
-    ZoneFinderResultContext(ZoneFinder::Result code_param,
-                            TreeNodeRRsetPtr rrset_param,
-                            ZoneFinder::FindResultFlags flags_param,
-                            const ZoneNode* node) :
-        code(code_param), rrset(rrset_param), flags(flags_param),
-        found_node(node)
-    {}
-
-    const ZoneFinder::Result code;
-    const TreeNodeRRsetPtr rrset;
-    const ZoneFinder::FindResultFlags flags;
-    const ZoneNode* const found_node;
-};
+namespace internal {
+// intermediate result context, only used in the zone finder implementation.
+class ZoneFinderResultContext;
+}
 
 /// A derived zone finder class intended to be used with the memory data
 /// source, using ZoneData for its contents.
@@ -92,16 +77,13 @@ public:
     findNSEC3(const isc::dns::Name& name, bool recursive);
 
     /// \brief Returns the origin of the zone.
-    virtual isc::dns::Name getOrigin() const {
-        return zone_data_.getOriginNode()->getName();
-    }
+    virtual isc::dns::Name getOrigin() const;
 
     /// \brief Returns the RR class of the zone.
     virtual isc::dns::RRClass getClass() const {
-        return rrclass_;
+        return (rrclass_);
     }
 
-
 private:
     /// \brief In-memory version of finder context.
     ///
@@ -110,7 +92,7 @@ private:
     class Context;
 
     /// Actual implementation for both find() and findAll()
-    ZoneFinderResultContext find_internal(
+    internal::ZoneFinderResultContext find_internal(
         const isc::dns::Name& name,
         const isc::dns::RRType& type,
         std::vector<isc::dns::ConstRRsetPtr>* target,
@@ -118,7 +100,7 @@ private:
         FIND_DEFAULT);
 
     const ZoneData& zone_data_;
-    const isc::dns::RRClass& rrclass_;
+    const isc::dns::RRClass rrclass_;
 };
 
 } // namespace memory

+ 0 - 116
src/lib/datasrc/query.cc

@@ -1,116 +0,0 @@
-// Copyright (C) 2010  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 <util/buffer.h>
-#include <dns/name.h>
-#include <dns/rrset.h>
-#include <dns/message.h>
-
-#include <cc/data.h>
-
-#include <datasrc/query.h>
-
-using namespace isc::dns;
-
-namespace isc {
-namespace datasrc {
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
-                     const isc::dns::RRType& t,
-                     const isc::dns::Message::Section sect) :
-    q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect),
-    op(AUTH_QUERY), state(GETANSWER), flags(0)
-{}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, 
-                     const isc::dns::RRType& t,
-                     const isc::dns::Message::Section sect,
-                     const Op o) :
-    q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect), op(o),
-    state(GETANSWER), flags(0)
-{}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
-                     const isc::dns::RRType& t,
-                     const isc::dns::Message::Section sect,
-                     const State st) :
-    q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect),
-    op(AUTH_QUERY), state(st), flags(0)
-{}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
-                     const isc::dns::RRType& t,
-                     const isc::dns::Message::Section sect,
-                     const Op o, const State st) :
-    q(qry), qname(n), qclass(qry.qclass()), qtype(t), section(sect), op(o),
-    state(st), flags(0) 
-{}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, 
-                     const isc::dns::RRType& t, const Op o) :
-    q(qry), qname(n), qclass(qry.qclass()), qtype(t),
-    section(Message::SECTION_ANSWER), op(o), state(GETANSWER), flags(0)
-{
-    if (op != SIMPLE_QUERY) {
-        isc_throw(Unexpected, "invalid constructor for this task operation");
-    }
-}
-
-// A referral query doesn't need to specify section, state, or type.
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n, const Op o) :
-    q(qry), qname(n), qclass(qry.qclass()), qtype(RRType::ANY()),
-    section(Message::SECTION_ANSWER), op(o), state(GETANSWER), flags(0)
-{
-    if (op != REF_QUERY) {
-        isc_throw(Unexpected, "invalid constructor for this task operation");
-    }
-}
-
-QueryTask::QueryTask(const Query& qry, const isc::dns::Name& n,
-                     const isc::dns::Message::Section sect, const Op o,
-                     const State st) :
-        q(qry), qname(n), qclass(qry.qclass()), qtype(RRType::ANY()),
-        section(sect), op(o), state(st), flags(0)
-{
-    if (op != GLUE_QUERY && op != NOGLUE_QUERY) {
-        isc_throw(Unexpected, "invalid constructor for this task operation");
-    }
-}
-
-QueryTask::~QueryTask() {}
-
-Query::Query(Message& m, HotCache& c, bool dnssec) :
-    status_(PENDING), qname_(NULL), qclass_(NULL), qtype_(NULL),
-    cache_(&c), message_(&m), want_additional_(true), want_dnssec_(dnssec)
-{
-    // Check message formatting
-    if (message_->getRRCount(Message::SECTION_QUESTION) != 1) {
-        isc_throw(Unexpected, "malformed message: too many questions");
-    }
-
-    // Populate the query task queue with the initial question
-    QuestionPtr question = *message_->beginQuestion();
-    qname_ = &question->getName();
-    qclass_ = &question->getClass();
-    qtype_ = &question->getType();
-    restarts_ = 0;
-
-    querytasks_.push(QueryTaskPtr(new QueryTask(*this, *qname_, *qtype_,
-                                                Message::SECTION_ANSWER)));
-}
-
-Query::~Query() {}
-
-}
-}

+ 0 - 255
src/lib/datasrc/query.h

@@ -1,255 +0,0 @@
-// Copyright (C) 2010  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 __QUERY_H
-#define __QUERY_H
-
-#include <boost/shared_ptr.hpp>
-
-#include <datasrc/cache.h>
-#include <datasrc/data_source.h>
-
-#include <dns/name.h>
-#include <dns/message.h>
-#include <dns/rrtype.h>
-#include <dns/rrclass.h>
-
-#include <queue>
-
-namespace isc {
-namespace datasrc {
-
-class Query;
-typedef boost::shared_ptr<Query> QueryPtr;
-
-// An individual task to be carried out by the query logic
-class QueryTask {
-private:
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    QueryTask(const QueryTask& source);
-    QueryTask& operator=(const QueryTask& source);
-public:
-    // XXX: Members are currently public, but should probably be
-    // moved to private and wrapped in get() functions later.
-
-    // The \c Query that this \c QueryTask was created to service.
-    const Query& q;
-
-    // The standard query tuple: qname/qclass/qtype.
-    // Note that qtype is ignored in the GLUE_QUERY/NOGLUE_QUERY case.
-    const isc::dns::Name qname;
-    const isc::dns::RRClass qclass;
-    const isc::dns::RRType qtype;
-
-    // The section of the reply into which the data should be
-    // written after it has been fetched from the data source.
-    const isc::dns::Message::Section section;
-
-    // The op field indicates the operation to be carried out by
-    // this query task:
-    //
-    // - SIMPLE_QUERY: look for a match for qname/qclass/qtype
-    //   in local data (regardless of whether it is above or below
-    //   a zone cut).
-    //
-    // - AUTH_QUERY: look for a match for qname/qclass/qtype, or
-    //   for qname/qclass/CNAME, or for a referral.
-    //
-    // - GLUE_QUERY: look for matches with qname/qclass/A
-    //   OR qname/class/AAAA in local data, regardless of
-    //   authority, for use in glue.  (This can be implemented
-    //   as two successive SIMPLE_QUERY tasks, but might be
-    //   optimized by the concrete data source implementation
-    //   by turning it into a single database lookup.)
-    //
-    // - NOGLUE_QUERY: same as GLUE_QUERY except that answers
-    //   are rejected if they are below a zone cut.
-    //
-    // - REF_QUERY: look for matches for qname/qclass/NS,
-    //   qname/qclass/DS, and qname/qclass/DNAME.  Used
-    //   to search for a zone cut.
-
-    const enum Op {
-        SIMPLE_QUERY,
-        AUTH_QUERY,
-        GLUE_QUERY,
-        NOGLUE_QUERY,
-        REF_QUERY
-    } op;
-
-    // The state field indicates the state of the query; it controls
-    // the next step after processing each query task.
-    //
-    // - GETANSWER: We are looking for the answer to a primary query.
-    //   (The qname of the task should exactly match the qname of the
-    //   query.)  If we have no match, the query has failed.
-    //
-    // - GETADDITIONAL: We are filling in additional data, either
-    //   as a result of finding NS or MX records via a GETANSWER
-    //   query task, or as a result of finding NS records when
-    //   getting authority-section data.
-    //
-    // - FOLLOWCNAME: We are looking for the target of a CNAME RR that
-    //   was found via a previous GETANSWER query task.  If we have no
-    //   match, the query is still successful.
-    //
-    // (NOTE: It is only necessary to set a task state when pushing
-    // tasks onto the query task queue, which in turn is only necessary
-    // when it's uncertain which data source will be authoritative for the
-    // data.  That's why there is no GETAUTHORITY task state; when
-    // processing an answer, either positive or negative, the authoritative
-    // data source will already have been discovered, and can be queried
-    // directly.)
-
-    enum State {
-        GETANSWER,
-        GETADDITIONAL,
-        FOLLOWCNAME
-    } state;
-
-    // Response flags to indicate conditions encountered while
-    // processing this task.
-    uint32_t flags;
-
-    // Constructors
-    QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t,
-              const isc::dns::Message::Section sect);
-    QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t,
-              const isc::dns::Message::Section sect, Op o);
-    QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t,
-              const isc::dns::Message::Section sect,
-              const State st);
-    QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t,
-              const isc::dns::Message::Section sect,
-              Op o, State st);
-
-    // These are special constructors for particular query task types,
-    // to simplify the code.
-    //
-    // A simple query doesn't need to specify section or state.
-    QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::RRType& t, Op o);
-    // A referral query doesn't need to specify section, state, or type.
-    QueryTask(const Query& q, const isc::dns::Name& n, Op o);
-    // A glue (or noglue) query doesn't need to specify type.
-    QueryTask(const Query& q, const isc::dns::Name& n,
-              const isc::dns::Message::Section sect, Op o, State st);
-
-    ~QueryTask();
-};
-
-typedef boost::shared_ptr<QueryTask> QueryTaskPtr;
-typedef std::queue<QueryTaskPtr> QueryTaskQueue;
-
-// Data Source query
-class Query {
-public:
-    // The state of a query: pending or answered.
-    enum Status {
-        PENDING,
-        ANSWERED
-    };
-
-    ///
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    //@{
-private:
-    Query(const Query& source);
-    Query& operator=(const Query& source);
-public:
-    // Query constructor
-    Query(isc::dns::Message& m, HotCache& c, bool dnssec);
-    /// \brief The destructor.
-    virtual ~Query();
-    //@}
-
-    // wantAdditional() == true indicates that additional-section data
-    // should be looked up while processing this query.  false indicates
-    // that we're only interested in answer-section data
-    bool wantAdditional() { return (want_additional_); }
-    void setWantAdditional(bool d) { want_additional_ = d; }
-
-    // wantDnssec() == true indicates that DNSSEC data should be retrieved
-    // from the data source when this query is being processed
-    bool wantDnssec() const { return (want_dnssec_); }
-    void setWantDnssec(bool d) { want_dnssec_ = d; }
-
-    const isc::dns::Name& qname() const { return (*qname_); }
-    const isc::dns::RRClass& qclass() const { return (*qclass_); }
-    const isc::dns::RRType& qtype() const { return (*qtype_); }
-
-    // Note: these can't be constant member functions because they expose
-    // writable 'handles' of internal member variables.  It's questionable
-    // whether we need these accessors in the first place because the
-    // corresponding members are public (which itself is not a good practice
-    // but it's a different topic), but at the moment we keep them.
-    // We should definitely revisit the design later.
-    isc::dns::Message& message() { return (*message_); }
-    QueryTaskQueue& tasks() { return (querytasks_); }
-
-    Status status() const { return (status_); }
-    void setStatus(Status s) { status_ = s; }
-
-    // Limit CNAME chains to 16 per query, to avoid loops
-    inline bool tooMany() {
-        if (++restarts_ > MAX_RESTARTS) {
-            return (true);
-        }
-        return (false);
-    }
-
-    void setDatasrc(DataSrc* ds) { datasrc_ = ds; }
-    DataSrc* datasrc() const { return (datasrc_); }
-
-    // \brief The query cache.  This is a static member of class \c Query;
-    // the same cache will be used by all instances.
-    HotCache& getCache() const { return (*cache_); }
-
-private:
-    Status status_;
-
-    const isc::dns::Name* qname_;
-    const isc::dns::RRClass* qclass_;
-    const isc::dns::RRType* qtype_;
-
-    HotCache* cache_;
-    DataSrc* datasrc_;
-
-    isc::dns::Message* message_;
-    QueryTaskQueue querytasks_;
-
-    bool want_additional_;
-    bool want_dnssec_;
-
-    static const int MAX_RESTARTS = 16;
-    int restarts_;
-};
-
-}
-}
-
-
-#endif
-
-// Local Variables: 
-// mode: c++
-// End: 

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

@@ -1,917 +0,0 @@
-// Copyright (C) 2010  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 <string>
-#include <sstream>
-#include <utility>
-
-#include <sqlite3.h>
-
-#include <datasrc/sqlite3_datasrc.h>
-#include <datasrc/logger.h>
-#include <exceptions/exceptions.h>
-#include <dns/rrttl.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrset.h>
-#include <dns/rrsetlist.h>
-
-namespace {
-// Expected schema.  The major version must match else there is an error.  If
-// the minor version of the database is less than this, a warning is output.
-//
-// It is assumed that a program written to run on m.n of the database will run
-// with a database version m.p, where p is any number.  However, if p < n,
-// we assume that the database structure was upgraded for some reason, and that
-// some advantage may result if the database is upgraded. Conversely, if p > n,
-// The database is at a later version than the program was written for and the
-// program may not be taking advantage of features (possibly performance
-// improvements) added to the database.
-const int SQLITE_SCHEMA_MAJOR_VERSION = 2;
-const int SQLITE_SCHEMA_MINOR_VERSION = 0;
-}
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-
-namespace isc {
-namespace datasrc {
-
-struct Sqlite3Parameters {
-    Sqlite3Parameters() :  db_(NULL), major_version_(-1), minor_version_(-1),
-        q_zone_(NULL), q_record_(NULL), q_addrs_(NULL), q_referral_(NULL),
-        q_any_(NULL), q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL),
-        q_prevnsec3_(NULL)
-    {}
-    sqlite3* db_;
-    int major_version_;
-    int minor_version_;
-    sqlite3_stmt* q_zone_;
-    sqlite3_stmt* q_record_;
-    sqlite3_stmt* q_addrs_;
-    sqlite3_stmt* q_referral_;
-    sqlite3_stmt* q_any_;
-    sqlite3_stmt* q_count_;
-    sqlite3_stmt* q_previous_;
-    sqlite3_stmt* q_nsec3_;
-    sqlite3_stmt* q_prevnsec3_;
-};
-
-namespace {
-const char* const SCHEMA_LIST[] = {
-    "CREATE TABLE schema_version (version INTEGER NOT NULL, "
-        "minor INTEGER NOT NULL DEFAULT 0)",
-    "INSERT INTO schema_version VALUES (2, 0)",
-    "CREATE TABLE zones (id INTEGER PRIMARY KEY, "
-    "name TEXT NOT NULL COLLATE NOCASE, "
-    "rdclass TEXT NOT NULL COLLATE NOCASE DEFAULT 'IN', "
-    "dnssec BOOLEAN NOT NULL DEFAULT 0)",
-    "CREATE INDEX zones_byname ON zones (name)",
-    "CREATE TABLE records (id INTEGER PRIMARY KEY, "
-    "zone_id INTEGER NOT NULL, name TEXT NOT NULL COLLATE NOCASE, "
-    "rname TEXT NOT NULL COLLATE NOCASE, ttl INTEGER NOT NULL, "
-    "rdtype TEXT NOT NULL COLLATE NOCASE, sigtype TEXT COLLATE NOCASE, "
-    "rdata TEXT NOT NULL)",
-    "CREATE INDEX records_byname ON records (name)",
-    "CREATE INDEX records_byrname ON records (rname)",
-    "CREATE INDEX records_bytype_and_rname ON records (rdtype, rname)",
-    "CREATE TABLE nsec3 (id INTEGER PRIMARY KEY, zone_id INTEGER NOT NULL, "
-    "hash TEXT NOT NULL COLLATE NOCASE, "
-    "owner TEXT NOT NULL COLLATE NOCASE, "
-    "ttl INTEGER NOT NULL, rdtype TEXT NOT NULL COLLATE NOCASE, "
-    "rdata TEXT NOT NULL)",
-    "CREATE INDEX nsec3_byhash ON nsec3 (hash)",
-    "CREATE TABLE diffs (id INTEGER PRIMARY KEY, "
-        "zone_id INTEGER NOT NULL, "
-        "version INTEGER NOT NULL, "
-        "operation INTEGER NOT NULL, "
-        "name TEXT NOT NULL COLLATE NOCASE, "
-        "rrtype TEXT NOT NULL COLLATE NOCASE, "
-        "ttl INTEGER NOT NULL, "
-        "rdata TEXT NOT NULL)",
-    NULL
-};
-
-const char* const q_version_str = "SELECT version FROM schema_version";
-const char* const q_minor_str = "SELECT minor FROM schema_version";
-
-const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1";
-
-const char* const q_record_str = "SELECT rdtype, ttl, sigtype, rdata "
-    "FROM records WHERE zone_id=?1 AND name=?2 AND "
-    "((rdtype=?3 OR sigtype=?3) OR "
-    "(rdtype='CNAME' OR sigtype='CNAME') OR "
-    "(rdtype='NS' OR sigtype='NS'))";
-
-const char* const q_addrs_str = "SELECT rdtype, ttl, sigtype, rdata "
-    "FROM records WHERE zone_id=?1 AND name=?2 AND "
-    "(rdtype='A' OR sigtype='A' OR rdtype='AAAA' OR sigtype='AAAA')";
-
-const char* const q_referral_str = "SELECT rdtype, ttl, sigtype, rdata FROM "
-    "records WHERE zone_id=?1 AND name=?2 AND"
-    "(rdtype='NS' OR sigtype='NS' OR rdtype='DS' OR sigtype='DS' OR "
-    "rdtype='DNAME' OR sigtype='DNAME')";
-
-const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
-    "FROM records WHERE zone_id=?1 AND name=?2";
-
-// Note: the wildcard symbol '%' is expected to be added to the text
-// for the placeholder for LIKE given via sqlite3_bind_text().  We don't
-// use the expression such as (?2 || '%') because it would disable the use
-// of indices and could result in terrible performance.
-const char* const q_count_str = "SELECT COUNT(*) FROM records "
-    "WHERE zone_id=?1 AND rname LIKE ?2;";
-
-const char* const q_previous_str = "SELECT name FROM records "
-    "WHERE rname < ?2 AND zone_id=?1 AND rdtype = 'NSEC' "
-    "ORDER BY rname DESC LIMIT 1";
-
-const char* const q_nsec3_str = "SELECT rdtype, ttl, rdata FROM nsec3 "
-    "WHERE zone_id = ?1 AND hash = $2";
-
-const char* const q_prevnsec3_str = "SELECT hash FROM nsec3 "
-    "WHERE zone_id = ?1 AND hash <= $2 ORDER BY hash DESC LIMIT 1";
-
-}
-
-//
-//  Find the exact zone match.  Return -1 if not found, or the zone's
-//  ID if found.  This will always be >= 0 if found.
-//
-int
-Sqlite3DataSrc::hasExactZone(const char* const name) const {
-    int rc;
-
-    sqlite3_reset(dbparameters->q_zone_);
-    rc = sqlite3_bind_text(dbparameters->q_zone_, 1, name, -1, SQLITE_STATIC);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind " << name <<
-                  " to SQL statement (zone)");
-    }
-
-    rc = sqlite3_step(dbparameters->q_zone_);
-    const int i = (rc == SQLITE_ROW) ?
-        sqlite3_column_int(dbparameters->q_zone_, 0) : -1; 
-    sqlite3_reset(dbparameters->q_zone_);
-    return (i);
-}
-
-namespace {
-int
-importSqlite3Rows(sqlite3_stmt* query, const Name& qname, const RRClass& qclass,
-                  const RRType& qtype, const bool nsec3_tree,
-                  RRsetList& result_sets, uint32_t& flags)
-{
-    int rows = 0;
-    int rc = sqlite3_step(query);
-    const bool qtype_is_any = (qtype == RRType::ANY());
-
-    while (rc == SQLITE_ROW) {
-        const char* type = (const char*)sqlite3_column_text(query, 0);
-        int ttl = sqlite3_column_int(query, 1);
-        const char* sigtype = NULL;
-        const char* rdata;
-
-        if (nsec3_tree) {
-            rdata = (const char*)sqlite3_column_text(query, 2);
-            if (RRType(type) == RRType::RRSIG()) {
-                sigtype = "NSEC3";
-            }
-        } else {
-            sigtype = (const char*)sqlite3_column_text(query, 2);
-            rdata = (const char*)sqlite3_column_text(query, 3);
-        }
-
-        const RRType base_rrtype(sigtype != NULL ? sigtype : type);
-
-        // found an NS; we need to inform the caller that this might be a
-        // referral, but we do not return the NS RRset to the caller
-        // unless asked for it.
-        if (base_rrtype == RRType::NS()) {
-            flags |= DataSrc::REFERRAL;
-            if (!qtype_is_any && qtype != RRType::NS()) {
-                rc = sqlite3_step(query);
-                continue;
-            }
-        }
-
-        ++rows;
-
-        // Looking for something else but found CNAME
-        if (base_rrtype == RRType::CNAME() && qtype != RRType::CNAME()) {
-            if (qtype == RRType::NSEC()) {
-                // NSEC query, just skip the CNAME
-                rc = sqlite3_step(query);
-                continue;
-            } else if (!qtype_is_any) {
-                // include the CNAME, but don't flag it for chasing if
-                // this is an ANY query
-                flags |= DataSrc::CNAME_FOUND;
-            }
-        }
-
-        RRsetPtr rrset = result_sets.findRRset(base_rrtype, qclass);
-        if (rrset == NULL) {
-            rrset = RRsetPtr(new RRset(qname, qclass, base_rrtype, RRTTL(ttl)));
-            result_sets.addRRset(rrset);
-        }
-
-        if (sigtype == NULL && base_rrtype == rrset->getType()) {
-            rrset->addRdata(createRdata(rrset->getType(), qclass, rdata));
-            if (ttl > rrset->getTTL().getValue()) {
-                rrset->setTTL(RRTTL(ttl));
-            }
-        } else if (sigtype != NULL && base_rrtype == rrset->getType()) {
-            RdataPtr rrsig = createRdata(RRType::RRSIG(), qclass, rdata);
-            if (rrset->getRRsig()) {
-                rrset->getRRsig()->addRdata(rrsig);
-            } else {
-                RRsetPtr sigs = RRsetPtr(new RRset(qname, qclass,
-                                                   RRType::RRSIG(),
-                                                   RRTTL(ttl)));
-                sigs->addRdata(rrsig);
-                rrset->addRRsig(sigs);
-            }
-
-            if (ttl > rrset->getRRsig()->getTTL().getValue()) {
-                rrset->getRRsig()->setTTL(RRTTL(ttl));
-            }
-        }
-
-        rc = sqlite3_step(query);
-    }
-
-    return (rows);
-}
-}
-
-int
-Sqlite3DataSrc::findRecords(const Name& name, const RRType& rdtype,
-                            RRsetList& target, const Name* zonename,
-                            const Mode mode, uint32_t& flags) const
-{
-    LOG_DEBUG(logger, DBG_TRACE_DETAILED, DATASRC_SQLITE_FINDREC).arg(name).
-        arg(rdtype);
-    flags = 0;
-    int zone_id = (zonename == NULL) ? findClosest(name, NULL) :
-        findClosest(*zonename, NULL);
-    if (zone_id < 0) {
-        flags = NO_SUCH_ZONE;
-        return (0);
-    }
-
-    sqlite3_stmt* query;
-    switch (mode) {
-    case ADDRESS:
-        query = dbparameters->q_addrs_;
-        break;
-    case DELEGATION:
-        query = dbparameters->q_referral_;
-        break;
-    default:
-        if (rdtype == RRType::ANY()) {
-            query = dbparameters->q_any_;
-        } else {
-            query = dbparameters->q_record_;
-        }
-        break;
-    }
-
-    sqlite3_reset(query);
-    sqlite3_clear_bindings(query);
-
-    int rc;
-    rc = sqlite3_bind_int(query, 1, zone_id);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
-                  " to SQL statement (query)");
-    }
-    const string name_text = name.toText();
-    rc = sqlite3_bind_text(query, 2, name_text.c_str(), -1, SQLITE_STATIC);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind name " << name_text <<
-                  " to SQL statement (query)");
-    }
-
-    const string rdtype_text = rdtype.toText();
-    if (query == dbparameters->q_record_) {
-        rc = sqlite3_bind_text(query, 3, rdtype_text.c_str(), -1,
-                               SQLITE_STATIC);
-        if (rc != SQLITE_OK) {
-            isc_throw(Sqlite3Error, "Could not bind RR type " <<
-                      rdtype.toText() << " to SQL statement (query)");
-        }
-    }
-
-    const int rows = importSqlite3Rows(query, name, getClass(), rdtype, false,
-                                       target, flags);
-    sqlite3_reset(query);
-    if (rows > 0) {
-        return (rows);
-    }
-
-    //
-    // No rows were found.  We need to find out whether there are
-    // any RRs with that name to determine whether this is NXDOMAIN or
-    // NXRRSET
-    //
-    sqlite3_reset(dbparameters->q_count_);
-    sqlite3_clear_bindings(dbparameters->q_count_);
-
-    rc = sqlite3_bind_int(dbparameters->q_count_, 1, zone_id);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
-                  " to SQL statement (qcount)");
-    }
-
-    const string revname_text = name.reverse().toText() + "%";
-    rc = sqlite3_bind_text(dbparameters->q_count_, 2,
-                           revname_text.c_str(),
-                           -1, SQLITE_STATIC);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind name " << name.reverse() <<
-                  " to SQL statement (qcount)");
-    }
-
-    rc = sqlite3_step(dbparameters->q_count_);
-    if (rc == SQLITE_ROW) {
-        if (sqlite3_column_int(dbparameters->q_count_, 0) != 0) {
-            flags |= TYPE_NOT_FOUND;
-            sqlite3_reset(dbparameters->q_count_);
-            return (0);
-        }
-    }
-
-    flags |= NAME_NOT_FOUND;
-    sqlite3_reset(dbparameters->q_count_);
-    return (0);
-}
-
-//
-//  Search for the closest enclosing zone.  Will return -1 if not found,
-//  >= 0 if found.  If position is not NULL, it will be filled in with the
-//  longest match found.
-//
-int
-Sqlite3DataSrc::findClosest(const Name& name, unsigned int* position) const {
-    const unsigned int nlabels = name.getLabelCount();
-    for (unsigned int i = 0; i < nlabels; ++i) {
-        const Name matchname(name.split(i));
-        const int rc = hasExactZone(matchname.toText().c_str());
-        if (rc >= 0) {
-            if (position != NULL) {
-                *position = i;
-            }
-            return (rc);
-        }
-    }
-
-    return (-1);
-}
-
-void
-Sqlite3DataSrc::findClosestEnclosure(DataSrcMatch& match) const {
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE).
-        arg(match.getName());
-    if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
-        return;
-    }
-
-    unsigned int position;
-    if (findClosest(match.getName(), &position) == -1) {
-        LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_ENCLOSURE_NOT_FOUND)
-                  .arg(match.getName());
-        return;
-    }
-
-    match.update(*this, match.getName().split(position));
-}
-
-DataSrc::Result
-Sqlite3DataSrc::findPreviousName(const Name& qname,
-                                 Name& target,
-                                 const Name* zonename) const
-{
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_PREVIOUS).arg(qname);
-    const int zone_id = (zonename == NULL) ?
-        findClosest(qname, NULL) : findClosest(*zonename, NULL);
-    if (zone_id < 0) {
-        LOG_ERROR(logger, DATASRC_SQLITE_PREVIOUS_NO_ZONE).arg(qname.toText());
-        return (ERROR);
-    }
-    
-    sqlite3_reset(dbparameters->q_previous_);
-    sqlite3_clear_bindings(dbparameters->q_previous_);
-
-    int rc = sqlite3_bind_int(dbparameters->q_previous_, 1, zone_id);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
-                  " to SQL statement (qprevious)");        
-    }
-    const string revname_text = qname.reverse().toText();
-    rc = sqlite3_bind_text(dbparameters->q_previous_, 2,
-                           revname_text.c_str(), -1, SQLITE_STATIC);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind name " << qname <<
-                  " to SQL statement (qprevious)");
-    }
-  
-    rc = sqlite3_step(dbparameters->q_previous_);
-    if (rc != SQLITE_ROW) {
-        sqlite3_reset(dbparameters->q_previous_);
-        return (ERROR);
-    }
-
-    // XXX: bad cast.  we should revisit this.
-    target = Name((const char*)sqlite3_column_text(dbparameters->q_previous_,
-                                                   0));
-    sqlite3_reset(dbparameters->q_previous_);
-    return (SUCCESS);
-}
-
-DataSrc::Result
-Sqlite3DataSrc::findCoveringNSEC3(const Name& zonename,
-                                  string& hashstr,
-                                  RRsetList& target) const
-{
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND_NSEC3).
-        arg(zonename).arg(hashstr);
-    const int zone_id = findClosest(zonename, NULL);
-    if (zone_id < 0) {
-        LOG_ERROR(logger, DATASRC_SQLITE_FIND_NSEC3_NO_ZONE).arg(zonename);
-        return (ERROR);
-    }
-
-    sqlite3_reset(dbparameters->q_prevnsec3_);
-    sqlite3_clear_bindings(dbparameters->q_prevnsec3_);
-
-    int rc = sqlite3_bind_int(dbparameters->q_prevnsec3_, 1, zone_id);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
-                  " to SQL statement (previous NSEC3)");        
-    }
-
-    rc = sqlite3_bind_text(dbparameters->q_prevnsec3_, 2, hashstr.c_str(),
-                           -1, SQLITE_STATIC);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind hash " << hashstr <<
-                  " to SQL statement (previous NSEC3)");
-    }
-
-    rc = sqlite3_step(dbparameters->q_prevnsec3_);
-    const char* hash;
-    if (rc == SQLITE_ROW) {
-        hash = (const char*) sqlite3_column_text(dbparameters->q_prevnsec3_, 0);
-    } else {
-        // We need to find the final NSEC3 in the chain.
-        // A valid NSEC3 hash is in base32, which contains no
-        // letters higher than V, so a search for the previous 
-        // NSEC3 from "w" will always find it.
-        sqlite3_reset(dbparameters->q_prevnsec3_);
-        rc = sqlite3_bind_text(dbparameters->q_prevnsec3_, 2, "w", -1,
-                               SQLITE_STATIC);
-        if (rc != SQLITE_OK) {
-            isc_throw(Sqlite3Error, "Could not bind \"w\""
-                      " to SQL statement (previous NSEC3)");
-        }
-
-        rc = sqlite3_step(dbparameters->q_prevnsec3_);
-        if (rc != SQLITE_ROW) {
-            return (ERROR);
-        }
-
-        hash = (const char*) sqlite3_column_text(dbparameters->q_prevnsec3_, 0);
-    }
-
-    sqlite3_reset(dbparameters->q_nsec3_);
-    sqlite3_clear_bindings(dbparameters->q_nsec3_);
-
-    rc = sqlite3_bind_int(dbparameters->q_nsec3_, 1, zone_id);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind zone ID " << zone_id <<
-                  " to SQL statement (NSEC3)");        
-    }
-
-    rc = sqlite3_bind_text(dbparameters->q_nsec3_, 2, hash, -1, SQLITE_STATIC);
-    if (rc != SQLITE_OK) {
-        isc_throw(Sqlite3Error, "Could not bind hash " << hash <<
-                  " to SQL statement (NSEC3)");
-    }
-
-    DataSrc::Result result = SUCCESS;
-    uint32_t flags = 0;
-    if (importSqlite3Rows(dbparameters->q_nsec3_,
-                          Name(hash).concatenate(zonename),
-                          getClass(), RRType::NSEC3(), true, target,
-                          flags) == 0 || flags != 0) {
-        result = ERROR;
-    }
-    hashstr = string(hash);
-    sqlite3_reset(dbparameters->q_nsec3_);
-    return (result);
-}
-
-DataSrc::Result
-Sqlite3DataSrc::findRRset(const Name& qname,
-                          const RRClass& qclass,
-                          const RRType& qtype,
-                          RRsetList& target,
-                          uint32_t& flags,
-                          const Name* zonename) const
-{
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FIND).arg(qname).
-        arg(qtype);
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        LOG_ERROR(logger, DATASRC_SQLITE_FIND_BAD_CLASS).arg(getClass()).
-            arg(qclass);
-        return (ERROR);
-    }
-    findRecords(qname, qtype, target, zonename, NORMAL, flags);
-    return (SUCCESS);
-}
-
-DataSrc::Result
-Sqlite3DataSrc::findExactRRset(const Name& qname,
-                               const RRClass& qclass,
-                               const RRType& qtype,
-                               RRsetList& target,
-                               uint32_t& flags,
-                               const Name* zonename) const
-{
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDEXACT).arg(qname).
-        arg(qtype);
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        LOG_ERROR(logger, DATASRC_SQLITE_FINDEXACT_BAD_CLASS).arg(getClass()).
-            arg(qclass);
-        return (ERROR);
-    }
-    findRecords(qname, qtype, target, zonename, NORMAL, flags);
-
-    // Ignore referrals in this case
-    flags &= ~REFERRAL;
-
-    // CNAMEs don't count in this case
-    if (flags & CNAME_FOUND) {
-        flags &= ~CNAME_FOUND;
-        flags |= TYPE_NOT_FOUND;
-    }
-
-    return (SUCCESS);
-}
-
-DataSrc::Result
-Sqlite3DataSrc::findAddrs(const Name& qname,
-                          const RRClass& qclass,
-                          RRsetList& target,
-                          uint32_t& flags,
-                          const Name* zonename) const
-{
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDADDRS).arg(qname);
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        LOG_ERROR(logger, DATASRC_SQLITE_FINDADDRS_BAD_CLASS).arg(getClass()).
-            arg(qclass);
-        return (ERROR);
-    }
-    findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags);
-    return (SUCCESS);
-}
-
-DataSrc::Result
-Sqlite3DataSrc::findReferral(const Name& qname,
-                             const RRClass& qclass,
-                             RRsetList& target,
-                             uint32_t& flags,
-                             const Name* zonename) const
-{
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_SQLITE_FINDREF).arg(qname);
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        LOG_ERROR(logger, DATASRC_SQLITE_FINDREF_BAD_CLASS).arg(getClass()).
-            arg(qclass);
-        return (ERROR);
-    }
-    findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
-    return (SUCCESS);
-}
-
-Sqlite3DataSrc::Sqlite3DataSrc() :
-    dbparameters(new Sqlite3Parameters)
-{
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CREATE);
-}
-
-Sqlite3DataSrc::~Sqlite3DataSrc() {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_DESTROY);
-    if (dbparameters->db_ != NULL) {
-        close();
-    }
-    delete dbparameters;
-}
-
-DataSrc::Result
-Sqlite3DataSrc::init(isc::data::ConstElementPtr config) {
-    if (config && config->contains("database_file")) {
-        open(config->get("database_file")->stringValue());
-    } else {
-        isc_throw(DataSourceError, "No SQLite database file specified");
-    }
-    return (SUCCESS);
-}
-
-namespace {
-// This is a helper class to initialize a Sqlite3 DB safely.  An object of
-// this class encapsulates all temporary resources that are necessary for
-// the initialization, and release them in the destructor.  Once everything
-// is properly initialized, the move() method moves the allocated resources
-// to the main object in an exception free manner.  This way, the main code
-// for the initialization can be exception safe, and can provide the strong
-// exception guarantee.
-class Sqlite3Initializer {
-public:
-    ~Sqlite3Initializer() {
-        if (params_.q_zone_ != NULL) {
-            sqlite3_finalize(params_.q_zone_);
-        }
-        if (params_.q_record_ != NULL) {
-            sqlite3_finalize(params_.q_record_);
-        }
-        if (params_.q_addrs_ != NULL) {
-            sqlite3_finalize(params_.q_addrs_);
-        }
-        if (params_.q_referral_ != NULL) {
-            sqlite3_finalize(params_.q_referral_);
-        }
-        if (params_.q_any_ != NULL) {
-            sqlite3_finalize(params_.q_any_);
-        }
-        if (params_.q_count_ != NULL) {
-            sqlite3_finalize(params_.q_count_);
-        }
-        if (params_.q_previous_ != NULL) {
-            sqlite3_finalize(params_.q_previous_);
-        }
-        if (params_.q_nsec3_ != NULL) {
-            sqlite3_finalize(params_.q_nsec3_);
-        }
-        if (params_.q_prevnsec3_ != NULL) {
-            sqlite3_finalize(params_.q_prevnsec3_);
-        }
-        if (params_.db_ != NULL) {
-            sqlite3_close(params_.db_);
-        }
-    }
-    void move(Sqlite3Parameters* dst) {
-        *dst = params_;
-        params_ = Sqlite3Parameters(); // clear everything
-    }
-    Sqlite3Parameters params_;
-};
-
-sqlite3_stmt*
-prepare(sqlite3* const db, const char* const statement) {
-    sqlite3_stmt* prepared = NULL;
-    if (sqlite3_prepare_v2(db, statement, -1, &prepared, NULL) != SQLITE_OK) { 
-        isc_throw(Sqlite3Error, "Could not prepare SQLite statement: " <<
-                  statement);
-    }
-    return (prepared);
-}
-
-// small function to sleep for 0.1 seconds, needed when waiting for
-// exclusive database locks (which should only occur on startup, and only
-// when the database has not been created yet)
-void do_sleep() {
-    struct timespec req;
-    req.tv_sec = 0;
-    req.tv_nsec = 100000000;
-    nanosleep(&req, NULL);
-}
-
-// returns the schema version element if the schema version table exists
-// returns -1 if it does not
-int check_schema_version_element(sqlite3* db, const char* const version_query) {
-    sqlite3_stmt* prepared = NULL;
-    // At this point in time, the database might be exclusively locked, in
-    // which case even prepare() will return BUSY, so we may need to try a
-    // few times
-    for (size_t i = 0; i < 50; ++i) {
-        int rc = sqlite3_prepare_v2(db, version_query, -1, &prepared, NULL);
-        if (rc == SQLITE_ERROR) {
-            // this is the error that is returned when the table does not
-            // exist
-            return (-1);
-        } else if (rc == SQLITE_OK) {
-            break;
-        } else if (rc != SQLITE_BUSY || i == 50) {
-            isc_throw(Sqlite3Error, "Unable to prepare version query: "
-                        << rc << " " << sqlite3_errmsg(db));
-        }
-        do_sleep();
-    }
-    if (sqlite3_step(prepared) != SQLITE_ROW) {
-        isc_throw(Sqlite3Error,
-                    "Unable to query version: " << sqlite3_errmsg(db));
-    }
-    int version = sqlite3_column_int(prepared, 0);
-    sqlite3_finalize(prepared);
-    return (version);
-}
-
-// Returns the schema major and minor version numbers in a pair.
-// Returns (-1, -1) if the table does not exist, (1, 0) for a V1
-// database, and (n, m) for any other.
-pair<int, int> check_schema_version(sqlite3* db) {
-    int major = check_schema_version_element(db, q_version_str);
-    if (major == -1) {
-        return (make_pair(-1, -1));
-    } else if (major == 1) {
-        return (make_pair(1, 0));
-    } else {
-        int minor = check_schema_version_element(db, q_minor_str);
-        return (make_pair(major, minor));
-    }
-}
-
-// A helper class used in create_database() below so we manage the one shot
-// transaction safely.
-class ScopedTransaction {
-public:
-    ScopedTransaction(sqlite3* db) : db_(NULL) {
-        // try for 5 secs (50*0.1)
-        for (size_t i = 0; i < 50; ++i) {
-            const int rc = sqlite3_exec(db, "BEGIN EXCLUSIVE TRANSACTION",
-                                        NULL, NULL, NULL);
-            if (rc == SQLITE_OK) {
-                break;
-            } else if (rc != SQLITE_BUSY || i == 50) {
-                isc_throw(Sqlite3Error, "Unable to acquire exclusive lock "
-                          "for database creation: " << sqlite3_errmsg(db));
-            }
-            do_sleep();
-        }
-        // Hold the DB pointer once we have successfully acquired the lock.
-        db_ = db;
-    }
-    ~ScopedTransaction() {
-        if (db_ != NULL) {
-            // Note: even rollback could fail in theory, but in that case
-            // we cannot do much for safe recovery anyway.  We could at least
-            // log the event, but for now don't even bother to do that, with
-            // the expectation that we'll soon stop creating the schema in this
-            // module.
-            sqlite3_exec(db_, "ROLLBACK", NULL, NULL, NULL);
-        }
-    }
-    void commit() {
-        if (sqlite3_exec(db_, "COMMIT TRANSACTION", NULL, NULL, NULL) !=
-            SQLITE_OK) {
-            isc_throw(Sqlite3Error, "Unable to commit newly created database "
-                      "schema: " << sqlite3_errmsg(db_));
-        }
-        db_ = NULL;
-    }
-
-private:
-    sqlite3* db_;
-};
-
-// return db version
-pair<int, int> create_database(sqlite3* db) {
-    logger.info(DATASRC_SQLITE_SETUP_OLD_API);
-
-    // try to get an exclusive lock. Once that is obtained, do the version
-    // check *again*, just in case this process was racing another
-    ScopedTransaction transaction(db);
-    pair<int, int> schema_version = check_schema_version(db);
-    if (schema_version.first == -1) {
-        for (int i = 0; SCHEMA_LIST[i] != NULL; ++i) {
-            if (sqlite3_exec(db, SCHEMA_LIST[i], NULL, NULL, NULL) !=
-                SQLITE_OK) {
-                isc_throw(Sqlite3Error,
-                        "Failed to set up schema " << SCHEMA_LIST[i]);
-            }
-        }
-        transaction.commit();
-
-        // Return the version. We query again to ensure that the only point
-        // in which the current schema version is defined is in the
-        // CREATE statements.
-        schema_version = check_schema_version(db);
-    }
-    return (schema_version);
-}
-
-void
-checkAndSetupSchema(Sqlite3Initializer* initializer) {
-    sqlite3* const db = initializer->params_.db_;
-
-    // Note: we use the same SCHEMA_xxx_VERSION log IDs here and in
-    // sqlite3_accessor.cc, which is against our policy of ID uniqueness.
-    // The assumption is that this file will soon be deprecated, and we don't
-    // bother to define separate IDs for the short period.
-    pair<int, int> schema_version = check_schema_version(db);
-    if (schema_version.first == -1) {
-        schema_version = create_database(db);
-    } else if (schema_version.first != SQLITE_SCHEMA_MAJOR_VERSION) {
-        LOG_ERROR(logger, DATASRC_SQLITE_INCOMPATIBLE_VERSION)
-            .arg(schema_version.first).arg(schema_version.second)
-            .arg(SQLITE_SCHEMA_MAJOR_VERSION).arg(SQLITE_SCHEMA_MINOR_VERSION);
-        isc_throw(IncompatibleDbVersion, "Incompatible database version");
-    } else if (schema_version.second < SQLITE_SCHEMA_MINOR_VERSION) {
-        LOG_WARN(logger, DATASRC_SQLITE_COMPATIBLE_VERSION)
-            .arg(schema_version.first).arg(schema_version.second)
-            .arg(SQLITE_SCHEMA_MAJOR_VERSION).arg(SQLITE_SCHEMA_MINOR_VERSION);
-    }
-
-    initializer->params_.major_version_ = schema_version.first;
-    initializer->params_.minor_version_ = schema_version.second;
-    initializer->params_.q_zone_ = prepare(db, q_zone_str);
-    initializer->params_.q_record_ = prepare(db, q_record_str);
-    initializer->params_.q_addrs_ = prepare(db, q_addrs_str);
-    initializer->params_.q_referral_ = prepare(db, q_referral_str);
-    initializer->params_.q_any_ = prepare(db, q_any_str);
-    initializer->params_.q_count_ = prepare(db, q_count_str);
-    initializer->params_.q_previous_ = prepare(db, q_previous_str);
-    initializer->params_.q_nsec3_ = prepare(db, q_nsec3_str);
-    initializer->params_.q_prevnsec3_ = prepare(db, q_prevnsec3_str);
-}
-}
-
-//
-//  Open the database.
-//
-void
-Sqlite3DataSrc::open(const string& name) {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_OPEN).arg(name);
-    if (dbparameters->db_ != NULL) {
-        isc_throw(DataSourceError, "Duplicate SQLite open with " << name);
-    }
-
-    Sqlite3Initializer initializer;
-
-    if (sqlite3_open(name.c_str(), &initializer.params_.db_) != 0) {
-        isc_throw(Sqlite3Error, "Cannot open SQLite database file: " << name);
-    }
-
-    checkAndSetupSchema(&initializer);
-    initializer.move(dbparameters);
-}
-
-//
-//  Close the database.
-//
-DataSrc::Result
-Sqlite3DataSrc::close(void) {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_CLOSE);
-    if (dbparameters->db_ == NULL) {
-        isc_throw(DataSourceError,
-                  "SQLite data source is being closed before open");
-    }
-
-    // XXX: sqlite3_finalize() could fail.  What should we do in that case?
-    sqlite3_finalize(dbparameters->q_zone_);
-    dbparameters->q_zone_ = NULL;
-
-    sqlite3_finalize(dbparameters->q_record_);
-    dbparameters->q_record_ = NULL;
-
-    sqlite3_finalize(dbparameters->q_addrs_);
-    dbparameters->q_addrs_ = NULL;
-
-    sqlite3_finalize(dbparameters->q_referral_);
-    dbparameters->q_referral_ = NULL;
-
-    sqlite3_finalize(dbparameters->q_any_);
-    dbparameters->q_any_ = NULL;
-
-    sqlite3_finalize(dbparameters->q_count_);
-    dbparameters->q_count_ = NULL;
-
-    sqlite3_finalize(dbparameters->q_previous_);
-    dbparameters->q_previous_ = NULL;
-
-    sqlite3_finalize(dbparameters->q_prevnsec3_);
-    dbparameters->q_prevnsec3_ = NULL;
-
-    sqlite3_finalize(dbparameters->q_nsec3_);
-    dbparameters->q_nsec3_ = NULL;
-
-    sqlite3_close(dbparameters->db_);
-    dbparameters->db_ = NULL;
-
-    return (SUCCESS);
-}
-
-}
-}

+ 0 - 130
src/lib/datasrc/sqlite3_datasrc.h

@@ -1,130 +0,0 @@
-// Copyright (C) 2010  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 __DATA_SOURCE_SQLITE3_H
-#define __DATA_SOURCE_SQLITE3_H
-
-#include <string>
-
-#include <exceptions/exceptions.h>
-
-#include <datasrc/data_source.h>
-
-namespace isc {
-
-namespace dns {
-class Name;
-class RRClass;
-class RRType;
-class RRsetList;
-}
-
-namespace datasrc {
-
-class Query;
-struct Sqlite3Parameters;
-
-class Sqlite3Error : public Exception {
-public:
-    Sqlite3Error(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-class IncompatibleDbVersion : public Exception {
-public:
-    IncompatibleDbVersion(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-class Sqlite3DataSrc : public DataSrc {
-    ///
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    //@{
-private:
-    Sqlite3DataSrc(const Sqlite3DataSrc& source);
-    Sqlite3DataSrc& operator=(const Sqlite3DataSrc& source);
-public:
-    Sqlite3DataSrc();
-    ~Sqlite3DataSrc();
-    //@}
-
-    void findClosestEnclosure(DataSrcMatch& match) const;
-
-    Result findRRset(const isc::dns::Name& qname,
-                     const isc::dns::RRClass& qclass,
-                     const isc::dns::RRType& qtype,
-                     isc::dns::RRsetList& target,
-                     uint32_t& flags,
-                     const isc::dns::Name* zonename) const;
-
-    Result findExactRRset(const isc::dns::Name& qname,
-                          const isc::dns::RRClass& qclass,
-                          const isc::dns::RRType& qtype,
-                          isc::dns::RRsetList& target,
-                          uint32_t& flags,
-                          const isc::dns::Name* zonename) const;
-
-    Result findAddrs(const isc::dns::Name& qname,
-                     const isc::dns::RRClass& qclass,
-                     isc::dns::RRsetList& target,
-                     uint32_t& flags,
-                     const isc::dns::Name* zonename) const;
-
-    Result findReferral(const isc::dns::Name& qname,
-                        const isc::dns::RRClass& qclass,
-                        isc::dns::RRsetList& target,
-                        uint32_t& flags,
-                        const isc::dns::Name* zonename) const;
-
-    DataSrc::Result findPreviousName(const isc::dns::Name& qname,
-                                     isc::dns::Name& target,
-                                     const isc::dns::Name* zonename) const;
-
-    Result findCoveringNSEC3(const isc::dns::Name& zonename,
-                             std::string& hash,
-                             isc::dns::RRsetList& target) const;
-
-    Result init() { return (init(isc::data::ElementPtr())); }
-    Result init(const isc::data::ConstElementPtr config);
-    Result close();
-
-private:
-    enum Mode {
-        NORMAL,
-        ADDRESS,
-        DELEGATION
-    };
-
-    void open(const std::string& name);
-    int hasExactZone(const char *name) const;
-    int findRecords(const isc::dns::Name& name, const isc::dns::RRType& rdtype,
-                    isc::dns::RRsetList& target, const isc::dns::Name* zonename,
-                    const Mode mode, uint32_t& flags) const;
-    int findClosest(const isc::dns::Name& name, unsigned int* position) const;
-
-private:
-    Sqlite3Parameters* dbparameters;
-};
-
-}
-}
-
-#endif // __DATA_SOURCE_SQLITE3_H
-
-// Local Variables: 
-// mode: c++
-// End: 

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

@@ -1,275 +0,0 @@
-// Copyright (C) 2010  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 <dns/name.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrset.h>
-#include <dns/rrsetlist.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-
-#include <datasrc/data_source.h>
-#include <datasrc/static_datasrc.h>
-#include <datasrc/logger.h>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-
-namespace isc {
-namespace datasrc {
-
-// This class stores the "static" data for the built-in static data source.
-// Since it's static, it could be literally static, i.e, defined as static
-// objects.  But to avoid the static initialization order fiasco, which would
-// be unlikely to happen for this class in practice but is still possible,
-// we took a safer approach.  A downside of this approach is that redundant
-// copies of exactly the same content of these objects can be created.
-// In practice, however, there's normally at most one StaticDataSrc object,
-// so this should be acceptable (if this turns out to be a real concern we
-// might consider making this class a singleton).
-// We use the "pimpl" idiom for this class.  Operations for this class is
-// not expected to be performance sensitive, so the overhead due to the pimpl
-// should be okay, and it's more beneficial to hide details and minimize
-// inter module dependencies in header files.
-struct StaticDataSrcImpl {
-public:
-    StaticDataSrcImpl();
-    const Name authors_name;
-    const Name version_name;
-    // XXX: unfortunately these can't be ConstRRsetPtr because they'll be
-    // passed to RRsetList::addRRset(), which expect non const RRsetPtr.
-    // We should revisit this design later.
-    RRsetPtr authors;
-    RRsetPtr authors_ns;
-    RRsetPtr authors_soa;
-    RRsetPtr version;
-    RRsetPtr version_ns;
-    RRsetPtr version_soa;
-};
-
-StaticDataSrcImpl::StaticDataSrcImpl() :
-    authors_name("authors.bind"), version_name("version.bind")
-{
-    authors = RRsetPtr(new RRset(authors_name, RRClass::CH(),
-                                 RRType::TXT(), RRTTL(0)));
-    authors->addRdata(generic::TXT("Chen Zhengzhang")); // Jerry
-    authors->addRdata(generic::TXT("Dmitriy Volodin"));
-    authors->addRdata(generic::TXT("Evan Hunt"));
-    authors->addRdata(generic::TXT("Haidong Wang")); // Ocean
-    authors->addRdata(generic::TXT("Haikuo Zhang"));
-    authors->addRdata(generic::TXT("Han Feng"));
-    authors->addRdata(generic::TXT("Jelte Jansen"));
-    authors->addRdata(generic::TXT("Jeremy C. Reed")); 
-    authors->addRdata(generic::TXT("Xie Jiagui")); // Kevin Tes
-    authors->addRdata(generic::TXT("Jin Jian"));
-    authors->addRdata(generic::TXT("JINMEI Tatuya"));
-    authors->addRdata(generic::TXT("Kazunori Fujiwara"));
-    authors->addRdata(generic::TXT("Michael Graff"));
-    authors->addRdata(generic::TXT("Michal Vaner"));
-    authors->addRdata(generic::TXT("Mukund Sivaraman"));
-    authors->addRdata(generic::TXT("Naoki Kambe"));
-    authors->addRdata(generic::TXT("Shane Kerr"));
-    authors->addRdata(generic::TXT("Shen Tingting"));
-    authors->addRdata(generic::TXT("Stephen Morris"));
-    authors->addRdata(generic::TXT("Yoshitaka Aharen"));
-    authors->addRdata(generic::TXT("Zhang Likun"));
-
-    authors_ns = RRsetPtr(new RRset(authors_name, RRClass::CH(),
-                                    RRType::NS(), RRTTL(0)));
-    authors_ns->addRdata(generic::NS(authors_name));
-
-    authors_soa = RRsetPtr(new RRset(authors_name, RRClass::CH(),
-                                     RRType::SOA(), RRTTL(0)));
-    authors_soa->addRdata(generic::SOA(
-                              "authors.bind. hostmaster.authors.bind. "
-                              "0 28800 7200 604800 86400"));
-
-    version = RRsetPtr(new RRset(version_name, RRClass::CH(),
-                                 RRType::TXT(), RRTTL(0)));
-    version->addRdata(generic::TXT(PACKAGE_STRING));
-
-    version_ns = RRsetPtr(new RRset(version_name, RRClass::CH(),
-                                    RRType::NS(), RRTTL(0)));
-    version_ns->addRdata(generic::NS(version_name));
-
-    version_soa = RRsetPtr(new RRset(version_name, RRClass::CH(),
-                                     RRType::SOA(), RRTTL(0)));
-    version_soa->addRdata(generic::SOA(
-                              "version.bind. hostmaster.version.bind. "
-                               "0 28800 7200 604800 86400"));
-}
-
-StaticDataSrc::StaticDataSrc() {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_STATIC_CREATE);
-    setClass(RRClass::CH());
-    impl_ = new StaticDataSrcImpl;
-}
-
-StaticDataSrc::~StaticDataSrc() {
-    delete impl_;
-}
-
-namespace {
-bool
-isSubdomain(const Name& qname, const Name& zone) {
-    const NameComparisonResult::NameRelation cmp =
-        qname.compare(zone).getRelation();
-    return (cmp == NameComparisonResult::EQUAL ||
-            cmp == NameComparisonResult::SUBDOMAIN);
-}
-}
-
-void
-StaticDataSrc::findClosestEnclosure(DataSrcMatch& match) const {
-    const Name& qname = match.getName();
-
-    if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
-        return;
-    }
-
-    if (isSubdomain(qname, impl_->version_name)) {
-        match.update(*this, impl_->version_name);
-        return;
-    }
-
-    if (isSubdomain(qname, impl_->authors_name)) {
-        match.update(*this, impl_->authors_name);
-        return;
-    }
-}
-
-DataSrc::Result
-StaticDataSrc::findRRset(const Name& qname,
-                         const RRClass& qclass, const RRType& qtype,
-                         RRsetList& target, uint32_t& flags,
-                         const Name* const zonename) const
-{
-    LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_STATIC_FIND).arg(qname).
-        arg(qtype);
-    flags = 0;
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        LOG_ERROR(logger, DATASRC_STATIC_CLASS_NOT_CH);
-        return (ERROR);
-    }
-
-    // Identify the appropriate zone.
-    bool is_versionname = false, is_authorsname = false;
-    if (zonename != NULL) {
-        if (*zonename == impl_->version_name &&
-            isSubdomain(qname, impl_->version_name)) {
-            is_versionname = true;
-        } else if (*zonename == impl_->authors_name &&
-                   isSubdomain(qname, impl_->authors_name)) {
-            is_authorsname = true;
-        } else {
-            flags = NO_SUCH_ZONE;
-            return (SUCCESS);
-        }
-    } else {
-        if (isSubdomain(qname, impl_->version_name)) {
-            is_versionname = true;
-        } else if (isSubdomain(qname, impl_->authors_name)) {
-            is_authorsname = true;
-        } else {
-            flags = NO_SUCH_ZONE;
-            return (SUCCESS);
-        }
-    }
-
-    const bool any = (qtype == RRType::ANY());
-
-    if (is_versionname) {
-        if (qname == impl_->version_name) {
-            if (qtype == RRType::TXT() || any) {
-                target.addRRset(impl_->version);
-            }
-            if (qtype == RRType::NS() || any) {
-                target.addRRset(impl_->version_ns);
-            }
-            if (qtype == RRType::SOA() || any) {
-                target.addRRset(impl_->version_soa);
-            }
-            if (target.size() == 0) {
-                flags = TYPE_NOT_FOUND;
-            }
-        } else {
-            flags = NAME_NOT_FOUND;
-        }
-    } else {
-        assert(is_authorsname);
-        if (qname == impl_->authors_name) {
-            if (qtype == RRType::TXT() || any) {
-                target.addRRset(impl_->authors);
-            }
-            if (qtype == RRType::NS() || any) {
-                target.addRRset(impl_->authors_ns);
-            }
-            if (qtype == RRType::SOA() || any) {
-                target.addRRset(impl_->authors_soa);
-            }
-            if (target.size() == 0 ) {
-                flags = TYPE_NOT_FOUND;
-            }
-        } else {
-            flags = NAME_NOT_FOUND;
-        }
-    }
-
-    return (SUCCESS);
-}
-
-DataSrc::Result
-StaticDataSrc::findExactRRset(const Name& qname,
-                              const RRClass& qclass, const RRType& qtype,
-                              RRsetList& target, uint32_t& flags,
-                              const Name* zonename) const
-{
-    return (findRRset(qname, qclass, qtype, target, flags, zonename));
-}
-
-DataSrc::Result
-StaticDataSrc::findPreviousName(const Name&, Name&, const Name*) const {
-    return (NOT_IMPLEMENTED);
-}
-
-DataSrc::Result
-StaticDataSrc::findCoveringNSEC3(const Name&, string&, RRsetList&) const {
-   return (NOT_IMPLEMENTED);
-}
-
-DataSrc::Result
-StaticDataSrc::init() {
-    return (SUCCESS);
-}
-
-// Static data source is "configuration less", so the \c config parameter
-// is intentionally ignored.
-DataSrc::Result
-StaticDataSrc::init(isc::data::ConstElementPtr) {
-    return (init());
-}
-
-DataSrc::Result
-StaticDataSrc::close() {
-    return (SUCCESS);
-}
-
-}
-}

+ 0 - 95
src/lib/datasrc/static_datasrc.h

@@ -1,95 +0,0 @@
-// Copyright (C) 2009  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.
-
-//
-// Sample Datasource implementation; this datasource only returns
-// static content for the queries
-// CH TXT version.bind
-// and
-// CH TXT authors.bind
-//
-
-#ifndef __STATIC_DATA_SOURCE_H
-#define __STATIC_DATA_SOURCE_H
-
-#include <datasrc/data_source.h>
-
-namespace isc {
-
-namespace dns {
-class Name;
-class RRClass;
-class RRType;
-class RRType;
-class RRsetList;
-}
-
-namespace datasrc {
-
-struct StaticDataSrcImpl;
-
-class StaticDataSrc : public DataSrc {
-private:
-    ///
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    //@{
-    StaticDataSrc(const StaticDataSrc& source);
-    StaticDataSrc& operator=(const StaticDataSrc& source);
-public:
-    StaticDataSrc();
-    ~StaticDataSrc();
-    //@}
-
-    void findClosestEnclosure(DataSrcMatch& match) const;
-
-    Result findRRset(const isc::dns::Name& qname,
-                     const isc::dns::RRClass& qclass,
-                     const isc::dns::RRType& qtype,
-                     isc::dns::RRsetList& target,
-                     uint32_t& flags,
-                     const isc::dns::Name* zonename) const;
-
-    Result findExactRRset(const isc::dns::Name& qname,
-                          const isc::dns::RRClass& qclass,
-                          const isc::dns::RRType& qtype,
-                          isc::dns::RRsetList& target,
-                          uint32_t& flags,
-                          const isc::dns::Name* zonename) const;
-
-    Result findPreviousName(const isc::dns::Name& qname,
-                            isc::dns::Name& target,
-                            const isc::dns::Name* zonename) const;
-
-    Result findCoveringNSEC3(const isc::dns::Name& zonename,
-                             std::string& hash,
-                             isc::dns::RRsetList& target) const;
-
-    Result init();
-    Result init(isc::data::ConstElementPtr config);
-    Result close();
-private:
-    StaticDataSrcImpl* impl_;
-};
-
-}
-}
-
-#endif
-
-// Local Variables: 
-// mode: c++
-// End: 

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

@@ -1,4 +1,4 @@
-SUBDIRS = testdata
+SUBDIRS = . memory testdata
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
@@ -47,15 +47,6 @@ common_ldadd += $(GTEST_LDADD) $(SQLITE_LIBS)
 # The general tests
 run_unittests_SOURCES = $(common_sources)
 
-# Commented out by ticket #2165. If you re-enable these, please modify
-# EXTRA_DIST at the bottom of this file.
-#run_unittests_SOURCES += datasrc_unittest.cc
-#run_unittests_SOURCES += static_unittest.cc
-#run_unittests_SOURCES += query_unittest.cc
-#run_unittests_SOURCES += cache_unittest.cc
-#run_unittests_SOURCES += sqlite3_unittest.cc
-#run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
-
 run_unittests_SOURCES += test_client.h test_client.cc
 run_unittests_SOURCES += rbtree_unittest.cc
 run_unittests_SOURCES += logger_unittest.cc
@@ -124,11 +115,3 @@ EXTRA_DIST += testdata/new_minor_schema.sqlite3
 EXTRA_DIST += testdata/newschema.sqlite3
 EXTRA_DIST += testdata/oldschema.sqlite3
 EXTRA_DIST += testdata/static.zone
-
-# Added by ticket #2165
-EXTRA_DIST += datasrc_unittest.cc
-EXTRA_DIST += static_unittest.cc
-EXTRA_DIST += query_unittest.cc
-EXTRA_DIST += cache_unittest.cc
-EXTRA_DIST += sqlite3_unittest.cc
-EXTRA_DIST += test_datasrc.h test_datasrc.cc

+ 0 - 340
src/lib/datasrc/tests/cache_unittest.cc

@@ -1,340 +0,0 @@
-// Copyright (C) 2010  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 <stdexcept>
-
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-#include <dns/rrset.h>
-
-#include <datasrc/cache.h>
-#include <datasrc/data_source.h>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc;
-
-namespace {
-class CacheTest : public ::testing::Test {
-protected:
-    CacheTest() : test_name("test.example.com"),
-                  test_nsname("ns.example.com"),
-                  test_ch("example.com")
-    {
-        RRsetPtr a(new RRset(test_name, RRClass::IN(), RRType::A(),
-                             RRTTL(3600)));
-        a->addRdata(in::A("192.0.2.1"));
-        a->addRdata(in::A("192.0.2.2"));
-
-        RRsetPtr b(new RRset(test_nsname, RRClass::IN(), RRType::NS(),
-                             RRTTL(86400)));
-        RRsetPtr c(new RRset(test_ch, RRClass::CH(), RRType::TXT(),
-                             RRTTL(0)));
-        c->addRdata(generic::TXT("Text record"));
-
-        cache.setSlots(5);
-
-        cache.addPositive(a, 1, 30);
-        cache.addPositive(b, 2, 30);
-        cache.addPositive(c, 4, 30);
-    }
-
-    Name test_name;
-    Name test_nsname;
-    Name test_ch;
-
-    HotCache cache;
-};
-
-class TestRRset : public RRset {
-public:
-    TestRRset(const Name& name, int& counter) :
-        RRset(name, RRClass::IN(), RRType::A(), RRTTL(3600)),
-        counter_(counter)
-    {
-        ++counter_;
-    }
-    ~TestRRset() {
-        --counter_;
-    }
-    int& counter_;
-};
-
-// make sure any remaining cache entries are purged on destruction of the
-// cache.
-TEST_F(CacheTest, cleanup) {
-    HotCache* local_cache(new HotCache);
-    int num_rrsets = 0;
-
-    local_cache->addPositive(RRsetPtr(new TestRRset(Name("example.com"),
-                                                    num_rrsets)), 0, 10);
-    local_cache->addPositive(RRsetPtr(new TestRRset(Name("example.org"),
-                                                    num_rrsets)), 0, 10);
-
-    EXPECT_EQ(2, num_rrsets);
-    delete local_cache;
-    EXPECT_EQ(0, num_rrsets);
-}
-
-TEST_F(CacheTest, slots) {
-    EXPECT_EQ(5, cache.getSlots());
-    EXPECT_EQ(3, cache.getCount());
-}
-
-TEST_F(CacheTest, insert) {
-    RRsetPtr aaaa(new RRset(Name("foo"), RRClass::IN(), RRType::AAAA(),
-                            RRTTL(0)));
-    aaaa->addRdata(in::AAAA("2001:db8:3:bb::5"));
-    cache.addPositive(aaaa, 0, 4);
-
-    EXPECT_EQ(4, cache.getCount());
-
-    RRsetPtr r;
-    uint32_t f;
-    bool hit = cache.retrieve(Name("foo"), RRClass::IN(),
-                                RRType::AAAA(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(aaaa, r);
-}
-
-TEST_F(CacheTest, retrieveOK) {
-    bool hit;
-    RRsetPtr r;
-    uint32_t f;
-
-    // Test repeatedly to ensure that all records remain accessible
-    // even after being promoted to the top of the cache
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(test_name, r->getName());
-    EXPECT_EQ(RRClass::IN(), r->getClass());
-    EXPECT_EQ(RRType::A(), r->getType());
-
-    hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(test_nsname, r->getName());
-    EXPECT_EQ(RRClass::IN(), r->getClass());
-    EXPECT_EQ(RRType::NS(), r->getType());
-
-    hit = cache.retrieve(test_ch, RRClass::CH(), RRType::TXT(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(test_ch, r->getName());
-    EXPECT_EQ(RRClass::CH(), r->getClass());
-    EXPECT_EQ(RRType::TXT(), r->getType());
-    
-    hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(test_nsname, r->getName());
-    EXPECT_EQ(RRClass::IN(), r->getClass());
-    EXPECT_EQ(RRType::NS(), r->getType());
-
-    hit = cache.retrieve(test_ch, RRClass::CH(), RRType::TXT(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(test_ch, r->getName());
-    EXPECT_EQ(RRClass::CH(), r->getClass());
-    EXPECT_EQ(RRType::TXT(), r->getType());
-
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(test_name, r->getName());
-    EXPECT_EQ(RRClass::IN(), r->getClass());
-    EXPECT_EQ(RRType::A(), r->getType());
-
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(test_name, r->getName());
-    EXPECT_EQ(RRClass::IN(), r->getClass());
-    EXPECT_EQ(RRType::A(), r->getType());
-};
-
-TEST_F(CacheTest, flags) {
-    bool hit;
-    RRsetPtr r;
-    uint32_t f;
-
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_TRUE(r);
-    EXPECT_EQ(DataSrc::REFERRAL, f);
-
-    hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_TRUE(r);
-    EXPECT_EQ(DataSrc::CNAME_FOUND, f);
-
-    hit = cache.retrieve(test_ch, RRClass::CH(), RRType::TXT(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_TRUE(r);
-    EXPECT_EQ(DataSrc::NAME_NOT_FOUND, f);
-}
-
-TEST_F(CacheTest, retrieveFail) {
-    bool hit;
-    RRsetPtr r;
-    uint32_t f;
-
-    hit = cache.retrieve(Name("fake"), RRClass::IN(), RRType::A(), r, f);
-    EXPECT_FALSE(hit);
-
-    hit = cache.retrieve(test_name, RRClass::CH(), RRType::A(), r, f);
-    EXPECT_FALSE(hit);
-
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::DNSKEY(), r, f);
-    EXPECT_FALSE(hit);
-}
-
-TEST_F(CacheTest, expire) {
-    // Insert "foo" with a duration of 1 seconds; sleep 2.  The
-    // record should not be returned from the cache even though it's
-    // at the top of the cache.
-    RRsetPtr aaaa(new RRset(Name("foo"), RRClass::IN(), RRType::AAAA(),
-                            RRTTL(0)));
-    aaaa->addRdata(in::AAAA("2001:db8:3:bb::5"));
-    cache.addPositive(aaaa, 0, 1);
-
-    sleep(2);
-
-    RRsetPtr r;
-    uint32_t f;
-    bool hit = cache.retrieve(Name("foo"), RRClass::IN(), RRType::AAAA(), r, f);
-    EXPECT_FALSE(hit);
-};
-
-TEST_F(CacheTest, LRU) {
-    // Retrieve a record, cache four new records; with five slots
-    // in the LRU queue this should remove all the previous records
-    // except the last one retreived.
-    bool hit;
-    RRsetPtr r;
-    uint32_t f;
-
-    hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_EQ(3, cache.getCount());
-
-    RRsetPtr one(new RRset(Name("one"), RRClass::IN(), RRType::TXT(),
-                           RRTTL(0)));
-    one->addRdata(generic::TXT("one"));
-    cache.addPositive(one, 0, 30);
-    EXPECT_EQ(4, cache.getCount());
-
-    RRsetPtr two(new RRset(Name("two"), RRClass::IN(), RRType::TXT(),
-                           RRTTL(0)));
-    two->addRdata(generic::TXT("two"));
-    cache.addPositive(two, 0, 30);
-    EXPECT_EQ(5, cache.getCount());
-
-    RRsetPtr three(new RRset(Name("three"), RRClass::IN(), RRType::TXT(),
-                             RRTTL(0)));
-    three->addRdata(generic::TXT("three"));
-    cache.addPositive(three, 0, 30);
-    EXPECT_EQ(5, cache.getCount());
-
-    RRsetPtr four(new RRset(Name("four"), RRClass::IN(), RRType::TXT(),
-                            RRTTL(0)));
-    four->addRdata(generic::TXT("four"));
-    cache.addPositive(four, 0, 30);
-    EXPECT_EQ(5, cache.getCount());
-
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_FALSE(hit);
-
-    hit = cache.retrieve(test_nsname, RRClass::IN(), RRType::NS(), r, f);
-    EXPECT_TRUE(hit);
-
-    hit = cache.retrieve(test_ch, RRClass::CH(), RRType::TXT(), r, f);
-    EXPECT_FALSE(hit);
-}
-
-TEST_F(CacheTest, ncache) {
-    Name missing("missing.example.com");
-    cache.addNegative(missing, RRClass::IN(), RRType::DNSKEY(), 8, 30);
-
-    RRsetPtr r;
-    uint32_t f;
-    bool hit = cache.retrieve(missing, RRClass::IN(), RRType::DNSKEY(), r, f);
-
-    EXPECT_TRUE(hit);
-    EXPECT_FALSE(r);
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, f);
-}
-
-TEST_F(CacheTest, overwrite) {
-    EXPECT_EQ(3, cache.getCount());
-
-    RRsetPtr a(new RRset(test_name, RRClass::IN(), RRType::A(), RRTTL(300)));
-    a->addRdata(in::A("192.0.2.100"));
-
-    EXPECT_NO_THROW(cache.addPositive(a, 16, 30));
-    EXPECT_EQ(3, cache.getCount());
-
-    RRsetPtr r;
-    uint32_t f;
-    bool hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_TRUE(r);
-    EXPECT_EQ(16, f);
-
-    EXPECT_NO_THROW(cache.addNegative(test_name, RRClass::IN(), RRType::A(), 1, 30));
-    EXPECT_EQ(3, cache.getCount());
-
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_TRUE(hit);
-    EXPECT_FALSE(r);
-    EXPECT_EQ(DataSrc::REFERRAL, f);
-}
-
-TEST_F(CacheTest, reduceSlots) {
-    EXPECT_EQ(3, cache.getCount());
-    cache.setSlots(2);
-    EXPECT_EQ(2, cache.getCount());
-    cache.setSlots(1);
-    EXPECT_EQ(1, cache.getCount());
-    cache.setSlots(0);
-    EXPECT_EQ(1, cache.getCount());
-}
-
-TEST_F(CacheTest, setEnabled) {
-    cache.setEnabled(false);
-    EXPECT_FALSE(cache.getEnabled());
-    cache.setEnabled(true);
-    EXPECT_TRUE(cache.getEnabled());
-}
-
-TEST_F(CacheTest, disabled) {
-    bool hit;
-    RRsetPtr r;
-    uint32_t f;
-
-    cache.setEnabled(false);
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_FALSE(hit);
-
-    cache.setEnabled(true);
-    hit = cache.retrieve(test_name, RRClass::IN(), RRType::A(), r, f);
-    EXPECT_TRUE(hit);
-
-    EXPECT_EQ(test_name, r->getName());
-    EXPECT_EQ(RRClass::IN(), r->getClass());
-    EXPECT_EQ(RRType::A(), r->getType());
-}
-
-}

+ 91 - 60
src/lib/datasrc/tests/client_list_unittest.cc

@@ -12,11 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <util/memory_segment_local.h>
+
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
 #include <datasrc/iterator.h>
 #include <datasrc/data_source.h>
-#include <datasrc/memory_datasrc.h>
+#include <datasrc/memory/memory_client.h>
+#include <datasrc/memory/zone_finder.h>
 
 #include <dns/rrclass.h>
 #include <dns/rrttl.h>
@@ -28,6 +31,8 @@
 #include <fstream>
 
 using namespace isc::datasrc;
+using isc::datasrc::memory::InMemoryClient;
+using isc::datasrc::memory::InMemoryZoneFinder;
 using namespace isc::data;
 using namespace isc::dns;
 using namespace boost;
@@ -67,35 +72,47 @@ public:
     };
     class Iterator : public ZoneIterator {
     public:
-        Iterator(const Name& origin) :
+        Iterator(const Name& origin, bool include_ns) :
             origin_(origin),
-            finished_(false),
-            soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(), RRTTL(3600)))
+            soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(),
+                           RRTTL(3600)))
         {
             // The RData here is bogus, but it is not used to anything. There
             // just needs to be some.
             soa_->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
                                                Name::ROOT_NAME(),
                                                0, 0, 0, 0, 0));
+            rrsets_.push_back(soa_);
+
+            if (include_ns) {
+                ns_.reset(new RRset(origin_, RRClass::IN(), RRType::NS(),
+                                    RRTTL(3600)));
+                ns_->addRdata(rdata::generic::NS(Name::ROOT_NAME()));
+                rrsets_.push_back(ns_);
+            }
+            rrsets_.push_back(ConstRRsetPtr());
+
+            it_ = rrsets_.begin();
         }
         virtual isc::dns::ConstRRsetPtr getNextRRset() {
-            if (finished_) {
-                return (ConstRRsetPtr());
-            } else {
-                finished_ = true;
-                return (soa_);
-            }
+            ConstRRsetPtr result = *it_;
+            ++it_;
+            return (result);
         }
         virtual isc::dns::ConstRRsetPtr getSOA() const {
             return (soa_);
         }
     private:
         const Name origin_;
-        bool finished_;
-        const isc::dns::RRsetPtr soa_;
+        const RRsetPtr soa_;
+        RRsetPtr ns_;
+        std::vector<ConstRRsetPtr> rrsets_;
+        std::vector<ConstRRsetPtr>::const_iterator it_;
     };
     // Constructor from a list of zones.
-    MockDataSourceClient(const char* zone_names[]) {
+    MockDataSourceClient(const char* zone_names[]) :
+        have_ns_(true), use_baditerator_(true)
+    {
         for (const char** zone(zone_names); *zone; ++zone) {
             zones.insert(Name(*zone));
         }
@@ -105,7 +122,8 @@ public:
     MockDataSourceClient(const string& type,
                          const ConstElementPtr& configuration) :
         type_(type),
-        configuration_(configuration)
+        configuration_(configuration),
+        have_ns_(true), use_baditerator_(true)
     {
         EXPECT_NE("MasterFiles", type) << "MasterFiles is a special case "
             "and it never should be created as a data source client";
@@ -146,23 +164,27 @@ public:
         isc_throw(isc::NotImplemented, "Not implemented");
     }
     virtual ZoneIteratorPtr getIterator(const Name& name, bool) const {
-        if (name == Name("noiter.org")) {
+        if (use_baditerator_ && name == Name("noiter.org")) {
             isc_throw(isc::NotImplemented, "Asked not to be implemented");
-        } else if (name == Name("null.org")) {
+        } else if (use_baditerator_ && name == Name("null.org")) {
             return (ZoneIteratorPtr());
         } else {
             FindResult result(findZone(name));
             if (result.code == isc::datasrc::result::SUCCESS) {
-                return (ZoneIteratorPtr(new Iterator(name)));
+                return (ZoneIteratorPtr(new Iterator(name, have_ns_)));
             } else {
                 isc_throw(DataSourceError, "No such zone");
             }
         }
     }
+    void disableNS() { have_ns_ = false; }
+    void disableBadIterator() { use_baditerator_ = false; }
     const string type_;
     const ConstElementPtr configuration_;
 private:
     set<Name> zones;
+    bool have_ns_; // control the iterator behavior wrt whether to include NS
+    bool use_baditerator_; // whether to use bogus zone iterators for tests
 };
 
 
@@ -220,8 +242,9 @@ const size_t ds_count = (sizeof(ds_zones) / sizeof(*ds_zones));
 class ListTest : public ::testing::Test {
 public:
     ListTest() :
+        rrclass_(RRClass::IN()),
         // The empty list corresponds to a list with no elements inside
-        list_(new TestedList(RRClass::IN())),
+        list_(new TestedList(rrclass_)),
         config_elem_(Element::fromJSON("["
             "{"
             "   \"type\": \"test_type\","
@@ -238,28 +261,35 @@ public:
             shared_ptr<MockDataSourceClient>
                 ds(new MockDataSourceClient(ds_zones[i]));
             ds_.push_back(ds);
-            ds_info_.push_back(ConfigurableClientList::DataSourceInfo(ds.get(),
-                DataSourceClientContainerPtr(), false));
+            ds_info_.push_back(ConfigurableClientList::DataSourceInfo(
+                                   ds.get(), DataSourceClientContainerPtr(),
+                                   false, rrclass_, mem_sgmt_));
         }
     }
-    void prepareCache(size_t index, const Name& zone, bool prefill = false) {
-        const shared_ptr<InMemoryClient> cache(new InMemoryClient());
-        const shared_ptr<InMemoryZoneFinder>
-            finder(new InMemoryZoneFinder(RRClass::IN(), zone));
-        if (prefill) {
-            RRsetPtr soa(new RRset(zone, RRClass::IN(), RRType::SOA(),
-                                   RRTTL(3600)));
-            // The RData here is bogus, but it is not used to anything. There
-            // just needs to be some.
-            soa->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
-                                              Name::ROOT_NAME(),
-                                              0, 0, 0, 0, 0));
-            finder->add(soa);
-        }
-        // If we don't do prefill, we leave the zone empty. This way,
-        // we can check when it was reloaded.
-        cache->addZone(finder);
-        list_->getDataSources()[index].cache_ = cache;
+
+    // Install a "fake" cached zone using a temporary underlying data source
+    // client.
+    void prepareCache(size_t index, const Name& zone) {
+        // Prepare the temporary data source client
+        const char* zones[2];
+        const std::string zonename_txt = zone.toText();
+        zones[0] = zonename_txt.c_str();
+        zones[1] = NULL;
+        MockDataSourceClient mock_client(zones);
+        // Disable some default features of the mock to distinguish the
+        // temporary case from normal case.
+        mock_client.disableNS();
+        mock_client.disableBadIterator();
+
+        // Create cache from the temporary data source, and push it to the
+        // client list.
+        const shared_ptr<InMemoryClient> cache(new InMemoryClient(mem_sgmt_,
+                                                                  rrclass_));
+        cache->load(zone, *mock_client.getIterator(zone, false));
+
+        ConfigurableClientList::DataSourceInfo& dsrc_info =
+                list_->getDataSources()[index];
+        dsrc_info.cache_ = cache;
     }
     // Check the positive result is as we expect it.
     void positiveResult(const ClientList::FindResult& result,
@@ -331,6 +361,8 @@ public:
         EXPECT_EQ(cache, list_->getDataSources()[index].cache_ !=
                   shared_ptr<InMemoryClient>());
     }
+    const RRClass rrclass_;
+    isc::util::MemorySegmentLocal mem_sgmt_;
     shared_ptr<TestedList> list_;
     const ClientList::FindResult negative_result_;
     vector<shared_ptr<MockDataSourceClient> > ds_;
@@ -815,39 +847,38 @@ TEST_F(ListTest, BadMasterFile) {
 // Test we can reload a zone
 TEST_F(ListTest, reloadSuccess) {
     list_->configure(config_elem_zones_, true);
-    Name name("example.org");
+    const Name name("example.org");
     prepareCache(0, name);
-    // Not there yet. It would be NXDOMAIN, but it is in apex and
-    // it returns NXRRSET instead.
+    // The cache currently contains a tweaked version of zone, which doesn't
+    // have apex NS.  So the lookup should result in NXRRSET.
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
-    // Now reload. It should be there now.
+              list_->find(name).finder_->find(name, RRType::NS())->code);
+    // Now reload the full zone. It should be there now.
     EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(name));
     EXPECT_EQ(ZoneFinder::SUCCESS,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              list_->find(name).finder_->find(name, RRType::NS())->code);
 }
 
 // The cache is not enabled. The load should be rejected.
 TEST_F(ListTest, reloadNotEnabled) {
     list_->configure(config_elem_zones_, false);
-    Name name("example.org");
+    const Name name("example.org");
     // We put the cache in even when not enabled. This won't confuse the thing.
     prepareCache(0, name);
-    // Not there yet. It would be NXDOMAIN, but it is in apex and
-    // it returns NXRRSET instead.
+    // See the reloadSuccess test.  This should result in NXRRSET.
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              list_->find(name).finder_->find(name, RRType::NS())->code);
     // Now reload. It should reject it.
     EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, list_->reload(name));
     // Nothing changed here
     EXPECT_EQ(ZoneFinder::NXRRSET,
-              list_->find(name).finder_->find(name, RRType::SOA())->code);
+              list_->find(name).finder_->find(name, RRType::NS())->code);
 }
 
 // Test several cases when the zone does not exist
 TEST_F(ListTest, reloadNoSuchZone) {
     list_->configure(config_elem_zones_, true);
-    Name name("example.org");
+    const Name name("example.org");
     // We put the cache in even when not enabled. This won't confuse the
     // reload method, as that one looks at the real state of things, not
     // at the configuration.
@@ -867,27 +898,27 @@ TEST_F(ListTest, reloadNoSuchZone) {
               list_->find(Name("example.cz")).dsrc_client_);
     EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
               list_->find(Name("sub.example.com"), true).dsrc_client_);
-    // Not reloaded
+    // Not reloaded, so NS shouldn't be visible yet.
     EXPECT_EQ(ZoneFinder::NXRRSET,
               list_->find(Name("example.com")).finder_->
-              find(Name("example.com"), RRType::SOA())->code);
+              find(Name("example.com"), RRType::NS())->code);
 }
 
 // Check we gracefuly throw an exception when a zone disappeared in
 // the underlying data source when we want to reload it
 TEST_F(ListTest, reloadZoneGone) {
     list_->configure(config_elem_, true);
-    Name name("example.org");
+    const Name name("example.org");
     // We put in a cache for non-existant zone. This emulates being loaded
     // and then the zone disappearing. We prefill the cache, so we can check
     // it.
-    prepareCache(0, name, true);
-    // The zone contains something
+    prepareCache(0, name);
+    // The (cached) zone contains zone's SOA
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
     // The zone is not there, so abort the reload.
     EXPECT_THROW(list_->reload(name), DataSourceError);
-    // The zone is not hurt.
+    // The (cached) zone is not hurt.
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
 }
@@ -895,8 +926,8 @@ TEST_F(ListTest, reloadZoneGone) {
 // The underlying data source throws. Check we don't modify the state.
 TEST_F(ListTest, reloadZoneThrow) {
     list_->configure(config_elem_zones_, true);
-    Name name("noiter.org");
-    prepareCache(0, name, true);
+    const Name name("noiter.org");
+    prepareCache(0, name);
     // The zone contains stuff now
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
@@ -909,8 +940,8 @@ TEST_F(ListTest, reloadZoneThrow) {
 
 TEST_F(ListTest, reloadNullIterator) {
     list_->configure(config_elem_zones_, true);
-    Name name("null.org");
-    prepareCache(0, name, true);
+    const Name name("null.org");
+    prepareCache(0, name);
     // The zone contains stuff now
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);

File diff suppressed because it is too large
+ 0 - 1209
src/lib/datasrc/tests/datasrc_unittest.cc


+ 17 - 0
src/lib/datasrc/tests/faked_nsec3.cc

@@ -67,6 +67,17 @@ public:
             "00000000000000000000000000000000";
         map_[Name("largest.example.org")] =
             "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
+
+        // These are used by the findNSEC3Walk test.
+        map_[Name("n0.example.org")] = "00000000000000000000000000000000";
+        map_[Name("n1.example.org")] = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+        map_[Name("n2.example.org")] = "02UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
+        map_[Name("n3.example.org")] = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
+        map_[Name("n4.example.org")] = "11111111111111111111111111111111";
+        map_[Name("n5.example.org")] = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
+        map_[Name("n6.example.org")] = "44444444444444444444444444444444";
+        map_[Name("n7.example.org")] = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
+        map_[Name("n8.example.org")] = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
     }
     virtual string calculate(const Name& name) const {
         const NSEC3HashMap::const_iterator found = map_.find(name);
@@ -94,6 +105,12 @@ NSEC3Hash* TestNSEC3HashCreator::create(const rdata::generic::NSEC3&) const {
     return (new TestNSEC3Hash);
 }
 
+NSEC3Hash* TestNSEC3HashCreator::create(uint8_t, uint16_t,
+                                        const uint8_t*, size_t) const
+{
+    return (new TestNSEC3Hash);
+}
+
 void
 findNSEC3Check(bool expected_matched, uint8_t expected_labels,
                const string& expected_closest,

+ 4 - 0
src/lib/datasrc/tests/faked_nsec3.h

@@ -57,11 +57,15 @@ class TestNSEC3HashCreator : public isc::dns::NSEC3HashCreator {
 private:
     class TestNSEC3Hash;
 public:
+    TestNSEC3HashCreator() {}
     virtual isc::dns::NSEC3Hash* create(const
                                         isc::dns::rdata::generic::NSEC3PARAM&)
         const;
     virtual isc::dns::NSEC3Hash* create(const isc::dns::rdata::generic::NSEC3&)
         const;
+    virtual isc::dns::NSEC3Hash* create(uint8_t, uint16_t,
+                                        const uint8_t*, size_t)
+        const;
 };
 
 // Check the result against expected values. It directly calls EXPECT_ macros

src/lib/datasrc/memory/tests/.gitignore → src/lib/datasrc/tests/memory/.gitignore


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

@@ -36,8 +36,7 @@ run_unittests_SOURCES += memory_client_unittest.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 
-run_unittests_LDADD = $(builddir)/../libdatasrc_memory.la
-run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
+run_unittests_LDADD = $(top_builddir)/src/lib/datasrc/libb10-datasrc.la
 run_unittests_LDADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.la

+ 62 - 0
src/lib/datasrc/memory/tests/domaintree_unittest.cc

@@ -596,6 +596,10 @@ TEST_F(DomainTreeTest, chainLevel) {
     // by default there should be no level in the chain.
     EXPECT_EQ(0, chain.getLevelCount());
 
+    // Copy should be consistent
+    TestDomainTreeNodeChain chain2(chain);
+    EXPECT_EQ(chain.getLevelCount(), chain2.getLevelCount());
+
     // insert one node to the tree and find it.  there should be exactly
     // one level in the chain.
     TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_, true));
@@ -607,6 +611,11 @@ TEST_F(DomainTreeTest, chainLevel) {
               tree.find(node_name, &cdtnode, chain));
     EXPECT_EQ(1, chain.getLevelCount());
 
+    // Copy should be consistent
+    TestDomainTreeNodeChain chain3(chain);
+    EXPECT_EQ(chain.getLevelCount(), chain3.getLevelCount());
+    EXPECT_EQ(chain.getAbsoluteName(), chain3.getAbsoluteName());
+
     // Check the name of the found node (should have '.' as both non-absolute
     // and absolute name
     EXPECT_EQ(".", cdtnode->getLabels().toText());
@@ -716,6 +725,48 @@ TEST_F(DomainTreeTest, getUpperNode) {
     EXPECT_EQ(static_cast<void*>(NULL), node);
 }
 
+
+#if 0
+// Disabled and kept still, for use in case we make getSubTreeRoot() a
+// public function again.
+
+const char* const subtree_root_node_names[] = {
+    "b", "b", "b", "b", "w.y.d.e.f", "w.y.d.e.f", "p.w.y.d.e.f",
+    "p.w.y.d.e.f", "p.w.y.d.e.f", "w.y.d.e.f", "j.z.d.e.f",
+    "b", "i.g.h", "i.g.h"};
+
+TEST_F(DomainTreeTest, getSubTreeRoot) {
+    TestDomainTreeNodeChain node_path;
+    const TestDomainTreeNode* node = NULL;
+    EXPECT_EQ(TestDomainTree::EXACTMATCH,
+              dtree_expose_empty_node.find(Name(names[0]),
+                                            &node,
+                                            node_path));
+    for (int i = 0; i < name_count; ++i) {
+        EXPECT_NE(static_cast<void*>(NULL), node);
+
+        const TestDomainTreeNode* sr_node = node->getSubTreeRoot();
+        if (subtree_root_node_names[i] != NULL) {
+            const TestDomainTreeNode* sr_node2 = NULL;
+            EXPECT_EQ(TestDomainTree::EXACTMATCH,
+                dtree_expose_empty_node.find(Name(subtree_root_node_names[i]),
+                                             &sr_node2));
+            EXPECT_NE(static_cast<void*>(NULL), sr_node2);
+            EXPECT_EQ(sr_node, sr_node2);
+        } else {
+            EXPECT_EQ(static_cast<void*>(NULL), sr_node);
+        }
+
+        node = dtree_expose_empty_node.nextNode(node_path);
+    }
+
+    // We should have reached the end of the tree.
+    EXPECT_EQ(static_cast<void*>(NULL), node);
+}
+
+#endif // disabled getSubTreeRoot()
+
+
 TEST_F(DomainTreeTest, nextNode) {
     TestDomainTreeNodeChain node_path;
     const TestDomainTreeNode* node = NULL;
@@ -937,6 +988,17 @@ TEST_F(DomainTreeTest, previousNode) {
     }
 }
 
+TEST_F(DomainTreeTest, largestNode) {
+    cdtnode = dtree.largestNode();
+    EXPECT_EQ(Name("k"), cdtnode->getName());
+
+    // Check for largest node in an empty tree.
+    TreeHolder empty_tree_holder
+        (mem_sgmt_, TestDomainTree::create(mem_sgmt_));
+    TestDomainTree& empty_tree(*empty_tree_holder.get());
+    EXPECT_EQ(static_cast<void*>(NULL), empty_tree.largestNode());
+}
+
 TEST_F(DomainTreeTest, nextNodeError) {
     // Empty chain for nextNode() is invalid.
     TestDomainTreeNodeChain chain;

+ 43 - 33
src/lib/datasrc/memory/tests/memory_client_unittest.cc

@@ -200,6 +200,11 @@ TEST_F(MemoryClientTest, load) {
     // should not result in any exceptions.
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org.zone");
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+    EXPECT_FALSE(zone_data->isSigned());
+    EXPECT_FALSE(zone_data->isNSEC3Signed());
 }
 
 TEST_F(MemoryClientTest, loadFromIterator) {
@@ -266,11 +271,33 @@ TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
 TEST_F(MemoryClientTest, loadNSEC3Signed) {
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org-nsec3-signed.zone");
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+    EXPECT_TRUE(zone_data->isSigned());
+    EXPECT_TRUE(zone_data->isNSEC3Signed());
+}
+
+TEST_F(MemoryClientTest, loadNSEC3EmptySalt) {
+    // Load NSEC3 with empty ("-") salt. This should not throw or crash
+    // or anything.
+    client_->load(Name("example.org"),
+                  TEST_DATA_DIR "/example.org-nsec3-empty-salt.zone");
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+    EXPECT_TRUE(zone_data->isSigned());
+    EXPECT_TRUE(zone_data->isNSEC3Signed());
 }
 
 TEST_F(MemoryClientTest, loadNSEC3SignedNoParam) {
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org-nsec3-signed-no-param.zone");
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
+    EXPECT_TRUE(zone_data->isSigned());
+    EXPECT_TRUE(zone_data->isNSEC3Signed());
 }
 
 TEST_F(MemoryClientTest, loadReloadZone) {
@@ -288,14 +315,12 @@ TEST_F(MemoryClientTest, loadReloadZone) {
                   client_->getFileName(Name("example.org")));
     EXPECT_EQ(1, client_->getZoneCount());
 
-    isc::datasrc::memory::ZoneTable::FindResult
-        result(client_->findZone2(Name("example.org")));
-    EXPECT_EQ(result::SUCCESS, result.code);
-    EXPECT_NE(static_cast<ZoneData*>(NULL),
-              result.zone_data);
+    const ZoneData* zone_data =
+        client_->findZoneData(Name("example.org"));
+    EXPECT_NE(static_cast<const ZoneData*>(NULL), zone_data);
 
     /* Check SOA */
-    const ZoneNode* node = result.zone_data->getOriginNode();
+    const ZoneNode* node = zone_data->getOriginNode();
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
 
     const RdataSet* set = node->getData();
@@ -306,7 +331,7 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
     /* Check ns1.example.org */
-    const ZoneTree& tree = result.zone_data->getZoneTree();
+    const ZoneTree& tree = zone_data->getZoneTree();
     ZoneTree::Result zresult(tree.find(Name("ns1.example.org"), &node));
     EXPECT_NE(ZoneTree::EXACTMATCH, zresult);
 
@@ -316,14 +341,11 @@ TEST_F(MemoryClientTest, loadReloadZone) {
                   TEST_DATA_DIR "/example.org-rrsigs.zone");
     EXPECT_EQ(1, client_->getZoneCount());
 
-    isc::datasrc::memory::ZoneTable::FindResult
-        result2(client_->findZone2(Name("example.org")));
-    EXPECT_EQ(result::SUCCESS, result2.code);
-    EXPECT_NE(static_cast<ZoneData*>(NULL),
-              result2.zone_data);
+    zone_data = client_->findZoneData(Name("example.org"));
+    EXPECT_NE(static_cast<const ZoneData*>(NULL), zone_data);
 
     /* Check SOA */
-    node = result2.zone_data->getOriginNode();
+    node = zone_data->getOriginNode();
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
 
     set = node->getData();
@@ -334,7 +356,7 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
     /* Check ns1.example.org */
-    const ZoneTree& tree2 = result2.zone_data->getZoneTree();
+    const ZoneTree& tree2 = zone_data->getZoneTree();
     ZoneTree::Result zresult2(tree2.find(Name("ns1.example.org"), &node));
     EXPECT_EQ(ZoneTree::EXACTMATCH, zresult2);
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
@@ -702,30 +724,18 @@ TEST_F(MemoryClientTest, add) {
     EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
 }
 
-TEST_F(MemoryClientTest, findZoneThrowsNotImplemented) {
-    // This method is not implemented.
-    EXPECT_THROW(client_->findZone(Name(".")),
-                 isc::NotImplemented);
-}
-
-TEST_F(MemoryClientTest, findZone2) {
+TEST_F(MemoryClientTest, findZoneData) {
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org-rrsigs.zone");
 
-    isc::datasrc::memory::ZoneTable::FindResult
-        result(client_->findZone2(Name("example.com")));
-    EXPECT_EQ(result::NOTFOUND, result.code);
-    EXPECT_EQ(static_cast<ZoneData*>(NULL),
-              result.zone_data);
+    const ZoneData* zone_data = client_->findZoneData(Name("example.com"));
+    EXPECT_EQ(static_cast<const ZoneData*>(NULL), zone_data);
 
-    isc::datasrc::memory::ZoneTable::FindResult
-        result2(client_->findZone2(Name("example.org")));
-    EXPECT_EQ(result::SUCCESS, result2.code);
-    EXPECT_NE(static_cast<ZoneData*>(NULL),
-              result2.zone_data);
+    zone_data = client_->findZoneData(Name("example.org"));
+    EXPECT_NE(static_cast<const ZoneData*>(NULL), zone_data);
 
     /* Check SOA */
-    const ZoneNode* node = result2.zone_data->getOriginNode();
+    const ZoneNode* node = zone_data->getOriginNode();
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
 
     const RdataSet* set = node->getData();
@@ -736,7 +746,7 @@ TEST_F(MemoryClientTest, findZone2) {
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
     /* Check ns1.example.org */
-    const ZoneTree& tree = result2.zone_data->getZoneTree();
+    const ZoneTree& tree = zone_data->getZoneTree();
     ZoneTree::Result result3(tree.find(Name("ns1.example.org"), &node));
     EXPECT_EQ(ZoneTree::EXACTMATCH, result3);
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);

src/lib/datasrc/memory/tests/memory_segment_test.h → src/lib/datasrc/tests/memory/memory_segment_test.h


+ 1 - 1
src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc

@@ -52,7 +52,7 @@ namespace isc {
 namespace datasrc{
 namespace memory {
 
-#include "../rdata_serialization_priv.cc"
+#include <datasrc/memory/rdata_serialization_priv.cc>
 
 }
 }

src/lib/datasrc/memory/tests/rdataset_unittest.cc → src/lib/datasrc/tests/memory/rdataset_unittest.cc


src/lib/datasrc/memory/tests/run_unittests.cc → src/lib/datasrc/tests/memory/run_unittests.cc


src/lib/datasrc/memory/tests/segment_object_holder_unittest.cc → src/lib/datasrc/tests/memory/segment_object_holder_unittest.cc


+ 1 - 0
src/lib/datasrc/memory/tests/testdata/Makefile.am

@@ -19,6 +19,7 @@ EXTRA_DIST += example.org-multiple-dname.zone
 EXTRA_DIST += example.org-multiple-nsec3.zone
 EXTRA_DIST += example.org-multiple-nsec3param.zone
 EXTRA_DIST += example.org-multiple.zone
+EXTRA_DIST += example.org-nsec3-empty-salt.zone
 EXTRA_DIST += example.org-nsec3-fewer-labels.zone example.org-nsec3-more-labels.zone
 EXTRA_DIST += example.org-nsec3-signed-no-param.zone
 EXTRA_DIST += example.org-nsec3-signed.zone

src/lib/datasrc/memory/tests/testdata/empty.zone → src/lib/datasrc/tests/memory/testdata/empty.zone


src/lib/datasrc/memory/tests/testdata/example.org-broken1.zone → src/lib/datasrc/tests/memory/testdata/example.org-broken1.zone


src/lib/datasrc/memory/tests/testdata/example.org-broken2.zone → src/lib/datasrc/tests/memory/testdata/example.org-broken2.zone


src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-1.zone → src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-1.zone


src/lib/datasrc/memory/tests/testdata/example.org-cname-and-not-nsec-2.zone → src/lib/datasrc/tests/memory/testdata/example.org-cname-and-not-nsec-2.zone


src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-1.zone → src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-1.zone


src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-apex-2.zone → src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-apex-2.zone


src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-1.zone → src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-1.zone


src/lib/datasrc/memory/tests/testdata/example.org-dname-ns-nonapex-2.zone → src/lib/datasrc/tests/memory/testdata/example.org-dname-ns-nonapex-2.zone


src/lib/datasrc/memory/tests/testdata/example.org-duplicate-type-bad.zone → src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type-bad.zone


src/lib/datasrc/memory/tests/testdata/example.org-duplicate-type.zone → src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type.zone


src/lib/datasrc/memory/tests/testdata/example.org-empty.zone → src/lib/datasrc/tests/memory/testdata/example.org-empty.zone


src/lib/datasrc/memory/tests/testdata/example.org-multiple-cname.zone → src/lib/datasrc/tests/memory/testdata/example.org-multiple-cname.zone


src/lib/datasrc/memory/tests/testdata/example.org-multiple-dname.zone → src/lib/datasrc/tests/memory/testdata/example.org-multiple-dname.zone


src/lib/datasrc/memory/tests/testdata/example.org-multiple-nsec3.zone → src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3.zone


src/lib/datasrc/memory/tests/testdata/example.org-multiple-nsec3param.zone → src/lib/datasrc/tests/memory/testdata/example.org-multiple-nsec3param.zone


src/lib/datasrc/memory/tests/testdata/example.org-multiple.zone → src/lib/datasrc/tests/memory/testdata/example.org-multiple.zone


+ 14 - 0
src/lib/datasrc/tests/memory/testdata/example.org-nsec3-empty-salt.zone

@@ -0,0 +1,14 @@
+example.org.				      86400 IN SOA	ns.example.org. ns.example.org. 2012092602 7200 3600 2592000 1200
+example.org.				      86400 IN RRSIG	SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
+example.org.				      86400 IN NS	ns.example.org.
+example.org.				      86400 IN RRSIG	NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
+example.org.				      86400 IN DNSKEY	256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
+example.org.				      86400 IN RRSIG	DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
+example.org.				      0	IN NSEC3PARAM	1 0 10 -
+example.org.				      0	IN RRSIG	NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
+ns.example.org.				      86400 IN A	192.0.2.1
+ns.example.org.				      86400 IN RRSIG	A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3	1 0 10 - RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
+09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
+RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3	1 0 10 - 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
+RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG	NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=

src/lib/datasrc/memory/tests/testdata/example.org-nsec3-fewer-labels.zone → src/lib/datasrc/tests/memory/testdata/example.org-nsec3-fewer-labels.zone


src/lib/datasrc/memory/tests/testdata/example.org-nsec3-more-labels.zone → src/lib/datasrc/tests/memory/testdata/example.org-nsec3-more-labels.zone


src/lib/datasrc/memory/tests/testdata/example.org-nsec3-signed-no-param.zone → src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed-no-param.zone


src/lib/datasrc/memory/tests/testdata/example.org-nsec3-signed.zone → src/lib/datasrc/tests/memory/testdata/example.org-nsec3-signed.zone


src/lib/datasrc/memory/tests/testdata/example.org-out-of-zone.zone → src/lib/datasrc/tests/memory/testdata/example.org-out-of-zone.zone


src/lib/datasrc/memory/tests/testdata/example.org-rrsig-follows-nothing.zone → src/lib/datasrc/tests/memory/testdata/example.org-rrsig-follows-nothing.zone


src/lib/datasrc/memory/tests/testdata/example.org-rrsigs.zone → src/lib/datasrc/tests/memory/testdata/example.org-rrsigs.zone


src/lib/datasrc/memory/tests/testdata/example.org-wildcard-dname.zone → src/lib/datasrc/tests/memory/testdata/example.org-wildcard-dname.zone


src/lib/datasrc/memory/tests/testdata/example.org-wildcard-ns.zone → src/lib/datasrc/tests/memory/testdata/example.org-wildcard-ns.zone


src/lib/datasrc/memory/tests/testdata/example.org-wildcard-nsec3.zone → src/lib/datasrc/tests/memory/testdata/example.org-wildcard-nsec3.zone


src/lib/datasrc/memory/tests/testdata/example.org.zone → src/lib/datasrc/tests/memory/testdata/example.org.zone


+ 49 - 9
src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc

@@ -25,6 +25,7 @@
 
 #include <gtest/gtest.h>
 
+#include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
 
 #include <string>
@@ -137,11 +138,22 @@ protected:
     RdataSet* wildcard_rdataset_; // for wildcard (type doesn't matter much)
 };
 
+void
+compareRRSIGData(RdataIteratorPtr rit, const void* data, size_t data_len) {
+    ASSERT_FALSE(rit->isLast());
+
+    OutputBuffer buffer(0);
+    rit->getCurrent().toWire(buffer);
+    matchWireData(data, data_len, buffer.getData(), buffer.getLength());
+    rit->next();
+}
+
 // Check some trivial fields of a constructed TreeNodeRRset (passed as
 // AbstractRRset as we'd normally use it in polymorphic way).
 // Other complicated fields are checked through rendering tests.
 void
-checkBasicFields(const AbstractRRset& actual_rrset, const Name& expected_name,
+checkBasicFields(const AbstractRRset& actual_rrset, const RdataSet* rdataset,
+                 const Name& expected_name,
                  const RRClass& expected_class, const RRType& expected_type,
                  const uint32_t expected_ttl,
                  size_t expected_rdatacount, size_t expected_sigcount)
@@ -152,6 +164,28 @@ checkBasicFields(const AbstractRRset& actual_rrset, const Name& expected_name,
     EXPECT_EQ(RRTTL(expected_ttl), actual_rrset.getTTL());
     EXPECT_EQ(expected_rdatacount, actual_rrset.getRdataCount());
     EXPECT_EQ(expected_sigcount, actual_rrset.getRRsigDataCount());
+
+    // getRRsig() should return non NULL iff the RRset is expected to be signed
+    if (expected_sigcount == 0) {
+        EXPECT_FALSE(actual_rrset.getRRsig());
+    } else {
+        ConstRRsetPtr actual_sigrrset = actual_rrset.getRRsig();
+        ASSERT_TRUE(actual_sigrrset);
+        EXPECT_EQ(expected_name, actual_sigrrset->getName());
+        EXPECT_EQ(expected_class, actual_sigrrset->getClass());
+        EXPECT_EQ(RRType::RRSIG(), actual_sigrrset->getType());
+        EXPECT_EQ(RRTTL(expected_ttl), actual_sigrrset->getTTL());
+        EXPECT_EQ(expected_sigcount, actual_sigrrset->getRdataCount());
+
+        // Compare each RRSIG RDATA
+        RdataIteratorPtr rit = actual_sigrrset->getRdataIterator();
+        RdataReader reader(expected_class, expected_type,
+                           rdataset->getDataBuf(), expected_rdatacount,
+                           expected_sigcount, &RdataReader::emptyNameAction,
+                           boost::bind(compareRRSIGData, rit, _1, _2));
+        while (reader.nextSig() != RdataReader::RRSET_BOUNDARY) {}
+        EXPECT_TRUE(rit->isLast()); // should check all RDATAs
+    }
 }
 
 // The following two are trivial wrapper to create a shared pointer
@@ -178,30 +212,37 @@ createRRset(const Name& realname, const RRClass& rrclass, const ZoneNode* node,
 TEST_F(TreeNodeRRsetTest, create) {
     // Constructed with RRSIG, and it should be visible.
     checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, true),
-                     www_name_, rrclass_, RRType::A(), 3600, 2, 1);
+                     a_rdataset_, www_name_, rrclass_, RRType::A(), 3600, 2,
+                     1);
     // Constructed with RRSIG, and it should be invisible.
     checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, false),
-                     www_name_, rrclass_, RRType::A(), 3600, 2, 0);
+                     a_rdataset_, www_name_, rrclass_, RRType::A(), 3600, 2,
+                     0);
     // Constructed without RRSIG, and it would be visible (but of course won't)
     checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, true),
-                     origin_name_, rrclass_, RRType::NS(), 3600, 1, 0);
+                     ns_rdataset_, origin_name_, rrclass_, RRType::NS(), 3600,
+                     1, 0);
     // Constructed without RRSIG, and it should be visible
     checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, false),
-                     origin_name_, rrclass_, RRType::NS(), 3600, 1, 0);
+                     ns_rdataset_, origin_name_, rrclass_, RRType::NS(), 3600,
+                     1, 0);
     // RRSIG-only case (note the RRset's type is covered type)
     checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
                                   true),
-                     www_name_, rrclass_, RRType::TXT(), 3600, 0, 1);
+                     rrsig_only_rdataset_, www_name_, rrclass_, RRType::TXT(),
+                     3600, 0, 1);
     // RRSIG-only case (note the RRset's type is covered type), but it's
     // invisible
     checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
                                   false),
-                     www_name_, rrclass_, RRType::TXT(), 3600, 0, 0);
+                     rrsig_only_rdataset_, www_name_, rrclass_, RRType::TXT(),
+                     3600, 0, 0);
     // Wildcard substitution
     checkBasicFields(*createRRset(match_name_, rrclass_,
                                   wildcard_node_, wildcard_rdataset_,
                                   true),
-                     match_name_, rrclass_, RRType::A(), 3600, 2, 1);
+                     wildcard_rdataset_, match_name_, rrclass_, RRType::A(),
+                     3600, 2, 1);
 }
 
 // The following two templated functions are helper to encapsulate the
@@ -578,7 +619,6 @@ TEST_F(TreeNodeRRsetTest, unexpectedMethods) {
     EXPECT_THROW(rrset.setName(Name("example")), isc::Unexpected);
     EXPECT_THROW(rrset.addRdata(createRdata(RRType::A(), rrclass_, "0.0.0.0")),
                  isc::Unexpected);
-    EXPECT_THROW(rrset.getRRsig(), isc::Unexpected);
     RdataPtr sig_rdata = createRdata(
         RRType::RRSIG(), rrclass_,
         "A 5 2 3600 20120814220826 20120715220826 5300 example.com. FAKE");

src/lib/datasrc/memory/tests/zone_data_unittest.cc → src/lib/datasrc/tests/memory/zone_data_unittest.cc


+ 236 - 113
src/lib/datasrc/memory/tests/zone_finder_unittest.cc

@@ -31,6 +31,8 @@
 
 #include <gtest/gtest.h>
 
+#include <string>
+
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
@@ -46,74 +48,6 @@ namespace {
 using result::SUCCESS;
 using result::EXIST;
 
-// Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
-// object.
-//
-// For apex (example.org)
-const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
-// For ns1.example.org
-const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
-// For w.example.org
-const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
-// For x.y.w.example.org (lower-cased)
-const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
-// For zzz.example.org.
-const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
-
-// A simple faked NSEC3 hash calculator with a dedicated creator for it.
-//
-// This is used in some NSEC3-related tests below.
-// Also see NOTE at inclusion of "../../tests/faked_nsec3.h"
-class TestNSEC3HashCreator : public NSEC3HashCreator {
-    class TestNSEC3Hash : public NSEC3Hash {
-    private:
-        typedef map<Name, string> NSEC3HashMap;
-        typedef NSEC3HashMap::value_type NSEC3HashPair;
-        NSEC3HashMap map_;
-    public:
-        TestNSEC3Hash() {
-            // Build pre-defined hash
-            map_[Name("example.org")] = apex_hash;
-            map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("x.y.w.example.org")] =
-                "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
-            map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
-            map_[Name("w.example.org")] = w_hash;
-            map_[Name("zzz.example.org")] = zzz_hash;
-            map_[Name("smallest.example.org")] =
-                "00000000000000000000000000000000";
-            map_[Name("largest.example.org")] =
-                "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
-        }
-        virtual string calculate(const Name& name) const {
-            const NSEC3HashMap::const_iterator found = map_.find(name);
-            if (found != map_.end()) {
-                return (found->second);
-            }
-            isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
-                      << name);
-        }
-        virtual bool match(const generic::NSEC3PARAM&) const {
-            return (true);
-        }
-        virtual bool match(const generic::NSEC3&) const {
-            return (true);
-        }
-    };
-
-public:
-    virtual NSEC3Hash* create(const generic::NSEC3PARAM&) const {
-        return (new TestNSEC3Hash);
-    }
-    virtual NSEC3Hash* create(const generic::NSEC3&) const {
-        return (new TestNSEC3Hash);
-    }
-};
-
-
 /// \brief expensive rrset converter
 ///
 /// converts any specialized rrset (which may not have implemented some
@@ -182,6 +116,8 @@ public:
             {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
             {"example.org. 300 IN A 192.0.2.1", &rr_a_},
             {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
+            // This one will place rr_ns_a_ at a zone cut, making it a glue:
+            {"ns.example.org. 300 IN NS 192.0.2.2", &rr_ns_ns_},
             {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
             {"cname.example.org. 300 IN CNAME canonical.example.org",
              &rr_cname_},
@@ -255,18 +191,46 @@ public:
     }
 
     // NSEC3-specific call for 'loading' data
-    // This needs to be updated and checked when implementing #2118
     void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
         assert(rrset->getType() == RRType::NSEC3());
 
-        const Rdata* rdata = &rrset->getRdataIterator()->getCurrent();
-        const generic::NSEC3* nsec3_rdata =
-            dynamic_cast<const generic::NSEC3*>(rdata);
-        NSEC3Data* nsec3_data = NSEC3Data::create(mem_sgmt_, *nsec3_rdata);
-        // in case we happen to be replacing, destroy old
-        NSEC3Data* old_data = zone_data_->setNSEC3Data(nsec3_data);
-        if (old_data != NULL) {
-            NSEC3Data::destroy(mem_sgmt_, old_data, rrset->getClass());
+        const generic::NSEC3& nsec3_rdata =
+             dynamic_cast<const generic::NSEC3&>(
+                  rrset->getRdataIterator()->getCurrent());
+
+        NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
+        if (nsec3_data == NULL) {
+             nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
+             zone_data_->setNSEC3Data(nsec3_data);
+        } else {
+             const size_t salt_len = nsec3_data->getSaltLen();
+             const uint8_t* salt_data = nsec3_data->getSaltData();
+             const vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
+
+             if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
+                 (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
+                 (salt_data_2.size() != salt_len)) {
+                  isc_throw(isc::Unexpected,
+                            "NSEC3 with inconsistent parameters: " <<
+                            rrset->toText());
+             }
+
+             if ((salt_len > 0) &&
+                 (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
+                  isc_throw(isc::Unexpected,
+                            "NSEC3 with inconsistent parameters: " <<
+                            rrset->toText());
+             }
+        }
+
+        ZoneNode* node;
+        nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
+
+        RdataSet* rdset = RdataSet::create(mem_sgmt_, encoder_,
+                                           rrset, ConstRRsetPtr());
+        RdataSet* old_rdset = node->setData(rdset);
+        if (old_rdset != NULL) {
+             RdataSet::destroy(mem_sgmt_, class_, old_rdset);
         }
         zone_data_->setSigned(true);
     }
@@ -312,6 +276,44 @@ public:
             }
             name = name.split(1);
         }
+
+        // If we've added NSEC3PARAM at zone origin, set up NSEC3
+        // specific data or check consistency with already set up
+        // parameters.
+        if (rrset->getType() == RRType::NSEC3PARAM() &&
+            rrset->getName() == origin_) {
+            // We know rrset has exactly one RDATA
+            const generic::NSEC3PARAM& param =
+                dynamic_cast<const generic::NSEC3PARAM&>
+                 (rrset->getRdataIterator()->getCurrent());
+
+            NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
+            if (nsec3_data == NULL) {
+                nsec3_data = NSEC3Data::create(mem_sgmt_, param);
+                zone_data_->setNSEC3Data(nsec3_data);
+                zone_data_->setSigned(true);
+            } else {
+                size_t salt_len = nsec3_data->getSaltLen();
+                const uint8_t* salt_data = nsec3_data->getSaltData();
+                const vector<uint8_t>& salt_data_2 = param.getSalt();
+
+                if ((param.getHashalg() != nsec3_data->hashalg) ||
+                    (param.getIterations() != nsec3_data->iterations) ||
+                    (salt_data_2.size() != salt_len)) {
+                     isc_throw(isc::Unexpected,
+                               "NSEC3PARAM with inconsistent parameters: "
+                               << rrset->toText());
+                }
+
+                if ((salt_len > 0) &&
+                    (std::memcmp(&salt_data_2[0],
+                                 salt_data, salt_len) != 0)) {
+                     isc_throw(isc::Unexpected,
+                               "NSEC3PARAM with inconsistent parameters: "
+                               << rrset->toText());
+                }
+            }
+        }
     }
 
     // Some data to test with
@@ -340,6 +342,7 @@ public:
         rr_ns_aaaa_,
         // A of example.org
         rr_a_;
+    RRsetPtr rr_ns_ns_;         // used to make rr_ns_a_ a glue.
     RRsetPtr rr_cname_;         // CNAME in example.org (RDATA will be added)
     RRsetPtr rr_cname_a_; // for mixed CNAME + A case
     RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
@@ -369,12 +372,6 @@ public:
     RRsetPtr rr_ns_nsec_;
     RRsetPtr rr_wild_nsec_;
 
-    // A faked NSEC3 hash calculator for convenience.
-    // Tests that need to use the faked hashed values should call
-    // setNSEC3HashCreator() with a pointer to this variable at the beginning
-    // of the test (at least before adding any NSEC3/NSEC3PARAM RR).
-    TestNSEC3HashCreator nsec3_hash_creator_;
-
     /**
      * \brief Test one find query to the zone finder.
      *
@@ -435,9 +432,12 @@ public:
                         ConstRRsetPtr result_rrset(
                             convertRRset(find_result->rrset));
                         rrsetCheck(answer, result_rrset);
-                        if (answer_sig) {
+                        if (answer_sig &&
+                            (options & ZoneFinder::FIND_DNSSEC) != 0) {
                             ASSERT_TRUE(result_rrset->getRRsig());
                             rrsetCheck(answer_sig, result_rrset->getRRsig());
+                        } else {
+                            EXPECT_FALSE(result_rrset->getRRsig());
                         }
                     }
                 } else if (check_wild_answer) {
@@ -527,6 +527,13 @@ public:
  */
 TEST_F(InMemoryZoneFinderTest, constructor) {
     ASSERT_EQ(origin_, zone_finder_.getOrigin());
+
+    // Some unusual (abnormal case): if we add a super domain name of the
+    // zone somehow, the label of the origin node won't be absolute.
+    // getOrigin() should still be the correct one.
+    ZoneNode *node;
+    zone_data_->insertName(mem_sgmt_, Name("org"), &node);
+    ASSERT_EQ(origin_, zone_finder_.getOrigin());
 }
 
 TEST_F(InMemoryZoneFinderTest, findCNAME) {
@@ -684,6 +691,9 @@ TEST_F(InMemoryZoneFinderTest, glue) {
     EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
     // glue under the deeper zone cut
     EXPECT_NO_THROW(addZoneData(rr_grandchild_glue_));
+    // glue 'at the' zone cut
+    EXPECT_NO_THROW(addZoneData(rr_ns_a_));
+    EXPECT_NO_THROW(addZoneData(rr_ns_ns_));
 
     // by default glue is hidden due to the zone cut
     findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
@@ -716,6 +726,13 @@ TEST_F(InMemoryZoneFinderTest, glue) {
     findTest(Name("www.grand.child.example.org"), RRType::TXT(),
              ZoneFinder::DELEGATION, true, rr_child_ns_,
              ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
+
+    // Glue at a zone cut
+    findTest(Name("ns.example.org"), RRType::A(),
+             ZoneFinder::DELEGATION, true, rr_ns_ns_);
+    findTest(Name("ns.example.org"), RRType::A(), ZoneFinder::SUCCESS,
+             true, rr_ns_a_, ZoneFinder::RESULT_DEFAULT,
+             NULL, ZoneFinder::FIND_GLUE_OK);
 }
 
 /**
@@ -729,6 +746,9 @@ InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
 {
     // Fill some data inside
     // Now put all the data we have there. It should throw nothing
+    rr_a_->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
+                                "A 5 3 3600 20120814220826 20120715220826 "
+                                "1234 example.com. FAKE"));
     EXPECT_NO_THROW(addZoneData(rr_ns_));
     EXPECT_NO_THROW(addZoneData(rr_ns_a_));
     EXPECT_NO_THROW(addZoneData(rr_ns_aaaa_));
@@ -747,6 +767,12 @@ InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
     findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
              rr_ns_a_);
 
+    // Similar test for a signed RRset.  We should see the RRSIG iff
+    // FIND_DNSSEC option is specified.
+    findTest(rr_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true, rr_a_);
+    findTest(rr_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
+             rr_a_, ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_DNSSEC);
+
     // These domains don't exist. (and one is out of the zone).  In an
     // NSEC-signed zone with DNSSEC records requested, it should return the
     // covering NSEC for the query name (the actual NSEC in the test data may
@@ -1427,36 +1453,10 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
 }
 
 
-// DISABLED: nsec3 will be re-added in #2118
-TEST_F(InMemoryZoneFinderTest, DISABLED_findNSEC3) {
+TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
     // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
-
-    // Add a few NSEC3 records:
-    // apex (example.org.): hash=0P..
-    // ns1.example.org:     hash=2T..
-    // w.example.org:       hash=01..
-    // zzz.example.org:     hash=R5..
-    const string apex_nsec3_text = string(apex_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(apex_nsec3_text));
-    const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(ns1_nsec3_text));
-    const string w_nsec3_text = string(w_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(w_nsec3_text));
-    const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
-        string(nsec3_common);
-    addZoneData(textToRRset(zzz_nsec3_text));
-
-    performNSEC3Test(zone_finder_);
-}
-
-// DISABLED: NSEC3 will be re-added in #2218
-TEST_F(InMemoryZoneFinderTest, DISABLED_findNSEC3ForBadZone) {
-    // Set up the faked hash calculator.
-    setNSEC3HashCreator(&nsec3_hash_creator_);
+    const TestNSEC3HashCreator creator;
+    setNSEC3HashCreator(&creator);
 
     // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
     // findNSEC3() should be rejected.
@@ -1478,4 +1478,127 @@ TEST_F(InMemoryZoneFinderTest, DISABLED_findNSEC3ForBadZone) {
                  DataSourceError);
 }
 
+/// \brief NSEC3 specific tests fixture for the InMemoryZoneFinder class
+class InMemoryZoneFinderNSEC3Test : public InMemoryZoneFinderTest {
+public:
+    InMemoryZoneFinderNSEC3Test() {
+        // Set up the faked hash calculator.
+        setNSEC3HashCreator(&creator_);
+
+        // Add a few NSEC3 records:
+        // apex (example.org.): hash=0P..
+        // ns1.example.org:     hash=2T..
+        // w.example.org:       hash=01..
+        // zzz.example.org:     hash=R5..
+        const string apex_nsec3_text = string(apex_hash) + ".example.org." +
+            string(nsec3_common);
+        addZoneData(textToRRset(apex_nsec3_text));
+        const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
+            string(nsec3_common);
+        addZoneData(textToRRset(ns1_nsec3_text));
+        const string w_nsec3_text = string(w_hash) + ".example.org." +
+            string(nsec3_common);
+        addZoneData(textToRRset(w_nsec3_text));
+        const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
+            string(nsec3_common);
+        addZoneData(textToRRset(zzz_nsec3_text));
+    }
+
+private:
+    const TestNSEC3HashCreator creator_;
+};
+
+TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3) {
+    performNSEC3Test(zone_finder_);
+}
+
+struct TestData {
+     // String for the name passed to findNSEC3() (concatenated with
+     // "example.org.")
+     const char* const name;
+     // Should recursive findNSEC3() be performed?
+     const bool recursive;
+     // The following are members of the FindNSEC3Result returned by
+     // findNSEC3(). The proofs are given as char*, which are converted
+     // to Name objects and checked against getName() on the returned
+     // ConstRRsetPtr. If any of these is NULL, then it's expected that
+     // ConstRRsetPtr() will be returned.
+     const bool matched;
+     const uint8_t closest_labels;
+     const char* const closest_proof;
+     const char* const next_proof;
+};
+
+const TestData nsec3_data[] = {
+     // ==== These are non-recursive tests.
+     {"n0", false, false, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
+     {"n1", false,  true, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
+     {"n2", false, false, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
+     {"n3", false,  true, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
+     {"n4", false, false, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
+     {"n5", false,  true, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
+     {"n6", false, false, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
+     {"n7", false,  true, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
+     {"n8", false, false, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
+
+     // ==== These are recursive tests.
+     {"n0",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN"},
+     {"n1",  true,  true, 4, "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H", NULL},
+     {"n2",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H"},
+     {"n3",  true,  true, 4, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM", NULL},
+     {"n4",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM"},
+     {"n5",  true,  true, 4, "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR", NULL},
+     {"n6",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR"},
+     {"n7",  true,  true, 4, "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN", NULL},
+     {"n8",  true,  true, 3, "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM",
+         "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN"}
+};
+
+const size_t data_count(sizeof(nsec3_data) / sizeof(*nsec3_data));
+
+TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3Walk) {
+    // This test basically uses nsec3_data[] declared above along with
+    // the fake hash setup to walk the NSEC3 tree. The names and fake
+    // hash calculation is specially setup so that the tree search
+    // terminates at specific locations in the tree. We findNSEC3() on
+    // each of the nsec3_data[], which is setup such that the hash
+    // results in the search terminating on either side of each node of
+    // the NSEC3 tree. This way, we check what result is returned in
+    // every search termination case in the NSEC3 tree.
+
+    const Name origin("example.org");
+    for (size_t i = 0; i < data_count; ++i) {
+        const Name name = Name(nsec3_data[i].name).concatenate(origin);
+
+        SCOPED_TRACE(name.toText() + (nsec3_data[i].recursive ?
+                                      ", recursive" :
+                                      ", non-recursive"));
+
+        const ZoneFinder::FindNSEC3Result result =
+            zone_finder_.findNSEC3(name, nsec3_data[i].recursive);
+
+        EXPECT_EQ(nsec3_data[i].matched, result.matched);
+        EXPECT_EQ(nsec3_data[i].closest_labels, result.closest_labels);
+
+        if (nsec3_data[i].closest_proof != NULL) {
+            ASSERT_TRUE(result.closest_proof);
+            EXPECT_EQ(Name(nsec3_data[i].closest_proof).concatenate(origin),
+                      result.closest_proof->getName());
+        } else {
+            EXPECT_FALSE(result.closest_proof);
+        }
+
+        if (nsec3_data[i].next_proof != NULL) {
+            ASSERT_TRUE(result.next_proof);
+            EXPECT_EQ(Name(nsec3_data[i].next_proof).concatenate(origin),
+                      result.next_proof->getName());
+        } else {
+            EXPECT_FALSE(result.next_proof);
+        }
+    }
+}
 }

src/lib/datasrc/memory/tests/zone_table_unittest.cc → src/lib/datasrc/tests/memory/zone_table_unittest.cc


+ 0 - 66
src/lib/datasrc/tests/memory_datasrc_unittest.cc

@@ -293,72 +293,6 @@ setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
     ++it;
 }
 
-// Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
-// object.
-//
-// For apex (example.org)
-const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
-// For ns1.example.org
-const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
-// For w.example.org
-const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
-// For x.y.w.example.org (lower-cased)
-const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
-// For zzz.example.org.
-const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";
-
-// A simple faked NSEC3 hash calculator with a dedicated creator for it.
-//
-// This is used in some NSEC3-related tests below.
-class TestNSEC3HashCreator : public NSEC3HashCreator {
-    class TestNSEC3Hash : public NSEC3Hash {
-    private:
-        typedef map<Name, string> NSEC3HashMap;
-        typedef NSEC3HashMap::value_type NSEC3HashPair;
-        NSEC3HashMap map_;
-    public:
-        TestNSEC3Hash() {
-            // Build pre-defined hash
-            map_[Name("example.org")] = apex_hash;
-            map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
-            map_[Name("x.y.w.example.org")] =
-                "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
-            map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
-            map_[Name("w.example.org")] = w_hash;
-            map_[Name("zzz.example.org")] = zzz_hash;
-            map_[Name("smallest.example.org")] =
-                "00000000000000000000000000000000";
-            map_[Name("largest.example.org")] =
-                "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
-        }
-        virtual string calculate(const Name& name) const {
-            const NSEC3HashMap::const_iterator found = map_.find(name);
-            if (found != map_.end()) {
-                return (found->second);
-            }
-            isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
-                      << name);
-        }
-        virtual bool match(const generic::NSEC3PARAM&) const {
-            return (true);
-        }
-        virtual bool match(const generic::NSEC3&) const {
-            return (true);
-        }
-    };
-
-public:
-    virtual NSEC3Hash* create(const generic::NSEC3PARAM&) const {
-        return (new TestNSEC3Hash);
-    }
-    virtual NSEC3Hash* create(const generic::NSEC3&) const {
-        return (new TestNSEC3Hash);
-    }
-};
-
 /// \brief Test fixture for the InMemoryZoneFinder class
 class InMemoryZoneFinderTest : public ::testing::Test {
     // A straightforward pair of textual RR(set) and a RRsetPtr variable

+ 0 - 71
src/lib/datasrc/tests/query_unittest.cc

@@ -1,71 +0,0 @@
-// Copyright (C) 2010  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 <gtest/gtest.h>
-
-#include <util/buffer.h>
-#include <dns/message.h>
-#include <dns/name.h>
-#include <dns/opcode.h>
-#include <dns/rrtype.h>
-#include <dns/rrclass.h>
-
-#include <datasrc/query.h>
-
-#include <dns/tests/unittest_util.h>
-
-using isc::UnitTestUtil;
-using namespace isc::dns;
-using namespace isc::datasrc;
-
-namespace {
-
-void
-createQuery(Message& m, const Name& qname, const RRClass& qclass,
-            const RRType& qtype)
-{
-    m.setOpcode(Opcode::QUERY());
-    m.setHeaderFlag(Message::HEADERFLAG_RD);
-    m.addQuestion(Question(qname, qclass, qtype));
-}
-
-QueryTaskPtr
-createTask(Message& m, const Name& name, const RRType& rrtype0, HotCache& c) {
-    RRType rrtype(rrtype0);
-    Query q(m, c, true);
-    return (QueryTaskPtr(new QueryTask(q, name, rrtype,
-                                       QueryTask::SIMPLE_QUERY)));
-}
-
-// Check the QueryTask created using a temporary RRType object will remain
-// valid.
-TEST(QueryTest, constructWithTemporary) {
-    HotCache cache;
-
-    Message m1(Message::RENDER);
-    createQuery(m1, Name("www.wild.example.com"), RRClass::IN(), RRType::A()); 
-    QueryTaskPtr task_a = createTask(m1, Name("www.wild.example.com"),
-                                        RRType::A(), cache);
-    EXPECT_EQ(RRType::A(), task_a->qtype);
-
-    Message m2(Message::RENDER);
-    createQuery(m2, Name("www.wild.example.com"), RRClass::IN(),
-                RRType::AAAA());
-    QueryTaskPtr task_aaaa = createTask(m2, Name("www.wild.example.com"),
-                                        RRType::AAAA(), cache);
-    EXPECT_EQ(RRType::AAAA(), task_aaaa->qtype);
-
-}
-
-}

+ 0 - 950
src/lib/datasrc/tests/sqlite3_unittest.cc

@@ -1,950 +0,0 @@
-// Copyright (C) 2010  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 <stdint.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include <sqlite3.h>
-#include <gtest/gtest.h>
-
-#include <dns/name.h>
-#include <dns/message.h>
-#include <dns/rdata.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rdataclass.h>
-#include <dns/rrsetlist.h>
-#include <cc/data.h>
-
-#include <datasrc/query.h>
-#include <datasrc/data_source.h>
-#include <datasrc/sqlite3_datasrc.h>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc;
-using namespace isc::data;
-
-namespace {
-ConstElementPtr SQLITE_DBFILE_EXAMPLE = Element::fromJSON(
-    "{ \"database_file\": \"" TEST_DATA_DIR "/test.sqlite3\"}");
-ConstElementPtr SQLITE_DBFILE_EXAMPLE2 = Element::fromJSON(
-    "{ \"database_file\": \"" TEST_DATA_DIR "/example2.com.sqlite3\"}");
-ConstElementPtr SQLITE_DBFILE_EXAMPLE_ROOT = Element::fromJSON(
-    "{ \"database_file\": \"" TEST_DATA_DIR "/test-root.sqlite3\"}");
-ConstElementPtr SQLITE_DBFILE_BROKENDB = Element::fromJSON(
-    "{ \"database_file\": \"" TEST_DATA_DIR "/brokendb.sqlite3\"}");
-ConstElementPtr SQLITE_DBFILE_MEMORY = Element::fromJSON(
-    "{ \"database_file\": \":memory:\"}");
-ConstElementPtr SQLITE_DBFILE_NEWSCHEMA = Element::fromJSON(
-    "{ \"database_file\": \"" TEST_DATA_DIR "/newschema.sqlite3\"}");
-ConstElementPtr SQLITE_DBFILE_OLDSCHEMA = Element::fromJSON(
-    "{ \"database_file\": \"" TEST_DATA_DIR "/oldschema.sqlite3\"}");
-
-// The following file must be non existent and must be non"creatable";
-// the sqlite3 library will try to create a new DB file if it doesn't exist,
-// so to test a failure case the create operation should also fail.
-// The "nodir", a non existent directory, is inserted for this purpose.
-ConstElementPtr SQLITE_DBFILE_NOTEXIST = Element::fromJSON(
-    "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}");
-
-const string sigdata_common(" 20100322084538 20100220084538 "
-                            "33495 example.com. FAKEFAKEFAKEFAKE");
-const string dnskey1_data(" AwEAAcOUBllYc1hf7ND9uDy+Yz1BF3sI0m4q"
-                          "NGV7WcTD0WEiuV7IjXgHE36fCmS9QsUxSSOV"
-                          "o1I/FMxI2PJVqTYHkXFBS7AzLGsQYMU7UjBZ"
-                          "SotBJ6Imt5pXMu+lEDNy8TOUzG3xm7g0qcbW"
-                          "YF6qCEfvZoBtAqi5Rk7Mlrqs8agxYyMx");
-const string dnskey2_data(" AwEAAe5WFbxdCPq2jZrZhlMj7oJdff3W7syJ"
-                          "tbvzg62tRx0gkoCDoBI9DPjlOQG0UAbj+xUV"
-                          "4HQZJStJaZ+fHU5AwVNT+bBZdtV+NujSikhd"
-                          "THb4FYLg2b3Cx9NyJvAVukHp/91HnWuG4T36"
-                          "CzAFrfPwsHIrBz9BsaIQ21VRkcmj7DswfI/i"
-                          "DGd8j6bqiODyNZYQ+ZrLmF0KIJ2yPN3iO6Zq"
-                          "23TaOrVTjB7d1a/h31ODfiHAxFHrkY3t3D5J"
-                          "R9Nsl/7fdRmSznwtcSDgLXBoFEYmw6p86Acv"
-                          "RyoYNcL1SXjaKVLG5jyU3UR+LcGZT5t/0xGf"
-                          "oIK/aKwENrsjcKZZj660b1M=");
-const string nsec3_signature("gNIVj4T8t51fEU6kOPpvK7HOGBFZGbalN5ZK"
-                             "mInyrww6UWZsUNdw07ge6/U6HfG+/s61RZ/L"
-                             "is2M6yUWHyXbNbj/QqwqgadG5dhxTArfuR02"
-                             "xP600x0fWX8LXzW4yLMdKVxGbzYT+vvGz71o"
-                             "8gHSY5vYTtothcZQa4BMKhmGQEk=");
-
-const Name zone_name("example.com");
-const Name nomatch_name("example.org");
-const Name child_name("sql1.example.com");
-const Name www_name("www.example.com");
-const Name www_upper_name("WWW.EXAMPLE.COM");
-
-typedef enum {
-    NORMAL,
-    EXACT,
-    ADDRESS,
-    REFERRAL
-} FindMode;
-
-class Sqlite3DataSourceTest : public ::testing::Test {
-protected:
-    Sqlite3DataSourceTest() : rrclass(RRClass::IN()),
-                              rrclass_notmatch(RRClass::CH()),
-                              rrtype(RRType::A()), rrttl(RRTTL(3600)),
-                              find_flags(0), rrset_matched(0), rrset_count(0)
-    {
-        data_source.init(SQLITE_DBFILE_EXAMPLE);
-
-        common_a_data.push_back("192.0.2.1");
-        common_sig_data.push_back("A 5 3 3600" + sigdata_common);
-        common_aaaa_data.push_back("2001:db8::1234");
-        common_aaaa_sig_data.push_back("AAAA 5 3 3600" + sigdata_common);
-
-        www_nsec_data.push_back("example.com. A RRSIG NSEC");
-        www_nsec_sig_data.push_back("NSEC 5 3 7200" + sigdata_common);
-
-        mix_a_data.push_back("192.0.2.1");
-        mix_a_data.push_back("192.0.2.2");
-        mix_aaaa_data.push_back("2001:db8::1");
-        mix_aaaa_data.push_back("2001:db8::2");
-
-        apex_soa_data.push_back("master.example.com. admin.example.com. "
-                                "1234 3600 1800 2419200 7200");
-        apex_soa_sig_data.push_back("SOA 5 2 3600" + sigdata_common);
-        apex_ns_data.push_back("dns01.example.com.");
-        apex_ns_data.push_back("dns02.example.com.");
-        apex_ns_data.push_back("dns03.example.com.");
-        apex_ns_sig_data.push_back("NS 5 2 3600" + sigdata_common);
-        apex_mx_data.push_back("10 mail.example.com.");
-        apex_mx_data.push_back("20 mail.subzone.example.com.");
-        apex_mx_sig_data.push_back("MX 5 2 3600" + sigdata_common);
-        apex_nsec_data.push_back("cname-ext.example.com. "
-                                 "NS SOA MX RRSIG NSEC DNSKEY");
-        apex_nsec_sig_data.push_back("NSEC 5 2 7200" + sigdata_common);
-        apex_dnskey_data.push_back("256 3 5" + dnskey1_data);
-        apex_dnskey_data.push_back("257 3 5" + dnskey2_data);
-        // this one is special (using different key):
-        apex_dnskey_sig_data.push_back("DNSKEY 5 2 3600 20100322084538 "
-                                       "20100220084538 4456 example.com. "
-                                       "FAKEFAKEFAKEFAKE");
-        apex_dnskey_sig_data.push_back("DNSKEY 5 2 3600" + sigdata_common);
-
-        wild_a_data.push_back("192.0.2.255");
-        dname_data.push_back("sql1.example.com.");
-        dname_sig_data.push_back("DNAME 5 3 3600" + sigdata_common);
-        cname_data.push_back("cnametest.example.org.");
-        cname_sig_data.push_back("CNAME 5 3 3600" + sigdata_common);
-        cname_nsec_data.push_back("mail.example.com. CNAME RRSIG NSEC");
-        cname_nsec_sig_data.push_back("NSEC 5 3 7200" + sigdata_common);
-        delegation_ns_data.push_back("ns1.subzone.example.com.");
-        delegation_ns_data.push_back("ns2.subzone.example.com.");
-        delegation_ds_data.push_back("40633 5 1 "
-                                     "3E56C0EA92CF529E005A4B62979533350492 "
-                                     "F105");
-        delegation_ds_data.push_back("40633 5 2 "
-                                     "AA8D4BD330C68BFB4D785894DDCF6B689CE9"
-                                     "873C4A3801F57A5AA3FE17925B8C");
-        delegation_ds_sig_data.push_back("DS 5 3 3600" + sigdata_common);
-        child_ds_data.push_back("33313 5 1 "
-                                "FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8DE");
-        child_ds_data.push_back("33313 5 2 "
-                                "0B99B7006F496D135B01AB17EDB469B4BE9E"
-                                "1973884DEA757BC4E3015A8C3AB3");
-        child_ds_sig_data.push_back("DS 5 3 3600" + sigdata_common);
-        delegation_nsec_data.push_back("*.wild.example.com. NS DS RRSIG NSEC");
-        delegation_nsec_sig_data.push_back("NSEC 5 3 7200" + sigdata_common);
-        child_a_data.push_back("192.0.2.100");
-        child_sig_data.push_back("A 5 4 3600 20100322084536 "
-                                 "20100220084536 12447 sql1.example.com. "
-                                 "FAKEFAKEFAKEFAKE");
-        nsec3_data.push_back("1 0 10 FEEDABEE 4KLSVDE8KH8G95VU68R7AHBE1CPQN38J");
-        nsec3_sig_data.push_back("NSEC3 5 4 7200 20100410172647 "
-                                 "20100311172647 63192 sql2.example.com. "
-                                 + nsec3_signature);
-    }
-    Sqlite3DataSrc data_source;
-    // we allow these to be modified in the test
-    RRClass rrclass;
-    RRClass rrclass_notmatch;
-    RRType rrtype;
-    RRTTL rrttl;
-    RRsetList result_sets;
-    uint32_t find_flags;
-    unsigned rrset_matched;
-    unsigned rrset_count;
-
-    vector<RRType> types;
-    vector<RRTTL> ttls;
-    vector<const vector<string>* > answers;
-    vector<const vector<string>* > signatures;
-
-    vector<RRType> expected_types;
-    vector<string> common_a_data;
-    vector<string> common_sig_data;
-    vector<string> common_aaaa_data;
-    vector<string> common_aaaa_sig_data;
-    vector<string> www_nsec_data;
-    vector<string> www_nsec_sig_data;
-    vector<string> mix_a_data;
-    vector<string> mix_aaaa_data;
-    vector<string> apex_soa_data;
-    vector<string> apex_soa_sig_data;
-    vector<string> apex_ns_data;
-    vector<string> apex_ns_sig_data;
-    vector<string> apex_mx_data;
-    vector<string> apex_mx_sig_data;
-    vector<string> apex_nsec_data;
-    vector<string> apex_nsec_sig_data;
-    vector<string> apex_dnskey_data;
-    vector<string> apex_dnskey_sig_data;
-    vector<string> wild_a_data;
-    vector<string> dname_data;
-    vector<string> dname_sig_data;
-    vector<string> cname_data;
-    vector<string> cname_sig_data;
-    vector<string> cname_nsec_data;
-    vector<string> cname_nsec_sig_data;
-    vector<string> delegation_ns_data;
-    vector<string> delegation_ns_sig_data;
-    vector<string> delegation_ds_data;
-    vector<string> delegation_ds_sig_data;
-    vector<string> child_ds_data;
-    vector<string> child_ds_sig_data;
-    vector<string> delegation_nsec_data;
-    vector<string> delegation_nsec_sig_data;
-    vector<string> child_a_data;
-    vector<string> child_sig_data;
-    vector<string> nsec3_data;
-    vector<string> nsec3_sig_data;
-
-    void findReferralRRsetCommon(const Name& qname, const RRClass& qclass);
-    void findAddressRRsetCommon(const RRClass& qclass);
-};
-
-void
-checkRRset(RRsetPtr rrset, const Name& expected_name,
-           const RRClass& expected_class, const RRType& expected_type,
-           const RRTTL& expected_rrttl, const vector<string>& expected_data,
-           const vector<string>* expected_sig_data)
-{
-    EXPECT_EQ(expected_name, rrset->getName());
-    EXPECT_EQ(expected_class, rrset->getClass());
-    EXPECT_EQ(expected_type, rrset->getType());
-    EXPECT_EQ(expected_rrttl, rrset->getTTL());
-
-    RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
-    vector<string>::const_iterator data_it = expected_data.begin();
-    for (; data_it != expected_data.end(); ++data_it) {
-        EXPECT_FALSE(rdata_iterator->isLast());
-        if (rdata_iterator->isLast()) {
-            // buggy case, should stop here
-            break;
-        }
-
-        // We use text-based comparison so that we can easily identify which
-        // data causes the error.  RDATA::compare() is the most strict
-        // comparison method, but in this case text-based comparison should
-        // be okay because we generate the text data from Rdata objects
-        // rather than hand-write the expected text.
-        EXPECT_EQ(createRdata(expected_type, expected_class,
-                              *data_it)->toText(),
-                  rdata_iterator->getCurrent().toText());
-        rdata_iterator->next();
-    }
-
-    if (expected_sig_data != NULL) {
-        RRsetPtr sig_rrset = rrset->getRRsig();
-        EXPECT_FALSE(sig_rrset == NULL);
-        if (sig_rrset != NULL) { // check this to avoid possible bug.
-            // Note: we assume the TTL for RRSIG is the same as that of the
-            // RRSIG target.
-            checkRRset(sig_rrset, expected_name, expected_class,
-                       RRType::RRSIG(), expected_rrttl, *expected_sig_data,
-                       NULL);
-        }
-    } else {
-        EXPECT_TRUE(NULL == rrset->getRRsig());
-    }
-
-    EXPECT_TRUE(rdata_iterator->isLast());
-}
-
-void
-checkFind(FindMode mode, const Sqlite3DataSrc& data_source,
-          const Name& expected_name, const Name* zone_name,
-          const RRClass& qclass, const RRClass& expected_class,
-          const RRType& expected_type, const vector<RRTTL>& expected_ttls,
-          const uint32_t expected_flags, const vector<RRType>& expected_types,
-          const vector<const vector<string>* >& expected_answers,
-          const vector<const vector<string>* >& expected_signatures)
-{
-    RRsetList result_sets;
-    uint32_t find_flags;
-    unsigned int rrset_matched = 0;
-    unsigned int rrset_count = 0;
-
-    switch (mode) {
-    case NORMAL:
-        EXPECT_EQ(DataSrc::SUCCESS,
-                  data_source.findRRset(expected_name, qclass,
-                                        expected_type, result_sets, find_flags,
-                                        zone_name));
-        break;
-    case EXACT:
-        EXPECT_EQ(DataSrc::SUCCESS,
-                  data_source.findExactRRset(expected_name, qclass,
-                                             expected_type, result_sets,
-                                             find_flags, zone_name));
-        break;
-    case ADDRESS:
-        EXPECT_EQ(DataSrc::SUCCESS,
-                  data_source.findAddrs(expected_name, qclass, result_sets,
-                                        find_flags, zone_name));
-        break;
-    case REFERRAL:
-        EXPECT_EQ(DataSrc::SUCCESS,
-                  data_source.findReferral(expected_name, qclass, result_sets,
-                                           find_flags, zone_name));
-        break;
-    }
-    EXPECT_EQ(expected_flags, find_flags);
-    RRsetList::iterator it = result_sets.begin();
-    for (; it != result_sets.end(); ++it) {
-        vector<RRType>::const_iterator found_type =
-            find(expected_types.begin(), expected_types.end(),
-                 (*it)->getType());
-        // there should be a match
-        EXPECT_TRUE(found_type != expected_types.end());
-        if (found_type != expected_types.end()) {
-            unsigned int index = distance(expected_types.begin(), found_type);
-            checkRRset(*it, expected_name, expected_class, (*it)->getType(),
-                       expected_ttls[index], *expected_answers[index],
-                       expected_signatures[index]);
-            ++rrset_matched;
-        }
-        ++rrset_count;
-    }
-    EXPECT_EQ(expected_types.size(), rrset_count);
-    EXPECT_EQ(expected_types.size(), rrset_matched);
-}
-
-void
-checkFind(FindMode mode, const Sqlite3DataSrc& data_source,
-          const Name& expected_name, const Name* zone_name,
-          const RRClass& qclass, const RRClass& expected_class,
-          const RRType& expected_type, const RRTTL& expected_rrttl,
-          const uint32_t expected_flags,
-          const vector<string>& expected_data,
-          const vector<string>* expected_sig_data)
-{
-    vector<RRType> types;
-    vector<RRTTL> ttls;
-    vector<const vector<string>* > answers;
-    vector<const vector<string>* > signatures;
-
-    types.push_back(expected_type);
-    ttls.push_back(expected_rrttl);
-    answers.push_back(&expected_data);
-    signatures.push_back(expected_sig_data);
-
-    checkFind(mode, data_source, expected_name, zone_name, qclass,
-              expected_class, expected_type, ttls, expected_flags, types,
-              answers, signatures);
-}
-
-TEST_F(Sqlite3DataSourceTest, close) {
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
-}
-
-TEST_F(Sqlite3DataSourceTest, reOpen) {
-    // Replace the data with a totally different zone.  This should succeed,
-    // and shouldn't match any names in the previously managed domains.
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE2));
-
-    DataSrcMatch match(www_name, rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(static_cast<void*>(NULL), match.getEnclosingZone());
-    EXPECT_EQ(static_cast<void*>(NULL), match.getDataSource());
-}
-
-TEST_F(Sqlite3DataSourceTest, openFail) {
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
-    EXPECT_THROW(data_source.init(SQLITE_DBFILE_NOTEXIST), Sqlite3Error);
-}
-
-TEST_F(Sqlite3DataSourceTest, doubleOpen) {
-    // An attempt of duplicate open should trigger an exception.
-    EXPECT_THROW(data_source.init(SQLITE_DBFILE_EXAMPLE), DataSourceError);
-}
-
-TEST_F(Sqlite3DataSourceTest, doubleClose) {
-    // An attempt of duplicate close should trigger an exception.
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
-    EXPECT_THROW(data_source.close(), DataSourceError);
-}
-
-TEST_F(Sqlite3DataSourceTest, openBrokenDB) {
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
-    // The database exists but is broken.  An exception will be thrown 
-    // in the middle of the initialization.
-    EXPECT_THROW(data_source.init(SQLITE_DBFILE_BROKENDB), Sqlite3Error);
-    // Confirming the strong exception guarantee: the data source must be
-    // in the closed state.
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE));
-}
-
-// Different schema versions, see sqlite3_accessor_unittest.
-TEST_F(Sqlite3DataSourceTest, differentSchemaVersions) {
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
-    EXPECT_THROW(data_source.init(SQLITE_DBFILE_NEWSCHEMA),
-                 IncompatibleDbVersion);
-    EXPECT_THROW(data_source.init(SQLITE_DBFILE_OLDSCHEMA),
-                 IncompatibleDbVersion);
-    // Don't bother to test the new_minor case; we should retire this stuff
-    // before it really happens.
-}
-
-// This test only confirms that on-the-fly schema creation works.
-TEST_F(Sqlite3DataSourceTest, memoryDB) {
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_MEMORY));
-}
-
-TEST_F(Sqlite3DataSourceTest, findClosestEnclosure) {
-    DataSrcMatch match(www_name, rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(zone_name, *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-TEST_F(Sqlite3DataSourceTest, findClosestEnclosureMatchRoot) {
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE_ROOT));
-
-    DataSrcMatch match(Name("org."), rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(Name("."), *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-TEST_F(Sqlite3DataSourceTest, findClosestEnclosureAtDelegation) {
-    // The search name exists both in the parent and child zones, but
-    // child has a better match.
-    DataSrcMatch match(child_name, rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(child_name, *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-TEST_F(Sqlite3DataSourceTest, findClosestEnclosureNoMatch) {
-    DataSrcMatch match(nomatch_name, rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(static_cast<void*>(NULL), match.getEnclosingZone());
-    EXPECT_EQ(static_cast<void*>(NULL), match.getDataSource());
-}
-
-TEST_F(Sqlite3DataSourceTest, findClosestClassMismatch) {
-    DataSrcMatch match(nomatch_name, rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(static_cast<void*>(NULL), match.getEnclosingZone());
-    EXPECT_EQ(static_cast<void*>(NULL), match.getDataSource());
-}
-
-// If the query class is ANY, the result should be the same as the case where
-// the class exactly matches.
-TEST_F(Sqlite3DataSourceTest, findClosestClassAny) {
-    DataSrcMatch match(www_name, RRClass::ANY());
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(zone_name, *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetNormal) {
-    // Without specifying the zone name, and then with the zone name
-    checkFind(NORMAL, data_source, www_name, NULL, rrclass, rrclass, rrtype,
-              rrttl, 0, common_a_data, &common_sig_data);
-
-    checkFind(NORMAL, data_source, www_name, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, 0, common_a_data, &common_sig_data);
-
-    // With a zone name that doesn't match
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(www_name, rrclass, rrtype,
-                                    result_sets, find_flags, &nomatch_name));
-    EXPECT_EQ(DataSrc::NO_SUCH_ZONE, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end()); // should be empty
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetClassMismatch) {
-    EXPECT_EQ(DataSrc::ERROR,
-              data_source.findRRset(www_name, rrclass_notmatch, rrtype,
-                                    result_sets, find_flags, NULL));
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetClassAny) {
-    checkFind(NORMAL, data_source, www_name, NULL, RRClass::ANY(), rrclass,
-              rrtype, rrttl, 0, common_a_data, &common_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetClassClassAny) {
-    checkFind(NORMAL, data_source, www_name, NULL, RRClass::ANY(), rrclass,
-              rrtype, rrttl, 0, common_a_data, &common_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetNormalANY) {
-    types.push_back(RRType::A());
-    types.push_back(RRType::NSEC());
-    ttls.push_back(RRTTL(3600));
-    ttls.push_back(RRTTL(7200));
-    answers.push_back(&common_a_data);
-    answers.push_back(&www_nsec_data);
-    signatures.push_back(&common_sig_data);
-    signatures.push_back(&www_nsec_sig_data);
-
-    rrtype = RRType::ANY();
-    checkFind(NORMAL, data_source, www_name, NULL, rrclass, rrclass, rrtype,
-              ttls, 0, types, answers, signatures);
-
-    checkFind(NORMAL, data_source, www_name, &zone_name, rrclass, rrclass,
-              rrtype, ttls, 0, types, answers, signatures);
-}
-
-// Case insensitive lookup
-TEST_F(Sqlite3DataSourceTest, findRRsetNormalCase) {
-    checkFind(NORMAL, data_source, www_upper_name, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, common_a_data, &common_sig_data);
-
-    checkFind(NORMAL, data_source, www_upper_name, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, 0, common_a_data, &common_sig_data);
-
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(www_upper_name, rrclass, rrtype,
-                                    result_sets, find_flags, &nomatch_name));
-    EXPECT_EQ(DataSrc::NO_SUCH_ZONE, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end()); // should be empty
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetApexNS) {
-    rrtype = RRType::NS();
-    checkFind(NORMAL, data_source, zone_name, NULL, rrclass, rrclass, rrtype,
-              rrttl, DataSrc::REFERRAL, apex_ns_data, &apex_ns_sig_data);
-
-    checkFind(NORMAL, data_source, zone_name, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, DataSrc::REFERRAL, apex_ns_data,
-              &apex_ns_sig_data);
-
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(zone_name, rrclass, rrtype,
-                                    result_sets, find_flags, &nomatch_name));
-    EXPECT_EQ(DataSrc::NO_SUCH_ZONE, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end()); // should be empty
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetApexANY) {
-    types.push_back(RRType::SOA());
-    types.push_back(RRType::NS());
-    types.push_back(RRType::MX());
-    types.push_back(RRType::NSEC());
-    types.push_back(RRType::DNSKEY());
-    ttls.push_back(rrttl); // SOA TTL
-    ttls.push_back(rrttl); // NS TTL
-    ttls.push_back(rrttl); // MX TTL
-    ttls.push_back(RRTTL(7200)); // NSEC TTL
-    ttls.push_back(rrttl); // DNSKEY TTL
-    answers.push_back(&apex_soa_data);
-    answers.push_back(&apex_ns_data);
-    answers.push_back(&apex_mx_data);
-    answers.push_back(&apex_nsec_data);
-    answers.push_back(&apex_dnskey_data);
-    signatures.push_back(&apex_soa_sig_data);
-    signatures.push_back(&apex_ns_sig_data);
-    signatures.push_back(&apex_mx_sig_data);
-    signatures.push_back(&apex_nsec_sig_data);
-    signatures.push_back(&apex_dnskey_sig_data);
-
-    rrtype = RRType::ANY();
-
-    // there is an NS at the zone apex, so the REFERRAL flag should
-    // be set, but will ordinarily be ignored by the caller
-    checkFind(NORMAL, data_source, zone_name, NULL, rrclass, rrclass, rrtype,
-              ttls, DataSrc::REFERRAL, types, answers, signatures);
-
-    checkFind(NORMAL, data_source, zone_name, &zone_name, rrclass, rrclass,
-              rrtype, ttls, DataSrc::REFERRAL, types, answers, signatures);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetMixedANY) {
-    // ANY query for mixed order RRs
-    const Name qname("mix.example.com");
-
-    types.push_back(RRType::A());
-    types.push_back(RRType::AAAA());
-    ttls.push_back(rrttl);
-    ttls.push_back(rrttl);
-    answers.push_back(&mix_a_data);
-    answers.push_back(&mix_aaaa_data);
-    signatures.push_back(NULL);
-    signatures.push_back(NULL);
-
-    rrtype = RRType::ANY();
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, ttls, 0, types, answers, signatures);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetApexNXRRSET) {
-    rrtype = RRType::AAAA();
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(zone_name, rrclass, rrtype,
-                                    result_sets, find_flags, &zone_name));
-    // there's an NS RRset at the apex name, so the REFERRAL flag should be
-    // set, too.
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND | DataSrc::REFERRAL, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-
-    // Same test, without specifying the zone name
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(zone_name, rrclass, rrtype,
-                                    result_sets, find_flags, NULL));
-    // there's an NS RRset at the apex name, so the REFERRAL flag should be
-    // set, too.
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND | DataSrc::REFERRAL, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-}
-
-// Matching a wildcard node.  There's nothing special for the data source API
-// point of view, but perform minimal tests anyway.
-TEST_F(Sqlite3DataSourceTest, findRRsetWildcard) {
-    const Name qname("*.wild.example.com");
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, wild_a_data, &common_sig_data);
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, 0, wild_a_data, &common_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetEmptyNode) {
-    // foo.bar.example.com exists, but bar.example.com doesn't have any data.
-    const Name qname("bar.example.com");
-
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(qname, rrclass, rrtype,
-                                    result_sets, find_flags, NULL));
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(qname, rrclass, rrtype,
-                                    result_sets, find_flags, &zone_name));
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-}
-
-// There's nothing special about DNAME lookup for the data source API
-// point of view, but perform minimal tests anyway.
-TEST_F(Sqlite3DataSourceTest, findRRsetDNAME) {
-    const Name qname("dname.example.com");
-
-    rrtype = RRType::DNAME();
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, dname_data, &dname_sig_data);
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, 0, dname_data, &dname_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetCNAME) {
-    const Name qname("foo.example.com");
-
-    // This qname only has the CNAME (+ sigs).  CNAME query is not different
-    // from ordinary queries.
-    rrtype = RRType::CNAME();
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, cname_data, &cname_sig_data);
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, 0, cname_data, &cname_sig_data);
-
-    // queries for (ordinary) different RR types that match the CNAME.
-    // CNAME_FOUND flag is set, and the CNAME RR is returned instead of A
-    rrtype = RRType::A();
-    types.push_back(RRType::CNAME());
-    ttls.push_back(rrttl);
-    answers.push_back(&cname_data);
-    signatures.push_back(&cname_sig_data);
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, ttls, DataSrc::CNAME_FOUND, types, answers, signatures);
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, ttls, DataSrc::CNAME_FOUND, types, answers, signatures);
-
-    // NSEC query that match the CNAME.
-    // CNAME_FOUND flag is NOT set, and the NSEC RR is returned instead of
-    // CNAME.
-    rrtype = RRType::NSEC();
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, RRTTL(7200), 0, cname_nsec_data, &cname_nsec_sig_data);
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, RRTTL(7200), 0, cname_nsec_data, &cname_nsec_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetDelegation) {
-    const Name qname("www.subzone.example.com");
-
-    // query for a name under a zone cut.  From the data source API point
-    // of view this is no different than "NXDOMAIN".
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(qname, rrclass, rrtype,
-                                    result_sets, find_flags, NULL));
-    EXPECT_EQ(DataSrc::NAME_NOT_FOUND, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetDelegationAtZoneCut) {
-    const Name qname("subzone.example.com");
-
-    // query for a name *at* a zone cut.  It matches the NS RRset for the
-    // delegation.
-
-    // For non-NS ordinary queries, "no type" should be set too, and no RRset is
-    // returned.
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(qname, rrclass, rrtype,
-                                    result_sets, find_flags, NULL));
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND | DataSrc::REFERRAL, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(qname, rrclass, rrtype,
-                                    result_sets, find_flags, &zone_name));
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND | DataSrc::REFERRAL, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-
-    // For NS query, RRset is returned with the REFERRAL flag.  No RRSIG should
-    // be provided.
-    rrtype = RRType::NS();
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, rrttl, DataSrc::REFERRAL, delegation_ns_data, NULL);
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, DataSrc::REFERRAL, delegation_ns_data, NULL);
-
-    // For ANY query.  At the backend data source level, it returns all
-    // existent records with their RRSIGs, setting the referral flag.
-    rrtype = RRType::ANY();
-    types.push_back(RRType::NS());
-    types.push_back(RRType::NSEC());
-    types.push_back(RRType::DS());
-    ttls.push_back(rrttl);
-    ttls.push_back(RRTTL(7200));
-    ttls.push_back(rrttl);
-    answers.push_back(&delegation_ns_data);
-    answers.push_back(&delegation_nsec_data);
-    answers.push_back(&delegation_ds_data);
-    signatures.push_back(NULL);
-    signatures.push_back(&delegation_nsec_sig_data);
-    signatures.push_back(&delegation_ds_sig_data);
-
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, ttls, DataSrc::REFERRAL, types, answers,
-              signatures);
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, ttls, DataSrc::REFERRAL, types, answers,
-              signatures);
-
-    // For NSEC query.  At the backend data source level, it returns NSEC+
-    // RRSIG with the referral flag.
-    rrtype = RRType::NSEC();
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, RRTTL(7200), DataSrc::REFERRAL, delegation_nsec_data,
-              &delegation_nsec_sig_data);
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, RRTTL(7200), DataSrc::REFERRAL, delegation_nsec_data,
-              &delegation_nsec_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetInChildZone) {
-    const Name qname("www.sql1.example.com");
-    const Name child_zone_name("sql1.example.com");
-
-    // If we don't specify the zone, the data source should identify the
-    // best matching zone.
-    checkFind(NORMAL, data_source, qname, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, child_a_data, &child_sig_data);
-
-    // If we specify the parent zone, it's treated as NXDOMAIN because it's
-    // under a zone cut.
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(qname, rrclass, rrtype,
-                                    result_sets, find_flags, &zone_name));
-    EXPECT_EQ(DataSrc::NAME_NOT_FOUND, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-
-    // If we specify the child zone, it should be the same as the first case.
-    checkFind(NORMAL, data_source, qname, &child_zone_name, rrclass, rrclass,
-              rrtype, rrttl, 0, child_a_data, &child_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findExactRRset) {
-    // Normal case.  No different than findRRset.
-    checkFind(EXACT, data_source, www_name, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, 0, common_a_data, &common_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findExactRRsetClassMismatch) {
-    EXPECT_EQ(DataSrc::ERROR,
-              data_source.findExactRRset(www_name, rrclass_notmatch, rrtype,
-                                         result_sets, find_flags, NULL));
-}
-
-TEST_F(Sqlite3DataSourceTest, findExactRRsetClassAny) {
-    checkFind(EXACT, data_source, www_name, &zone_name, RRClass::ANY(), rrclass,
-              rrtype, rrttl, 0, common_a_data, &common_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findRRsetNSEC3) {
-    // Simple NSEC3 tests (more should be added)
-    string hashstr("1BB7SO0452U1QHL98UISNDD9218GELR5");
-
-    const Name nsec3_zonename("sql2.example.com");
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findCoveringNSEC3(nsec3_zonename,
-                                            hashstr, result_sets));
-    RRsetList::iterator it = result_sets.begin();
-    checkRRset(*it, Name(hashstr).concatenate(nsec3_zonename), rrclass,
-               RRType::NSEC3(), RRTTL(7200), nsec3_data, &nsec3_sig_data);
-    ++it;
-    EXPECT_TRUE(it == result_sets.end());
-
-}
-
-TEST_F(Sqlite3DataSourceTest, findExactRRsetCNAME) {
-    const Name qname("foo.example.com");
-
-    // This qname only has the CNAME (+ sigs).  In this case it should be
-    // no different than findRRset for CNAME query.
-    rrtype = RRType::CNAME();
-    checkFind(NORMAL, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, rrttl, 0, cname_data, &cname_sig_data);
-
-    // queries for (ordinary) different RR types that match the CNAME.
-    // "type not found" set, but CNAME and its sig are returned (awkward,
-    // but that's how it currently works).
-    rrtype = RRType::A();
-    types.push_back(RRType::CNAME());
-    ttls.push_back(rrttl);
-    answers.push_back(&cname_data);
-    signatures.push_back(&cname_sig_data);
-    checkFind(EXACT, data_source, qname, &zone_name, rrclass, rrclass,
-              rrtype, ttls, DataSrc::TYPE_NOT_FOUND, types, answers,
-              signatures);
-}
-
-void
-Sqlite3DataSourceTest::findReferralRRsetCommon(const Name& qname,
-                                               const RRClass& qclass)
-{
-    types.push_back(RRType::NS());
-    types.push_back(RRType::DS());
-    ttls.push_back(rrttl);
-    ttls.push_back(rrttl);
-    answers.push_back(&apex_ns_data);
-    answers.push_back(&child_ds_data);
-    signatures.push_back(NULL);
-    signatures.push_back(&child_ds_sig_data);
-    // Note: zone_name matters here because we need to perform the search
-    // in the parent zone.
-    checkFind(REFERRAL, data_source, qname, &zone_name, qclass, rrclass,
-              rrtype, ttls, DataSrc::REFERRAL, types, answers, signatures);
-}
-    
-
-TEST_F(Sqlite3DataSourceTest, findReferralRRset) {
-    // A referral lookup searches for NS, DS, or DNAME, or their sigs.
-    const Name qname("sql1.example.com");
-    findReferralRRsetCommon(qname, rrclass);
-}
-
-TEST_F(Sqlite3DataSourceTest, findReferralRRsetClassMismatch) {
-    EXPECT_EQ(DataSrc::ERROR,
-              data_source.findReferral(www_name, rrclass_notmatch, result_sets,
-                                       find_flags, NULL));
-}
-
-TEST_F(Sqlite3DataSourceTest, findReferralRRsetClassAny) {
-    const Name qname("sql1.example.com");
-    findReferralRRsetCommon(qname, RRClass::ANY());
-}
-
-TEST_F(Sqlite3DataSourceTest, findReferralRRsetDNAME) {
-    // same as above.  the DNAME case.
-    const Name qname("dname.example.com");
-    checkFind(REFERRAL, data_source, qname, &zone_name, rrclass, rrclass,
-              RRType::DNAME(), rrttl, 0, dname_data, &dname_sig_data);
-}
-
-TEST_F(Sqlite3DataSourceTest, findReferralRRsetFail) {
-    // qname has not "referral" records.  the result should be "empty".
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findReferral(www_name, rrclass,
-                                       result_sets, find_flags, &zone_name));
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-}
-
-void
-Sqlite3DataSourceTest::findAddressRRsetCommon(const RRClass& qclass) {
-    // A referral lookup searches for A or AAAA, or their sigs.
-
-    // A-only case
-    checkFind(ADDRESS, data_source, www_name, &zone_name, qclass, rrclass,
-              rrtype, rrttl, 0, common_a_data, &common_sig_data);
-
-    // AAAA-only case
-    checkFind(ADDRESS, data_source, Name("ip6.example.com"), &zone_name,
-              qclass, rrclass, RRType::AAAA(), rrttl, 0, common_aaaa_data,
-              &common_aaaa_sig_data);
-
-    // Dual-stack
-    types.push_back(RRType::A());
-    ttls.push_back(rrttl);
-    answers.push_back(&common_a_data);
-    signatures.push_back(&common_sig_data);
-    types.push_back(RRType::AAAA());
-    ttls.push_back(rrttl);
-    answers.push_back(&common_aaaa_data);
-    signatures.push_back(&common_aaaa_sig_data);
-    checkFind(ADDRESS, data_source, Name("ip46.example.com"), &zone_name,
-              rrclass, rrclass, rrtype, ttls, 0, types, answers, signatures);
-
-    // The qname doesn't have no address records.
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findAddrs(Name("text.example.com"), qclass,
-                                    result_sets, find_flags, &zone_name));
-    EXPECT_EQ(DataSrc::TYPE_NOT_FOUND, find_flags);
-    EXPECT_TRUE(result_sets.begin() == result_sets.end());
-}
-
-TEST_F(Sqlite3DataSourceTest, findAddressRRset) {
-    findAddressRRsetCommon(rrclass);
-}
-
-TEST_F(Sqlite3DataSourceTest, findAddressRRsetClassMismatch) {
-    EXPECT_EQ(DataSrc::ERROR, data_source.findAddrs(www_name, rrclass_notmatch,
-                                                    result_sets, find_flags,
-                                                    NULL));
-}
-
-TEST_F(Sqlite3DataSourceTest, findAddressRRsetClassAny) {
-    findAddressRRsetCommon(RRClass::ANY());
-}
-
-}

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

@@ -1,422 +0,0 @@
-// Copyright (C) 2010  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 <stdint.h>
-#include <string>
-#include <vector>
-
-#include <config.h>
-
-#include <gtest/gtest.h>
-
-#include <dns/name.h>
-#include <dns/message.h>
-#include <dns/rdata.h>
-#include <dns/rrclass.h>
-#include <dns/rrtype.h>
-#include <dns/rdataclass.h>
-#include <dns/rrsetlist.h>
-#include <cc/data.h>
-
-#include <datasrc/query.h>
-#include <datasrc/data_source.h>
-#include <datasrc/static_datasrc.h>
-
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-using namespace isc::datasrc;
-
-namespace {
-class StaticDataSourceTest : public ::testing::Test {
-protected:
-    StaticDataSourceTest() : version_name("version.bind"),
-                             authors_name("authors.bind"),
-                             nomatch_name("example.com"),
-                             rrclass(RRClass::CH()), rrtype(RRType::TXT()),
-                             rrttl(RRTTL(0)), find_flags(0), matched_rdata(0)
-    {
-        // version.bind is answered with package name+version
-        // (defined as PACKAGE_STRING in config.h)
-        version_data.push_back(PACKAGE_STRING);
-
-        // NOTE: in addition, the order of the following items matter.
-        authors_data.push_back("Chen Zhengzhang");
-        authors_data.push_back("Dmitriy Volodin");
-        authors_data.push_back("Evan Hunt");
-        authors_data.push_back("Haidong Wang");
-        authors_data.push_back("Haikuo Zhang");
-        authors_data.push_back("Han Feng");
-        authors_data.push_back("Jelte Jansen");
-        authors_data.push_back("Jeremy C. Reed");
-        authors_data.push_back("Xie Jiagui");
-        authors_data.push_back("Jin Jian");
-        authors_data.push_back("JINMEI Tatuya");
-        authors_data.push_back("Kazunori Fujiwara");
-        authors_data.push_back("Michael Graff");
-        authors_data.push_back("Michal Vaner");
-        authors_data.push_back("Mukund Sivaraman");
-        authors_data.push_back("Naoki Kambe");
-        authors_data.push_back("Shane Kerr");
-        authors_data.push_back("Shen Tingting");
-        authors_data.push_back("Stephen Morris");
-        authors_data.push_back("Yoshitaka Aharen");
-        authors_data.push_back("Zhang Likun");
-
-        version_ns_data.push_back("version.bind.");
-        authors_ns_data.push_back("authors.bind.");
-
-        version_soa_data.push_back("version.bind. hostmaster.version.bind. "
-                                   "0 28800 7200 604800 86400");
-        authors_soa_data.push_back("authors.bind. hostmaster.authors.bind. "
-                                   "0 28800 7200 604800 86400");
-    }
-    StaticDataSrc data_source;
-    const Name version_name;
-    const Name authors_name;
-    const Name nomatch_name;
-    const RRClass rrclass;
-    RRType rrtype;              // we allow this to be modified in the test
-    RRTTL rrttl;
-    RRsetList result_sets;
-    uint32_t find_flags;
-    unsigned matched_rdata;
-    vector<RRType> types;
-    vector<RRTTL> ttls;
-    vector<const vector<string>* > answers;
-    vector<string> version_data;
-    vector<string> authors_data;
-    vector<string> version_ns_data;
-    vector<string> authors_ns_data;
-    vector<string> version_soa_data;
-    vector<string> authors_soa_data;
-};
-
-void
-checkRRset(ConstRRsetPtr rrset, const Name& expected_name,
-           const RRClass& expected_class, const RRType& expected_type,
-           const RRTTL& rrttl, const vector<string>& expected_data)
-{
-    EXPECT_EQ(expected_name, rrset->getName());
-    EXPECT_EQ(expected_class, rrset->getClass());
-    EXPECT_EQ(expected_type, rrset->getType());
-    EXPECT_EQ(rrttl, rrset->getTTL());
-
-    RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
-    vector<string>::const_iterator data_it = expected_data.begin();
-    for (; data_it != expected_data.end(); ++data_it) {
-        EXPECT_FALSE(rdata_iterator->isLast());
-        if (rdata_iterator->isLast()) {
-            // buggy case, should stop here
-            break;
-        }
-        EXPECT_EQ(0, (rdata_iterator->getCurrent()).compare(
-                      *createRdata(expected_type,
-                                   expected_class,
-                                   *data_it)));
-        rdata_iterator->next();
-    }
-
-    EXPECT_TRUE(rdata_iterator->isLast());
-}
-
-void
-checkFind(const DataSrc& data_source,
-          const Name& qname, const Name* zone_name,
-          const RRClass& qclass, const RRClass& expected_class,
-          const RRType& qtype, const vector<RRTTL>& expected_ttls,
-          const uint32_t expected_flags, const vector<RRType>& expected_types,
-          const vector<const vector<string>* >& expected_answers)
-{
-    RRsetList result_sets;
-    uint32_t find_flags;
-    unsigned int rrset_matched = 0;
-    unsigned int rrset_count = 0;
-
-    EXPECT_EQ(DataSrc::SUCCESS,
-              data_source.findRRset(qname, qclass, qtype, result_sets,
-                                    find_flags, zone_name));
-    EXPECT_EQ(expected_flags, find_flags);
-
-    if ((find_flags & (DataSrc::NO_SUCH_ZONE | DataSrc::NAME_NOT_FOUND |
-                       DataSrc::TYPE_NOT_FOUND)) != 0) {
-        EXPECT_TRUE(result_sets.begin() == result_sets.end());
-        return;
-    }
-
-    RRsetList::iterator it = result_sets.begin();
-    for (; it != result_sets.end(); ++it) {
-        vector<RRType>::const_iterator found_type =
-            find(expected_types.begin(), expected_types.end(),
-                 (*it)->getType());
-        // there should be a match
-        EXPECT_TRUE(found_type != expected_types.end());
-        if (found_type != expected_types.end()) {
-            unsigned int index = distance(expected_types.begin(), found_type);
-            checkRRset(*it, qname, expected_class, (*it)->getType(),
-                       expected_ttls[index], *expected_answers[index]);
-            ++rrset_matched;
-        }
-        ++rrset_count;
-    }
-    EXPECT_EQ(expected_types.size(), rrset_count);
-    EXPECT_EQ(expected_types.size(), rrset_matched);
-}
-
-void
-checkFind(const DataSrc& data_source,
-          const Name& qname, const Name* zone_name,
-          const RRClass& qclass, const RRClass& expected_class,
-          const RRType& qtype,  // == expected RRType
-          const RRTTL& expected_ttl, const uint32_t expected_flags,
-          const vector<string>& expected_answers)
-{
-    vector<RRType> types;
-    vector<RRTTL> ttls;
-    vector<const vector<string>* > answers;
-
-    types.push_back(qtype);
-    ttls.push_back(expected_ttl);
-    answers.push_back(&expected_answers);
-
-    checkFind(data_source, qname, zone_name, qclass, expected_class, qtype,
-              ttls, expected_flags, types, answers);
-}
-
-TEST_F(StaticDataSourceTest, init) {
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.init());
-}
-
-TEST_F(StaticDataSourceTest, close) {
-    EXPECT_EQ(DataSrc::SUCCESS, data_source.init());
-}
-
-TEST_F(StaticDataSourceTest, findClosestEnclosureForVersion) {
-    DataSrcMatch match(version_name, rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(version_name, *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-// Class Any query should result in the same answer.
-TEST_F(StaticDataSourceTest, findClosestEnclosureForVersionClassAny) {
-    DataSrcMatch match(version_name, RRClass::ANY());
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(version_name, *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-// If class doesn't match the lookup should fail.
-TEST_F(StaticDataSourceTest, findClosestEnclosureForVersionClassMismatch) {
-    DataSrcMatch match(version_name, RRClass::IN());
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(static_cast<void*>(NULL), match.getEnclosingZone());
-    EXPECT_EQ(static_cast<void*>(NULL), match.getDataSource());
-}
-
-TEST_F(StaticDataSourceTest, findClosestEnclosureForVersionPartial) {
-    DataSrcMatch match(Name("foo").concatenate(version_name), rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(version_name, *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-TEST_F(StaticDataSourceTest, findClosestEnclosureForAuthors) {
-    DataSrcMatch match(authors_name, rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(authors_name, *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-TEST_F(StaticDataSourceTest, findClosestEnclosureForAuthorsPartial) {
-    DataSrcMatch match(Name("foo").concatenate(authors_name), rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(authors_name, *match.getEnclosingZone());
-    EXPECT_EQ(&data_source, match.getDataSource());
-}
-
-TEST_F(StaticDataSourceTest, findClosestEnclosureNoMatch) {
-    DataSrcMatch match(nomatch_name, rrclass);
-    data_source.findClosestEnclosure(match);
-    EXPECT_EQ(static_cast<void*>(NULL), match.getEnclosingZone());
-    EXPECT_EQ(static_cast<void*>(NULL), match.getDataSource());
-}
-
-TEST_F(StaticDataSourceTest, findRRsetVersionTXT) {
-    checkFind(data_source, version_name, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, version_data);
-    checkFind(data_source, version_name, &version_name, rrclass, rrclass,
-              rrtype, rrttl, 0, version_data);
-}
-
-TEST_F(StaticDataSourceTest, findRRsetVersionNS) {
-    rrtype = RRType::NS();
-    checkFind(data_source, version_name, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, version_ns_data);
-    checkFind(data_source, version_name, &version_name, rrclass, rrclass,
-              rrtype, rrttl, 0, version_ns_data);
-}
-
-TEST_F(StaticDataSourceTest, findRRsetVersionSOA) {
-    rrtype = RRType::SOA();
-
-    checkFind(data_source, version_name, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, version_soa_data);
-    checkFind(data_source, version_name, &version_name, rrclass, rrclass,
-              rrtype, rrttl, 0, version_soa_data);
-}
-
-TEST_F(StaticDataSourceTest, findRRsetVersionANY) {
-    rrtype = RRType::ANY();
-    
-    types.push_back(RRType::TXT());
-    types.push_back(RRType::NS());
-    types.push_back(RRType::SOA());
-    ttls.push_back(rrttl);
-    ttls.push_back(rrttl);
-    ttls.push_back(rrttl);
-    answers.push_back(&version_data);
-    answers.push_back(&version_ns_data);
-    answers.push_back(&version_soa_data);
-
-    checkFind(data_source, version_name, NULL, rrclass, rrclass, rrtype, ttls,
-              0, types, answers);
-    checkFind(data_source, version_name, &version_name, rrclass, rrclass,
-              rrtype, ttls, 0, types, answers);
-}
-
-TEST_F(StaticDataSourceTest, findRRsetAuthorsTXT) {
-    checkFind(data_source, authors_name, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, authors_data);
-    checkFind(data_source, authors_name, &authors_name, rrclass, rrclass,
-              rrtype, rrttl, 0, authors_data);
-}
-
-TEST_F(StaticDataSourceTest, findRRsetAuthorsNS) {
-    rrtype = RRType::NS();
-    checkFind(data_source, authors_name, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, authors_ns_data);
-    checkFind(data_source, authors_name, &authors_name, rrclass, rrclass,
-              rrtype, rrttl, 0, authors_ns_data);
-}
-
-TEST_F(StaticDataSourceTest, findRRsetAuthorsSOA) {
-    rrtype = RRType::SOA();
-    checkFind(data_source, authors_name, NULL, rrclass, rrclass,
-              rrtype, rrttl, 0, authors_soa_data);
-    checkFind(data_source, authors_name, &authors_name, rrclass, rrclass,
-              rrtype, rrttl, 0, authors_soa_data);
-}
-
-TEST_F(StaticDataSourceTest, findRRsetAuthorsANY) {
-    rrtype = RRType::ANY();
-    
-    types.push_back(RRType::TXT());
-    types.push_back(RRType::NS());
-    types.push_back(RRType::SOA());
-    ttls.push_back(rrttl);
-    ttls.push_back(rrttl);
-    ttls.push_back(rrttl);
-    answers.push_back(&authors_data);
-    answers.push_back(&authors_ns_data);
-    answers.push_back(&authors_soa_data);
-
-    checkFind(data_source, authors_name, NULL, rrclass, rrclass, rrtype, ttls,
-              0, types, answers);
-    checkFind(data_source, authors_name, &authors_name, rrclass, rrclass,
-              rrtype, ttls, 0, types, answers);
-}
-// Class ANY lookup should result in the same answer.
-TEST_F(StaticDataSourceTest, findRRsetVersionClassAny) {
-    checkFind(data_source, version_name, NULL, RRClass::ANY(), rrclass,
-              rrtype, rrttl, 0, version_data);
-    checkFind(data_source, version_name, &version_name, RRClass::ANY(), rrclass,
-              rrtype, rrttl, 0, version_data);
-}
-
-// If the class doesn't match, it should simply fail.
-TEST_F(StaticDataSourceTest, findRRsetVersionClassMismatch) {
-    EXPECT_EQ(DataSrc::ERROR,
-              data_source.findRRset(version_name, RRClass::IN(), rrtype,
-                                    result_sets, find_flags, &version_name));
-}
-
-TEST_F(StaticDataSourceTest, findRRsetOutOfZone) {
-    // If the qname doesn't match any of the static zones, the result should
-    // be "no such zone", regardless of whether the zone is explicitly
-    // specified.  Other "expected" result parameters will be ignored.
-    checkFind(data_source, nomatch_name, NULL, rrclass, rrclass,
-              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
-    checkFind(data_source, nomatch_name, &version_name, rrclass, rrclass,
-              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
-    checkFind(data_source, nomatch_name, &authors_name, rrclass, rrclass,
-              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
-}
-
-// If a zone name is given but doesn't match any of the static zones,
-// the result should be "no such zone"
-TEST_F(StaticDataSourceTest, findRRsetZoneMismatch) {
-    const Name& short_zonename(Name("bind"));
-    checkFind(data_source, version_name, &short_zonename, rrclass, rrclass,
-              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
-    checkFind(data_source, authors_name, &short_zonename, rrclass, rrclass,
-              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
-}
-
-// Zone matches, but name doesn't exist in the zone
-TEST_F(StaticDataSourceTest, findRRsetNoName) {
-    checkFind(data_source, Name("foo").concatenate(version_name), NULL, rrclass,
-              rrclass, rrtype, rrttl, DataSrc::NAME_NOT_FOUND, authors_ns_data);
-    checkFind(data_source, Name("foo").concatenate(version_name), &version_name,
-              rrclass, rrclass, rrtype, rrttl, DataSrc::NAME_NOT_FOUND,
-              authors_ns_data);
-    checkFind(data_source, Name("foo").concatenate(authors_name), NULL, rrclass,
-              rrclass, rrtype, rrttl, DataSrc::NAME_NOT_FOUND, authors_ns_data);
-    checkFind(data_source, Name("foo").concatenate(authors_name), &authors_name,
-              rrclass, rrclass, rrtype, rrttl, DataSrc::NAME_NOT_FOUND,
-              authors_ns_data);
-}
-
-// Zone matches and qname exists, but type doesn't exist for the name.
-TEST_F(StaticDataSourceTest, findRRsetNoType) {
-    const RRType& nomatch_type = RRType::A();
-
-    checkFind(data_source, version_name, NULL, rrclass,
-              rrclass, nomatch_type, rrttl, DataSrc::TYPE_NOT_FOUND,
-              authors_ns_data);
-    checkFind(data_source, version_name, &version_name, rrclass,
-              rrclass, nomatch_type, rrttl, DataSrc::TYPE_NOT_FOUND,
-              authors_ns_data);
-    checkFind(data_source, authors_name, NULL, rrclass,
-              rrclass, nomatch_type, rrttl, DataSrc::TYPE_NOT_FOUND,
-              authors_ns_data);
-    checkFind(data_source, authors_name, &authors_name, rrclass,
-              rrclass, nomatch_type, rrttl, DataSrc::TYPE_NOT_FOUND,
-              authors_ns_data);
-}
-
-// Simple tests for "unsupported" tests.
-TEST_F(StaticDataSourceTest, notImplemented) {
-    Name target_name(version_name);
-    EXPECT_EQ(DataSrc::NOT_IMPLEMENTED,
-              data_source.findPreviousName(version_name, target_name,
-                                           &version_name));
-
-    string target_hash;
-    EXPECT_EQ(DataSrc::NOT_IMPLEMENTED,
-              data_source.findCoveringNSEC3(version_name, target_hash,
-                                            result_sets));
-}
-
-}

+ 0 - 657
src/lib/datasrc/tests/test_datasrc.cc

@@ -1,657 +0,0 @@
-// Copyright (C) 2010  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 <algorithm>
-
-#include <dns/tests/unittest_util.h>
-#include <datasrc/tests/test_datasrc.h>
-
-#include <datasrc/data_source.h>
-
-#include <util/buffer.h>
-#include <dns/messagerenderer.h>
-#include <dns/name.h>
-#include <dns/rdata.h>
-#include <dns/rdataclass.h>
-#include <dns/rrclass.h>
-#include <dns/rrset.h>
-#include <dns/rrsetlist.h>
-#include <dns/rrtype.h>
-#include <dns/rrttl.h>
-
-#include <iostream>
-
-using isc::UnitTestUtil;
-using namespace std;
-using namespace isc::dns;
-using namespace isc::dns::rdata;
-
-namespace isc {
-namespace datasrc {
-
-namespace {
-
-// This is a mock data source for testing.  It can contain multiple zones.
-// The content of each zone should be configured in the form of RRData{}.
-// Each RRData element is a tuple of char strings, representing
-// "name, RRtype, RDATA".  For simplicity we use the same single TTL for
-// RRs (TEST_TTL) defined below.
-// Multiple RRs of the same pair of (name, RRtype) can be defined, but
-// they must not be interleaved with other types of pair.  For example,
-// This is okay:
-// {"example.com", "AAAA", "2001:db8::1"},
-// {"example.com", "AAAA", "2001:db8::2"},
-// ...
-// but this is invalid:
-// {"example.com", "AAAA", "2001:db8::1"},
-// {"example.com", "A", "192.0.2.1"},
-// {"example.com", "AAAA", "2001:db8::2"},
-// ...
-// If an RRset is associated with an RRSIG, the RRSIG must immediately follow
-// the RRset to be signed.  Multiple RRSIGs can follow the RRset.  RRSIG
-// records will always be attached to the most recent non-RRSIG RRset;
-// consequently, the first RR listed must not be an RRSIG record.
-//
-// Names are sorted internally, and don't have to be sorted in the data.
-//
-// A zone is defined in the form of ZoneData{}, which contains:
-// zone name (character string)
-// RRclass (character string)
-// A pointer to in-zone RRs in the form of RRData{}
-// A pointer to glue RRs in the form of RRData{}
-// Glues can be omitted, in which case a convenient constant "empty_records"
-// can be specified.
-
-// For simplicity we use the same single TTL for all test RRs.
-const uint32_t TEST_TTL = 3600;
-
-struct RRData {
-    const char* const name;
-    const char* const rrtype;
-    const char* const rdata;
-};
-
-struct ZoneData {
-    const char* const zone_name;
-    const char* const rrclass;
-    const struct RRData* records;
-    const struct RRData* glue_records;
-};
-
-//
-// zone data for example.com
-//
-const struct RRData example_com_records[] = {
-    // example.com
-    {"example.com", "NS", "dns01.example.com"},
-    {"example.com", "NS", "dns02.example.com"},
-    {"example.com", "NS", "dns03.example.com"},
-    {"example.com", "RRSIG", "NS 5 2 3600 20100322084538 20100220084538 33495 example.com. ClcrfjkQZUY5L6ZlCkU3cJHzcrEGrofKSVeeoeZ+w6yeEowFNVXs2YBo3tom53DiCrdD9rs3feVSLGW5rjsz/O6lDuomgQG+EVSnWa7GTIPBXj1BmDXXp3XxeldYmhf4UzaN5BA+RUA5E8NChNKuNNof76j2S9tilfN/kvpy4fw="},
-    {"example.com", "SOA", "master.example.com. admin.example.com. 1234 3600 1800 2419200 7200"},
-    {"example.com", "RRSIG", "SOA 5 2 3600 20100322084538 20100220084538 33495 example.com.  KUun66Qaw36osk2BJS6U1fAy3PPDkNo2QK4meGNbDBY8q8b+f2o+IXJ14YCvssGl1ORW0CcLnDRxssnk8V/Svmj5iFhO+8HC2hnVBdi2zewvdVtwRb+lWwKN7pkXXwuy6g1t9WCd/j5FCc/wgxqtZUTPb6XgZcnHrORDMOTqLs4="},
-    {"example.com", "NSEC", "cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY"},
-    {"example.com", "RRSIG", "NSEC 5 2 7200 20100322084538 20100220084538 33495 example.com. KxuVaPPKNPJzr/q+cJPiNlkHVTQK0LVsgTbSqruXQc25lAd0wn5oKUtxL1bEAchHkfA8eLzcYCj2ZqqAv9OJubw53mfskTad7UHs4Uj2RTrIsNGMCiZGgOpvNb9JcWpQtoyXVT1uNse+Qsbeir0eyeYIufUynFU041jtNrlJMio="},
-    {"example.com", "DNSKEY", "257 3 5 AwEAAe5WFbxdCPq2jZrZhlMj7oJdff3W7syJtbvzg62tRx0gkoCDoBI9DPjlOQG0UAbj+xUV4HQZJStJaZ+fHU5AwVNT+bBZdtV+NujSikhdTHb4FYLg2b3Cx9NyJvAVukHp/91HnWuG4T36CzAFrfPwsHIrBz9BsaIQ21VRkcmj7DswfI/iDGd8j6bqiODyNZYQ+ZrLmF0KIJ2yPN3iO6Zq23TaOrVTjB7d1a/h31ODfiHAxFHrkY3t3D5JR9Nsl/7fdRmSznwtcSDgLXBoFEYmw6p86AcvRyoYNcL1SXjaKVLG5jyU3UR+LcGZT5t/0xGfoIK/aKwENrsjcKZZj660b1M="},
-    {"example.com", "DNSKEY", "256 3 5 AwEAAcOUBllYc1hf7ND9uDy+Yz1BF3sI0m4qNGV7WcTD0WEiuV7IjXgHE36fCmS9QsUxSSOVo1I/FMxI2PJVqTYHkXFBS7AzLGsQYMU7UjBZSotBJ6Imt5pXMu+lEDNy8TOUzG3xm7g0qcbWYF6qCEfvZoBtAqi5Rk7Mlrqs8agxYyMx"},
-    {"example.com", "RRSIG", "DNSKEY 5 2 3600 20100416210049 20100317210049 4456 example.com. 37FC0rcwOZVarTMjft0BMbvv8hbJU7OHNsvO7R1q6OgsLTj7QGMX3sC42JGbwUrYI/OwnZblNcv1eim0g0jX5k+sVr2OJsEubngRjVqLo54qV8rBC14tLk9PGKxxjQG0IBJU866uHxzXYBO2a1r2g93/qyTtrT7iPLu/2Ce1WRKMBPK0yf4nW2usFU/PXesXFWpZ7HLGZL73/NWv8wcezBDuU0B2PlHLjSu7k6poq6JWDC02o5SYnEBwsJ5Chi+3/NZmzKTiNP7g0H4t6QhunkEXxL3z0617mwwQt00ypXsNunnPy4Ub5Kllk1SKJl8ZkEDKkJtSvuXJhcAZsLyMQw=="},
-    {"example.com", "RRSIG", "DNSKEY 5 2 3600 20100416210049 20100317210049 33495 example.com. h3OM5r3roBsgnEQk9fcjTg5L7p3yDptDpVzDN/lgjqpaWxtlz5LsulBH3YzwYyXzT7pG7L0/qT6dcuRECc/rniECviWvmJMJZzEAMry0Of/pk/8ekuGTxABpqwAoCwM5as30sc0cfMJTS7umpJVDA4lRB2zoKGefWnJ3+pREDiY="},
-
-    // dns01.example.com
-    {"dns01.example.com", "A", "192.0.2.1"},
-    {"dns01.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. NIawlZLk8WZAjNux7oQM2mslfW52OZFFkWt++7FHu2SU98XqEeKfCMnpgtWe5T8Nr9cS8df901iEOJoWQzGTEaHYUBtEhsSjBVn7mKp3fz6473a2xxy75SUKZ0rxjNXSZ8Q5rnFmkX0HTH2Sg51mtjH6aC2pfheQnA2t193BnSg="},
-    {"dns01.example.com", "NSEC", "dns02.example.com. A RRSIG NSEC"},
-    {"dns01.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. EkyeshmMNP9xiAz6mDFDIwksTdmkF9zsFzLuVKAgK6eUk7St6tp5PSvjA8nWol0vdvvz4LK85a4ffTFEiNRyvWeYP2vOhEkyDcrwuCd8Vc3jh/8Sm1Js+nX7hJStrZGFvp2TWPpt9nKH5p3MxXvTb/YVurnue0xSeFAE17O3+I0="},
-
-    // dns02.example.com
-    {"dns02.example.com", "A", "192.0.2.2"},
-    {"dns02.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. XJtVMbUIRE0mk6Hn/Nx6k36jaxaBDPK2/IYB6vCQjJETz6gW4T6q/H/eY9/Lsw5iYPFhoBRDxT4XFj575t98kELXnJe1WhuMbRPlOhyOjxkLECaUne/sbFPOtbGFx9ohuojI0RgxxZiCFaO8wJuv6nfPuzmlLajWS6z9NZeOMIk="},
-    {"dns02.example.com", "NSEC", "dns03.example.com. A RRSIG NSEC"},
-    {"dns02.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. imBNTMB3sPU4kblcaAH6V7lCVt5xgtAybi3DA/SbLEulLaV2NE6vcoEn/AieaM4mOJicQnUDj/H+1hSEhzxU2tRM8zfVlvztxQWn6eh7ZR4mKfNDSvRUGU9ykhpwMyC7wjOt1j5bcSA/OTnLRAilslnJyOM4bSaxVEFo8YPjncY="},
-
-    // dns03.example.com
-    {"dns03.example.com", "A", "192.0.2.3"},
-    {"dns03.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. Ubrcm1H+F6m8khle7P9zU8eO+Jtuj+1Vx1MM5KAkmZPJwQe9uTcoCpQa6DXOGG9kajDTnNN1Be1gkZuJDTZJG4SmJLXLbNY3RDnxpGmWta3qs/VgDq78/YM8ropt1/s7YKyrCfGE2ff+FUB0mLObiG01ZV2gu5HJzgE7SEWLEiI="},
-    {"dns03.example.com", "NSEC", "foo.example.com. A RRSIG NSEC"},
-    {"dns03.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com.  nn829Xw5CJFnPHwI9WHeT5epQv+odtCkHnjlPFGoPTLOyiks+041UmMqtq3uiSp4d2meMSe9UuDvoROT0L6NTtQQvVqiDhTn0irTFw1uw7fO8ZTG7eyu6Ypfz0+HvfbNvd4kMoD2OTgADRXPVsCTwK+PBOIIG9YTEQfl8pCqW5g="},
-
-    // www.example.com
-    {"www.example.com", "A", "192.0.2.1"},
-    {"www.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. qyFyyV/mE8x4pdhudr5iycwhDsva31MzwO1kBR+bDKvzJg8mN8KxlPZrOlNNUhd3YRXQVwieMyxOTWRPXoxrNEDkNwimXkfe3rrHY7ibV9eNS4OIBUjb44VjCNr9CmQSzfuQ2yxO2r+YIuPYHRCjieD4xh6t9ay4IaCN/tDAJ+Q="},
-    {"www.example.com", "NSEC", "example.com. A RRSIG NSEC"},
-    {"www.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. ZLZlSVBa2oe4U+7SZASnypP2VkI5gg1/1cVGqYUvfYNIUkcVMWDgn7DZCfpmo+2vdlV/4VhAc+sjDd+X+e57XGnW8+lqZHvG6NMMhmSGmeATD3D+8lEJJGo0dxoN4rHJQyp/eT2S4nChz+D/ze+YRagYxGF7pXm9zcrw3kKZGTs="},
-
-    // *.wild.example.com
-    {"*.wild.example.com", "A", "192.0.2.2"},
-    {"*.wild.example.com", "RRSIG", "A 5 3 3600 20100322084538 20100220084538 33495 example.com. FdO+UWONgtLKFxUzzygGunw67F9y8SzsP7yOLEYVJclRR8X3Ii62L0gtQHq2y0TcKsXttRsD6XY+tM5P/pgXlTNi7Bk4Fgb0PIDPjOsfT4DrS80kWn0YbinM/4/FA1j5ru5sTTboOY5UGhvDnoA9ogNuQQYb2/3wkoH0PrA2Q/0="},
-    {"*.wild.example.com", "NSEC", "*.wild2.example.com. A RRSIG NSEC"},
-    {"*.wild.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. OoGYslRj4xjZnBuzgOqsrvkDAHWycmQzbUxCRmgWnCbXiobJK7/ynONH3jm8G3vGlU0lwpHkhNs6cUK+6Nu8W49X3MT0Xksl/brroLcXYLi3vfxnYUNMMpXdeFl6WNNfoJRo90F/f/TWXAClRrDS29qiG3G1PEJZikIxZsZ0tyM="},
-
-    // *.wild2.example.com
-    {"*.wild2.example.com", "CNAME", "www.example.com"},
-    {"*.wild2.example.com", "RRSIG", "CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="},
-    {"*.wild2.example.com", "NSEC", "*.wild3.example.com. CNAME RRSIG NSEC"},
-    {"*.wild2.example.com", "RRSIG", "NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="},
-
-    // *.wild3.example.com -- a wildcard record with a lame CNAME
-    {"*.wild3.example.com", "CNAME", "spork.example.com"},
-    {"*.wild3.example.com", "RRSIG", "CNAME 5 3 3600 20100410212307 20100311212307 33495 example.com. pGHtGdRBi4GKFSKszi6SsKvuBLDX8dFhZubU0tMojQ9SJuiFNF+WtxvdAYuUaoWP/9VLUaYmiw5u7JnzmR84DiXZPEs6DtD+UJdOZhaS7V7RTpE+tMOfVQBLpUnRWYtlTTmiBpFquzf3DdIxgUFhEPEuJJyp3LFRxJObCaq9 nvI="},
-    {"*.wild3.example.com", "NSEC", "www.example.com. CNAME RRSIG NSEC"},
-    {"*.wild3.example.com", "RRSIG", "NSEC 5 3 7200 20100410212307 20100311212307 33495 example.com. EuSzh6or8mbvwru2H7fyYeMpW6J8YZ528rabU38V/lMN0TdamghIuCneAvSNaZgwk2MSN1bWpZqB2kAipaM/ZI9/piLlTvVjjOQ8pjk0auwCEqT7Z7Qng3E92O9yVzO+WHT9QZn/fR6t60392In4IvcBGjZyjzQk8njIwbui xGA="},
-
-    // foo.example.com
-    {"foo.example.com", "CNAME", "cnametest.example.net"},
-    {"foo.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. DSqkLnsh0gCeCPVW/Q8viy9GNP+KHmFGfWqyVG1S6koBtGN/VQQ16M4PHZ9Zssmf/JcDVJNIhAChHPE2WJiaPCNGTprsaUshf1Q2vMPVnkrJKgDY8SVRYMptmT8eaT0gGri4KhqRoFpMT5OYfesybwDgfhFSQQAh6ps3bIUsy4o="},
-    {"foo.example.com", "NSEC", "mail.example.com. CNAME RRSIG NSEC"},
-    {"foo.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. RTQwlSqui6StUYye1KCSOEr1d3irndWFqHBpwP7g7n+w8EDXJ8I7lYgwzHvlQt6BLAxe5fUDi7ct8M5hXvsm7FoWPZ5wXH+2/eJUCYxIw4vezKMkMwBP6M/YkJ2CMqY8DppYf60QaLDONQAr7AcK/naSyioeI5h6eaoVitUDMso="},
-
-    // cname-int.example.com
-    {"cname-int.example.com", "CNAME", "www.example.com."},
-    {"cname-int.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. U1wjt0XY9xjTwvUmWSUcfLGMhCjfX2ylWfHrycy50x2oxcK9z94E1ejen9wDTIEBSGYgi6wpZ8RK0+02N1DWTGpDqNXd7aFRfDrWQJ/q/XJHDx0vlcmhkWhrT82LBfKxkrptOzchuSo/c0mpK+mpiIMc1VOwY+yuQ2ALfcD6EHw="},
-    {"cname-int.example.com", "NSEC", "dname.example.com. CNAME RRSIG NSEC"},
-    {"cname-int.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. rbV+gaxfrsoha59NOLF4EFyWQ+GuFCVK/8D77x1atan3HNlXBlZ1smgudKTaJ3CtlobIDt0MEdPxY1yn2Tskw/5mlP1PWf8oaP3BwGSQdn4gLI8+sMpNOPFEdXpxqxngm2F6/7fqniL1QuSAQBEdO+5UiCAgnncPmAsSJg3u1zg="},
-
-    // cname-ext.example.com
-    {"cname-ext.example.com", "CNAME", "www.sql1.example.com"},
-    {"cname-ext.example.com", "RRSIG", "CNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. bGPIuZilyygvTThK4BrdECuaBcnZUgW/0d09iN2CrNjckchQl3dtbnMNirFsVs9hShDSldRNlQpiAVMpnPgXHhReNum7jmX6yqIH6s8GKIo91zr3VL/ramlezie5w4MilDHrxXLK2pb8IHmP+ZHivQ2EtdYQZgETWBWxr5FDfwk="},
-    {"cname-ext.example.com", "NSEC", "cname-int.example.com. CNAME RRSIG NSEC"},
-    {"cname-ext.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. inWsFwSDWG7TakjwbUTzTRpXz0WifelA5Kn3ABk6BVirIPmd+yQoNj2QZBDFAQwhnLPlNws2Oo4vgMsBMyx1Fv5eHgMUuCN3DUDaLlzlPtUb42CjOUa+jZBeTV/Hd7WZrirluASE1QFDprLdSSqoPPfAKvN3pORtW7y580dMOIM="},
-
-    // dname.example.com
-    {"dname.example.com", "DNAME", "sql1.example.com."},
-    {"dname.example.com", "RRSIG", "DNAME 5 3 3600 20100322084538 20100220084538 33495 example.com. ae8U47oaiwWdurkSyzcsCAF6DxBqjukizwF7K7U6lQVMtfoUE14oiAqfj1fjH8YLDOO/Hd1twrd/u0vgjnI1Gg32YTi7cYOzwE912SV1u2B/y0awaQKWPBwOW0aI7vxelt1vMUF81xosiQD04gOIdDBTqbHKcDxum87iWbhk4Ug="},
-    {"dname.example.com", "NSEC", "dns01.example.com. DNAME RRSIG NSEC"},
-    {"dname.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. c21Fff2D8vBrLzohBnUeflkaRdUAnUxAFGp+UQ0miACDCMOFBlCS9v9g/2+orOnKfd3l4vyz55C310t8JXgXb119ofaZWj2zkdUe+X8Bax+sMS0Y5K/sUhSNvbJbozr9UYPdvjSVBiWgh3s9fsb+etKq9uFukAzGU/FuGYpO0r0="},
-
-    // subzone.example.com
-    {"subzone.example.com", "NS", "ns1.subzone.example.com"},
-    {"subzone.example.com", "NS", "ns2.subzone.example.com"},
-    {"subzone.example.com", "NSEC", "*.wild.example.com. NS DS RRSIG NSEC"},
-    {"subzone.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. Oe2kgIhsLtPJ4+lDZDxznV8/vEVoXKOBFN9lwWyebaKa19BaSXlQ+YVejmulmKDDjEucMvEfuItfn6w7bnU+DzOLk5D1lJCjwDlKz8u3xOAx16TiuQn4bgQAOiFtBQygmGGqO3BVpX+jxsmw7eH3emofy8uUqr/C4aopnwuf28g="},
-    {"subzone.example.com", "DS", "33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"},
-    {"subzone.example.com", "DS", "33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"},
-    {"subzone.example.com", "RRSIG", "DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="},
-
-    // subset of child zone: sql1
-    {"sql1.example.com", "NS", "dns01.example.com"},
-    {"sql1.example.com", "NS", "dns02.example.com"},
-    {"sql1.example.com", "NS", "dns03.example.com"},
-
-    {"sql1.example.com", "DS", "33313 5 1 0FDD7A2C11AA7F55D50FBF9B7EDDA2322C541A8D"},
-    {"sql1.example.com", "DS", "33313 5 2 00B99B7006F496D135B01AB17EDB469B4BE9E1973884DEA757BC4E3015A8C3AB"},
-    {"sql1.example.com", "RRSIG", "DS 5 3 3600 20100322084538 20100220084538 33495 example.com. dIqZKvpkJN1l92SOiWgJh3KbjErIN+EfojMsm4pEdV5xQdZwj6DNNEu6Kw4rRwdvrZIu0TyqPr3jSJb7o6R7vZgZzmLfVV/ojQah7rwuYHCFcfyZ4JyK2311fMhRR1QAvMsdcjdyA1XC140Cm6AnL3cH5rh/KUks/0ec3Ca7GNQ="},
-    {"sql1.example.com", "NSEC", "subzone.example.com. NS DS RRSIG NSEC"},
-    {"sql1.example.com", "RRSIG", "NSEC 5 3 7200 20100322084538 20100220084538 33495 example.com. k9FRdFyk/cPdkmmaoZbGZPpzIzfbFWQ3QCHd2qhJa0xAXaEOT/GBL6aFqx9SlunDu2wgES+To5fWPZGi4NzWpp6c5t27rnATN/oCEQ/UYIJKmWbqrXdst0Ps5boznk7suK2Y+km31KxaIf3fDd/T3kZCVsR0aWKRRRatPb7GfLw="},
-
-    {NULL, NULL, NULL}
-};
-
-const struct RRData example_com_glue_records[] = {
-    {"ns1.subzone.example.com", "A", "192.0.2.1"},
-    {"ns2.subzone.example.com", "A", "192.0.2.2"},
-    {NULL, NULL, NULL}
-};
-
-//
-// zone data for sql1.example.com
-//
-const struct RRData sql1_example_com_records[] = {
-    {"sql1.example.com", "NS", "dns01.example.com"},
-    {"sql1.example.com", "NS", "dns02.example.com"},
-    {"sql1.example.com", "NS", "dns03.example.com"},
-    {"sql1.example.com", "RRSIG", "NS 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. 0CL8noy0NSgoWwuKd+Dc6vyIIw2BrAEBx0IJzcSB6GlB25x/zjEd6AJG0be13HN6jOaTX8iWTuCVrEYuXg76V+M4EvTZHjEScj0az74TrDv4Vdo459paGKCX9B8NLJW1mW4fzZrrXQ8jmBEZeS91Q5rJrO+UKJEuUz3LYdTPvao="},
-    {"sql1.example.com", "SOA", "master.example.com. admin.example.com. 678 3600 1800 2419200 7200"},
-    {"sql1.example.com", "RRSIG", "SOA 5 3 3600 20100322084536 20100220084536 12447 sql1.example.com. oakulfyljL/RAKgCKXEZ3KsG8BJj5WG4JK4moWFB6c9OKem6jIk8hKP2XlUVXFuOYJlRdIM4KicmR2GAK+5jJp6z5ShssstYTXo3QosVm6oCKumuFeLFHzcjfqP1D+F9NsvHldJIBnS/4ebPkmR5OENyCZXQF5HmN2awIj4CLjE="},
-    {"sql1.example.com", "NSEC", "www.sql1.example.com. NS SOA RRSIG NSEC DNSKEY"},
-    {"sql1.example.com", "RRSIG", "NSEC 5 3 7200 20100322084536 20100220084536 12447 sql1.example.com. v71CgdTYccCiTqfRcn6HsvISQa8ruvUfCKtpwym0RW/G27xlZn8otj2IMtWwkLxti8Rqqu+PTViLaOIbeVfHBcqzAd7U59cAOYoq3ODZx6auiE3C23HAKqUavKcP7Esaajm1cbcWy6Kyie4CAZc8M7EeKxgkXMKJGqBQzF+/FOo="},
-
-    // www.sql1.example.com
-    {"www.sql1.example.com", "A", "192.0.2.2"},
-    {"www.sql1.example.com", "RRSIG", "A 5 4 3600 20100322084536 20100220084536 12447 sql1.example.com. DNdVKxB3oBsB14NPoV9WG14Y/g4zMcIXLYnFjj9vRZRZJpAvbTEipiXlayuhOxnqU827OipETQyeULZmLsqIQ1wK4Fgf+9b5aJ8D85/o4wBka00X4hZ3MwDPRb4mjuogwBTBg5NRpNSzUfbkPGiav08BFwgg+Efm9veSB05arS0="},
-    {"www.sql1.example.com", "NSEC", "sql1.example.com. A RRSIG NSEC"},
-    {"www.sql1.example.com", "RRSIG", "NSEC 5 4 7200 20100322084536 20100220084536 12447 sql1.example.com. cJMJhDx/ND7/9j3zhyXe+6eaSsU7ByYpXhJzbe+OhjFgH0VasQXq7o1QB3I293UZ+yhkjgXap+9QtPlraaNaYyTyOMQ42OoxSefJpYz9CME/FI2tsUfyrCnLFxYRNet7sMS0q+hLqxRayuEHDFDp72hHPGLJQ8a7jq4SrIonT50="},
-
-    {NULL, NULL, NULL}
-};
-
-//
-// zone data for loop.example
-//
-const struct RRData loop_example_records[] = {
-    {"loop.example", "SOA", "master.loop.example admin.loop.example. "
-     "1234 3600 1800 2419200 7200"},
-    {"loop.example", "NS", "ns.loop.example"},
-    {"one.loop.example", "CNAME", "two.loop.example"},
-    {"two.loop.example", "CNAME", "one.loop.example"},
-    {NULL, NULL, NULL}
-};
-
-//
-// zone data for nons.example
-//
-const struct RRData nons_example_records[] = {
-    {"nons.example", "SOA", "master.nons.example admin.nons.example. "
-     "1234 3600 1800 2419200 7200"},
-    {"www.nons.example", "A", "192.0.2.1"},
-    {"ns.nons.example", "A", "192.0.2.2"},
-
-    // One of the NS names is intentionally non existent in the zone it belongs
-    // to.  This delegation is used to see if we still return the NS and the
-    // existent glue.
-    // (These are not relevant to test the case for the "no NS" case.  We use
-    // this zone to minimize the number of test zones)
-    {"incompletechild.nons.example", "NS", "ns.incompletechild.nons.example"},
-    {"incompletechild.nons.example", "NS", "nx.nosoa.example"},
-
-    {NULL, NULL, NULL}
-};
-
-const struct RRData nons_example_glue_records[] = {
-    {"ns.incompletechild.nons.example", "A", "192.0.2.1"},
-    {NULL, NULL, NULL}
-};
-
-//
-// zone data for nons-dname.example
-//
-const struct RRData nonsdname_example_records[] = {
-    {"nons-dname.example", "SOA", "master.nons-dname.example "
-     "admin.nons-dname.example. 1234 3600 1800 2419200 7200"},
-    {"nons-dname.example", "DNAME", "example.org"},
-    {"www.nons-dname.example", "A", "192.0.2.1"},
-    {"ns.nons-dname.example", "A", "192.0.2.2"},
-    {NULL, NULL, NULL}
-};
-
-//
-// zone data for nosoa.example
-//
-const struct RRData nosoa_example_records[] = {
-    {"nosoa.example", "NS", "ns.nosoa.example"},
-    {"www.nosoa.example", "A", "192.0.2.1"},
-    {"ns.nosoa.example", "A", "192.0.2.2"},
-    {NULL, NULL, NULL}
-};
-
-//
-// zone data for apexcname.example.
-//
-const struct RRData apexcname_example_records[] = {
-    {"apexcname.example", "CNAME", "canonical.apexcname.example"},
-    {"canonical.apexcname.example", "SOA",
-     "master.apexcname.example "
-     "admin.apexcname.example. 1234 3600 1800 2419200 7200"},
-    {NULL, NULL, NULL}
-};
-
-
-//
-// empty data set, for convenience.
-//
-const struct RRData empty_records[] = {
-    {NULL, NULL, NULL}
-};
-
-//
-// test zones
-//
-const struct ZoneData zone_data[] = {
-    { "example.com", "IN", example_com_records, example_com_glue_records },
-    { "sql1.example.com", "IN", sql1_example_com_records, empty_records },
-    { "loop.example", "IN", loop_example_records, empty_records },
-    { "nons.example", "IN", nons_example_records, nons_example_glue_records },
-    { "nons-dname.example", "IN", nonsdname_example_records, empty_records },
-    { "nosoa.example", "IN", nosoa_example_records, empty_records },
-    { "apexcname.example", "IN", nosoa_example_records, empty_records }
-};
-const size_t NUM_ZONES = sizeof(zone_data) / sizeof(zone_data[0]);
-
-struct Zone {
-    Zone(const char* const name, const char* const class_txt) :
-        zone_name(Name(name)), rrclass(class_txt)
-    {}
-    Name zone_name;
-    RRClass rrclass;
-    vector<Name> names;
-    vector<RRsetPtr> rrsets;
-};
-vector<Zone> zones;
-}
-
-DataSrc::Result
-TestDataSrc::init(isc::data::ConstElementPtr) {
-    return (init());
-}
-
-void
-buildZone(Zone& zone, const RRData* records, const bool is_glue) {
-    RRsetPtr prev_rrset;
-    for (int i = 0; records[i].name != NULL; ++i) {
-        Name name(records[i].name);
-        RRType rrtype(records[i].rrtype);
-        RRsetPtr rrset;
-        bool new_name = false;
-
-        if (!prev_rrset || prev_rrset->getName() != name) {
-            if (!is_glue) {
-                zone.names.push_back(name);
-            }
-            new_name = true;
-        }
-
-        if (new_name || prev_rrset->getType() != rrtype) {
-            rrset = RRsetPtr(new RRset(name, zone.rrclass, rrtype,
-                                       RRTTL(TEST_TTL)));
-            if (rrtype != RRType::RRSIG()) {
-                zone.rrsets.push_back(rrset);
-            }
-        } else {
-            rrset = prev_rrset;
-        }
-        rrset->addRdata(createRdata(rrtype, zone.rrclass, records[i].rdata));
-        if (rrtype == RRType::RRSIG()) {
-            prev_rrset->addRRsig(rrset);
-        } else {
-            prev_rrset = rrset;
-        }
-    }
-}
-
-DataSrc::Result
-TestDataSrc::init() {
-    if (initialized) {
-        return (SUCCESS);
-    }
-
-    if (zones.empty()) {
-        for (int i = 0; i < NUM_ZONES; ++i) {
-            Zone zone(zone_data[i].zone_name, zone_data[i].rrclass);
-            buildZone(zone, zone_data[i].records, false);
-            buildZone(zone, zone_data[i].glue_records, true);
-            sort(zone.names.begin(), zone.names.end());
-            zones.push_back(zone);
-        }
-    }
-
-    initialized = true;
-    return (SUCCESS);
-}
-
-void
-TestDataSrc::findClosestEnclosure(DataSrcMatch& match) const {
-    const Name& qname = match.getName();
-
-    if (match.getClass() != getClass() && match.getClass() != RRClass::ANY()) {
-        return;
-    }
-
-    vector<Zone>::const_iterator it;
-    vector<Zone>::const_iterator best_it = zones.end();
-    unsigned int best_common_labels = 0;
-    for (it = zones.begin(); it != zones.end(); ++it) {
-        const NameComparisonResult cmp = qname.compare(it->zone_name);
-        const NameComparisonResult::NameRelation reln = cmp.getRelation();
-
-        if ((reln == NameComparisonResult::EQUAL ||
-             reln == NameComparisonResult::SUBDOMAIN) &&
-            cmp.getCommonLabels() > best_common_labels) {
-            best_it = it;
-            best_common_labels = cmp.getCommonLabels();
-        }
-    }
-
-    if (best_it != zones.end()) {
-        match.update(*this, best_it->zone_name);
-    }
-}
-
-struct ZoneNameMatch : public unary_function<Name, bool> {
-    ZoneNameMatch(const Name& name) : name_(name) {}
-    bool operator()(const Zone& zone) const {
-        return (zone.zone_name == name_);
-    }
-    const Name& name_;
-};
-
-// XXX: the main data source module can override the returned RRset.
-// That's bad and should be fixed (Trac #254), but for now we work around it.
-RRsetPtr
-copyRRset(RRsetPtr const source) {
-    RRsetPtr rrset = RRsetPtr(new RRset(source->getName(), source->getClass(),
-                                        source->getType(), source->getTTL()));
-    RdataIteratorPtr it = source->getRdataIterator();
-    for (; !it->isLast(); it->next()) {
-        rrset->addRdata(it->getCurrent());
-    }
-    if (source->getRRsig()) {
-        rrset->addRRsig(copyRRset(source->getRRsig()));
-    }
-
-    return (rrset);
-}
-
-class TestDataSrc::RRsetMatch {
-public:
-    struct MatchResult {
-        MatchResult(const bool name_found, const bool has_delegation) :
-            name_found_(name_found), has_delegation_(has_delegation)
-        {}
-        bool name_found_;
-        bool has_delegation_;
-    };
-    RRsetMatch(const Name& name, const RRType& rrtype, const Mode mode,
-               RRsetList& target, uint32_t& flags) :
-        name_(name), rrtype_(rrtype), mode_(mode), target_(target),
-        flags_(flags), name_found_(false), has_delegation_(false)
-    {}
-    void operator()(const RRsetPtr& rrset) {
-        if (rrset->getName() != name_) {
-            return;
-        }
-        name_found_ = true;
-
-        if (rrset->getType() == RRType::NS() ||
-            rrset->getType() == RRType::DNAME()) {
-            has_delegation_ = true;
-        }
-
-        if (mode_ == DELEGATION) {
-            if (rrset->getType() == RRType::NS() ||
-                rrset->getType() == RRType::DNAME() ||
-                rrset->getType() == RRType::DS()) {
-                target_.addRRset(copyRRset(rrset));
-            }
-        } else if (mode_ == ADDRESS) {
-            if (rrset->getType() == RRType::A() ||
-                rrset->getType() == RRType::AAAA()) {
-                target_.addRRset(copyRRset(rrset));
-            }
-        } else {
-            if (rrtype_ == RRType::NSEC() &&
-                rrset->getType() == RRType::CNAME()) {
-                // XXX: ignore CNAME if the qtype is NSEC.
-                // tricky, but necessary.
-                return;
-            }
-            if (rrtype_ == RRType::ANY() || rrtype_ == rrset->getType() ||
-                rrset->getType() == RRType::CNAME() ||
-                rrset->getType() == RRType::DNAME()) {
-                target_.addRRset(copyRRset(rrset));
-                if (rrset->getType() == RRType::CNAME()) {
-                    flags_ |= CNAME_FOUND;
-                }
-                if (rrset->getType() == RRType::DNAME()) {
-                    flags_ |= REFERRAL;
-                }
-            }
-        }
-        
-    }
-    MatchResult getResult() { return (MatchResult(name_found_,
-                                                  has_delegation_)); }
-    const Name& name_;
-    const RRType& rrtype_;
-    const Mode mode_;
-    RRsetList& target_;
-    uint32_t& flags_;
-    bool name_found_;
-    bool has_delegation_;
-};
-
-void
-TestDataSrc::findRecords(const Name& name, const RRType& rdtype,
-                         RRsetList& target, const Name* zonename,
-                         const Mode mode, uint32_t& flags) const
-{
-    flags = 0;
-
-    assert(zonename != NULL);
-
-    vector<Zone>::const_iterator zone = find_if(zones.begin(), zones.end(),
-                                                ZoneNameMatch(*zonename));
-    if (zone == zones.end()) {
-        return;
-    }
-
-    const RRsetMatch::MatchResult match_result =
-        for_each(zone->rrsets.begin(), zone->rrsets.end(),
-                 RRsetMatch(name, rdtype, mode, target, flags)).getResult();
-    if (match_result.has_delegation_) {
-        flags |= REFERRAL;
-    }
-    if (target.size() == 0) {
-        if (match_result.name_found_) {
-            flags |= TYPE_NOT_FOUND;
-        } else {
-            flags |= NAME_NOT_FOUND;
-        }
-    }
-}
-
-DataSrc::Result
-TestDataSrc::findRRset(const Name& qname,
-                       const RRClass& qclass,
-                       const RRType& qtype,
-                       RRsetList& target,
-                       uint32_t& flags,
-                       const Name* zonename) const
-{
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        return (ERROR);
-    }
-
-    findRecords(qname, qtype, target, zonename, NORMAL, flags);
-    return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findExactRRset(const Name& qname,
-                            const RRClass& qclass,
-                            const RRType& qtype,
-                            RRsetList& target,
-                            uint32_t& flags,
-                            const Name* zonename) const
-{
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        return (ERROR);
-    }
-
-    findRecords(qname, qtype, target, zonename, NORMAL, flags);
-    // Ignore referrals in this case
-    flags &= ~REFERRAL;
-
-    // CNAMEs don't count in this case
-    if ((flags & CNAME_FOUND) != 0) {
-        flags &= ~CNAME_FOUND;
-        flags |= TYPE_NOT_FOUND;
-    }
-
-    return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findAddrs(const Name& qname,
-                       const RRClass& qclass,
-                       RRsetList& target,
-                       uint32_t& flags,
-                       const Name* zonename) const
-{
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        return (ERROR);
-    }
-
-    findRecords(qname, RRType::ANY(), target, zonename, ADDRESS, flags);
-    return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findReferral(const Name& qname,
-                          const RRClass& qclass,
-                          RRsetList& target,
-                          uint32_t& flags,
-                          const Name* zonename) const
-{
-    if (qclass != getClass() && qclass != RRClass::ANY()) {
-        return (ERROR);
-    }
-
-    findRecords(qname, RRType::ANY(), target, zonename, DELEGATION, flags);
-    return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findPreviousName(const Name& qname,
-                              Name& target,
-                              const Name* zonename) const
-{
-    assert(zonename != NULL);
-
-    vector<Zone>::const_iterator zone = find_if(zones.begin(), zones.end(),
-                                                ZoneNameMatch(*zonename));
-    if (zone == zones.end()) {
-        return (ERROR);
-    }
-
-    if (zone->names.empty()) {
-        return (ERROR);
-    }
-
-    // if found, next_name >= qname.
-    vector<Name>::const_iterator next_name =
-        lower_bound(zone->names.begin(), zone->names.end(), qname);
-    if (next_name == zone->names.end()) {
-        // if no such name was found, the previous name is the last name.
-        target = zone->names.back();
-    } else if (*next_name == qname) {
-        target = *next_name;
-    } else if (next_name == zone->names.begin()) {
-        // if qname < first_name, the "previous name" is the last name.
-        target = zone->names.back();
-    } else {
-        // otherwise, qname and next_name share the same previous name.
-        target = *(next_name - 1);
-    }
-    return (SUCCESS);
-}
-
-DataSrc::Result
-TestDataSrc::findCoveringNSEC3(const Name&, string&, RRsetList&) const {
-    return (NOT_IMPLEMENTED);
-}
-
-}
-}

+ 0 - 111
src/lib/datasrc/tests/test_datasrc.h

@@ -1,111 +0,0 @@
-// Copyright (C) 2010  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 __TEST_DATA_SOURCE_H
-#define __TEST_DATA_SOURCE_H
-
-#include <gtest/gtest.h>
-
-#include <datasrc/data_source.h>
-
-namespace isc {
-
-namespace dns {
-class Name;
-class RRClass;
-class RRType;
-class RRsetList;
-}
-
-namespace datasrc {
-class Query;
-
-class TestDataSrc : public DataSrc {
-    ///
-    /// \name Constructors, Assignment Operator and Destructor.
-    ///
-    /// Note: The copy constructor and the assignment operator are intentionally
-    /// defined as private.
-    //@{
-private:
-    TestDataSrc(const TestDataSrc& source);
-    TestDataSrc operator=(const TestDataSrc& source); 
-public:
-    TestDataSrc() : initialized(false) {}
-    ~TestDataSrc() {}
-    //@}
-
-    void findClosestEnclosure(DataSrcMatch& match) const;
-
-    Result findRRset(const isc::dns::Name& qname,
-                     const isc::dns::RRClass& qclass,
-                     const isc::dns::RRType& qtype,
-                     isc::dns::RRsetList& target,
-                     uint32_t& flags,
-                     const isc::dns::Name* zonename) const;
-
-    Result findExactRRset(const isc::dns::Name& qname,
-                          const isc::dns::RRClass& qclass,
-                          const isc::dns::RRType& qtype,
-                          isc::dns::RRsetList& target,
-                          uint32_t& flags,
-                          const isc::dns::Name* zonename) const;
-
-    Result findAddrs(const isc::dns::Name& qname,
-                     const isc::dns::RRClass& qclass,
-                     isc::dns::RRsetList& target,
-                     uint32_t& flags,
-                     const isc::dns::Name* zonename) const;
-
-    Result findReferral(const isc::dns::Name& qname,
-                        const isc::dns::RRClass& qclass,
-                        isc::dns::RRsetList& target,
-                        uint32_t& flags,
-                        const isc::dns::Name* zonename) const;
-
-    Result findPreviousName(const isc::dns::Name& qname,
-                            isc::dns::Name& target,
-                            const isc::dns::Name* zonename) const;
-
-    Result findCoveringNSEC3(const isc::dns::Name& zonename,
-                             std::string& hash,
-                             isc::dns::RRsetList& target) const;
-
-    Result init();
-    Result init(isc::data::ConstElementPtr config);
-    Result close() { return (SUCCESS); }
-
-private:
-    bool initialized;
-    enum Mode {
-        NORMAL,
-        ADDRESS,
-        DELEGATION
-    };
-    class RRsetMatch;
-
-    void findRecords(const isc::dns::Name& name, const isc::dns::RRType& rdtype,
-                     isc::dns::RRsetList& target,
-                     const isc::dns::Name* zonename, const Mode mode,
-                     uint32_t& flags) const;
-};
-
-}
-}
-
-#endif
-
-// Local Variables: 
-// mode: c++
-// End: 

+ 4 - 1
src/lib/datasrc/tests/testdata/contexttest.zone

@@ -1,7 +1,7 @@
 ;; test zone file used for ZoneFinderContext tests.
 ;; RRSIGs are (obviouslly) faked ones for testing.
 
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 67 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 71 3600 300 3600000 3600
 example.org.			      3600 IN NS	ns1.example.org.
 example.org.			      3600 IN NS	ns2.example.org.
 example.org.			      3600 IN MX	1 mx1.example.org.
@@ -71,6 +71,9 @@ a.*.emptywild.example.org.    3600 IN AAAA	2001:db8::2
 ;; expansion
 *.wildmx.example.org. 3600 IN MX 1 mx1.example.org.
 
+;; the owner name of additional for an answer RRset (MX) has DNAME
+dnamemx.example.org. 3600 IN MX 1 dname.example.org.
+
 ;; CNAME
 alias.example.org. 3600 IN CNAME cname.example.org.
 

+ 27 - 12
src/lib/datasrc/tests/zone_finder_context_unittest.cc

@@ -14,12 +14,14 @@
 
 #include <exceptions/exceptions.h>
 
+#include <util/memory_segment_local.h>
+
 #include <dns/masterload.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 
 #include <datasrc/zone.h>
-#include <datasrc/memory_datasrc.h>
+#include <datasrc/memory/memory_client.h>
 #include <datasrc/database.h>
 #include <datasrc/sqlite3_accessor.h>
 
@@ -39,8 +41,10 @@
 using namespace std;
 using boost::shared_ptr;
 
+using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::datasrc;
+using isc::datasrc::memory::InMemoryClient;
 using namespace isc::testutils;
 
 namespace {
@@ -54,18 +58,16 @@ typedef shared_ptr<DataSourceClient> DataSourceClientPtr;
 // This is the type used as the test parameter.  Note that this is
 // intentionally a plain old type (i.e. a function pointer), not a class;
 // otherwise it could cause initialization fiasco at the instantiation time.
-typedef DataSourceClientPtr (*ClientCreator)(RRClass, const Name&);
+typedef DataSourceClientPtr (*ClientCreator)(MemorySegment&, RRClass,
+                                             const Name&);
 
 // Creator for the in-memory client to be tested
 DataSourceClientPtr
-createInMemoryClient(RRClass zclass, const Name& zname) {
-    shared_ptr<InMemoryClient> client(new InMemoryClient);
-
-    shared_ptr<InMemoryZoneFinder> finder(
-        new InMemoryZoneFinder(zclass, zname));
-    finder->load(TEST_ZONE_FILE);
-
-    client->addZone(finder);
+createInMemoryClient(MemorySegment& mem_sgmt, RRClass zclass,
+                     const Name& zname)
+{
+    shared_ptr<InMemoryClient> client(new InMemoryClient(mem_sgmt, zclass));
+    client->load(zname, TEST_ZONE_FILE);
 
     return (client);
 }
@@ -76,7 +78,7 @@ addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
 }
 
 DataSourceClientPtr
-createSQLite3Client(RRClass zclass, const Name& zname) {
+createSQLite3Client(MemorySegment&, RRClass zclass, const Name& zname) {
     // We always begin with an empty template SQLite3 DB file and install
     // the zone data from the zone file to ensure both cases have the
     // same test data.
@@ -103,7 +105,7 @@ class ZoneFinderContextTest :
 {
 protected:
     ZoneFinderContextTest() : qclass_(RRClass::IN()), qzone_("example.org") {
-        client_ = (*GetParam())(qclass_, qzone_);
+        client_ = (*GetParam())(mem_sgmt_, qclass_, qzone_);
         REQUESTED_A.push_back(RRType::A());
         REQUESTED_AAAA.push_back(RRType::AAAA());
         REQUESTED_BOTH.push_back(RRType::A());
@@ -114,6 +116,7 @@ protected:
         ASSERT_TRUE(finder_);
     }
 
+    MemorySegmentLocal mem_sgmt_;
     const RRClass qclass_;
     const Name qzone_;
     DataSourceClientPtr client_;
@@ -232,6 +235,18 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithDname) {
                 result_sets_.begin(), result_sets_.end());
 }
 
+TEST_P(ZoneFinderContextTest, getAdditionalOnDname) {
+    // The additional name has a DNAME as well as the additional record.
+    // The existence of DNAME shouldn't hide the additional record.
+    ZoneFinderContextPtr ctx = finder_->find(Name("dnamemx.example.org"),
+                                             RRType::MX());
+    EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
+
+    ctx->getAdditional(REQUESTED_BOTH, result_sets_);
+    rrsetsCheck("dname.example.org. 3600 IN A 192.0.2.12\n",
+                result_sets_.begin(), result_sets_.end());
+}
+
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithEmptyName) {
     // One of NS names is at an empty non terminal node.  It shouldn't cause
     // any disruption.

+ 64 - 170
src/lib/dhcp/iface_mgr.cc

@@ -122,8 +122,6 @@ IfaceMgr::IfaceMgr()
      session_socket_(INVALID_SOCKET), session_callback_(NULL)
 {
 
-    cout << "IfaceMgr initialization." << endl;
-
     try {
         // required for sending/receiving packets
         // let's keep it in front, just in case someone
@@ -134,13 +132,7 @@ IfaceMgr::IfaceMgr()
         detectIfaces();
 
     } catch (const std::exception& ex) {
-        cout << "IfaceMgr creation failed:" << ex.what() << endl;
-
-        // TODO Uncomment this (or call LOG_FATAL) once
-        // interface detection is implemented. Otherwise
-        // it is not possible to run tests in a portable
-        // way (see detectIfaces() method).
-        throw;
+        isc_throw(IfaceDetectError, ex.what());
     }
 }
 
@@ -166,51 +158,34 @@ void IfaceMgr::stubDetectIfaces() {
     // is faked by detecting loopback interface (lo or lo0). It will eventually
     // be removed once we have actual implementations for all supported systems.
 
-    cout << "Interface detection is not implemented on this Operating System yet. "
-         << endl;
-
-    try {
-        if (if_nametoindex("lo") > 0) {
-            ifaceName = "lo";
-            // this is Linux-like OS
-        } else if (if_nametoindex("lo0") > 0) {
-            ifaceName = "lo0";
-            // this is BSD-like OS
-        } else {
-            // we give up. What OS is this, anyway? Solaris? Hurd?
-            isc_throw(NotImplemented,
-                      "Interface detection on this OS is not supported.");
-        }
-
-        Iface iface(ifaceName, if_nametoindex(ifaceName.c_str()));
-        iface.flag_up_ = true;
-        iface.flag_running_ = true;
-
-        // Note that we claim that this is not a loopback. iface_mgr tries to open a
-        // socket on all interaces that are up, running and not loopback. As this is
-        // the only interface we were able to detect, let's pretend this is a normal
-        // interface.
-        iface.flag_loopback_ = false;
-        iface.flag_multicast_ = true;
-        iface.flag_broadcast_ = true;
-        iface.setHWType(HWTYPE_ETHERNET);
-
-        iface.addAddress(IOAddress(v4addr));
-        iface.addAddress(IOAddress(v6addr));
-        addInterface(iface);
-
-        cout << "Detected interface " << ifaceName << "/" << v4addr << "/"
-             << v6addr << endl;
-    } catch (const std::exception& ex) {
-        // TODO: deallocate whatever memory we used
-        // not that important, since this function is going to be
-        // thrown away as soon as we get proper interface detection
-        // implemented
-
-        // TODO Do LOG_FATAL here
-        std::cerr << "Interface detection failed." << std::endl;
-        throw;
+    if (if_nametoindex("lo") > 0) {
+        ifaceName = "lo";
+        // this is Linux-like OS
+    } else if (if_nametoindex("lo0") > 0) {
+        ifaceName = "lo0";
+        // this is BSD-like OS
+    } else {
+        // we give up. What OS is this, anyway? Solaris? Hurd?
+        isc_throw(NotImplemented,
+                  "Interface detection on this OS is not supported.");
     }
+
+    Iface iface(ifaceName, if_nametoindex(ifaceName.c_str()));
+    iface.flag_up_ = true;
+    iface.flag_running_ = true;
+
+    // Note that we claim that this is not a loopback. iface_mgr tries to open a
+    // socket on all interaces that are up, running and not loopback. As this is
+    // the only interface we were able to detect, let's pretend this is a normal
+    // interface.
+    iface.flag_loopback_ = false;
+    iface.flag_multicast_ = true;
+    iface.flag_broadcast_ = true;
+    iface.setHWType(HWTYPE_ETHERNET);
+
+    iface.addAddress(IOAddress(v4addr));
+    iface.addAddress(IOAddress(v6addr));
+    addInterface(iface);
 }
 
 bool IfaceMgr::openSockets4(const uint16_t port) {
@@ -221,13 +196,9 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
          iface != ifaces_.end();
          ++iface) {
 
-        cout << "Trying opening socket on interface " << iface->getFullName() << endl;
-
         if (iface->flag_loopback_ ||
             !iface->flag_up_ ||
             !iface->flag_running_) {
-            cout << "Interface " << iface->getFullName()
-                 << " not suitable: is loopback, is down or not running" << endl;
             continue;
         }
 
@@ -243,15 +214,13 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
 
             sock = openSocket(iface->getName(), *addr, port);
             if (sock < 0) {
-                cout << "Failed to open unicast socket." << endl;
-                return (false);
+                isc_throw(SocketConfigError, "failed to open unicast socket");
             }
 
             count++;
         }
     }
     return (count > 0);
-
 }
 
 bool IfaceMgr::openSockets6(const uint16_t port) {
@@ -280,8 +249,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
 
             sock = openSocket(iface->getName(), *addr, port);
             if (sock < 0) {
-                cout << "Failed to open unicast socket." << endl;
-                return (false);
+                isc_throw(SocketConfigError, "failed to open unicast socket");
             }
 
             // Binding socket to unicast address and then joining multicast group
@@ -290,7 +258,8 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
             if ( !joinMulticast(sock, iface->getName(),
                                 string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS))) {
                 close(sock);
-                isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
+                isc_throw(SocketConfigError, "Failed to join "
+                          << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
                           << " multicast group.");
             }
 
@@ -305,7 +274,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
                                    IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
                                    port);
             if (sock2 < 0) {
-                isc_throw(Unexpected, "Failed to open multicast socket on "
+                isc_throw(SocketConfigError, "Failed to open multicast socket on "
                           << " interface " << iface->getFullName());
                 iface->delSocket(sock); // delete previously opened socket
             }
@@ -418,7 +387,7 @@ int IfaceMgr::openSocketFromIface(const std::string& ifname,
                 family_name = "AF_INET6";
             }
             // We did not find address on the interface.
-            isc_throw(BadValue, "There is no address for interface: "
+            isc_throw(SocketConfigError, "There is no address for interface: "
                       << ifname << ", port: " << port << ", address "
                       " family: " << family_name);
         }
@@ -460,9 +429,13 @@ int IfaceMgr::openSocketFromAddress(const IOAddress& addr,
 
 int IfaceMgr::openSocketFromRemoteAddress(const IOAddress& remote_addr,
                                           const uint16_t port) {
-    // Get local address to be used to connect to remote location.
-    IOAddress local_address(getLocalAddress(remote_addr, port).getAddress());
-    return openSocketFromAddress(local_address, port);
+    try {
+        // Get local address to be used to connect to remote location.
+        IOAddress local_address(getLocalAddress(remote_addr, port).getAddress());
+        return openSocketFromAddress(local_address, port);
+    } catch (const Exception& e) {
+        isc_throw(SocketConfigError, e.what());
+    }
 }
 
 isc::asiolink::IOAddress
@@ -506,7 +479,7 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
     sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
     if (err_code) {
         sock.close();
-        isc_throw(Unexpected,"failed to connect to remote endpoint.");
+        isc_throw(Unexpected, "failed to connect to remote endpoint.");
     }
 
     // Once we are connected socket object holds local endpoint.
@@ -523,9 +496,6 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
 
 int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
 
-    cout << "Creating UDP4 socket on " << iface.getFullName()
-         << " " << addr.toText() << "/port=" << port << endl;
-
     struct sockaddr_in addr4;
     memset(&addr4, 0, sizeof(sockaddr));
     addr4.sin_family = AF_INET;
@@ -537,12 +507,12 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
 
     int sock = socket(AF_INET, SOCK_DGRAM, 0);
     if (sock < 0) {
-        isc_throw(Unexpected, "Failed to create UDP6 socket.");
+        isc_throw(SocketConfigError, "Failed to create UDP6 socket.");
     }
 
     if (bind(sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0) {
         close(sock);
-        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
+        isc_throw(SocketConfigError, "Failed to bind socket " << sock << " to " << addr.toText()
                   << "/port=" << port);
     }
 
@@ -552,13 +522,10 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
     int flag = 1;
     if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
         close(sock);
-        isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
+        isc_throw(SocketConfigError, "setsockopt: IP_PKTINFO: failed.");
     }
 #endif
 
-    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
-        addr.toText() << "/port=" << port << endl;
-
     SocketInfo info(sock, addr, port);
     iface.addSocket(info);
 
@@ -567,9 +534,6 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
 
 int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
 
-    cout << "Creating UDP6 socket on " << iface.getFullName()
-         << " " << addr.toText() << "/port=" << port << endl;
-
     struct sockaddr_in6 addr6;
     memset(&addr6, 0, sizeof(addr6));
     addr6.sin6_family = AF_INET6;
@@ -590,7 +554,7 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
     // make a socket
     int sock = socket(AF_INET6, SOCK_DGRAM, 0);
     if (sock < 0) {
-        isc_throw(Unexpected, "Failed to create UDP6 socket.");
+        isc_throw(SocketConfigError, "Failed to create UDP6 socket.");
     }
 
     // Set the REUSEADDR option so that we don't fail to start if
@@ -599,12 +563,12 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *)&flag, sizeof(flag)) < 0) {
         close(sock);
-        isc_throw(Unexpected, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
+        isc_throw(SocketConfigError, "Can't set SO_REUSEADDR option on dhcpv6 socket.");
     }
 
     if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
         close(sock);
-        isc_throw(Unexpected, "Failed to bind socket " << sock << " to " << addr.toText()
+        isc_throw(SocketConfigError, "Failed to bind socket " << sock << " to " << addr.toText()
                   << "/port=" << port);
     }
 #ifdef IPV6_RECVPKTINFO
@@ -612,14 +576,14 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                    &flag, sizeof(flag)) != 0) {
         close(sock);
-        isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
+        isc_throw(SocketConfigError, "setsockopt: IPV6_RECVPKTINFO failed.");
     }
 #else
     // RFC2292 - an old way
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
                    &flag, sizeof(flag)) != 0) {
         close(sock);
-        isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
+        isc_throw(SocketConfigError, "setsockopt: IPV6_PKTINFO: failed.");
     }
 #endif
 
@@ -632,14 +596,11 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
         if ( !joinMulticast( sock, iface.getName(),
                          string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
             close(sock);
-            isc_throw(Unexpected, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
+            isc_throw(SocketConfigError, "Failed to join " << ALL_DHCP_RELAY_AGENTS_AND_SERVERS
                       << " multicast group.");
         }
     }
 
-    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
-        addr.toText() << "/port=" << port << endl;
-
     SocketInfo info(sock, addr, port);
     iface.addSocket(info);
 
@@ -654,20 +615,15 @@ const std::string & mcast) {
 
     if (inet_pton(AF_INET6, mcast.c_str(),
                   &mreq.ipv6mr_multiaddr) <= 0) {
-        cout << "Failed to convert " << ifname
-             << " to IPv6 multicast address." << endl;
         return (false);
     }
 
     mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                    &mreq, sizeof(mreq)) < 0) {
-        cout << "Failed to join " << mcast << " multicast group." << endl;
         return (false);
     }
 
-    cout << "Joined multicast " << mcast << " group." << endl;
-
     return (true);
 }
 
@@ -746,13 +702,8 @@ IfaceMgr::send(const Pkt6Ptr& pkt) {
 
     result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 0) {
-        isc_throw(Unexpected, "Pkt6 send failed: sendmsg() returned " << result);
+        isc_throw(SocketWriteError, "Pkt6 send failed: sendmsg() returned " << result);
     }
-    cout << "Sent " << pkt->getBuffer().getLength() << " bytes over socket " << getSocket(*pkt)
-         << " on " << iface->getFullName() << " interface: "
-         << " dst=[" << pkt->getRemoteAddr().toText() << "]:" << pkt->getRemotePort()
-         << ", src=" << pkt->getLocalAddr().toText() << "]:" << pkt->getLocalPort()
-         << endl;
 
     return (result);
 }
@@ -797,24 +748,13 @@ IfaceMgr::send(const Pkt4Ptr& pkt)
     // call OS-specific routines (like setting interface index)
     os_send4(m, control_buf_, control_buf_len_, pkt);
 
-    cout << "Trying to send " << pkt->getBuffer().getLength() << " bytes to "
-         << pkt->getRemoteAddr().toText() << ":" << pkt->getRemotePort()
-         << " over socket " << getSocket(*pkt) << " on interface "
-         << getIface(pkt->getIface())->getFullName() << endl;
-
     pkt->updateTimestamp();
 
     int result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 0) {
-        isc_throw(Unexpected, "Pkt4 send failed.");
+        isc_throw(SocketWriteError, "pkt4 send failed");
     }
 
-    cout << "Sent " << pkt->getBuffer().getLength() << " bytes over socket " << getSocket(*pkt)
-         << " on " << iface->getFullName() << " interface: "
-         << " dst=" << pkt->getRemoteAddr().toText() << ":" << pkt->getRemotePort()
-         << ", src=" << pkt->getLocalAddr().toText() << ":" << pkt->getLocalPort()
-         << endl;
-
     return (result);
 }
 
@@ -869,27 +809,18 @@ IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
     select_timeout.tv_sec = timeout_sec;
     select_timeout.tv_usec = timeout_usec;
 
-    cout << "Trying to receive data on sockets: " << names.str()
-         << ". Timeout is " << timeout_sec << "." << setw(6) << setfill('0')
-         << timeout_usec << " 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
+        isc_throw(SocketReadError, strerror(errno));
     }
 
     // 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
@@ -918,14 +849,9 @@ IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
     }
 
     if (!candidate) {
-        cout << "Received data over unknown socket." << endl;
-        return (Pkt4Ptr()); // NULL
+        isc_throw(SocketReadError, "received data over unknown socket");
     }
 
-    cout << "Trying to receive over UDP4 socket " << candidate->sockfd_ << " bound to "
-         << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
-         << iface->getFullName() << endl;
-
     // Now we have a socket, let's get some data from it!
     struct sockaddr_in from_addr;
     uint8_t buf[RCVBUFSIZE];
@@ -958,8 +884,7 @@ IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
 
     result = recvmsg(candidate->sockfd_, &m, 0);
     if (result < 0) {
-        cout << "Failed to receive UDP4 data." << endl;
-        return (Pkt4Ptr()); // NULL
+        isc_throw(SocketReadError, "failed to receive UDP4 data");
     }
 
     // We have all data let's create Pkt4 object.
@@ -982,15 +907,9 @@ IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
     pkt->setLocalPort(candidate->port_);
 
     if (!os_receive4(m, pkt)) {
-        cout << "Unable to find pktinfo" << endl;
-        return (boost::shared_ptr<Pkt4>()); // NULL
+        isc_throw(SocketReadError, "unable to find pktinfo");
     }
 
-    cout << "Received " << result << " bytes from " << from.toText()
-         << "/port=" << from_port
-         << " sent to " << pkt->getLocalAddr().toText() << " over interface "
-         << iface->getFullName() << endl;
-
     return (pkt);
 }
 
@@ -1039,10 +958,6 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
         names << session_socket_ << "(session)";
     }
 
-    cout << "Trying to receive data on sockets: " << names.str()
-         << ". Timeout is " << timeout_sec << "." << setw(6) << setfill('0')
-         << timeout_usec << " seconds." << endl;
-
     struct timeval select_timeout;
     select_timeout.tv_sec = timeout_sec;
     select_timeout.tv_usec = timeout_usec;
@@ -1053,17 +968,12 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
         // nothing received and timeout has been reached
         return (Pkt6Ptr()); // NULL
     } else if (result < 0) {
-        cout << "Socket read error: " << strerror(errno) << endl;
-
-        /// @todo: perhaps throw here?
-        return (Pkt6Ptr()); // NULL
+        isc_throw(SocketReadError, strerror(errno));
     }
 
     // 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
@@ -1092,14 +1002,9 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
     }
 
     if (!candidate) {
-        cout << "Received data over unknown socket." << endl;
-        return (Pkt6Ptr()); // NULL
+        isc_throw(SocketReadError, "received data over unknown socket");
     }
 
-    cout << "Trying to receive over UDP6 socket " << candidate->sockfd_ << " bound to "
-         << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
-         << iface->getFullName() << endl;
-
     // Now we have a socket, let's get some data from it!
     uint8_t buf[RCVBUFSIZE];
     memset(&control_buf_[0], 0, control_buf_len_);
@@ -1163,12 +1068,10 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
             cmsg = CMSG_NXTHDR(&m, cmsg);
         }
         if (!found_pktinfo) {
-            cout << "Unable to find pktinfo" << endl;
-            return (Pkt6Ptr()); // NULL
+            isc_throw(SocketReadError, "unable to find pktinfo");
         }
     } else {
-        cout << "Failed to receive data." << endl;
-        return (Pkt6Ptr()); // NULL
+        isc_throw(SocketReadError, "failed to receive data");
     }
 
     // Let's create a packet.
@@ -1176,8 +1079,7 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
     try {
         pkt = Pkt6Ptr(new Pkt6(buf, result));
     } catch (const std::exception& ex) {
-        cout << "Failed to create new packet." << endl;
-        return (Pkt6Ptr()); // NULL
+        isc_throw(SocketReadError, "failed to create new packet");
     }
 
     pkt->updateTimestamp();
@@ -1193,18 +1095,10 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
     if (received) {
         pkt->setIface(received->getName());
     } else {
-        cout << "Received packet over unknown interface (ifindex="
-             << pkt->getIndex() << ")." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
+        isc_throw(SocketReadError, "received packet over unknown interface"
+                  << "(ifindex=" << pkt->getIndex() << ")");
     }
 
-    /// @todo: Move this to LOG_DEBUG
-    cout << "Received " << pkt->getBuffer().getLength() << " bytes over "
-         << pkt->getIface() << "/" << pkt->getIndex() << " interface: "
-         << " src=" << pkt->getRemoteAddr().toText()
-         << ", dst=" << pkt->getLocalAddr().toText()
-         << endl;
-
     return (pkt);
 }
 

+ 40 - 0
src/lib/dhcp/iface_mgr.h

@@ -28,6 +28,38 @@
 namespace isc {
 
 namespace dhcp {
+
+/// @brief IfaceMgr exception thrown thrown when interface detection fails.
+class IfaceDetectError : public Exception {
+public:
+    IfaceDetectError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief IfaceMgr exception thrown thrown when socket opening
+/// or configuration failed.
+class SocketConfigError : public Exception {
+public:
+    SocketConfigError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief IfaceMgr exception thrown thrown when error occured during
+/// reading data from socket.
+class SocketReadError : public Exception {
+public:
+    SocketReadError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief IfaceMgr exception thrown thrown when error occured during
+/// sedning data through socket.
+class SocketWriteError : public Exception {
+public:
+    SocketWriteError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
 /// @brief handles network interfaces, transmission and reception
 ///
 /// IfaceMgr is an interface manager class that detects available network
@@ -340,6 +372,8 @@ public:
     ///
     /// @param pkt packet to be sent
     ///
+    /// @throw isc::BadValue if invalid interface specified in the packet.
+    /// @throw isc::dhcp::SocketWriteError if sendmsg() failed to send packet.
     /// @return true if sending was successful
     bool send(const Pkt6Ptr& pkt);
 
@@ -351,6 +385,8 @@ public:
     ///
     /// @param pkt a packet to be sent
     ///
+    /// @throw isc::BadValue if invalid interface specified in the packet.
+    /// @throw isc::dhcp::SocketWriteError if sendmsg() failed to send packet.
     /// @return true if sending was successful
     bool send(const Pkt4Ptr& pkt);
 
@@ -369,6 +405,7 @@ public:
     /// (in microseconds)
     ///
     /// @throw isc::BadValue if timeout_usec is greater than one million
+    /// @throw isc::dhcp::SocketReadError if error occured when receiving a packet.
     /// @return Pkt6 object representing received packet (or NULL)
     Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
 
@@ -383,6 +420,7 @@ public:
     /// (in microseconds)
     ///
     /// @throw isc::BadValue if timeout_usec is greater than one million
+    /// @throw isc::dhcp::SocketReadError if error occured when receiving a packet.
     /// @return Pkt4 object representing received packet (or NULL)
     Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);
 
@@ -460,6 +498,7 @@ public:
     ///
     /// @param port specifies port number (usually DHCP6_SERVER_PORT)
     ///
+    /// @throw SocketOpenFailure if tried and failed to open socket.
     /// @return true if any sockets were open
     bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT);
 
@@ -472,6 +511,7 @@ public:
     ///
     /// @param port specifies port number (usually DHCP4_SERVER_PORT)
     ///
+    /// @throw SocketOpenFailure if tried and failed to open socket.
     /// @return true if any sockets were open
     bool openSockets4(const uint16_t port = DHCP4_SERVER_PORT);
 

+ 1 - 8
src/lib/dhcp/iface_mgr_linux.cc

@@ -417,8 +417,6 @@ namespace dhcp {
 /// Uses the socket-based netlink protocol to retrieve the list of interfaces
 /// from the Linux kernel.
 void IfaceMgr::detectIfaces() {
-    cout << "Linux: detecting interfaces." << endl;
-
     // Copies of netlink messages about links will be stored here.
     Netlink::NetlinkMessages link_info;
 
@@ -495,8 +493,6 @@ void IfaceMgr::detectIfaces() {
 
     nl.release_list(link_info);
     nl.release_list(addr_info);
-
-    printIfaces();
 }
 
 /// @brief sets flag_*_ fields.
@@ -558,10 +554,7 @@ bool IfaceMgr::os_receive4(struct msghdr& m, Pkt4Ptr& pkt) {
             // broadcast. This will return broadcast address, not
             // the address we are bound to.
 
-            // IOAddress tmp(htonl(pktinfo->ipi_spec_dst.s_addr));
-            // cout << "The other addr is: " << tmp.toText() << endl;
-
-            // Perhaps we should uncomment this:
+            // XXX: Perhaps we should uncomment this:
             // to_addr = pktinfo->ipi_spec_dst;
         }
         cmsg = CMSG_NXTHDR(&m, cmsg);

+ 4 - 13
src/lib/dhcp/libdhcp++.cc

@@ -72,26 +72,23 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
         offset += 2;
 
         if (offset + opt_len > end) {
-            cout << "Option " << opt_type << " truncated." << endl;
+            // @todo: consider throwing exception here.
             return (offset);
         }
         OptionPtr opt;
         switch (opt_type) {
         case D6O_IA_NA:
         case D6O_IA_PD:
-            // cout << "Creating Option6IA" << endl;
             opt = OptionPtr(new Option6IA(opt_type,
                                           buf.begin() + offset,
                                           buf.begin() + offset + opt_len));
             break;
         case D6O_IAADDR:
-            // cout << "Creating Option6IAAddr" << endl;
             opt = OptionPtr(new Option6IAAddr(opt_type,
                                               buf.begin() + offset,
                                               buf.begin() + offset + opt_len));
             break;
         default:
-            // cout << "Creating Option" << endl;
             opt = OptionPtr(new Option(Option::V6,
                                        opt_type,
                                        buf.begin() + offset,
@@ -151,15 +148,9 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
 
 void LibDHCP::packOptions6(isc::util::OutputBuffer &buf,
                            const isc::dhcp::Option::OptionCollection& options) {
-    try {
-        for (Option::OptionCollection::const_iterator it = options.begin();
-             it != options.end(); ++it) {
-            it->second->pack(buf);
-        }
-    }
-    catch (const Exception&) {
-        cout << "Packet build failed (Option build failed)." << endl;
-        throw;
+    for (Option::OptionCollection::const_iterator it = options.begin();
+         it != options.end(); ++it) {
+        it->second->pack(buf);
     }
 }
 

+ 0 - 2
src/lib/dhcp/pkt4.cc

@@ -197,8 +197,6 @@ void Pkt4::check() {
 }
 
 void Pkt4::repack() {
-    cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;
-
     bufferOut_.writeData(&data_[0], data_.size());
 }
 

+ 4 - 6
src/lib/dhcp/pkt6.cc

@@ -100,7 +100,7 @@ Pkt6::packUDP() {
         LibDHCP::packOptions6(bufferOut_, options_);
     }
     catch (const Exception& e) {
-        cout << "Packet build failed:" << e.what() << endl;
+        /// @todo: throw exception here once we turn this function to void.
         return (false);
     }
     return (true);
@@ -129,8 +129,8 @@ Pkt6::unpack() {
 bool
 Pkt6::unpackUDP() {
     if (data_.size() < 4) {
-        std::cout << "DHCPv6 packet truncated. Only " << data_.size()
-                  << " bytes. Need at least 4." << std::endl;
+        // @todo: throw exception here informing that packet is truncated
+        // once we turn this function to void.
         return (false);
     }
     msg_type_ = data_[0];
@@ -143,7 +143,7 @@ Pkt6::unpackUDP() {
 
         LibDHCP::unpackOptions6(opt_buffer, options_);
     } catch (const Exception& e) {
-        cout << "Packet parsing failed:" << e.what() << endl;
+        // @todo: throw exception here once we turn this function to void.
         return (false);
     }
     return (true);
@@ -197,8 +197,6 @@ Pkt6::delOption(uint16_t type) {
 }
 
 void Pkt6::repack() {
-    cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;
-
     bufferOut_.writeData(&data_[0], data_.size());
 }
 

+ 66 - 19
src/lib/dhcp/tests/iface_mgr_unittest.cc

@@ -82,10 +82,8 @@ TEST_F(IfaceMgrTest, loDetect) {
     // it will go away as soon as proper interface detection
     // is implemented
     if (if_nametoindex("lo") > 0) {
-        cout << "This is Linux, using lo as loopback." << endl;
         snprintf(LOOPBACK, BUF_SIZE - 1, "lo");
     } else if (if_nametoindex("lo0") > 0) {
-        cout << "This is BSD, using lo0 as loopback." << endl;
         snprintf(LOOPBACK, BUF_SIZE - 1, "lo0");
     } else {
         cout << "Failed to detect loopback interface. Neither "
@@ -421,7 +419,7 @@ TEST_F(IfaceMgrTest, sockets6) {
     // testing socket operation in a portable way is tricky
     // without interface detection implemented
 
-    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+    boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
 
     IOAddress loAddr("::1");
 
@@ -441,10 +439,25 @@ TEST_F(IfaceMgrTest, sockets6) {
     // removed code for binding socket twice to the same address/port
     // as it caused problems on some platforms (e.g. Mac OS X)
 
-    close(socket1);
-    close(socket2);
+    // Close sockets here because the following tests will want to
+    // open sockets on the same ports.
+    ifacemgr->closeSockets();
 
-    delete ifacemgr;
+    // Use address that is not assigned to LOOPBACK iface.
+    IOAddress invalidAddr("::2");
+    EXPECT_THROW(
+        ifacemgr->openSocket(LOOPBACK, invalidAddr, 10547),
+        SocketConfigError
+    );
+
+    // Use non-existing interface name.
+    EXPECT_THROW(
+        ifacemgr->openSocket("non_existing_interface", loAddr, 10548),
+        BadValue
+    );
+
+    // Do not call closeSockets() because it is called by IfaceMgr's
+    // virtual destructor.
 }
 
 TEST_F(IfaceMgrTest, socketsFromIface) {
@@ -468,6 +481,18 @@ TEST_F(IfaceMgrTest, socketsFromIface) {
     EXPECT_GT(socket2, 0);
     close(socket2);
 
+    // Close sockets here because the following tests will want to
+    // open sockets on the same ports.
+    ifacemgr->closeSockets();
+
+    // Use invalid interface name.
+    EXPECT_THROW(
+        ifacemgr->openSocketFromIface("non_existing_interface", PORT1, AF_INET),
+        BadValue
+    );
+
+    // Do not call closeSockets() because it is called by IfaceMgr's
+    // virtual destructor.
 }
 
 
@@ -482,7 +507,6 @@ TEST_F(IfaceMgrTest, socketsFromAddress) {
     );
     // socket descriptor must be positive integer
     EXPECT_GT(socket1, 0);
-    close(socket1);
 
     // Open v4 socket on loopback interface and bind to different port
     int socket2 = 0;
@@ -492,7 +516,19 @@ TEST_F(IfaceMgrTest, socketsFromAddress) {
     );
     // socket descriptor must be positive integer
     EXPECT_GT(socket2, 0);
-    close(socket2);
+
+    // Close sockets here because the following tests will want to
+    // open sockets on the same ports.
+    ifacemgr->closeSockets();
+
+    // Use non-existing address.
+    IOAddress invalidAddr("1.2.3.4");
+    EXPECT_THROW(
+        ifacemgr->openSocketFromAddress(invalidAddr, PORT1), BadValue
+    );
+
+    // Do not call closeSockets() because it is called by IfaceMgr's
+    // virtual destructor.
 }
 
 TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
@@ -507,7 +543,6 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
         socket1 = ifacemgr->openSocketFromRemoteAddress(loAddr6, PORT1);
     );
     EXPECT_GT(socket1, 0);
-    close(socket1);
 
     // Open v4 socket to connect to remote address.
     int socket2 = 0;
@@ -516,7 +551,10 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
         socket2 = ifacemgr->openSocketFromRemoteAddress(loAddr, PORT2);
     );
     EXPECT_GT(socket2, 0);
-    close(socket2);
+
+    // Close sockets here because the following tests will want to
+    // open sockets on the same ports.
+    ifacemgr->closeSockets();
 
     // The following test is currently disabled for OSes other than
     // Linux because interface detection is not implemented on them.
@@ -530,8 +568,10 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
         socket3 = ifacemgr->openSocketFromRemoteAddress(bcastAddr, PORT2);
     );
     EXPECT_GT(socket3, 0);
-    close(socket3);
 #endif
+
+    // Do not call closeSockets() because it is called by IfaceMgr's
+    // virtual destructor.
 }
 
 // TODO: disabled due to other naming on various systems
@@ -570,7 +610,7 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     // testing socket operation in a portable way is tricky
     // without interface detection implemented
 
-    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+    boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
 
     // let's assume that every supported OS have lo interface
     IOAddress loAddr("::1");
@@ -619,7 +659,11 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     // we should accept both values as source ports.
     EXPECT_TRUE((rcvPkt->getRemotePort() == 10546) || (rcvPkt->getRemotePort() == 10547));
 
-    delete ifacemgr;
+    // try to send/receive data over the closed socket. Closed socket's descriptor is
+    // still being hold by IfaceMgr which will try to use it to receive data.
+    close(socket1);
+    EXPECT_THROW(ifacemgr->receive6(10), SocketReadError);
+    EXPECT_THROW(ifacemgr->send(sendPkt), SocketWriteError);
 }
 
 TEST_F(IfaceMgrTest, sendReceive4) {
@@ -627,7 +671,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
     // testing socket operation in a portable way is tricky
     // without interface detection implemented
 
-    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+    boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
 
     // let's assume that every supported OS have lo interface
     IOAddress loAddr("127.0.0.1");
@@ -675,8 +719,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
 
     EXPECT_EQ(true, ifacemgr->send(sendPkt));
 
-    rcvPkt = ifacemgr->receive4(10);
-
+    ASSERT_NO_THROW(rcvPkt = ifacemgr->receive4(10));
     ASSERT_TRUE(rcvPkt); // received our own packet
 
     ASSERT_NO_THROW(
@@ -710,7 +753,11 @@ TEST_F(IfaceMgrTest, sendReceive4) {
     // assume the one or the other will always be choosen for sending data. We should
     // skip checking source port of sent address.
 
-    delete ifacemgr;
+    // try to receive data over the closed socket. Closed socket's descriptor is
+    // still being hold by IfaceMgr which will try to use it to receive data.
+    close(socket1);
+    EXPECT_THROW(ifacemgr->receive4(10), SocketReadError);
+    EXPECT_THROW(ifacemgr->send(sendPkt), SocketWriteError);
 }
 
 
@@ -1214,7 +1261,7 @@ TEST_F(IfaceMgrTest, controlSession) {
     EXPECT_NO_THROW(ifacemgr->set_session_socket(pipefd[0], my_callback));
 
     Pkt4Ptr pkt4;
-    pkt4 = ifacemgr->receive4(1);
+    ASSERT_NO_THROW(pkt4 = ifacemgr->receive4(1));
 
     // Our callback should not be called this time (there was no data)
     EXPECT_FALSE(callback_ok);
@@ -1226,7 +1273,7 @@ TEST_F(IfaceMgrTest, controlSession) {
     EXPECT_EQ(38, write(pipefd[1], "Hi, this is a message sent over a pipe", 38));
 
     // ... and repeat
-    pkt4 = ifacemgr->receive4(1);
+    ASSERT_NO_THROW(pkt4 = ifacemgr->receive4(1));
 
     // IfaceMgr should not process control socket data as incoming packets
     EXPECT_FALSE(pkt4);

+ 0 - 0
src/lib/dns/labelsequence.cc


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