Chromium Code Reviews| 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_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/file_path.h" | 13 #include "base/file_path.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
| 16 #include "base/string_split.h" | 16 #include "base/string_split.h" |
| 17 #include "base/string_util.h" | 17 #include "base/string_util.h" |
| 18 #include "base/synchronization/lock.h" | 18 #include "base/synchronization/lock.h" |
| 19 #include "base/threading/non_thread_safe.h" | |
| 19 #include "base/threading/thread_restrictions.h" | 20 #include "base/threading/thread_restrictions.h" |
| 20 #include "base/utf_string_conversions.h" | 21 #include "base/utf_string_conversions.h" |
| 21 #include "base/win/object_watcher.h" | 22 #include "base/win/object_watcher.h" |
| 22 #include "base/win/registry.h" | 23 #include "base/win/registry.h" |
| 23 #include "base/win/windows_version.h" | 24 #include "base/win/windows_version.h" |
| 24 #include "googleurl/src/url_canon.h" | 25 #include "googleurl/src/url_canon.h" |
| 25 #include "net/base/net_util.h" | 26 #include "net/base/net_util.h" |
| 26 #include "net/dns/dns_protocol.h" | 27 #include "net/dns/dns_protocol.h" |
| 27 #include "net/dns/file_path_watcher_wrapper.h" | 28 #include "net/dns/file_path_watcher_wrapper.h" |
| 28 #include "net/dns/serial_worker.h" | 29 #include "net/dns/serial_worker.h" |
| 29 | 30 |
| 30 #pragma comment(lib, "iphlpapi.lib") | 31 #pragma comment(lib, "iphlpapi.lib") |
| 31 | 32 |
| 32 namespace net { | 33 namespace net { |
| 33 | 34 |
| 34 namespace internal { | 35 namespace internal { |
| 35 | 36 |
| 36 namespace { | 37 namespace { |
| 37 | 38 |
| 38 // Watches a single registry key for changes. Thread-safe. | 39 // Registry key paths. |
| 39 class RegistryWatcher : public base::win::ObjectWatcher::Delegate { | 40 const wchar_t* const kTcpipPath = |
| 41 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; | |
| 42 const wchar_t* const kTcpip6Path = | |
| 43 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"; | |
| 44 const wchar_t* const kDnscachePath = | |
| 45 L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters"; | |
| 46 const wchar_t* const kPolicyPath = | |
| 47 L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient"; | |
| 48 | |
| 49 // Convenience for reading values using RegKey. | |
| 50 class RegistryReader : public base::NonThreadSafe { | |
| 40 public: | 51 public: |
| 41 typedef base::Callback<void(bool succeeded)> CallbackType; | 52 explicit RegistryReader(const wchar_t* key) { |
| 42 RegistryWatcher() {} | 53 // Ignoring the result. |key_.Valid()| will catch failures. |
| 43 | 54 key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); |
| 44 bool Watch(const wchar_t* key, const CallbackType& callback) { | |
| 45 base::AutoLock lock(lock_); | |
| 46 DCHECK(!callback.is_null()); | |
| 47 CancelLocked(); | |
| 48 if (key_.Open(HKEY_LOCAL_MACHINE, key, | |
| 49 KEY_NOTIFY | KEY_QUERY_VALUE) != ERROR_SUCCESS) | |
| 50 return false; | |
| 51 if (key_.StartWatching() != ERROR_SUCCESS) | |
| 52 return false; | |
| 53 if (!watcher_.StartWatching(key_.watch_event(), this)) | |
| 54 return false; | |
| 55 callback_ = callback; | |
| 56 return true; | |
| 57 } | |
| 58 | |
| 59 void Cancel() { | |
| 60 base::AutoLock lock(lock_); | |
| 61 CancelLocked(); | |
| 62 } | |
| 63 | |
| 64 virtual void OnObjectSignaled(HANDLE object) OVERRIDE { | |
| 65 base::AutoLock lock(lock_); | |
| 66 bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) && | |
| 67 watcher_.StartWatching(key_.watch_event(), this); | |
| 68 if (!callback_.is_null()) | |
| 69 callback_.Run(succeeded); | |
| 70 } | 55 } |
| 71 | 56 |
| 72 bool ReadString(const wchar_t* name, | 57 bool ReadString(const wchar_t* name, |
| 73 DnsSystemSettings::RegString* out) const { | 58 DnsSystemSettings::RegString* out) const { |
| 74 base::AutoLock lock(lock_); | 59 DCHECK(CalledOnValidThread()); |
| 75 out->set = false; | 60 out->set = false; |
| 76 if (!key_.Valid()) { | 61 if (!key_.Valid()) { |
| 77 // Assume that if the |key_| is invalid then the key is missing. | 62 // Assume that if the |key_| is invalid then the key is missing. |
| 78 return true; | 63 return true; |
| 79 } | 64 } |
| 80 LONG result = key_.ReadValue(name, &out->value); | 65 LONG result = key_.ReadValue(name, &out->value); |
| 81 if (result == ERROR_SUCCESS) { | 66 if (result == ERROR_SUCCESS) { |
| 82 out->set = true; | 67 out->set = true; |
| 83 return true; | 68 return true; |
| 84 } | 69 } |
| 85 return (result == ERROR_FILE_NOT_FOUND); | 70 return (result == ERROR_FILE_NOT_FOUND); |
| 86 } | 71 } |
| 87 | 72 |
| 88 bool ReadDword(const wchar_t* name, | 73 bool ReadDword(const wchar_t* name, |
| 89 DnsSystemSettings::RegDword* out) const { | 74 DnsSystemSettings::RegDword* out) const { |
| 90 base::AutoLock lock(lock_); | 75 DCHECK(CalledOnValidThread()); |
| 91 out->set = false; | 76 out->set = false; |
| 92 if (!key_.Valid()) { | 77 if (!key_.Valid()) { |
| 93 // Assume that if the |key_| is invalid then the key is missing. | 78 // Assume that if the |key_| is invalid then the key is missing. |
| 94 return true; | 79 return true; |
| 95 } | 80 } |
| 96 LONG result = key_.ReadValueDW(name, &out->value); | 81 LONG result = key_.ReadValueDW(name, &out->value); |
| 97 if (result == ERROR_SUCCESS) { | 82 if (result == ERROR_SUCCESS) { |
| 98 out->set = true; | 83 out->set = true; |
| 99 return true; | 84 return true; |
| 100 } | 85 } |
| 101 return (result == ERROR_FILE_NOT_FOUND); | 86 return (result == ERROR_FILE_NOT_FOUND); |
| 102 } | 87 } |
| 103 | 88 |
| 104 private: | 89 private: |
| 105 void CancelLocked() { | 90 base::win::RegKey key_; |
| 106 lock_.AssertAcquired(); | 91 |
| 92 DISALLOW_COPY_AND_ASSIGN(RegistryReader); | |
| 93 }; | |
| 94 | |
| 95 | |
| 96 // Watches a single registry key for changes. | |
| 97 class RegistryWatcher : public base::win::ObjectWatcher::Delegate, | |
| 98 public base::NonThreadSafe { | |
| 99 public: | |
| 100 typedef base::Callback<void(bool succeeded)> CallbackType; | |
| 101 RegistryWatcher() {} | |
| 102 | |
| 103 bool Watch(const wchar_t* key, const CallbackType& callback) { | |
| 104 DCHECK(CalledOnValidThread()); | |
| 105 DCHECK(!callback.is_null()); | |
| 106 Cancel(); | |
| 107 if (key_.Open(HKEY_LOCAL_MACHINE, key, KEY_NOTIFY) != ERROR_SUCCESS) | |
| 108 return false; | |
| 109 if (key_.StartWatching() != ERROR_SUCCESS) | |
| 110 return false; | |
| 111 if (!watcher_.StartWatching(key_.watch_event(), this)) | |
| 112 return false; | |
| 113 callback_ = callback; | |
| 114 return true; | |
| 115 } | |
| 116 | |
| 117 void Cancel() { | |
| 118 DCHECK(CalledOnValidThread()); | |
| 107 callback_.Reset(); | 119 callback_.Reset(); |
| 108 if (key_.Valid()) { | 120 if (key_.Valid()) { |
| 109 watcher_.StopWatching(); | 121 watcher_.StopWatching(); |
| 110 key_.StopWatching(); | 122 key_.StopWatching(); |
| 111 } | 123 } |
| 112 } | 124 } |
| 113 | 125 |
| 114 mutable base::Lock lock_; | 126 virtual void OnObjectSignaled(HANDLE object) OVERRIDE { |
| 127 DCHECK(CalledOnValidThread()); | |
| 128 bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) && | |
| 129 watcher_.StartWatching(key_.watch_event(), this); | |
|
mmenke
2012/03/19 15:18:01
nit: Think this should be indented one more space
| |
| 130 if (!callback_.is_null()) | |
| 131 callback_.Run(succeeded); | |
| 132 } | |
| 133 | |
| 134 private: | |
| 115 CallbackType callback_; | 135 CallbackType callback_; |
| 116 base::win::RegKey key_; | 136 base::win::RegKey key_; |
| 117 base::win::ObjectWatcher watcher_; | 137 base::win::ObjectWatcher watcher_; |
| 118 | 138 |
| 119 DISALLOW_COPY_AND_ASSIGN(RegistryWatcher); | 139 DISALLOW_COPY_AND_ASSIGN(RegistryWatcher); |
| 120 }; | 140 }; |
| 121 | 141 |
| 122 // Converts a string16 domain name to ASCII, possibly using punycode. | 142 // Converts a string16 domain name to ASCII, possibly using punycode. |
| 123 // Returns true if the conversion succeeds and output is not empty. In case of | 143 // Returns true if the conversion succeeds and output is not empty. In case of |
| 124 // failure, |domain| might become dirty. | 144 // failure, |domain| might become dirty. |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 316 : service_(service), | 336 : service_(service), |
| 317 success_(false) {} | 337 success_(false) {} |
| 318 | 338 |
| 319 bool Watch() { | 339 bool Watch() { |
| 320 DCHECK(loop()->BelongsToCurrentThread()); | 340 DCHECK(loop()->BelongsToCurrentThread()); |
| 321 | 341 |
| 322 RegistryWatcher::CallbackType callback = | 342 RegistryWatcher::CallbackType callback = |
| 323 base::Bind(&ConfigReader::OnChange, base::Unretained(this)); | 343 base::Bind(&ConfigReader::OnChange, base::Unretained(this)); |
| 324 | 344 |
| 325 // The Tcpip key must be present. | 345 // The Tcpip key must be present. |
| 326 if (!tcpip_watcher_.Watch( | 346 if (!tcpip_watcher_.Watch(kTcpipPath, callback)) |
| 327 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", | |
| 328 callback)) | |
| 329 return false; | 347 return false; |
| 330 | 348 |
| 331 // Watch for IPv6 nameservers. | 349 // Watch for IPv6 nameservers. |
| 332 tcpip6_watcher_.Watch( | 350 tcpip6_watcher_.Watch(kTcpip6Path, callback); |
| 333 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters", | |
| 334 callback); | |
| 335 | 351 |
| 336 // DNS suffix search list and devolution can be configured via group | 352 // DNS suffix search list and devolution can be configured via group |
| 337 // policy which sets this registry key. If the key is missing, the policy | 353 // policy which sets this registry key. If the key is missing, the policy |
| 338 // does not apply, and the DNS client uses Tcpip and Dnscache settings. | 354 // does not apply, and the DNS client uses Tcpip and Dnscache settings. |
| 339 // If a policy is installed, DnsConfigService will need to be restarted. | 355 // If a policy is installed, DnsConfigService will need to be restarted. |
| 340 // BUG=99509 | 356 // BUG=99509 |
| 341 | 357 |
| 342 dnscache_watcher_.Watch( | 358 dnscache_watcher_.Watch(kDnscachePath, callback); |
| 343 L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters", | 359 policy_watcher_.Watch(kPolicyPath, callback); |
| 344 callback); | |
| 345 | |
| 346 policy_watcher_.Watch( | |
| 347 L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient", | |
| 348 callback); | |
| 349 | 360 |
| 350 WorkNow(); | 361 WorkNow(); |
| 351 return true; | 362 return true; |
| 352 } | 363 } |
| 353 | 364 |
| 354 void Cancel() { | 365 void Cancel() { |
| 355 DCHECK(loop()->BelongsToCurrentThread()); | 366 DCHECK(loop()->BelongsToCurrentThread()); |
| 356 SerialWorker::Cancel(); | 367 SerialWorker::Cancel(); |
| 357 policy_watcher_.Cancel(); | 368 policy_watcher_.Cancel(); |
| 358 dnscache_watcher_.Cancel(); | 369 dnscache_watcher_.Cancel(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); | 402 (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); |
| 392 tries++) { | 403 tries++) { |
| 393 settings->addresses.reset( | 404 settings->addresses.reset( |
| 394 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); | 405 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); |
| 395 rv = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, | 406 rv = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, |
| 396 settings->addresses.get(), &len); | 407 settings->addresses.get(), &len); |
| 397 } | 408 } |
| 398 return (rv == NO_ERROR); | 409 return (rv == NO_ERROR); |
| 399 } | 410 } |
| 400 | 411 |
| 401 bool ReadDevolutionSetting(const RegistryWatcher& watcher, | 412 bool ReadDevolutionSetting(const RegistryReader& reader, |
| 402 DnsSystemSettings::DevolutionSetting& setting) { | 413 DnsSystemSettings::DevolutionSetting& setting) { |
| 403 return watcher.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && | 414 return reader.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && |
| 404 watcher.ReadDword(L"DomainNameDevolutionLevel", &setting.level); | 415 reader.ReadDword(L"DomainNameDevolutionLevel", &setting.level); |
| 405 } | 416 } |
| 406 | 417 |
| 407 virtual void DoWork() OVERRIDE { | 418 virtual void DoWork() OVERRIDE { |
| 408 // Should be called on WorkerPool. | 419 // Should be called on WorkerPool. |
| 409 success_ = false; | 420 success_ = false; |
| 410 | 421 |
| 411 DnsSystemSettings settings; | 422 DnsSystemSettings settings; |
| 412 memset(&settings, 0, sizeof(settings)); | 423 memset(&settings, 0, sizeof(settings)); |
| 413 if (!ReadIpHelper(&settings)) | 424 if (!ReadIpHelper(&settings)) |
| 414 return; // no point reading the rest | 425 return; // no point reading the rest |
| 415 | 426 |
| 416 if (!policy_watcher_.ReadString(L"SearchList", | 427 RegistryReader tcpip_reader(kTcpipPath); |
| 417 &settings.policy_search_list)) | 428 RegistryReader tcpip6_reader(kTcpip6Path); |
| 429 RegistryReader dnscache_reader(kDnscachePath); | |
| 430 RegistryReader policy_reader(kPolicyPath); | |
| 431 | |
| 432 if (!policy_reader.ReadString(L"SearchList", | |
| 433 &settings.policy_search_list)) | |
| 418 return; | 434 return; |
| 419 | 435 |
| 420 if (!tcpip_watcher_.ReadString(L"SearchList", &settings.tcpip_search_list)) | 436 if (!tcpip_reader.ReadString(L"SearchList", &settings.tcpip_search_list)) |
| 421 return; | 437 return; |
| 422 | 438 |
| 423 if (!tcpip_watcher_.ReadString(L"Domain", &settings.tcpip_domain)) | 439 if (!tcpip_reader.ReadString(L"Domain", &settings.tcpip_domain)) |
| 424 return; | 440 return; |
| 425 | 441 |
| 426 if (!ReadDevolutionSetting(policy_watcher_, settings.policy_devolution)) | 442 if (!ReadDevolutionSetting(policy_reader, settings.policy_devolution)) |
| 427 return; | 443 return; |
| 428 | 444 |
| 429 if (!ReadDevolutionSetting(dnscache_watcher_, | 445 if (!ReadDevolutionSetting(dnscache_reader, |
| 430 settings.dnscache_devolution)) | 446 settings.dnscache_devolution)) |
| 431 return; | 447 return; |
| 432 | 448 |
| 433 if (!ReadDevolutionSetting(tcpip_watcher_, settings.tcpip_devolution)) | 449 if (!ReadDevolutionSetting(tcpip_reader, settings.tcpip_devolution)) |
| 434 return; | 450 return; |
| 435 | 451 |
| 436 if (!policy_watcher_.ReadDword(L"AppendToMultiLabelName", | 452 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", |
| 437 &settings.append_to_multi_label_name)) | 453 &settings.append_to_multi_label_name)) |
| 438 return; | 454 return; |
| 439 | 455 |
| 440 success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); | 456 success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); |
| 441 } | 457 } |
| 442 | 458 |
| 443 virtual void OnWorkFinished() OVERRIDE { | 459 virtual void OnWorkFinished() OVERRIDE { |
| 444 DCHECK(loop()->BelongsToCurrentThread()); | 460 DCHECK(loop()->BelongsToCurrentThread()); |
| 445 DCHECK(!IsCancelled()); | 461 DCHECK(!IsCancelled()); |
| 446 if (success_) { | 462 if (success_) { |
| 447 service_->OnConfigRead(dns_config_); | 463 service_->OnConfigRead(dns_config_); |
| 448 } else { | 464 } else { |
| 449 LOG(WARNING) << "Failed to read config."; | 465 LOG(WARNING) << "Failed to read config."; |
| 450 } | 466 } |
| 451 } | 467 } |
| 452 | 468 |
| 453 DnsConfigServiceWin* service_; | 469 DnsConfigServiceWin* service_; |
| 454 // Written in DoRead(), read in OnReadFinished(). No locking required. | 470 // Written in DoRead(), read in OnReadFinished(). No locking required. |
| 455 DnsConfig dns_config_; | 471 DnsConfig dns_config_; |
| 456 bool success_; | 472 bool success_; |
| 457 | 473 |
| 458 RegistryWatcher tcpip_watcher_; | 474 RegistryWatcher tcpip_watcher_; |
| 459 RegistryWatcher tcpip6_watcher_; | 475 RegistryWatcher tcpip6_watcher_; |
| 460 RegistryWatcher dnscache_watcher_; | 476 RegistryWatcher dnscache_watcher_; |
| 461 RegistryWatcher policy_watcher_; | 477 RegistryWatcher policy_watcher_; |
| 462 }; | 478 }; |
| 463 | 479 |
| 480 | |
| 481 // An extension for DnsHostsReader which also reads local name from | |
| 482 // GetComputerNameEx and watches registry for changes to local name. | |
| 483 class DnsConfigServiceWin::HostsReader : public base::NonThreadSafe { | |
| 484 public: | |
| 485 explicit HostsReader(DnsConfigServiceWin* service) : service_(service) { | |
| 486 TCHAR buffer[MAX_PATH]; | |
| 487 UINT rc = GetSystemDirectory(buffer, MAX_PATH); | |
| 488 DCHECK(0 < rc && rc < MAX_PATH); | |
| 489 FilePath hosts_path = FilePath(buffer). | |
| 490 Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); | |
| 491 hosts_reader_ = new DnsHostsReader( | |
| 492 hosts_path, | |
| 493 base::Bind(&HostsReader::OnHostsRead, base::Unretained(this))); | |
| 494 } | |
| 495 | |
| 496 bool Watch() { | |
| 497 DCHECK(CalledOnValidThread()); | |
| 498 if (!hosts_watcher_.Watch(hosts_reader_->path(), | |
| 499 base::Bind(&HostsReader::OnHostsChanged, | |
| 500 base::Unretained(this)))) { | |
| 501 return false; | |
| 502 } | |
| 503 if (!registry_watcher_.Watch(kTcpipPath, | |
| 504 base::Bind(&HostsReader::OnNameChanged, | |
| 505 base::Unretained(this)))) { | |
|
mmenke
2012/03/19 15:18:01
nit: Indent this to the open paren, if it fits, s
| |
| 506 return false; | |
| 507 } | |
| 508 | |
| 509 hosts_reader_->WorkNow(); | |
| 510 return true; | |
| 511 } | |
| 512 | |
| 513 ~HostsReader() { | |
| 514 hosts_reader_->Cancel(); | |
| 515 } | |
| 516 | |
| 517 private: | |
| 518 void OnHostsChanged(bool succeeded) { | |
| 519 DCHECK(CalledOnValidThread()); | |
| 520 service_->InvalidateHosts(); | |
| 521 if (succeeded) | |
| 522 hosts_reader_->WorkNow(); | |
| 523 else | |
| 524 LOG(ERROR) << "Failed to watch DNS hosts"; | |
| 525 } | |
| 526 | |
| 527 void OnHostsRead(const DnsHosts& hosts) { | |
| 528 DCHECK(CalledOnValidThread()); | |
| 529 hosts_ = hosts; | |
| 530 UpdateService(); | |
| 531 } | |
| 532 | |
| 533 void OnNameChanged(bool succeeded) { | |
| 534 DCHECK(CalledOnValidThread()); | |
| 535 if (!succeeded) { | |
| 536 LOG(ERROR) << "Failed to watch local computer name"; | |
| 537 service_->InvalidateHosts(); | |
| 538 return; | |
| 539 } | |
| 540 WCHAR buffer[MAX_PATH]; | |
| 541 DWORD size = MAX_PATH; | |
| 542 std::string localname; | |
| 543 if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || | |
| 544 !ParseDomainASCII(buffer, &localname)) { | |
| 545 service_->InvalidateHosts(); | |
| 546 LOG(ERROR) << "Failed to read local computer name"; | |
| 547 return; | |
| 548 } | |
| 549 | |
| 550 if (localname != localname_) { | |
| 551 localname_ = localname; | |
| 552 UpdateService(); | |
|
mmenke
2012/03/19 15:18:01
What if the last call to OnHostsChanged failed?
S
| |
| 553 } | |
| 554 } | |
| 555 | |
| 556 void UpdateService() { | |
| 557 DCHECK(CalledOnValidThread()); | |
| 558 DnsHosts complete_hosts = hosts_; | |
| 559 | |
| 560 const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; | |
| 561 const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, | |
| 562 0, 0, 0, 0, 0, 0, 0, 1 }; | |
| 563 | |
| 564 complete_hosts[DnsHostsKey(localname_, ADDRESS_FAMILY_IPV4)] = | |
| 565 IPAddressNumber(kIPv4Localhost, | |
| 566 kIPv4Localhost + arraysize(kIPv4Localhost)); | |
| 567 complete_hosts[DnsHostsKey(localname_, ADDRESS_FAMILY_IPV6)] = | |
| 568 IPAddressNumber(kIPv6Localhost, | |
| 569 kIPv6Localhost + arraysize(kIPv6Localhost)); | |
| 570 service_->OnHostsRead(complete_hosts); | |
| 571 } | |
| 572 | |
| 573 DnsConfigServiceWin* service_; | |
| 574 FilePathWatcherWrapper hosts_watcher_; | |
| 575 RegistryWatcher registry_watcher_; | |
| 576 scoped_refptr<DnsHostsReader> hosts_reader_; | |
| 577 | |
| 578 // Contents of the HOSTS file. | |
| 579 DnsHosts hosts_; | |
| 580 // Local computer name in ASCII. | |
| 581 std::string localname_; | |
| 582 | |
| 583 DISALLOW_COPY_AND_ASSIGN(HostsReader); | |
| 584 }; | |
| 585 | |
| 586 | |
| 464 DnsConfigServiceWin::DnsConfigServiceWin() | 587 DnsConfigServiceWin::DnsConfigServiceWin() |
| 465 : config_reader_(new ConfigReader(this)), | 588 : config_reader_(new ConfigReader(this)), |
| 466 hosts_watcher_(new FilePathWatcherWrapper()) {} | 589 hosts_reader_(new HostsReader(this)) {} |
| 467 | 590 |
| 468 DnsConfigServiceWin::~DnsConfigServiceWin() { | 591 DnsConfigServiceWin::~DnsConfigServiceWin() { |
| 469 DCHECK(CalledOnValidThread()); | 592 DCHECK(CalledOnValidThread()); |
| 470 config_reader_->Cancel(); | 593 config_reader_->Cancel(); |
| 471 if (hosts_reader_) | |
| 472 hosts_reader_->Cancel(); | |
| 473 } | 594 } |
| 474 | 595 |
| 475 void DnsConfigServiceWin::Watch(const CallbackType& callback) { | 596 void DnsConfigServiceWin::Watch(const CallbackType& callback) { |
| 476 DCHECK(CalledOnValidThread()); | 597 DCHECK(CalledOnValidThread()); |
| 477 DCHECK(!callback.is_null()); | 598 DCHECK(!callback.is_null()); |
| 478 set_callback(callback); | 599 set_callback(callback); |
| 479 | 600 |
| 480 // This is done only once per lifetime so open the keys and file watcher | 601 // This is done only once per lifetime so open the keys and file watcher |
| 481 // handles on this thread. | 602 // handles on this thread. |
| 482 // TODO(szym): Should/can this be avoided? http://crbug.com/114223 | 603 // TODO(szym): Should/can this be avoided? http://crbug.com/114223 |
| 483 base::ThreadRestrictions::ScopedAllowIO allow_io; | 604 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 484 | 605 |
| 485 if (!config_reader_->Watch()) { | 606 if (!config_reader_->Watch()) { |
| 486 LOG(ERROR) << "Failed to start watching DNS config"; | 607 LOG(ERROR) << "Failed to start watching DNS config"; |
| 487 InvalidateConfig(); | 608 InvalidateConfig(); |
| 488 } | 609 } |
| 489 | 610 |
| 490 TCHAR buffer[MAX_PATH]; | 611 if (!hosts_reader_->Watch()) { |
| 491 UINT rc = GetSystemDirectory(buffer, MAX_PATH); | 612 LOG(ERROR) << "Failed to start watching HOSTS"; |
| 492 DCHECK(0 < rc && rc < MAX_PATH); | 613 InvalidateHosts(); |
| 493 FilePath hosts_path = FilePath(buffer). | |
| 494 Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); | |
| 495 hosts_reader_ = new DnsHostsReader( | |
| 496 hosts_path, | |
| 497 base::Bind(&DnsConfigServiceWin::OnHostsRead, base::Unretained(this))); | |
| 498 if (hosts_watcher_->Watch(hosts_path, | |
| 499 base::Bind(&DnsConfigServiceWin::OnHostsChanged, | |
| 500 base::Unretained(this)))) { | |
| 501 OnHostsChanged(true); | |
| 502 } else { | |
| 503 OnHostsChanged(false); | |
| 504 } | 614 } |
| 505 } | 615 } |
| 506 | 616 |
| 507 void DnsConfigServiceWin::OnHostsChanged(bool succeeded) { | |
| 508 InvalidateHosts(); | |
| 509 if (succeeded) | |
| 510 hosts_reader_->WorkNow(); | |
| 511 else | |
| 512 LOG(ERROR) << "Failed to watch DNS hosts"; | |
| 513 } | |
| 514 | 617 |
|
mmenke
2012/03/19 15:18:01
nit: Remove extra blank line.
| |
| 515 } // namespace internal | 618 } // namespace internal |
| 516 | 619 |
| 517 // static | 620 // static |
| 518 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 621 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
| 519 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); | 622 return scoped_ptr<DnsConfigService>(new internal::DnsConfigServiceWin()); |
| 520 } | 623 } |
| 521 | 624 |
| 522 } // namespace net | 625 } // namespace net |
| 523 | 626 |
| OLD | NEW |