OLD | NEW |
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/files/file.h" |
11 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
12 #include "base/files/file_path_watcher.h" | 13 #include "base/files/file_path_watcher.h" |
13 #include "base/lazy_instance.h" | 14 #include "base/lazy_instance.h" |
14 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
15 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
16 #include "base/time/time.h" | 17 #include "base/time/time.h" |
17 #include "net/base/ip_endpoint.h" | 18 #include "net/base/ip_endpoint.h" |
18 #include "net/base/net_util.h" | 19 #include "net/base/net_util.h" |
19 #include "net/dns/dns_hosts.h" | 20 #include "net/dns/dns_hosts.h" |
20 #include "net/dns/dns_protocol.h" | 21 #include "net/dns/dns_protocol.h" |
(...skipping 30 matching lines...) Expand all Loading... |
51 public: | 52 public: |
52 typedef base::Callback<void(bool succeeded)> CallbackType; | 53 typedef base::Callback<void(bool succeeded)> CallbackType; |
53 | 54 |
54 bool Watch(const CallbackType& callback) { | 55 bool Watch(const CallbackType& callback) { |
55 return false; | 56 return false; |
56 } | 57 } |
57 }; | 58 }; |
58 | 59 |
59 #elif defined(OS_ANDROID) | 60 #elif defined(OS_ANDROID) |
60 // On Android, assume DNS config may have changed on every network change. | 61 // On Android, assume DNS config may have changed on every network change. |
61 class DnsConfigWatcher : public NetworkChangeNotifier::NetworkChangeObserver { | 62 class DnsConfigWatcher { |
62 public: | 63 public: |
63 DnsConfigWatcher() { | |
64 NetworkChangeNotifier::AddNetworkChangeObserver(this); | |
65 } | |
66 | |
67 ~DnsConfigWatcher() override { | |
68 NetworkChangeNotifier::RemoveNetworkChangeObserver(this); | |
69 } | |
70 | |
71 bool Watch(const base::Callback<void(bool succeeded)>& callback) { | 64 bool Watch(const base::Callback<void(bool succeeded)>& callback) { |
72 callback_ = callback; | 65 callback_ = callback; |
73 return true; | 66 return true; |
74 } | 67 } |
75 | 68 |
76 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override { | 69 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) { |
77 if (!callback_.is_null() && type != NetworkChangeNotifier::CONNECTION_NONE) | 70 if (!callback_.is_null() && type != NetworkChangeNotifier::CONNECTION_NONE) |
78 callback_.Run(true); | 71 callback_.Run(true); |
79 } | 72 } |
80 | 73 |
81 private: | 74 private: |
82 base::Callback<void(bool succeeded)> callback_; | 75 base::Callback<void(bool succeeded)> callback_; |
83 }; | 76 }; |
84 #elif !defined(OS_MACOSX) | 77 #elif !defined(OS_MACOSX) |
85 // DnsConfigWatcher for OS_MACOSX is in dns_config_watcher_mac.{hh,cc}. | 78 // DnsConfigWatcher for OS_MACOSX is in dns_config_watcher_mac.{hh,cc}. |
86 | 79 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 | 187 |
195 return CONFIG_PARSE_POSIX_OK; | 188 return CONFIG_PARSE_POSIX_OK; |
196 } | 189 } |
197 #endif | 190 #endif |
198 | 191 |
199 } // namespace | 192 } // namespace |
200 | 193 |
201 class DnsConfigServicePosix::Watcher { | 194 class DnsConfigServicePosix::Watcher { |
202 public: | 195 public: |
203 explicit Watcher(DnsConfigServicePosix* service) | 196 explicit Watcher(DnsConfigServicePosix* service) |
204 : service_(service), | 197 : service_(service), weak_factory_(this) {} |
205 weak_factory_(this) {} | |
206 ~Watcher() {} | 198 ~Watcher() {} |
207 | 199 |
208 bool Watch() { | 200 bool Watch() { |
209 bool success = true; | 201 bool success = true; |
210 if (!config_watcher_.Watch(base::Bind(&Watcher::OnConfigChanged, | 202 if (!config_watcher_.Watch(base::Bind(&Watcher::OnConfigChanged, |
211 base::Unretained(this)))) { | 203 base::Unretained(this)))) { |
212 LOG(ERROR) << "DNS config watch failed to start."; | 204 LOG(ERROR) << "DNS config watch failed to start."; |
213 success = false; | 205 success = false; |
214 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", | 206 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", |
215 DNS_CONFIG_WATCH_FAILED_TO_START_CONFIG, | 207 DNS_CONFIG_WATCH_FAILED_TO_START_CONFIG, |
216 DNS_CONFIG_WATCH_MAX); | 208 DNS_CONFIG_WATCH_MAX); |
217 } | 209 } |
218 if (!hosts_watcher_.Watch(base::FilePath(kFilePathHosts), false, | 210 if (!hosts_watcher_.Watch( |
219 base::Bind(&Watcher::OnHostsChanged, | 211 base::FilePath(service_->file_path_hosts_), false, |
220 base::Unretained(this)))) { | 212 base::Bind(&Watcher::OnHostsChanged, base::Unretained(this)))) { |
221 LOG(ERROR) << "DNS hosts watch failed to start."; | 213 LOG(ERROR) << "DNS hosts watch failed to start."; |
222 success = false; | 214 success = false; |
223 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", | 215 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", |
224 DNS_CONFIG_WATCH_FAILED_TO_START_HOSTS, | 216 DNS_CONFIG_WATCH_FAILED_TO_START_HOSTS, |
225 DNS_CONFIG_WATCH_MAX); | 217 DNS_CONFIG_WATCH_MAX); |
226 } | 218 } |
227 return success; | 219 return success; |
228 } | 220 } |
229 | 221 |
| 222 #if defined(OS_ANDROID) |
| 223 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) { |
| 224 config_watcher_.OnNetworkChanged(type); |
| 225 } |
| 226 #endif // defined(OS_ANDROID) |
| 227 |
230 private: | 228 private: |
231 void OnConfigChanged(bool succeeded) { | 229 void OnConfigChanged(bool succeeded) { |
| 230 #if defined(OS_ANDROID) |
| 231 service_->seen_config_change_ = true; |
| 232 #endif // defined(OS_ANDROID) |
232 // Ignore transient flutter of resolv.conf by delaying the signal a bit. | 233 // Ignore transient flutter of resolv.conf by delaying the signal a bit. |
233 const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(50); | 234 const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(50); |
234 base::MessageLoop::current()->PostDelayedTask( | 235 base::MessageLoop::current()->PostDelayedTask( |
235 FROM_HERE, | 236 FROM_HERE, |
236 base::Bind(&Watcher::OnConfigChangedDelayed, | 237 base::Bind(&Watcher::OnConfigChangedDelayed, |
237 weak_factory_.GetWeakPtr(), | 238 weak_factory_.GetWeakPtr(), |
238 succeeded), | 239 succeeded), |
239 kDelay); | 240 kDelay); |
240 } | 241 } |
241 void OnConfigChangedDelayed(bool succeeded) { | 242 void OnConfigChangedDelayed(bool succeeded) { |
(...skipping 16 matching lines...) Expand all Loading... |
258 // it to DnsConfig (except on Android, where it reads system properties | 259 // it to DnsConfig (except on Android, where it reads system properties |
259 // net.dns1 and net.dns2; see #if around ReadDnsConfig above.) | 260 // net.dns1 and net.dns2; see #if around ReadDnsConfig above.) |
260 class DnsConfigServicePosix::ConfigReader : public SerialWorker { | 261 class DnsConfigServicePosix::ConfigReader : public SerialWorker { |
261 public: | 262 public: |
262 explicit ConfigReader(DnsConfigServicePosix* service) | 263 explicit ConfigReader(DnsConfigServicePosix* service) |
263 : service_(service), success_(false) {} | 264 : service_(service), success_(false) {} |
264 | 265 |
265 void DoWork() override { | 266 void DoWork() override { |
266 base::TimeTicks start_time = base::TimeTicks::Now(); | 267 base::TimeTicks start_time = base::TimeTicks::Now(); |
267 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); | 268 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); |
| 269 if (service_->dns_config_for_testing_) { |
| 270 dns_config_ = *service_->dns_config_for_testing_; |
| 271 result = CONFIG_PARSE_POSIX_OK; |
| 272 } |
268 switch (result) { | 273 switch (result) { |
269 case CONFIG_PARSE_POSIX_MISSING_OPTIONS: | 274 case CONFIG_PARSE_POSIX_MISSING_OPTIONS: |
270 case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS: | 275 case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS: |
271 DCHECK(dns_config_.unhandled_options); | 276 DCHECK(dns_config_.unhandled_options); |
272 // Fall through. | 277 // Fall through. |
273 case CONFIG_PARSE_POSIX_OK: | 278 case CONFIG_PARSE_POSIX_OK: |
274 success_ = true; | 279 success_ = true; |
275 break; | 280 break; |
276 default: | 281 default: |
277 success_ = false; | 282 success_ = false; |
(...skipping 23 matching lines...) Expand all Loading... |
301 DnsConfig dns_config_; | 306 DnsConfig dns_config_; |
302 bool success_; | 307 bool success_; |
303 | 308 |
304 DISALLOW_COPY_AND_ASSIGN(ConfigReader); | 309 DISALLOW_COPY_AND_ASSIGN(ConfigReader); |
305 }; | 310 }; |
306 | 311 |
307 // A SerialWorker that reads the HOSTS file and runs Callback. | 312 // A SerialWorker that reads the HOSTS file and runs Callback. |
308 class DnsConfigServicePosix::HostsReader : public SerialWorker { | 313 class DnsConfigServicePosix::HostsReader : public SerialWorker { |
309 public: | 314 public: |
310 explicit HostsReader(DnsConfigServicePosix* service) | 315 explicit HostsReader(DnsConfigServicePosix* service) |
311 : service_(service), path_(kFilePathHosts), success_(false) {} | 316 : service_(service), success_(false) {} |
312 | 317 |
313 private: | 318 private: |
314 ~HostsReader() override {} | 319 ~HostsReader() override {} |
315 | 320 |
316 void DoWork() override { | 321 void DoWork() override { |
317 base::TimeTicks start_time = base::TimeTicks::Now(); | 322 base::TimeTicks start_time = base::TimeTicks::Now(); |
318 success_ = ParseHostsFile(path_, &hosts_); | 323 success_ = |
| 324 ParseHostsFile(base::FilePath(service_->file_path_hosts_), &hosts_); |
319 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); | 325 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_); |
320 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", | 326 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration", |
321 base::TimeTicks::Now() - start_time); | 327 base::TimeTicks::Now() - start_time); |
322 } | 328 } |
323 | 329 |
324 void OnWorkFinished() override { | 330 void OnWorkFinished() override { |
325 if (success_) { | 331 if (success_) { |
326 service_->OnHostsRead(hosts_); | 332 service_->OnHostsRead(hosts_); |
327 } else { | 333 } else { |
328 LOG(WARNING) << "Failed to read DnsHosts."; | 334 LOG(WARNING) << "Failed to read DnsHosts."; |
329 } | 335 } |
330 } | 336 } |
331 | 337 |
332 DnsConfigServicePosix* service_; | 338 DnsConfigServicePosix* service_; |
333 const base::FilePath path_; | |
334 // Written in DoWork, read in OnWorkFinished, no locking necessary. | 339 // Written in DoWork, read in OnWorkFinished, no locking necessary. |
335 DnsHosts hosts_; | 340 DnsHosts hosts_; |
336 bool success_; | 341 bool success_; |
337 | 342 |
338 DISALLOW_COPY_AND_ASSIGN(HostsReader); | 343 DISALLOW_COPY_AND_ASSIGN(HostsReader); |
339 }; | 344 }; |
340 | 345 |
341 DnsConfigServicePosix::DnsConfigServicePosix() | 346 DnsConfigServicePosix::DnsConfigServicePosix() |
342 : config_reader_(new ConfigReader(this)), | 347 : file_path_hosts_(kFilePathHosts), |
343 hosts_reader_(new HostsReader(this)) {} | 348 dns_config_for_testing_(nullptr), |
| 349 config_reader_(new ConfigReader(this)), |
| 350 hosts_reader_(new HostsReader(this)) |
| 351 #if defined(OS_ANDROID) |
| 352 , |
| 353 seen_config_change_(false) |
| 354 #endif // defined(OS_ANDROID) |
| 355 { |
| 356 } |
344 | 357 |
345 DnsConfigServicePosix::~DnsConfigServicePosix() { | 358 DnsConfigServicePosix::~DnsConfigServicePosix() { |
346 config_reader_->Cancel(); | 359 config_reader_->Cancel(); |
347 hosts_reader_->Cancel(); | 360 hosts_reader_->Cancel(); |
348 } | 361 } |
349 | 362 |
350 void DnsConfigServicePosix::ReadNow() { | 363 void DnsConfigServicePosix::ReadNow() { |
351 config_reader_->WorkNow(); | 364 config_reader_->WorkNow(); |
352 hosts_reader_->WorkNow(); | 365 hosts_reader_->WorkNow(); |
353 } | 366 } |
(...skipping 25 matching lines...) Expand all Loading... |
379 hosts_reader_->WorkNow(); | 392 hosts_reader_->WorkNow(); |
380 } else { | 393 } else { |
381 LOG(ERROR) << "DNS hosts watch failed."; | 394 LOG(ERROR) << "DNS hosts watch failed."; |
382 set_watch_failed(true); | 395 set_watch_failed(true); |
383 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", | 396 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", |
384 DNS_CONFIG_WATCH_FAILED_HOSTS, | 397 DNS_CONFIG_WATCH_FAILED_HOSTS, |
385 DNS_CONFIG_WATCH_MAX); | 398 DNS_CONFIG_WATCH_MAX); |
386 } | 399 } |
387 } | 400 } |
388 | 401 |
| 402 void DnsConfigServicePosix::SetDnsConfigForTesting( |
| 403 const DnsConfig* dns_config) { |
| 404 DCHECK(CalledOnValidThread()); |
| 405 dns_config_for_testing_ = dns_config; |
| 406 } |
| 407 |
389 #if !defined(OS_ANDROID) | 408 #if !defined(OS_ANDROID) |
390 ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, | 409 ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res, |
391 DnsConfig* dns_config) { | 410 DnsConfig* dns_config) { |
392 CHECK(dns_config != NULL); | 411 CHECK(dns_config != NULL); |
393 if (!(res.options & RES_INIT)) | 412 if (!(res.options & RES_INIT)) |
394 return CONFIG_PARSE_POSIX_RES_INIT_UNSET; | 413 return CONFIG_PARSE_POSIX_RES_INIT_UNSET; |
395 | 414 |
396 dns_config->nameservers.clear(); | 415 dns_config->nameservers.clear(); |
397 | 416 |
398 #if defined(OS_MACOSX) || defined(OS_FREEBSD) | 417 #if defined(OS_MACOSX) || defined(OS_FREEBSD) |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 | 505 |
487 // If any name server is 0.0.0.0, assume the configuration is invalid. | 506 // If any name server is 0.0.0.0, assume the configuration is invalid. |
488 // TODO(szym): Measure how often this happens. http://crbug.com/125599 | 507 // TODO(szym): Measure how often this happens. http://crbug.com/125599 |
489 const IPAddressNumber kEmptyAddress(kIPv4AddressSize); | 508 const IPAddressNumber kEmptyAddress(kIPv4AddressSize); |
490 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) { | 509 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) { |
491 if (dns_config->nameservers[i].address() == kEmptyAddress) | 510 if (dns_config->nameservers[i].address() == kEmptyAddress) |
492 return CONFIG_PARSE_POSIX_NULL_ADDRESS; | 511 return CONFIG_PARSE_POSIX_NULL_ADDRESS; |
493 } | 512 } |
494 return CONFIG_PARSE_POSIX_OK; | 513 return CONFIG_PARSE_POSIX_OK; |
495 } | 514 } |
496 #endif // !defined(OS_ANDROID) | 515 |
| 516 #else // defined(OS_ANDROID) |
| 517 |
| 518 bool DnsConfigServicePosix::SeenChangeSince( |
| 519 const base::Time& since_time) const { |
| 520 DCHECK(CalledOnValidThread()); |
| 521 if (seen_config_change_) |
| 522 return true; |
| 523 base::File hosts(base::FilePath(file_path_hosts_), |
| 524 base::File::FLAG_OPEN | base::File::FLAG_READ); |
| 525 base::File::Info hosts_info; |
| 526 // File last modified times are not nearly as accurate as Time::Now() and are |
| 527 // rounded down. This means a file modified at 1:23.456 might only |
| 528 // be given a last modified time of 1:23.450. If we compared the last |
| 529 // modified time directly to |since_time| we might miss changes to the hosts |
| 530 // file because of this rounding down. To account for this the |since_time| |
| 531 // is pushed back by 1s which should more than account for any rounding. |
| 532 // In practice file modified times on Android are two orders of magnitude |
| 533 // more accurate than this 1s. In practice the hosts file on Android always |
| 534 // contains "127.0.0.1 localhost" and is never modified after Android is |
| 535 // installed. |
| 536 return !hosts.GetInfo(&hosts_info) || |
| 537 hosts_info.last_modified >= |
| 538 (since_time - base::TimeDelta::FromSeconds(1)); |
| 539 } |
| 540 |
| 541 void DnsConfigServicePosix::OnNetworkChanged( |
| 542 NetworkChangeNotifier::ConnectionType type) { |
| 543 DCHECK(CalledOnValidThread()); |
| 544 DCHECK(watcher_); |
| 545 watcher_->OnNetworkChanged(type); |
| 546 } |
| 547 #endif // defined(OS_ANDROID) |
497 | 548 |
498 } // namespace internal | 549 } // namespace internal |
499 | 550 |
500 // static | 551 // static |
501 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 552 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
502 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix()); | 553 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServicePosix()); |
503 } | 554 } |
504 | 555 |
505 } // namespace net | 556 } // namespace net |
OLD | NEW |