Commit ad55ea2d authored by Evan Hunt's avatar Evan Hunt

Refactored asiolink so that the many classes defined in asiolink.h and

asiolink.cc are now in multiple files (ioaddress.h, iosocket.h, etc).
Also removed some shared_ptr's that weren't really needed in tcpdns
and udpdns.  This work isn't done yet, but committing now to simplify
the review a bit.



git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac327@3150 e5f2f494-b856-4b98-b285-d166d9295462
parent ced31563
......@@ -40,6 +40,7 @@
#include <dns/rrset.h>
#include <dns/rrttl.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <xfr/xfrout_client.h>
......
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
AM_CXXFLAGS = $(B10_CXXFLAGS)
CLEANFILES = *.gcno *.gcda
# This is a wrapper library solely used for b10-auth. The ASIO header files
# have some code fragments that would hit gcc's unused-parameter warning,
# which would make the build fail with -Werror (our default setting).
lib_LTLIBRARIES = libasiolink.la
libasiolink_la_SOURCES = asiolink.cc asiolink.h
libasiolink_la_SOURCES += iosocket.h
libasiolink_la_SOURCES += ioaddress.cc ioaddress.h
libasiolink_la_SOURCES += ioendpoint.cc ioendpoint.h
libasiolink_la_SOURCES += udpdns.cc internal/udpdns.h
libasiolink_la_SOURCES += tcpdns.cc internal/tcpdns.h
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
# B10_CXXFLAGS)
libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)
if USE_GXX
libasiolink_la_CXXFLAGS += -Wno-unused-parameter
endif
libasiolink_la_CPPFLAGS = $(AM_CPPFLAGS)
......@@ -42,83 +42,6 @@ using namespace isc::dns;
namespace asiolink {
IOAddress::IOAddress(const string& address_str)
// XXX: we cannot simply construct the address in the initialization list
// because we'd like to throw our own exception on failure.
{
error_code err;
asio_address_ = ip::address::from_string(address_str, err);
if (err) {
isc_throw(IOError, "Failed to convert string to address '"
<< address_str << "': " << err.message());
}
}
IOAddress::IOAddress(const ip::address& asio_address) :
asio_address_(asio_address)
{}
string
IOAddress::toText() const {
return (asio_address_.to_string());
}
short
IOAddress::getFamily() const {
if (asio_address_.is_v4()) {
return (AF_INET);
} else {
return (AF_INET6);
}
}
const IOEndpoint*
IOEndpoint::create(const int protocol, const IOAddress& address,
const unsigned short port)
{
if (protocol == IPPROTO_UDP) {
return (new UDPEndpoint(address, port));
} else if (protocol == IPPROTO_TCP) {
return (new TCPEndpoint(address, port));
}
isc_throw(IOError,
"IOEndpoint creation attempt for unsupported protocol: " <<
protocol);
}
IOMessage::IOMessage(const void* data, const size_t data_size,
const IOSocket& io_socket,
const IOEndpoint& remote_endpoint) :
data_(data), data_size_(data_size), io_socket_(io_socket),
remote_endpoint_(remote_endpoint)
{}
RecursiveQuery::RecursiveQuery(IOService& io_service, const char& forward,
uint16_t port) :
io_service_(io_service), port_(port)
{
error_code err;
ns_addr_ = ip::address::from_string(&forward, err);
if (err) {
isc_throw(IOError, "Invalid IP address '" << &ns_addr_ << "': "
<< err.message());
}
}
void
RecursiveQuery::sendQuery(const Question& question, 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 = io_service_.get_io_service();
UDPQuery q(io, question, ns_addr_, port_, buffer, server);
io.post(q);
}
class IOServiceImpl {
public:
IOServiceImpl(const char& port,
......@@ -247,4 +170,30 @@ IOService::get_io_service() {
return (impl_->io_service_);
}
RecursiveQuery::RecursiveQuery(IOService& io_service, const char& forward,
uint16_t port) :
io_service_(io_service), port_(port)
{
error_code err;
ns_addr_ = ip::address::from_string(&forward, err);
if (err) {
isc_throw(IOError, "Invalid IP address '" << &ns_addr_ << "': "
<< err.message());
}
}
void
RecursiveQuery::sendQuery(const Question& question, 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 = io_service_.get_io_service();
UDPQuery q(io, question, ns_addr_, port_, buffer, server);
io.post(q);
}
}
......@@ -26,15 +26,17 @@
#include <functional>
#include <string>
#include <boost/function.hpp>
#include <dns/buffer.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/question.h>
#include <exceptions/exceptions.h>
#include <asiolink/ioaddress.h>
#include <asiolink/ioendpoint.h>
#include <asiolink/iomessage.h>
#include <asiolink/iosocket.h>
namespace asio {
// forward declaration for IOService::get_io_service() below
class io_service;
......@@ -107,297 +109,6 @@ class SimpleCallback;
class DNSLookup;
class DNSAnswer;
/// \brief The \c IOAddress class represents an IP addresses (version
/// agnostic)
///
/// This class is a wrapper for the ASIO \c ip::address class.
class IOAddress {
public:
///
/// \name Constructors and Destructor
///
/// This class is copyable. We use default versions of copy constructor
/// and the assignment operator.
/// We use the default destructor.
//@{
/// \brief Constructor from string.
///
/// This constructor converts a textual representation of IPv4 and IPv6
/// addresses into an IOAddress object.
/// If \c address_str is not a valid representation of any type of
/// address, an exception of class \c IOError will be thrown.
/// This constructor allocates memory for the object, and if that fails
/// a corresponding standard exception will be thrown.
///
/// \param address_str Textual representation of address.
IOAddress(const std::string& address_str);
/// \brief Constructor from an ASIO \c ip::address object.
///
/// This constructor is intended to be used within the wrapper
/// implementation; user applications of the wrapper API won't use it.
///
/// This constructor never throws an exception.
///
/// \param asio_address The ASIO \c ip::address to be converted.
IOAddress(const asio::ip::address& asio_adress);
//@}
/// \brief Convert the address to a string.
///
/// This method is basically expected to be exception free, but
/// generating the string will involve resource allocation,
/// and if it fails the corresponding standard exception will be thrown.
///
/// \return A string representation of the address.
std::string toText() const;
/// \brief Returns the address family.
virtual short getFamily() const;
private:
asio::ip::address asio_address_;
};
/// \brief The \c IOEndpoint class is an abstract base class to represent
/// a communication endpoint.
///
/// This class is a wrapper for the ASIO endpoint classes such as
/// \c ip::tcp::endpoint and \c ip::udp::endpoint.
///
/// Derived class implementations are completely hidden within the
/// implementation. User applications only get access to concrete
/// \c IOEndpoint objects via the abstract interfaces.
class IOEndpoint {
///
/// \name Constructors and Destructor
///
/// Note: The copy constructor and the assignment operator are
/// intentionally defined as private, making this class non-copyable.
//@{
private:
IOEndpoint(const IOEndpoint& source);
IOEndpoint& operator=(const IOEndpoint& source);
protected:
/// \brief The default constructor.
///
/// This is intentionally defined as \c protected as this base class
/// should never be instantiated (except as part of a derived class).
IOEndpoint() {}
public:
/// The destructor.
virtual ~IOEndpoint() {}
//@}
/// \brief Returns the address of the endpoint.
///
/// This method returns an IOAddress object corresponding to \c this
/// endpoint.
///
/// Note that the return value is a real object, not a reference or
/// a pointer.
///
/// This is aligned with the interface of the ASIO counterpart:
/// the \c address() method of \c ip::xxx::endpoint classes returns
/// an \c ip::address object.
///
/// This also means handling the address of an endpoint using this method
/// can be expensive. If the address information is necessary in a
/// performance sensitive context and there's a more efficient interface
/// for that purpose, it's probably better to avoid using this method.
///
/// This method never throws an exception.
///
/// \return A copy of \c IOAddress object corresponding to the endpoint.
virtual IOAddress getAddress() const = 0;
/// \brief Returns the port of the endpoint.
virtual uint16_t getPort() const = 0;
/// \brief Returns the protocol number of the endpoint (TCP, UDP...)
virtual short getProtocol() const = 0;
/// \brief Returns the address family of the endpoint.
virtual short getFamily() const = 0;
/// \brief A polymorphic factory of endpoint from address and port.
///
/// This method creates a new instance of (a derived class of)
/// \c IOEndpoint object that identifies the pair of given address
/// and port.
/// The appropriate derived class is chosen based on the specified
/// transport protocol. If the \c protocol doesn't specify a protocol
/// supported in this implementation, an exception of class \c IOError
/// will be thrown.
///
/// Memory for the created object will be dynamically allocated. It's
/// the caller's responsibility to \c delete it later.
/// If resource allocation for the new object fails, a corresponding
/// standard exception will be thrown.
///
/// \param protocol The transport protocol used for the endpoint.
/// Currently, only \c IPPROTO_UDP and \c IPPROTO_TCP can be specified.
/// \param address The (IP) address of the endpoint.
/// \param port The transport port number of the endpoint
/// \return A pointer to a newly created \c IOEndpoint object.
static const IOEndpoint* create(const int protocol,
const IOAddress& address,
const unsigned short port);
};
/// \brief The \c IOSocket class is an abstract base class to represent
/// various types of network sockets.
///
/// This class is a wrapper for the ASIO socket classes such as
/// \c ip::tcp::socket and \c ip::udp::socket.
///
/// Derived class implementations are completely hidden within the
/// implementation. User applications only get access to concrete
/// \c IOSocket objects via the abstract interfaces.
///
/// We may revisit this decision when we generalize the wrapper and more
/// modules use it. Also, at that point we may define a separate (visible)
/// derived class for testing purposes rather than providing factory methods
/// (i.e., getDummy variants below).
class IOSocket {
///
/// \name Constructors and Destructor
///
/// Note: The copy constructor and the assignment operator are
/// intentionally defined as private, making this class non-copyable.
//@{
private:
IOSocket(const IOSocket& source);
IOSocket& operator=(const IOSocket& source);
protected:
/// \brief The default constructor.
///
/// This is intentionally defined as \c protected as this base class
/// should never be instantiated (except as part of a derived class).
IOSocket() {}
public:
/// The destructor.
virtual ~IOSocket() {}
//@}
/// \brief Return the "native" representation of the socket.
///
/// In practice, this is the file descriptor of the socket for
/// UNIX-like systems so the current implementation simply uses
/// \c int as the type of the return value.
/// We may have to need revisit this decision later.
///
/// In general, the application should avoid using this method;
/// it essentially discloses an implementation specific "handle" that
/// can change the internal state of the socket (consider the
/// application closes it, for example).
/// But we sometimes need to perform very low-level operations that
/// requires the native representation. Passing the file descriptor
/// to a different process is one example.
/// This method is provided as a necessary evil for such limited purposes.
///
/// This method never throws an exception.
///
/// \return The native representation of the socket. This is the socket
/// file descriptor for UNIX-like systems.
virtual int getNative() const = 0;
/// \brief Return the transport protocol of the socket.
///
/// Currently, it returns \c IPPROTO_UDP for UDP sockets, and
/// \c IPPROTO_TCP for TCP sockets.
///
/// This method never throws an exception.
///
/// \return IPPROTO_UDP for UDP sockets
/// \return IPPROTO_TCP for TCP sockets
virtual int getProtocol() const = 0;
/// \brief Return a non-usable "dummy" UDP socket for testing.
///
/// This is a class method that returns a "mock" of UDP socket.
/// This is not associated with any actual socket, and its only
/// responsibility is to return \c IPPROTO_UDP from \c getProtocol().
/// The only feasible usage of this socket is for testing so that
/// the test code can prepare some "UDP data" even without opening any
/// actual socket.
///
/// This method never throws an exception.
///
/// \return A reference to an \c IOSocket object whose \c getProtocol()
/// returns \c IPPROTO_UDP.
static IOSocket& getDummyUDPSocket();
/// \brief Return a non-usable "dummy" TCP socket for testing.
///
/// See \c getDummyUDPSocket(). This method is its TCP version.
///
/// \return A reference to an \c IOSocket object whose \c getProtocol()
/// returns \c IPPROTO_TCP.
static IOSocket& getDummyTCPSocket();
};
/// \brief The \c IOMessage class encapsulates an incoming message received
/// on a socket.
///
/// An \c IOMessage object represents a tuple of a chunk of data
/// (a UDP packet or some segment of TCP stream), the socket over which the
/// data is passed, the information about the other end point of the
/// communication, and perhaps more.
///
/// The current design and interfaces of this class is tentative.
/// It only provides a minimal level of support that is necessary for
/// the current implementation of the authoritative server.
/// A future version of this class will definitely support more.
class IOMessage {
///
/// \name Constructors and Destructor
///
/// Note: The copy constructor and the assignment operator are
/// intentionally defined as private, making this class non-copyable.
//@{
private:
IOMessage(const IOMessage& source);
IOMessage& operator=(const IOMessage& source);
public:
/// \brief Constructor from message information.
///
/// This constructor needs to handle the ASIO \c ip::address class,
/// and is intended to be used within this wrapper implementation.
/// Once the \c IOMessage object is created, the application can
/// get access to the information via the wrapper interface such as
/// \c getRemoteAddress().
///
/// This constructor never throws an exception.
///
/// \param data A pointer to the message data.
/// \param data_size The size of the message data in bytes.
/// \param io_socket The socket over which the data is given.
/// \param remote_endpoint The other endpoint of the socket, that is,
/// the sender of the message.
IOMessage(const void* data, const size_t data_size,
const IOSocket& io_socket, const IOEndpoint& remote_endpoint);
//@}
/// \brief Returns a pointer to the received data.
const void* getData() const { return (data_); }
/// \brief Returns the size of the received data in bytes.
size_t getDataSize() const { return (data_size_); }
/// \brief Returns the socket on which the message arrives.
const IOSocket& getSocket() const { return (io_socket_); }
/// \brief Returns the endpoint that sends the message.
const IOEndpoint& getRemoteEndpoint() const { return (remote_endpoint_); }
private:
const void* data_;
const size_t data_size_;
const IOSocket& io_socket_;
const IOEndpoint& remote_endpoint_;
};
/// \brief The \c IOService class is a wrapper for the ASIO \c io_service
/// class.
///
......
......@@ -137,17 +137,6 @@ private:
// are not copyable.
boost::shared_ptr<asio::ip::tcp::socket> socket_;
// An \c IOSocket object to wrap socket_
boost::shared_ptr<asiolink::IOSocket> iosock_;
// An \c IOEndpoint object to wrap the remote endpoint of socket_
boost::shared_ptr<asiolink::IOEndpoint> peer_;
// A small buffer for writing the length of a DNS message;
// this is prepended to the actual response buffer when sending a reply
// to the client.
boost::shared_ptr<isc::dns::OutputBuffer> lenbuf_;
// The buffer into which the response is written
boost::shared_ptr<isc::dns::OutputBuffer> respbuf_;
......
......@@ -129,15 +129,9 @@ private:
// are not copyable.
boost::shared_ptr<asio::ip::udp::socket> socket_;
// An \c IOSocket object to wrap socket_
boost::shared_ptr<asiolink::IOSocket> iosock_;
// The ASIO-enternal endpoint object representing the client
boost::shared_ptr<asio::ip::udp::endpoint> sender_;
// An \c IOEndpoint object to wrap sender_
boost::shared_ptr<asiolink::IOEndpoint> peer_;
// \c IOMessage and \c Message objects to be passed to the
// DNS lookup and answer providers
boost::shared_ptr<asiolink::IOMessage> io_message_;
......
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#include <config.h>
#include <unistd.h> // for some IPC/network system calls
#include <sys/socket.h>
#include <netinet/in.h>
#include <asio.hpp>
#include <asiolink/asiolink.h>
using namespace asio;
using asio::ip::udp;
using asio::ip::tcp;
using namespace std;
namespace asiolink {
// XXX: we cannot simply construct the address in the initialization list,
// because we'd like to throw our own exception on failure.
IOAddress::IOAddress(const string& address_str) {
error_code err;
asio_address_ = ip::address::from_string(address_str, err);
if (err) {
isc_throw(IOError, "Failed to convert string to address '"
<< address_str << "': " << err.message());
}
}
IOAddress::IOAddress(const ip::address& asio_address) :
asio_address_(asio_address)
{}
string
IOAddress::toText() const {
return (asio_address_.to_string());
}
short
IOAddress::getFamily() const {
if (asio_address_.is_v4()) {
return (AF_INET);
} else {
return (AF_INET6);
}
}
}
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// $Id$
#ifndef __IOADDRESS_H
#define __IOADDRESS_H 1
// IMPORTANT NOTE: only very few ASIO headers files can be included in
// this file. In particular, asio.hpp should never be included here.
// See the description of the namespace below.
#include <unistd.h> // for some network system calls
#include <asio/ip/address.hpp>
#include <functional>
#include <string>
#include <exceptions/exceptions.h>
namespace asiolink {
/// \brief The \c IOAddress class represents an IP addresses (version
/// agnostic)
///
/// This class is a wrapper for the ASIO \c ip::address class.
class IOAddress {
public:
///
/// \name Constructors and Destructor
///
/// This class is copyable. We use default versions of copy constructor
/// and the assignment operator.
/// We use the default destructor.
//@{
/// \brief Constructor from string.
///
/// This constructor converts a textual representation of IPv4 and IPv6
/// addresses into an IOAddress object.
/// If \c address_str is not a valid representation of any type of
/// address, an exception of class \c IOError will be thrown.
/// This constructor allocates memory for the object, and if that fails
/// a corresponding standard exception will be thrown.
///
/// \param address_str Textual representation of address.
IOAddress(const std::string& address_str);
/// \brief Constructor from an ASIO \c ip::address object.
///
/// This constructor is intended to be used within the wrapper
/// implementation; user applications of the wrapper API won't use it.
///
/// This constructor never throws an exception.
///
/// \param asio_address The ASIO \c ip::address to be converted.
IOAddress(const asio::ip::address& asio_adress);
//@}
/// \brief Convert the address to a string.
///
/// This method is basically expected to be exception free, but
/// generating the string will involve resource allocation,
/// and if it fails the corresponding standard exception will be thrown.
///
/// \return A string representation of the address.
std::string toText() const;
/// \brief Returns the address family.
virtual short getFamily() const;
private:
asio::ip::address asio_address_;