Commit 4c05048b authored by Stephen Morris's avatar Stephen Morris
Browse files

[master] Merge branch 'trac499'

Conflicts:
	src/lib/server_common/tests/Makefile.am
parents d6f57908 ba92da63
......@@ -13,29 +13,34 @@ CLEANFILES = *.gcno *.gcda
# which would make the build fail with -Werror (our default setting).
lib_LTLIBRARIES = libasiolink.la
libasiolink_la_SOURCES = asiolink.h
libasiolink_la_SOURCES += asiolink_utilities.h
libasiolink_la_SOURCES += asiodef.cc asiodef.h
libasiolink_la_SOURCES += dns_answer.h
libasiolink_la_SOURCES += dns_lookup.h
libasiolink_la_SOURCES += dns_server.h
libasiolink_la_SOURCES += dns_service.h dns_service.cc
libasiolink_la_SOURCES += dns_service.cc dns_service.h
libasiolink_la_SOURCES += dummy_io_cb.h
libasiolink_la_SOURCES += interval_timer.h interval_timer.cc
libasiolink_la_SOURCES += io_address.h io_address.cc
libasiolink_la_SOURCES += interval_timer.cc interval_timer.h
libasiolink_la_SOURCES += io_address.cc io_address.h
libasiolink_la_SOURCES += io_asio_socket.h
libasiolink_la_SOURCES += io_endpoint.h io_endpoint.cc
libasiolink_la_SOURCES += io_endpoint.cc io_endpoint.h
libasiolink_la_SOURCES += io_error.h
libasiolink_la_SOURCES += io_fetch.h io_fetch.cc
libasiolink_la_SOURCES += io_fetch.cc io_fetch.h
libasiolink_la_SOURCES += io_message.h
libasiolink_la_SOURCES += io_service.h io_service.cc
libasiolink_la_SOURCES += io_socket.h io_socket.cc
libasiolink_la_SOURCES += recursive_query.h recursive_query.cc
libasiolink_la_SOURCES += io_service.cc io_service.h
libasiolink_la_SOURCES += io_socket.cc io_socket.h
libasiolink_la_SOURCES += qid_gen.cc qid_gen.h
libasiolink_la_SOURCES += recursive_query.cc recursive_query.h
libasiolink_la_SOURCES += simple_callback.h
libasiolink_la_SOURCES += tcp_endpoint.h
libasiolink_la_SOURCES += tcp_server.h tcp_server.cc
libasiolink_la_SOURCES += tcp_server.cc tcp_server.h
libasiolink_la_SOURCES += tcp_socket.h
libasiolink_la_SOURCES += udp_endpoint.h
libasiolink_la_SOURCES += udp_server.h udp_server.cc
libasiolink_la_SOURCES += udp_server.cc udp_server.h
libasiolink_la_SOURCES += udp_socket.h
libasiolink_la_SOURCES += qid_gen.cc qid_gen.h
EXTRA_DIST = asiodef.msg
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
# B10_CXXFLAGS)
libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)
......@@ -47,7 +52,8 @@ if USE_CLANGPP
libasiolink_la_CXXFLAGS += -Wno-error
endif
libasiolink_la_CPPFLAGS = $(AM_CPPFLAGS)
libasiolink_la_LIBADD = $(top_builddir)/src/lib/log/liblog.la
libasiolink_la_LIBADD =
libasiolink_la_LIBADD += $(top_builddir)/src/lib/resolve/libresolve.la
libasiolink_la_LIBADD += $(top_builddir)/src/lib/cache/libcache.la
libasiolink_la_LIBADD += $(top_builddir)/src/lib/nsas/libnsas.la
libasiolink_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
// File created from asiodef.msg on Mon Feb 28 17:15:30 2011
#include <cstddef>
#include <log/message_types.h>
#include <log/message_initializer.h>
namespace asiolink {
extern const isc::log::MessageID ASIO_FETCHCOMP = "FETCHCOMP";
extern const isc::log::MessageID ASIO_FETCHSTOP = "FETCHSTOP";
extern const isc::log::MessageID ASIO_OPENSOCK = "OPENSOCK";
extern const isc::log::MessageID ASIO_RECVSOCK = "RECVSOCK";
extern const isc::log::MessageID ASIO_RECVTMO = "RECVTMO";
extern const isc::log::MessageID ASIO_SENDSOCK = "SENDSOCK";
extern const isc::log::MessageID ASIO_UNKORIGIN = "UNKORIGIN";
extern const isc::log::MessageID ASIO_UNKRESULT = "UNKRESULT";
} // namespace asiolink
namespace {
const char* values[] = {
"FETCHCOMP", "upstream fetch to %s(%d) has now completed",
"FETCHSTOP", "upstream fetch to %s(%d) has been stopped",
"OPENSOCK", "error %d opening %s socket to %s(%d)",
"RECVSOCK", "error %d reading %s data from %s(%d)",
"RECVTMO", "receive timeout while waiting for data from %s(%d)",
"SENDSOCK", "error %d sending data using %s to %s(%d)",
"UNKORIGIN", "unknown origin for ASIO error code %d (protocol: %s, address %s)",
"UNKRESULT", "unknown result (%d) when IOFetch::stop() was executed for I/O to %s(%d)",
NULL
};
const isc::log::MessageInitializer initializer(values);
} // Anonymous namespace
// File created from asiodef.msg on Mon Feb 28 17:15:30 2011
#ifndef __ASIODEF_H
#define __ASIODEF_H
#include <log/message_types.h>
namespace asiolink {
extern const isc::log::MessageID ASIO_FETCHCOMP;
extern const isc::log::MessageID ASIO_FETCHSTOP;
extern const isc::log::MessageID ASIO_OPENSOCK;
extern const isc::log::MessageID ASIO_RECVSOCK;
extern const isc::log::MessageID ASIO_RECVTMO;
extern const isc::log::MessageID ASIO_SENDSOCK;
extern const isc::log::MessageID ASIO_UNKORIGIN;
extern const isc::log::MessageID ASIO_UNKRESULT;
} // namespace asiolink
#endif // __ASIODEF_H
# Copyright (C) 2011 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.
$PREFIX ASIO_
$NAMESPACE asiolink
FETCHCOMP upstream fetch to %s(%d) has now completed
+ A debug message, this records the the upstream fetch (a query made by the
+ resolver on behalf of its client) to the specified address has completed.
FETCHSTOP upstream fetch to %s(%d) has been stopped
+ An external component has requested the halting of an upstream fetch. This
+ is an allowed operation, and the message should only appear if debug is
+ enabled.
OPENSOCK error %d opening %s socket to %s(%d)
+ The asynchronous I/O code encountered an error when trying to open a socket
+ of the specified protocol in order to send a message to the target address.
+ The the number of the system error that cause the problem is given in the
+ message.
RECVSOCK error %d reading %s data from %s(%d)
+ The asynchronous I/O code encountered an error when trying read data from
+ the specified address on the given protocol. The the number of the system
+ error that cause the problem is given in the message.
SENDSOCK error %d sending data using %s to %s(%d)
+ The asynchronous I/O code encountered an error when trying send data to
+ the specified address on the given protocol. The the number of the system
+ error that cause the problem is given in the message.
RECVTMO receive timeout while waiting for data from %s(%d)
+ An upstream fetch from the specified address timed out. This may happen for
+ any number of reasons and is most probably a problem at the remote server
+ or a problem on the network. The message will only appear if debug is
+ enabled.
UNKORIGIN unknown origin for ASIO error code %d (protocol: %s, address %s)
+ This message should not appear and indicates an internal error if it does.
+ Please enter a bug report.
UNKRESULT unknown result (%d) when IOFetch::stop() was executed for I/O to %s(%d)
+ The termination method of the resolver's upstream fetch class was called with
+ an unknown result code (which is given in the message). This message should
+ not appear and may indicate an internal error. Please enter a bug report.
......@@ -85,7 +85,3 @@
/// http://think-async.com/Asio/asio-1.3.1/doc/asio/reference/asio_handler_allocate.html
#endif // __ASIOLINK_H
// Local Variables:
// mode: c++
// End:
// Copyright (C) 2011 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.
#ifndef __ASIOLINK_UTILITIES_H
#define __ASIOLINK_UTILITIES_H
#include <cstddef>
namespace asiolink {
/// \brief Read Unsigned 16-Bit Integer from Buffer
///
/// This is essentially a copy of the isc::dns::InputBuffer::readUint16. It
/// should really be moved into a separate library.
///
/// \param buffer Data buffer at least two bytes long of which the first two
/// bytes are assumed to represent a 16-bit integer in network-byte
/// order.
///
/// \return Value of 16-bit integer
inline uint16_t
readUint16(const void* buffer) {
const uint8_t* byte_buffer = static_cast<const uint8_t*>(buffer);
uint16_t result = (static_cast<uint16_t>(byte_buffer[0])) << 8;
result |= static_cast<uint16_t>(byte_buffer[1]);
return (result);
}
/// \brief Write Unisgned 16-Bit Integer to Buffer
///
/// This is essentially a copy of isc::dns::OutputBuffer::writeUint16. It
/// should really be moved into a separate library.
///
/// \param value 16-bit value to convert
/// \param buffer Data buffer at least two bytes long into which the 16-bit
/// value is written in network-byte order.
inline void
writeUint16(uint16_t value, void* buffer) {
uint8_t* byte_buffer = static_cast<uint8_t*>(buffer);
byte_buffer[0] = static_cast<uint8_t>((value & 0xff00U) >> 8);
byte_buffer[1] = static_cast<uint8_t>(value & 0x00ffU);
}
} // namespace asiolink
#endif // __ASIOLINK_UTILITIES_H
......@@ -21,7 +21,7 @@ namespace asiolink {
/// \brief The \c DNSServer class is a wrapper (and base class) for
/// classes which provide DNS server functionality.
///
///
/// The classes derived from this one, \c TCPServer and \c UDPServer,
/// act as the interface layer between clients sending queries, and
/// functions defined elsewhere that provide answers to those queries.
......@@ -42,10 +42,10 @@ namespace asiolink {
/// when "forking", and that instances will be posted as ASIO handler
/// objects, which are always copied.
///
/// Because these objects are frequently copied, it is recommended
/// Because these objects are frequently copied, it is recommended
/// that derived classes be kept small to reduce copy overhead.
class DNSServer {
protected:
protected:
///
/// \name Constructors and destructors
///
......@@ -66,7 +66,7 @@ public:
/// the ones in the derived class. This makes it possible to pass
/// instances of derived classes as references to this base class
/// without losing access to derived class data.
///
///
//@{
/// \brief The funtion operator
virtual void operator()(asio::error_code ec = asio::error_code(),
......@@ -87,7 +87,7 @@ public:
/// \brief Indicate whether the server is able to send an answer
/// to a query.
///
///
/// This is presently used only for testing purposes.
virtual bool hasAnswer() { return (self_->hasAnswer()); }
......
......@@ -26,13 +26,13 @@ class DNSLookup;
class DNSAnswer;
class DNSServiceImpl;
/// \brief Handle DNS Queries
///
/// DNSService is the service that handles DNS queries and answers with
/// a given IOService. This class is mainly intended to hold all the
/// logic that is shared between the authoritative and the recursive
/// server implementations. As such, it handles asio, including config
/// updates (through the 'Checkinprovider'), and listening sockets.
///
class DNSService {
///
/// \name Constructors and Destructor
......
......@@ -36,6 +36,14 @@ namespace asiolink {
class DummyIOCallback {
public:
/// \brief Asynchronous I/O callback method
///
/// \param error Unused
void operator()(asio::error_code)
{
// TODO: log an error if this method ever gets called.
}
/// \brief Asynchronous I/O callback method
///
/// \param error Unused
......
// 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.
#ifndef __IOFETCH_H
#define __IOFETCH_H 1
#include <config.h>
#include <asio.hpp>
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>
#include <dns/buffer.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <asiolink/asiolink.h>
#include <asiolink/internal/coroutine.h>
// This file contains TCP/UDP-specific implementations of generic classes
// defined in asiolink.h. It is *not* intended to be part of the public
// API.
namespace asiolink {
//
// Asynchronous UDP/TCP coroutine for upstream fetches
//
//class IOFetch : public coroutine, public UdpFetch, public TcpFetch {
class IOFetch : public coroutine {
public:
// TODO Maybe this should be more generic than just for IOFetch?
///
/// \brief Result of the query
///
/// This is related only to contacting the remote server. If the answer
///indicates error, it is still counted as SUCCESS here, if it comes back.
///
enum Result {
SUCCESS,
TIME_OUT,
STOPPED
};
/// Abstract callback for the IOFetch.
class Callback {
public:
virtual ~Callback() {}
/// This will be called when the IOFetch is completed
virtual void operator()(Result result) = 0;
};
///
/// \brief Constructor.
///
/// It creates the query.
/// @param callback will be called when we terminate. It is your task to
/// delete it if allocated on heap.
///@param timeout in ms.
///
IOFetch(asio::io_service& io_service,
const isc::dns::Question& q,
const IOAddress& addr, uint16_t port,
isc::dns::OutputBufferPtr buffer,
Callback* callback, int timeout = -1,
int protocol = IPPROTO_UDP);
void operator()(asio::error_code ec = asio::error_code(),
size_t length = 0);
/// Terminate the query.
void stop(Result reason = STOPPED);
private:
enum { MAX_LENGTH = 4096 };
///
/// \short Private data
///
/// They are not private because of stability of the
/// interface (this is private class anyway), but because this class
/// will be copyed often (it is used as a coroutine and passed as callback
/// to many async_*() functions) and we want keep the same data. Some of
/// the data is not copyable too.
///
//struct IOFetchProtocol;
//boost::shared_ptr<IOFetchProtocol> data_;
//struct UdpData;
//struct TcpData;
boost::shared_ptr<UdpFetch> data_;
boost::shared_ptr<TcpFetch> tcp_data_;
};
class UdpFetch : public IOFetch {
public:
struct UdpData;
explicit UdpFetch(asio::io_service& io_service,
const isc::dns::Question& q,
const IOAddress& addr,
uint16_t port,
isc::dns::OutputBufferPtr buffer,
IOFetch::Callback *callback,
int timeout);
};
class TcpFetch : public IOFetch {
public:
struct TcpData;
explicit TcpFetch(io_service& io_service, const Question& q,
const IOAddress& addr, uint16_t port,
OutputBufferPtr buffer, Callback *callback, int timeout);
};
}
#endif // __IOFETCH_H
// Local Variables:
// mode: c++
// End:
......@@ -37,7 +37,7 @@ struct IntervalTimerImpl;
/// The function calls the call back function set by \c setup() and updates
/// the timer to expire in (now + interval) milliseconds.
/// The type of call back function is \c void(void).
///
///
/// The call back function will not be called if the instance of this class is
/// destroyed before the timer is expired.
///
......
......@@ -121,7 +121,3 @@ private:
} // asiolink
#endif // __IO_ADDRESS_H
// Local Variables:
// mode: c++
// End:
......@@ -26,6 +26,8 @@
#include <exceptions/exceptions.h>
#include <coroutine.h>
#include <dns/buffer.h>
#include <asiolink/io_error.h>
#include <asiolink/io_socket.h>
......@@ -41,7 +43,24 @@ public:
IOError(file, line, what) {}
};
/// \brief Error setting socket options
///
/// Thrown if attempt to change socket options fails.
class SocketSetError : public IOError {
public:
SocketSetError(const char* file, size_t line, const char* what) :
IOError(file, line, what) {}
};
/// \brief Buffer overflow
///
/// Thrown if an attempt is made to receive into an area beyond the end of
/// the receive data buffer.
class BufferOverflow : public IOError {
public:
BufferOverflow(const char* file, size_t line, const char* what) :
IOError(file, line, what) {}
};
/// Forward declaration of an IOEndpoint
class IOEndpoint;
......@@ -91,24 +110,23 @@ public:
/// \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 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.
/// 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 what would happen if
/// 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.
/// file descriptor for UNIX-like systems.
virtual int getNative() const = 0;
/// \brief Return the transport protocol of the socket.
......@@ -118,36 +136,50 @@ public:
///
/// This method never throws an exception.
///
/// \return IPPROTO_UDP for UDP sockets
/// \return IPPROTO_TCP for TCP sockets
/// \return \c IPPROTO_UDP for UDP sockets, \c IPPROTO_TCP for TCP sockets
virtual int getProtocol() const = 0;
/// \brief Open AsioSocket
/// \brief Is Open() synchronous?
///
/// Opens the socket for asynchronous I/O. On a UDP socket, this is merely
/// an "open()" on the underlying socket (so completes immediately), but on
/// a TCP socket it also connects to the remote end (which is done as an
/// asynchronous operation).
/// On a TCP socket, an "open" operation is a call to the socket's "open()"
/// method followed by a connection to the remote system: it is an
/// asynchronous operation. On a UDP socket, it is just a call to "open()"
/// and completes synchronously.
///
/// For TCP, signalling of the completion of the operation is done by
/// by calling the callback function in the normal way. This could be done
/// for UDP (by posting en event on the event queue); however, that will
/// incur additional overhead in the most common case. Instead, the return
/// value indicates whether the operation was asynchronous or not. If yes,
/// (i.e. TCP) the callback has been posted to the event queue: if no (UDP),
/// no callback has been posted (in which case it is up to the caller as to
/// whether they want to manually post the callback themself.)
/// incur additional overhead in the most common case. So we give the
/// caller the choice for calling this open() method synchronously or
/// asynchronously.
///
/// Owing to the way that the stackless coroutines are implemented, we need
/// to know _before_ executing the "open" function whether or not it is
/// asynchronous. So this method is called to provide that information.
///
/// (The reason there is a need to know is because the call to open() passes
/// in the state of the coroutine at the time the call is made. On an
/// asynchronous I/O, we need to set the state to point to the statement
/// after the call to open() _before_ we pass the corouine to the open()
/// call. Unfortunately, the macros that set the state of the coroutine
/// also yield control - which we don't want to do if the open is
/// synchronous. Hence we need to know before we make the call to open()
/// whether that call will complete asynchronously.)
virtual bool isOpenSynchronous() const = 0;
/// \brief Open AsioSocket
///
/// Opens the socket for asynchronous I/O. The open will complete
/// synchronously on UCP or asynchronously on TCP (in which case a callback
/// will be queued).
///
/// \param endpoint Pointer to the endpoint object. This is ignored for
/// a UDP socket (the target is specified in the send call), but should
/// be of type TCPEndpoint for a TCP connection.
/// a UDP socket (the target is specified in the send call), but
/// should be of type TCPEndpoint for a TCP connection.
/// \param callback I/O Completion callback, called when the operation has
/// completed, but only if the operation was asynchronous.
///
/// \return true if an asynchronous operation was started and the caller
/// should yield and wait for completion, false if the operation was
/// completed synchronously and no callback was queued.
virtual bool open(const IOEndpoint* endpoint, C& callback) = 0;
/// completed, but only if the operation was asynchronous. (It is
/// ignored on a UDP socket.)
virtual void open(const IOEndpoint* endpoint, C& callback) = 0;
/// \brief Send Asynchronously
///
......@@ -160,44 +192,85 @@ public:
/// \param endpoint Target of the send
/// \param callback Callback object.
virtual void asyncSend(const void* data, size_t length,
const IOEndpoint* endpoint, C& callback) = 0;
const IOEndpoint* endpoint, C& callback) = 0;
/// \brief Receive Asynchronously
///
/// This correstponds to async_receive_from() for UDP sockets and
/// This corresponds to async_receive_from() for UDP sockets and
/// async_receive() for TCP. In both cases, an endpoint argument is
/// supplied to receive the source of the communication. For TCP it will
/// be filled in with details of the connection.
///
/// \param data Buffer to receive incoming message
/// \param length Length of the data buffer
/// \param cumulative Amount of data that should already be in the buffer.
/// \param offset Offset into buffer where data is to be put. Although the
/// offset could be implied by adjusting "data" and "length"
/// appropriately, using this argument allows data to be specified as
/// "const void*" - the overhead of converting it to a pointer to a
/// set of bytes is hidden away here.