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
 479.	[func]		marcin
 	Refactored perfdhcp tool to C++, added missing unit tests and removed
 	Refactored perfdhcp tool to C++, added missing unit tests and removed
 	the old code. The new code uses libdhcp++ (src/lib/dhcp) for DHCP
 	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 #1954, git 8d56105742f3043ed4b561f26241f3e4331f51dc)
 	(Trac #1955, git 6f914bb2c388eb4dd3e5c55297f8988ab9529b3f)
 	(Trac #1955, git 6f914bb2c388eb4dd3e5c55297f8988ab9529b3f)
 	(Trac #1956, 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/exceptions/tests/Makefile
                  src/lib/datasrc/Makefile
                  src/lib/datasrc/Makefile
                  src/lib/datasrc/memory/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/memory/benchmarks/Makefile
                  src/lib/datasrc/tests/Makefile
                  src/lib/datasrc/tests/Makefile
                  src/lib/datasrc/tests/testdata/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/Makefile
                  src/lib/xfr/tests/Makefile
                  src/lib/xfr/tests/Makefile
                  src/lib/log/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.
       many modules. So we show them here in one place.
     </para>
     </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'>
     <section id='common-acl'>
       <title>ACLs</title>
       <title>ACLs</title>
 
 
@@ -1375,9 +1458,9 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
         <para>
         <para>
           The other is TSIG key by which the message was signed. The ACL
           The other is TSIG key by which the message was signed. The ACL
           contains only the name (under the name "key"), the key itself
           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>
 
 
         <para>
         <para>
@@ -1403,18 +1486,6 @@ AND_MATCH := "ALL": [ RULE_RAW, RULE_RAW, ... ]
           will work in a similar way.
           will work in a similar way.
         </para>
         </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>
         <para>
           If that is not enough, you can compose the matching conditions
           If that is not enough, you can compose the matching conditions
           to logical expressions. They are called "ANY", "ALL" and "NOT".
           to logical expressions. They are called "ANY", "ALL" and "NOT".
@@ -2151,7 +2222,7 @@ Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)</screen>
 
 
     <para>
     <para>
       If you want to require TSIG in access control, a system wide TSIG
       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
       In this example, we allow client matching both the IP address
       and key.
       and key.
     </para>
     </para>
@@ -2161,7 +2232,7 @@ Xfrout/transfer_acl[0]	{"action": "ACCEPT"}	any	(default)</screen>
 &gt; <userinput>config commit</userinput></screen>
 &gt; <userinput>config commit</userinput></screen>
 
 
     <para>Both <command>b10-xfrout</command> and <command>b10-auth</command>
     <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>
       TSIGs in the incoming messages and to sign responses.</para>
 
 
     <para>
     <para>
@@ -2371,11 +2442,12 @@ what is XfroutClient xfr_client??
 &gt; <userinput>config commit</userinput>
 &gt; <userinput>config commit</userinput>
 </screen>
 </screen>
       The TSIG key must be configured system wide
       The TSIG key must be configured system wide
-      (see <xref linkend="xfrout"/>.)
+      (see <xref linkend="common-tsig"/>).
       </para>
       </para>
 
 
       <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>
       </para>
 
 
       <note><simpara>
       <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 += statistics.cc statistics.h
 b10_auth_SOURCES += datasrc_configurator.h
 b10_auth_SOURCES += datasrc_configurator.h
 b10_auth_SOURCES += main.cc
 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
 nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
 EXTRA_DIST += auth_messages.mes
 EXTRA_DIST += auth_messages.mes

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

@@ -41,10 +41,7 @@
 
 
 #include <asiodns/dns_service.h>
 #include <asiodns/dns_service.h>
 
 
-#include <datasrc/query.h>
 #include <datasrc/data_source.h>
 #include <datasrc/data_source.h>
-#include <datasrc/static_datasrc.h>
-#include <datasrc/sqlite3_datasrc.h>
 #include <datasrc/client_list.h>
 #include <datasrc/client_list.h>
 
 
 #include <xfr/xfrout_client.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 += ../auth_config.h ../auth_config.cc
 query_bench_SOURCES += ../statistics.h ../statistics.cc
 query_bench_SOURCES += ../statistics.h ../statistics.cc
 query_bench_SOURCES += ../auth_log.h ../auth_log.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
 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 += statistics_unittest.cc
 run_unittests_SOURCES += datasrc_configurator_unittest.cc
 run_unittests_SOURCES += datasrc_configurator_unittest.cc
 run_unittests_SOURCES += run_unittests.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
 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 <config.h>
 
 
 #include <util/io/sockaddr_util.h>
 #include <util/io/sockaddr_util.h>
+#include <util/memory_segment_local.h>
 
 
 #include <dns/message.h>
 #include <dns/message.h>
 #include <dns/messagerenderer.h>
 #include <dns/messagerenderer.h>
@@ -1393,16 +1394,19 @@ public:
              const isc::datasrc::DataSourceClientPtr
              const isc::datasrc::DataSourceClientPtr
                  client(new FakeClient(info.data_src_client_ != NULL ?
                  client(new FakeClient(info.data_src_client_ != NULL ?
                                        info.data_src_client_ :
                                        info.data_src_client_ :
-                                       info.cache_.get(),
+                                       info.getCacheClient(),
                                        throw_when, isc_exception, fake_rrset));
                                        throw_when, isc_exception, fake_rrset));
              clients_.push_back(client);
              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:
 private:
     const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
     const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
     vector<isc::datasrc::DataSourceClientPtr> clients_;
     vector<isc::datasrc::DataSourceClientPtr> clients_;
+    MemorySegmentLocal mem_sgmt_;
 };
 };
 
 
 } // end anonymous namespace for throwing proxy classes
 } // 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
 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.
 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
 % DHCP4_PACKET_RECEIVED %1 (type %2) packet received on interface %3
 A debug message noting that the server has received the specified type of
 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
 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
 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).
 (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
 % DHCP4_PACK_FAIL failed to assemble response correctly
 This error is output if the server failed to assemble the data to be
 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
 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;
         int timeout = 1000;
 
 
         // client's message and server's response
         // client's message and server's response
-        Pkt4Ptr query = IfaceMgr::instance().receive4(timeout);
+        Pkt4Ptr query;
         Pkt4Ptr rsp;
         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) {
         if (query) {
             try {
             try {
                 query->unpack();
                 query->unpack();
@@ -141,7 +147,11 @@ Dhcpv4Srv::run() {
                           .arg(rsp->getType()).arg(rsp->toText());
                           .arg(rsp->getType()).arg(rsp->toText());
 
 
                 if (rsp->pack()) {
                 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 {
                 } else {
                     LOG_ERROR(dhcp4_logger, DHCP4_PACK_FAIL);
                     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
 % DHCP6_PACKET_PARSE_FAIL failed to parse incoming packet
 The IPv6 DHCP server has received a packet that it is unable to interpret.
 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
 % DHCP6_PACKET_RECEIVED %1 (type %2) packet received
 A debug message noting that the server has received the specified type
 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
 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
 DHCP packet, just a type not expected by the server (e.g. it will report
 a received OFFER packet as UNKNOWN).
 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
 % DHCP6_PACK_FAIL failed to assemble response correctly
 This error is output if the server failed to assemble the data to be
 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
 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;
         int timeout = 1000;
 
 
         // client's message and server's response
         // client's message and server's response
-        Pkt6Ptr query = IfaceMgr::instance().receive6(timeout);
+        Pkt6Ptr query;
         Pkt6Ptr rsp;
         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) {
             if (!query->unpack()) {
             if (!query->unpack()) {
                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
                 LOG_DEBUG(dhcp6_logger, DBG_DHCP6_DETAIL,
@@ -154,7 +160,11 @@ bool Dhcpv6Srv::run() {
                           .arg(rsp->getType()).arg(rsp->toText());
                           .arg(rsp->getType()).arg(rsp->toText());
 
 
                 if (rsp->pack()) {
                 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 {
                 } else {
                     LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL);
                     LOG_ERROR(dhcp6_logger, DHCP6_PACK_FAIL);
                 }
                 }

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

@@ -136,10 +136,6 @@ public:
     virtual boost::shared_ptr<RequestCheck>
     virtual boost::shared_ptr<RequestCheck>
     create(const std::string& name, isc::data::ConstElementPtr definition,
     create(const std::string& name, isc::data::ConstElementPtr definition,
            const acl::Loader<RequestContext>& loader);
            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"
 } // 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\"}]")));
                                               "  \"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 {
 class RequestCheckCreatorTest : public ::testing::Test {
 protected:
 protected:
     dns::internal::RequestCheckCreator creator_;
     dns::internal::RequestCheckCreator creator_;
@@ -78,7 +90,7 @@ TEST_F(RequestCheckCreatorTest, names) {
 }
 }
 
 
 TEST_F(RequestCheckCreatorTest, allowListAbbreviation) {
 TEST_F(RequestCheckCreatorTest, allowListAbbreviation) {
-    EXPECT_FALSE(creator_.allowListAbbreviation());
+    EXPECT_TRUE(creator_.allowListAbbreviation());
 }
 }
 
 
 // The following two tests check the creator for the form of
 // 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 -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 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
 CLEANFILES += static.zone
 
 
 lib_LTLIBRARIES = libb10-datasrc.la
 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 += rbnode_rrset.h
 libb10_datasrc_la_SOURCES += rbtree.h
 libb10_datasrc_la_SOURCES += rbtree.h
 libb10_datasrc_la_SOURCES += zonetable.h zonetable.cc
 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/dns/libb10-dns++.la
 libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.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 += $(top_builddir)/src/lib/cc/libb10-cc.la
+libb10_datasrc_la_LIBADD += $(builddir)/memory/libdatasrc_memory.la
 libb10_datasrc_la_LIBADD += $(SQLITE_LIBS)
 libb10_datasrc_la_LIBADD += $(SQLITE_LIBS)
 
 
 BUILT_SOURCES = datasrc_config.h datasrc_messages.h datasrc_messages.cc
 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
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <util/memory_segment_local.h>
+
 #include "client_list.h"
 #include "client_list.h"
 #include "client.h"
 #include "client.h"
 #include "factory.h"
 #include "factory.h"
-#include "memory_datasrc.h"
+#include "memory/memory_client.h"
 #include "logger.h"
 #include "logger.h"
 #include <dns/masterload.h>
 #include <dns/masterload.h>
 
 
@@ -25,32 +27,58 @@
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace std;
 using namespace std;
+using isc::util::MemorySegment;
 using boost::lexical_cast;
 using boost::lexical_cast;
 using boost::shared_ptr;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 using boost::dynamic_pointer_cast;
+using isc::datasrc::memory::InMemoryClient;
 
 
 namespace isc {
 namespace isc {
 namespace datasrc {
 namespace datasrc {
 
 
 ConfigurableClientList::DataSourceInfo::DataSourceInfo(
 ConfigurableClientList::DataSourceInfo::DataSourceInfo(
     DataSourceClient* data_src_client,
     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),
     data_src_client_(data_src_client),
     container_(container)
     container_(container)
 {
 {
     if (has_cache) {
     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)
     data_src_client_(NULL)
 {
 {
     if (has_cache) {
     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
 void
 ConfigurableClientList::configure(const ConstElementPtr& config,
 ConfigurableClientList::configure(const ConstElementPtr& config,
                                   bool allow_cache)
                                   bool allow_cache)
@@ -98,14 +126,16 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                     isc_throw(ConfigurationError, "The cache must be enabled "
                     isc_throw(ConfigurationError, "The cache must be enabled "
                               "for the MasterFiles type");
                               "for the MasterFiles type");
                 }
                 }
-                new_data_sources.push_back(DataSourceInfo(true));
+                new_data_sources.push_back(DataSourceInfo(rrclass_, *mem_sgmt_,
+                                                          true));
             } else {
             } else {
                 // Ask the factory to create the data source for us
                 // Ask the factory to create the data source for us
                 const DataSourcePair ds(this->getDataSourceClient(type,
                 const DataSourcePair ds(this->getDataSourceClient(type,
                                                                   paramConf));
                                                                   paramConf));
                 // And put it into the vector
                 // And put it into the vector
                 new_data_sources.push_back(DataSourceInfo(ds.first, ds.second,
                 new_data_sources.push_back(DataSourceInfo(ds.first, ds.second,
-                                                          want_cache));
+                                                          want_cache, rrclass_,
+                                                          *mem_sgmt_));
             }
             }
 
 
             if (want_cache) {
             if (want_cache) {
@@ -141,13 +171,10 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                 for (vector<string>::const_iterator it(zones_origins.begin());
                 for (vector<string>::const_iterator it(zones_origins.begin());
                      it != zones_origins.end(); ++it) {
                      it != zones_origins.end(); ++it) {
                     const Name origin(*it);
                     const Name origin(*it);
-                    shared_ptr<InMemoryZoneFinder>
-                        finder(new
-                            InMemoryZoneFinder(rrclass_, origin));
                     if (type == "MasterFiles") {
                     if (type == "MasterFiles") {
                         try {
                         try {
-                            finder->load(paramConf->get(*it)->stringValue());
-                            cache->addZone(finder);
+                            cache->load(origin,
+                                        paramConf->get(*it)->stringValue());
                         } catch (const isc::dns::MasterLoadError& mle) {
                         } catch (const isc::dns::MasterLoadError& mle) {
                             LOG_ERROR(logger, DATASRC_MASTERLOAD_ERROR)
                             LOG_ERROR(logger, DATASRC_MASTERLOAD_ERROR)
                                 .arg(mle.what());
                                 .arg(mle.what());
@@ -165,8 +192,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                             isc_throw(isc::Unexpected, "Got NULL iterator "
                             isc_throw(isc::Unexpected, "Got NULL iterator "
                                       "for zone " << origin);
                                       "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,
     // Try to convert the finder to in-memory one. If it is the cache,
     // it should work.
     // 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.
     // It is of a different type or there's no cache.
-    if (!info->cache_ || !finder) {
+    if (!result.info->cache_) {
         return (ZONE_NOT_CACHED);
         return (ZONE_NOT_CACHED);
     }
     }
-    DataSourceClient* client(info->data_src_client_);
+    DataSourceClient* client(result.info->data_src_client_);
     if (client) {
     if (client) {
         // Now do the final reload. If it does not exist in client,
         // Now do the final reload. If it does not exist in client,
         // DataSourceError is thrown, which is exactly the result what we
         // DataSourceError is thrown, which is exactly the result what we
@@ -340,15 +363,15 @@ ConfigurableClientList::reload(const Name& name) {
         if (!iterator) {
         if (!iterator) {
             isc_throw(isc::Unexpected, "Null iterator from " << name);
             isc_throw(isc::Unexpected, "Null iterator from " << name);
         }
         }
-        finder->load(*iterator);
+        result.info->cache_->load(name, *iterator);
     } else {
     } else {
         // The MasterFiles special case
         // The MasterFiles special case
-        const string filename(finder->getFileName());
+        const string filename(result.info->cache_->getFileName(name));
         if (filename.empty()) {
         if (filename.empty()) {
             isc_throw(isc::Unexpected, "Confused about missing both filename "
             isc_throw(isc::Unexpected, "Confused about missing both filename "
                       "and data source");
                       "and data source");
         }
         }
-        finder->load(filename);
+        result.info->cache_->load(name, filename);
     }
     }
     return (ZONE_RELOADED);
     return (ZONE_RELOADED);
 }
 }

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

@@ -15,6 +15,8 @@
 #ifndef DATASRC_CONTAINER_H
 #ifndef DATASRC_CONTAINER_H
 #define DATASRC_CONTAINER_H
 #define DATASRC_CONTAINER_H
 
 
+#include <util/memory_segment.h>
+
 #include <dns/name.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <dns/rrclass.h>
 #include <cc/data.h>
 #include <cc/data.h>
@@ -22,6 +24,7 @@
 
 
 #include <vector>
 #include <vector>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
 #include <boost/noncopyable.hpp>
 #include <boost/noncopyable.hpp>
 
 
 namespace isc {
 namespace isc {
@@ -34,7 +37,13 @@ typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
 class DataSourceClientContainer;
 class DataSourceClientContainer;
 typedef boost::shared_ptr<DataSourceClientContainer>
 typedef boost::shared_ptr<DataSourceClientContainer>
     DataSourceClientContainerPtr;
     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;
 class InMemoryClient;
+}
 
 
 /// \brief The list of data source clients.
 /// \brief The list of data source clients.
 ///
 ///
@@ -209,11 +218,11 @@ public:
     /// \brief Constructor
     /// \brief Constructor
     ///
     ///
     /// \param rrclass For which class the list should work.
     /// \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.
     /// \brief Exception thrown when there's an error in configuration.
     class ConfigurationError : public Exception {
     class ConfigurationError : public Exception {
     public:
     public:
@@ -290,24 +299,27 @@ public:
     /// \todo The content yet to be defined.
     /// \todo The content yet to be defined.
     struct DataSourceInfo {
     struct DataSourceInfo {
         // Plays a role of default constructor too (for vector)
         // 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,
         DataSourceInfo(DataSourceClient* data_src_client,
                        const DataSourceClientContainerPtr& container,
                        const DataSourceClientContainerPtr& container,
-                       bool has_cache);
+                       bool has_cache, const dns::RRClass& rrclass,
+                       util::MemorySegment& mem_sgmt);
         DataSourceClient* data_src_client_;
         DataSourceClient* data_src_client_;
         DataSourceClientContainerPtr container_;
         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.
     /// \brief The collection of data sources.
     typedef std::vector<DataSourceInfo> DataSources;
     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.
     /// \brief Convenience type alias.
     ///
     ///
@@ -357,10 +369,26 @@ private:
     void findInternal(MutableResult& result, const dns::Name& name,
     void findInternal(MutableResult& result, const dns::Name& name,
                       bool want_exact_match, bool want_finder) const;
                       bool want_exact_match, bool want_finder) const;
     const isc::dns::RRClass rrclass_;
     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.
     /// \brief Currently active configuration.
     isc::data::ConstElementPtr configuration_;
     isc::data::ConstElementPtr configuration_;
+
     /// \brief The last set value of allow_cache.
     /// \brief The last set value of allow_cache.
     bool 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
 } // 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 {
 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
 /// This exception represents Backend-independent errors relating to
 /// data source operations.
 /// data source operations.
 class DataSourceError : public Exception {
 class DataSourceError : public Exception {
@@ -65,361 +58,6 @@ public:
         DataSourceError(file, line, what) {}
         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 -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
 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 {
     bool isSubTreeRoot() const {
         return ((flags_ & FLAG_SUBTREE_ROOT) != 0);
         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:
 public:
     /// \brief returns the parent of the root of its subtree
     /// \brief returns the parent of the root of its subtree
     ///
     ///
@@ -388,7 +401,6 @@ public:
     /// This method never throws an exception.
     /// This method never throws an exception.
     const DomainTreeNode<T>* getUpperNode() const;
     const DomainTreeNode<T>* getUpperNode() const;
 
 
-private:
     /// \brief return the next node which is bigger than current node
     /// \brief return the next node which is bigger than current node
     /// in the same subtree
     /// in the same subtree
     ///
     ///
@@ -423,6 +435,7 @@ private:
     /// This method never throws an exception.
     /// This method never throws an exception.
     const DomainTreeNode<T>* predecessor() const;
     const DomainTreeNode<T>* predecessor() const;
 
 
+private:
     /// \brief private shared implementation of successor and predecessor
     /// \brief private shared implementation of successor and predecessor
     ///
     ///
     /// As the two mentioned functions are merely mirror images of each other,
     /// As the two mentioned functions are merely mirror images of each other,
@@ -538,7 +551,7 @@ DomainTreeNode<T>::~DomainTreeNode() {
 
 
 template <typename T>
 template <typename T>
 const DomainTreeNode<T>*
 const DomainTreeNode<T>*
-DomainTreeNode<T>::getUpperNode() const {
+DomainTreeNode<T>::getSubTreeRoot() const {
     const DomainTreeNode<T>* current = this;
     const DomainTreeNode<T>* current = this;
 
 
     // current would never be equal to NULL here (in a correct tree
     // current would never be equal to NULL here (in a correct tree
@@ -547,7 +560,13 @@ DomainTreeNode<T>::getUpperNode() const {
         current = current->getParent();
         current = current->getParent();
     }
     }
 
 
-    return (current->getParent());
+    return (current);
+}
+
+template <typename T>
+const DomainTreeNode<T>*
+DomainTreeNode<T>::getUpperNode() const {
+    return (getSubTreeRoot()->getParent());
 }
 }
 
 
 template <typename T>
 template <typename T>
@@ -555,7 +574,17 @@ isc::dns::LabelSequence
 DomainTreeNode<T>::getAbsoluteLabels(
 DomainTreeNode<T>::getAbsoluteLabels(
     uint8_t buf[isc::dns::LabelSequence::MAX_SERIALIZED_LENGTH]) const
     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();
     const DomainTreeNode<T>* upper = getUpperNode();
     while (upper != NULL) {
     while (upper != NULL) {
         result.extend(upper->getLabels(), buf);
         result.extend(upper->getLabels(), buf);
@@ -672,14 +701,26 @@ public:
     /// The default constructor.
     /// The default constructor.
     ///
     ///
     /// \exception None
     /// \exception None
-    DomainTreeNodeChain() : node_count_(0), last_compared_(NULL),
+    DomainTreeNodeChain() : level_count_(0), last_compared_(NULL),
                         // XXX: meaningless initial values:
                         // XXX: meaningless initial values:
                         last_comparison_(0, 0,
                         last_comparison_(0, 0,
                                          isc::dns::NameComparisonResult::EQUAL)
                                          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:
 private:
-    DomainTreeNodeChain(const DomainTreeNodeChain<T>&);
     DomainTreeNodeChain<T>& operator=(const DomainTreeNodeChain<T>&);
     DomainTreeNodeChain<T>& operator=(const DomainTreeNodeChain<T>&);
     //@}
     //@}
 
 
@@ -691,7 +732,7 @@ public:
     ///
     ///
     /// \exception None
     /// \exception None
     void clear() {
     void clear() {
-        node_count_ = 0;
+        level_count_ = 0;
         last_compared_ = NULL;
         last_compared_ = NULL;
     }
     }
 
 
@@ -732,7 +773,7 @@ public:
     /// chain, 0 will be returned.
     /// chain, 0 will be returned.
     ///
     ///
     /// \exception None
     /// \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
     /// \brief return the absolute name for the node which this
     /// \c DomainTreeNodeChain currently refers to.
     /// \c DomainTreeNodeChain currently refers to.
@@ -750,11 +791,11 @@ public:
 
 
         const DomainTreeNode<T>* top_node = top();
         const DomainTreeNode<T>* top_node = top();
         isc::dns::Name absolute_name = top_node->getName();
         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());
             absolute_name = absolute_name.concatenate(top_node->getName());
-            --node_count;
+            --level;
         }
         }
         return (absolute_name);
         return (absolute_name);
     }
     }
@@ -768,7 +809,7 @@ private:
     /// \brief return whether node chain has node in it.
     /// \brief return whether node chain has node in it.
     ///
     ///
     /// \exception None
     /// \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
     /// \brief return the top node for the node chain
     ///
     ///
@@ -778,7 +819,7 @@ private:
     /// \exception None
     /// \exception None
     const DomainTreeNode<T>* top() const {
     const DomainTreeNode<T>* top() const {
         assert(!isEmpty());
         assert(!isEmpty());
-        return (nodes_[node_count_ - 1]);
+        return (nodes_[level_count_ - 1]);
     }
     }
 
 
     /// \brief pop the top node from the node chain
     /// \brief pop the top node from the node chain
@@ -789,7 +830,7 @@ private:
     /// \exception None
     /// \exception None
     void pop() {
     void pop() {
         assert(!isEmpty());
         assert(!isEmpty());
-        --node_count_;
+        --level_count_;
     }
     }
 
 
     /// \brief add the node into the node chain
     /// \brief add the node into the node chain
@@ -800,8 +841,8 @@ private:
     ///
     ///
     /// \exception None
     /// \exception None
     void push(const DomainTreeNode<T>* node) {
     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:
 private:
@@ -810,7 +851,7 @@ private:
     // it's also equal to the possible maximum level.
     // it's also equal to the possible maximum level.
     const static int RBT_MAX_LEVEL = isc::dns::Name::MAX_LABELS;
     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>* nodes_[RBT_MAX_LEVEL];
     const DomainTreeNode<T>* last_compared_;
     const DomainTreeNode<T>* last_compared_;
     isc::dns::NameComparisonResult last_comparison_;
     isc::dns::NameComparisonResult last_comparison_;
@@ -1265,12 +1306,20 @@ public:
     const DomainTreeNode<T>*
     const DomainTreeNode<T>*
     previousNode(DomainTreeNodeChain<T>& node_path) const;
     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
     /// \brief Get the total number of nodes in the tree
     ///
     ///
     /// It includes nodes internally created as a result of adding a domain
     /// It includes nodes internally created as a result of adding a domain
     /// name that is a subdomain of an existing node of the tree.
     /// name that is a subdomain of an existing node of the tree.
     /// This function is mainly intended to be used for debugging.
     /// 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
     /// \name Debug function
     //@{
     //@{
@@ -1402,8 +1451,15 @@ private:
     //@}
     //@}
 
 
     typename DomainTreeNode<T>::DomainTreeNodePtr root_;
     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
     /// search policy for domaintree
     const bool needsReturnEmptyNode_;
     const bool needsReturnEmptyNode_;
 };
 };
@@ -1710,6 +1766,24 @@ DomainTree<T>::previousNode(DomainTreeNodeChain<T>& node_path) const {
 }
 }
 
 
 template <typename T>
 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
 typename DomainTree<T>::Result
 DomainTree<T>::insert(util::MemorySegment& mem_sgmt,
 DomainTree<T>::insert(util::MemorySegment& mem_sgmt,
                       const isc::dns::Name& target_name,
                       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/domaintree.h>
 #include <datasrc/memory/segment_object_holder.h>
 #include <datasrc/memory/segment_object_holder.h>
 #include <datasrc/memory/treenode_rrset.h>
 #include <datasrc/memory/treenode_rrset.h>
+#include <datasrc/memory/zone_finder.h>
 
 
 #include <util/memory_segment_local.h>
 #include <util/memory_segment_local.h>
 
 
@@ -100,9 +101,6 @@ public:
         FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
         FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
 
 
         ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
         ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
-
-        // see above for the assert().
-        assert(mem_sgmt_.allMemoryDeallocated());
     }
     }
 
 
     util::MemorySegment& mem_sgmt_;
     util::MemorySegment& mem_sgmt_;
@@ -326,6 +324,7 @@ public:
         if (nsec3_data == NULL) {
         if (nsec3_data == NULL) {
             nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
             nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
             zone_data.setNSEC3Data(nsec3_data);
             zone_data.setNSEC3Data(nsec3_data);
+            zone_data.setSigned(true);
         } else {
         } else {
             size_t salt_len = nsec3_data->getSaltLen();
             size_t salt_len = nsec3_data->getSaltLen();
             const uint8_t* salt_data = nsec3_data->getSaltData();
             const uint8_t* salt_data = nsec3_data->getSaltData();
@@ -333,7 +332,12 @@ public:
 
 
             if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
             if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
                 (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
                 (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)) {
                 (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
                 isc_throw(AddError,
                 isc_throw(AddError,
                           "NSEC3 with inconsistent parameters: " <<
                           "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;
         ZoneNode* node;
-        nsec3_data->insertName(mem_sgmt_, Name(fst_label), &node);
+        nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
 
 
         RdataEncoder encoder;
         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* set = RdataSet::create(mem_sgmt_, encoder, rrset, rrsig);
         RdataSet* old_set = node->setData(set);
         RdataSet* old_set = node->setData(set);
         if (old_set != NULL) {
         if (old_set != NULL) {
@@ -416,6 +413,7 @@ public:
                 if (nsec3_data == NULL) {
                 if (nsec3_data == NULL) {
                     nsec3_data = NSEC3Data::create(mem_sgmt_, param);
                     nsec3_data = NSEC3Data::create(mem_sgmt_, param);
                     zone_data.setNSEC3Data(nsec3_data);
                     zone_data.setNSEC3Data(nsec3_data);
+                    zone_data.setSigned(true);
                 } else {
                 } else {
                     size_t salt_len = nsec3_data->getSaltLen();
                     size_t salt_len = nsec3_data->getSaltLen();
                     const uint8_t* salt_data = nsec3_data->getSaltData();
                     const uint8_t* salt_data = nsec3_data->getSaltData();
@@ -423,7 +421,13 @@ public:
 
 
                     if ((param.getHashalg() != nsec3_data->hashalg) ||
                     if ((param.getHashalg() != nsec3_data->hashalg) ||
                         (param.getIterations() != nsec3_data->iterations) ||
                         (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],
                         (std::memcmp(&salt_data_2[0],
                                      salt_data, salt_len) != 0)) {
                                      salt_data, salt_len) != 0)) {
                         isc_throw(AddError,
                         isc_throw(AddError,
@@ -606,7 +610,7 @@ InMemoryClient::InMemoryClientImpl::load(
     }
     }
 
 
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
     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()
     // Set the filename in file_name_tree_ now, so that getFileName()
     // can use it (during zone reloading).
     // can use it (during zone reloading).
@@ -686,21 +690,25 @@ InMemoryClient::getZoneCount() const {
     return (impl_->zone_count_);
     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,
     LOG_DEBUG(logger, DBG_TRACE_DATA,
               DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
               DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
+
     ZoneTable::FindResult result(impl_->zone_table_->findZone(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
 result::Result

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

@@ -20,11 +20,7 @@
 #include <datasrc/iterator.h>
 #include <datasrc/iterator.h>
 #include <datasrc/client.h>
 #include <datasrc/client.h>
 #include <datasrc/memory/zone_table.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>
 #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.
     /// This derived version of the method never throws an exception.
     /// For other details see \c DataSourceClient::findZone().
     /// 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
     virtual isc::datasrc::DataSourceClient::FindResult
     findZone(const isc::dns::Name& name) const;
     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
     /// \brief Implementation of the getIterator method
     virtual isc::datasrc::ZoneIteratorPtr
     virtual isc::datasrc::ZoneIteratorPtr
     getIterator(const isc::dns::Name& name, bool separate_rrs = false) const;
     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
 std::string
 TreeNodeRRset::toText() const {
 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
     // Dump the main RRset, if not empty
     std::string ret;
     std::string ret;
     RRsetPtr tmp_rrset;
     RRsetPtr tmp_rrset;
@@ -92,7 +88,7 @@ TreeNodeRRset::toText() const {
     {
     {
         if (!tmp_rrset) {
         if (!tmp_rrset) {
             tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_, getType(),
             tmp_rrset = RRsetPtr(new RRset(getName(), rrclass_, getType(),
-                                           ttl));
+                                           getTTL()));
         }
         }
         tmp_rrset->addRdata(rit->getCurrent());
         tmp_rrset->addRdata(rit->getCurrent());
     }
     }
@@ -101,17 +97,7 @@ TreeNodeRRset::toText() const {
     }
     }
 
 
     // Dump any RRSIGs
     // 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) {
     if (tmp_rrset) {
         ret += tmp_rrset->toText();
         ret += tmp_rrset->toText();
     }
     }
@@ -292,7 +278,26 @@ TreeNodeRRset::getSigRdataIterator() const {
 
 
 RRsetPtr
 RRsetPtr
 TreeNodeRRset::getRRsig() const {
 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
 void

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

@@ -190,8 +190,6 @@ public:
     virtual dns::RdataIteratorPtr getRdataIterator() const;
     virtual dns::RdataIteratorPtr getRdataIterator() const;
 
 
     /// \brief Specialized version of \c getRRsig() for \c TreeNodeRRset.
     /// \brief Specialized version of \c getRRsig() for \c TreeNodeRRset.
-    ///
-    /// It throws \c isc::Unexpected unconditionally.
     virtual dns::RRsetPtr getRRsig() const;
     virtual dns::RRsetPtr getRRsig() const;
 
 
     virtual unsigned int getRRsigDataCount() 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/zone_finder.h>
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/treenode_rrset.h>
 #include <datasrc/memory/treenode_rrset.h>
+#include <datasrc/memory/rdata_serialization.h>
 
 
 #include <datasrc/zone.h>
 #include <datasrc/zone.h>
 #include <datasrc/data_source.h>
 #include <datasrc/data_source.h>
@@ -22,9 +23,16 @@
 #include <dns/name.h>
 #include <dns/name.h>
 #include <dns/rrset.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 #include <dns/rrtype.h>
+#include <dns/nsec3hash.h>
 
 
 #include <datasrc/logger.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::dns;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc;
 using namespace isc::datasrc;
@@ -33,6 +41,37 @@ namespace isc {
 namespace datasrc {
 namespace datasrc {
 namespace memory {
 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 {
 namespace {
 /// Creates a TreeNodeRRsetPtr for the given RdataSet at the given Node, for
 /// Creates a TreeNodeRRsetPtr for the given RdataSet at the given Node, for
 /// the given RRClass
 /// the given RRClass
@@ -51,18 +90,21 @@ TreeNodeRRsetPtr
 createTreeNodeRRset(const ZoneNode* node,
 createTreeNodeRRset(const ZoneNode* node,
                     const RdataSet* rdataset,
                     const RdataSet* rdataset,
                     const RRClass& rrclass,
                     const RRClass& rrclass,
+                    ZoneFinder::FindOptions options,
                     const Name* realname = NULL)
                     const Name* realname = NULL)
 {
 {
+    const bool dnssec = ((options & ZoneFinder::FIND_DNSSEC) != 0);
     if (node != NULL && rdataset != NULL) {
     if (node != NULL && rdataset != NULL) {
         if (realname != NULL) {
         if (realname != NULL) {
-            return TreeNodeRRsetPtr(new TreeNodeRRset(*realname, rrclass, node,
-                                                      rdataset, true));
+            return (TreeNodeRRsetPtr(new TreeNodeRRset(*realname, rrclass,
+                                                       node, rdataset,
+                                                       dnssec)));
         } else {
         } else {
-            return TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node,
-                                                      rdataset, true));
+            return (TreeNodeRRsetPtr(new TreeNodeRRset(rrclass, node, rdataset,
+                                                       dnssec)));
         }
         }
     } else {
     } else {
-        return TreeNodeRRsetPtr();
+        return (TreeNodeRRsetPtr());
     }
     }
 }
 }
 
 
@@ -145,6 +187,27 @@ bool cutCallback(const ZoneNode& node, FindState* state) {
     return (false);
     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
 // convenience function to fill in the final details
 //
 //
 // Set up ZoneFinderResultContext object as a return value of find(),
 // 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 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
 // If qname is not NULL, this is the query name, to be used in wildcard
 // substitution instead of the Node's name).
 // substitution instead of the Node's name).
-isc::datasrc::memory::ZoneFinderResultContext
+ZoneFinderResultContext
 createFindResult(const RRClass& rrclass,
 createFindResult(const RRClass& rrclass,
                  const ZoneData& zone_data,
                  const ZoneData& zone_data,
                  ZoneFinder::Result code,
                  ZoneFinder::Result code,
-                 const RdataSet* rrset,
+                 const RdataSet* rdset,
                  const ZoneNode* node,
                  const ZoneNode* node,
+                 ZoneFinder::FindOptions options,
                  bool wild = false,
                  bool wild = false,
-                 const Name* qname = NULL) {
+                 const Name* qname = NULL)
+{
     ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
     ZoneFinder::FindResultFlags flags = ZoneFinder::RESULT_DEFAULT;
     const Name* rename = NULL;
     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
 // A helper function for NSEC-signed zones.  It searches the zone for
@@ -341,19 +407,22 @@ public:
 // caught above.
 // caught above.
 //
 //
 // If none of the above succeeds, we conclude the name doesn't exist in
 // 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,
 FindNodeResult findNode(const ZoneData& zone_data,
-                        const Name& name,
+                        const LabelSequence& name_labels,
                         ZoneChain& node_path,
                         ZoneChain& node_path,
-                        ZoneFinder::FindOptions options)
+                        ZoneFinder::FindOptions options,
+                        bool out_of_zone_ok = false)
 {
 {
     ZoneNode* node = NULL;
     ZoneNode* node = NULL;
     FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
     FindState state((options & ZoneFinder::FIND_GLUE_OK) != 0);
 
 
     const ZoneTree& tree(zone_data.getZoneTree());
     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 =
     const unsigned int zonecut_flag =
         (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
         (state.zonecut_node_ != NULL) ? FindNodeResult::FIND_ZONECUT : 0;
     if (result == ZoneTree::EXACTMATCH) {
     if (result == ZoneTree::EXACTMATCH) {
@@ -377,7 +446,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
         if (node_path.getLastComparisonResult().getRelation() ==
         if (node_path.getLastComparisonResult().getRelation() ==
             NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
             NameComparisonResult::SUPERDOMAIN) { // empty node, so NXRRSET
             LOG_DEBUG(logger, DBG_TRACE_DATA,
             LOG_DEBUG(logger, DBG_TRACE_DATA,
-                      DATASRC_MEM_SUPER_STOP).arg(name);
+                      DATASRC_MEM_SUPER_STOP).arg(name_labels);
             const ZoneNode* nsec_node;
             const ZoneNode* nsec_node;
             const RdataSet* nsec_rds = getClosestNSEC(zone_data,
             const RdataSet* nsec_rds = getClosestNSEC(zone_data,
                                                       node_path,
                                                       node_path,
@@ -398,7 +467,7 @@ FindNodeResult findNode(const ZoneData& zone_data,
                 // baz.foo.wild.example. The common ancestor, foo.wild.example,
                 // baz.foo.wild.example. The common ancestor, foo.wild.example,
                 // should cancel wildcard.  Treat it as NXDOMAIN.
                 // should cancel wildcard.  Treat it as NXDOMAIN.
                 LOG_DEBUG(logger, DBG_TRACE_DATA,
                 LOG_DEBUG(logger, DBG_TRACE_DATA,
-                          DATASRC_MEM_WILDCARD_CANCEL).arg(name);
+                          DATASRC_MEM_WILDCARD_CANCEL).arg(name_labels);
                     const ZoneNode* nsec_node;
                     const ZoneNode* nsec_node;
                     const RdataSet* nsec_rds = getClosestNSEC(zone_data,
                     const RdataSet* nsec_rds = getClosestNSEC(zone_data,
                                                               node_path,
                                                               node_path,
@@ -431,53 +500,198 @@ FindNodeResult findNode(const ZoneData& zone_data,
                         FindNodeResult::FIND_WILDCARD | zonecut_flag));
                         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 ZoneNode* nsec_node;
         const RdataSet* nsec_rds = getClosestNSEC(zone_data, node_path,
         const RdataSet* nsec_rds = getClosestNSEC(zone_data, node_path,
                                                   &nsec_node, options);
                                                   &nsec_node, options);
         return (FindNodeResult(ZoneFinder::NXDOMAIN, nsec_node, nsec_rds));
         return (FindNodeResult(ZoneFinder::NXDOMAIN, nsec_node, nsec_rds));
     } else {
     } else {
         // If the name is neither an exact or partial match, it is
         // 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());
                              zone_data.getOriginNode()->getName());
     }
     }
 }
 }
 
 
 } // end anonymous namespace
 } // 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 {
 class InMemoryZoneFinder::Context : public ZoneFinder::Context {
 public:
 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,
     Context(ZoneFinder& finder, ZoneFinder::FindOptions options,
-            ZoneFinderResultContext result) :
+            const RRClass& rrclass, const ZoneFinderResultContext& result) :
         ZoneFinder::Context(finder, options,
         ZoneFinder::Context(finder, options,
                             ResultContext(result.code, result.rrset,
                             ResultContext(result.code, result.rrset,
                                           result.flags)),
                                           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:
 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 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>
 boost::shared_ptr<ZoneFinder::Context>
 InMemoryZoneFinder::find(const isc::dns::Name& name,
 InMemoryZoneFinder::find(const isc::dns::Name& name,
                 const isc::dns::RRType& type,
                 const isc::dns::RRType& type,
                 const FindOptions options)
                 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>
 boost::shared_ptr<ZoneFinder::Context>
@@ -485,11 +699,11 @@ InMemoryZoneFinder::findAll(const isc::dns::Name& name,
         std::vector<isc::dns::ConstRRsetPtr>& target,
         std::vector<isc::dns::ConstRRsetPtr>& target,
         const FindOptions options)
         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
 ZoneFinderResultContext
@@ -502,10 +716,11 @@ InMemoryZoneFinder::find_internal(const isc::dns::Name& name,
     // in findNode().  We simply construct a result structure and return.
     // in findNode().  We simply construct a result structure and return.
     ZoneChain node_path;
     ZoneChain node_path;
     const FindNodeResult node_result =
     const FindNodeResult node_result =
-        findNode(zone_data_, name, node_path, options);
+        findNode(zone_data_, LabelSequence(name), node_path, options);
     if (node_result.code != SUCCESS) {
     if (node_result.code != SUCCESS) {
         return (createFindResult(rrclass_, zone_data_, node_result.code,
         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;
     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,
         const RdataSet* nsec_rds = getClosestNSEC(zone_data_, node_path,
                                                   &nsec_node, options);
                                                   &nsec_node, options);
         return (createFindResult(rrclass_, zone_data_, NXRRSET,
         return (createFindResult(rrclass_, zone_data_, NXRRSET,
-                                 nsec_rds,
-                                 nsec_node,
-                                 wild));
+                                 nsec_rds, nsec_node, options, wild));
     }
     }
 
 
     const RdataSet* found;
     const RdataSet* found;
 
 
     // If the node callback is enabled, this may be a zone cut.  If it
     // 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.
     // 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) &&
     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());
         found = RdataSet::find(node->getData(), RRType::NS());
         if (found != NULL) {
         if (found != NULL) {
             LOG_DEBUG(logger, DBG_TRACE_DATA,
             LOG_DEBUG(logger, DBG_TRACE_DATA,
                       DATASRC_MEM_EXACT_DELEGATION).arg(name);
                       DATASRC_MEM_EXACT_DELEGATION).arg(name);
             return (createFindResult(rrclass_, zone_data_, DELEGATION,
             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();
         const RdataSet* cur_rds = node->getData();
         while (cur_rds != NULL) {
         while (cur_rds != NULL) {
             target->push_back(createTreeNodeRRset(node, cur_rds, rrclass_,
             target->push_back(createTreeNodeRRset(node, cur_rds, rrclass_,
-                                                  &name));
+                                                  options, &name));
             cur_rds = cur_rds->getNext();
             cur_rds = cur_rds->getNext();
         }
         }
         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ANY_SUCCESS).
             arg(name);
             arg(name);
         return (createFindResult(rrclass_, zone_data_, SUCCESS, NULL, node,
         return (createFindResult(rrclass_, zone_data_, SUCCESS, NULL, node,
-                                 wild, &name));
+                                 options, wild, &name));
     }
     }
 
 
     found = RdataSet::find(node->getData(), type);
     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).
         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_SUCCESS).arg(name).
             arg(type);
             arg(type);
         return (createFindResult(rrclass_, zone_data_, SUCCESS, found, node,
         return (createFindResult(rrclass_, zone_data_, SUCCESS, found, node,
-                                 wild, &name));
+                                 options, wild, &name));
     } else {
     } else {
         // Next, try CNAME.
         // Next, try CNAME.
         found = RdataSet::find(node->getData(), RRType::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);
             LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_CNAME).arg(name);
             return (createFindResult(rrclass_, zone_data_, CNAME, found, node,
             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.
     // No exact match or CNAME.  Get NSEC if necessary and return NXRRSET.
     return (createFindResult(rrclass_, zone_data_, NXRRSET,
     return (createFindResult(rrclass_, zone_data_, NXRRSET,
                              getNSECForNXRRSET(zone_data_, options, node),
                              getNSECForNXRRSET(zone_data_, options, node),
-                             node, wild, &name));
+                             node, options, wild, &name));
 }
 }
 
 
 isc::datasrc::ZoneFinder::FindNSEC3Result
 isc::datasrc::ZoneFinder::FindNSEC3Result
 InMemoryZoneFinder::findNSEC3(const isc::dns::Name& name, bool recursive) {
 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
 } // namespace memory

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

@@ -23,30 +23,15 @@
 #include <dns/rrset.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 #include <dns/rrtype.h>
 
 
+#include <string>
+
 namespace isc {
 namespace isc {
 namespace datasrc {
 namespace datasrc {
 namespace memory {
 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
 /// A derived zone finder class intended to be used with the memory data
 /// source, using ZoneData for its contents.
 /// source, using ZoneData for its contents.
@@ -92,16 +77,13 @@ public:
     findNSEC3(const isc::dns::Name& name, bool recursive);
     findNSEC3(const isc::dns::Name& name, bool recursive);
 
 
     /// \brief Returns the origin of the zone.
     /// \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.
     /// \brief Returns the RR class of the zone.
     virtual isc::dns::RRClass getClass() const {
     virtual isc::dns::RRClass getClass() const {
-        return rrclass_;
+        return (rrclass_);
     }
     }
 
 
-
 private:
 private:
     /// \brief In-memory version of finder context.
     /// \brief In-memory version of finder context.
     ///
     ///
@@ -110,7 +92,7 @@ private:
     class Context;
     class Context;
 
 
     /// Actual implementation for both find() and findAll()
     /// Actual implementation for both find() and findAll()
-    ZoneFinderResultContext find_internal(
+    internal::ZoneFinderResultContext find_internal(
         const isc::dns::Name& name,
         const isc::dns::Name& name,
         const isc::dns::RRType& type,
         const isc::dns::RRType& type,
         std::vector<isc::dns::ConstRRsetPtr>* target,
         std::vector<isc::dns::ConstRRsetPtr>* target,
@@ -118,7 +100,7 @@ private:
         FIND_DEFAULT);
         FIND_DEFAULT);
 
 
     const ZoneData& zone_data_;
     const ZoneData& zone_data_;
-    const isc::dns::RRClass& rrclass_;
+    const isc::dns::RRClass rrclass_;
 };
 };
 
 
 } // namespace memory
 } // 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_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
 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
 # The general tests
 run_unittests_SOURCES = $(common_sources)
 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 += test_client.h test_client.cc
 run_unittests_SOURCES += rbtree_unittest.cc
 run_unittests_SOURCES += rbtree_unittest.cc
 run_unittests_SOURCES += logger_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/newschema.sqlite3
 EXTRA_DIST += testdata/oldschema.sqlite3
 EXTRA_DIST += testdata/oldschema.sqlite3
 EXTRA_DIST += testdata/static.zone
 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
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 // PERFORMANCE OF THIS SOFTWARE.
 
 
+#include <util/memory_segment_local.h>
+
 #include <datasrc/client_list.h>
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
 #include <datasrc/client.h>
 #include <datasrc/iterator.h>
 #include <datasrc/iterator.h>
 #include <datasrc/data_source.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/rrclass.h>
 #include <dns/rrttl.h>
 #include <dns/rrttl.h>
@@ -28,6 +31,8 @@
 #include <fstream>
 #include <fstream>
 
 
 using namespace isc::datasrc;
 using namespace isc::datasrc;
+using isc::datasrc::memory::InMemoryClient;
+using isc::datasrc::memory::InMemoryZoneFinder;
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace boost;
 using namespace boost;
@@ -67,35 +72,47 @@ public:
     };
     };
     class Iterator : public ZoneIterator {
     class Iterator : public ZoneIterator {
     public:
     public:
-        Iterator(const Name& origin) :
+        Iterator(const Name& origin, bool include_ns) :
             origin_(origin),
             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
             // The RData here is bogus, but it is not used to anything. There
             // just needs to be some.
             // just needs to be some.
             soa_->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
             soa_->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
                                                Name::ROOT_NAME(),
                                                Name::ROOT_NAME(),
                                                0, 0, 0, 0, 0));
                                                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() {
         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 {
         virtual isc::dns::ConstRRsetPtr getSOA() const {
             return (soa_);
             return (soa_);
         }
         }
     private:
     private:
         const Name origin_;
         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.
     // 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) {
         for (const char** zone(zone_names); *zone; ++zone) {
             zones.insert(Name(*zone));
             zones.insert(Name(*zone));
         }
         }
@@ -105,7 +122,8 @@ public:
     MockDataSourceClient(const string& type,
     MockDataSourceClient(const string& type,
                          const ConstElementPtr& configuration) :
                          const ConstElementPtr& configuration) :
         type_(type),
         type_(type),
-        configuration_(configuration)
+        configuration_(configuration),
+        have_ns_(true), use_baditerator_(true)
     {
     {
         EXPECT_NE("MasterFiles", type) << "MasterFiles is a special case "
         EXPECT_NE("MasterFiles", type) << "MasterFiles is a special case "
             "and it never should be created as a data source client";
             "and it never should be created as a data source client";
@@ -146,23 +164,27 @@ public:
         isc_throw(isc::NotImplemented, "Not implemented");
         isc_throw(isc::NotImplemented, "Not implemented");
     }
     }
     virtual ZoneIteratorPtr getIterator(const Name& name, bool) const {
     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");
             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());
             return (ZoneIteratorPtr());
         } else {
         } else {
             FindResult result(findZone(name));
             FindResult result(findZone(name));
             if (result.code == isc::datasrc::result::SUCCESS) {
             if (result.code == isc::datasrc::result::SUCCESS) {
-                return (ZoneIteratorPtr(new Iterator(name)));
+                return (ZoneIteratorPtr(new Iterator(name, have_ns_)));
             } else {
             } else {
                 isc_throw(DataSourceError, "No such zone");
                 isc_throw(DataSourceError, "No such zone");
             }
             }
         }
         }
     }
     }
+    void disableNS() { have_ns_ = false; }
+    void disableBadIterator() { use_baditerator_ = false; }
     const string type_;
     const string type_;
     const ConstElementPtr configuration_;
     const ConstElementPtr configuration_;
 private:
 private:
     set<Name> zones;
     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 {
 class ListTest : public ::testing::Test {
 public:
 public:
     ListTest() :
     ListTest() :
+        rrclass_(RRClass::IN()),
         // The empty list corresponds to a list with no elements inside
         // The empty list corresponds to a list with no elements inside
-        list_(new TestedList(RRClass::IN())),
+        list_(new TestedList(rrclass_)),
         config_elem_(Element::fromJSON("["
         config_elem_(Element::fromJSON("["
             "{"
             "{"
             "   \"type\": \"test_type\","
             "   \"type\": \"test_type\","
@@ -238,28 +261,35 @@ public:
             shared_ptr<MockDataSourceClient>
             shared_ptr<MockDataSourceClient>
                 ds(new MockDataSourceClient(ds_zones[i]));
                 ds(new MockDataSourceClient(ds_zones[i]));
             ds_.push_back(ds);
             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.
     // Check the positive result is as we expect it.
     void positiveResult(const ClientList::FindResult& result,
     void positiveResult(const ClientList::FindResult& result,
@@ -331,6 +361,8 @@ public:
         EXPECT_EQ(cache, list_->getDataSources()[index].cache_ !=
         EXPECT_EQ(cache, list_->getDataSources()[index].cache_ !=
                   shared_ptr<InMemoryClient>());
                   shared_ptr<InMemoryClient>());
     }
     }
+    const RRClass rrclass_;
+    isc::util::MemorySegmentLocal mem_sgmt_;
     shared_ptr<TestedList> list_;
     shared_ptr<TestedList> list_;
     const ClientList::FindResult negative_result_;
     const ClientList::FindResult negative_result_;
     vector<shared_ptr<MockDataSourceClient> > ds_;
     vector<shared_ptr<MockDataSourceClient> > ds_;
@@ -815,39 +847,38 @@ TEST_F(ListTest, BadMasterFile) {
 // Test we can reload a zone
 // Test we can reload a zone
 TEST_F(ListTest, reloadSuccess) {
 TEST_F(ListTest, reloadSuccess) {
     list_->configure(config_elem_zones_, true);
     list_->configure(config_elem_zones_, true);
-    Name name("example.org");
+    const Name name("example.org");
     prepareCache(0, name);
     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,
     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(ConfigurableClientList::ZONE_RELOADED, list_->reload(name));
     EXPECT_EQ(ZoneFinder::SUCCESS,
     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.
 // The cache is not enabled. The load should be rejected.
 TEST_F(ListTest, reloadNotEnabled) {
 TEST_F(ListTest, reloadNotEnabled) {
     list_->configure(config_elem_zones_, false);
     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.
     // We put the cache in even when not enabled. This won't confuse the thing.
     prepareCache(0, name);
     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,
     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.
     // Now reload. It should reject it.
     EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, list_->reload(name));
     EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, list_->reload(name));
     // Nothing changed here
     // Nothing changed here
     EXPECT_EQ(ZoneFinder::NXRRSET,
     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 several cases when the zone does not exist
 TEST_F(ListTest, reloadNoSuchZone) {
 TEST_F(ListTest, reloadNoSuchZone) {
     list_->configure(config_elem_zones_, true);
     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
     // 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
     // reload method, as that one looks at the real state of things, not
     // at the configuration.
     // at the configuration.
@@ -867,27 +898,27 @@ TEST_F(ListTest, reloadNoSuchZone) {
               list_->find(Name("example.cz")).dsrc_client_);
               list_->find(Name("example.cz")).dsrc_client_);
     EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
     EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
               list_->find(Name("sub.example.com"), true).dsrc_client_);
               list_->find(Name("sub.example.com"), true).dsrc_client_);
-    // Not reloaded
+    // Not reloaded, so NS shouldn't be visible yet.
     EXPECT_EQ(ZoneFinder::NXRRSET,
     EXPECT_EQ(ZoneFinder::NXRRSET,
               list_->find(Name("example.com")).finder_->
               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
 // Check we gracefuly throw an exception when a zone disappeared in
 // the underlying data source when we want to reload it
 // the underlying data source when we want to reload it
 TEST_F(ListTest, reloadZoneGone) {
 TEST_F(ListTest, reloadZoneGone) {
     list_->configure(config_elem_, true);
     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
     // 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
     // and then the zone disappearing. We prefill the cache, so we can check
     // it.
     // it.
-    prepareCache(0, name, true);
-    // The zone contains something
+    prepareCache(0, name);
+    // The (cached) zone contains zone's SOA
     EXPECT_EQ(ZoneFinder::SUCCESS,
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
               list_->find(name).finder_->find(name, RRType::SOA())->code);
     // The zone is not there, so abort the reload.
     // The zone is not there, so abort the reload.
     EXPECT_THROW(list_->reload(name), DataSourceError);
     EXPECT_THROW(list_->reload(name), DataSourceError);
-    // The zone is not hurt.
+    // The (cached) zone is not hurt.
     EXPECT_EQ(ZoneFinder::SUCCESS,
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
               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.
 // The underlying data source throws. Check we don't modify the state.
 TEST_F(ListTest, reloadZoneThrow) {
 TEST_F(ListTest, reloadZoneThrow) {
     list_->configure(config_elem_zones_, true);
     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
     // The zone contains stuff now
     EXPECT_EQ(ZoneFinder::SUCCESS,
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
               list_->find(name).finder_->find(name, RRType::SOA())->code);
@@ -909,8 +940,8 @@ TEST_F(ListTest, reloadZoneThrow) {
 
 
 TEST_F(ListTest, reloadNullIterator) {
 TEST_F(ListTest, reloadNullIterator) {
     list_->configure(config_elem_zones_, true);
     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
     // The zone contains stuff now
     EXPECT_EQ(ZoneFinder::SUCCESS,
     EXPECT_EQ(ZoneFinder::SUCCESS,
               list_->find(name).finder_->find(name, RRType::SOA())->code);
               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";
             "00000000000000000000000000000000";
         map_[Name("largest.example.org")] =
         map_[Name("largest.example.org")] =
             "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
             "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 {
     virtual string calculate(const Name& name) const {
         const NSEC3HashMap::const_iterator found = map_.find(name);
         const NSEC3HashMap::const_iterator found = map_.find(name);
@@ -94,6 +105,12 @@ NSEC3Hash* TestNSEC3HashCreator::create(const rdata::generic::NSEC3&) const {
     return (new TestNSEC3Hash);
     return (new TestNSEC3Hash);
 }
 }
 
 
+NSEC3Hash* TestNSEC3HashCreator::create(uint8_t, uint16_t,
+                                        const uint8_t*, size_t) const
+{
+    return (new TestNSEC3Hash);
+}
+
 void
 void
 findNSEC3Check(bool expected_matched, uint8_t expected_labels,
 findNSEC3Check(bool expected_matched, uint8_t expected_labels,
                const string& expected_closest,
                const string& expected_closest,

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

@@ -57,11 +57,15 @@ class TestNSEC3HashCreator : public isc::dns::NSEC3HashCreator {
 private:
 private:
     class TestNSEC3Hash;
     class TestNSEC3Hash;
 public:
 public:
+    TestNSEC3HashCreator() {}
     virtual isc::dns::NSEC3Hash* create(const
     virtual isc::dns::NSEC3Hash* create(const
                                         isc::dns::rdata::generic::NSEC3PARAM&)
                                         isc::dns::rdata::generic::NSEC3PARAM&)
         const;
         const;
     virtual isc::dns::NSEC3Hash* create(const isc::dns::rdata::generic::NSEC3&)
     virtual isc::dns::NSEC3Hash* create(const isc::dns::rdata::generic::NSEC3&)
         const;
         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
 // 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_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 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/dns/libb10-dns++.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/libb10-util.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.
     // by default there should be no level in the chain.
     EXPECT_EQ(0, chain.getLevelCount());
     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
     // insert one node to the tree and find it.  there should be exactly
     // one level in the chain.
     // one level in the chain.
     TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_, true));
     TreeHolder tree_holder(mem_sgmt_, TestDomainTree::create(mem_sgmt_, true));
@@ -607,6 +611,11 @@ TEST_F(DomainTreeTest, chainLevel) {
               tree.find(node_name, &cdtnode, chain));
               tree.find(node_name, &cdtnode, chain));
     EXPECT_EQ(1, chain.getLevelCount());
     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
     // Check the name of the found node (should have '.' as both non-absolute
     // and absolute name
     // and absolute name
     EXPECT_EQ(".", cdtnode->getLabels().toText());
     EXPECT_EQ(".", cdtnode->getLabels().toText());
@@ -716,6 +725,48 @@ TEST_F(DomainTreeTest, getUpperNode) {
     EXPECT_EQ(static_cast<void*>(NULL), node);
     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) {
 TEST_F(DomainTreeTest, nextNode) {
     TestDomainTreeNodeChain node_path;
     TestDomainTreeNodeChain node_path;
     const TestDomainTreeNode* node = NULL;
     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) {
 TEST_F(DomainTreeTest, nextNodeError) {
     // Empty chain for nextNode() is invalid.
     // Empty chain for nextNode() is invalid.
     TestDomainTreeNodeChain chain;
     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.
     // should not result in any exceptions.
     client_->load(Name("example.org"),
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org.zone");
                   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) {
 TEST_F(MemoryClientTest, loadFromIterator) {
@@ -266,11 +271,33 @@ TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
 TEST_F(MemoryClientTest, loadNSEC3Signed) {
 TEST_F(MemoryClientTest, loadNSEC3Signed) {
     client_->load(Name("example.org"),
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org-nsec3-signed.zone");
                   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) {
 TEST_F(MemoryClientTest, loadNSEC3SignedNoParam) {
     client_->load(Name("example.org"),
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org-nsec3-signed-no-param.zone");
                   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) {
 TEST_F(MemoryClientTest, loadReloadZone) {
@@ -288,14 +315,12 @@ TEST_F(MemoryClientTest, loadReloadZone) {
                   client_->getFileName(Name("example.org")));
                   client_->getFileName(Name("example.org")));
     EXPECT_EQ(1, client_->getZoneCount());
     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 */
     /* Check SOA */
-    const ZoneNode* node = result.zone_data->getOriginNode();
+    const ZoneNode* node = zone_data->getOriginNode();
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
 
 
     const RdataSet* set = node->getData();
     const RdataSet* set = node->getData();
@@ -306,7 +331,7 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
 
     /* Check ns1.example.org */
     /* 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));
     ZoneTree::Result zresult(tree.find(Name("ns1.example.org"), &node));
     EXPECT_NE(ZoneTree::EXACTMATCH, zresult);
     EXPECT_NE(ZoneTree::EXACTMATCH, zresult);
 
 
@@ -316,14 +341,11 @@ TEST_F(MemoryClientTest, loadReloadZone) {
                   TEST_DATA_DIR "/example.org-rrsigs.zone");
                   TEST_DATA_DIR "/example.org-rrsigs.zone");
     EXPECT_EQ(1, client_->getZoneCount());
     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 */
     /* Check SOA */
-    node = result2.zone_data->getOriginNode();
+    node = zone_data->getOriginNode();
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
 
 
     set = node->getData();
     set = node->getData();
@@ -334,7 +356,7 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
 
     /* Check ns1.example.org */
     /* 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));
     ZoneTree::Result zresult2(tree2.find(Name("ns1.example.org"), &node));
     EXPECT_EQ(ZoneTree::EXACTMATCH, zresult2);
     EXPECT_EQ(ZoneTree::EXACTMATCH, zresult2);
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
@@ -702,30 +724,18 @@ TEST_F(MemoryClientTest, add) {
     EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
     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"),
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org-rrsigs.zone");
                   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 */
     /* Check SOA */
-    const ZoneNode* node = result2.zone_data->getOriginNode();
+    const ZoneNode* node = zone_data->getOriginNode();
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
 
 
     const RdataSet* set = node->getData();
     const RdataSet* set = node->getData();
@@ -736,7 +746,7 @@ TEST_F(MemoryClientTest, findZone2) {
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
 
 
     /* Check ns1.example.org */
     /* 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));
     ZoneTree::Result result3(tree.find(Name("ns1.example.org"), &node));
     EXPECT_EQ(ZoneTree::EXACTMATCH, result3);
     EXPECT_EQ(ZoneTree::EXACTMATCH, result3);
     EXPECT_NE(static_cast<const ZoneNode*>(NULL), node);
     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 datasrc{
 namespace memory {
 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-nsec3.zone
 EXTRA_DIST += example.org-multiple-nsec3param.zone
 EXTRA_DIST += example.org-multiple-nsec3param.zone
 EXTRA_DIST += example.org-multiple.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-fewer-labels.zone example.org-nsec3-more-labels.zone
 EXTRA_DIST += example.org-nsec3-signed-no-param.zone
 EXTRA_DIST += example.org-nsec3-signed-no-param.zone
 EXTRA_DIST += example.org-nsec3-signed.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 <gtest/gtest.h>
 
 
+#include <boost/bind.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 
 
 #include <string>
 #include <string>
@@ -137,11 +138,22 @@ protected:
     RdataSet* wildcard_rdataset_; // for wildcard (type doesn't matter much)
     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
 // Check some trivial fields of a constructed TreeNodeRRset (passed as
 // AbstractRRset as we'd normally use it in polymorphic way).
 // AbstractRRset as we'd normally use it in polymorphic way).
 // Other complicated fields are checked through rendering tests.
 // Other complicated fields are checked through rendering tests.
 void
 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 RRClass& expected_class, const RRType& expected_type,
                  const uint32_t expected_ttl,
                  const uint32_t expected_ttl,
                  size_t expected_rdatacount, size_t expected_sigcount)
                  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(RRTTL(expected_ttl), actual_rrset.getTTL());
     EXPECT_EQ(expected_rdatacount, actual_rrset.getRdataCount());
     EXPECT_EQ(expected_rdatacount, actual_rrset.getRdataCount());
     EXPECT_EQ(expected_sigcount, actual_rrset.getRRsigDataCount());
     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
 // 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) {
 TEST_F(TreeNodeRRsetTest, create) {
     // Constructed with RRSIG, and it should be visible.
     // Constructed with RRSIG, and it should be visible.
     checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, true),
     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.
     // Constructed with RRSIG, and it should be invisible.
     checkBasicFields(*createRRset(rrclass_, www_node_, a_rdataset_, false),
     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)
     // Constructed without RRSIG, and it would be visible (but of course won't)
     checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, true),
     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
     // Constructed without RRSIG, and it should be visible
     checkBasicFields(*createRRset(rrclass_, origin_node_, ns_rdataset_, false),
     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)
     // RRSIG-only case (note the RRset's type is covered type)
     checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
     checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
                                   true),
                                   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
     // RRSIG-only case (note the RRset's type is covered type), but it's
     // invisible
     // invisible
     checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
     checkBasicFields(*createRRset(rrclass_, www_node_, rrsig_only_rdataset_,
                                   false),
                                   false),
-                     www_name_, rrclass_, RRType::TXT(), 3600, 0, 0);
+                     rrsig_only_rdataset_, www_name_, rrclass_, RRType::TXT(),
+                     3600, 0, 0);
     // Wildcard substitution
     // Wildcard substitution
     checkBasicFields(*createRRset(match_name_, rrclass_,
     checkBasicFields(*createRRset(match_name_, rrclass_,
                                   wildcard_node_, wildcard_rdataset_,
                                   wildcard_node_, wildcard_rdataset_,
                                   true),
                                   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
 // 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.setName(Name("example")), isc::Unexpected);
     EXPECT_THROW(rrset.addRdata(createRdata(RRType::A(), rrclass_, "0.0.0.0")),
     EXPECT_THROW(rrset.addRdata(createRdata(RRType::A(), rrclass_, "0.0.0.0")),
                  isc::Unexpected);
                  isc::Unexpected);
-    EXPECT_THROW(rrset.getRRsig(), isc::Unexpected);
     RdataPtr sig_rdata = createRdata(
     RdataPtr sig_rdata = createRdata(
         RRType::RRSIG(), rrclass_,
         RRType::RRSIG(), rrclass_,
         "A 5 2 3600 20120814220826 20120715220826 5300 example.com. FAKE");
         "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 <gtest/gtest.h>
 
 
+#include <string>
+
 using namespace std;
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::dns::rdata;
@@ -46,74 +48,6 @@ namespace {
 using result::SUCCESS;
 using result::SUCCESS;
 using result::EXIST;
 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
 /// \brief expensive rrset converter
 ///
 ///
 /// converts any specialized rrset (which may not have implemented some
 /// 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 NS ns.example.org.", &rr_ns_},
             {"example.org. 300 IN A 192.0.2.1", &rr_a_},
             {"example.org. 300 IN A 192.0.2.1", &rr_a_},
             {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_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_},
             {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
             {"cname.example.org. 300 IN CNAME canonical.example.org",
             {"cname.example.org. 300 IN CNAME canonical.example.org",
              &rr_cname_},
              &rr_cname_},
@@ -255,18 +191,46 @@ public:
     }
     }
 
 
     // NSEC3-specific call for 'loading' data
     // NSEC3-specific call for 'loading' data
-    // This needs to be updated and checked when implementing #2118
     void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
     void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
         assert(rrset->getType() == RRType::NSEC3());
         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);
         zone_data_->setSigned(true);
     }
     }
@@ -312,6 +276,44 @@ public:
             }
             }
             name = name.split(1);
             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
     // Some data to test with
@@ -340,6 +342,7 @@ public:
         rr_ns_aaaa_,
         rr_ns_aaaa_,
         // A of example.org
         // A of example.org
         rr_a_;
         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_;         // CNAME in example.org (RDATA will be added)
     RRsetPtr rr_cname_a_; // for mixed CNAME + A case
     RRsetPtr rr_cname_a_; // for mixed CNAME + A case
     RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
     RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
@@ -369,12 +372,6 @@ public:
     RRsetPtr rr_ns_nsec_;
     RRsetPtr rr_ns_nsec_;
     RRsetPtr rr_wild_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.
      * \brief Test one find query to the zone finder.
      *
      *
@@ -435,9 +432,12 @@ public:
                         ConstRRsetPtr result_rrset(
                         ConstRRsetPtr result_rrset(
                             convertRRset(find_result->rrset));
                             convertRRset(find_result->rrset));
                         rrsetCheck(answer, result_rrset);
                         rrsetCheck(answer, result_rrset);
-                        if (answer_sig) {
+                        if (answer_sig &&
+                            (options & ZoneFinder::FIND_DNSSEC) != 0) {
                             ASSERT_TRUE(result_rrset->getRRsig());
                             ASSERT_TRUE(result_rrset->getRRsig());
                             rrsetCheck(answer_sig, result_rrset->getRRsig());
                             rrsetCheck(answer_sig, result_rrset->getRRsig());
+                        } else {
+                            EXPECT_FALSE(result_rrset->getRRsig());
                         }
                         }
                     }
                     }
                 } else if (check_wild_answer) {
                 } else if (check_wild_answer) {
@@ -527,6 +527,13 @@ public:
  */
  */
 TEST_F(InMemoryZoneFinderTest, constructor) {
 TEST_F(InMemoryZoneFinderTest, constructor) {
     ASSERT_EQ(origin_, zone_finder_.getOrigin());
     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) {
 TEST_F(InMemoryZoneFinderTest, findCNAME) {
@@ -684,6 +691,9 @@ TEST_F(InMemoryZoneFinderTest, glue) {
     EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
     EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
     // glue under the deeper zone cut
     // glue under the deeper zone cut
     EXPECT_NO_THROW(addZoneData(rr_grandchild_glue_));
     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
     // by default glue is hidden due to the zone cut
     findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
     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(),
     findTest(Name("www.grand.child.example.org"), RRType::TXT(),
              ZoneFinder::DELEGATION, true, rr_child_ns_,
              ZoneFinder::DELEGATION, true, rr_child_ns_,
              ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
              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
     // Fill some data inside
     // Now put all the data we have there. It should throw nothing
     // 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_));
     EXPECT_NO_THROW(addZoneData(rr_ns_a_));
     EXPECT_NO_THROW(addZoneData(rr_ns_a_));
     EXPECT_NO_THROW(addZoneData(rr_ns_aaaa_));
     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,
     findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
              rr_ns_a_);
              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
     // 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
     // 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
     // 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.
     // 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),
     // If the zone has nothing about NSEC3 (neither NSEC3 or NSEC3PARAM),
     // findNSEC3() should be rejected.
     // findNSEC3() should be rejected.
@@ -1478,4 +1478,127 @@ TEST_F(InMemoryZoneFinderTest, DISABLED_findNSEC3ForBadZone) {
                  DataSourceError);
                  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;
     ++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
 /// \brief Test fixture for the InMemoryZoneFinder class
 class InMemoryZoneFinderTest : public ::testing::Test {
 class InMemoryZoneFinderTest : public ::testing::Test {
     // A straightforward pair of textual RR(set) and a RRsetPtr variable
     // 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.
 ;; test zone file used for ZoneFinderContext tests.
 ;; RRSIGs are (obviouslly) faked ones for testing.
 ;; 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	ns1.example.org.
 example.org.			      3600 IN NS	ns2.example.org.
 example.org.			      3600 IN NS	ns2.example.org.
 example.org.			      3600 IN MX	1 mx1.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
 ;; expansion
 *.wildmx.example.org. 3600 IN MX 1 mx1.example.org.
 *.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
 ;; CNAME
 alias.example.org. 3600 IN CNAME cname.example.org.
 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 <exceptions/exceptions.h>
 
 
+#include <util/memory_segment_local.h>
+
 #include <dns/masterload.h>
 #include <dns/masterload.h>
 #include <dns/name.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <dns/rrclass.h>
 
 
 #include <datasrc/zone.h>
 #include <datasrc/zone.h>
-#include <datasrc/memory_datasrc.h>
+#include <datasrc/memory/memory_client.h>
 #include <datasrc/database.h>
 #include <datasrc/database.h>
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/sqlite3_accessor.h>
 
 
@@ -39,8 +41,10 @@
 using namespace std;
 using namespace std;
 using boost::shared_ptr;
 using boost::shared_ptr;
 
 
+using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::datasrc;
 using namespace isc::datasrc;
+using isc::datasrc::memory::InMemoryClient;
 using namespace isc::testutils;
 using namespace isc::testutils;
 
 
 namespace {
 namespace {
@@ -54,18 +58,16 @@ typedef shared_ptr<DataSourceClient> DataSourceClientPtr;
 // This is the type used as the test parameter.  Note that this is
 // 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;
 // intentionally a plain old type (i.e. a function pointer), not a class;
 // otherwise it could cause initialization fiasco at the instantiation time.
 // 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
 // Creator for the in-memory client to be tested
 DataSourceClientPtr
 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);
     return (client);
 }
 }
@@ -76,7 +78,7 @@ addRRset(ZoneUpdaterPtr updater, ConstRRsetPtr rrset) {
 }
 }
 
 
 DataSourceClientPtr
 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
     // 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
     // the zone data from the zone file to ensure both cases have the
     // same test data.
     // same test data.
@@ -103,7 +105,7 @@ class ZoneFinderContextTest :
 {
 {
 protected:
 protected:
     ZoneFinderContextTest() : qclass_(RRClass::IN()), qzone_("example.org") {
     ZoneFinderContextTest() : qclass_(RRClass::IN()), qzone_("example.org") {
-        client_ = (*GetParam())(qclass_, qzone_);
+        client_ = (*GetParam())(mem_sgmt_, qclass_, qzone_);
         REQUESTED_A.push_back(RRType::A());
         REQUESTED_A.push_back(RRType::A());
         REQUESTED_AAAA.push_back(RRType::AAAA());
         REQUESTED_AAAA.push_back(RRType::AAAA());
         REQUESTED_BOTH.push_back(RRType::A());
         REQUESTED_BOTH.push_back(RRType::A());
@@ -114,6 +116,7 @@ protected:
         ASSERT_TRUE(finder_);
         ASSERT_TRUE(finder_);
     }
     }
 
 
+    MemorySegmentLocal mem_sgmt_;
     const RRClass qclass_;
     const RRClass qclass_;
     const Name qzone_;
     const Name qzone_;
     DataSourceClientPtr client_;
     DataSourceClientPtr client_;
@@ -232,6 +235,18 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithDname) {
                 result_sets_.begin(), result_sets_.end());
                 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) {
 TEST_P(ZoneFinderContextTest, getAdditionalDelegationWithEmptyName) {
     // One of NS names is at an empty non terminal node.  It shouldn't cause
     // One of NS names is at an empty non terminal node.  It shouldn't cause
     // any disruption.
     // any disruption.

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

@@ -122,8 +122,6 @@ IfaceMgr::IfaceMgr()
      session_socket_(INVALID_SOCKET), session_callback_(NULL)
      session_socket_(INVALID_SOCKET), session_callback_(NULL)
 {
 {
 
 
-    cout << "IfaceMgr initialization." << endl;
-
     try {
     try {
         // required for sending/receiving packets
         // required for sending/receiving packets
         // let's keep it in front, just in case someone
         // let's keep it in front, just in case someone
@@ -134,13 +132,7 @@ IfaceMgr::IfaceMgr()
         detectIfaces();
         detectIfaces();
 
 
     } catch (const std::exception& ex) {
     } 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
     // is faked by detecting loopback interface (lo or lo0). It will eventually
     // be removed once we have actual implementations for all supported systems.
     // 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) {
 bool IfaceMgr::openSockets4(const uint16_t port) {
@@ -221,13 +196,9 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
          iface != ifaces_.end();
          iface != ifaces_.end();
          ++iface) {
          ++iface) {
 
 
-        cout << "Trying opening socket on interface " << iface->getFullName() << endl;
-
         if (iface->flag_loopback_ ||
         if (iface->flag_loopback_ ||
             !iface->flag_up_ ||
             !iface->flag_up_ ||
             !iface->flag_running_) {
             !iface->flag_running_) {
-            cout << "Interface " << iface->getFullName()
-                 << " not suitable: is loopback, is down or not running" << endl;
             continue;
             continue;
         }
         }
 
 
@@ -243,15 +214,13 @@ bool IfaceMgr::openSockets4(const uint16_t port) {
 
 
             sock = openSocket(iface->getName(), *addr, port);
             sock = openSocket(iface->getName(), *addr, port);
             if (sock < 0) {
             if (sock < 0) {
-                cout << "Failed to open unicast socket." << endl;
-                return (false);
+                isc_throw(SocketConfigError, "failed to open unicast socket");
             }
             }
 
 
             count++;
             count++;
         }
         }
     }
     }
     return (count > 0);
     return (count > 0);
-
 }
 }
 
 
 bool IfaceMgr::openSockets6(const uint16_t port) {
 bool IfaceMgr::openSockets6(const uint16_t port) {
@@ -280,8 +249,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
 
 
             sock = openSocket(iface->getName(), *addr, port);
             sock = openSocket(iface->getName(), *addr, port);
             if (sock < 0) {
             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
             // 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(),
             if ( !joinMulticast(sock, iface->getName(),
                                 string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS))) {
                                 string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS))) {
                 close(sock);
                 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.");
                           << " multicast group.");
             }
             }
 
 
@@ -305,7 +274,7 @@ bool IfaceMgr::openSockets6(const uint16_t port) {
                                    IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
                                    IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
                                    port);
                                    port);
             if (sock2 < 0) {
             if (sock2 < 0) {
-                isc_throw(Unexpected, "Failed to open multicast socket on "
+                isc_throw(SocketConfigError, "Failed to open multicast socket on "
                           << " interface " << iface->getFullName());
                           << " interface " << iface->getFullName());
                 iface->delSocket(sock); // delete previously opened socket
                 iface->delSocket(sock); // delete previously opened socket
             }
             }
@@ -418,7 +387,7 @@ int IfaceMgr::openSocketFromIface(const std::string& ifname,
                 family_name = "AF_INET6";
                 family_name = "AF_INET6";
             }
             }
             // We did not find address on the interface.
             // 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 "
                       << ifname << ", port: " << port << ", address "
                       " family: " << family_name);
                       " family: " << family_name);
         }
         }
@@ -460,9 +429,13 @@ int IfaceMgr::openSocketFromAddress(const IOAddress& addr,
 
 
 int IfaceMgr::openSocketFromRemoteAddress(const IOAddress& remote_addr,
 int IfaceMgr::openSocketFromRemoteAddress(const IOAddress& remote_addr,
                                           const uint16_t port) {
                                           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
 isc::asiolink::IOAddress
@@ -506,7 +479,7 @@ IfaceMgr::getLocalAddress(const IOAddress& remote_addr, const uint16_t port) {
     sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
     sock.connect(remote_endpoint->getASIOEndpoint(), err_code);
     if (err_code) {
     if (err_code) {
         sock.close();
         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.
     // 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) {
 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;
     struct sockaddr_in addr4;
     memset(&addr4, 0, sizeof(sockaddr));
     memset(&addr4, 0, sizeof(sockaddr));
     addr4.sin_family = AF_INET;
     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);
     int sock = socket(AF_INET, SOCK_DGRAM, 0);
     if (sock < 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) {
     if (bind(sock, (struct sockaddr *)&addr4, sizeof(addr4)) < 0) {
         close(sock);
         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);
                   << "/port=" << port);
     }
     }
 
 
@@ -552,13 +522,10 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
     int flag = 1;
     int flag = 1;
     if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
     if (setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &flag, sizeof(flag)) != 0) {
         close(sock);
         close(sock);
-        isc_throw(Unexpected, "setsockopt: IP_PKTINFO: failed.");
+        isc_throw(SocketConfigError, "setsockopt: IP_PKTINFO: failed.");
     }
     }
 #endif
 #endif
 
 
-    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
-        addr.toText() << "/port=" << port << endl;
-
     SocketInfo info(sock, addr, port);
     SocketInfo info(sock, addr, port);
     iface.addSocket(info);
     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) {
 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;
     struct sockaddr_in6 addr6;
     memset(&addr6, 0, sizeof(addr6));
     memset(&addr6, 0, sizeof(addr6));
     addr6.sin6_family = AF_INET6;
     addr6.sin6_family = AF_INET6;
@@ -590,7 +554,7 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
     // make a socket
     // make a socket
     int sock = socket(AF_INET6, SOCK_DGRAM, 0);
     int sock = socket(AF_INET6, SOCK_DGRAM, 0);
     if (sock < 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
     // 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,
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *)&flag, sizeof(flag)) < 0) {
                    (char *)&flag, sizeof(flag)) < 0) {
         close(sock);
         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) {
     if (bind(sock, (struct sockaddr *)&addr6, sizeof(addr6)) < 0) {
         close(sock);
         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);
                   << "/port=" << port);
     }
     }
 #ifdef IPV6_RECVPKTINFO
 #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,
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                    &flag, sizeof(flag)) != 0) {
                    &flag, sizeof(flag)) != 0) {
         close(sock);
         close(sock);
-        isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
+        isc_throw(SocketConfigError, "setsockopt: IPV6_RECVPKTINFO failed.");
     }
     }
 #else
 #else
     // RFC2292 - an old way
     // RFC2292 - an old way
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
                    &flag, sizeof(flag)) != 0) {
                    &flag, sizeof(flag)) != 0) {
         close(sock);
         close(sock);
-        isc_throw(Unexpected, "setsockopt: IPV6_PKTINFO: failed.");
+        isc_throw(SocketConfigError, "setsockopt: IPV6_PKTINFO: failed.");
     }
     }
 #endif
 #endif
 
 
@@ -632,14 +596,11 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
         if ( !joinMulticast( sock, iface.getName(),
         if ( !joinMulticast( sock, iface.getName(),
                          string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
                          string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
             close(sock);
             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.");
                       << " multicast group.");
         }
         }
     }
     }
 
 
-    cout << "Created socket " << sock << " on " << iface.getName() << "/" <<
-        addr.toText() << "/port=" << port << endl;
-
     SocketInfo info(sock, addr, port);
     SocketInfo info(sock, addr, port);
     iface.addSocket(info);
     iface.addSocket(info);
 
 
@@ -654,20 +615,15 @@ const std::string & mcast) {
 
 
     if (inet_pton(AF_INET6, mcast.c_str(),
     if (inet_pton(AF_INET6, mcast.c_str(),
                   &mreq.ipv6mr_multiaddr) <= 0) {
                   &mreq.ipv6mr_multiaddr) <= 0) {
-        cout << "Failed to convert " << ifname
-             << " to IPv6 multicast address." << endl;
         return (false);
         return (false);
     }
     }
 
 
     mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
     mreq.ipv6mr_interface = if_nametoindex(ifname.c_str());
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                    &mreq, sizeof(mreq)) < 0) {
                    &mreq, sizeof(mreq)) < 0) {
-        cout << "Failed to join " << mcast << " multicast group." << endl;
         return (false);
         return (false);
     }
     }
 
 
-    cout << "Joined multicast " << mcast << " group." << endl;
-
     return (true);
     return (true);
 }
 }
 
 
@@ -746,13 +702,8 @@ IfaceMgr::send(const Pkt6Ptr& pkt) {
 
 
     result = sendmsg(getSocket(*pkt), &m, 0);
     result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 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);
     return (result);
 }
 }
@@ -797,24 +748,13 @@ IfaceMgr::send(const Pkt4Ptr& pkt)
     // call OS-specific routines (like setting interface index)
     // call OS-specific routines (like setting interface index)
     os_send4(m, control_buf_, control_buf_len_, pkt);
     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();
     pkt->updateTimestamp();
 
 
     int result = sendmsg(getSocket(*pkt), &m, 0);
     int result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 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);
     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_sec = timeout_sec;
     select_timeout.tv_usec = timeout_usec;
     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);
     int result = select(maxfd + 1, &sockets, NULL, NULL, &select_timeout);
-    cout << "select returned " << result << endl;
 
 
     if (result == 0) {
     if (result == 0) {
         // nothing received and timeout has been reached
         // nothing received and timeout has been reached
         return (Pkt4Ptr()); // NULL
         return (Pkt4Ptr()); // NULL
     } else if (result < 0) {
     } 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
     // Let's find out which socket has the data
     if ((session_socket_ != INVALID_SOCKET) && (FD_ISSET(session_socket_, &sockets))) {
     if ((session_socket_ != INVALID_SOCKET) && (FD_ISSET(session_socket_, &sockets))) {
         // something received over session socket
         // something received over session socket
-        cout << "BIND10 command or config available over session socket." << endl;
-
         if (session_callback_) {
         if (session_callback_) {
             // in theory we could call io_service.run_one() here, instead of
             // in theory we could call io_service.run_one() here, instead of
             // implementing callback mechanism, but that would introduce
             // implementing callback mechanism, but that would introduce
@@ -918,14 +849,9 @@ IfaceMgr::receive4(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) {
     }
     }
 
 
     if (!candidate) {
     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!
     // Now we have a socket, let's get some data from it!
     struct sockaddr_in from_addr;
     struct sockaddr_in from_addr;
     uint8_t buf[RCVBUFSIZE];
     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);
     result = recvmsg(candidate->sockfd_, &m, 0);
     if (result < 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.
     // 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_);
     pkt->setLocalPort(candidate->port_);
 
 
     if (!os_receive4(m, pkt)) {
     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);
     return (pkt);
 }
 }
 
 
@@ -1039,10 +958,6 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
         names << session_socket_ << "(session)";
         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;
     struct timeval select_timeout;
     select_timeout.tv_sec = timeout_sec;
     select_timeout.tv_sec = timeout_sec;
     select_timeout.tv_usec = timeout_usec;
     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
         // nothing received and timeout has been reached
         return (Pkt6Ptr()); // NULL
         return (Pkt6Ptr()); // NULL
     } else if (result < 0) {
     } 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
     // Let's find out which socket has the data
     if ((session_socket_ != INVALID_SOCKET) && (FD_ISSET(session_socket_, &sockets))) {
     if ((session_socket_ != INVALID_SOCKET) && (FD_ISSET(session_socket_, &sockets))) {
         // something received over session socket
         // something received over session socket
-        cout << "BIND10 command or config available over session socket." << endl;
-
         if (session_callback_) {
         if (session_callback_) {
             // in theory we could call io_service.run_one() here, instead of
             // in theory we could call io_service.run_one() here, instead of
             // implementing callback mechanism, but that would introduce
             // 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) {
     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!
     // Now we have a socket, let's get some data from it!
     uint8_t buf[RCVBUFSIZE];
     uint8_t buf[RCVBUFSIZE];
     memset(&control_buf_[0], 0, control_buf_len_);
     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);
             cmsg = CMSG_NXTHDR(&m, cmsg);
         }
         }
         if (!found_pktinfo) {
         if (!found_pktinfo) {
-            cout << "Unable to find pktinfo" << endl;
-            return (Pkt6Ptr()); // NULL
+            isc_throw(SocketReadError, "unable to find pktinfo");
         }
         }
     } else {
     } else {
-        cout << "Failed to receive data." << endl;
-        return (Pkt6Ptr()); // NULL
+        isc_throw(SocketReadError, "failed to receive data");
     }
     }
 
 
     // Let's create a packet.
     // Let's create a packet.
@@ -1176,8 +1079,7 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
     try {
     try {
         pkt = Pkt6Ptr(new Pkt6(buf, result));
         pkt = Pkt6Ptr(new Pkt6(buf, result));
     } catch (const std::exception& ex) {
     } 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();
     pkt->updateTimestamp();
@@ -1193,18 +1095,10 @@ Pkt6Ptr IfaceMgr::receive6(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */
     if (received) {
     if (received) {
         pkt->setIface(received->getName());
         pkt->setIface(received->getName());
     } else {
     } 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);
     return (pkt);
 }
 }
 
 

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

@@ -28,6 +28,38 @@
 namespace isc {
 namespace isc {
 
 
 namespace dhcp {
 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
 /// @brief handles network interfaces, transmission and reception
 ///
 ///
 /// IfaceMgr is an interface manager class that detects available network
 /// IfaceMgr is an interface manager class that detects available network
@@ -340,6 +372,8 @@ public:
     ///
     ///
     /// @param pkt packet to be sent
     /// @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
     /// @return true if sending was successful
     bool send(const Pkt6Ptr& pkt);
     bool send(const Pkt6Ptr& pkt);
 
 
@@ -351,6 +385,8 @@ public:
     ///
     ///
     /// @param pkt a packet to be sent
     /// @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
     /// @return true if sending was successful
     bool send(const Pkt4Ptr& pkt);
     bool send(const Pkt4Ptr& pkt);
 
 
@@ -369,6 +405,7 @@ public:
     /// (in microseconds)
     /// (in microseconds)
     ///
     ///
     /// @throw isc::BadValue if timeout_usec is greater than one million
     /// @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)
     /// @return Pkt6 object representing received packet (or NULL)
     Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
     Pkt6Ptr receive6(uint32_t timeout_sec, uint32_t timeout_usec = 0);
 
 
@@ -383,6 +420,7 @@ public:
     /// (in microseconds)
     /// (in microseconds)
     ///
     ///
     /// @throw isc::BadValue if timeout_usec is greater than one million
     /// @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)
     /// @return Pkt4 object representing received packet (or NULL)
     Pkt4Ptr receive4(uint32_t timeout_sec, uint32_t timeout_usec = 0);
     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)
     /// @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
     /// @return true if any sockets were open
     bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT);
     bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT);
 
 
@@ -472,6 +511,7 @@ public:
     ///
     ///
     /// @param port specifies port number (usually DHCP4_SERVER_PORT)
     /// @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
     /// @return true if any sockets were open
     bool openSockets4(const uint16_t port = DHCP4_SERVER_PORT);
     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
 /// Uses the socket-based netlink protocol to retrieve the list of interfaces
 /// from the Linux kernel.
 /// from the Linux kernel.
 void IfaceMgr::detectIfaces() {
 void IfaceMgr::detectIfaces() {
-    cout << "Linux: detecting interfaces." << endl;
-
     // Copies of netlink messages about links will be stored here.
     // Copies of netlink messages about links will be stored here.
     Netlink::NetlinkMessages link_info;
     Netlink::NetlinkMessages link_info;
 
 
@@ -495,8 +493,6 @@ void IfaceMgr::detectIfaces() {
 
 
     nl.release_list(link_info);
     nl.release_list(link_info);
     nl.release_list(addr_info);
     nl.release_list(addr_info);
-
-    printIfaces();
 }
 }
 
 
 /// @brief sets flag_*_ fields.
 /// @brief sets flag_*_ fields.
@@ -558,10 +554,7 @@ bool IfaceMgr::os_receive4(struct msghdr& m, Pkt4Ptr& pkt) {
             // broadcast. This will return broadcast address, not
             // broadcast. This will return broadcast address, not
             // the address we are bound to.
             // 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;
             // to_addr = pktinfo->ipi_spec_dst;
         }
         }
         cmsg = CMSG_NXTHDR(&m, cmsg);
         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;
         offset += 2;
 
 
         if (offset + opt_len > end) {
         if (offset + opt_len > end) {
-            cout << "Option " << opt_type << " truncated." << endl;
+            // @todo: consider throwing exception here.
             return (offset);
             return (offset);
         }
         }
         OptionPtr opt;
         OptionPtr opt;
         switch (opt_type) {
         switch (opt_type) {
         case D6O_IA_NA:
         case D6O_IA_NA:
         case D6O_IA_PD:
         case D6O_IA_PD:
-            // cout << "Creating Option6IA" << endl;
             opt = OptionPtr(new Option6IA(opt_type,
             opt = OptionPtr(new Option6IA(opt_type,
                                           buf.begin() + offset,
                                           buf.begin() + offset,
                                           buf.begin() + offset + opt_len));
                                           buf.begin() + offset + opt_len));
             break;
             break;
         case D6O_IAADDR:
         case D6O_IAADDR:
-            // cout << "Creating Option6IAAddr" << endl;
             opt = OptionPtr(new Option6IAAddr(opt_type,
             opt = OptionPtr(new Option6IAAddr(opt_type,
                                               buf.begin() + offset,
                                               buf.begin() + offset,
                                               buf.begin() + offset + opt_len));
                                               buf.begin() + offset + opt_len));
             break;
             break;
         default:
         default:
-            // cout << "Creating Option" << endl;
             opt = OptionPtr(new Option(Option::V6,
             opt = OptionPtr(new Option(Option::V6,
                                        opt_type,
                                        opt_type,
                                        buf.begin() + offset,
                                        buf.begin() + offset,
@@ -151,15 +148,9 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
 
 
 void LibDHCP::packOptions6(isc::util::OutputBuffer &buf,
 void LibDHCP::packOptions6(isc::util::OutputBuffer &buf,
                            const isc::dhcp::Option::OptionCollection& options) {
                            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() {
 void Pkt4::repack() {
-    cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;
-
     bufferOut_.writeData(&data_[0], data_.size());
     bufferOut_.writeData(&data_[0], data_.size());
 }
 }
 
 

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

@@ -100,7 +100,7 @@ Pkt6::packUDP() {
         LibDHCP::packOptions6(bufferOut_, options_);
         LibDHCP::packOptions6(bufferOut_, options_);
     }
     }
     catch (const Exception& e) {
     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 (false);
     }
     }
     return (true);
     return (true);
@@ -129,8 +129,8 @@ Pkt6::unpack() {
 bool
 bool
 Pkt6::unpackUDP() {
 Pkt6::unpackUDP() {
     if (data_.size() < 4) {
     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);
         return (false);
     }
     }
     msg_type_ = data_[0];
     msg_type_ = data_[0];
@@ -143,7 +143,7 @@ Pkt6::unpackUDP() {
 
 
         LibDHCP::unpackOptions6(opt_buffer, options_);
         LibDHCP::unpackOptions6(opt_buffer, options_);
     } catch (const Exception& e) {
     } 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 (false);
     }
     }
     return (true);
     return (true);
@@ -197,8 +197,6 @@ Pkt6::delOption(uint16_t type) {
 }
 }
 
 
 void Pkt6::repack() {
 void Pkt6::repack() {
-    cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;
-
     bufferOut_.writeData(&data_[0], data_.size());
     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
     // it will go away as soon as proper interface detection
     // is implemented
     // is implemented
     if (if_nametoindex("lo") > 0) {
     if (if_nametoindex("lo") > 0) {
-        cout << "This is Linux, using lo as loopback." << endl;
         snprintf(LOOPBACK, BUF_SIZE - 1, "lo");
         snprintf(LOOPBACK, BUF_SIZE - 1, "lo");
     } else if (if_nametoindex("lo0") > 0) {
     } else if (if_nametoindex("lo0") > 0) {
-        cout << "This is BSD, using lo0 as loopback." << endl;
         snprintf(LOOPBACK, BUF_SIZE - 1, "lo0");
         snprintf(LOOPBACK, BUF_SIZE - 1, "lo0");
     } else {
     } else {
         cout << "Failed to detect loopback interface. Neither "
         cout << "Failed to detect loopback interface. Neither "
@@ -421,7 +419,7 @@ TEST_F(IfaceMgrTest, sockets6) {
     // testing socket operation in a portable way is tricky
     // testing socket operation in a portable way is tricky
     // without interface detection implemented
     // without interface detection implemented
 
 
-    NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
+    boost::scoped_ptr<NakedIfaceMgr> ifacemgr(new NakedIfaceMgr());
 
 
     IOAddress loAddr("::1");
     IOAddress loAddr("::1");
 
 
@@ -441,10 +439,25 @@ TEST_F(IfaceMgrTest, sockets6) {
     // removed code for binding socket twice to the same address/port
     // removed code for binding socket twice to the same address/port
     // as it caused problems on some platforms (e.g. Mac OS X)
     // 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) {
 TEST_F(IfaceMgrTest, socketsFromIface) {
@@ -468,6 +481,18 @@ TEST_F(IfaceMgrTest, socketsFromIface) {
     EXPECT_GT(socket2, 0);
     EXPECT_GT(socket2, 0);
     close(socket2);
     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
     // socket descriptor must be positive integer
     EXPECT_GT(socket1, 0);
     EXPECT_GT(socket1, 0);
-    close(socket1);
 
 
     // Open v4 socket on loopback interface and bind to different port
     // Open v4 socket on loopback interface and bind to different port
     int socket2 = 0;
     int socket2 = 0;
@@ -492,7 +516,19 @@ TEST_F(IfaceMgrTest, socketsFromAddress) {
     );
     );
     // socket descriptor must be positive integer
     // socket descriptor must be positive integer
     EXPECT_GT(socket2, 0);
     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) {
 TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
@@ -507,7 +543,6 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
         socket1 = ifacemgr->openSocketFromRemoteAddress(loAddr6, PORT1);
         socket1 = ifacemgr->openSocketFromRemoteAddress(loAddr6, PORT1);
     );
     );
     EXPECT_GT(socket1, 0);
     EXPECT_GT(socket1, 0);
-    close(socket1);
 
 
     // Open v4 socket to connect to remote address.
     // Open v4 socket to connect to remote address.
     int socket2 = 0;
     int socket2 = 0;
@@ -516,7 +551,10 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
         socket2 = ifacemgr->openSocketFromRemoteAddress(loAddr, PORT2);
         socket2 = ifacemgr->openSocketFromRemoteAddress(loAddr, PORT2);
     );
     );
     EXPECT_GT(socket2, 0);
     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
     // The following test is currently disabled for OSes other than
     // Linux because interface detection is not implemented on them.
     // Linux because interface detection is not implemented on them.
@@ -530,8 +568,10 @@ TEST_F(IfaceMgrTest, socketsFromRemoteAddress) {
         socket3 = ifacemgr->openSocketFromRemoteAddress(bcastAddr, PORT2);
         socket3 = ifacemgr->openSocketFromRemoteAddress(bcastAddr, PORT2);
     );
     );
     EXPECT_GT(socket3, 0);
     EXPECT_GT(socket3, 0);
-    close(socket3);
 #endif
 #endif
+
+    // Do not call closeSockets() because it is called by IfaceMgr's
+    // virtual destructor.
 }
 }
 
 
 // TODO: disabled due to other naming on various systems
 // 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
     // testing socket operation in a portable way is tricky
     // without interface detection implemented
     // 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
     // let's assume that every supported OS have lo interface
     IOAddress loAddr("::1");
     IOAddress loAddr("::1");
@@ -619,7 +659,11 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     // we should accept both values as source ports.
     // we should accept both values as source ports.
     EXPECT_TRUE((rcvPkt->getRemotePort() == 10546) || (rcvPkt->getRemotePort() == 10547));
     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) {
 TEST_F(IfaceMgrTest, sendReceive4) {
@@ -627,7 +671,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
     // testing socket operation in a portable way is tricky
     // testing socket operation in a portable way is tricky
     // without interface detection implemented
     // 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
     // let's assume that every supported OS have lo interface
     IOAddress loAddr("127.0.0.1");
     IOAddress loAddr("127.0.0.1");
@@ -675,8 +719,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
 
 
     EXPECT_EQ(true, ifacemgr->send(sendPkt));
     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_TRUE(rcvPkt); // received our own packet
 
 
     ASSERT_NO_THROW(
     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
     // assume the one or the other will always be choosen for sending data. We should
     // skip checking source port of sent address.
     // 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));
     EXPECT_NO_THROW(ifacemgr->set_session_socket(pipefd[0], my_callback));
 
 
     Pkt4Ptr pkt4;
     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)
     // Our callback should not be called this time (there was no data)
     EXPECT_FALSE(callback_ok);
     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));
     EXPECT_EQ(38, write(pipefd[1], "Hi, this is a message sent over a pipe", 38));
 
 
     // ... and repeat
     // ... and repeat
-    pkt4 = ifacemgr->receive4(1);
+    ASSERT_NO_THROW(pkt4 = ifacemgr->receive4(1));
 
 
     // IfaceMgr should not process control socket data as incoming packets
     // IfaceMgr should not process control socket data as incoming packets
     EXPECT_FALSE(pkt4);
     EXPECT_FALSE(pkt4);

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


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