BIND 10 trac826, updated. 02c9630face814b97344f720aabff89ddfb00e29 lib testutils
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Jun 29 00:56:44 UTC 2012
The branch, trac826 has been updated
via 02c9630face814b97344f720aabff89ddfb00e29 (commit)
via 1890856ef64d369703e6de05445aadf61e8a2292 (commit)
via 21a1882aec22a03d25ebc3a572be2392ec9a0aba (commit)
from 46183f26dea3366d9e269e728baa16b6afd73cd3 (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 02c9630face814b97344f720aabff89ddfb00e29
Author: Francis Dupont <fdupont at isc.org>
Date: Fri Jun 29 02:56:32 2012 +0200
lib testutils
commit 1890856ef64d369703e6de05445aadf61e8a2292
Author: Francis Dupont <fdupont at isc.org>
Date: Fri Jun 29 02:25:59 2012 +0200
libresolve first attempt
commit 21a1882aec22a03d25ebc3a572be2392ec9a0aba
Author: Francis Dupont <fdupont at isc.org>
Date: Fri Jun 29 01:25:44 2012 +0200
libcache first attempt
-----------------------------------------------------------------------
Summary of changes:
src/lib/asiolink/io_asio_socket.h | 8 +
src/lib/asiolink/io_socket.cc | 4 +
src/lib/asiolink/io_socket.h | 4 +
src/lib/asiolink/tcp_socket.h | 7 +-
src/lib/asiolink/tests/io_socket_unittest.cc | 5 +
src/lib/asiolink/udp_socket.h | 7 +-
src/lib/cache/.gitignore | 2 +
src/lib/cache/cache_messages.mes | 6 +-
src/lib/cache/local_zone_data.cc | 2 +-
src/lib/cache/local_zone_data.h | 2 +-
src/lib/cache/logger.h | 17 +-
src/lib/cache/message_cache.h | 2 +
src/lib/cache/resolver_cache.cc | 9 +-
src/lib/cache/resolver_cache.h | 7 +-
src/lib/cache/rrset_cache.cc | 2 +-
src/lib/cache/rrset_cache.h | 2 +-
src/lib/cache/rrset_copy.cc | 2 +-
src/lib/cache/rrset_copy.h | 2 +-
src/lib/cache/rrset_entry.cc | 3 +-
src/lib/cache/rrset_entry.h | 7 +-
src/lib/{acl => cache}/tests/.gitignore | 0
src/lib/cache/tests/Makefile.am | 8 +-
src/lib/cache/tests/message_entry_unittest.cc | 2 +
src/lib/cache/tests/negative_cache_unittest.cc | 56 ++-
src/lib/resolve/.gitignore | 2 +
src/lib/resolve/Makefile.am | 1 +
src/lib/resolve/recursive_query.cc | 199 ++++++---
src/lib/resolve/recursive_query.h | 22 +-
src/lib/resolve/resolve.cc | 4 -
src/lib/resolve/resolve.h | 1 -
src/lib/resolve/resolve_log.h | 8 +-
src/lib/resolve/resolve_messages.mes | 97 ++++-
src/lib/resolve/response_classifier.cc | 9 +-
src/lib/resolve/response_classifier.h | 4 +-
src/lib/{acl => resolve}/tests/.gitignore | 0
src/lib/resolve/tests/Makefile.am | 4 +
src/lib/resolve/tests/recursive_query_unittest.cc | 424 +++++++++++++-------
.../resolve/tests/recursive_query_unittest_2.cc | 33 +-
...unittest_2.cc => recursive_query_unittest_3.cc} | 384 ++++++------------
src/lib/testutils/Makefile.am | 2 +-
src/lib/testutils/dnsmessage_test.cc | 29 ++
src/lib/testutils/dnsmessage_test.h | 63 ++-
src/lib/testutils/mockups.h | 87 +++-
src/lib/testutils/portconfig.h | 16 +-
src/lib/testutils/socket_request.h | 219 ++++++++++
src/lib/testutils/srv_test.cc | 23 +-
src/lib/testutils/srv_test.h | 12 +-
src/lib/testutils/testdata/.gitignore | 15 +
src/lib/testutils/testdata/Makefile.am | 4 +
.../lib/testutils/testdata/auth_test.sqlite3 | Bin 14336 -> 16384 bytes
src/lib/testutils/testdata/example.sqlite3 | Bin 11264 -> 15360 bytes
.../testutils/testdata/nsec3query_fromWire.spec | 11 +
.../testdata/nsec3query_nodnssec_fromWire.spec | 9 +
.../testdata}/rfc5155-example.zone.signed | 4 +-
.../lib/testutils/testdata/rwtest.sqlite3 | Bin 14336 -> 17408 bytes
src/lib/util/io/fd_share.cc | 18 +-
src/lib/util/io/fd_share.h | 8 +
src/lib/util/io/fdshare_python.cc | 4 +-
src/lib/xfr/xfrout_client.cc | 7 +-
src/lib/xfr/xfrout_client.h | 16 +-
60 files changed, 1291 insertions(+), 614 deletions(-)
create mode 100644 src/lib/cache/.gitignore
copy src/lib/{acl => cache}/tests/.gitignore (100%)
create mode 100644 src/lib/resolve/.gitignore
copy src/lib/{acl => resolve}/tests/.gitignore (100%)
copy src/lib/resolve/tests/{recursive_query_unittest_2.cc => recursive_query_unittest_3.cc} (57%)
create mode 100644 src/lib/testutils/socket_request.h
create mode 100644 src/lib/testutils/testdata/.gitignore
copy tests/lettuce/data/empty_db.sqlite3 => src/lib/testutils/testdata/auth_test.sqlite3 (71%)
mode change 100644 => 100755
create mode 100644 src/lib/testutils/testdata/nsec3query_fromWire.spec
create mode 100644 src/lib/testutils/testdata/nsec3query_nodnssec_fromWire.spec
copy {tests/lettuce/configurations/nsec3 => src/lib/testutils/testdata}/rfc5155-example.zone.signed (99%)
copy tests/lettuce/data/empty_db.sqlite3 => src/lib/testutils/testdata/rwtest.sqlite3 (60%)
-----------------------------------------------------------------------
diff --git a/src/lib/asiolink/io_asio_socket.h b/src/lib/asiolink/io_asio_socket.h
index 42b4a6a..8267cbc 100644
--- a/src/lib/asiolink/io_asio_socket.h
+++ b/src/lib/asiolink/io_asio_socket.h
@@ -127,7 +127,11 @@ public:
///
/// \return The native representation of the socket. This is the socket
/// file descriptor for UNIX-like systems.
+#ifdef _WIN32
+ virtual SOCKET getNative() const = 0;
+#else
virtual int getNative() const = 0;
+#endif
/// \brief Return the transport protocol of the socket.
///
@@ -309,7 +313,11 @@ public:
///
/// \return Always returns -1 as the object is not associated with a real
/// (native) socket.
+#ifdef _WIN32
+ virtual SOCKET getNative() const { return (INVALID_SOCKET); }
+#else
virtual int getNative() const { return (-1); }
+#endif
/// \brief A dummy derived method of \c IOAsioSocket::getProtocol().
///
diff --git a/src/lib/asiolink/io_socket.cc b/src/lib/asiolink/io_socket.cc
index 2e31003..9677203 100644
--- a/src/lib/asiolink/io_socket.cc
+++ b/src/lib/asiolink/io_socket.cc
@@ -44,7 +44,11 @@ public:
///
/// This version of method always returns -1 as the object is not
/// associated with a real (native) socket.
+#ifdef _WIN32
+ virtual SOCKET getNative() const { return (INVALID_SOCKET); }
+#else
virtual int getNative() const { return (-1); }
+#endif
virtual int getProtocol() const { return (protocol_); }
private:
diff --git a/src/lib/asiolink/io_socket.h b/src/lib/asiolink/io_socket.h
index 2f51895..2948e67 100644
--- a/src/lib/asiolink/io_socket.h
+++ b/src/lib/asiolink/io_socket.h
@@ -85,7 +85,11 @@ public:
///
/// \return The native representation of the socket. This is the socket
/// file descriptor for UNIX-like systems.
+#ifdef _WIN32
+ virtual SOCKET getNative() const = 0;
+#else
virtual int getNative() const = 0;
+#endif
/// \brief Return the transport protocol of the socket.
///
diff --git a/src/lib/asiolink/tcp_socket.h b/src/lib/asiolink/tcp_socket.h
index b0fc4fb..10a3260 100644
--- a/src/lib/asiolink/tcp_socket.h
+++ b/src/lib/asiolink/tcp_socket.h
@@ -91,7 +91,12 @@ public:
virtual ~TCPSocket();
/// \brief Return file descriptor of underlying socket
- virtual int getNative() const {
+#ifdef _WIN32
+ virtual SOCKET getNative() const
+#else
+ virtual int getNative() const
+#endif
+ {
return (socket_.native());
}
diff --git a/src/lib/asiolink/tests/io_socket_unittest.cc b/src/lib/asiolink/tests/io_socket_unittest.cc
index fdda1e4..1005dd2 100644
--- a/src/lib/asiolink/tests/io_socket_unittest.cc
+++ b/src/lib/asiolink/tests/io_socket_unittest.cc
@@ -29,8 +29,13 @@ using namespace isc::asiolink;
TEST(IOSocketTest, dummySockets) {
EXPECT_EQ(IPPROTO_UDP, IOSocket::getDummyUDPSocket().getProtocol());
EXPECT_EQ(IPPROTO_TCP, IOSocket::getDummyTCPSocket().getProtocol());
+#ifdef _WIN32
+ EXPECT_EQ(INVALID_SOCKET, IOSocket::getDummyUDPSocket().getNative());
+ EXPECT_EQ(INVALID_SOCKET, IOSocket::getDummyTCPSocket().getNative());
+#else
EXPECT_EQ(-1, IOSocket::getDummyUDPSocket().getNative());
EXPECT_EQ(-1, IOSocket::getDummyTCPSocket().getNative());
+#endif
}
diff --git a/src/lib/asiolink/udp_socket.h b/src/lib/asiolink/udp_socket.h
index 0063744..83cef35 100644
--- a/src/lib/asiolink/udp_socket.h
+++ b/src/lib/asiolink/udp_socket.h
@@ -73,7 +73,12 @@ public:
virtual ~UDPSocket();
/// \brief Return file descriptor of underlying socket
- virtual int getNative() const {
+#ifdef
+ virtual SOCKET getNative() const
+#else
+ virtual int getNative() const
+#endif
+ {
return (socket_.native());
}
diff --git a/src/lib/cache/.gitignore b/src/lib/cache/.gitignore
new file mode 100644
index 0000000..a33f3f0
--- /dev/null
+++ b/src/lib/cache/.gitignore
@@ -0,0 +1,2 @@
+/cache_messages.cc
+/cache_messages.h
diff --git a/src/lib/cache/cache_messages.mes b/src/lib/cache/cache_messages.mes
index 19102ae..51f2264 100644
--- a/src/lib/cache/cache_messages.mes
+++ b/src/lib/cache/cache_messages.mes
@@ -66,14 +66,14 @@ is created.
Debug message. The resolver cache is looking up the deepest known nameserver,
so the resolution doesn't have to start from the root.
+% CACHE_RESOLVER_INIT initializing resolver cache for class %1
+Debug message. The resolver cache is being created for this given class.
+
% CACHE_RESOLVER_INIT_INFO initializing resolver cache for class %1
Debug message, the resolver cache is being created for this given class. The
difference from CACHE_RESOLVER_INIT is only in different format of passed
information, otherwise it does the same.
-% CACHE_RESOLVER_INIT initializing resolver cache for class %1
-Debug message. The resolver cache is being created for this given class.
-
% CACHE_RESOLVER_LOCAL_MSG message for %1/%2 found in local zone data
Debug message. The resolver cache found a complete message for the user query
in the zone data.
diff --git a/src/lib/cache/local_zone_data.cc b/src/lib/cache/local_zone_data.cc
index 13d1d75..29ab2bf 100644
--- a/src/lib/cache/local_zone_data.cc
+++ b/src/lib/cache/local_zone_data.cc
@@ -43,7 +43,7 @@ LocalZoneData::lookup(const isc::dns::Name& name,
}
void
-LocalZoneData::update(const isc::dns::RRset& rrset) {
+LocalZoneData::update(const isc::dns::AbstractRRset& rrset) {
//TODO Do we really need to recreate the rrset again?
string key = genCacheEntryName(rrset.getName(), rrset.getType());
LOG_DEBUG(logger, DBG_TRACE_DATA, CACHE_LOCALZONE_UPDATE).arg(key);
diff --git a/src/lib/cache/local_zone_data.h b/src/lib/cache/local_zone_data.h
index 3015847..df77f40 100644
--- a/src/lib/cache/local_zone_data.h
+++ b/src/lib/cache/local_zone_data.h
@@ -47,7 +47,7 @@ public:
/// Otherwise, the existed one will be overwritten.
///
/// \param rrset The rrset to update
- void update(const isc::dns::RRset& rrset);
+ void update(const isc::dns::AbstractRRset& rrset);
private:
std::map<std::string, isc::dns::RRsetPtr> rrsets_map_; // RRsets of the zone
diff --git a/src/lib/cache/logger.h b/src/lib/cache/logger.h
index 8159ed4..52c9743 100644
--- a/src/lib/cache/logger.h
+++ b/src/lib/cache/logger.h
@@ -18,7 +18,7 @@
#include <log/macros.h>
#include <cache/cache_messages.h>
-/// \file logger.h
+/// \file cache/logger.h
/// \brief Cache library global logger
///
/// This holds the logger for the cache library. It is a private header
@@ -31,14 +31,13 @@ namespace cache {
/// \brief The logger for this library
extern isc::log::Logger logger;
-enum {
- /// \brief Trace basic operations
- DBG_TRACE_BASIC = 10,
- /// \brief Trace data operations
- DBG_TRACE_DATA = 40,
-};
+/// \brief Trace basic operations
+const int DBG_TRACE_BASIC = DBGLVL_TRACE_BASIC;
-}
-}
+/// \brief Trace data operations
+const int DBG_TRACE_DATA = DBGLVL_TRACE_BASIC_DATA;
+
+} // namespace cache
+} // namespace isc
#endif
diff --git a/src/lib/cache/message_cache.h b/src/lib/cache/message_cache.h
index 44d7fd1..b418f23 100644
--- a/src/lib/cache/message_cache.h
+++ b/src/lib/cache/message_cache.h
@@ -52,6 +52,8 @@ public:
virtual ~MessageCache();
/// \brief Look up message in cache.
+ /// \param qname Name of the domain for which the message is being sought.
+ /// \param qtype Type of the RR for which the message is being sought.
/// \param message generated response message if the message entry
/// can be found.
///
diff --git a/src/lib/cache/resolver_cache.cc b/src/lib/cache/resolver_cache.cc
index 3ed38ea..20f470e 100644
--- a/src/lib/cache/resolver_cache.cc
+++ b/src/lib/cache/resolver_cache.cc
@@ -164,14 +164,16 @@ ResolverCache::ResolverCache()
ResolverCache::ResolverCache(std::vector<CacheSizeInfo> caches_info)
{
- for (unsigned int i = 0; i < caches_info.size(); ++i) {
+ for (std::vector<CacheSizeInfo>::size_type i = 0;
+ i < caches_info.size(); ++i) {
class_caches_.push_back(new ResolverClassCache(caches_info[i]));
}
}
ResolverCache::~ResolverCache()
{
- for (unsigned int i = 0; i < class_caches_.size(); ++i) {
+ for (std::vector<ResolverClassCache*>::size_type i = 0;
+ i < class_caches_.size(); ++i) {
delete class_caches_[i];
}
}
@@ -261,7 +263,8 @@ ResolverCache::update(const isc::dns::ConstRRsetPtr& rrset_ptr) {
ResolverClassCache*
ResolverCache::getClassCache(const isc::dns::RRClass& cache_class) const {
- for (unsigned int i = 0; i < class_caches_.size(); ++i) {
+ for (std::vector<ResolverClassCache*>::size_type i = 0;
+ i < class_caches_.size(); ++i) {
if (class_caches_[i]->getClass() == cache_class) {
return (class_caches_[i]);
}
diff --git a/src/lib/cache/resolver_cache.h b/src/lib/cache/resolver_cache.h
index 6d68663..5630bd7 100644
--- a/src/lib/cache/resolver_cache.h
+++ b/src/lib/cache/resolver_cache.h
@@ -89,8 +89,8 @@ public:
ResolverClassCache(const isc::dns::RRClass& cache_class);
/// \brief Construct Function.
- /// \param caches_size cache size information for each
- /// messages/rrsets of different classes.
+ /// \param cache_info Cache size information for each message/rrsets of
+ /// different classes.
ResolverClassCache(const CacheSizeInfo& cache_info);
/// \name Lookup Interfaces
@@ -197,9 +197,6 @@ private:
/// \brief cache the SOA rrset parsed from the negative response message.
RRsetCachePtr negative_soa_cache_;
-
- // silence MSVC warning C4512: assignment operator could not be generated
- ResolverClassCache& operator=(ResolverClassCache const&);
};
class ResolverCache {
diff --git a/src/lib/cache/rrset_cache.cc b/src/lib/cache/rrset_cache.cc
index 1a5fd48..bb4d339 100644
--- a/src/lib/cache/rrset_cache.cc
+++ b/src/lib/cache/rrset_cache.cc
@@ -70,7 +70,7 @@ RRsetCache::lookup(const isc::dns::Name& qname,
}
RRsetEntryPtr
-RRsetCache::update(const isc::dns::RRset& rrset,
+RRsetCache::update(const isc::dns::AbstractRRset& rrset,
const RRsetTrustLevel& level)
{
LOG_DEBUG(logger, DBG_TRACE_DATA, CACHE_RRSET_UPDATE).arg(rrset.getName()).
diff --git a/src/lib/cache/rrset_cache.h b/src/lib/cache/rrset_cache.h
index 73f9b58..a4ea54e 100644
--- a/src/lib/cache/rrset_cache.h
+++ b/src/lib/cache/rrset_cache.h
@@ -73,7 +73,7 @@ public:
/// \param level trustworthiness of the rrset.
/// \return return the rrset entry in the cache, it may be the
/// new added rrset entry or existed one if it is not replaced.
- RRsetEntryPtr update(const isc::dns::RRset& rrset,
+ RRsetEntryPtr update(const isc::dns::AbstractRRset& rrset,
const RRsetTrustLevel& level);
/// \short Protected memebers, so they can be accessed by tests.
diff --git a/src/lib/cache/rrset_copy.cc b/src/lib/cache/rrset_copy.cc
index 05b139a..b395ce1 100644
--- a/src/lib/cache/rrset_copy.cc
+++ b/src/lib/cache/rrset_copy.cc
@@ -20,7 +20,7 @@ namespace isc {
namespace cache {
void
-rrsetCopy(const isc::dns::RRset& src, isc::dns::RRset& dst) {
+rrsetCopy(const isc::dns::AbstractRRset& src, isc::dns::AbstractRRset& dst) {
RdataIteratorPtr rdata_itor = src.getRdataIterator();
rdata_itor->first();
while(!rdata_itor->isLast()){
diff --git a/src/lib/cache/rrset_copy.h b/src/lib/cache/rrset_copy.h
index b6af8d6..e1dc489 100644
--- a/src/lib/cache/rrset_copy.h
+++ b/src/lib/cache/rrset_copy.h
@@ -33,7 +33,7 @@ namespace cache {
/// we have to do the copy.
void
-rrsetCopy(const isc::dns::RRset& src, isc::dns::RRset& dst);
+rrsetCopy(const isc::dns::AbstractRRset& src, isc::dns::AbstractRRset& dst);
} // namespace cache
} // namespace isc
diff --git a/src/lib/cache/rrset_entry.cc b/src/lib/cache/rrset_entry.cc
index a17d28a..14622fe 100644
--- a/src/lib/cache/rrset_entry.cc
+++ b/src/lib/cache/rrset_entry.cc
@@ -27,7 +27,8 @@ using namespace isc::dns;
namespace isc {
namespace cache {
-RRsetEntry::RRsetEntry(const isc::dns::RRset& rrset, const RRsetTrustLevel& level):
+RRsetEntry::RRsetEntry(const isc::dns::AbstractRRset& rrset,
+ const RRsetTrustLevel& level):
entry_name_(genCacheEntryName(rrset.getName(), rrset.getType())),
expire_time_(time(NULL) + rrset.getTTL().getValue()),
trust_level_(level),
diff --git a/src/lib/cache/rrset_entry.h b/src/lib/cache/rrset_entry.h
index 5fa8f2c..129300d 100644
--- a/src/lib/cache/rrset_entry.h
+++ b/src/lib/cache/rrset_entry.h
@@ -27,9 +27,9 @@ using namespace isc::nsas;
namespace isc {
namespace cache {
-/// \enum RRset Trustworthiness
+/// \enum RRsetTrustLevel
/// For detail of RRset trustworthiness, please refer to
-/// RFC2181 section5.4.1.
+/// RFC 2181 section 5.4.1.
/// Bigger value is more trustworthy.
enum RRsetTrustLevel {
/// Default trust for RRset.
@@ -75,7 +75,8 @@ public:
/// \brief Constructor
/// \param rrset The RRset used to initialize the RRset entry.
/// \param level trustworthiness of the RRset.
- RRsetEntry(const isc::dns::RRset& rrset, const RRsetTrustLevel& level);
+ RRsetEntry(const isc::dns::AbstractRRset& rrset,
+ const RRsetTrustLevel& level);
/// The destructor.
~RRsetEntry() {}
diff --git a/src/lib/cache/tests/.gitignore b/src/lib/cache/tests/.gitignore
new file mode 100644
index 0000000..d6d1ec8
--- /dev/null
+++ b/src/lib/cache/tests/.gitignore
@@ -0,0 +1 @@
+/run_unittests
diff --git a/src/lib/cache/tests/Makefile.am b/src/lib/cache/tests/Makefile.am
index a215c56..4e47314 100644
--- a/src/lib/cache/tests/Makefile.am
+++ b/src/lib/cache/tests/Makefile.am
@@ -28,6 +28,9 @@ endif
CLEANFILES = *.gcno *.gcda
+TESTS_ENVIRONMENT = \
+ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
TESTS =
if HAVE_GTEST
TESTS += run_unittests
@@ -47,11 +50,6 @@ run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
-# NOTE: we may have to clean up this hack later (see the note in configure.ac)
-if NEED_LIBBOOST_THREAD
-run_unittests_LDADD += -lboost_thread
-endif
-
run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la
run_unittests_LDADD += $(top_builddir)/src/lib/log/liblog.la
run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
diff --git a/src/lib/cache/tests/message_entry_unittest.cc b/src/lib/cache/tests/message_entry_unittest.cc
index 8961ee9..7f909f1 100644
--- a/src/lib/cache/tests/message_entry_unittest.cc
+++ b/src/lib/cache/tests/message_entry_unittest.cc
@@ -1,3 +1,5 @@
+// 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.
diff --git a/src/lib/cache/tests/negative_cache_unittest.cc b/src/lib/cache/tests/negative_cache_unittest.cc
index 3059519..879fe1c 100644
--- a/src/lib/cache/tests/negative_cache_unittest.cc
+++ b/src/lib/cache/tests/negative_cache_unittest.cc
@@ -52,14 +52,17 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){
msg_nxdomain.makeResponse();
Name non_exist_qname("nonexist.example.com.");
- EXPECT_TRUE(cache->lookup(non_exist_qname, RRType::A(), RRClass::IN(), msg_nxdomain));
+ EXPECT_TRUE(cache->lookup(non_exist_qname, RRType::A(), RRClass::IN(),
+ msg_nxdomain));
RRsetIterator iter = msg_nxdomain.beginSection(Message::SECTION_AUTHORITY);
RRsetPtr rrset_ptr = *iter;
// The TTL should equal to the TTL of SOA record
const RRTTL& nxdomain_ttl1 = rrset_ptr->getTTL();
- EXPECT_EQ(nxdomain_ttl1.getValue(), 86400);
+ // May have already crossed seconds boundary
+ EXPECT_GE(nxdomain_ttl1.getValue(), 86399);
+ EXPECT_LE(nxdomain_ttl1.getValue(), 86400);
// SOA response for example.com
Message msg_example_com_soa(Message::PARSE);
@@ -68,19 +71,25 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){
msg_example_com_soa.makeResponse();
Name soa_qname("example.com.");
- EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(), msg_example_com_soa));
+ EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(),
+ msg_example_com_soa));
iter = msg_example_com_soa.beginSection(Message::SECTION_ANSWER);
rrset_ptr = *iter;
// The TTL should equal to the TTL of SOA record in answer section
const RRTTL& soa_ttl = rrset_ptr->getTTL();
- EXPECT_EQ(soa_ttl.getValue(), 172800);
+ // May have already crossed seconds boundary
+ EXPECT_GE(soa_ttl.getValue(), 172799);
+ EXPECT_LE(soa_ttl.getValue(), 172800);
+ // Sleep for 2 seconds. 2 seconds to make sure the final range check
+ // does not overlap with the original ones (in which case this test
+ // would erroneously pass if the ttl value is not changed)
#ifdef _WIN32
- Sleep(1000);
+ Sleep(2000);
#else
- sleep(1);
+ sleep(2);
#endif
// Query nonexist.example.com again
@@ -94,7 +103,8 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){
// The TTL should equal to the TTL of negative response SOA record
const RRTTL& nxdomain_ttl2 = rrset_ptr->getTTL();
- EXPECT_TRUE(86398 <= nxdomain_ttl2.getValue() && nxdomain_ttl2.getValue() <= 86399);
+ EXPECT_GE(nxdomain_ttl2.getValue(), 86397);
+ EXPECT_LE(nxdomain_ttl2.getValue(), 86398);
// No RRset in ANSWER section
EXPECT_TRUE(msg_nxdomain2.getRRCount(Message::SECTION_ANSWER) == 0);
// Check that only one SOA record exist in AUTHORITY section
@@ -107,13 +117,15 @@ TEST_F(NegativeCacheTest, testNXDOMAIN){
Message msg_example_com_soa2(Message::PARSE);
messageFromFile(msg_example_com_soa2, "message_example_com_soa.wire");
msg_example_com_soa2.makeResponse();
- EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(), msg_example_com_soa2));
+ EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(),
+ msg_example_com_soa2));
iter = msg_example_com_soa2.beginSection(Message::SECTION_ANSWER);
rrset_ptr = *iter;
const RRTTL& soa_ttl2 = rrset_ptr->getTTL();
// The TTL should equal to the TTL of SOA record in answer section
- EXPECT_TRUE(172798 <= soa_ttl2.getValue() && soa_ttl2.getValue() <= 172799);
+ EXPECT_GE(soa_ttl2.getValue(), 172797);
+ EXPECT_LE(soa_ttl2.getValue(), 172798);
}
TEST_F(NegativeCacheTest, testNXDOMAINWithoutSOA){
@@ -170,15 +182,16 @@ TEST_F(NegativeCacheTest, testNoerrorNodata){
msg_nodata.makeResponse();
Name example_dot_com("example.com.");
- EXPECT_TRUE(cache->lookup(example_dot_com, RRType::MX(), RRClass::IN(), msg_nodata));
+ EXPECT_TRUE(cache->lookup(example_dot_com, RRType::MX(), RRClass::IN(),
+ msg_nodata));
RRsetIterator iter = msg_nodata.beginSection(Message::SECTION_AUTHORITY);
RRsetPtr rrset_ptr = *iter;
// The TTL should equal to the TTL of SOA record
const RRTTL& nodata_ttl1 = rrset_ptr->getTTL();
- EXPECT_EQ(nodata_ttl1.getValue(), 86400);
-
+ EXPECT_GE(nodata_ttl1.getValue(), 86399);
+ EXPECT_LE(nodata_ttl1.getValue(), 86400);
// Normal SOA response for example.com
Message msg_example_com_soa(Message::PARSE);
@@ -187,24 +200,29 @@ TEST_F(NegativeCacheTest, testNoerrorNodata){
msg_example_com_soa.makeResponse();
Name soa_qname("example.com.");
- EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(), msg_example_com_soa));
+ EXPECT_TRUE(cache->lookup(soa_qname, RRType::SOA(), RRClass::IN(),
+ msg_example_com_soa));
iter = msg_example_com_soa.beginSection(Message::SECTION_ANSWER);
rrset_ptr = *iter;
// The TTL should equal to the TTL of SOA record in answer section
const RRTTL& soa_ttl = rrset_ptr->getTTL();
- EXPECT_EQ(soa_ttl.getValue(), 172800);
+ EXPECT_GE(soa_ttl.getValue(), 172799);
+ EXPECT_LE(soa_ttl.getValue(), 172800);
// Query MX record of example.com again
Message msg_nodata2(Message::PARSE);
messageFromFile(msg_nodata2, "message_nodata_with_soa.wire");
msg_nodata2.makeResponse();
+ // Sleep for 2 seconds. 2 seconds to make sure the final range check
+ // does not overlap with the original ones (in which case this test
+ // would erroneously pass if the ttl value is not changed)
#ifdef _WIN32
- Sleep(1000);
+ Sleep(2000);
#else
- sleep(1);
+ sleep(2);
#endif
EXPECT_TRUE(cache->lookup(example_dot_com, RRType::MX(), RRClass::IN(), msg_nodata2));
@@ -217,9 +235,11 @@ TEST_F(NegativeCacheTest, testNoerrorNodata){
iter = msg_nodata2.beginSection(Message::SECTION_AUTHORITY);
rrset_ptr = *iter;
- // The TTL should equal to the TTL of negative response SOA record and counted down
+ // The TTL should equal to the TTL of negative response SOA record
+ // and counted down
const RRTTL& nodata_ttl2 = rrset_ptr->getTTL();
- EXPECT_TRUE(86398 <= nodata_ttl2.getValue() && nodata_ttl2.getValue() <= 86399);
+ EXPECT_GE(nodata_ttl2.getValue(), 86397);
+ EXPECT_LE(nodata_ttl2.getValue(), 86398);
}
TEST_F(NegativeCacheTest, testReferralResponse){
diff --git a/src/lib/resolve/.gitignore b/src/lib/resolve/.gitignore
new file mode 100644
index 0000000..292ed1a
--- /dev/null
+++ b/src/lib/resolve/.gitignore
@@ -0,0 +1,2 @@
+/resolve_messages.cc
+/resolve_messages.h
diff --git a/src/lib/resolve/Makefile.am b/src/lib/resolve/Makefile.am
index ceccce8..4b81862 100644
--- a/src/lib/resolve/Makefile.am
+++ b/src/lib/resolve/Makefile.am
@@ -34,6 +34,7 @@ nodist_libresolve_la_SOURCES = resolve_messages.h resolve_messages.cc
libresolve_la_LIBADD = $(top_builddir)/src/lib/dns/libdns++.la
libresolve_la_LIBADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
libresolve_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
+libresolve_la_LIBADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
# The message file should be in the distribution.
EXTRA_DIST = resolve_messages.mes
diff --git a/src/lib/resolve/recursive_query.cc b/src/lib/resolve/recursive_query.cc
index eac12d2..400ac86 100644
--- a/src/lib/resolve/recursive_query.cc
+++ b/src/lib/resolve/recursive_query.cc
@@ -33,9 +33,9 @@
#include <dns/opcode.h>
#include <dns/exceptions.h>
#include <dns/rdataclass.h>
-
#include <resolve/resolve.h>
#include <resolve/resolve_log.h>
+#include <resolve/resolve_messages.h>
#include <cache/resolver_cache.h>
#include <nsas/address_request_callback.h>
#include <nsas/nameserver_address.h>
@@ -44,6 +44,7 @@
#include <asiodns/dns_service.h>
#include <asiodns/io_fetch.h>
#include <asiolink/io_service.h>
+#include <resolve/response_classifier.h>
#include <resolve/recursive_query.h>
using namespace isc::dns;
@@ -89,6 +90,7 @@ questionText(const isc::dns::Question& question) {
/// It is not public function, therefore it's not in header. But it's not
/// in anonymous namespace, so we can call it from unittests.
/// \param name The name we want to delegate to.
+/// \param rrclass The class.
/// \param cache The place too look for known delegations.
std::string
deepestDelegation(Name name, RRClass rrclass,
@@ -131,7 +133,7 @@ typedef std::vector<std::pair<std::string, uint16_t> > AddressVector;
// mishandles this in its name mangling, and wouldn't compile.
// We can probably use a typedef, but need to move it to a central
// location and use it consistently.
-RecursiveQuery::RecursiveQuery(DNSService& dns_service,
+RecursiveQuery::RecursiveQuery(DNSServiceBase& dns_service,
isc::nsas::NameserverAddressStore& nsas,
isc::cache::ResolverCache& cache,
const std::vector<std::pair<std::string, uint16_t> >& upstream,
@@ -254,6 +256,9 @@ private:
// case of a TCP packet being returned with the TC bit set.
IOFetch::Protocol protocol_;
+ // EDNS flag
+ bool edns_;
+
// To prevent both unreasonably long cname chains and cname loops,
// we simply keep a counter of the number of CNAMEs we have
// followed so far (and error if it exceeds RESOLVER_MAX_CNAME_CHAIN
@@ -381,23 +386,25 @@ private:
IOFetch query(protocol_, io_, question_,
test_server_.first,
test_server_.second, buffer_, this,
- query_timeout_);
+ query_timeout_, edns_);
io_.get_io_service().post(query);
} else {
IOFetch query(protocol_, io_, question_,
current_ns_address.getAddress(),
53, buffer_, this,
- query_timeout_);
+ query_timeout_, edns_);
io_.get_io_service().post(query);
}
}
// 'general' send, ask the NSAS to give us an address.
- void send(IOFetch::Protocol protocol = IOFetch::UDP) {
+ void send(IOFetch::Protocol protocol = IOFetch::UDP, bool edns = true) {
protocol_ = protocol; // Store protocol being used for this
+ edns_ = edns;
if (test_server_.second != 0) {
// Send query to test server
- LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_TEST_UPSTREAM)
+ LOG_DEBUG(isc::resolve::logger,
+ RESLIB_DBG_TRACE, RESLIB_TEST_UPSTREAM)
.arg(questionText(question_)).arg(test_server_.first);
#ifdef _WIN32
win32_gettimeofday(¤t_ns_qsent_time);
@@ -408,14 +415,15 @@ private:
IOFetch query(protocol, io_, question_,
test_server_.first,
test_server_.second, buffer_, this,
- query_timeout_);
+ query_timeout_, edns_);
io_.get_io_service().post(query);
} else {
// Ask the NSAS for an address for the current zone,
// the callback will call the actual sendTo()
- LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_TRACE, RESLIB_NSAS_LOOKUP)
- .arg(cur_zone_);
+ LOG_DEBUG(isc::resolve::logger,
+ RESLIB_DBG_TRACE, RESLIB_NSAS_LOOKUP)
+ .arg(cur_zone_);
// Can we have multiple calls to nsas_out? Let's assume not
// for now
@@ -464,7 +472,7 @@ private:
.arg(questionText(question_));
isc::resolve::copyResponseMessage(incoming, answer_message_);
cache_.update(*answer_message_);
- return true;
+ return (true);
break;
case isc::resolve::ResponseClassifier::CNAME:
@@ -478,7 +486,7 @@ private:
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_LONG_CHAIN)
.arg(questionText(question_));
makeSERVFAIL();
- return true;
+ return (true);
}
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_CNAME)
@@ -494,7 +502,7 @@ private:
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_FOLLOW_CNAME)
.arg(questionText(question_));
doLookup();
- return false;
+ return (false);
break;
case isc::resolve::ResponseClassifier::NXDOMAIN:
@@ -505,7 +513,7 @@ private:
isc::resolve::copyResponseMessage(incoming, answer_message_);
// no negcache yet
//cache_.update(*answer_message_);
- return true;
+ return (true);
break;
case isc::resolve::ResponseClassifier::REFERRAL:
@@ -554,7 +562,7 @@ private:
nsas_callback_out_ = true;
nsas_.lookup(cur_zone_, question_.getClass(),
nsas_callback_, ANY_OK, glue_hints);
- return false;
+ return (false);
} else {
// Referral was received but did not contain an NS RRset.
LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_NO_NS_RRSET)
@@ -562,48 +570,143 @@ private:
// TODO this will result in answering with the delegation. oh well
isc::resolve::copyResponseMessage(incoming, answer_message_);
- return true;
+ return (true);
}
break;
+
case isc::resolve::ResponseClassifier::TRUNCATED:
// Truncated packet. If the protocol we used for the last one is
// UDP, re-query using TCP. Otherwise regard it as an error.
if (protocol_ == IOFetch::UDP) {
- LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_TRUNCATED)
- .arg(questionText(question_));
+ LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS,
+ RESLIB_TRUNCATED).arg(questionText(question_));
send(IOFetch::TCP);
- return false;
+ return (false);
}
- // Was a TCP query so we have received a packet over TCP with the TC
- // bit set: drop through to common error processing.
- // TODO: Can we use what we have received instead of discarding it?
-
- case isc::resolve::ResponseClassifier::EMPTY:
- case isc::resolve::ResponseClassifier::EXTRADATA:
- case isc::resolve::ResponseClassifier::INVNAMCLASS:
- case isc::resolve::ResponseClassifier::INVTYPE:
- case isc::resolve::ResponseClassifier::MISMATQUEST:
- case isc::resolve::ResponseClassifier::MULTICLASS:
- case isc::resolve::ResponseClassifier::NOTONEQUEST:
- case isc::resolve::ResponseClassifier::NOTRESPONSE:
- case isc::resolve::ResponseClassifier::NOTSINGLE:
- case isc::resolve::ResponseClassifier::OPCODE:
+
+ // Was a TCP query so we have received a packet over TCP with the
+ // TC bit set: report an error by going to the common
+ // error code.
+ goto SERVFAIL;
+
case isc::resolve::ResponseClassifier::RCODE:
- LOG_DEBUG(isc::resolve::logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_ERR)
- .arg(questionText(question_));
- // Should we try a different server rather than SERVFAIL?
+ // see if it's a FORMERR and a potential EDNS problem
+ if (incoming.getRcode() == Rcode::FORMERR()) {
+ if (protocol_ == IOFetch::UDP && edns_) {
+ // TODO: in case we absolutely need EDNS (i.e. for DNSSEC
+ // aware queries), we might want to try TCP before we give
+ // up. For now, just try UDP, no EDNS
+ send(IOFetch::UDP, false);
+ return (false);
+ }
+
+ // TC should take care of non-EDNS over UDP, fall through to
+ // SERVFAIL if we get FORMERR instead
+ }
+ goto SERVFAIL;
+
+ default:
+SERVFAIL:
+ // Some error in received packet it. Report it and return SERVFAIL
+ // to the caller.
+ if (logger.isDebugEnabled()) {
+ reportResponseClassifierError(category, incoming.getRcode());
+ }
makeSERVFAIL();
- return true;
- break;
+ return (true);
}
- // Since we do not have a default in the switch above,
- // the compiler should have errored on any missing case
- // statements.
+ // If we get here, there is some serious logic error (or a missing
+ // "return").
assert(false);
- return true;
+ return (true); // To keep the compiler happy
}
-
+
+ /// \brief Report classification-detected error
+ ///
+ /// When the response classifier has detected an error in the response from
+ /// an upstream query, this method is called to log a debug message giving
+ /// information about the problem.
+ ///
+ /// \param category Classification code for the packet
+ /// \param rcode RCODE value in the packet
+ void reportResponseClassifierError(ResponseClassifier::Category category,
+ const Rcode& rcode)
+ {
+ // We could set up a table of response classifications to message
+ // IDs here and index into that table. But given that (a) C++ does
+ // not have C's named initializers, (b) the codes for the
+ // response classifier are in another module and (c) not all messages
+ // have the same number of arguments, the setup of the table would be
+ // almost as long as the code here: it would need to include a number
+ // of assertions to ensure that any change to the the response
+ // classifier codes was detected, and the checking logic would need to
+ // check that the numeric value of the code lay within the defined
+ // limits of the table.
+
+ if (category == ResponseClassifier::RCODE) {
+
+ // Special case as this message takes two arguments.
+ LOG_DEBUG(logger, RESLIB_DBG_RESULTS, RESLIB_RCODE_ERROR).
+ arg(questionText(question_)).arg(rcode);
+
+ } else {
+
+ isc::log::MessageID message_id;
+ switch (category) {
+ case ResponseClassifier::TRUNCATED:
+ message_id = RESLIB_TCP_TRUNCATED;
+ break;
+
+ case ResponseClassifier::EMPTY:
+ message_id = RESLIB_EMPTY_RESPONSE;
+ break;
+
+ case ResponseClassifier::EXTRADATA:
+ message_id = RESLIB_EXTRADATA_RESPONSE;
+ break;
+
+ case ResponseClassifier::INVNAMCLASS:
+ message_id = RESLIB_INVALID_NAMECLASS_RESPONSE;
+ break;
+
+ case ResponseClassifier::INVTYPE:
+ message_id = RESLIB_INVALID_TYPE_RESPONSE;
+ break;
+
+ case ResponseClassifier::MISMATQUEST:
+ message_id = RESLIB_INVALID_QNAME_RESPONSE;
+ break;
+
+ case ResponseClassifier::MULTICLASS:
+ message_id = RESLIB_MULTIPLE_CLASS_RESPONSE;
+ break;
+
+ case ResponseClassifier::NOTONEQUEST:
+ message_id = RESLIB_NOT_ONE_QNAME_RESPONSE;
+ break;
+
+ case ResponseClassifier::NOTRESPONSE:
+ message_id = RESLIB_NOT_RESPONSE;
+ break;
+
+ case ResponseClassifier::NOTSINGLE:
+ message_id = RESLIB_NOTSINGLE_RESPONSE;
+ break;
+
+ case ResponseClassifier::OPCODE:
+ message_id = RESLIB_OPCODE_RESPONSE;
+ break;
+
+ default:
+ message_id = RESLIB_ERROR_RESPONSE;
+ break;
+ }
+ LOG_DEBUG(logger, RESLIB_DBG_RESULTS, message_id).
+ arg(questionText(question_));
+ }
+ }
+
public:
RunningQuery(IOService& io,
const Question& question,
@@ -635,11 +738,14 @@ public:
nsas_(nsas),
cache_(cache),
cur_zone_("."),
- nsas_callback_(new ResolverNSASCallback(this)),
+ nsas_callback_(),
nsas_callback_out_(false),
outstanding_events_(0),
rtt_recorder_(recorder)
{
+ // Set here to avoid using "this" in initializer list.
+ nsas_callback_.reset(new ResolverNSASCallback(this));
+
// Setup the timer to stop trying (lookup_timeout)
if (lookup_timeout >= 0) {
lookup_timer.expires_from_now(
@@ -772,12 +878,7 @@ public:
incoming.fromWire(ibuf);
buffer_->clear();
- if (incoming.getRcode() == Rcode::NOERROR()) {
- done_ = handleRecursiveAnswer(incoming);
- } else {
- isc::resolve::copyResponseMessage(incoming, answer_message_);
- done_ = true;
- }
+ done_ = handleRecursiveAnswer(incoming);
if (done_) {
callCallback(true);
stop();
diff --git a/src/lib/resolve/recursive_query.h b/src/lib/resolve/recursive_query.h
index e9dd72e..a819a94 100644
--- a/src/lib/resolve/recursive_query.h
+++ b/src/lib/resolve/recursive_query.h
@@ -38,7 +38,7 @@ public:
///
/// Adds a round-trip time to the internal vector of times.
///
- /// \param RTT to record.
+ /// \param rtt RTT to record.
void addRtt(uint32_t rtt) {
rtt_.push_back(rtt);
}
@@ -73,6 +73,10 @@ public:
///
/// \param dns_service The DNS Service to perform the recursive
/// query on.
+ /// \param nsas Nameserver address store, used to hold information about zone
+ /// nameservers.
+ /// \param cache Resolver cache object, used to hold information about retrieved
+ /// records.
/// \param upstream Addresses and ports of the upstream servers
/// to forward queries to.
/// \param upstream_root Addresses and ports of the root servers
@@ -83,7 +87,7 @@ public:
/// \param lookup_timeout Timeout value for when we give up, in ms
/// \param retries how many times we try again (0 means just send and
/// and return if it returs).
- RecursiveQuery(DNSService& dns_service,
+ RecursiveQuery(DNSServiceBase& dns_service,
isc::nsas::NameserverAddressStore& nsas,
isc::cache::ResolverCache& cache,
const std::vector<std::pair<std::string, uint16_t> >&
@@ -133,8 +137,10 @@ public:
/// object.
///
/// \param question The question being answered <qname/qclass/qtype>
- /// \param answer_message An output Message into which the final response will be copied
- /// \param buffer An output buffer into which the intermediate responses will be copied
+ /// \param answer_message An output Message into which the final response will
+ /// be copied.
+ /// \param buffer An output buffer into which the intermediate responses will
+ /// be copied.
/// \param server A pointer to the \c DNSServer object handling the client
void resolve(const isc::dns::Question& question,
isc::dns::MessagePtr answer_message,
@@ -147,6 +153,10 @@ public:
/// function resolve().
///
/// \param query_message the full query got from client.
+ /// \param answer_message the full answer received from other server.
+ /// \param buffer Output buffer into which the responses will be copied.
+ /// \param server Server object that handles receipt and processing of the
+ /// received messages.
/// \param callback callback object
void forward(isc::dns::ConstMessagePtr query_message,
isc::dns::MessagePtr answer_message,
@@ -168,7 +178,7 @@ public:
void setTestServer(const std::string& address, uint16_t port);
private:
- DNSService& dns_service_;
+ DNSServiceBase& dns_service_;
isc::nsas::NameserverAddressStore& nsas_;
isc::cache::ResolverCache& cache_;
boost::shared_ptr<std::vector<std::pair<std::string, uint16_t> > >
@@ -181,8 +191,6 @@ private:
int lookup_timeout_;
unsigned retries_;
boost::shared_ptr<RttRecorder> rtt_recorder_; ///< Round-trip time recorder
- // silence MSVC warning C4512: assignment operator could not be generated
- RecursiveQuery& operator=(RecursiveQuery const&);
};
} // namespace asiodns
diff --git a/src/lib/resolve/resolve.cc b/src/lib/resolve/resolve.cc
index d10d25a..4e5614a 100644
--- a/src/lib/resolve/resolve.cc
+++ b/src/lib/resolve/resolve.cc
@@ -37,10 +37,6 @@ namespace {
}
MessagePtr message_;
const Message::Section section_;
- private:
- // silence MSVC warning C4512:
- // assignment operator could not be generated
- SectionInserter& operator=(SectionInserter const&);
};
}
diff --git a/src/lib/resolve/resolve.h b/src/lib/resolve/resolve.h
index 550b620..0a588e2 100644
--- a/src/lib/resolve/resolve.h
+++ b/src/lib/resolve/resolve.h
@@ -37,7 +37,6 @@ namespace resolve {
/// section), you can simply use this to create an error response.
///
/// \param answer_message The message to clear and place the error in
-/// \param question The question to add to the
/// \param error_code The error Rcode
void makeErrorMessage(isc::dns::MessagePtr answer_message,
const isc::dns::Rcode& error_code);
diff --git a/src/lib/resolve/resolve_log.h b/src/lib/resolve/resolve_log.h
index 1f2869e..828b9d3 100644
--- a/src/lib/resolve/resolve_log.h
+++ b/src/lib/resolve/resolve_log.h
@@ -27,17 +27,17 @@ namespace resolve {
/// Note that higher numbers equate to more verbose (and detailed) output.
// The first level traces normal operations
-const int RESLIB_DBG_TRACE = 10;
+const int RESLIB_DBG_TRACE = DBGLVL_TRACE_BASIC;
// The next level extends the normal operations and records the results of the
// lookups.
-const int RESLIB_DBG_RESULTS = 20;
+const int RESLIB_DBG_RESULTS = DBGLVL_TRACE_BASIC_DATA;
// Report cache lookups and results
-const int RESLIB_DBG_CACHE = 40;
+const int RESLIB_DBG_CACHE = DBGLVL_TRACE_DETAIL_DATA;
// Indicate when callbacks are called
-const int RESLIB_DBG_CB = 50;
+const int RESLIB_DBG_CB = DBGLVL_TRACE_DETAIL_DATA + 10;
/// \brief Resolver Library Logger
diff --git a/src/lib/resolve/resolve_messages.mes b/src/lib/resolve/resolve_messages.mes
index f702d9b..1df544a 100644
--- a/src/lib/resolve/resolve_messages.mes
+++ b/src/lib/resolve/resolve_messages.mes
@@ -15,22 +15,61 @@
$NAMESPACE isc::resolve
% RESLIB_ANSWER answer received in response to query for <%1>
-A debug message recording that an answer has been received to an upstream
-query for the specified question. Previous debug messages will have indicated
-the server to which the question was sent.
+A debug message reporting that an answer has been received to an upstream
+query for the specified question. Previous debug messages will have
+indicated the server to which the question was sent.
% RESLIB_CNAME CNAME received in response to query for <%1>
-A debug message recording that CNAME response has been received to an upstream
-query for the specified question. Previous debug messages will have indicated
-the server to which the question was sent.
+A debug message recording that CNAME response has been received to an
+upstream query for the specified question. Previous debug messages will
+have indicated the server to which the question was sent.
% RESLIB_DEEPEST did not find <%1> in cache, deepest delegation found is %2
-A debug message, a cache lookup did not find the specified <name, class,
-type> tuple in the cache; instead, the deepest delegation found is indicated.
+A debug message, a cache lookup did not find the specified <name,
+class, type> tuple in the cache; instead, the deepest delegation found
+is indicated.
+
+% RESLIB_EMPTY_RESPONSE empty response received to query for <%1>
+A debug message, the response to the specified query from an upstream
+nameserver did not contain anything in the answer or authority sections,
+although in all other respects it was a valid response. A SERVFAIL will
+be returned to the system making the original query.
+
+% RESLIB_ERROR_RESPONSE unspecified error received in response to query for <%1>
+A debug message, the response to the specified query to an upstream
+nameserver indicated that the response was classified as an erroneous
+response, but that the nature of the error cannot be identified.
+A SERVFAIL will be returned to the system making the original query.
+
+% RESLIB_EXTRADATA_RESPONSE extra data in response to query for <%1>
+A debug message indicating that the response to the specified query
+from an upstream nameserver contained too much data. This can happen if
+an ANY query was sent and the answer section in the response contained
+multiple RRs with different names. A SERVFAIL will be returned to the
+system making the original query.
% RESLIB_FOLLOW_CNAME following CNAME chain to <%1>
-A debug message, a CNAME response was received and another query is being issued
-for the <name, class, type> tuple.
+A debug message, a CNAME response was received and another query is
+being issued for the <name, class, type> tuple.
+
+% RESLIB_INVALID_NAMECLASS_RESPONSE invalid name or class in response to query for <%1>
+A debug message, the response to the specified query from an upstream
+nameserver (as identified by the ID of the response) contained either
+an answer not matching the query name or an answer having a different
+class to that queried for. A SERVFAIL will be returned to the system
+making the original query.
+
+% RESLIB_INVALID_QNAME_RESPONSE invalid name or class in response to query for <%1>
+A debug message, the response to the specified query from an upstream
+nameserver (as identified by the ID of the response) contained a name
+in the question section that did not match that of the query. A SERVFAIL
+will be returned to the system making the original query.
+
+% RESLIB_INVALID_TYPE_RESPONSE invalid name or class in response to query for <%1>
+A debug message, the response to the specified query from an upstream
+nameserver (as identified by the ID of the response) contained an
+invalid type field. A SERVFAIL will be returned to the system making
+the original query.
% RESLIB_LONG_CHAIN CNAME received in response to query for <%1>: CNAME chain length exceeded
A debug message recording that a CNAME response has been received to an upstream
@@ -39,6 +78,30 @@ the server to which the question was sent). However, receipt of this CNAME
has meant that the resolver has exceeded the CNAME chain limit (a CNAME chain
is where on CNAME points to another) and so an error is being returned.
+% RESLIB_MULTIPLE_CLASS_RESPONSE response to query for <%1> contained multiple RRsets with different classes
+A debug message reporting that the response to an upstream query for
+the specified name contained multiple RRsets in the answer and not all
+were of the same class. This is a violation of the standard and so a
+SERVFAIL will be returned.
+
+% RESLIB_NOTSINGLE_RESPONSE response to query for <%1> was not a response
+A debug message, the response to the specified query from an upstream
+nameserver was a CNAME that had mutiple RRs in the RRset. This is
+an invalid response according to the standards so a SERVFAIL will be
+returned to the system making the original query.
+
+% RESLIB_NOT_ONE_QNAME_RESPONSE not one question in response to query for <%1>
+A debug message, the response to the specified query from an upstream
+nameserver (as identified by the ID of the response) did not contain
+one name in the question section as required by the standard. A SERVFAIL
+will be returned to the system making the original query.
+
+% RESLIB_NOT_RESPONSE response to query for <%1> was not a response
+A debug message, the response to the specified query from an upstream
+nameserver (as identified by the ID of the response) did not have the QR
+bit set (thus indicating that the packet was a query, not a response).
+A SERVFAIL will be returned to the system making the original query.
+
% RESLIB_NO_NS_RRSET no NS RRSet in referral response received to query for <%1>
A debug message, this indicates that a response was received for the specified
query and was categorized as a referral. However, the received message did
@@ -54,6 +117,13 @@ A debug message recording that either a NXDOMAIN or an NXRRSET response has
been received to an upstream query for the specified question. Previous debug
messages will have indicated the server to which the question was sent.
+% RESLIB_OPCODE_RESPONSE response to query for <%1> did not have query opcode
+A debug message, the response to the specified query from an upstream
+nameserver was a response that did not have the opcode set to that of
+a query. According to the standards, this is an invalid response to
+the query that was made, so a SERVFAIL will be returned to the system
+making the original query.
+
% RESLIB_PROTOCOL protocol error in answer for %1: %3
A debug message indicating that a protocol error was received. As there
are no retries left, an error will be reported.
@@ -63,7 +133,7 @@ A debug message indicating that a protocol error was received and that
the resolver is repeating the query to the same nameserver. After this
repeated query, there will be the indicated number of retries left.
-% RESLIB_RCODE_ERR RCODE indicates error in response to query for <%1>
+% RESLIB_RCODE_ERROR response to query for <%1> returns RCODE of %2
A debug message, the response to the specified query indicated an error
that is not covered by a specific code path. A SERVFAIL will be returned.
@@ -122,6 +192,11 @@ A debug message indicating that a RunningQuery's success callback has been
called because a nameserver has been found, and that a query is being sent
to the specified nameserver.
+% RESLIB_TCP_TRUNCATED TCP response to query for %1 was truncated
+This is a debug message logged when a response to the specified query to an
+upstream nameserver returned a response with the TC (truncation) bit set. This
+is treated as an error by the code.
+
% RESLIB_TEST_SERVER setting test server to %1(%2)
This is a warning message only generated in unit tests. It indicates
that all upstream queries from the resolver are being routed to the
diff --git a/src/lib/resolve/response_classifier.cc b/src/lib/resolve/response_classifier.cc
index 3cf37f8..27c5cfc 100644
--- a/src/lib/resolve/response_classifier.cc
+++ b/src/lib/resolve/response_classifier.cc
@@ -119,7 +119,7 @@ ResponseClassifier::Category ResponseClassifier::classify(
if (authority.empty()) {
return (EMPTY);
}
- for (unsigned int i = 0; i < authority.size(); ++i) {
+ for (vector<RRsetPtr>::size_type i = 0; i < authority.size(); ++i) {
if (authority[i]->getType() == RRType::NS()) {
return (REFERRAL);
}
@@ -161,7 +161,7 @@ ResponseClassifier::Category ResponseClassifier::classify(
// There are multiple RRsets in the answer. They should all have the same
// QCLASS, else there is some error in the response.
- for (unsigned int i = 1; i < answer.size(); ++i) {
+ for (vector<RRsetPtr>::size_type i = 1; i < answer.size(); ++i) {
if (answer[0]->getClass() != answer[i]->getClass()) {
return (MULTICLASS);
}
@@ -173,7 +173,8 @@ ResponseClassifier::Category ResponseClassifier::classify(
// CNAME - in which case there should no other record types at that QNAME.
if (question.getType() == RRType::ANY()) {
bool all_same = true;
- for (unsigned int i = 1; (i < answer.size()) && all_same; ++i) {
+ for (vector<RRsetPtr>::size_type i = 1; (i < answer.size()) && all_same;
+ ++i) {
all_same = (answer[0]->getName() == answer[i]->getName());
}
if (all_same) {
@@ -211,7 +212,7 @@ ResponseClassifier::Category ResponseClassifier::cnameChase(
{
// Search through the vector of RRset pointers until we find one with the
// right QNAME.
- for (unsigned int i = 0; i < ansrrset.size(); ++i) {
+ for (vector<RRsetPtr>::size_type i = 0; i < ansrrset.size(); ++i) {
if (present[i]) {
// This entry has not been logically removed, so look at it.
diff --git a/src/lib/resolve/response_classifier.h b/src/lib/resolve/response_classifier.h
index 3821560..a027bd0 100644
--- a/src/lib/resolve/response_classifier.h
+++ b/src/lib/resolve/response_classifier.h
@@ -151,7 +151,7 @@ private:
size_t size);
};
-#endif // __RESPONSE_CLASSIFIER_H
-
} // namespace resolve
} // namespace isc
+
+#endif // __RESPONSE_CLASSIFIER_H
diff --git a/src/lib/resolve/tests/.gitignore b/src/lib/resolve/tests/.gitignore
new file mode 100644
index 0000000..d6d1ec8
--- /dev/null
+++ b/src/lib/resolve/tests/.gitignore
@@ -0,0 +1 @@
+/run_unittests
diff --git a/src/lib/resolve/tests/Makefile.am b/src/lib/resolve/tests/Makefile.am
index cf05d9b..97afe5c 100644
--- a/src/lib/resolve/tests/Makefile.am
+++ b/src/lib/resolve/tests/Makefile.am
@@ -8,6 +8,9 @@ endif
CLEANFILES = *.gcno *.gcda
+TESTS_ENVIRONMENT = \
+ $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
TESTS =
if HAVE_GTEST
TESTS += run_unittests
@@ -23,6 +26,7 @@ run_unittests_SOURCES += resolver_callback_unittest.cc
run_unittests_SOURCES += response_classifier_unittest.cc
run_unittests_SOURCES += recursive_query_unittest.cc
run_unittests_SOURCES += recursive_query_unittest_2.cc
+run_unittests_SOURCES += recursive_query_unittest_3.cc
run_unittests_LDADD = $(GTEST_LDADD)
run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
diff --git a/src/lib/resolve/tests/recursive_query_unittest.cc b/src/lib/resolve/tests/recursive_query_unittest.cc
index 01a6428..b63738e 100644
--- a/src/lib/resolve/tests/recursive_query_unittest.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest.cc
@@ -19,14 +19,17 @@
#include <mswsock.h>
#include <time.h>
#else
+#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#endif
-#include <string.h>
+#include <cstring>
+#include <boost/noncopyable.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <gtest/gtest.h>
@@ -67,6 +70,7 @@ using namespace isc::asiodns;
using namespace isc::asiolink;
using namespace isc::dns;
using namespace isc::util;
+using boost::scoped_ptr;
namespace isc {
namespace asiodns {
@@ -90,18 +94,14 @@ const char* const TEST_IPV4_ADDR = "127.0.0.1";
// for the tests below.
const uint8_t test_data[] = {0, 4, 1, 2, 3, 4};
-// This function returns an addrinfo structure for use by tests, using
-// different addresses and ports depending on whether we're testing
-// IPv4 or v6, TCP or UDP, and client or server operation.
+// This function returns an addrinfo structure for use by tests.
struct addrinfo*
-resolveAddress(const int family, const int protocol, const bool client) {
- const char* const addr = (family == AF_INET6) ?
- TEST_IPV6_ADDR : TEST_IPV4_ADDR;
- const char* const port = client ? TEST_CLIENT_PORT : TEST_SERVER_PORT;
-
+resolveAddress(const int protocol, const char* const addr,
+ const char* const port)
+{
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = family;
+ hints.ai_family = AF_UNSPEC; // let the address decide it.
hints.ai_socktype = (protocol == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
hints.ai_protocol = protocol;
hints.ai_flags = AI_NUMERICSERV;
@@ -115,6 +115,73 @@ resolveAddress(const int family, const int protocol, const bool client) {
return (res);
}
+// convenience shortcut of the other version using different addresses and
+// ports depending on whether we're testing IPv4 or v6, TCP or UDP, and
+// client or server operation.
+struct addrinfo*
+resolveAddress(const int family, const int protocol, const bool client) {
+ return (resolveAddress(protocol,
+ (family == AF_INET6) ? TEST_IPV6_ADDR :
+ TEST_IPV4_ADDR,
+ client ? TEST_CLIENT_PORT : TEST_SERVER_PORT));
+}
+
+// A helper holder of addrinfo so we can safely release the resource
+// either when leaving the defined scope either normally or due to exception.
+struct ScopedAddrInfo {
+ ScopedAddrInfo(struct addrinfo* res) : res_(res) {}
+ ~ScopedAddrInfo() { freeaddrinfo(res_); }
+ struct addrinfo* res_;
+};
+
+// Similar to ScopedAddrInfo but for socket FD. It also supports the "release"
+// operation so it can release the ownership of the FD.
+// This is made non copyable to avoid making an accidental copy, which could
+// result in duplicate close.
+struct ScopedSocket : private boost::noncopyable {
+#ifdef _WIN32
+ ScopedSocket() : s_(INVALID_SOCKET) {}
+ ScopedSocket(SOCKET s) : s_(s) {}
+ ~ScopedSocket() {
+ if (s_ != INVALID_SOCKET) {
+ closesocket(s_);
+ }
+ }
+ void reset(SOCKET new_s) {
+ if (s_ != INVALID_SOCKET) {
+ closesocket(s_);
+ }
+ s_ = new_s;
+ }
+ SOCKET release() {
+ SOCKET s = s_;
+ s_ = INVALID_SOCKET;
+ return (s);
+ }
+ SOCKET s_;
+#else
+ ScopedSocket() : s_(-1) {}
+ ScopedSocket(int s) : s_(s) {}
+ ~ScopedSocket() {
+ if (s_ >= 0) {
+ close(s_);
+ }
+ }
+ void reset(int new_s) {
+ if (s_ >= 0) {
+ close(s_);
+ }
+ s_ = new_s;
+ }
+ int release() {
+ int s = s_;
+ s_ = -1;
+ return (s);
+ }
+ int s_;
+#endif
+};
+
// This fixture is a framework for various types of network operations
// using the ASIO interfaces. Each test case creates an IOService object,
// opens a local "client" socket for testing, sends data via the local socket
@@ -134,98 +201,91 @@ protected:
// It would delete itself, but after the io_service_, which could
// segfailt in case there were unhandled requests
resolver_.reset();
- if (res_ != NULL) {
- freeaddrinfo(res_);
- }
-#ifdef _WIN32
- if (sock_ != INVALID_SOCKET) {
- closesocket(sock_);
- }
-#else
- if (sock_ != -1) {
- close(sock_);
- }
-#endif
- delete dns_service_;
- delete callback_;
- delete io_service_;
+ }
+
+ void SetUp() {
+ callback_.reset(new ASIOCallBack(this));
}
// Send a test UDP packet to a mock server
void sendUDP(const int family) {
- res_ = resolveAddress(family, IPPROTO_UDP, false);
+ ScopedAddrInfo sai(resolveAddress(family, IPPROTO_UDP, false));
+ struct addrinfo* res = sai.res_;
- sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
+ sock_.reset(socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol));
#ifdef _WIN32
- if (sock_ == INVALID_SOCKET) {
+ if (sock_.s_ == INVALID_SOCKET) {
isc_throw(IOError, "failed to open test socket");
}
- const int cc = sendto(sock_,
+ const int cc = sendto(sock_.s_,
(const char *) test_data, sizeof(test_data), 0,
- res_->ai_addr, res_->ai_addrlen);
+ res->ai_addr, res->ai_addrlen);
#else
- if (sock_ < 0) {
+ if (sock_.s_ < 0) {
isc_throw(IOError, "failed to open test socket");
}
- const int cc = sendto(sock_, test_data, sizeof(test_data), 0,
- res_->ai_addr, res_->ai_addrlen);
+ const int cc = sendto(sock_.s_, test_data, sizeof(test_data), 0,
+ res->ai_addr, res->ai_addrlen);
#endif
if (cc != sizeof(test_data)) {
isc_throw(IOError, "unexpected sendto result: " << cc);
}
- io_service_->run();
+ io_service_.run();
}
// Send a test TCP packet to a mock server
void sendTCP(const int family) {
- res_ = resolveAddress(family, IPPROTO_TCP, false);
+ ScopedAddrInfo sai(resolveAddress(family, IPPROTO_TCP, false));
+ struct addrinfo* res = sai.res_;
- sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
+ sock_.reset(socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol));
#ifdef _WIN32
- if (sock_ == INVALID_SOCKET) {
+ if (sock_.s_ == INVALID_SOCKET) {
isc_throw(IOError, "failed to open test socket");
}
#else
- if (sock_ < 0) {
+ if (sock_.s_ < 0) {
isc_throw(IOError, "failed to open test socket");
}
#endif
- if (connect(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
+ if (connect(sock_.s_, res->ai_addr, res->ai_addrlen) < 0) {
isc_throw(IOError, "failed to connect to the test server");
}
#ifdef _WIN32
- const int cc = send(sock_, (const char *) test_data,
- sizeof(test_data), 0);
+ const int cc = send(sock_.s_,
+ (const char *) test_data, sizeof(test_data), 0);
#else
- const int cc = send(sock_, test_data, sizeof(test_data), 0);
+ const int cc = send(sock_.s_, test_data, sizeof(test_data), 0);
#endif
if (cc != sizeof(test_data)) {
isc_throw(IOError, "unexpected send result: " << cc);
}
- io_service_->run();
+ io_service_.run();
}
// Receive a UDP packet from a mock server; used for testing
// recursive lookup. The caller must place a RecursiveQuery
// on the IO Service queue before running this routine.
void recvUDP(const int family, void* buffer, size_t& size) {
- res_ = resolveAddress(family, IPPROTO_UDP, true);
+ ScopedAddrInfo sai(resolveAddress(family, IPPROTO_UDP, true));
+ struct addrinfo* res = sai.res_;
- sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
+ sock_.reset(socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol));
#ifdef _WIN32
- if (sock_ == INVALID_SOCKET) {
+ if (sock_.s_ == INVALID_SOCKET) {
isc_throw(IOError, "failed to open test socket");
}
-
- if (::bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
+ if (::bind(sock_.s_, res->ai_addr, res->ai_addrlen) < 0) {
isc_throw(IOError, "bind failed: " << strerror(WSAGetLastError()));
}
#else
- if (sock_ < 0) {
+ if (sock_.s_ < 0) {
isc_throw(IOError, "failed to open test socket");
}
-
- if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
+ if (bind(sock_.s_, res->ai_addr, res->ai_addrlen) < 0) {
isc_throw(IOError, "bind failed: " << strerror(errno));
}
#endif
@@ -233,10 +293,10 @@ protected:
// The IO service queue should have a RecursiveQuery object scheduled
// to run at this point. This call will cause it to begin an
// async send, then return.
- io_service_->run_one();
+ io_service_.run_one();
// ... and this one will block until the send has completed
- io_service_->run_one();
+ io_service_.run_one();
// Now we attempt to recv() whatever was sent.
// XXX: there's no guarantee the receiving socket can immediately get
@@ -247,19 +307,18 @@ protected:
const struct timeval timeo = { 10, 0 };
int recv_options = 0;
#ifdef _WIN32
- if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO,
+ if (setsockopt(sock_.s_, SOL_SOCKET, SO_RCVTIMEO,
(const char *) &timeo, sizeof(timeo))) {
- isc_throw(IOError,
- "set RCVTIMEO failed: " <<
- strerror(WSAGetLastError()));
+ isc_throw(IOError,
+ "set RCVTIMEO failed: " << strerror(WSAGetLastError()));
}
- const int ret = recv(sock_, (char *) buffer, size, recv_options);
+ const int ret = recv(sock_.s_, (char *) buffer, size, recv_options);
if (ret < 0) {
isc_throw(IOError,
"recvfrom failed: " << strerror(WSAGetLastError()));
}
#else
- if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo,
+ if (setsockopt(sock_.s_, SOL_SOCKET, SO_RCVTIMEO, &timeo,
sizeof(timeo))) {
if (errno == ENOPROTOOPT) {
// Workaround for Solaris: it doesn't accept SO_RCVTIMEO
@@ -272,48 +331,93 @@ protected:
isc_throw(IOError, "set RCVTIMEO failed: " << strerror(errno));
}
}
- const int ret = recv(sock_, buffer, size, recv_options);
+ const int ret = recv(sock_.s_, buffer, size, recv_options);
if (ret < 0) {
isc_throw(IOError, "recvfrom failed: " << strerror(errno));
}
-#endif
-
+#endif
// Pass the message size back via the size parameter
size = ret;
}
+ void
+ addServer(const string& address, const char* const port, int protocol) {
+ ScopedAddrInfo sai(resolveAddress(protocol, address.c_str(), port));
+ struct addrinfo* res = sai.res_;
+ const int family = res->ai_family;
+
+ ScopedSocket sock(socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol));
+#ifdef _WIN32
+ const SOCKET s = sock.s_;
+ if (s == INVALID_SOCKET) {
+ isc_throw(isc::Unexpected, "failed to open a test socket");
+ }
+ const int on = 1;
+ if (family == AF_INET6) {
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+ (const char *) &on, sizeof(on)) == -1) {
+ isc_throw(isc::Unexpected,
+ "failed to set socket option(IPV6_V6ONLY)");
+ }
+ }
+ if (::bind(s, res->ai_addr, res->ai_addrlen) != 0) {
+ isc_throw(isc::Unexpected, "failed to bind a test socket");
+ }
+#else
+ const int s = sock.s_;
+ if (s < 0) {
+ isc_throw(isc::Unexpected, "failed to open a test socket");
+ }
+ const int on = 1;
+ if (family == AF_INET6) {
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) ==
+ -1) {
+ isc_throw(isc::Unexpected,
+ "failed to set socket option(IPV6_V6ONLY)");
+ }
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
+ isc_throw(isc::Unexpected,
+ "failed to set socket option(SO_REUSEADDR)");
+ }
+ if (bind(s, res->ai_addr, res->ai_addrlen) != 0) {
+ isc_throw(isc::Unexpected, "failed to bind a test socket");
+ }
+#endif
+ if (protocol == IPPROTO_TCP) {
+ dns_service_->addServerTCPFromFD(sock.release(), family);
+ } else {
+ dns_service_->addServerUDPFromFD(sock.release(), family);
+ }
+ }
// Set up an IO Service queue using the specified address
- void setDNSService(const char& address) {
- delete dns_service_;
- dns_service_ = NULL;
- delete io_service_;
- io_service_ = new IOService();
- callback_ = new ASIOCallBack(this);
- dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, address, callback_, NULL, NULL);
+ void setDNSService(const string& address) {
+ setDNSService();
+ addServer(address, TEST_SERVER_PORT, IPPROTO_TCP);
+ addServer(address, TEST_SERVER_PORT, IPPROTO_UDP);
}
// Set up an IO Service queue using the "any" address, on IPv4 if
// 'use_ipv4' is true and on IPv6 if 'use_ipv6' is true.
void setDNSService(const bool use_ipv4, const bool use_ipv6) {
- delete dns_service_;
- dns_service_ = NULL;
- delete io_service_;
- io_service_ = new IOService();
- callback_ = new ASIOCallBack(this);
- dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, use_ipv4, use_ipv6, callback_,
- NULL, NULL);
+ setDNSService();
+ if (use_ipv6) {
+ addServer("::", TEST_SERVER_PORT, IPPROTO_TCP);
+ addServer("::", TEST_SERVER_PORT, IPPROTO_UDP);
+ }
+ if (use_ipv4) {
+ addServer("0.0.0.0", TEST_SERVER_PORT, IPPROTO_TCP);
+ addServer("0.0.0.0", TEST_SERVER_PORT, IPPROTO_UDP);
+ }
}
// Set up empty DNS Service
// Set up an IO Service queue without any addresses
void setDNSService() {
- delete dns_service_;
- dns_service_ = NULL;
- delete io_service_;
- io_service_ = new IOService();
- callback_ = new ASIOCallBack(this);
- dns_service_ = new DNSService(*io_service_, callback_, NULL, NULL);
+ dns_service_.reset(new DNSService(io_service_, callback_.get(), NULL,
+ NULL));
}
// Run a simple server test, on either IPv4 or IPv6, and over either
@@ -332,7 +436,7 @@ protected:
// There doesn't seem to be an effective test for the validity of
// 'native'.
// One thing we are sure is it must be different from our local socket.
- EXPECT_NE(sock_, callback_native_);
+ EXPECT_NE(sock_.s_, callback_native_);
EXPECT_EQ(protocol, callback_protocol_);
EXPECT_EQ(family == AF_INET6 ? TEST_IPV6_ADDR : TEST_IPV4_ADDR,
callback_address_);
@@ -367,7 +471,7 @@ protected:
void operator()(asio::error_code ec = asio::error_code(),
size_t length = 0)
- { ec; }
+ {}
void resume(const bool) {
// should never be called in our tests
@@ -401,9 +505,6 @@ protected:
const SimpleCallback* checkin_;
const DNSLookup* lookup_;
const DNSAnswer* answer_;
- // silence MSVC warning C4512:
- // assignment operator could not be generated
- MockServer& operator=(MockServer const&);
};
// This version of mock server just stops the io_service when it is resumed
@@ -424,9 +525,6 @@ protected:
}
private:
bool* done_;
- // silence MSVC warning C4512:
- // assignment operator could not be generated
- MockServerStop& operator=(MockServerStop const&);
};
// This version of mock server just stops the io_service when it is resumed
@@ -460,9 +558,6 @@ protected:
bool* done1_;
bool* done2_;
bool stopped_once_;
- // silence MSVC warning C4512:
- // assignment operator could not be generated
- MockServerStop2& operator=(MockServerStop2 const&);
};
private:
@@ -484,48 +579,55 @@ private:
static_cast<const uint8_t*>(io_message.getData()),
static_cast<const uint8_t*>(io_message.getData()) +
io_message.getDataSize());
- io_service_->stop();
+ io_service_.stop();
}
protected:
- // We use a pointer for io_service_, because for some tests we
- // need to recreate a new one within one onstance of this class
- IOService* io_service_;
- DNSService* dns_service_;
- isc::nsas::NameserverAddressStore* nsas_;
+ IOService io_service_;
+ scoped_ptr<DNSService> dns_service_;
+ scoped_ptr<isc::nsas::NameserverAddressStore> nsas_;
isc::cache::ResolverCache cache_;
- ASIOCallBack* callback_;
+ scoped_ptr<ASIOCallBack> callback_;
int callback_protocol_;
+#ifdef _WIN32
+ SOCKET callback_native_;
+#else
int callback_native_;
+#endif
string callback_address_;
vector<uint8_t> callback_data_;
- int sock_;
- struct addrinfo* res_;
+ ScopedSocket sock_;
boost::shared_ptr<isc::util::unittests::TestResolver> resolver_;
};
RecursiveQueryTest::RecursiveQueryTest() :
dns_service_(NULL), callback_(NULL), callback_protocol_(0),
- callback_native_(-1), sock_(-1), res_(NULL),
+#ifdef _WIN32
+ callback_native_(INVALID_SOCKET),
+#else
+ callback_native_(-1),
+#endif
resolver_(new isc::util::unittests::TestResolver())
{
- io_service_ = new IOService();
- setDNSService(true, true);
- nsas_ = new isc::nsas::NameserverAddressStore(resolver_);
+ nsas_.reset(new isc::nsas::NameserverAddressStore(resolver_));
}
TEST_F(RecursiveQueryTest, v6UDPSend) {
+ setDNSService(true, true);
doTest(AF_INET6, IPPROTO_UDP);
}
TEST_F(RecursiveQueryTest, v6TCPSend) {
+ setDNSService(true, true);
doTest(AF_INET6, IPPROTO_TCP);
}
TEST_F(RecursiveQueryTest, v4UDPSend) {
+ setDNSService(true, true);
doTest(AF_INET, IPPROTO_UDP);
}
TEST_F(RecursiveQueryTest, v4TCPSend) {
+ setDNSService(true, true);
doTest(AF_INET, IPPROTO_TCP);
}
@@ -541,24 +643,24 @@ TEST_F(RecursiveQueryTest, v6UDPSendSpecific) {
// an error on a subsequent read operation. We could do it, but for
// simplicity we only tests the easier cases for now.
- setDNSService(*TEST_IPV6_ADDR);
+ setDNSService(TEST_IPV6_ADDR);
doTest(AF_INET6, IPPROTO_UDP);
}
TEST_F(RecursiveQueryTest, v6TCPSendSpecific) {
- setDNSService(*TEST_IPV6_ADDR);
+ setDNSService(TEST_IPV6_ADDR);
doTest(AF_INET6, IPPROTO_TCP);
EXPECT_THROW(sendTCP(AF_INET), IOError);
}
TEST_F(RecursiveQueryTest, v4UDPSendSpecific) {
- setDNSService(*TEST_IPV4_ADDR);
+ setDNSService(TEST_IPV4_ADDR);
doTest(AF_INET, IPPROTO_UDP);
}
TEST_F(RecursiveQueryTest, v4TCPSendSpecific) {
- setDNSService(*TEST_IPV4_ADDR);
+ setDNSService(TEST_IPV4_ADDR);
doTest(AF_INET, IPPROTO_TCP);
EXPECT_THROW(sendTCP(AF_INET6), IOError);
@@ -566,7 +668,7 @@ TEST_F(RecursiveQueryTest, v4TCPSendSpecific) {
TEST_F(RecursiveQueryTest, v6AddServer) {
setDNSService();
- dns_service_->addServer(*TEST_SERVER_PORT, TEST_IPV6_ADDR);
+ addServer(TEST_IPV6_ADDR, TEST_SERVER_PORT, IPPROTO_TCP);
doTest(AF_INET6, IPPROTO_TCP);
EXPECT_THROW(sendTCP(AF_INET), IOError);
@@ -574,7 +676,7 @@ TEST_F(RecursiveQueryTest, v6AddServer) {
TEST_F(RecursiveQueryTest, v4AddServer) {
setDNSService();
- dns_service_->addServer(*TEST_SERVER_PORT, TEST_IPV4_ADDR);
+ addServer(TEST_IPV4_ADDR, TEST_SERVER_PORT, IPPROTO_TCP);
doTest(AF_INET, IPPROTO_TCP);
EXPECT_THROW(sendTCP(AF_INET6), IOError);
@@ -603,9 +705,9 @@ TEST_F(RecursiveQueryTest, v4TCPOnly) {
vector<pair<string, uint16_t> >
singleAddress(const string &address, uint16_t port) {
- vector<pair<string, uint16_t> > result_;
- result_.push_back(pair<string, uint16_t>(address, port));
- return (result_);
+ vector<pair<string, uint16_t> > results;
+ results.push_back(pair<string, uint16_t>(address, port));
+ return (results);
}
TEST_F(RecursiveQueryTest, recursiveSetupV4) {
@@ -638,7 +740,7 @@ TEST_F(RecursiveQueryTest, forwarderSend) {
// to the same port as the actual server
uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
- MockServer server(*io_service_);
+ MockServer server(io_service_);
RecursiveQuery rq(*dns_service_,
*nsas_, cache_,
singleAddress(TEST_IPV4_ADDR, port),
@@ -670,41 +772,52 @@ TEST_F(RecursiveQueryTest, forwarderSend) {
EXPECT_EQ(q.getClass(), q2->getClass());
}
+#ifdef _WIN32
+SOCKET
+#else
int
-createTestSocket()
-{
- struct addrinfo* res_ = resolveAddress(AF_INET, IPPROTO_UDP, true);
- int sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
+#endif
+createTestSocket() {
+ ScopedAddrInfo sai(resolveAddress(AF_INET, IPPROTO_UDP, true));
+ struct addrinfo* res = sai.res_;
+
+ ScopedSocket sock(socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol));
#ifdef _WIN32
- if (sock_ == INVALID_SOCKET) {
+ if (sock.s_ == INVALID_SOCKET) {
isc_throw(IOError, "failed to open test socket");
}
- if (::bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
+ if (::bind(sock.s_, res->ai_addr, res->ai_addrlen) < 0) {
isc_throw(IOError, "failed to bind test socket");
}
#else
- if (sock_ < 0) {
+ if (sock.s_ < 0) {
isc_throw(IOError, "failed to open test socket");
}
- if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
+ if (bind(sock.s_, res->ai_addr, res->ai_addrlen) < 0) {
isc_throw(IOError, "failed to bind test socket");
}
#endif
- return sock_;
+ return (sock.release());
}
int
-setSocketTimeout(int sock_, size_t tv_sec, size_t tv_usec) {
+#ifdef _WIN32
+setSocketTimeout(SOCKET sock, size_t tv_sec, size_t tv_usec)
+#else
+setSocketTimeout(int sock, size_t tv_sec, size_t tv_usec)
+#endif
+{
const struct timeval timeo = { tv_sec, tv_usec };
int recv_options = 0;
#ifdef _WIN32
- if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO,
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
(const char *) &timeo, sizeof(timeo))) {
isc_throw(IOError,
- "set RCVTIMEO failed: " << strerror(WSAGetLastError()));
+ "set RCVTIMEO failed: " << strerror(WSAGetLastError()));
}
#else
- if (setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo))) {
if (errno == ENOPROTOOPT) { // see RecursiveQueryTest::recvUDP()
recv_options = MSG_DONTWAIT;
} else {
@@ -712,17 +825,22 @@ setSocketTimeout(int sock_, size_t tv_sec, size_t tv_usec) {
}
}
#endif
- return recv_options;
+ return (recv_options);
}
// try to read from the socket max time
// *num is incremented for every succesfull read
// returns true if it can read max times, false otherwise
-bool tryRead(int sock_, int recv_options, size_t max, int* num) {
+#ifdef
+bool tryRead(SOCKET sock, int recv_options, size_t max, int* num)
+#else
+bool tryRead(int sock, int recv_options, size_t max, int* num)
+#endif
+{
size_t i = 0;
do {
char inbuff[512];
- if (recv(sock_, inbuff, sizeof(inbuff), recv_options) < 0) {
+ if (recv(sock, inbuff, sizeof(inbuff), recv_options) < 0) {
return false;
} else {
++i;
@@ -742,7 +860,7 @@ public:
};
MockResolverCallback(DNSServer* server):
- result(DEFAULT),
+ result_(DEFAULT),
server_(server->clone())
{}
@@ -751,16 +869,16 @@ public:
}
void success(const isc::dns::MessagePtr response) {
- result = SUCCESS;
+ result_ = SUCCESS;
server_->resume(true);
}
void failure() {
- result = FAILURE;
+ result_ = FAILURE;
server_->resume(false);
}
- uint32_t result;
+ uint32_t result_;
private:
DNSServer* server_;
};
@@ -772,11 +890,11 @@ TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
setDNSService();
// Prepare the socket
- sock_ = createTestSocket();
+ sock_.reset(createTestSocket());
// Prepare the server
bool done(true);
- MockServerStop server(*io_service_, &done);
+ MockServerStop server(io_service_, &done);
// Do the answer
const uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
@@ -794,7 +912,7 @@ TEST_F(RecursiveQueryTest, forwardQueryTimeout) {
boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
// Run the test
- io_service_->run();
+ io_service_.run();
EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
}
@@ -806,11 +924,11 @@ TEST_F(RecursiveQueryTest, forwardClientTimeout) {
// Prepare the service (we do not use the common setup, we do not answer
setDNSService();
- sock_ = createTestSocket();
+ sock_.reset(createTestSocket());
// Prepare the server
bool done1(true);
- MockServerStop server(*io_service_, &done1);
+ MockServerStop server(io_service_, &done1);
MessagePtr answer(new Message(Message::RENDER));
@@ -829,7 +947,7 @@ TEST_F(RecursiveQueryTest, forwardClientTimeout) {
boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
// Run the test
- io_service_->run();
+ io_service_.run();
EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
}
@@ -840,11 +958,11 @@ TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
setDNSService();
// Prepare the socket
- sock_ = createTestSocket();
+ sock_.reset(createTestSocket());
// Prepare the server
bool done(true);
- MockServerStop server(*io_service_, &done);
+ MockServerStop server(io_service_, &done);
MessagePtr answer(new Message(Message::RENDER));
@@ -864,7 +982,7 @@ TEST_F(RecursiveQueryTest, forwardLookupTimeout) {
boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
// Run the test
- io_service_->run();
+ io_service_.run();
EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
}
@@ -875,11 +993,11 @@ TEST_F(RecursiveQueryTest, lowtimeouts) {
setDNSService();
// Prepare the socket
- sock_ = createTestSocket();
+ sock_.reset(createTestSocket());
// Prepare the server
bool done(true);
- MockServerStop server(*io_service_, &done);
+ MockServerStop server(io_service_, &done);
MessagePtr answer(new Message(Message::RENDER));
@@ -899,7 +1017,7 @@ TEST_F(RecursiveQueryTest, lowtimeouts) {
boost::shared_ptr<MockResolverCallback> callback(new MockResolverCallback(&server));
query.forward(ConstMessagePtr(&query_message), answer, buffer, &server, callback);
// Run the test
- io_service_->run();
+ io_service_.run();
EXPECT_EQ(callback->result, MockResolverCallback::FAILURE);
}
@@ -913,7 +1031,7 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendOk) {
setDNSService(true, false);
bool done;
- MockServerStop server(*io_service_, &done);
+ MockServerStop server(io_service_, &done);
vector<pair<string, uint16_t> > empty_vector;
RecursiveQuery rq(*dns_service_, *nsas_, cache_, empty_vector,
empty_vector, 10000, 0);
@@ -922,7 +1040,7 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendOk) {
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
rq.resolve(q, answer, buffer, &server);
- io_service_->run();
+ io_service_.run();
// Check that the answer we got matches the one we wanted
EXPECT_EQ(Rcode::NOERROR(), answer->getRcode());
@@ -939,7 +1057,7 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
setDNSService(true, false);
bool done;
- MockServerStop server(*io_service_, &done);
+ MockServerStop server(io_service_, &done);
vector<pair<string, uint16_t> > empty_vector;
RecursiveQuery rq(*dns_service_, *nsas_, cache_, empty_vector,
empty_vector, 10000, 0);
@@ -948,7 +1066,7 @@ TEST_F(RecursiveQueryTest, DISABLED_recursiveSendNXDOMAIN) {
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
rq.resolve(q, answer, buffer, &server);
- io_service_->run();
+ io_service_.run();
// Check that the answer we got matches the one we wanted
EXPECT_EQ(Rcode::NXDOMAIN(), answer->getRcode());
@@ -1022,7 +1140,7 @@ TEST_F(RecursiveQueryTest, CachedNS) {
OutputBufferPtr buffer(new OutputBuffer(0));
MessagePtr answer(new Message(Message::RENDER));
// The server is here so we have something to pass there
- MockServer server(*io_service_);
+ MockServer server(io_service_);
rq.resolve(q, answer, buffer, &server);
// We don't need to run the service in this test. We are interested only
// in the place it starts resolving at
diff --git a/src/lib/resolve/tests/recursive_query_unittest_2.cc b/src/lib/resolve/tests/recursive_query_unittest_2.cc
index 3fbd537..bdf6284 100644
--- a/src/lib/resolve/tests/recursive_query_unittest_2.cc
+++ b/src/lib/resolve/tests/recursive_query_unittest_2.cc
@@ -283,7 +283,8 @@ public:
/// by the "server" to receive data.
/// \param length Amount of data received.
void udpReceiveHandler(asio::error_code ec = asio::error_code(),
- size_t length = 0) {
+ size_t length = 0)
+ {
if (debug_) {
cout << "udpReceiveHandler(): error = " << ec.value() <<
", length = " << length << ", last state = " << last_ <<
@@ -349,7 +350,8 @@ public:
// Convert to wire format
udp_send_buffer_->clear();
- MessageRenderer renderer(*udp_send_buffer_);
+ MessageRenderer renderer;
+ renderer.setBuffer(udp_send_buffer_.get());
msg.toWire(renderer);
if (mangle_response) {
@@ -377,7 +379,8 @@ public:
/// \param ec Completion error code of the send.
/// \param length Actual number of bytes sent.
void udpSendHandler(asio::error_code ec = asio::error_code(),
- size_t length = 0) {
+ size_t length = 0)
+ {
if (debug_) {
cout << "udpSendHandler(): error = " << ec.value() <<
", length = " << length << endl;
@@ -402,7 +405,8 @@ public:
/// \param socket Socket on which data will be received
/// \param ec Boost error code, value should be zero.
void tcpAcceptHandler(asio::error_code ec = asio::error_code(),
- size_t length = 0) {
+ size_t length = 0)
+ {
if (debug_) {
cout << "tcpAcceptHandler(): error = " << ec.value() <<
", length = " << length << endl;
@@ -430,7 +434,8 @@ public:
/// by the "server" to receive data.
/// \param length Amount of data received.
void tcpReceiveHandler(asio::error_code ec = asio::error_code(),
- size_t length = 0) {
+ size_t length = 0)
+ {
if (debug_) {
cout << "tcpReceiveHandler(): error = " << ec.value() <<
", length = " << length <<
@@ -480,10 +485,9 @@ public:
setReferralExampleOrg(msg);
// Convert to wire format
- // Use a temporary buffer for the dns wire data (we copy it
+ // Use a temporary renderer for the dns wire data (we copy it
// to the 'real' buffer below)
- OutputBuffer msg_buf(BUFFER_SIZE);
- MessageRenderer renderer(msg_buf);
+ MessageRenderer renderer;
msg.toWire(renderer);
// Expected next state (when checked) is the UDP query to example.org.
@@ -499,12 +503,13 @@ public:
// followed by the actual data. We copy them to a new buffer
// first
tcp_send_buffer_->clear();
- tcp_send_buffer_->writeUint16(msg_buf.getLength());
- tcp_send_buffer_->writeData(msg_buf.getData(), msg_buf.getLength());
+ tcp_send_buffer_->writeUint16(renderer.getLength());
+ tcp_send_buffer_->writeData(renderer.getData(), renderer.getLength());
tcp_socket_.async_send(asio::buffer(tcp_send_buffer_->getData(),
tcp_send_buffer_->getLength()),
- boost::bind(&RecursiveQueryTest2::tcpSendHandler, this,
- tcp_send_buffer_->getLength(), _1, _2));
+ boost::bind(
+ &RecursiveQueryTest2::tcpSendHandler, this,
+ tcp_send_buffer_->getLength(), _1, _2));
}
/// \brief Completion Handler for Sending TCP data
@@ -643,8 +648,6 @@ private:
bool run_; ///< Set true when completion handler run
bool status_; ///< Set true for success, false on error
bool debug_; ///< Debug flag
- // silence MSVC warning C4512: assignment operator could not be generated
- ResolverCallback& operator=(ResolverCallback const&);
};
// Sets up the UDP and TCP "servers", then tries a resolution.
@@ -703,7 +706,7 @@ TEST_F(RecursiveQueryTest2, Resolve) {
// weren't, we would expect some absurdly high answers.
vector<uint32_t> rtt = recorder->getRtt();
EXPECT_GT(rtt.size(), 0);
- for (unsigned int i = 0; i < rtt.size(); ++i) {
+ for (vector<uint32_t>::size_type i = 0; i < rtt.size(); ++i) {
EXPECT_LT(rtt[i], 2000);
}
}
diff --git a/src/lib/resolve/tests/recursive_query_unittest_3.cc b/src/lib/resolve/tests/recursive_query_unittest_3.cc
new file mode 100644
index 0000000..1104680
--- /dev/null
+++ b/src/lib/resolve/tests/recursive_query_unittest_3.cc
@@ -0,0 +1,578 @@
+// 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 <algorithm>
+#include <cstdlib>
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <boost/bind.hpp>
+
+#include <asio.hpp>
+
+#include <util/buffer.h>
+#include <util/io_utilities.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 <dns/rrtype.h>
+#include <dns/rrset.h>
+#include <dns/rrttl.h>
+#include <dns/rdata.h>
+
+#include <util/io_utilities.h>
+#include <asiodns/dns_service.h>
+#include <asiodns/io_fetch.h>
+#include <asiolink/io_address.h>
+#include <asiolink/io_endpoint.h>
+#include <asiolink/io_service.h>
+#include <resolve/recursive_query.h>
+#include <resolve/resolver_interface.h>
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4351)
+#endif
+
+using namespace asio;
+using namespace asio::ip;
+using namespace isc::asiolink;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using namespace isc::util;
+using namespace isc::resolve;
+using namespace std;
+
+/// RecursiveQuery Test - 3
+///
+/// The second part of the RecursiveQuery unit tests, this attempts to get the
+/// RecursiveQuery object to follow a set of EDNS-induced errors, causing the
+/// resolver to follow the fallback logic.
+///
+/// - Send EDNS question over UDP - get FORMERR
+/// - Send EDNS question over TCP - get FORMERR
+/// - Send non-EDNS question over UDP - get RESPONSE
+///
+/// By using the "test_server_" element of RecursiveQuery, all queries are
+/// directed to one or other of the "servers" in the RecursiveQueryTest3 class.
+
+namespace isc {
+namespace asiodns {
+
+const std::string TEST_ADDRESS3 = "127.0.0.1";
+ ///< Servers are on this address
+const uint16_t TEST_PORT3 = 5303; ///< ... and this port
+const size_t BUFFER_SIZE = 1024; ///< For all buffers
+
+const std::string DUMMY_ADDR3 = "1.2.3.4"; ///< address to return as A
+
+class MockResolver3 : public isc::resolve::ResolverInterface {
+public:
+ virtual void resolve(const QuestionPtr& question,
+ const ResolverInterface::CallbackPtr& callback) {
+ }
+
+ virtual ~MockResolver3() {}
+};
+
+
+
+/// \brief Test fixture for the RecursiveQuery Test
+class RecursiveQueryTest3 : public virtual ::testing::Test
+{
+public:
+
+ /// \brief Status of query
+ ///
+ /// Set before the query and then by each "server" when responding.
+ enum QueryStatus {
+ NONE = 0, ///< Default
+ EDNS_UDP = 1, ///< EDNS query over UDP
+ NON_EDNS_UDP = 2, ///< Non-EDNS query over UDP
+ COMPLETE = 6 ///< Query is complete
+ };
+
+ // Common stuff
+ IOService service_; ///< Service to run everything
+ DNSService dns_service_; ///< Resolver is part of "server"
+ QuestionPtr question_; ///< What to ask
+ QueryStatus last_; ///< What was the last state
+ QueryStatus expected_; ///< Expected next state
+ OutputBufferPtr question_buffer_; ///< Question we expect to receive
+ boost::shared_ptr<MockResolver3> resolver_; ///< Mock resolver
+ isc::nsas::NameserverAddressStore* nsas_; ///< Nameserver address store
+ isc::cache::ResolverCache cache_; ///< Resolver cache
+
+ // Data for TCP Server
+ size_t tcp_cumulative_; ///< Cumulative TCP data received
+ tcp::endpoint tcp_endpoint_; ///< Endpoint for TCP receives
+ size_t tcp_length_; ///< Expected length value
+ uint8_t tcp_receive_buffer_[BUFFER_SIZE]; ///< Receive buffer for TCP I/O
+ OutputBufferPtr tcp_send_buffer_; ///< Send buffer for TCP I/O
+ tcp::socket tcp_socket_; ///< Socket used by TCP server
+
+ /// Data for UDP
+ udp::endpoint udp_remote_; ///< Endpoint for UDP receives
+ size_t udp_length_; ///< Expected length value
+ uint8_t udp_receive_buffer_[BUFFER_SIZE]; ///< Receive buffer for UDP I/O
+ OutputBufferPtr udp_send_buffer_; ///< Send buffer for UDP I/O
+ udp::socket udp_socket_; ///< Socket used by UDP server
+
+ /// \brief Constructor
+ RecursiveQueryTest3() :
+ service_(),
+ dns_service_(service_, NULL, NULL, NULL),
+ question_(new Question(Name("ednsfallback"),
+ RRClass::IN(), RRType::A())),
+ last_(NONE),
+ expected_(NONE),
+ question_buffer_(new OutputBuffer(BUFFER_SIZE)),
+ resolver_(new MockResolver3()),
+ nsas_(new isc::nsas::NameserverAddressStore(resolver_)),
+ tcp_cumulative_(0),
+ tcp_endpoint_(asio::ip::address::from_string(TEST_ADDRESS3),
+ TEST_PORT3),
+ tcp_length_(0),
+ tcp_receive_buffer_(),
+ tcp_send_buffer_(new OutputBuffer(BUFFER_SIZE)),
+ tcp_socket_(service_.get_io_service()),
+ udp_remote_(),
+ udp_length_(0),
+ udp_receive_buffer_(),
+ udp_send_buffer_(new OutputBuffer(BUFFER_SIZE)),
+ udp_socket_(service_.get_io_service(), udp::v4())
+ {
+ }
+
+ /// \brief Set Common Message Bits
+ ///
+ /// Sets up the common bits of a response message returned by the handlers.
+ ///
+ /// \param message Message buffer in RENDER mode.
+ /// \param qid QID to set the message to
+ void setCommonMessage(isc::dns::Message& message, uint16_t qid) {
+ message.setQid(qid);
+ message.setHeaderFlag(Message::HEADERFLAG_QR);
+ message.setOpcode(Opcode::QUERY());
+ message.setHeaderFlag(Message::HEADERFLAG_AA);
+ message.addQuestion(*question_);
+ }
+
+ /// \brief Set FORMERR answer
+ ///
+ /// \param message Message to update with FORMERR status
+ void setFORMERR(isc::dns::Message& message) {
+ message.setRcode(Rcode::FORMERR());
+ }
+
+ /// \brief Set Answer
+ ///
+ /// \param message Message to update with FORMERR status
+ void setAnswer(isc::dns::Message& message) {
+ // Give a response
+ RRsetPtr answer(new RRset(Name("ednsfallback."), RRClass::IN(),
+ RRType::A(), RRTTL(300)));
+ answer->addRdata(createRdata(RRType::A(), RRClass::IN(), DUMMY_ADDR3));
+ message.addRRset(Message::SECTION_ANSWER, answer);
+ message.setRcode(Rcode::NOERROR());
+ }
+
+ /// \brief UDP Receive Handler
+ ///
+ /// This is invoked when a message is received over UDP from the
+ /// RecursiveQuery object under test. It formats an answer and sends it
+ /// asynchronously, with the UdpSendHandler method being specified as the
+ /// completion handler.
+ ///
+ /// \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 udpReceiveHandler(error_code ec = error_code(), size_t length = 0) {
+ // Expected state should be one greater than the last state.
+ EXPECT_EQ(static_cast<int>(expected_), static_cast<int>(last_) + 1);
+ last_ = expected_;
+
+ Message query(Message::PARSE);
+
+ // 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.)
+ // And check that question we received is what was expected.
+ checkReceivedPacket(udp_receive_buffer_, length, query);
+
+ // The message returned depends on what state we are in. Set up
+ // common stuff first: bits not mentioned are set to 0.
+ Message message(Message::RENDER);
+ setCommonMessage(message, query.getQid());
+
+ // Set up state-dependent bits:
+ switch (expected_) {
+ case EDNS_UDP:
+ EXPECT_TRUE(query.getEDNS());
+ // Return FORMERROR
+ setFORMERR(message);
+ expected_ = NON_EDNS_UDP;
+ break;
+
+ case NON_EDNS_UDP:
+ EXPECT_FALSE(query.getEDNS());
+ // Return the answer to the question.
+ setAnswer(message);
+ expected_ = COMPLETE;
+ break;
+
+ default:
+ FAIL() << "UdpReceiveHandler called with unknown state";
+ }
+
+ // Convert to wire format
+ udp_send_buffer_->clear();
+ MessageRenderer renderer;
+ renderer.setBuffer(udp_send_buffer_.get());
+ message.toWire(renderer);
+ renderer.setBuffer(NULL);
+
+ // Return a message back to the IOFetch object (after setting the
+ // expected length of data for the check in the send handler).
+ udp_length_ = udp_send_buffer_->getLength();
+ udp_socket_.async_send_to(asio::buffer(udp_send_buffer_->getData(),
+ udp_send_buffer_->getLength()),
+ udp_remote_,
+ boost::bind(&RecursiveQueryTest3::udpSendHandler,
+ this, _1, _2));
+ }
+
+ /// \brief UDP Send Handler
+ ///
+ /// Called when a send operation of the UDP server (i.e. a response
+ /// being sent to the RecursiveQuery) has completed, this re-issues
+ /// a read call.
+ ///
+ /// \param ec Completion error code of the send.
+ /// \param length Actual number of bytes sent.
+ void udpSendHandler(error_code ec = error_code(), size_t length = 0) {
+ // Check send was OK
+ EXPECT_EQ(0, ec.value());
+ EXPECT_EQ(udp_length_, length);
+
+ // Reissue the receive call to await the next message.
+ udp_socket_.async_receive_from(
+ asio::buffer(udp_receive_buffer_, sizeof(udp_receive_buffer_)),
+ udp_remote_,
+ boost::bind(&RecursiveQueryTest3::udpReceiveHandler,
+ this, _1, _2));
+ }
+
+ /// \brief Completion Handler for Accepting TCP Data
+ ///
+ /// Called when the remote system connects to the "TCP 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(error_code ec = error_code(), size_t length = 0) {
+ // Expect that the accept completed without a problem.
+ EXPECT_EQ(0, ec.value());
+
+ // Initiate a read on the socket, indicating that nothing has yet been
+ // received.
+ tcp_cumulative_ = 0;
+ tcp_socket_.async_receive(
+ asio::buffer(tcp_receive_buffer_, sizeof(tcp_receive_buffer_)),
+ boost::bind(&RecursiveQueryTest3::tcpReceiveHandler, this, _1, _2));
+ }
+
+ /// \brief Completion Handler for Receiving TCP Data
+ ///
+ /// Reads data from the RecursiveQuery object and loops, reissuing reads,
+ /// until all the message has been read. It then returns an appropriate
+ /// response.
+ ///
+ /// \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(error_code ec = error_code(), size_t length = 0) {
+ // Expect that the receive completed without a problem.
+ EXPECT_EQ(0, ec.value());
+
+ // Have we received all the data? We know this by checking if the two-
+ // byte length count in the message is equal to the data received.
+ tcp_cumulative_ += length;
+ bool complete = false;
+ if (tcp_cumulative_ > 2) {
+ uint16_t dns_length = readUint16(tcp_receive_buffer_);
+ complete = ((dns_length + 2) == tcp_cumulative_);
+ }
+
+ if (!complete) {
+ // Not complete yet, issue another read.
+ tcp_socket_.async_receive(
+ asio::buffer(tcp_receive_buffer_ + tcp_cumulative_,
+ sizeof(tcp_receive_buffer_) - tcp_cumulative_),
+ boost::bind(&RecursiveQueryTest3::tcpReceiveHandler,
+ this, _1, _2));
+ return;
+ }
+
+ // Have received a TCP message. Expected state should be one greater
+ // than the last state.
+ EXPECT_EQ(static_cast<int>(expected_), static_cast<int>(last_) + 1);
+ last_ = expected_;
+
+ Message query(Message::PARSE);
+
+ // Check that question we received is what was expected. Note that we
+ // have to ignore the two-byte header in order to parse the message.
+ checkReceivedPacket(tcp_receive_buffer_ + 2, length - 2, query);
+
+ // Return a message back. This is a referral to example.org, which
+ // should result in another query over UDP. Note the setting of the
+ // QID in the returned message with what was in the received message.
+ Message message(Message::RENDER);
+ setCommonMessage(message, query.getQid());
+
+ // Set up state-dependent bits:
+ switch (expected_) {
+ default:
+ FAIL() << "TcpReceiveHandler called with unknown state";
+ }
+
+
+ // Convert to wire format
+ // Use a temporary buffer for the dns wire data (we copy it
+ // to the 'real' buffer below)
+ MessageRenderer renderer;
+ message.toWire(renderer);
+
+ // Also, take this opportunity to clear the accumulated read count in
+ // readiness for the next read. (If any - at present, there is only
+ // one read in the test, although extensions to this test suite could
+ // change that.)
+ tcp_cumulative_ = 0;
+
+ // Unless we go through a callback loop we cannot simply use
+ // async_send() multiple times, so we cannot send the size first
+ // followed by the actual data. We copy them to a new buffer
+ // first
+ tcp_send_buffer_->clear();
+ tcp_send_buffer_->writeUint16(renderer.getLength());
+ tcp_send_buffer_->writeData(renderer.getData(), renderer.getLength());
+ tcp_socket_.async_send(asio::buffer(tcp_send_buffer_->getData(),
+ tcp_send_buffer_->getLength()),
+ boost::bind(
+ &RecursiveQueryTest3::tcpSendHandler,
+ this,
+ tcp_send_buffer_->getLength(), _1, _2));
+ }
+
+ /// \brief Completion Handler for Sending TCP data
+ ///
+ /// Called when the asynchronous send of data back to the RecursiveQuery
+ /// 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.)
+ ///
+ /// \param expected_length Number of bytes that were expected to have been
+ /// sent.
+ /// \param ec Boost error code, value should be zero.
+ /// \param length Number of bytes sent.
+ void tcpSendHandler(size_t expected_length = 0,
+ error_code ec = error_code(),
+ size_t length = 0)
+ {
+ EXPECT_EQ(0, ec.value()); // Expect no error
+ EXPECT_EQ(expected_length, length); // And that amount sent is as
+ // expected
+ }
+
+ /// \brief Check Received Packet
+ ///
+ /// Checks the packet received from the RecursiveQuery object to ensure
+ /// that the question is what is expected.
+ ///
+ /// \param data Start of data. This is the start of the received buffer in
+ /// the case of UDP data, and an offset into the buffer past the
+ /// count field for TCP data.
+ /// \param length Length of data.
+ /// \return The QID of the message
+ void checkReceivedPacket(uint8_t* data, size_t length, Message& message) {
+
+ // Decode the received buffer.
+ InputBuffer buffer(data, length);
+ message.fromWire(buffer);
+
+ // Check the packet.
+ EXPECT_FALSE(message.getHeaderFlag(Message::HEADERFLAG_QR));
+
+ Question question = **(message.beginQuestion());
+ EXPECT_TRUE(question == *question_);
+ }
+};
+
+/// \brief Resolver Callback Object
+///
+/// Holds the success and failure callback methods for the resolver
+class ResolverCallback3 : public isc::resolve::ResolverInterface::Callback {
+public:
+ /// \brief Constructor
+ ResolverCallback3(IOService& service) :
+ service_(service), run_(false), status_(false)
+ {}
+
+ /// \brief Destructor
+ virtual ~ResolverCallback3()
+ {}
+
+ /// \brief Resolver Callback Success
+ ///
+ /// Called if the resolver detects that the call has succeeded.
+ ///
+ /// \param response Answer to the question.
+ virtual void success(const isc::dns::MessagePtr response) {
+ // There should be one RR each in the question and answer sections,
+ // and two RRs in each of the the authority and additional sections.
+ EXPECT_EQ(1, response->getRRCount(Message::SECTION_QUESTION));
+ EXPECT_EQ(1, response->getRRCount(Message::SECTION_ANSWER));
+
+ // Check the answer - that the RRset is there...
+ EXPECT_TRUE(response->hasRRset(Message::SECTION_ANSWER,
+ RRsetPtr(new RRset(Name("ednsfallback."),
+ RRClass::IN(),
+ RRType::A(),
+ RRTTL(300)))));
+ const RRsetIterator rrset_i = response->beginSection(Message::SECTION_ANSWER);
+
+ // ... get iterator into the Rdata of this RRset and point to first
+ // element...
+ const RdataIteratorPtr rdata_i = (*rrset_i)->getRdataIterator();
+ rdata_i->first();
+
+ // ... and check it is what we expect.
+ EXPECT_EQ(string(DUMMY_ADDR3), rdata_i->getCurrent().toText());
+
+ // Flag completion
+ run_ = true;
+ status_ = true;
+
+ service_.stop(); // Cause run() to exit.
+ }
+
+ /// \brief Resolver Failure Completion
+ ///
+ /// Called if the resolver detects that the resolution has failed.
+ virtual void failure() {
+ FAIL() << "Resolver reported completion failure";
+
+ // Flag completion
+ run_ = true;
+ status_ = false;
+
+ service_.stop(); // Cause run() to exit.
+ }
+
+ /// \brief Return status of "run" flag
+ bool getRun() const {
+ return (run_);
+ }
+
+ /// \brief Return "status" flag
+ bool getStatus() const {
+ return (status_);
+ }
+
+private:
+ IOService& service_; ///< Service handling the run queue
+ bool run_; ///< Set true when completion handler run
+ bool status_; ///< Set true for success, false on error
+};
+
+// Sets up the UDP and TCP "servers", then tries a resolution.
+
+TEST_F(RecursiveQueryTest3, Resolve) {
+ // Set up the UDP server and issue the first read. The endpoint from which
+ // the query is sent is put in udp_endpoint_ when the read completes, which
+ // is referenced in the callback as the place to which the response is
+ // sent.
+ udp_socket_.set_option(socket_base::reuse_address(true));
+ udp_socket_.bind(udp::endpoint(address::from_string(TEST_ADDRESS3),
+ TEST_PORT3));
+ udp_socket_.async_receive_from(asio::buffer(udp_receive_buffer_,
+ sizeof(udp_receive_buffer_)),
+ udp_remote_,
+ boost::bind(&RecursiveQueryTest3::udpReceiveHandler,
+ this, _1, _2));
+
+ // Set up the TCP server and issue the accept. Acceptance will cause the
+ // read to be issued.
+ tcp::acceptor acceptor(service_.get_io_service(),
+ tcp::endpoint(tcp::v4(), TEST_PORT3));
+ acceptor.async_accept(tcp_socket_,
+ boost::bind(&RecursiveQueryTest3::tcpAcceptHandler,
+ this, _1, 0));
+
+ // Set up the RecursiveQuery object. We will also test that it correctly
+ // records RTT times by setting up a RTT recorder object as well.
+ std::vector<std::pair<std::string, uint16_t> > upstream; // Empty
+ std::vector<std::pair<std::string, uint16_t> > upstream_root; // Empty
+ RecursiveQuery query(dns_service_, *nsas_, cache_,
+ upstream, upstream_root);
+ query.setTestServer(TEST_ADDRESS3, TEST_PORT3);
+
+ boost::shared_ptr<RttRecorder> recorder(new RttRecorder());
+ query.setRttRecorder(recorder);
+
+ // Set up callback to receive notification that the query has completed.
+ isc::resolve::ResolverInterface::CallbackPtr
+ resolver_callback(new ResolverCallback3(service_));
+
+ // Kick off the resolution process.
+ expected_ = EDNS_UDP;
+ query.resolve(question_, resolver_callback);
+ service_.run();
+
+ // Check what ran. (We have to cast the callback to ResolverCallback3 as we
+ // lost the information on the derived class when we used a
+ // ResolverInterface::CallbackPtr to store a pointer to it.)
+ ResolverCallback3* rc
+ = static_cast<ResolverCallback3*>(resolver_callback.get());
+ EXPECT_TRUE(rc->getRun());
+ EXPECT_TRUE(rc->getStatus());
+
+ // Finally, check that all the RTTs were "reasonable" (defined here as
+ // being below 2 seconds). This is an explicit check to test that the
+ // variables in the RTT calculation are at least being initialized; if they
+ // weren't, we would expect some absurdly high answers.
+ vector<uint32_t> rtt = recorder->getRtt();
+ EXPECT_GT(rtt.size(), 0);
+ for (int i = 0; i < rtt.size(); ++i) {
+ EXPECT_LT(rtt[i], 2000);
+ }
+}
+
+} // namespace asiodns
+} // namespace isc
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
diff --git a/src/lib/testutils/Makefile.am b/src/lib/testutils/Makefile.am
index a511d24..7a4c8d7 100644
--- a/src/lib/testutils/Makefile.am
+++ b/src/lib/testutils/Makefile.am
@@ -14,4 +14,4 @@ libtestutils_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
libtestutils_la_LIBADD = $(top_builddir)/src/lib/asiolink/libasiolink.la
endif
-EXTRA_DIST = portconfig.h
+EXTRA_DIST = portconfig.h socket_request.h
diff --git a/src/lib/testutils/dnsmessage_test.cc b/src/lib/testutils/dnsmessage_test.cc
index af354d5..ec6914d 100644
--- a/src/lib/testutils/dnsmessage_test.cc
+++ b/src/lib/testutils/dnsmessage_test.cc
@@ -23,6 +23,12 @@
#include <testutils/dnsmessage_test.h>
+#include <boost/bind.hpp>
+
+#include <string>
+#include <sstream>
+
+using namespace std;
using namespace isc::dns;
namespace isc {
@@ -80,12 +86,35 @@ matchRdata(const char*, const char*,
}
return (::testing::AssertionSuccess());
}
+
+// A helper callback of masterLoad() used by textToRRset() below.
+void
+setRRset(RRsetPtr rrset, RRsetPtr* rrsetp) {
+ if (*rrsetp) {
+ isc_throw(isc::Unexpected,
+ "multiple RRsets are given to textToRRset");
+ }
+ *rrsetp = rrset;
+}
+}
+
+RRsetPtr
+textToRRset(const string& text_rrset, const RRClass& rrclass,
+ const Name& origin)
+{
+ stringstream ss(text_rrset);
+ RRsetPtr rrset;
+ masterLoad(ss, origin, rrclass, boost::bind(setRRset, _1, &rrset));
+ return (rrset);
}
void
rrsetCheck(isc::dns::ConstRRsetPtr expected_rrset,
isc::dns::ConstRRsetPtr actual_rrset)
{
+ SCOPED_TRACE("Comparing RRsets\n"
+ " Actual: " + actual_rrset->toText() +
+ " Expected: " + expected_rrset->toText());
EXPECT_EQ(expected_rrset->getName(), actual_rrset->getName());
EXPECT_EQ(expected_rrset->getClass(), actual_rrset->getClass());
EXPECT_EQ(expected_rrset->getType(), actual_rrset->getType());
diff --git a/src/lib/testutils/dnsmessage_test.h b/src/lib/testutils/dnsmessage_test.h
index 8fc2216..57cb72c 100644
--- a/src/lib/testutils/dnsmessage_test.h
+++ b/src/lib/testutils/dnsmessage_test.h
@@ -12,6 +12,9 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#ifndef __ISC_TESTUTILS_DNSMESSAGETEST_H
+#define __ISC_TESTUTILS_DNSMESSAGETEST_H 1
+
#include <algorithm>
#include <functional>
#include <iosfwd>
@@ -142,9 +145,6 @@ struct RRsetMatch : public std::unary_function<isc::dns::ConstRRsetPtr, bool> {
targetit->getCurrent()).typeCovered());
}
const isc::dns::ConstRRsetPtr target_;
-private:
- // silence MSVC warning C4512: assignment operator could not be generated
- RRsetMatch& operator=(RRsetMatch const&);
};
// Helper callback functor for masterLoad() used in rrsetsCheck (stream
@@ -159,11 +159,44 @@ public:
}
private:
std::vector<isc::dns::ConstRRsetPtr>& rrsets_;
- // silence MSVC warning C4512: assignment operator could not be generated
- RRsetInserter& operator=(RRsetInserter const&);
+};
+
+class RRsetDumper {
+public:
+ RRsetDumper(std::string& output) :
+ output_(output)
+ {}
+ void operator()(isc::dns::ConstRRsetPtr rrset) {
+ output_ += " " + rrset->toText();
+ }
+private:
+ std::string& output_;
};
}
+/// \brief A converter from a string to RRset.
+///
+/// This is a convenient shortcut for tests that need to create an RRset
+/// from textual representation with a single call to a function.
+///
+/// An RRset consisting of multiple RRs can be constructed, but only one
+/// RRset is allowed. If the given string contains mixed types of RRs
+/// it throws an \c isc::Unexpected exception.
+///
+/// \param text_rrset A complete textual representation of an RRset.
+/// It must meets the assumption of the \c dns::masterLoad() function.
+/// \param rrclass The RR class of the RRset. Note that \c text_rrset should
+/// contain the RR class, but it's needed for \c dns::masterLoad().
+/// \param origin The zone origin where the RR is expected to belong. This
+/// parameter normally doesn't have to be specified, but for an SOA RR it
+/// must be set to its owner name, due to the internal check of
+/// \c dns::masterLoad().
+isc::dns::RRsetPtr textToRRset(const std::string& text_rrset,
+ const isc::dns::RRClass& rrclass =
+ isc::dns::RRClass::IN(),
+ const isc::dns::Name& origin =
+ isc::dns::Name::ROOT_NAME());
+
/// Set of unit tests to check if two sets of RRsets are identical.
///
/// This templated function takes two sets of sequences, each defined by
@@ -200,6 +233,10 @@ rrsetsCheck(EXPECTED_ITERATOR expected_begin, EXPECTED_ITERATOR expected_end,
ACTUAL_ITERATOR actual_begin, ACTUAL_ITERATOR actual_end)
{
std::vector<isc::dns::ConstRRsetPtr> checked_rrsets; // for duplicate check
+ std::string expected_text, actual_text;
+ std::for_each(expected_begin, expected_end,
+ detail::RRsetDumper(expected_text));
+ std::for_each(actual_begin, actual_end, detail::RRsetDumper(actual_text));
unsigned int rrset_matched = 0;
ACTUAL_ITERATOR it;
for (it = actual_begin; it != actual_end; ++it) {
@@ -222,11 +259,16 @@ rrsetsCheck(EXPECTED_ITERATOR expected_begin, EXPECTED_ITERATOR expected_end,
}
}
- // make sure all expected RRsets are in actual sets
- EXPECT_EQ(std::distance(expected_begin, expected_end), rrset_matched);
- // make sure rrsets only contains expected RRsets
- EXPECT_EQ(std::distance(expected_begin, expected_end),
- std::distance(actual_begin, actual_end));
+ {
+ SCOPED_TRACE(std::string("Comparing two RRsets:\n") +
+ "Actual:\n" + actual_text +
+ "Expected:\n" + expected_text);
+ // make sure all expected RRsets are in actual sets
+ EXPECT_EQ(std::distance(expected_begin, expected_end), rrset_matched);
+ // make sure rrsets only contains expected RRsets
+ EXPECT_EQ(std::distance(expected_begin, expected_end),
+ std::distance(actual_begin, actual_end));
+ }
}
/// Set of unit tests to check if two sets of RRsets are identical using
@@ -323,6 +365,7 @@ rrsetsCheck(const std::string& expected,
} // end of namespace testutils
} // end of namespace isc
+#endif // __ISC_TESTUTILS_DNSMESSAGETEST_H
// Local Variables:
// mode: c++
diff --git a/src/lib/testutils/mockups.h b/src/lib/testutils/mockups.h
index 2441ad7..73fae96 100644
--- a/src/lib/testutils/mockups.h
+++ b/src/lib/testutils/mockups.h
@@ -12,8 +12,13 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#ifndef __ISC_TESTUTILS_MOCKUPS_H
+#define __ISC_TESTUTILS_MOCKUPS_H 1
+
#include <config.h>
+#include <exceptions/exceptions.h>
+
#include <cc/data.h>
#include <cc/session.h>
@@ -21,6 +26,12 @@
#include <asiodns/asiodns.h>
+#include <utility>
+#include <vector>
+
+namespace isc {
+namespace testutils {
+
// A minimal mock configuration session. Most the methods are
// stubbed out, except for a very basic group_sendmsg() and
// group_recvmsg(). hasQueuedMessages() always returns false.
@@ -93,6 +104,68 @@ private:
bool receive_ok_;
};
+// This mock object does nothing except for recording passed parameters
+// to addServerXXX methods so the test code subsequently checks the parameters.
+class MockDNSService : public isc::asiodns::DNSServiceBase {
+public:
+ // A helper tuple of parameters passed to addServerUDPFromFD().
+ struct UDPFdParams {
+#ifdef _WIN32
+ SOCKET fd;
+#else
+ int fd;
+#endif
+ int af;
+ ServerFlag options;
+ };
+
+#ifdef _WIN32
+ virtual void addServerTCPFromFD(SOCKET fd, int af) {
+ tcp_fd_params_.push_back(std::pair<SOCKET, int>(fd, af));
+ }
+ virtual void addServerUDPFromFD(SOCKET fd, int af, ServerFlag options) {
+ UDPFdParams params = { fd, af, options };
+ udp_fd_params_.push_back(params);
+ }
+#else
+ virtual void addServerTCPFromFD(int fd, int af) {
+ tcp_fd_params_.push_back(std::pair<int, int>(fd, af));
+ }
+ virtual void addServerUDPFromFD(int fd, int af, ServerFlag options) {
+ UDPFdParams params = { fd, af, options };
+ udp_fd_params_.push_back(params);
+ }
+#endif
+ virtual void clearServers() {}
+
+ virtual asiolink::IOService& getIOService() {
+ isc_throw(isc::Unexpected,
+ "MockDNSService::getIOService() shouldn't be called");
+ }
+
+ // These two allow the tests to check how the servers have been created
+ // through this object.
+#ifdef _WIN32
+ const std::vector<std::pair<SOCKET, int> >& getTCPFdParams() const
+#else
+ const std::vector<std::pair<int, int> >& getTCPFdParams() const
+#endif
+ {
+ return (tcp_fd_params_);
+ }
+ const std::vector<UDPFdParams>& getUDPFdParams() const {
+ return (udp_fd_params_);
+ }
+
+private:
+#ifdef _WIN32
+ std::vector<std::pair<SOCKET, int> > tcp_fd_params_;
+#else
+ std::vector<std::pair<int, int> > tcp_fd_params_;
+#endif
+ std::vector<UDPFdParams> udp_fd_params_;
+};
+
// A nonoperative DNSServer object to be used in calls to processMessage().
class MockServer : public isc::asiodns::DNSServer {
public:
@@ -129,7 +202,12 @@ public:
is_connected_ = false;
}
- virtual int sendXfroutRequestInfo(int, const void*, uint16_t) {
+#ifdef _WIN32
+ virtual int sendXfroutRequestInfo(SOCKET, const void*, uint16_t)
+#else
+ virtual int sendXfroutRequestInfo(int, const void*, uint16_t)
+#endif
+ {
if (!send_ok_) {
isc_throw(isc::xfr::XfroutError,
"xfrout connection send is disabled for test");
@@ -149,3 +227,10 @@ private:
bool disconnect_ok_;
};
+} // end of testutils
+} // end of isc
+#endif // __ISC_TESTUTILS_MOCKUPS_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/testutils/portconfig.h b/src/lib/testutils/portconfig.h
index 8e61ffc..ce1bb39 100644
--- a/src/lib/testutils/portconfig.h
+++ b/src/lib/testutils/portconfig.h
@@ -12,8 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef TESTUTILS_PORTCONFIG_H
-#define TESTUTILS_PORTCONFIG_H
+#ifndef __ISC_TESTUTILS_PORTCONFIG_H
+#define __ISC_TESTUTILS_PORTCONFIG_H
#include <gtest/gtest.h>
#include <cc/data.h>
@@ -46,7 +46,7 @@ template<class Server>
void
listenAddresses(Server& server) {
using namespace isc::server_common::portconfig;
- // Default value should be fully recursive
+ // In this test we assume the address list is originally empty.
EXPECT_TRUE(server.getListenAddresses().empty());
// Try putting there some addresses
@@ -61,7 +61,8 @@ listenAddresses(Server& server) {
addresses.clear();
EXPECT_EQ(2, server.getListenAddresses().size());
- // Did it return to fully recursive?
+ // If we set to an empty list next, the server configuration should
+ // become empty, too.
server.setListenAddresses(addresses);
EXPECT_TRUE(server.getListenAddresses().empty());
}
@@ -95,12 +96,11 @@ listenAddressConfig(Server& server) {
EXPECT_EQ("127.0.0.1", server.getListenAddresses()[0].first);
EXPECT_EQ(53210, server.getListenAddresses()[0].second);
- // As this is example address, the machine should not have it on
- // any interface
+ // This address is rejected by the test socket requestor
config = Element::fromJSON("{"
"\"listen_on\": ["
" {"
- " \"address\": \"192.0.2.0\","
+ " \"address\": \"192.0.2.2\","
" \"port\": 53210"
" }"
"]"
@@ -186,4 +186,4 @@ invalidListenAddressConfig(Server& server) {
}
}
-#endif
+#endif // __ISC_TESTUTILS_PORTCONFIG_H
diff --git a/src/lib/testutils/socket_request.h b/src/lib/testutils/socket_request.h
new file mode 100644
index 0000000..0ae15f3
--- /dev/null
+++ b/src/lib/testutils/socket_request.h
@@ -0,0 +1,219 @@
+// 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 __ISC_TESTUTILS_SOCKETREQUEST_H
+#define __ISC_TESTUTILS_SOCKETREQUEST_H 1
+
+#include <server_common/socket_request.h>
+#include <server_common/portconfig.h>
+
+#include <asiodns/asiodns.h>
+
+#include <gtest/gtest.h>
+#include <boost/lexical_cast.hpp>
+
+#include <vector>
+#include <string>
+
+namespace isc {
+namespace testutils {
+
+/// \brief A testcase part for faking the SocketRequestor in tests
+///
+/// It's awkward to request real sockets from the real socket creator
+/// during tests (for one, because it would have to be running, for
+/// another, we need to block real ports). If you instantiate this class in
+/// a test case, the socket requestor will be initialized to a test one which
+/// handles fake socket FDs and stores what was requested, etc.
+///
+/// Furthermore, you can check if the code requested or released the correct
+/// list of sockets using the checkTokens() method.
+///
+/// Some member variables are intentionally made public so that test cases
+/// can easily check the value of them. We prefer convenience for tests over
+/// class integrity here.
+class TestSocketRequestor : public isc::server_common::SocketRequestor {
+public:
+ /// \brief Constructor
+ ///
+ /// \param dnss The DNS service. It is expected this gets initialized
+ /// after the TestSocketRequestor constructor is called, as the
+ /// TestSocketRequestor should be a base class and the service only
+ /// a member.
+ /// \param store Address store used when cleaning up.
+ /// \param expect_port The port which is expected to be requested. If
+ /// the application requests a different port, it is considered
+ /// a failure.
+ /// \param expected_app The share name for which all the requests should
+ /// be made. This is not the usual app_name - the requestSocket does
+ /// not fall back to this value if its share_name is left empty, if
+ /// you want to check the code relies on the requestor to use the
+ /// app name, you set this to empty string.
+ TestSocketRequestor(asiodns::DNSServiceBase& dnss,
+ server_common::portconfig::AddressList& store,
+ uint16_t expect_port,
+ const std::string& expected_app) :
+ last_token_(0), break_rollback_(false), break_release_(false),
+ dnss_(dnss), store_(store), expect_port_(expect_port),
+ expected_app_(expected_app)
+ {
+ // Prepare the requestor (us) for the test
+ server_common::initTestSocketRequestor(this);
+ }
+
+ /// \brief Destructor
+ ///
+ /// Removes the addresses (if any) installed by installListenAddresses,
+ /// resets the socket requestor to uninitialized state and turns off
+ /// the portconfig test mode.
+ virtual ~TestSocketRequestor() {
+ // Make sure no sockets are left inside (if installListenAddresses
+ // wasn't used, this is NOP, so it won't hurt).
+ server_common::portconfig::AddressList list;
+ server_common::portconfig::installListenAddresses(list, store_, dnss_);
+ // Don't leave invalid pointers here
+ server_common::initTestSocketRequestor(NULL);
+ }
+
+ /// \brief Tokens released by releaseSocket
+ ///
+ /// They are stored here by this class and you can examine them.
+ std::vector<std::string> released_tokens_;
+
+ /// \brief Tokens returned from requestSocket
+ ///
+ /// They are stored here by this class and you can examine them.
+ std::vector<std::string> given_tokens_;
+private:
+ // Last token number and fd given out
+ size_t last_token_;
+public:
+ /// \brief Support a broken rollback case
+ ///
+ /// If this is set to true, the requestSocket will throw when the
+ /// ::1 address is requested.
+ bool break_rollback_;
+
+ /// \brief Throw on releaseSocket
+ ///
+ /// If this is set to true, the releaseSocket will throw SocketError.
+ /// Defaults to false.
+ bool break_release_;
+
+ /// \brief Release a socket
+ ///
+ /// This only stores the token passed.
+ /// \param token The socket to release
+ ///
+ /// \throw SocketError in case the break_release_ is set to true. This is
+ /// to test exception handling.
+ void releaseSocket(const std::string& token) {
+ if (break_release_) {
+ isc_throw(SocketError, "Fatal test socket error");
+ }
+ released_tokens_.push_back(token);
+ }
+
+ /// \brief Request a socket
+ ///
+ /// This creates a new token and fakes a new socket and returns it.
+ /// The token is stored.
+ ///
+ /// In case the address is 192.0.2.2, it throws SocketAllocateError
+ /// or if the break_rollback_ is true and address is ::1, it throws
+ /// ShareError. If the address is 192.0.2.3, it throws SocketError.
+ ///
+ /// The tokens produced are in form of protocol:address:port:fd. The fds
+ /// start at 1 and increase by each successfull call.
+ ///
+ /// \param protocol The protocol to request
+ /// \param address to bind to
+ /// \param port to bind to
+ /// \param mode checked to be SHARE_SAME for now
+ /// \param name checked to be the same as expected_app parameter of the
+ /// constructor. Note that this class does not provide the fallback
+ /// to an app_name if this is empty string. To check the code relies
+ /// on the fallback (wants to use the app_name instead of providing
+ /// its own share name), you need to create this class with empty
+ /// expected_app.
+ /// \return The token and FD
+ /// \throw SocketAllocateError as described above, to test error handling
+ /// \throw ShareError as described above, to test error handling
+ /// \throw SocketError as described above, to test error handling
+ SocketID requestSocket(Protocol protocol, const std::string& address,
+ uint16_t port, ShareMode mode,
+ const std::string& name)
+ {
+ if (address == "192.0.2.2") {
+ isc_throw(SocketAllocateError, "This address is not allowed");
+ }
+ if (address == "192.0.2.3") {
+ isc_throw(SocketError, "Fatal test error");
+ }
+ if (address == "::1" && break_rollback_) {
+ // This is valid address, but in case we need to break the
+ // rollback, it needs to be busy or whatever
+ //
+ // We break the second address to see the first one was
+ // allocated and then returned
+ isc_throw(ShareError,
+ "This address is available, but not for you");
+ }
+ const std::string proto(protocol == TCP ? "TCP" : "UDP");
+ const size_t number = ++ last_token_;
+ EXPECT_EQ(expect_port_, port);
+ EXPECT_EQ(SHARE_SAME, mode);
+ EXPECT_EQ(expected_app_, name);
+ const std::string token(proto + ":" + address + ":" +
+ boost::lexical_cast<std::string>(port) + ":" +
+ boost::lexical_cast<std::string>(number));
+ given_tokens_.push_back(token);
+ return (SocketID(number, token));
+ }
+
+ /// \brief Check the list of tokens is as expected
+ ///
+ /// Compares the expected and real tokens.
+ ///
+ /// \param expected List of the expected tokens, as NULL-terminated array
+ /// of C strings (it is more convenient to type as a constant than to
+ /// manually push_back all the strings to a vector).
+ /// \param real The token list that was produced by this class (usually
+ /// either given_tokens_ or released_tokens_).
+ /// \param scope Human readable identifier of which checkTokens call it is.
+ /// It is printed as a part of failure message.
+ void checkTokens(const char** expected,
+ const std::vector<std::string>& real,
+ const char* scope) const
+ {
+ SCOPED_TRACE(scope);
+ size_t position(0);
+ while (expected[position] != NULL) {
+ ASSERT_LT(position, real.size());
+ EXPECT_EQ(expected[position], real[position]) << position;
+ position ++;
+ }
+ EXPECT_EQ(position, real.size());
+ }
+
+private:
+ asiodns::DNSServiceBase& dnss_;
+ server_common::portconfig::AddressList& store_;
+ const uint16_t expect_port_;
+ const std::string expected_app_;
+};
+
+}
+}
+#endif // __ISC_TESTUTILS_SOCKETREQUEST_H
diff --git a/src/lib/testutils/srv_test.cc b/src/lib/testutils/srv_test.cc
index 6128493..78fbfad 100644
--- a/src/lib/testutils/srv_test.cc
+++ b/src/lib/testutils/srv_test.cc
@@ -18,6 +18,7 @@
#include <ws2tcpip.h>
#include <mswsock.h>
#else
+#include <sys/types.h>
#include <netinet/in.h>
#endif
@@ -38,6 +39,7 @@ using namespace isc::asiolink;
namespace isc {
namespace testutils {
const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
+const uint16_t DEFAULT_REMOTE_PORT = 53210;
SrvTestBase::SrvTestBase() : request_message(Message::RENDER),
parse_message(new Message(Message::PARSE)),
@@ -48,8 +50,6 @@ SrvTestBase::SrvTestBase() : request_message(Message::RENDER),
qclass(RRClass::IN()),
qtype(RRType::A()), io_sock(NULL),
io_message(NULL), endpoint(NULL),
- request_obuffer(0),
- request_renderer(request_obuffer),
response_obuffer(new OutputBuffer(0))
{}
@@ -68,7 +68,8 @@ SrvTestBase::createDataFromFile(const char* const datafile,
delete endpoint;
endpoint = IOEndpoint::create(protocol,
- IOAddress(DEFAULT_REMOTE_ADDRESS), 53210);
+ IOAddress(DEFAULT_REMOTE_ADDRESS),
+ DEFAULT_REMOTE_PORT);
UnitTestUtil::readWireData(datafile, data);
io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
&IOSocket::getDummyTCPSocket();
@@ -77,7 +78,9 @@ SrvTestBase::createDataFromFile(const char* const datafile,
void
SrvTestBase::createRequestPacket(Message& message,
- const int protocol, TSIGContext* context)
+ const int protocol, TSIGContext* context,
+ const char* const remote_address,
+ uint16_t remote_port)
{
if (context == NULL) {
message.toWire(request_renderer);
@@ -87,10 +90,11 @@ SrvTestBase::createRequestPacket(Message& message,
delete io_message;
- endpoint = IOEndpoint::create(protocol,
- IOAddress(DEFAULT_REMOTE_ADDRESS), 53210);
+ endpoint = IOEndpoint::create(protocol, IOAddress(remote_address),
+ remote_port);
io_sock = (protocol == IPPROTO_UDP) ? &IOSocket::getDummyUDPSocket() :
&IOSocket::getDummyTCPSocket();
+
io_message = new IOMessage(request_renderer.getData(),
request_renderer.getLength(),
*io_sock, *endpoint);
@@ -99,11 +103,12 @@ SrvTestBase::createRequestPacket(Message& message,
// Unsupported requests. Should result in NOTIMP.
void
SrvTestBase::unsupportedRequest() {
- for (int i = 0; i < 16; ++i) {
+ for (unsigned int i = 0; i < 16; ++i) {
// set Opcode to 'i', which iterators over all possible codes except
- // the standard query and notify
+ // the standard opcodes we support.
if (i == isc::dns::Opcode::QUERY().getCode() ||
- i == isc::dns::Opcode::NOTIFY().getCode()) {
+ i == isc::dns::Opcode::NOTIFY().getCode() ||
+ i == isc::dns::Opcode::UPDATE().getCode()) {
continue;
}
createDataFromFile("simplequery_fromWire.wire");
diff --git a/src/lib/testutils/srv_test.h b/src/lib/testutils/srv_test.h
index c92e876..a5c516e 100644
--- a/src/lib/testutils/srv_test.h
+++ b/src/lib/testutils/srv_test.h
@@ -12,6 +12,9 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#ifndef __ISC_TESTUTILS_SRVTEST_H
+#define __ISC_TESTUTILS_SRVTEST_H 1
+
#include <util/buffer.h>
#include <dns/name.h>
#include <dns/message.h>
@@ -32,6 +35,7 @@ class IOEndpoint;
namespace isc {
namespace testutils {
extern const char* const DEFAULT_REMOTE_ADDRESS;
+extern const uint16_t DEFAULT_REMOTE_PORT;
// These are flags to indicate whether the corresponding flag bit of the
// DNS header is to be set in the test cases. (The flag values
@@ -44,7 +48,7 @@ extern const unsigned int RA_FLAG;
extern const unsigned int AD_FLAG;
extern const unsigned int CD_FLAG;
-// The base class for Auth and Recurse test case
+/// \brief The base class for Auth and Recurse test case
class SrvTestBase : public ::testing::Test {
protected:
SrvTestBase();
@@ -85,7 +89,9 @@ protected:
/// The existing content of \c io_message, if any, will be deleted.
void createRequestPacket(isc::dns::Message& message,
const int protocol = IPPROTO_UDP,
- isc::dns::TSIGContext* context = NULL);
+ isc::dns::TSIGContext* context = NULL,
+ const char* const address = DEFAULT_REMOTE_ADDRESS,
+ uint16_t port = DEFAULT_REMOTE_PORT);
MockSession notify_session;
MockServer dnsserv;
@@ -100,13 +106,13 @@ protected:
asiolink::IOSocket* io_sock;
asiolink::IOMessage* io_message;
const asiolink::IOEndpoint* endpoint;
- isc::util::OutputBuffer request_obuffer;
isc::dns::MessageRenderer request_renderer;
isc::util::OutputBufferPtr response_obuffer;
std::vector<uint8_t> data;
};
} // end of namespace testutils
} // end of namespace isc
+#endif // __ISC_TESTUTILS_SRVTEST_H
// Local Variables:
// mode: c++
diff --git a/src/lib/testutils/testdata/.gitignore b/src/lib/testutils/testdata/.gitignore
new file mode 100644
index 0000000..4d41a44
--- /dev/null
+++ b/src/lib/testutils/testdata/.gitignore
@@ -0,0 +1,15 @@
+/auth_test.sqlite3.copied
+/badExampleQuery_fromWire.wire
+/examplequery_fromWire.wire
+/iquery_fromWire.wire
+/iquery_response_fromWire.wire
+/iqueryresponse_fromWire.wire
+/multiquestion_fromWire.wire
+/nsec3query_fromWire.wire
+/nsec3query_nodnssec_fromWire.wire
+/queryBadEDNS_fromWire.wire
+/shortanswer_fromWire.wire
+/simplequery_fromWire.wire
+/simpleresponse_fromWire.wire
+/test1.zone.copied
+/test2.zone.copied
diff --git a/src/lib/testutils/testdata/Makefile.am b/src/lib/testutils/testdata/Makefile.am
index 918d5c5..b9ef53f 100644
--- a/src/lib/testutils/testdata/Makefile.am
+++ b/src/lib/testutils/testdata/Makefile.am
@@ -5,6 +5,7 @@ BUILT_SOURCES += iqueryresponse_fromWire.wire multiquestion_fromWire.wire
BUILT_SOURCES += queryBadEDNS_fromWire.wire shortanswer_fromWire.wire
BUILT_SOURCES += simplequery_fromWire.wire simpleresponse_fromWire.wire
BUILT_SOURCES += iquery_fromWire.wire iquery_response_fromWire.wire
+BUILT_SOURCES += nsec3query_nodnssec_fromWire.wire nsec3query_fromWire.wire
# NOTE: keep this in sync with real file listing
# so is included in tarball
@@ -19,11 +20,14 @@ EXTRA_DIST += shortquestion_fromWire
EXTRA_DIST += shortresponse_fromWire
EXTRA_DIST += simplequery_fromWire.spec
EXTRA_DIST += simpleresponse_fromWire.spec
+EXTRA_DIST += nsec3query_nodnssec_fromWire.spec nsec3query_fromWire.spec
EXTRA_DIST += iquery_fromWire.spec iquery_response_fromWire.spec
EXTRA_DIST += example.com.zone example.net.zone example.org.zone example.zone
+EXTRA_DIST += rfc5155-example.zone.signed
EXTRA_DIST += example.com
EXTRA_DIST += example.sqlite3
+EXTRA_DIST += rwtest.sqlite3 # SQLite3 DB file as a template data source
EXTRA_DIST += test1.zone.in
EXTRA_DIST += test1-new.zone.in
diff --git a/src/lib/testutils/testdata/auth_test.sqlite3 b/src/lib/testutils/testdata/auth_test.sqlite3
new file mode 100755
index 0000000..5eeb2c3
Binary files /dev/null and b/src/lib/testutils/testdata/auth_test.sqlite3 differ
diff --git a/src/lib/testutils/testdata/example.sqlite3 b/src/lib/testutils/testdata/example.sqlite3
index e8e255b..0f6ee02 100644
Binary files a/src/lib/testutils/testdata/example.sqlite3 and b/src/lib/testutils/testdata/example.sqlite3 differ
diff --git a/src/lib/testutils/testdata/nsec3query_fromWire.spec b/src/lib/testutils/testdata/nsec3query_fromWire.spec
new file mode 100644
index 0000000..f68a09e
--- /dev/null
+++ b/src/lib/testutils/testdata/nsec3query_fromWire.spec
@@ -0,0 +1,11 @@
+#
+# A simple QUERY message (with DO bit on) for "example" zone signed with NSEC3
+#
+
+[header]
+arcount: 1
+[question]
+# use default
+name: ns2.example
+[edns]
+do: 1
diff --git a/src/lib/testutils/testdata/nsec3query_nodnssec_fromWire.spec b/src/lib/testutils/testdata/nsec3query_nodnssec_fromWire.spec
new file mode 100644
index 0000000..06a9561
--- /dev/null
+++ b/src/lib/testutils/testdata/nsec3query_nodnssec_fromWire.spec
@@ -0,0 +1,9 @@
+#
+# A simple QUERY message (without DO bit) for "example" zone signed with NSEC3
+#
+
+[header]
+# use default
+[question]
+# use default
+name: ns2.example
diff --git a/src/lib/testutils/testdata/rfc5155-example.zone.signed b/src/lib/testutils/testdata/rfc5155-example.zone.signed
new file mode 100644
index 0000000..595c441
--- /dev/null
+++ b/src/lib/testutils/testdata/rfc5155-example.zone.signed
@@ -0,0 +1,72 @@
+;; The example NSEC3-signed zone used in RFC5155.
+
+example. 3600 IN SOA ns1.example. bugs.x.w.example. 1 3600 300 3600000 3600
+example. 3600 IN RRSIG SOA 7 1 3600 20150420235959 20051021000000 40430 example. Hu25UIyNPmvPIVBrldN+9Mlp9Zql39qaUd8iq4ZLlYWfUUbbAS41pG+6 8z81q1xhkYAcEyHdVI2LmKusbZsT0Q==
+example. 3600 IN NS ns1.example.
+example. 3600 IN NS ns2.example.
+example. 3600 IN RRSIG NS 7 1 3600 20150420235959 20051021000000 40430 example. PVOgtMK1HHeSTau+HwDWC8Ts+6C8qtqd4pQJqOtdEVgg+MA+ai4fWDEh u3qHJyLcQ9tbD2vvCnMXjtz6SyObxA==
+example. 3600 IN MX 1 xx.example.
+example. 3600 IN RRSIG MX 7 1 3600 20150420235959 20051021000000 40430 example. GgQ1A9xs47k42VPvpL/a1BWUz/6XsnHkjotw9So8MQtZtl2wJBsnOQsa oHrRCrRbyriEl/GZn9Mto/Kx+wBo+w==
+example. 3600 IN DNSKEY 256 3 7 AwEAAaetidLzsKWUt4swWR8yu0wPHPiUi8LUsAD0QPWU+wzt89epO6tH zkMBVDkC7qphQO2hTY4hHn9npWFRw5BYubE= ; key id = 40430
+example. 3600 IN DNSKEY 257 3 7 AwEAAcUlFV1vhmqx6NSOUOq2R/dsR7Xm3upJj7IommWSpJABVfW8Q0rO vXdM6kzt+TAu92L9AbsUdblMFin8CVF3n4s= ; key id = 12708
+example. 3600 IN RRSIG DNSKEY 7 1 3600 20150420235959 20051021000000 12708 example. AuU4juU9RaxescSmStrQks3Gh9FblGBlVU31uzMZ/U/FpsUb8aC6QZS+ sTsJXnLnz7flGOsmMGQZf3bH+QsCtg==
+example. 3600 IN NSEC3PARAM 1 0 12 AABBCCDD
+example. 3600 IN RRSIG NSEC3PARAM 7 1 3600 20150420235959 20051021000000 40430 example. C1Gl8tPZNtnjlrYWDeeUV/sGLCyy/IHie2rerN05XSA3Pq0U3+4VvGWY WdUMfflOdxqnXHwJTLQsjlkynhG6Cg==
+2t7b4g4vsa5smi47k61mv5bv1a22bojr.example. 3600 IN A 192.0.2.127
+2t7b4g4vsa5smi47k61mv5bv1a22bojr.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. h6c++bzhRuWWt2bykN6mjaTNBcXNq5UuL5EdK+iDP4eY8I0kSiKaCjg3 tC1SQkeloMeub2GWk8p6xHMPZumXlw==
+a.example. 3600 IN NS ns1.a.example.
+a.example. 3600 IN NS ns2.a.example.
+a.example. 3600 IN DS 58470 5 1 3079F1593EBAD6DC121E202A8B766A6A4837206C
+a.example. 3600 IN RRSIG DS 7 2 3600 20150420235959 20051021000000 40430 example. XacFcQVHLVzdoc45EJhN616zQ4mEXtE8FzUhM2KWjfy1VfRKD9r1MeVG wwoukOKgJxBPFsWoo722vZ4UZ2dIdA==
+ns1.a.example. 3600 IN A 192.0.2.5
+ns2.a.example. 3600 IN A 192.0.2.6
+ai.example. 3600 IN A 192.0.2.9
+ai.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. hVe+wKYMlObTRPhX0NL67GxeZfdxqr/QeR6FtfdAj5+FgYxyzPEjIzvK Wy00hWIl6wD3Vws+rznEn8sQ64UdqA==
+ai.example. 3600 IN HINFO "KLH-10" "ITS"
+ai.example. 3600 IN RRSIG HINFO 7 2 3600 20150420235959 20051021000000 40430 example. Yi42uOq43eyO6qXHNvwwfFnIustWgV5urFcxenkLvs6pKRh00VBjODmf 3Z4nMO7IOl6nHSQ1v0wLHpEZG7Xj2w==
+ai.example. 3600 IN AAAA 2001:db8::f00:baa9
+ai.example. 3600 IN RRSIG AAAA 7 2 3600 20150420235959 20051021000000 40430 example. LcdxKaCB5bGZwPDg+3JJ4O02zoMBrjxqlf6WuaHQZZfTUpb9Nf2nxFGe 2XRPfR5tpJT6GdRGcHueLuXkMjBArQ==
+c.example. 3600 IN NS ns1.c.example.
+c.example. 3600 IN NS ns2.c.example.
+ns1.c.example. 3600 IN A 192.0.2.7
+ns2.c.example. 3600 IN A 192.0.2.8
+ns1.example. 3600 IN A 192.0.2.1
+ns1.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. bu6kx73n6XEunoVGuRfAgY7EF/AJqHy7hj0jkiqJjB0dOrx3wuz9SaBe GfqWIdn/uta3SavN4FRvZR9SCFHF5Q==
+ns2.example. 3600 IN A 192.0.2.2
+ns2.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. ktQ3TqE0CfRfki0Rb/Ip5BM0VnxelbuejCC4zpLbFKA/7eD7UNAwxMgx JPtbdST+syjYSJaj4IHfeX6n8vfoGA==
+*.w.example. 3600 IN MX 1 ai.example.
+*.w.example. 3600 IN RRSIG MX 7 2 3600 20150420235959 20051021000000 40430 example. CikebjQwGQPwijVcxgcZcSJKtfynugtlBiKb9FcBTrmOoyQ4InoWVudh CWsh/URX3lc4WRUMivEBP6+4KS3ldA==
+x.w.example. 3600 IN MX 1 xx.example.
+x.w.example. 3600 IN RRSIG MX 7 3 3600 20150420235959 20051021000000 40430 example. IrK3tq/tHFIBF0scHiE/1IwMAvckS/55hAVvQyxTFbkAdDloP3NbZzu+ yoSsr3b3OX6qbBpY7WCtwwekLKRAwQ==
+x.y.w.example. 3600 IN MX 1 xx.example.
+x.y.w.example. 3600 IN RRSIG MX 7 4 3600 20150420235959 20051021000000 40430 example. MqSt5HqJIN8+SLlzTOImrh5h9Xa6gDvAW/GnnbdPc6Z7nXvCpLPJj/5l Cwx3VuzVOjkbvXze8/8Ccl2Zn2hbug==
+xx.example. 3600 IN A 192.0.2.10
+xx.example. 3600 IN RRSIG A 7 2 3600 20150420235959 20051021000000 40430 example. T35hBWEZ017VC5u2c4OriKyVn/pu+fVK4AlXYOxJ6iQylfV2HQIKjv6b 7DzINB3aF/wjJqgXpQvhq+Ac6+ZiFg==
+xx.example. 3600 IN HINFO "KLH-10" "TOPS-20"
+xx.example. 3600 IN RRSIG HINFO 7 2 3600 20150420235959 20051021000000 40430 example. KimG+rDd+7VA1zRsu0ITNAQUTRlpnsmqWrihFRnU+bRa93v2e5oFNFYC s3Rqgv62K93N7AhW6Jfqj/8NzWjvKg==
+xx.example. 3600 IN AAAA 2001:db8::f00:baaa
+xx.example. 3600 IN RRSIG AAAA 7 2 3600 20150420235959 20051021000000 40430 example. IXBcXORITNwd8h3gNwyxtYFvAupS/CYWufVeuBUX0O25ivBCULjZjpDx FSxfohb/KA7YRdxENzYfMItpILl/Xw==
+0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN NSEC3 1 1 12 AABBCCDD 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR NS SOA MX RRSIG DNSKEY NSEC3PARAM
+0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OSgWSm26B+cS+dDL8b5QrWr/dEWhtCsKlwKLIBHYH6blRxK9rC0bMJPw Q4mLIuw85H2EY762BOCXJZMnpuwhpA==
+2t7b4g4vsa5smi47k61mv5bv1a22bojr.example. 3600 IN NSEC3 1 1 12 AABBCCDD 2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S A RRSIG
+2t7b4g4vsa5smi47k61mv5bv1a22bojr.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. OmBvJ1Vgg1hCKMXHFiNeIYHK9XVW0iLDLwJN4TFoNxZuP03gAXEI634Y wOc4YBNITrj413iqNI6mRk/r1dOSUw==
+2vptu5timamqttgl4luu9kg21e0aor3s.example. 3600 IN NSEC3 1 1 12 AABBCCDD 35MTHGPGCU1QG68FAB165KLNSNK3DPVL MX RRSIG
+2vptu5timamqttgl4luu9kg21e0aor3s.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. KL1V2oFYghNV0Hm7Tf2vpJjM6l+0g1JCcVYGVfI0lKrhPmTsOA96cLEA Cgo1x8I7kApJX+obTuktZ+sdsZPY1w==
+35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN NSEC3 1 1 12 AABBCCDD B4UM86EGHHDS6NEA196SMVMLO4ORS995 NS DS RRSIG
+35mthgpgcu1qg68fab165klnsnk3dpvl.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. g6jPUUpduAJKRljUsN8gB4UagAX0NxY9shwQAynzo8EUWH+z6hEIBlUT PGj15eZll6VhQqgZXtAIR3chwgW+SA==
+b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN NSEC3 1 1 12 AABBCCDD GJEQE526PLBF1G8MKLP59ENFD789NJGI MX RRSIG
+b4um86eghhds6nea196smvmlo4ors995.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. ZkPG3M32lmoHM6pa3D6gZFGB/rhL//Bs3Omh5u4m/CUiwtblEVOaAKKZ d7S959OeiX43aLX3pOv0TSTyiTxIZg==
+gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN NSEC3 1 1 12 AABBCCDD JI6NEOAEPV8B5O6K4EV33ABHA8HT9FGC A HINFO AAAA RRSIG
+gjeqe526plbf1g8mklp59enfd789njgi.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. IVnezTJ9iqblFF97vPSmfXZ5Zozngx3KX3byLTZC4QBH2dFWhf6scrGF ZB980AfCxoD9qbbKDy+rdGIeRSVNyw==
+ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. 3600 IN NSEC3 1 1 12 AABBCCDD K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H
+ji6neoaepv8b5o6k4ev33abha8ht9fgc.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. gPkFp1s2QDQ6wQzcg1uSebZ61W33rUBDcTj72F3kQ490fEdp7k1BUIfb cZtPbX3YCpE+sIt0MpzVSKfTwx4uYA==
+k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN NSEC3 1 1 12 AABBCCDD KOHAR7MBB8DC2CE8A9QVL8HON4K53UHI
+k8udemvp1j2f7eg6jebps17vp3n8i58h.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. FtXGbvF0+wf8iWkyo73enAuVx03klN+pILBKS6qCcftVtfH4yVzsEZqu J27NHR7ruxJWDNMtOtx7w9WfcIg62A==
+kohar7mbb8dc2ce8a9qvl8hon4k53uhi.example. 3600 IN NSEC3 1 1 12 AABBCCDD Q04JKCEVQVMU85R014C7DKBA38O0JI5R A RRSIG
+kohar7mbb8dc2ce8a9qvl8hon4k53uhi.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. VrDXs2uVW21N08SyQIz88zml+y4ZCInTwgDr6zz43yAg+LFERjOrj3Oj ct51ac7Dp4eZbf9FQJazmASFKGxGXg==
+q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN NSEC3 1 1 12 AABBCCDD R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN A RRSIG
+q04jkcevqvmu85r014c7dkba38o0ji5r.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. hV5I89b+4FHJDATp09g4bbN0R1F845CaXpL3ZxlMKimoPAyqletMlEWw LfFia7sdpSzn+ZlNNlkxWcLsIlMmUg==
+r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN NSEC3 1 1 12 AABBCCDD T644EBQK9BIBCNA874GIVR6JOJ62MLHV MX RRSIG
+r53bq7cc2uvmubfu5ocmm6pers9tk9en.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. aupviViruXs4bDg9rCbezzBMf9h1ZlDvbW/CZFKulIGXXLj8B/fsDJar XVDA9bnUoRhEbKp+HF1FWKW7RIJdtQ==
+t644ebqk9bibcna874givr6joj62mlhv.example. 3600 IN NSEC3 1 1 12 AABBCCDD 0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM A HINFO AAAA RRSIG
+t644ebqk9bibcna874givr6joj62mlhv.example. 3600 IN RRSIG NSEC3 7 2 3600 20150420235959 20051021000000 40430 example. RAjGECB8P7O+F4Pa4Dx3tC0M+Z3KmlLKImcafb9XWwx+NWUNz7NBEDBQ HivIyKPVDkChcePIX1xPl1ATNa+8Dw==
diff --git a/src/lib/testutils/testdata/rwtest.sqlite3 b/src/lib/testutils/testdata/rwtest.sqlite3
new file mode 100644
index 0000000..558bc3f
Binary files /dev/null and b/src/lib/testutils/testdata/rwtest.sqlite3 differ
diff --git a/src/lib/util/io/fd_share.cc b/src/lib/util/io/fd_share.cc
index eb02561..eb6dd3b 100644
--- a/src/lib/util/io/fd_share.cc
+++ b/src/lib/util/io/fd_share.cc
@@ -182,7 +182,7 @@ namespace {
// Need the peer PID
int
-send_pid(const int sock) {
+send_pid(const SOCKET sock) {
pid_t pid(_getpid());
if (send(sock, (const char *)&pid, sizeof(pid), 0) != sizeof(pid)) {
return (FD_SYSTEM_ERROR);
@@ -191,7 +191,7 @@ send_pid(const int sock) {
}
pid_t
-recv_pid(const int sock) {
+recv_pid(const SOCKET sock) {
pid_t pid;
if (recv(sock, (char *)&pid , sizeof(pid), 0) != sizeof(pid)) {
return (FD_SYSTEM_ERROR);
@@ -200,28 +200,28 @@ recv_pid(const int sock) {
}
}
-int
-recv_fd(const int sock) {
+SOCKET
+recv_fd(const SOCKET sock) {
int ret(send_pid(sock));
if (ret != 0) {
- return (ret);
+ return ((SOCKET) ret);
}
WSAPROTOCOL_INFO pi;
if (recv(sock, (char *)&pi, sizeof(pi), 0) != sizeof(pi)) {
- return (FD_SYSTEM_ERROR);
+ return ((SOCKET) FD_SYSTEM_ERROR);
}
SOCKET nsock = WSASocket(pi.iAddressFamily,
pi.iSocketType,
pi.iProtocol,
&pi, 0, 0);
if (nsock == INVALID_SOCKET) {
- return (FD_OTHER_ERROR);
+ return ((SOCKET) FD_OTHER_ERROR);
}
- return ((int) nsock);
+ return (nsock);
}
int
-send_fd(const int sock, const int fd) {
+send_fd(const SOCKET sock, const SOCKET fd) {
pid_t peerpid(recv_pid(sock));
if (peerpid == FD_SYSTEM_ERROR) {
return (FD_SYSTEM_ERROR);
diff --git a/src/lib/util/io/fd_share.h b/src/lib/util/io/fd_share.h
index 2b30abd..f5d81da 100644
--- a/src/lib/util/io/fd_share.h
+++ b/src/lib/util/io/fd_share.h
@@ -41,7 +41,11 @@ const int FD_OTHER_ERROR = -1;
* \param sock The unix domain socket to read from. Tested and it does
* not work with a pipe.
*/
+#ifdef _WIN32
+SOCKET recv_fd(const SOCKET sock);
+#else
int recv_fd(const int sock);
+#endif
/**
* \short Sends a file descriptor.
@@ -56,7 +60,11 @@ int recv_fd(const int sock);
* \param fd The file descriptor to send. It should work with any valid
* file descriptor.
*/
+#ifdef _WIN32
+int send_fd(const SOCKET sock, const SOCKET fd);
+#else
int send_fd(const int sock, const int fd);
+#endif
} // End for namespace io
} // End for namespace util
diff --git a/src/lib/util/io/fdshare_python.cc b/src/lib/util/io/fdshare_python.cc
index 249f8b0..1a67e86 100644
--- a/src/lib/util/io/fdshare_python.cc
+++ b/src/lib/util/io/fdshare_python.cc
@@ -27,7 +27,7 @@ fdshare_recv_fd(PyObject*, PyObject* args) {
if (!PyArg_ParseTuple(args, "i", &sock)) {
return (NULL);
}
- fd = isc::util::io::recv_fd(sock);
+ fd = (int) isc::util::io::recv_fd((SOCKET) sock);
return (Py_BuildValue("i", fd));
}
@@ -37,7 +37,7 @@ fdshare_send_fd(PyObject*, PyObject* args) {
if (!PyArg_ParseTuple(args, "ii", &sock, &fd)) {
return (NULL);
}
- result = isc::util::io::send_fd(sock, fd);
+ result = isc::util::io::send_fd((SOCKET) sock, (SOCKET) fd);
return (Py_BuildValue("i", result));
}
diff --git a/src/lib/xfr/xfrout_client.cc b/src/lib/xfr/xfrout_client.cc
index a5f60cb..2542fff 100644
--- a/src/lib/xfr/xfrout_client.cc
+++ b/src/lib/xfr/xfrout_client.cc
@@ -93,7 +93,12 @@ XfroutClient::disconnect() {
}
int
-XfroutClient::sendXfroutRequestInfo(const int tcp_sock,
+XfroutClient::sendXfroutRequestInfo(
+#ifdef _WIN32
+ const SOCKET tcp_sock,
+#else
+ const int tcp_sock,
+#endif
const void* const msg_data,
const uint16_t msg_len)
{
diff --git a/src/lib/xfr/xfrout_client.h b/src/lib/xfr/xfrout_client.h
index bad963c..b8bac0a 100644
--- a/src/lib/xfr/xfrout_client.h
+++ b/src/lib/xfr/xfrout_client.h
@@ -60,7 +60,13 @@ public:
//@}
virtual void connect() = 0;
virtual void disconnect() = 0;
- virtual int sendXfroutRequestInfo(int tcp_sock, const void* msg_data,
+ virtual int sendXfroutRequestInfo(
+#ifdef _WIN32
+ SOCKET tcp_sock,
+#else
+ int tcp_sock,
+#endif
+ const void* msg_data,
uint16_t msg_len) = 0;
};
@@ -75,7 +81,13 @@ private:
public:
virtual void connect();
virtual void disconnect();
- virtual int sendXfroutRequestInfo(int tcp_sock, const void* msg_data,
+ virtual int sendXfroutRequestInfo(
+#ifdef _WIN32
+ SOCKET tcp_sock,
+#else
+ int tcp_sock,
+#endif
+ const void* msg_data,
uint16_t msg_len);
private:
XfroutClientImpl* impl_;
More information about the bind10-changes
mailing list