summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-23 16:17:06 +0000
committerszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-23 16:17:06 +0000
commitcb5076276c9336a7616954739a44c274a28d45cc (patch)
treedb5ae9a75244b1c998100b7271ac491625e03525 /net
parent137d52caea690b8d256f2cd4534edc25c3dcc42d (diff)
downloadchromium_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.cc8
-rw-r--r--net/base/host_resolver_impl_unittest.cc5
-rw-r--r--net/dns/dns_config_service.cc12
-rw-r--r--net/dns/dns_config_service.h3
-rw-r--r--net/dns/dns_config_service_win.cc386
-rw-r--r--net/dns/dns_config_service_win.h6
-rw-r--r--net/dns/dns_hosts.cc10
-rw-r--r--net/dns/dns_hosts.h5
-rw-r--r--net/dns/dns_hosts_unittest.cc4
-rw-r--r--net/dns/file_path_watcher_wrapper.h6
-rw-r--r--net/dns/serial_worker.cc7
-rw-r--r--net/dns/serial_worker.h3
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