1 #include "ares-test.h"
2 #include "ares-test-ai.h"
3 #include "dns-proto.h"
4
5 // Include ares internal files for DNS protocol details
6 #include "nameser.h"
7 #include "ares_dns.h"
8
9 #ifdef HAVE_NETDB_H
10 #include <netdb.h>
11 #endif
12 #ifdef HAVE_NETINET_TCP_H
13 #include <netinet/tcp.h>
14 #endif
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 #include <functional>
19 #include <sstream>
20
21 #ifdef WIN32
22 #define BYTE_CAST (char *)
23 #define mkdir_(d, p) mkdir(d)
24 #else
25 #define BYTE_CAST
26 #define mkdir_(d, p) mkdir(d, p)
27 #endif
28
29 namespace ares {
30 namespace test {
31
32 bool verbose = false;
33 int mock_port = 5300;
34
35 const std::vector<int> both_families = {AF_INET, AF_INET6};
36 const std::vector<int> ipv4_family = {AF_INET};
37 const std::vector<int> ipv6_family = {AF_INET6};
38
39 const std::vector<std::pair<int, bool>> both_families_both_modes = {
40 std::make_pair<int, bool>(AF_INET, false),
41 std::make_pair<int, bool>(AF_INET, true),
42 std::make_pair<int, bool>(AF_INET6, false),
43 std::make_pair<int, bool>(AF_INET6, true)
44 };
45 const std::vector<std::pair<int, bool>> ipv4_family_both_modes = {
46 std::make_pair<int, bool>(AF_INET, false),
47 std::make_pair<int, bool>(AF_INET, true)
48 };
49 const std::vector<std::pair<int, bool>> ipv6_family_both_modes = {
50 std::make_pair<int, bool>(AF_INET6, false),
51 std::make_pair<int, bool>(AF_INET6, true)
52 };
53
54 // Which parameters to use in tests
55 std::vector<int> families = both_families;
56 std::vector<std::pair<int, bool>> families_modes = both_families_both_modes;
57
58 unsigned long long LibraryTest::fails_ = 0;
59 std::map<size_t, int> LibraryTest::size_fails_;
60
ProcessWork(ares_channel channel,std::function<std::set<int> ()> get_extrafds,std::function<void (int)> process_extra)61 void ProcessWork(ares_channel channel,
62 std::function<std::set<int>()> get_extrafds,
63 std::function<void(int)> process_extra) {
64 int nfds, count;
65 fd_set readers, writers;
66 struct timeval tv;
67 while (true) {
68 // Retrieve the set of file descriptors that the library wants us to monitor.
69 FD_ZERO(&readers);
70 FD_ZERO(&writers);
71 nfds = ares_fds(channel, &readers, &writers);
72 if (nfds == 0) // no work left to do in the library
73 return;
74
75 // Add in the extra FDs if present.
76 std::set<int> extrafds = get_extrafds();
77 for (int extrafd : extrafds) {
78 FD_SET(extrafd, &readers);
79 if (extrafd >= nfds) {
80 nfds = extrafd + 1;
81 }
82 }
83
84 // Wait for activity or timeout.
85 tv.tv_sec = 0;
86 tv.tv_usec = 100000; // 100ms
87 count = select(nfds, &readers, &writers, nullptr, &tv);
88 if (count < 0) {
89 fprintf(stderr, "select() failed, errno %d\n", errno);
90 return;
91 }
92
93 // Let the library process any activity.
94 ares_process(channel, &readers, &writers);
95
96 // Let the provided callback process any activity on the extra FD.
97 for (int extrafd : extrafds) {
98 if (FD_ISSET(extrafd, &readers)) {
99 process_extra(extrafd);
100 }
101 }
102 }
103 }
104
105 // static
SetAllocFail(int nth)106 void LibraryTest::SetAllocFail(int nth) {
107 assert(nth > 0);
108 assert(nth <= (int)(8 * sizeof(fails_)));
109 fails_ |= (1LL << (nth - 1));
110 }
111
112 // static
SetAllocSizeFail(size_t size)113 void LibraryTest::SetAllocSizeFail(size_t size) {
114 size_fails_[size]++;
115 }
116
117 // static
ClearFails()118 void LibraryTest::ClearFails() {
119 fails_ = 0;
120 size_fails_.clear();
121 }
122
123
124 // static
ShouldAllocFail(size_t size)125 bool LibraryTest::ShouldAllocFail(size_t size) {
126 bool fail = (fails_ & 0x01);
127 fails_ >>= 1;
128 if (size_fails_[size] > 0) {
129 size_fails_[size]--;
130 fail = true;
131 }
132 return fail;
133 }
134
135 // static
amalloc(size_t size)136 void* LibraryTest::amalloc(size_t size) {
137 if (ShouldAllocFail(size)) {
138 if (verbose) std::cerr << "Failing malloc(" << size << ") request" << std::endl;
139 return nullptr;
140 } else {
141 return malloc(size);
142 }
143 }
144
145 // static
arealloc(void * ptr,size_t size)146 void* LibraryTest::arealloc(void *ptr, size_t size) {
147 if (ShouldAllocFail(size)) {
148 if (verbose) std::cerr << "Failing realloc(" << ptr << ", " << size << ") request" << std::endl;
149 return nullptr;
150 } else {
151 return realloc(ptr, size);
152 }
153 }
154
155 // static
afree(void * ptr)156 void LibraryTest::afree(void *ptr) {
157 free(ptr);
158 }
159
NoExtraFDs()160 std::set<int> NoExtraFDs() {
161 return std::set<int>();
162 }
163
Process()164 void DefaultChannelTest::Process() {
165 ProcessWork(channel_, NoExtraFDs, nullptr);
166 }
167
Process()168 void DefaultChannelModeTest::Process() {
169 ProcessWork(channel_, NoExtraFDs, nullptr);
170 }
171
MockServer(int family,int port,int tcpport)172 MockServer::MockServer(int family, int port, int tcpport)
173 : udpport_(port), tcpport_(tcpport ? tcpport : udpport_), qid_(-1) {
174 // Create a TCP socket to receive data on.
175 tcpfd_ = socket(family, SOCK_STREAM, 0);
176 EXPECT_NE(-1, tcpfd_);
177 int optval = 1;
178 setsockopt(tcpfd_, SOL_SOCKET, SO_REUSEADDR,
179 BYTE_CAST &optval , sizeof(int));
180 // Send TCP data right away.
181 setsockopt(tcpfd_, IPPROTO_TCP, TCP_NODELAY,
182 BYTE_CAST &optval , sizeof(int));
183
184 // Create a UDP socket to receive data on.
185 udpfd_ = socket(family, SOCK_DGRAM, 0);
186 EXPECT_NE(-1, udpfd_);
187
188 // Bind the sockets to the given port.
189 if (family == AF_INET) {
190 struct sockaddr_in addr;
191 memset(&addr, 0, sizeof(addr));
192 addr.sin_family = AF_INET;
193 addr.sin_addr.s_addr = htonl(INADDR_ANY);
194 addr.sin_port = htons(tcpport_);
195 int tcprc = bind(tcpfd_, (struct sockaddr*)&addr, sizeof(addr));
196 EXPECT_EQ(0, tcprc) << "Failed to bind AF_INET to TCP port " << tcpport_;
197 addr.sin_port = htons(udpport_);
198 int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr));
199 EXPECT_EQ(0, udprc) << "Failed to bind AF_INET to UDP port " << udpport_;
200 } else {
201 EXPECT_EQ(AF_INET6, family);
202 struct sockaddr_in6 addr;
203 memset(&addr, 0, sizeof(addr));
204 addr.sin6_family = AF_INET6;
205 memset(&addr.sin6_addr, 0, sizeof(addr.sin6_addr)); // in6addr_any
206 addr.sin6_port = htons(tcpport_);
207 int tcprc = bind(tcpfd_, (struct sockaddr*)&addr, sizeof(addr));
208 EXPECT_EQ(0, tcprc) << "Failed to bind AF_INET6 to TCP port " << tcpport_;
209 addr.sin6_port = htons(udpport_);
210 int udprc = bind(udpfd_, (struct sockaddr*)&addr, sizeof(addr));
211 EXPECT_EQ(0, udprc) << "Failed to bind AF_INET6 to UDP port " << udpport_;
212 }
213 if (verbose) std::cerr << "Configured "
214 << (family == AF_INET ? "IPv4" : "IPv6")
215 << " mock server with TCP socket " << tcpfd_
216 << " on port " << tcpport_
217 << " and UDP socket " << udpfd_
218 << " on port " << udpport_ << std::endl;
219
220 // For TCP, also need to listen for connections.
221 EXPECT_EQ(0, listen(tcpfd_, 5)) << "Failed to listen for TCP connections";
222 }
223
~MockServer()224 MockServer::~MockServer() {
225 for (int fd : connfds_) {
226 sclose(fd);
227 }
228 sclose(tcpfd_);
229 sclose(udpfd_);
230 }
231
ProcessFD(int fd)232 void MockServer::ProcessFD(int fd) {
233 if (fd != tcpfd_ && fd != udpfd_ && connfds_.find(fd) == connfds_.end()) {
234 // Not one of our FDs.
235 return;
236 }
237 if (fd == tcpfd_) {
238 int connfd = accept(tcpfd_, NULL, NULL);
239 if (connfd < 0) {
240 std::cerr << "Error accepting connection on fd " << fd << std::endl;
241 } else {
242 connfds_.insert(connfd);
243 }
244 return;
245 }
246
247 // Activity on a data-bearing file descriptor.
248 struct sockaddr_storage addr;
249 socklen_t addrlen = sizeof(addr);
250 byte buffer[2048];
251 int len = recvfrom(fd, BYTE_CAST buffer, sizeof(buffer), 0,
252 (struct sockaddr *)&addr, &addrlen);
253 byte* data = buffer;
254 if (fd != udpfd_) {
255 if (len == 0) {
256 connfds_.erase(std::find(connfds_.begin(), connfds_.end(), fd));
257 sclose(fd);
258 return;
259 }
260 if (len < 2) {
261 std::cerr << "Packet too short (" << len << ")" << std::endl;
262 return;
263 }
264 int tcplen = (data[0] << 8) + data[1];
265 data += 2;
266 len -= 2;
267 if (tcplen != len) {
268 std::cerr << "Warning: TCP length " << tcplen
269 << " doesn't match remaining data length " << len << std::endl;
270 }
271 }
272
273 // Assume the packet is a well-formed DNS request and extract the request
274 // details.
275 if (len < NS_HFIXEDSZ) {
276 std::cerr << "Packet too short (" << len << ")" << std::endl;
277 return;
278 }
279 int qid = DNS_HEADER_QID(data);
280 if (DNS_HEADER_QR(data) != 0) {
281 std::cerr << "Not a request" << std::endl;
282 return;
283 }
284 if (DNS_HEADER_OPCODE(data) != ns_o_query) {
285 std::cerr << "Not a query (opcode " << DNS_HEADER_OPCODE(data)
286 << ")" << std::endl;
287 return;
288 }
289 if (DNS_HEADER_QDCOUNT(data) != 1) {
290 std::cerr << "Unexpected question count (" << DNS_HEADER_QDCOUNT(data)
291 << ")" << std::endl;
292 return;
293 }
294 byte* question = data + 12;
295 int qlen = len - 12;
296
297 char *name = nullptr;
298 long enclen;
299 ares_expand_name(question, data, len, &name, &enclen);
300 if (!name) {
301 std::cerr << "Failed to retrieve name" << std::endl;
302 return;
303 }
304 qlen -= enclen;
305 question += enclen;
306 std::string namestr(name);
307 ares_free_string(name);
308
309 if (qlen < 4) {
310 std::cerr << "Unexpected question size (" << qlen
311 << " bytes after name)" << std::endl;
312 return;
313 }
314 if (DNS_QUESTION_CLASS(question) != ns_c_in) {
315 std::cerr << "Unexpected question class (" << DNS_QUESTION_CLASS(question)
316 << ")" << std::endl;
317 return;
318 }
319 int rrtype = DNS_QUESTION_TYPE(question);
320
321 if (verbose) {
322 std::vector<byte> req(data, data + len);
323 std::cerr << "received " << (fd == udpfd_ ? "UDP" : "TCP") << " request " << PacketToString(req)
324 << " on port " << (fd == udpfd_ ? udpport_ : tcpport_) << std::endl;
325 std::cerr << "ProcessRequest(" << qid << ", '" << namestr
326 << "', " << RRTypeToString(rrtype) << ")" << std::endl;
327 }
328 ProcessRequest(fd, &addr, addrlen, qid, namestr, rrtype);
329 }
330
fds() const331 std::set<int> MockServer::fds() const {
332 std::set<int> result = connfds_;
333 result.insert(tcpfd_);
334 result.insert(udpfd_);
335 return result;
336 }
337
ProcessRequest(int fd,struct sockaddr_storage * addr,int addrlen,int qid,const std::string & name,int rrtype)338 void MockServer::ProcessRequest(int fd, struct sockaddr_storage* addr, int addrlen,
339 int qid, const std::string& name, int rrtype) {
340 // Before processing, let gMock know the request is happening.
341 OnRequest(name, rrtype);
342
343 if (reply_.size() == 0) {
344 return;
345 }
346
347 // Make a local copy of the current pending reply.
348 std::vector<byte> reply = reply_;
349
350 if (qid_ >= 0) {
351 // Use the explicitly specified query ID.
352 qid = qid_;
353 }
354 if (reply.size() >= 2) {
355 // Overwrite the query ID if space to do so.
356 reply[0] = (byte)((qid >> 8) & 0xff);
357 reply[1] = (byte)(qid & 0xff);
358 }
359 if (verbose) std::cerr << "sending reply " << PacketToString(reply)
360 << " on port " << ((fd == udpfd_) ? udpport_ : tcpport_) << std::endl;
361
362 // Prefix with 2-byte length if TCP.
363 if (fd != udpfd_) {
364 int len = reply.size();
365 std::vector<byte> vlen = {(byte)((len & 0xFF00) >> 8), (byte)(len & 0xFF)};
366 reply.insert(reply.begin(), vlen.begin(), vlen.end());
367 // Also, don't bother with the destination address.
368 addr = nullptr;
369 addrlen = 0;
370 }
371
372 int rc = sendto(fd, BYTE_CAST reply.data(), reply.size(), 0,
373 (struct sockaddr *)addr, addrlen);
374 if (rc < static_cast<int>(reply.size())) {
375 std::cerr << "Failed to send full reply, rc=" << rc << std::endl;
376 }
377 }
378
379 // static
BuildServers(int count,int family,int base_port)380 MockChannelOptsTest::NiceMockServers MockChannelOptsTest::BuildServers(int count, int family, int base_port) {
381 NiceMockServers servers;
382 assert(count > 0);
383 for (int ii = 0; ii < count; ii++) {
384 std::unique_ptr<NiceMockServer> server(new NiceMockServer(family, base_port + ii));
385 servers.push_back(std::move(server));
386 }
387 return servers;
388 }
389
MockChannelOptsTest(int count,int family,bool force_tcp,struct ares_options * givenopts,int optmask)390 MockChannelOptsTest::MockChannelOptsTest(int count,
391 int family,
392 bool force_tcp,
393 struct ares_options* givenopts,
394 int optmask)
395 : servers_(BuildServers(count, family, mock_port)),
396 server_(*servers_[0].get()), channel_(nullptr) {
397 // Set up channel options.
398 struct ares_options opts;
399 if (givenopts) {
400 memcpy(&opts, givenopts, sizeof(opts));
401 } else {
402 memset(&opts, 0, sizeof(opts));
403 }
404
405 // Point the library at the first mock server by default (overridden below).
406 opts.udp_port = mock_port;
407 optmask |= ARES_OPT_UDP_PORT;
408 opts.tcp_port = mock_port;
409 optmask |= ARES_OPT_TCP_PORT;
410
411 // If not already overridden, set short-ish timeouts.
412 if (!(optmask & (ARES_OPT_TIMEOUTMS|ARES_OPT_TIMEOUT))) {
413 opts.timeout = 1500;
414 optmask |= ARES_OPT_TIMEOUTMS;
415 }
416 // If not already overridden, set 3 retries.
417 if (!(optmask & ARES_OPT_TRIES)) {
418 opts.tries = 3;
419 optmask |= ARES_OPT_TRIES;
420 }
421 // If not already overridden, set search domains.
422 const char *domains[3] = {"first.com", "second.org", "third.gov"};
423 if (!(optmask & ARES_OPT_DOMAINS)) {
424 opts.ndomains = 3;
425 opts.domains = (char**)domains;
426 optmask |= ARES_OPT_DOMAINS;
427 }
428 if (force_tcp) {
429 opts.flags |= ARES_FLAG_USEVC;
430 optmask |= ARES_OPT_FLAGS;
431 }
432
433 EXPECT_EQ(ARES_SUCCESS, ares_init_options(&channel_, &opts, optmask));
434 EXPECT_NE(nullptr, channel_);
435
436 // Set up servers after construction so we can set individual ports
437 struct ares_addr_port_node* prev = nullptr;
438 struct ares_addr_port_node* first = nullptr;
439 for (const auto& server : servers_) {
440 struct ares_addr_port_node* node = (struct ares_addr_port_node*)malloc(sizeof(*node));
441 if (prev) {
442 prev->next = node;
443 } else {
444 first = node;
445 }
446 node->next = nullptr;
447 node->family = family;
448 node->udp_port = server->udpport();
449 node->tcp_port = server->tcpport();
450 if (family == AF_INET) {
451 node->addr.addr4.s_addr = htonl(0x7F000001);
452 } else {
453 memset(&node->addr.addr6, 0, sizeof(node->addr.addr6));
454 node->addr.addr6._S6_un._S6_u8[15] = 1;
455 }
456 prev = node;
457 }
458 EXPECT_EQ(ARES_SUCCESS, ares_set_servers_ports(channel_, first));
459
460 while (first) {
461 prev = first;
462 first = first->next;
463 free(prev);
464 }
465 if (verbose) {
466 std::cerr << "Configured library with servers:";
467 std::vector<std::string> servers = GetNameServers(channel_);
468 for (const auto& server : servers) {
469 std::cerr << " " << server;
470 }
471 std::cerr << std::endl;
472 }
473 }
474
~MockChannelOptsTest()475 MockChannelOptsTest::~MockChannelOptsTest() {
476 if (channel_) {
477 ares_destroy(channel_);
478 }
479 channel_ = nullptr;
480 }
481
fds() const482 std::set<int> MockChannelOptsTest::fds() const {
483 std::set<int> fds;
484 for (const auto& server : servers_) {
485 std::set<int> serverfds = server->fds();
486 fds.insert(serverfds.begin(), serverfds.end());
487 }
488 return fds;
489 }
490
ProcessFD(int fd)491 void MockChannelOptsTest::ProcessFD(int fd) {
492 for (auto& server : servers_) {
493 server->ProcessFD(fd);
494 }
495 }
496
Process()497 void MockChannelOptsTest::Process() {
498 using namespace std::placeholders;
499 ProcessWork(channel_,
500 std::bind(&MockChannelOptsTest::fds, this),
501 std::bind(&MockChannelOptsTest::ProcessFD, this, _1));
502 }
503
operator <<(std::ostream & os,const HostResult & result)504 std::ostream& operator<<(std::ostream& os, const HostResult& result) {
505 os << '{';
506 if (result.done_) {
507 os << StatusToString(result.status_) << " " << result.host_;
508 } else {
509 os << "(incomplete)";
510 }
511 os << '}';
512 return os;
513 }
514
HostEnt(const struct hostent * hostent)515 HostEnt::HostEnt(const struct hostent *hostent) : addrtype_(-1) {
516 if (!hostent)
517 return;
518 if (hostent->h_name)
519 name_ = hostent->h_name;
520 if (hostent->h_aliases) {
521 char** palias = hostent->h_aliases;
522 while (*palias != nullptr) {
523 aliases_.push_back(*palias);
524 palias++;
525 }
526 }
527 addrtype_ = hostent->h_addrtype;
528 if (hostent->h_addr_list) {
529 char** paddr = hostent->h_addr_list;
530 while (*paddr != nullptr) {
531 std::string addr = AddressToString(*paddr, hostent->h_length);
532 addrs_.push_back(addr);
533 paddr++;
534 }
535 }
536 }
537
operator <<(std::ostream & os,const HostEnt & host)538 std::ostream& operator<<(std::ostream& os, const HostEnt& host) {
539 os << '{';
540 os << "'" << host.name_ << "' "
541 << "aliases=[";
542 for (size_t ii = 0; ii < host.aliases_.size(); ii++) {
543 if (ii > 0) os << ", ";
544 os << host.aliases_[ii];
545 }
546 os << "] ";
547 os << "addrs=[";
548 for (size_t ii = 0; ii < host.addrs_.size(); ii++) {
549 if (ii > 0) os << ", ";
550 os << host.addrs_[ii];
551 }
552 os << "]";
553 os << '}';
554 return os;
555 }
556
HostCallback(void * data,int status,int timeouts,struct hostent * hostent)557 void HostCallback(void *data, int status, int timeouts,
558 struct hostent *hostent) {
559 EXPECT_NE(nullptr, data);
560 HostResult* result = reinterpret_cast<HostResult*>(data);
561 result->done_ = true;
562 result->status_ = status;
563 result->timeouts_ = timeouts;
564 result->host_ = HostEnt(hostent);
565 if (verbose) std::cerr << "HostCallback(" << *result << ")" << std::endl;
566 }
567
operator <<(std::ostream & os,const AddrInfoResult & result)568 std::ostream& operator<<(std::ostream& os, const AddrInfoResult& result) {
569 os << '{';
570 if (result.done_ && result.ai_) {
571 os << StatusToString(result.status_) << " " << result.ai_;
572 } else {
573 os << "(incomplete)";
574 }
575 os << '}';
576 return os;
577 }
578
operator <<(std::ostream & os,const AddrInfo & ai)579 std::ostream& operator<<(std::ostream& os, const AddrInfo& ai) {
580 os << '{';
581 if (ai == nullptr) {
582 os << "nullptr}";
583 return os;
584 }
585
586 struct ares_addrinfo_cname *next_cname = ai->cnames;
587 while(next_cname) {
588 if(next_cname->alias) {
589 os << next_cname->alias << "->";
590 }
591 if(next_cname->name) {
592 os << next_cname->name;
593 }
594 if((next_cname = next_cname->next))
595 os << ", ";
596 else
597 os << " ";
598 }
599
600 struct ares_addrinfo_node *next = ai->nodes;
601 while(next) {
602 //if(next->ai_canonname) {
603 //os << "'" << next->ai_canonname << "' ";
604 //}
605 unsigned short port = 0;
606 os << "addr=[";
607 if(next->ai_family == AF_INET) {
608 sockaddr_in* sin = (sockaddr_in*)next->ai_addr;
609 port = ntohs(sin->sin_port);
610 os << AddressToString(&sin->sin_addr, 4);
611 }
612 else if (next->ai_family == AF_INET6) {
613 sockaddr_in6* sin = (sockaddr_in6*)next->ai_addr;
614 port = ntohs(sin->sin6_port);
615 os << "[" << AddressToString(&sin->sin6_addr, 16) << "]";
616 }
617 else
618 os << "unknown family";
619 if(port) {
620 os << ":" << port;
621 }
622 os << "]";
623 if((next = next->ai_next))
624 os << ", ";
625 }
626 os << '}';
627 return os;
628 }
629
AddrInfoCallback(void * data,int status,int timeouts,struct ares_addrinfo * ai)630 void AddrInfoCallback(void *data, int status, int timeouts,
631 struct ares_addrinfo *ai) {
632 EXPECT_NE(nullptr, data);
633 AddrInfoResult* result = reinterpret_cast<AddrInfoResult*>(data);
634 result->done_ = true;
635 result->status_ = status;
636 result->timeouts_= timeouts;
637 result->ai_ = AddrInfo(ai);
638 if (verbose) std::cerr << "AddrInfoCallback(" << *result << ")" << std::endl;
639 }
640
operator <<(std::ostream & os,const SearchResult & result)641 std::ostream& operator<<(std::ostream& os, const SearchResult& result) {
642 os << '{';
643 if (result.done_) {
644 os << StatusToString(result.status_) << " " << PacketToString(result.data_);
645 } else {
646 os << "(incomplete)";
647 }
648 os << '}';
649 return os;
650 }
651
SearchCallback(void * data,int status,int timeouts,unsigned char * abuf,int alen)652 void SearchCallback(void *data, int status, int timeouts,
653 unsigned char *abuf, int alen) {
654 EXPECT_NE(nullptr, data);
655 SearchResult* result = reinterpret_cast<SearchResult*>(data);
656 result->done_ = true;
657 result->status_ = status;
658 result->timeouts_ = timeouts;
659 result->data_.assign(abuf, abuf + alen);
660 if (verbose) std::cerr << "SearchCallback(" << *result << ")" << std::endl;
661 }
662
operator <<(std::ostream & os,const NameInfoResult & result)663 std::ostream& operator<<(std::ostream& os, const NameInfoResult& result) {
664 os << '{';
665 if (result.done_) {
666 os << StatusToString(result.status_) << " " << result.node_ << " " << result.service_;
667 } else {
668 os << "(incomplete)";
669 }
670 os << '}';
671 return os;
672 }
673
NameInfoCallback(void * data,int status,int timeouts,char * node,char * service)674 void NameInfoCallback(void *data, int status, int timeouts,
675 char *node, char *service) {
676 EXPECT_NE(nullptr, data);
677 NameInfoResult* result = reinterpret_cast<NameInfoResult*>(data);
678 result->done_ = true;
679 result->status_ = status;
680 result->timeouts_ = timeouts;
681 result->node_ = std::string(node ? node : "");
682 result->service_ = std::string(service ? service : "");
683 if (verbose) std::cerr << "NameInfoCallback(" << *result << ")" << std::endl;
684 }
685
GetNameServers(ares_channel channel)686 std::vector<std::string> GetNameServers(ares_channel channel) {
687 struct ares_addr_port_node* servers = nullptr;
688 EXPECT_EQ(ARES_SUCCESS, ares_get_servers_ports(channel, &servers));
689 struct ares_addr_port_node* server = servers;
690 std::vector<std::string> results;
691 while (server) {
692 std::stringstream ss;
693 switch (server->family) {
694 case AF_INET:
695 ss << AddressToString((char*)&server->addr.addr4, 4);
696 break;
697 case AF_INET6:
698 if (server->udp_port != 0) {
699 ss << '[';
700 }
701 ss << AddressToString((char*)&server->addr.addr6, 16);
702 if (server->udp_port != 0) {
703 ss << ']';
704 }
705 break;
706 default:
707 results.push_back("<unknown family>");
708 break;
709 }
710 if (server->udp_port != 0) {
711 ss << ":" << server->udp_port;
712 }
713 results.push_back(ss.str());
714 server = server->next;
715 }
716 if (servers) ares_free_data(servers);
717 return results;
718 }
719
TransientDir(const std::string & dirname)720 TransientDir::TransientDir(const std::string& dirname) : dirname_(dirname) {
721 if (mkdir_(dirname_.c_str(), 0755) != 0) {
722 std::cerr << "Failed to create subdirectory '" << dirname_ << "'" << std::endl;
723 }
724 }
725
~TransientDir()726 TransientDir::~TransientDir() {
727 rmdir(dirname_.c_str());
728 }
729
TransientFile(const std::string & filename,const std::string & contents)730 TransientFile::TransientFile(const std::string& filename,
731 const std::string& contents)
732 : filename_(filename) {
733 FILE *f = fopen(filename.c_str(), "w");
734 if (f == nullptr) {
735 std::cerr << "Error: failed to create '" << filename << "'" << std::endl;
736 return;
737 }
738 int rc = fwrite(contents.data(), 1, contents.size(), f);
739 if (rc != (int)contents.size()) {
740 std::cerr << "Error: failed to write contents of '" << filename << "'" << std::endl;
741 }
742 fclose(f);
743 }
744
~TransientFile()745 TransientFile::~TransientFile() {
746 unlink(filename_.c_str());
747 }
748
TempNam(const char * dir,const char * prefix)749 std::string TempNam(const char *dir, const char *prefix) {
750 char *p = tempnam(dir, prefix);
751 std::string result(p);
752 free(p);
753 return result;
754 }
755
TempFile(const std::string & contents)756 TempFile::TempFile(const std::string& contents)
757 : TransientFile(TempNam(nullptr, "ares"), contents) {
758
759 }
760
VirtualizeIO(ares_channel c)761 VirtualizeIO::VirtualizeIO(ares_channel c)
762 : channel_(c)
763 {
764 ares_set_socket_functions(channel_, &default_functions, 0);
765 }
766
~VirtualizeIO()767 VirtualizeIO::~VirtualizeIO() {
768 ares_set_socket_functions(channel_, 0, 0);
769 }
770
771 } // namespace test
772 } // namespace ares
773