• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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