DatabaseClient::Finder::FoundRRsets
DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
- bool check_ns, const string* construct_name)
+ bool check_ns, const string* construct_name,
+ bool any)
{
RRsigStore sig_store;
bool records_found = false;
columns[DatabaseAccessor::RDATA_COLUMN]));
}
- if (types.find(cur_type) != types.end()) {
+ if (types.find(cur_type) != types.end() || any) {
// This type is requested, so put it into result
const RRTTL cur_ttl(columns[DatabaseAccessor::TTL_COLUMN]);
// Ths sigtype column was an optimization for finding the
sig_store.appendSignatures(i->second);
}
+ if (records_found && any) {
+ result[RRType::ANY()] = RRsetPtr();
+ // These will be sitting on the other RRsets.
+ result.erase(RRType::RRSIG());
+ }
+
return (FoundRRsets(records_found, result));
}
}
ZoneFinder::FindResult
-DatabaseClient::Finder::findAll(const isc::dns::Name&,
- std::vector<isc::dns::ConstRRsetPtr>&,
- const FindOptions)
+DatabaseClient::Finder::findAll(const isc::dns::Name& name,
+ std::vector<isc::dns::ConstRRsetPtr>& target,
+ const FindOptions options)
{
- isc_throw(isc::NotImplemented, "Not implemented");
+ return (findInternal(name, RRType::ANY(), &target, options));
}
ZoneFinder::FindResult
DatabaseClient::Finder::find(const isc::dns::Name& name,
const isc::dns::RRType& type,
const FindOptions options)
+{
+ return (findInternal(name, type, NULL, options));
+}
+
+ZoneFinder::FindResult
+DatabaseClient::Finder::findInternal(const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ std::vector<isc::dns::ConstRRsetPtr>*
+ target,
+ const FindOptions options)
{
// This variable is used to determine the difference between
// NXDOMAIN and NXRRSET
bool glue_ok((options & FIND_GLUE_OK) != 0);
const bool dnssec_data((options & FIND_DNSSEC) != 0);
bool get_cover(false);
+ bool any(type == RRType::ANY());
isc::dns::RRsetPtr result_rrset;
ZoneFinder::Result result_status = SUCCESS;
FoundRRsets found;
WantedTypes final_types(FINAL_TYPES());
final_types.insert(type);
- found = getRRsets(name.toText(), final_types, name != origin);
+ found = getRRsets(name.toText(), final_types, name != origin, NULL,
+ any);
records_found = found.first;
// NS records, CNAME record and Wanted Type records
}
} else if (wti != found.second.end()) {
// Just get the answer
+ // TODO update here
result_rrset = wti->second;
+ if (any) {
+ for (FoundIterator it(found.second.begin());
+ it != found.second.end(); ++it) {
+ if (it->second) {
+ // Skip over the empty ANY
+ target->push_back(it->second);
+ }
+ }
+ return (FindResult(result_status, result_rrset));
+ }
} else if (!records_found) {
// Nothing lives here.
// But check if something lives below this
// TODO What do we do about DNAME here?
// The types are the same as with original query
found = getRRsets(wildcard, final_types, true,
- &construct_name);
+ &construct_name, any);
if (found.first) {
if (first_ns) {
// In case we are under NS, we don't
result_status = DELEGATION;
} else if (wti != found.second.end()) {
result_rrset = wti->second;
+ // TODO Update here
result_status = WILDCARD;
+ if (any) {
+ for (FoundIterator
+ it(found.second.begin());
+ it != found.second.end(); ++it) {
+ if (it->second) {
+ // Skip over the empty ANY
+ target->push_back(it->second);
+ }
+ }
+ return (FindResult(result_status,
+ result_rrset));
+ }
} else {
// NXRRSET case in the wildcard
result_status = WILDCARD_NXRRSET;
boost::shared_ptr<DatabaseAccessor> accessor_;
const int zone_id_;
const isc::dns::Name origin_;
- //
/// \brief Shortcut name for the result of getRRsets
typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
FoundRRsets;
/// \brief Just shortcut for set of types
typedef std::set<dns::RRType> WantedTypes;
+ /**
+ * \brief Internal logit of find and findAll methods.
+ *
+ * Most of their handling is in the "error" cases and delegations
+ * and so on. So they share the logic here and find and findAll provide
+ * just an interface for it.
+ *
+ * Parameters and behaviour is like of those combined together.
+ * Unexpected parameters, like type != ANY and having the target, are
+ * just that - unexpected and not checked.
+ */
+ FindResult findInternal(const isc::dns::Name& name,
+ const isc::dns::RRType& type,
+ std::vector<isc::dns::ConstRRsetPtr>* target,
+ const FindOptions options = FIND_DEFAULT);
/**
* \brief Searches database for RRsets of one domain.
*
* their name set to name. If it is not NULL, it overrides the name
* and uses this one (this can be used for wildcard synthesized
* records).
+ * \param any If this is true, it records all the types, not only the
+ * ones requested by types. It also puts a NULL pointer under the
+ * ANY type into the result, if it finds any RRs at all, to easy the
+ * identification of success.
* \return A pair, where the first element indicates if the domain
* contains any RRs at all (not only the requested, it may happen
* this is set to true, but the second part is empty). The second
*/
FoundRRsets getRRsets(const std::string& name,
const WantedTypes& types, bool check_ns,
- const std::string* construct_name = NULL);
+ const std::string* construct_name = NULL,
+ bool any = false);
/**
* \brief Checks if something lives below this domain.
*
}
}
+void
+doFindAllTestResult(ZoneFinder& finder, const isc::dns::Name& name,
+ ZoneFinder::Result expected_result,
+ const isc::dns::RRType expected_type,
+ std::vector<std::string> expected_rdata,
+ const isc::dns::Name& expected_name =
+ isc::dns::Name::ROOT_NAME(),
+ const ZoneFinder::FindOptions options =
+ ZoneFinder::FIND_DEFAULT)
+{
+ SCOPED_TRACE("All test for " + name.toText());
+ std::vector<ConstRRsetPtr> target;
+ ZoneFinder::FindResult result(finder.findAll(name, target, options));
+ EXPECT_TRUE(target.empty());
+ EXPECT_EQ(expected_result, result.code);
+ EXPECT_EQ(expected_type, result.rrset->getType());
+ RdataIteratorPtr it(result.rrset->getRdataIterator());
+ std::vector<std::string> rdata;
+ while (!it->isLast()) {
+ rdata.push_back(it->getCurrent().toText());
+ it->next();
+ }
+ std::sort(rdata.begin(), rdata.end());
+ std::sort(expected_rdata.begin(), expected_rdata.end());
+ ASSERT_EQ(expected_rdata.size(), rdata.size());
+ for (size_t i(0); i < expected_rdata.size(); ++ i) {
+ EXPECT_EQ(expected_rdata[i], rdata[i]);
+ }
+ EXPECT_TRUE(expected_rdata == rdata);
+ EXPECT_EQ(expected_name == isc::dns::Name::ROOT_NAME() ? name :
+ expected_name, result.rrset->getName());
+}
+
// When asking for an RRset where RRs somehow have different TTLs, it should
// convert to the lowest one.
TEST_F(MockDatabaseClientTest, ttldiff) {
Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC));
}
+// Test the findAll method.
+TYPED_TEST(DatabaseClientTest, getAll) {
+ // The domain doesn't exist, so we must get the right NSEC
+ shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
+
+ // It should act the same on the "failures"
+ std::vector<ConstRRsetPtr> target;
+ EXPECT_EQ(ZoneFinder::NXDOMAIN,
+ finder->findAll(isc::dns::Name("nothere.example.org."),
+ target).code);
+ EXPECT_TRUE(target.empty());
+ EXPECT_EQ(ZoneFinder::NXRRSET,
+ finder->findAll(isc::dns::Name("here.wild.example.org."),
+ target).code);
+ this->expected_rdatas_.push_back("ns.delegation.example.org.");
+ this->expected_rdatas_.push_back("ns.example.com.");
+ doFindAllTestResult(*finder, isc::dns::Name("xx.delegation.example.org."),
+ ZoneFinder::DELEGATION, RRType::NS(),
+ this->expected_rdatas_,
+ isc::dns::Name("delegation.example.org."));
+ this->expected_rdatas_.clear();
+ this->expected_rdatas_.push_back("www.example.org.");
+ doFindAllTestResult(*finder, isc::dns::Name("cname.example.org"),
+ ZoneFinder::CNAME, RRType::CNAME(),
+ this->expected_rdatas_);
+ this->expected_rdatas_.clear();
+ this->expected_rdatas_.push_back("dname.example.com.");
+ doFindAllTestResult(*finder, isc::dns::Name("a.dname.example.org"),
+ ZoneFinder::DNAME, RRType::DNAME(),
+ this->expected_rdatas_,
+ isc::dns::Name("dname.example.org."));
+ // It should get the data on success
+ EXPECT_EQ(ZoneFinder::SUCCESS,
+ finder->findAll(isc::dns::Name("www2.example.org."),
+ target).code);
+ ASSERT_EQ(2, target.size());
+ size_t a_idx(target[1]->getType() == RRType::A());
+ EXPECT_EQ(RRType::A(), target[a_idx]->getType());
+ std::string previous;
+ size_t count(0);
+ for (RdataIteratorPtr it(target[a_idx]->getRdataIterator());
+ !it->isLast(); it->next()) {
+ count ++;
+ EXPECT_NE(previous, it->getCurrent().toText());
+ EXPECT_TRUE(it->getCurrent().toText() == "192.0.2.1" ||
+ it->getCurrent().toText() == "192.0.2.2");
+ previous = it->getCurrent().toText();
+ }
+ EXPECT_EQ(2, count);
+ EXPECT_EQ(RRType::AAAA(), target[1 - a_idx]->getType());
+ RdataIteratorPtr it(target[1 - a_idx]->getRdataIterator());
+ ASSERT_FALSE(it->isLast());
+ EXPECT_EQ("2001:db8::1", it->getCurrent().toText());
+ it->next();
+ EXPECT_TRUE(it->isLast());
+
+ // And on wildcard. Check the signatures as well.
+ target.clear();
+ EXPECT_EQ(ZoneFinder::WILDCARD,
+ finder->findAll(isc::dns::Name("a.wild.example.org"),
+ target, ZoneFinder::FIND_DNSSEC).code);
+ ASSERT_EQ(2, target.size());
+ a_idx = target[1]->getType() == RRType::A();
+ EXPECT_EQ(RRType::A(), target[a_idx]->getType());
+ it = target[a_idx]->getRdataIterator();
+ ASSERT_FALSE(it->isLast());
+ EXPECT_EQ("192.0.2.5", it->getCurrent().toText());
+ it->next();
+ EXPECT_TRUE(it->isLast());
+ ConstRRsetPtr sig(target[a_idx]->getRRsig());
+ ASSERT_TRUE(sig);
+ EXPECT_EQ(RRType::RRSIG(), sig->getType());
+ EXPECT_EQ("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE",
+ sig->getRdataIterator()->getCurrent().toText());
+ EXPECT_EQ(RRType::NSEC(), target[1 - a_idx]->getType());
+ it = target[1 - a_idx]->getRdataIterator();
+ ASSERT_FALSE(it->isLast());
+ EXPECT_EQ("cancel.here.wild.example.org. A RRSIG NSEC",
+ it->getCurrent().toText());
+ it->next();
+ EXPECT_TRUE(it->isLast());
+ sig = target[1 - a_idx]->getRRsig();
+ ASSERT_TRUE(sig);
+ EXPECT_EQ(RRType::RRSIG(), sig->getType());
+ EXPECT_EQ("NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE",
+ sig->getRdataIterator()->getCurrent().toText());
+}
+
TYPED_TEST(DatabaseClientTest, getOrigin) {
DataSourceClient::FindResult
zone(this->client_->findZone(Name("example.org")));