BIND 10 master, updated. 83d00dc305a33e69e4bee379895697742a1eaab7 Merge branch 'master' into trac2268
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Oct 16 01:29:20 UTC 2012
The branch, master has been updated
via 83d00dc305a33e69e4bee379895697742a1eaab7 (commit)
via 66524e1594263bb19fd73660fef31f4e49dbe81d (commit)
via 0e2c14089b820cbb0bdef6e813042992896375bc (commit)
via 45f0d1f2e771efaf7ca21e7f0450626847e75d90 (commit)
via 31d092681cc44a6d742474090430c7ddba3f81e6 (commit)
via 3744e7a8584a1c51bc5163751975af8e297c53c5 (commit)
via e93e6f3873ca08ae835dfd883c36f19b42df247f (commit)
via 0e1a1b2ee0fc9a3a510d348d5449a825779c03b2 (commit)
via e2b120a2e016f249eabaf7753b97a79ece0bffa1 (commit)
via 1e6d2102d1402cfcd6d2c1ecd88c6aa83133daa2 (commit)
via 8b59a7d661ce81cb47c2f18d2908a01a8ab9ded0 (commit)
via f17651217197a8006509ef121f1a3d7a5eada1b4 (commit)
via e77ef46d0c78265ab0bd0ca12b541aaee2a52898 (commit)
via 97a6125c538e5f44790b55ded90fccf363416496 (commit)
via 2150123bd60f00e070198b9c9717eb685dd0eebe (commit)
via 6bceaa250bef898410db1555341887b6a6f7e900 (commit)
via 65c54c90ed874825b0418acade6179bd905bd470 (commit)
via c1ce5449aa72d538cbfca94f88cda0b8617081ba (commit)
via eb84acab80c1a4f59f7c49ef5214279358e8ed79 (commit)
via 31fdd062b59d6ac480ff48cde57e5abad2b3487c (commit)
via ed2b8eb0e3f827c89ba16200312424384a54a9a7 (commit)
via c16c1ab29b3a52012a806974dd6afaddc01c9436 (commit)
via 2eb96fb05e736e2f16d03174f663d030cc883f00 (commit)
via c6f7cced73d38d5108862be4a104cb89d0f832e4 (commit)
via 587a13699275e9a582fb9358463047362ef9f21e (commit)
via ec2aecacc46f071cc6479881418825920e8f8f50 (commit)
via 83a27d452c13b468d2103b0314ecf2bae17cd6b1 (commit)
via ece07281abf99ae142b20b4aead428e3333121a9 (commit)
via d05029362843411c46c6d8d278fcf17ba9d8d32a (commit)
via ef49adadf64f56558c75d34483895e1e8d8bcf66 (commit)
via a475756bf185c9e364ed00e245e307789e22fed3 (commit)
via 27be672609dde261c85ffc671f1026277cfc3e9a (commit)
via 18cff787ef721f58322db5c5662ab7980357fe68 (commit)
via 34020849e9b1d560fdc21b25ac0fe03c64f71a01 (commit)
via ae53c8fd697e2cd037facfccc8205d580b27f04e (commit)
via 97fb03f6b015205da25e9c5be3cd90d4f9948d04 (commit)
via 23d2eaf5f8e5febc4732f3fdc851e1b04914daf8 (commit)
via 1137e979e1a22465feb03ee0a48499bebcdf6aae (commit)
via 12bc8985691e22aad1811322fe1f550b3f710ab8 (commit)
via bf382bba28e32de82649284620e36749a183472d (commit)
via 247cb9c1d6ca73bb212cb9dfe0aa85dcf342e924 (commit)
via 25cd191443ffd0cffc036c53a0ff57ad2391cead (commit)
via e01716291c402d11710387fa6a9b2cfcd8e3953f (commit)
via b3d273056fa988f289ae4bf3f0a677808613b97b (commit)
via b9250ecc03ef6854def286e388e9042fbd579971 (commit)
via 8de132995eade03f030a3a66c0f0bf4bc1b0726c (commit)
via 86fcb73a66e62bda72bf5d6aea7f1f852c7f5739 (commit)
via 61beda153425bfbd855c9bca9ff51fb0e99f2943 (commit)
via 038ba06b6e663343e93e63e0d77d3e3c1abf66bf (commit)
via b643e4ef3098a5671687031b2b1348ef60c780fa (commit)
via 371a652b90f43c0a2759b2be4d2fb6ef95d57ff0 (commit)
from f8181bb72251fd3d5f33e157d1f2a2a75a58d765 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 83d00dc305a33e69e4bee379895697742a1eaab7
Merge: 66524e1 f8181bb
Author: Mukund Sivaraman <muks at isc.org>
Date: Tue Oct 16 06:35:50 2012 +0530
Merge branch 'master' into trac2268
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/memory/Makefile.am | 5 +-
src/lib/datasrc/memory/memory_client.cc | 639 ++------------------
src/lib/datasrc/memory/memory_client.h | 57 +-
src/lib/datasrc/memory/zone_data_loader.cc | 250 ++++++++
src/lib/datasrc/memory/zone_data_loader.h | 80 +++
src/lib/datasrc/memory/zone_data_updater.cc | 347 +++++++++++
src/lib/datasrc/memory/zone_data_updater.h | 180 ++++++
.../datasrc/tests/memory/memory_client_unittest.cc | 137 +++--
.../datasrc/tests/memory/zone_finder_unittest.cc | 276 +++------
.../datasrc/tests/memory/zone_table_unittest.cc | 25 +-
10 files changed, 1106 insertions(+), 890 deletions(-)
create mode 100644 src/lib/datasrc/memory/zone_data_loader.cc
create mode 100644 src/lib/datasrc/memory/zone_data_loader.h
create mode 100644 src/lib/datasrc/memory/zone_data_updater.cc
create mode 100644 src/lib/datasrc/memory/zone_data_updater.h
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index 743caa2..6fce958 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -16,12 +16,15 @@ libdatasrc_memory_la_SOURCES += treenode_rrset.h treenode_rrset.cc
libdatasrc_memory_la_SOURCES += rdata_serialization.h rdata_serialization.cc
libdatasrc_memory_la_SOURCES += zone_data.h zone_data.cc
libdatasrc_memory_la_SOURCES += segment_object_holder.h
-libdatasrc_memory_la_SOURCES += memory_client.h memory_client.cc
libdatasrc_memory_la_SOURCES += logger.h logger.cc
libdatasrc_memory_la_SOURCES += zone_table.h zone_table.cc
libdatasrc_memory_la_SOURCES += zone_finder.h zone_finder.cc
libdatasrc_memory_la_SOURCES += zone_table_segment.h zone_table_segment.cc
libdatasrc_memory_la_SOURCES += zone_table_segment_local.h zone_table_segment_local.cc
+libdatasrc_memory_la_SOURCES += zone_data_updater.h zone_data_updater.cc
+libdatasrc_memory_la_SOURCES += zone_data_loader.h zone_data_loader.cc
+libdatasrc_memory_la_SOURCES += memory_client.h memory_client.cc
+
nodist_libdatasrc_memory_la_SOURCES = memory_messages.h memory_messages.cc
EXTRA_DIST = rdata_serialization_priv.cc
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index f421347..2f5fe67 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -17,12 +17,11 @@
#include <datasrc/memory/memory_client.h>
#include <datasrc/memory/logger.h>
#include <datasrc/memory/zone_data.h>
-#include <datasrc/memory/rdata_serialization.h>
#include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/domaintree.h>
#include <datasrc/memory/segment_object_holder.h>
#include <datasrc/memory/treenode_rrset.h>
#include <datasrc/memory/zone_finder.h>
+#include <datasrc/memory/zone_data_loader.h>
#include <util/memory_segment_local.h>
@@ -31,20 +30,10 @@
#include <datasrc/result.h>
#include <dns/name.h>
-#include <dns/nsec3hash.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
-#include <dns/masterload.h>
-
-#include <boost/function.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-#include <boost/noncopyable.hpp>
#include <algorithm>
-#include <map>
#include <utility>
#include <cctype>
#include <cassert>
@@ -53,7 +42,6 @@ using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc::memory;
-using boost::scoped_ptr;
namespace isc {
namespace datasrc {
@@ -61,552 +49,49 @@ namespace memory {
using detail::SegmentObjectHolder;
-namespace {
-// Some type aliases
-typedef DomainTree<std::string> FileNameTree;
-typedef DomainTreeNode<std::string> FileNameNode;
-
-// A functor type used for loading.
-typedef boost::function<void(ConstRRsetPtr)> LoadCallback;
-
-} // end of anonymous namespace
-
-/// Implementation details for \c InMemoryClient hidden from the public
-/// interface.
-///
-/// For now, \c InMemoryClient only contains a \c ZoneTable object, which
-/// consists of (pointers to) \c InMemoryZoneFinder objects, we may add more
-/// member variables later for new features.
-class InMemoryClient::InMemoryClientImpl {
-private:
- // The deleter for the filenames stored in the tree.
- struct FileNameDeleter {
- FileNameDeleter() {}
- void operator()(std::string* filename) const {
- delete filename;
- }
- };
+namespace { // unnamed namespace
+// A helper internal class used by the memory client, used for deleting
+// filenames stored in an internal tree.
+class FileNameDeleter {
public:
- InMemoryClientImpl(util::MemorySegment& mem_sgmt, RRClass rrclass) :
- mem_sgmt_(mem_sgmt),
- rrclass_(rrclass),
- zone_count_(0),
- zone_table_(ZoneTable::create(mem_sgmt_, rrclass)),
- file_name_tree_(FileNameTree::create(mem_sgmt_, false))
- {}
- ~InMemoryClientImpl() {
- FileNameDeleter deleter;
- FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
-
- ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
- }
-
- util::MemorySegment& mem_sgmt_;
- const RRClass rrclass_;
- unsigned int zone_count_;
- ZoneTable* zone_table_;
- FileNameTree* file_name_tree_;
-
- // Common process for zone load.
- // rrset_installer is a functor that takes another functor as an argument,
- // and expected to call the latter for each RRset of the zone. How the
- // sequence of the RRsets is generated depends on the internal
- // details of the loader: either from a textual master file or from
- // another data source.
- // filename is the file name of the master file or empty if the zone is
- // loaded from another data source.
- result::Result load(const Name& zone_name, const string& filename,
- boost::function<void(LoadCallback)> rrset_installer);
-
- // Add the necessary magic for any wildcard contained in 'name'
- // (including itself) to be found in the zone.
- //
- // In order for wildcard matching to work correctly in the zone finder,
- // we must ensure that a node for the wildcarding level exists in the
- // backend ZoneTree.
- // E.g. if the wildcard name is "*.sub.example." then we must ensure
- // that "sub.example." exists and is marked as a wildcard level.
- // Note: the "wildcarding level" is for the parent name of the wildcard
- // name (such as "sub.example.").
- //
- // We also perform the same trick for empty wild card names possibly
- // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
- void addWildcards(const Name& zone_name, ZoneData& zone_data,
- const Name& name)
- {
- Name wname(name);
- const unsigned int labels(wname.getLabelCount());
- const unsigned int origin_labels(zone_name.getLabelCount());
- for (unsigned int l = labels;
- l > origin_labels;
- --l, wname = wname.split(1)) {
- if (wname.isWildcard()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA,
- DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
-
- // Ensure a separate level exists for the "wildcarding" name,
- // and mark the node as "wild".
- ZoneNode* node;
- zone_data.insertName(mem_sgmt_, wname.split(1), &node);
- node->setFlag(ZoneData::WILDCARD_NODE);
-
- // Ensure a separate level exists for the wildcard name.
- // Note: for 'name' itself we do this later anyway, but the
- // overhead should be marginal because wildcard names should
- // be rare.
- zone_data.insertName(mem_sgmt_, wname, &node);
- }
- }
- }
-
- /*
- * Does some checks in context of the data that are already in the zone.
- * Currently checks for forbidden combinations of RRsets in the same
- * domain (CNAME+anything, DNAME+NS).
- *
- * If such condition is found, it throws AddError.
- */
- void contextCheck(const Name& zone_name, const AbstractRRset& rrset,
- const RdataSet* set) const
- {
- // Ensure CNAME and other type of RR don't coexist for the same
- // owner name except with NSEC, which is the only RR that can coexist
- // with CNAME (and also RRSIG, which is handled separately)
- if (rrset.getType() == RRType::CNAME()) {
- for (const RdataSet* sp = set; sp != NULL; sp = sp->getNext()) {
- if (sp->type != RRType::NSEC()) {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY).
- arg(rrset.getName());
- isc_throw(AddError, "CNAME can't be added with "
- << sp->type << " RRType for "
- << rrset.getName());
- }
- }
- } else if ((rrset.getType() != RRType::NSEC()) &&
- (RdataSet::find(set, RRType::CNAME()) != NULL)) {
- LOG_ERROR(logger,
- DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
- isc_throw(AddError, "CNAME and " << rrset.getType() <<
- " can't coexist for " << rrset.getName());
- }
-
- /*
- * Similar with DNAME, but it must not coexist only with NS and only in
- * non-apex domains.
- * RFC 2672 section 3 mentions that it is implied from it and RFC 2181
- */
- if (rrset.getName() != zone_name &&
- // Adding DNAME, NS already there
- ((rrset.getType() == RRType::DNAME() &&
- RdataSet::find(set, RRType::NS()) != NULL) ||
- // Adding NS, DNAME already there
- (rrset.getType() == RRType::NS() &&
- RdataSet::find(set, RRType::DNAME()) != NULL)))
- {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_DNAME_NS).arg(rrset.getName());
- isc_throw(AddError, "DNAME can't coexist with NS in non-apex "
- "domain " << rrset.getName());
- }
- }
-
- // Validate rrset before adding it to the zone. If something is wrong
- // it throws an exception. It doesn't modify the zone, and provides
- // the strong exception guarantee.
- void addValidation(const Name& zone_name, const ConstRRsetPtr rrset) {
- if (!rrset) {
- isc_throw(NullRRset, "The rrset provided is NULL");
- }
- if (rrset->getRdataCount() == 0) {
- isc_throw(AddError, "The rrset provided is empty: " <<
- rrset->getName() << "/" << rrset->getType());
- }
- // Check for singleton RRs. It should probably handled at a different
- // layer in future.
- if ((rrset->getType() == RRType::CNAME() ||
- rrset->getType() == RRType::DNAME()) &&
- rrset->getRdataCount() > 1)
- {
- // XXX: this is not only for CNAME or DNAME. We should generalize
- // this code for all other "singleton RR types" (such as SOA) in a
- // separate task.
- LOG_ERROR(logger,
- DATASRC_MEMORY_MEM_SINGLETON).arg(rrset->getName()).
- arg(rrset->getType());
- isc_throw(AddError, "multiple RRs of singleton type for "
- << rrset->getName());
- }
- // NSEC3/NSEC3PARAM is not a "singleton" per protocol, but this
- // implementation requests it be so at the moment.
- if ((rrset->getType() == RRType::NSEC3() ||
- rrset->getType() == RRType::NSEC3PARAM()) &&
- rrset->getRdataCount() > 1) {
- isc_throw(AddError, "Multiple NSEC3/NSEC3PARAM RDATA is given for "
- << rrset->getName() << " which isn't supported");
- }
-
- // For RRSIGs, check consistency of the type covered.
- // We know the RRset isn't empty, so the following check is safe.
- if (rrset->getType() == RRType::RRSIG()) {
- RdataIteratorPtr rit = rrset->getRdataIterator();
- const RRType covered = dynamic_cast<const generic::RRSIG&>(
- rit->getCurrent()).typeCovered();
- for (rit->next(); !rit->isLast(); rit->next()) {
- if (dynamic_cast<const generic::RRSIG&>(
- rit->getCurrent()).typeCovered() != covered) {
- isc_throw(AddError, "RRSIG contains mixed covered types: "
- << rrset->toText());
- }
- }
- }
-
- const NameComparisonResult compare =
- zone_name.compare(rrset->getName());
- if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
- compare.getRelation() != NameComparisonResult::EQUAL)
- {
- LOG_ERROR(logger,
- DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
- arg(zone_name);
- isc_throw(OutOfZone, "The name " << rrset->getName() <<
- " is not contained in zone " << zone_name);
- }
-
- // Some RR types do not really work well with a wildcard.
- // Even though the protocol specifically doesn't completely ban such
- // usage, we refuse to load a zone containing such RR in order to
- // keep the lookup logic simpler and more predictable.
- // See RFC4592 and (for DNAME) RFC6672 for more technical background.
- // Note also that BIND 9 refuses NS at a wildcard, so in that sense
- // we simply provide compatible behavior.
- if (rrset->getName().isWildcard()) {
- if (rrset->getType() == RRType::NS()) {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_NS).
- arg(rrset->getName());
- isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
- rrset->getName());
- }
- if (rrset->getType() == RRType::DNAME()) {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_DNAME).
- arg(rrset->getName());
- isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
- rrset->getName());
- }
- }
-
- // Owner names of NSEC3 have special format as defined in RFC5155,
- // and cannot be a wildcard name or must be one label longer than
- // the zone origin. While the RFC doesn't prohibit other forms of
- // names, no sane zone would have such names for NSEC3.
- // BIND 9 also refuses NSEC3 at wildcard.
- if (rrset->getType() == RRType::NSEC3() &&
- (rrset->getName().isWildcard() ||
- rrset->getName().getLabelCount() !=
- zone_name.getLabelCount() + 1)) {
- LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).
- arg(rrset->getName());
- isc_throw(AddError, "Invalid NSEC3 owner name: " <<
- rrset->getName());
- }
- }
-
- void addNSEC3(const ConstRRsetPtr rrset,
- const ConstRRsetPtr rrsig,
- ZoneData& zone_data)
- {
- // We know rrset has exactly one RDATA
- 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);
- 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 = nsec3_rdata.getSalt();
-
- if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
- (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
- (salt_data_2.size() != salt_len)) {
- isc_throw(AddError,
- "NSEC3 with inconsistent parameters: " <<
- rrset->toText());
- }
- if ((salt_len > 0) &&
- (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
- isc_throw(AddError,
- "NSEC3 with inconsistent parameters: " <<
- rrset->toText());
- }
- }
-
- ZoneNode* node;
- nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
-
- RdataEncoder encoder;
- RdataSet* set = RdataSet::create(mem_sgmt_, encoder, rrset, rrsig);
- RdataSet* old_set = node->setData(set);
- if (old_set != NULL) {
- RdataSet::destroy(mem_sgmt_, rrclass_, old_set);
- }
- }
-
- void addRdataSet(const Name& zone_name, ZoneData& zone_data,
- const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
- {
- if (rrset->getType() == RRType::NSEC3()) {
- addNSEC3(rrset, rrsig, zone_data);
- } else {
- ZoneNode* node;
- zone_data.insertName(mem_sgmt_, rrset->getName(), &node);
-
- RdataSet* rdataset_head = node->getData();
-
- // Checks related to the surrounding data.
- // Note: when the check fails and the exception is thrown,
- // it may break strong exception guarantee. At the moment
- // we prefer code simplicity and don't bother to introduce
- // complicated recovery code.
- contextCheck(zone_name, *rrset, rdataset_head);
-
- if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
- isc_throw(AddError,
- "RRset of the type already exists: "
- << rrset->getName() << " (type: "
- << rrset->getType() << ")");
- }
-
- RdataEncoder encoder;
- RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder, rrset,
- rrsig);
- rdataset->next = rdataset_head;
- node->setData(rdataset);
-
- // Ok, we just put it in
-
- // If this RRset creates a zone cut at this node, mark the
- // node indicating the need for callback in find().
- if (rrset->getType() == RRType::NS() &&
- rrset->getName() != zone_name) {
- node->setFlag(ZoneNode::FLAG_CALLBACK);
- // If it is DNAME, we have a callback as well here
- } else if (rrset->getType() == RRType::DNAME()) {
- node->setFlag(ZoneNode::FLAG_CALLBACK);
- }
-
- // 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() == zone_name) {
- // 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(AddError,
- "NSEC3PARAM with inconsistent parameters: "
- << rrset->toText());
- }
-
- if ((salt_len > 0) &&
- (std::memcmp(&salt_data_2[0],
- salt_data, salt_len) != 0)) {
- isc_throw(AddError,
- "NSEC3PARAM with inconsistent parameters: "
- << rrset->toText());
- }
- }
- } else if (rrset->getType() == RRType::NSEC()) {
- // If it is NSEC signed zone, we mark the zone as signed
- // (conceptually "signed" is a broader notion but our current
- // zone finder implementation regards "signed" as "NSEC
- // signed")
- zone_data.setSigned(true);
- }
- }
- }
-
- // Implementation of InMemoryClient::add()
- void add(const ConstRRsetPtr& rrset, const ConstRRsetPtr& sig_rrset,
- const Name& zone_name, ZoneData& zone_data)
- {
- // Sanitize input. This will cause an exception to be thrown
- // if the input RRset is empty.
- addValidation(zone_name, rrset);
- if (sig_rrset) {
- addValidation(zone_name, sig_rrset);
- }
-
- // OK, can add the RRset.
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
- arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
-
- // Add wildcards possibly contained in the owner name to the domain
- // tree. This can only happen for the normal (non-NSEC3) tree.
- // Note: this can throw an exception, breaking strong exception
- // guarantee. (see also the note for the call to contextCheck()
- // above).
- if (rrset->getType() != RRType::NSEC3()) {
- addWildcards(zone_name, zone_data, rrset->getName());
- }
+ FileNameDeleter() {}
- addRdataSet(zone_name, zone_data, rrset, sig_rrset);
+ void operator()(std::string* filename) const {
+ delete filename;
}
};
-// A helper internal class for load(). make it non-copyable to avoid
-// accidental copy.
-//
-// The current internal implementation expects that both a normal
-// (non RRSIG) RRset and (when signed) its RRSIG are added at once.
-// Also in the current implementation, the input sequence of RRsets
-// are grouped with their owner name (so once a new owner name is encountered,
-// no subsequent RRset has the previous owner name), but the ordering
-// in the same group is not fixed. So we hold all RRsets of the same
-// owner name in node_rrsets_ and node_rrsigsets_, and add the matching
-// pairs of RRsets to the zone when we see a new owner name.
-//
-// The caller is responsible for adding the RRsets of the last group
-// in the input sequence by explicitly calling flushNodeRRsets() at the
-// end. It's cleaner and more robust if we let the destructor of this class
-// do it, but since we cannot guarantee the adding operation is exception free,
-// we don't choose that option to maintain the common expectation for
-// destructors.
-class InMemoryClient::Loader : boost::noncopyable {
- typedef std::map<RRType, ConstRRsetPtr> NodeRRsets;
- typedef NodeRRsets::value_type NodeRRsetsVal;
-public:
- Loader(InMemoryClientImpl* client_impl, const Name& zone_name,
- ZoneData& zone_data) :
- client_impl_(client_impl), zone_name_(zone_name), zone_data_(zone_data)
- {}
- void addFromLoad(const ConstRRsetPtr& rrset) {
- // If we see a new name, flush the temporary holders, adding the
- // pairs of RRsets and RRSIGs of the previous name to the zone.
- if ((!node_rrsets_.empty() || !node_rrsigsets_.empty()) &&
- getCurrentName() != rrset->getName()) {
- flushNodeRRsets();
- }
+} // end of unnamed namespace
- // Store this RRset until it can be added to the zone. The current
- // implementation requires RRs of the same RRset should be added at
- // once, so we check the "duplicate" here.
- const bool is_rrsig = rrset->getType() == RRType::RRSIG();
- NodeRRsets& node_rrsets = is_rrsig ? node_rrsigsets_ : node_rrsets_;
- const RRType& rrtype = is_rrsig ?
- getCoveredType(rrset) : rrset->getType();
- if (!node_rrsets.insert(NodeRRsetsVal(rrtype, rrset)).second) {
- isc_throw(AddError,
- "Duplicate add of the same type of"
- << (is_rrsig ? " RRSIG" : "") << " RRset: "
- << rrset->getName() << "/" << rrtype);
- }
- }
- void flushNodeRRsets() {
- BOOST_FOREACH(NodeRRsetsVal val, node_rrsets_) {
- // Identify the corresponding RRSIG for the RRset, if any.
- // If found add both the RRset and its RRSIG at once.
- ConstRRsetPtr sig_rrset;
- NodeRRsets::iterator sig_it =
- node_rrsigsets_.find(val.first);
- if (sig_it != node_rrsigsets_.end()) {
- sig_rrset = sig_it->second;
- node_rrsigsets_.erase(sig_it);
- }
- client_impl_->add(val.second, sig_rrset, zone_name_, zone_data_);
- }
+InMemoryClient::InMemoryClient(util::MemorySegment& mem_sgmt,
+ RRClass rrclass) :
+ mem_sgmt_(mem_sgmt),
+ rrclass_(rrclass),
+ zone_count_(0)
+{
+ SegmentObjectHolder<ZoneTable, RRClass> holder(
+ mem_sgmt_, ZoneTable::create(mem_sgmt_, rrclass), rrclass_);
- // Right now, we don't accept RRSIG without covered RRsets (this
- // should eventually allowed, but to do so we'll need to update the
- // finder).
- if (!node_rrsigsets_.empty()) {
- isc_throw(AddError, "RRSIG is added without covered RRset for "
- << getCurrentName());
- }
+ file_name_tree_ = FileNameTree::create(mem_sgmt_, false);
- node_rrsets_.clear();
- node_rrsigsets_.clear();
- }
-private:
- // A helper to identify the covered type of an RRSIG.
- static RRType getCoveredType(const ConstRRsetPtr& sig_rrset) {
- RdataIteratorPtr it = sig_rrset->getRdataIterator();
- // Empty RRSIG shouldn't be passed either via a master file or another
- // data source iterator, but it could still happen if the iterator
- // has a bug. We catch and reject such cases.
- if (it->isLast()) {
- isc_throw(isc::Unexpected,
- "Empty RRset is passed in-memory loader, name: "
- << sig_rrset->getName());
- }
- return (dynamic_cast<const generic::RRSIG&>(it->getCurrent()).
- typeCovered());
- }
- const Name& getCurrentName() const {
- if (!node_rrsets_.empty()) {
- return (node_rrsets_.begin()->second->getName());
- }
- assert(!node_rrsigsets_.empty());
- return (node_rrsigsets_.begin()->second->getName());
- }
+ zone_table_ = holder.release();
+}
-private:
- InMemoryClientImpl* client_impl_;
- const Name& zone_name_;
- ZoneData& zone_data_;
- NodeRRsets node_rrsets_;
- NodeRRsets node_rrsigsets_;
-};
+InMemoryClient::~InMemoryClient() {
+ FileNameDeleter deleter;
+ FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
+
+ ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
+}
result::Result
-InMemoryClient::InMemoryClientImpl::load(
- const Name& zone_name,
- const string& filename,
- boost::function<void(LoadCallback)> rrset_installer)
+InMemoryClient::loadInternal(const isc::dns::Name& zone_name,
+ const std::string& filename,
+ ZoneData* zone_data)
{
SegmentObjectHolder<ZoneData, RRClass> holder(
- mem_sgmt_, ZoneData::create(mem_sgmt_, zone_name), rrclass_);
-
- Loader loader(this, zone_name, *holder.get());
- rrset_installer(boost::bind(&Loader::addFromLoad, &loader, _1));
- // Add any last RRsets that were left
- loader.flushNodeRRsets();
-
- const ZoneNode* origin_node = holder.get()->getOriginNode();
- const RdataSet* set = origin_node->getData();
- // If the zone is NSEC3-signed, check if it has NSEC3PARAM
- if (holder.get()->isNSEC3Signed()) {
- if (RdataSet::find(set, RRType::NSEC3PARAM()) == NULL) {
- LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
- arg(zone_name).arg(rrclass_);
- }
- }
-
- // When an empty zone file is loaded, the origin doesn't even have
- // an SOA RR. This condition should be avoided, and hence load()
- // should throw when an empty zone is loaded.
- if (RdataSet::find(set, RRType::SOA()) == NULL) {
- isc_throw(EmptyZone,
- "Won't create an empty zone for: " << zone_name);
- }
+ mem_sgmt_, zone_data, rrclass_);
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
arg(zone_name).arg(rrclass_);
@@ -645,46 +130,14 @@ InMemoryClient::InMemoryClientImpl::load(
return (result.code);
}
-namespace {
-// A wrapper for dns::masterLoad used by load() below. Essentially it
-// converts the two callback types. Note the mostly redundant wrapper of
-// boost::bind. It converts function<void(ConstRRsetPtr)> to
-// function<void(RRsetPtr)> (masterLoad() expects the latter). SunStudio
-// doesn't seem to do this conversion if we just pass 'callback'.
-void
-masterLoadWrapper(const char* const filename, const Name& origin,
- const RRClass& zone_class, LoadCallback callback)
-{
- masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
-}
-
-// The installer called from Impl::load() for the iterator version of load().
-void
-generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
- ConstRRsetPtr rrset;
- while ((rrset = iterator->getNextRRset()) != NULL) {
- callback(rrset);
- }
-}
-}
-
-InMemoryClient::InMemoryClient(util::MemorySegment& mem_sgmt,
- RRClass rrclass) :
- impl_(new InMemoryClientImpl(mem_sgmt, rrclass))
-{}
-
-InMemoryClient::~InMemoryClient() {
- delete impl_;
-}
-
RRClass
InMemoryClient::getClass() const {
- return (impl_->rrclass_);
+ return (rrclass_);
}
unsigned int
InMemoryClient::getZoneCount() const {
- return (impl_->zone_count_);
+ return (zone_count_);
}
isc::datasrc::DataSourceClient::FindResult
@@ -692,7 +145,7 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
LOG_DEBUG(logger, DBG_TRACE_DATA,
DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
- ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+ ZoneTable::FindResult result(zone_table_->findZone(zone_name));
ZoneFinderPtr finder;
if (result.code != result::NOTFOUND) {
@@ -704,34 +157,34 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
const ZoneData*
InMemoryClient::findZoneData(const isc::dns::Name& zone_name) {
- ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+ ZoneTable::FindResult result(zone_table_->findZone(zone_name));
return (result.zone_data);
}
result::Result
InMemoryClient::load(const isc::dns::Name& zone_name,
- const std::string& filename) {
+ const std::string& filename)
+{
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD).arg(zone_name).
arg(filename);
- return (impl_->load(zone_name, filename,
- boost::bind(masterLoadWrapper, filename.c_str(),
- zone_name, getClass(), _1)));
+ ZoneData* zone_data = loadZoneData(mem_sgmt_, rrclass_, zone_name,
+ filename);
+ return (loadInternal(zone_name, filename, zone_data));
}
result::Result
-InMemoryClient::load(const isc::dns::Name& zone_name,
- ZoneIterator& iterator) {
- return (impl_->load(zone_name, string(),
- boost::bind(generateRRsetFromIterator,
- &iterator, _1)));
+InMemoryClient::load(const isc::dns::Name& zone_name, ZoneIterator& iterator) {
+ ZoneData* zone_data = loadZoneData(mem_sgmt_, rrclass_, zone_name,
+ iterator);
+ return (loadInternal(zone_name, string(), zone_data));
}
const std::string
InMemoryClient::getFileName(const isc::dns::Name& zone_name) const {
const FileNameNode* node(NULL);
- const FileNameTree::Result result = impl_->file_name_tree_->find(zone_name,
- &node);
+ const FileNameTree::Result result = file_name_tree_->find(zone_name,
+ &node);
if (result == FileNameTree::EXACTMATCH) {
return (*node->getData());
} else {
@@ -853,7 +306,7 @@ public:
ZoneIteratorPtr
InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
- ZoneTable::FindResult result(impl_->zone_table_->findZone(name));
+ ZoneTable::FindResult result(zone_table_->findZone(name));
if (result.code != result::SUCCESS) {
isc_throw(DataSourceError, "No such zone: " + name.toText());
}
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index c37ad53..3313c5b 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -139,40 +139,6 @@ public:
/// zone from a file before.
const std::string getFileName(const isc::dns::Name& zone_name) const;
- /// \brief RRset is NULL exception.
- ///
- /// This is thrown if the provided RRset parameter is NULL.
- struct NullRRset : public InvalidParameter {
- NullRRset(const char* file, size_t line, const char* what) :
- InvalidParameter(file, line, what)
- { }
- };
-
- /// \brief Zone is empty exception.
- ///
- /// This is thrown if we have an empty zone created as a result of
- /// load().
- struct EmptyZone : public InvalidParameter {
- EmptyZone(const char* file, size_t line, const char* what) :
- InvalidParameter(file, line, what)
- { }
- };
-
- /// \brief General failure exception for \c add().
- ///
- /// This is thrown against general error cases in adding an RRset
- /// to the zone.
- ///
- /// Note: this exception would cover cases for \c OutOfZone or
- /// \c NullRRset. We'll need to clarify and unify the granularity
- /// of exceptions eventually. For now, exceptions are added as
- /// developers see the need for it.
- struct AddError : public InvalidParameter {
- AddError(const char* file, size_t line, const char* what) :
- InvalidParameter(file, line, what)
- { }
- };
-
/// Returns a \c ZoneFinder result that best matches the given name.
///
/// This derived version of the method never throws an exception.
@@ -210,14 +176,21 @@ public:
uint32_t end_serial) const;
private:
- // TODO: Do we still need the PImpl if nobody should manipulate this class
- // directly any more (it should be handled through DataSourceClient)?
- class InMemoryClientImpl;
- InMemoryClientImpl* impl_;
-
- // A helper internal class used by load(). It maintains some intermediate
- // states while loading RRs of the zone.
- class Loader;
+ // Some type aliases
+ typedef DomainTree<std::string> FileNameTree;
+ typedef DomainTreeNode<std::string> FileNameNode;
+
+ // Common process for zone load. Registers filename internally and
+ // adds the ZoneData to the ZoneTable.
+ result::Result loadInternal(const isc::dns::Name& zone_name,
+ const std::string& filename,
+ ZoneData* zone_data);
+
+ util::MemorySegment& mem_sgmt_;
+ const isc::dns::RRClass rrclass_;
+ unsigned int zone_count_;
+ ZoneTable* zone_table_;
+ FileNameTree* file_name_tree_;
};
} // namespace memory
diff --git a/src/lib/datasrc/memory/zone_data_loader.cc b/src/lib/datasrc/memory/zone_data_loader.cc
new file mode 100644
index 0000000..97c8092
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_loader.cc
@@ -0,0 +1,250 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <datasrc/memory/zone_data_loader.h>
+#include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/logger.h>
+#include <datasrc/memory/segment_object_holder.h>
+
+#include <dns/rdataclass.h>
+#include <dns/rrset.h>
+#include <dns/masterload.h>
+
+#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <map>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+using detail::SegmentObjectHolder;
+
+namespace { // unnamed namespace
+
+// A functor type used for loading.
+typedef boost::function<void(isc::dns::ConstRRsetPtr)> LoadCallback;
+
+// A helper internal class for \c loadZoneData(). make it non-copyable
+// to avoid accidental copy.
+//
+// The current internal implementation expects that both a normal
+// (non RRSIG) RRset and (when signed) its RRSIG are added at once.
+// Also in the current implementation, the input sequence of RRsets
+// are grouped with their owner name (so once a new owner name is encountered,
+// no subsequent RRset has the previous owner name), but the ordering
+// in the same group is not fixed. So we hold all RRsets of the same
+// owner name in node_rrsets_ and node_rrsigsets_, and add the matching
+// pairs of RRsets to the zone when we see a new owner name.
+//
+// The caller is responsible for adding the RRsets of the last group
+// in the input sequence by explicitly calling flushNodeRRsets() at the
+// end. It's cleaner and more robust if we let the destructor of this class
+// do it, but since we cannot guarantee the adding operation is exception free,
+// we don't choose that option to maintain the common expectation for
+// destructors.
+class ZoneDataLoader : boost::noncopyable {
+public:
+ ZoneDataLoader(util::MemorySegment& mem_sgmt,
+ const isc::dns::RRClass rrclass,
+ const isc::dns::Name& zone_name, ZoneData& zone_data) :
+ updater_(mem_sgmt, rrclass, zone_name, zone_data)
+ {}
+
+ void addFromLoad(const isc::dns::ConstRRsetPtr& rrset);
+ void flushNodeRRsets();
+
+private:
+ typedef std::map<isc::dns::RRType, isc::dns::ConstRRsetPtr> NodeRRsets;
+ typedef NodeRRsets::value_type NodeRRsetsVal;
+
+ // A helper to identify the covered type of an RRSIG.
+ static isc::dns::RRType getCoveredType
+ (const isc::dns::ConstRRsetPtr& sig_rrset);
+ const isc::dns::Name& getCurrentName() const;
+
+private:
+ NodeRRsets node_rrsets_;
+ NodeRRsets node_rrsigsets_;
+ ZoneDataUpdater updater_;
+};
+
+void
+ZoneDataLoader::addFromLoad(const ConstRRsetPtr& rrset) {
+ // If we see a new name, flush the temporary holders, adding the
+ // pairs of RRsets and RRSIGs of the previous name to the zone.
+ if ((!node_rrsets_.empty() || !node_rrsigsets_.empty()) &&
+ (getCurrentName() != rrset->getName())) {
+ flushNodeRRsets();
+ }
+
+ // Store this RRset until it can be added to the zone. The current
+ // implementation requires RRs of the same RRset should be added at
+ // once, so we check the "duplicate" here.
+ const bool is_rrsig = rrset->getType() == RRType::RRSIG();
+ NodeRRsets& node_rrsets = is_rrsig ? node_rrsigsets_ : node_rrsets_;
+ const RRType& rrtype = is_rrsig ? getCoveredType(rrset) : rrset->getType();
+ if (!node_rrsets.insert(NodeRRsetsVal(rrtype, rrset)).second) {
+ isc_throw(ZoneDataUpdater::AddError,
+ "Duplicate add of the same type of"
+ << (is_rrsig ? " RRSIG" : "") << " RRset: "
+ << rrset->getName() << "/" << rrtype);
+ }
+
+ if (rrset->getRRsig()) {
+ addFromLoad(rrset->getRRsig());
+ }
+}
+
+void
+ZoneDataLoader::flushNodeRRsets() {
+ BOOST_FOREACH(NodeRRsetsVal val, node_rrsets_) {
+ // Identify the corresponding RRSIG for the RRset, if any. If
+ // found add both the RRset and its RRSIG at once.
+ ConstRRsetPtr sig_rrset;
+ NodeRRsets::iterator sig_it = node_rrsigsets_.find(val.first);
+ if (sig_it != node_rrsigsets_.end()) {
+ sig_rrset = sig_it->second;
+ node_rrsigsets_.erase(sig_it);
+ }
+ updater_.add(val.second, sig_rrset);
+ }
+
+ // Right now, we don't accept RRSIG without covered RRsets (this
+ // should eventually allowed, but to do so we'll need to update the
+ // finder).
+ if (!node_rrsigsets_.empty()) {
+ isc_throw(ZoneDataUpdater::AddError,
+ "RRSIG is added without covered RRset for "
+ << getCurrentName());
+ }
+
+ node_rrsets_.clear();
+ node_rrsigsets_.clear();
+}
+
+RRType
+ZoneDataLoader::getCoveredType(const ConstRRsetPtr& sig_rrset) {
+ RdataIteratorPtr it = sig_rrset->getRdataIterator();
+ // Empty RRSIG shouldn't be passed either via a master file or
+ // another data source iterator, but it could still happen if the
+ // iterator has a bug. We catch and reject such cases.
+ if (it->isLast()) {
+ isc_throw(isc::Unexpected,
+ "Empty RRset is passed in-memory loader, name: "
+ << sig_rrset->getName());
+ }
+ return (dynamic_cast<const generic::RRSIG&>(it->getCurrent()).
+ typeCovered());
+}
+
+const Name&
+ZoneDataLoader::getCurrentName() const {
+ if (!node_rrsets_.empty()) {
+ return (node_rrsets_.begin()->second->getName());
+ }
+ assert(!node_rrsigsets_.empty());
+ return (node_rrsigsets_.begin()->second->getName());
+}
+
+ZoneData*
+loadZoneDataInternal(util::MemorySegment& mem_sgmt,
+ const isc::dns::RRClass rrclass,
+ const Name& zone_name,
+ boost::function<void(LoadCallback)> rrset_installer)
+{
+ SegmentObjectHolder<ZoneData, RRClass> holder(
+ mem_sgmt, ZoneData::create(mem_sgmt, zone_name), rrclass);
+
+ ZoneDataLoader loader(mem_sgmt, rrclass, zone_name, *holder.get());
+ rrset_installer(boost::bind(&ZoneDataLoader::addFromLoad, &loader, _1));
+ // Add any last RRsets that were left
+ loader.flushNodeRRsets();
+
+ const ZoneNode* origin_node = holder.get()->getOriginNode();
+ const RdataSet* rdataset = origin_node->getData();
+ // If the zone is NSEC3-signed, check if it has NSEC3PARAM
+ if (holder.get()->isNSEC3Signed()) {
+ if (RdataSet::find(rdataset, RRType::NSEC3PARAM()) == NULL) {
+ LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
+ arg(zone_name).arg(rrclass);
+ }
+ }
+
+ // When an empty zone file is loaded, the origin doesn't even have
+ // an SOA RR. This condition should be avoided, and hence load()
+ // should throw when an empty zone is loaded.
+ if (RdataSet::find(rdataset, RRType::SOA()) == NULL) {
+ isc_throw(EmptyZone,
+ "Won't create an empty zone for: " << zone_name);
+ }
+
+ return (holder.release());
+}
+
+// A wrapper for dns::masterLoad used by loadZoneData() below. Essentially it
+// converts the two callback types. Note the mostly redundant wrapper of
+// boost::bind. It converts function<void(ConstRRsetPtr)> to
+// function<void(RRsetPtr)> (masterLoad() expects the latter). SunStudio
+// doesn't seem to do this conversion if we just pass 'callback'.
+void
+masterLoadWrapper(const char* const filename, const Name& origin,
+ const RRClass& zone_class, LoadCallback callback)
+{
+ masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
+}
+
+// The installer called from the iterator version of loadZoneData().
+void
+generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
+ ConstRRsetPtr rrset;
+ while ((rrset = iterator->getNextRRset()) != NULL) {
+ callback(rrset);
+ }
+}
+
+} // end of unnamed namespace
+
+ZoneData*
+loadZoneData(util::MemorySegment& mem_sgmt,
+ const isc::dns::RRClass rrclass,
+ const isc::dns::Name& zone_name,
+ const std::string& zone_file)
+{
+ return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
+ boost::bind(masterLoadWrapper,
+ zone_file.c_str(),
+ zone_name, rrclass,
+ _1)));
+}
+
+ZoneData*
+loadZoneData(util::MemorySegment& mem_sgmt,
+ const isc::dns::RRClass rrclass,
+ const isc::dns::Name& zone_name,
+ ZoneIterator& iterator)
+{
+ return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
+ boost::bind(generateRRsetFromIterator,
+ &iterator, _1)));
+}
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
diff --git a/src/lib/datasrc/memory/zone_data_loader.h b/src/lib/datasrc/memory/zone_data_loader.h
new file mode 100644
index 0000000..298af46
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_loader.h
@@ -0,0 +1,80 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_ZONE_DATA_LOADER_H
+#define DATASRC_ZONE_DATA_LOADER_H 1
+
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/iterator.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <util/memory_segment.h>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+/// \brief Zone is empty exception.
+///
+/// This is thrown if an empty zone would be created during
+/// \c loadZoneData().
+struct EmptyZone : public InvalidParameter {
+ EmptyZone(const char* file, size_t line, const char* what) :
+ InvalidParameter(file, line, what)
+ {}
+};
+
+/// \brief Create and return a ZoneData instance populated from the
+/// \c zone_file.
+///
+/// Throws \c ZoneDataUpdater::AddError if invalid or inconsistent data
+/// is present in the \c zone_file. Throws \c isc::Unexpected if empty
+/// RRsets are passed by the master loader. Throws \c EmptyZone if an
+/// empty zone would be created due to the \c loadZoneData().
+///
+/// \param mem_sgmt The memory segment.
+/// \param rrclass The RRClass.
+/// \param zone_name The name of the zone that is being loaded.
+/// \param zone_file Filename which contains the zone data for \c zone_name.
+ZoneData* loadZoneData(util::MemorySegment& mem_sgmt,
+ const isc::dns::RRClass rrclass,
+ const isc::dns::Name& zone_name,
+ const std::string& zone_file);
+
+/// \brief Create and return a ZoneData instance populated from the
+/// \c iterator.
+///
+/// Throws \c ZoneDataUpdater::AddError if invalid or inconsistent data
+/// is present in the \c zone_file. Throws \c isc::Unexpected if empty
+/// RRsets are passed by the zone iterator. Throws \c EmptyZone if an
+/// empty zone would be created due to the \c loadZoneData().
+///
+/// \param mem_sgmt The memory segment.
+/// \param rrclass The RRClass.
+/// \param zone_name The name of the zone that is being loaded.
+/// \param iterator Iterator that returns RRsets to load into the zone.
+ZoneData* loadZoneData(util::MemorySegment& mem_sgmt,
+ const isc::dns::RRClass rrclass,
+ const isc::dns::Name& zone_name,
+ ZoneIterator& iterator);
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_ZONE_DATA_LOADER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/memory/zone_data_updater.cc b/src/lib/datasrc/memory/zone_data_updater.cc
new file mode 100644
index 0000000..037eeb4
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_updater.cc
@@ -0,0 +1,347 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/logger.h>
+#include <datasrc/zone.h>
+
+#include <dns/rdataclass.h>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+void
+ZoneDataUpdater::addWildcards(const Name& name) {
+ Name wname(name);
+ const unsigned int labels(wname.getLabelCount());
+ const unsigned int origin_labels(zone_name_.getLabelCount());
+ for (unsigned int l = labels;
+ l > origin_labels;
+ --l, wname = wname.split(1))
+ {
+ if (wname.isWildcard()) {
+ LOG_DEBUG(logger, DBG_TRACE_DATA,
+ DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
+
+ // Ensure a separate level exists for the "wildcarding"
+ // name, and mark the node as "wild".
+ ZoneNode* node;
+ zone_data_.insertName(mem_sgmt_, wname.split(1), &node);
+ node->setFlag(ZoneData::WILDCARD_NODE);
+
+ // Ensure a separate level exists for the wildcard name.
+ // Note: for 'name' itself we do this later anyway, but the
+ // overhead should be marginal because wildcard names should
+ // be rare.
+ zone_data_.insertName(mem_sgmt_, wname, &node);
+ }
+ }
+}
+
+void
+ZoneDataUpdater::contextCheck(const AbstractRRset& rrset,
+ const RdataSet* rdataset) const
+{
+ // Ensure CNAME and other type of RR don't coexist for the same
+ // owner name except with NSEC, which is the only RR that can
+ // coexist with CNAME (and also RRSIG, which is handled separately)
+ if (rrset.getType() == RRType::CNAME()) {
+ for (const RdataSet* sp = rdataset; sp != NULL; sp = sp->getNext()) {
+ if (sp->type != RRType::NSEC()) {
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY).
+ arg(rrset.getName());
+ isc_throw(AddError,
+ "CNAME can't be added with " << sp->type
+ << " RRType for " << rrset.getName());
+ }
+ }
+ } else if ((rrset.getType() != RRType::NSEC()) &&
+ (RdataSet::find(rdataset, RRType::CNAME()) != NULL))
+ {
+ LOG_ERROR(logger,
+ DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
+ isc_throw(AddError,
+ "CNAME and " << rrset.getType() <<
+ " can't coexist for " << rrset.getName());
+ }
+
+ // Similar with DNAME, but it must not coexist only with NS and only
+ // in non-apex domains. RFC 2672 section 3 mentions that it is
+ // implied from it and RFC 2181.
+ if (rrset.getName() != zone_name_ &&
+ // Adding DNAME, NS already there
+ ((rrset.getType() == RRType::DNAME() &&
+ RdataSet::find(rdataset, RRType::NS()) != NULL) ||
+ // Adding NS, DNAME already there
+ (rrset.getType() == RRType::NS() &&
+ RdataSet::find(rdataset, RRType::DNAME()) != NULL)))
+ {
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_DNAME_NS).arg(rrset.getName());
+ isc_throw(AddError, "DNAME can't coexist with NS in non-apex domain: "
+ << rrset.getName());
+ }
+}
+
+void
+ZoneDataUpdater::validate(const isc::dns::ConstRRsetPtr rrset) const {
+ if (!rrset) {
+ isc_throw(NullRRset, "The rrset provided is NULL");
+ }
+
+ if (rrset->getRdataCount() == 0) {
+ isc_throw(AddError,
+ "The rrset provided is empty: "
+ << rrset->getName() << "/" << rrset->getType());
+ }
+
+ // Check for singleton RRs. It should probably handled at a different
+ // layer in future.
+ if ((rrset->getType() == RRType::CNAME() ||
+ rrset->getType() == RRType::DNAME()) &&
+ rrset->getRdataCount() > 1)
+ {
+ // XXX: this is not only for CNAME or DNAME. We should
+ // generalize this code for all other "singleton RR types" (such
+ // as SOA) in a separate task.
+ LOG_ERROR(logger,
+ DATASRC_MEMORY_MEM_SINGLETON).arg(rrset->getName()).
+ arg(rrset->getType());
+ isc_throw(AddError, "multiple RRs of singleton type for "
+ << rrset->getName());
+ }
+
+ // NSEC3/NSEC3PARAM is not a "singleton" per protocol, but this
+ // implementation requests it be so at the moment.
+ if ((rrset->getType() == RRType::NSEC3() ||
+ rrset->getType() == RRType::NSEC3PARAM()) &&
+ (rrset->getRdataCount() > 1))
+ {
+ isc_throw(AddError, "Multiple NSEC3/NSEC3PARAM RDATA is given for "
+ << rrset->getName() << " which isn't supported");
+ }
+
+ // For RRSIGs, check consistency of the type covered. We know the
+ // RRset isn't empty, so the following check is safe.
+ if (rrset->getType() == RRType::RRSIG()) {
+ RdataIteratorPtr rit = rrset->getRdataIterator();
+ const RRType covered = dynamic_cast<const generic::RRSIG&>(
+ rit->getCurrent()).typeCovered();
+ for (rit->next(); !rit->isLast(); rit->next()) {
+ if (dynamic_cast<const generic::RRSIG&>(
+ rit->getCurrent()).typeCovered() != covered)
+ {
+ isc_throw(AddError, "RRSIG contains mixed covered types: "
+ << rrset->toText());
+ }
+ }
+ }
+
+ const NameComparisonResult compare = zone_name_.compare(rrset->getName());
+ if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
+ compare.getRelation() != NameComparisonResult::EQUAL)
+ {
+ LOG_ERROR(logger,
+ DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
+ arg(zone_name_);
+ isc_throw(OutOfZone,
+ "The name " << rrset->getName() <<
+ " is not contained in zone " << zone_name_);
+ }
+
+ // Some RR types do not really work well with a wildcard. Even
+ // though the protocol specifically doesn't completely ban such
+ // usage, we refuse to load a zone containing such RR in order to
+ // keep the lookup logic simpler and more predictable. See RFC4592
+ // and (for DNAME) RFC6672 for more technical background. Note also
+ // that BIND 9 refuses NS at a wildcard, so in that sense we simply
+ // provide compatible behavior.
+ if (rrset->getName().isWildcard()) {
+ if (rrset->getType() == RRType::NS()) {
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_NS).
+ arg(rrset->getName());
+ isc_throw(AddError, "Invalid NS owner name (wildcard): "
+ << rrset->getName());
+ }
+
+ if (rrset->getType() == RRType::DNAME()) {
+ LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_DNAME).
+ arg(rrset->getName());
+ isc_throw(AddError, "Invalid DNAME owner name (wildcard): "
+ << rrset->getName());
+ }
+ }
+
+ // Owner names of NSEC3 have special format as defined in RFC5155,
+ // and cannot be a wildcard name or must be one label longer than
+ // the zone origin. While the RFC doesn't prohibit other forms of
+ // names, no sane zone would have such names for NSEC3. BIND 9 also
+ // refuses NSEC3 at wildcard.
+ if (rrset->getType() == RRType::NSEC3() &&
+ (rrset->getName().isWildcard() ||
+ rrset->getName().getLabelCount() != zone_name_.getLabelCount() + 1))
+ {
+ LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).arg(rrset->getName());
+ isc_throw(AddError, "Invalid NSEC3 owner name: " <<
+ rrset->getName() << "; zone: " << zone_name_);
+ }
+}
+
+const NSEC3Hash*
+ZoneDataUpdater::getNSEC3Hash() {
+ if (hash_ == NULL) {
+ NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+ // This should never be NULL in this codepath.
+ assert(nsec3_data != NULL);
+
+ hash_ = NSEC3Hash::create(nsec3_data->hashalg,
+ nsec3_data->iterations,
+ nsec3_data->getSaltData(),
+ nsec3_data->getSaltLen());
+ }
+
+ return (hash_);
+}
+
+template <typename T>
+void
+ZoneDataUpdater::setupNSEC3(const ConstRRsetPtr rrset) {
+ // We know rrset has exactly one RDATA
+ const T& nsec3_rdata =
+ dynamic_cast<const T&>(
+ 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);
+ zone_data_.setSigned(true);
+ } else {
+ const NSEC3Hash* hash = getNSEC3Hash();
+ if (!hash->match(nsec3_rdata)) {
+ isc_throw(AddError,
+ rrset->getType() << " with inconsistent parameters: "
+ << rrset->toText());
+ }
+ }
+}
+
+void
+ZoneDataUpdater::addNSEC3(const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
+{
+ setupNSEC3<generic::NSEC3>(rrset);
+
+ NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+
+ ZoneNode* node;
+ nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
+
+ RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, rrset, rrsig);
+ RdataSet* old_rdataset = node->setData(rdataset);
+ if (old_rdataset != NULL) {
+ RdataSet::destroy(mem_sgmt_, rrclass_, old_rdataset);
+ }
+}
+
+void
+ZoneDataUpdater::addRdataSet(const ConstRRsetPtr rrset,
+ const ConstRRsetPtr rrsig)
+{
+ if (rrset->getType() == RRType::NSEC3()) {
+ addNSEC3(rrset, rrsig);
+ } else {
+ ZoneNode* node;
+ zone_data_.insertName(mem_sgmt_, rrset->getName(), &node);
+
+ RdataSet* rdataset_head = node->getData();
+
+ // Checks related to the surrounding data. Note: when the check
+ // fails and the exception is thrown, it may break strong
+ // exception guarantee. At the moment we prefer code simplicity
+ // and don't bother to introduce complicated recovery code.
+ contextCheck(*rrset, rdataset_head);
+
+ if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
+ isc_throw(AddError,
+ "RRset of the type already exists: "
+ << rrset->getName() << " (type: "
+ << rrset->getType() << ")");
+ }
+
+ RdataSet* rdataset_new = RdataSet::create(mem_sgmt_, encoder_,
+ rrset, rrsig);
+ rdataset_new->next = rdataset_head;
+ node->setData(rdataset_new);
+
+ // Ok, we just put it in.
+
+ // If this RRset creates a zone cut at this node, mark the node
+ // indicating the need for callback in find().
+ if (rrset->getType() == RRType::NS() &&
+ rrset->getName() != zone_name_) {
+ node->setFlag(ZoneNode::FLAG_CALLBACK);
+ // If it is DNAME, we have a callback as well here
+ } else if (rrset->getType() == RRType::DNAME()) {
+ node->setFlag(ZoneNode::FLAG_CALLBACK);
+ }
+
+ // 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() == zone_name_) {
+ setupNSEC3<generic::NSEC3PARAM>(rrset);
+ } else if (rrset->getType() == RRType::NSEC()) {
+ // If it is NSEC signed zone, we mark the zone as signed
+ // (conceptually "signed" is a broader notion but our
+ // current zone finder implementation regards "signed" as
+ // "NSEC signed")
+ zone_data_.setSigned(true);
+ }
+ }
+}
+
+void
+ZoneDataUpdater::add(const ConstRRsetPtr& rrset,
+ const ConstRRsetPtr& sig_rrset)
+{
+ // Validate input. This will cause an exception to be thrown if the
+ // input RRset is empty.
+ validate(rrset);
+ if (sig_rrset) {
+ validate(sig_rrset);
+ }
+
+ // OK, can add the RRset.
+ LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
+ arg(rrset->getName()).arg(rrset->getType()).arg(zone_name_);
+
+ // Add wildcards possibly contained in the owner name to the domain
+ // tree. This can only happen for the normal (non-NSEC3) tree.
+ // Note: this can throw an exception, breaking strong exception
+ // guarantee. (see also the note for the call to contextCheck()
+ // above).
+ if (rrset->getType() != RRType::NSEC3()) {
+ addWildcards(rrset->getName());
+ }
+
+ addRdataSet(rrset, sig_rrset);
+}
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
diff --git a/src/lib/datasrc/memory/zone_data_updater.h b/src/lib/datasrc/memory/zone_data_updater.h
new file mode 100644
index 0000000..341d8ae
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_updater.h
@@ -0,0 +1,180 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_ZONE_DATA_UPDATER_H
+#define DATASRC_ZONE_DATA_UPDATER_H 1
+
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/rdata_serialization.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrset.h>
+#include <dns/nsec3hash.h>
+#include <util/memory_segment.h>
+
+#include <boost/noncopyable.hpp>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+/// \brief A helper class to add records to a zone.
+///
+/// This class provides an \c add() method that can be used to add
+/// RRsets to a ZoneData instance. The RRsets are first validated for
+/// correctness and consistency, and their data is made into RdataSets
+/// which are added to the ZoneData for the zone.
+///
+/// The way to use this is to make a ZoneDataUpdater instance, and call
+/// add() on it as follows:
+///
+/// \code
+/// ZoneDataUpdater updater(mem_sgmt, rrclass, zone_origin_name, zone_data);
+/// ConstRRsetPtr rrset;
+/// updater.add(rrset, ConstRRsetPtr());
+/// \endcode
+///
+/// We enforce that instances are non-copyable as it's pointless to make
+/// copies.
+class ZoneDataUpdater : boost::noncopyable {
+public:
+ ///
+ /// \name Constructors and Destructor.
+ ///
+ //@{
+
+ /// The constructor.
+ ///
+ /// \throw none
+ ///
+ /// \param mem_sgmt The memory segment used for the zone data.
+ /// \param rrclass The RRclass of the zone data.
+ /// \param zone_name The Name of the zone under which records will be
+ /// added.
+ // \param zone_data The ZoneData object which is populated with
+ // record data.
+ ZoneDataUpdater(util::MemorySegment& mem_sgmt,
+ isc::dns::RRClass rrclass,
+ const isc::dns::Name& zone_name,
+ ZoneData& zone_data) :
+ mem_sgmt_(mem_sgmt),
+ rrclass_(rrclass),
+ zone_name_(zone_name),
+ zone_data_(zone_data),
+ hash_(NULL)
+ {}
+
+ /// The destructor.
+ ~ZoneDataUpdater() {
+ delete hash_;
+ }
+
+ //@}
+
+ /// This is thrown if the provided RRset parameter passed to \c
+ /// add() is NULL.
+ struct NullRRset : public InvalidParameter {
+ NullRRset(const char* file, size_t line, const char* what) :
+ InvalidParameter(file, line, what)
+ {}
+ };
+
+ /// \brief General failure exception for \c add().
+ ///
+ /// This is thrown against general error cases in adding an RRset
+ /// to the zone.
+ ///
+ /// Note: this exception would cover cases for \c OutOfZone or
+ /// \c NullRRset. We'll need to clarify and unify the granularity
+ /// of exceptions eventually. For now, exceptions are added as
+ /// developers see the need for it.
+ struct AddError : public InvalidParameter {
+ AddError(const char* file, size_t line, const char* what) :
+ InvalidParameter(file, line, what)
+ {}
+ };
+
+ /// \brief Add an RRset to the zone.
+ ///
+ /// This is the core method of this class. It is used to add an
+ /// RRset to the ZoneData associated with this object. The RRset is
+ /// first validated for correctness and consistency with the rest of
+ /// the records in the zone, and then an RdataSet is created and
+ /// populated with the record data and added to the ZoneData for the
+ /// name in the RRset.
+ ///
+ /// This method throws an \c NullRRset exception (see above) if
+ /// \c rrset is empty. It throws \c AddError if any of a variety of
+ /// validation checks fail for the \c rrset and its associated
+ /// \c sig_rrset.
+ ///
+ /// \param rrset The RRset to be added.
+ /// \param sig_rrset An associated RRSIG RRset for the \c rrset. It
+ /// can be empty if there is no RRSIG for the \c rrset.
+ void add(const isc::dns::ConstRRsetPtr& rrset,
+ const isc::dns::ConstRRsetPtr& sig_rrset);
+
+private:
+ // Add the necessary magic for any wildcard contained in 'name'
+ // (including itself) to be found in the zone.
+ //
+ // In order for wildcard matching to work correctly in the zone finder,
+ // we must ensure that a node for the wildcarding level exists in the
+ // backend ZoneTree.
+ // E.g. if the wildcard name is "*.sub.example." then we must ensure
+ // that "sub.example." exists and is marked as a wildcard level.
+ // Note: the "wildcarding level" is for the parent name of the wildcard
+ // name (such as "sub.example.").
+ //
+ // We also perform the same trick for empty wild card names possibly
+ // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
+ void addWildcards(const isc::dns::Name& name);
+
+ // Does some checks in context of the data that are already in the
+ // zone. Currently checks for forbidden combinations of RRsets in
+ // the same domain (CNAME+anything, DNAME+NS). If such condition is
+ // found, it throws AddError.
+ void contextCheck(const isc::dns::AbstractRRset& rrset,
+ const RdataSet* set) const;
+
+ // Validate rrset before adding it to the zone. If something is wrong
+ // it throws an exception. It doesn't modify the zone, and provides
+ // the strong exception guarantee.
+ void validate(const isc::dns::ConstRRsetPtr rrset) const;
+
+ const isc::dns::NSEC3Hash* getNSEC3Hash();
+ template <typename T>
+ void setupNSEC3(const isc::dns::ConstRRsetPtr rrset);
+ void addNSEC3(const isc::dns::ConstRRsetPtr rrset,
+ const isc::dns::ConstRRsetPtr rrsig);
+ void addRdataSet(const isc::dns::ConstRRsetPtr rrset,
+ const isc::dns::ConstRRsetPtr rrsig);
+
+ util::MemorySegment& mem_sgmt_;
+ const isc::dns::RRClass rrclass_;
+ const isc::dns::Name& zone_name_;
+ ZoneData& zone_data_;
+ RdataEncoder encoder_;
+ const isc::dns::NSEC3Hash* hash_;
+};
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_ZONE_DATA_UPDATER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index c5b6c10..8785a10 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -29,6 +29,8 @@
#include <datasrc/data_source.h>
#include <datasrc/memory/zone_data.h>
#include <datasrc/memory/zone_table.h>
+#include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/memory/zone_data_loader.h>
#include <datasrc/memory/memory_client.h>
#include <testutils/dnsmessage_test.h>
@@ -44,6 +46,7 @@ using namespace isc::dns::rdata;
using namespace isc::datasrc;
using namespace isc::datasrc::memory;
using namespace isc::testutils;
+using std::vector;
namespace {
@@ -86,8 +89,7 @@ private:
MockIterator(const char** rrset_data_ptr, bool pass_empty_rrsig) :
rrset_data_ptr_(rrset_data_ptr),
pass_empty_rrsig_(pass_empty_rrsig)
- {
- }
+ {}
const char** rrset_data_ptr_;
// If true, emulate an unexpected bogus case where an RRSIG RRset is
@@ -123,6 +125,34 @@ public:
}
};
+class MockVectorIterator : public ZoneIterator {
+private:
+ MockVectorIterator(const vector<ConstRRsetPtr>& rrsets) :
+ rrsets_(rrsets),
+ counter_(0)
+ {}
+
+ const vector<ConstRRsetPtr> rrsets_;
+ int counter_;
+
+public:
+ virtual ConstRRsetPtr getNextRRset() {
+ if (counter_ >= rrsets_.size()) {
+ return (ConstRRsetPtr());
+ }
+
+ return (rrsets_[counter_++]);
+ }
+
+ virtual ConstRRsetPtr getSOA() const {
+ isc_throw(isc::NotImplemented, "Not implemented");
+ }
+
+ static ZoneIteratorPtr makeIterator(const vector<ConstRRsetPtr>& rrsets) {
+ return (ZoneIteratorPtr(new MockVectorIterator(rrsets)));
+ }
+};
+
class MemoryClientTest : public ::testing::Test {
protected:
MemoryClientTest() : zclass_(RRClass::IN()),
@@ -187,7 +217,7 @@ TEST_F(MemoryClientTest, loadEmptyZoneFileThrows) {
EXPECT_THROW(client_->load(Name("."),
TEST_DATA_DIR "/empty.zone"),
- InMemoryClient::EmptyZone);
+ EmptyZone);
EXPECT_EQ(0, client_->getZoneCount());
@@ -241,13 +271,13 @@ TEST_F(MemoryClientTest, loadFromIterator) {
EXPECT_THROW(client_->load(Name("example.org"),
*MockIterator::makeIterator(
rrset_data_separated)),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Similar to the previous case, but with separated RRSIGs.
EXPECT_THROW(client_->load(Name("example.org"),
*MockIterator::makeIterator(
rrset_data_sigseparated)),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Emulating bogus iterator implementation that passes empty RRSIGs.
EXPECT_THROW(client_->load(Name("example.org"),
@@ -259,10 +289,17 @@ TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
// Just to check that things get cleaned up
for (int i = 1; i < 16; i++) {
+ SCOPED_TRACE("For throw count = " + i);
mem_sgmt_.setThrowCount(i);
- EXPECT_THROW(client_->load(Name("example.org"),
- TEST_DATA_DIR "/example.org.zone"),
- std::bad_alloc);
+ EXPECT_THROW({
+ // Include the InMemoryClient construction too here. Now,
+ // even allocations done from InMemoryClient constructor
+ // fail (due to MemorySegmentTest throwing) and we check for
+ // leaks when this happens.
+ InMemoryClient client2(mem_sgmt_, zclass_);
+ client2.load(Name("example.org"),
+ TEST_DATA_DIR "/example.org.zone");
+ }, std::bad_alloc);
}
// Teardown checks for memory segment leaks
}
@@ -383,7 +420,7 @@ TEST_F(MemoryClientTest, loadDuplicateType) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-duplicate-type-bad.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -392,7 +429,7 @@ TEST_F(MemoryClientTest, loadMultipleCNAMEThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-multiple-cname.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -401,7 +438,7 @@ TEST_F(MemoryClientTest, loadMultipleDNAMEThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-multiple-dname.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -410,7 +447,7 @@ TEST_F(MemoryClientTest, loadMultipleNSEC3Throws) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-multiple-nsec3.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -419,7 +456,7 @@ TEST_F(MemoryClientTest, loadMultipleNSEC3PARAMThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-multiple-nsec3param.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -437,7 +474,7 @@ TEST_F(MemoryClientTest, loadWildcardNSThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-wildcard-ns.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -446,7 +483,7 @@ TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-wildcard-dname.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -455,7 +492,7 @@ TEST_F(MemoryClientTest, loadWildcardNSEC3Throws) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-wildcard-nsec3.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -464,7 +501,7 @@ TEST_F(MemoryClientTest, loadNSEC3WithFewerLabelsThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-nsec3-fewer-labels.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -473,7 +510,7 @@ TEST_F(MemoryClientTest, loadNSEC3WithMoreLabelsThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-nsec3-more-labels.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -482,12 +519,12 @@ TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-cname-and-not-nsec-1.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-cname-and-not-nsec-2.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -513,7 +550,7 @@ TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex1) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-dname-ns-nonapex-1.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -522,7 +559,7 @@ TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex2) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-dname-ns-nonapex-2.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -532,7 +569,7 @@ TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-rrsig-follows-nothing.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -542,6 +579,33 @@ TEST_F(MemoryClientTest, loadRRSIGs) {
EXPECT_EQ(1, client_->getZoneCount());
}
+TEST_F(MemoryClientTest, loadRRSIGsRdataMixedCoveredTypes) {
+ vector<ConstRRsetPtr> rrsets_vec;
+
+ rrsets_vec.push_back(textToRRset("example.org. 3600 IN SOA "
+ "ns1.example.org. bugs.x.w.example.org. "
+ "2010012601 3600 300 3600000 1200",
+ zclass_, Name("example.org")));
+ RRsetPtr rrset(textToRRset("example.org. 3600 IN A 192.0.2.1\n"
+ "example.org. 3600 IN A 192.0.2.2\n"));
+ RRsetPtr rrsig(textToRRset("example.org. 300 IN RRSIG "
+ "A 5 3 3600 20000101000000 20000201000000 "
+ "12345 example.org. FAKEFAKEFAKE"));
+ // textToRRset (correctly) consider this RDATA belongs to a different
+ // RRSIG, so we need to manually add it.
+ rrsig->addRdata(generic::RRSIG("NS 5 3 3600 20000101000000 20000201000000 "
+ "54321 example.org. FAKEFAKEFAKEFAKE"));
+ rrset->addRRsig(rrsig);
+
+ rrsets_vec.push_back(rrset);
+
+ EXPECT_THROW(
+ client_->load(Name("example.org"),
+ *MockVectorIterator::makeIterator(rrsets_vec)),
+ ZoneDataUpdater::AddError);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, getZoneCount) {
EXPECT_EQ(0, client_->getZoneCount());
client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
@@ -631,6 +695,22 @@ TEST_F(MemoryClientTest, getIteratorGetSOAThrowsNotImplemented) {
EXPECT_THROW(iterator->getSOA(), isc::NotImplemented);
}
+TEST_F(MemoryClientTest, addEmptyRRsetThrows) {
+ vector<ConstRRsetPtr> rrsets_vec;
+ rrsets_vec.push_back(textToRRset("example.org. 3600 IN SOA "
+ "ns1.example.org. bugs.x.w.example.org. "
+ "2010012601 3600 300 3600000 1200",
+ zclass_, Name("example.org")));
+ rrsets_vec.push_back(RRsetPtr(new RRset(Name("example.org"), zclass_,
+ RRType::A(), RRTTL(3600))));
+
+ EXPECT_THROW(
+ client_->load(Name("example.org"),
+ *MockVectorIterator::makeIterator(rrsets_vec)),
+ ZoneDataUpdater::AddError);
+ // Teardown checks for memory segment leaks
+}
+
TEST_F(MemoryClientTest, findZoneData) {
client_->load(Name("example.org"),
TEST_DATA_DIR "/example.org-rrsigs.zone");
@@ -682,15 +762,4 @@ TEST_F(MemoryClientTest, getJournalReaderNotImplemented) {
isc::NotImplemented);
}
-// TODO (upon merge of #2268): Re-add (and modify not to need
-// InMemoryClient::add) the tests removed in
-// 7a628baa1a158b5837d6f383e10b30542d2ac59b. Maybe some of them
-// are really not needed.
-//
-// * MemoryClientTest::loadRRSIGsRdataMixedCoveredTypes
-// * MemoryClientTest::addRRsetToNonExistentZoneThrows
-// * MemoryClientTest::addOutOfZoneThrows
-// * MemoryClientTest::addNullRRsetThrows
-// * MemoryClientTest::addEmptyRRsetThrows
-// * MemoryClientTest::add
}
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index a536bf5..4cd08c0 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -23,6 +23,7 @@
#include "../../tests/faked_nsec3.h"
#include <datasrc/memory/zone_finder.h>
+#include <datasrc/memory/zone_data_updater.h>
#include <datasrc/memory/rdata_serialization.h>
#include <datasrc/data_source.h>
#include <testutils/dnsmessage_test.h>
@@ -105,7 +106,8 @@ public:
class_(RRClass::IN()),
origin_("example.org"),
zone_data_(ZoneData::create(mem_sgmt_, origin_)),
- zone_finder_(*zone_data_, class_)
+ zone_finder_(*zone_data_, class_),
+ updater_(mem_sgmt_, class_, origin_, *zone_data_)
{
// Build test RRsets. Below, we construct an RRset for
// each textual RR(s) of zone_data, and assign it to the corresponding
@@ -190,130 +192,8 @@ public:
ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
}
- // NSEC3-specific call for 'loading' data
- void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
- assert(rrset->getType() == RRType::NSEC3());
-
- 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);
- }
-
- // simplified version of 'loading' data
- void addZoneData(const ConstRRsetPtr rrset) {
- ZoneNode* node = NULL;
-
- if (rrset->getType() == RRType::NSEC3()) {
- return (addZoneDataNSEC3(rrset));
- } else if (rrset->getType() == RRType::NSEC()) {
- zone_data_->setSigned(true);
- }
-
- zone_data_->insertName(mem_sgmt_, rrset->getName(), &node);
-
- if (rrset->getType() == RRType::NS() &&
- rrset->getName() != zone_data_->getOriginNode()->getName()) {
- node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
- } else if (rrset->getType() == RRType::DNAME()) {
- node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
- }
-
- RdataSet* next_rds = node->getData();
- RdataSet* rdataset =
- RdataSet::create(mem_sgmt_, encoder_, rrset, rrset->getRRsig());
- rdataset->next = next_rds;
- node->setData(rdataset);
-
- // find wildcard nodes in name (go through all of them in case there
- // is a nonterminal one)
- // Note that this method is pretty much equal to the 'real' loader;
- // but less efficient
- Name name(rrset->getName());
- while (name.getLabelCount() > 1) {
- if (name.isWildcard()) {
- ZoneNode* wnode = NULL;
- // add Wild node
- zone_data_->insertName(mem_sgmt_, name.split(1), &wnode);
- wnode->setFlag(ZoneData::WILDCARD_NODE);
- // add wildcard name itself too
- zone_data_->insertName(mem_sgmt_, name, &wnode);
- }
- 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());
- }
- }
- }
+ void addToZoneData(const ConstRRsetPtr rrset) {
+ updater_.add(rrset, rrset->getRRsig());
}
// Some data to test with
@@ -323,7 +203,7 @@ public:
MemorySegmentTest mem_sgmt_;
memory::ZoneData* zone_data_;
memory::InMemoryZoneFinder zone_finder_;
- isc::datasrc::memory::RdataEncoder encoder_;
+ ZoneDataUpdater updater_;
// Placeholder for storing RRsets to be checked with rrsetsCheck()
vector<ConstRRsetPtr> actual_rrsets_;
@@ -538,7 +418,7 @@ TEST_F(InMemoryZoneFinderTest, constructor) {
TEST_F(InMemoryZoneFinderTest, findCNAME) {
// install CNAME RR
- addZoneData(rr_cname_);
+ addToZoneData(rr_cname_);
// Find A RR of the same. Should match the CNAME
findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
@@ -553,10 +433,10 @@ TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
// There's nothing special when we find a CNAME under a zone cut
// (with FIND_GLUE_OK). The behavior is different from BIND 9,
// so we test this case explicitly.
- addZoneData(rr_child_ns_);
+ addToZoneData(rr_child_ns_);
ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
"cname.child.example.org. 300 IN CNAME target.child.example.org.");
- addZoneData(rr_cname_under_cut_);
+ addToZoneData(rr_cname_under_cut_);
findTest(Name("cname.child.example.org"), RRType::AAAA(),
ZoneFinder::CNAME, true, rr_cname_under_cut_,
ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
@@ -564,7 +444,7 @@ TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
// Search under a DNAME record. It should return the DNAME
TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
- EXPECT_NO_THROW(addZoneData(rr_dname_));
+ EXPECT_NO_THROW(addToZoneData(rr_dname_));
findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
true, rr_dname_);
}
@@ -572,8 +452,8 @@ TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
// Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
// influences only the data below (see RFC 2672, section 3)
TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
- EXPECT_NO_THROW(addZoneData(rr_dname_));
- EXPECT_NO_THROW(addZoneData(rr_dname_a_));
+ EXPECT_NO_THROW(addToZoneData(rr_dname_));
+ EXPECT_NO_THROW(addToZoneData(rr_dname_a_));
const Name dname_name(rr_dname_->getName());
findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
@@ -585,8 +465,8 @@ TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
// Try searching something that is both under NS and DNAME, without and with
// GLUE_OK mode (it should stop at the NS and DNAME respectively).
TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
- addZoneData(rr_child_ns_);
- addZoneData(rr_child_dname_);
+ addToZoneData(rr_child_ns_);
+ addToZoneData(rr_child_dname_);
Name lowName("below.dname.child.example.org.");
@@ -598,10 +478,10 @@ TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
// Test adding child zones and zone cut handling
TEST_F(InMemoryZoneFinderTest, delegationNS) {
// add in-zone data
- EXPECT_NO_THROW(addZoneData(rr_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_ns_));
// install a zone cut
- EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
// below the zone cut
findTest(Name("www.child.example.org"), RRType::A(),
@@ -618,7 +498,7 @@ TEST_F(InMemoryZoneFinderTest, delegationNS) {
findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
// unusual case of "nested delegation": the highest cut should be used.
- EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_grandchild_ns_));
findTest(Name("www.grand.child.example.org"), RRType::A(),
// note: !rr_grandchild_ns_
ZoneFinder::DELEGATION, true, rr_child_ns_);
@@ -627,9 +507,9 @@ TEST_F(InMemoryZoneFinderTest, delegationNS) {
TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
// Similar setup to the previous one, but with DS RR at the delegation
// point.
- addZoneData(rr_ns_);
- addZoneData(rr_child_ns_);
- addZoneData(rr_child_ds_);
+ addToZoneData(rr_ns_);
+ addToZoneData(rr_child_ns_);
+ addToZoneData(rr_child_ds_);
// Normal types of query should result in delegation, but DS query
// should be considered in-zone (but only exactly at the delegation point).
@@ -647,9 +527,9 @@ TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
}
TEST_F(InMemoryZoneFinderTest, findAny) {
- EXPECT_NO_THROW(addZoneData(rr_a_));
- EXPECT_NO_THROW(addZoneData(rr_ns_));
- EXPECT_NO_THROW(addZoneData(rr_child_glue_));
+ EXPECT_NO_THROW(addToZoneData(rr_a_));
+ EXPECT_NO_THROW(addToZoneData(rr_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_child_glue_));
vector<ConstRRsetPtr> expected_sets;
@@ -668,7 +548,7 @@ TEST_F(InMemoryZoneFinderTest, findAny) {
findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
// add zone cut
- EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
// zone cut
findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
@@ -684,16 +564,16 @@ TEST_F(InMemoryZoneFinderTest, findAny) {
TEST_F(InMemoryZoneFinderTest, glue) {
// install zone data:
// a zone cut
- EXPECT_NO_THROW(addZoneData(rr_child_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_child_ns_));
// glue for this cut
- EXPECT_NO_THROW(addZoneData(rr_child_glue_));
+ EXPECT_NO_THROW(addToZoneData(rr_child_glue_));
// a nested zone cut (unusual)
- EXPECT_NO_THROW(addZoneData(rr_grandchild_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_grandchild_ns_));
// glue under the deeper zone cut
- EXPECT_NO_THROW(addZoneData(rr_grandchild_glue_));
+ EXPECT_NO_THROW(addToZoneData(rr_grandchild_glue_));
// glue 'at the' zone cut
- EXPECT_NO_THROW(addZoneData(rr_ns_a_));
- EXPECT_NO_THROW(addZoneData(rr_ns_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_ns_a_));
+ EXPECT_NO_THROW(addToZoneData(rr_ns_ns_));
// by default glue is hidden due to the zone cut
findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
@@ -749,16 +629,16 @@ InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
rr_a_->addRRsig(createRdata(RRType::RRSIG(), RRClass::IN(),
"A 5 3 3600 20120814220826 20120715220826 "
"1234 example.com. FAKE"));
- EXPECT_NO_THROW(addZoneData(rr_ns_));
- EXPECT_NO_THROW(addZoneData(rr_ns_a_));
- EXPECT_NO_THROW(addZoneData(rr_ns_aaaa_));
- EXPECT_NO_THROW(addZoneData(rr_a_));
+ EXPECT_NO_THROW(addToZoneData(rr_ns_));
+ EXPECT_NO_THROW(addToZoneData(rr_ns_a_));
+ EXPECT_NO_THROW(addToZoneData(rr_ns_aaaa_));
+ EXPECT_NO_THROW(addToZoneData(rr_a_));
if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- addZoneData(rr_nsec3_);
+ addToZoneData(rr_nsec3_);
zone_data_->setSigned(true);
}
if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- addZoneData(rr_nsec_);
+ addToZoneData(rr_nsec_);
zone_data_->setSigned(true);
}
@@ -805,7 +685,7 @@ InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags,
expected_nsec, expected_flags, NULL, find_options);
if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- addZoneData(rr_ns_nsec_);
+ addToZoneData(rr_ns_nsec_);
zone_data_->setSigned(true);
if ((find_options & ZoneFinder::FIND_DNSSEC) != 0) {
expected_nsec = rr_ns_nsec_;
@@ -841,8 +721,8 @@ InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
ConstRRsetPtr expected_nsec,
ZoneFinder::FindResultFlags expected_flags)
{
- addZoneData(rr_emptywild_);
- addZoneData(rr_under_wild_);
+ addToZoneData(rr_emptywild_);
+ addToZoneData(rr_under_wild_);
// Sanity check: Should result in NXRRSET
findTest(ent_name, RRType::A(), ZoneFinder::NXRRSET, true,
@@ -854,10 +734,10 @@ InMemoryZoneFinderTest::findNSECENTCheck(const Name& ent_name,
// Now add the NSEC rrs making it a 'complete' zone (in terms of NSEC,
// there are no sigs)
- addZoneData(rr_nsec_);
- addZoneData(rr_ent_nsec2_);
- addZoneData(rr_ent_nsec3_);
- addZoneData(rr_ent_nsec4_);
+ addToZoneData(rr_nsec_);
+ addToZoneData(rr_ent_nsec2_);
+ addToZoneData(rr_ent_nsec3_);
+ addToZoneData(rr_ent_nsec4_);
zone_data_->setSigned(true);
// Should result in NXRRSET, and RESULT_NSEC_SIGNED
@@ -915,14 +795,14 @@ InMemoryZoneFinderTest::emptyNodeCheck(
for (int i = 0; names[i] != NULL; ++i) {
ConstRRsetPtr rrset = textToRRset(string(names[i]) +
" 300 IN A 192.0.2.1");
- addZoneData(rrset);
+ addToZoneData(rrset);
}
if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- addZoneData(rr_nsec3_);
+ addToZoneData(rr_nsec3_);
zone_data_->setSigned(true);
}
if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- addZoneData(rr_nsec_);
+ addToZoneData(rr_nsec_);
zone_data_->setSigned(true);
}
@@ -989,15 +869,15 @@ InMemoryZoneFinderTest::wildcardCheck(
"RRSIG CNAME " +
string(rrsig_common)));
}
- addZoneData(rr_wild_);
- addZoneData(rr_cnamewild_);
+ addToZoneData(rr_wild_);
+ addToZoneData(rr_cnamewild_);
// If the zone is expected to be "signed" with NSEC3, add an NSEC3.
// (the content of the NSEC3 shouldn't matter)
if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- addZoneData(rr_nsec3_);
+ addToZoneData(rr_nsec3_);
}
if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- addZoneData(rr_nsec_);
+ addToZoneData(rr_nsec_);
}
// Search at the parent. The parent will not have the A, but it will
@@ -1073,7 +953,7 @@ InMemoryZoneFinderTest::wildcardCheck(
wild_expected_flags, NULL, find_options, wild_ok);
}
- addZoneData(rr_under_wild_);
+ addToZoneData(rr_under_wild_);
{
SCOPED_TRACE("Search under non-wildcard");
findTest(Name("bar.foo.wild.example.org"), RRType::A(),
@@ -1090,7 +970,7 @@ InMemoryZoneFinderTest::wildcardCheck(
// NO_WILDCARD effect itself can be checked by the result code (NXDOMAIN).
ConstRRsetPtr expected_wild_nsec; // by default it's NULL
if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- addZoneData(rr_wild_nsec_);
+ addToZoneData(rr_wild_nsec_);
expected_wild_nsec = rr_wild_nsec_;
}
{
@@ -1127,8 +1007,8 @@ TEST_F(InMemoryZoneFinderTest, wildcardDisabledWithoutNSEC) {
* the wildcard defaults."
*/
TEST_F(InMemoryZoneFinderTest, delegatedWildcard) {
- addZoneData(rr_child_wild_);
- addZoneData(rr_child_ns_);
+ addToZoneData(rr_child_wild_);
+ addToZoneData(rr_child_ns_);
{
SCOPED_TRACE("Looking under delegation point");
@@ -1149,12 +1029,12 @@ void
InMemoryZoneFinderTest::anyWildcardCheck(
ZoneFinder::FindResultFlags expected_flags)
{
- addZoneData(rr_wild_);
+ addToZoneData(rr_wild_);
if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- addZoneData(rr_nsec3_);
+ addToZoneData(rr_nsec3_);
}
if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- addZoneData(rr_nsec_);
+ addToZoneData(rr_nsec_);
}
vector<ConstRRsetPtr> expected_sets;
@@ -1206,12 +1086,12 @@ InMemoryZoneFinderTest::emptyWildcardCheck(
* *
* wild
*/
- addZoneData(rr_emptywild_);
+ addToZoneData(rr_emptywild_);
if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
- addZoneData(rr_nsec3_);
+ addToZoneData(rr_nsec3_);
}
if ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0) {
- addZoneData(rr_nsec_);
+ addToZoneData(rr_nsec_);
}
{
@@ -1263,7 +1143,7 @@ TEST_F(InMemoryZoneFinderTest, emptyWildcardNSEC) {
// Same as emptyWildcard, but with multiple * in the path.
TEST_F(InMemoryZoneFinderTest, nestedEmptyWildcard) {
- addZoneData(rr_nested_emptywild_);
+ addToZoneData(rr_nested_emptywild_);
{
SCOPED_TRACE("Asking for the original record under wildcards");
@@ -1394,8 +1274,8 @@ InMemoryZoneFinderTest::doCancelWildcardCheck(
* shouldn't be canceled isn't.
*/
TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
- addZoneData(rr_wild_);
- addZoneData(rr_not_wild_);
+ addToZoneData(rr_wild_);
+ addToZoneData(rr_not_wild_);
{
SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
@@ -1405,7 +1285,7 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
// Try putting another one under foo.wild....
// The result should be the same but it will be done in another way in the
// code, because the foo.wild.example.org will exist in the tree.
- addZoneData(rr_not_wild_another_);
+ addToZoneData(rr_not_wild_another_);
{
SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
doCancelWildcardCheck();
@@ -1414,15 +1294,15 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcard) {
// Same tests as cancelWildcard for NSEC3-signed zone
TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
- addZoneData(rr_wild_);
- addZoneData(rr_not_wild_);
- addZoneData(rr_nsec3_);
+ addToZoneData(rr_wild_);
+ addToZoneData(rr_not_wild_);
+ addToZoneData(rr_nsec3_);
{
SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
}
- addZoneData(rr_not_wild_another_);
+ addToZoneData(rr_not_wild_another_);
{
SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
doCancelWildcardCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
@@ -1433,9 +1313,9 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC3) {
// or without FIND_DNSSEC option. NSEC should be returned only when the option
// is given.
TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
- addZoneData(rr_wild_);
- addZoneData(rr_not_wild_);
- addZoneData(rr_nsec_);
+ addToZoneData(rr_wild_);
+ addToZoneData(rr_not_wild_);
+ addToZoneData(rr_nsec_);
{
SCOPED_TRACE("Runnig with single entry under foo.wild.example.org");
@@ -1443,7 +1323,7 @@ TEST_F(InMemoryZoneFinderTest, cancelWildcardNSEC) {
ZoneFinder::FIND_DNSSEC);
doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED);
}
- addZoneData(rr_not_wild_another_);
+ addToZoneData(rr_not_wild_another_);
{
SCOPED_TRACE("Runnig with two entries under foo.wild.example.org");
doCancelWildcardCheck(ZoneFinder::RESULT_NSEC_SIGNED,
@@ -1464,7 +1344,7 @@ TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
DataSourceError);
// Only having NSEC3PARAM isn't enough
- addZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
+ addToZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
"1 0 12 aabbccdd"));
EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
DataSourceError);
@@ -1473,7 +1353,7 @@ TEST_F(InMemoryZoneFinderTest, findNSEC3ForBadZone) {
// is guaranteed.
const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
string(nsec3_common);
- addZoneData(textToRRset(ns1_nsec3_text));
+ addToZoneData(textToRRset(ns1_nsec3_text));
EXPECT_THROW(zone_finder_.findNSEC3(Name("www.example.org"), true),
DataSourceError);
}
@@ -1492,16 +1372,16 @@ public:
// zzz.example.org: hash=R5..
const string apex_nsec3_text = string(apex_hash) + ".example.org." +
string(nsec3_common);
- addZoneData(textToRRset(apex_nsec3_text));
+ addToZoneData(textToRRset(apex_nsec3_text));
const string ns1_nsec3_text = string(ns1_hash) + ".example.org." +
string(nsec3_common);
- addZoneData(textToRRset(ns1_nsec3_text));
+ addToZoneData(textToRRset(ns1_nsec3_text));
const string w_nsec3_text = string(w_hash) + ".example.org." +
string(nsec3_common);
- addZoneData(textToRRset(w_nsec3_text));
+ addToZoneData(textToRRset(w_nsec3_text));
const string zzz_nsec3_text = string(zzz_hash) + ".example.org." +
string(nsec3_common);
- addZoneData(textToRRset(zzz_nsec3_text));
+ addToZoneData(textToRRset(zzz_nsec3_text));
}
private:
diff --git a/src/lib/datasrc/tests/memory/zone_table_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
index 401d434..80f2a6e 100644
--- a/src/lib/datasrc/tests/memory/zone_table_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
@@ -12,6 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include "memory_segment_test.h"
+
#include <exceptions/exceptions.h>
#include <util/memory_segment_local.h>
@@ -34,27 +36,6 @@ using namespace isc::datasrc::memory;
using namespace isc::datasrc::memory::detail;
namespace {
-// Memory segment specified for tests. It normally behaves like a "local"
-// memory segment. If "throw count" is set to non 0 via setThrowCount(),
-// it continues the normal behavior up to the specified number of calls to
-// allocate(), and throws an exception at the next call.
-class TestMemorySegment : public isc::util::MemorySegmentLocal {
-public:
- TestMemorySegment() : throw_count_(0) {}
- virtual void* allocate(size_t size) {
- if (throw_count_ > 0) {
- if (--throw_count_ == 0) {
- throw std::bad_alloc();
- }
- }
- return (isc::util::MemorySegmentLocal::allocate(size));
- }
- void setThrowCount(size_t count) { throw_count_ = count; }
-
-private:
- size_t throw_count_;
-};
-
class ZoneTableTest : public ::testing::Test {
protected:
ZoneTableTest() : zclass_(RRClass::IN()),
@@ -75,7 +56,7 @@ protected:
}
const RRClass zclass_;
const Name zname1, zname2, zname3;
- TestMemorySegment mem_sgmt_;
+ test::MemorySegmentTest mem_sgmt_;
ZoneTable* zone_table;
};
More information about the bind10-changes
mailing list