Commit 17106327 authored by Stephen Morris's avatar Stephen Morris

[trac703] Merge branch 'master' into trac703

... master being updated shortly after the last merge.
Conflicts:
	src/lib/asiodns/io_fetch.cc
	src/lib/asiodns/io_fetch.h
parents 06c4fa64 262ac6c6
......@@ -644,6 +644,8 @@ AC_CONFIG_FILES([Makefile
src/lib/Makefile
src/lib/asiolink/Makefile
src/lib/asiolink/tests/Makefile
src/lib/asiodns/Makefile
src/lib/asiodns/tests/Makefile
src/lib/bench/Makefile
src/lib/bench/example/Makefile
src/lib/bench/tests/Makefile
......
......@@ -49,6 +49,7 @@ b10_auth_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
b10_auth_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
b10_auth_LDADD += $(top_builddir)/src/lib/cc/libcc.la
b10_auth_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
b10_auth_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
b10_auth_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
b10_auth_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
b10_auth_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
......
......@@ -68,7 +68,8 @@ using namespace isc::dns::rdata;
using namespace isc::data;
using namespace isc::config;
using namespace isc::xfr;
using namespace asiolink;
using namespace isc::asiolink;
using namespace isc::asiodns;
using namespace isc::server_common::portconfig;
class AuthSrvImpl {
......@@ -766,6 +767,6 @@ AuthSrv::setListenAddresses(const AddressList& addresses) {
}
void
AuthSrv::setDNSService(asiolink::DNSService& dnss) {
AuthSrv::setDNSService(isc::asiodns::DNSService& dnss) {
dnss_ = &dnss;
}
......@@ -26,11 +26,11 @@
#include <dns/message.h>
#include <dns/buffer.h>
#include <asiodns/dns_server.h>
#include <asiodns/dns_lookup.h>
#include <asiodns/dns_answer.h>
#include <asiolink/io_message.h>
#include <asiolink/io_service.h>
#include <asiolink/dns_server.h>
#include <asiolink/dns_lookup.h>
#include <asiolink/dns_answer.h>
#include <asiolink/simple_callback.h>
#include <asiolink/asiolink.h>
......@@ -116,10 +116,10 @@ public:
/// \param server Pointer to the \c DNSServer
///
/// \throw isc::Unexpected Protocol type of \a message is unexpected
void processMessage(const asiolink::IOMessage& io_message,
void processMessage(const isc::asiolink::IOMessage& io_message,
isc::dns::MessagePtr message,
isc::dns::OutputBufferPtr buffer,
asiolink::DNSServer* server);
isc::asiodns::DNSServer* server);
/// \brief Set verbose flag
///
......@@ -202,16 +202,16 @@ public:
void setConfigSession(isc::config::ModuleCCSession* config_session);
/// \brief Return this object's ASIO IO Service queue
asiolink::IOService& getIOService();
isc::asiolink::IOService& getIOService();
/// \brief Return pointer to the DNS Lookup callback function
asiolink::DNSLookup* getDNSLookupProvider() const { return (dns_lookup_); }
isc::asiodns::DNSLookup* getDNSLookupProvider() const { return (dns_lookup_); }
/// \brief Return pointer to the DNS Answer callback function
asiolink::DNSAnswer* getDNSAnswerProvider() const { return (dns_answer_); }
isc::asiodns::DNSAnswer* getDNSAnswerProvider() const { return (dns_answer_); }
/// \brief Return pointer to the Checkin callback function
asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); }
isc::asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); }
/// \brief Set or update the size (number of slots) of hot spot cache.
///
......@@ -372,15 +372,15 @@ public:
const;
/// \brief Assign an ASIO DNS Service queue to this Auth object
void setDNSService(asiolink::DNSService& dnss);
void setDNSService(isc::asiodns::DNSService& dnss);
private:
AuthSrvImpl* impl_;
asiolink::SimpleCallback* checkin_;
asiolink::DNSLookup* dns_lookup_;
asiolink::DNSAnswer* dns_answer_;
asiolink::DNSService* dnss_;
isc::asiolink::SimpleCallback* checkin_;
isc::asiodns::DNSLookup* dns_lookup_;
isc::asiodns::DNSAnswer* dns_answer_;
isc::asiodns::DNSService* dnss_;
};
#endif // __AUTH_SRV_H
......
......@@ -22,6 +22,7 @@ query_bench_LDADD += $(top_builddir)/src/lib/cc/libcc.la
query_bench_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
query_bench_LDADD += $(top_builddir)/src/lib/log/liblog.la
query_bench_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
query_bench_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
query_bench_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
query_bench_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
query_bench_LDADD += $(SQLITE_LIBS)
......@@ -36,6 +36,7 @@
#include <auth/auth_config.h>
#include <auth/query.h>
#include <asiodns/asiodns.h>
#include <asiolink/asiolink.h>
using namespace std;
......@@ -45,7 +46,8 @@ using namespace isc::auth;
using namespace isc::dns;
using namespace isc::xfr;
using namespace isc::bench;
using namespace asiolink;
using namespace isc::asiodns;
using namespace isc::asiolink;
namespace {
// Commonly used constant:
......
......@@ -43,6 +43,7 @@
#include <auth/command.h>
#include <auth/change_user.h>
#include <auth/auth_srv.h>
#include <asiodns/asiodns.h>
#include <asiolink/asiolink.h>
#include <log/dummylog.h>
......@@ -52,7 +53,8 @@ using namespace isc::cc;
using namespace isc::config;
using namespace isc::dns;
using namespace isc::xfr;
using namespace asiolink;
using namespace isc::asiolink;
using namespace isc::asiodns;
namespace {
......
......@@ -45,6 +45,7 @@ run_unittests_LDADD += $(SQLITE_LIBS)
run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
......
......@@ -44,7 +44,8 @@ using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::data;
using namespace isc::xfr;
using namespace asiolink;
using namespace isc::asiodns;
using namespace isc::asiolink;
using namespace isc::testutils;
using namespace isc::server_common::portconfig;
using isc::UnitTestUtil;
......
......@@ -99,7 +99,7 @@ AuthConmmandTest::stopServer() {
}
TEST_F(AuthConmmandTest, shutdown) {
asiolink::IntervalTimer itimer(server.getIOService());
isc::asiolink::IntervalTimer itimer(server.getIOService());
itimer.setup(boost::bind(&AuthConmmandTest::stopServer, this), 1);
server.getIOService().run();
EXPECT_EQ(0, rcode);
......
......@@ -35,7 +35,8 @@
using namespace isc::dns;
using namespace isc::data;
using namespace isc::datasrc;
using namespace asiolink;
using namespace isc::asiodns;
using namespace isc::asiolink;
namespace {
class AuthConfigTest : public ::testing::Test {
......
......@@ -4,6 +4,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/bin -I$(top_builddir)/src/bin
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cc -I$(top_builddir)/src/lib/cc
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiodns
AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiodns
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink
AM_CPPFLAGS += -I$(top_builddir)/src/lib/asiolink
AM_CPPFLAGS += $(BOOST_INCLUDES)
......@@ -45,6 +47,7 @@ b10_resolver_LDADD = $(top_builddir)/src/lib/dns/libdns++.la
b10_resolver_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
b10_resolver_LDADD += $(top_builddir)/src/lib/cc/libcc.la
b10_resolver_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
b10_resolver_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
b10_resolver_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
b10_resolver_LDADD += $(top_builddir)/src/lib/xfr/libxfr.la
b10_resolver_LDADD += $(top_builddir)/src/lib/log/liblog.la
......
......@@ -27,6 +27,7 @@
#include <boost/foreach.hpp>
#include <asiodns/asiodns.h>
#include <asiolink/asiolink.h>
#include <exceptions/exceptions.h>
......@@ -58,7 +59,8 @@ using namespace isc::cc;
using namespace isc::config;
using namespace isc::data;
using isc::log::dlog;
using namespace asiolink;
using namespace isc::asiodns;
using namespace isc::asiolink;
namespace {
......
......@@ -20,6 +20,7 @@
#include <vector>
#include <cassert>
#include <asiodns/asiodns.h>
#include <asiolink/asiolink.h>
#include <boost/foreach.hpp>
......@@ -54,7 +55,8 @@ using namespace isc::dns;
using namespace isc::data;
using namespace isc::config;
using isc::log::dlog;
using namespace asiolink;
using namespace isc::asiodns;
using namespace isc::asiolink;
using namespace isc::server_common::portconfig;
class ResolverImpl {
......@@ -295,7 +297,7 @@ public:
edns_response->setUDPSize(Message::DEFAULT_MAX_EDNS0_UDPSIZE);
answer_message->setEDNS(edns_response);
}
if (io_message.getSocket().getProtocol() == IPPROTO_UDP) {
if (edns) {
renderer.setLengthLimit(edns->getUDPSize());
......@@ -345,7 +347,7 @@ Resolver::~Resolver() {
}
void
Resolver::setDNSService(asiolink::DNSService& dnss) {
Resolver::setDNSService(isc::asiodns::DNSService& dnss) {
dnss_ = &dnss;
}
......
......@@ -24,12 +24,12 @@
#include <dns/message.h>
#include <dns/buffer.h>
#include <asiodns/dns_server.h>
#include <asiodns/dns_service.h>
#include <asiodns/dns_lookup.h>
#include <asiodns/dns_answer.h>
#include <asiolink/io_message.h>
#include <asiolink/io_service.h>
#include <asiolink/dns_server.h>
#include <asiolink/dns_service.h>
#include <asiolink/dns_lookup.h>
#include <asiolink/dns_answer.h>
#include <asiolink/simple_callback.h>
#include <nsas/nameserver_address_store.h>
......@@ -82,11 +82,11 @@ public:
/// shall return to the client
/// \param buffer Pointer to an \c OutputBuffer for the resposne
/// \param server Pointer to the \c DNSServer
void processMessage(const asiolink::IOMessage& io_message,
void processMessage(const isc::asiolink::IOMessage& io_message,
isc::dns::MessagePtr query_message,
isc::dns::MessagePtr answer_message,
isc::dns::OutputBufferPtr buffer,
asiolink::DNSServer* server);
isc::asiodns::DNSServer* server);
/// \brief Set and get the config session
isc::config::ModuleCCSession* getConfigSession() const;
......@@ -96,16 +96,16 @@ public:
isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
/// \brief Assign an ASIO IO Service queue to this Resolver object
void setDNSService(asiolink::DNSService& dnss);
void setDNSService(isc::asiodns::DNSService& dnss);
/// \brief Assign a NameserverAddressStore to this Resolver object
void setNameserverAddressStore(isc::nsas::NameserverAddressStore &nsas);
/// \brief Assign a cache to this Resolver object
void setCache(isc::cache::ResolverCache& cache);
/// \brief Return this object's ASIO IO Service queue
asiolink::DNSService& getDNSService() const { return (*dnss_); }
isc::asiodns::DNSService& getDNSService() const { return (*dnss_); }
/// \brief Returns this object's NSAS
isc::nsas::NameserverAddressStore& getNameserverAddressStore() const {
......@@ -116,15 +116,15 @@ public:
isc::cache::ResolverCache& getResolverCache() const {
return *cache_;
};
/// \brief Return pointer to the DNS Lookup callback function
asiolink::DNSLookup* getDNSLookupProvider() { return (dns_lookup_); }
isc::asiodns::DNSLookup* getDNSLookupProvider() { return (dns_lookup_); }
/// \brief Return pointer to the DNS Answer callback function
asiolink::DNSAnswer* getDNSAnswerProvider() { return (dns_answer_); }
isc::asiodns::DNSAnswer* getDNSAnswerProvider() { return (dns_answer_); }
/// \brief Return pointer to the Checkin callback function
asiolink::SimpleCallback* getCheckinProvider() { return (checkin_); }
isc::asiolink::SimpleCallback* getCheckinProvider() { return (checkin_); }
/**
* \brief Tell the Resolver that is has already been configured
......@@ -238,10 +238,10 @@ public:
private:
ResolverImpl* impl_;
asiolink::DNSService* dnss_;
asiolink::SimpleCallback* checkin_;
asiolink::DNSLookup* dns_lookup_;
asiolink::DNSAnswer* dns_answer_;
isc::asiodns::DNSService* dnss_;
isc::asiolink::SimpleCallback* checkin_;
isc::asiodns::DNSLookup* dns_lookup_;
isc::asiodns::DNSAnswer* dns_answer_;
isc::nsas::NameserverAddressStore* nsas_;
isc::cache::ResolverCache* cache_;
// This value is initally false, and will be set to true
......@@ -252,6 +252,6 @@ private:
#endif // __RESOLVER_H
// Local Variables:
// Local Variables:
// mode: c++
// End:
// End:
......@@ -26,7 +26,7 @@ using namespace std;
// Compare addresses etc.
ResponseScrubber::Category ResponseScrubber::addressCheck(
const asiolink::IOEndpoint& to, const asiolink::IOEndpoint& from)
const isc::asiolink::IOEndpoint& to, const isc::asiolink::IOEndpoint& from)
{
if (from.getProtocol() == to.getProtocol()) {
if (from.getAddress() == to.getAddress()) {
......
......@@ -282,8 +282,8 @@ public:
///
/// \return SUCCESS if the two endpoints match, otherwise an error status
/// indicating what was incorrect.
static Category addressCheck(const asiolink::IOEndpoint& to,
const asiolink::IOEndpoint& from);
static Category addressCheck(const isc::asiolink::IOEndpoint& to,
const isc::asiolink::IOEndpoint& from);
/// \brief Check QID
///
......
......@@ -31,6 +31,7 @@ run_unittests_LDADD += $(SQLITE_LIBS)
run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libtestutils.la
run_unittests_LDADD += $(top_builddir)/src/lib/datasrc/libdatasrc.la
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
......
......@@ -20,6 +20,7 @@
#include <cc/data.h>
#include <asiodns/asiodns.h>
#include <asiolink/asiolink.h>
#include <resolver/resolver.h>
......@@ -31,7 +32,8 @@
using namespace std;
using namespace isc::data;
using namespace isc::testutils;
using namespace asiolink;
using namespace isc::asiodns;
using namespace isc::asiolink;
using isc::UnitTestUtil;
namespace {
......
......@@ -41,6 +41,7 @@
// Class for endpoint checks. The family of the endpoint is set in the
// constructor; the address family by the string provided for the address.
namespace isc {
namespace asiolink {
class GenericEndpoint : public IOEndpoint {
......@@ -73,13 +74,14 @@ private:
short protocol_; // Protocol of the endpoint
};
}
}
using namespace asio::ip;
using namespace isc::dns;
using namespace rdata;
using namespace isc::dns::rdata::generic;
using namespace isc::dns::rdata::in;
using namespace asiolink;
using namespace isc::asiolink;
// Test class
......
SUBDIRS = exceptions dns cc config util python xfr bench log asiolink \
nsas cache resolve testutils datasrc server_common
asiodns nsas cache resolve testutils datasrc server_common
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/asiolink -I$(top_builddir)/src/lib/asiolink
AM_CXXFLAGS = $(B10_CXXFLAGS)
CLEANFILES = *.gcno *.gcda
lib_LTLIBRARIES = libasiodns.la
libasiodns_la_SOURCES = dns_answer.h
libasiodns_la_SOURCES += asiodef.cc asiodef.h
libasiodns_la_SOURCES += dns_lookup.h
libasiodns_la_SOURCES += dns_server.h
libasiodns_la_SOURCES += dns_service.cc dns_service.h
libasiodns_la_SOURCES += tcp_server.cc tcp_server.h
libasiodns_la_SOURCES += udp_server.cc udp_server.h
libasiodns_la_SOURCES += io_fetch.cc io_fetch.h
libasiodns_la_SOURCES += qid_gen.cc qid_gen.h
EXTRA_DIST = asiodef.msg
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
# B10_CXXFLAGS)
libasiodns_la_CXXFLAGS = $(AM_CXXFLAGS)
if USE_CLANGPP
# Same for clang++, but we need to turn off -Werror completely.
libasiodns_la_CXXFLAGS += -Wno-error
endif
libasiodns_la_CPPFLAGS = $(AM_CPPFLAGS)
libasiodns_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la
The asiodns library is intended to provide an abstraction layer between
BIND10 modules and asiolink library.
These DNS server and client routines are written using the "stackless
coroutine" pattern invented by Chris Kohlhoff and described at
http://blog.think-async.com/2010/03/potted-guide-to-stackless-coroutines.html.
This is intended to simplify development a bit, since it allows the
routines to be written in a straightfowrard step-step-step fashion rather
than as a complex chain of separate handler functions.
Coroutine objects (i.e., UDPServer, TCPServer and IOFetch) are objects
with reenterable operator() members. When an instance of one of these
classes is called as a function, it resumes at the position where it left
off. Thus, a UDPServer can issue an asynchronous I/O call and specify
itself as the handler object; when the call completes, the UDPServer
carries on at the same position. As a result, the code can look as
if it were using synchronous, not asynchronous, I/O, providing some of
the benefit of threading but with minimal switching overhead.
So, in simplified form, the behavior of a DNS Server is:
REENTER:
while true:
YIELD packet = read_packet
FORK
if not parent:
break
# This callback informs the caller that a packet has arrived, and
# gives it a chance to update configuration, etc
SimpleCallback(packet)
YIELD answer = DNSLookup(packet, this)
response = DNSAnswer(answer)
YIELD send(response)
At each "YIELD" point, the coroutine initiates an asynchronous operation,
then pauses and turns over control to some other task on the ASIO service
queue. When the operation completes, the coroutine resumes.
DNSLookup, DNSAnswer and SimpleCallback define callback methods
used by a DNS Server to communicate with the module that called it.
They are abstract-only classes whose concrete implementations
are supplied by the calling module.
The DNSLookup callback always runs asynchronously. Concrete
implementations must be sure to call the server's "resume" method when
it is finished.
In an authoritative server, the DNSLookup implementation would examine
the query, look up the answer, then call "resume". (See the diagram
in doc/auth_process.jpg.)
In a recursive server, the DNSLookup impelemtation would initiate a
DNSQuery, which in turn would be responsible for calling the server's
"resume" method. (See the diagram in doc/recursive_process.jpg.)
A DNSQuery object is intended to handle resolution of a query over
the network when the local authoritative data sources or cache are not
sufficient. The plan is that it will make use of subsidiary DNSFetch
calls to get data from particular authoritative servers, and when it has
gotten a complete answer, it calls "resume".
In current form, however, DNSQuery is much simpler; it forwards queries
to a single upstream resolver and passes the answers back to the client.
It is constructed with the address of the forward server. Queries are
initiated with the question to ask the forward server, a buffer into
which to write the answer, and a pointer to the coroutine to be resumed
when the answer has arrived. In simplified form, the DNSQuery routine is:
REENTER:
render the question into a wire-format query packet
YIELD send(query)
YIELD response = read_packet
server->resume
Currently, DNSQuery is only implemented for UDP queries. In future work
it will be necessary to write code to fall back to TCP when circumstances
require it.
Upstream Fetches
================
Upstream fetches (queries by the resolver on behalf of a client) are made
using a slightly-modified version of the pattern described above.
Sockets
-------
First, it will be useful to understand the class hierarchy used in the
fetch logic:
IOSocket
|
IOAsioSocket
|
+-----+-----+
| |
UDPSocket TCPSocket
IOSocket is a wrapper class for a socket and is used by the authoritative
server code. It is an abstract base class, providing little more that the ability to hold the socket and to return the protocol in use.
Built on this is IOAsioSocket, which adds the open, close, asyncSend and
asyncReceive methods. This is a template class, which takes as template
argument the class of the object that will be used as the callback when the
asynchronous operation completes. This object can be of any type, but must
include an operator() method with the signature:
operator()(asio::error_code ec, size_t length)
... the two arguments being the status of the completed I/O operation and
the number of bytes transferred. (In the case of the open method, the second
argument will be zero.)
Finally, the TCPSocket and UDPSocket classes provide the body of the
asynchronous operations.
Fetch Sequence
--------------
The fetch is implemented by the IOFetch class, which takes as argument the
protocol to use. The sequence is:
REENTER:
render the question into a wire-format query packet
open() // Open socket and optionally connect
if (! synchronous) {
YIELD;
}
YIELD asyncSend(query) // Send query
do {
YIELD asyncReceive(response) // Read response
} while (! complete(response))
close() // Drop connection and close socket
server->resume
The open() method opens a socket for use. On TCP, it also makes a
connection to the remote end. So under UDP the operation will complete
immediately, but under TCP it could take a long time. One solution would be
for the open operation to post an event to the I/O queue; then both cases
could be regarded as being equivalent, with the completion being signalled
by the posting of the completion event. However UDP is the most common case
and that would involve extra overhead. So the open() returns a status
indicating whether the operation completed asynchronously. If it did, the
code yields back to the coroutine; if not the yield is bypassed.
The asynchronous send is straightforward, invoking the underlying ASIO
function. (Note that the address/port is supplied to both the open() and
asyncSend() methods - it is used by the TCPSocket in open() and by the
UDPSocket in asyncSend().)
The asyncReceive() method issues an asynchronous read and waits for completion.
The fetch object keeps track of the amount of data received so far and when
the receive completes it calls a method on the socket to determine if the
entire message has been received. (This will always be the case for UDP. On
TCP though, the message is preceded by a count field as several reads may be