false),
ConstRRsetPtr(), ConstRRsetPtr());
}
+
+TEST_F(TreeNodeRRsetTest, isSameKind) {
+ const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
+
+ // Same name (node), same type (rdataset) => same kind
+ EXPECT_TRUE(rrset.isSameKind(TreeNodeRRset(rrclass_, www_node_,
+ a_rdataset_, true)));
+
+ // Same name (node), different type (rdataset) => not same kind
+ EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, www_node_,
+ aaaa_rdataset_, true)));
+
+ // Different name, different type => not same kind
+ EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, origin_node_,
+ ns_rdataset_, true)));
+
+ // Different name, same type => not same kind.
+ // Note: this shouldn't happen in our in-memory data source implementation,
+ // but API doesn't prohibit it.
+ EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, origin_node_,
+ a_rdataset_, true)));
+
+ // Wildcard and expanded RRset
+ const TreeNodeRRset wildcard_rrset(rrclass_, wildcard_node_,
+ wildcard_rdataset_, true);
+ const TreeNodeRRset match_rrset(match_name_, rrclass_, wildcard_node_,
+ wildcard_rdataset_, true);
+ EXPECT_FALSE(wildcard_rrset.isSameKind(match_rrset));
+ EXPECT_FALSE(match_rrset.isSameKind(wildcard_rrset));
+
+ // Both are wildcard expanded, and have different names
+ const TreeNodeRRset match2_rrset(Name("match2.example.com"), rrclass_,
+ wildcard_node_, wildcard_rdataset_, true);
+ EXPECT_FALSE(match_rrset.isSameKind(match2_rrset));
+ EXPECT_FALSE(match2_rrset.isSameKind(match_rrset));
+
+ // Pathological case. "badwild" is constructed as if expanded due to
+ // a wildcard, but has the same owner name of the wildcard itself.
+ // Technically, they should be considered of the same kind, but this
+ // implementation considers they are not. But this case shouldn't happen
+ // as long as the RRsets are only constructed inside the in-memory
+ // zone finder implementation.
+ const TreeNodeRRset badwild_rrset(wildcard_name_, rrclass_, wildcard_node_,
+ wildcard_rdataset_, true);
+ EXPECT_FALSE(wildcard_rrset.isSameKind(badwild_rrset));
+ EXPECT_EQ(wildcard_rrset.toText(), badwild_rrset.toText());
+
+ // Pathological case: Same name, same type, but different class.
+ // This case should be impossible because if the RRsets share the same
+ // tree node, they must belong to the same RR class. This case is
+ // a caller's bug, and the isSameKind() implementation returns the
+ // "wrong" (= true) answer.
+ EXPECT_TRUE(rrset.isSameKind(TreeNodeRRset(RRClass::CH(), www_node_,
+ a_rdataset_, true)));
+
+ // Same kind of different RRset class
+ EXPECT_TRUE(rrset.isSameKind(*a_rrset_));
+
+ // Different kind of different RRset class
+ EXPECT_FALSE(rrset.isSameKind(*aaaa_rrset_));
+}
}
namespace datasrc {
namespace memory {
-TreeNodeRRset::TreeNodeRRset(const dns::Name& realname, dns::RRClass rrclass,
+TreeNodeRRset::TreeNodeRRset(const dns::Name& realname,
+ const dns::RRClass& rrclass,
const ZoneNode* node, const RdataSet* rdataset,
bool dnssec_ok) :
node_(node), rdataset_(rdataset),
isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
}
-// needed
bool
-TreeNodeRRset::isSameKind(const AbstractRRset& /*other*/) const {
- isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
+TreeNodeRRset::isSameKind(const AbstractRRset& abs_other) const {
+ const TreeNodeRRset* other =
+ dynamic_cast<const TreeNodeRRset*>(&abs_other);
+ if (other != NULL) {
+ // If type is different, they are not the same kind
+ if (rdataset_ != other->rdataset_) {
+ return (false);
+ }
+ // Same for the owner name (note: in practice this method would be
+ // called for rrsets at different nodes, so we check that condition
+ // first). Note also that based on the basic assumption of the
+ // ZoneTree, if the nodes are different their RR classes must be
+ // different.
+ if (node_ != other->node_ || !hasSameRealName(*other)) {
+ return (false);
+ }
+ return (true);
+ }
+ return (AbstractRRset::isSameKind(abs_other));
+}
+
+bool
+TreeNodeRRset::hasSameRealName(const TreeNodeRRset& other) const {
+ // If one is constructed with a "real name" and the other isn't
+ // *we consider* them different.
+ if ((realname_buf_ == NULL && other.realname_buf_ != NULL) ||
+ (realname_buf_ != NULL && other.realname_buf_ == NULL)) {
+ return (false);
+ }
+
+ // If both are constructed with a "real name", we compare their names
+ // (as label sequences) explicitly.
+ if (realname_buf_ != NULL && other.realname_buf_ != NULL) {
+ uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+ uint8_t other_labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+ if (!getOwnerLabels(labels_buf).equals(
+ other.getOwnerLabels(other_labels_buf))) {
+ return (false);
+ }
+ }
+
+ return (true);
}
} // namespace memory
class TreeNodeRRset : public dns::AbstractRRset {
public:
- TreeNodeRRset(dns::RRClass rrclass, const ZoneNode* node,
+ TreeNodeRRset(const dns::RRClass& rrclass, const ZoneNode* node,
const RdataSet* rdataset, bool dnssec_ok) :
node_(node), rdataset_(rdataset),
rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
dnssec_ok_(dnssec_ok), name_(NULL), realname_buf_(NULL)
{}
- TreeNodeRRset(const dns::Name& realname, dns::RRClass rrclass,
+ TreeNodeRRset(const dns::Name& realname, const dns::RRClass& rrclass,
const ZoneNode* node, const RdataSet* rdataset,
bool dnssec_ok);
virtual void addRRsig(const dns::RRsetPtr& sigs);
virtual void removeRRsig();
- // needed
- virtual bool isSameKind(const dns::AbstractRRset& other) const;
+ /// \brief Specialized version of \c isSameKind() for \c TreeNodeRRset.
+ ///
+ /// As a kind of optimization, this implementation exploits the assumption
+ /// of how \c TreeNodeRRset objects are created: They must be always
+ /// created inside the in-memory data source finder implementation,
+ /// and they are constructed with the \c realname parameter if and only
+ /// if the corresponding query name is subject to wildcard substitution.
+ ///
+ /// So, if the given RRset is of \c TreeNodeRRset, and one and only one of
+ /// of them has \c realname, they are considered to have different names.
+ ///
+ /// Also, this implementation does not compare RR classes explicitly;
+ /// if two \c TreeNodeRRset objects belong to different RR classes,
+ /// they should belong to different zone trees (according to the assumption
+ /// of how the zone data are built), and therefore they cannot be at
+ /// same zone node. So it's sufficient to compare the (address of the)
+ /// node; if they are different they cannot be of the same kind.
+ virtual bool isSameKind(const dns::AbstractRRset& abs_other) const;
private:
dns::RdataIteratorPtr getSigRdataIterator() const;
return (node_->getAbsoluteLabels(labels_buf));
}
+ // A helper for isSameKind() to check if 'this' and 'other' has
+ // the same "real" name in case at least either is constructed with
+ // a real name.
+ bool hasSameRealName(const TreeNodeRRset& other) const;
+
const ZoneNode* node_;
const RdataSet* rdataset_;
const size_t rrsig_count_;