2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-03 23:45:27 +00:00

[1820] avoid using the removed DNSService interfaces.

also made other cleanups, making it the code more exception safe.
This commit is contained in:
JINMEI Tatuya
2012-04-02 18:05:27 -07:00
parent a3f1538ebc
commit 1eb1ca43bb

View File

@@ -18,10 +18,11 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/time.h> #include <sys/time.h>
#include <string.h> #include <cstring>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp> #include <boost/date_time/posix_time/posix_time_types.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@@ -62,6 +63,7 @@ using namespace isc::asiodns;
using namespace isc::asiolink; using namespace isc::asiolink;
using namespace isc::dns; using namespace isc::dns;
using namespace isc::util; using namespace isc::util;
using boost::scoped_ptr;
namespace isc { namespace isc {
namespace asiodns { namespace asiodns {
@@ -85,18 +87,14 @@ const char* const TEST_IPV4_ADDR = "127.0.0.1";
// for the tests below. // for the tests below.
const uint8_t test_data[] = {0, 4, 1, 2, 3, 4}; const uint8_t test_data[] = {0, 4, 1, 2, 3, 4};
// This function returns an addrinfo structure for use by tests, using // This function returns an addrinfo structure for use by tests.
// different addresses and ports depending on whether we're testing
// IPv4 or v6, TCP or UDP, and client or server operation.
struct addrinfo* struct addrinfo*
resolveAddress(const int family, const int protocol, const bool client) { resolveAddress(const int protocol, const char* const addr,
const char* const addr = (family == AF_INET6) ? const char* const port)
TEST_IPV6_ADDR : TEST_IPV4_ADDR; {
const char* const port = client ? TEST_CLIENT_PORT : TEST_SERVER_PORT;
struct addrinfo hints; struct addrinfo hints;
memset(&hints, 0, sizeof(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_socktype = (protocol == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
hints.ai_protocol = protocol; hints.ai_protocol = protocol;
hints.ai_flags = AI_NUMERICSERV; hints.ai_flags = AI_NUMERICSERV;
@@ -110,6 +108,42 @@ resolveAddress(const int family, const int protocol, const bool client) {
return (res); 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.
struct ScopedSocket {
ScopedSocket(int s) : s_(s) {}
~ScopedSocket() {
if (s_ >= 0) {
close(s_);
}
}
int release() {
int s = s_;
s_ = -1;
return (s);
}
int s_;
};
// This fixture is a framework for various types of network operations // This fixture is a framework for various types of network operations
// using the ASIO interfaces. Each test case creates an IOService object, // using the ASIO interfaces. Each test case creates an IOService object,
// opens a local "client" socket for testing, sends data via the local socket // opens a local "client" socket for testing, sends data via the local socket
@@ -129,27 +163,22 @@ protected:
// It would delete itself, but after the io_service_, which could // It would delete itself, but after the io_service_, which could
// segfailt in case there were unhandled requests // segfailt in case there were unhandled requests
resolver_.reset(); resolver_.reset();
if (res_ != NULL) {
freeaddrinfo(res_);
}
if (sock_ != -1) { if (sock_ != -1) {
close(sock_); close(sock_);
} }
delete dns_service_;
delete callback_;
delete io_service_;
} }
// Send a test UDP packet to a mock server // Send a test UDP packet to a mock server
void sendUDP(const int family) { 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_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock_ < 0) { if (sock_ < 0) {
isc_throw(IOError, "failed to open test socket"); isc_throw(IOError, "failed to open test socket");
} }
const int cc = sendto(sock_, test_data, sizeof(test_data), 0, const int cc = sendto(sock_, test_data, sizeof(test_data), 0,
res_->ai_addr, res_->ai_addrlen); res->ai_addr, res->ai_addrlen);
if (cc != sizeof(test_data)) { if (cc != sizeof(test_data)) {
isc_throw(IOError, "unexpected sendto result: " << cc); isc_throw(IOError, "unexpected sendto result: " << cc);
} }
@@ -158,13 +187,14 @@ protected:
// Send a test TCP packet to a mock server // Send a test TCP packet to a mock server
void sendTCP(const int family) { 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_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock_ < 0) { if (sock_ < 0) {
isc_throw(IOError, "failed to open test socket"); isc_throw(IOError, "failed to open test socket");
} }
if (connect(sock_, res_->ai_addr, res_->ai_addrlen) < 0) { if (connect(sock_, res->ai_addr, res->ai_addrlen) < 0) {
isc_throw(IOError, "failed to connect to the test server"); isc_throw(IOError, "failed to connect to the test server");
} }
const int cc = send(sock_, test_data, sizeof(test_data), 0); const int cc = send(sock_, test_data, sizeof(test_data), 0);
@@ -178,14 +208,15 @@ protected:
// recursive lookup. The caller must place a RecursiveQuery // recursive lookup. The caller must place a RecursiveQuery
// on the IO Service queue before running this routine. // on the IO Service queue before running this routine.
void recvUDP(const int family, void* buffer, size_t& size) { 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_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock_ < 0) { if (sock_ < 0) {
isc_throw(IOError, "failed to open test socket"); isc_throw(IOError, "failed to open test socket");
} }
if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) { if (bind(sock_, res->ai_addr, res->ai_addrlen) < 0) {
isc_throw(IOError, "bind failed: " << strerror(errno)); isc_throw(IOError, "bind failed: " << strerror(errno));
} }
@@ -227,38 +258,68 @@ protected:
size = ret; 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));
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");
}
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 // Set up an IO Service queue using the specified address
void setDNSService(const char& address) { void setDNSService(const string& address) {
delete dns_service_; setDNSService();
dns_service_ = NULL; addServer(address, TEST_SERVER_PORT, IPPROTO_TCP);
delete io_service_; addServer(address, TEST_SERVER_PORT, IPPROTO_UDP);
io_service_ = new IOService();
callback_ = new ASIOCallBack(this);
dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, address, callback_, NULL, NULL);
} }
// Set up an IO Service queue using the "any" address, on IPv4 if // 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. // 'use_ipv4' is true and on IPv6 if 'use_ipv6' is true.
void setDNSService(const bool use_ipv4, const bool use_ipv6) { void setDNSService(const bool use_ipv4, const bool use_ipv6) {
delete dns_service_; setDNSService();
dns_service_ = NULL; if (use_ipv6) {
delete io_service_; addServer("::", TEST_SERVER_PORT, IPPROTO_TCP);
io_service_ = new IOService(); addServer("::", TEST_SERVER_PORT, IPPROTO_UDP);
callback_ = new ASIOCallBack(this); }
dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, use_ipv4, use_ipv6, callback_, if (use_ipv4) {
NULL, NULL); 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 empty DNS Service
// Set up an IO Service queue without any addresses // Set up an IO Service queue without any addresses
void setDNSService() { void setDNSService() {
delete dns_service_; io_service_.reset(new IOService());
dns_service_ = NULL; callback_.reset(new ASIOCallBack(this));
delete io_service_; dns_service_.reset(new DNSService(*io_service_, callback_.get(), NULL,
io_service_ = new IOService(); NULL));
callback_ = new ASIOCallBack(this);
dns_service_ = new DNSService(*io_service_, callback_, NULL, NULL);
} }
// Run a simple server test, on either IPv4 or IPv6, and over either // Run a simple server test, on either IPv4 or IPv6, and over either
@@ -425,28 +486,27 @@ private:
protected: protected:
// We use a pointer for io_service_, because for some tests we // We use a pointer for io_service_, because for some tests we
// need to recreate a new one within one onstance of this class // need to recreate a new one within one onstance of this class
IOService* io_service_; scoped_ptr<IOService> io_service_;
DNSService* dns_service_; scoped_ptr<DNSService> dns_service_;
isc::nsas::NameserverAddressStore* nsas_; scoped_ptr<isc::nsas::NameserverAddressStore> nsas_;
isc::cache::ResolverCache cache_; isc::cache::ResolverCache cache_;
ASIOCallBack* callback_; scoped_ptr<ASIOCallBack> callback_;
int callback_protocol_; int callback_protocol_;
int callback_native_; int callback_native_;
string callback_address_; string callback_address_;
vector<uint8_t> callback_data_; vector<uint8_t> callback_data_;
int sock_; int sock_;
struct addrinfo* res_;
boost::shared_ptr<isc::util::unittests::TestResolver> resolver_; boost::shared_ptr<isc::util::unittests::TestResolver> resolver_;
}; };
RecursiveQueryTest::RecursiveQueryTest() : RecursiveQueryTest::RecursiveQueryTest() :
dns_service_(NULL), callback_(NULL), callback_protocol_(0), dns_service_(NULL), callback_(NULL), callback_protocol_(0),
callback_native_(-1), sock_(-1), res_(NULL), callback_native_(-1), sock_(-1),
resolver_(new isc::util::unittests::TestResolver()) resolver_(new isc::util::unittests::TestResolver())
{ {
io_service_ = new IOService(); io_service_.reset(new IOService());
setDNSService(true, true); setDNSService(true, true);
nsas_ = new isc::nsas::NameserverAddressStore(resolver_); nsas_.reset(new isc::nsas::NameserverAddressStore(resolver_));
} }
TEST_F(RecursiveQueryTest, v6UDPSend) { TEST_F(RecursiveQueryTest, v6UDPSend) {
@@ -477,24 +537,24 @@ TEST_F(RecursiveQueryTest, v6UDPSendSpecific) {
// an error on a subsequent read operation. We could do it, but for // an error on a subsequent read operation. We could do it, but for
// simplicity we only tests the easier cases for now. // simplicity we only tests the easier cases for now.
setDNSService(*TEST_IPV6_ADDR); setDNSService(TEST_IPV6_ADDR);
doTest(AF_INET6, IPPROTO_UDP); doTest(AF_INET6, IPPROTO_UDP);
} }
TEST_F(RecursiveQueryTest, v6TCPSendSpecific) { TEST_F(RecursiveQueryTest, v6TCPSendSpecific) {
setDNSService(*TEST_IPV6_ADDR); setDNSService(TEST_IPV6_ADDR);
doTest(AF_INET6, IPPROTO_TCP); doTest(AF_INET6, IPPROTO_TCP);
EXPECT_THROW(sendTCP(AF_INET), IOError); EXPECT_THROW(sendTCP(AF_INET), IOError);
} }
TEST_F(RecursiveQueryTest, v4UDPSendSpecific) { TEST_F(RecursiveQueryTest, v4UDPSendSpecific) {
setDNSService(*TEST_IPV4_ADDR); setDNSService(TEST_IPV4_ADDR);
doTest(AF_INET, IPPROTO_UDP); doTest(AF_INET, IPPROTO_UDP);
} }
TEST_F(RecursiveQueryTest, v4TCPSendSpecific) { TEST_F(RecursiveQueryTest, v4TCPSendSpecific) {
setDNSService(*TEST_IPV4_ADDR); setDNSService(TEST_IPV4_ADDR);
doTest(AF_INET, IPPROTO_TCP); doTest(AF_INET, IPPROTO_TCP);
EXPECT_THROW(sendTCP(AF_INET6), IOError); EXPECT_THROW(sendTCP(AF_INET6), IOError);
@@ -502,7 +562,7 @@ TEST_F(RecursiveQueryTest, v4TCPSendSpecific) {
TEST_F(RecursiveQueryTest, v6AddServer) { TEST_F(RecursiveQueryTest, v6AddServer) {
setDNSService(); setDNSService();
dns_service_->addServer(*TEST_SERVER_PORT, TEST_IPV6_ADDR); addServer(TEST_IPV6_ADDR, TEST_SERVER_PORT, IPPROTO_TCP);
doTest(AF_INET6, IPPROTO_TCP); doTest(AF_INET6, IPPROTO_TCP);
EXPECT_THROW(sendTCP(AF_INET), IOError); EXPECT_THROW(sendTCP(AF_INET), IOError);
@@ -510,7 +570,7 @@ TEST_F(RecursiveQueryTest, v6AddServer) {
TEST_F(RecursiveQueryTest, v4AddServer) { TEST_F(RecursiveQueryTest, v4AddServer) {
setDNSService(); setDNSService();
dns_service_->addServer(*TEST_SERVER_PORT, TEST_IPV4_ADDR); addServer(TEST_IPV4_ADDR, TEST_SERVER_PORT, IPPROTO_TCP);
doTest(AF_INET, IPPROTO_TCP); doTest(AF_INET, IPPROTO_TCP);
EXPECT_THROW(sendTCP(AF_INET6), IOError); EXPECT_THROW(sendTCP(AF_INET6), IOError);
@@ -607,17 +667,18 @@ TEST_F(RecursiveQueryTest, forwarderSend) {
} }
int int
createTestSocket() createTestSocket() {
{ ScopedAddrInfo sai(resolveAddress(AF_INET, IPPROTO_UDP, true));
struct addrinfo* res_ = resolveAddress(AF_INET, IPPROTO_UDP, true); struct addrinfo* res = sai.res_;
int sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
int sock_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock_ < 0) { if (sock_ < 0) {
isc_throw(IOError, "failed to open test socket"); isc_throw(IOError, "failed to open test socket");
} }
if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) { if (bind(sock_, res->ai_addr, res->ai_addrlen) < 0) {
isc_throw(IOError, "failed to bind test socket"); isc_throw(IOError, "failed to bind test socket");
} }
return sock_; return (sock_);
} }
int int