Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Side by Side Diff: net/dns/dns_config_service_posix.cc

Issue 10543168: [net/dns] Instrument DnsConfigService to measure performance and failures. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/dns/dns_config_service_posix.h ('k') | net/dns/dns_config_service_posix_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/dns/dns_config_service_posix.h" 5 #include "net/dns/dns_config_service_posix.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/file_path.h" 11 #include "base/file_path.h"
12 #include "base/file_util.h" 12 #include "base/file_util.h"
13 #include "base/memory/scoped_ptr.h" 13 #include "base/memory/scoped_ptr.h"
14 #include "base/metrics/histogram.h"
15 #include "base/time.h"
14 #include "net/base/ip_endpoint.h" 16 #include "net/base/ip_endpoint.h"
15 #include "net/base/net_util.h" 17 #include "net/base/net_util.h"
16 #include "net/dns/dns_hosts.h" 18 #include "net/dns/dns_hosts.h"
17 #include "net/dns/dns_protocol.h" 19 #include "net/dns/dns_protocol.h"
18 #include "net/dns/serial_worker.h" 20 #include "net/dns/serial_worker.h"
19 21
20 namespace net { 22 namespace net {
21 23
24 #if !defined(OS_ANDROID)
25 namespace internal {
26
22 namespace { 27 namespace {
23 28
24 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> 29 #ifndef _PATH_RESCONF // Normally defined in <resolv.h>
25 #define _PATH_RESCONF "/etc/resolv.conf" 30 #define _PATH_RESCONF "/etc/resolv.conf"
26 #endif 31 #endif
27 32
28 const FilePath::CharType* kFilePathHosts = FILE_PATH_LITERAL("/etc/hosts"); 33 const FilePath::CharType* kFilePathHosts = FILE_PATH_LITERAL("/etc/hosts");
29 34
35 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) {
36 ConfigParsePosixResult result;
37 #if defined(OS_OPENBSD)
38 // Note: res_ninit in glibc always returns 0 and sets RES_INIT.
39 // res_init behaves the same way.
40 memset(&_res, 0, sizeof(_res));
41 if (res_init() == 0) {
42 result = ConvertResStateToDnsConfig(_res, config);
43 } else {
44 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED;
45 }
46 #else // all other OS_POSIX
47 struct __res_state res;
48 memset(&res, 0, sizeof(res));
49 if (res_ninit(&res) == 0) {
50 result = ConvertResStateToDnsConfig(res, config);
51 } else {
52 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED;
53 }
54 // Prefer res_ndestroy where available.
55 #if defined(OS_MACOSX) || defined(OS_FREEBSD)
56 res_ndestroy(&res);
57 #else
58 res_nclose(&res);
59 #endif
60 #endif
61 return result;
62 }
63
30 // A SerialWorker that uses libresolv to initialize res_state and converts 64 // A SerialWorker that uses libresolv to initialize res_state and converts
31 // it to DnsConfig. 65 // it to DnsConfig.
32 class ConfigReader : public SerialWorker { 66 class ConfigReader : public SerialWorker {
33 public: 67 public:
34 typedef base::Callback<void(const DnsConfig& config)> CallbackType; 68 typedef base::Callback<void(const DnsConfig& config)> CallbackType;
35 explicit ConfigReader(const CallbackType& callback) 69 explicit ConfigReader(const CallbackType& callback)
36 : callback_(callback), success_(false) {} 70 : callback_(callback), success_(false) {}
37 71
38 void DoWork() OVERRIDE { 72 void DoWork() OVERRIDE {
39 success_ = false; 73 base::TimeTicks start_time = base::TimeTicks::Now();
40 #if defined(OS_ANDROID) 74 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_);
41 NOTIMPLEMENTED(); 75 success_ = (result == CONFIG_PARSE_POSIX_OK);
42 #elif defined(OS_OPENBSD) 76 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix",
43 // Note: res_ninit in glibc always returns 0 and sets RES_INIT. 77 result, CONFIG_PARSE_POSIX_MAX);
44 // res_init behaves the same way. 78 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_);
45 memset(&_res, 0, sizeof(_res)); 79 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration",
46 if ((res_init() == 0) && (_res.options & RES_INIT)) 80 base::TimeTicks::Now() - start_time);
47 success_ = internal::ConvertResStateToDnsConfig(_res, &dns_config_);
48 #else // all other OS_POSIX
49 struct __res_state res;
50 memset(&res, 0, sizeof(res));
51 if ((res_ninit(&res) == 0) && (res.options & RES_INIT))
52 success_ = internal::ConvertResStateToDnsConfig(res, &dns_config_);
53
54 // Prefer res_ndestroy where available.
55 #if defined(OS_MACOSX) || defined(OS_FREEBSD)
56 res_ndestroy(&res);
57 #else
58 res_nclose(&res);
59 #endif
60 #endif
61 } 81 }
62 82
63 void OnWorkFinished() OVERRIDE { 83 void OnWorkFinished() OVERRIDE {
64 DCHECK(!IsCancelled()); 84 DCHECK(!IsCancelled());
65 if (success_) { 85 if (success_) {
66 callback_.Run(dns_config_); 86 callback_.Run(dns_config_);
67 } else { 87 } else {
68 LOG(WARNING) << "Failed to read DnsConfig."; 88 LOG(WARNING) << "Failed to read DnsConfig.";
69 } 89 }
70 } 90 }
(...skipping 13 matching lines...) Expand all
84 class HostsReader : public SerialWorker { 104 class HostsReader : public SerialWorker {
85 public: 105 public:
86 typedef base::Callback<void(const DnsHosts& hosts)> CallbackType; 106 typedef base::Callback<void(const DnsHosts& hosts)> CallbackType;
87 explicit HostsReader(const CallbackType& callback) 107 explicit HostsReader(const CallbackType& callback)
88 : path_(kFilePathHosts), callback_(callback), success_(false) {} 108 : path_(kFilePathHosts), callback_(callback), success_(false) {}
89 109
90 private: 110 private:
91 virtual ~HostsReader() {} 111 virtual ~HostsReader() {}
92 112
93 virtual void DoWork() OVERRIDE { 113 virtual void DoWork() OVERRIDE {
114 base::TimeTicks start_time = base::TimeTicks::Now();
94 success_ = ParseHostsFile(path_, &hosts_); 115 success_ = ParseHostsFile(path_, &hosts_);
116 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_);
117 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration",
118 base::TimeTicks::Now() - start_time);
95 } 119 }
96 120
97 virtual void OnWorkFinished() OVERRIDE { 121 virtual void OnWorkFinished() OVERRIDE {
98 if (success_) { 122 if (success_) {
99 callback_.Run(hosts_); 123 callback_.Run(hosts_);
100 } else { 124 } else {
101 LOG(WARNING) << "Failed to read DnsHosts."; 125 LOG(WARNING) << "Failed to read DnsHosts.";
102 } 126 }
103 } 127 }
104 128
105 const FilePath path_; 129 const FilePath path_;
106 const CallbackType callback_; 130 const CallbackType callback_;
107 // Written in DoWork, read in OnWorkFinished, no locking necessary. 131 // Written in DoWork, read in OnWorkFinished, no locking necessary.
108 DnsHosts hosts_; 132 DnsHosts hosts_;
109 bool success_; 133 bool success_;
110 134
111 DISALLOW_COPY_AND_ASSIGN(HostsReader); 135 DISALLOW_COPY_AND_ASSIGN(HostsReader);
112 }; 136 };
113 137
114 } // namespace 138 } // namespace
115 139
116 namespace internal {
117
118 DnsConfigServicePosix::DnsConfigServicePosix() { 140 DnsConfigServicePosix::DnsConfigServicePosix() {
119 config_reader_ = new ConfigReader( 141 config_reader_ = new ConfigReader(
120 base::Bind(&DnsConfigServicePosix::OnConfigRead, 142 base::Bind(&DnsConfigServicePosix::OnConfigRead,
121 base::Unretained(this))); 143 base::Unretained(this)));
122 hosts_reader_ = new HostsReader( 144 hosts_reader_ = new HostsReader(
123 base::Bind(&DnsConfigServicePosix::OnHostsRead, 145 base::Bind(&DnsConfigServicePosix::OnHostsRead,
124 base::Unretained(this))); 146 base::Unretained(this)));
125 } 147 }
126 148
127 DnsConfigServicePosix::~DnsConfigServicePosix() { 149 DnsConfigServicePosix::~DnsConfigServicePosix() {
(...skipping 15 matching lines...) Expand all
143 if (detail & NetworkChangeNotifier::CHANGE_DNS_SETTINGS) { 165 if (detail & NetworkChangeNotifier::CHANGE_DNS_SETTINGS) {
144 InvalidateConfig(); 166 InvalidateConfig();
145 config_reader_->WorkNow(); 167 config_reader_->WorkNow();
146 } 168 }
147 if (detail & NetworkChangeNotifier::CHANGE_DNS_HOSTS) { 169 if (detail & NetworkChangeNotifier::CHANGE_DNS_HOSTS) {
148 InvalidateHosts(); 170 InvalidateHosts();
149 hosts_reader_->WorkNow(); 171 hosts_reader_->WorkNow();
150 } 172 }
151 } 173 }
152 174
153 #if !defined(OS_ANDROID) 175 ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res,
154 bool ConvertResStateToDnsConfig(const struct __res_state& res, 176 DnsConfig* dns_config) {
155 DnsConfig* dns_config) {
156 CHECK(dns_config != NULL); 177 CHECK(dns_config != NULL);
157 DCHECK(res.options & RES_INIT); 178 if (!(res.options & RES_INIT))
179 return CONFIG_PARSE_POSIX_RES_INIT_UNSET;
158 180
159 dns_config->nameservers.clear(); 181 dns_config->nameservers.clear();
160 182
161 #if defined(OS_MACOSX) || defined(OS_FREEBSD) 183 #if defined(OS_MACOSX) || defined(OS_FREEBSD)
162 union res_sockaddr_union addresses[MAXNS]; 184 union res_sockaddr_union addresses[MAXNS];
163 int nscount = res_getservers(const_cast<res_state>(&res), addresses, MAXNS); 185 int nscount = res_getservers(const_cast<res_state>(&res), addresses, MAXNS);
164 DCHECK_GE(nscount, 0); 186 DCHECK_GE(nscount, 0);
165 DCHECK_LE(nscount, MAXNS); 187 DCHECK_LE(nscount, MAXNS);
166 for (int i = 0; i < nscount; ++i) { 188 for (int i = 0; i < nscount; ++i) {
167 IPEndPoint ipe; 189 IPEndPoint ipe;
168 if (!ipe.FromSockAddr( 190 if (!ipe.FromSockAddr(
169 reinterpret_cast<const struct sockaddr*>(&addresses[i]), 191 reinterpret_cast<const struct sockaddr*>(&addresses[i]),
170 sizeof addresses[i])) { 192 sizeof addresses[i])) {
171 return false; 193 return CONFIG_PARSE_POSIX_BAD_ADDRESS;
172 } 194 }
173 dns_config->nameservers.push_back(ipe); 195 dns_config->nameservers.push_back(ipe);
174 } 196 }
175 #elif defined(OS_LINUX) 197 #elif defined(OS_LINUX)
176 COMPILE_ASSERT(arraysize(res.nsaddr_list) >= MAXNS && 198 COMPILE_ASSERT(arraysize(res.nsaddr_list) >= MAXNS &&
177 arraysize(res._u._ext.nsaddrs) >= MAXNS, 199 arraysize(res._u._ext.nsaddrs) >= MAXNS,
178 incompatible_libresolv_res_state); 200 incompatible_libresolv_res_state);
179 DCHECK_LE(res.nscount, MAXNS); 201 DCHECK_LE(res.nscount, MAXNS);
180 // Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|. 202 // Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|.
181 // In res_send.c:res_nsend, it merges |nsaddr_list| into |nsaddrs|, 203 // In res_send.c:res_nsend, it merges |nsaddr_list| into |nsaddrs|,
182 // but we have to combine the two arrays ourselves. 204 // but we have to combine the two arrays ourselves.
183 for (int i = 0; i < res.nscount; ++i) { 205 for (int i = 0; i < res.nscount; ++i) {
184 IPEndPoint ipe; 206 IPEndPoint ipe;
185 const struct sockaddr* addr = NULL; 207 const struct sockaddr* addr = NULL;
186 size_t addr_len = 0; 208 size_t addr_len = 0;
187 if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend. 209 if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend.
188 addr = reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]); 210 addr = reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]);
189 addr_len = sizeof res.nsaddr_list[i]; 211 addr_len = sizeof res.nsaddr_list[i];
190 } else if (res._u._ext.nsaddrs[i] != NULL) { 212 } else if (res._u._ext.nsaddrs[i] != NULL) {
191 addr = reinterpret_cast<const struct sockaddr*>(res._u._ext.nsaddrs[i]); 213 addr = reinterpret_cast<const struct sockaddr*>(res._u._ext.nsaddrs[i]);
192 addr_len = sizeof *res._u._ext.nsaddrs[i]; 214 addr_len = sizeof *res._u._ext.nsaddrs[i];
193 } else { 215 } else {
194 return false; 216 return CONFIG_PARSE_POSIX_BAD_EXT_STRUCT;
195 } 217 }
196 if (!ipe.FromSockAddr(addr, addr_len)) 218 if (!ipe.FromSockAddr(addr, addr_len))
197 return false; 219 return CONFIG_PARSE_POSIX_BAD_ADDRESS;
198 dns_config->nameservers.push_back(ipe); 220 dns_config->nameservers.push_back(ipe);
199 } 221 }
200 #else // !(defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_FREEBSD)) 222 #else // !(defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_FREEBSD))
201 DCHECK_LE(res.nscount, MAXNS); 223 DCHECK_LE(res.nscount, MAXNS);
202 for (int i = 0; i < res.nscount; ++i) { 224 for (int i = 0; i < res.nscount; ++i) {
203 IPEndPoint ipe; 225 IPEndPoint ipe;
204 if (!ipe.FromSockAddr( 226 if (!ipe.FromSockAddr(
205 reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]), 227 reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]),
206 sizeof res.nsaddr_list[i])) { 228 sizeof res.nsaddr_list[i])) {
207 return false; 229 return CONFIG_PARSE_POSIX_BAD_ADDRESS;
208 } 230 }
209 dns_config->nameservers.push_back(ipe); 231 dns_config->nameservers.push_back(ipe);
210 } 232 }
211 #endif 233 #endif
212 234
213 dns_config->search.clear(); 235 dns_config->search.clear();
214 for (int i = 0; (i < MAXDNSRCH) && res.dnsrch[i]; ++i) { 236 for (int i = 0; (i < MAXDNSRCH) && res.dnsrch[i]; ++i) {
215 dns_config->search.push_back(std::string(res.dnsrch[i])); 237 dns_config->search.push_back(std::string(res.dnsrch[i]));
216 } 238 }
217 239
218 dns_config->ndots = res.ndots; 240 dns_config->ndots = res.ndots;
219 dns_config->timeout = base::TimeDelta::FromSeconds(res.retrans); 241 dns_config->timeout = base::TimeDelta::FromSeconds(res.retrans);
220 dns_config->attempts = res.retry; 242 dns_config->attempts = res.retry;
221 #if defined(RES_ROTATE) 243 #if defined(RES_ROTATE)
222 dns_config->rotate = res.options & RES_ROTATE; 244 dns_config->rotate = res.options & RES_ROTATE;
223 #endif 245 #endif
224 dns_config->edns0 = res.options & RES_USE_EDNS0; 246 dns_config->edns0 = res.options & RES_USE_EDNS0;
225 247
248 // The current implementation assumes these options are set. They normally
249 // cannot be overwritten by /etc/resolv.conf
250 unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
251 if ((res.options & kRequiredOptions) != kRequiredOptions)
252 return CONFIG_PARSE_POSIX_MISSING_OPTIONS;
253
254 unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC;
255 if (res.options & kUnhandledOptions)
256 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
257
258 if (dns_config->nameservers.empty())
259 return CONFIG_PARSE_POSIX_NO_NAMESERVERS;
260
226 // If any name server is 0.0.0.0, assume the configuration is invalid. 261 // If any name server is 0.0.0.0, assume the configuration is invalid.
227 // TODO(szym): Measure how often this happens. http://crbug.com/125599 262 // TODO(szym): Measure how often this happens. http://crbug.com/125599
228 const IPAddressNumber kEmptyAddress(kIPv4AddressSize); 263 const IPAddressNumber kEmptyAddress(kIPv4AddressSize);
229 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) 264 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) {
230 if (dns_config->nameservers[i].address() == kEmptyAddress) 265 if (dns_config->nameservers[i].address() == kEmptyAddress)
231 return false; 266 return CONFIG_PARSE_POSIX_NULL_ADDRESS;
232 return true; 267 }
268 return CONFIG_PARSE_POSIX_OK;
233 } 269 }
234 #endif // !defined(OS_ANDROID)
235 270
236 } // namespace internal 271 } // namespace internal
237 272
238 // static 273 // static
239 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { 274 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
240 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix()); 275 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix());
241 } 276 }
242 277
278 #else // defined(OS_ANDROID)
279 // Android NDK provides only a stub <resolv.h> header.
280 class StubDnsConfigService : public DnsConfigService {
281 public:
282 StubDnsConfigService() {}
283 virtual ~StubDnsConfigService() {}
284 virtual void OnDNSChanged(unsigned detail) OVERRIDE {}
285 };
286 // static
287 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
288 return scoped_ptr<DnsConfigService>(new StubDnsConfigService());
289 }
290 #endif
291
243 } // namespace net 292 } // namespace net
OLDNEW
« no previous file with comments | « net/dns/dns_config_service_posix.h ('k') | net/dns/dns_config_service_posix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698