Commit 692c6b15 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

Merge branch 'trac504'

parents 3e151d44 ea084ffd
......@@ -73,6 +73,15 @@ struct MemoryZone::MemoryZoneImpl {
if (!rrset) {
isc_throw(NullRRset, "The rrset provided is NULL");
if (rrset->getType() == RRType::CNAME() &&
rrset->getRdataCount() > 1) {
// XXX: this is not only for CNAME. We should generalize this
// code for all other "singleton RR types" (such as SOA) in a
// separate task.
isc_throw(AddError, "multiple RRs of singleton type for "
<< rrset->getName());
Name name(rrset->getName());
NameComparisonResult compare(;
if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
......@@ -92,7 +101,7 @@ struct MemoryZone::MemoryZoneImpl {
assert(node != NULL);
// Now get the domain
DomainPtr domain;
......@@ -104,6 +113,25 @@ struct MemoryZone::MemoryZoneImpl {
domain = node->getData();
// Ensure CNAME and other type of RR don't coexist for the same
// owner name.
// 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.
if (rrset->getType() == RRType::CNAME()) {
// XXX: this check will become incorrect when we support DNSSEC
// (depending on how we support DNSSEC). We should revisit it
// at that point.
if (!domain->empty()) {
isc_throw(AddError, "CNAME can't be added with other data for "
<< rrset->getName());
} else if (domain->find(RRType::CNAME()) != domain->end()) {
isc_throw(AddError, "CNAME and " << rrset->getType() <<
" can't coexist for " << rrset->getName());
// Try inserting the rrset there
if (domain->insert(DomainPair(rrset->getType(), rrset)).second) {
// Ok, we just put it in
......@@ -227,13 +255,14 @@ struct MemoryZone::MemoryZoneImpl {
// Good, it is here
return (FindResult(SUCCESS, found->second));
} else {
* TODO Look for CNAME and DNAME (it should be OK to do so when
* the value is not found, as CNAME/DNAME domain should be
* empty otherwise.)
return (FindResult(NXRRSET, ConstRRsetPtr()));
// Next, try CNAME.
found = node->getData()->find(RRType::CNAME());
if (found != node->getData()->end()) {
return (FindResult(CNAME, found->second));
// No exact match or CNAME. Return NXRRSET.
return (FindResult(NXRRSET, ConstRRsetPtr()));
......@@ -71,10 +71,15 @@ public:
/// It puts another RRset into the zone.
/// It throws NullRRset or OutOfZone if the provided rrset is invalid. It
/// might throw standard allocation exceptions, in which case this function
/// does not guarantee strong exception safety (it is currently not needed,
/// if it is needed in future, it should be implemented).
/// Except for NullRRset and OutOfZone, this method does not guarantee
/// strong exception safety (it is currently not needed, if it is needed
/// in future, it should be implemented).
/// \throw NullRRset \c rrset is a NULL pointer.
/// \throw OutOfZone The owner name of \c rrset is outside of the
/// origin of the zone.
/// \throw AddError Other general errors.
/// \throw Others This method might throw standard allocation exceptions.
/// \param rrset The set to add.
/// \return SUCCESS or EXIST (if an rrset for given name and type already
......@@ -100,6 +105,21 @@ public:
{ }
/// \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)
{ }
/// Return the master file name of the zone
/// This method returns the name of the zone's master file to be loaded.
......@@ -15,6 +15,8 @@
#include <exceptions/exceptions.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
#include <dns/rrttl.h>
#include <dns/masterload.h>
......@@ -24,6 +26,7 @@
#include <gtest/gtest.h>
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc;
namespace {
......@@ -142,6 +145,7 @@ public:
......@@ -153,6 +157,8 @@ public:
rr_ns_a_(new RRset(ns_name_, class_, RRType::A(), RRTTL(300))),
rr_ns_aaaa_(new RRset(ns_name_, class_, RRType::AAAA(), RRTTL(300))),
rr_a_(new RRset(origin_, class_, RRType::A(), RRTTL(300))),
rr_cname_(new RRset(cname_name_, class_, RRType::CNAME(), RRTTL(300))),
rr_cname_a_(new RRset(cname_name_, class_, RRType::A(), RRTTL(300))),
rr_child_ns_(new RRset(child_ns_name_, class_, RRType::NS(),
rr_child_glue_(new RRset(child_glue_name_, class_, RRType::A(),
......@@ -165,8 +171,8 @@ public:
// Some data to test with
const RRClass class_;
const Name origin_, ns_name_, child_ns_name_, child_glue_name_,
grandchild_ns_name_, grandchild_glue_name_;
const Name origin_, ns_name_, cname_name_, child_ns_name_,
child_glue_name_, grandchild_ns_name_, grandchild_glue_name_;
// The zone to torture by tests
MemoryZone zone_;
......@@ -187,6 +193,8 @@ public:
// A of
RRsetPtr rr_cname_; // CNAME in (RDATA will be added)
ConstRRsetPtr rr_cname_a_; // for mixed CNAME + A case
ConstRRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
ConstRRsetPtr rr_child_glue_; // glue RR of the child domain
ConstRRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
......@@ -264,6 +272,49 @@ TEST_F(MemoryZoneTest, add) {
EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_.add(rr_ns_a_)));
TEST_F(MemoryZoneTest, addMultipleCNAMEs) {
EXPECT_THROW(zone_.add(rr_cname_), MemoryZone::AddError);
TEST_F(MemoryZoneTest, addCNAMEThenOther) {
EXPECT_EQ(SUCCESS, zone_.add(rr_cname_));
EXPECT_THROW(zone_.add(rr_cname_a_), MemoryZone::AddError);
TEST_F(MemoryZoneTest, addOtherThenCNAME) {
EXPECT_EQ(SUCCESS, zone_.add(rr_cname_a_));
EXPECT_THROW(zone_.add(rr_cname_), MemoryZone::AddError);
TEST_F(MemoryZoneTest, findCNAME) {
// install CNAME RR
EXPECT_EQ(SUCCESS, zone_.add(rr_cname_));
// Find A RR of the same. Should match the CNAME
findTest(cname_name_, RRType::NS(), Zone::CNAME, true, rr_cname_);
// Find the CNAME itself. Should result in normal SUCCESS
findTest(cname_name_, RRType::CNAME(), Zone::SUCCESS, true, rr_cname_);
TEST_F(MemoryZoneTest, 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.
EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_));
RRsetPtr rr_cname_under_cut_(new RRset(Name(""),
class_, RRType::CNAME(),
EXPECT_EQ(SUCCESS, zone_.add(rr_cname_under_cut_));
findTest(Name(""), RRType::AAAA(),
Zone::CNAME, true, rr_cname_under_cut_, NULL, Zone::FIND_GLUE_OK);
// Test adding child zones and zone cut handling
TEST_F(MemoryZoneTest, delegationNS) {
// add in-zone data
......@@ -155,8 +155,11 @@ public:
/// - If there is a matching name but no RRset of the search type, it
/// returns the code of \c NXRRSET, and, if DNSSEC is required,
/// the NSEC RRset for that name.
/// - If there is a matching name with CNAME, it returns the code of
/// \c CNAME and that CNAME RR.
/// - If there is a CNAME RR of the searched name but there is no
/// RR of the searched type of the name (so this type is different from
/// CNAME), it returns the code of \c CNAME and that CNAME RR.
/// Note that if the searched RR type is CNAME, it is considered
/// a successful match, and the code of \c SUCCESS will be returned.
/// - If the search name matches a delegation point of DNAME, it returns
/// the code of \c DNAME and that DNAME RR.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment