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