Commit 75692d6d authored by Jelte Jansen's avatar Jelte Jansen

Merge branch 'trac494'

Conflicts:
	src/lib/asiolink/asiolink.cc
parents 254f3491 cc5136da
......@@ -652,6 +652,8 @@ AC_CONFIG_FILES([Makefile
src/lib/datasrc/tests/Makefile
src/lib/xfr/Makefile
src/lib/log/Makefile
src/lib/resolve/Makefile
src/lib/resolve/tests/Makefile
src/lib/testutils/Makefile
src/lib/testutils/testdata/Makefile
src/lib/nsas/Makefile
......
......@@ -131,6 +131,9 @@ public:
}
}
void resolve(const isc::dns::QuestionPtr& question,
const isc::resolve::ResolverInterface::CallbackPtr& callback);
void processNormalQuery(const Question& question,
MessagePtr answer_message,
OutputBufferPtr buffer,
......@@ -333,7 +336,6 @@ Resolver::~Resolver() {
delete checkin_;
delete dns_lookup_;
delete dns_answer_;
dlog("Deleting the Resolver",true);
}
void
......@@ -351,6 +353,14 @@ Resolver::getConfigSession() const {
return (impl_->config_session_);
}
void
Resolver::resolve(const isc::dns::QuestionPtr& question,
const isc::resolve::ResolverInterface::CallbackPtr& callback)
{
impl_->resolve(question, callback);
}
void
Resolver::processMessage(const IOMessage& io_message,
MessagePtr query_message,
......@@ -434,6 +444,13 @@ Resolver::processMessage(const IOMessage& io_message,
}
}
void
ResolverImpl::resolve(const QuestionPtr& question,
const isc::resolve::ResolverInterface::CallbackPtr& callback)
{
rec_query_->resolve(question, callback);
}
void
ResolverImpl::processNormalQuery(const Question& question,
MessagePtr answer_message,
......@@ -441,7 +458,7 @@ ResolverImpl::processNormalQuery(const Question& question,
DNSServer* server)
{
dlog("Processing normal query");
rec_query_->sendQuery(question, answer_message, buffer, server);
rec_query_->resolve(question, answer_message, buffer, server);
}
namespace {
......
......@@ -24,6 +24,8 @@
#include <asiolink/asiolink.h>
#include <resolve/resolver_interface.h>
class ResolverImpl;
/**
......@@ -35,7 +37,7 @@ class ResolverImpl;
* answer. It doesn't really know about chasing referrals and similar, it
* simply plugs the parts that know into the network handling code.
*/
class Resolver {
class Resolver : public isc::resolve::ResolverInterface {
///
/// \name Constructors, Assignment Operator and Destructor.
///
......@@ -51,6 +53,10 @@ public:
~Resolver();
//@}
virtual void resolve(
const isc::dns::QuestionPtr& question,
const isc::resolve::ResolverInterface::CallbackPtr& callback);
/// \brief Process an incoming DNS message, then signal 'server' to resume
///
/// A DNS query (or other message) has been received by a \c DNSServer
......
SUBDIRS = exceptions dns cc config datasrc python xfr bench log asiolink \
testutils nsas
testutils nsas resolve
......@@ -32,3 +32,4 @@ libasiolink_la_CXXFLAGS += -Wno-error
endif
libasiolink_la_CPPFLAGS = $(AM_CPPFLAGS)
libasiolink_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la
libasiolink_la_LIBADD += $(top_builddir)/src/lib/resolve/libresolve.la
......@@ -31,13 +31,15 @@
#include <dns/buffer.h>
#include <dns/message.h>
#include <dns/rcode.h>
#include <dns/opcode.h>
#include <asiolink/asiolink.h>
#include <asiolink/internal/tcpdns.h>
#include <asiolink/internal/udpdns.h>
#include <log/dummylog.h>
#include <resolve/resolve.h>
#include <log/dummylog.h>
using namespace asio;
using asio::ip::udp;
......@@ -360,7 +362,8 @@ private:
OutputBufferPtr buffer_;
// Server to notify when we succeed or fail
shared_ptr<DNSServer> server_;
//shared_ptr<DNSServer> server_;
isc::resolve::ResolverInterface::CallbackPtr resolvercallback_;
/*
* TODO Do something more clever with timeouts. In the long term, some
......@@ -487,7 +490,8 @@ public:
RunningQuery(asio::io_service& io, const Question &question,
MessagePtr answer_message, shared_ptr<AddressVector> upstream,
shared_ptr<AddressVector> upstream_root,
OutputBufferPtr buffer, DNSServer* server,
OutputBufferPtr buffer,
isc::resolve::ResolverInterface::CallbackPtr cb,
int query_timeout, int client_timeout, int lookup_timeout,
unsigned retries) :
io_(io),
......@@ -496,7 +500,7 @@ public:
upstream_(upstream),
upstream_root_(upstream_root),
buffer_(buffer),
server_(server->clone()),
resolvercallback_(cb),
query_timeout_(query_timeout),
retries_(retries),
client_timer(io),
......@@ -557,7 +561,7 @@ public:
// same goes if we have an outstanding query (can't delete
// until that one comes back to us)
done_ = true;
server_->resume(resume);
resolvercallback_->success(answer_message_);
if (lookup_timer.cancel() != 0) {
return;
}
......@@ -589,15 +593,19 @@ public:
}
if (done_) {
stop(result == UDPQuery::SUCCESS);
resolvercallback_->success(answer_message_);
//server_->resume(result == UDPQuery::SUCCESS);
delete this;
}
} else if (!done_ && retries_--) {
// We timed out, but we have some retries, so send again
dlog("Timeout, resending query");
send();
} else {
// We are done
stop(false);
// out of retries, give up for now
resolvercallback_->failure();
//server_->resume(false);
delete this;
}
}
};
......@@ -605,19 +613,38 @@ public:
}
void
RecursiveQuery::sendQuery(const Question& question,
MessagePtr answer_message,
OutputBufferPtr buffer,
DNSServer* server)
RecursiveQuery::resolve(const isc::dns::QuestionPtr& question,
const isc::resolve::ResolverInterface::CallbackPtr callback)
{
asio::io_service& io = dns_service_.get_io_service();
MessagePtr answer_message(new Message(Message::RENDER));
OutputBufferPtr buffer(new OutputBuffer(0));
// It will delete itself when it is done
new RunningQuery(io, *question, answer_message, upstream_,
upstream_root_, buffer, callback, query_timeout_,
client_timeout_, lookup_timeout_, retries_);
}
void
RecursiveQuery::resolve(const Question& question,
MessagePtr answer_message,
OutputBufferPtr buffer,
DNSServer* server)
{
// XXX: eventually we will need to be able to determine whether
// the message should be sent via TCP or UDP, or sent initially via
// UDP and then fall back to TCP on failure, but for the moment
// we're only going to handle UDP.
asio::io_service& io = dns_service_.get_io_service();
isc::resolve::ResolverInterface::CallbackPtr crs(
new isc::resolve::ResolverCallbackServer(server));
// It will delete itself when it is done
new RunningQuery(io, question, answer_message, upstream_, upstream_root_,
buffer, server, query_timeout_, client_timeout_,
buffer, crs, query_timeout_, client_timeout_,
lookup_timeout_, retries_);
}
......
......@@ -31,6 +31,7 @@
#include <dns/buffer.h>
#include <dns/message.h>
#include <dns/question.h>
#include <dns/rcode.h>
#include <exceptions/exceptions.h>
......@@ -39,6 +40,8 @@
#include <asiolink/iomessage.h>
#include <asiolink/iosocket.h>
#include <resolve/resolver_interface.h>
namespace asio {
// forward declaration for IOService::get_io_service() below
class io_service;
......@@ -99,6 +102,7 @@ class DNSServiceImpl;
struct IOServiceImpl;
struct IntervalTimerImpl;
/// \brief An exception that is thrown if an error occurs within the IO
/// module. This is mainly intended to be a wrapper exception class for
/// ASIO specific exceptions.
......@@ -529,11 +533,13 @@ class RecursiveQuery {
///
//@{
public:
/// \brief Constructor for use when acting as a forwarder
/// \brief Constructor
///
/// This is currently the only way to construct \c RecursiveQuery
/// object. The addresses of the forward nameservers is specified,
/// and every upstream query will be sent to one random address.
/// object. If the addresses of the forward nameservers is specified,
/// and every upstream query will be sent to one random address, and
/// the result sent back directly. If not, it will do full resolving.
///
/// \param dns_service The DNS Service to perform the recursive
/// query on.
/// \param upstream Addresses and ports of the upstream servers
......@@ -556,20 +562,42 @@ public:
unsigned retries = 3);
//@}
/// \brief Initiates an upstream query in the \c RecursiveQuery object.
/// \brief Initiate resolving
///
/// When sendQuery() is called, a (set of) message(s) is sent
/// asynchronously. If upstream servers are set, one is chosen
/// and the response (if any) from that server will be returned.
///
/// If not upstream is set, a root server is chosen from the
/// root_servers, and the RunningQuery shall do a full resolve
/// (i.e. if the answer is a delegation, it will be followed, etc.)
/// until there is an answer or an error.
///
/// When there is a response or an error and we give up, the given
/// CallbackPtr object shall be called (with either success() or
/// failure(). See ResolverInterface::Callback for more information.
///
/// \param question The question being answered <qname/qclass/qtype>
/// \param callback Callback object. See
/// \c ResolverInterface::Callback for more information
void resolve(const isc::dns::QuestionPtr& question,
const isc::resolve::ResolverInterface::CallbackPtr callback);
/// \brief Initiates resolving for the given question.
///
/// When sendQuery() is called, a message is sent asynchronously to
/// the upstream name server. When a reply arrives, 'server'
/// is placed on the ASIO service queue via io_service::post(), so
/// that the original \c DNSServer objct can resume processing.
/// This actually calls the previous sendQuery() with a default
/// callback object, which calls resume() on the given DNSServer
/// object.
///
/// \param question The question being answered <qname/qclass/qtype>
/// \param buffer An output buffer into which the response can be copied
/// \param answer_message An output Message into which the final response will be copied
/// \param buffer An output buffer into which the intermediate responses will be copied
/// \param server A pointer to the \c DNSServer object handling the client
void sendQuery(const isc::dns::Question& question,
isc::dns::MessagePtr answer_message,
isc::dns::OutputBufferPtr buffer,
DNSServer* server);
void resolve(const isc::dns::Question& question,
isc::dns::MessagePtr answer_message,
isc::dns::OutputBufferPtr buffer,
DNSServer* server);
private:
DNSService& dns_service_;
boost::shared_ptr<std::vector<std::pair<std::string, uint16_t> > >
......
......@@ -678,7 +678,7 @@ TEST_F(ASIOLinkTest, forwarderSend) {
Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
rq.sendQuery(q, answer, buffer, &server);
rq.resolve(q, answer, buffer, &server);
char data[4096];
size_t size = sizeof(data);
......@@ -765,7 +765,7 @@ TEST_F(ASIOLinkTest, forwardQueryTimeout) {
Question question(Name("example.net"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
query.sendQuery(question, answer, buffer, &server);
query.resolve(question, answer, buffer, &server);
// Run the test
io_service_->run();
......@@ -808,7 +808,7 @@ TEST_F(ASIOLinkTest, forwardClientTimeout) {
50, 120, 1000, 3);
Question question(Name("example.net"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
query.sendQuery(question, answer, buffer, &server);
query.resolve(question, answer, buffer, &server);
// Run the test
io_service_->run();
......@@ -854,7 +854,7 @@ TEST_F(ASIOLinkTest, forwardLookupTimeout) {
50, 4000, 120, 5);
Question question(Name("example.net"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
query.sendQuery(question, answer, buffer, &server);
query.resolve(question, answer, buffer, &server);
// Run the test
io_service_->run();
......@@ -888,7 +888,7 @@ TEST_F(ASIOLinkTest, DISABLED_recursiveSendOk) {
Question q(Name("www.isc.org"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
rq.sendQuery(q, answer, buffer, &server);
rq.resolve(q, answer, buffer, &server);
io_service_->run();
// Check that the answer we got matches the one we wanted
......@@ -913,7 +913,7 @@ TEST_F(ASIOLinkTest, DISABLED_recursiveSendNXDOMAIN) {
Question q(Name("wwwdoesnotexist.isc.org"), RRClass::IN(), RRType::A());
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
rq.sendQuery(q, answer, buffer, &server);
rq.resolve(q, answer, buffer, &server);
io_service_->run();
// Check that the answer we got matches the one we wanted
......
......@@ -35,7 +35,6 @@ libnsas_la_SOURCES += nsas_entry.h nsas_types.h
libnsas_la_SOURCES += zone_entry.cc zone_entry.h
libnsas_la_SOURCES += fetchable.h
libnsas_la_SOURCES += address_request_callback.h
libnsas_la_SOURCES += resolver_interface.h
libnsas_la_SOURCES += random_number_generator.h
CLEANFILES = *.gcno *.gcda
......@@ -56,8 +56,8 @@ namespace nsas {
// hash table, on the assumption that three elements is the longest linear
// search we want to do when looking up names in the hash table.
NameserverAddressStore::NameserverAddressStore(
boost::shared_ptr<ResolverInterface> resolver, uint32_t zonehashsize,
uint32_t nshashsize) :
boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
uint32_t zonehashsize, uint32_t nshashsize) :
zone_hash_(new HashTable<ZoneEntry>(new NsasEntryCompare<ZoneEntry>,
zonehashsize)),
nameserver_hash_(new HashTable<NameserverEntry>(
......@@ -78,8 +78,9 @@ namespace {
* called at all to create the object, just call the function.
*/
boost::shared_ptr<ZoneEntry>
newZone(const boost::shared_ptr<ResolverInterface>* resolver, const string* zone,
const RRClass* class_code,
newZone(
const boost::shared_ptr<isc::resolve::ResolverInterface>* resolver,
const string* zone, const RRClass* class_code,
const boost::shared_ptr<HashTable<NameserverEntry> >* ns_hash,
const boost::shared_ptr<LruList<NameserverEntry> >* ns_lru)
{
......
......@@ -20,6 +20,8 @@
#include <boost/shared_ptr.hpp>
#include <resolve/resolver_interface.h>
#include "nsas_types.h"
namespace isc {
......@@ -62,7 +64,8 @@ public:
/// value of 3001 is the first prime number over 3000, and by implication,
/// there is an assumption that there will be more nameservers than zones
/// in the store.
NameserverAddressStore(boost::shared_ptr<ResolverInterface> resolver,
NameserverAddressStore(
boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
uint32_t zonehashsize = 1009, uint32_t nshashsize = 3001);
/// \brief Destructor
......@@ -105,7 +108,7 @@ protected:
boost::shared_ptr<LruList<NameserverEntry> > nameserver_lru_;
// The resolver we use
private:
boost::shared_ptr<ResolverInterface> resolver_;
boost::shared_ptr<isc::resolve::ResolverInterface> resolver_;
//}@
};
......
......@@ -30,12 +30,14 @@
#include <dns/name.h>
#include <dns/rrclass.h>
#include <dns/rrttl.h>
#include <dns/rcode.h>
#include <dns/opcode.h>
#include <dns/question.h>
#include <resolve/resolver_interface.h>
#include "address_entry.h"
#include "nameserver_address.h"
#include "nameserver_entry.h"
#include "resolver_interface.h"
using namespace asiolink;
using namespace isc::nsas;
......@@ -199,7 +201,8 @@ NameserverEntry::setAddressUnreachable(const IOAddress& address) {
* fed back trough this. It holds a shared pointer to the entry so it is not
* destroyed too soon.
*/
class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
class NameserverEntry::ResolverCallback :
public isc::resolve::ResolverInterface::Callback {
public:
ResolverCallback(boost::shared_ptr<NameserverEntry> entry,
AddressFamily family, const RRType& type) :
......@@ -213,11 +216,22 @@ class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
* This extracts the addresses out from the response and puts them
* inside the entry. It tries to reuse the address entries from before (if there were any), to keep their RTTs.
*/
virtual void success(const boost::shared_ptr<AbstractRRset>& response) {
virtual void success(MessagePtr response_message) {
time_t now = time(NULL);
Lock lock(entry_->mutex_);
// TODO: find the correct RRset, not simply the first
if (!response_message ||
response_message->getRcode() != isc::dns::Rcode::NOERROR() ||
response_message->getRRCount(isc::dns::Message::SECTION_ANSWER) == 0) {
failureInternal(lock);
}
isc::dns::RRsetIterator rrsi =
response_message->beginSection(isc::dns::Message::SECTION_ANSWER);
const isc::dns::RRsetPtr response = *rrsi;
vector<AddressEntry> entries;
if (response->getType() != type_ ||
......@@ -363,7 +377,8 @@ class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
};
void
NameserverEntry::askIP(boost::shared_ptr<ResolverInterface> resolver,
NameserverEntry::askIP(
boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
const RRType& type, AddressFamily family)
{
QuestionPtr question(new Question(Name(getName()), RRClass(getClass()),
......@@ -374,7 +389,8 @@ NameserverEntry::askIP(boost::shared_ptr<ResolverInterface> resolver,
}
void
NameserverEntry::askIP(boost::shared_ptr<ResolverInterface> resolver,
NameserverEntry::askIP(
boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
boost::shared_ptr<Callback> callback, AddressFamily family)
{
Lock lock(mutex_);
......
......@@ -36,13 +36,14 @@
#include <dns/rrset.h>
#include <dns/rrtype.h>
#include <resolve/resolver_interface.h>
#include "address_entry.h"
#include "asiolink.h"
#include "nsas_types.h"
#include "hash_key.h"
#include "lru_list.h"
#include "fetchable.h"
#include "resolver_interface.h"
#include "nsas_entry.h"
#include "nameserver_address.h"
......@@ -84,7 +85,6 @@ public:
};
class ZoneEntry;
class ResolverInterface;
/// \brief Nameserver Entry
///
......@@ -247,7 +247,7 @@ public:
* even when there are addresses, if there are no addresses for this
* family.
*/
void askIP(boost::shared_ptr<ResolverInterface> resolver,
void askIP(boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
boost::shared_ptr<Callback> callback, AddressFamily family);
//@}
......@@ -279,7 +279,7 @@ private:
/// \short Private version that does the actual asking of one address type
///
/// Call unlocked.
void askIP(boost::shared_ptr<ResolverInterface> resolver,
void askIP(boost::shared_ptr<isc::resolve::ResolverInterface> resolver,
const isc::dns::RRType&, AddressFamily);
};
......
......@@ -86,7 +86,7 @@ public:
* if it is asked for by the resolver.
*/
void lookupAndAnswer(const string& name, const RRClass& class_code,
boost::shared_ptr<AbstractRRset> authority,
RRsetPtr authority,
boost::shared_ptr<AddressRequestCallback> callback)
{
size_t size(resolver_->requests.size());
......
......@@ -39,7 +39,7 @@ class NameserverEntrySample {
public:
NameserverEntrySample():
name_("example.org"),
rrv4_(new BasicRRset(name_, RRClass::IN(), RRType::A(), RRTTL(1200)))
rrv4_(new RRset(name_, RRClass::IN(), RRType::A(), RRTTL(1200)))
{
// Add some sample A records
rrv4_->addRdata(ConstRdataPtr(new RdataTest<A>("1.2.3.4")));
......@@ -50,7 +50,7 @@ public:
boost::shared_ptr<TestResolver> resolver(new TestResolver);
ns_->askIP(resolver, boost::shared_ptr<Callback>(new Callback), ANY_OK);
resolver->asksIPs(name_, 0, 1);
resolver->requests[0].second->success(rrv4_);
resolver->requests[0].second->success(createResponseMessage(rrv4_));
}
// Return the sample NameserverEntry
......@@ -73,7 +73,7 @@ public:
private:
Name name_; ///< Name of the sample
boost::shared_ptr<BasicRRset> rrv4_; ///< Standard RRSet - IN, A, lowercase name
RRsetPtr rrv4_; ///< Standard RRSet - IN, A, lowercase name
boost::shared_ptr<NameserverEntry> ns_; ///< Shared_ptr that points to a NameserverEntry object
class Callback : public NameserverEntry::Callback {
......
......@@ -69,10 +69,10 @@ private:
* as a failure.
*/
void fillSet(boost::shared_ptr<TestResolver> resolver, size_t index,
boost::shared_ptr<BasicRRset> set)
RRsetPtr set)
{
if (set) {
resolver->requests[index].second->success(set);
resolver->requests[index].second->success(createResponseMessage(set));
} else {
resolver->requests[index].second->failure();
}
......@@ -80,7 +80,7 @@ private:
protected:
/// Fills the nameserver entry with data trough ask IP
void fillNSEntry(boost::shared_ptr<NameserverEntry> entry,
boost::shared_ptr<BasicRRset> rrv4, boost::shared_ptr<BasicRRset> rrv6)
RRsetPtr rrv4, RRsetPtr rrv6)
{
// Prepare data to run askIP
boost::shared_ptr<TestResolver> resolver(new TestResolver);
......@@ -212,13 +212,13 @@ TEST_F(NameserverEntryTest, ExpirationTime) {
// Test where there is a single TTL
boost::shared_ptr<NameserverEntry> alpha(new NameserverEntry(EXAMPLE_CO_UK,
RRClass::IN()));
fillNSEntry(alpha, rrv4_, boost::shared_ptr<BasicRRset>());
fillNSEntry(alpha, rrv4_, RRsetPtr());
expiration = alpha->getExpiration();
EXPECT_EQ(expiration, curtime + rrv4_->getTTL().getValue());
boost::shared_ptr<NameserverEntry> beta(new NameserverEntry(EXAMPLE_CO_UK,
RRClass::IN()));
fillNSEntry(beta, boost::shared_ptr<BasicRRset>(), rrv6_);
fillNSEntry(beta, RRsetPtr(), rrv6_);
expiration = beta->getExpiration();
EXPECT_EQ(expiration, curtime + rrv6_->getTTL().getValue());
......@@ -237,7 +237,7 @@ TEST_F(NameserverEntryTest, ExpirationTime) {
boost::shared_ptr<NameserverEntry> delta(new NameserverEntry(EXAMPLE_CO_UK,
RRClass::IN()));
fillNSEntry(delta, rrv4_, boost::shared_ptr<BasicRRset>());
fillNSEntry(delta, rrv4_, RRsetPtr());
EXPECT_GT(delta->getExpiration(), rrv4_->getTTL().getValue());
}
......@@ -347,9 +347,9 @@ TEST_F(NameserverEntryTest, DirectAnswer) {
resolver->addPresetAnswer(Question(Name(EXAMPLE_CO_UK), RRClass::IN(),
RRType::AAAA()), rrv6_);
resolver->addPresetAnswer(Question(Name(EXAMPLE_NET), RRClass::IN(),
RRType::A()), boost::shared_ptr<AbstractRRset>());
RRType::A()), RRsetPtr());
resolver->addPresetAnswer(Question(Name(EXAMPLE_NET), RRClass::IN(),
RRType::AAAA()), boost::shared_ptr<AbstractRRset>());
RRType::AAAA()), RRsetPtr());
// A successfull test first
entry->askIP(resolver, callback, ANY_OK);
......