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