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

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

Issue 10873018: [net] Move DnsConfigService to NetworkChangeNotifier. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix null-dereference Created 8 years, 3 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_win.h" 5 #include "net/dns/dns_config_service_win.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
13 #include "base/files/file_path_watcher.h"
13 #include "base/file_path.h" 14 #include "base/file_path.h"
14 #include "base/logging.h" 15 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h" 16 #include "base/memory/scoped_ptr.h"
16 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
17 #include "base/string_split.h" 18 #include "base/string_split.h"
18 #include "base/string_util.h" 19 #include "base/string_util.h"
19 #include "base/synchronization/lock.h" 20 #include "base/synchronization/lock.h"
20 #include "base/threading/non_thread_safe.h" 21 #include "base/threading/non_thread_safe.h"
21 #include "base/threading/thread_restrictions.h" 22 #include "base/threading/thread_restrictions.h"
22 #include "base/time.h" 23 #include "base/time.h"
23 #include "base/utf_string_conversions.h" 24 #include "base/utf_string_conversions.h"
25 #include "base/win/object_watcher.h"
24 #include "base/win/registry.h" 26 #include "base/win/registry.h"
25 #include "base/win/windows_version.h" 27 #include "base/win/windows_version.h"
26 #include "googleurl/src/url_canon.h" 28 #include "googleurl/src/url_canon.h"
27 #include "net/base/net_util.h" 29 #include "net/base/net_util.h"
28 #include "net/base/network_change_notifier.h"
29 #include "net/dns/dns_hosts.h" 30 #include "net/dns/dns_hosts.h"
30 #include "net/dns/dns_protocol.h" 31 #include "net/dns/dns_protocol.h"
31 #include "net/dns/serial_worker.h" 32 #include "net/dns/serial_worker.h"
32 33
33 #pragma comment(lib, "iphlpapi.lib") 34 #pragma comment(lib, "iphlpapi.lib")
34 35
35 namespace net { 36 namespace net {
36 37
37 namespace internal { 38 namespace internal {
38 39
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address(); 266 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = ipe.address();
266 } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) { 267 } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) {
267 have_ipv6 = true; 268 have_ipv6 = true;
268 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address(); 269 (*hosts)[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = ipe.address();
269 } 270 }
270 } 271 }
271 } 272 }
272 return HOSTS_PARSE_WIN_OK; 273 return HOSTS_PARSE_WIN_OK;
273 } 274 }
274 275
276 // Watches a single registry key for changes.
277 class RegistryWatcher : public base::win::ObjectWatcher::Delegate,
278 public base::NonThreadSafe {
279 public:
280 typedef base::Callback<void(bool succeeded)> CallbackType;
281 RegistryWatcher() {}
282
283 bool Watch(const wchar_t* key, const CallbackType& callback) {
284 DCHECK(CalledOnValidThread());
285 DCHECK(!callback.is_null());
286 DCHECK(callback_.is_null());
287 callback_ = callback;
288 if (key_.Open(HKEY_LOCAL_MACHINE, key, KEY_NOTIFY) != ERROR_SUCCESS)
289 return false;
290 if (key_.StartWatching() != ERROR_SUCCESS)
291 return false;
292 if (!watcher_.StartWatching(key_.watch_event(), this))
293 return false;
294 return true;
295 }
296
297 virtual void OnObjectSignaled(HANDLE object) OVERRIDE {
298 DCHECK(CalledOnValidThread());
299 bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) &&
300 watcher_.StartWatching(key_.watch_event(), this);
301 if (!succeeded && key_.Valid()) {
302 watcher_.StopWatching();
303 key_.StopWatching();
304 key_.Close();
305 }
306 if (!callback_.is_null())
307 callback_.Run(succeeded);
308 }
309
310 private:
311 CallbackType callback_;
312 base::win::RegKey key_;
313 base::win::ObjectWatcher watcher_;
314
315 DISALLOW_COPY_AND_ASSIGN(RegistryWatcher);
316 };
317
275 } // namespace 318 } // namespace
276 319
277 FilePath GetHostsPath() { 320 FilePath GetHostsPath() {
278 TCHAR buffer[MAX_PATH]; 321 TCHAR buffer[MAX_PATH];
279 UINT rc = GetSystemDirectory(buffer, MAX_PATH); 322 UINT rc = GetSystemDirectory(buffer, MAX_PATH);
280 DCHECK(0 < rc && rc < MAX_PATH); 323 DCHECK(0 < rc && rc < MAX_PATH);
281 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); 324 return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts"));
282 } 325 }
283 326
284 bool ParseSearchList(const string16& value, std::vector<std::string>* output) { 327 bool ParseSearchList(const string16& value, std::vector<std::string>* output) {
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 unsigned num_dots = std::count(primary_suffix.begin(), 486 unsigned num_dots = std::count(primary_suffix.begin(),
444 primary_suffix.end(), '.'); 487 primary_suffix.end(), '.');
445 488
446 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) { 489 for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) {
447 offset = primary_suffix.find('.', offset + 1); 490 offset = primary_suffix.find('.', offset + 1);
448 config->search.push_back(primary_suffix.substr(offset + 1)); 491 config->search.push_back(primary_suffix.substr(offset + 1));
449 } 492 }
450 return CONFIG_PARSE_WIN_OK; 493 return CONFIG_PARSE_WIN_OK;
451 } 494 }
452 495
496 // Watches registry and HOSTS file for changes. Setting up watches requires
497 // IO loop.
mmenke 2012/08/28 15:18:40 nit: I think "Must live on a thread which allows
498 class DnsConfigServiceWin::Watcher {
499 public:
500 explicit Watcher(DnsConfigServiceWin* service) : service_(service) {}
501 ~Watcher() {}
502
503 bool Watch() {
504 RegistryWatcher::CallbackType callback =
505 base::Bind(&DnsConfigServiceWin::OnConfigChanged,
506 base::Unretained(service_));
507
508 bool success = true;
509
510 // The Tcpip key must be present.
511 if (!tcpip_watcher_.Watch(kTcpipPath, callback)) {
512 LOG(ERROR) << "DNS registry watch failed to start.";
513 success = false;
514 }
515
516 // Watch for IPv6 nameservers.
517 tcpip6_watcher_.Watch(kTcpip6Path, callback);
518
519 // DNS suffix search list and devolution can be configured via group
520 // policy which sets this registry key. If the key is missing, the policy
521 // does not apply, and the DNS client uses Tcpip and Dnscache settings.
522 // If a policy is installed, DnsConfigService will need to be restarted.
523 // BUG=99509
524
525 dnscache_watcher_.Watch(kDnscachePath, callback);
526 policy_watcher_.Watch(kPolicyPath, callback);
527
528 if (!hosts_watcher_.Watch(GetHostsPath(),
529 base::Bind(&Watcher::OnHostsChanged,
530 base::Unretained(this)))) {
531 LOG(ERROR) << "DNS hosts watch failed to start.";
532 success = false;
533 }
534 return success;
535 }
536
537 private:
538 void OnHostsChanged(const FilePath& path, bool error) {
539 service_->OnHostsChanged(!error);
540 }
541
542 DnsConfigServiceWin* service_;
543
544 RegistryWatcher tcpip_watcher_;
545 RegistryWatcher tcpip6_watcher_;
546 RegistryWatcher dnscache_watcher_;
547 RegistryWatcher policy_watcher_;
548 base::files::FilePathWatcher hosts_watcher_;
549
550 DISALLOW_COPY_AND_ASSIGN(Watcher);
551 };
552
453 // Reads config from registry and IpHelper. All work performed on WorkerPool. 553 // Reads config from registry and IpHelper. All work performed on WorkerPool.
454 class DnsConfigServiceWin::ConfigReader : public SerialWorker { 554 class DnsConfigServiceWin::ConfigReader : public SerialWorker {
455 public: 555 public:
456 explicit ConfigReader(DnsConfigServiceWin* service) 556 explicit ConfigReader(DnsConfigServiceWin* service)
457 : service_(service), 557 : service_(service),
458 success_(false) {} 558 success_(false) {}
459 559
460 private: 560 private:
461 virtual ~ConfigReader() {} 561 virtual ~ConfigReader() {}
462 562
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 const FilePath path_; 634 const FilePath path_;
535 DnsConfigServiceWin* service_; 635 DnsConfigServiceWin* service_;
536 // Written in DoWork, read in OnWorkFinished, no locking necessary. 636 // Written in DoWork, read in OnWorkFinished, no locking necessary.
537 DnsHosts hosts_; 637 DnsHosts hosts_;
538 bool success_; 638 bool success_;
539 639
540 DISALLOW_COPY_AND_ASSIGN(HostsReader); 640 DISALLOW_COPY_AND_ASSIGN(HostsReader);
541 }; 641 };
542 642
543 DnsConfigServiceWin::DnsConfigServiceWin() 643 DnsConfigServiceWin::DnsConfigServiceWin()
544 : config_reader_(new ConfigReader(this)), 644 : watcher_(new Watcher(this)),
645 config_reader_(new ConfigReader(this)),
545 hosts_reader_(new HostsReader(this)) {} 646 hosts_reader_(new HostsReader(this)) {}
546 647
547 DnsConfigServiceWin::~DnsConfigServiceWin() { 648 DnsConfigServiceWin::~DnsConfigServiceWin() {
548 config_reader_->Cancel(); 649 config_reader_->Cancel();
549 hosts_reader_->Cancel(); 650 hosts_reader_->Cancel();
550 NetworkChangeNotifier::RemoveIPAddressObserver(this); 651 NetworkChangeNotifier::RemoveIPAddressObserver(this);
551 } 652 }
552 653
553 void DnsConfigServiceWin::Watch(const CallbackType& callback) { 654 void DnsConfigServiceWin::ReadNow() {
554 DnsConfigService::Watch(callback); 655 config_reader_->WorkNow();
656 hosts_reader_->WorkNow();
657 }
658
659 bool DnsConfigServiceWin::StartWatching() {
555 // Also need to observe changes to local non-loopback IP for DnsHosts. 660 // Also need to observe changes to local non-loopback IP for DnsHosts.
556 NetworkChangeNotifier::AddIPAddressObserver(this); 661 NetworkChangeNotifier::AddIPAddressObserver(this);
557 } 662 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139
558 663 return watcher_->Watch();
559 void DnsConfigServiceWin::OnDNSChanged(unsigned detail) {
560 if (detail & NetworkChangeNotifier::CHANGE_DNS_WATCH_FAILED) {
561 InvalidateConfig();
562 InvalidateHosts();
563 // We don't trust a config that we cannot watch in the future.
564 config_reader_->Cancel();
565 hosts_reader_->Cancel();
566 return;
567 }
568 if (detail & NetworkChangeNotifier::CHANGE_DNS_WATCH_STARTED)
569 detail = ~0; // Assume everything changed.
570 if (detail & NetworkChangeNotifier::CHANGE_DNS_SETTINGS) {
571 InvalidateConfig();
572 config_reader_->WorkNow();
573 }
574 if (detail & NetworkChangeNotifier::CHANGE_DNS_HOSTS) {
575 InvalidateHosts();
576 hosts_reader_->WorkNow();
577 }
578 } 664 }
579 665
580 void DnsConfigServiceWin::OnIPAddressChanged() { 666 void DnsConfigServiceWin::OnIPAddressChanged() {
581 // Need to update non-loopback IP of local host. 667 // Need to update non-loopback IP of local host.
582 if (NetworkChangeNotifier::IsWatchingDNS()) 668 OnHostsChanged(true);
mmenke 2012/08/28 15:18:40 This seems a little weird. If the hosts_watcher_
szym 2012/08/28 23:14:38 Right, hence I RemoveIPAddressObserver in OnHostsC
mmenke 2012/08/29 16:31:20 But you don't stop watching if watcher_->Watch();
szym 2012/08/29 17:08:52 Right, I think having a broken Watcher makes every
mmenke 2012/08/29 17:55:45 Seems like we shouldn't start watching OnIPAddress
583 OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_HOSTS); 669 }
670
671 void DnsConfigServiceWin::OnConfigChanged(bool succeeded) {
672 InvalidateConfig();
673 if (succeeded) {
674 config_reader_->WorkNow();
675 } else {
676 LOG(ERROR) << "DNS config watch failed.";
677 // Don't trust the result if the watcher failed.
678 // Note: The SerialWorker will need to be re-constructed to accept new jobs.
679 config_reader_->Cancel();
680 }
681 }
682
683 void DnsConfigServiceWin::OnHostsChanged(bool succeeded) {
684 InvalidateHosts();
685 if (succeeded) {
686 hosts_reader_->WorkNow();
687 } else {
688 LOG(ERROR) << "DNS hosts watch failed.";
689 // Don't trust the result if the watcher failed.
690 // Note: The SerialWorker will need to be re-constructed to accept new jobs.
691 hosts_reader_->Cancel();
692 NetworkChangeNotifier::RemoveIPAddressObserver(this);
693 }
584 } 694 }
585 695
586 } // namespace internal 696 } // namespace internal
587 697
588 // static 698 // static
589 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { 699 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
590 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); 700 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin());
591 } 701 }
592 702
593 } // namespace net 703 } // namespace net
594 704
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698