BIND 10 trac703, updated. 20607bda887846e2745bac1d275c51874885f917 [trac703] Update git version in ChangeLog
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Apr 15 10:36:33 UTC 2011
The branch, trac703 has been updated
via 20607bda887846e2745bac1d275c51874885f917 (commit)
via 17106327efdf114e15b21cf8079f9191ab073648 (commit)
via 262ac6c6fc61224d54705ed4c700dadb606fcb1c (commit)
via 8eb32c279693c55b444cbacaa835c9d04ee3f242 (commit)
via 7bc6ee513da806b25cab12a32465122f33232128 (commit)
via 0eacaf1a394d3674ca73c6531aca60dd952e0e3b (commit)
via 95b1c90380f6b12bf29939b7164fce8d5516d443 (commit)
via 8fc7cdd216bead2a98f1c98a6b6dc7a8a3bea4f4 (commit)
via 8fdbc3e46da7c31b4a533bbfe5778bf7d68e1bbe (commit)
via 7e561fe2f8d44b9224cf107287f79df14584512b (commit)
from 06c4fa64bb59638af953e9b3961d23e173eab49f (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 20607bda887846e2745bac1d275c51874885f917
Author: Stephen Morris <stephen at isc.org>
Date: Fri Apr 15 11:36:13 2011 +0100
[trac703] Update git version in ChangeLog
commit 17106327efdf114e15b21cf8079f9191ab073648
Merge: 06c4fa64bb59638af953e9b3961d23e173eab49f 262ac6c6fc61224d54705ed4c700dadb606fcb1c
Author: Stephen Morris <stephen at isc.org>
Date: Fri Apr 15 11:34:45 2011 +0100
[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
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 2 +-
configure.ac | 2 +
src/bin/auth/Makefile.am | 1 +
src/bin/auth/auth_srv.cc | 5 +-
src/bin/auth/auth_srv.h | 28 ++--
src/bin/auth/benchmarks/Makefile.am | 1 +
src/bin/auth/benchmarks/query_bench.cc | 4 +-
src/bin/auth/main.cc | 4 +-
src/bin/auth/tests/Makefile.am | 1 +
src/bin/auth/tests/auth_srv_unittest.cc | 3 +-
src/bin/auth/tests/command_unittest.cc | 2 +-
src/bin/auth/tests/config_unittest.cc | 3 +-
src/bin/resolver/Makefile.am | 3 +
src/bin/resolver/main.cc | 4 +-
src/bin/resolver/resolver.cc | 8 +-
src/bin/resolver/resolver.h | 40 +++---
src/bin/resolver/response_scrubber.cc | 2 +-
src/bin/resolver/response_scrubber.h | 4 +-
src/bin/resolver/tests/Makefile.am | 1 +
src/bin/resolver/tests/resolver_config_unittest.cc | 4 +-
.../resolver/tests/response_scrubber_unittest.cc | 4 +-
src/lib/Makefile.am | 2 +-
src/lib/asiodns/Makefile.am | 33 ++++
src/lib/{asiolink => asiodns}/README | 29 +----
src/lib/{asiolink => asiodns}/asiodef.cc | 26 ++--
src/lib/asiodns/asiodef.h | 23 +++
src/lib/{asiolink => asiodns}/asiodef.msg | 4 +-
.../tests/run_unittests.cc => asiodns/asiodns.h} | 13 +-
src/lib/{asiolink => asiodns}/dns_answer.h | 10 +-
src/lib/{asiolink => asiodns}/dns_lookup.h | 10 +-
src/lib/{asiolink => asiodns}/dns_server.h | 8 +-
src/lib/{asiolink => asiodns}/dns_service.cc | 17 +-
src/lib/{asiolink => asiodns}/dns_service.h | 20 ++-
src/lib/{asiolink => asiodns}/io_fetch.cc | 64 ++++----
src/lib/{asiolink => asiodns}/io_fetch.h | 20 ++-
src/lib/{asiolink => asiodns}/qid_gen.cc | 10 +-
src/lib/{asiolink => asiodns}/qid_gen.h | 6 +-
src/lib/{asiolink => asiodns}/tcp_server.cc | 10 +-
src/lib/{asiolink => asiodns}/tcp_server.h | 20 ++-
src/lib/{asiolink => asiodns}/tests/Makefile.am | 12 +--
.../tests/dns_server_unittest.cc | 11 +-
.../tests/io_fetch_unittest.cc | 9 +-
.../tests/io_service_unittest.cc | 4 +-
.../tests/qid_gen_unittest.cc | 8 +-
.../{asiolink => asiodns}/tests/run_unittests.cc | 0
src/lib/{asiolink => asiodns}/udp_server.cc | 9 +-
src/lib/{asiolink => asiodns}/udp_server.h | 14 +-
src/lib/asiolink/Makefile.am | 11 --
src/lib/asiolink/README | 160 --------------------
src/lib/asiolink/asiodef.h | 21 ---
src/lib/asiolink/asiolink.h | 9 -
src/lib/asiolink/asiolink_utilities.h | 2 +
src/lib/asiolink/dummy_io_cb.h | 2 +
src/lib/asiolink/interval_timer.cc | 4 +-
src/lib/asiolink/interval_timer.h | 4 +-
src/lib/asiolink/io_address.cc | 4 +-
src/lib/asiolink/io_address.h | 4 +-
src/lib/asiolink/io_asio_socket.h | 3 +-
src/lib/asiolink/io_endpoint.cc | 4 +-
src/lib/asiolink/io_endpoint.h | 4 +-
src/lib/asiolink/io_error.h | 4 +-
src/lib/asiolink/io_message.h | 4 +-
src/lib/asiolink/io_service.cc | 4 +-
src/lib/asiolink/io_service.h | 4 +-
src/lib/asiolink/io_socket.cc | 6 +-
src/lib/asiolink/io_socket.h | 2 +
src/lib/asiolink/simple_callback.h | 4 +-
src/lib/asiolink/tcp_endpoint.h | 4 +-
src/lib/asiolink/tcp_socket.h | 2 +
src/lib/asiolink/tests/Makefile.am | 4 -
.../asiolink/tests/asiolink_utilities_unittest.cc | 2 +-
src/lib/asiolink/tests/interval_timer_unittest.cc | 2 +-
src/lib/asiolink/tests/io_address_unittest.cc | 2 +-
src/lib/asiolink/tests/io_endpoint_unittest.cc | 2 +-
src/lib/asiolink/tests/io_socket_unittest.cc | 2 +-
src/lib/asiolink/tests/tcp_endpoint_unittest.cc | 2 +-
src/lib/asiolink/tests/tcp_socket_unittest.cc | 2 +-
src/lib/asiolink/tests/udp_endpoint_unittest.cc | 2 +-
src/lib/asiolink/tests/udp_socket_unittest.cc | 2 +-
src/lib/asiolink/udp_endpoint.h | 4 +-
src/lib/asiolink/udp_socket.h | 2 +
src/lib/nsas/glue_hints.cc | 2 +-
src/lib/nsas/nameserver_entry.cc | 2 +-
src/lib/nsas/tests/address_entry_unittest.cc | 2 +-
src/lib/nsas/tests/nameserver_address_unittest.cc | 4 +-
src/lib/nsas/tests/nameserver_entry_unittest.cc | 2 +-
src/lib/nsas/tests/zone_entry_unittest.cc | 2 +-
src/lib/resolve/recursive_query.cc | 13 +-
src/lib/resolve/recursive_query.h | 19 ++-
src/lib/resolve/resolver_callback.h | 6 +-
src/lib/resolve/tests/Makefile.am | 1 +
src/lib/resolve/tests/recursive_query_unittest.cc | 7 +-
.../resolve/tests/recursive_query_unittest_2.cc | 11 +-
.../resolve/tests/resolver_callback_unittest.cc | 8 +-
src/lib/server_common/portconfig.cc | 7 +-
src/lib/server_common/portconfig.h | 6 +-
src/lib/server_common/tests/Makefile.am | 3 +-
src/lib/server_common/tests/portconfig_unittest.cc | 4 +-
src/lib/testutils/mockups.h | 4 +-
src/lib/testutils/srv_test.cc | 2 +-
tests/tools/badpacket/Makefile.am | 3 +-
tests/tools/badpacket/scan.cc | 7 +-
tests/tools/badpacket/scan.h | 11 +-
103 files changed, 437 insertions(+), 501 deletions(-)
create mode 100644 src/lib/asiodns/Makefile.am
copy src/lib/{asiolink => asiodns}/README (84%)
rename src/lib/{asiolink => asiodns}/asiodef.cc (58%)
create mode 100644 src/lib/asiodns/asiodef.h
rename src/lib/{asiolink => asiodns}/asiodef.msg (98%)
copy src/lib/{util/io/tests/run_unittests.cc => asiodns/asiodns.h} (80%)
rename src/lib/{asiolink => asiodns}/dns_answer.h (93%)
rename src/lib/{asiolink => asiodns}/dns_lookup.h (94%)
rename src/lib/{asiolink => asiodns}/dns_server.h (97%)
rename src/lib/{asiolink => asiodns}/dns_service.cc (97%)
rename src/lib/{asiolink => asiodns}/dns_service.h (88%)
rename src/lib/{asiolink => asiodns}/io_fetch.cc (94%)
rename src/lib/{asiolink => asiodns}/io_fetch.h (93%)
rename src/lib/{asiolink => asiodns}/qid_gen.cc (89%)
rename src/lib/{asiolink => asiodns}/qid_gen.h (97%)
rename src/lib/{asiolink => asiodns}/tcp_server.cc (98%)
rename src/lib/{asiolink => asiodns}/tcp_server.h (90%)
copy src/lib/{asiolink => asiodns}/tests/Makefile.am (78%)
rename src/lib/{asiolink => asiodns}/tests/dns_server_unittest.cc (98%)
rename src/lib/{asiolink => asiodns}/tests/io_fetch_unittest.cc (99%)
rename src/lib/{asiolink => asiodns}/tests/io_service_unittest.cc (98%)
rename src/lib/{asiolink => asiodns}/tests/qid_gen_unittest.cc (89%)
copy src/lib/{asiolink => asiodns}/tests/run_unittests.cc (100%)
rename src/lib/{asiolink => asiodns}/udp_server.cc (98%)
rename src/lib/{asiolink => asiodns}/udp_server.h (93%)
delete mode 100644 src/lib/asiolink/asiodef.h
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index bd6dc79..252b49a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,7 @@
219. [func] stephen
Added the 'badpacket' program for testing; it sends a set of
(potentially) bad packets to a nameserver and prints the responses.
- (Trac #703, git 3b42967a83f4e15e1b1d07a159a600cb67628039)
+ (Trac #703, git 17106327efdf114e15b21cf8079f9191ab073648)
218. [func] jinmei
src/lib/dns: added support for RP RDATA.
diff --git a/configure.ac b/configure.ac
index d4519b6..63bd985 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index dfe23ee..56dc348 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -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
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index 9a49cc7..100e188 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -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;
}
diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h
index 8a6d522..24dca34 100644
--- a/src/bin/auth/auth_srv.h
+++ b/src/bin/auth/auth_srv.h
@@ -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
diff --git a/src/bin/auth/benchmarks/Makefile.am b/src/bin/auth/benchmarks/Makefile.am
index c7de8d4..a569147 100644
--- a/src/bin/auth/benchmarks/Makefile.am
+++ b/src/bin/auth/benchmarks/Makefile.am
@@ -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)
diff --git a/src/bin/auth/benchmarks/query_bench.cc b/src/bin/auth/benchmarks/query_bench.cc
index 86d9813..62c9c5b 100644
--- a/src/bin/auth/benchmarks/query_bench.cc
+++ b/src/bin/auth/benchmarks/query_bench.cc
@@ -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:
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index 64a8325..9bb0b45 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -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 {
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 882f7fd..026dde3 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -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
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index 379342e..3f98412 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -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;
diff --git a/src/bin/auth/tests/command_unittest.cc b/src/bin/auth/tests/command_unittest.cc
index dd1f6eb..3fdd086 100644
--- a/src/bin/auth/tests/command_unittest.cc
+++ b/src/bin/auth/tests/command_unittest.cc
@@ -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);
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index 9c94e25..7658b84 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -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 {
diff --git a/src/bin/resolver/Makefile.am b/src/bin/resolver/Makefile.am
index 54e15bd..094e3ad 100644
--- a/src/bin/resolver/Makefile.am
+++ b/src/bin/resolver/Makefile.am
@@ -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
diff --git a/src/bin/resolver/main.cc b/src/bin/resolver/main.cc
index 092ec54..33098a1 100644
--- a/src/bin/resolver/main.cc
+++ b/src/bin/resolver/main.cc
@@ -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 {
diff --git a/src/bin/resolver/resolver.cc b/src/bin/resolver/resolver.cc
index 2322076..4e0fe7b 100644
--- a/src/bin/resolver/resolver.cc
+++ b/src/bin/resolver/resolver.cc
@@ -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;
}
diff --git a/src/bin/resolver/resolver.h b/src/bin/resolver/resolver.h
index 8f07ff7..ca2ecd3 100644
--- a/src/bin/resolver/resolver.h
+++ b/src/bin/resolver/resolver.h
@@ -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:
diff --git a/src/bin/resolver/response_scrubber.cc b/src/bin/resolver/response_scrubber.cc
index 060a8b1..93bd808 100644
--- a/src/bin/resolver/response_scrubber.cc
+++ b/src/bin/resolver/response_scrubber.cc
@@ -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()) {
diff --git a/src/bin/resolver/response_scrubber.h b/src/bin/resolver/response_scrubber.h
index 680aa5a..c59ac15 100644
--- a/src/bin/resolver/response_scrubber.h
+++ b/src/bin/resolver/response_scrubber.h
@@ -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
///
diff --git a/src/bin/resolver/tests/Makefile.am b/src/bin/resolver/tests/Makefile.am
index b85c223..444358b 100644
--- a/src/bin/resolver/tests/Makefile.am
+++ b/src/bin/resolver/tests/Makefile.am
@@ -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
diff --git a/src/bin/resolver/tests/resolver_config_unittest.cc b/src/bin/resolver/tests/resolver_config_unittest.cc
index c1ff853..70e856d 100644
--- a/src/bin/resolver/tests/resolver_config_unittest.cc
+++ b/src/bin/resolver/tests/resolver_config_unittest.cc
@@ -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 {
diff --git a/src/bin/resolver/tests/response_scrubber_unittest.cc b/src/bin/resolver/tests/response_scrubber_unittest.cc
index 1dc6639..eff5598 100644
--- a/src/bin/resolver/tests/response_scrubber_unittest.cc
+++ b/src/bin/resolver/tests/response_scrubber_unittest.cc
@@ -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
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index a5f67e5..c8a38ec 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,2 +1,2 @@
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
diff --git a/src/lib/asiodns/Makefile.am b/src/lib/asiodns/Makefile.am
new file mode 100644
index 0000000..03b2bb5
--- /dev/null
+++ b/src/lib/asiodns/Makefile.am
@@ -0,0 +1,33 @@
+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
diff --git a/src/lib/asiodns/README b/src/lib/asiodns/README
new file mode 100644
index 0000000..596d1df
--- /dev/null
+++ b/src/lib/asiodns/README
@@ -0,0 +1,157 @@
+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
+required to read all the data.) The fetch loops until all the data is read.
+
+Finally, the socket is closed and the server called to resume operation.
diff --git a/src/lib/asiodns/asiodef.cc b/src/lib/asiodns/asiodef.cc
new file mode 100644
index 0000000..127e848
--- /dev/null
+++ b/src/lib/asiodns/asiodef.cc
@@ -0,0 +1,39 @@
+// 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 isc {
+namespace asiodns {
+
+extern const isc::log::MessageID ASIODNS_FETCHCOMP = "FETCHCOMP";
+extern const isc::log::MessageID ASIODNS_FETCHSTOP = "FETCHSTOP";
+extern const isc::log::MessageID ASIODNS_OPENSOCK = "OPENSOCK";
+extern const isc::log::MessageID ASIODNS_RECVSOCK = "RECVSOCK";
+extern const isc::log::MessageID ASIODNS_RECVTMO = "RECVTMO";
+extern const isc::log::MessageID ASIODNS_SENDSOCK = "SENDSOCK";
+extern const isc::log::MessageID ASIODNS_UNKORIGIN = "UNKORIGIN";
+extern const isc::log::MessageID ASIODNS_UNKRESULT = "UNKRESULT";
+
+} // namespace asiodns
+} // namespace isc
+
+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
+
diff --git a/src/lib/asiodns/asiodef.h b/src/lib/asiodns/asiodef.h
new file mode 100644
index 0000000..50aa8a9
--- /dev/null
+++ b/src/lib/asiodns/asiodef.h
@@ -0,0 +1,23 @@
+// 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 isc {
+namespace asiodns {
+
+extern const isc::log::MessageID ASIODNS_FETCHCOMP;
+extern const isc::log::MessageID ASIODNS_FETCHSTOP;
+extern const isc::log::MessageID ASIODNS_OPENSOCK;
+extern const isc::log::MessageID ASIODNS_RECVSOCK;
+extern const isc::log::MessageID ASIODNS_RECVTMO;
+extern const isc::log::MessageID ASIODNS_SENDSOCK;
+extern const isc::log::MessageID ASIODNS_UNKORIGIN;
+extern const isc::log::MessageID ASIODNS_UNKRESULT;
+
+} // namespace asiodns
+} // namespace isc
+
+#endif // __ASIODEF_H
diff --git a/src/lib/asiodns/asiodef.msg b/src/lib/asiodns/asiodef.msg
new file mode 100644
index 0000000..7f86acb
--- /dev/null
+++ b/src/lib/asiodns/asiodef.msg
@@ -0,0 +1,56 @@
+# 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 ASIODNS_
+$NAMESPACE isc::asiodns
+
+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.
diff --git a/src/lib/asiodns/asiodns.h b/src/lib/asiodns/asiodns.h
new file mode 100644
index 0000000..8791a72
--- /dev/null
+++ b/src/lib/asiodns/asiodns.h
@@ -0,0 +1,23 @@
+// 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 __ASIODNS_H
+#define __ASIODNS_H 1
+
+#include <asiodns/dns_service.h>
+#include <asiodns/dns_server.h>
+#include <asiodns/dns_lookup.h>
+#include <asiodns/dns_answer.h>
+
+#endif // __ASIODNS_H
diff --git a/src/lib/asiodns/dns_answer.h b/src/lib/asiodns/dns_answer.h
new file mode 100644
index 0000000..f4d643e
--- /dev/null
+++ b/src/lib/asiodns/dns_answer.h
@@ -0,0 +1,77 @@
+// 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_DNS_ANSWER_H
+#define __ASIOLINK_DNS_ANSWER_H 1
+
+#include <asiolink/io_message.h>
+#include <dns/buffer.h>
+#include <dns/message.h>
+
+namespace isc {
+namespace asiodns {
+
+/// \brief The \c DNSAnswer class is an abstract base class for a DNS
+/// Answer provider function.
+///
+/// Specific derived class implementations are hidden within the
+/// implementation. Instances of the derived classes can be called
+/// as functions via the operator() interface. Pointers to these
+/// instances can then be provided to the \c IOService class
+/// via its constructor.
+///
+/// A DNS Answer provider function takes answer data that has been obtained
+/// from a DNS Lookup provider functon and readies it to be sent to the
+/// client. After it has run, the OutputBuffer object passed to it should
+/// contain the answer to the query rendered into wire format.
+class DNSAnswer {
+ ///
+ /// \name Constructors and Destructor
+ ///
+ /// Note: The copy constructor and the assignment operator are
+ /// intentionally defined as private, making this class non-copyable.
+ //@{
+private:
+ DNSAnswer(const DNSAnswer& source);
+ DNSAnswer& operator=(const DNSAnswer& 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).
+ DNSAnswer() {}
+public:
+ /// \brief The destructor
+ 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 query_message The DNS MessagePtr of the original query
+ /// \param answer_message The DNS MessagePtr of the answer we are
+ /// building
+ /// \param buffer Intermediate data results are put here
+ virtual void operator()(const asiolink::IOMessage& io_message,
+ isc::dns::MessagePtr query_message,
+ isc::dns::MessagePtr answer_message,
+ isc::dns::OutputBufferPtr buffer) const = 0;
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __ASIOLINK_DNS_ANSWER_H
diff --git a/src/lib/asiodns/dns_lookup.h b/src/lib/asiodns/dns_lookup.h
new file mode 100644
index 0000000..a3b0b36
--- /dev/null
+++ b/src/lib/asiodns/dns_lookup.h
@@ -0,0 +1,85 @@
+// 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_DNS_LOOKUP_H
+#define __ASIOLINK_DNS_LOOKUP_H 1
+
+#include <asiolink/io_message.h>
+#include <asiodns/dns_server.h>
+#include <dns/buffer.h>
+#include <dns/message.h>
+
+namespace isc {
+namespace asiodns {
+
+/// \brief The \c DNSLookup class is an abstract base class for a DNS
+/// Lookup provider function.
+///
+/// Specific derived class implementations are hidden within the
+/// implementation. Instances of the derived classes can be called
+/// as functions via the operator() interface. Pointers to these
+/// instances can then be provided to the \c IOService class
+/// via its constructor.
+///
+/// A DNS Lookup provider function obtains the data needed to answer
+/// a DNS query (e.g., from authoritative data source, cache, or upstream
+/// query). After it has run, the OutputBuffer object passed to it
+/// should contain the answer to the query, in an internal representation.
+class DNSLookup {
+ ///
+ /// \name Constructors and Destructor
+ ///
+ /// Note: The copy constructor and the assignment operator are
+ /// intentionally defined as private, making this class non-copyable.
+ //@{
+private:
+ DNSLookup(const DNSLookup& source);
+ DNSLookup& operator=(const DNSLookup& 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).
+ DNSLookup() : self_(this) {}
+public:
+ /// \brief The destructor
+ virtual ~DNSLookup() {}
+ //@}
+ /// \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 answer_message The final answer will be constructed in
+ /// this MessagePtr
+ /// \param buffer The final answer is put here
+ /// \param server DNSServer object to use
+ virtual void operator()(const asiolink::IOMessage& io_message,
+ isc::dns::MessagePtr message,
+ isc::dns::MessagePtr answer_message,
+ isc::dns::OutputBufferPtr buffer,
+ DNSServer* server) const
+ {
+ (*self_)(io_message, message, answer_message, buffer, server);
+ }
+private:
+ DNSLookup* self_;
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __ASIOLINK_DNS_LOOKUP_H
diff --git a/src/lib/asiodns/dns_server.h b/src/lib/asiodns/dns_server.h
new file mode 100644
index 0000000..f235860
--- /dev/null
+++ b/src/lib/asiodns/dns_server.h
@@ -0,0 +1,157 @@
+// 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_DNS_SERVER_H
+#define __ASIOLINK_DNS_SERVER_H 1
+
+#include <asiolink/io_message.h>
+
+namespace isc {
+namespace asiodns {
+
+/// \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.
+/// Those functions are described in more detail below under
+/// \c SimpleCallback, \c DNSLookup, and \c DNSAnswer.
+///
+/// Notes to developers:
+/// When constructed, this class (and its derived classes) will have its
+/// "self_" member set to point to "this". Objects of this class (as
+/// instantiated through a base class) are sometimes passed by
+/// reference (as this superclass); calls to methods in the base
+/// class are then rerouted via this pointer to methods in the derived
+/// class. This allows code from outside asiodns, with no specific
+/// knowledge of \c TCPServer or \c UDPServer, to access their methods.
+///
+/// This class is both assignable and copy-constructable. Its subclasses
+/// use the "stackless coroutine" pattern, meaning that it will copy itself
+/// 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
+/// that derived classes be kept small to reduce copy overhead.
+class DNSServer {
+protected:
+ ///
+ /// \name Constructors and destructors
+ ///
+ /// This is intentionally defined as \c protected, as this base class
+ /// should never be instantiated except as part of a derived class.
+ //@{
+ DNSServer() : self_(this) {}
+public:
+ /// \brief The destructor
+ virtual ~DNSServer() {}
+ //@}
+
+ ///
+ /// \name Class methods
+ ///
+ /// These methods all make their calls indirectly via the "self_"
+ /// pointer, ensuring that the functions ultimately invoked will be
+ /// 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(),
+ size_t length = 0)
+ {
+ (*self_)(ec, length);
+ }
+
+ /// \brief Stop current running server
+ virtual void stop() { self_->stop();}
+
+ /// \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 void resume(const bool done) { self_->resume(done); }
+
+ /// \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()); }
+
+ /// \brief Returns the current value of the 'coroutine' object
+ ///
+ /// This is a temporary method, intended to be used for debugging
+ /// 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 int value() { return (self_->value()); }
+
+ /// \brief Returns a pointer to a clone of this DNSServer object.
+ ///
+ /// When a \c DNSServer object is copied or assigned, the result will
+ /// 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 DNSServer* clone() { return (self_->clone()); }
+ //@}
+
+protected:
+ /// \brief Lookup handler object.
+ ///
+ /// This is a protected class; it can only be instantiated
+ /// from within a derived class of \c DNSServer.
+ ///
+ /// A server object that has received a query creates an instance
+ /// of this class and scheudles it on the ASIO service queue
+ /// using asio::io_service::post(). When the handler executes, it
+ /// calls the asyncLookup() method in the server object to start a
+ /// DNS lookup. When the lookup is complete, the server object is
+ /// scheduled to resume, again using io_service::post().
+ ///
+ /// Note that the calling object is copied into the handler object,
+ /// not referenced. This is because, once the calling object yields
+ /// control to the handler, it falls out of scope and may disappear
+ template <typename T>
+ class AsyncLookup {
+ public:
+ AsyncLookup(T& caller) : caller_(caller) {}
+ void operator()() { caller_.asyncLookup(); }
+ private:
+ T caller_;
+ };
+
+ /// \brief Carries out a DNS lookup.
+ ///
+ /// This function calls the \c DNSLookup object specified by the
+ /// DNS server when the \c IOService was created, passing along
+ /// the details of the query and a pointer back to the current
+ /// server object. It is called asynchronously via the AsyncLookup
+ /// handler class.
+ virtual void asyncLookup() { self_->asyncLookup(); }
+
+private:
+ DNSServer* self_;
+};
+
+
+} // namespace asiodns
+} // namespace isc
+#endif // __ASIOLINK_DNS_SERVER_H
diff --git a/src/lib/asiodns/dns_service.cc b/src/lib/asiodns/dns_service.cc
new file mode 100644
index 0000000..94510fe
--- /dev/null
+++ b/src/lib/asiodns/dns_service.cc
@@ -0,0 +1,201 @@
+// 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.
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h> // for some IPC/network system calls
+
+#include <boost/lexical_cast.hpp>
+
+#include <config.h>
+
+#include <log/dummylog.h>
+
+#include <asio.hpp>
+#include <dns_service.h>
+#include <asiolink/io_service.h>
+#include <asiolink/io_service.h>
+#include <tcp_server.h>
+#include <udp_server.h>
+
+#include <log/dummylog.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/foreach.hpp>
+
+using isc::log::dlog;
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+class DNSLookup;
+class DNSAnswer;
+
+namespace {
+
+asio::ip::address
+convertAddr(const std::string& address) {
+ asio::error_code err;
+ asio::ip::address addr = asio::ip::address::from_string(address, err);
+ if (err) {
+ isc_throw(IOError, "Invalid IP address '" << &address << "': "
+ << err.message());
+ }
+ return (addr);
+}
+
+}
+
+
+class DNSServiceImpl {
+public:
+ DNSServiceImpl(IOService& io_service, const char& port,
+ const asio::ip::address* v4addr,
+ const asio::ip::address* v6addr,
+ SimpleCallback* checkin, DNSLookup* lookup,
+ DNSAnswer* answer);
+
+ IOService& io_service_;
+
+ typedef boost::shared_ptr<UDPServer> UDPServerPtr;
+ typedef boost::shared_ptr<TCPServer> TCPServerPtr;
+ typedef boost::shared_ptr<DNSServer> DNSServerPtr;
+ std::vector<DNSServerPtr> servers_;
+ SimpleCallback *checkin_;
+ DNSLookup *lookup_;
+ DNSAnswer *answer_;
+
+ void addServer(uint16_t port, const asio::ip::address& address) {
+ try {
+ dlog(std::string("Initialize TCP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
+ TCPServerPtr tcpServer(new TCPServer(io_service_.get_io_service(),
+ address, port, checkin_, lookup_, answer_));
+ (*tcpServer)();
+ servers_.push_back(tcpServer);
+ dlog(std::string("Initialize UDP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
+ UDPServerPtr udpServer(new UDPServer(io_service_.get_io_service(),
+ address, port, checkin_, lookup_, answer_));
+ (*udpServer)();
+ servers_.push_back(udpServer);
+ }
+ catch (const asio::system_error& err) {
+ // We need to catch and convert any ASIO level exceptions.
+ // This can happen for unavailable address, binding a privilege port
+ // without the privilege, etc.
+ isc_throw(IOError, "Failed to initialize network servers: " <<
+ err.what());
+ }
+ }
+ void addServer(const char& port, const asio::ip::address& address) {
+ uint16_t portnum;
+ try {
+ // XXX: SunStudio with stlport4 doesn't reject some invalid
+ // representation such as "-1" by lexical_cast<uint16_t>, so
+ // we convert it into a signed integer of a larger size and perform
+ // range check ourselves.
+ const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
+ if (portnum32 < 0 || portnum32 > 65535) {
+ isc_throw(IOError, "Invalid port number '" << &port);
+ }
+ portnum = portnum32;
+ } catch (const boost::bad_lexical_cast& ex) {
+ isc_throw(IOError, "Invalid port number '" << &port << "': " <<
+ ex.what());
+ }
+ addServer(portnum, address);
+ }
+};
+
+DNSServiceImpl::DNSServiceImpl(IOService& io_service,
+ const char& port,
+ const asio::ip::address* const v4addr,
+ const asio::ip::address* const v6addr,
+ SimpleCallback* checkin,
+ DNSLookup* lookup,
+ DNSAnswer* answer) :
+ io_service_(io_service),
+ checkin_(checkin),
+ lookup_(lookup),
+ answer_(answer)
+{
+
+ if (v4addr) {
+ addServer(port, *v4addr);
+ }
+ if (v6addr) {
+ addServer(port, *v6addr);
+ }
+}
+
+DNSService::DNSService(IOService& io_service,
+ const char& port, const char& address,
+ SimpleCallback* checkin,
+ DNSLookup* lookup,
+ DNSAnswer* answer) :
+ impl_(new DNSServiceImpl(io_service, port, NULL, NULL, checkin, lookup,
+ answer)), io_service_(io_service)
+{
+ addServer(port, &address);
+}
+
+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 asio::ip::address v4addr_any =
+ asio::ip::address(asio::ip::address_v4::any());
+ const asio::ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL;
+ const asio::ip::address v6addr_any =
+ asio::ip::address(asio::ip::address_v6::any());
+ const asio::ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
+ impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
+}
+
+DNSService::DNSService(IOService& io_service, SimpleCallback* checkin,
+ DNSLookup* lookup, DNSAnswer *answer) :
+ impl_(new DNSServiceImpl(io_service, *"0", NULL, NULL, checkin, lookup,
+ answer)), io_service_(io_service)
+{
+}
+
+DNSService::~DNSService() {
+ delete impl_;
+}
+
+void
+DNSService::addServer(const char& port, const std::string& address) {
+ impl_->addServer(port, convertAddr(address));
+}
+
+void
+DNSService::addServer(uint16_t port, const std::string& address) {
+ impl_->addServer(port, convertAddr(address));
+}
+
+void
+DNSService::clearServers() {
+ BOOST_FOREACH(const DNSServiceImpl::DNSServerPtr& s, impl_->servers_) {
+ s->stop();
+ }
+ impl_->servers_.clear();
+}
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/dns_service.h b/src/lib/asiodns/dns_service.h
new file mode 100644
index 0000000..6b6a6c0
--- /dev/null
+++ b/src/lib/asiodns/dns_service.h
@@ -0,0 +1,114 @@
+// 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_DNS_SERVICE_H
+#define __ASIOLINK_DNS_SERVICE_H 1
+
+#include <resolve/resolver_interface.h>
+
+#include <asiolink/io_service.h>
+#include <asiolink/simple_callback.h>
+
+namespace isc {
+namespace asiodns {
+
+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
+ ///
+ /// 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(asiolink::IOService& io_service, const char& port,
+ const char& address, isc::asiolink::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 use_ipv4 If true, listen on ipv4 'any'
+ /// \param use_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(asiolink::IOService& io_service, const char& port,
+ const bool use_ipv4, const bool use_ipv6,
+ isc::asiolink::SimpleCallback* checkin, DNSLookup* lookup,
+ DNSAnswer* answer);
+ /// \brief The constructor without any servers.
+ ///
+ /// Use addServer() to add some servers.
+ DNSService(asiolink::IOService& io_service, isc::asiolink::SimpleCallback* checkin,
+ DNSLookup* lookup, DNSAnswer* answer);
+ /// \brief The destructor.
+ ~DNSService();
+ //@}
+
+ /// \brief Add another server to the service
+ void addServer(uint16_t port, const std::string &address);
+ void addServer(const char &port, const std::string &address);
+ /// \brief Remove all servers from the service
+ void clearServers();
+
+ /// \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(); }
+
+ /// \brief Return the IO Service Object
+ ///
+ /// \return IOService object for this DNS service.
+ asiolink::IOService& getIOService() { return (io_service_);}
+
+private:
+ DNSServiceImpl* impl_;
+ asiolink::IOService& io_service_;
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __ASIOLINK_DNS_SERVICE_H
diff --git a/src/lib/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc
new file mode 100644
index 0000000..f543ce2
--- /dev/null
+++ b/src/lib/asiodns/io_fetch.cc
@@ -0,0 +1,404 @@
+// 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.
+
+#include <config.h>
+
+#include <netinet/in.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <unistd.h> // for some IPC/network system calls
+
+#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <asio.hpp>
+#include <asio/deadline_timer.hpp>
+
+#include <asiolink/io_address.h>
+#include <asiolink/io_asio_socket.h>
+#include <asiolink/io_endpoint.h>
+#include <asiolink/io_service.h>
+#include <asiolink/tcp_endpoint.h>
+#include <asiolink/tcp_socket.h>
+#include <asiolink/udp_endpoint.h>
+#include <asiolink/udp_socket.h>
+
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <log/logger.h>
+
+#include <asiodns/asiodef.h>
+#include <asiodns/io_fetch.h>
+#include <asiodns/qid_gen.h>
+
+
+using namespace asio;
+using namespace isc::asiolink;
+using namespace isc::dns;
+using namespace isc::log;
+using namespace std;
+
+namespace isc {
+namespace asiodns {
+
+/// Use the ASIO logger
+
+isc::log::Logger logger("asiolink");
+
+/// \brief IOFetch Data
+///
+/// The data for IOFetch is held in a separate struct pointed to by a shared_ptr
+/// object. This is because the IOFetch object will be copied often (it is used
+/// as a coroutine and passed as callback to many async_*() functions) and we
+/// want keep the same data). Organising the data in this way keeps copying to
+/// a minimum.
+struct IOFetchData {
+
+ // The first two members are shared pointers to a base class because what is
+ // actually instantiated depends on whether the fetch is over UDP or TCP,
+ // which is not known until construction of the IOFetch. Use of a shared
+ // pointer here is merely to ensure deletion when the data object is deleted.
+ boost::scoped_ptr<IOAsioSocket<IOFetch> > socket;
+ ///< Socket to use for I/O
+ boost::scoped_ptr<IOEndpoint> remote_snd;///< Where the fetch is sent
+ boost::scoped_ptr<IOEndpoint> remote_rcv;///< Where the response came from
+ isc::dns::Question question; ///< Question to be asked
+ isc::dns::OutputBufferPtr msgbuf; ///< Wire buffer for question
+ isc::dns::OutputBufferPtr received; ///< Received data put here
+ IOFetch::Callback* callback; ///< Called on I/O Completion
+ asio::deadline_timer timer; ///< Timer to measure timeouts
+ IOFetch::Protocol protocol; ///< Protocol being used
+ size_t cumulative; ///< Cumulative received amount
+ size_t expected; ///< Expected amount of data
+ size_t offset; ///< Offset to receive data
+ bool stopped; ///< Have we stopped running?
+ int timeout; ///< Timeout in ms
+ bool packet; ///< true if packet was supplied
+
+ // In case we need to log an error, the origin of the last asynchronous
+ // I/O is recorded. To save time and simplify the code, this is recorded
+ // as the ID of the error message that would be generated if the I/O failed.
+ // This means that we must make sure that all possible "origins" take the
+ // same arguments in their message in the same order.
+ isc::log::MessageID origin; ///< Origin of last asynchronous I/O
+ uint8_t staging[IOFetch::STAGING_LENGTH];
+ ///< Temporary array for received data
+ isc::dns::qid_t qid; ///< The QID set in the query
+
+ /// \brief Constructor
+ ///
+ /// Just fills in the data members of the IOFetchData structure
+ ///
+ /// \param proto Either IOFetch::TCP or IOFetch::UDP.
+ /// \param service I/O Service object to handle the asynchronous
+ /// operations.
+ /// \param query DNS question to send to the upstream server.
+ /// \param address IP address of upstream server
+ /// \param port Port to use for the query
+ /// \param buff Output buffer into which the response (in wire format)
+ /// is written (if a response is received).
+ /// \param cb Callback object containing the callback to be called
+ /// when we terminate. The caller is responsible for managing this
+ /// object and deleting it if necessary.
+ /// \param wait Timeout for the fetch (in ms).
+ ///
+ /// TODO: May need to alter constructor (see comment 4 in Trac ticket #554)
+ IOFetchData(IOFetch::Protocol proto, IOService& service,
+ const isc::dns::Question& query, const IOAddress& address,
+ uint16_t port, isc::dns::OutputBufferPtr& buff, IOFetch::Callback* cb,
+ int wait)
+ :
+ socket((proto == IOFetch::UDP) ?
+ static_cast<IOAsioSocket<IOFetch>*>(
+ new UDPSocket<IOFetch>(service)) :
+ static_cast<IOAsioSocket<IOFetch>*>(
+ new TCPSocket<IOFetch>(service))
+ ),
+ remote_snd((proto == IOFetch::UDP) ?
+ static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
+ static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
+ ),
+ remote_rcv((proto == IOFetch::UDP) ?
+ static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
+ static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
+ ),
+ question(query),
+ msgbuf(new isc::dns::OutputBuffer(512)),
+ received(buff),
+ callback(cb),
+ timer(service.get_io_service()),
+ protocol(proto),
+ cumulative(0),
+ expected(0),
+ offset(0),
+ stopped(false),
+ timeout(wait),
+ packet(false),
+ origin(ASIODNS_UNKORIGIN),
+ staging(),
+ qid(QidGenerator::getInstance().generateQid())
+ {}
+
+ // Checks if the response we received was ok;
+ // - data contains the buffer we read, as well as the address
+ // we sent to and the address we received from.
+ // length is provided by the operator() in IOFetch.
+ // Addresses must match, number of octets read must be at least
+ // 2, and the first two octets must match the qid of the message
+ // we sent.
+ bool responseOK() {
+ return (*remote_snd == *remote_rcv && cumulative >= 2 &&
+ readUint16(received->getData()) == qid);
+ }
+};
+
+/// IOFetch Constructor - just initialize the private data
+
+IOFetch::IOFetch(Protocol protocol, IOService& service,
+ const isc::dns::Question& question, const IOAddress& address, uint16_t port,
+ OutputBufferPtr& buff, Callback* cb, int wait)
+ :
+ data_(new IOFetchData(protocol, service, question, address,
+ port, buff, cb, wait))
+{
+}
+
+IOFetch::IOFetch(Protocol protocol, IOService& service,
+ OutputBufferPtr& outpkt, const IOAddress& address, uint16_t port,
+ OutputBufferPtr& buff, Callback* cb, int wait)
+ :
+ data_(new IOFetchData(protocol, service,
+ isc::dns::Question(isc::dns::Name("dummy.example.org"),
+ isc::dns::RRClass::IN(), isc::dns::RRType::A()),
+ address, port, buff, cb, wait))
+{
+ data_->msgbuf = outpkt;
+ data_->packet = true;
+}
+
+// Return protocol in use.
+
+IOFetch::Protocol
+IOFetch::getProtocol() const {
+ return (data_->protocol);
+}
+
+/// The function operator is implemented with the "stackless coroutine"
+/// pattern; see internal/coroutine.h for details.
+
+void
+IOFetch::operator()(asio::error_code ec, size_t length) {
+
+ if (data_->stopped) {
+ return;
+ } else if (ec) {
+ logIOFailure(ec);
+ return;
+ }
+
+ CORO_REENTER (this) {
+
+ /// Generate the upstream query and render it to wire format
+ /// This is done in a different scope to allow inline variable
+ /// declarations.
+ {
+ if (data_->packet) {
+ // A packet was given, overwrite the QID (which is in the
+ // first two bytes of the packet).
+ data_->msgbuf->writeUint16At(data_->qid, 0);
+
+ } else {
+ // A question was given, construct the packet
+ Message msg(Message::RENDER);
+ msg.setQid(data_->qid);
+ msg.setOpcode(Opcode::QUERY());
+ msg.setRcode(Rcode::NOERROR());
+ msg.setHeaderFlag(Message::HEADERFLAG_RD);
+ msg.addQuestion(data_->question);
+ MessageRenderer renderer(*data_->msgbuf);
+ msg.toWire(renderer);
+ }
+ }
+
+ // If we timeout, we stop, which will can cancel outstanding I/Os and
+ // shutdown everything.
+ if (data_->timeout != -1) {
+ data_->timer.expires_from_now(boost::posix_time::milliseconds(
+ data_->timeout));
+ data_->timer.async_wait(boost::bind(&IOFetch::stop, *this,
+ TIME_OUT));
+ }
+
+ // Open a connection to the target system. For speed, if the operation
+ // is synchronous (i.e. UDP operation) we bypass the yield.
+ data_->origin = ASIODNS_OPENSOCK;
+ if (data_->socket->isOpenSynchronous()) {
+ data_->socket->open(data_->remote_snd.get(), *this);
+ } else {
+ CORO_YIELD data_->socket->open(data_->remote_snd.get(), *this);
+ }
+
+ do {
+ // Begin an asynchronous send, and then yield. When the send completes,
+ // we will resume immediately after this point.
+ data_->origin = ASIODNS_SENDSOCK;
+ CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
+ data_->msgbuf->getLength(), data_->remote_snd.get(), *this);
+
+ // Now receive the response. Since TCP may not receive the entire
+ // message in one operation, we need to loop until we have received
+ // it. (This can't be done within the asyncReceive() method because
+ // each I/O operation will be done asynchronously and between each one
+ // we need to yield ... and we *really* don't want to set up another
+ // coroutine within that method.) So after each receive (and yield),
+ // we check if the operation is complete and if not, loop to read again.
+ //
+ // Another concession to TCP is that the amount of is contained in the
+ // first two bytes. This leads to two problems:
+ //
+ // a) We don't want those bytes in the return buffer.
+ // b) They may not both arrive in the first I/O.
+ //
+ // So... we need to loop until we have at least two bytes, then store
+ // the expected amount of data. Then we need to loop until we have
+ // received all the data before copying it back to the user's buffer.
+ // And we want to minimise the amount of copying...
+
+ data_->origin = ASIODNS_RECVSOCK;
+ data_->cumulative = 0; // No data yet received
+ data_->offset = 0; // First data into start of buffer
+ data_->received->clear(); // Clear the receive buffer
+ do {
+ CORO_YIELD data_->socket->asyncReceive(data_->staging,
+ static_cast<size_t>(STAGING_LENGTH),
+ data_->offset,
+ data_->remote_rcv.get(), *this);
+ } while (!data_->socket->processReceivedData(data_->staging, length,
+ data_->cumulative, data_->offset,
+ data_->expected, data_->received));
+ } while (!data_->responseOK());
+
+ // Finished with this socket, so close it. This will not generate an
+ // I/O error, but reset the origin to unknown in case we change this.
+ data_->origin = ASIODNS_UNKORIGIN;
+ data_->socket->close();
+
+ /// We are done
+ stop(SUCCESS);
+ }
+}
+
+// Function that stops the coroutine sequence. It is called either when the
+// query finishes or when the timer times out. Either way, it sets the
+// "stopped_" flag and cancels anything that is in progress.
+//
+// As the function may be entered multiple times as things wind down, it checks
+// if the stopped_ flag is already set. If it is, the call is a no-op.
+
+void
+IOFetch::stop(Result result) {
+
+ if (!data_->stopped) {
+
+ // Mark the fetch as stopped to prevent other completion callbacks
+ // (invoked because of the calls to cancel()) from executing the
+ // cancel calls again.
+ //
+ // In a single threaded environment, the callbacks won't be invoked
+ // until this one completes. In a multi-threaded environment, they may
+ // well be, in which case the testing (and setting) of the stopped_
+ // variable should be done inside a mutex (and the stopped_ variable
+ // declared as "volatile").
+ //
+ // The numeric arguments indicate the debug level, with the lower
+ // numbers indicating the most important information. The relative
+ // values are somewhat arbitrary.
+ //
+ // Although Logger::debug checks the debug flag internally, doing it
+ // below before calling Logger::debug avoids the overhead of a string
+ // conversion in the common case when debug is not enabled.
+ //
+ // TODO: Update testing of stopped_ if threads are used.
+ data_->stopped = true;
+ switch (result) {
+ case TIME_OUT:
+ if (logger.isDebugEnabled(1)) {
+ logger.debug(20, ASIODNS_RECVTMO,
+ data_->remote_snd->getAddress().toText().c_str(),
+ static_cast<int>(data_->remote_snd->getPort()));
+ }
+ break;
+
+ case SUCCESS:
+ if (logger.isDebugEnabled(50)) {
+ logger.debug(30, ASIODNS_FETCHCOMP,
+ data_->remote_rcv->getAddress().toText().c_str(),
+ static_cast<int>(data_->remote_rcv->getPort()));
+ }
+ break;
+
+ case STOPPED:
+ // Fetch has been stopped for some other reason. This is
+ // allowed but as it is unusual it is logged, but with a lower
+ // debug level than a timeout (which is totally normal).
+ logger.debug(1, ASIODNS_FETCHSTOP,
+ data_->remote_snd->getAddress().toText().c_str(),
+ static_cast<int>(data_->remote_snd->getPort()));
+ break;
+
+ default:
+ logger.error(ASIODNS_UNKRESULT, static_cast<int>(result),
+ data_->remote_snd->getAddress().toText().c_str(),
+ static_cast<int>(data_->remote_snd->getPort()));
+ }
+
+ // Stop requested, cancel and I/O's on the socket and shut it down,
+ // and cancel the timer.
+ data_->socket->cancel();
+ data_->socket->close();
+
+ data_->timer.cancel();
+
+ // Execute the I/O completion callback (if present).
+ if (data_->callback) {
+ (*(data_->callback))(result);
+ }
+ }
+}
+
+// Log an error - called on I/O failure
+
+void IOFetch::logIOFailure(asio::error_code ec) {
+
+ // Should only get here with a known error code.
+ assert((data_->origin == ASIODNS_OPENSOCK) ||
+ (data_->origin == ASIODNS_SENDSOCK) ||
+ (data_->origin == ASIODNS_RECVSOCK) ||
+ (data_->origin == ASIODNS_UNKORIGIN));
+
+ static const char* PROTOCOL[2] = {"TCP", "UDP"};
+ logger.error(data_->origin,
+ ec.value(),
+ ((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
+ PROTOCOL[0] : PROTOCOL[1]),
+ data_->remote_snd->getAddress().toText().c_str(),
+ static_cast<int>(data_->remote_snd->getPort()));
+}
+
+} // namespace asiodns
+} // namespace isc {
+
diff --git a/src/lib/asiodns/io_fetch.h b/src/lib/asiodns/io_fetch.h
new file mode 100644
index 0000000..9c34acf
--- /dev/null
+++ b/src/lib/asiodns/io_fetch.h
@@ -0,0 +1,204 @@
+// 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 __IO_FETCH_H
+#define __IO_FETCH_H 1
+
+#include <config.h>
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <coroutine.h>
+
+#include <asio/error_code.hpp>
+#include <asiolink/io_address.h>
+#include <asiolink/io_service.h>
+
+#include <dns/buffer.h>
+#include <dns/question.h>
+
+namespace isc {
+namespace asiodns {
+
+// Forward declarations
+class IOFetchData;
+
+/// \brief Upstream Fetch Processing
+///
+/// IOFetch is the class used to send upstream fetches and to handle responses.
+///
+/// \param E Endpoint type to use.
+
+class IOFetch : public coroutine {
+public:
+ /// \brief Protocol to use on the fetch
+ enum Protocol {
+ UDP = 0,
+ TCP = 1
+ };
+
+ /// \brief Origin of Asynchronous I/O Call
+ ///
+ /// Indicates what initiated an asynchronous I/O call and used in deciding
+ /// what error message to output if the I/O fails.
+ enum Origin {
+ NONE = 0, ///< No asynchronous call outstanding
+ OPEN = 1,
+ SEND = 2,
+ RECEIVE = 3,
+ CLOSE = 4
+ };
+
+ /// \brief Result of Upstream Fetch
+ ///
+ /// Note that this applies to the status of I/Os in the fetch - a fetch
+ /// that resulted in a packet being received from the server is a SUCCESS,
+ /// even if the contents of the packet indicate that some error occurred.
+ enum Result {
+ SUCCESS = 0, ///< Success, fetch completed
+ TIME_OUT = 1, ///< Failure, fetch timed out
+ STOPPED = 2, ///< Control code, fetch has been stopped
+ NOTSET = 3 ///< For testing, indicates value not set
+ };
+
+ // The next enum is a "trick" to allow constants to be defined in a class
+ // declaration.
+
+ /// \brief Integer Constants
+ enum {
+ STAGING_LENGTH = 8192 ///< Size of staging buffer
+ };
+
+ /// \brief I/O Fetch Callback
+ ///
+ /// Class of callback object for when the fetch itself has completed - an
+ /// object of this class is passed to the IOFetch constructor and its
+ /// operator() method called when the fetch completes.
+ ///
+ /// Note the difference between the two operator() methods:
+ /// - IOFetch::operator() callback is called when an asynchronous I/O has
+ /// completed.
+ /// - IOFetch::Callback::operator() is called when an upstream fetch - which
+ /// may have involved several asynchronous I/O operations - has completed.
+ ///
+ /// This is an abstract class.
+ class Callback {
+ public:
+ /// \brief Default Constructor
+ Callback()
+ {}
+
+ /// \brief Virtual Destructor
+ virtual ~Callback()
+ {}
+
+ /// \brief Callback method
+ ///
+ /// This is the method called when the fetch completes.
+ ///
+ /// \param result Result of the fetch
+ virtual void operator()(Result result) = 0;
+ };
+
+ /// \brief Constructor.
+ ///
+ /// Creates the object that will handle the upstream fetch.
+ ///
+ /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
+ /// \param service I/O Service object to handle the asynchronous
+ /// operations.
+ /// \param question DNS question to send to the upstream server.
+ /// \param address IP address of upstream server
+ /// \param port Port to which to connect on the upstream server
+ /// \param buff Output buffer into which the response (in wire format)
+ /// is written (if a response is received).
+ /// \param cb Callback object containing the callback to be called when we
+ /// terminate. The caller is responsible for managing this object
+ /// and deleting it if necessary.
+ /// \param wait Timeout for the fetch (in ms). The default value of
+ /// -1 indicates no timeout.
+ IOFetch(Protocol protocol, isc::asiolink::IOService& service,
+ const isc::dns::Question& question,
+ const isc::asiolink::IOAddress& address,
+ uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
+ int wait = -1);
+
+ /// \brief Constructor.
+ ///
+ /// Creates the object that will handle the upstream fetch.
+ ///
+ /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
+ /// \param service I/O Service object to handle the asynchronous
+ /// operations.
+ /// \param outpkt Packet to send to upstream server. Note that the
+ /// QID (first two bytes of the packet) may be altered in the sending.
+ /// \param buff Output buffer into which the response (in wire format)
+ /// is written (if a response is received).
+ /// \param cb Callback object containing the callback to be called
+ /// when we terminate. The caller is responsible for managing this
+ /// object and deleting it if necessary.
+ /// \param address IP address of upstream server
+ /// \param port Port to which to connect on the upstream server
+ /// (default = 53)
+ /// \param wait Timeout for the fetch (in ms). The default value of
+ /// -1 indicates no timeout.
+ IOFetch(Protocol protocol, isc::asiolink::IOService& service,
+ isc::dns::OutputBufferPtr& outpkt,
+ const isc::asiolink::IOAddress& address,
+ uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
+ int wait = -1);
+
+ /// \brief Return Current Protocol
+ ///
+ /// \return Protocol associated with this IOFetch object.
+ Protocol getProtocol() const;
+
+ /// \brief Coroutine entry point
+ ///
+ /// The operator() method is the method in which the coroutine code enters
+ /// this object when an operation has been completed.
+ ///
+ /// \param ec Error code, the result of the last asynchronous I/O operation.
+ /// \param length Amount of data received on the last asynchronous read
+ void operator()(asio::error_code ec = asio::error_code(), size_t length = 0);
+
+ /// \brief Terminate query
+ ///
+ /// This method can be called at any point. It terminates the current
+ /// query with the specified reason.
+ ///
+ /// \param reason Reason for terminating the query
+ void stop(Result reason = STOPPED);
+
+private:
+ /// \brief Log I/O Failure
+ ///
+ /// Records an I/O failure to the log file
+ ///
+ /// \param ec ASIO error code
+ void logIOFailure(asio::error_code ec);
+
+ // Member variables. All data is in a structure pointed to by a shared
+ // pointer. The IOFetch object is copied a number of times during its
+ // life, and only requiring a pointer to be copied reduces overhead.
+ boost::shared_ptr<IOFetchData> data_; ///< Private data
+
+};
+
+} // namespace asiodns
+} // namespace isc
+
+#endif // __IO_FETCH_H
diff --git a/src/lib/asiodns/qid_gen.cc b/src/lib/asiodns/qid_gen.cc
new file mode 100644
index 0000000..f200364
--- /dev/null
+++ b/src/lib/asiodns/qid_gen.cc
@@ -0,0 +1,56 @@
+// 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.
+
+// qid_gen defines a generator for query id's
+//
+// We probably want to merge this with the weighted random in the nsas
+// (and other parts where we need randomness, perhaps another thing
+// for a general libutil?)
+
+#include <asiodns/qid_gen.h>
+
+#include <sys/time.h>
+
+namespace {
+ isc::asiodns::QidGenerator qid_generator_instance;
+}
+
+namespace isc {
+namespace asiodns {
+
+QidGenerator&
+QidGenerator::getInstance() {
+ return (qid_generator_instance);
+}
+
+QidGenerator::QidGenerator() : dist_(0, 65535),
+ vgen_(generator_, dist_)
+{
+ seed();
+}
+
+void
+QidGenerator::seed() {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ generator_.seed((tv.tv_sec * 1000000) + tv.tv_usec);
+}
+
+isc::dns::qid_t
+QidGenerator::generateQid() {
+ return (vgen_());
+}
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/qid_gen.h b/src/lib/asiodns/qid_gen.h
new file mode 100644
index 0000000..bc6e2ad
--- /dev/null
+++ b/src/lib/asiodns/qid_gen.h
@@ -0,0 +1,87 @@
+// 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.
+
+// qid_gen defines a generator for query id's
+//
+// We probably want to merge this with the weighted random in the nsas
+// (and other parts where we need randomness, perhaps another thing
+// for a general libutil?)
+
+#ifndef __QID_GEN_H
+#define __QID_GEN_H
+
+#include <dns/message.h>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/variate_generator.hpp>
+
+
+namespace isc {
+namespace asiodns {
+
+/// This class generates Qids for outgoing queries
+///
+/// It is implemented as a singleton; the public way to access it
+/// is to call getInstance()->generateQid().
+///
+/// It automatically seeds it with the current time when it is first
+/// used.
+class QidGenerator {
+public:
+ /// \brief Returns the singleton instance of the QidGenerator
+ ///
+ /// Returns a reference to the singleton instance of the generator
+ static QidGenerator& getInstance();
+
+ /// \brief Default constructor
+ ///
+ /// It is recommended that getInstance is used rather than creating
+ /// separate instances of this class.
+ ///
+ /// The constructor automatically seeds the generator with the
+ /// current time.
+ QidGenerator();
+
+ /// Generate a Qid
+ ///
+ /// \return A random Qid
+ isc::dns::qid_t generateQid();
+
+ /// \brief Seeds the QidGenerator (based on the current time)
+ ///
+ /// This is automatically called by the constructor
+ void seed();
+
+private:
+ // "Mersenne Twister: A 623-dimensionally equidistributed
+ // uniform pseudo-random number generator", Makoto Matsumoto and
+ // Takuji Nishimura, ACM Transactions on Modeling and Computer
+ // Simulation: Special Issue on Uniform Random Number Generation,
+ // Vol. 8, No. 1, January 1998, pp. 3-30.
+ //
+ // mt19937 is an implementation of one of the pseudo random
+ // generators described in this paper.
+ boost::mt19937 generator_;
+
+ // For qid's we want a uniform distribution
+ boost::uniform_int<> dist_;
+
+ boost::variate_generator<boost::mt19937&, boost::uniform_int<> > vgen_;
+};
+
+
+} // namespace asiodns
+} // namespace isc
+
+#endif // __QID_GEN_H
diff --git a/src/lib/asiodns/tcp_server.cc b/src/lib/asiodns/tcp_server.cc
new file mode 100644
index 0000000..7655df0
--- /dev/null
+++ b/src/lib/asiodns/tcp_server.cc
@@ -0,0 +1,241 @@
+// 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.
+
+#include <config.h>
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h> // for some IPC/network system calls
+#include <errno.h>
+
+#include <boost/shared_array.hpp>
+
+#include <log/dummylog.h>
+
+#include <asio.hpp>
+#include <asiolink/dummy_io_cb.h>
+#include <asiolink/tcp_endpoint.h>
+#include <asiolink/tcp_socket.h>
+#include <tcp_server.h>
+
+
+using namespace asio;
+using asio::ip::udp;
+using asio::ip::tcp;
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+/// The following functions implement the \c TCPServer class.
+///
+/// The constructor
+TCPServer::TCPServer(io_service& io_service,
+ const ip::address& addr, const uint16_t port,
+ const SimpleCallback* checkin,
+ const DNSLookup* lookup,
+ const DNSAnswer* answer) :
+ io_(io_service), done_(false),
+ checkin_callback_(checkin), lookup_callback_(lookup),
+ answer_callback_(answer)
+{
+ tcp::endpoint endpoint(addr, port);
+ acceptor_.reset(new tcp::acceptor(io_service));
+ acceptor_->open(endpoint.protocol());
+ // Set v6-only (we use a separate instantiation for v4,
+ // otherwise asio will bind to both v4 and v6
+ if (addr.is_v6()) {
+ acceptor_->set_option(ip::v6_only(true));
+ }
+ acceptor_->set_option(tcp::acceptor::reuse_address(true));
+ acceptor_->bind(endpoint);
+ acceptor_->listen();
+}
+
+void
+TCPServer::operator()(error_code ec, size_t length) {
+ /// Because the coroutine reentry block is implemented as
+ /// a switch statement, inline variable declarations are not
+ /// permitted. Certain variables used below can be declared here.
+
+ boost::array<const_buffer,2> bufs;
+ OutputBuffer lenbuf(TCP_MESSAGE_LENGTHSIZE);
+
+ CORO_REENTER (this) {
+ do {
+ /// Create a socket to listen for connections
+ socket_.reset(new tcp::socket(acceptor_->get_io_service()));
+
+ /// Wait for new connections. In the event of non-fatal error,
+ /// try again
+ do {
+ CORO_YIELD acceptor_->async_accept(*socket_, *this);
+
+ // Abort on fatal errors
+ // TODO: Log error?
+ if (ec) {
+ using namespace asio::error;
+ if (ec.value() != would_block && ec.value() != try_again &&
+ ec.value() != connection_aborted &&
+ ec.value() != interrupted) {
+ return;
+ }
+ }
+ } while (ec);
+
+ /// Fork the coroutine by creating a copy of this one and
+ /// scheduling it on the ASIO service queue. The parent
+ /// will continue listening for DNS connections while the
+ /// handles the one that has just arrived.
+ CORO_FORK io_.post(TCPServer(*this));
+ } while (is_parent());
+
+ /// Instantiate the data buffer that will be used by the
+ /// asynchronous read call.
+ data_.reset(new char[MAX_LENGTH]);
+
+ /// Read the message, in two parts. First, the message length:
+ CORO_YIELD async_read(*socket_, asio::buffer(data_.get(),
+ TCP_MESSAGE_LENGTHSIZE), *this);
+ if (ec) {
+ socket_->close();
+ CORO_YIELD return;
+ }
+
+ /// Now read the message itself. (This is done in a different scope
+ /// to allow inline variable declarations.)
+ CORO_YIELD {
+ InputBuffer dnsbuffer(data_.get(), length);
+ uint16_t msglen = dnsbuffer.readUint16();
+ async_read(*socket_, asio::buffer(data_.get(), msglen), *this);
+ }
+
+ if (ec) {
+ socket_->close();
+ CORO_YIELD return;
+ }
+
+
+ // Create an \c IOMessage object to store the query.
+ //
+ // (XXX: It would be good to write a factory function
+ // that would quickly generate an IOMessage object without
+ // all these calls to "new".)
+ peer_.reset(new TCPEndpoint(socket_->remote_endpoint()));
+
+ // The TCP socket class has been extended with asynchronous functions
+ // and takes as a template parameter a completion callback class. As
+ // TCPServer does not use these extended functions (only those defined
+ // in the IOSocket base class) - but needs a TCPSocket to get hold of
+ // the underlying Boost TCP socket - DummyIOCallback is used. This
+ // provides the appropriate operator() but is otherwise functionless.
+ iosock_.reset(new TCPSocket<DummyIOCallback>(*socket_));
+ io_message_.reset(new IOMessage(data_.get(), length, *iosock_, *peer_));
+ bytes_ = length;
+
+ // Perform any necessary operations prior to processing the incoming
+ // packet (e.g., checking for queued configuration messages).
+ //
+ // (XXX: it may be a performance issue to have this called for
+ // every single incoming packet; we may wish to throttle it somehow
+ // in the future.)
+ if (checkin_callback_ != NULL) {
+ (*checkin_callback_)(*io_message_);
+ }
+
+ // If we don't have a DNS Lookup provider, there's no point in
+ // continuing; we exit the coroutine permanently.
+ if (lookup_callback_ == NULL) {
+ socket_->close();
+ CORO_YIELD return;
+ }
+
+ // Reset or instantiate objects that will be needed by the
+ // DNS lookup and the write call.
+ respbuf_.reset(new OutputBuffer(0));
+ query_message_.reset(new Message(Message::PARSE));
+ answer_message_.reset(new Message(Message::RENDER));
+
+ // Schedule a DNS lookup, and yield. When the lookup is
+ // finished, the coroutine will resume immediately after
+ // this point.
+ CORO_YIELD io_.post(AsyncLookup<TCPServer>(*this));
+
+ // The 'done_' flag indicates whether we have an answer
+ // to send back. If not, exit the coroutine permanently.
+ if (!done_) {
+ // TODO: should we keep the connection open for a short time
+ // to see if new requests come in?
+ socket_->close();
+ CORO_YIELD return;
+ }
+
+ if (ec) {
+ CORO_YIELD return;
+ }
+ // Call the DNS answer provider to render the answer into
+ // wire format
+ (*answer_callback_)(*io_message_, query_message_,
+ answer_message_, respbuf_);
+
+ // Set up the response, beginning with two length bytes.
+ lenbuf.writeUint16(respbuf_->getLength());
+ bufs[0] = buffer(lenbuf.getData(), lenbuf.getLength());
+ bufs[1] = buffer(respbuf_->getData(), respbuf_->getLength());
+
+ // Begin an asynchronous send, and then yield. When the
+ // send completes, we will resume immediately after this point
+ // (though we have nothing further to do, so the coroutine
+ // will simply exit at that time).
+ CORO_YIELD async_write(*socket_, bufs, *this);
+
+ // TODO: should we keep the connection open for a short time
+ // to see if new requests come in?
+ socket_->close();
+ }
+}
+
+/// Call the DNS lookup provider. (Expected to be called by the
+/// AsyncLookup<TCPServer> handler.)
+void
+TCPServer::asyncLookup() {
+ (*lookup_callback_)(*io_message_, query_message_,
+ answer_message_, respbuf_, this);
+}
+
+void TCPServer::stop() {
+ /// we use close instead of cancel, with the same reason
+ /// with udp server stop, refer to the udp server code
+
+ acceptor_->close();
+ // User may stop the server even when it hasn't started to
+ // run, in that that socket_ is empty
+ if (socket_) {
+ socket_->close();
+ }
+}
+/// Post this coroutine on the ASIO service queue so that it will
+/// resume processing where it left off. The 'done' parameter indicates
+/// whether there is an answer to return to the client.
+void
+TCPServer::resume(const bool done) {
+ done_ = done;
+ io_.post(*this);
+}
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/tcp_server.h b/src/lib/asiodns/tcp_server.h
new file mode 100644
index 0000000..3b00293
--- /dev/null
+++ b/src/lib/asiodns/tcp_server.h
@@ -0,0 +1,124 @@
+// 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 __TCP_SERVER_H
+#define __TCP_SERVER_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <boost/shared_array.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <asiolink/asiolink.h>
+#include <coroutine.h>
+#include "dns_server.h"
+#include "dns_lookup.h"
+#include "dns_answer.h"
+
+namespace isc {
+namespace asiodns {
+
+/// \brief A TCP-specific \c DNSServer object.
+///
+/// This class inherits from both \c DNSServer and from \c coroutine,
+/// defined in coroutine.h.
+class TCPServer : public virtual DNSServer, public virtual coroutine {
+public:
+ explicit TCPServer(asio::io_service& io_service,
+ const asio::ip::address& addr, const uint16_t port,
+ const isc::asiolink::SimpleCallback* checkin = NULL,
+ const DNSLookup* lookup = NULL,
+ const DNSAnswer* answer = NULL);
+
+ void operator()(asio::error_code ec = asio::error_code(),
+ size_t length = 0);
+ void asyncLookup();
+ void stop();
+ void resume(const bool done);
+ bool hasAnswer() { return (done_); }
+ int value() { return (get_value()); }
+
+ DNSServer* clone() {
+ TCPServer* s = new TCPServer(*this);
+ return (s);
+ }
+
+private:
+ enum { MAX_LENGTH = 65535 };
+ static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
+
+ // The ASIO service object
+ asio::io_service& io_;
+
+ // Class member variables which are dynamic, and changes to which
+ // need to accessible from both sides of a coroutine fork or from
+ // outside of the coroutine (i.e., from an asynchronous I/O call),
+ // should be declared here as pointers and allocated in the
+ // constructor or in the coroutine. This allows state information
+ // to persist when an individual copy of the coroutine falls out
+ // scope while waiting for an event, *so long as* there is another
+ // object that is referencing the same data. As a side-benefit, using
+ // pointers also reduces copy overhead for coroutine objects.
+ //
+ // Note: Currently these objects are allocated by "new" in the
+ // constructor, or in the function operator while processing a query.
+ // Repeated allocations from the heap for every incoming query is
+ // clearly a performance issue; this must be optimized in the future.
+ // The plan is to have a structure pre-allocate several "server state"
+ // objects which can be pulled off a free list and placed on an in-use
+ // list whenever a query comes in. This will serve the dual purpose
+ // of improving performance and guaranteeing that state information
+ // will *not* be destroyed when any one instance of the coroutine
+ // falls out of scope while waiting for an event.
+ //
+ // An ASIO acceptor object to handle new connections. Created in
+ // the constructor.
+ boost::shared_ptr<asio::ip::tcp::acceptor> acceptor_;
+
+ // Socket used to for listen for queries. Created in the
+ // constructor and stored in a shared_ptr because socket objects
+ // are not copyable.
+ boost::shared_ptr<asio::ip::tcp::socket> socket_;
+
+ // The buffer into which the response is written
+ boost::shared_ptr<isc::dns::OutputBuffer> respbuf_;
+
+ // \c IOMessage and \c Message objects to be passed to the
+ // DNS lookup and answer providers
+ boost::shared_ptr<isc::asiolink::IOMessage> io_message_;
+ isc::dns::MessagePtr query_message_;
+ isc::dns::MessagePtr answer_message_;
+
+ // The buffer into which the query packet is written
+ boost::shared_array<char>data_;
+
+ // State information that is entirely internal to a given instance
+ // of the coroutine can be declared here.
+ size_t bytes_;
+ bool done_;
+
+ // Callback functions provided by the caller
+ const isc::asiolink::SimpleCallback* checkin_callback_;
+ const DNSLookup* lookup_callback_;
+ const DNSAnswer* answer_callback_;
+
+ boost::shared_ptr<isc::asiolink::IOEndpoint> peer_;
+ boost::shared_ptr<isc::asiolink::IOSocket> iosock_;
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __TCP_SERVER_H
diff --git a/src/lib/asiodns/tests/Makefile.am b/src/lib/asiodns/tests/Makefile.am
new file mode 100644
index 0000000..e319604
--- /dev/null
+++ b/src/lib/asiodns/tests/Makefile.am
@@ -0,0 +1,50 @@
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/bin
+AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
+AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(srcdir)/testdata\"
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.h
+run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
+run_unittests_SOURCES += io_service_unittest.cc
+run_unittests_SOURCES += dns_server_unittest.cc
+run_unittests_SOURCES += io_fetch_unittest.cc
+run_unittests_SOURCES += qid_gen_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+
+run_unittests_LDADD = $(GTEST_LDADD)
+run_unittests_LDADD += $(SQLITE_LIBS)
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
+
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
+# B10_CXXFLAGS)
+run_unittests_CXXFLAGS = $(AM_CXXFLAGS)
+if USE_GXX
+run_unittests_CXXFLAGS += -Wno-unused-parameter
+endif
+if USE_CLANGPP
+# Same for clang++, but we need to turn off -Werror completely.
+run_unittests_CXXFLAGS += -Wno-error
+endif
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/asiodns/tests/dns_server_unittest.cc b/src/lib/asiodns/tests/dns_server_unittest.cc
new file mode 100644
index 0000000..0d5a554
--- /dev/null
+++ b/src/lib/asiodns/tests/dns_server_unittest.cc
@@ -0,0 +1,502 @@
+// 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.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <asio.hpp>
+#include <asiolink/io_endpoint.h>
+#include <asiolink/io_error.h>
+#include <asiodns/udp_server.h>
+#include <asiodns/tcp_server.h>
+#include <asiodns/dns_answer.h>
+#include <asiodns/dns_lookup.h>
+#include <string>
+#include <csignal>
+#include <unistd.h> //for alarm
+
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+
+
+/// The following tests focus on stop interface for udp and
+/// tcp server, there are lots of things can be shared to test
+/// both tcp and udp server, so they are in the same unittest
+
+/// The general work flow for dns server, is that wait for user
+/// query, once get one query, we will check the data is valid or
+/// not, if it passed, we will try to loop up the question, then
+/// compose the answer and finally send it back to user. The server
+/// may be stopped at any point during this porcess, so the test strategy
+/// is that we define 5 stop point and stop the server at these
+/// 5 points, to check whether stop is successful
+/// The 5 test points are :
+/// Before the server start to run
+/// After we get the query and check whether it's valid
+/// After we lookup the query
+/// After we compoisite the answer
+/// After user get the final result.
+
+/// The standard about whether we stop the server successfully or not
+/// is based on the fact that if the server is still running, the io
+/// service won't quit since it will wait for some asynchronized event for
+/// server. So if the io service block function run returns we assume
+/// that the server is stopped. To avoid stop interface failure which
+/// will block followed tests, using alarm signal to stop the blocking
+/// io service
+///
+/// The whole test context including one server and one client, and
+/// five stop checkpoints, we call them ServerStopper exclude the first
+/// stop point. Once the unittest fired, the client will send message
+/// to server, and the stopper may stop the server at the checkpoint, then
+/// we check the client get feedback or not. Since there is no DNS logic
+/// involved so the message sending between client and server is plain text
+/// And the valid checker, question lookup and answer composition are dummy.
+
+using namespace isc::asiolink;
+using namespace isc::asiodns;
+using namespace asio;
+namespace {
+static const std::string server_ip = "127.0.0.1";
+const int server_port = 5553;
+//message client send to udp server, which isn't dns package
+//just for simple testing
+static const std::string query_message("BIND10 is awesome");
+
+// \brief provide capacity to derived class the ability
+// to stop DNSServer at certern point
+class ServerStopper {
+ public:
+ ServerStopper() : server_to_stop_(NULL) {}
+ virtual ~ServerStopper(){}
+
+ void setServerToStop(DNSServer* server) {
+ server_to_stop_ = server;
+ }
+
+ void stopServer() const {
+ if (server_to_stop_) {
+ server_to_stop_->stop();
+ }
+ }
+
+ private:
+ DNSServer* server_to_stop_;
+};
+
+// \brief no check logic at all,just provide a checkpoint to stop the server
+class DummyChecker : public SimpleCallback, public ServerStopper {
+ public:
+ virtual void operator()(const IOMessage&) const {
+ stopServer();
+ }
+};
+
+// \brief no lookup logic at all,just provide a checkpoint to stop the server
+class DummyLookup : public DNSLookup, public ServerStopper {
+ public:
+ void operator()(const IOMessage& io_message,
+ isc::dns::MessagePtr message,
+ isc::dns::MessagePtr answer_message,
+ isc::dns::OutputBufferPtr buffer,
+ DNSServer* server) const {
+ stopServer();
+ server->resume(true);
+ }
+};
+
+// \brief copy the data received from user to the answer part
+// provide checkpoint to stop server
+class SimpleAnswer : public DNSAnswer, public ServerStopper {
+ public:
+ void operator()(const IOMessage& message,
+ isc::dns::MessagePtr query_message,
+ isc::dns::MessagePtr answer_message,
+ isc::dns::OutputBufferPtr buffer) const
+ {
+ //copy what we get from user
+ buffer->writeData(message.getData(), message.getDataSize());
+ stopServer();
+ }
+
+};
+
+// \brief simple client, send one string to server and wait for response
+// in case, server stopped and client cann't get response, there is a timer wait
+// for specified seconds (the value is just a estimate since server process logic is quite
+// simple, and all the intercommunication is local) then cancel the waiting.
+class SimpleClient : public ServerStopper {
+ public:
+ static const size_t MAX_DATA_LEN = 256;
+ SimpleClient(asio::io_service& service,
+ unsigned int wait_server_time_out)
+ {
+ wait_for_response_timer_.reset(new deadline_timer(service));
+ received_data_ = new char[MAX_DATA_LEN];
+ received_data_len_ = 0;
+ wait_server_time_out_ = wait_server_time_out;
+ }
+
+ virtual ~SimpleClient() {
+ delete [] received_data_;
+ }
+
+ void setGetFeedbackCallback(boost::function<void()>& func) {
+ get_response_call_back_ = func;
+ }
+
+ virtual void sendDataThenWaitForFeedback(const std::string& data) = 0;
+ virtual std::string getReceivedData() const = 0;
+
+ void startTimer() {
+ wait_for_response_timer_->cancel();
+ wait_for_response_timer_->
+ expires_from_now(boost::posix_time::
+ seconds(wait_server_time_out_));
+ wait_for_response_timer_->
+ async_wait(boost::bind(&SimpleClient::stopWaitingforResponse,
+ this));
+ }
+
+ void cancelTimer() { wait_for_response_timer_->cancel(); }
+
+ void getResponseCallBack(const asio::error_code& error, size_t
+ received_bytes)
+ {
+ cancelTimer();
+ if (!error)
+ received_data_len_ = received_bytes;
+ if (!get_response_call_back_.empty()) {
+ get_response_call_back_();
+ }
+ stopServer();
+ }
+
+
+ protected:
+ virtual void stopWaitingforResponse() = 0;
+
+ boost::shared_ptr<deadline_timer> wait_for_response_timer_;
+ char* received_data_;
+ size_t received_data_len_;
+ boost::function<void()> get_response_call_back_;
+ unsigned int wait_server_time_out_;
+};
+
+
+
+class UDPClient : public SimpleClient {
+ public:
+ //After 1 seconds without feedback client will stop wait
+ static const unsigned int server_time_out = 1;
+
+ UDPClient(asio::io_service& service, const ip::udp::endpoint& server) :
+ SimpleClient(service, server_time_out)
+ {
+ server_ = server;
+ socket_.reset(new ip::udp::socket(service));
+ socket_->open(ip::udp::v4());
+ }
+
+
+ void sendDataThenWaitForFeedback(const std::string& data) {
+ received_data_len_ = 0;
+ socket_->send_to(buffer(data.c_str(), data.size() + 1), server_);
+ socket_->async_receive_from(buffer(received_data_, MAX_DATA_LEN),
+ received_from_,
+ boost::bind(&SimpleClient::
+ getResponseCallBack, this, _1,
+ _2));
+ startTimer();
+ }
+
+ virtual std::string getReceivedData() const {
+ return (received_data_len_ == 0 ? std::string("") :
+ std::string(received_data_));
+ }
+
+ private:
+ void stopWaitingforResponse() {
+ socket_->close();
+ }
+
+ boost::shared_ptr<ip::udp::socket> socket_;
+ ip::udp::endpoint server_;
+ ip::udp::endpoint received_from_;
+};
+
+
+class TCPClient : public SimpleClient {
+ public:
+ // after 2 seconds without feedback client will stop wait,
+ // this includes connect, send message and recevice message
+ static const unsigned int server_time_out = 2;
+ TCPClient(asio::io_service& service, const ip::tcp::endpoint& server)
+ : SimpleClient(service, server_time_out)
+ {
+ server_ = server;
+ socket_.reset(new ip::tcp::socket(service));
+ socket_->open(ip::tcp::v4());
+ }
+
+
+ virtual void sendDataThenWaitForFeedback(const std::string &data) {
+ received_data_len_ = 0;
+ data_to_send_ = data;
+ data_to_send_len_ = data.size() + 1;
+ socket_->async_connect(server_, boost::bind(&TCPClient::connectHandler,
+ this, _1));
+ startTimer();
+ }
+
+ virtual std::string getReceivedData() const {
+ return (received_data_len_ == 0 ? std::string("") :
+ std::string(received_data_ + 2));
+ }
+
+ private:
+ void stopWaitingforResponse() {
+ socket_->close();
+ }
+
+ void connectHandler(const asio::error_code& error) {
+ if (!error) {
+ data_to_send_len_ = htons(data_to_send_len_);
+ socket_->async_send(buffer(&data_to_send_len_, 2),
+ boost::bind(&TCPClient::sendMessageBodyHandler,
+ this, _1, _2));
+ }
+ }
+
+ void sendMessageBodyHandler(const asio::error_code& error,
+ size_t send_bytes)
+ {
+ if (!error && send_bytes == 2) {
+ socket_->async_send(buffer(data_to_send_.c_str(),
+ data_to_send_.size() + 1),
+ boost::bind(&TCPClient::finishSendHandler, this, _1, _2));
+ }
+ }
+
+ void finishSendHandler(const asio::error_code& error, size_t send_bytes) {
+ if (!error && send_bytes == data_to_send_.size() + 1) {
+ socket_->async_receive(buffer(received_data_, MAX_DATA_LEN),
+ boost::bind(&SimpleClient::getResponseCallBack, this, _1,
+ _2));
+ }
+ }
+
+ boost::shared_ptr<ip::tcp::socket> socket_;
+ ip::tcp::endpoint server_;
+ std::string data_to_send_;
+ uint16_t data_to_send_len_;
+};
+
+
+
+// \brief provide the context which including two client and
+// two server, udp client will only communicate with udp server, same for tcp client
+class DNSServerTest : public::testing::Test {
+ protected:
+ void SetUp() {
+ ip::address server_address = ip::address::from_string(server_ip);
+ checker_ = new DummyChecker();
+ lookup_ = new DummyLookup();
+ answer_ = new SimpleAnswer();
+ udp_server_ = new UDPServer(service, server_address, server_port,
+ checker_, lookup_, answer_);
+ udp_client_ = new UDPClient(service,
+ ip::udp::endpoint(server_address,
+ server_port));
+ tcp_server_ = new TCPServer(service, server_address, server_port,
+ checker_, lookup_, answer_);
+ tcp_client_ = new TCPClient(service,
+ ip::tcp::endpoint(server_address,
+ server_port));
+ }
+
+
+ void TearDown() {
+ udp_server_->stop();
+ tcp_server_->stop();
+ delete checker_;
+ delete lookup_;
+ delete answer_;
+ delete udp_server_;
+ delete udp_client_;
+ delete tcp_server_;
+ delete tcp_client_;
+ }
+
+
+ void testStopServerByStopper(DNSServer* server, SimpleClient* client,
+ ServerStopper* stopper)
+ {
+ static const unsigned int io_service_time_out = 5;
+ io_service_is_time_out = false;
+ stopper->setServerToStop(server);
+ (*server)();
+ client->sendDataThenWaitForFeedback(query_message);
+ // Since thread hasn't been introduced into the tool box, using signal
+ // to make sure run function will eventually return even server stop
+ // failed
+ void (*prev_handler)(int) = std::signal(SIGALRM, DNSServerTest::stopIOService);
+ alarm(io_service_time_out);
+ service.run();
+ service.reset();
+ //cancel scheduled alarm
+ alarm(0);
+ std::signal(SIGALRM, prev_handler);
+ }
+
+
+ static void stopIOService(int _no_use_parameter) {
+ io_service_is_time_out = true;
+ service.stop();
+ }
+
+ bool serverStopSucceed() const {
+ return (!io_service_is_time_out);
+ }
+
+ DummyChecker* checker_;
+ DummyLookup* lookup_;
+ SimpleAnswer* answer_;
+ UDPServer* udp_server_;
+ UDPClient* udp_client_;
+ TCPClient* tcp_client_;
+ TCPServer* tcp_server_;
+
+ // To access them in signal handle function, the following
+ // variables have to be static.
+ static asio::io_service service;
+ static bool io_service_is_time_out;
+};
+
+bool DNSServerTest::io_service_is_time_out = false;
+asio::io_service DNSServerTest::service;
+
+// Test whether server stopped successfully after client get response
+// client will send query and start to wait for response, once client
+// get response, udp server will be stopped, the io service won't quit
+// if udp server doesn't stop successfully.
+TEST_F(DNSServerTest, stopUDPServerAfterOneQuery) {
+ testStopServerByStopper(udp_server_, udp_client_, udp_client_);
+ EXPECT_EQ(query_message, udp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether udp server stopped successfully before server start to serve
+TEST_F(DNSServerTest, stopUDPServerBeforeItStartServing) {
+ udp_server_->stop();
+ testStopServerByStopper(udp_server_, udp_client_, udp_client_);
+ EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+
+// Test whether udp server stopped successfully during message check
+TEST_F(DNSServerTest, stopUDPServerDuringMessageCheck) {
+ testStopServerByStopper(udp_server_, udp_client_, checker_);
+ EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether udp server stopped successfully during query lookup
+TEST_F(DNSServerTest, stopUDPServerDuringQueryLookup) {
+ testStopServerByStopper(udp_server_, udp_client_, lookup_);
+ EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether udp server stopped successfully during composing answer
+TEST_F(DNSServerTest, stopUDPServerDuringPrepareAnswer) {
+ testStopServerByStopper(udp_server_, udp_client_, answer_);
+ EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+static void stopServerManyTimes(DNSServer *server, unsigned int times) {
+ for (int i = 0; i < times; ++i) {
+ server->stop();
+ }
+}
+
+// Test whether udp server stop interface can be invoked several times without
+// throw any exception
+TEST_F(DNSServerTest, stopUDPServeMoreThanOnce) {
+ ASSERT_NO_THROW({
+ boost::function<void()> stop_server_3_times
+ = boost::bind(stopServerManyTimes, udp_server_, 3);
+ udp_client_->setGetFeedbackCallback(stop_server_3_times);
+ testStopServerByStopper(udp_server_, udp_client_, udp_client_);
+ EXPECT_EQ(query_message, udp_client_->getReceivedData());
+ });
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+
+TEST_F(DNSServerTest, stopTCPServerAfterOneQuery) {
+ testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
+ EXPECT_EQ(query_message, tcp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+
+// Test whether tcp server stopped successfully before server start to serve
+TEST_F(DNSServerTest, stopTCPServerBeforeItStartServing) {
+ tcp_server_->stop();
+ testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
+ EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+
+// Test whether tcp server stopped successfully during message check
+TEST_F(DNSServerTest, stopTCPServerDuringMessageCheck) {
+ testStopServerByStopper(tcp_server_, tcp_client_, checker_);
+ EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether tcp server stopped successfully during query lookup
+TEST_F(DNSServerTest, stopTCPServerDuringQueryLookup) {
+ testStopServerByStopper(tcp_server_, tcp_client_, lookup_);
+ EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+// Test whether tcp server stopped successfully during composing answer
+TEST_F(DNSServerTest, stopTCPServerDuringPrepareAnswer) {
+ testStopServerByStopper(tcp_server_, tcp_client_, answer_);
+ EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+
+// Test whether tcp server stop interface can be invoked several times without
+// throw any exception
+TEST_F(DNSServerTest, stopTCPServeMoreThanOnce) {
+ ASSERT_NO_THROW({
+ boost::function<void()> stop_server_3_times
+ = boost::bind(stopServerManyTimes, tcp_server_, 3);
+ tcp_client_->setGetFeedbackCallback(stop_server_3_times);
+ testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
+ EXPECT_EQ(query_message, tcp_client_->getReceivedData());
+ });
+ EXPECT_TRUE(serverStopSucceed());
+}
+
+}
diff --git a/src/lib/asiodns/tests/io_fetch_unittest.cc b/src/lib/asiodns/tests/io_fetch_unittest.cc
new file mode 100644
index 0000000..eba5809
--- /dev/null
+++ b/src/lib/asiodns/tests/io_fetch_unittest.cc
@@ -0,0 +1,726 @@
+// 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.
+
+#include <algorithm>
+#include <cstdlib>
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <iterator>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <boost/bind.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <asio.hpp>
+
+#include <dns/buffer.h>
+#include <dns/question.h>
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/opcode.h>
+#include <dns/name.h>
+#include <dns/rcode.h>
+
+#include <asiolink/asiolink_utilities.h>
+#include <asiolink/io_address.h>
+#include <asiolink/io_endpoint.h>
+#include <asiolink/io_service.h>
+#include <asiodns/io_fetch.h>
+
+using namespace asio;
+using namespace isc::dns;
+using namespace asio::ip;
+using namespace std;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+const asio::ip::address TEST_HOST(asio::ip::address::from_string("127.0.0.1"));
+const uint16_t TEST_PORT(5301);
+const int SEND_INTERVAL = 250; // Interval in ms between TCP sends
+const size_t MAX_SIZE = 64 * 1024; // Should be able to take 64kB
+
+// The tests are complex, so debug output has been left in (although disabled).
+// Set this to true to enable it.
+const bool DEBUG = false;
+
+/// \brief Test fixture for the asiolink::IOFetch.
+class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Callback
+{
+public:
+ IOService service_; ///< Service to run the query
+ IOFetch::Result expected_; ///< Expected result of the callback
+ bool run_; ///< Did the callback run already?
+ Question question_; ///< What to ask
+ OutputBufferPtr result_buff_; ///< Buffer to hold result of fetch
+ OutputBufferPtr msgbuf_; ///< Buffer corresponding to known question
+ IOFetch udp_fetch_; ///< For UDP query test
+ IOFetch tcp_fetch_; ///< For TCP query test
+ IOFetch::Protocol protocol_; ///< Protocol being tested
+ size_t cumulative_; ///< Cumulative data received by "server".
+ deadline_timer timer_; ///< Timer to measure timeouts
+
+ // The next member is the buffer in which the "server" (implemented by the
+ // response handler methods in this class) receives the question sent by the
+ // fetch object.
+ uint8_t receive_buffer_[MAX_SIZE]; ///< Server receive buffer
+ OutputBufferPtr expected_buffer_; ///< Data we expect to receive
+ vector<uint8_t> send_buffer_; ///< Server send buffer
+ uint16_t send_cumulative_; ///< Data sent so far
+
+ // Other data.
+ string return_data_; ///< Data returned by server
+ string test_data_; ///< Large string - here for convenience
+ bool debug_; ///< true to enable debug output
+ size_t tcp_send_size_; ///< Max size of TCP send
+ uint8_t qid_0; ///< First octet of qid
+ uint8_t qid_1; ///< Second octet of qid
+
+ bool tcp_short_send_; ///< If set to true, we do not send
+ /// all data in the tcp response
+
+ /// \brief Constructor
+ IOFetchTest() :
+ service_(),
+ expected_(IOFetch::NOTSET),
+ run_(false),
+ question_(Name("example.net"), RRClass::IN(), RRType::A()),
+ result_buff_(new OutputBuffer(512)),
+ msgbuf_(new OutputBuffer(512)),
+ udp_fetch_(IOFetch::UDP, service_, question_, IOAddress(TEST_HOST),
+ TEST_PORT, result_buff_, this, 100),
+ tcp_fetch_(IOFetch::TCP, service_, question_, IOAddress(TEST_HOST),
+ TEST_PORT, result_buff_, this, (16 * SEND_INTERVAL)),
+ // Timeout interval chosen to ensure no timeout
+ protocol_(IOFetch::TCP), // for initialization - will be changed
+ cumulative_(0),
+ timer_(service_.get_io_service()),
+ receive_buffer_(),
+ expected_buffer_(new OutputBuffer(512)),
+ send_buffer_(),
+ send_cumulative_(0),
+ return_data_(""),
+ test_data_(""),
+ debug_(DEBUG),
+ tcp_send_size_(0),
+ qid_0(0),
+ qid_1(0),
+ tcp_short_send_(false)
+ {
+ // Construct the data buffer for question we expect to receive.
+ Message msg(Message::RENDER);
+ msg.setQid(0);
+ msg.setOpcode(Opcode::QUERY());
+ msg.setRcode(Rcode::NOERROR());
+ msg.setHeaderFlag(Message::HEADERFLAG_RD);
+ msg.addQuestion(question_);
+ MessageRenderer renderer(*msgbuf_);
+ msg.toWire(renderer);
+ MessageRenderer renderer2(*expected_buffer_);
+ msg.toWire(renderer2);
+
+ // Initialize the test data to be returned: tests will return a
+ // substring of this data. (It's convenient to have this as a member of
+ // the class.)
+ //
+ // We could initialize the data with a single character, but as an added
+ // check we'll make ssre that it has some structure.
+
+ test_data_.clear();
+ test_data_.reserve(MAX_SIZE);
+ while (test_data_.size() < MAX_SIZE) {
+ test_data_ += "A message to be returned to the client that has "
+ "some sort of structure.";
+ }
+ }
+
+ /// \brief UDP Response handler (the "remote UDP DNS server")
+ ///
+ /// When IOFetch is sending data, this response handler emulates the remote
+ /// DNS server. It checks that the data sent by the IOFetch object is what
+ /// was expected to have been sent, then sends back a known buffer of data.
+ ///
+ /// \param remote Endpoint to which to send the answer
+ /// \param socket Socket to use to send the answer
+ /// \param ec ASIO error code, completion code of asynchronous I/O issued
+ /// by the "server" to receive data.
+ /// \param bad_qid If set to true, the QID in the response will be mangled
+ /// \param second_send If set to true, (and bad_qid is too), after the
+ /// mangled qid response has been sent, a second packet will be
+ /// sent with the correct QID.
+ /// \param length Amount of data received.
+ void udpReceiveHandler(udp::endpoint* remote, udp::socket* socket,
+ error_code ec = error_code(), size_t length = 0,
+ bool bad_qid = false, bool second_send = false) {
+ if (debug_) {
+ cout << "udpReceiveHandler(): error = " << ec.value() <<
+ ", length = " << length << endl;
+ }
+
+ // The QID in the incoming data is random so set it to 0 for the
+ // data comparison check. (It is set to 0 in the buffer containing
+ // the expected data.)
+ qid_0 = receive_buffer_[0];
+ qid_1 = receive_buffer_[1];
+ receive_buffer_[0] = receive_buffer_[1] = 0;
+
+ // Check that length of the received data and the expected data are
+ // identical, then check that the data is identical as well.
+ EXPECT_EQ(msgbuf_->getLength(), length);
+ EXPECT_TRUE(equal(receive_buffer_, (receive_buffer_ + length - 1),
+ static_cast<const uint8_t*>(msgbuf_->getData())));
+
+ // Return a message back to the IOFetch object.
+ if (!bad_qid) {
+ expected_buffer_->writeUint8At(qid_0, 0);
+ expected_buffer_->writeUint8At(qid_1, 1);
+ } else {
+ expected_buffer_->writeUint8At(qid_0 + 1, 0);
+ expected_buffer_->writeUint8At(qid_1 + 1, 1);
+ }
+ socket->send_to(asio::buffer(expected_buffer_->getData(), length), *remote);
+
+ if (bad_qid && second_send) {
+ expected_buffer_->writeUint8At(qid_0, 0);
+ expected_buffer_->writeUint8At(qid_1, 1);
+ socket->send_to(asio::buffer(expected_buffer_->getData(),
+ expected_buffer_->getLength()), *remote);
+ }
+ if (debug_) {
+ cout << "udpReceiveHandler(): returned " << expected_buffer_->getLength() <<
+ " bytes to the client" << endl;
+ }
+ }
+
+ /// \brief Completion Handler for accepting TCP data
+ ///
+ /// Called when the remote system connects to the "server". It issues
+ /// an asynchronous read on the socket to read data.
+ ///
+ /// \param socket Socket on which data will be received
+ /// \param ec Boost error code, value should be zero.
+ void tcpAcceptHandler(tcp::socket* socket, error_code ec = error_code())
+ {
+ if (debug_) {
+ cout << "tcpAcceptHandler(): error = " << ec.value() << endl;
+ }
+
+ // Expect that the accept completed without a problem.
+ EXPECT_EQ(0, ec.value());
+
+ // Work out the maximum size of data we can send over it when we
+ // respond, then subtract 1kB or so for safety.
+ tcp::socket::send_buffer_size send_size;
+ socket->get_option(send_size);
+ if (send_size.value() < (2 * 1024)) {
+ FAIL() << "TCP send size is less than 2kB";
+ } else {
+ tcp_send_size_ = send_size.value() - 1024;
+ if (debug_) {
+ cout << "tcpacceptHandler(): will use send size = " << tcp_send_size_ << endl;
+ }
+ }
+
+ // Initiate a read on the socket.
+ cumulative_ = 0;
+ socket->async_receive(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
+ boost::bind(&IOFetchTest::tcpReceiveHandler, this, socket, _1, _2));
+ }
+
+ /// \brief Completion handler for receiving TCP data
+ ///
+ /// When IOFetch is sending data, this response handler emulates the remote
+ /// DNS server. It that all the data sent by the IOFetch object has been
+ /// received, issuing another read if not. If the data is complete, it is
+ /// compared to what is expected and a reply sent back to the IOFetch.
+ ///
+ /// \param socket Socket to use to send the answer
+ /// \param ec ASIO error code, completion code of asynchronous I/O issued
+ /// by the "server" to receive data.
+ /// \param length Amount of data received.
+ void tcpReceiveHandler(tcp::socket* socket, error_code ec = error_code(),
+ size_t length = 0)
+ {
+ if (debug_) {
+ cout << "tcpReceiveHandler(): error = " << ec.value() <<
+ ", length = " << length << endl;
+ }
+ // Expect that the receive completed without a problem.
+ EXPECT_EQ(0, ec.value());
+
+ // If we haven't received all the data, issue another read.
+ cumulative_ += length;
+ bool complete = false;
+ if (cumulative_ > 2) {
+ uint16_t dns_length = readUint16(receive_buffer_);
+ complete = ((dns_length + 2) == cumulative_);
+ }
+
+ if (!complete) {
+ socket->async_receive(asio::buffer((receive_buffer_ + cumulative_),
+ (sizeof(receive_buffer_) - cumulative_)),
+ boost::bind(&IOFetchTest::tcpReceiveHandler, this, socket, _1, _2));
+ return;
+ }
+
+ // Check that length of the DNS message received is that expected, then
+ // compare buffers, zeroing the QID in the received buffer to match
+ // that set in our expected question. Note that due to the length
+ // field the QID in the received buffer is in the third and fourth
+ // bytes.
+ EXPECT_EQ(msgbuf_->getLength() + 2, cumulative_);
+ qid_0 = receive_buffer_[2];
+ qid_1 = receive_buffer_[3];
+
+ receive_buffer_[2] = receive_buffer_[3] = 0;
+ EXPECT_TRUE(equal((receive_buffer_ + 2), (receive_buffer_ + cumulative_ - 2),
+ static_cast<const uint8_t*>(msgbuf_->getData())));
+
+ // ... and return a message back. This has to be preceded by a two-byte
+ // count field.
+
+ send_buffer_.clear();
+ send_buffer_.push_back(0);
+ send_buffer_.push_back(0);
+ writeUint16(return_data_.size(), &send_buffer_[0]);
+ copy(return_data_.begin(), return_data_.end(), back_inserter(send_buffer_));
+ if (return_data_.size() >= 2) {
+ send_buffer_[2] = qid_0;
+ send_buffer_[3] = qid_1;
+ }
+ // Send the data. This is done in multiple writes with a delay between
+ // each to check that the reassembly of TCP packets from fragments works.
+ send_cumulative_ = 0;
+ tcpSendData(socket);
+ }
+
+ /// \brief Sent Data Over TCP
+ ///
+ /// Send the TCP data back to the IOFetch object. The data is sent in
+ /// three chunks - two of 16 bytes and the remainder, with a 250ms gap
+ /// between each. (Amounts of data smaller than one 32 bytes are sent in
+ /// one or two packets.)
+ ///
+ /// \param socket Socket over which send should take place
+ void tcpSendData(tcp::socket* socket) {
+ if (debug_) {
+ cout << "tcpSendData()" << endl;
+ }
+
+ // Decide what to send based on the cumulative count. At most we'll do
+ // two chunks of 16 bytes (with a 250ms gap between) and then the
+ // remainder.
+ uint8_t* send_ptr = &send_buffer_[send_cumulative_];
+ // Pointer to data to send
+ size_t amount = 16; // Amount of data to send
+ if (send_cumulative_ < (2 * amount)) {
+
+ // First or second time through, send at most 16 bytes
+ amount = min(amount, (send_buffer_.size() - send_cumulative_));
+
+ } else {
+
+ // For all subsequent times, send the remainder, maximised to
+ // whatever we have chosen for the maximum send size.
+ amount = min(tcp_send_size_,
+ (send_buffer_.size() - send_cumulative_));
+ }
+
+ // This is for the short send test; reduce the actual amount of
+ // data we send
+ if (tcp_short_send_) {
+ if (debug_) {
+ cout << "tcpSendData(): sending incomplete data (" <<
+ (amount - 1) << " of " << amount << " bytes)" <<
+ endl;
+ }
+ --amount;
+ } else {
+ if (debug_) {
+ cout << "tcpSendData(): sending " << amount << " bytes" << endl;
+ }
+ }
+
+ // ... and send it. The amount sent is also passed as the first
+ // argument of the send callback, as a check.
+ socket->async_send(asio::buffer(send_ptr, amount),
+ boost::bind(&IOFetchTest::tcpSendHandler, this,
+ amount, socket, _1, _2));
+ }
+
+ /// \brief Completion Handler for Sending TCP data
+ ///
+ /// Called when the asynchronous send of data back to the IOFetch object
+ /// by the TCP "server" in this class has completed. (This send has to
+ /// be asynchronous because control needs to return to the caller in order
+ /// for the IOService "run()" method to be called to run the handlers.)
+ ///
+ /// If not all the data has been sent, a short delay is instigated (during
+ /// which control returns to the IOService). This should force the queued
+ /// data to actually be sent and the IOFetch receive handler to be triggered.
+ /// In this way, the ability of IOFetch to handle fragmented TCP packets
+ /// should be checked.
+ ///
+ /// \param expected Number of bytes that were expected to have been sent.
+ /// \param socket Socket over which the send took place. Only used to
+ /// pass back to the send method.
+ /// \param ec Boost error code, value should be zero.
+ /// \param length Number of bytes sent.
+ void tcpSendHandler(size_t expected, tcp::socket* socket,
+ error_code ec = error_code(), size_t length = 0)
+ {
+ if (debug_) {
+ cout << "tcpSendHandler(): error = " << ec.value() <<
+ ", length = " << length << endl;
+ }
+
+ EXPECT_EQ(0, ec.value()); // Expect no error
+ EXPECT_EQ(expected, length); // And that amount sent is as expected
+
+ // Do we need to send more?
+ send_cumulative_ += length;
+ if (send_cumulative_ < send_buffer_.size()) {
+
+ // Yes - set up a timer: the callback handler for the timer is
+ // tcpSendData, which will then send the next chunk. We pass the
+ // socket over which data should be sent as an argument to that
+ // function.
+ timer_.expires_from_now(boost::posix_time::milliseconds(SEND_INTERVAL));
+ timer_.async_wait(boost::bind(&IOFetchTest::tcpSendData, this,
+ socket));
+ }
+ }
+
+ /// \brief Fetch completion callback
+ ///
+ /// This is the callback's operator() method which is called when the fetch
+ /// is complete. It checks that the data received is the wire format of the
+ /// data sent back by the server.
+ ///
+ /// \param result Result indicated by the callback
+ void operator()(IOFetch::Result result) {
+ if (debug_) {
+ cout << "operator()(): result = " << result << endl;
+ }
+
+ EXPECT_EQ(expected_, result); // Check correct result returned
+ EXPECT_FALSE(run_); // Check it is run only once
+ run_ = true; // Note success
+
+ // If the expected result for SUCCESS, then this should have been called
+ // when one of the "servers" in this class has sent back return_data_.
+ // Check the data is as expected/
+ if (expected_ == IOFetch::SUCCESS) {
+ // In the case of UDP, we actually send back a real looking packet
+ // in the case of TCP, we send back a 'random' string
+ if (protocol_ == IOFetch::UDP) {
+ EXPECT_EQ(expected_buffer_->getLength(), result_buff_->getLength());
+ EXPECT_EQ(0, memcmp(expected_buffer_->getData(), result_buff_->getData(),
+ expected_buffer_->getLength()));
+ } else {
+ EXPECT_EQ(return_data_.size(), result_buff_->getLength());
+ // Overwrite the random qid with our own data for the
+ // comparison to succeed
+ if (result_buff_->getLength() >= 2) {
+ result_buff_->writeUint8At(return_data_[0], 0);
+ result_buff_->writeUint8At(return_data_[1], 1);
+ }
+ const uint8_t* start = static_cast<const uint8_t*>(result_buff_->getData());
+ EXPECT_TRUE(equal(return_data_.begin(), return_data_.end(), start));
+ }
+ }
+
+ // ... and cause the run loop to exit.
+ service_.stop();
+ }
+
+ // The next set of methods are the tests themselves. A number of the TCP
+ // and UDP tests are very similar.
+
+ /// \brief Check for stop()
+ ///
+ /// Test that when we run the query and stop it after it was run, it returns
+ /// "stopped" correctly. (That is why stop() is posted to the service_ as
+ /// well instead of calling it.)
+ ///
+ /// \param protocol Test protocol
+ /// \param fetch Fetch object being tested
+ void stopTest(IOFetch::Protocol protocol, IOFetch& fetch) {
+ protocol_ = protocol;
+ expected_ = IOFetch::STOPPED;
+
+ // Post the query
+ service_.get_io_service().post(fetch);
+
+ // Post query_.stop() (yes, the boost::bind thing is just
+ // query_.stop()).
+ service_.get_io_service().post(
+ boost::bind(&IOFetch::stop, fetch, IOFetch::STOPPED));
+
+ // Run both of them. run() returns when everything in the I/O service
+ // queue has completed.
+ service_.run();
+ EXPECT_TRUE(run_);
+ }
+
+ /// \brief Premature stop test
+ ///
+ /// Test that when we queue the query to service_ and call stop() before it
+ /// gets executed, it acts sanely as well (eg. has the same result as
+ /// running stop() after - calls the callback).
+ ///
+ /// \param protocol Test protocol
+ /// \param fetch Fetch object being tested
+ void prematureStopTest(IOFetch::Protocol protocol, IOFetch& fetch) {
+ protocol_ = protocol;
+ expected_ = IOFetch::STOPPED;
+
+ // Stop before it is started
+ fetch.stop();
+ service_.get_io_service().post(fetch);
+
+ service_.run();
+ EXPECT_TRUE(run_);
+ }
+
+ /// \brief Timeout test
+ ///
+ /// Test that fetch times out when no answer arrives.
+ ///
+ /// \param protocol Test protocol
+ /// \param fetch Fetch object being tested
+ void timeoutTest(IOFetch::Protocol protocol, IOFetch& fetch) {
+ protocol_ = protocol;
+ expected_ = IOFetch::TIME_OUT;
+
+ service_.get_io_service().post(fetch);
+ service_.run();
+ EXPECT_TRUE(run_);
+ }
+
+ /// \brief Send/Receive Test
+ ///
+ /// Send a query to the server then receives a response.
+ ///
+ /// \param Test data to return to client
+ /// \param short_send If true, do not send all data
+ /// (should result in timeout)
+ void tcpSendReturnTest(const std::string& return_data, bool short_send = false) {
+ if (debug_) {
+ cout << "tcpSendReturnTest(): data size = " << return_data.size() << endl;
+ }
+ return_data_ = return_data;
+ protocol_ = IOFetch::TCP;
+ if (short_send) {
+ tcp_short_send_ = true;
+ expected_ = IOFetch::TIME_OUT;
+ } else {
+ expected_ = IOFetch::SUCCESS;
+ }
+
+ // Socket into which the connection will be accepted.
+ tcp::socket socket(service_.get_io_service());
+
+ // Acceptor object - called when the connection is made, the handler
+ // will initiate a read on the socket.
+ tcp::acceptor acceptor(service_.get_io_service(),
+ tcp::endpoint(tcp::v4(), TEST_PORT));
+ acceptor.async_accept(socket,
+ boost::bind(&IOFetchTest::tcpAcceptHandler, this, &socket, _1));
+
+ // Post the TCP fetch object to send the query and receive the response.
+ service_.get_io_service().post(tcp_fetch_);
+
+ // ... and execute all the callbacks. This exits when the fetch
+ // completes.
+ service_.run();
+ EXPECT_TRUE(run_); // Make sure the callback did execute
+
+ // Tidy up
+ socket.close();
+ }
+
+ /// Perform a send/receive test over UDP
+ ///
+ /// \param bad_qid If true, do the test where the QID is mangled
+ /// in the response
+ /// \param second_send If true, do the test where the QID is
+ /// mangled in the response, but a second
+ /// (correct) packet is used
+ void udpSendReturnTest(bool bad_qid, bool second_send) {
+ protocol_ = IOFetch::UDP;
+
+ // Set up the server.
+ udp::socket socket(service_.get_io_service(), udp::v4());
+ socket.set_option(socket_base::reuse_address(true));
+ socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
+ return_data_ = "Message returned to the client";
+
+ udp::endpoint remote;
+ socket.async_receive_from(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
+ remote,
+ boost::bind(&IOFetchTest::udpReceiveHandler, this, &remote, &socket,
+ _1, _2, bad_qid, second_send));
+ service_.get_io_service().post(udp_fetch_);
+ if (debug_) {
+ cout << "udpSendReceive: async_receive_from posted, waiting for callback" <<
+ endl;
+ }
+ service_.run();
+
+ socket.close();
+
+ EXPECT_TRUE(run_);;
+ }
+};
+
+// Check the protocol
+TEST_F(IOFetchTest, Protocol) {
+ EXPECT_EQ(IOFetch::UDP, udp_fetch_.getProtocol());
+ EXPECT_EQ(IOFetch::TCP, tcp_fetch_.getProtocol());
+}
+
+// UDP Stop test - see IOFetchTest::stopTest() header.
+TEST_F(IOFetchTest, UdpStop) {
+ stopTest(IOFetch::UDP, udp_fetch_);
+}
+
+// UDP premature stop test - see IOFetchTest::prematureStopTest() header.
+TEST_F(IOFetchTest, UdpPrematureStop) {
+ prematureStopTest(IOFetch::UDP, udp_fetch_);
+}
+
+// UDP premature stop test - see IOFetchTest::timeoutTest() header.
+TEST_F(IOFetchTest, UdpTimeout) {
+ timeoutTest(IOFetch::UDP, udp_fetch_);
+}
+
+// UDP SendReceive test. Set up a UDP server then ports a UDP fetch object.
+// This will send question_ to the server and receive the answer back from it.
+TEST_F(IOFetchTest, UdpSendReceive) {
+ expected_ = IOFetch::SUCCESS;
+
+ udpSendReturnTest(false, false);
+
+ EXPECT_TRUE(run_);;
+}
+
+TEST_F(IOFetchTest, UdpSendReceiveBadQid) {
+ expected_ = IOFetch::TIME_OUT;
+
+ udpSendReturnTest(true, false);
+
+ EXPECT_TRUE(run_);;
+}
+
+TEST_F(IOFetchTest, UdpSendReceiveBadQidResend) {
+ expected_ = IOFetch::SUCCESS;
+
+ udpSendReturnTest(true, true);
+
+ EXPECT_TRUE(run_);;
+}
+
+// Do the same tests for TCP transport
+
+TEST_F(IOFetchTest, TcpStop) {
+ stopTest(IOFetch::TCP, tcp_fetch_);
+}
+
+TEST_F(IOFetchTest, TcpPrematureStop) {
+ prematureStopTest(IOFetch::TCP, tcp_fetch_);
+}
+
+TEST_F(IOFetchTest, TcpTimeout) {
+ timeoutTest(IOFetch::TCP, tcp_fetch_);
+}
+
+// Test with values at or near 2, then at or near the chunk size (16 and 32
+// bytes, the sizes of the first two packets) then up to 65535. These are done
+// in separate tests because in practice a new IOFetch is created for each
+// query/response exchange and we don't want to confuse matters in the test
+// by running the test with an IOFetch that has already done one exchange.
+//
+// Don't do 0 or 1; the server would not accept the packet
+// (since the length is too short to check the qid)
+TEST_F(IOFetchTest, TcpSendReceive2) {
+ tcpSendReturnTest(test_data_.substr(0, 2));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive3) {
+ tcpSendReturnTest(test_data_.substr(0, 3));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive15) {
+ tcpSendReturnTest(test_data_.substr(0, 15));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive16) {
+ tcpSendReturnTest(test_data_.substr(0, 16));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive17) {
+ tcpSendReturnTest(test_data_.substr(0, 17));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive31) {
+ tcpSendReturnTest(test_data_.substr(0, 31));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive32) {
+ tcpSendReturnTest(test_data_.substr(0, 32));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive33) {
+ tcpSendReturnTest(test_data_.substr(0, 33));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive4096) {
+ tcpSendReturnTest(test_data_.substr(0, 4096));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive8192) {
+ tcpSendReturnTest(test_data_.substr(0, 8192));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive16384) {
+ tcpSendReturnTest(test_data_.substr(0, 16384));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive32768) {
+ tcpSendReturnTest(test_data_.substr(0, 32768));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive65535) {
+ tcpSendReturnTest(test_data_.substr(0, 65535));
+}
+
+TEST_F(IOFetchTest, TcpSendReceive2ShortSend) {
+ tcpSendReturnTest(test_data_.substr(0, 2), true);
+}
+
+TEST_F(IOFetchTest, TcpSendReceive15ShortSend) {
+ tcpSendReturnTest(test_data_.substr(0, 15), true);
+}
+
+TEST_F(IOFetchTest, TcpSendReceive8192ShortSend) {
+ tcpSendReturnTest(test_data_.substr(0, 8192), true);
+}
+
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/tests/io_service_unittest.cc b/src/lib/asiodns/tests/io_service_unittest.cc
new file mode 100644
index 0000000..cc64022
--- /dev/null
+++ b/src/lib/asiodns/tests/io_service_unittest.cc
@@ -0,0 +1,118 @@
+// 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.
+
+#include <config.h>
+#include <gtest/gtest.h>
+
+#include <asio.hpp>
+#include <asiolink/asiolink.h>
+#include <asiodns/asiodns.h>
+
+using namespace isc::asiolink;
+using namespace isc::asiodns;
+
+const char* const TEST_SERVER_PORT = "53535";
+const char* const TEST_CLIENT_PORT = "53536";
+const char* const TEST_IPV6_ADDR = "::1";
+const char* const TEST_IPV4_ADDR = "127.0.0.1";
+
+TEST(IOServiceTest, badPort) {
+ IOService io_service;
+ EXPECT_THROW(DNSService(io_service, *"65536", true, false, NULL, NULL, NULL), IOError);
+ EXPECT_THROW(DNSService(io_service, *"53210.0", true, false, NULL, NULL, NULL), IOError);
+ EXPECT_THROW(DNSService(io_service, *"-1", true, false, NULL, NULL, NULL), IOError);
+ EXPECT_THROW(DNSService(io_service, *"domain", true, false, NULL, NULL, NULL), IOError);
+}
+
+TEST(IOServiceTest, badAddress) {
+ IOService io_service;
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"localhost", NULL, NULL, NULL), IOError);
+}
+
+TEST(IOServiceTest, unavailableAddress) {
+ IOService io_service;
+ // These addresses should generally be unavailable as a valid local
+ // address, although there's no guarantee in theory.
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.0", NULL, NULL, NULL), IOError);
+
+ // Some OSes would simply reject binding attempt for an AF_INET6 socket
+ // to an IPv4-mapped IPv6 address. Even if those that allow it, since
+ // the corresponding IPv4 address is the same as the one used in the
+ // AF_INET socket case above, it should at least show the same result
+ // as the previous one.
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:192.0.2.0", NULL, NULL, NULL), IOError);
+}
+
+TEST(IOServiceTest, duplicateBind_v6) {
+ // In each sub test case, second attempt should fail due to duplicate bind
+ IOService io_service;
+
+ // IPv6, "any" address
+ DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL);
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL), IOError);
+ delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v6_address) {
+ // In each sub test case, second attempt should fail due to duplicate bind
+ IOService io_service;
+
+ // IPv6, specific address
+ DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
+ delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v4) {
+ // In each sub test case, second attempt should fail due to duplicate bind
+ IOService io_service;
+
+ // IPv4, "any" address
+ DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL);
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL), IOError);
+ delete dns_service;
+
+}
+
+TEST(IOServiceTest, duplicateBind_v4_address) {
+ // In each sub test case, second attempt should fail due to duplicate bind
+ IOService io_service;
+
+ // IPv4, specific address
+ DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
+ delete dns_service;
+}
+
+// Disabled because IPv4-mapped addresses don't seem to be working with
+// the IOService constructor
+TEST(IOServiceTest, DISABLED_IPv4MappedDuplicateBind) {
+ IOService io_service;
+ // Duplicate bind on IPv4-mapped IPv6 address
+ DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL);
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL), IOError);
+ delete dns_service;
+
+ // XXX:
+ // Currently, this throws an "invalid argument" exception. I have
+ // not been able to get IPv4-mapped addresses to work.
+ dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL);
+ EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL), IOError);
+ delete dns_service;
+}
+
diff --git a/src/lib/asiodns/tests/qid_gen_unittest.cc b/src/lib/asiodns/tests/qid_gen_unittest.cc
new file mode 100644
index 0000000..878d9a2
--- /dev/null
+++ b/src/lib/asiodns/tests/qid_gen_unittest.cc
@@ -0,0 +1,59 @@
+// 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.
+
+// 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.
+
+
+/// \brief Test of QidGenerator
+///
+
+#include <gtest/gtest.h>
+
+#include <asiodns/qid_gen.h>
+#include <dns/message.h>
+
+// Tests the operation of the Qid generator
+
+// Check that getInstance returns a singleton
+TEST(QidGenerator, singleton) {
+ isc::asiodns::QidGenerator& g1 = isc::asiodns::QidGenerator::getInstance();
+ isc::asiodns::QidGenerator& g2 = isc::asiodns::QidGenerator::getInstance();
+
+ EXPECT_TRUE(&g1 == &g2);
+}
+
+TEST(QidGenerator, generate) {
+ // We'll assume that boost's generator is 'good enough', and won't
+ // do full statistical checking here. Let's just call it the xkcd
+ // test (http://xkcd.com/221/), and check if three consecutive
+ // generates are not all the same.
+ isc::dns::qid_t one, two, three;
+ isc::asiodns::QidGenerator& gen = isc::asiodns::QidGenerator::getInstance();
+ one = gen.generateQid();
+ two = gen.generateQid();
+ three = gen.generateQid();
+ ASSERT_FALSE((one == two) && (one == three));
+}
diff --git a/src/lib/asiodns/tests/run_unittests.cc b/src/lib/asiodns/tests/run_unittests.cc
new file mode 100644
index 0000000..c285f9e
--- /dev/null
+++ b/src/lib/asiodns/tests/run_unittests.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2009 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.
+
+#include <gtest/gtest.h>
+
+#include <log/root_logger_name.h>
+#include <dns/tests/unittest_util.h>
+
+int
+main(int argc, char* argv[])
+{
+ ::testing::InitGoogleTest(&argc, argv); // Initialize Google test
+ isc::log::setRootLoggerName("unittest"); // Set a root logger name
+ isc::UnitTestUtil::addDataPath(TEST_DATA_DIR); // Add location of test data
+
+ return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/asiodns/udp_server.cc b/src/lib/asiodns/udp_server.cc
new file mode 100644
index 0000000..4d2a0ed
--- /dev/null
+++ b/src/lib/asiodns/udp_server.cc
@@ -0,0 +1,324 @@
+// 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.
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h> // for some IPC/network system calls
+#include <errno.h>
+
+#include <boost/shared_array.hpp>
+
+#include <config.h>
+
+#include <log/dummylog.h>
+
+#include <asio.hpp>
+#include <asio/error.hpp>
+#include <asiolink/dummy_io_cb.h>
+#include <asiolink/udp_endpoint.h>
+#include <asiolink/udp_socket.h>
+#include "udp_server.h"
+
+#include <dns/opcode.h>
+
+using namespace asio;
+using asio::ip::udp;
+using isc::log::dlog;
+
+using namespace std;
+using namespace isc::dns;
+using namespace isc::asiolink;
+
+namespace isc {
+namespace asiodns {
+
+/*
+ * Some of the member variables here are shared_ptrs and some are
+ * auto_ptrs. There will be one instance of Data for the lifetime
+ * of packet. The variables that are state only for a single packet
+ * use auto_ptr, as it is more lightweight. In the case of shared
+ * configuration (eg. the callbacks, socket), we use shared_ptrs.
+ */
+struct UDPServer::Data {
+ /*
+ * Constructor from parameters passed to UDPServer constructor.
+ * This instance will not be used to retrieve and answer the actual
+ * query, it will only hold parameters until we wait for the
+ * first packet. But we do initialize the socket in here.
+ */
+ Data(io_service& io_service, const ip::address& addr, const uint16_t port,
+ SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
+ io_(io_service), done_(false),
+ checkin_callback_(checkin),lookup_callback_(lookup),
+ answer_callback_(answer)
+ {
+ // We must use different instantiations for v4 and v6;
+ // otherwise ASIO will bind to both
+ udp proto = addr.is_v4() ? udp::v4() : udp::v6();
+ socket_.reset(new udp::socket(io_service, proto));
+ socket_->set_option(socket_base::reuse_address(true));
+ if (addr.is_v6()) {
+ socket_->set_option(asio::ip::v6_only(true));
+ }
+ socket_->bind(udp::endpoint(addr, port));
+ }
+
+ /*
+ * Copy constructor. Default one would probably do, but it is unnecessary
+ * to copy many of the member variables every time we fork to handle
+ * another packet.
+ *
+ * We also allocate data for receiving the packet here.
+ */
+ Data(const Data& other) :
+ io_(other.io_), socket_(other.socket_), done_(false),
+ checkin_callback_(other.checkin_callback_),
+ lookup_callback_(other.lookup_callback_),
+ answer_callback_(other.answer_callback_)
+ {
+ // Instantiate the data buffer and endpoint that will
+ // be used by the asynchronous receive call.
+ data_.reset(new char[MAX_LENGTH]);
+ sender_.reset(new udp::endpoint());
+ }
+
+ // The ASIO service object
+ asio::io_service& io_;
+
+ // Class member variables which are dynamic, and changes to which
+ // need to accessible from both sides of a coroutine fork or from
+ // outside of the coroutine (i.e., from an asynchronous I/O call),
+ // should be declared here as pointers and allocated in the
+ // constructor or in the coroutine. This allows state information
+ // to persist when an individual copy of the coroutine falls out
+ // scope while waiting for an event, *so long as* there is another
+ // object that is referencing the same data. As a side-benefit, using
+ // pointers also reduces copy overhead for coroutine objects.
+ //
+ // Note: Currently these objects are allocated by "new" in the
+ // constructor, or in the function operator while processing a query.
+ // Repeated allocations from the heap for every incoming query is
+ // clearly a performance issue; this must be optimized in the future.
+ // The plan is to have a structure pre-allocate several "Data"
+ // objects which can be pulled off a free list and placed on an in-use
+ // list whenever a query comes in. This will serve the dual purpose
+ // of improving performance and guaranteeing that state information
+ // will *not* be destroyed when any one instance of the coroutine
+ // falls out of scope while waiting for an event.
+ //
+ // Socket used to for listen for queries. Created in the
+ // constructor and stored in a shared_ptr because socket objects
+ // are not copyable.
+ boost::shared_ptr<asio::ip::udp::socket> socket_;
+
+ // The ASIO-internal endpoint object representing the client
+ std::auto_ptr<asio::ip::udp::endpoint> sender_;
+
+ // \c IOMessage and \c Message objects to be passed to the
+ // DNS lookup and answer providers
+ std::auto_ptr<asiolink::IOMessage> io_message_;
+
+ // The original query as sent by the client
+ isc::dns::MessagePtr query_message_;
+
+ // The response message we are building
+ isc::dns::MessagePtr answer_message_;
+
+ // The buffer into which the response is written
+ isc::dns::OutputBufferPtr respbuf_;
+
+ // The buffer into which the query packet is written
+ boost::shared_array<char> data_;
+
+ // State information that is entirely internal to a given instance
+ // of the coroutine can be declared here.
+ size_t bytes_;
+ bool done_;
+
+
+ // Callback functions provided by the caller
+ const SimpleCallback* checkin_callback_;
+ const DNSLookup* lookup_callback_;
+ const DNSAnswer* answer_callback_;
+
+ std::auto_ptr<IOEndpoint> peer_;
+ std::auto_ptr<IOSocket> iosock_;
+};
+
+/// The following functions implement the \c UDPServer class.
+///
+/// The constructor. It just creates new internal state object
+/// and lets it handle the initialization.
+UDPServer::UDPServer(io_service& io_service, const ip::address& addr,
+ const uint16_t port, SimpleCallback* checkin, DNSLookup* lookup,
+ DNSAnswer* answer) :
+ data_(new Data(io_service, addr, port, checkin, lookup, answer))
+{ }
+
+/// The function operator is implemented with the "stackless coroutine"
+/// pattern; see internal/coroutine.h for details.
+void
+UDPServer::operator()(error_code ec, size_t length) {
+ /// Because the coroutine reentry block is implemented as
+ /// a switch statement, inline variable declarations are not
+ /// permitted. Certain variables used below can be declared here.
+
+ CORO_REENTER (this) {
+ do {
+ /*
+ * This is preparation for receiving a packet. We get a new
+ * state object for the lifetime of the next packet to come.
+ * It allocates the buffers to receive data into.
+ */
+ data_.reset(new Data(*data_));
+
+ do {
+ // Begin an asynchronous receive, then yield.
+ // When the receive event is posted, the coroutine
+ // will resume immediately after this point.
+ CORO_YIELD data_->socket_->async_receive_from(
+ buffer(data_->data_.get(), MAX_LENGTH), *data_->sender_,
+ *this);
+
+ // Abort on fatal errors
+ // TODO: add log
+ if (ec) {
+ using namespace asio::error;
+ if (ec.value() != would_block && ec.value() != try_again &&
+ ec.value() != interrupted) {
+ return;
+ }
+ }
+
+ } while (ec || length == 0);
+
+ data_->bytes_ = length;
+
+ /*
+ * We fork the coroutine now. One (the child) will keep
+ * the current state and handle the packet, then die and
+ * drop ownership of the state. The other (parent) will just
+ * go into the loop again and replace the current state with
+ * a new one for a new object.
+ *
+ * Actually, both of the coroutines will be a copy of this
+ * one, but that's just internal implementation detail.
+ */
+ CORO_FORK data_->io_.post(UDPServer(*this));
+ } while (is_parent());
+
+ // Create an \c IOMessage object to store the query.
+ //
+ // (XXX: It would be good to write a factory function
+ // that would quickly generate an IOMessage object without
+ // all these calls to "new".)
+ data_->peer_.reset(new UDPEndpoint(*data_->sender_));
+
+ // The UDP socket class has been extended with asynchronous functions
+ // and takes as a template parameter a completion callback class. As
+ // UDPServer does not use these extended functions (only those defined
+ // in the IOSocket base class) - but needs a UDPSocket to get hold of
+ // the underlying Boost UDP socket - DummyIOCallback is used. This
+ // provides the appropriate operator() but is otherwise functionless.
+ data_->iosock_.reset(
+ new UDPSocket<DummyIOCallback>(*data_->socket_));
+
+ data_->io_message_.reset(new IOMessage(data_->data_.get(),
+ data_->bytes_, *data_->iosock_, *data_->peer_));
+
+ // Perform any necessary operations prior to processing an incoming
+ // query (e.g., checking for queued configuration messages).
+ //
+ // (XXX: it may be a performance issue to check in for every single
+ // incoming query; we may wish to throttle this in the future.)
+ if (data_->checkin_callback_ != NULL) {
+ (*data_->checkin_callback_)(*data_->io_message_);
+ }
+
+ // If we don't have a DNS Lookup provider, there's no point in
+ // continuing; we exit the coroutine permanently.
+ if (data_->lookup_callback_ == NULL) {
+ CORO_YIELD return;
+ }
+
+ // Instantiate objects that will be needed by the
+ // asynchronous DNS lookup and/or by the send call.
+ data_->respbuf_.reset(new OutputBuffer(0));
+ data_->query_message_.reset(new Message(Message::PARSE));
+ data_->answer_message_.reset(new Message(Message::RENDER));
+
+ // Schedule a DNS lookup, and yield. When the lookup is
+ // finished, the coroutine will resume immediately after
+ // this point.
+ CORO_YIELD data_->io_.post(AsyncLookup<UDPServer>(*this));
+
+ // The 'done_' flag indicates whether we have an answer
+ // to send back. If not, exit the coroutine permanently.
+ if (!data_->done_) {
+ CORO_YIELD return;
+ }
+
+ // Call the DNS answer provider to render the answer into
+ // wire format
+ (*data_->answer_callback_)(*data_->io_message_, data_->query_message_,
+ data_->answer_message_, data_->respbuf_);
+
+ // Begin an asynchronous send, and then yield. When the
+ // send completes, we will resume immediately after this point
+ // (though we have nothing further to do, so the coroutine
+ // will simply exit at that time).
+ CORO_YIELD data_->socket_->async_send_to(
+ buffer(data_->respbuf_->getData(), data_->respbuf_->getLength()),
+ *data_->sender_, *this);
+ }
+}
+
+/// Call the DNS lookup provider. (Expected to be called by the
+/// AsyncLookup<UDPServer> handler.)
+void
+UDPServer::asyncLookup() {
+ (*data_->lookup_callback_)(*data_->io_message_,
+ data_->query_message_, data_->answer_message_, data_->respbuf_, this);
+}
+
+/// Stop the UDPServer
+void
+UDPServer::stop() {
+ /// Using close instead of cancel, because cancel
+ /// will only cancel the asynchornized event already submitted
+ /// to io service, the events post to io service after
+ /// cancel still can be scheduled by io service, if
+ /// the socket is cloesed, all the asynchronized event
+ /// for it won't be scheduled by io service not matter it is
+ /// submit to io serice before or after close call. And we will
+ //. get bad_descriptor error
+ data_->socket_->close();
+}
+
+/// Post this coroutine on the ASIO service queue so that it will
+/// resume processing where it left off. The 'done' parameter indicates
+/// whether there is an answer to return to the client.
+void
+UDPServer::resume(const bool done) {
+ data_->done_ = done;
+ data_->io_.post(*this);
+}
+
+bool
+UDPServer::hasAnswer() {
+ return (data_->done_);
+}
+
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/asiodns/udp_server.h b/src/lib/asiodns/udp_server.h
new file mode 100644
index 0000000..4c19544
--- /dev/null
+++ b/src/lib/asiodns/udp_server.h
@@ -0,0 +1,108 @@
+// 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 __UDP_SERVER_H
+#define __UDP_SERVER_H 1
+
+#ifndef ASIO_HPP
+#error "asio.hpp must be included before including this, see asiolink.h as to why"
+#endif
+
+#include <asiolink/simple_callback.h>
+#include <asiodns/dns_answer.h>
+#include <asiodns/dns_lookup.h>
+#include <asiodns/dns_server.h>
+
+#include <coroutine.h>
+
+namespace isc {
+namespace asiodns {
+
+//
+// Asynchronous UDP server coroutine
+//
+///
+/// \brief This class implements the coroutine to handle UDP
+/// DNS query event. As such, it is both a \c DNSServer and
+/// a \c coroutine
+///
+class UDPServer : public virtual DNSServer, public virtual coroutine {
+public:
+ /// \brief Constructor
+ /// \param io_service the asio::io_service to work with
+ /// \param addr the IP address to listen for queries on
+ /// \param port the port to listen for queries on
+ /// \param checkin the callbackprovider for non-DNS events
+ /// \param lookup the callbackprovider for DNS lookup events
+ /// \param answer the callbackprovider for DNS answer events
+ explicit UDPServer(asio::io_service& io_service,
+ const asio::ip::address& addr, const uint16_t port,
+ isc::asiolink::SimpleCallback* checkin = NULL,
+ DNSLookup* lookup = NULL,
+ DNSAnswer* answer = NULL);
+
+ /// \brief The function operator
+ void operator()(asio::error_code ec = asio::error_code(),
+ size_t length = 0);
+
+ /// \brief Calls the lookup callback
+ void asyncLookup();
+
+ /// \brief Stop the running server
+ /// \note once the server stopped, it can't restart
+ void stop();
+
+ /// \brief Resume operation
+ ///
+ /// \param done Set this to true if the lookup action is done and
+ /// we have an answer
+ void resume(const bool done);
+
+ /// \brief Check if we have an answer
+ ///
+ /// \return true if we have an answer
+ bool hasAnswer();
+
+ /// \brief Returns the coroutine state value
+ ///
+ /// \return the coroutine state value
+ int value() { return (get_value()); }
+
+ /// \brief Clones the object
+ ///
+ /// \return a newly allocated copy of this object
+ DNSServer* clone() {
+ UDPServer* s = new UDPServer(*this);
+ return (s);
+ }
+
+private:
+ enum { MAX_LENGTH = 4096 };
+
+ /**
+ * \brief Internal state and data.
+ *
+ * We use the pimple design pattern, but not because we need to hide
+ * internal data. This class and whole header is for private use anyway.
+ * It turned out that UDPServer is copied a lot, because it is a coroutine.
+ * This way the overhead of copying is lower, we copy only one shared
+ * pointer instead of about 10 of them.
+ */
+ class Data;
+ boost::shared_ptr<Data> data_;
+};
+
+} // namespace asiodns
+} // namespace isc
+#endif // __UDP_SERVER_H
diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am
index 2fda728..07dec89 100644
--- a/src/lib/asiolink/Makefile.am
+++ b/src/lib/asiolink/Makefile.am
@@ -14,32 +14,21 @@ CLEANFILES = *.gcno *.gcda
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.cc dns_service.h
libasiolink_la_SOURCES += dummy_io_cb.h
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.cc io_endpoint.h
libasiolink_la_SOURCES += io_error.h
-libasiolink_la_SOURCES += io_fetch.cc io_fetch.h
libasiolink_la_SOURCES += io_message.h
-libasiolink_la_SOURCES += qid_gen.cc qid_gen.h
libasiolink_la_SOURCES += io_service.h io_service.cc
libasiolink_la_SOURCES += io_socket.h io_socket.cc
libasiolink_la_SOURCES += simple_callback.h
libasiolink_la_SOURCES += tcp_endpoint.h
-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.cc udp_server.h
libasiolink_la_SOURCES += udp_socket.h
-EXTRA_DIST = asiodef.msg
-
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in
# B10_CXXFLAGS)
libasiolink_la_CXXFLAGS = $(AM_CXXFLAGS)
diff --git a/src/lib/asiolink/README b/src/lib/asiolink/README
index 6bd1a73..66091b1 100644
--- a/src/lib/asiolink/README
+++ b/src/lib/asiolink/README
@@ -16,167 +16,7 @@ including:
them in only one place allows us to relax strictness here, while
leaving it in place elsewhere.
-Currently, the asiolink library only supports DNS servers (i.e., b10-auth
-and b10-resolver). The plan is to make it more generic and allow it to
-support other modules as well.
-
Some of the classes defined here--for example, IOSocket, IOEndpoint,
and IOAddress--are to be used by BIND 10 modules as wrappers around
ASIO-specific classes.
-Other classes implement the DNS protocol on behalf of BIND 10 modules.
-
-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
-required to read all the data.) The fetch loops until all the data is read.
-
-Finally, the socket is closed and the server called to resume operation.
diff --git a/src/lib/asiolink/asiodef.cc b/src/lib/asiolink/asiodef.cc
deleted file mode 100644
index 94c71b5..0000000
--- a/src/lib/asiolink/asiodef.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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
-
diff --git a/src/lib/asiolink/asiodef.h b/src/lib/asiolink/asiodef.h
deleted file mode 100644
index ba77817..0000000
--- a/src/lib/asiolink/asiodef.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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
diff --git a/src/lib/asiolink/asiodef.msg b/src/lib/asiolink/asiodef.msg
deleted file mode 100644
index 2fcadd1..0000000
--- a/src/lib/asiolink/asiodef.msg
+++ /dev/null
@@ -1,56 +0,0 @@
-# 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.
diff --git a/src/lib/asiolink/asiolink.h b/src/lib/asiolink/asiolink.h
index 6e8fe84..51d3a14 100644
--- a/src/lib/asiolink/asiolink.h
+++ b/src/lib/asiolink/asiolink.h
@@ -20,10 +20,6 @@
// See the description of the namespace below.
#include <asiolink/io_service.h>
-#include <asiolink/dns_service.h>
-#include <asiolink/dns_server.h>
-#include <asiolink/dns_lookup.h>
-#include <asiolink/dns_answer.h>
#include <asiolink/simple_callback.h>
#include <asiolink/interval_timer.h>
@@ -62,11 +58,6 @@
/// this module. The resulting interfaces are thus straightforward mapping
/// to the ASIO counterparts.
///
-/// Notes to developers:
-/// Currently the wrapper interface is fairly specific to use by a
-/// DNS server, i.e., b10-auth or b10-resolver. But the plan is to
-/// generalize it and have other modules use it as well.
-///
/// One obvious drawback of this approach is performance overhead
/// due to the additional layer. We should eventually evaluate the cost
/// of the wrapper abstraction in benchmark tests. Another drawback is
diff --git a/src/lib/asiolink/asiolink_utilities.h b/src/lib/asiolink/asiolink_utilities.h
index 659e6a0..6ac423e 100644
--- a/src/lib/asiolink/asiolink_utilities.h
+++ b/src/lib/asiolink/asiolink_utilities.h
@@ -17,6 +17,7 @@
#include <cstddef>
+namespace isc {
namespace asiolink {
/// \brief Read Unsigned 16-Bit Integer from Buffer
@@ -57,5 +58,6 @@ writeUint16(uint16_t value, void* buffer) {
}
} // namespace asiolink
+} // namespace isc
#endif // __ASIOLINK_UTILITIES_H
diff --git a/src/lib/asiolink/dns_answer.h b/src/lib/asiolink/dns_answer.h
deleted file mode 100644
index 84e1f6f..0000000
--- a/src/lib/asiolink/dns_answer.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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_DNS_ANSWER_H
-#define __ASIOLINK_DNS_ANSWER_H 1
-
-#include <asiolink/io_message.h>
-
-namespace asiolink {
-
-/// \brief The \c DNSAnswer class is an abstract base class for a DNS
-/// Answer provider function.
-///
-/// Specific derived class implementations are hidden within the
-/// implementation. Instances of the derived classes can be called
-/// as functions via the operator() interface. Pointers to these
-/// instances can then be provided to the \c IOService class
-/// via its constructor.
-///
-/// A DNS Answer provider function takes answer data that has been obtained
-/// from a DNS Lookup provider functon and readies it to be sent to the
-/// client. After it has run, the OutputBuffer object passed to it should
-/// contain the answer to the query rendered into wire format.
-class DNSAnswer {
- ///
- /// \name Constructors and Destructor
- ///
- /// Note: The copy constructor and the assignment operator are
- /// intentionally defined as private, making this class non-copyable.
- //@{
-private:
- DNSAnswer(const DNSAnswer& source);
- DNSAnswer& operator=(const DNSAnswer& 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).
- DNSAnswer() {}
-public:
- /// \brief The destructor
- 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 query_message The DNS MessagePtr of the original query
- /// \param answer_message The DNS MessagePtr of the answer we are
- /// building
- /// \param buffer Intermediate data results are put here
- virtual void operator()(const IOMessage& io_message,
- isc::dns::MessagePtr query_message,
- isc::dns::MessagePtr answer_message,
- isc::dns::OutputBufferPtr buffer) const = 0;
-};
-
-} // namespace asiolink
-#endif // __ASIOLINK_DNS_ANSWER_H
diff --git a/src/lib/asiolink/dns_lookup.h b/src/lib/asiolink/dns_lookup.h
deleted file mode 100644
index a79976f..0000000
--- a/src/lib/asiolink/dns_lookup.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// 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_DNS_LOOKUP_H
-#define __ASIOLINK_DNS_LOOKUP_H 1
-
-#include <asiolink/io_message.h>
-#include <asiolink/dns_server.h>
-#include <dns/buffer.h>
-#include <dns/message.h>
-
-namespace asiolink {
-
-/// \brief The \c DNSLookup class is an abstract base class for a DNS
-/// Lookup provider function.
-///
-/// Specific derived class implementations are hidden within the
-/// implementation. Instances of the derived classes can be called
-/// as functions via the operator() interface. Pointers to these
-/// instances can then be provided to the \c IOService class
-/// via its constructor.
-///
-/// A DNS Lookup provider function obtains the data needed to answer
-/// a DNS query (e.g., from authoritative data source, cache, or upstream
-/// query). After it has run, the OutputBuffer object passed to it
-/// should contain the answer to the query, in an internal representation.
-class DNSLookup {
- ///
- /// \name Constructors and Destructor
- ///
- /// Note: The copy constructor and the assignment operator are
- /// intentionally defined as private, making this class non-copyable.
- //@{
-private:
- DNSLookup(const DNSLookup& source);
- DNSLookup& operator=(const DNSLookup& 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).
- DNSLookup() : self_(this) {}
-public:
- /// \brief The destructor
- virtual ~DNSLookup() {}
- //@}
- /// \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 answer_message The final answer will be constructed in
- /// this MessagePtr
- /// \param buffer The final answer is put here
- /// \param server DNSServer object to use
- virtual void operator()(const IOMessage& io_message,
- isc::dns::MessagePtr message,
- isc::dns::MessagePtr answer_message,
- isc::dns::OutputBufferPtr buffer,
- DNSServer* server) const
- {
- (*self_)(io_message, message, answer_message, buffer, server);
- }
-private:
- DNSLookup* self_;
-};
-
-} // namespace asiolink
-#endif // __ASIOLINK_DNS_LOOKUP_H
diff --git a/src/lib/asiolink/dns_server.h b/src/lib/asiolink/dns_server.h
deleted file mode 100644
index f15f808..0000000
--- a/src/lib/asiolink/dns_server.h
+++ /dev/null
@@ -1,155 +0,0 @@
-// 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_DNS_SERVER_H
-#define __ASIOLINK_DNS_SERVER_H 1
-
-#include <asiolink/io_message.h>
-
-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.
-/// Those functions are described in more detail below under
-/// \c SimpleCallback, \c DNSLookup, and \c DNSAnswer.
-///
-/// Notes to developers:
-/// When constructed, this class (and its derived classes) will have its
-/// "self_" member set to point to "this". Objects of this class (as
-/// instantiated through a base class) are sometimes passed by
-/// reference (as this superclass); calls to methods in the base
-/// class are then rerouted via this pointer to methods in the derived
-/// class. This allows code from outside asiolink, with no specific
-/// knowledge of \c TCPServer or \c UDPServer, to access their methods.
-///
-/// This class is both assignable and copy-constructable. Its subclasses
-/// use the "stackless coroutine" pattern, meaning that it will copy itself
-/// 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
-/// that derived classes be kept small to reduce copy overhead.
-class DNSServer {
-protected:
- ///
- /// \name Constructors and destructors
- ///
- /// This is intentionally defined as \c protected, as this base class
- /// should never be instantiated except as part of a derived class.
- //@{
- DNSServer() : self_(this) {}
-public:
- /// \brief The destructor
- virtual ~DNSServer() {}
- //@}
-
- ///
- /// \name Class methods
- ///
- /// These methods all make their calls indirectly via the "self_"
- /// pointer, ensuring that the functions ultimately invoked will be
- /// 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(),
- size_t length = 0)
- {
- (*self_)(ec, length);
- }
-
- /// \brief Stop current running server
- virtual void stop() { self_->stop();}
-
- /// \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 void resume(const bool done) { self_->resume(done); }
-
- /// \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()); }
-
- /// \brief Returns the current value of the 'coroutine' object
- ///
- /// This is a temporary method, intended to be used for debugging
- /// 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 int value() { return (self_->value()); }
-
- /// \brief Returns a pointer to a clone of this DNSServer object.
- ///
- /// When a \c DNSServer object is copied or assigned, the result will
- /// 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 DNSServer* clone() { return (self_->clone()); }
- //@}
-
-protected:
- /// \brief Lookup handler object.
- ///
- /// This is a protected class; it can only be instantiated
- /// from within a derived class of \c DNSServer.
- ///
- /// A server object that has received a query creates an instance
- /// of this class and scheudles it on the ASIO service queue
- /// using asio::io_service::post(). When the handler executes, it
- /// calls the asyncLookup() method in the server object to start a
- /// DNS lookup. When the lookup is complete, the server object is
- /// scheduled to resume, again using io_service::post().
- ///
- /// Note that the calling object is copied into the handler object,
- /// not referenced. This is because, once the calling object yields
- /// control to the handler, it falls out of scope and may disappear
- template <typename T>
- class AsyncLookup {
- public:
- AsyncLookup(T& caller) : caller_(caller) {}
- void operator()() { caller_.asyncLookup(); }
- private:
- T caller_;
- };
-
- /// \brief Carries out a DNS lookup.
- ///
- /// This function calls the \c DNSLookup object specified by the
- /// DNS server when the \c IOService was created, passing along
- /// the details of the query and a pointer back to the current
- /// server object. It is called asynchronously via the AsyncLookup
- /// handler class.
- virtual void asyncLookup() { self_->asyncLookup(); }
-
-private:
- DNSServer* self_;
-};
-
-
-} // asiolink
-#endif // __ASIOLINK_DNS_SERVER_H
diff --git a/src/lib/asiolink/dns_service.cc b/src/lib/asiolink/dns_service.cc
deleted file mode 100644
index f17bb44..0000000
--- a/src/lib/asiolink/dns_service.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-// 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.
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h> // for some IPC/network system calls
-
-#include <boost/lexical_cast.hpp>
-
-#include <config.h>
-
-#include <log/dummylog.h>
-
-#include <asio.hpp>
-#include <asiolink/dns_service.h>
-#include <asiolink/io_service.h>
-#include <asiolink/io_service.h>
-#include <asiolink/tcp_server.h>
-#include <asiolink/udp_server.h>
-
-#include <log/dummylog.h>
-
-#include <boost/lexical_cast.hpp>
-#include <boost/foreach.hpp>
-
-using isc::log::dlog;
-
-namespace asiolink {
-
-class SimpleCallback;
-class DNSLookup;
-class DNSAnswer;
-
-namespace {
-
-asio::ip::address
-convertAddr(const std::string& address) {
- asio::error_code err;
- asio::ip::address addr = asio::ip::address::from_string(address, err);
- if (err) {
- isc_throw(IOError, "Invalid IP address '" << &address << "': "
- << err.message());
- }
- return (addr);
-}
-
-}
-
-
-class DNSServiceImpl {
-public:
- DNSServiceImpl(IOService& io_service, const char& port,
- const asio::ip::address* v4addr,
- const asio::ip::address* v6addr,
- SimpleCallback* checkin, DNSLookup* lookup,
- DNSAnswer* answer);
-
- IOService& io_service_;
-
- typedef boost::shared_ptr<UDPServer> UDPServerPtr;
- typedef boost::shared_ptr<TCPServer> TCPServerPtr;
- typedef boost::shared_ptr<DNSServer> DNSServerPtr;
- std::vector<DNSServerPtr> servers_;
- SimpleCallback *checkin_;
- DNSLookup *lookup_;
- DNSAnswer *answer_;
-
- void addServer(uint16_t port, const asio::ip::address& address) {
- try {
- dlog(std::string("Initialize TCP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
- TCPServerPtr tcpServer(new TCPServer(io_service_.get_io_service(),
- address, port, checkin_, lookup_, answer_));
- (*tcpServer)();
- servers_.push_back(tcpServer);
- dlog(std::string("Initialize UDP server at ") + address.to_string() + ":" + boost::lexical_cast<std::string>(port));
- UDPServerPtr udpServer(new UDPServer(io_service_.get_io_service(),
- address, port, checkin_, lookup_, answer_));
- (*udpServer)();
- servers_.push_back(udpServer);
- }
- catch (const asio::system_error& err) {
- // We need to catch and convert any ASIO level exceptions.
- // This can happen for unavailable address, binding a privilege port
- // without the privilege, etc.
- isc_throw(IOError, "Failed to initialize network servers: " <<
- err.what());
- }
- }
- void addServer(const char& port, const asio::ip::address& address) {
- uint16_t portnum;
- try {
- // XXX: SunStudio with stlport4 doesn't reject some invalid
- // representation such as "-1" by lexical_cast<uint16_t>, so
- // we convert it into a signed integer of a larger size and perform
- // range check ourselves.
- const int32_t portnum32 = boost::lexical_cast<int32_t>(&port);
- if (portnum32 < 0 || portnum32 > 65535) {
- isc_throw(IOError, "Invalid port number '" << &port);
- }
- portnum = portnum32;
- } catch (const boost::bad_lexical_cast& ex) {
- isc_throw(IOError, "Invalid port number '" << &port << "': " <<
- ex.what());
- }
- addServer(portnum, address);
- }
-};
-
-DNSServiceImpl::DNSServiceImpl(IOService& io_service,
- const char& port,
- const asio::ip::address* const v4addr,
- const asio::ip::address* const v6addr,
- SimpleCallback* checkin,
- DNSLookup* lookup,
- DNSAnswer* answer) :
- io_service_(io_service),
- checkin_(checkin),
- lookup_(lookup),
- answer_(answer)
-{
-
- if (v4addr) {
- addServer(port, *v4addr);
- }
- if (v6addr) {
- addServer(port, *v6addr);
- }
-}
-
-DNSService::DNSService(IOService& io_service,
- const char& port, const char& address,
- SimpleCallback* checkin,
- DNSLookup* lookup,
- DNSAnswer* answer) :
- impl_(new DNSServiceImpl(io_service, port, NULL, NULL, checkin, lookup,
- answer)), io_service_(io_service)
-{
- addServer(port, &address);
-}
-
-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 asio::ip::address v4addr_any =
- asio::ip::address(asio::ip::address_v4::any());
- const asio::ip::address* const v4addrp = use_ipv4 ? &v4addr_any : NULL;
- const asio::ip::address v6addr_any =
- asio::ip::address(asio::ip::address_v6::any());
- const asio::ip::address* const v6addrp = use_ipv6 ? &v6addr_any : NULL;
- impl_ = new DNSServiceImpl(io_service, port, v4addrp, v6addrp, checkin, lookup, answer);
-}
-
-DNSService::DNSService(IOService& io_service, SimpleCallback* checkin,
- DNSLookup* lookup, DNSAnswer *answer) :
- impl_(new DNSServiceImpl(io_service, *"0", NULL, NULL, checkin, lookup,
- answer)), io_service_(io_service)
-{
-}
-
-DNSService::~DNSService() {
- delete impl_;
-}
-
-void
-DNSService::addServer(const char& port, const std::string& address) {
- impl_->addServer(port, convertAddr(address));
-}
-
-void
-DNSService::addServer(uint16_t port, const std::string& address) {
- impl_->addServer(port, convertAddr(address));
-}
-
-void
-DNSService::clearServers() {
- BOOST_FOREACH(const DNSServiceImpl::DNSServerPtr& s, impl_->servers_) {
- s->stop();
- }
- impl_->servers_.clear();
-}
-
-
-
-} // namespace asiolink
diff --git a/src/lib/asiolink/dns_service.h b/src/lib/asiolink/dns_service.h
deleted file mode 100644
index 9a3fb4c..0000000
--- a/src/lib/asiolink/dns_service.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// 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_DNS_SERVICE_H
-#define __ASIOLINK_DNS_SERVICE_H 1
-
-#include <resolve/resolver_interface.h>
-
-#include <asiolink/io_service.h>
-
-namespace asiolink {
-
-class SimpleCallback;
-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
- ///
- /// 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 use_ipv4 If true, listen on ipv4 'any'
- /// \param use_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 constructor without any servers.
- ///
- /// Use addServer() to add some servers.
- DNSService(IOService& io_service, SimpleCallback* checkin,
- DNSLookup* lookup, DNSAnswer* answer);
- /// \brief The destructor.
- ~DNSService();
- //@}
-
- /// \brief Add another server to the service
- void addServer(uint16_t port, const std::string &address);
- void addServer(const char &port, const std::string &address);
- /// \brief Remove all servers from the service
- void clearServers();
-
- /// \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(); }
-
- /// \brief Return the IO Service Object
- ///
- /// \return IOService object for this DNS service.
- asiolink::IOService& getIOService() { return (io_service_);}
-
-private:
- DNSServiceImpl* impl_;
- IOService& io_service_;
-};
-
-} // namespace asiolink
-#endif // __ASIOLINK_DNS_SERVICE_H
diff --git a/src/lib/asiolink/dummy_io_cb.h b/src/lib/asiolink/dummy_io_cb.h
index 0006b95..2081906 100644
--- a/src/lib/asiolink/dummy_io_cb.h
+++ b/src/lib/asiolink/dummy_io_cb.h
@@ -20,6 +20,7 @@
#include <asio/error.hpp>
#include <asio/error_code.hpp>
+namespace isc {
namespace asiolink {
/// \brief Asynchronous I/O Completion Callback
@@ -55,5 +56,6 @@ public:
};
} // namespace asiolink
+} // namespace isc
#endif // __DUMMY_IO_CB_H
diff --git a/src/lib/asiolink/interval_timer.cc b/src/lib/asiolink/interval_timer.cc
index 8efb102..0ed06eb 100644
--- a/src/lib/asiolink/interval_timer.cc
+++ b/src/lib/asiolink/interval_timer.cc
@@ -26,6 +26,7 @@
#include <asiolink/interval_timer.h>
#include <asiolink/io_service.h>
+namespace isc {
namespace asiolink {
class IntervalTimerImpl {
@@ -133,4 +134,5 @@ IntervalTimer::getInterval() const {
return (impl_->getInterval());
}
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/interval_timer.h b/src/lib/asiolink/interval_timer.h
index 6c43327..0831d44 100644
--- a/src/lib/asiolink/interval_timer.h
+++ b/src/lib/asiolink/interval_timer.h
@@ -19,6 +19,7 @@
#include <asiolink/io_service.h>
+namespace isc {
namespace asiolink {
struct IntervalTimerImpl;
@@ -129,5 +130,6 @@ private:
IntervalTimerImpl* impl_;
};
-} // namespace asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __ASIOLINK_INTERVAL_TIMER_H
diff --git a/src/lib/asiolink/io_address.cc b/src/lib/asiolink/io_address.cc
index 70e8374..7f7a6fc 100644
--- a/src/lib/asiolink/io_address.cc
+++ b/src/lib/asiolink/io_address.cc
@@ -31,6 +31,7 @@ using asio::ip::tcp;
using namespace std;
+namespace isc {
namespace asiolink {
// XXX: we cannot simply construct the address in the initialization list,
@@ -62,4 +63,5 @@ IOAddress::getFamily() const {
}
}
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/io_address.h b/src/lib/asiolink/io_address.h
index 53c1a7a..655b727 100644
--- a/src/lib/asiolink/io_address.h
+++ b/src/lib/asiolink/io_address.h
@@ -26,6 +26,7 @@
#include <exceptions/exceptions.h>
+namespace isc {
namespace asiolink {
/// \brief The \c IOAddress class represents an IP addresses (version
@@ -119,5 +120,6 @@ private:
asio::ip::address asio_address_;
};
-} // asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __IO_ADDRESS_H
diff --git a/src/lib/asiolink/io_asio_socket.h b/src/lib/asiolink/io_asio_socket.h
index ac793a6..d618ff8 100644
--- a/src/lib/asiolink/io_asio_socket.h
+++ b/src/lib/asiolink/io_asio_socket.h
@@ -31,7 +31,7 @@
#include <asiolink/io_error.h>
#include <asiolink/io_socket.h>
-
+namespace isc {
namespace asiolink {
/// \brief Socket not open
@@ -395,5 +395,6 @@ private:
};
} // namespace asiolink
+} // namespace isc
#endif // __IO_ASIO_SOCKET_H
diff --git a/src/lib/asiolink/io_endpoint.cc b/src/lib/asiolink/io_endpoint.cc
index e0b1a9e..63830a5 100644
--- a/src/lib/asiolink/io_endpoint.cc
+++ b/src/lib/asiolink/io_endpoint.cc
@@ -28,6 +28,7 @@
using namespace std;
+namespace isc {
namespace asiolink {
const IOEndpoint*
@@ -57,4 +58,5 @@ IOEndpoint::operator!=(const IOEndpoint& other) const {
return (!operator==(other));
}
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/io_endpoint.h b/src/lib/asiolink/io_endpoint.h
index d21da96..756fa3b 100644
--- a/src/lib/asiolink/io_endpoint.h
+++ b/src/lib/asiolink/io_endpoint.h
@@ -26,6 +26,7 @@
#include <exceptions/exceptions.h>
#include <asiolink/io_address.h>
+namespace isc {
namespace asiolink {
/// \brief The \c IOEndpoint class is an abstract base class to represent
@@ -117,5 +118,6 @@ public:
const unsigned short port);
};
-} // asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __IO_ENDPOINT_H
diff --git a/src/lib/asiolink/io_error.h b/src/lib/asiolink/io_error.h
index 2869e0b..c19d91c 100644
--- a/src/lib/asiolink/io_error.h
+++ b/src/lib/asiolink/io_error.h
@@ -18,6 +18,7 @@
#include <exceptions/exceptions.h>
+namespace isc {
namespace asiolink {
/// \brief An exception that is thrown if an error occurs within the IO
@@ -30,6 +31,7 @@ public:
};
-} // asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __IO_ERROR_H
diff --git a/src/lib/asiolink/io_fetch.cc b/src/lib/asiolink/io_fetch.cc
deleted file mode 100644
index a00a0ef..0000000
--- a/src/lib/asiolink/io_fetch.cc
+++ /dev/null
@@ -1,402 +0,0 @@
-// 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.
-
-#include <config.h>
-
-#include <unistd.h> // for some IPC/network system calls
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-#include <boost/bind.hpp>
-#include <boost/scoped_ptr.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <dns/message.h>
-#include <dns/messagerenderer.h>
-#include <dns/opcode.h>
-#include <dns/rcode.h>
-#include <log/logger.h>
-
-#include <asiolink/qid_gen.h>
-
-#include <asio.hpp>
-#include <asio/deadline_timer.hpp>
-
-#include <asiolink/asiodef.h>
-#include <asiolink/io_address.h>
-#include <asiolink/io_asio_socket.h>
-#include <asiolink/io_endpoint.h>
-#include <asiolink/io_fetch.h>
-#include <asiolink/io_service.h>
-#include <asiolink/tcp_endpoint.h>
-#include <asiolink/tcp_socket.h>
-#include <asiolink/udp_endpoint.h>
-#include <asiolink/udp_socket.h>
-#include <asiolink/qid_gen.h>
-
-#include <stdint.h>
-
-using namespace asio;
-using namespace isc::dns;
-using namespace isc::log;
-using namespace std;
-
-namespace asiolink {
-
-/// Use the ASIO logger
-
-isc::log::Logger logger("asiolink");
-
-/// \brief IOFetch Data
-///
-/// The data for IOFetch is held in a separate struct pointed to by a shared_ptr
-/// object. This is because the IOFetch object will be copied often (it is used
-/// as a coroutine and passed as callback to many async_*() functions) and we
-/// want keep the same data). Organising the data in this way keeps copying to
-/// a minimum.
-struct IOFetchData {
-
- // The first two members are shared pointers to a base class because what is
- // actually instantiated depends on whether the fetch is over UDP or TCP,
- // which is not known until construction of the IOFetch. Use of a shared
- // pointer here is merely to ensure deletion when the data object is deleted.
- boost::scoped_ptr<IOAsioSocket<IOFetch> > socket;
- ///< Socket to use for I/O
- boost::scoped_ptr<IOEndpoint> remote_snd;///< Where the fetch is sent
- boost::scoped_ptr<IOEndpoint> remote_rcv;///< Where the response came from
- isc::dns::Question question; ///< Question to be asked
- isc::dns::OutputBufferPtr msgbuf; ///< Wire buffer for question
- isc::dns::OutputBufferPtr received; ///< Received data put here
- IOFetch::Callback* callback; ///< Called on I/O Completion
- asio::deadline_timer timer; ///< Timer to measure timeouts
- IOFetch::Protocol protocol; ///< Protocol being used
- size_t cumulative; ///< Cumulative received amount
- size_t expected; ///< Expected amount of data
- size_t offset; ///< Offset to receive data
- bool stopped; ///< Have we stopped running?
- int timeout; ///< Timeout in ms
- bool packet; ///< true if packet was supplied
-
- // In case we need to log an error, the origin of the last asynchronous
- // I/O is recorded. To save time and simplify the code, this is recorded
- // as the ID of the error message that would be generated if the I/O failed.
- // This means that we must make sure that all possible "origins" take the
- // same arguments in their message in the same order.
- isc::log::MessageID origin; ///< Origin of last asynchronous I/O
- uint8_t staging[IOFetch::STAGING_LENGTH];
- ///< Temporary array for received data
- isc::dns::qid_t qid; ///< The QID set in the query
-
- /// \brief Constructor
- ///
- /// Just fills in the data members of the IOFetchData structure
- ///
- /// \param proto Either IOFetch::TCP or IOFetch::UDP.
- /// \param service I/O Service object to handle the asynchronous
- /// operations.
- /// \param query DNS question to send to the upstream server.
- /// \param address IP address of upstream server
- /// \param port Port to use for the query
- /// \param buff Output buffer into which the response (in wire format)
- /// is written (if a response is received).
- /// \param cb Callback object containing the callback to be called
- /// when we terminate. The caller is responsible for managing this
- /// object and deleting it if necessary.
- /// \param wait Timeout for the fetch (in ms).
- ///
- /// TODO: May need to alter constructor (see comment 4 in Trac ticket #554)
- IOFetchData(IOFetch::Protocol proto, IOService& service,
- const isc::dns::Question& query, const IOAddress& address,
- uint16_t port, isc::dns::OutputBufferPtr& buff, IOFetch::Callback* cb,
- int wait)
- :
- socket((proto == IOFetch::UDP) ?
- static_cast<IOAsioSocket<IOFetch>*>(
- new UDPSocket<IOFetch>(service)) :
- static_cast<IOAsioSocket<IOFetch>*>(
- new TCPSocket<IOFetch>(service))
- ),
- remote_snd((proto == IOFetch::UDP) ?
- static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
- static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
- ),
- remote_rcv((proto == IOFetch::UDP) ?
- static_cast<IOEndpoint*>(new UDPEndpoint(address, port)) :
- static_cast<IOEndpoint*>(new TCPEndpoint(address, port))
- ),
- question(query),
- msgbuf(new isc::dns::OutputBuffer(512)),
- received(buff),
-
- callback(cb),
- timer(service.get_io_service()),
- protocol(proto),
- cumulative(0),
- expected(0),
- offset(0),
- stopped(false),
- timeout(wait),
- packet(false),
- origin(ASIO_UNKORIGIN),
- staging(),
- qid(QidGenerator::getInstance().generateQid())
- {}
-
- // Checks if the response we received was ok;
- // - data contains the buffer we read, as well as the address
- // we sent to and the address we received from.
- // length is provided by the operator() in IOFetch.
- // Addresses must match, number of octets read must be at least
- // 2, and the first two octets must match the qid of the message
- // we sent.
- bool responseOK() {
- return (*remote_snd == *remote_rcv && cumulative >= 2 &&
- readUint16(received->getData()) == qid);
- }
-};
-
-/// IOFetch Constructor - just initialize the private data
-
-IOFetch::IOFetch(Protocol protocol, IOService& service,
- const isc::dns::Question& question, const IOAddress& address, uint16_t port,
- OutputBufferPtr& buff, Callback* cb, int wait)
- :
- data_(new IOFetchData(protocol, service, question, address,
- port, buff, cb, wait))
-{
-}
-
-IOFetch::IOFetch(Protocol protocol, IOService& service,
- OutputBufferPtr& outpkt, const IOAddress& address, uint16_t port,
- OutputBufferPtr& buff, Callback* cb, int wait)
- :
- data_(new IOFetchData(protocol, service,
- isc::dns::Question(isc::dns::Name("dummy.example.org"), isc::dns::RRClass::IN(), isc::dns::RRType::A()),
- address, port, buff, cb, wait))
-{
- data_->msgbuf = outpkt;
- data_->packet = true;
-}
-
-// Return protocol in use.
-
-IOFetch::Protocol
-IOFetch::getProtocol() const {
- return (data_->protocol);
-}
-
-/// The function operator is implemented with the "stackless coroutine"
-/// pattern; see internal/coroutine.h for details.
-
-void
-IOFetch::operator()(asio::error_code ec, size_t length) {
-
- if (data_->stopped) {
- return;
- } else if (ec) {
- logIOFailure(ec);
- return;
- }
-
- CORO_REENTER (this) {
-
- /// Generate the upstream query and render it to wire format
- /// This is done in a different scope to allow inline variable
- /// declarations.
- {
- if (data_->packet) {
- // A packet was given, overwrite the QID (which is in the
- // first two bytes of the packet).
- data_->msgbuf->writeUint16At(data_->qid, 0);
-
- } else {
- // A question was given, construct the packet
- Message msg(Message::RENDER);
- msg.setQid(data_->qid);
- msg.setOpcode(Opcode::QUERY());
- msg.setRcode(Rcode::NOERROR());
- msg.setHeaderFlag(Message::HEADERFLAG_RD);
- msg.addQuestion(data_->question);
- MessageRenderer renderer(*data_->msgbuf);
- msg.toWire(renderer);
- }
- }
-
- // If we timeout, we stop, which will can cancel outstanding I/Os and
- // shutdown everything.
- if (data_->timeout != -1) {
- data_->timer.expires_from_now(boost::posix_time::milliseconds(
- data_->timeout));
- data_->timer.async_wait(boost::bind(&IOFetch::stop, *this,
- TIME_OUT));
- }
-
- // Open a connection to the target system. For speed, if the operation
- // is synchronous (i.e. UDP operation) we bypass the yield.
- data_->origin = ASIO_OPENSOCK;
- if (data_->socket->isOpenSynchronous()) {
- data_->socket->open(data_->remote_snd.get(), *this);
- } else {
- CORO_YIELD data_->socket->open(data_->remote_snd.get(), *this);
- }
-
- do {
- // Begin an asynchronous send, and then yield. When the send completes,
- // we will resume immediately after this point.
- data_->origin = ASIO_SENDSOCK;
- CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
- data_->msgbuf->getLength(), data_->remote_snd.get(), *this);
-
- // Now receive the response. Since TCP may not receive the entire
- // message in one operation, we need to loop until we have received
- // it. (This can't be done within the asyncReceive() method because
- // each I/O operation will be done asynchronously and between each one
- // we need to yield ... and we *really* don't want to set up another
- // coroutine within that method.) So after each receive (and yield),
- // we check if the operation is complete and if not, loop to read again.
- //
- // Another concession to TCP is that the amount of is contained in the
- // first two bytes. This leads to two problems:
- //
- // a) We don't want those bytes in the return buffer.
- // b) They may not both arrive in the first I/O.
- //
- // So... we need to loop until we have at least two bytes, then store
- // the expected amount of data. Then we need to loop until we have
- // received all the data before copying it back to the user's buffer.
- // And we want to minimise the amount of copying...
-
- data_->origin = ASIO_RECVSOCK;
- data_->cumulative = 0; // No data yet received
- data_->offset = 0; // First data into start of buffer
- data_->received->clear(); // Clear the receive buffer
- do {
- CORO_YIELD data_->socket->asyncReceive(data_->staging,
- static_cast<size_t>(STAGING_LENGTH),
- data_->offset,
- data_->remote_rcv.get(), *this);
- } while (!data_->socket->processReceivedData(data_->staging, length,
- data_->cumulative, data_->offset,
- data_->expected, data_->received));
- } while (!data_->responseOK());
-
- // Finished with this socket, so close it. This will not generate an
- // I/O error, but reset the origin to unknown in case we change this.
- data_->origin = ASIO_UNKORIGIN;
- data_->socket->close();
-
- /// We are done
- stop(SUCCESS);
- }
-}
-
-// Function that stops the coroutine sequence. It is called either when the
-// query finishes or when the timer times out. Either way, it sets the
-// "stopped_" flag and cancels anything that is in progress.
-//
-// As the function may be entered multiple times as things wind down, it checks
-// if the stopped_ flag is already set. If it is, the call is a no-op.
-
-void
-IOFetch::stop(Result result) {
-
- if (!data_->stopped) {
-
- // Mark the fetch as stopped to prevent other completion callbacks
- // (invoked because of the calls to cancel()) from executing the
- // cancel calls again.
- //
- // In a single threaded environment, the callbacks won't be invoked
- // until this one completes. In a multi-threaded environment, they may
- // well be, in which case the testing (and setting) of the stopped_
- // variable should be done inside a mutex (and the stopped_ variable
- // declared as "volatile").
- //
- // The numeric arguments indicate the debug level, with the lower
- // numbers indicating the most important information. The relative
- // values are somewhat arbitrary.
- //
- // Although Logger::debug checks the debug flag internally, doing it
- // below before calling Logger::debug avoids the overhead of a string
- // conversion in the common case when debug is not enabled.
- //
- // TODO: Update testing of stopped_ if threads are used.
- data_->stopped = true;
- switch (result) {
- case TIME_OUT:
- if (logger.isDebugEnabled(1)) {
- logger.debug(20, ASIO_RECVTMO,
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
- }
- break;
-
- case SUCCESS:
- if (logger.isDebugEnabled(50)) {
- logger.debug(30, ASIO_FETCHCOMP,
- data_->remote_rcv->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_rcv->getPort()));
- }
- break;
-
- case STOPPED:
- // Fetch has been stopped for some other reason. This is
- // allowed but as it is unusual it is logged, but with a lower
- // debug level than a timeout (which is totally normal).
- logger.debug(1, ASIO_FETCHSTOP,
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
- break;
-
- default:
- logger.error(ASIO_UNKRESULT, static_cast<int>(result),
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
- }
-
- // Stop requested, cancel and I/O's on the socket and shut it down,
- // and cancel the timer.
- data_->socket->cancel();
- data_->socket->close();
-
- data_->timer.cancel();
-
- // Execute the I/O completion callback (if present).
- if (data_->callback) {
- (*(data_->callback))(result);
- }
- }
-}
-
-// Log an error - called on I/O failure
-
-void IOFetch::logIOFailure(asio::error_code ec) {
-
- // Should only get here with a known error code.
- assert((data_->origin == ASIO_OPENSOCK) ||
- (data_->origin == ASIO_SENDSOCK) ||
- (data_->origin == ASIO_RECVSOCK) ||
- (data_->origin == ASIO_UNKORIGIN));
-
- static const char* PROTOCOL[2] = {"TCP", "UDP"};
- logger.error(data_->origin,
- ec.value(),
- ((data_->remote_snd->getProtocol() == IPPROTO_TCP) ?
- PROTOCOL[0] : PROTOCOL[1]),
- data_->remote_snd->getAddress().toText().c_str(),
- static_cast<int>(data_->remote_snd->getPort()));
-}
-
-} // namespace asiolink
-
diff --git a/src/lib/asiolink/io_fetch.h b/src/lib/asiolink/io_fetch.h
deleted file mode 100644
index 4611628..0000000
--- a/src/lib/asiolink/io_fetch.h
+++ /dev/null
@@ -1,200 +0,0 @@
-// 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 __IO_FETCH_H
-#define __IO_FETCH_H 1
-
-#include <config.h>
-
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <coroutine.h>
-
-#include <asio/error_code.hpp>
-
-#include <dns/buffer.h>
-#include <dns/question.h>
-
-namespace asiolink {
-
-// Forward declarations
-class IOAddress;
-class IOFetchData;
-class IOService;
-
-/// \brief Upstream Fetch Processing
-///
-/// IOFetch is the class used to send upstream fetches and to handle responses.
-///
-/// \param E Endpoint type to use.
-
-class IOFetch : public coroutine {
-public:
- /// \brief Protocol to use on the fetch
- enum Protocol {
- UDP = 0,
- TCP = 1
- };
-
- /// \brief Origin of Asynchronous I/O Call
- ///
- /// Indicates what initiated an asynchronous I/O call and used in deciding
- /// what error message to output if the I/O fails.
- enum Origin {
- NONE = 0, ///< No asynchronous call outstanding
- OPEN = 1,
- SEND = 2,
- RECEIVE = 3,
- CLOSE = 4
- };
-
- /// \brief Result of Upstream Fetch
- ///
- /// Note that this applies to the status of I/Os in the fetch - a fetch
- /// that resulted in a packet being received from the server is a SUCCESS,
- /// even if the contents of the packet indicate that some error occurred.
- enum Result {
- SUCCESS = 0, ///< Success, fetch completed
- TIME_OUT = 1, ///< Failure, fetch timed out
- STOPPED = 2, ///< Control code, fetch has been stopped
- NOTSET = 3 ///< For testing, indicates value not set
- };
-
- // The next enum is a "trick" to allow constants to be defined in a class
- // declaration.
-
- /// \brief Integer Constants
- enum {
- STAGING_LENGTH = 8192 ///< Size of staging buffer
- };
-
- /// \brief I/O Fetch Callback
- ///
- /// Class of callback object for when the fetch itself has completed - an
- /// object of this class is passed to the IOFetch constructor and its
- /// operator() method called when the fetch completes.
- ///
- /// Note the difference between the two operator() methods:
- /// - IOFetch::operator() callback is called when an asynchronous I/O has
- /// completed.
- /// - IOFetch::Callback::operator() is called when an upstream fetch - which
- /// may have involved several asynchronous I/O operations - has completed.
- ///
- /// This is an abstract class.
- class Callback {
- public:
- /// \brief Default Constructor
- Callback()
- {}
-
- /// \brief Virtual Destructor
- virtual ~Callback()
- {}
-
- /// \brief Callback method
- ///
- /// This is the method called when the fetch completes.
- ///
- /// \param result Result of the fetch
- virtual void operator()(Result result) = 0;
- };
-
- /// \brief Constructor.
- ///
- /// Creates the object that will handle the upstream fetch.
- ///
- /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
- /// \param service I/O Service object to handle the asynchronous
- /// operations.
- /// \param question DNS question to send to the upstream server.
- /// \param address IP address of upstream server
- /// \param port Port to which to connect on the upstream server
- /// \param buff Output buffer into which the response (in wire format)
- /// is written (if a response is received).
- /// \param cb Callback object containing the callback to be called when we
- /// terminate. The caller is responsible for managing this object
- /// and deleting it if necessary.
- /// \param wait Timeout for the fetch (in ms). The default value of
- /// -1 indicates no timeout.
- IOFetch(Protocol protocol, IOService& service,
- const isc::dns::Question& question, const IOAddress& address,
- uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
- int wait = -1);
-
- /// \brief Constructor.
- ///
- /// Creates the object that will handle the upstream fetch.
- ///
- /// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
- /// \param service I/O Service object to handle the asynchronous
- /// operations.
- /// \param outpkt Packet to send to upstream server. Note that the
- /// QID (first two bytes of the packet) may be altered in the sending.
- /// \param buff Output buffer into which the response (in wire format)
- /// is written (if a response is received).
- /// \param cb Callback object containing the callback to be called
- /// when we terminate. The caller is responsible for managing this
- /// object and deleting it if necessary.
- /// \param address IP address of upstream server
- /// \param port Port to which to connect on the upstream server
- /// (default = 53)
- /// \param wait Timeout for the fetch (in ms). The default value of
- /// -1 indicates no timeout.
- IOFetch(Protocol protocol, IOService& service,
- isc::dns::OutputBufferPtr& outpkt, const IOAddress& address,
- uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
- int wait = -1);
-
- /// \brief Return Current Protocol
- ///
- /// \return Protocol associated with this IOFetch object.
- Protocol getProtocol() const;
-
- /// \brief Coroutine entry point
- ///
- /// The operator() method is the method in which the coroutine code enters
- /// this object when an operation has been completed.
- ///
- /// \param ec Error code, the result of the last asynchronous I/O operation.
- /// \param length Amount of data received on the last asynchronous read
- void operator()(asio::error_code ec = asio::error_code(), size_t length = 0);
-
- /// \brief Terminate query
- ///
- /// This method can be called at any point. It terminates the current
- /// query with the specified reason.
- ///
- /// \param reason Reason for terminating the query
- void stop(Result reason = STOPPED);
-
-private:
- /// \brief Log I/O Failure
- ///
- /// Records an I/O failure to the log file
- ///
- /// \param ec ASIO error code
- void logIOFailure(asio::error_code ec);
-
- // Member variables. All data is in a structure pointed to by a shared
- // pointer. The IOFetch object is copied a number of times during its
- // life, and only requiring a pointer to be copied reduces overhead.
- boost::shared_ptr<IOFetchData> data_; ///< Private data
-
-};
-
-} // namespace asiolink
-
-#endif // __IO_FETCH_H
diff --git a/src/lib/asiolink/io_message.h b/src/lib/asiolink/io_message.h
index e857bd9..81f6da1 100644
--- a/src/lib/asiolink/io_message.h
+++ b/src/lib/asiolink/io_message.h
@@ -28,6 +28,7 @@
#include <asiolink/io_endpoint.h>
#include <asiolink/io_socket.h>
+namespace isc {
namespace asiolink {
/// \brief The \c IOMessage class encapsulates an incoming message received
@@ -96,5 +97,6 @@ private:
};
-} // asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __IO_MESSAGE_H
diff --git a/src/lib/asiolink/io_service.cc b/src/lib/asiolink/io_service.cc
index 55fc4b3..70cc18b 100644
--- a/src/lib/asiolink/io_service.cc
+++ b/src/lib/asiolink/io_service.cc
@@ -21,6 +21,7 @@
#include <asio.hpp>
#include <asiolink/io_service.h>
+namespace isc {
namespace asiolink {
class IOServiceImpl {
@@ -95,4 +96,5 @@ IOService::get_io_service() {
return (io_impl_->get_io_service());
}
-} // namepsace asiolink
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/io_service.h b/src/lib/asiolink/io_service.h
index 66558b7..438667c 100644
--- a/src/lib/asiolink/io_service.h
+++ b/src/lib/asiolink/io_service.h
@@ -19,6 +19,7 @@ namespace asio {
class io_service;
}
+namespace isc {
namespace asiolink {
struct IOServiceImpl;
@@ -73,5 +74,6 @@ private:
IOServiceImpl* io_impl_;
};
-} // namespace asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __ASIOLINK_IO_SERVICE_H
diff --git a/src/lib/asiolink/io_socket.cc b/src/lib/asiolink/io_socket.cc
index c386ca1..e1498dc 100644
--- a/src/lib/asiolink/io_socket.cc
+++ b/src/lib/asiolink/io_socket.cc
@@ -16,8 +16,7 @@
#include <asio.hpp>
-using namespace asio;
-
+namespace isc {
namespace asiolink {
/// \brief The \c DummySocket class is a concrete derived class of
@@ -62,4 +61,5 @@ IOSocket::getDummyTCPSocket() {
return (socket);
}
-}
+} // namespace asiolink
+} // namespace isc
diff --git a/src/lib/asiolink/io_socket.h b/src/lib/asiolink/io_socket.h
index bebc8b6..ab6479c 100644
--- a/src/lib/asiolink/io_socket.h
+++ b/src/lib/asiolink/io_socket.h
@@ -25,6 +25,7 @@
#include <exceptions/exceptions.h>
+namespace isc {
namespace asiolink {
/// \brief The \c IOSocket class is an abstract base class to represent
@@ -120,5 +121,6 @@ public:
};
} // namespace asiolink
+} // namespace isc
#endif // __IO_SOCKET_H
diff --git a/src/lib/asiolink/qid_gen.cc b/src/lib/asiolink/qid_gen.cc
deleted file mode 100644
index 4063b39..0000000
--- a/src/lib/asiolink/qid_gen.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.
-
-// qid_gen defines a generator for query id's
-//
-// We probably want to merge this with the weighted random in the nsas
-// (and other parts where we need randomness, perhaps another thing
-// for a general libutil?)
-
-#include <asiolink/qid_gen.h>
-
-#include <sys/time.h>
-
-namespace {
- asiolink::QidGenerator qid_generator_instance;
-}
-
-namespace asiolink {
-
-QidGenerator&
-QidGenerator::getInstance() {
- return (qid_generator_instance);
-}
-
-QidGenerator::QidGenerator() : dist_(0, 65535),
- vgen_(generator_, dist_)
-{
- seed();
-}
-
-void
-QidGenerator::seed() {
- struct timeval tv;
- gettimeofday(&tv, 0);
- generator_.seed((tv.tv_sec * 1000000) + tv.tv_usec);
-}
-
-isc::dns::qid_t
-QidGenerator::generateQid() {
- return (vgen_());
-}
-
-} // namespace asiolink
diff --git a/src/lib/asiolink/qid_gen.h b/src/lib/asiolink/qid_gen.h
deleted file mode 100644
index a5caa17..0000000
--- a/src/lib/asiolink/qid_gen.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-
-// qid_gen defines a generator for query id's
-//
-// We probably want to merge this with the weighted random in the nsas
-// (and other parts where we need randomness, perhaps another thing
-// for a general libutil?)
-
-#ifndef __QID_GEN_H
-#define __QID_GEN_H
-
-#include <dns/message.h>
-#include <boost/random/mersenne_twister.hpp>
-#include <boost/random/uniform_int.hpp>
-#include <boost/random/variate_generator.hpp>
-
-
-namespace asiolink {
-
-/// This class generates Qids for outgoing queries
-///
-/// It is implemented as a singleton; the public way to access it
-/// is to call getInstance()->generateQid().
-///
-/// It automatically seeds it with the current time when it is first
-/// used.
-class QidGenerator {
-public:
- /// \brief Returns the singleton instance of the QidGenerator
- ///
- /// Returns a reference to the singleton instance of the generator
- static QidGenerator& getInstance();
-
- /// \brief Default constructor
- ///
- /// It is recommended that getInstance is used rather than creating
- /// separate instances of this class.
- ///
- /// The constructor automatically seeds the generator with the
- /// current time.
- QidGenerator();
-
- /// Generate a Qid
- ///
- /// \return A random Qid
- isc::dns::qid_t generateQid();
-
- /// \brief Seeds the QidGenerator (based on the current time)
- ///
- /// This is automatically called by the constructor
- void seed();
-
-private:
- // "Mersenne Twister: A 623-dimensionally equidistributed
- // uniform pseudo-random number generator", Makoto Matsumoto and
- // Takuji Nishimura, ACM Transactions on Modeling and Computer
- // Simulation: Special Issue on Uniform Random Number Generation,
- // Vol. 8, No. 1, January 1998, pp. 3-30.
- //
- // mt19937 is an implementation of one of the pseudo random
- // generators described in this paper.
- boost::mt19937 generator_;
-
- // For qid's we want a uniform distribution
- boost::uniform_int<> dist_;
-
- boost::variate_generator<boost::mt19937&, boost::uniform_int<> > vgen_;
-};
-
-
-} // namespace asiolink
-
-#endif // __QID_GEN_H
diff --git a/src/lib/asiolink/simple_callback.h b/src/lib/asiolink/simple_callback.h
index ab5deaf..92093ec 100644
--- a/src/lib/asiolink/simple_callback.h
+++ b/src/lib/asiolink/simple_callback.h
@@ -17,6 +17,7 @@
#include <asiolink/io_message.h>
+namespace isc {
namespace asiolink {
/// \brief The \c SimpleCallback class is an abstract base class for a
@@ -67,5 +68,6 @@ private:
SimpleCallback* self_;
};
-} // namespace asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __ASIOLINK_SIMPLE_CALLBACK_H
diff --git a/src/lib/asiolink/tcp_endpoint.h b/src/lib/asiolink/tcp_endpoint.h
index 158ca4a..3e420f3 100644
--- a/src/lib/asiolink/tcp_endpoint.h
+++ b/src/lib/asiolink/tcp_endpoint.h
@@ -21,6 +21,7 @@
#include <asiolink/io_endpoint.h>
+namespace isc {
namespace asiolink {
/// \brief The \c TCPEndpoint class is a concrete derived class of
@@ -109,5 +110,6 @@ private:
asio::ip::tcp::endpoint& asio_endpoint_;
};
-} // namespace asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __TCP_ENDPOINT_H
diff --git a/src/lib/asiolink/tcp_server.cc b/src/lib/asiolink/tcp_server.cc
deleted file mode 100644
index db59551..0000000
--- a/src/lib/asiolink/tcp_server.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// 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.
-
-#include <config.h>
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h> // for some IPC/network system calls
-#include <errno.h>
-
-#include <boost/shared_array.hpp>
-
-#include <log/dummylog.h>
-
-#include <asio.hpp>
-#include <asiolink/dummy_io_cb.h>
-#include <asiolink/tcp_endpoint.h>
-#include <asiolink/tcp_socket.h>
-#include <asiolink/tcp_server.h>
-
-
-using namespace asio;
-using asio::ip::udp;
-using asio::ip::tcp;
-
-using namespace std;
-using namespace isc::dns;
-
-namespace asiolink {
-
-/// The following functions implement the \c TCPServer class.
-///
-/// The constructor
-TCPServer::TCPServer(io_service& io_service,
- const ip::address& addr, const uint16_t port,
- const SimpleCallback* checkin,
- const DNSLookup* lookup,
- const DNSAnswer* answer) :
- io_(io_service), done_(false),
- checkin_callback_(checkin), lookup_callback_(lookup),
- answer_callback_(answer)
-{
- tcp::endpoint endpoint(addr, port);
- acceptor_.reset(new tcp::acceptor(io_service));
- acceptor_->open(endpoint.protocol());
- // Set v6-only (we use a separate instantiation for v4,
- // otherwise asio will bind to both v4 and v6
- if (addr.is_v6()) {
- acceptor_->set_option(ip::v6_only(true));
- }
- acceptor_->set_option(tcp::acceptor::reuse_address(true));
- acceptor_->bind(endpoint);
- acceptor_->listen();
-}
-
-void
-TCPServer::operator()(error_code ec, size_t length) {
- /// Because the coroutine reentry block is implemented as
- /// a switch statement, inline variable declarations are not
- /// permitted. Certain variables used below can be declared here.
-
- boost::array<const_buffer,2> bufs;
- OutputBuffer lenbuf(TCP_MESSAGE_LENGTHSIZE);
-
- CORO_REENTER (this) {
- do {
- /// Create a socket to listen for connections
- socket_.reset(new tcp::socket(acceptor_->get_io_service()));
-
- /// Wait for new connections. In the event of non-fatal error,
- /// try again
- do {
- CORO_YIELD acceptor_->async_accept(*socket_, *this);
-
- // Abort on fatal errors
- // TODO: Log error?
- if (ec) {
- using namespace asio::error;
- if (ec.value() != would_block && ec.value() != try_again &&
- ec.value() != connection_aborted &&
- ec.value() != interrupted) {
- return;
- }
- }
- } while (ec);
-
- /// Fork the coroutine by creating a copy of this one and
- /// scheduling it on the ASIO service queue. The parent
- /// will continue listening for DNS connections while the
- /// handles the one that has just arrived.
- CORO_FORK io_.post(TCPServer(*this));
- } while (is_parent());
-
- /// Instantiate the data buffer that will be used by the
- /// asynchronous read call.
- data_.reset(new char[MAX_LENGTH]);
-
- /// Read the message, in two parts. First, the message length:
- CORO_YIELD async_read(*socket_, asio::buffer(data_.get(),
- TCP_MESSAGE_LENGTHSIZE), *this);
- if (ec) {
- socket_->close();
- CORO_YIELD return;
- }
-
- /// Now read the message itself. (This is done in a different scope
- /// to allow inline variable declarations.)
- CORO_YIELD {
- InputBuffer dnsbuffer(data_.get(), length);
- uint16_t msglen = dnsbuffer.readUint16();
- async_read(*socket_, asio::buffer(data_.get(), msglen), *this);
- }
-
- if (ec) {
- socket_->close();
- CORO_YIELD return;
- }
-
-
- // Create an \c IOMessage object to store the query.
- //
- // (XXX: It would be good to write a factory function
- // that would quickly generate an IOMessage object without
- // all these calls to "new".)
- peer_.reset(new TCPEndpoint(socket_->remote_endpoint()));
-
- // The TCP socket class has been extended with asynchronous functions
- // and takes as a template parameter a completion callback class. As
- // TCPServer does not use these extended functions (only those defined
- // in the IOSocket base class) - but needs a TCPSocket to get hold of
- // the underlying Boost TCP socket - DummyIOCallback is used. This
- // provides the appropriate operator() but is otherwise functionless.
- iosock_.reset(new TCPSocket<DummyIOCallback>(*socket_));
- io_message_.reset(new IOMessage(data_.get(), length, *iosock_, *peer_));
- bytes_ = length;
-
- // Perform any necessary operations prior to processing the incoming
- // packet (e.g., checking for queued configuration messages).
- //
- // (XXX: it may be a performance issue to have this called for
- // every single incoming packet; we may wish to throttle it somehow
- // in the future.)
- if (checkin_callback_ != NULL) {
- (*checkin_callback_)(*io_message_);
- }
-
- // If we don't have a DNS Lookup provider, there's no point in
- // continuing; we exit the coroutine permanently.
- if (lookup_callback_ == NULL) {
- socket_->close();
- CORO_YIELD return;
- }
-
- // Reset or instantiate objects that will be needed by the
- // DNS lookup and the write call.
- respbuf_.reset(new OutputBuffer(0));
- query_message_.reset(new Message(Message::PARSE));
- answer_message_.reset(new Message(Message::RENDER));
-
- // Schedule a DNS lookup, and yield. When the lookup is
- // finished, the coroutine will resume immediately after
- // this point.
- CORO_YIELD io_.post(AsyncLookup<TCPServer>(*this));
-
- // The 'done_' flag indicates whether we have an answer
- // to send back. If not, exit the coroutine permanently.
- if (!done_) {
- // TODO: should we keep the connection open for a short time
- // to see if new requests come in?
- socket_->close();
- CORO_YIELD return;
- }
-
- if (ec) {
- CORO_YIELD return;
- }
- // Call the DNS answer provider to render the answer into
- // wire format
- (*answer_callback_)(*io_message_, query_message_,
- answer_message_, respbuf_);
-
- // Set up the response, beginning with two length bytes.
- lenbuf.writeUint16(respbuf_->getLength());
- bufs[0] = buffer(lenbuf.getData(), lenbuf.getLength());
- bufs[1] = buffer(respbuf_->getData(), respbuf_->getLength());
-
- // Begin an asynchronous send, and then yield. When the
- // send completes, we will resume immediately after this point
- // (though we have nothing further to do, so the coroutine
- // will simply exit at that time).
- CORO_YIELD async_write(*socket_, bufs, *this);
-
- // TODO: should we keep the connection open for a short time
- // to see if new requests come in?
- socket_->close();
- }
-}
-
-/// Call the DNS lookup provider. (Expected to be called by the
-/// AsyncLookup<TCPServer> handler.)
-void
-TCPServer::asyncLookup() {
- (*lookup_callback_)(*io_message_, query_message_,
- answer_message_, respbuf_, this);
-}
-
-void TCPServer::stop() {
- /// we use close instead of cancel, with the same reason
- /// with udp server stop, refer to the udp server code
-
- acceptor_->close();
- // User may stop the server even when it hasn't started to
- // run, in that that socket_ is empty
- if (socket_) {
- socket_->close();
- }
-}
-/// Post this coroutine on the ASIO service queue so that it will
-/// resume processing where it left off. The 'done' parameter indicates
-/// whether there is an answer to return to the client.
-void
-TCPServer::resume(const bool done) {
- done_ = done;
- io_.post(*this);
-}
-
-} // namespace asiolink
-
diff --git a/src/lib/asiolink/tcp_server.h b/src/lib/asiolink/tcp_server.h
deleted file mode 100644
index 2fe0d37..0000000
--- a/src/lib/asiolink/tcp_server.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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 __TCP_SERVER_H
-#define __TCP_SERVER_H 1
-
-#ifndef ASIO_HPP
-#error "asio.hpp must be included before including this, see asiolink.h as to why"
-#endif
-
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include <asiolink/asiolink.h>
-#include <coroutine.h>
-
-
-namespace asiolink {
-
-/// \brief A TCP-specific \c DNSServer object.
-///
-/// This class inherits from both \c DNSServer and from \c coroutine,
-/// defined in coroutine.h.
-class TCPServer : public virtual DNSServer, public virtual coroutine {
-public:
- explicit TCPServer(asio::io_service& io_service,
- const asio::ip::address& addr, const uint16_t port,
- const SimpleCallback* checkin = NULL,
- const DNSLookup* lookup = NULL,
- const DNSAnswer* answer = NULL);
-
- void operator()(asio::error_code ec = asio::error_code(),
- size_t length = 0);
- void asyncLookup();
- void stop();
- void resume(const bool done);
- bool hasAnswer() { return (done_); }
- int value() { return (get_value()); }
-
- DNSServer* clone() {
- TCPServer* s = new TCPServer(*this);
- return (s);
- }
-
-private:
- enum { MAX_LENGTH = 65535 };
- static const size_t TCP_MESSAGE_LENGTHSIZE = 2;
-
- // The ASIO service object
- asio::io_service& io_;
-
- // Class member variables which are dynamic, and changes to which
- // need to accessible from both sides of a coroutine fork or from
- // outside of the coroutine (i.e., from an asynchronous I/O call),
- // should be declared here as pointers and allocated in the
- // constructor or in the coroutine. This allows state information
- // to persist when an individual copy of the coroutine falls out
- // scope while waiting for an event, *so long as* there is another
- // object that is referencing the same data. As a side-benefit, using
- // pointers also reduces copy overhead for coroutine objects.
- //
- // Note: Currently these objects are allocated by "new" in the
- // constructor, or in the function operator while processing a query.
- // Repeated allocations from the heap for every incoming query is
- // clearly a performance issue; this must be optimized in the future.
- // The plan is to have a structure pre-allocate several "server state"
- // objects which can be pulled off a free list and placed on an in-use
- // list whenever a query comes in. This will serve the dual purpose
- // of improving performance and guaranteeing that state information
- // will *not* be destroyed when any one instance of the coroutine
- // falls out of scope while waiting for an event.
- //
- // An ASIO acceptor object to handle new connections. Created in
- // the constructor.
- boost::shared_ptr<asio::ip::tcp::acceptor> acceptor_;
-
- // Socket used to for listen for queries. Created in the
- // constructor and stored in a shared_ptr because socket objects
- // are not copyable.
- boost::shared_ptr<asio::ip::tcp::socket> socket_;
-
- // The buffer into which the response is written
- boost::shared_ptr<isc::dns::OutputBuffer> respbuf_;
-
- // \c IOMessage and \c Message objects to be passed to the
- // DNS lookup and answer providers
- boost::shared_ptr<asiolink::IOMessage> io_message_;
- isc::dns::MessagePtr query_message_;
- isc::dns::MessagePtr answer_message_;
-
- // The buffer into which the query packet is written
- boost::shared_array<char>data_;
-
- // State information that is entirely internal to a given instance
- // of the coroutine can be declared here.
- size_t bytes_;
- bool done_;
-
- // Callback functions provided by the caller
- const SimpleCallback* checkin_callback_;
- const DNSLookup* lookup_callback_;
- const DNSAnswer* answer_callback_;
-
- boost::shared_ptr<IOEndpoint> peer_;
- boost::shared_ptr<IOSocket> iosock_;
-};
-
-} // namespace asiolink
-#endif // __TCP_SERVER_H
diff --git a/src/lib/asiolink/tcp_socket.h b/src/lib/asiolink/tcp_socket.h
index e6e0863..bf1e909 100644
--- a/src/lib/asiolink/tcp_socket.h
+++ b/src/lib/asiolink/tcp_socket.h
@@ -41,6 +41,7 @@
#include <asiolink/io_service.h>
#include <asiolink/tcp_endpoint.h>
+namespace isc {
namespace asiolink {
/// \brief Buffer Too Large
@@ -412,5 +413,6 @@ TCPSocket<C>::close() {
}
} // namespace asiolink
+} // namespace isc
#endif // __TCP_SOCKET_H
diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am
index f67e547..dfbd47c 100644
--- a/src/lib/asiolink/tests/Makefile.am
+++ b/src/lib/asiolink/tests/Makefile.am
@@ -21,16 +21,12 @@ run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
run_unittests_SOURCES += asiolink_utilities_unittest.cc
run_unittests_SOURCES += io_address_unittest.cc
run_unittests_SOURCES += io_endpoint_unittest.cc
-run_unittests_SOURCES += io_fetch_unittest.cc
run_unittests_SOURCES += io_socket_unittest.cc
-run_unittests_SOURCES += io_service_unittest.cc
run_unittests_SOURCES += interval_timer_unittest.cc
run_unittests_SOURCES += tcp_endpoint_unittest.cc
run_unittests_SOURCES += tcp_socket_unittest.cc
run_unittests_SOURCES += udp_endpoint_unittest.cc
run_unittests_SOURCES += udp_socket_unittest.cc
-run_unittests_SOURCES += dns_server_unittest.cc
-run_unittests_SOURCES += qid_gen_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/lib/asiolink/tests/asiolink_utilities_unittest.cc b/src/lib/asiolink/tests/asiolink_utilities_unittest.cc
index 51f565f..369b0f9 100644
--- a/src/lib/asiolink/tests/asiolink_utilities_unittest.cc
+++ b/src/lib/asiolink/tests/asiolink_utilities_unittest.cc
@@ -24,7 +24,7 @@
#include <dns/buffer.h>
#include <asiolink/asiolink_utilities.h>
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace isc::dns;
TEST(asioutil, readUint16) {
diff --git a/src/lib/asiolink/tests/dns_server_unittest.cc b/src/lib/asiolink/tests/dns_server_unittest.cc
deleted file mode 100644
index 5b8b683..0000000
--- a/src/lib/asiolink/tests/dns_server_unittest.cc
+++ /dev/null
@@ -1,501 +0,0 @@
-// 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.
-
-#include <config.h>
-#include <gtest/gtest.h>
-
-#include <asio.hpp>
-#include <asiolink/io_endpoint.h>
-#include <asiolink/io_error.h>
-#include <asiolink/udp_server.h>
-#include <asiolink/tcp_server.h>
-#include <asiolink/dns_answer.h>
-#include <asiolink/dns_lookup.h>
-#include <string>
-#include <csignal>
-#include <unistd.h> //for alarm
-
-#include <boost/shared_ptr.hpp>
-#include <boost/bind.hpp>
-#include <boost/function.hpp>
-
-
-/// The following tests focus on stop interface for udp and
-/// tcp server, there are lots of things can be shared to test
-/// both tcp and udp server, so they are in the same unittest
-
-/// The general work flow for dns server, is that wait for user
-/// query, once get one query, we will check the data is valid or
-/// not, if it passed, we will try to loop up the question, then
-/// compose the answer and finally send it back to user. The server
-/// may be stopped at any point during this porcess, so the test strategy
-/// is that we define 5 stop point and stop the server at these
-/// 5 points, to check whether stop is successful
-/// The 5 test points are :
-/// Before the server start to run
-/// After we get the query and check whether it's valid
-/// After we lookup the query
-/// After we compoisite the answer
-/// After user get the final result.
-
-/// The standard about whether we stop the server successfully or not
-/// is based on the fact that if the server is still running, the io
-/// service won't quit since it will wait for some asynchronized event for
-/// server. So if the io service block function run returns we assume
-/// that the server is stopped. To avoid stop interface failure which
-/// will block followed tests, using alarm signal to stop the blocking
-/// io service
-///
-/// The whole test context including one server and one client, and
-/// five stop checkpoints, we call them ServerStopper exclude the first
-/// stop point. Once the unittest fired, the client will send message
-/// to server, and the stopper may stop the server at the checkpoint, then
-/// we check the client get feedback or not. Since there is no DNS logic
-/// involved so the message sending between client and server is plain text
-/// And the valid checker, question lookup and answer composition are dummy.
-
-using namespace asiolink;
-using namespace asio;
-namespace {
-static const std::string server_ip = "127.0.0.1";
-const int server_port = 5553;
-//message client send to udp server, which isn't dns package
-//just for simple testing
-static const std::string query_message("BIND10 is awesome");
-
-// \brief provide capacity to derived class the ability
-// to stop DNSServer at certern point
-class ServerStopper {
- public:
- ServerStopper() : server_to_stop_(NULL) {}
- virtual ~ServerStopper(){}
-
- void setServerToStop(DNSServer* server) {
- server_to_stop_ = server;
- }
-
- void stopServer() const {
- if (server_to_stop_) {
- server_to_stop_->stop();
- }
- }
-
- private:
- DNSServer* server_to_stop_;
-};
-
-// \brief no check logic at all,just provide a checkpoint to stop the server
-class DummyChecker : public SimpleCallback, public ServerStopper {
- public:
- virtual void operator()(const IOMessage&) const {
- stopServer();
- }
-};
-
-// \brief no lookup logic at all,just provide a checkpoint to stop the server
-class DummyLookup : public DNSLookup, public ServerStopper {
- public:
- void operator()(const IOMessage& io_message,
- isc::dns::MessagePtr message,
- isc::dns::MessagePtr answer_message,
- isc::dns::OutputBufferPtr buffer,
- DNSServer* server) const {
- stopServer();
- server->resume(true);
- }
-};
-
-// \brief copy the data received from user to the answer part
-// provide checkpoint to stop server
-class SimpleAnswer : public DNSAnswer, public ServerStopper {
- public:
- void operator()(const IOMessage& message,
- isc::dns::MessagePtr query_message,
- isc::dns::MessagePtr answer_message,
- isc::dns::OutputBufferPtr buffer) const
- {
- //copy what we get from user
- buffer->writeData(message.getData(), message.getDataSize());
- stopServer();
- }
-
-};
-
-// \brief simple client, send one string to server and wait for response
-// in case, server stopped and client cann't get response, there is a timer wait
-// for specified seconds (the value is just a estimate since server process logic is quite
-// simple, and all the intercommunication is local) then cancel the waiting.
-class SimpleClient : public ServerStopper {
- public:
- static const size_t MAX_DATA_LEN = 256;
- SimpleClient(asio::io_service& service,
- unsigned int wait_server_time_out)
- {
- wait_for_response_timer_.reset(new deadline_timer(service));
- received_data_ = new char[MAX_DATA_LEN];
- received_data_len_ = 0;
- wait_server_time_out_ = wait_server_time_out;
- }
-
- virtual ~SimpleClient() {
- delete [] received_data_;
- }
-
- void setGetFeedbackCallback(boost::function<void()>& func) {
- get_response_call_back_ = func;
- }
-
- virtual void sendDataThenWaitForFeedback(const std::string& data) = 0;
- virtual std::string getReceivedData() const = 0;
-
- void startTimer() {
- wait_for_response_timer_->cancel();
- wait_for_response_timer_->
- expires_from_now(boost::posix_time::
- seconds(wait_server_time_out_));
- wait_for_response_timer_->
- async_wait(boost::bind(&SimpleClient::stopWaitingforResponse,
- this));
- }
-
- void cancelTimer() { wait_for_response_timer_->cancel(); }
-
- void getResponseCallBack(const asio::error_code& error, size_t
- received_bytes)
- {
- cancelTimer();
- if (!error)
- received_data_len_ = received_bytes;
- if (!get_response_call_back_.empty()) {
- get_response_call_back_();
- }
- stopServer();
- }
-
-
- protected:
- virtual void stopWaitingforResponse() = 0;
-
- boost::shared_ptr<deadline_timer> wait_for_response_timer_;
- char* received_data_;
- size_t received_data_len_;
- boost::function<void()> get_response_call_back_;
- unsigned int wait_server_time_out_;
-};
-
-
-
-class UDPClient : public SimpleClient {
- public:
- //After 1 seconds without feedback client will stop wait
- static const unsigned int server_time_out = 1;
-
- UDPClient(asio::io_service& service, const ip::udp::endpoint& server) :
- SimpleClient(service, server_time_out)
- {
- server_ = server;
- socket_.reset(new ip::udp::socket(service));
- socket_->open(ip::udp::v4());
- }
-
-
- void sendDataThenWaitForFeedback(const std::string& data) {
- received_data_len_ = 0;
- socket_->send_to(buffer(data.c_str(), data.size() + 1), server_);
- socket_->async_receive_from(buffer(received_data_, MAX_DATA_LEN),
- received_from_,
- boost::bind(&SimpleClient::
- getResponseCallBack, this, _1,
- _2));
- startTimer();
- }
-
- virtual std::string getReceivedData() const {
- return (received_data_len_ == 0 ? std::string("") :
- std::string(received_data_));
- }
-
- private:
- void stopWaitingforResponse() {
- socket_->close();
- }
-
- boost::shared_ptr<ip::udp::socket> socket_;
- ip::udp::endpoint server_;
- ip::udp::endpoint received_from_;
-};
-
-
-class TCPClient : public SimpleClient {
- public:
- // after 2 seconds without feedback client will stop wait,
- // this includes connect, send message and recevice message
- static const unsigned int server_time_out = 2;
- TCPClient(asio::io_service& service, const ip::tcp::endpoint& server)
- : SimpleClient(service, server_time_out)
- {
- server_ = server;
- socket_.reset(new ip::tcp::socket(service));
- socket_->open(ip::tcp::v4());
- }
-
-
- virtual void sendDataThenWaitForFeedback(const std::string &data) {
- received_data_len_ = 0;
- data_to_send_ = data;
- data_to_send_len_ = data.size() + 1;
- socket_->async_connect(server_, boost::bind(&TCPClient::connectHandler,
- this, _1));
- startTimer();
- }
-
- virtual std::string getReceivedData() const {
- return (received_data_len_ == 0 ? std::string("") :
- std::string(received_data_ + 2));
- }
-
- private:
- void stopWaitingforResponse() {
- socket_->close();
- }
-
- void connectHandler(const asio::error_code& error) {
- if (!error) {
- data_to_send_len_ = htons(data_to_send_len_);
- socket_->async_send(buffer(&data_to_send_len_, 2),
- boost::bind(&TCPClient::sendMessageBodyHandler,
- this, _1, _2));
- }
- }
-
- void sendMessageBodyHandler(const asio::error_code& error,
- size_t send_bytes)
- {
- if (!error && send_bytes == 2) {
- socket_->async_send(buffer(data_to_send_.c_str(),
- data_to_send_.size() + 1),
- boost::bind(&TCPClient::finishSendHandler, this, _1, _2));
- }
- }
-
- void finishSendHandler(const asio::error_code& error, size_t send_bytes) {
- if (!error && send_bytes == data_to_send_.size() + 1) {
- socket_->async_receive(buffer(received_data_, MAX_DATA_LEN),
- boost::bind(&SimpleClient::getResponseCallBack, this, _1,
- _2));
- }
- }
-
- boost::shared_ptr<ip::tcp::socket> socket_;
- ip::tcp::endpoint server_;
- std::string data_to_send_;
- uint16_t data_to_send_len_;
-};
-
-
-
-// \brief provide the context which including two client and
-// two server, udp client will only communicate with udp server, same for tcp client
-class DNSServerTest : public::testing::Test {
- protected:
- void SetUp() {
- ip::address server_address = ip::address::from_string(server_ip);
- checker_ = new DummyChecker();
- lookup_ = new DummyLookup();
- answer_ = new SimpleAnswer();
- udp_server_ = new UDPServer(service, server_address, server_port,
- checker_, lookup_, answer_);
- udp_client_ = new UDPClient(service,
- ip::udp::endpoint(server_address,
- server_port));
- tcp_server_ = new TCPServer(service, server_address, server_port,
- checker_, lookup_, answer_);
- tcp_client_ = new TCPClient(service,
- ip::tcp::endpoint(server_address,
- server_port));
- }
-
-
- void TearDown() {
- udp_server_->stop();
- tcp_server_->stop();
- delete checker_;
- delete lookup_;
- delete answer_;
- delete udp_server_;
- delete udp_client_;
- delete tcp_server_;
- delete tcp_client_;
- }
-
-
- void testStopServerByStopper(DNSServer* server, SimpleClient* client,
- ServerStopper* stopper)
- {
- static const unsigned int io_service_time_out = 5;
- io_service_is_time_out = false;
- stopper->setServerToStop(server);
- (*server)();
- client->sendDataThenWaitForFeedback(query_message);
- // Since thread hasn't been introduced into the tool box, using signal
- // to make sure run function will eventually return even server stop
- // failed
- void (*prev_handler)(int) = std::signal(SIGALRM, DNSServerTest::stopIOService);
- alarm(io_service_time_out);
- service.run();
- service.reset();
- //cancel scheduled alarm
- alarm(0);
- std::signal(SIGALRM, prev_handler);
- }
-
-
- static void stopIOService(int _no_use_parameter) {
- io_service_is_time_out = true;
- service.stop();
- }
-
- bool serverStopSucceed() const {
- return (!io_service_is_time_out);
- }
-
- DummyChecker* checker_;
- DummyLookup* lookup_;
- SimpleAnswer* answer_;
- UDPServer* udp_server_;
- UDPClient* udp_client_;
- TCPClient* tcp_client_;
- TCPServer* tcp_server_;
-
- // To access them in signal handle function, the following
- // variables have to be static.
- static asio::io_service service;
- static bool io_service_is_time_out;
-};
-
-bool DNSServerTest::io_service_is_time_out = false;
-asio::io_service DNSServerTest::service;
-
-// Test whether server stopped successfully after client get response
-// client will send query and start to wait for response, once client
-// get response, udp server will be stopped, the io service won't quit
-// if udp server doesn't stop successfully.
-TEST_F(DNSServerTest, stopUDPServerAfterOneQuery) {
- testStopServerByStopper(udp_server_, udp_client_, udp_client_);
- EXPECT_EQ(query_message, udp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether udp server stopped successfully before server start to serve
-TEST_F(DNSServerTest, stopUDPServerBeforeItStartServing) {
- udp_server_->stop();
- testStopServerByStopper(udp_server_, udp_client_, udp_client_);
- EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-
-// Test whether udp server stopped successfully during message check
-TEST_F(DNSServerTest, stopUDPServerDuringMessageCheck) {
- testStopServerByStopper(udp_server_, udp_client_, checker_);
- EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether udp server stopped successfully during query lookup
-TEST_F(DNSServerTest, stopUDPServerDuringQueryLookup) {
- testStopServerByStopper(udp_server_, udp_client_, lookup_);
- EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether udp server stopped successfully during composing answer
-TEST_F(DNSServerTest, stopUDPServerDuringPrepareAnswer) {
- testStopServerByStopper(udp_server_, udp_client_, answer_);
- EXPECT_EQ(std::string(""), udp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-static void stopServerManyTimes(DNSServer *server, unsigned int times) {
- for (int i = 0; i < times; ++i) {
- server->stop();
- }
-}
-
-// Test whether udp server stop interface can be invoked several times without
-// throw any exception
-TEST_F(DNSServerTest, stopUDPServeMoreThanOnce) {
- ASSERT_NO_THROW({
- boost::function<void()> stop_server_3_times
- = boost::bind(stopServerManyTimes, udp_server_, 3);
- udp_client_->setGetFeedbackCallback(stop_server_3_times);
- testStopServerByStopper(udp_server_, udp_client_, udp_client_);
- EXPECT_EQ(query_message, udp_client_->getReceivedData());
- });
- EXPECT_TRUE(serverStopSucceed());
-}
-
-
-TEST_F(DNSServerTest, stopTCPServerAfterOneQuery) {
- testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
- EXPECT_EQ(query_message, tcp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-
-// Test whether tcp server stopped successfully before server start to serve
-TEST_F(DNSServerTest, stopTCPServerBeforeItStartServing) {
- tcp_server_->stop();
- testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
- EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-
-// Test whether tcp server stopped successfully during message check
-TEST_F(DNSServerTest, stopTCPServerDuringMessageCheck) {
- testStopServerByStopper(tcp_server_, tcp_client_, checker_);
- EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether tcp server stopped successfully during query lookup
-TEST_F(DNSServerTest, stopTCPServerDuringQueryLookup) {
- testStopServerByStopper(tcp_server_, tcp_client_, lookup_);
- EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-// Test whether tcp server stopped successfully during composing answer
-TEST_F(DNSServerTest, stopTCPServerDuringPrepareAnswer) {
- testStopServerByStopper(tcp_server_, tcp_client_, answer_);
- EXPECT_EQ(std::string(""), tcp_client_->getReceivedData());
- EXPECT_TRUE(serverStopSucceed());
-}
-
-
-// Test whether tcp server stop interface can be invoked several times without
-// throw any exception
-TEST_F(DNSServerTest, stopTCPServeMoreThanOnce) {
- ASSERT_NO_THROW({
- boost::function<void()> stop_server_3_times
- = boost::bind(stopServerManyTimes, tcp_server_, 3);
- tcp_client_->setGetFeedbackCallback(stop_server_3_times);
- testStopServerByStopper(tcp_server_, tcp_client_, tcp_client_);
- EXPECT_EQ(query_message, tcp_client_->getReceivedData());
- });
- EXPECT_TRUE(serverStopSucceed());
-}
-
-}
diff --git a/src/lib/asiolink/tests/interval_timer_unittest.cc b/src/lib/asiolink/tests/interval_timer_unittest.cc
index 7e0e7bc..c24e60e 100644
--- a/src/lib/asiolink/tests/interval_timer_unittest.cc
+++ b/src/lib/asiolink/tests/interval_timer_unittest.cc
@@ -26,7 +26,7 @@ const boost::posix_time::time_duration TIMER_MARGIN_MSEC =
boost::posix_time::milliseconds(50);
}
-using namespace asiolink;
+using namespace isc::asiolink;
// This fixture is for testing IntervalTimer. Some callback functors are
// registered as callback function of the timer to test if they are called
diff --git a/src/lib/asiolink/tests/io_address_unittest.cc b/src/lib/asiolink/tests/io_address_unittest.cc
index 894f143..18b181e 100644
--- a/src/lib/asiolink/tests/io_address_unittest.cc
+++ b/src/lib/asiolink/tests/io_address_unittest.cc
@@ -18,7 +18,7 @@
#include <asiolink/io_error.h>
#include <asiolink/io_address.h>
-using namespace asiolink;
+using namespace isc::asiolink;
TEST(IOAddressTest, fromText) {
IOAddress io_address_v4("192.0.2.1");
diff --git a/src/lib/asiolink/tests/io_endpoint_unittest.cc b/src/lib/asiolink/tests/io_endpoint_unittest.cc
index 5170f7d..ce21fde 100644
--- a/src/lib/asiolink/tests/io_endpoint_unittest.cc
+++ b/src/lib/asiolink/tests/io_endpoint_unittest.cc
@@ -18,7 +18,7 @@
#include <asiolink/io_endpoint.h>
#include <asiolink/io_error.h>
-using namespace asiolink;
+using namespace isc::asiolink;
TEST(IOEndpointTest, createUDPv4) {
const IOEndpoint* ep;
diff --git a/src/lib/asiolink/tests/io_fetch_unittest.cc b/src/lib/asiolink/tests/io_fetch_unittest.cc
deleted file mode 100644
index 2b258b8..0000000
--- a/src/lib/asiolink/tests/io_fetch_unittest.cc
+++ /dev/null
@@ -1,723 +0,0 @@
-// 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.
-
-#include <algorithm>
-#include <cstdlib>
-#include <string>
-#include <iostream>
-#include <iomanip>
-#include <iterator>
-#include <vector>
-
-#include <gtest/gtest.h>
-#include <boost/bind.hpp>
-#include <boost/date_time/posix_time/posix_time_types.hpp>
-
-#include <asio.hpp>
-
-#include <dns/buffer.h>
-#include <dns/question.h>
-#include <dns/message.h>
-#include <dns/messagerenderer.h>
-#include <dns/opcode.h>
-#include <dns/name.h>
-#include <dns/rcode.h>
-
-#include <asiolink/asiolink_utilities.h>
-#include <asiolink/io_address.h>
-#include <asiolink/io_endpoint.h>
-#include <asiolink/io_fetch.h>
-#include <asiolink/io_service.h>
-
-using namespace asio;
-using namespace isc::dns;
-using namespace asio::ip;
-using namespace std;
-
-namespace asiolink {
-
-const asio::ip::address TEST_HOST(asio::ip::address::from_string("127.0.0.1"));
-const uint16_t TEST_PORT(5301);
-const int SEND_INTERVAL = 250; // Interval in ms between TCP sends
-const size_t MAX_SIZE = 64 * 1024; // Should be able to take 64kB
-
-// The tests are complex, so debug output has been left in (although disabled).
-// Set this to true to enable it.
-const bool DEBUG = false;
-
-/// \brief Test fixture for the asiolink::IOFetch.
-class IOFetchTest : public virtual ::testing::Test, public virtual IOFetch::Callback
-{
-public:
- IOService service_; ///< Service to run the query
- IOFetch::Result expected_; ///< Expected result of the callback
- bool run_; ///< Did the callback run already?
- Question question_; ///< What to ask
- OutputBufferPtr result_buff_; ///< Buffer to hold result of fetch
- OutputBufferPtr msgbuf_; ///< Buffer corresponding to known question
- IOFetch udp_fetch_; ///< For UDP query test
- IOFetch tcp_fetch_; ///< For TCP query test
- IOFetch::Protocol protocol_; ///< Protocol being tested
- size_t cumulative_; ///< Cumulative data received by "server".
- deadline_timer timer_; ///< Timer to measure timeouts
-
- // The next member is the buffer in which the "server" (implemented by the
- // response handler methods in this class) receives the question sent by the
- // fetch object.
- uint8_t receive_buffer_[MAX_SIZE]; ///< Server receive buffer
- OutputBufferPtr expected_buffer_; ///< Data we expect to receive
- vector<uint8_t> send_buffer_; ///< Server send buffer
- uint16_t send_cumulative_; ///< Data sent so far
-
- // Other data.
- string return_data_; ///< Data returned by server
- string test_data_; ///< Large string - here for convenience
- bool debug_; ///< true to enable debug output
- size_t tcp_send_size_; ///< Max size of TCP send
- uint8_t qid_0; ///< First octet of qid
- uint8_t qid_1; ///< Second octet of qid
-
- bool tcp_short_send_; ///< If set to true, we do not send
- /// all data in the tcp response
-
- /// \brief Constructor
- IOFetchTest() :
- service_(),
- expected_(IOFetch::NOTSET),
- run_(false),
- question_(Name("example.net"), RRClass::IN(), RRType::A()),
- result_buff_(new OutputBuffer(512)),
- msgbuf_(new OutputBuffer(512)),
- udp_fetch_(IOFetch::UDP, service_, question_, IOAddress(TEST_HOST),
- TEST_PORT, result_buff_, this, 100),
- tcp_fetch_(IOFetch::TCP, service_, question_, IOAddress(TEST_HOST),
- TEST_PORT, result_buff_, this, (16 * SEND_INTERVAL)),
- // Timeout interval chosen to ensure no timeout
- protocol_(IOFetch::TCP), // for initialization - will be changed
- cumulative_(0),
- timer_(service_.get_io_service()),
- receive_buffer_(),
- expected_buffer_(new OutputBuffer(512)),
- send_buffer_(),
- send_cumulative_(0),
- return_data_(""),
- test_data_(""),
- debug_(DEBUG),
- tcp_send_size_(0),
- qid_0(0),
- qid_1(0),
- tcp_short_send_(false)
- {
- // Construct the data buffer for question we expect to receive.
- Message msg(Message::RENDER);
- msg.setQid(0);
- msg.setOpcode(Opcode::QUERY());
- msg.setRcode(Rcode::NOERROR());
- msg.setHeaderFlag(Message::HEADERFLAG_RD);
- msg.addQuestion(question_);
- MessageRenderer renderer(*msgbuf_);
- msg.toWire(renderer);
- MessageRenderer renderer2(*expected_buffer_);
- msg.toWire(renderer2);
-
- // Initialize the test data to be returned: tests will return a
- // substring of this data. (It's convenient to have this as a member of
- // the class.)
- //
- // We could initialize the data with a single character, but as an added
- // check we'll make ssre that it has some structure.
-
- test_data_.clear();
- test_data_.reserve(MAX_SIZE);
- while (test_data_.size() < MAX_SIZE) {
- test_data_ += "A message to be returned to the client that has "
- "some sort of structure.";
- }
- }
-
- /// \brief UDP Response handler (the "remote UDP DNS server")
- ///
- /// When IOFetch is sending data, this response handler emulates the remote
- /// DNS server. It checks that the data sent by the IOFetch object is what
- /// was expected to have been sent, then sends back a known buffer of data.
- ///
- /// \param remote Endpoint to which to send the answer
- /// \param socket Socket to use to send the answer
- /// \param ec ASIO error code, completion code of asynchronous I/O issued
- /// by the "server" to receive data.
- /// \param bad_qid If set to true, the QID in the response will be mangled
- /// \param second_send If set to true, (and bad_qid is too), after the
- /// mangled qid response has been sent, a second packet will be
- /// sent with the correct QID.
- /// \param length Amount of data received.
- void udpReceiveHandler(udp::endpoint* remote, udp::socket* socket,
- error_code ec = error_code(), size_t length = 0,
- bool bad_qid = false, bool second_send = false) {
- if (debug_) {
- cout << "udpReceiveHandler(): error = " << ec.value() <<
- ", length = " << length << endl;
- }
-
- // The QID in the incoming data is random so set it to 0 for the
- // data comparison check. (It is set to 0 in the buffer containing
- // the expected data.)
- qid_0 = receive_buffer_[0];
- qid_1 = receive_buffer_[1];
- receive_buffer_[0] = receive_buffer_[1] = 0;
-
- // Check that length of the received data and the expected data are
- // identical, then check that the data is identical as well.
- EXPECT_EQ(msgbuf_->getLength(), length);
- EXPECT_TRUE(equal(receive_buffer_, (receive_buffer_ + length - 1),
- static_cast<const uint8_t*>(msgbuf_->getData())));
-
- // Return a message back to the IOFetch object.
- if (!bad_qid) {
- expected_buffer_->writeUint8At(qid_0, 0);
- expected_buffer_->writeUint8At(qid_1, 1);
- } else {
- expected_buffer_->writeUint8At(qid_0 + 1, 0);
- expected_buffer_->writeUint8At(qid_1 + 1, 1);
- }
- socket->send_to(asio::buffer(expected_buffer_->getData(), length), *remote);
-
- if (bad_qid && second_send) {
- expected_buffer_->writeUint8At(qid_0, 0);
- expected_buffer_->writeUint8At(qid_1, 1);
- socket->send_to(asio::buffer(expected_buffer_->getData(),
- expected_buffer_->getLength()), *remote);
- }
- if (debug_) {
- cout << "udpReceiveHandler(): returned " << expected_buffer_->getLength() <<
- " bytes to the client" << endl;
- }
- }
-
- /// \brief Completion Handler for accepting TCP data
- ///
- /// Called when the remote system connects to the "server". It issues
- /// an asynchronous read on the socket to read data.
- ///
- /// \param socket Socket on which data will be received
- /// \param ec Boost error code, value should be zero.
- void tcpAcceptHandler(tcp::socket* socket, error_code ec = error_code())
- {
- if (debug_) {
- cout << "tcpAcceptHandler(): error = " << ec.value() << endl;
- }
-
- // Expect that the accept completed without a problem.
- EXPECT_EQ(0, ec.value());
-
- // Work out the maximum size of data we can send over it when we
- // respond, then subtract 1kB or so for safety.
- tcp::socket::send_buffer_size send_size;
- socket->get_option(send_size);
- if (send_size.value() < (2 * 1024)) {
- FAIL() << "TCP send size is less than 2kB";
- } else {
- tcp_send_size_ = send_size.value() - 1024;
- if (debug_) {
- cout << "tcpacceptHandler(): will use send size = " << tcp_send_size_ << endl;
- }
- }
-
- // Initiate a read on the socket.
- cumulative_ = 0;
- socket->async_receive(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
- boost::bind(&IOFetchTest::tcpReceiveHandler, this, socket, _1, _2));
- }
-
- /// \brief Completion handler for receiving TCP data
- ///
- /// When IOFetch is sending data, this response handler emulates the remote
- /// DNS server. It that all the data sent by the IOFetch object has been
- /// received, issuing another read if not. If the data is complete, it is
- /// compared to what is expected and a reply sent back to the IOFetch.
- ///
- /// \param socket Socket to use to send the answer
- /// \param ec ASIO error code, completion code of asynchronous I/O issued
- /// by the "server" to receive data.
- /// \param length Amount of data received.
- void tcpReceiveHandler(tcp::socket* socket, error_code ec = error_code(),
- size_t length = 0)
- {
- if (debug_) {
- cout << "tcpReceiveHandler(): error = " << ec.value() <<
- ", length = " << length << endl;
- }
- // Expect that the receive completed without a problem.
- EXPECT_EQ(0, ec.value());
-
- // If we haven't received all the data, issue another read.
- cumulative_ += length;
- bool complete = false;
- if (cumulative_ > 2) {
- uint16_t dns_length = readUint16(receive_buffer_);
- complete = ((dns_length + 2) == cumulative_);
- }
-
- if (!complete) {
- socket->async_receive(asio::buffer((receive_buffer_ + cumulative_),
- (sizeof(receive_buffer_) - cumulative_)),
- boost::bind(&IOFetchTest::tcpReceiveHandler, this, socket, _1, _2));
- return;
- }
-
- // Check that length of the DNS message received is that expected, then
- // compare buffers, zeroing the QID in the received buffer to match
- // that set in our expected question. Note that due to the length
- // field the QID in the received buffer is in the third and fourth
- // bytes.
- EXPECT_EQ(msgbuf_->getLength() + 2, cumulative_);
- qid_0 = receive_buffer_[2];
- qid_1 = receive_buffer_[3];
-
- receive_buffer_[2] = receive_buffer_[3] = 0;
- EXPECT_TRUE(equal((receive_buffer_ + 2), (receive_buffer_ + cumulative_ - 2),
- static_cast<const uint8_t*>(msgbuf_->getData())));
-
- // ... and return a message back. This has to be preceded by a two-byte
- // count field.
-
- send_buffer_.clear();
- send_buffer_.push_back(0);
- send_buffer_.push_back(0);
- writeUint16(return_data_.size(), &send_buffer_[0]);
- copy(return_data_.begin(), return_data_.end(), back_inserter(send_buffer_));
- if (return_data_.size() >= 2) {
- send_buffer_[2] = qid_0;
- send_buffer_[3] = qid_1;
- }
- // Send the data. This is done in multiple writes with a delay between
- // each to check that the reassembly of TCP packets from fragments works.
- send_cumulative_ = 0;
- tcpSendData(socket);
- }
-
- /// \brief Sent Data Over TCP
- ///
- /// Send the TCP data back to the IOFetch object. The data is sent in
- /// three chunks - two of 16 bytes and the remainder, with a 250ms gap
- /// between each. (Amounts of data smaller than one 32 bytes are sent in
- /// one or two packets.)
- ///
- /// \param socket Socket over which send should take place
- void tcpSendData(tcp::socket* socket) {
- if (debug_) {
- cout << "tcpSendData()" << endl;
- }
-
- // Decide what to send based on the cumulative count. At most we'll do
- // two chunks of 16 bytes (with a 250ms gap between) and then the
- // remainder.
- uint8_t* send_ptr = &send_buffer_[send_cumulative_];
- // Pointer to data to send
- size_t amount = 16; // Amount of data to send
- if (send_cumulative_ < (2 * amount)) {
-
- // First or second time through, send at most 16 bytes
- amount = min(amount, (send_buffer_.size() - send_cumulative_));
-
- } else {
-
- // For all subsequent times, send the remainder, maximised to
- // whatever we have chosen for the maximum send size.
- amount = min(tcp_send_size_,
- (send_buffer_.size() - send_cumulative_));
- }
-
- // This is for the short send test; reduce the actual amount of
- // data we send
- if (tcp_short_send_) {
- if (debug_) {
- cout << "tcpSendData(): sending incomplete data (" <<
- (amount - 1) << " of " << amount << " bytes)" <<
- endl;
- }
- --amount;
- } else {
- if (debug_) {
- cout << "tcpSendData(): sending " << amount << " bytes" << endl;
- }
- }
-
- // ... and send it. The amount sent is also passed as the first
- // argument of the send callback, as a check.
- socket->async_send(asio::buffer(send_ptr, amount),
- boost::bind(&IOFetchTest::tcpSendHandler, this,
- amount, socket, _1, _2));
- }
-
- /// \brief Completion Handler for Sending TCP data
- ///
- /// Called when the asynchronous send of data back to the IOFetch object
- /// by the TCP "server" in this class has completed. (This send has to
- /// be asynchronous because control needs to return to the caller in order
- /// for the IOService "run()" method to be called to run the handlers.)
- ///
- /// If not all the data has been sent, a short delay is instigated (during
- /// which control returns to the IOService). This should force the queued
- /// data to actually be sent and the IOFetch receive handler to be triggered.
- /// In this way, the ability of IOFetch to handle fragmented TCP packets
- /// should be checked.
- ///
- /// \param expected Number of bytes that were expected to have been sent.
- /// \param socket Socket over which the send took place. Only used to
- /// pass back to the send method.
- /// \param ec Boost error code, value should be zero.
- /// \param length Number of bytes sent.
- void tcpSendHandler(size_t expected, tcp::socket* socket,
- error_code ec = error_code(), size_t length = 0)
- {
- if (debug_) {
- cout << "tcpSendHandler(): error = " << ec.value() <<
- ", length = " << length << endl;
- }
-
- EXPECT_EQ(0, ec.value()); // Expect no error
- EXPECT_EQ(expected, length); // And that amount sent is as expected
-
- // Do we need to send more?
- send_cumulative_ += length;
- if (send_cumulative_ < send_buffer_.size()) {
-
- // Yes - set up a timer: the callback handler for the timer is
- // tcpSendData, which will then send the next chunk. We pass the
- // socket over which data should be sent as an argument to that
- // function.
- timer_.expires_from_now(boost::posix_time::milliseconds(SEND_INTERVAL));
- timer_.async_wait(boost::bind(&IOFetchTest::tcpSendData, this,
- socket));
- }
- }
-
- /// \brief Fetch completion callback
- ///
- /// This is the callback's operator() method which is called when the fetch
- /// is complete. It checks that the data received is the wire format of the
- /// data sent back by the server.
- ///
- /// \param result Result indicated by the callback
- void operator()(IOFetch::Result result) {
- if (debug_) {
- cout << "operator()(): result = " << result << endl;
- }
-
- EXPECT_EQ(expected_, result); // Check correct result returned
- EXPECT_FALSE(run_); // Check it is run only once
- run_ = true; // Note success
-
- // If the expected result for SUCCESS, then this should have been called
- // when one of the "servers" in this class has sent back return_data_.
- // Check the data is as expected/
- if (expected_ == IOFetch::SUCCESS) {
- // In the case of UDP, we actually send back a real looking packet
- // in the case of TCP, we send back a 'random' string
- if (protocol_ == IOFetch::UDP) {
- EXPECT_EQ(expected_buffer_->getLength(), result_buff_->getLength());
- EXPECT_EQ(0, memcmp(expected_buffer_->getData(), result_buff_->getData(),
- expected_buffer_->getLength()));
- } else {
- EXPECT_EQ(return_data_.size(), result_buff_->getLength());
- // Overwrite the random qid with our own data for the
- // comparison to succeed
- if (result_buff_->getLength() >= 2) {
- result_buff_->writeUint8At(return_data_[0], 0);
- result_buff_->writeUint8At(return_data_[1], 1);
- }
- const uint8_t* start = static_cast<const uint8_t*>(result_buff_->getData());
- EXPECT_TRUE(equal(return_data_.begin(), return_data_.end(), start));
- }
- }
-
- // ... and cause the run loop to exit.
- service_.stop();
- }
-
- // The next set of methods are the tests themselves. A number of the TCP
- // and UDP tests are very similar.
-
- /// \brief Check for stop()
- ///
- /// Test that when we run the query and stop it after it was run, it returns
- /// "stopped" correctly. (That is why stop() is posted to the service_ as
- /// well instead of calling it.)
- ///
- /// \param protocol Test protocol
- /// \param fetch Fetch object being tested
- void stopTest(IOFetch::Protocol protocol, IOFetch& fetch) {
- protocol_ = protocol;
- expected_ = IOFetch::STOPPED;
-
- // Post the query
- service_.get_io_service().post(fetch);
-
- // Post query_.stop() (yes, the boost::bind thing is just
- // query_.stop()).
- service_.get_io_service().post(
- boost::bind(&IOFetch::stop, fetch, IOFetch::STOPPED));
-
- // Run both of them. run() returns when everything in the I/O service
- // queue has completed.
- service_.run();
- EXPECT_TRUE(run_);
- }
-
- /// \brief Premature stop test
- ///
- /// Test that when we queue the query to service_ and call stop() before it
- /// gets executed, it acts sanely as well (eg. has the same result as
- /// running stop() after - calls the callback).
- ///
- /// \param protocol Test protocol
- /// \param fetch Fetch object being tested
- void prematureStopTest(IOFetch::Protocol protocol, IOFetch& fetch) {
- protocol_ = protocol;
- expected_ = IOFetch::STOPPED;
-
- // Stop before it is started
- fetch.stop();
- service_.get_io_service().post(fetch);
-
- service_.run();
- EXPECT_TRUE(run_);
- }
-
- /// \brief Timeout test
- ///
- /// Test that fetch times out when no answer arrives.
- ///
- /// \param protocol Test protocol
- /// \param fetch Fetch object being tested
- void timeoutTest(IOFetch::Protocol protocol, IOFetch& fetch) {
- protocol_ = protocol;
- expected_ = IOFetch::TIME_OUT;
-
- service_.get_io_service().post(fetch);
- service_.run();
- EXPECT_TRUE(run_);
- }
-
- /// \brief Send/Receive Test
- ///
- /// Send a query to the server then receives a response.
- ///
- /// \param Test data to return to client
- /// \param short_send If true, do not send all data
- /// (should result in timeout)
- void tcpSendReturnTest(const std::string& return_data, bool short_send = false) {
- if (debug_) {
- cout << "tcpSendReturnTest(): data size = " << return_data.size() << endl;
- }
- return_data_ = return_data;
- protocol_ = IOFetch::TCP;
- if (short_send) {
- tcp_short_send_ = true;
- expected_ = IOFetch::TIME_OUT;
- } else {
- expected_ = IOFetch::SUCCESS;
- }
-
- // Socket into which the connection will be accepted.
- tcp::socket socket(service_.get_io_service());
-
- // Acceptor object - called when the connection is made, the handler
- // will initiate a read on the socket.
- tcp::acceptor acceptor(service_.get_io_service(),
- tcp::endpoint(tcp::v4(), TEST_PORT));
- acceptor.async_accept(socket,
- boost::bind(&IOFetchTest::tcpAcceptHandler, this, &socket, _1));
-
- // Post the TCP fetch object to send the query and receive the response.
- service_.get_io_service().post(tcp_fetch_);
-
- // ... and execute all the callbacks. This exits when the fetch
- // completes.
- service_.run();
- EXPECT_TRUE(run_); // Make sure the callback did execute
-
- // Tidy up
- socket.close();
- }
-
- /// Perform a send/receive test over UDP
- ///
- /// \param bad_qid If true, do the test where the QID is mangled
- /// in the response
- /// \param second_send If true, do the test where the QID is
- /// mangled in the response, but a second
- /// (correct) packet is used
- void udpSendReturnTest(bool bad_qid, bool second_send) {
- protocol_ = IOFetch::UDP;
-
- // Set up the server.
- udp::socket socket(service_.get_io_service(), udp::v4());
- socket.set_option(socket_base::reuse_address(true));
- socket.bind(udp::endpoint(TEST_HOST, TEST_PORT));
- return_data_ = "Message returned to the client";
-
- udp::endpoint remote;
- socket.async_receive_from(asio::buffer(receive_buffer_, sizeof(receive_buffer_)),
- remote,
- boost::bind(&IOFetchTest::udpReceiveHandler, this, &remote, &socket,
- _1, _2, bad_qid, second_send));
- service_.get_io_service().post(udp_fetch_);
- if (debug_) {
- cout << "udpSendReceive: async_receive_from posted, waiting for callback" <<
- endl;
- }
- service_.run();
-
- socket.close();
-
- EXPECT_TRUE(run_);;
- }
-};
-
-// Check the protocol
-TEST_F(IOFetchTest, Protocol) {
- EXPECT_EQ(IOFetch::UDP, udp_fetch_.getProtocol());
- EXPECT_EQ(IOFetch::TCP, tcp_fetch_.getProtocol());
-}
-
-// UDP Stop test - see IOFetchTest::stopTest() header.
-TEST_F(IOFetchTest, UdpStop) {
- stopTest(IOFetch::UDP, udp_fetch_);
-}
-
-// UDP premature stop test - see IOFetchTest::prematureStopTest() header.
-TEST_F(IOFetchTest, UdpPrematureStop) {
- prematureStopTest(IOFetch::UDP, udp_fetch_);
-}
-
-// UDP premature stop test - see IOFetchTest::timeoutTest() header.
-TEST_F(IOFetchTest, UdpTimeout) {
- timeoutTest(IOFetch::UDP, udp_fetch_);
-}
-
-// UDP SendReceive test. Set up a UDP server then ports a UDP fetch object.
-// This will send question_ to the server and receive the answer back from it.
-TEST_F(IOFetchTest, UdpSendReceive) {
- expected_ = IOFetch::SUCCESS;
-
- udpSendReturnTest(false, false);
-
- EXPECT_TRUE(run_);;
-}
-
-TEST_F(IOFetchTest, UdpSendReceiveBadQid) {
- expected_ = IOFetch::TIME_OUT;
-
- udpSendReturnTest(true, false);
-
- EXPECT_TRUE(run_);;
-}
-
-TEST_F(IOFetchTest, UdpSendReceiveBadQidResend) {
- expected_ = IOFetch::SUCCESS;
-
- udpSendReturnTest(true, true);
-
- EXPECT_TRUE(run_);;
-}
-
-// Do the same tests for TCP transport
-
-TEST_F(IOFetchTest, TcpStop) {
- stopTest(IOFetch::TCP, tcp_fetch_);
-}
-
-TEST_F(IOFetchTest, TcpPrematureStop) {
- prematureStopTest(IOFetch::TCP, tcp_fetch_);
-}
-
-TEST_F(IOFetchTest, TcpTimeout) {
- timeoutTest(IOFetch::TCP, tcp_fetch_);
-}
-
-// Test with values at or near 2, then at or near the chunk size (16 and 32
-// bytes, the sizes of the first two packets) then up to 65535. These are done
-// in separate tests because in practice a new IOFetch is created for each
-// query/response exchange and we don't want to confuse matters in the test
-// by running the test with an IOFetch that has already done one exchange.
-//
-// Don't do 0 or 1; the server would not accept the packet
-// (since the length is too short to check the qid)
-TEST_F(IOFetchTest, TcpSendReceive2) {
- tcpSendReturnTest(test_data_.substr(0, 2));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive3) {
- tcpSendReturnTest(test_data_.substr(0, 3));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive15) {
- tcpSendReturnTest(test_data_.substr(0, 15));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive16) {
- tcpSendReturnTest(test_data_.substr(0, 16));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive17) {
- tcpSendReturnTest(test_data_.substr(0, 17));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive31) {
- tcpSendReturnTest(test_data_.substr(0, 31));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive32) {
- tcpSendReturnTest(test_data_.substr(0, 32));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive33) {
- tcpSendReturnTest(test_data_.substr(0, 33));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive4096) {
- tcpSendReturnTest(test_data_.substr(0, 4096));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive8192) {
- tcpSendReturnTest(test_data_.substr(0, 8192));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive16384) {
- tcpSendReturnTest(test_data_.substr(0, 16384));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive32768) {
- tcpSendReturnTest(test_data_.substr(0, 32768));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive65535) {
- tcpSendReturnTest(test_data_.substr(0, 65535));
-}
-
-TEST_F(IOFetchTest, TcpSendReceive2ShortSend) {
- tcpSendReturnTest(test_data_.substr(0, 2), true);
-}
-
-TEST_F(IOFetchTest, TcpSendReceive15ShortSend) {
- tcpSendReturnTest(test_data_.substr(0, 15), true);
-}
-
-TEST_F(IOFetchTest, TcpSendReceive8192ShortSend) {
- tcpSendReturnTest(test_data_.substr(0, 8192), true);
-}
-
-
-} // namespace asiolink
diff --git a/src/lib/asiolink/tests/io_service_unittest.cc b/src/lib/asiolink/tests/io_service_unittest.cc
deleted file mode 100644
index 779d03e..0000000
--- a/src/lib/asiolink/tests/io_service_unittest.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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.
-
-#include <config.h>
-#include <gtest/gtest.h>
-
-#include <asio.hpp>
-#include <asiolink/asiolink.h>
-
-using namespace asiolink;
-
-const char* const TEST_SERVER_PORT = "53535";
-const char* const TEST_CLIENT_PORT = "53536";
-const char* const TEST_IPV6_ADDR = "::1";
-const char* const TEST_IPV4_ADDR = "127.0.0.1";
-
-TEST(IOServiceTest, badPort) {
- IOService io_service;
- EXPECT_THROW(DNSService(io_service, *"65536", true, false, NULL, NULL, NULL), IOError);
- EXPECT_THROW(DNSService(io_service, *"53210.0", true, false, NULL, NULL, NULL), IOError);
- EXPECT_THROW(DNSService(io_service, *"-1", true, false, NULL, NULL, NULL), IOError);
- EXPECT_THROW(DNSService(io_service, *"domain", true, false, NULL, NULL, NULL), IOError);
-}
-
-TEST(IOServiceTest, badAddress) {
- IOService io_service;
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"localhost", NULL, NULL, NULL), IOError);
-}
-
-TEST(IOServiceTest, unavailableAddress) {
- IOService io_service;
- // These addresses should generally be unavailable as a valid local
- // address, although there's no guarantee in theory.
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.0", NULL, NULL, NULL), IOError);
-
- // Some OSes would simply reject binding attempt for an AF_INET6 socket
- // to an IPv4-mapped IPv6 address. Even if those that allow it, since
- // the corresponding IPv4 address is the same as the one used in the
- // AF_INET socket case above, it should at least show the same result
- // as the previous one.
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:192.0.2.0", NULL, NULL, NULL), IOError);
-}
-
-TEST(IOServiceTest, duplicateBind_v6) {
- // In each sub test case, second attempt should fail due to duplicate bind
- IOService io_service;
-
- // IPv6, "any" address
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL);
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL), IOError);
- delete dns_service;
-
-}
-
-TEST(IOServiceTest, duplicateBind_v6_address) {
- // In each sub test case, second attempt should fail due to duplicate bind
- IOService io_service;
-
- // IPv6, specific address
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
- delete dns_service;
-
-}
-
-TEST(IOServiceTest, duplicateBind_v4) {
- // In each sub test case, second attempt should fail due to duplicate bind
- IOService io_service;
-
- // IPv4, "any" address
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL);
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL), IOError);
- delete dns_service;
-
-}
-
-TEST(IOServiceTest, duplicateBind_v4_address) {
- // In each sub test case, second attempt should fail due to duplicate bind
- IOService io_service;
-
- // IPv4, specific address
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
- delete dns_service;
-}
-
-// Disabled because IPv4-mapped addresses don't seem to be working with
-// the IOService constructor
-TEST(IOServiceTest, DISABLED_IPv4MappedDuplicateBind) {
- IOService io_service;
- // Duplicate bind on IPv4-mapped IPv6 address
- DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL);
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL), IOError);
- delete dns_service;
-
- // XXX:
- // Currently, this throws an "invalid argument" exception. I have
- // not been able to get IPv4-mapped addresses to work.
- dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL);
- EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL), IOError);
- delete dns_service;
-}
-
diff --git a/src/lib/asiolink/tests/io_socket_unittest.cc b/src/lib/asiolink/tests/io_socket_unittest.cc
index 6538550..15afc17 100644
--- a/src/lib/asiolink/tests/io_socket_unittest.cc
+++ b/src/lib/asiolink/tests/io_socket_unittest.cc
@@ -20,7 +20,7 @@
#include <asio.hpp>
#include <asiolink/io_socket.h>
-using namespace asiolink;
+using namespace isc::asiolink;
TEST(IOSocketTest, dummySockets) {
EXPECT_EQ(IPPROTO_UDP, IOSocket::getDummyUDPSocket().getProtocol());
diff --git a/src/lib/asiolink/tests/qid_gen_unittest.cc b/src/lib/asiolink/tests/qid_gen_unittest.cc
deleted file mode 100644
index 3ad8a03..0000000
--- a/src/lib/asiolink/tests/qid_gen_unittest.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.
-
-// 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.
-
-
-/// \brief Test of QidGenerator
-///
-
-#include <gtest/gtest.h>
-
-#include <asiolink/qid_gen.h>
-#include <dns/message.h>
-
-// Tests the operation of the Qid generator
-
-// Check that getInstance returns a singleton
-TEST(QidGenerator, singleton) {
- asiolink::QidGenerator& g1 = asiolink::QidGenerator::getInstance();
- asiolink::QidGenerator& g2 = asiolink::QidGenerator::getInstance();
-
- EXPECT_TRUE(&g1 == &g2);
-}
-
-TEST(QidGenerator, generate) {
- // We'll assume that boost's generator is 'good enough', and won't
- // do full statistical checking here. Let's just call it the xkcd
- // test (http://xkcd.com/221/), and check if three consecutive
- // generates are not all the same.
- isc::dns::qid_t one, two, three;
- asiolink::QidGenerator& gen = asiolink::QidGenerator::getInstance();
- one = gen.generateQid();
- two = gen.generateQid();
- three = gen.generateQid();
- ASSERT_FALSE((one == two) && (one == three));
-}
diff --git a/src/lib/asiolink/tests/tcp_endpoint_unittest.cc b/src/lib/asiolink/tests/tcp_endpoint_unittest.cc
index 3787e1c..6988082 100644
--- a/src/lib/asiolink/tests/tcp_endpoint_unittest.cc
+++ b/src/lib/asiolink/tests/tcp_endpoint_unittest.cc
@@ -22,7 +22,7 @@
#include <asiolink/io_address.h>
#include <asiolink/tcp_endpoint.h>
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace std;
// This test checks that the endpoint can manage its own internal
diff --git a/src/lib/asiolink/tests/tcp_socket_unittest.cc b/src/lib/asiolink/tests/tcp_socket_unittest.cc
index f0a45ee..e2d2365 100644
--- a/src/lib/asiolink/tests/tcp_socket_unittest.cc
+++ b/src/lib/asiolink/tests/tcp_socket_unittest.cc
@@ -46,7 +46,7 @@
using namespace asio;
using namespace asio::ip;
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace isc::dns;
using namespace std;
diff --git a/src/lib/asiolink/tests/udp_endpoint_unittest.cc b/src/lib/asiolink/tests/udp_endpoint_unittest.cc
index 18135ec..03de6b8 100644
--- a/src/lib/asiolink/tests/udp_endpoint_unittest.cc
+++ b/src/lib/asiolink/tests/udp_endpoint_unittest.cc
@@ -22,7 +22,7 @@
#include <asiolink/io_address.h>
#include <asiolink/udp_endpoint.h>
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace std;
// This test checks that the endpoint can manage its own internal
diff --git a/src/lib/asiolink/tests/udp_socket_unittest.cc b/src/lib/asiolink/tests/udp_socket_unittest.cc
index 8563d22..a98ed30 100644
--- a/src/lib/asiolink/tests/udp_socket_unittest.cc
+++ b/src/lib/asiolink/tests/udp_socket_unittest.cc
@@ -45,7 +45,7 @@
#include <asiolink/udp_socket.h>
using namespace asio;
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace isc::dns;
using namespace std;
diff --git a/src/lib/asiolink/udp_endpoint.h b/src/lib/asiolink/udp_endpoint.h
index 99dc27f..5c8a1fe 100644
--- a/src/lib/asiolink/udp_endpoint.h
+++ b/src/lib/asiolink/udp_endpoint.h
@@ -21,6 +21,7 @@
#include <asiolink/io_endpoint.h>
+namespace isc {
namespace asiolink {
/// \brief The \c UDPEndpoint class is a concrete derived class of
@@ -109,5 +110,6 @@ private:
asio::ip::udp::endpoint& asio_endpoint_;
};
-} // namespace asiolink
+} // namespace asiolink
+} // namespace isc
#endif // __UDP_ENDPOINT_H
diff --git a/src/lib/asiolink/udp_server.cc b/src/lib/asiolink/udp_server.cc
deleted file mode 100644
index 5b48f28..0000000
--- a/src/lib/asiolink/udp_server.cc
+++ /dev/null
@@ -1,321 +0,0 @@
-// 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.
-
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <unistd.h> // for some IPC/network system calls
-#include <errno.h>
-
-#include <boost/shared_array.hpp>
-
-#include <config.h>
-
-#include <log/dummylog.h>
-
-#include <asio.hpp>
-#include <asio/error.hpp>
-#include <asiolink/dummy_io_cb.h>
-#include <asiolink/udp_endpoint.h>
-#include <asiolink/udp_server.h>
-#include <asiolink/udp_socket.h>
-
-#include <dns/opcode.h>
-
-using namespace asio;
-using asio::ip::udp;
-using isc::log::dlog;
-
-using namespace std;
-using namespace isc::dns;
-
-namespace asiolink {
-
-/*
- * Some of the member variables here are shared_ptrs and some are
- * auto_ptrs. There will be one instance of Data for the lifetime
- * of packet. The variables that are state only for a single packet
- * use auto_ptr, as it is more lightweight. In the case of shared
- * configuration (eg. the callbacks, socket), we use shared_ptrs.
- */
-struct UDPServer::Data {
- /*
- * Constructor from parameters passed to UDPServer constructor.
- * This instance will not be used to retrieve and answer the actual
- * query, it will only hold parameters until we wait for the
- * first packet. But we do initialize the socket in here.
- */
- Data(io_service& io_service, const ip::address& addr, const uint16_t port,
- SimpleCallback* checkin, DNSLookup* lookup, DNSAnswer* answer) :
- io_(io_service), done_(false),
- checkin_callback_(checkin),lookup_callback_(lookup),
- answer_callback_(answer)
- {
- // We must use different instantiations for v4 and v6;
- // otherwise ASIO will bind to both
- udp proto = addr.is_v4() ? udp::v4() : udp::v6();
- socket_.reset(new udp::socket(io_service, proto));
- socket_->set_option(socket_base::reuse_address(true));
- if (addr.is_v6()) {
- socket_->set_option(asio::ip::v6_only(true));
- }
- socket_->bind(udp::endpoint(addr, port));
- }
-
- /*
- * Copy constructor. Default one would probably do, but it is unnecessary
- * to copy many of the member variables every time we fork to handle
- * another packet.
- *
- * We also allocate data for receiving the packet here.
- */
- Data(const Data& other) :
- io_(other.io_), socket_(other.socket_), done_(false),
- checkin_callback_(other.checkin_callback_),
- lookup_callback_(other.lookup_callback_),
- answer_callback_(other.answer_callback_)
- {
- // Instantiate the data buffer and endpoint that will
- // be used by the asynchronous receive call.
- data_.reset(new char[MAX_LENGTH]);
- sender_.reset(new udp::endpoint());
- }
-
- // The ASIO service object
- asio::io_service& io_;
-
- // Class member variables which are dynamic, and changes to which
- // need to accessible from both sides of a coroutine fork or from
- // outside of the coroutine (i.e., from an asynchronous I/O call),
- // should be declared here as pointers and allocated in the
- // constructor or in the coroutine. This allows state information
- // to persist when an individual copy of the coroutine falls out
- // scope while waiting for an event, *so long as* there is another
- // object that is referencing the same data. As a side-benefit, using
- // pointers also reduces copy overhead for coroutine objects.
- //
- // Note: Currently these objects are allocated by "new" in the
- // constructor, or in the function operator while processing a query.
- // Repeated allocations from the heap for every incoming query is
- // clearly a performance issue; this must be optimized in the future.
- // The plan is to have a structure pre-allocate several "Data"
- // objects which can be pulled off a free list and placed on an in-use
- // list whenever a query comes in. This will serve the dual purpose
- // of improving performance and guaranteeing that state information
- // will *not* be destroyed when any one instance of the coroutine
- // falls out of scope while waiting for an event.
- //
- // Socket used to for listen for queries. Created in the
- // constructor and stored in a shared_ptr because socket objects
- // are not copyable.
- boost::shared_ptr<asio::ip::udp::socket> socket_;
-
- // The ASIO-internal endpoint object representing the client
- std::auto_ptr<asio::ip::udp::endpoint> sender_;
-
- // \c IOMessage and \c Message objects to be passed to the
- // DNS lookup and answer providers
- std::auto_ptr<asiolink::IOMessage> io_message_;
-
- // The original query as sent by the client
- isc::dns::MessagePtr query_message_;
-
- // The response message we are building
- isc::dns::MessagePtr answer_message_;
-
- // The buffer into which the response is written
- isc::dns::OutputBufferPtr respbuf_;
-
- // The buffer into which the query packet is written
- boost::shared_array<char> data_;
-
- // State information that is entirely internal to a given instance
- // of the coroutine can be declared here.
- size_t bytes_;
- bool done_;
-
-
- // Callback functions provided by the caller
- const SimpleCallback* checkin_callback_;
- const DNSLookup* lookup_callback_;
- const DNSAnswer* answer_callback_;
-
- std::auto_ptr<IOEndpoint> peer_;
- std::auto_ptr<IOSocket> iosock_;
-};
-
-/// The following functions implement the \c UDPServer class.
-///
-/// The constructor. It just creates new internal state object
-/// and lets it handle the initialization.
-UDPServer::UDPServer(io_service& io_service, const ip::address& addr,
- const uint16_t port, SimpleCallback* checkin, DNSLookup* lookup,
- DNSAnswer* answer) :
- data_(new Data(io_service, addr, port, checkin, lookup, answer))
-{ }
-
-/// The function operator is implemented with the "stackless coroutine"
-/// pattern; see internal/coroutine.h for details.
-void
-UDPServer::operator()(error_code ec, size_t length) {
- /// Because the coroutine reentry block is implemented as
- /// a switch statement, inline variable declarations are not
- /// permitted. Certain variables used below can be declared here.
-
- CORO_REENTER (this) {
- do {
- /*
- * This is preparation for receiving a packet. We get a new
- * state object for the lifetime of the next packet to come.
- * It allocates the buffers to receive data into.
- */
- data_.reset(new Data(*data_));
-
- do {
- // Begin an asynchronous receive, then yield.
- // When the receive event is posted, the coroutine
- // will resume immediately after this point.
- CORO_YIELD data_->socket_->async_receive_from(
- buffer(data_->data_.get(), MAX_LENGTH), *data_->sender_,
- *this);
-
- // Abort on fatal errors
- // TODO: add log
- if (ec) {
- using namespace asio::error;
- if (ec.value() != would_block && ec.value() != try_again &&
- ec.value() != interrupted) {
- return;
- }
- }
-
- } while (ec || length == 0);
-
- data_->bytes_ = length;
-
- /*
- * We fork the coroutine now. One (the child) will keep
- * the current state and handle the packet, then die and
- * drop ownership of the state. The other (parent) will just
- * go into the loop again and replace the current state with
- * a new one for a new object.
- *
- * Actually, both of the coroutines will be a copy of this
- * one, but that's just internal implementation detail.
- */
- CORO_FORK data_->io_.post(UDPServer(*this));
- } while (is_parent());
-
- // Create an \c IOMessage object to store the query.
- //
- // (XXX: It would be good to write a factory function
- // that would quickly generate an IOMessage object without
- // all these calls to "new".)
- data_->peer_.reset(new UDPEndpoint(*data_->sender_));
-
- // The UDP socket class has been extended with asynchronous functions
- // and takes as a template parameter a completion callback class. As
- // UDPServer does not use these extended functions (only those defined
- // in the IOSocket base class) - but needs a UDPSocket to get hold of
- // the underlying Boost UDP socket - DummyIOCallback is used. This
- // provides the appropriate operator() but is otherwise functionless.
- data_->iosock_.reset(
- new UDPSocket<DummyIOCallback>(*data_->socket_));
-
- data_->io_message_.reset(new IOMessage(data_->data_.get(),
- data_->bytes_, *data_->iosock_, *data_->peer_));
-
- // Perform any necessary operations prior to processing an incoming
- // query (e.g., checking for queued configuration messages).
- //
- // (XXX: it may be a performance issue to check in for every single
- // incoming query; we may wish to throttle this in the future.)
- if (data_->checkin_callback_ != NULL) {
- (*data_->checkin_callback_)(*data_->io_message_);
- }
-
- // If we don't have a DNS Lookup provider, there's no point in
- // continuing; we exit the coroutine permanently.
- if (data_->lookup_callback_ == NULL) {
- CORO_YIELD return;
- }
-
- // Instantiate objects that will be needed by the
- // asynchronous DNS lookup and/or by the send call.
- data_->respbuf_.reset(new OutputBuffer(0));
- data_->query_message_.reset(new Message(Message::PARSE));
- data_->answer_message_.reset(new Message(Message::RENDER));
-
- // Schedule a DNS lookup, and yield. When the lookup is
- // finished, the coroutine will resume immediately after
- // this point.
- CORO_YIELD data_->io_.post(AsyncLookup<UDPServer>(*this));
-
- // The 'done_' flag indicates whether we have an answer
- // to send back. If not, exit the coroutine permanently.
- if (!data_->done_) {
- CORO_YIELD return;
- }
-
- // Call the DNS answer provider to render the answer into
- // wire format
- (*data_->answer_callback_)(*data_->io_message_, data_->query_message_,
- data_->answer_message_, data_->respbuf_);
-
- // Begin an asynchronous send, and then yield. When the
- // send completes, we will resume immediately after this point
- // (though we have nothing further to do, so the coroutine
- // will simply exit at that time).
- CORO_YIELD data_->socket_->async_send_to(
- buffer(data_->respbuf_->getData(), data_->respbuf_->getLength()),
- *data_->sender_, *this);
- }
-}
-
-/// Call the DNS lookup provider. (Expected to be called by the
-/// AsyncLookup<UDPServer> handler.)
-void
-UDPServer::asyncLookup() {
- (*data_->lookup_callback_)(*data_->io_message_,
- data_->query_message_, data_->answer_message_, data_->respbuf_, this);
-}
-
-/// Stop the UDPServer
-void
-UDPServer::stop() {
- /// Using close instead of cancel, because cancel
- /// will only cancel the asynchornized event already submitted
- /// to io service, the events post to io service after
- /// cancel still can be scheduled by io service, if
- /// the socket is cloesed, all the asynchronized event
- /// for it won't be scheduled by io service not matter it is
- /// submit to io serice before or after close call. And we will
- //. get bad_descriptor error
- data_->socket_->close();
-}
-
-/// Post this coroutine on the ASIO service queue so that it will
-/// resume processing where it left off. The 'done' parameter indicates
-/// whether there is an answer to return to the client.
-void
-UDPServer::resume(const bool done) {
- data_->done_ = done;
- data_->io_.post(*this);
-}
-
-bool
-UDPServer::hasAnswer() {
- return (data_->done_);
-}
-
-} // namespace asiolink
diff --git a/src/lib/asiolink/udp_server.h b/src/lib/asiolink/udp_server.h
deleted file mode 100644
index 1d37471..0000000
--- a/src/lib/asiolink/udp_server.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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 __UDP_SERVER_H
-#define __UDP_SERVER_H 1
-
-#ifndef ASIO_HPP
-#error "asio.hpp must be included before including this, see asiolink.h as to why"
-#endif
-
-#include <asiolink/dns_server.h>
-#include <asiolink/simple_callback.h>
-#include <asiolink/dns_lookup.h>
-#include <asiolink/dns_answer.h>
-
-#include <coroutine.h>
-
-namespace asiolink {
-
-//
-// Asynchronous UDP server coroutine
-//
-///
-/// \brief This class implements the coroutine to handle UDP
-/// DNS query event. As such, it is both a \c DNSServer and
-/// a \c coroutine
-///
-class UDPServer : public virtual DNSServer, public virtual coroutine {
-public:
- /// \brief Constructor
- /// \param io_service the asio::io_service to work with
- /// \param addr the IP address to listen for queries on
- /// \param port the port to listen for queries on
- /// \param checkin the callbackprovider for non-DNS events
- /// \param lookup the callbackprovider for DNS lookup events
- /// \param answer the callbackprovider for DNS answer events
- explicit UDPServer(asio::io_service& io_service,
- const asio::ip::address& addr, const uint16_t port,
- SimpleCallback* checkin = NULL,
- DNSLookup* lookup = NULL,
- DNSAnswer* answer = NULL);
-
- /// \brief The function operator
- void operator()(asio::error_code ec = asio::error_code(),
- size_t length = 0);
-
- /// \brief Calls the lookup callback
- void asyncLookup();
-
- /// \brief Stop the running server
- /// \note once the server stopped, it can't restart
- void stop();
-
- /// \brief Resume operation
- ///
- /// \param done Set this to true if the lookup action is done and
- /// we have an answer
- void resume(const bool done);
-
- /// \brief Check if we have an answer
- ///
- /// \return true if we have an answer
- bool hasAnswer();
-
- /// \brief Returns the coroutine state value
- ///
- /// \return the coroutine state value
- int value() { return (get_value()); }
-
- /// \brief Clones the object
- ///
- /// \return a newly allocated copy of this object
- DNSServer* clone() {
- UDPServer* s = new UDPServer(*this);
- return (s);
- }
-
-private:
- enum { MAX_LENGTH = 4096 };
-
- /**
- * \brief Internal state and data.
- *
- * We use the pimple design pattern, but not because we need to hide
- * internal data. This class and whole header is for private use anyway.
- * It turned out that UDPServer is copied a lot, because it is a coroutine.
- * This way the overhead of copying is lower, we copy only one shared
- * pointer instead of about 10 of them.
- */
- class Data;
- boost::shared_ptr<Data> data_;
-};
-
-} // namespace asiolink
-#endif // __UDP_SERVER_H
diff --git a/src/lib/asiolink/udp_socket.h b/src/lib/asiolink/udp_socket.h
index 35fc7b1..d26d04c 100644
--- a/src/lib/asiolink/udp_socket.h
+++ b/src/lib/asiolink/udp_socket.h
@@ -33,6 +33,7 @@
#include <asiolink/io_service.h>
#include <asiolink/udp_endpoint.h>
+namespace isc {
namespace asiolink {
/// \brief The \c UDPSocket class is a concrete derived class of \c IOAsioSocket
@@ -318,5 +319,6 @@ UDPSocket<C>::close() {
}
} // namespace asiolink
+} // namespace isc
#endif // __UDP_SOCKET_H
diff --git a/src/lib/nsas/glue_hints.cc b/src/lib/nsas/glue_hints.cc
index d4c653a..02c27ee 100644
--- a/src/lib/nsas/glue_hints.cc
+++ b/src/lib/nsas/glue_hints.cc
@@ -58,7 +58,7 @@ namespace {
const std::string ns_name = rrset->getName().toText();
RdataIteratorPtr rdi = rrset->getRdataIterator();
while (!rdi->isLast()) {
- AddressEntry entry(asiolink::IOAddress(rdi->getCurrent().toText()));
+ AddressEntry entry(isc::asiolink::IOAddress(rdi->getCurrent().toText()));
boost::shared_ptr<NameserverEntry> ns_entry(new NameserverEntry(ns_name, rrset->getClass()));
NameserverAddress ns_address(ns_entry, entry, V4_ONLY);
addresses.push_back(ns_address);
diff --git a/src/lib/nsas/nameserver_entry.cc b/src/lib/nsas/nameserver_entry.cc
index 40d5cd7..bdda4e2 100644
--- a/src/lib/nsas/nameserver_entry.cc
+++ b/src/lib/nsas/nameserver_entry.cc
@@ -41,7 +41,7 @@
#include "nameserver_address.h"
#include "nameserver_entry.h"
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace isc::nsas;
using namespace isc::dns;
using namespace std;
diff --git a/src/lib/nsas/tests/address_entry_unittest.cc b/src/lib/nsas/tests/address_entry_unittest.cc
index 02fef51..60aa3cc 100644
--- a/src/lib/nsas/tests/address_entry_unittest.cc
+++ b/src/lib/nsas/tests/address_entry_unittest.cc
@@ -32,7 +32,7 @@ static std::string V4B_TEXT("5.6.7.8");
static std::string V6A_TEXT("2001:dead:beef::");
static std::string V6B_TEXT("1984:1985::1986:1987");
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace std;
using namespace isc::nsas;
diff --git a/src/lib/nsas/tests/nameserver_address_unittest.cc b/src/lib/nsas/tests/nameserver_address_unittest.cc
index 457e61c..e3bc5de 100644
--- a/src/lib/nsas/tests/nameserver_address_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_address_unittest.cc
@@ -58,7 +58,7 @@ public:
boost::shared_ptr<NameserverEntry>& getNameserverEntry() { return ns_; }
// Return the IOAddress corresponding to the index in rrv4_
- asiolink::IOAddress getAddressAtIndex(uint32_t index) {
+ isc::asiolink::IOAddress getAddressAtIndex(uint32_t index) {
return ns_.get()->getAddressAtIndex(index, V4_ONLY);
}
@@ -107,7 +107,7 @@ TEST_F(NameserverAddressTest, Address) {
boost::shared_ptr<NameserverEntry> empty_ne((NameserverEntry*)NULL);
// It will throw an NullNameserverEntryPointer exception with the empty NameserverEntry shared pointer
ASSERT_THROW({NameserverAddress empty_ns_address(empty_ne,
- asiolink::IOAddress("127.0.0.1"), V4_ONLY);},
+ isc::asiolink::IOAddress("127.0.0.1"), V4_ONLY);},
NullNameserverEntryPointer);
}
diff --git a/src/lib/nsas/tests/nameserver_entry_unittest.cc b/src/lib/nsas/tests/nameserver_entry_unittest.cc
index 4225e87..d489cbc 100644
--- a/src/lib/nsas/tests/nameserver_entry_unittest.cc
+++ b/src/lib/nsas/tests/nameserver_entry_unittest.cc
@@ -39,7 +39,7 @@
#include "nsas_test.h"
using namespace isc::nsas;
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace std;
using namespace isc::dns;
using namespace rdata;
diff --git a/src/lib/nsas/tests/zone_entry_unittest.cc b/src/lib/nsas/tests/zone_entry_unittest.cc
index 34f995c..f131b71 100644
--- a/src/lib/nsas/tests/zone_entry_unittest.cc
+++ b/src/lib/nsas/tests/zone_entry_unittest.cc
@@ -33,7 +33,7 @@
#include "nsas_test.h"
using namespace isc::nsas;
-using namespace asiolink;
+using namespace isc::asiolink;
using namespace std;
using namespace isc::dns;
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index 30ce6bd..8ce8ee7 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -35,15 +35,17 @@
#include <nsas/nameserver_address.h>
#include <asio.hpp>
-#include <asiolink/dns_service.h>
-#include <asiolink/io_fetch.h>
+#include <asiodns/dns_service.h>
+#include <asiodns/io_fetch.h>
#include <asiolink/io_service.h>
#include <resolve/recursive_query.h>
using isc::log::dlog;
using namespace isc::dns;
+using namespace isc::asiolink;
-namespace asiolink {
+namespace isc {
+namespace asiodns {
typedef std::vector<std::pair<std::string, uint16_t> > AddressVector;
@@ -812,6 +814,5 @@ RecursiveQuery::resolve(const Question& question,
}
}
-
-
-} // namespace asiolink
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/resolve/recursive_query.h b/src/lib/resolve/recursive_query.h
index 720375c..f63e5fb 100644
--- a/src/lib/resolve/recursive_query.h
+++ b/src/lib/resolve/recursive_query.h
@@ -15,14 +15,14 @@
#ifndef __RECURSIVE_QUERY_H
#define __RECURSIVE_QUERY_H 1
-#include <asiolink/dns_service.h>
-#include <asiolink/dns_server.h>
+#include <asiodns/dns_service.h>
+#include <asiodns/dns_server.h>
#include <dns/buffer.h>
#include <nsas/nameserver_address_store.h>
#include <cache/resolver_cache.h>
-namespace asiolink {
-
+namespace isc {
+namespace asiodns {
/// \brief RTT Recorder
///
@@ -87,9 +87,9 @@ public:
isc::nsas::NameserverAddressStore& nsas,
isc::cache::ResolverCache& cache,
const std::vector<std::pair<std::string, uint16_t> >&
- upstream,
+ upstream,
const std::vector<std::pair<std::string, uint16_t> >&
- upstream_root,
+ upstream_root,
int query_timeout = 2000,
int client_timeout = 4000,
int lookup_timeout = 30000,
@@ -105,7 +105,7 @@ public:
void setRttRecorder(boost::shared_ptr<RttRecorder>& recorder);
/// \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.
@@ -152,7 +152,7 @@ public:
/// \param address IP address of the test server.
/// \param port Port number of the test server
void setTestServer(const std::string& address, uint16_t port);
-
+
private:
DNSService& dns_service_;
isc::nsas::NameserverAddressStore& nsas_;
@@ -169,5 +169,6 @@ private:
boost::shared_ptr<RttRecorder> rtt_recorder_; ///< Round-trip time recorder
};
-} // namespace asiolink
+} // namespace asiodns
+} // namespace isc
#endif // __RECURSIVE_QUERY_H
diff --git a/src/lib/resolve/resolver_callback.h b/src/lib/resolve/resolver_callback.h
index 4244f19..79138e8 100644
--- a/src/lib/resolve/resolver_callback.h
+++ b/src/lib/resolve/resolver_callback.h
@@ -15,7 +15,7 @@
#ifndef _ISC_RESOLVER_CALLBACK_H
#define _ISC_RESOLVER_CALLBACK_H 1
-#include <asiolink/dns_server.h>
+#include <asiodns/dns_server.h>
#include <dns/message.h>
#include <resolve/resolver_interface.h>
@@ -33,7 +33,7 @@ namespace resolve {
/// as the server itself should also have a reference.
class ResolverCallbackServer : public ResolverInterface::Callback {
public:
- ResolverCallbackServer(asiolink::DNSServer* server) :
+ ResolverCallbackServer(asiodns::DNSServer* server) :
server_(server->clone()) {}
~ResolverCallbackServer() { delete server_; };
@@ -41,7 +41,7 @@ public:
void failure();
private:
- asiolink::DNSServer* server_;
+ asiodns::DNSServer* server_;
};
} //namespace resolve
diff --git a/src/lib/resolve/tests/Makefile.am b/src/lib/resolve/tests/Makefile.am
index a403272..edea7cd 100644
--- a/src/lib/resolve/tests/Makefile.am
+++ b/src/lib/resolve/tests/Makefile.am
@@ -27,6 +27,7 @@ run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
run_unittests_LDADD += $(top_builddir)/src/lib/resolve/libresolve.la
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
diff --git a/src/lib/resolve/tests/recursive_query_unittest.cc b/src/lib/resolve/tests/recursive_query_unittest.cc
index ab1ffa3..5a3536b 100644
--- a/src/lib/resolve/tests/recursive_query_unittest.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest.cc
@@ -45,16 +45,17 @@
// If we need to test something at the level of underlying ASIO and need
// their definition, that test should go to asiolink/internal/tests.
#include <resolve/recursive_query.h>
+#include <asiodns/dns_lookup.h>
#include <asiolink/io_socket.h>
#include <asiolink/io_service.h>
#include <asiolink/io_message.h>
#include <asiolink/io_error.h>
-#include <asiolink/dns_lookup.h>
#include <asiolink/simple_callback.h>
using isc::UnitTestUtil;
using namespace std;
-using namespace asiolink;
+using namespace isc::asiodns;
+using namespace isc::asiolink;
using namespace isc::dns;
namespace {
@@ -316,7 +317,7 @@ protected:
private:
// Currently unused; these will be used for testing
// asynchronous lookup calls via the asyncLookup() method
- boost::shared_ptr<asiolink::IOMessage> io_message_;
+ boost::shared_ptr<isc::asiolink::IOMessage> io_message_;
isc::dns::MessagePtr message_;
isc::dns::MessagePtr answer_message_;
isc::dns::OutputBufferPtr respbuf_;
diff --git a/src/lib/resolve/tests/recursive_query_unittest_2.cc b/src/lib/resolve/tests/recursive_query_unittest_2.cc
index 95af7b5..69215b6 100644
--- a/src/lib/resolve/tests/recursive_query_unittest_2.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest_2.cc
@@ -37,16 +37,17 @@
#include <dns/rdata.h>
#include <asiolink/asiolink_utilities.h>
-#include <asiolink/dns_service.h>
+#include <asiodns/dns_service.h>
+#include <asiodns/io_fetch.h>
#include <asiolink/io_address.h>
#include <asiolink/io_endpoint.h>
-#include <asiolink/io_fetch.h>
#include <asiolink/io_service.h>
#include <resolve/recursive_query.h>
#include <resolve/resolver_interface.h>
using namespace asio;
using namespace asio::ip;
+using namespace isc::asiolink;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::resolve;
@@ -72,7 +73,8 @@ using namespace std;
/// directed to one or other of the "servers" in the RecursiveQueryTest2 class,
/// regardless of the glue returned in referrals.
-namespace asiolink {
+namespace isc {
+namespace asiodns {
const std::string TEST_ADDRESS = "127.0.0.1"; ///< Servers are on this address
const uint16_t TEST_PORT = 5301; ///< ... and this port
@@ -689,4 +691,5 @@ TEST_F(RecursiveQueryTest2, Resolve) {
}
}
-} // namespace asiolink
+} // namespace asiodns
+} // namespace isc
diff --git a/src/lib/resolve/tests/resolver_callback_unittest.cc b/src/lib/resolve/tests/resolver_callback_unittest.cc
index 666b853..e94f13d 100644
--- a/src/lib/resolve/tests/resolver_callback_unittest.cc
+++ b/src/lib/resolve/tests/resolver_callback_unittest.cc
@@ -13,7 +13,7 @@
// PERFORMANCE OF THIS SOFTWARE.
#include <gtest/gtest.h>
-#include <asiolink/dns_server.h>
+#include <asiodns/dns_server.h>
#include <resolve/resolver_callback.h>
using namespace isc::resolve;
@@ -22,7 +22,7 @@ using namespace isc::resolve;
// We want to check if resume is called
// Since the server will get cloned(), we want the clones to share
// our bools for whether resume got called and with what value
-class DummyServer : public asiolink::DNSServer {
+class DummyServer : public isc::asiodns::DNSServer {
public:
DummyServer(DummyServer* orig) {
resume_called_ = orig->getResumeCalled();
@@ -31,10 +31,10 @@ public:
DummyServer(bool* resume_called, bool* resume_value) :
resume_called_(resume_called), resume_value_(resume_value)
{}
-
+
bool* getResumeCalled() { return resume_called_; }
bool* getResumeValue() { return resume_value_; }
-
+
DNSServer* clone() {
DummyServer* n = new DummyServer(this);
return n;
diff --git a/src/lib/server_common/portconfig.cc b/src/lib/server_common/portconfig.cc
index 3765f52..941644e 100644
--- a/src/lib/server_common/portconfig.cc
+++ b/src/lib/server_common/portconfig.cc
@@ -15,7 +15,7 @@
#include <server_common/portconfig.h>
#include <asiolink/io_address.h>
-#include <asiolink/dns_service.h>
+#include <asiodns/dns_service.h>
#include <log/dummylog.h>
#include <boost/foreach.hpp>
@@ -23,7 +23,8 @@
using namespace std;
using namespace isc::data;
-using namespace asiolink;
+using namespace isc::asiolink;
+using namespace isc::asiodns;
using isc::log::dlog;
namespace isc {
@@ -82,7 +83,7 @@ setAddresses(DNSService& service, const AddressList& addresses) {
void
installListenAddresses(const AddressList& newAddresses,
AddressList& addressStore,
- asiolink::DNSService& service)
+ isc::asiodns::DNSService& service)
{
try {
dlog("Setting listen addresses:");
diff --git a/src/lib/server_common/portconfig.h b/src/lib/server_common/portconfig.h
index bcb8528..e4e7bf6 100644
--- a/src/lib/server_common/portconfig.h
+++ b/src/lib/server_common/portconfig.h
@@ -25,9 +25,11 @@
/*
* Some forward declarations.
*/
-namespace asiolink {
+namespace isc {
+namespace asiodns {
class DNSService;
}
+}
namespace isc {
namespace server_common {
@@ -112,7 +114,7 @@ parseAddresses(isc::data::ConstElementPtr addresses,
void
installListenAddresses(const AddressList& newAddresses,
AddressList& addressStore,
- asiolink::DNSService& dnsService);
+ asiodns::DNSService& dnsService);
}
}
diff --git a/src/lib/server_common/tests/Makefile.am b/src/lib/server_common/tests/Makefile.am
index 55ccc85..a04a884 100644
--- a/src/lib/server_common/tests/Makefile.am
+++ b/src/lib/server_common/tests/Makefile.am
@@ -12,7 +12,7 @@ endif
# Some versions of GCC warn about some versions of Boost regarding
# missing initializer for members in its posix_time.
# https://svn.boost.org/trac/boost/ticket/3477
-# But older GCC compilers don't have the flag.
+# But older GCC compilers don't have the flag.
AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
if USE_CLANGPP
@@ -35,6 +35,7 @@ run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
+run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
endif
diff --git a/src/lib/server_common/tests/portconfig_unittest.cc b/src/lib/server_common/tests/portconfig_unittest.cc
index fabdfa2..5262565 100644
--- a/src/lib/server_common/tests/portconfig_unittest.cc
+++ b/src/lib/server_common/tests/portconfig_unittest.cc
@@ -17,6 +17,7 @@
#include <cc/data.h>
#include <exceptions/exceptions.h>
#include <asiolink/asiolink.h>
+#include <asiodns/asiodns.h>
#include <gtest/gtest.h>
#include <string>
@@ -25,7 +26,8 @@ using namespace isc::server_common::portconfig;
using namespace isc::data;
using namespace isc;
using namespace std;
-using namespace asiolink;
+using namespace isc::asiolink;
+using namespace isc::asiodns;
namespace {
diff --git a/src/lib/testutils/mockups.h b/src/lib/testutils/mockups.h
index 4bec83d..2441ad7 100644
--- a/src/lib/testutils/mockups.h
+++ b/src/lib/testutils/mockups.h
@@ -19,7 +19,7 @@
#include <xfr/xfrout_client.h>
-#include <asiolink/asiolink.h>
+#include <asiodns/asiodns.h>
// A minimal mock configuration session. Most the methods are
// stubbed out, except for a very basic group_sendmsg() and
@@ -94,7 +94,7 @@ private:
};
// A nonoperative DNSServer object to be used in calls to processMessage().
-class MockServer : public asiolink::DNSServer {
+class MockServer : public isc::asiodns::DNSServer {
public:
MockServer() : done_(false) {}
void operator()(asio::error_code, size_t) {}
diff --git a/src/lib/testutils/srv_test.cc b/src/lib/testutils/srv_test.cc
index d5da8a0..f851a2e 100644
--- a/src/lib/testutils/srv_test.cc
+++ b/src/lib/testutils/srv_test.cc
@@ -27,7 +27,7 @@
#include <testutils/srv_test.h>
using namespace isc::dns;
-using namespace asiolink;
+using namespace isc::asiolink;
namespace isc {
namespace testutils {
diff --git a/tests/tools/badpacket/Makefile.am b/tests/tools/badpacket/Makefile.am
index 8d7b0b3..b249f0e 100644
--- a/tests/tools/badpacket/Makefile.am
+++ b/tests/tools/badpacket/Makefile.am
@@ -20,8 +20,9 @@ badpacket_SOURCES += option_info.cc option_info.h
badpacket_SOURCES += scan.cc scan.h
badpacket_SOURCES += version.h
-badpacket_LDADD = $(top_builddir)/src/lib/asiolink/libasiolink.la
+badpacket_LDADD = $(top_builddir)/src/lib/asiodns/libasiodns.la
badpacket_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+badpacket_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
badpacket_LDADD += $(top_builddir)/src/lib/log/liblog.la
badpacket_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
diff --git a/tests/tools/badpacket/scan.cc b/tests/tools/badpacket/scan.cc
index 18924a9..7b843b4 100644
--- a/tests/tools/badpacket/scan.cc
+++ b/tests/tools/badpacket/scan.cc
@@ -22,7 +22,7 @@
#include <asio.hpp>
#include <asiolink/io_address.h>
-#include <asiolink/io_fetch.h>
+#include <asiodns/io_fetch.h>
#include <dns/buffer.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
@@ -38,7 +38,8 @@
#include "scan.h"
using namespace std;
-using namespace asiolink;
+using namespace isc::asiolink;
+using namespace isc::asiodns;
using namespace isc::dns;
using namespace isc::strutil;
@@ -286,7 +287,7 @@ Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf,
IOAddress(options.getAddress()), options.getPort(), recvbuf,
this, options.getTimeout());
- // Execute the message exhange. The call to run() will return when a
+ // Execute the message exchange. The call to run() will return when a
// response is received or when the I/O times out.
(service_->get_io_service()).post(fetch);
service_->run();
diff --git a/tests/tools/badpacket/scan.h b/tests/tools/badpacket/scan.h
index 65084e2..956bf29 100644
--- a/tests/tools/badpacket/scan.h
+++ b/tests/tools/badpacket/scan.h
@@ -21,8 +21,8 @@
#include <config.h>
-#include <asiolink/io_fetch.h>
#include <asiolink/io_service.h>
+#include <asiodns/io_fetch.h>
#include <dns/buffer.h>
#include "command_options.h"
@@ -37,7 +37,7 @@ namespace badpacket {
/// cycle through combinations of the given options, sending and receiving
/// messages. For each packet exchange, a summary is written to stdout.
-class Scan : public asiolink::IOFetch::Callback {
+class Scan : public isc::asiodns::IOFetch::Callback {
public:
/// \brief Constructor
@@ -58,7 +58,7 @@ public:
/// will be called.
///
/// \param result Result of the asynchronous I/O. Zero implies success.
- virtual void operator()(asiolink::IOFetch::Result result);
+ virtual void operator()(isc::asiodns::IOFetch::Result result);
private:
/// \brief Iterate over flags fields options
@@ -187,8 +187,9 @@ private:
// Member variables
- boost::scoped_ptr<asiolink::IOService> service_;///< Service to run the scan
- asiolink::IOFetch::Result result_; ///< Result of the I/O
+ boost::scoped_ptr<isc::asiolink::IOService> service_;
+ ///< Service to run the scan
+ isc::asiodns::IOFetch::Result result_; ///< Result of the I/O
};
} // namespace test
More information about the bind10-changes
mailing list