asiolink_unittest.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // $Id$
  15. #include <config.h>
  16. #include <string.h>
  17. #include <boost/lexical_cast.hpp>
  18. #include <boost/bind.hpp>
  19. #include <gtest/gtest.h>
  20. #include <exceptions/exceptions.h>
  21. #include <dns/tests/unittest_util.h>
  22. #include <dns/buffer.h>
  23. #include <dns/message.h>
  24. #include <asiolink/asiolink.h>
  25. #include <asiolink/internal/tcpdns.h>
  26. #include <asiolink/internal/udpdns.h>
  27. #include <asio.hpp>
  28. using isc::UnitTestUtil;
  29. using namespace std;
  30. using namespace asiolink;
  31. using namespace isc::dns;
  32. using namespace asio;
  33. using asio::ip::udp;
  34. namespace {
  35. const char* const TEST_SERVER_PORT = "53535";
  36. const char* const TEST_CLIENT_PORT = "53536";
  37. const char* const TEST_IPV6_ADDR = "::1";
  38. const char* const TEST_IPV4_ADDR = "127.0.0.1";
  39. // This data is intended to be valid as a DNS/TCP-like message: the first
  40. // two octets encode the length of the rest of the data. This is crucial
  41. // for the tests below.
  42. const uint8_t test_data[] = {0, 4, 1, 2, 3, 4};
  43. class DummySocket : public IOSocket {
  44. private:
  45. DummySocket(const DummySocket& source);
  46. DummySocket& operator=(const DummySocket& source);
  47. public:
  48. DummySocket(const int protocol) : protocol_(protocol) {}
  49. virtual int getNative() const { return (-1); }
  50. virtual int getProtocol() const { return (protocol_); }
  51. private:
  52. const int protocol_;
  53. };
  54. TEST(IOAddressTest, fromText) {
  55. IOAddress io_address_v4("192.0.2.1");
  56. EXPECT_EQ("192.0.2.1", io_address_v4.toText());
  57. IOAddress io_address_v6("2001:db8::1234");
  58. EXPECT_EQ("2001:db8::1234", io_address_v6.toText());
  59. // bogus IPv4 address-like input
  60. EXPECT_THROW(IOAddress("192.0.2.2.1"), IOError);
  61. // bogus IPv4 address-like input: out-of-range octet
  62. EXPECT_THROW(IOAddress("192.0.2.300"), IOError);
  63. // bogus IPv6 address-like input
  64. EXPECT_THROW(IOAddress("2001:db8:::1234"), IOError);
  65. // bogus IPv6 address-like input
  66. EXPECT_THROW(IOAddress("2001:db8::efgh"), IOError);
  67. }
  68. TEST(IOEndpointTest, createUDPv4) {
  69. const IOEndpoint* ep;
  70. ep = IOEndpoint::create(IPPROTO_UDP, IOAddress("192.0.2.1"), 5300);
  71. EXPECT_EQ("192.0.2.1", ep->getAddress().toText());
  72. EXPECT_EQ(5300, ep->getPort());
  73. EXPECT_EQ(AF_INET, ep->getFamily());
  74. EXPECT_EQ(AF_INET, ep->getAddress().getFamily());
  75. EXPECT_EQ(IPPROTO_UDP, ep->getProtocol());
  76. }
  77. TEST(IOEndpointTest, createTCPv4) {
  78. const IOEndpoint* ep;
  79. ep = IOEndpoint::create(IPPROTO_TCP, IOAddress("192.0.2.1"), 5301);
  80. EXPECT_EQ("192.0.2.1", ep->getAddress().toText());
  81. EXPECT_EQ(5301, ep->getPort());
  82. EXPECT_EQ(AF_INET, ep->getFamily());
  83. EXPECT_EQ(AF_INET, ep->getAddress().getFamily());
  84. EXPECT_EQ(IPPROTO_TCP, ep->getProtocol());
  85. }
  86. TEST(IOEndpointTest, createUDPv6) {
  87. const IOEndpoint* ep;
  88. ep = IOEndpoint::create(IPPROTO_UDP, IOAddress("2001:db8::1234"), 5302);
  89. EXPECT_EQ("2001:db8::1234", ep->getAddress().toText());
  90. EXPECT_EQ(5302, ep->getPort());
  91. EXPECT_EQ(AF_INET6, ep->getFamily());
  92. EXPECT_EQ(AF_INET6, ep->getAddress().getFamily());
  93. EXPECT_EQ(IPPROTO_UDP, ep->getProtocol());
  94. }
  95. TEST(IOEndpointTest, createTCPv6) {
  96. const IOEndpoint* ep;
  97. ep = IOEndpoint::create(IPPROTO_TCP, IOAddress("2001:db8::1234"), 5303);
  98. EXPECT_EQ("2001:db8::1234", ep->getAddress().toText());
  99. EXPECT_EQ(5303, ep->getPort());
  100. EXPECT_EQ(AF_INET6, ep->getFamily());
  101. EXPECT_EQ(AF_INET6, ep->getAddress().getFamily());
  102. EXPECT_EQ(IPPROTO_TCP, ep->getProtocol());
  103. }
  104. TEST(IOEndpointTest, createIPProto) {
  105. EXPECT_THROW(IOEndpoint::create(IPPROTO_IP, IOAddress("192.0.2.1"),
  106. 5300)->getAddress().toText(),
  107. IOError);
  108. }
  109. TEST(IOSocketTest, dummySockets) {
  110. EXPECT_EQ(IPPROTO_UDP, DummySocket(IPPROTO_UDP).getProtocol());
  111. EXPECT_EQ(IPPROTO_TCP, DummySocket(IPPROTO_TCP).getProtocol());
  112. EXPECT_EQ(-1, DummySocket(IPPROTO_UDP).getNative());
  113. EXPECT_EQ(-1, DummySocket(IPPROTO_TCP).getNative());
  114. }
  115. TEST(IOServiceTest, badPort) {
  116. IOService io_service;
  117. EXPECT_THROW(DNSService(io_service, *"65536", true, false, NULL, NULL, NULL), IOError);
  118. EXPECT_THROW(DNSService(io_service, *"5300.0", true, false, NULL, NULL, NULL), IOError);
  119. EXPECT_THROW(DNSService(io_service, *"-1", true, false, NULL, NULL, NULL), IOError);
  120. EXPECT_THROW(DNSService(io_service, *"domain", true, false, NULL, NULL, NULL), IOError);
  121. }
  122. TEST(IOServiceTest, badAddress) {
  123. IOService io_service;
  124. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"192.0.2.1.1", NULL, NULL, NULL), IOError);
  125. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"2001:db8:::1", NULL, NULL, NULL), IOError);
  126. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"localhost", NULL, NULL, NULL), IOError);
  127. }
  128. TEST(IOServiceTest, unavailableAddress) {
  129. IOService io_service;
  130. // These addresses should generally be unavailable as a valid local
  131. // address, although there's no guarantee in theory.
  132. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"255.255.0.0", NULL, NULL, NULL), IOError);
  133. // Some OSes would simply reject binding attempt for an AF_INET6 socket
  134. // to an IPv4-mapped IPv6 address. Even if those that allow it, since
  135. // the corresponding IPv4 address is the same as the one used in the
  136. // AF_INET socket case above, it should at least show the same result
  137. // as the previous one.
  138. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:255.255.0.0", NULL, NULL, NULL), IOError);
  139. }
  140. TEST(IOServiceTest, duplicateBind_v6) {
  141. // In each sub test case, second attempt should fail due to duplicate bind
  142. IOService io_service;
  143. // IPv6, "any" address
  144. DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL);
  145. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, false, true, NULL, NULL, NULL), IOError);
  146. delete dns_service;
  147. }
  148. TEST(IOServiceTest, duplicateBind_v6_address) {
  149. // In each sub test case, second attempt should fail due to duplicate bind
  150. IOService io_service;
  151. // IPv6, specific address
  152. DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL);
  153. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV6_ADDR, NULL, NULL, NULL), IOError);
  154. delete dns_service;
  155. }
  156. TEST(IOServiceTest, duplicateBind_v4) {
  157. // In each sub test case, second attempt should fail due to duplicate bind
  158. IOService io_service;
  159. // IPv4, "any" address
  160. DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL);
  161. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, true, false, NULL, NULL, NULL), IOError);
  162. delete dns_service;
  163. }
  164. TEST(IOServiceTest, duplicateBind_v4_address) {
  165. // In each sub test case, second attempt should fail due to duplicate bind
  166. IOService io_service;
  167. // IPv4, specific address
  168. DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL);
  169. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *TEST_IPV4_ADDR, NULL, NULL, NULL), IOError);
  170. delete dns_service;
  171. }
  172. // Disabled because IPv4-mapped addresses don't seem to be working with
  173. // the IOService constructor
  174. TEST(IOServiceTest, DISABLED_IPv4MappedDuplicateBind) {
  175. IOService io_service;
  176. // Duplicate bind on IPv4-mapped IPv6 address
  177. DNSService* dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL);
  178. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL), IOError);
  179. delete dns_service;
  180. // XXX:
  181. // Currently, this throws an "invalid argument" exception. I have
  182. // not been able to get IPv4-mapped addresses to work.
  183. dns_service = new DNSService(io_service, *TEST_SERVER_PORT, *"::ffff:127.0.0.1", NULL, NULL, NULL);
  184. EXPECT_THROW(DNSService(io_service, *TEST_SERVER_PORT, *"127.0.0.1", NULL, NULL, NULL), IOError);
  185. delete dns_service;
  186. }
  187. // This function returns an addrinfo structure for use by tests, using
  188. // different addresses and ports depending on whether we're testing
  189. // IPv4 or v6, TCP or UDP, and client or server operation.
  190. struct addrinfo*
  191. resolveAddress(const int family, const int protocol, const bool client) {
  192. const char* const addr = (family == AF_INET6) ?
  193. TEST_IPV6_ADDR : TEST_IPV4_ADDR;
  194. const char* const port = client ? TEST_CLIENT_PORT : TEST_SERVER_PORT;
  195. struct addrinfo hints;
  196. memset(&hints, 0, sizeof(hints));
  197. hints.ai_family = family;
  198. hints.ai_socktype = (protocol == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
  199. hints.ai_protocol = protocol;
  200. hints.ai_flags = AI_NUMERICSERV;
  201. struct addrinfo* res;
  202. const int error = getaddrinfo(addr, port, &hints, &res);
  203. if (error != 0) {
  204. isc_throw(IOError, "getaddrinfo failed: " << gai_strerror(error));
  205. }
  206. return (res);
  207. }
  208. // This fixture is a framework for various types of network operations
  209. // using the ASIO interfaces. Each test case creates an IOService object,
  210. // opens a local "client" socket for testing, sends data via the local socket
  211. // to the service that would run in the IOService object.
  212. // A mock callback function (an ASIOCallBack object) is registered with the
  213. // IOService object, so the test code should be able to examine the data
  214. // received on the server side. It then checks the received data matches
  215. // expected parameters.
  216. // If initialization parameters of the IOService should be modified, the test
  217. // case can do it using the setDNSService() method.
  218. // Note: the set of tests in ASIOLinkTest use actual network services and may
  219. // involve undesirable side effects such as blocking.
  220. class ASIOLinkTest : public ::testing::Test {
  221. protected:
  222. ASIOLinkTest();
  223. ~ASIOLinkTest() {
  224. if (res_ != NULL) {
  225. freeaddrinfo(res_);
  226. }
  227. if (sock_ != -1) {
  228. close(sock_);
  229. }
  230. delete dns_service_;
  231. delete callback_;
  232. delete io_service_;
  233. }
  234. // Send a test UDP packet to a mock server
  235. void sendUDP(const int family) {
  236. res_ = resolveAddress(family, IPPROTO_UDP, false);
  237. sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  238. if (sock_ < 0) {
  239. isc_throw(IOError, "failed to open test socket");
  240. }
  241. const int cc = sendto(sock_, test_data, sizeof(test_data), 0,
  242. res_->ai_addr, res_->ai_addrlen);
  243. if (cc != sizeof(test_data)) {
  244. isc_throw(IOError, "unexpected sendto result: " << cc);
  245. }
  246. io_service_->run();
  247. }
  248. // Send a test TCP packet to a mock server
  249. void sendTCP(const int family) {
  250. res_ = resolveAddress(family, IPPROTO_TCP, false);
  251. sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  252. if (sock_ < 0) {
  253. isc_throw(IOError, "failed to open test socket");
  254. }
  255. if (connect(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
  256. isc_throw(IOError, "failed to connect to the test server");
  257. }
  258. const int cc = send(sock_, test_data, sizeof(test_data), 0);
  259. if (cc != sizeof(test_data)) {
  260. isc_throw(IOError, "unexpected send result: " << cc);
  261. }
  262. io_service_->run();
  263. }
  264. // Receive a UDP packet from a mock server; used for testing
  265. // recursive lookup. The caller must place a RecursiveQuery
  266. // on the IO Service queue before running this routine.
  267. void recvUDP(const int family, void* buffer, size_t& size) {
  268. res_ = resolveAddress(family, IPPROTO_UDP, true);
  269. sock_ = socket(res_->ai_family, res_->ai_socktype, res_->ai_protocol);
  270. if (sock_ < 0) {
  271. isc_throw(IOError, "failed to open test socket");
  272. }
  273. if (bind(sock_, res_->ai_addr, res_->ai_addrlen) < 0) {
  274. isc_throw(IOError, "bind failed: " << strerror(errno));
  275. }
  276. // The IO service queue should have a RecursiveQuery object scheduled
  277. // to run at this point. This call will cause it to begin an
  278. // async send, then return.
  279. io_service_->run_one();
  280. // ... and this one will block until the send has completed
  281. io_service_->run_one();
  282. // Now we attempt to recv() whatever was sent
  283. const int ret = recv(sock_, buffer, size, MSG_DONTWAIT);
  284. if (ret < 0) {
  285. isc_throw(IOError, "recvfrom failed");
  286. }
  287. // Pass the message size back via the size parameter
  288. size = ret;
  289. }
  290. // Set up an IO Service queue using the specified address
  291. void setDNSService(const char& address) {
  292. delete dns_service_;
  293. dns_service_ = NULL;
  294. delete io_service_;
  295. io_service_ = new IOService();
  296. callback_ = new ASIOCallBack(this);
  297. dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, address, callback_, NULL, NULL);
  298. }
  299. // Set up an IO Service queue using the "any" address, on IPv4 if
  300. // 'use_ipv4' is true and on IPv6 if 'use_ipv6' is true.
  301. void setDNSService(const bool use_ipv4, const bool use_ipv6) {
  302. delete dns_service_;
  303. dns_service_ = NULL;
  304. delete io_service_;
  305. io_service_ = new IOService();
  306. callback_ = new ASIOCallBack(this);
  307. dns_service_ = new DNSService(*io_service_, *TEST_SERVER_PORT, use_ipv4, use_ipv6, callback_,
  308. NULL, NULL);
  309. }
  310. // Set up empty DNS Service
  311. void setDNSService() {
  312. delete dns_service_;
  313. dns_service_ = NULL;
  314. delete io_service_;
  315. io_service_ = new IOService();
  316. callback_ = new ASIOCallBack(this);
  317. dns_service_ = new DNSService(*io_service_, callback_, NULL, NULL);
  318. }
  319. // Run a simple server test, on either IPv4 or IPv6, and over either
  320. // UDP or TCP. Calls the sendUDP() or sendTCP() methods, which will
  321. // start the IO Service queue. The UDPServer or TCPServer that was
  322. // created by setIOSerice() will receive the test packet and issue a
  323. // callback, which enables us to check that the data it received
  324. // matches what we sent.
  325. void doTest(const int family, const int protocol) {
  326. if (protocol == IPPROTO_UDP) {
  327. sendUDP(family);
  328. } else {
  329. sendTCP(family);
  330. }
  331. // There doesn't seem to be an effective test for the validity of
  332. // 'native'.
  333. // One thing we are sure is it must be different from our local socket.
  334. EXPECT_NE(sock_, callback_native_);
  335. EXPECT_EQ(protocol, callback_protocol_);
  336. EXPECT_EQ(family == AF_INET6 ? TEST_IPV6_ADDR : TEST_IPV4_ADDR,
  337. callback_address_);
  338. const uint8_t* expected_data =
  339. protocol == IPPROTO_UDP ? test_data : test_data + 2;
  340. const size_t expected_datasize =
  341. protocol == IPPROTO_UDP ? sizeof(test_data) :
  342. sizeof(test_data) - 2;
  343. EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, &callback_data_[0],
  344. callback_data_.size(),
  345. expected_data, expected_datasize);
  346. }
  347. protected:
  348. // This is a nonfunctional mockup of a DNSServer object. Its purpose
  349. // is to resume after a recursive query or other asynchronous call
  350. // has completed.
  351. class MockServer : public DNSServer {
  352. public:
  353. explicit MockServer(asio::io_service& io_service,
  354. const asio::ip::address& addr, const uint16_t port,
  355. SimpleCallback* checkin = NULL,
  356. DNSLookup* lookup = NULL,
  357. DNSAnswer* answer = NULL) :
  358. io_(io_service),
  359. message_(new Message(Message::PARSE)),
  360. respbuf_(new OutputBuffer(0)),
  361. checkin_(checkin), lookup_(lookup), answer_(answer)
  362. {}
  363. void operator()(asio::error_code ec = asio::error_code(),
  364. size_t length = 0)
  365. {}
  366. void resume(const bool done) {
  367. done_ = done;
  368. io_.post(*this);
  369. }
  370. DNSServer* clone() {
  371. MockServer* s = new MockServer(*this);
  372. return (s);
  373. }
  374. inline void asyncLookup() {
  375. if (lookup_) {
  376. (*lookup_)(*io_message_, message_, respbuf_, this);
  377. }
  378. }
  379. protected:
  380. asio::io_service& io_;
  381. bool done_;
  382. private:
  383. // Currently unused; these will be used for testing
  384. // asynchronous lookup calls via the asyncLookup() method
  385. boost::shared_ptr<asiolink::IOMessage> io_message_;
  386. isc::dns::MessagePtr message_;
  387. isc::dns::OutputBufferPtr respbuf_;
  388. // Callback functions provided by the caller
  389. const SimpleCallback* checkin_;
  390. const DNSLookup* lookup_;
  391. const DNSAnswer* answer_;
  392. };
  393. // This version of mock server just stops the io_service when it is resumed
  394. class MockServerStop : public MockServer {
  395. public:
  396. explicit MockServerStop(asio::io_service& io_service, bool* done) :
  397. MockServer(io_service, asio::ip::address(), 0),
  398. done_(done)
  399. {}
  400. void resume(const bool done) {
  401. *done_ = done;
  402. io_.stop();
  403. }
  404. DNSServer* clone() {
  405. return (new MockServerStop(*this));
  406. }
  407. private:
  408. bool* done_;
  409. };
  410. private:
  411. class ASIOCallBack : public SimpleCallback {
  412. public:
  413. ASIOCallBack(ASIOLinkTest* test_obj) : test_obj_(test_obj) {}
  414. void operator()(const IOMessage& io_message) const {
  415. test_obj_->callBack(io_message);
  416. }
  417. private:
  418. ASIOLinkTest* test_obj_;
  419. };
  420. void callBack(const IOMessage& io_message) {
  421. callback_protocol_ = io_message.getSocket().getProtocol();
  422. callback_native_ = io_message.getSocket().getNative();
  423. callback_address_ =
  424. io_message.getRemoteEndpoint().getAddress().toText();
  425. callback_data_.assign(
  426. static_cast<const uint8_t*>(io_message.getData()),
  427. static_cast<const uint8_t*>(io_message.getData()) +
  428. io_message.getDataSize());
  429. io_service_->stop();
  430. }
  431. protected:
  432. // We use a pointer for io_service_, because for some tests we
  433. // need to recreate a new one within one onstance of this class
  434. IOService* io_service_;
  435. DNSService* dns_service_;
  436. ASIOCallBack* callback_;
  437. int callback_protocol_;
  438. int callback_native_;
  439. string callback_address_;
  440. vector<uint8_t> callback_data_;
  441. int sock_;
  442. private:
  443. struct addrinfo* res_;
  444. };
  445. ASIOLinkTest::ASIOLinkTest() :
  446. dns_service_(NULL), callback_(NULL), sock_(-1), res_(NULL)
  447. {
  448. io_service_ = new IOService();
  449. setDNSService(true, true);
  450. }
  451. TEST_F(ASIOLinkTest, v6UDPSend) {
  452. doTest(AF_INET6, IPPROTO_UDP);
  453. }
  454. TEST_F(ASIOLinkTest, v6TCPSend) {
  455. doTest(AF_INET6, IPPROTO_TCP);
  456. }
  457. TEST_F(ASIOLinkTest, v4UDPSend) {
  458. doTest(AF_INET, IPPROTO_UDP);
  459. }
  460. TEST_F(ASIOLinkTest, v4TCPSend) {
  461. doTest(AF_INET, IPPROTO_TCP);
  462. }
  463. TEST_F(ASIOLinkTest, v6UDPSendSpecific) {
  464. // Explicitly set a specific address to be bound to the socket.
  465. // The subsequent test does not directly ensures the underlying socket
  466. // is bound to the expected address, but the success of the tests should
  467. // reasonably suggest it works as intended.
  468. // Specifying an address also implicitly means the service runs in a
  469. // single address-family mode. In tests using TCP we can confirm that
  470. // by trying to make a connection and seeing a failure. In UDP, it'd be
  471. // more complicated because we need to use a connected socket and catch
  472. // an error on a subsequent read operation. We could do it, but for
  473. // simplicity we only tests the easier cases for now.
  474. setDNSService(*TEST_IPV6_ADDR);
  475. doTest(AF_INET6, IPPROTO_UDP);
  476. }
  477. TEST_F(ASIOLinkTest, v6TCPSendSpecific) {
  478. setDNSService(*TEST_IPV6_ADDR);
  479. doTest(AF_INET6, IPPROTO_TCP);
  480. EXPECT_THROW(sendTCP(AF_INET), IOError);
  481. }
  482. TEST_F(ASIOLinkTest, v4UDPSendSpecific) {
  483. setDNSService(*TEST_IPV4_ADDR);
  484. doTest(AF_INET, IPPROTO_UDP);
  485. }
  486. TEST_F(ASIOLinkTest, v4TCPSendSpecific) {
  487. setDNSService(*TEST_IPV4_ADDR);
  488. doTest(AF_INET, IPPROTO_TCP);
  489. EXPECT_THROW(sendTCP(AF_INET6), IOError);
  490. }
  491. TEST_F(ASIOLinkTest, v6TCPOnly) {
  492. // Open only IPv6 TCP socket. A subsequent attempt of establishing an
  493. // IPv4/TCP connection should fail. See above for why we only test this
  494. // for TCP.
  495. setDNSService(false, true);
  496. EXPECT_THROW(sendTCP(AF_INET), IOError);
  497. }
  498. TEST_F(ASIOLinkTest, v4TCPOnly) {
  499. setDNSService(true, false);
  500. EXPECT_THROW(sendTCP(AF_INET6), IOError);
  501. }
  502. TEST_F(ASIOLinkTest, recursiveSetupV4) {
  503. setDNSService(true, false);
  504. uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  505. EXPECT_NO_THROW(RecursiveQuery(*dns_service_, *TEST_IPV4_ADDR, port));
  506. }
  507. TEST_F(ASIOLinkTest, recursiveSetupV6) {
  508. setDNSService(false, true);
  509. uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  510. EXPECT_NO_THROW(RecursiveQuery(*dns_service_, *TEST_IPV6_ADDR, port));
  511. }
  512. // XXX:
  513. // This is very inadequate unit testing. It should be generalized into
  514. // a routine that can do this with variable address family, address, and
  515. // port, and with the various callbacks defined in such a way as to ensure
  516. // full code coverage including error cases.
  517. TEST_F(ASIOLinkTest, recursiveSend) {
  518. setDNSService(true, false);
  519. asio::io_service& io = io_service_->get_io_service();
  520. // Note: We use the test prot plus one to ensure we aren't binding
  521. // to the same port as the actual server
  522. uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  523. asio::ip::address addr = asio::ip::address::from_string(TEST_IPV4_ADDR);
  524. MockServer server(io, addr, port, NULL, NULL, NULL);
  525. RecursiveQuery rq(*dns_service_, *TEST_IPV4_ADDR, port);
  526. Question q(Name("example.com"), RRClass::IN(), RRType::TXT());
  527. OutputBufferPtr buffer(new OutputBuffer(0));
  528. rq.sendQuery(q, buffer, &server);
  529. char data[4096];
  530. size_t size = sizeof(data);
  531. EXPECT_NO_THROW(recvUDP(AF_INET, data, size));
  532. Message m(Message::PARSE);
  533. InputBuffer ibuf(data, size);
  534. // Make sure we can parse the message that was sent
  535. EXPECT_NO_THROW(m.parseHeader(ibuf));
  536. EXPECT_NO_THROW(m.fromWire(ibuf));
  537. // Check that the question sent matches the one we wanted
  538. QuestionPtr q2 = *m.beginQuestion();
  539. EXPECT_EQ(q.getName(), q2->getName());
  540. EXPECT_EQ(q.getType(), q2->getType());
  541. EXPECT_EQ(q.getClass(), q2->getClass());
  542. }
  543. void
  544. receive_and_inc(udp::socket* socket, int* num) {
  545. (*num) ++;
  546. static char inbuff[512];
  547. socket->async_receive(asio::buffer(inbuff, 512),
  548. boost::bind(receive_and_inc, socket, num));
  549. }
  550. // Test it tries the correct amount of times before giving up
  551. TEST_F(ASIOLinkTest, recursiveTimeout) {
  552. // Prepare the service (we do not use the common setup, we do not answer
  553. setDNSService();
  554. asio::io_service& service = io_service_->get_io_service();
  555. // Prepare the socket
  556. uint16_t port = boost::lexical_cast<uint16_t>(TEST_CLIENT_PORT);
  557. udp::socket socket(service, udp::v4());
  558. socket.set_option(socket_base::reuse_address(true));
  559. socket.bind(udp::endpoint(ip::address::from_string(TEST_IPV4_ADDR), port));
  560. // And count the answers
  561. int num = -1; // One is counted before the receipt of the first one
  562. receive_and_inc(&socket, &num);
  563. // Prepare the server
  564. bool done(true);
  565. MockServerStop server(service, &done);
  566. // Do the answer
  567. RecursiveQuery query(*dns_service_, *TEST_IPV4_ADDR, port, 10, 2);
  568. Question question(Name("example.net"), RRClass::IN(), RRType::A());
  569. OutputBufferPtr buffer(new OutputBuffer(0));
  570. query.sendQuery(question, buffer, &server);
  571. // Run the test
  572. service.run();
  573. // The query should fail
  574. EXPECT_FALSE(done);
  575. EXPECT_EQ(3, num);
  576. }
  577. }