summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Imai <imaipi@google.com>2016-04-19 16:17:07 +0900
committerPierre Imai <imaipi@google.com>2016-04-28 17:28:21 +0900
commit3a272070fc318ef1a7a5a04e500483f1a7c629a8 (patch)
tree50007c33c076de30837d3ba8470559b4c236e384
parentbeedec3bc42d6f40a2c83a65522e85b5ff046f79 (diff)
downloadnetd-3a272070fc318ef1a7a5a04e500483f1a7c629a8.tar.gz
Add dumpsys support to ResolverController
BUG: 25731675 Change-Id: I1c715368b1f2d5e732528cd226b3f69792b75321
-rw-r--r--server/NetworkController.cpp3
-rw-r--r--server/ResolverController.cpp56
-rw-r--r--server/ResolverController.h2
-rw-r--r--tests/netd_test.cpp143
4 files changed, 159 insertions, 45 deletions
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index 7c2a8266..8b1f84e5 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -38,6 +38,7 @@
#include "cutils/misc.h"
#include "resolv_netid.h"
+#include "Controllers.h"
#include "DummyNetwork.h"
#include "DumpWriter.h"
#include "Fwmark.h"
@@ -525,6 +526,8 @@ void NetworkController::dump(DumpWriter& dw) {
dw.incIndent();
for (const auto& i : mNetworks) {
dw.println(i.second->toString().c_str());
+ android::net::gCtls->resolverCtrl.dump(dw, i.first);
+ dw.blankline();
}
dw.decIndent();
diff --git a/server/ResolverController.cpp b/server/ResolverController.cpp
index 20c93026..41913d38 100644
--- a/server/ResolverController.cpp
+++ b/server/ResolverController.cpp
@@ -33,8 +33,10 @@
#include <resolv_params.h>
#include <resolv_stats.h>
+#include <android-base/strings.h>
#include <android/net/INetd.h>
+#include "DumpWriter.h"
#include "ResolverController.h"
#include "ResolverStats.h"
@@ -189,3 +191,57 @@ int ResolverController::getResolverInfo(int32_t netId, std::vector<std::string>*
(*params)[INetd::RESOLVER_PARAMS_MAX_SAMPLES] = res_params.max_samples;
return 0;
}
+
+void ResolverController::dump(DumpWriter& dw, unsigned netId) {
+ // No lock needed since Bionic's resolver locks all accessed data structures internally.
+ using android::net::ResolverStats;
+ std::vector<std::string> servers;
+ std::vector<std::string> domains;
+ __res_params params;
+ std::vector<ResolverStats> stats;
+ time_t now = time(nullptr);
+ int rv = getDnsInfo(netId, &servers, &domains, &params, &stats);
+ dw.incIndent();
+ if (rv != 0) {
+ dw.println("getDnsInfo() failed for netid %u", netId);
+ } else {
+ if (servers.empty()) {
+ dw.println("No DNS servers defined");
+ } else {
+ dw.println("DNS servers: # IP (total, successes, errors, timeouts, internal errors, "
+ "RTT avg, last sample)");
+ dw.incIndent();
+ for (size_t i = 0 ; i < servers.size() ; ++i) {
+ if (i < stats.size()) {
+ const ResolverStats& s = stats[i];
+ int total = s.successes + s.errors + s.timeouts + s.internal_errors;
+ if (total > 0) {
+ int time_delta = (s.last_sample_time > 0) ? now - s.last_sample_time : -1;
+ dw.println("%s (%d, %d, %d, %d, %d, %dms, %ds)%s", servers[i].c_str(),
+ total, s.successes, s.errors, s.timeouts, s.internal_errors,
+ s.rtt_avg, time_delta, s.usable ? "" : " BROKEN");
+ } else {
+ dw.println("%s <no data>", servers[i].c_str());
+ }
+ } else {
+ dw.println("%s <no stats>", servers[i].c_str());
+ }
+ }
+ dw.decIndent();
+ }
+ if (domains.empty()) {
+ dw.println("No search domains defined");
+ } else {
+ std::string domains_str = android::base::Join(domains, ", ");
+ dw.println("search domains: %s", domains_str.c_str());
+ }
+ if (params.sample_validity != 0) {
+ dw.println("DNS parameters: sample validity = %us, success threshold = %u%%, "
+ "samples (min, max) = (%u, %u)", params.sample_validity,
+ static_cast<unsigned>(params.success_threshold),
+ static_cast<unsigned>(params.min_samples),
+ static_cast<unsigned>(params.max_samples));
+ }
+ }
+ dw.decIndent();
+}
diff --git a/server/ResolverController.h b/server/ResolverController.h
index a3810d43..d0c984f4 100644
--- a/server/ResolverController.h
+++ b/server/ResolverController.h
@@ -22,6 +22,7 @@
#include <linux/in.h>
struct __res_params;
+class DumpWriter;
namespace android {
namespace net {
@@ -55,6 +56,7 @@ public:
int getResolverInfo(int32_t netId, std::vector<std::string>* servers,
std::vector<std::string>* domains, std::vector<int32_t>* params,
std::vector<int32_t>* stats);
+ void dump(DumpWriter& dw, unsigned netId);
};
#endif /* _RESOLVER_CONTROLLER_H_ */
diff --git a/tests/netd_test.cpp b/tests/netd_test.cpp
index ef912665..d2d1428d 100644
--- a/tests/netd_test.cpp
+++ b/tests/netd_test.cpp
@@ -124,6 +124,50 @@ bool expectNetdResult(int expected, const char* sockname, const char* format, ..
return (200 <= expected && expected < 300);
}
+class AddrInfo {
+ public:
+ AddrInfo() : ai_(nullptr), error_(0) {}
+
+ AddrInfo(const char* node, const char* service, const addrinfo& hints) : ai_(nullptr) {
+ init(node, service, hints);
+ }
+
+ AddrInfo(const char* node, const char* service) : ai_(nullptr) {
+ init(node, service);
+ }
+
+ ~AddrInfo() { clear(); }
+
+ int init(const char* node, const char* service, const addrinfo& hints) {
+ clear();
+ error_ = getaddrinfo(node, service, &hints, &ai_);
+ return error_;
+ }
+
+ int init(const char* node, const char* service) {
+ clear();
+ error_ = getaddrinfo(node, service, nullptr, &ai_);
+ return error_;
+ }
+
+ void clear() {
+ if (ai_ != nullptr) {
+ freeaddrinfo(ai_);
+ ai_ = nullptr;
+ error_ = 0;
+ }
+ }
+
+ const addrinfo& operator*() const { return *ai_; }
+ const addrinfo* get() const { return ai_; }
+ const addrinfo* operator&() const { return ai_; }
+ int error() const { return error_; }
+
+ private:
+ addrinfo* ai_;
+ int error_;
+};
+
class ResolverTest : public ::testing::Test {
protected:
struct Mapping {
@@ -471,57 +515,66 @@ TEST_F(ResolverTest, GetAddrInfo) {
dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
dns.addMapping(host_name, ns_type::ns_t_aaaa, "::1.2.3.4");
ASSERT_TRUE(dns.startServer());
- std::vector<std::string> servers = { listen_addr };
- ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, mDefaultParams));
-
- dns.clearQueries();
- EXPECT_EQ(0, getaddrinfo("howdy", nullptr, nullptr, &result));
- size_t found = GetNumQueries(dns, host_name);
- EXPECT_LE(1U, found);
- // Could be A or AAAA
- std::string result_str = ToString(result);
- EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
- << ", result_str='" << result_str << "'";
- // TODO: Use ScopedAddrinfo or similar once it is available in a common header file.
- if (result) {
- freeaddrinfo(result);
- result = nullptr;
- }
- // Verify that the name is cached.
- EXPECT_EQ(0, getaddrinfo("howdy", nullptr, nullptr, &result));
- found = GetNumQueries(dns, host_name);
- EXPECT_LE(1U, found);
- result_str = ToString(result);
- EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
- << result_str;
- if (result) {
- freeaddrinfo(result);
- result = nullptr;
- }
-
- // Change the DNS resolver, ensure that queries are no longer cached.
- dns.clearQueries();
test::DNSResponder dns2(listen_addr2, listen_srv, 250,
ns_rcode::ns_r_servfail, 1.0);
dns2.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
dns2.addMapping(host_name, ns_type::ns_t_aaaa, "::1.2.3.4");
ASSERT_TRUE(dns2.startServer());
- servers = { listen_addr2 };
- ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, mDefaultParams));
- EXPECT_EQ(0, getaddrinfo("howdy", nullptr, nullptr, &result));
- found = GetNumQueries(dns, host_name);
- size_t found2 = GetNumQueries(dns2, host_name);
- EXPECT_EQ(0U, found);
- EXPECT_LE(1U, found2);
-
- // Could be A or AAAA
- result_str = ToString(result);
- EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
- << ", result_str='" << result_str << "'";
- if (result) {
- freeaddrinfo(result);
- result = nullptr;
+
+ for (size_t i = 0 ; i < 1000 ; ++i) {
+ std::vector<std::string> servers = { listen_addr };
+ ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, mDefaultParams));
+ dns.clearQueries();
+ dns2.clearQueries();
+
+ EXPECT_EQ(0, getaddrinfo("howdy", nullptr, nullptr, &result));
+ size_t found = GetNumQueries(dns, host_name);
+ EXPECT_LE(1U, found);
+ // Could be A or AAAA
+ std::string result_str = ToString(result);
+ EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
+ << ", result_str='" << result_str << "'";
+ // TODO: Use ScopedAddrinfo or similar once it is available in a common header file.
+ if (result) {
+ freeaddrinfo(result);
+ result = nullptr;
+ }
+
+ // Verify that the name is cached.
+ size_t old_found = found;
+ EXPECT_EQ(0, getaddrinfo("howdy", nullptr, nullptr, &result));
+ found = GetNumQueries(dns, host_name);
+ EXPECT_LE(1U, found);
+ EXPECT_EQ(old_found, found);
+ result_str = ToString(result);
+ EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
+ << result_str;
+ if (result) {
+ freeaddrinfo(result);
+ result = nullptr;
+ }
+
+ // Change the DNS resolver, ensure that queries are no longer cached.
+ servers = { listen_addr2 };
+ ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, mDefaultParams));
+ dns.clearQueries();
+ dns2.clearQueries();
+
+ EXPECT_EQ(0, getaddrinfo("howdy", nullptr, nullptr, &result));
+ found = GetNumQueries(dns, host_name);
+ size_t found2 = GetNumQueries(dns2, host_name);
+ EXPECT_EQ(0U, found);
+ EXPECT_LE(1U, found2);
+
+ // Could be A or AAAA
+ result_str = ToString(result);
+ EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
+ << ", result_str='" << result_str << "'";
+ if (result) {
+ freeaddrinfo(result);
+ result = nullptr;
+ }
}
dns.stopServer();
dns2.stopServer();