Commit f8e8b2de authored by Jelte Jansen's avatar Jelte Jansen
Browse files

merge ticket #383 (Generalize IOService) back into branches/trac327


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac327@3327 e5f2f494-b856-4b98-b285-d166d9295462
parents 80eda916 d7b6c25f
......@@ -66,7 +66,7 @@ static const char* DNSPORT = "5300";
* class itself? */
static AuthSrv *auth_server;
static IOService* io_service;
static IOService io_service;
ConstElementPtr
my_config_handler(ConstElementPtr new_config) {
......@@ -82,7 +82,7 @@ my_command_handler(const string& command, ConstElementPtr args) {
/* let's add that message to our answer as well */
answer = createAnswer(0, args);
} else if (command == "shutdown") {
io_service->stop();
io_service.stop();
}
return (answer);
......@@ -193,6 +193,7 @@ main(int argc, char* argv[]) {
DNSLookup* lookup = auth_server->getDNSLookupProvider();
DNSAnswer* answer = auth_server->getDNSAnswerProvider();
DNSService* dns_service;
if (address != NULL) {
// XXX: we can only specify at most one explicit address.
// This also means the server cannot run in the dual address
......@@ -200,16 +201,17 @@ main(int argc, char* argv[]) {
// We don't bother to fix this problem, however. The -a option
// is a short term workaround until we support dynamic listening
// port allocation.
io_service = new IOService(*port, *address,
checkin, lookup, answer);
dns_service = new DNSService(io_service, *port, *address,
checkin, lookup, answer);
} else {
io_service = new IOService(*port, use_ipv4, use_ipv6,
checkin, lookup, answer);
dns_service = new DNSService(io_service, *port, use_ipv4,
use_ipv6, checkin, lookup,
answer);
}
auth_server->setIOService(*io_service);
auth_server->setIOService(io_service);
cout << "[b10-auth] IOService created." << endl;
cc_session = new Session(io_service->get_io_service());
cc_session = new Session(io_service.get_io_service());
cout << "[b10-auth] Configuration session channel created." << endl;
config_session = new ModuleCCSession(specfile, *cc_session,
......@@ -221,7 +223,7 @@ main(int argc, char* argv[]) {
changeUser(uid);
}
xfrin_session = new Session(io_service->get_io_service());
xfrin_session = new Session(io_service.get_io_service());
cout << "[b10-auth] Xfrin session channel created." << endl;
xfrin_session->establish(NULL);
xfrin_session_established = true;
......@@ -237,7 +239,7 @@ main(int argc, char* argv[]) {
auth_server->updateConfig(ElementPtr());
cout << "[b10-auth] Server started." << endl;
io_service->run();
io_service.run();
} catch (const std::exception& ex) {
cerr << "[b10-auth] Server failed: " << ex.what() << endl;
ret = 1;
......@@ -250,7 +252,6 @@ main(int argc, char* argv[]) {
delete xfrin_session;
delete config_session;
delete cc_session;
delete io_service;
delete auth_server;
return (ret);
......
......@@ -63,7 +63,7 @@ static bool verbose_mode = false;
static const string PROGRAM = "Recurse";
static const char* DNSPORT = "5300";
static IOService* io_service;
IOService io_service;
static Recursor *recursor;
ConstElementPtr
......@@ -80,7 +80,7 @@ my_command_handler(const string& command, ConstElementPtr args) {
/* let's add that message to our answer as well */
answer = createAnswer(0, args);
} else if (command == "shutdown") {
io_service->stop();
io_service.stop();
}
return (answer);
......@@ -189,6 +189,8 @@ main(int argc, char* argv[]) {
DNSLookup* lookup = recursor->getDNSLookupProvider();
DNSAnswer* answer = recursor->getDNSAnswerProvider();
DNSService* dns_service;
if (address != NULL) {
// XXX: we can only specify at most one explicit address.
// This also means the server cannot run in the dual address
......@@ -196,16 +198,16 @@ main(int argc, char* argv[]) {
// We don't bother to fix this problem, however. The -a option
// is a short term workaround until we support dynamic listening
// port allocation.
io_service = new IOService(*port, *address,
checkin, lookup, answer);
dns_service = new DNSService(io_service, *port, *address,
checkin, lookup, answer);
} else {
io_service = new IOService(*port, use_ipv4, use_ipv6,
checkin, lookup, answer);
dns_service = new DNSService(io_service, *port, use_ipv4, use_ipv6,
checkin, lookup, answer);
}
recursor->setIOService(*io_service);
recursor->setDNSService(*dns_service);
cout << "[b10-recurse] IOService created." << endl;
cc_session = new Session(io_service->get_io_service());
cc_session = new Session(io_service.get_io_service());
cout << "[b10-recurse] Configuration session channel created." << endl;
config_session = new ModuleCCSession(specfile, *cc_session,
......@@ -221,7 +223,7 @@ main(int argc, char* argv[]) {
recursor->updateConfig(ElementPtr());
cout << "[b10-recurse] Server started." << endl;
io_service->run();
io_service.run();
} catch (const std::exception& ex) {
cerr << "[b10-recurse] Server failed: " << ex.what() << endl;
ret = 1;
......@@ -229,7 +231,6 @@ main(int argc, char* argv[]) {
delete config_session;
delete cc_session;
delete io_service;
delete recursor;
return (ret);
......
......@@ -72,8 +72,8 @@ public:
queryShutdown();
}
void querySetup(IOService& ios) {
rec_query_ = new RecursiveQuery(ios, forward_);
void querySetup(DNSService& dnss) {
rec_query_ = new RecursiveQuery(dnss, forward_);
}
void queryShutdown() {
......@@ -296,10 +296,10 @@ Recursor::~Recursor() {
}
void
Recursor::setIOService(asiolink::IOService& ios) {
Recursor::setDNSService(asiolink::DNSService& dnss) {
impl_->queryShutdown();
impl_->querySetup(ios);
io_ = &ios;
impl_->querySetup(dnss);
dnss_ = &dnss;
}
void
......
......@@ -79,10 +79,10 @@ public:
isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr config);
/// \brief Assign an ASIO IO Service queue to this Recursor object
void setIOService(asiolink::IOService& ios);
void setDNSService(asiolink::DNSService& dnss);
/// \brief Return this object's ASIO IO Service queue
asiolink::IOService& getIOService() const { return (*io_); }
asiolink::DNSService& getDNSService() const { return (*dnss_); }
/// \brief Return pointer to the DNS Lookup callback function
asiolink::DNSLookup* getDNSLookupProvider() { return (dns_lookup_); }
......@@ -95,7 +95,7 @@ public:
private:
RecursorImpl* impl_;
asiolink::IOService* io_;
asiolink::DNSService* dnss_;
asiolink::SimpleCallback* checkin_;
asiolink::DNSLookup* dns_lookup_;
asiolink::DNSAnswer* dns_answer_;
......
......@@ -63,16 +63,15 @@ private:
class RecursorTest : public ::testing::Test {
protected:
RecursorTest() : ios(*TEST_PORT, true, false, NULL, NULL, NULL),
server(*DEFAULT_REMOTE_ADDRESS),
request_message(Message::RENDER),
parse_message(new Message(Message::PARSE)),
default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
qname("www.example.com"),
qclass(RRClass::IN()), qtype(RRType::A()),
io_message(NULL), endpoint(NULL), request_obuffer(0),
request_renderer(request_obuffer),
response_obuffer(new OutputBuffer(0))
RecursorTest() : server(*DEFAULT_REMOTE_ADDRESS),
request_message(Message::RENDER),
parse_message(new Message(Message::PARSE)),
default_qid(0x1035), opcode(Opcode(Opcode::QUERY())),
qname("www.example.com"),
qclass(RRClass::IN()), qtype(RRType::A()),
io_message(NULL), endpoint(NULL), request_obuffer(0),
request_renderer(request_obuffer),
response_obuffer(new OutputBuffer(0))
{}
~RecursorTest() {
delete io_message;
......@@ -80,7 +79,6 @@ protected:
}
MockSession notify_session;
MockServer dnsserv;
IOService ios;
Recursor server;
Message request_message;
MessagePtr parse_message;
......
......@@ -43,13 +43,82 @@ using namespace isc::dns;
namespace asiolink {
class IOServiceImpl {
private:
IOServiceImpl(const IOService& source);
IOServiceImpl& operator=(const IOService& source);
public:
IOServiceImpl(const char& port,
/// \brief The constructor
IOServiceImpl() : io_service_() {};
/// \brief The destructor.
~IOServiceImpl() {};
//@}
/// \brief Start the underlying event loop.
///
/// This method does not return control to the caller until
/// the \c stop() method is called via some handler.
void run() { io_service_.run(); };
/// \brief Run the underlying event loop for a single event.
///
/// This method return control to the caller as soon as the
/// first handler has completed. (If no handlers are ready when
/// it is run, it will block until one is.)
void run_one() { io_service_.run_one();} ;
/// \brief Stop the underlying event loop.
///
/// This will return the control to the caller of the \c run() method.
void stop() { io_service_.stop();} ;
/// \brief Return the native \c io_service object used in this wrapper.
///
/// This is a short term work around to support other BIND 10 modules
/// that share the same \c io_service with the authoritative server.
/// It will eventually be removed once the wrapper interface is
/// generalized.
asio::io_service& get_io_service() { return io_service_; };
private:
asio::io_service io_service_;
};
IOService::IOService() {
io_impl_ = new IOServiceImpl();
}
IOService::~IOService() {
delete io_impl_;
}
void
IOService::run() {
io_impl_->run();
}
void
IOService::run_one() {
io_impl_->run_one();
}
void
IOService::stop() {
io_impl_->stop();
}
asio::io_service&
IOService::get_io_service() {
return (io_impl_->get_io_service());
}
class DNSServiceImpl {
public:
DNSServiceImpl(IOService& io_service, const char& port,
const ip::address* v4addr, const ip::address* v6addr,
SimpleCallback* checkin, DNSLookup* lookup,
DNSAnswer* answer);
asio::io_service io_service_;
//asio::io_service io_service_;
void stop();
typedef boost::shared_ptr<UDPServer> UDPServerPtr;
typedef boost::shared_ptr<TCPServer> TCPServerPtr;
UDPServerPtr udp4_server_;
......@@ -58,12 +127,13 @@ public:
TCPServerPtr tcp6_server_;
};
IOServiceImpl::IOServiceImpl(const char& port,
const ip::address* const v4addr,
const ip::address* const v6addr,
SimpleCallback* checkin,
DNSLookup* lookup,
DNSAnswer* answer) :
DNSServiceImpl::DNSServiceImpl(IOService& io_service_,
const char& port,
const ip::address* const v4addr,
const ip::address* const v6addr,
SimpleCallback* checkin,
DNSLookup* lookup,
DNSAnswer* answer) :
udp4_server_(UDPServerPtr()), udp6_server_(UDPServerPtr()),
tcp4_server_(TCPServerPtr()), tcp6_server_(TCPServerPtr())
{
......@@ -85,21 +155,21 @@ IOServiceImpl::IOServiceImpl(const char& port,
try {
if (v4addr != NULL) {
udp4_server_ = UDPServerPtr(new UDPServer(io_service_,
udp4_server_ = UDPServerPtr(new UDPServer(io_service_.get_io_service(),
*v4addr, portnum,
checkin, lookup, answer));
(*udp4_server_)();
tcp4_server_ = TCPServerPtr(new TCPServer(io_service_,
tcp4_server_ = TCPServerPtr(new TCPServer(io_service_.get_io_service(),
*v4addr, portnum,
checkin, lookup, answer));
(*tcp4_server_)();
}
if (v6addr != NULL) {
udp6_server_ = UDPServerPtr(new UDPServer(io_service_,
udp6_server_ = UDPServerPtr(new UDPServer(io_service_.get_io_service(),
*v6addr, portnum,
checkin, lookup, answer));
(*udp6_server_)();
tcp6_server_ = TCPServerPtr(new TCPServer(io_service_,
tcp6_server_ = TCPServerPtr(new TCPServer(io_service_.get_io_service(),
*v6addr, portnum,
checkin, lookup, answer));
(*tcp6_server_)();
......@@ -113,11 +183,12 @@ IOServiceImpl::IOServiceImpl(const char& port,
}
}
IOService::IOService(const char& port, const char& address,
SimpleCallback* checkin,
DNSLookup* lookup,
DNSAnswer* answer) :
impl_(NULL)
DNSService::DNSService(IOService& io_service,
const char& port, const char& address,
SimpleCallback* checkin,
DNSLookup* lookup,
DNSAnswer* answer) :
impl_(NULL), io_service_(io_service)
{
error_code err;
const ip::address addr = ip::address::from_string(&address, err);
......@@ -126,53 +197,34 @@ IOService::IOService(const char& port, const char& address,
<< err.message());
}
impl_ = new IOServiceImpl(port,
impl_ = new DNSServiceImpl(io_service, port,
addr.is_v4() ? &addr : NULL,
addr.is_v6() ? &addr : NULL,
checkin, lookup, answer);
}
IOService::IOService(const char& port,
const bool use_ipv4, const bool use_ipv6,
SimpleCallback* checkin,
DNSLookup* lookup,
DNSAnswer* answer) :
impl_(NULL)
DNSService::DNSService(IOService& io_service,
const char& port,
const bool use_ipv4, const bool use_ipv6,
SimpleCallback* checkin,
DNSLookup* lookup,
DNSAnswer* answer) :
impl_(NULL), io_service_(io_service)
{
const ip::address v4addr_any = ip::address(ip::address_v4::any());
const ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL;
const ip::address v6addr_any = ip::address(ip::address_v6::any());
const ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
impl_ = new IOServiceImpl(port, v4addrp, v6addrp, checkin, lookup, answer);
impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
}
IOService::~IOService() {
DNSService::~DNSService() {
delete impl_;
}
void
IOService::run() {
impl_->io_service_.run();
}
void
IOService::run_one() {
impl_->io_service_.run_one();
}
void
IOService::stop() {
impl_->io_service_.stop();
}
asio::io_service&
IOService::get_io_service() {
return (impl_->io_service_);
}
RecursiveQuery::RecursiveQuery(IOService& io_service, const char& forward,
RecursiveQuery::RecursiveQuery(DNSService& dns_service, const char& forward,
uint16_t port) :
io_service_(io_service), ns_addr_(&forward), port_(port)
dns_service_(dns_service), ns_addr_(&forward), port_(port)
{}
void
......@@ -184,7 +236,7 @@ RecursiveQuery::sendQuery(const Question& question, OutputBufferPtr buffer,
// 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 = io_service_.get_io_service();
asio::io_service& io = dns_service_.get_io_service();
UDPQuery q(io, question, ns_addr_, port_, buffer, server);
io.post(q);
}
......
......@@ -36,6 +36,7 @@
#include <asiolink/ioendpoint.h>
#include <asiolink/iomessage.h>
#include <asiolink/iosocket.h>
//#include <asio/io_service.hpp>
namespace asio {
// forward declaration for IOService::get_io_service() below
......@@ -93,6 +94,7 @@ class io_service;
/// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html
namespace asiolink {
struct DNSServiceImpl;
struct IOServiceImpl;
/// \brief An exception that is thrown if an error occurs within the IO
......@@ -112,18 +114,10 @@ class DNSAnswer;
/// \brief The \c IOService class is a wrapper for the ASIO \c io_service
/// class.
///
/// Currently, the interface of this class is very specific to the
/// authoritative/recursive DNS server implementationss in b10-auth
/// and b10-recurse; this is reflected in the constructor signatures.
/// Ultimately the plan is to generalize it so that other BIND 10
/// modules can use this interface, too.
class IOService {
///
/// \name Constructors and Destructor
///
/// These are currently very specific to the authoritative server
/// implementation.
///
/// Note: The copy constructor and the assignment operator are
/// intentionally defined as private, making this class non-copyable.
//@{
......@@ -131,22 +125,8 @@ private:
IOService(const IOService& source);
IOService& operator=(const IOService& source);
public:
/// \brief The constructor with a specific IP address and port on which
/// the services listen on.
IOService(const char& port, const char& address,
SimpleCallback* checkin,
DNSLookup* lookup,
DNSAnswer* answer);
/// \brief The constructor with a specific port on which the services
/// listen on.
///
/// It effectively listens on "any" IPv4 and/or IPv6 addresses.
/// IPv4/IPv6 services will be available if and only if \c use_ipv4
/// or \c use_ipv6 is \c true, respectively.
IOService(const char& port, const bool use_ipv4, const bool use_ipv6,
SimpleCallback* checkin,
DNSLookup* lookup,
DNSAnswer* answer);
/// \brief The constructor
IOService();
/// \brief The destructor.
~IOService();
//@}
......@@ -176,8 +156,71 @@ public:
/// It will eventually be removed once the wrapper interface is
/// generalized.
asio::io_service& get_io_service();
private:
IOServiceImpl* io_impl_;
};
///
/// DNSService is the service that handles DNS queries and answers with
/// a given IOService.
///
class DNSService {
///
/// \name Constructors and Destructor
///
/// Note: The copy constructor and the assignment operator are
/// intentionally defined as private, making this class non-copyable.
//@{
private:
DNSService(const DNSService& source);
DNSService& operator=(const DNSService& source);
public:
/// \brief The constructor with a specific IP address and port on which
/// the services listen on.
///
/// \param io_service The IOService to work with
/// \param port the port to listen on
/// \param address the IP address to listen on
/// \param checkin Provider for cc-channel events (see \c SimpleCallback)
/// \param lookup The lookup provider (see \c DNSLookup)
/// \param answer The answer provider (see \c DNSAnswer)
DNSService(IOService& io_service, const char& port,
const char& address, SimpleCallback* checkin,
DNSLookup* lookup, DNSAnswer* answer);
/// \brief The constructor with a specific port on which the services
/// listen on.
///
/// It effectively listens on "any" IPv4 and/or IPv6 addresses.
/// IPv4/IPv6 services will be available if and only if \c use_ipv4
/// or \c use_ipv6 is \c true, respectively.
///
/// \param io_service The IOService to work with
/// \param port the port to listen on
/// \param ipv4 If true, listen on ipv4 'any'
/// \param ipv6 If true, listen on ipv6 'any'
/// \param checkin Provider for cc-channel events (see \c SimpleCallback)
/// \param lookup The lookup provider (see \c DNSLookup)
/// \param answer The answer provider (see \c DNSAnswer)
DNSService(IOService& io_service, const char& port,
const bool use_ipv4, const bool use_ipv6,
SimpleCallback* checkin, DNSLookup* lookup,
DNSAnswer* answer);
/// \brief The destructor.
~DNSService();
//@}
/// \brief Return the native \c io_service object used in this wrapper.
///
/// This is a short term work around to support other BIND 10 modules
/// that share the same \c io_service with the authoritative server.
/// It will eventually be removed once the wrapper interface is
/// generalized.
asio::io_service& get_io_service() { return io_service_.get_io_service(); };
private:
IOServiceImpl* impl_;
DNSServiceImpl* impl_;
IOService& io_service_;
};
/// \brief The \c DNSServer class is a wrapper (and base class) for
......@@ -236,6 +279,9 @@ public:
/// \brief Resume processing of the server coroutine after an
/// asynchronous call (e.g., to the DNS Lookup provider) has completed.
///
/// \param done If true, this signals the system there is an answer
/// to return.
virtual inline void resume(const bool done) { self_->resume(done); }
/// \brief Indicate whether the server is able to send an answer
......@@ -250,6 +296,8 @@ public:
/// purposes during development and removed later. It allows
/// callers from outside the coroutine object to retrieve information
/// about its current state.
///
/// \return The value of the 'coroutine' object
virtual inline int value() { return (self_->value()); }
/// \brief Returns a pointer to a clone of this DNSServer object.
......@@ -258,6 +306,8 @@ public:
/// normally be another \c DNSServer object containing a copy
/// of the original "self_" pointer. Calling clone() guarantees
/// that the underlying object is also correctly copied.
///
/// \return A deep copy of this DNSServer object
virtual inline DNSServer* clone() { return (self_->clone()); }
//@}
......@@ -337,6 +387,11 @@ public:
/// This makes its call indirectly via the "self" pointer, ensuring
/// that the function ultimately invoked will be the one in the derived
/// class.
///
/// \param io_message The event message to handle
/// \param message The DNS MessagePtr that needs handling
/// \param buffer The final answer is put here
/// \param DNSServer DNSServer object to use
virtual void operator()(const IOMessage& io_message,
isc::dns::MessagePtr message,
isc::dns::OutputBufferPtr buffer,
......@@ -382,6 +437,14 @@ public:
virtual ~DNSAnswer() {}
//@}
/// \brief The function operator
///
/// This makes its call indirectly via the "self" pointer, ensuring
/// that the function ultimately invoked will be the one in the derived
/// class.
///
/// \param io_message The event message to handle
/// \param message The DNS MessagePtr that needs handling
/// \param buffer The result is put here
virtual void operator()(const IOMessage& io_message,