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

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: Provide stub service for Android. 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
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)
22 namespace { 25 namespace {
23 26
24 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> 27 #ifndef _PATH_RESCONF // Normally defined in <resolv.h>
25 #define _PATH_RESCONF "/etc/resolv.conf" 28 #define _PATH_RESCONF "/etc/resolv.conf"
26 #endif 29 #endif
27 30
28 const FilePath::CharType* kFilePathHosts = FILE_PATH_LITERAL("/etc/hosts"); 31 const FilePath::CharType* kFilePathHosts = FILE_PATH_LITERAL("/etc/hosts");
29 32
33 enum ConfigParsePosixResult {
34 CONFIG_PARSE_POSIX_OK = 0,
35 CONFIG_PARSE_POSIX_RES_INIT_FAILED,
36 CONFIG_PARSE_POSIX_RES_INIT_UNSET,
37 CONFIG_PARSE_POSIX_BAD_ADDRESS,
38 CONFIG_PARSE_POSIX_BAD_EXT_STRUCT,
39 CONFIG_PARSE_POSIX_NULL_ADDRESS,
40 CONFIG_PARSE_POSIX_NO_NAMESERVERS,
41 CONFIG_PARSE_POSIX_MISSING_OPTIONS,
42 CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS,
43 CONFIG_PARSE_POSIX_MAX // Bounding values for enumeration.
44 };
45
46 static void RecordConfigParseResult(ConfigParsePosixResult result) {
47 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix",
48 result, CONFIG_PARSE_POSIX_MAX);
49 }
50
30 // A SerialWorker that uses libresolv to initialize res_state and converts 51 // A SerialWorker that uses libresolv to initialize res_state and converts
31 // it to DnsConfig. 52 // it to DnsConfig.
32 class ConfigReader : public SerialWorker { 53 class ConfigReader : public SerialWorker {
33 public: 54 public:
34 typedef base::Callback<void(const DnsConfig& config)> CallbackType; 55 typedef base::Callback<void(const DnsConfig& config)> CallbackType;
35 explicit ConfigReader(const CallbackType& callback) 56 explicit ConfigReader(const CallbackType& callback)
36 : callback_(callback), success_(false) {} 57 : callback_(callback), success_(false) {}
37 58
38 void DoWork() OVERRIDE { 59 void DoWork() OVERRIDE {
60 base::TimeTicks start_time = base::TimeTicks::Now();
39 success_ = false; 61 success_ = false;
40 #if defined(OS_ANDROID) 62 #if defined(OS_OPENBSD)
41 NOTIMPLEMENTED();
42 #elif defined(OS_OPENBSD)
43 // Note: res_ninit in glibc always returns 0 and sets RES_INIT. 63 // Note: res_ninit in glibc always returns 0 and sets RES_INIT.
44 // res_init behaves the same way. 64 // res_init behaves the same way.
45 memset(&_res, 0, sizeof(_res)); 65 memset(&_res, 0, sizeof(_res));
46 if ((res_init() == 0) && (_res.options & RES_INIT)) 66 if (res_init() == 0) {
47 success_ = internal::ConvertResStateToDnsConfig(_res, &dns_config_); 67 success_ = internal::ConvertResStateToDnsConfig(_res, &dns_config_);
68 } else {
69 RecordConfigParseResult(CONFIG_PARSE_POSIX_RES_INIT_FAILED);
70 }
48 #else // all other OS_POSIX 71 #else // all other OS_POSIX
49 struct __res_state res; 72 struct __res_state res;
50 memset(&res, 0, sizeof(res)); 73 memset(&res, 0, sizeof(res));
51 if ((res_ninit(&res) == 0) && (res.options & RES_INIT)) 74 if (res_ninit(&res) == 0) {
52 success_ = internal::ConvertResStateToDnsConfig(res, &dns_config_); 75 success_ = internal::ConvertResStateToDnsConfig(res, &dns_config_);
53 76 } else {
77 RecordConfigParseResult(CONFIG_PARSE_POSIX_RES_INIT_FAILED);
78 }
54 // Prefer res_ndestroy where available. 79 // Prefer res_ndestroy where available.
55 #if defined(OS_MACOSX) || defined(OS_FREEBSD) 80 #if defined(OS_MACOSX) || defined(OS_FREEBSD)
56 res_ndestroy(&res); 81 res_ndestroy(&res);
57 #else 82 #else
58 res_nclose(&res); 83 res_nclose(&res);
59 #endif 84 #endif
60 #endif 85 #endif
86 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_);
mmenke 2012/06/18 17:19:50 Do these give us anything that AsyncDNS.ConfigPars
szym 2012/06/18 20:53:08 They would share the name across platforms. Not su
mmenke 2012/06/18 20:55:56 They wouldn't, though, since the windows one is ca
szym 2012/06/18 20:59:55 That was my mistake. Notice that initially both re
87 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration",
88 base::TimeTicks::Now() - start_time);
61 } 89 }
62 90
63 void OnWorkFinished() OVERRIDE { 91 void OnWorkFinished() OVERRIDE {
64 DCHECK(!IsCancelled()); 92 DCHECK(!IsCancelled());
65 if (success_) { 93 if (success_) {
66 callback_.Run(dns_config_); 94 callback_.Run(dns_config_);
67 } else { 95 } else {
68 LOG(WARNING) << "Failed to read DnsConfig."; 96 LOG(WARNING) << "Failed to read DnsConfig.";
69 } 97 }
70 } 98 }
(...skipping 13 matching lines...) Expand all
84 class HostsReader : public SerialWorker { 112 class HostsReader : public SerialWorker {
85 public: 113 public:
86 typedef base::Callback<void(const DnsHosts& hosts)> CallbackType; 114 typedef base::Callback<void(const DnsHosts& hosts)> CallbackType;
87 explicit HostsReader(const CallbackType& callback) 115 explicit HostsReader(const CallbackType& callback)
88 : path_(kFilePathHosts), callback_(callback), success_(false) {} 116 : path_(kFilePathHosts), callback_(callback), success_(false) {}
89 117
90 private: 118 private:
91 virtual ~HostsReader() {} 119 virtual ~HostsReader() {}
92 120
93 virtual void DoWork() OVERRIDE { 121 virtual void DoWork() OVERRIDE {
122 base::TimeTicks start_time = base::TimeTicks::Now();
94 success_ = ParseHostsFile(path_, &hosts_); 123 success_ = ParseHostsFile(path_, &hosts_);
124 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_);
125 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration",
126 base::TimeTicks::Now() - start_time);
95 } 127 }
96 128
97 virtual void OnWorkFinished() OVERRIDE { 129 virtual void OnWorkFinished() OVERRIDE {
98 if (success_) { 130 if (success_) {
99 callback_.Run(hosts_); 131 callback_.Run(hosts_);
100 } else { 132 } else {
101 LOG(WARNING) << "Failed to read DnsHosts."; 133 LOG(WARNING) << "Failed to read DnsHosts.";
102 } 134 }
103 } 135 }
104 136
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
143 if (detail & NetworkChangeNotifier::CHANGE_DNS_SETTINGS) { 175 if (detail & NetworkChangeNotifier::CHANGE_DNS_SETTINGS) {
144 InvalidateConfig(); 176 InvalidateConfig();
145 config_reader_->WorkNow(); 177 config_reader_->WorkNow();
146 } 178 }
147 if (detail & NetworkChangeNotifier::CHANGE_DNS_HOSTS) { 179 if (detail & NetworkChangeNotifier::CHANGE_DNS_HOSTS) {
148 InvalidateHosts(); 180 InvalidateHosts();
149 hosts_reader_->WorkNow(); 181 hosts_reader_->WorkNow();
150 } 182 }
151 } 183 }
152 184
153 #if !defined(OS_ANDROID)
154 bool ConvertResStateToDnsConfig(const struct __res_state& res, 185 bool ConvertResStateToDnsConfig(const struct __res_state& res,
155 DnsConfig* dns_config) { 186 DnsConfig* dns_config) {
mmenke 2012/06/18 17:19:50 Optional: I'd suggest making this return a Config
156 CHECK(dns_config != NULL); 187 CHECK(dns_config != NULL);
157 DCHECK(res.options & RES_INIT); 188 if (!(res.options & RES_INIT)) {
189 RecordConfigParseResult(CONFIG_PARSE_POSIX_RES_INIT_UNSET);
190 return false;
191 }
158 192
159 dns_config->nameservers.clear(); 193 dns_config->nameservers.clear();
160 194
161 #if defined(OS_MACOSX) || defined(OS_FREEBSD) 195 #if defined(OS_MACOSX) || defined(OS_FREEBSD)
162 union res_sockaddr_union addresses[MAXNS]; 196 union res_sockaddr_union addresses[MAXNS];
163 int nscount = res_getservers(const_cast<res_state>(&res), addresses, MAXNS); 197 int nscount = res_getservers(const_cast<res_state>(&res), addresses, MAXNS);
164 DCHECK_GE(nscount, 0); 198 DCHECK_GE(nscount, 0);
165 DCHECK_LE(nscount, MAXNS); 199 DCHECK_LE(nscount, MAXNS);
166 for (int i = 0; i < nscount; ++i) { 200 for (int i = 0; i < nscount; ++i) {
167 IPEndPoint ipe; 201 IPEndPoint ipe;
168 if (!ipe.FromSockAddr( 202 if (!ipe.FromSockAddr(
169 reinterpret_cast<const struct sockaddr*>(&addresses[i]), 203 reinterpret_cast<const struct sockaddr*>(&addresses[i]),
170 sizeof addresses[i])) { 204 sizeof addresses[i])) {
205 RecordConfigParseResult(CONFIG_PARSE_POSIX_BAD_ADDRESS);
171 return false; 206 return false;
172 } 207 }
173 dns_config->nameservers.push_back(ipe); 208 dns_config->nameservers.push_back(ipe);
174 } 209 }
175 #elif defined(OS_LINUX) 210 #elif defined(OS_LINUX)
176 COMPILE_ASSERT(arraysize(res.nsaddr_list) >= MAXNS && 211 COMPILE_ASSERT(arraysize(res.nsaddr_list) >= MAXNS &&
177 arraysize(res._u._ext.nsaddrs) >= MAXNS, 212 arraysize(res._u._ext.nsaddrs) >= MAXNS,
178 incompatible_libresolv_res_state); 213 incompatible_libresolv_res_state);
179 DCHECK_LE(res.nscount, MAXNS); 214 DCHECK_LE(res.nscount, MAXNS);
180 // Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|. 215 // 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|, 216 // In res_send.c:res_nsend, it merges |nsaddr_list| into |nsaddrs|,
182 // but we have to combine the two arrays ourselves. 217 // but we have to combine the two arrays ourselves.
183 for (int i = 0; i < res.nscount; ++i) { 218 for (int i = 0; i < res.nscount; ++i) {
184 IPEndPoint ipe; 219 IPEndPoint ipe;
185 const struct sockaddr* addr = NULL; 220 const struct sockaddr* addr = NULL;
186 size_t addr_len = 0; 221 size_t addr_len = 0;
187 if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend. 222 if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend.
188 addr = reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]); 223 addr = reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]);
189 addr_len = sizeof res.nsaddr_list[i]; 224 addr_len = sizeof res.nsaddr_list[i];
190 } else if (res._u._ext.nsaddrs[i] != NULL) { 225 } else if (res._u._ext.nsaddrs[i] != NULL) {
191 addr = reinterpret_cast<const struct sockaddr*>(res._u._ext.nsaddrs[i]); 226 addr = reinterpret_cast<const struct sockaddr*>(res._u._ext.nsaddrs[i]);
192 addr_len = sizeof *res._u._ext.nsaddrs[i]; 227 addr_len = sizeof *res._u._ext.nsaddrs[i];
193 } else { 228 } else {
229 RecordConfigParseResult(CONFIG_PARSE_POSIX_BAD_EXT_STRUCT);
194 return false; 230 return false;
195 } 231 }
196 if (!ipe.FromSockAddr(addr, addr_len)) 232 if (!ipe.FromSockAddr(addr, addr_len)) {
233 RecordConfigParseResult(CONFIG_PARSE_POSIX_BAD_ADDRESS);
197 return false; 234 return false;
235 }
198 dns_config->nameservers.push_back(ipe); 236 dns_config->nameservers.push_back(ipe);
199 } 237 }
200 #else // !(defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_FREEBSD)) 238 #else // !(defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_FREEBSD))
201 DCHECK_LE(res.nscount, MAXNS); 239 DCHECK_LE(res.nscount, MAXNS);
202 for (int i = 0; i < res.nscount; ++i) { 240 for (int i = 0; i < res.nscount; ++i) {
203 IPEndPoint ipe; 241 IPEndPoint ipe;
204 if (!ipe.FromSockAddr( 242 if (!ipe.FromSockAddr(
205 reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]), 243 reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]),
206 sizeof res.nsaddr_list[i])) { 244 sizeof res.nsaddr_list[i])) {
245 RecordConfigParseResult(CONFIG_PARSE_POSIX_BAD_ADDRESS);
207 return false; 246 return false;
208 } 247 }
209 dns_config->nameservers.push_back(ipe); 248 dns_config->nameservers.push_back(ipe);
210 } 249 }
211 #endif 250 #endif
212 251
213 dns_config->search.clear(); 252 dns_config->search.clear();
214 for (int i = 0; (i < MAXDNSRCH) && res.dnsrch[i]; ++i) { 253 for (int i = 0; (i < MAXDNSRCH) && res.dnsrch[i]; ++i) {
215 dns_config->search.push_back(std::string(res.dnsrch[i])); 254 dns_config->search.push_back(std::string(res.dnsrch[i]));
216 } 255 }
217 256
218 dns_config->ndots = res.ndots; 257 dns_config->ndots = res.ndots;
219 dns_config->timeout = base::TimeDelta::FromSeconds(res.retrans); 258 dns_config->timeout = base::TimeDelta::FromSeconds(res.retrans);
220 dns_config->attempts = res.retry; 259 dns_config->attempts = res.retry;
221 #if defined(RES_ROTATE) 260 #if defined(RES_ROTATE)
222 dns_config->rotate = res.options & RES_ROTATE; 261 dns_config->rotate = res.options & RES_ROTATE;
223 #endif 262 #endif
224 dns_config->edns0 = res.options & RES_USE_EDNS0; 263 dns_config->edns0 = res.options & RES_USE_EDNS0;
225 264
265 // The current implementation assumes these options are set. They normally
266 // cannot be overwritten by /etc/resolv.conf
267 unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
268 if ((res.options & kRequiredOptions) != kRequiredOptions) {
269 RecordConfigParseResult(CONFIG_PARSE_POSIX_MISSING_OPTIONS);
270 return false;
271 }
272
273 unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC;
274 if (res.options & kUnhandledOptions) {
275 RecordConfigParseResult(CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS);
276 return false;
277 }
278
279 if (dns_config->nameservers.empty()) {
280 RecordConfigParseResult(CONFIG_PARSE_POSIX_NO_NAMESERVERS);
281 return false;
282 }
283
226 // If any name server is 0.0.0.0, assume the configuration is invalid. 284 // 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 285 // TODO(szym): Measure how often this happens. http://crbug.com/125599
228 const IPAddressNumber kEmptyAddress(kIPv4AddressSize); 286 const IPAddressNumber kEmptyAddress(kIPv4AddressSize);
229 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) 287 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) {
230 if (dns_config->nameservers[i].address() == kEmptyAddress) 288 if (dns_config->nameservers[i].address() == kEmptyAddress) {
289 RecordConfigParseResult(CONFIG_PARSE_POSIX_NULL_ADDRESS);
231 return false; 290 return false;
291 }
292 }
293 RecordConfigParseResult(CONFIG_PARSE_POSIX_OK);
232 return true; 294 return true;
233 } 295 }
234 #endif // !defined(OS_ANDROID)
235 296
236 } // namespace internal 297 } // namespace internal
237 298
238 // static 299 // static
239 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { 300 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
240 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix()); 301 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix());
241 } 302 }
242 303
304 #else // defined(OS_ANDROID)
305 // Android NDK provides only a stub <resolv.h> header.
306 class StubDnsConfigService : public DnsConfigService {
307 public:
308 StubDnsConfigService() {}
309 virtual ~StubDnsConfigService() {}
310 virtual void OnDNSChanged(unsigned detail) OVERRIDE {}
311 };
312 // static
313 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
314 return scoped_ptr<DnsConfigService>(new StubDnsConfigService());
315 }
316 #endif
317
243 } // namespace net 318 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698