217 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * Copyright (C) 2019 The Android Open Source Project
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "resolv_test_utils.h"
 | |
| 
 | |
| #include <arpa/inet.h>
 | |
| 
 | |
| #include <android-base/chrono_utils.h>
 | |
| #include <android-base/logging.h>
 | |
| 
 | |
| using android::netdutils::ScopedAddrinfo;
 | |
| 
 | |
| std::string ToString(const hostent* he) {
 | |
|     if (he == nullptr) return "<null>";
 | |
|     char buffer[INET6_ADDRSTRLEN];
 | |
|     if (!inet_ntop(he->h_addrtype, he->h_addr_list[0], buffer, sizeof(buffer))) {
 | |
|         return "<invalid>";
 | |
|     }
 | |
|     return buffer;
 | |
| }
 | |
| 
 | |
| std::string ToString(const addrinfo* ai) {
 | |
|     if (!ai) return "<null>";
 | |
| 
 | |
|     char host[NI_MAXHOST];
 | |
|     int rv = getnameinfo(ai->ai_addr, ai->ai_addrlen, host, sizeof(host), nullptr, 0,
 | |
|                          NI_NUMERICHOST);
 | |
|     if (rv != 0) return gai_strerror(rv);
 | |
|     return host;
 | |
| }
 | |
| 
 | |
| std::string ToString(const ScopedAddrinfo& ai) {
 | |
|     return ToString(ai.get());
 | |
| }
 | |
| 
 | |
| std::string ToString(const sockaddr_storage* addr) {
 | |
|     if (!addr) return "<null>";
 | |
|     char host[NI_MAXHOST];
 | |
|     int rv = getnameinfo((const sockaddr*)addr, sizeof(sockaddr_storage), host, sizeof(host),
 | |
|                          nullptr, 0, NI_NUMERICHOST);
 | |
|     if (rv != 0) return gai_strerror(rv);
 | |
|     return host;
 | |
| }
 | |
| 
 | |
| std::vector<std::string> ToStrings(const hostent* he) {
 | |
|     std::vector<std::string> hosts;
 | |
|     if (he == nullptr) {
 | |
|         hosts.push_back("<null>");
 | |
|         return hosts;
 | |
|     }
 | |
|     uint32_t i = 0;
 | |
|     while (he->h_addr_list[i] != nullptr) {
 | |
|         char host[INET6_ADDRSTRLEN];
 | |
|         if (!inet_ntop(he->h_addrtype, he->h_addr_list[i], host, sizeof(host))) {
 | |
|             hosts.push_back("<invalid>");
 | |
|             return hosts;
 | |
|         } else {
 | |
|             hosts.push_back(host);
 | |
|         }
 | |
|         i++;
 | |
|     }
 | |
|     if (hosts.empty()) hosts.push_back("<invalid>");
 | |
|     return hosts;
 | |
| }
 | |
| 
 | |
| std::vector<std::string> ToStrings(const addrinfo* ai) {
 | |
|     std::vector<std::string> hosts;
 | |
|     if (!ai) {
 | |
|         hosts.push_back("<null>");
 | |
|         return hosts;
 | |
|     }
 | |
|     for (const auto* aip = ai; aip != nullptr; aip = aip->ai_next) {
 | |
|         char host[NI_MAXHOST];
 | |
|         int rv = getnameinfo(aip->ai_addr, aip->ai_addrlen, host, sizeof(host), nullptr, 0,
 | |
|                              NI_NUMERICHOST);
 | |
|         if (rv != 0) {
 | |
|             hosts.clear();
 | |
|             hosts.push_back(gai_strerror(rv));
 | |
|             return hosts;
 | |
|         } else {
 | |
|             hosts.push_back(host);
 | |
|         }
 | |
|     }
 | |
|     if (hosts.empty()) hosts.push_back("<invalid>");
 | |
|     return hosts;
 | |
| }
 | |
| 
 | |
| std::vector<std::string> ToStrings(const ScopedAddrinfo& ai) {
 | |
|     return ToStrings(ai.get());
 | |
| }
 | |
| 
 | |
| size_t GetNumQueries(const test::DNSResponder& dns, const char* name) {
 | |
|     std::vector<test::DNSResponder::QueryInfo> queries = dns.queries();
 | |
|     size_t found = 0;
 | |
|     for (const auto& p : queries) {
 | |
|         if (p.name == name) {
 | |
|             ++found;
 | |
|         }
 | |
|     }
 | |
|     return found;
 | |
| }
 | |
| 
 | |
| size_t GetNumQueriesForProtocol(const test::DNSResponder& dns, const int protocol,
 | |
|                                 const char* name) {
 | |
|     std::vector<test::DNSResponder::QueryInfo> queries = dns.queries();
 | |
|     size_t found = 0;
 | |
|     for (const auto& p : queries) {
 | |
|         if (p.protocol == protocol && p.name == name) {
 | |
|             ++found;
 | |
|         }
 | |
|     }
 | |
|     return found;
 | |
| }
 | |
| 
 | |
| size_t GetNumQueriesForType(const test::DNSResponder& dns, ns_type type, const char* name) {
 | |
|     std::vector<test::DNSResponder::QueryInfo> queries = dns.queries();
 | |
|     size_t found = 0;
 | |
|     for (const auto& p : queries) {
 | |
|         if (p.type == type && p.name == name) {
 | |
|             ++found;
 | |
|         }
 | |
|     }
 | |
|     return found;
 | |
| }
 | |
| 
 | |
| bool PollForCondition(const std::function<bool()>& condition, std::chrono::milliseconds timeout) {
 | |
|     constexpr std::chrono::milliseconds retryIntervalMs{5};
 | |
|     android::base::Timer t;
 | |
|     while (t.duration() < timeout) {
 | |
|         if (condition()) return true;
 | |
|         std::this_thread::sleep_for(retryIntervalMs);
 | |
|     }
 | |
|     return false;
 | |
| }
 | |
| 
 | |
| ScopedAddrinfo safe_getaddrinfo(const char* node, const char* service,
 | |
|                                 const struct addrinfo* hints) {
 | |
|     addrinfo* result = nullptr;
 | |
|     if (getaddrinfo(node, service, hints, &result) != 0) {
 | |
|         result = nullptr;  // Should already be the case, but...
 | |
|     }
 | |
|     return ScopedAddrinfo(result);
 | |
| }
 | |
| 
 | |
| int WaitChild(pid_t pid) {
 | |
|     int status;
 | |
|     const pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
 | |
| 
 | |
|     if (got_pid != pid) {
 | |
|         PLOG(WARNING) << __func__ << ": waitpid failed: wanted " << pid << ", got " << got_pid;
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
 | |
|         return 0;
 | |
|     } else {
 | |
|         return status;
 | |
|     }
 | |
| }
 | |
| 
 | |
| int ForkAndRun(const std::vector<std::string>& args) {
 | |
|     std::vector<const char*> argv;
 | |
|     argv.resize(args.size() + 1, nullptr);
 | |
|     std::transform(args.begin(), args.end(), argv.begin(),
 | |
|                    [](const std::string& in) { return in.c_str(); });
 | |
| 
 | |
|     pid_t pid = fork();
 | |
|     if (pid == -1) {
 | |
|         // Fork failed.
 | |
|         PLOG(ERROR) << __func__ << ": Unable to fork";
 | |
|         return -1;
 | |
|     }
 | |
| 
 | |
|     if (pid == 0) {
 | |
|         execv(argv[0], const_cast<char**>(argv.data()));
 | |
|         PLOG(ERROR) << __func__ << ": execv failed";
 | |
|         _exit(1);
 | |
|     }
 | |
| 
 | |
|     int rc = WaitChild(pid);
 | |
|     if (rc != 0) {
 | |
|         PLOG(ERROR) << __func__ << ": Failed run: status=" << rc;
 | |
|     }
 | |
|     return rc;
 | |
| }
 | |
| 
 | |
| // Add routing rules for MDNS packets, or MDNS packets won't know the destination is MDNS
 | |
| // muticast address "224.0.0.251".
 | |
| void SetMdnsRoute() {
 | |
|     const std::vector<std::string> args = {
 | |
|             "system/bin/ip", "route",  "add",   "local", "224.0.0.251", "dev",       "lo",
 | |
|             "proto",         "static", "scope", "host",  "src",         "127.0.0.1",
 | |
|     };
 | |
|     EXPECT_EQ(0, ForkAndRun(args));
 | |
| }
 | |
| 
 | |
| void RemoveMdnsRoute() {
 | |
|     const std::vector<std::string> args = {
 | |
|             "system/bin/ip", "route",  "del",   "local", "224.0.0.251", "dev",       "lo",
 | |
|             "proto",         "static", "scope", "host",  "src",         "127.0.0.1",
 | |
|     };
 | |
|     EXPECT_EQ(0, ForkAndRun(args));
 | |
| } |