diff options
author | szym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-23 16:17:06 +0000 |
---|---|---|
committer | szym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-23 16:17:06 +0000 |
commit | cb5076276c9336a7616954739a44c274a28d45cc (patch) | |
tree | db5ae9a75244b1c998100b7271ac491625e03525 /net | |
parent | 137d52caea690b8d256f2cd4534edc25c3dcc42d (diff) | |
download | chromium_src-cb5076276c9336a7616954739a44c274a28d45cc.zip chromium_src-cb5076276c9336a7616954739a44c274a28d45cc.tar.gz chromium_src-cb5076276c9336a7616954739a44c274a28d45cc.tar.bz2 |
[net/dns] Removes locking from DnsConfigServiceWin and adds local computer name.
Also adds hostname normalization to lower case when resolving from HOSTS.
BUG=112907, 118412, 118995
TEST=./net_unittests --gtest_filter=DnsConfigService*
Review URL: http://codereview.chromium.org/9721002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@128498 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/host_resolver_impl.cc | 8 | ||||
-rw-r--r-- | net/base/host_resolver_impl_unittest.cc | 5 | ||||
-rw-r--r-- | net/dns/dns_config_service.cc | 12 | ||||
-rw-r--r-- | net/dns/dns_config_service.h | 3 | ||||
-rw-r--r-- | net/dns/dns_config_service_win.cc | 386 | ||||
-rw-r--r-- | net/dns/dns_config_service_win.h | 6 | ||||
-rw-r--r-- | net/dns/dns_hosts.cc | 10 | ||||
-rw-r--r-- | net/dns/dns_hosts.h | 5 | ||||
-rw-r--r-- | net/dns/dns_hosts_unittest.cc | 4 | ||||
-rw-r--r-- | net/dns/file_path_watcher_wrapper.h | 6 | ||||
-rw-r--r-- | net/dns/serial_worker.cc | 7 | ||||
-rw-r--r-- | net/dns/serial_worker.h | 3 |
12 files changed, 326 insertions, 129 deletions
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc index e890222..696617e 100644 --- a/net/base/host_resolver_impl.cc +++ b/net/base/host_resolver_impl.cc @@ -1759,7 +1759,6 @@ bool HostResolverImpl::ServeFromCache(const Key& key, if (!cache_entry) return false; - *net_error = cache_entry->error; if (*net_error == OK) *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port()); @@ -1773,13 +1772,16 @@ bool HostResolverImpl::ServeFromHosts(const Key& key, if (!HaveDnsConfig()) return false; + // HOSTS lookups are case-insensitive. + std::string hostname = StringToLowerASCII(key.hostname); + // If |address_family| is ADDRESS_FAMILY_UNSPECIFIED other implementations // (glibc and c-ares) return the first matching line. We have more // flexibility, but lose implicit ordering. // TODO(szym) http://crbug.com/117850 const DnsHosts& hosts = dns_client_->GetConfig()->hosts; DnsHosts::const_iterator it = hosts.find( - DnsHostsKey(key.hostname, + DnsHostsKey(hostname, key.address_family == ADDRESS_FAMILY_UNSPECIFIED ? ADDRESS_FAMILY_IPV4 : key.address_family)); @@ -1787,7 +1789,7 @@ bool HostResolverImpl::ServeFromHosts(const Key& key, if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED) return false; - it = hosts.find(DnsHostsKey(key.hostname, ADDRESS_FAMILY_IPV6)); + it = hosts.find(DnsHostsKey(hostname, ADDRESS_FAMILY_IPV6)); if (it == hosts.end()) return false; } diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc index 3ea7d04..eff34a7 100644 --- a/net/base/host_resolver_impl_unittest.cc +++ b/net/base/host_resolver_impl_unittest.cc @@ -1928,6 +1928,11 @@ TEST_F(HostResolverImplTest, ServeFromHosts) { if (ipv6string != "UNSUPPORTED") EXPECT_EQ("[::1]:80", ipv6string); EXPECT_EQ(1u, NumberOfAddresses(req6.addrlist())); + + // Request with upper case. + ResolveRequest req7(host_resolver.get(), "er_IPV4", 80); + EXPECT_EQ(OK, req7.result()); + EXPECT_EQ("127.0.0.1:80", FirstAddressToString(req7.addrlist())); } } // namespace net diff --git a/net/dns/dns_config_service.cc b/net/dns/dns_config_service.cc index be48d2a..bd42b64 100644 --- a/net/dns/dns_config_service.cc +++ b/net/dns/dns_config_service.cc @@ -100,7 +100,18 @@ void DnsConfigService::OnHostsRead(const DnsHosts& hosts) { void DnsConfigService::StartTimer() { DCHECK(CalledOnValidThread()); timer_.Stop(); + + // Give it a short timeout to come up with a valid config. Otherwise withdraw + // the config from the receiver. The goal is to avoid perceivable network + // outage (when using the wrong config) but at the same time avoid + // unnecessary Job aborts in HostResolverImpl. The signals come from multiple + // sources so it might receive multiple events during a config change. + + // DHCP and user-induced changes are on the order of seconds, so 100ms should + // not add perceivable delay. On the other hand, config readers should finish + // within 100ms with the rare exception of I/O block or extra large HOSTS. const base::TimeDelta kTimeout = base::TimeDelta::FromMilliseconds(100); + timer_.Start(FROM_HERE, kTimeout, this, @@ -112,6 +123,7 @@ void DnsConfigService::OnTimeout() { // Indicate that even if there is no change in On*Read, we will need to // update the receiver when the config becomes complete. need_update_ = true; + // Empty config is considered invalid. callback_.Run(DnsConfig()); } diff --git a/net/dns/dns_config_service.h b/net/dns/dns_config_service.h index cdbdb40..e5794c2 100644 --- a/net/dns/dns_config_service.h +++ b/net/dns/dns_config_service.h @@ -68,8 +68,7 @@ struct NET_EXPORT_PRIVATE DnsConfig { class NET_EXPORT_PRIVATE DnsConfigService : NON_EXPORTED_BASE(public base::NonThreadSafe) { public: - // Callback interface for the client. The observer is called on the same - // thread as Watch(). Observer must outlive the service. + // Callback interface for the client, called on the same thread as Watch(). typedef base::Callback<void(const DnsConfig& config)> CallbackType; // Creates the platform-specific DnsConfigService. diff --git a/net/dns/dns_config_service_win.cc b/net/dns/dns_config_service_win.cc index 047b92d..5e7a530 100644 --- a/net/dns/dns_config_service_win.cc +++ b/net/dns/dns_config_service_win.cc @@ -16,6 +16,7 @@ #include "base/string_split.h" #include "base/string_util.h" #include "base/synchronization/lock.h" +#include "base/threading/non_thread_safe.h" #include "base/threading/thread_restrictions.h" #include "base/utf_string_conversions.h" #include "base/win/object_watcher.h" @@ -23,6 +24,7 @@ #include "base/win/windows_version.h" #include "googleurl/src/url_canon.h" #include "net/base/net_util.h" +#include "net/base/network_change_notifier.h" #include "net/dns/dns_protocol.h" #include "net/dns/file_path_watcher_wrapper.h" #include "net/dns/serial_worker.h" @@ -35,43 +37,27 @@ namespace internal { namespace { -// Watches a single registry key for changes. Thread-safe. -class RegistryWatcher : public base::win::ObjectWatcher::Delegate { +// Registry key paths. +const wchar_t* const kTcpipPath = + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"; +const wchar_t* const kTcpip6Path = + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"; +const wchar_t* const kDnscachePath = + L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters"; +const wchar_t* const kPolicyPath = + L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient"; + +// Convenience for reading values using RegKey. +class RegistryReader : public base::NonThreadSafe { public: - typedef base::Callback<void(bool succeeded)> CallbackType; - RegistryWatcher() {} - - bool Watch(const wchar_t* key, const CallbackType& callback) { - base::AutoLock lock(lock_); - DCHECK(!callback.is_null()); - CancelLocked(); - if (key_.Open(HKEY_LOCAL_MACHINE, key, - KEY_NOTIFY | KEY_QUERY_VALUE) != ERROR_SUCCESS) - return false; - if (key_.StartWatching() != ERROR_SUCCESS) - return false; - if (!watcher_.StartWatching(key_.watch_event(), this)) - return false; - callback_ = callback; - return true; - } - - void Cancel() { - base::AutoLock lock(lock_); - CancelLocked(); - } - - virtual void OnObjectSignaled(HANDLE object) OVERRIDE { - base::AutoLock lock(lock_); - bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) && - watcher_.StartWatching(key_.watch_event(), this); - if (!callback_.is_null()) - callback_.Run(succeeded); + explicit RegistryReader(const wchar_t* key) { + // Ignoring the result. |key_.Valid()| will catch failures. + key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE); } bool ReadString(const wchar_t* name, DnsSystemSettings::RegString* out) const { - base::AutoLock lock(lock_); + DCHECK(CalledOnValidThread()); out->set = false; if (!key_.Valid()) { // Assume that if the |key_| is invalid then the key is missing. @@ -87,7 +73,7 @@ class RegistryWatcher : public base::win::ObjectWatcher::Delegate { bool ReadDword(const wchar_t* name, DnsSystemSettings::RegDword* out) const { - base::AutoLock lock(lock_); + DCHECK(CalledOnValidThread()); out->set = false; if (!key_.Valid()) { // Assume that if the |key_| is invalid then the key is missing. @@ -102,16 +88,60 @@ class RegistryWatcher : public base::win::ObjectWatcher::Delegate { } private: - void CancelLocked() { - lock_.AssertAcquired(); + base::win::RegKey key_; + + DISALLOW_COPY_AND_ASSIGN(RegistryReader); +}; + + +// Watches a single registry key for changes. +class RegistryWatcher : public base::win::ObjectWatcher::Delegate, + public base::NonThreadSafe { + public: + typedef base::Callback<void(bool succeeded)> CallbackType; + RegistryWatcher() {} + + bool Watch(const wchar_t* key, const CallbackType& callback) { + DCHECK(CalledOnValidThread()); + DCHECK(!callback.is_null()); + Cancel(); + if (key_.Open(HKEY_LOCAL_MACHINE, key, KEY_NOTIFY) != ERROR_SUCCESS) + return false; + if (key_.StartWatching() != ERROR_SUCCESS) + return false; + if (!watcher_.StartWatching(key_.watch_event(), this)) + return false; + callback_ = callback; + return true; + } + + bool IsWatching() const { + DCHECK(CalledOnValidThread()); + return !callback_.is_null(); + } + + void Cancel() { + DCHECK(CalledOnValidThread()); callback_.Reset(); if (key_.Valid()) { watcher_.StopWatching(); key_.StopWatching(); + key_.Close(); } } - mutable base::Lock lock_; + virtual void OnObjectSignaled(HANDLE object) OVERRIDE { + DCHECK(CalledOnValidThread()); + bool succeeded = (key_.StartWatching() == ERROR_SUCCESS) && + watcher_.StartWatching(key_.watch_event(), this); + CallbackType callback = callback_; + if (!succeeded) + Cancel(); + if (!callback.is_null()) + callback.Run(succeeded); + } + + private: CallbackType callback_; base::win::RegKey key_; base::win::ObjectWatcher watcher_; @@ -119,6 +149,24 @@ class RegistryWatcher : public base::win::ObjectWatcher::Delegate { DISALLOW_COPY_AND_ASSIGN(RegistryWatcher); }; +// Returns NULL if failed. +scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> ReadIpHelper(ULONG flags) { + base::ThreadRestrictions::AssertIOAllowed(); + + scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> out; + ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. + UINT rv = ERROR_BUFFER_OVERFLOW; + // Try up to three times. + for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); + tries++) { + out.reset(reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); + rv = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, out.get(), &len); + } + if (rv != NO_ERROR) + out.reset(); + return out.Pass(); +} + // Converts a string16 domain name to ASCII, possibly using punycode. // Returns true if the conversion succeeds and output is not empty. In case of // failure, |domain| might become dirty. @@ -323,15 +371,11 @@ class DnsConfigServiceWin::ConfigReader : public SerialWorker { base::Bind(&ConfigReader::OnChange, base::Unretained(this)); // The Tcpip key must be present. - if (!tcpip_watcher_.Watch( - L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", - callback)) + if (!tcpip_watcher_.Watch(kTcpipPath, callback)) return false; // Watch for IPv6 nameservers. - tcpip6_watcher_.Watch( - L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters", - callback); + tcpip6_watcher_.Watch(kTcpip6Path, callback); // DNS suffix search list and devolution can be configured via group // policy which sets this registry key. If the key is missing, the policy @@ -339,13 +383,8 @@ class DnsConfigServiceWin::ConfigReader : public SerialWorker { // If a policy is installed, DnsConfigService will need to be restarted. // BUG=99509 - dnscache_watcher_.Watch( - L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters", - callback); - - policy_watcher_.Watch( - L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient", - callback); + dnscache_watcher_.Watch(kDnscachePath, callback); + policy_watcher_.Watch(kPolicyPath, callback); WorkNow(); return true; @@ -377,31 +416,10 @@ class DnsConfigServiceWin::ConfigReader : public SerialWorker { LOG(ERROR) << "Failed to watch DNS config"; } - bool ReadIpHelper(DnsSystemSettings* settings) { - base::ThreadRestrictions::AssertIOAllowed(); - - ULONG flags = GAA_FLAG_SKIP_ANYCAST | - GAA_FLAG_SKIP_UNICAST | - GAA_FLAG_SKIP_MULTICAST | - GAA_FLAG_SKIP_FRIENDLY_NAME; - ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses. - UINT rv = ERROR_BUFFER_OVERFLOW; - // Try up to three times. - for (unsigned tries = 0; - (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW); - tries++) { - settings->addresses.reset( - reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(len))); - rv = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, - settings->addresses.get(), &len); - } - return (rv == NO_ERROR); - } - - bool ReadDevolutionSetting(const RegistryWatcher& watcher, + bool ReadDevolutionSetting(const RegistryReader& reader, DnsSystemSettings::DevolutionSetting& setting) { - return watcher.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && - watcher.ReadDword(L"DomainNameDevolutionLevel", &setting.level); + return reader.ReadDword(L"UseDomainNameDevolution", &setting.enabled) && + reader.ReadDword(L"DomainNameDevolutionLevel", &setting.level); } virtual void DoWork() OVERRIDE { @@ -410,31 +428,40 @@ class DnsConfigServiceWin::ConfigReader : public SerialWorker { DnsSystemSettings settings; memset(&settings, 0, sizeof(settings)); - if (!ReadIpHelper(&settings)) + settings.addresses = ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_UNICAST | + GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_FRIENDLY_NAME); + if (!settings.addresses.get()) return; // no point reading the rest - if (!policy_watcher_.ReadString(L"SearchList", - &settings.policy_search_list)) + RegistryReader tcpip_reader(kTcpipPath); + RegistryReader tcpip6_reader(kTcpip6Path); + RegistryReader dnscache_reader(kDnscachePath); + RegistryReader policy_reader(kPolicyPath); + + if (!policy_reader.ReadString(L"SearchList", + &settings.policy_search_list)) return; - if (!tcpip_watcher_.ReadString(L"SearchList", &settings.tcpip_search_list)) + if (!tcpip_reader.ReadString(L"SearchList", &settings.tcpip_search_list)) return; - if (!tcpip_watcher_.ReadString(L"Domain", &settings.tcpip_domain)) + if (!tcpip_reader.ReadString(L"Domain", &settings.tcpip_domain)) return; - if (!ReadDevolutionSetting(policy_watcher_, settings.policy_devolution)) + if (!ReadDevolutionSetting(policy_reader, settings.policy_devolution)) return; - if (!ReadDevolutionSetting(dnscache_watcher_, + if (!ReadDevolutionSetting(dnscache_reader, settings.dnscache_devolution)) return; - if (!ReadDevolutionSetting(tcpip_watcher_, settings.tcpip_devolution)) + if (!ReadDevolutionSetting(tcpip_reader, settings.tcpip_devolution)) return; - if (!policy_watcher_.ReadDword(L"AppendToMultiLabelName", - &settings.append_to_multi_label_name)) + if (!policy_reader.ReadDword(L"AppendToMultiLabelName", + &settings.append_to_multi_label_name)) return; success_ = ConvertSettingsToDnsConfig(settings, &dns_config_); @@ -461,15 +488,177 @@ class DnsConfigServiceWin::ConfigReader : public SerialWorker { RegistryWatcher policy_watcher_; }; +FilePath GetHostsPath() { + TCHAR buffer[MAX_PATH]; + UINT rc = GetSystemDirectory(buffer, MAX_PATH); + DCHECK(0 < rc && rc < MAX_PATH); + return FilePath(buffer).Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); +} + +// An extension for DnsHostsReader which also watches the HOSTS file, +// reads local name from GetComputerNameEx, local IP from GetAdaptersAddresses, +// and observes changes to local IP address. +class DnsConfigServiceWin::HostsReader + : public DnsHostsReader, + public NetworkChangeNotifier::IPAddressObserver { + public: + explicit HostsReader(DnsConfigServiceWin* service) + : DnsHostsReader(GetHostsPath()), service_(service) { + } + + bool Watch() { + DCHECK(loop()->BelongsToCurrentThread()); + DCHECK(!IsCancelled()); + + // In case the reader is restarted, remove it from the observer list. + NetworkChangeNotifier::RemoveIPAddressObserver(this); + + if (!hosts_watcher_.Watch(path(), + base::Bind(&HostsReader::OnHostsChanged, + base::Unretained(this)))) { + return false; + } + NetworkChangeNotifier::AddIPAddressObserver(this); + WorkNow(); + return true; + } + + // Cancels the underlying SerialWorker. Cannot be undone. + void Cancel() { + DnsHostsReader::Cancel(); + hosts_watcher_.Cancel(); + NetworkChangeNotifier::RemoveIPAddressObserver(this); + } + + private: + virtual void OnIPAddressChanged() OVERRIDE { + DCHECK(loop()->BelongsToCurrentThread()); + service_->InvalidateHosts(); + if (!hosts_watcher_.IsWatching()) + return; + WorkNow(); + } + + void OnHostsChanged(bool succeeded) { + DCHECK(loop()->BelongsToCurrentThread()); + service_->InvalidateHosts(); + if (succeeded) + WorkNow(); + else + LOG(ERROR) << "Failed to watch DNS hosts"; + } + + virtual void DoWork() OVERRIDE { + DnsHostsReader::DoWork(); + + if (!success_) + return; + + success_ = false; + + // Default address of "localhost" and local computer name can be overridden + // by the HOSTS file, but if it's not there, then we need to fill it in. + + const unsigned char kIPv4Localhost[] = { 127, 0, 0, 1 }; + const unsigned char kIPv6Localhost[] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1 }; + IPAddressNumber loopback_ipv4(kIPv4Localhost, + kIPv4Localhost + arraysize(kIPv4Localhost)); + IPAddressNumber loopback_ipv6(kIPv6Localhost, + kIPv6Localhost + arraysize(kIPv6Localhost)); + + // This does not override any pre-existing entries from the HOSTS file. + dns_hosts_.insert( + std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), + loopback_ipv4)); + dns_hosts_.insert( + std::make_pair(DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), + loopback_ipv6)); + + WCHAR buffer[MAX_PATH]; + DWORD size = MAX_PATH; + std::string localname; + if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size) || + !ParseDomainASCII(buffer, &localname)) { + LOG(ERROR) << "Failed to read local computer name"; + return; + } + StringToLowerASCII(&localname); + + bool have_ipv4 = + dns_hosts_.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0; + bool have_ipv6 = + dns_hosts_.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0; + + if (have_ipv4 && have_ipv6) { + success_ = true; + return; + } + + scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> addresses = + ReadIpHelper(GAA_FLAG_SKIP_ANYCAST | + GAA_FLAG_SKIP_DNS_SERVER | + GAA_FLAG_SKIP_MULTICAST | + GAA_FLAG_SKIP_FRIENDLY_NAME); + if (!addresses.get()) + return; + + // The order of adapters is the network binding order, so stick to the + // first good adapter for each family. + for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get(); + adapter != NULL && (!have_ipv4 || !have_ipv6); + adapter = adapter->Next) { + if (adapter->OperStatus != IfOperStatusUp) + continue; + if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) + continue; + + for (const IP_ADAPTER_UNICAST_ADDRESS* address = + adapter->FirstUnicastAddress; + address != NULL; + address = address->Next) { + IPEndPoint ipe; + if (!ipe.FromSockAddr(address->Address.lpSockaddr, + address->Address.iSockaddrLength)) { + return; + } + if (!have_ipv4 && (ipe.GetFamily() == AF_INET)) { + have_ipv4 = true; + dns_hosts_[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] = + ipe.address(); + } else if (!have_ipv6 && (ipe.GetFamily() == AF_INET6)) { + have_ipv6 = true; + dns_hosts_[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] = + ipe.address(); + } + } + } + + success_ = true; + } + + virtual void OnWorkFinished() OVERRIDE { + DCHECK(loop()->BelongsToCurrentThread()); + if (!success_ || !hosts_watcher_.IsWatching()) + return; + service_->OnHostsRead(dns_hosts_); + } + + DnsConfigServiceWin* service_; + FilePathWatcherWrapper hosts_watcher_; + + DISALLOW_COPY_AND_ASSIGN(HostsReader); +}; + + DnsConfigServiceWin::DnsConfigServiceWin() : config_reader_(new ConfigReader(this)), - hosts_watcher_(new FilePathWatcherWrapper()) {} + hosts_reader_(new HostsReader(this)) {} DnsConfigServiceWin::~DnsConfigServiceWin() { DCHECK(CalledOnValidThread()); config_reader_->Cancel(); - if (hosts_reader_) - hosts_reader_->Cancel(); + hosts_reader_->Cancel(); } void DnsConfigServiceWin::Watch(const CallbackType& callback) { @@ -487,31 +676,12 @@ void DnsConfigServiceWin::Watch(const CallbackType& callback) { InvalidateConfig(); } - TCHAR buffer[MAX_PATH]; - UINT rc = GetSystemDirectory(buffer, MAX_PATH); - DCHECK(0 < rc && rc < MAX_PATH); - FilePath hosts_path = FilePath(buffer). - Append(FILE_PATH_LITERAL("drivers\\etc\\hosts")); - hosts_reader_ = new DnsHostsReader( - hosts_path, - base::Bind(&DnsConfigServiceWin::OnHostsRead, base::Unretained(this))); - if (hosts_watcher_->Watch(hosts_path, - base::Bind(&DnsConfigServiceWin::OnHostsChanged, - base::Unretained(this)))) { - OnHostsChanged(true); - } else { - OnHostsChanged(false); + if (!hosts_reader_->Watch()) { + LOG(ERROR) << "Failed to start watching HOSTS"; + InvalidateHosts(); } } -void DnsConfigServiceWin::OnHostsChanged(bool succeeded) { - InvalidateHosts(); - if (succeeded) - hosts_reader_->WorkNow(); - else - LOG(ERROR) << "Failed to watch DNS hosts"; -} - } // namespace internal // static diff --git a/net/dns/dns_config_service_win.h b/net/dns/dns_config_service_win.h index 3159f77..0d75d9f 100644 --- a/net/dns/dns_config_service_win.h +++ b/net/dns/dns_config_service_win.h @@ -48,12 +48,10 @@ class NET_EXPORT_PRIVATE DnsConfigServiceWin private: class ConfigReader; - - void OnHostsChanged(bool succeeded); + class HostsReader; scoped_refptr<ConfigReader> config_reader_; - scoped_ptr<FilePathWatcherWrapper> hosts_watcher_; - scoped_refptr<SerialWorker> hosts_reader_; + scoped_refptr<HostsReader> hosts_reader_; DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceWin); }; diff --git a/net/dns/dns_hosts.cc b/net/dns/dns_hosts.cc index bd46912..bfd216c 100644 --- a/net/dns/dns_hosts.cc +++ b/net/dns/dns_hosts.cc @@ -7,6 +7,7 @@ #include "base/file_util.h" #include "base/logging.h" #include "base/string_tokenizer.h" +#include "base/string_util.h" namespace net { @@ -34,7 +35,9 @@ void ParseHosts(const std::string& contents, DnsHosts* dns_hosts) { AddressFamily fam = (ip.size() == 4) ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6; while (tokens.GetNext()) { - IPAddressNumber& mapped_ip = hosts[DnsHostsKey(tokens.token(), fam)]; + DnsHostsKey key(tokens.token(), fam); + StringToLowerASCII(&(key.first)); + IPAddressNumber& mapped_ip = hosts[key]; if (mapped_ip.empty()) mapped_ip = ip; // else ignore this entry (first hit counts) @@ -52,6 +55,11 @@ DnsHostsReader::DnsHostsReader(const FilePath& path, DCHECK(!callback.is_null()); } +DnsHostsReader::DnsHostsReader(const FilePath& path) + : path_(path), + success_(false) { +} + // Reads the contents of the file at |path| into |str| if the total length is // less than |max_size|. static bool ReadFile(const FilePath& path, int64 max_size, std::string* str) { diff --git a/net/dns/dns_hosts.h b/net/dns/dns_hosts.h index 91c35ba..5349ab5 100644 --- a/net/dns/dns_hosts.h +++ b/net/dns/dns_hosts.h @@ -48,7 +48,10 @@ class NET_EXPORT_PRIVATE DnsHostsReader DnsHostsReader(const FilePath& path, const CallbackType& callback); - private: + const FilePath& path() const { return path_; } + + protected: + explicit DnsHostsReader(const FilePath& path); virtual ~DnsHostsReader(); virtual void DoWork() OVERRIDE; diff --git a/net/dns/dns_hosts_unittest.cc b/net/dns/dns_hosts_unittest.cc index 6da41a9..f9ee294 100644 --- a/net/dns/dns_hosts_unittest.cc +++ b/net/dns/dns_hosts_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -18,7 +18,7 @@ TEST(DnsHostsTest, ParseHosts) { "fe00::x example company # ignored, malformed IPv6\n" "1.0.0.300 company # ignored, malformed IPv4\n" "1.0.0.1 # ignored, missing hostname\n" - "1.0.0.1\t company \n" + "1.0.0.1\t CoMpANy # normalized to 'company' \n" "::1\tlocalhost ip6-localhost ip6-loopback # comment # within a comment\n" "\t fe00::0 ip6-localnet\r\n" "2048::2 example\n" diff --git a/net/dns/file_path_watcher_wrapper.h b/net/dns/file_path_watcher_wrapper.h index 172bbaf65..2a5a776 100644 --- a/net/dns/file_path_watcher_wrapper.h +++ b/net/dns/file_path_watcher_wrapper.h @@ -34,10 +34,8 @@ class NET_EXPORT FilePathWatcherWrapper virtual ~FilePathWatcherWrapper(); // Starts watching the file at |path|. Returns true if Watch succeeds. - // If so, the delegate will call callback.Run(true) from OnFilePathChanged and - // callback.Run(false) from OnFilePathError. After failure the watch is - // cancelled and will have to be restarted. If called again, the previous - // watch is cancelled. + // If so, |callback| will be called with true on change and false on error. + // After failure the watch is cancelled and will have to be restarted. bool Watch(const FilePath& path, const base::Callback<void(bool succeeded)>& callback); diff --git a/net/dns/serial_worker.cc b/net/dns/serial_worker.cc index d2e42c0..60040a6 100644 --- a/net/dns/serial_worker.cc +++ b/net/dns/serial_worker.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,6 +11,11 @@ namespace net { +namespace { + // Delay between calls to WorkerPool::PostTask + const int kWorkerPoolRetryDelayMs = 100; +} + SerialWorker::SerialWorker() : message_loop_(base::MessageLoopProxy::current()), state_(IDLE) {} diff --git a/net/dns/serial_worker.h b/net/dns/serial_worker.h index 41ca768..b4bfe54 100644 --- a/net/dns/serial_worker.h +++ b/net/dns/serial_worker.h @@ -51,9 +51,6 @@ class NET_EXPORT_PRIVATE SerialWorker bool IsCancelled() const { return state_ == CANCELLED; } - // Delay between calls to WorkerPool::PostTask - static const int kWorkerPoolRetryDelayMs = 100; - protected: friend class base::RefCountedThreadSafe<SerialWorker>; // protected to allow sub-classing, but prevent deleting |