summaryrefslogtreecommitdiff
path: root/chromium/net/dns
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/dns')
-rw-r--r--chromium/net/dns/address_sorter_posix_unittest.cc16
-rw-r--r--chromium/net/dns/dns_client.cc2
-rw-r--r--chromium/net/dns/dns_client.h3
-rw-r--r--chromium/net/dns/dns_config_service.cc14
-rw-r--r--chromium/net/dns/dns_config_service.h9
-rw-r--r--chromium/net/dns/dns_config_service_posix.cc121
-rw-r--r--chromium/net/dns/dns_config_service_posix.h1
-rw-r--r--chromium/net/dns/dns_config_service_win.cc194
-rw-r--r--chromium/net/dns/dns_config_service_win.h18
-rw-r--r--chromium/net/dns/dns_config_service_win_unittest.cc39
-rw-r--r--chromium/net/dns/dns_hosts.cc2
-rw-r--r--chromium/net/dns/dns_session_unittest.cc24
-rw-r--r--chromium/net/dns/dns_socket_pool.cc4
-rw-r--r--chromium/net/dns/dns_test_util.cc111
-rw-r--r--chromium/net/dns/dns_test_util.h35
-rw-r--r--chromium/net/dns/dns_transaction_unittest.cc14
-rw-r--r--chromium/net/dns/host_resolver.cc4
-rw-r--r--chromium/net/dns/host_resolver.h11
-rw-r--r--chromium/net/dns/host_resolver_impl.cc484
-rw-r--r--chromium/net/dns/host_resolver_impl.h20
-rw-r--r--chromium/net/dns/host_resolver_impl_unittest.cc543
-rw-r--r--chromium/net/dns/mapped_host_resolver.cc3
-rw-r--r--chromium/net/dns/mapped_host_resolver.h1
-rw-r--r--chromium/net/dns/mapped_host_resolver_unittest.cc104
-rw-r--r--chromium/net/dns/mdns_client.cc29
-rw-r--r--chromium/net/dns/mdns_client.h3
-rw-r--r--chromium/net/dns/mdns_client_impl.cc97
-rw-r--r--chromium/net/dns/mdns_client_impl.h24
-rw-r--r--chromium/net/dns/mdns_client_unittest.cc31
-rw-r--r--chromium/net/dns/mock_host_resolver.cc12
-rw-r--r--chromium/net/dns/mock_host_resolver.h9
-rw-r--r--chromium/net/dns/single_request_host_resolver.cc10
-rw-r--r--chromium/net/dns/single_request_host_resolver.h9
-rw-r--r--chromium/net/dns/single_request_host_resolver_unittest.cc10
34 files changed, 1448 insertions, 563 deletions
diff --git a/chromium/net/dns/address_sorter_posix_unittest.cc b/chromium/net/dns/address_sorter_posix_unittest.cc
index 96cbfc6fcb0..c4517379957 100644
--- a/chromium/net/dns/address_sorter_posix_unittest.cc
+++ b/chromium/net/dns/address_sorter_posix_unittest.cc
@@ -10,6 +10,8 @@
#include "net/base/net_util.h"
#include "net/base/test_completion_callback.h"
#include "net/socket/client_socket_factory.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/stream_socket.h"
#include "net/udp/datagram_client_socket.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -90,27 +92,27 @@ class TestSocketFactory : public ClientSocketFactory {
TestSocketFactory() {}
virtual ~TestSocketFactory() {}
- virtual DatagramClientSocket* CreateDatagramClientSocket(
+ virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
DatagramSocket::BindType,
const RandIntCallback&,
NetLog*,
const NetLog::Source&) OVERRIDE {
- return new TestUDPClientSocket(&mapping_);
+ return scoped_ptr<DatagramClientSocket>(new TestUDPClientSocket(&mapping_));
}
- virtual StreamSocket* CreateTransportClientSocket(
+ virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
const AddressList&,
NetLog*,
const NetLog::Source&) OVERRIDE {
NOTIMPLEMENTED();
- return NULL;
+ return scoped_ptr<StreamSocket>();
}
- virtual SSLClientSocket* CreateSSLClientSocket(
- ClientSocketHandle*,
+ virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+ scoped_ptr<ClientSocketHandle>,
const HostPortPair&,
const SSLConfig&,
const SSLClientSocketContext&) OVERRIDE {
NOTIMPLEMENTED();
- return NULL;
+ return scoped_ptr<SSLClientSocket>();
}
virtual void ClearSSLSessionCache() OVERRIDE {
NOTIMPLEMENTED();
diff --git a/chromium/net/dns/dns_client.cc b/chromium/net/dns/dns_client.cc
index 976f1533905..9e29ca4265d 100644
--- a/chromium/net/dns/dns_client.cc
+++ b/chromium/net/dns/dns_client.cc
@@ -27,7 +27,7 @@ class DnsClientImpl : public DnsClient {
virtual void SetConfig(const DnsConfig& config) OVERRIDE {
factory_.reset();
session_ = NULL;
- if (config.IsValid()) {
+ if (config.IsValid() && !config.unhandled_options) {
ClientSocketFactory* factory = ClientSocketFactory::GetDefaultFactory();
scoped_ptr<DnsSocketPool> socket_pool(
config.randomize_ports ? DnsSocketPool::CreateDefault(factory)
diff --git a/chromium/net/dns/dns_client.h b/chromium/net/dns/dns_client.h
index 650c7d0d416..0484d44c0c6 100644
--- a/chromium/net/dns/dns_client.h
+++ b/chromium/net/dns/dns_client.h
@@ -22,7 +22,8 @@ class NET_EXPORT DnsClient {
public:
virtual ~DnsClient() {}
- // Creates a new DnsTransactionFactory according to the new |config|.
+ // Destroys the current DnsTransactionFactory and creates a new one
+ // according to |config|, unless it is invalid or has |unhandled_options|.
virtual void SetConfig(const DnsConfig& config) = 0;
// Returns NULL if the current config is not valid.
diff --git a/chromium/net/dns/dns_config_service.cc b/chromium/net/dns/dns_config_service.cc
index ea8a3421cd2..66131825571 100644
--- a/chromium/net/dns/dns_config_service.cc
+++ b/chromium/net/dns/dns_config_service.cc
@@ -14,13 +14,15 @@ namespace net {
// Default values are taken from glibc resolv.h except timeout which is set to
// |kDnsTimeoutSeconds|.
DnsConfig::DnsConfig()
- : append_to_multi_label_name(true),
+ : unhandled_options(false),
+ append_to_multi_label_name(true),
randomize_ports(false),
ndots(1),
timeout(base::TimeDelta::FromSeconds(kDnsTimeoutSeconds)),
attempts(2),
rotate(false),
- edns0(false) {}
+ edns0(false),
+ use_local_ipv6(false) {}
DnsConfig::~DnsConfig() {}
@@ -31,23 +33,27 @@ bool DnsConfig::Equals(const DnsConfig& d) const {
bool DnsConfig::EqualsIgnoreHosts(const DnsConfig& d) const {
return (nameservers == d.nameservers) &&
(search == d.search) &&
+ (unhandled_options == d.unhandled_options) &&
(append_to_multi_label_name == d.append_to_multi_label_name) &&
(ndots == d.ndots) &&
(timeout == d.timeout) &&
(attempts == d.attempts) &&
(rotate == d.rotate) &&
- (edns0 == d.edns0);
+ (edns0 == d.edns0) &&
+ (use_local_ipv6 == d.use_local_ipv6);
}
void DnsConfig::CopyIgnoreHosts(const DnsConfig& d) {
nameservers = d.nameservers;
search = d.search;
+ unhandled_options = d.unhandled_options;
append_to_multi_label_name = d.append_to_multi_label_name;
ndots = d.ndots;
timeout = d.timeout;
attempts = d.attempts;
rotate = d.rotate;
edns0 = d.edns0;
+ use_local_ipv6 = d.use_local_ipv6;
}
base::Value* DnsConfig::ToValue() const {
@@ -63,12 +69,14 @@ base::Value* DnsConfig::ToValue() const {
list->Append(new base::StringValue(search[i]));
dict->Set("search", list);
+ dict->SetBoolean("unhandled_options", unhandled_options);
dict->SetBoolean("append_to_multi_label_name", append_to_multi_label_name);
dict->SetInteger("ndots", ndots);
dict->SetDouble("timeout", timeout.InSecondsF());
dict->SetInteger("attempts", attempts);
dict->SetBoolean("rotate", rotate);
dict->SetBoolean("edns0", edns0);
+ dict->SetBoolean("use_local_ipv6", use_local_ipv6);
dict->SetInteger("num_hosts", hosts.size());
return dict;
diff --git a/chromium/net/dns/dns_config_service.h b/chromium/net/dns/dns_config_service.h
index 4babb9e7d37..7386e601790 100644
--- a/chromium/net/dns/dns_config_service.h
+++ b/chromium/net/dns/dns_config_service.h
@@ -59,6 +59,10 @@ struct NET_EXPORT_PRIVATE DnsConfig {
DnsHosts hosts;
+ // True if there are options set in the system configuration that are not yet
+ // supported by DnsClient.
+ bool unhandled_options;
+
// AppendToMultiLabelName: is suffix search performed for multi-label names?
// True, except on Windows where it can be configured.
bool append_to_multi_label_name;
@@ -79,6 +83,11 @@ struct NET_EXPORT_PRIVATE DnsConfig {
bool rotate;
// Enable EDNS0 extensions.
bool edns0;
+
+ // Indicates system configuration uses local IPv6 connectivity, e.g.,
+ // DirectAccess. This is exposed for HostResolver to skip IPv6 probes,
+ // as it may cause them to return incorrect results.
+ bool use_local_ipv6;
};
diff --git a/chromium/net/dns/dns_config_service_posix.cc b/chromium/net/dns/dns_config_service_posix.cc
index ff2295e704a..baf917284c7 100644
--- a/chromium/net/dns/dns_config_service_posix.cc
+++ b/chromium/net/dns/dns_config_service_posix.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
+#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/time/time.h"
@@ -20,6 +21,69 @@
#include "net/dns/notify_watcher_mac.h"
#include "net/dns/serial_worker.h"
+#if defined(OS_MACOSX)
+#include <dlfcn.h>
+
+#include "third_party/apple_apsl/dnsinfo.h"
+
+namespace {
+
+// dnsinfo symbols are available via libSystem.dylib, but can also be present in
+// SystemConfiguration.framework. To avoid confusion, load them explicitly from
+// libSystem.dylib.
+class DnsInfoApi {
+ public:
+ typedef const char* (*dns_configuration_notify_key_t)();
+ typedef dns_config_t* (*dns_configuration_copy_t)();
+ typedef void (*dns_configuration_free_t)(dns_config_t*);
+
+ DnsInfoApi()
+ : dns_configuration_notify_key(NULL),
+ dns_configuration_copy(NULL),
+ dns_configuration_free(NULL) {
+ handle_ = dlopen("/usr/lib/libSystem.dylib",
+ RTLD_LAZY | RTLD_NOLOAD);
+ if (!handle_)
+ return;
+ dns_configuration_notify_key =
+ reinterpret_cast<dns_configuration_notify_key_t>(
+ dlsym(handle_, "dns_configuration_notify_key"));
+ dns_configuration_copy =
+ reinterpret_cast<dns_configuration_copy_t>(
+ dlsym(handle_, "dns_configuration_copy"));
+ dns_configuration_free =
+ reinterpret_cast<dns_configuration_free_t>(
+ dlsym(handle_, "dns_configuration_free"));
+ }
+
+ ~DnsInfoApi() {
+ if (handle_)
+ dlclose(handle_);
+ }
+
+ dns_configuration_notify_key_t dns_configuration_notify_key;
+ dns_configuration_copy_t dns_configuration_copy;
+ dns_configuration_free_t dns_configuration_free;
+
+ private:
+ void* handle_;
+};
+
+const DnsInfoApi& GetDnsInfoApi() {
+ static base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER;
+ return api.Get();
+}
+
+struct DnsConfigTDeleter {
+ inline void operator()(dns_config_t* ptr) const {
+ if (GetDnsInfoApi().dns_configuration_free)
+ GetDnsInfoApi().dns_configuration_free(ptr);
+ }
+};
+
+} // namespace
+#endif // defined(OS_MACOSX)
+
namespace net {
#if !defined(OS_ANDROID)
@@ -31,14 +95,13 @@ const base::FilePath::CharType* kFilePathHosts =
FILE_PATH_LITERAL("/etc/hosts");
#if defined(OS_MACOSX)
-// From 10.7.3 configd-395.10/dnsinfo/dnsinfo.h
-static const char* kDnsNotifyKey =
- "com.apple.system.SystemConfiguration.dns_configuration";
-
class ConfigWatcher {
public:
bool Watch(const base::Callback<void(bool succeeded)>& callback) {
- return watcher_.Watch(kDnsNotifyKey, callback);
+ if (!GetDnsInfoApi().dns_configuration_notify_key)
+ return false;
+ return watcher_.Watch(GetDnsInfoApi().dns_configuration_notify_key(),
+ callback);
}
private:
@@ -76,6 +139,7 @@ class ConfigWatcher {
ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) {
ConfigParsePosixResult result;
+ config->unhandled_options = false;
#if defined(OS_OPENBSD)
// Note: res_ninit in glibc always returns 0 and sets RES_INIT.
// res_init behaves the same way.
@@ -100,6 +164,32 @@ ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) {
res_nclose(&res);
#endif
#endif
+
+#if defined(OS_MACOSX)
+ if (!GetDnsInfoApi().dns_configuration_copy)
+ return CONFIG_PARSE_POSIX_NO_DNSINFO;
+ scoped_ptr<dns_config_t, DnsConfigTDeleter> dns_config(
+ GetDnsInfoApi().dns_configuration_copy());
+ if (!dns_config)
+ return CONFIG_PARSE_POSIX_NO_DNSINFO;
+
+ // TODO(szym): Parse dns_config_t for resolvers rather than res_state.
+ // DnsClient can't handle domain-specific unscoped resolvers.
+ unsigned num_resolvers = 0;
+ for (int i = 0; i < dns_config->n_resolver; ++i) {
+ dns_resolver_t* resolver = dns_config->resolver[i];
+ if (!resolver->n_nameserver)
+ continue;
+ if (resolver->options && !strcmp(resolver->options, "mdns"))
+ continue;
+ ++num_resolvers;
+ }
+ if (num_resolvers > 1) {
+ LOG(WARNING) << "dns_config has unhandled options!";
+ config->unhandled_options = true;
+ return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
+ }
+#endif // defined(OS_MACOSX)
// Override timeout value to match default setting on Windows.
config->timeout = base::TimeDelta::FromSeconds(kDnsTimeoutSeconds);
return result;
@@ -172,7 +262,18 @@ class DnsConfigServicePosix::ConfigReader : public SerialWorker {
virtual void DoWork() OVERRIDE {
base::TimeTicks start_time = base::TimeTicks::Now();
ConfigParsePosixResult result = ReadDnsConfig(&dns_config_);
- success_ = (result == CONFIG_PARSE_POSIX_OK);
+ switch (result) {
+ case CONFIG_PARSE_POSIX_MISSING_OPTIONS:
+ case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS:
+ DCHECK(dns_config_.unhandled_options);
+ // Fall through.
+ case CONFIG_PARSE_POSIX_OK:
+ success_ = true;
+ break;
+ default:
+ success_ = false;
+ break;
+ }
UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix",
result, CONFIG_PARSE_POSIX_MAX);
UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_);
@@ -358,12 +459,16 @@ ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res,
// The current implementation assumes these options are set. They normally
// cannot be overwritten by /etc/resolv.conf
unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
- if ((res.options & kRequiredOptions) != kRequiredOptions)
+ if ((res.options & kRequiredOptions) != kRequiredOptions) {
+ dns_config->unhandled_options = true;
return CONFIG_PARSE_POSIX_MISSING_OPTIONS;
+ }
unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC;
- if (res.options & kUnhandledOptions)
+ if (res.options & kUnhandledOptions) {
+ dns_config->unhandled_options = true;
return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
+ }
if (dns_config->nameservers.empty())
return CONFIG_PARSE_POSIX_NO_NAMESERVERS;
diff --git a/chromium/net/dns/dns_config_service_posix.h b/chromium/net/dns/dns_config_service_posix.h
index 95a4377d932..be19ab90b08 100644
--- a/chromium/net/dns/dns_config_service_posix.h
+++ b/chromium/net/dns/dns_config_service_posix.h
@@ -53,6 +53,7 @@ enum ConfigParsePosixResult {
CONFIG_PARSE_POSIX_NO_NAMESERVERS,
CONFIG_PARSE_POSIX_MISSING_OPTIONS,
CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS,
+ CONFIG_PARSE_POSIX_NO_DNSINFO,
CONFIG_PARSE_POSIX_MAX // Bounding values for enumeration.
};
diff --git a/chromium/net/dns/dns_config_service_win.cc b/chromium/net/dns/dns_config_service_win.cc
index 6d12155d8cc..fe97b74f73e 100644
--- a/chromium/net/dns/dns_config_service_win.cc
+++ b/chromium/net/dns/dns_config_service_win.cc
@@ -43,8 +43,19 @@ namespace {
// Interval between retries to parse config. Used only until parsing succeeds.
const int kRetryIntervalSeconds = 5;
+// 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";
const wchar_t* const kPrimaryDnsSuffixPath =
L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient";
+const wchar_t* const kNRPTPath =
+ L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
enum HostsParseWinResult {
HOSTS_PARSE_WIN_OK = 0,
@@ -198,6 +209,10 @@ ConfigParseWinResult ReadSystemSettings(DnsSystemSettings* settings) {
&settings->primary_dns_suffix)) {
return CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX;
}
+
+ base::win::RegistryKeyIterator nrpt_rules(HKEY_LOCAL_MACHINE, kNRPTPath);
+ settings->have_name_resolution_policy = (nrpt_rules.SubkeyCount() > 0);
+
return CONFIG_PARSE_WIN_OK;
}
@@ -330,8 +345,7 @@ bool IsStatelessDiscoveryAddress(const IPAddressNumber& address) {
address.begin()) && (address.back() < 4);
}
-} // namespace
-
+// Returns the path to the HOSTS file.
base::FilePath GetHostsPath() {
TCHAR buffer[MAX_PATH];
UINT rc = GetSystemDirectory(buffer, MAX_PATH);
@@ -340,6 +354,92 @@ base::FilePath GetHostsPath() {
FILE_PATH_LITERAL("drivers\\etc\\hosts"));
}
+void ConfigureSuffixSearch(const DnsSystemSettings& settings,
+ DnsConfig* config) {
+ // SearchList takes precedence, so check it first.
+ if (settings.policy_search_list.set) {
+ std::vector<std::string> search;
+ if (ParseSearchList(settings.policy_search_list.value, &search)) {
+ config->search.swap(search);
+ return;
+ }
+ // Even if invalid, the policy disables the user-specified setting below.
+ } else if (settings.tcpip_search_list.set) {
+ std::vector<std::string> search;
+ if (ParseSearchList(settings.tcpip_search_list.value, &search)) {
+ config->search.swap(search);
+ return;
+ }
+ }
+
+ // In absence of explicit search list, suffix search is:
+ // [primary suffix, connection-specific suffix, devolution of primary suffix].
+ // Primary suffix can be set by policy (primary_dns_suffix) or
+ // user setting (tcpip_domain).
+ //
+ // The policy (primary_dns_suffix) can be edited via Group Policy Editor
+ // (gpedit.msc) at Local Computer Policy => Computer Configuration
+ // => Administrative Template => Network => DNS Client => Primary DNS Suffix.
+ //
+ // The user setting (tcpip_domain) can be configurred at Computer Name in
+ // System Settings
+ std::string primary_suffix;
+ if ((settings.primary_dns_suffix.set &&
+ ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) ||
+ (settings.tcpip_domain.set &&
+ ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) {
+ // Primary suffix goes in front.
+ config->search.insert(config->search.begin(), primary_suffix);
+ } else {
+ return; // No primary suffix, hence no devolution.
+ }
+
+ // Devolution is determined by precedence: policy > dnscache > tcpip.
+ // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel
+ // are overridden independently.
+ DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution;
+
+ if (!devolution.enabled.set)
+ devolution.enabled = settings.dnscache_devolution.enabled;
+ if (!devolution.enabled.set)
+ devolution.enabled = settings.tcpip_devolution.enabled;
+ if (devolution.enabled.set && (devolution.enabled.value == 0))
+ return; // Devolution disabled.
+
+ // By default devolution is enabled.
+
+ if (!devolution.level.set)
+ devolution.level = settings.dnscache_devolution.level;
+ if (!devolution.level.set)
+ devolution.level = settings.tcpip_devolution.level;
+
+ // After the recent update, Windows will try to determine a safe default
+ // value by comparing the forest root domain (FRD) to the primary suffix.
+ // See http://support.microsoft.com/kb/957579 for details.
+ // For now, if the level is not set, we disable devolution, assuming that
+ // we will fallback to the system getaddrinfo anyway. This might cause
+ // performance loss for resolutions which depend on the system default
+ // devolution setting.
+ //
+ // If the level is explicitly set below 2, devolution is disabled.
+ if (!devolution.level.set || devolution.level.value < 2)
+ return; // Devolution disabled.
+
+ // Devolve the primary suffix. This naive logic matches the observed
+ // behavior (see also ParseSearchList). If a suffix is not valid, it will be
+ // discarded when the fully-qualified name is converted to DNS format.
+
+ unsigned num_dots = std::count(primary_suffix.begin(),
+ primary_suffix.end(), '.');
+
+ for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) {
+ offset = primary_suffix.find('.', offset + 1);
+ config->search.push_back(primary_suffix.substr(offset + 1));
+ }
+}
+
+} // namespace
+
bool ParseSearchList(const base::string16& value,
std::vector<std::string>* output) {
DCHECK(output);
@@ -429,87 +529,16 @@ ConfigParseWinResult ConvertSettingsToDnsConfig(
(settings.append_to_multi_label_name.value != 0);
}
- // SearchList takes precedence, so check it first.
- if (settings.policy_search_list.set) {
- std::vector<std::string> search;
- if (ParseSearchList(settings.policy_search_list.value, &search)) {
- config->search.swap(search);
- return CONFIG_PARSE_WIN_OK;
- }
- // Even if invalid, the policy disables the user-specified setting below.
- } else if (settings.tcpip_search_list.set) {
- std::vector<std::string> search;
- if (ParseSearchList(settings.tcpip_search_list.value, &search)) {
- config->search.swap(search);
- return CONFIG_PARSE_WIN_OK;
- }
+ ConfigParseWinResult result = CONFIG_PARSE_WIN_OK;
+ if (settings.have_name_resolution_policy) {
+ config->unhandled_options = true;
+ // TODO(szym): only set this to true if NRPT has DirectAccess rules.
+ config->use_local_ipv6 = true;
+ result = CONFIG_PARSE_WIN_UNHANDLED_OPTIONS;
}
- // In absence of explicit search list, suffix search is:
- // [primary suffix, connection-specific suffix, devolution of primary suffix].
- // Primary suffix can be set by policy (primary_dns_suffix) or
- // user setting (tcpip_domain).
- //
- // The policy (primary_dns_suffix) can be edited via Group Policy Editor
- // (gpedit.msc) at Local Computer Policy => Computer Configuration
- // => Administrative Template => Network => DNS Client => Primary DNS Suffix.
- //
- // The user setting (tcpip_domain) can be configurred at Computer Name in
- // System Settings
- std::string primary_suffix;
- if ((settings.primary_dns_suffix.set &&
- ParseDomainASCII(settings.primary_dns_suffix.value, &primary_suffix)) ||
- (settings.tcpip_domain.set &&
- ParseDomainASCII(settings.tcpip_domain.value, &primary_suffix))) {
- // Primary suffix goes in front.
- config->search.insert(config->search.begin(), primary_suffix);
- } else {
- return CONFIG_PARSE_WIN_OK; // No primary suffix, hence no devolution.
- }
-
- // Devolution is determined by precedence: policy > dnscache > tcpip.
- // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel
- // are overridden independently.
- DnsSystemSettings::DevolutionSetting devolution = settings.policy_devolution;
-
- if (!devolution.enabled.set)
- devolution.enabled = settings.dnscache_devolution.enabled;
- if (!devolution.enabled.set)
- devolution.enabled = settings.tcpip_devolution.enabled;
- if (devolution.enabled.set && (devolution.enabled.value == 0))
- return CONFIG_PARSE_WIN_OK; // Devolution disabled.
-
- // By default devolution is enabled.
-
- if (!devolution.level.set)
- devolution.level = settings.dnscache_devolution.level;
- if (!devolution.level.set)
- devolution.level = settings.tcpip_devolution.level;
-
- // After the recent update, Windows will try to determine a safe default
- // value by comparing the forest root domain (FRD) to the primary suffix.
- // See http://support.microsoft.com/kb/957579 for details.
- // For now, if the level is not set, we disable devolution, assuming that
- // we will fallback to the system getaddrinfo anyway. This might cause
- // performance loss for resolutions which depend on the system default
- // devolution setting.
- //
- // If the level is explicitly set below 2, devolution is disabled.
- if (!devolution.level.set || devolution.level.value < 2)
- return CONFIG_PARSE_WIN_OK; // Devolution disabled.
-
- // Devolve the primary suffix. This naive logic matches the observed
- // behavior (see also ParseSearchList). If a suffix is not valid, it will be
- // discarded when the fully-qualified name is converted to DNS format.
-
- unsigned num_dots = std::count(primary_suffix.begin(),
- primary_suffix.end(), '.');
-
- for (size_t offset = 0; num_dots >= devolution.level.value; --num_dots) {
- offset = primary_suffix.find('.', offset + 1);
- config->search.push_back(primary_suffix.substr(offset + 1));
- }
- return CONFIG_PARSE_WIN_OK;
+ ConfigureSuffixSearch(settings, config);
+ return result;
}
// Watches registry and HOSTS file for changes. Must live on a thread which
@@ -606,7 +635,8 @@ class DnsConfigServiceWin::ConfigReader : public SerialWorker {
ConfigParseWinResult result = ReadSystemSettings(&settings);
if (result == CONFIG_PARSE_WIN_OK)
result = ConvertSettingsToDnsConfig(settings, &dns_config_);
- success_ = (result == CONFIG_PARSE_WIN_OK);
+ success_ = (result == CONFIG_PARSE_WIN_OK ||
+ result == CONFIG_PARSE_WIN_UNHANDLED_OPTIONS);
UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParseWin",
result, CONFIG_PARSE_WIN_MAX);
UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_);
diff --git a/chromium/net/dns/dns_config_service_win.h b/chromium/net/dns/dns_config_service_win.h
index 06fc0d9663b..9503dc8593f 100644
--- a/chromium/net/dns/dns_config_service_win.h
+++ b/chromium/net/dns/dns_config_service_win.h
@@ -34,19 +34,6 @@ namespace net {
namespace internal {
-// 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";
-
-// Returns the path to the HOSTS file.
-base::FilePath GetHostsPath();
-
// Parses |value| as search list (comma-delimited list of domain names) from
// a registry key and stores it in |out|. Returns true on success. Empty
// entries (e.g., "chromium.org,,org") terminate the list. Non-ascii hostnames
@@ -98,6 +85,10 @@ struct NET_EXPORT_PRIVATE DnsSystemSettings {
// SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\AppendToMultiLabelName
RegDword append_to_multi_label_name;
+
+ // True when the Name Resolution Policy Table (NRPT) has at least one rule:
+ // SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\DnsPolicyConfig\Rule*
+ bool have_name_resolution_policy;
};
enum ConfigParseWinResult {
@@ -113,6 +104,7 @@ enum ConfigParseWinResult {
CONFIG_PARSE_WIN_READ_PRIMARY_SUFFIX,
CONFIG_PARSE_WIN_BAD_ADDRESS,
CONFIG_PARSE_WIN_NO_NAMESERVERS,
+ CONFIG_PARSE_WIN_UNHANDLED_OPTIONS,
CONFIG_PARSE_WIN_MAX // Bounding values for enumeration.
};
diff --git a/chromium/net/dns/dns_config_service_win_unittest.cc b/chromium/net/dns/dns_config_service_win_unittest.cc
index b28b8e9554a..3f3e4ed1e37 100644
--- a/chromium/net/dns/dns_config_service_win_unittest.cc
+++ b/chromium/net/dns/dns_config_service_win_unittest.cc
@@ -4,6 +4,7 @@
#include "net/dns/dns_config_service_win.h"
+#include "base/basictypes.h"
#include "base/logging.h"
#include "base/win/windows_version.h"
#include "net/dns/dns_protocol.h"
@@ -420,10 +421,46 @@ TEST(DnsConfigServiceWinTest, AppendToMultiLabelName) {
DnsConfig config;
EXPECT_EQ(internal::CONFIG_PARSE_WIN_OK,
internal::ConvertSettingsToDnsConfig(settings, &config));
- EXPECT_EQ(config.append_to_multi_label_name, t.expected_output);
+ EXPECT_EQ(t.expected_output, config.append_to_multi_label_name);
}
}
+// Setting have_name_resolution_policy_table should set unhandled_options.
+TEST(DnsConfigServiceWinTest, HaveNRPT) {
+ AdapterInfo infos[2] = {
+ { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
+ { 0 },
+ };
+
+ const struct TestCase {
+ bool have_nrpt;
+ bool unhandled_options;
+ internal::ConfigParseWinResult result;
+ } cases[] = {
+ { false, false, internal::CONFIG_PARSE_WIN_OK },
+ { true, true, internal::CONFIG_PARSE_WIN_UNHANDLED_OPTIONS },
+ };
+
+ for (size_t i = 0; i < arraysize(cases); ++i) {
+ const TestCase& t = cases[i];
+ internal::DnsSystemSettings settings = {
+ CreateAdapterAddresses(infos),
+ { false }, { false }, { false }, { false },
+ { { false }, { false } },
+ { { false }, { false } },
+ { { false }, { false } },
+ { false },
+ t.have_nrpt,
+ };
+ DnsConfig config;
+ EXPECT_EQ(t.result,
+ internal::ConvertSettingsToDnsConfig(settings, &config));
+ EXPECT_EQ(t.unhandled_options, config.unhandled_options);
+ EXPECT_EQ(t.have_nrpt, config.use_local_ipv6);
+ }
+}
+
+
} // namespace
} // namespace net
diff --git a/chromium/net/dns/dns_hosts.cc b/chromium/net/dns/dns_hosts.cc
index 852d35c8bb4..3edea2a7abc 100644
--- a/chromium/net/dns/dns_hosts.cc
+++ b/chromium/net/dns/dns_hosts.cc
@@ -158,7 +158,7 @@ bool ParseHostsFile(const base::FilePath& path, DnsHosts* dns_hosts) {
return false;
std::string contents;
- if (!file_util::ReadFileToString(path, &contents))
+ if (!base::ReadFileToString(path, &contents))
return false;
ParseHosts(contents, dns_hosts);
diff --git a/chromium/net/dns/dns_session_unittest.cc b/chromium/net/dns/dns_session_unittest.cc
index 46627069f66..ed726f23234 100644
--- a/chromium/net/dns/dns_session_unittest.cc
+++ b/chromium/net/dns/dns_session_unittest.cc
@@ -14,6 +14,8 @@
#include "net/dns/dns_protocol.h"
#include "net/dns/dns_socket_pool.h"
#include "net/socket/socket_test_util.h"
+#include "net/socket/ssl_client_socket.h"
+#include "net/socket/stream_socket.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -24,26 +26,26 @@ class TestClientSocketFactory : public ClientSocketFactory {
public:
virtual ~TestClientSocketFactory();
- virtual DatagramClientSocket* CreateDatagramClientSocket(
+ virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
const net::NetLog::Source& source) OVERRIDE;
- virtual StreamSocket* CreateTransportClientSocket(
+ virtual scoped_ptr<StreamSocket> CreateTransportClientSocket(
const AddressList& addresses,
NetLog*, const NetLog::Source&) OVERRIDE {
NOTIMPLEMENTED();
- return NULL;
+ return scoped_ptr<StreamSocket>();
}
- virtual SSLClientSocket* CreateSSLClientSocket(
- ClientSocketHandle* transport_socket,
+ virtual scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
+ scoped_ptr<ClientSocketHandle> transport_socket,
const HostPortPair& host_and_port,
const SSLConfig& ssl_config,
const SSLClientSocketContext& context) OVERRIDE {
NOTIMPLEMENTED();
- return NULL;
+ return scoped_ptr<SSLClientSocket>();
}
virtual void ClearSSLSessionCache() OVERRIDE {
@@ -179,7 +181,8 @@ bool DnsSessionTest::ExpectEvent(const PoolEvent& expected) {
return true;
}
-DatagramClientSocket* TestClientSocketFactory::CreateDatagramClientSocket(
+scoped_ptr<DatagramClientSocket>
+TestClientSocketFactory::CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
@@ -188,9 +191,10 @@ DatagramClientSocket* TestClientSocketFactory::CreateDatagramClientSocket(
// simplest SocketDataProvider with no data supplied.
SocketDataProvider* data_provider = new StaticSocketDataProvider();
data_providers_.push_back(data_provider);
- MockUDPClientSocket* socket = new MockUDPClientSocket(data_provider, net_log);
- data_provider->set_socket(socket);
- return socket;
+ scoped_ptr<MockUDPClientSocket> socket(
+ new MockUDPClientSocket(data_provider, net_log));
+ data_provider->set_socket(socket.get());
+ return socket.PassAs<DatagramClientSocket>();
}
TestClientSocketFactory::~TestClientSocketFactory() {
diff --git a/chromium/net/dns/dns_socket_pool.cc b/chromium/net/dns/dns_socket_pool.cc
index 64570fca8fc..7a7ecd6ee8f 100644
--- a/chromium/net/dns/dns_socket_pool.cc
+++ b/chromium/net/dns/dns_socket_pool.cc
@@ -76,8 +76,8 @@ scoped_ptr<DatagramClientSocket> DnsSocketPool::CreateConnectedSocket(
scoped_ptr<DatagramClientSocket> socket;
NetLog::Source no_source;
- socket.reset(socket_factory_->CreateDatagramClientSocket(
- kBindType, base::Bind(&base::RandInt), net_log_, no_source));
+ socket = socket_factory_->CreateDatagramClientSocket(
+ kBindType, base::Bind(&base::RandInt), net_log_, no_source);
if (socket.get()) {
int rv = socket->Connect((*nameservers_)[server_index]);
diff --git a/chromium/net/dns/dns_test_util.cc b/chromium/net/dns/dns_test_util.cc
index 37bf855dd10..63014213faa 100644
--- a/chromium/net/dns/dns_test_util.cc
+++ b/chromium/net/dns/dns_test_util.cc
@@ -15,9 +15,6 @@
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/dns/address_sorter.h"
-#include "net/dns/dns_client.h"
-#include "net/dns/dns_config_service.h"
-#include "net/dns/dns_protocol.h"
#include "net/dns/dns_query.h"
#include "net/dns/dns_response.h"
#include "net/dns/dns_transaction.h"
@@ -26,6 +23,16 @@
namespace net {
namespace {
+class MockAddressSorter : public AddressSorter {
+ public:
+ virtual ~MockAddressSorter() {}
+ virtual void Sort(const AddressList& list,
+ const CallbackType& callback) const OVERRIDE {
+ // Do nothing.
+ callback.Run(true, list);
+ }
+};
+
// A DnsTransaction which uses MockDnsClientRuleList to determine the response.
class MockTransaction : public DnsTransaction,
public base::SupportsWeakPtr<MockTransaction> {
@@ -38,7 +45,8 @@ class MockTransaction : public DnsTransaction,
hostname_(hostname),
qtype_(qtype),
callback_(callback),
- started_(false) {
+ started_(false),
+ delayed_(false) {
// Find the relevant rule which matches |qtype| and prefix of |hostname|.
for (size_t i = 0; i < rules.size(); ++i) {
const std::string& prefix = rules[i].prefix;
@@ -46,6 +54,7 @@ class MockTransaction : public DnsTransaction,
(hostname.size() >= prefix.size()) &&
(hostname.compare(0, prefix.size(), prefix) == 0)) {
result_ = rules[i].result;
+ delayed_ = rules[i].delay;
break;
}
}
@@ -62,11 +71,21 @@ class MockTransaction : public DnsTransaction,
virtual void Start() OVERRIDE {
EXPECT_FALSE(started_);
started_ = true;
+ if (delayed_)
+ return;
// Using WeakPtr to cleanly cancel when transaction is destroyed.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&MockTransaction::Finish, AsWeakPtr()));
}
+ void FinishDelayedTransaction() {
+ EXPECT_TRUE(delayed_);
+ delayed_ = false;
+ Finish();
+ }
+
+ bool delayed() const { return delayed_; }
+
private:
void Finish() {
switch (result_) {
@@ -136,14 +155,17 @@ class MockTransaction : public DnsTransaction,
const uint16 qtype_;
DnsTransactionFactory::CallbackType callback_;
bool started_;
+ bool delayed_;
};
+} // namespace
// A DnsTransactionFactory which creates MockTransaction.
class MockTransactionFactory : public DnsTransactionFactory {
public:
explicit MockTransactionFactory(const MockDnsClientRuleList& rules)
: rules_(rules) {}
+
virtual ~MockTransactionFactory() {}
virtual scoped_ptr<DnsTransaction> CreateTransaction(
@@ -151,60 +173,57 @@ class MockTransactionFactory : public DnsTransactionFactory {
uint16 qtype,
const DnsTransactionFactory::CallbackType& callback,
const BoundNetLog&) OVERRIDE {
- return scoped_ptr<DnsTransaction>(
- new MockTransaction(rules_, hostname, qtype, callback));
+ MockTransaction* transaction =
+ new MockTransaction(rules_, hostname, qtype, callback);
+ if (transaction->delayed())
+ delayed_transactions_.push_back(transaction->AsWeakPtr());
+ return scoped_ptr<DnsTransaction>(transaction);
+ }
+
+ void CompleteDelayedTransactions() {
+ DelayedTransactionList old_delayed_transactions;
+ old_delayed_transactions.swap(delayed_transactions_);
+ for (DelayedTransactionList::iterator it = old_delayed_transactions.begin();
+ it != old_delayed_transactions.end(); ++it) {
+ if (it->get())
+ (*it)->FinishDelayedTransaction();
+ }
}
private:
- MockDnsClientRuleList rules_;
-};
+ typedef std::vector<base::WeakPtr<MockTransaction> > DelayedTransactionList;
-class MockAddressSorter : public AddressSorter {
- public:
- virtual ~MockAddressSorter() {}
- virtual void Sort(const AddressList& list,
- const CallbackType& callback) const OVERRIDE {
- // Do nothing.
- callback.Run(true, list);
- }
+ MockDnsClientRuleList rules_;
+ DelayedTransactionList delayed_transactions_;
};
-// MockDnsClient provides MockTransactionFactory.
-class MockDnsClient : public DnsClient {
- public:
- MockDnsClient(const DnsConfig& config,
- const MockDnsClientRuleList& rules)
- : config_(config), factory_(rules) {}
- virtual ~MockDnsClient() {}
+MockDnsClient::MockDnsClient(const DnsConfig& config,
+ const MockDnsClientRuleList& rules)
+ : config_(config),
+ factory_(new MockTransactionFactory(rules)),
+ address_sorter_(new MockAddressSorter()) {
+}
- virtual void SetConfig(const DnsConfig& config) OVERRIDE {
- config_ = config;
- }
+MockDnsClient::~MockDnsClient() {}
- virtual const DnsConfig* GetConfig() const OVERRIDE {
- return config_.IsValid() ? &config_ : NULL;
- }
-
- virtual DnsTransactionFactory* GetTransactionFactory() OVERRIDE {
- return config_.IsValid() ? &factory_ : NULL;
- }
+void MockDnsClient::SetConfig(const DnsConfig& config) {
+ config_ = config;
+}
- virtual AddressSorter* GetAddressSorter() OVERRIDE {
- return &address_sorter_;
- }
+const DnsConfig* MockDnsClient::GetConfig() const {
+ return config_.IsValid() ? &config_ : NULL;
+}
- private:
- DnsConfig config_;
- MockTransactionFactory factory_;
- MockAddressSorter address_sorter_;
-};
+DnsTransactionFactory* MockDnsClient::GetTransactionFactory() {
+ return config_.IsValid() ? factory_.get() : NULL;
+}
-} // namespace
+AddressSorter* MockDnsClient::GetAddressSorter() {
+ return address_sorter_.get();
+}
-// static
-scoped_ptr<DnsClient> CreateMockDnsClient(const DnsConfig& config,
- const MockDnsClientRuleList& rules) {
- return scoped_ptr<DnsClient>(new MockDnsClient(config, rules));
+void MockDnsClient::CompleteDelayedTransactions() {
+ factory_->CompleteDelayedTransactions();
}
} // namespace net
diff --git a/chromium/net/dns/dns_test_util.h b/chromium/net/dns/dns_test_util.h
index d447b299c86..d0b8e81b7ed 100644
--- a/chromium/net/dns/dns_test_util.h
+++ b/chromium/net/dns/dns_test_util.h
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "net/dns/dns_client.h"
#include "net/dns/dns_config_service.h"
#include "net/dns/dns_protocol.h"
@@ -174,7 +175,9 @@ static const int kT3TTL = 0x00000015;
// +2 for the CNAME records, +1 for TXT record.
static const unsigned kT3RecordCount = arraysize(kT3IpAddresses) + 3;
+class AddressSorter;
class DnsClient;
+class MockTransactionFactory;
struct MockDnsClientRule {
enum Result {
@@ -184,21 +187,43 @@ struct MockDnsClientRule {
OK, // Return a response with loopback address.
};
+ // If |delay| is true, matching transactions will be delayed until triggered
+ // by the consumer.
MockDnsClientRule(const std::string& prefix_arg,
uint16 qtype_arg,
- Result result_arg)
- : result(result_arg), prefix(prefix_arg), qtype(qtype_arg) { }
+ Result result_arg,
+ bool delay)
+ : result(result_arg), prefix(prefix_arg), qtype(qtype_arg),
+ delay(delay) {}
Result result;
std::string prefix;
uint16 qtype;
+ bool delay;
};
typedef std::vector<MockDnsClientRule> MockDnsClientRuleList;
-// Creates mock DnsClient for testing HostResolverImpl.
-scoped_ptr<DnsClient> CreateMockDnsClient(const DnsConfig& config,
- const MockDnsClientRuleList& rules);
+// MockDnsClient provides MockTransactionFactory.
+class MockDnsClient : public DnsClient {
+ public:
+ MockDnsClient(const DnsConfig& config, const MockDnsClientRuleList& rules);
+ virtual ~MockDnsClient();
+
+ // DnsClient interface:
+ virtual void SetConfig(const DnsConfig& config) OVERRIDE;
+ virtual const DnsConfig* GetConfig() const OVERRIDE;
+ virtual DnsTransactionFactory* GetTransactionFactory() OVERRIDE;
+ virtual AddressSorter* GetAddressSorter() OVERRIDE;
+
+ // Completes all DnsTransactions that were delayed by a rule.
+ void CompleteDelayedTransactions();
+
+ private:
+ DnsConfig config_;
+ scoped_ptr<MockTransactionFactory> factory_;
+ scoped_ptr<AddressSorter> address_sorter_;
+};
} // namespace net
diff --git a/chromium/net/dns/dns_transaction_unittest.cc b/chromium/net/dns/dns_transaction_unittest.cc
index f9667eed5f4..7040e44be16 100644
--- a/chromium/net/dns/dns_transaction_unittest.cc
+++ b/chromium/net/dns/dns_transaction_unittest.cc
@@ -180,21 +180,21 @@ class TestSocketFactory : public MockClientSocketFactory {
TestSocketFactory() : fail_next_socket_(false) {}
virtual ~TestSocketFactory() {}
- virtual DatagramClientSocket* CreateDatagramClientSocket(
+ virtual scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
const net::NetLog::Source& source) OVERRIDE {
if (fail_next_socket_) {
fail_next_socket_ = false;
- return new FailingUDPClientSocket(&empty_data_, net_log);
+ return scoped_ptr<DatagramClientSocket>(
+ new FailingUDPClientSocket(&empty_data_, net_log));
}
SocketDataProvider* data_provider = mock_data().GetNext();
- TestUDPClientSocket* socket = new TestUDPClientSocket(this,
- data_provider,
- net_log);
- data_provider->set_socket(socket);
- return socket;
+ scoped_ptr<TestUDPClientSocket> socket(
+ new TestUDPClientSocket(this, data_provider, net_log));
+ data_provider->set_socket(socket.get());
+ return socket.PassAs<DatagramClientSocket>();
}
void OnConnect(const IPEndPoint& endpoint) {
diff --git a/chromium/net/dns/host_resolver.cc b/chromium/net/dns/host_resolver.cc
index d74be91beb0..9b1e3314acd 100644
--- a/chromium/net/dns/host_resolver.cc
+++ b/chromium/net/dns/host_resolver.cc
@@ -98,9 +98,7 @@ HostResolver::RequestInfo::RequestInfo(const HostPortPair& host_port_pair)
address_family_(ADDRESS_FAMILY_UNSPECIFIED),
host_resolver_flags_(0),
allow_cached_response_(true),
- is_speculative_(false),
- priority_(MEDIUM) {
-}
+ is_speculative_(false) {}
HostResolver::~HostResolver() {
}
diff --git a/chromium/net/dns/host_resolver.h b/chromium/net/dns/host_resolver.h
index 558a1ddc4b2..2964fe600df 100644
--- a/chromium/net/dns/host_resolver.h
+++ b/chromium/net/dns/host_resolver.h
@@ -53,8 +53,8 @@ class NET_EXPORT HostResolver {
bool enable_caching;
};
- // The parameters for doing a Resolve(). A hostname and port are required,
- // the rest are optional (and have reasonable defaults).
+ // The parameters for doing a Resolve(). A hostname and port are
+ // required; the rest are optional (and have reasonable defaults).
class NET_EXPORT RequestInfo {
public:
explicit RequestInfo(const HostPortPair& host_port_pair);
@@ -85,9 +85,6 @@ class NET_EXPORT HostResolver {
bool is_speculative() const { return is_speculative_; }
void set_is_speculative(bool b) { is_speculative_ = b; }
- RequestPriority priority() const { return priority_; }
- void set_priority(RequestPriority priority) { priority_ = priority; }
-
private:
// The hostname to resolve, and the port to use in resulting sockaddrs.
HostPortPair host_port_pair_;
@@ -103,9 +100,6 @@ class NET_EXPORT HostResolver {
// Whether this request was started by the DNS prefetcher.
bool is_speculative_;
-
- // The priority for the request.
- RequestPriority priority_;
};
// Opaque type used to cancel a request.
@@ -144,6 +138,7 @@ class NET_EXPORT HostResolver {
//
// Profiling information for the request is saved to |net_log| if non-NULL.
virtual int Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
diff --git a/chromium/net/dns/host_resolver_impl.cc b/chromium/net/dns/host_resolver_impl.cc
index e656f03955f..e4098d003be 100644
--- a/chromium/net/dns/host_resolver_impl.cc
+++ b/chromium/net/dns/host_resolver_impl.cc
@@ -69,10 +69,6 @@ const unsigned kNegativeCacheEntryTTLSeconds = 0;
// Minimum TTL for successful resolutions with DnsTask.
const unsigned kMinimumTTLSeconds = kCacheEntryTTLSeconds;
-// Number of consecutive failures of DnsTask (with successful fallback) before
-// the DnsClient is disabled until the next DNS change.
-const unsigned kMaximumDnsFailures = 16;
-
// We use a separate histogram name for each platform to facilitate the
// display of error codes by their symbolic name (since each platform has
// different mappings).
@@ -343,7 +339,6 @@ base::Value* NetLogRequestInfoCallback(const NetLog::Source& source,
static_cast<int>(info->address_family()));
dict->SetBoolean("allow_cached_response", info->allow_cached_response());
dict->SetBoolean("is_speculative", info->is_speculative());
- dict->SetInteger("priority", info->priority());
return dict;
}
@@ -457,6 +452,8 @@ class PriorityTracker {
//-----------------------------------------------------------------------------
+const unsigned HostResolverImpl::kMaximumDnsFailures = 16;
+
// Holds the data for a request that could not be completed synchronously.
// It is owned by a Job. Canceled Requests are only marked as canceled rather
// than removed from the Job's |requests_| list.
@@ -465,16 +462,17 @@ class HostResolverImpl::Request {
Request(const BoundNetLog& source_net_log,
const BoundNetLog& request_net_log,
const RequestInfo& info,
+ RequestPriority priority,
const CompletionCallback& callback,
AddressList* addresses)
: source_net_log_(source_net_log),
request_net_log_(request_net_log),
info_(info),
+ priority_(priority),
job_(NULL),
callback_(callback),
addresses_(addresses),
- request_time_(base::TimeTicks::Now()) {
- }
+ request_time_(base::TimeTicks::Now()) {}
// Mark the request as canceled.
void MarkAsCanceled() {
@@ -521,16 +519,19 @@ class HostResolverImpl::Request {
return info_;
}
- base::TimeTicks request_time() const {
- return request_time_;
- }
+ RequestPriority priority() const { return priority_; }
+
+ base::TimeTicks request_time() const { return request_time_; }
private:
BoundNetLog source_net_log_;
BoundNetLog request_net_log_;
// The request info that started the request.
- RequestInfo info_;
+ const RequestInfo info_;
+
+ // TODO(akalin): Support reprioritization.
+ const RequestPriority priority_;
// The resolve job that this request is dependent on.
Job* job_;
@@ -967,54 +968,98 @@ class HostResolverImpl::LoopbackProbeJob {
// TODO(szym): This could be moved to separate source file as well.
class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
public:
- typedef base::Callback<void(int net_error,
- const AddressList& addr_list,
- base::TimeDelta ttl)> Callback;
+ class Delegate {
+ public:
+ virtual void OnDnsTaskComplete(base::TimeTicks start_time,
+ int net_error,
+ const AddressList& addr_list,
+ base::TimeDelta ttl) = 0;
+
+ // Called when the first of two jobs succeeds. If the first completed
+ // transaction fails, this is not called. Also not called when the DnsTask
+ // only needs to run one transaction.
+ virtual void OnFirstDnsTransactionComplete() = 0;
+
+ protected:
+ Delegate() {}
+ virtual ~Delegate() {}
+ };
DnsTask(DnsClient* client,
const Key& key,
- const Callback& callback,
+ Delegate* delegate,
const BoundNetLog& job_net_log)
: client_(client),
- family_(key.address_family),
- callback_(callback),
- net_log_(job_net_log) {
+ key_(key),
+ delegate_(delegate),
+ net_log_(job_net_log),
+ num_completed_transactions_(0),
+ task_start_time_(base::TimeTicks::Now()) {
DCHECK(client);
- DCHECK(!callback.is_null());
-
- // If unspecified, do IPv4 first, because suffix search will be faster.
- uint16 qtype = (family_ == ADDRESS_FAMILY_IPV6) ?
- dns_protocol::kTypeAAAA :
- dns_protocol::kTypeA;
- transaction_ = client_->GetTransactionFactory()->CreateTransaction(
- key.hostname,
- qtype,
- base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
- true /* first_query */, base::TimeTicks::Now()),
- net_log_);
+ DCHECK(delegate_);
}
- void Start() {
+ bool needs_two_transactions() const {
+ return key_.address_family == ADDRESS_FAMILY_UNSPECIFIED;
+ }
+
+ bool needs_another_transaction() const {
+ return needs_two_transactions() && !transaction_aaaa_;
+ }
+
+ void StartFirstTransaction() {
+ DCHECK_EQ(0u, num_completed_transactions_);
net_log_.BeginEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK);
- transaction_->Start();
+ if (key_.address_family == ADDRESS_FAMILY_IPV6) {
+ StartAAAA();
+ } else {
+ StartA();
+ }
+ }
+
+ void StartSecondTransaction() {
+ DCHECK(needs_two_transactions());
+ StartAAAA();
}
private:
- void OnTransactionComplete(bool first_query,
- const base::TimeTicks& start_time,
+ void StartA() {
+ DCHECK(!transaction_a_);
+ DCHECK_NE(ADDRESS_FAMILY_IPV6, key_.address_family);
+ transaction_a_ = CreateTransaction(ADDRESS_FAMILY_IPV4);
+ transaction_a_->Start();
+ }
+
+ void StartAAAA() {
+ DCHECK(!transaction_aaaa_);
+ DCHECK_NE(ADDRESS_FAMILY_IPV4, key_.address_family);
+ transaction_aaaa_ = CreateTransaction(ADDRESS_FAMILY_IPV6);
+ transaction_aaaa_->Start();
+ }
+
+ scoped_ptr<DnsTransaction> CreateTransaction(AddressFamily family) {
+ DCHECK_NE(ADDRESS_FAMILY_UNSPECIFIED, family);
+ return client_->GetTransactionFactory()->CreateTransaction(
+ key_.hostname,
+ family == ADDRESS_FAMILY_IPV6 ? dns_protocol::kTypeAAAA :
+ dns_protocol::kTypeA,
+ base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
+ base::TimeTicks::Now()),
+ net_log_);
+ }
+
+ void OnTransactionComplete(const base::TimeTicks& start_time,
DnsTransaction* transaction,
int net_error,
const DnsResponse* response) {
DCHECK(transaction);
base::TimeDelta duration = base::TimeTicks::Now() - start_time;
- // Run |callback_| last since the owning Job will then delete this DnsTask.
if (net_error != OK) {
DNS_HISTOGRAM("AsyncDNS.TransactionFailure", duration);
OnFailure(net_error, DnsResponse::DNS_PARSE_OK);
return;
}
- CHECK(response);
DNS_HISTOGRAM("AsyncDNS.TransactionSuccess", duration);
switch (transaction->GetType()) {
case dns_protocol::kTypeA:
@@ -1024,6 +1069,7 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
DNS_HISTOGRAM("AsyncDNS.TransactionSuccess_AAAA", duration);
break;
}
+
AddressList addr_list;
base::TimeDelta ttl;
DnsResponse::Result result = response->ParseToAddressList(&addr_list, &ttl);
@@ -1036,58 +1082,53 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
return;
}
- bool needs_sort = false;
- if (first_query) {
- DCHECK(client_->GetConfig()) <<
- "Transaction should have been aborted when config changed!";
- if (family_ == ADDRESS_FAMILY_IPV6) {
- needs_sort = (addr_list.size() > 1);
- } else if (family_ == ADDRESS_FAMILY_UNSPECIFIED) {
- first_addr_list_ = addr_list;
- first_ttl_ = ttl;
- // Use fully-qualified domain name to avoid search.
- transaction_ = client_->GetTransactionFactory()->CreateTransaction(
- response->GetDottedName() + ".",
- dns_protocol::kTypeAAAA,
- base::Bind(&DnsTask::OnTransactionComplete, base::Unretained(this),
- false /* first_query */, base::TimeTicks::Now()),
- net_log_);
- transaction_->Start();
- return;
- }
+ ++num_completed_transactions_;
+ if (num_completed_transactions_ == 1) {
+ ttl_ = ttl;
} else {
- DCHECK_EQ(ADDRESS_FAMILY_UNSPECIFIED, family_);
- bool has_ipv6_addresses = !addr_list.empty();
- if (!first_addr_list_.empty()) {
- ttl = std::min(ttl, first_ttl_);
- // Place IPv4 addresses after IPv6.
- addr_list.insert(addr_list.end(), first_addr_list_.begin(),
- first_addr_list_.end());
- }
- needs_sort = (has_ipv6_addresses && addr_list.size() > 1);
+ ttl_ = std::min(ttl_, ttl);
}
- if (addr_list.empty()) {
+ if (transaction->GetType() == dns_protocol::kTypeA) {
+ DCHECK_EQ(transaction_a_.get(), transaction);
+ // Place IPv4 addresses after IPv6.
+ addr_list_.insert(addr_list_.end(), addr_list.begin(), addr_list.end());
+ } else {
+ DCHECK_EQ(transaction_aaaa_.get(), transaction);
+ // Place IPv6 addresses before IPv4.
+ addr_list_.insert(addr_list_.begin(), addr_list.begin(), addr_list.end());
+ }
+
+ if (needs_two_transactions() && num_completed_transactions_ == 1) {
+ // No need to repeat the suffix search.
+ key_.hostname = transaction->GetHostname();
+ delegate_->OnFirstDnsTransactionComplete();
+ return;
+ }
+
+ if (addr_list_.empty()) {
// TODO(szym): Don't fallback to ProcTask in this case.
OnFailure(ERR_NAME_NOT_RESOLVED, DnsResponse::DNS_PARSE_OK);
return;
}
- if (needs_sort) {
- // Sort could complete synchronously.
+ // If there are multiple addresses, and at least one is IPv6, need to sort
+ // them. Note that IPv6 addresses are always put before IPv4 ones, so it's
+ // sufficient to just check the family of the first address.
+ if (addr_list_.size() > 1 &&
+ addr_list_[0].GetFamily() == ADDRESS_FAMILY_IPV6) {
+ // Sort addresses if needed. Sort could complete synchronously.
client_->GetAddressSorter()->Sort(
- addr_list,
+ addr_list_,
base::Bind(&DnsTask::OnSortComplete,
AsWeakPtr(),
- base::TimeTicks::Now(),
- ttl));
+ base::TimeTicks::Now()));
} else {
- OnSuccess(addr_list, ttl);
+ OnSuccess(addr_list_);
}
}
void OnSortComplete(base::TimeTicks start_time,
- base::TimeDelta ttl,
bool success,
const AddressList& addr_list) {
if (!success) {
@@ -1107,7 +1148,7 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
return;
}
- OnSuccess(addr_list, ttl);
+ OnSuccess(addr_list);
}
void OnFailure(int net_error, DnsResponse::Result result) {
@@ -1115,26 +1156,34 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
net_log_.EndEvent(
NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
base::Bind(&NetLogDnsTaskFailedCallback, net_error, result));
- callback_.Run(net_error, AddressList(), base::TimeDelta());
+ delegate_->OnDnsTaskComplete(task_start_time_, net_error, AddressList(),
+ base::TimeDelta());
}
- void OnSuccess(const AddressList& addr_list, base::TimeDelta ttl) {
+ void OnSuccess(const AddressList& addr_list) {
net_log_.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_DNS_TASK,
addr_list.CreateNetLogCallback());
- callback_.Run(OK, addr_list, ttl);
+ delegate_->OnDnsTaskComplete(task_start_time_, OK, addr_list, ttl_);
}
DnsClient* client_;
- AddressFamily family_;
+ Key key_;
+
// The listener to the results of this DnsTask.
- Callback callback_;
+ Delegate* delegate_;
const BoundNetLog net_log_;
- scoped_ptr<DnsTransaction> transaction_;
+ scoped_ptr<DnsTransaction> transaction_a_;
+ scoped_ptr<DnsTransaction> transaction_aaaa_;
+
+ unsigned num_completed_transactions_;
- // Results from the first transaction. Used only if |family_| is unspecified.
- AddressList first_addr_list_;
- base::TimeDelta first_ttl_;
+ // These are updated as each transaction completes.
+ base::TimeDelta ttl_;
+ // IPv6 addresses must appear first in the list.
+ AddressList addr_list_;
+
+ base::TimeTicks task_start_time_;
DISALLOW_COPY_AND_ASSIGN(DnsTask);
};
@@ -1142,7 +1191,8 @@ class HostResolverImpl::DnsTask : public base::SupportsWeakPtr<DnsTask> {
//-----------------------------------------------------------------------------
// Aggregates all Requests for the same Key. Dispatched via PriorityDispatch.
-class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
+class HostResolverImpl::Job : public PrioritizedDispatcher::Job,
+ public HostResolverImpl::DnsTask::Delegate {
public:
// Creates new job for |key| where |request_net_log| is bound to the
// request that spawned it.
@@ -1155,6 +1205,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
priority_tracker_(priority),
had_non_speculative_request_(false),
had_dns_config_(false),
+ num_occupied_job_slots_(0),
dns_task_error_(OK),
creation_time_(base::TimeTicks::Now()),
priority_change_time_(creation_time_),
@@ -1178,7 +1229,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
proc_task_ = NULL;
}
// Clean up now for nice NetLog.
- dns_task_.reset(NULL);
+ KillDnsTask();
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
ERR_ABORTED);
} else if (is_queued()) {
@@ -1201,16 +1252,30 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
}
}
- // Add this job to the dispatcher.
- void Schedule() {
- handle_ = resolver_->dispatcher_.Add(this, priority());
+ // Add this job to the dispatcher. If "at_head" is true, adds at the front
+ // of the queue.
+ void Schedule(bool at_head) {
+ DCHECK(!is_queued());
+ PrioritizedDispatcher::Handle handle;
+ if (!at_head) {
+ handle = resolver_->dispatcher_.Add(this, priority());
+ } else {
+ handle = resolver_->dispatcher_.AddAtHead(this, priority());
+ }
+ // The dispatcher could have started |this| in the above call to Add, which
+ // could have called Schedule again. In that case |handle| will be null,
+ // but |handle_| may have been set by the other nested call to Schedule.
+ if (!handle.is_null()) {
+ DCHECK(handle_.is_null());
+ handle_ = handle;
+ }
}
void AddRequest(scoped_ptr<Request> req) {
DCHECK_EQ(key_.hostname, req->info().hostname());
req->set_job(this);
- priority_tracker_.Add(req->info().priority());
+ priority_tracker_.Add(req->priority());
req->request_net_log().AddEvent(
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
@@ -1245,12 +1310,11 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
LogCancelRequest(req->source_net_log(), req->request_net_log(),
req->info());
- priority_tracker_.Remove(req->info().priority());
- net_log_.AddEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
- base::Bind(&NetLogJobAttachCallback,
- req->request_net_log().source(),
- priority()));
+ priority_tracker_.Remove(req->priority());
+ net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
+ base::Bind(&NetLogJobAttachCallback,
+ req->request_net_log().source(),
+ priority()));
if (num_active_requests() > 0) {
UpdatePriority();
@@ -1272,7 +1336,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
// If DnsTask present, abort it and fall back to ProcTask.
void AbortDnsTask() {
if (dns_task_) {
- dns_task_.reset();
+ KillDnsTask();
dns_task_error_ = OK;
StartProcTask();
}
@@ -1321,6 +1385,29 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
}
private:
+ void KillDnsTask() {
+ if (dns_task_) {
+ ReduceToOneJobSlot();
+ dns_task_.reset();
+ }
+ }
+
+ // Reduce the number of job slots occupied and queued in the dispatcher
+ // to one. If the second Job slot is queued in the dispatcher, cancels the
+ // queued job. Otherwise, the second Job has been started by the
+ // PrioritizedDispatcher, so signals it is complete.
+ void ReduceToOneJobSlot() {
+ DCHECK_GE(num_occupied_job_slots_, 1u);
+ if (is_queued()) {
+ resolver_->dispatcher_.Cancel(handle_);
+ handle_.Reset();
+ } else if (num_occupied_job_slots_ > 1) {
+ resolver_->dispatcher_.OnJobFinished();
+ --num_occupied_job_slots_;
+ }
+ DCHECK_EQ(1u, num_occupied_job_slots_);
+ }
+
void UpdatePriority() {
if (is_queued()) {
if (priority() != static_cast<RequestPriority>(handle_.priority()))
@@ -1337,8 +1424,17 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
// PriorityDispatch::Job:
virtual void Start() OVERRIDE {
- DCHECK(!is_running());
+ DCHECK_LE(num_occupied_job_slots_, 1u);
+
handle_.Reset();
+ ++num_occupied_job_slots_;
+
+ if (num_occupied_job_slots_ == 2) {
+ StartSecondDnsTransaction();
+ return;
+ }
+
+ DCHECK(!is_running());
net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED);
@@ -1359,8 +1455,12 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
queue_time_after_change);
}
+ bool system_only =
+ (key_.host_resolver_flags & HOST_RESOLVER_SYSTEM_ONLY) != 0;
+
// Caution: Job::Start must not complete synchronously.
- if (had_dns_config_ && !ResemblesMulticastDNSName(key_.hostname)) {
+ if (!system_only && had_dns_config_ &&
+ !ResemblesMulticastDNSName(key_.hostname)) {
StartDnsTask();
} else {
StartProcTask();
@@ -1442,14 +1542,18 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
void StartDnsTask() {
DCHECK(resolver_->HaveDnsConfig());
- base::TimeTicks start_time = base::TimeTicks::Now();
- dns_task_.reset(new DnsTask(
- resolver_->dns_client_.get(),
- key_,
- base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this), start_time),
- net_log_));
+ dns_task_.reset(new DnsTask(resolver_->dns_client_.get(), key_, this,
+ net_log_));
- dns_task_->Start();
+ dns_task_->StartFirstTransaction();
+ // Schedule a second transaction, if needed.
+ if (dns_task_->needs_two_transactions())
+ Schedule(true);
+ }
+
+ void StartSecondDnsTransaction() {
+ DCHECK(dns_task_->needs_two_transactions());
+ dns_task_->StartSecondTransaction();
}
// Called if DnsTask fails. It is posted from StartDnsTask, so Job may be
@@ -1471,7 +1575,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
// TODO(szym): Some net errors indicate lack of connectivity. Starting
// ProcTask in that case is a waste of time.
if (resolver_->fallback_to_proctask_) {
- dns_task_.reset();
+ KillDnsTask();
StartProcTask();
} else {
UmaAsyncDnsResolveStatus(RESOLVE_STATUS_FAIL);
@@ -1479,11 +1583,13 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
}
}
- // Called by DnsTask when it completes.
- void OnDnsTaskComplete(base::TimeTicks start_time,
- int net_error,
- const AddressList& addr_list,
- base::TimeDelta ttl) {
+
+ // HostResolverImpl::DnsTask::Delegate implementation:
+
+ virtual void OnDnsTaskComplete(base::TimeTicks start_time,
+ int net_error,
+ const AddressList& addr_list,
+ base::TimeDelta ttl) OVERRIDE {
DCHECK(is_dns_running());
base::TimeDelta duration = base::TimeTicks::Now() - start_time;
@@ -1518,6 +1624,19 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
bounded_ttl);
}
+ virtual void OnFirstDnsTransactionComplete() OVERRIDE {
+ DCHECK(dns_task_->needs_two_transactions());
+ DCHECK_EQ(dns_task_->needs_another_transaction(), is_queued());
+ // No longer need to occupy two dispatcher slots.
+ ReduceToOneJobSlot();
+
+ // We already have a job slot at the dispatcher, so if the second
+ // transaction hasn't started, reuse it now instead of waiting in the queue
+ // for the second slot.
+ if (dns_task_->needs_another_transaction())
+ dns_task_->StartSecondTransaction();
+ }
+
// Performs Job's last rites. Completes all Requests. Deletes this.
void CompleteRequests(const HostCache::Entry& entry,
base::TimeDelta ttl) {
@@ -1532,12 +1651,12 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
resolver_->RemoveJob(this);
if (is_running()) {
- DCHECK(!is_queued());
if (is_proc_running()) {
+ DCHECK(!is_queued());
proc_task_->Cancel();
proc_task_ = NULL;
}
- dns_task_.reset();
+ KillDnsTask();
// Signal dispatcher that a slot has opened.
resolver_->dispatcher_.OnJobFinished();
@@ -1631,6 +1750,9 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job {
// Distinguishes measurements taken while DnsClient was fully configured.
bool had_dns_config_;
+ // Number of slots occupied by this Job in resolver's PrioritizedDispatcher.
+ unsigned num_occupied_job_slots_;
+
// Result of DnsTask.
int dns_task_error_;
@@ -1681,6 +1803,7 @@ HostResolverImpl::HostResolverImpl(
received_dns_config_(false),
num_dns_failures_(0),
probe_ipv6_support_(true),
+ use_local_ipv6_(false),
resolved_known_ipv6_hostname_(false),
additional_resolver_flags_(0),
fallback_to_proctask_(true) {
@@ -1706,19 +1829,22 @@ HostResolverImpl::HostResolverImpl(
EnsureDnsReloaderInit();
#endif
- // TODO(szym): Remove when received_dns_config_ is removed, once
- // http://crbug.com/137914 is resolved.
{
DnsConfig dns_config;
NetworkChangeNotifier::GetDnsConfig(&dns_config);
received_dns_config_ = dns_config.IsValid();
+ // Conservatively assume local IPv6 is needed when DnsConfig is not valid.
+ use_local_ipv6_ = !dns_config.IsValid() || dns_config.use_local_ipv6;
}
fallback_to_proctask_ = !ConfigureAsyncDnsNoFallbackFieldTrial();
}
HostResolverImpl::~HostResolverImpl() {
- // This will also cancel all outstanding requests.
+ // Prevent the dispatcher from starting new jobs.
+ dispatcher_.SetLimitsToZero();
+ // It's now safe for Jobs to call KillDsnTask on destruction, because
+ // OnJobComplete will not start any new jobs.
STLDeleteValues(&jobs_);
NetworkChangeNotifier::RemoveIPAddressObserver(this);
@@ -1732,6 +1858,7 @@ void HostResolverImpl::SetMaxQueuedJobs(size_t value) {
}
int HostResolverImpl::Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
@@ -1768,9 +1895,9 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
JobMap::iterator jobit = jobs_.find(key);
Job* job;
if (jobit == jobs_.end()) {
- job = new Job(weak_ptr_factory_.GetWeakPtr(), key, info.priority(),
- request_net_log);
- job->Schedule();
+ job =
+ new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, request_net_log);
+ job->Schedule(false);
// Check for queue overflow.
if (dispatcher_.num_queued_jobs() > max_queued_jobs_) {
@@ -1789,11 +1916,8 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
}
// Can't complete synchronously. Create and attach request.
- scoped_ptr<Request> req(new Request(source_net_log,
- request_net_log,
- info,
- callback,
- addresses));
+ scoped_ptr<Request> req(new Request(
+ source_net_log, request_net_log, info, priority, callback, addresses));
if (out_req)
*out_req = reinterpret_cast<RequestHandle>(req.get());
@@ -2023,35 +2147,35 @@ HostResolverImpl::Key HostResolverImpl::GetEffectiveKeyForRequest(
AddressFamily effective_address_family = info.address_family();
if (info.address_family() == ADDRESS_FAMILY_UNSPECIFIED) {
- base::TimeTicks start_time = base::TimeTicks::Now();
- // Google DNS address.
- const uint8 kIPv6Address[] =
- { 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88 };
- IPAddressNumber address(kIPv6Address,
- kIPv6Address + arraysize(kIPv6Address));
- bool rv6 = IsGloballyReachable(address, net_log);
- if (rv6)
- net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_IPV6_SUPPORTED);
-
- UMA_HISTOGRAM_TIMES("Net.IPv6ConnectDuration",
- base::TimeTicks::Now() - start_time);
- if (rv6) {
- UMA_HISTOGRAM_BOOLEAN("Net.IPv6ConnectSuccessMatch",
- default_address_family_ == ADDRESS_FAMILY_UNSPECIFIED);
+ if (probe_ipv6_support_ && !use_local_ipv6_) {
+ base::TimeTicks start_time = base::TimeTicks::Now();
+ // Google DNS address.
+ const uint8 kIPv6Address[] =
+ { 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88 };
+ IPAddressNumber address(kIPv6Address,
+ kIPv6Address + arraysize(kIPv6Address));
+ bool rv6 = IsGloballyReachable(address, net_log);
+ if (rv6)
+ net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_IPV6_SUPPORTED);
+
+ UMA_HISTOGRAM_TIMES("Net.IPv6ConnectDuration",
+ base::TimeTicks::Now() - start_time);
+ if (rv6) {
+ UMA_HISTOGRAM_BOOLEAN("Net.IPv6ConnectSuccessMatch",
+ default_address_family_ == ADDRESS_FAMILY_UNSPECIFIED);
+ } else {
+ UMA_HISTOGRAM_BOOLEAN("Net.IPv6ConnectFailureMatch",
+ default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED);
+
+ effective_address_family = ADDRESS_FAMILY_IPV4;
+ effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
+ }
} else {
- UMA_HISTOGRAM_BOOLEAN("Net.IPv6ConnectFailureMatch",
- default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED);
+ effective_address_family = default_address_family_;
}
}
- if (effective_address_family == ADDRESS_FAMILY_UNSPECIFIED &&
- default_address_family_ != ADDRESS_FAMILY_UNSPECIFIED) {
- effective_address_family = default_address_family_;
- if (probe_ipv6_support_)
- effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
- }
-
return Key(info.hostname(), effective_address_family, effective_flags);
}
@@ -2070,8 +2194,13 @@ void HostResolverImpl::AbortAllInProgressJobs() {
}
}
- // Check if no dispatcher slots leaked out.
- DCHECK_EQ(dispatcher_.num_running_jobs(), jobs_to_abort.size());
+ // Pause the dispatcher so it won't start any new dispatcher jobs while
+ // aborting the old ones. This is needed so that it won't start the second
+ // DnsTransaction for a job in |jobs_to_abort| if the DnsConfig just became
+ // invalid.
+ PrioritizedDispatcher::Limits limits = dispatcher_.GetLimits();
+ dispatcher_.SetLimits(
+ PrioritizedDispatcher::Limits(limits.reserved_slots.size(), 0));
// Life check to bail once |this| is deleted.
base::WeakPtr<HostResolverImpl> self = weak_ptr_factory_.GetWeakPtr();
@@ -2081,6 +2210,22 @@ void HostResolverImpl::AbortAllInProgressJobs() {
jobs_to_abort[i]->Abort();
jobs_to_abort[i] = NULL;
}
+
+ if (self)
+ dispatcher_.SetLimits(limits);
+}
+
+void HostResolverImpl::AbortDnsTasks() {
+ // Pause the dispatcher so it won't start any new dispatcher jobs while
+ // aborting the old ones. This is needed so that it won't start the second
+ // DnsTransaction for a job if the DnsConfig just changed.
+ PrioritizedDispatcher::Limits limits = dispatcher_.GetLimits();
+ dispatcher_.SetLimits(
+ PrioritizedDispatcher::Limits(limits.reserved_slots.size(), 0));
+
+ for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
+ it->second->AbortDnsTask();
+ dispatcher_.SetLimits(limits);
}
void HostResolverImpl::TryServingAllJobsFromHosts() {
@@ -2126,6 +2271,8 @@ void HostResolverImpl::OnDNSChanged() {
// TODO(szym): Remove once http://crbug.com/137914 is resolved.
received_dns_config_ = dns_config.IsValid();
+ // Conservatively assume local IPv6 is needed when DnsConfig is not valid.
+ use_local_ipv6_ = !dns_config.IsValid() || dns_config.use_local_ipv6;
num_dns_failures_ = 0;
@@ -2133,7 +2280,7 @@ void HostResolverImpl::OnDNSChanged() {
// the newly started jobs use the new config.
if (dns_client_.get()) {
dns_client_->SetConfig(dns_config);
- if (dns_config.IsValid())
+ if (dns_client_->GetConfig())
UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
}
@@ -2175,10 +2322,14 @@ void HostResolverImpl::OnDnsTaskResolve(int net_error) {
++num_dns_failures_;
if (num_dns_failures_ < kMaximumDnsFailures)
return;
- // Disable DnsClient until the next DNS change.
- for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
- it->second->AbortDnsTask();
+
+ // Disable DnsClient until the next DNS change. Must be done before aborting
+ // DnsTasks, since doing so may start new jobs.
dns_client_->SetConfig(DnsConfig());
+
+ // Switch jobs with active DnsTasks over to using ProcTasks.
+ AbortDnsTasks();
+
UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", false);
UMA_HISTOGRAM_CUSTOM_ENUMERATION("AsyncDNS.DnsClientDisabledReason",
std::abs(net_error),
@@ -2186,21 +2337,20 @@ void HostResolverImpl::OnDnsTaskResolve(int net_error) {
}
void HostResolverImpl::SetDnsClient(scoped_ptr<DnsClient> dns_client) {
- if (HaveDnsConfig()) {
- for (JobMap::iterator it = jobs_.begin(); it != jobs_.end(); ++it)
- it->second->AbortDnsTask();
- }
+ // DnsClient and config must be updated before aborting DnsTasks, since doing
+ // so may start new jobs.
dns_client_ = dns_client.Pass();
- if (!dns_client_ || dns_client_->GetConfig() ||
- num_dns_failures_ >= kMaximumDnsFailures) {
- return;
+ if (dns_client_ && !dns_client_->GetConfig() &&
+ num_dns_failures_ < kMaximumDnsFailures) {
+ DnsConfig dns_config;
+ NetworkChangeNotifier::GetDnsConfig(&dns_config);
+ dns_client_->SetConfig(dns_config);
+ num_dns_failures_ = 0;
+ if (dns_client_->GetConfig())
+ UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
}
- DnsConfig dns_config;
- NetworkChangeNotifier::GetDnsConfig(&dns_config);
- dns_client_->SetConfig(dns_config);
- num_dns_failures_ = 0;
- if (dns_config.IsValid())
- UMA_HISTOGRAM_BOOLEAN("AsyncDNS.DnsClientEnabled", true);
+
+ AbortDnsTasks();
}
} // namespace net
diff --git a/chromium/net/dns/host_resolver_impl.h b/chromium/net/dns/host_resolver_impl.h
index 928d07af8b8..e7f5f6541ca 100644
--- a/chromium/net/dns/host_resolver_impl.h
+++ b/chromium/net/dns/host_resolver_impl.h
@@ -131,6 +131,7 @@ class NET_EXPORT HostResolverImpl
// HostResolver methods:
virtual int Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
@@ -156,6 +157,10 @@ class NET_EXPORT HostResolverImpl
typedef std::map<Key, Job*> JobMap;
typedef ScopedVector<Request> RequestsList;
+ // Number of consecutive failures of DnsTask (with successful fallback to
+ // ProcTask) before the DnsClient is disabled until the next DNS change.
+ static const unsigned kMaximumDnsFailures;
+
// Helper used by |Resolve()| and |ResolveFromCache()|. Performs IP
// literal, cache and HOSTS lookup (if enabled), returns OK if successful,
// ERR_NAME_NOT_RESOLVED if either hostname is invalid or IP literal is
@@ -207,6 +212,11 @@ class NET_EXPORT HostResolverImpl
// requests. Might start new jobs.
void AbortAllInProgressJobs();
+ // Aborts all in progress DnsTasks. In-progress jobs will fall back to
+ // ProcTasks. Might start new jobs, if any jobs were taking up two dispatcher
+ // slots.
+ void AbortDnsTasks();
+
// Attempts to serve each Job in |jobs_| from the HOSTS file if we have
// a DnsClient with a valid DnsConfig.
void TryServingAllJobsFromHosts();
@@ -224,8 +234,10 @@ class NET_EXPORT HostResolverImpl
// and resulted in |net_error|.
void OnDnsTaskResolve(int net_error);
- // Allows the tests to catch slots leaking out of the dispatcher.
- size_t num_running_jobs_for_tests() const {
+ // Allows the tests to catch slots leaking out of the dispatcher. One
+ // HostResolverImpl::Job could occupy multiple PrioritizedDispatcher job
+ // slots.
+ size_t num_running_dispatcher_jobs_for_tests() const {
return dispatcher_.num_running_jobs();
}
@@ -267,6 +279,10 @@ class NET_EXPORT HostResolverImpl
// explicit setting in |default_address_family_| is used.
bool probe_ipv6_support_;
+ // True if DnsConfigService detected that system configuration depends on
+ // local IPv6 connectivity. Disables probing.
+ bool use_local_ipv6_;
+
// True iff ProcTask has successfully resolved a hostname known to have IPv6
// addresses using ADDRESS_FAMILY_UNSPECIFIED. Reset on IP address change.
bool resolved_known_ipv6_hostname_;
diff --git a/chromium/net/dns/host_resolver_impl_unittest.cc b/chromium/net/dns/host_resolver_impl_unittest.cc
index f6b7f690675..c314f80c24d 100644
--- a/chromium/net/dns/host_resolver_impl_unittest.cc
+++ b/chromium/net/dns/host_resolver_impl_unittest.cc
@@ -12,6 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/condition_variable.h"
@@ -197,10 +198,12 @@ class Request {
};
Request(const HostResolver::RequestInfo& info,
+ RequestPriority priority,
size_t index,
HostResolver* resolver,
Handler* handler)
: info_(info),
+ priority_(priority),
index_(index),
resolver_(resolver),
handler_(handler),
@@ -213,8 +216,12 @@ class Request {
DCHECK(!handle_);
list_ = AddressList();
result_ = resolver_->Resolve(
- info_, &list_, base::Bind(&Request::OnComplete, base::Unretained(this)),
- &handle_, BoundNetLog());
+ info_,
+ priority_,
+ &list_,
+ base::Bind(&Request::OnComplete, base::Unretained(this)),
+ &handle_,
+ BoundNetLog());
if (!list_.empty())
EXPECT_EQ(OK, result_);
return result_;
@@ -291,6 +298,7 @@ class Request {
}
HostResolver::RequestInfo info_;
+ RequestPriority priority_;
size_t index_;
HostResolver* resolver_;
Handler* handler_;
@@ -413,14 +421,29 @@ class HostResolverImplTest : public testing::Test {
HostResolverImplTest() : proc_(new MockHostResolverProc()) {}
+ void CreateResolver() {
+ CreateResolverWithLimitsAndParams(DefaultLimits(),
+ DefaultParams(proc_.get()));
+ }
+
+ // This HostResolverImpl will only allow 1 outstanding resolve at a time and
+ // perform no retries.
+ void CreateSerialResolver() {
+ HostResolverImpl::ProcTaskParams params = DefaultParams(proc_.get());
+ params.max_retry_attempts = 0u;
+ PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
+ CreateResolverWithLimitsAndParams(limits, params);
+ }
+
protected:
// A Request::Handler which is a proxy to the HostResolverImplTest fixture.
struct Handler : public Request::Handler {
virtual ~Handler() {}
// Proxy functions so that classes derived from Handler can access them.
- Request* CreateRequest(const HostResolver::RequestInfo& info) {
- return test->CreateRequest(info);
+ Request* CreateRequest(const HostResolver::RequestInfo& info,
+ RequestPriority priority) {
+ return test->CreateRequest(info, priority);
}
Request* CreateRequest(const std::string& hostname, int port) {
return test->CreateRequest(hostname, port);
@@ -435,31 +458,30 @@ class HostResolverImplTest : public testing::Test {
HostResolverImplTest* test;
};
- void CreateResolver() {
- resolver_.reset(new HostResolverImpl(HostCache::CreateDefaultCache(),
- DefaultLimits(),
- DefaultParams(proc_.get()),
- NULL));
+ // testing::Test implementation:
+ virtual void SetUp() OVERRIDE {
+ CreateResolver();
}
- // This HostResolverImpl will only allow 1 outstanding resolve at a time and
- // perform no retries.
- void CreateSerialResolver() {
- HostResolverImpl::ProcTaskParams params = DefaultParams(proc_.get());
- params.max_retry_attempts = 0u;
- PrioritizedDispatcher::Limits limits(NUM_PRIORITIES, 1);
- resolver_.reset(new HostResolverImpl(
- HostCache::CreateDefaultCache(),
- limits,
- params,
- NULL));
+ virtual void TearDown() OVERRIDE {
+ if (resolver_.get())
+ EXPECT_EQ(0u, resolver_->num_running_dispatcher_jobs_for_tests());
+ EXPECT_FALSE(proc_->HasBlockedRequests());
+ }
+
+ virtual void CreateResolverWithLimitsAndParams(
+ const PrioritizedDispatcher::Limits& limits,
+ const HostResolverImpl::ProcTaskParams& params) {
+ resolver_.reset(new HostResolverImpl(HostCache::CreateDefaultCache(),
+ limits, params, NULL));
}
// The Request will not be made until a call to |Resolve()|, and the Job will
// not start until released by |proc_->SignalXXX|.
- Request* CreateRequest(const HostResolver::RequestInfo& info) {
- Request* req = new Request(info, requests_.size(), resolver_.get(),
- handler_.get());
+ Request* CreateRequest(const HostResolver::RequestInfo& info,
+ RequestPriority priority) {
+ Request* req = new Request(
+ info, priority, requests_.size(), resolver_.get(), handler_.get());
requests_.push_back(req);
return req;
}
@@ -469,9 +491,8 @@ class HostResolverImplTest : public testing::Test {
RequestPriority priority,
AddressFamily family) {
HostResolver::RequestInfo info(HostPortPair(hostname, port));
- info.set_priority(priority);
info.set_address_family(family);
- return CreateRequest(info);
+ return CreateRequest(info, priority);
}
Request* CreateRequest(const std::string& hostname,
@@ -488,25 +509,15 @@ class HostResolverImplTest : public testing::Test {
return CreateRequest(hostname, kDefaultPort);
}
- virtual void SetUp() OVERRIDE {
- CreateResolver();
- }
-
- virtual void TearDown() OVERRIDE {
- if (resolver_.get())
- EXPECT_EQ(0u, resolver_->num_running_jobs_for_tests());
- EXPECT_FALSE(proc_->HasBlockedRequests());
- }
-
void set_handler(Handler* handler) {
handler_.reset(handler);
handler_->test = this;
}
// Friendship is not inherited, so use proxies to access those.
- size_t num_running_jobs() const {
+ size_t num_running_dispatcher_jobs() const {
DCHECK(resolver_.get());
- return resolver_->num_running_jobs_for_tests();
+ return resolver_->num_running_dispatcher_jobs_for_tests();
}
void set_fallback_to_proctask(bool fallback_to_proctask) {
@@ -514,6 +525,10 @@ class HostResolverImplTest : public testing::Test {
resolver_->fallback_to_proctask_ = fallback_to_proctask;
}
+ static unsigned maximum_dns_failures() {
+ return HostResolverImpl::kMaximumDnsFailures;
+ }
+
scoped_refptr<MockHostResolverProc> proc_;
scoped_ptr<HostResolverImpl> resolver_;
ScopedVector<Request> requests_;
@@ -817,7 +832,8 @@ TEST_F(HostResolverImplTest, BypassCache) {
// longer service the request synchronously.
HostResolver::RequestInfo info(HostPortPair(hostname, 71));
info.set_allow_cached_response(false);
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING,
+ CreateRequest(info, DEFAULT_PRIORITY)->Resolve());
} else if (71 == req->info().port()) {
// Test is done.
base::MessageLoop::current()->Quit();
@@ -889,7 +905,7 @@ TEST_F(HostResolverImplTest, ObeyPoolConstraintsAfterIPAddressChange) {
EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[0]->WaitForResult());
- EXPECT_EQ(1u, num_running_jobs());
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
EXPECT_FALSE(requests_[1]->completed());
EXPECT_FALSE(requests_[2]->completed());
@@ -1189,14 +1205,15 @@ TEST_F(HostResolverImplTest, ResolveFromCache) {
HostResolver::RequestInfo info(HostPortPair("just.testing", 80));
// First hit will miss the cache.
- EXPECT_EQ(ERR_DNS_CACHE_MISS, CreateRequest(info)->ResolveFromCache());
+ EXPECT_EQ(ERR_DNS_CACHE_MISS,
+ CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
// This time, we fetch normally.
- EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info, DEFAULT_PRIORITY)->Resolve());
EXPECT_EQ(OK, requests_[1]->WaitForResult());
// Now we should be able to fetch from the cache.
- EXPECT_EQ(OK, CreateRequest(info)->ResolveFromCache());
+ EXPECT_EQ(OK, CreateRequest(info, DEFAULT_PRIORITY)->ResolveFromCache());
EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.1.42", 80));
}
@@ -1228,7 +1245,7 @@ TEST_F(HostResolverImplTest, MultipleAttempts) {
// Resolve "host1".
HostResolver::RequestInfo info(HostPortPair("host1", 70));
- Request* req = CreateRequest(info);
+ Request* req = CreateRequest(info, DEFAULT_PRIORITY);
EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
// Resolve returns -4 to indicate that 3rd attempt has resolved the host.
@@ -1255,36 +1272,70 @@ DnsConfig CreateValidDnsConfig() {
// Specialized fixture for tests of DnsTask.
class HostResolverImplDnsTest : public HostResolverImplTest {
+ public:
+ HostResolverImplDnsTest() : dns_client_(NULL) {}
+
protected:
+ // testing::Test implementation:
virtual void SetUp() OVERRIDE {
- AddDnsRule("nx", dns_protocol::kTypeA, MockDnsClientRule::FAIL);
- AddDnsRule("nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL);
- AddDnsRule("ok", dns_protocol::kTypeA, MockDnsClientRule::OK);
- AddDnsRule("ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK);
- AddDnsRule("4ok", dns_protocol::kTypeA, MockDnsClientRule::OK);
- AddDnsRule("4ok", dns_protocol::kTypeAAAA, MockDnsClientRule::EMPTY);
- AddDnsRule("6ok", dns_protocol::kTypeA, MockDnsClientRule::EMPTY);
- AddDnsRule("6ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK);
- AddDnsRule("4nx", dns_protocol::kTypeA, MockDnsClientRule::OK);
- AddDnsRule("4nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL);
+ AddDnsRule("nx", dns_protocol::kTypeA, MockDnsClientRule::FAIL, false);
+ AddDnsRule("nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL, false);
+ AddDnsRule("ok", dns_protocol::kTypeA, MockDnsClientRule::OK, false);
+ AddDnsRule("ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK, false);
+ AddDnsRule("4ok", dns_protocol::kTypeA, MockDnsClientRule::OK, false);
+ AddDnsRule("4ok", dns_protocol::kTypeAAAA, MockDnsClientRule::EMPTY, false);
+ AddDnsRule("6ok", dns_protocol::kTypeA, MockDnsClientRule::EMPTY, false);
+ AddDnsRule("6ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK, false);
+ AddDnsRule("4nx", dns_protocol::kTypeA, MockDnsClientRule::OK, false);
+ AddDnsRule("4nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL, false);
+ AddDnsRule("empty", dns_protocol::kTypeA, MockDnsClientRule::EMPTY, false);
+ AddDnsRule("empty", dns_protocol::kTypeAAAA, MockDnsClientRule::EMPTY,
+ false);
+
+ AddDnsRule("slow_nx", dns_protocol::kTypeA, MockDnsClientRule::FAIL, true);
+ AddDnsRule("slow_nx", dns_protocol::kTypeAAAA, MockDnsClientRule::FAIL,
+ true);
+
+ AddDnsRule("4slow_ok", dns_protocol::kTypeA, MockDnsClientRule::OK, true);
+ AddDnsRule("4slow_ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK,
+ false);
+ AddDnsRule("6slow_ok", dns_protocol::kTypeA, MockDnsClientRule::OK, false);
+ AddDnsRule("6slow_ok", dns_protocol::kTypeAAAA, MockDnsClientRule::OK,
+ true);
+ AddDnsRule("4slow_4ok", dns_protocol::kTypeA, MockDnsClientRule::OK, true);
+ AddDnsRule("4slow_4ok", dns_protocol::kTypeAAAA, MockDnsClientRule::EMPTY,
+ false);
+ AddDnsRule("4slow_4timeout", dns_protocol::kTypeA,
+ MockDnsClientRule::TIMEOUT, true);
+ AddDnsRule("4slow_4timeout", dns_protocol::kTypeAAAA, MockDnsClientRule::OK,
+ false);
+ AddDnsRule("4slow_6timeout", dns_protocol::kTypeA,
+ MockDnsClientRule::OK, true);
+ AddDnsRule("4slow_6timeout", dns_protocol::kTypeAAAA,
+ MockDnsClientRule::TIMEOUT, false);
CreateResolver();
}
- void CreateResolver() {
+ // HostResolverImplTest implementation:
+ virtual void CreateResolverWithLimitsAndParams(
+ const PrioritizedDispatcher::Limits& limits,
+ const HostResolverImpl::ProcTaskParams& params) OVERRIDE {
resolver_.reset(new HostResolverImpl(HostCache::CreateDefaultCache(),
- DefaultLimits(),
- DefaultParams(proc_.get()),
+ limits,
+ params,
NULL));
// Disable IPv6 support probing.
resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
- resolver_->SetDnsClient(CreateMockDnsClient(DnsConfig(), dns_rules_));
+ dns_client_ = new MockDnsClient(DnsConfig(), dns_rules_);
+ resolver_->SetDnsClient(scoped_ptr<DnsClient>(dns_client_));
}
// Adds a rule to |dns_rules_|. Must be followed by |CreateResolver| to apply.
void AddDnsRule(const std::string& prefix,
uint16 qtype,
- MockDnsClientRule::Result result) {
- dns_rules_.push_back(MockDnsClientRule(prefix, qtype, result));
+ MockDnsClientRule::Result result,
+ bool delay) {
+ dns_rules_.push_back(MockDnsClientRule(prefix, qtype, result, delay));
}
void ChangeDnsConfig(const DnsConfig& config) {
@@ -1294,6 +1345,8 @@ class HostResolverImplDnsTest : public HostResolverImplTest {
}
MockDnsClientRuleList dns_rules_;
+ // Owned by |resolver_|.
+ MockDnsClient* dns_client_;
};
// TODO(szym): Test AbortAllInProgressJobs due to DnsConfig change.
@@ -1361,7 +1414,8 @@ TEST_F(HostResolverImplDnsTest, NoFallbackToProcTask) {
// Simulate the case when the preference or policy has disabled the DNS client
// causing AbortDnsTasks.
- resolver_->SetDnsClient(CreateMockDnsClient(DnsConfig(), dns_rules_));
+ resolver_->SetDnsClient(
+ scoped_ptr<DnsClient>(new MockDnsClient(DnsConfig(), dns_rules_)));
ChangeDnsConfig(CreateValidDnsConfig());
// First request is resolved by MockDnsClient, others should fail due to
@@ -1509,6 +1563,24 @@ TEST_F(HostResolverImplDnsTest, BypassDnsTask) {
EXPECT_EQ(OK, requests_[i]->WaitForResult()) << i;
}
+TEST_F(HostResolverImplDnsTest, SystemOnlyBypassesDnsTask) {
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ proc_->AddRuleForAllFamilies(std::string(), std::string());
+
+ HostResolver::RequestInfo info_bypass(HostPortPair("ok", 80));
+ info_bypass.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY);
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info_bypass, MEDIUM)->Resolve());
+
+ HostResolver::RequestInfo info(HostPortPair("ok", 80));
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(info, MEDIUM)->Resolve());
+
+ proc_->SignalMultiple(requests_.size());
+
+ EXPECT_EQ(ERR_NAME_NOT_RESOLVED, requests_[0]->WaitForResult());
+ EXPECT_EQ(OK, requests_[1]->WaitForResult());
+}
+
TEST_F(HostResolverImplDnsTest, DisableDnsClientOnPersistentFailure) {
ChangeDnsConfig(CreateValidDnsConfig());
@@ -1520,7 +1592,7 @@ TEST_F(HostResolverImplDnsTest, DisableDnsClientOnPersistentFailure) {
EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
EXPECT_EQ(OK, req->WaitForResult());
- for (unsigned i = 0; i < 20; ++i) {
+ for (unsigned i = 0; i < maximum_dns_failures(); ++i) {
// Use custom names to require separate Jobs.
std::string hostname = base::StringPrintf("nx_%u", i);
// Ensure fallback to ProcTask succeeds.
@@ -1585,7 +1657,8 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
DefaultLimits(),
DefaultParams(proc.get()),
NULL));
- resolver_->SetDnsClient(CreateMockDnsClient(DnsConfig(), dns_rules_));
+ resolver_->SetDnsClient(
+ scoped_ptr<DnsClient>(new MockDnsClient(DnsConfig(), dns_rules_)));
resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
// Get the expected output.
@@ -1609,7 +1682,7 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
// Try without DnsClient.
ChangeDnsConfig(DnsConfig());
- Request* req = CreateRequest(info);
+ Request* req = CreateRequest(info, DEFAULT_PRIORITY);
// It is resolved via getaddrinfo, so expect asynchronous result.
EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
EXPECT_EQ(OK, req->WaitForResult());
@@ -1630,7 +1703,7 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
config.hosts = hosts;
ChangeDnsConfig(config);
- req = CreateRequest(info);
+ req = CreateRequest(info, DEFAULT_PRIORITY);
// Expect synchronous resolution from DnsHosts.
EXPECT_EQ(OK, req->Resolve());
@@ -1638,4 +1711,346 @@ TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
EXPECT_EQ(saw_ipv6, req->HasAddress("::1", 80));
}
+// Cancel a request with a single DNS transaction active.
+TEST_F(HostResolverImplDnsTest, CancelWithOneTransactionActive) {
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+ requests_[0]->Cancel();
+
+ // Dispatcher state checked in TearDown.
+}
+
+// Cancel a request with a single DNS transaction active and another pending.
+TEST_F(HostResolverImplDnsTest, CancelWithOneTransactionActiveOnePending) {
+ CreateSerialResolver();
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+ requests_[0]->Cancel();
+
+ // Dispatcher state checked in TearDown.
+}
+
+// Cancel a request with two DNS transactions active.
+TEST_F(HostResolverImplDnsTest, CancelWithTwoTransactionsActive) {
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_EQ(2u, num_running_dispatcher_jobs());
+ requests_[0]->Cancel();
+
+ // Dispatcher state checked in TearDown.
+}
+
+// Delete a resolver with some active requests and some queued requests.
+TEST_F(HostResolverImplDnsTest, DeleteWithActiveTransactions) {
+ // At most 10 Jobs active at once.
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, 10u),
+ DefaultParams(proc_.get()));
+
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ // First active job is an IPv4 request.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80, MEDIUM,
+ ADDRESS_FAMILY_IPV4)->Resolve());
+
+ // Add 10 more DNS lookups for different hostnames. First 4 should have two
+ // active jobs, next one has a single active job, and one pending. Others
+ // should all be queued.
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(
+ base::StringPrintf("ok%i", i))->Resolve());
+ }
+ EXPECT_EQ(10u, num_running_dispatcher_jobs());
+
+ resolver_.reset();
+}
+
+// Cancel a request with only the IPv6 transaction active.
+TEST_F(HostResolverImplDnsTest, CancelWithIPv6TransactionActive) {
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("6slow_ok", 80)->Resolve());
+ EXPECT_EQ(2u, num_running_dispatcher_jobs());
+
+ // The IPv4 request should complete, the IPv6 request is still pending.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+ requests_[0]->Cancel();
+
+ // Dispatcher state checked in TearDown.
+}
+
+// Cancel a request with only the IPv4 transaction pending.
+TEST_F(HostResolverImplDnsTest, CancelWithIPv4TransactionPending) {
+ set_fallback_to_proctask(false);
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_ok", 80)->Resolve());
+ EXPECT_EQ(2u, num_running_dispatcher_jobs());
+
+ // The IPv6 request should complete, the IPv4 request is still pending.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+
+ requests_[0]->Cancel();
+}
+
+// Test cases where AAAA completes first.
+TEST_F(HostResolverImplDnsTest, AAAACompletesFirst) {
+ set_fallback_to_proctask(false);
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_ok", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_4ok", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_4timeout", 80)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_6timeout", 80)->Resolve());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(requests_[0]->completed());
+ EXPECT_FALSE(requests_[1]->completed());
+ EXPECT_FALSE(requests_[2]->completed());
+ // The IPv6 of the third request should have failed and resulted in cancelling
+ // the IPv4 request.
+ EXPECT_TRUE(requests_[3]->completed());
+ EXPECT_EQ(ERR_DNS_TIMED_OUT, requests_[3]->result());
+ EXPECT_EQ(3u, num_running_dispatcher_jobs());
+
+ dns_client_->CompleteDelayedTransactions();
+ EXPECT_TRUE(requests_[0]->completed());
+ EXPECT_EQ(OK, requests_[0]->result());
+ EXPECT_EQ(2u, requests_[0]->NumberOfAddresses());
+ EXPECT_TRUE(requests_[0]->HasAddress("127.0.0.1", 80));
+ EXPECT_TRUE(requests_[0]->HasAddress("::1", 80));
+
+ EXPECT_TRUE(requests_[1]->completed());
+ EXPECT_EQ(OK, requests_[1]->result());
+ EXPECT_EQ(1u, requests_[1]->NumberOfAddresses());
+ EXPECT_TRUE(requests_[1]->HasAddress("127.0.0.1", 80));
+
+ EXPECT_TRUE(requests_[2]->completed());
+ EXPECT_EQ(ERR_DNS_TIMED_OUT, requests_[2]->result());
+}
+
+// Test the case where only a single transaction slot is available.
+TEST_F(HostResolverImplDnsTest, SerialResolver) {
+ CreateSerialResolver();
+ set_fallback_to_proctask(false);
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(requests_[0]->completed());
+ EXPECT_EQ(OK, requests_[0]->result());
+ EXPECT_EQ(2u, requests_[0]->NumberOfAddresses());
+ EXPECT_TRUE(requests_[0]->HasAddress("127.0.0.1", 80));
+ EXPECT_TRUE(requests_[0]->HasAddress("::1", 80));
+}
+
+// Test the case where the AAAA query is started when another transaction
+// completes.
+TEST_F(HostResolverImplDnsTest, AAAAStartsAfterOtherJobFinishes) {
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, 2),
+ DefaultParams(proc_.get()));
+ set_fallback_to_proctask(false);
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80, MEDIUM,
+ ADDRESS_FAMILY_IPV4)->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING,
+ CreateRequest("4slow_ok", 80, MEDIUM)->Resolve());
+ // An IPv4 request should have been started pending for each job.
+ EXPECT_EQ(2u, num_running_dispatcher_jobs());
+
+ // Request 0's IPv4 request should complete, starting Request 1's IPv6
+ // request, which should also complete.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, num_running_dispatcher_jobs());
+ EXPECT_TRUE(requests_[0]->completed());
+ EXPECT_FALSE(requests_[1]->completed());
+
+ dns_client_->CompleteDelayedTransactions();
+ EXPECT_TRUE(requests_[1]->completed());
+ EXPECT_EQ(OK, requests_[1]->result());
+ EXPECT_EQ(2u, requests_[1]->NumberOfAddresses());
+ EXPECT_TRUE(requests_[1]->HasAddress("127.0.0.1", 80));
+ EXPECT_TRUE(requests_[1]->HasAddress("::1", 80));
+}
+
+// Tests the case that a Job with a single transaction receives an empty address
+// list, triggering fallback to ProcTask.
+TEST_F(HostResolverImplDnsTest, IPv4EmptyFallback) {
+ ChangeDnsConfig(CreateValidDnsConfig());
+ proc_->AddRuleForAllFamilies("empty_fallback", "192.168.0.1");
+ proc_->SignalMultiple(1u);
+ EXPECT_EQ(ERR_IO_PENDING,
+ CreateRequest("empty_fallback", 80, MEDIUM,
+ ADDRESS_FAMILY_IPV4)->Resolve());
+ EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
+}
+
+// Tests the case that a Job with two transactions receives two empty address
+// lists, triggering fallback to ProcTask.
+TEST_F(HostResolverImplDnsTest, UnspecEmptyFallback) {
+ ChangeDnsConfig(CreateValidDnsConfig());
+ proc_->AddRuleForAllFamilies("empty_fallback", "192.168.0.1");
+ proc_->SignalMultiple(1u);
+ EXPECT_EQ(ERR_IO_PENDING,
+ CreateRequest("empty_fallback", 80, MEDIUM,
+ ADDRESS_FAMILY_UNSPECIFIED)->Resolve());
+ EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
+}
+
+// Tests getting a new invalid DnsConfig while there are active DnsTasks.
+TEST_F(HostResolverImplDnsTest, InvalidDnsConfigWithPendingRequests) {
+ // At most 3 jobs active at once. This number is important, since we want to
+ // make sure that aborting the first HostResolverImpl::Job does not trigger
+ // another DnsTransaction on the second Job when it releases its second
+ // prioritized dispatcher slot.
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, 3u),
+ DefaultParams(proc_.get()));
+
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ proc_->AddRuleForAllFamilies("slow_nx1", "192.168.0.1");
+ proc_->AddRuleForAllFamilies("slow_nx2", "192.168.0.2");
+ proc_->AddRuleForAllFamilies("ok", "192.168.0.3");
+
+ // First active job gets two slots.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_nx1")->Resolve());
+ // Next job gets one slot, and waits on another.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_nx2")->Resolve());
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok")->Resolve());
+
+ EXPECT_EQ(3u, num_running_dispatcher_jobs());
+
+ // Clear DNS config. Two in-progress jobs should be aborted, and the next one
+ // should use a ProcTask.
+ ChangeDnsConfig(DnsConfig());
+ EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[0]->WaitForResult());
+ EXPECT_EQ(ERR_NETWORK_CHANGED, requests_[1]->WaitForResult());
+
+ // Finish up the third job. Should bypass the DnsClient, and get its results
+ // from MockHostResolverProc.
+ EXPECT_FALSE(requests_[2]->completed());
+ proc_->SignalMultiple(1u);
+ EXPECT_EQ(OK, requests_[2]->WaitForResult());
+ EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.0.3", 80));
+}
+
+// Tests the case that DnsClient is automatically disabled due to failures
+// while there are active DnsTasks.
+TEST_F(HostResolverImplDnsTest,
+ AutomaticallyDisableDnsClientWithPendingRequests) {
+ // Trying different limits is important for this test: Different limits
+ // result in different behavior when aborting in-progress DnsTasks. Having
+ // a DnsTask that has one job active and one in the queue when another job
+ // occupying two slots has its DnsTask aborted is the case most likely to run
+ // into problems.
+ for (size_t limit = 1u; limit < 6u; ++limit) {
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, limit),
+ DefaultParams(proc_.get()));
+
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ // Queue up enough failures to disable DnsTasks. These will all fall back
+ // to ProcTasks, and succeed there.
+ for (unsigned i = 0u; i < maximum_dns_failures(); ++i) {
+ std::string host = base::StringPrintf("nx%u", i);
+ proc_->AddRuleForAllFamilies(host, "192.168.0.1");
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest(host)->Resolve());
+ }
+
+ // These requests should all bypass DnsTasks, due to the above failures,
+ // so should end up using ProcTasks.
+ proc_->AddRuleForAllFamilies("slow_ok1", "192.168.0.2");
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok1")->Resolve());
+ proc_->AddRuleForAllFamilies("slow_ok2", "192.168.0.3");
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok2")->Resolve());
+ proc_->AddRuleForAllFamilies("slow_ok3", "192.168.0.4");
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok3")->Resolve());
+ proc_->SignalMultiple(maximum_dns_failures() + 3);
+
+ for (size_t i = 0u; i < maximum_dns_failures(); ++i) {
+ EXPECT_EQ(OK, requests_[i]->WaitForResult());
+ EXPECT_TRUE(requests_[i]->HasOneAddress("192.168.0.1", 80));
+ }
+
+ EXPECT_EQ(OK, requests_[maximum_dns_failures()]->WaitForResult());
+ EXPECT_TRUE(requests_[maximum_dns_failures()]->HasOneAddress(
+ "192.168.0.2", 80));
+ EXPECT_EQ(OK, requests_[maximum_dns_failures() + 1]->WaitForResult());
+ EXPECT_TRUE(requests_[maximum_dns_failures() + 1]->HasOneAddress(
+ "192.168.0.3", 80));
+ EXPECT_EQ(OK, requests_[maximum_dns_failures() + 2]->WaitForResult());
+ EXPECT_TRUE(requests_[maximum_dns_failures() + 2]->HasOneAddress(
+ "192.168.0.4", 80));
+ requests_.clear();
+ }
+}
+
+// Tests a call to SetDnsClient while there are active DnsTasks.
+TEST_F(HostResolverImplDnsTest, ManuallyDisableDnsClientWithPendingRequests) {
+ // At most 3 jobs active at once. This number is important, since we want to
+ // make sure that aborting the first HostResolverImpl::Job does not trigger
+ // another DnsTransaction on the second Job when it releases its second
+ // prioritized dispatcher slot.
+ CreateResolverWithLimitsAndParams(
+ PrioritizedDispatcher::Limits(NUM_PRIORITIES, 3u),
+ DefaultParams(proc_.get()));
+
+ resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
+ ChangeDnsConfig(CreateValidDnsConfig());
+
+ proc_->AddRuleForAllFamilies("slow_ok1", "192.168.0.1");
+ proc_->AddRuleForAllFamilies("slow_ok2", "192.168.0.2");
+ proc_->AddRuleForAllFamilies("ok", "192.168.0.3");
+
+ // First active job gets two slots.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok1")->Resolve());
+ // Next job gets one slot, and waits on another.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("slow_ok2")->Resolve());
+ // Next one is queued.
+ EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok")->Resolve());
+
+ EXPECT_EQ(3u, num_running_dispatcher_jobs());
+
+ // Clear DnsClient. The two in-progress jobs should fall back to a ProcTask,
+ // and the next one should be started with a ProcTask.
+ resolver_->SetDnsClient(scoped_ptr<DnsClient>());
+
+ // All three in-progress requests should now be running a ProcTask.
+ EXPECT_EQ(3u, num_running_dispatcher_jobs());
+ proc_->SignalMultiple(3u);
+
+ EXPECT_EQ(OK, requests_[0]->WaitForResult());
+ EXPECT_TRUE(requests_[0]->HasOneAddress("192.168.0.1", 80));
+ EXPECT_EQ(OK, requests_[1]->WaitForResult());
+ EXPECT_TRUE(requests_[1]->HasOneAddress("192.168.0.2", 80));
+ EXPECT_EQ(OK, requests_[2]->WaitForResult());
+ EXPECT_TRUE(requests_[2]->HasOneAddress("192.168.0.3", 80));
+}
+
} // namespace net
diff --git a/chromium/net/dns/mapped_host_resolver.cc b/chromium/net/dns/mapped_host_resolver.cc
index 4db7bc97928..7b182077cfb 100644
--- a/chromium/net/dns/mapped_host_resolver.cc
+++ b/chromium/net/dns/mapped_host_resolver.cc
@@ -19,6 +19,7 @@ MappedHostResolver::~MappedHostResolver() {
}
int MappedHostResolver::Resolve(const RequestInfo& original_info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
@@ -28,7 +29,7 @@ int MappedHostResolver::Resolve(const RequestInfo& original_info,
if (rv != OK)
return rv;
- return impl_->Resolve(info, addresses, callback, out_req, net_log);
+ return impl_->Resolve(info, priority, addresses, callback, out_req, net_log);
}
int MappedHostResolver::ResolveFromCache(const RequestInfo& original_info,
diff --git a/chromium/net/dns/mapped_host_resolver.h b/chromium/net/dns/mapped_host_resolver.h
index 50062a9848e..a121d4ed4c4 100644
--- a/chromium/net/dns/mapped_host_resolver.h
+++ b/chromium/net/dns/mapped_host_resolver.h
@@ -46,6 +46,7 @@ class NET_EXPORT MappedHostResolver : public HostResolver {
// HostResolver methods:
virtual int Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
diff --git a/chromium/net/dns/mapped_host_resolver_unittest.cc b/chromium/net/dns/mapped_host_resolver_unittest.cc
index d8594663c9d..fbbfde8adff 100644
--- a/chromium/net/dns/mapped_host_resolver_unittest.cc
+++ b/chromium/net/dns/mapped_host_resolver_unittest.cc
@@ -40,10 +40,13 @@ TEST(MappedHostResolverTest, Inclusion) {
// Try resolving "www.google.com:80". There are no mappings yet, so this
// hits |resolver_impl| and fails.
TestCompletionCallback callback;
- rv = resolver->Resolve(HostResolver::RequestInfo(
- HostPortPair("www.google.com", 80)),
- &address_list, callback.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
@@ -52,10 +55,13 @@ TEST(MappedHostResolverTest, Inclusion) {
EXPECT_TRUE(resolver->AddRuleFromString("map *.google.com baz.com"));
// Try resolving "www.google.com:80". Should be remapped to "baz.com:80".
- rv = resolver->Resolve(HostResolver::RequestInfo(
- HostPortPair("www.google.com", 80)),
- &address_list, callback.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -64,7 +70,10 @@ TEST(MappedHostResolverTest, Inclusion) {
// Try resolving "foo.com:77". This will NOT be remapped, so result
// is "foo.com:77".
rv = resolver->Resolve(HostResolver::RequestInfo(HostPortPair("foo.com", 77)),
- &address_list, callback.callback(), NULL,
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback.callback(),
+ NULL,
BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
@@ -75,10 +84,13 @@ TEST(MappedHostResolverTest, Inclusion) {
EXPECT_TRUE(resolver->AddRuleFromString("Map *.org proxy:99"));
// Try resolving "chromium.org:61". Should be remapped to "proxy:99".
- rv = resolver->Resolve(HostResolver::RequestInfo
- (HostPortPair("chromium.org", 61)),
- &address_list, callback.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("chromium.org", 61)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -107,20 +119,26 @@ TEST(MappedHostResolverTest, Exclusion) {
EXPECT_TRUE(resolver->AddRuleFromString("EXCLUDE *.google.com"));
// Try resolving "www.google.com". Should not be remapped due to exclusion).
- rv = resolver->Resolve(HostResolver::RequestInfo(
- HostPortPair("www.google.com", 80)),
- &address_list, callback.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.3:80", FirstAddress(address_list));
// Try resolving "chrome.com:80". Should be remapped to "baz:80".
- rv = resolver->Resolve(HostResolver::RequestInfo(
- HostPortPair("chrome.com", 80)),
- &address_list, callback.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("chrome.com", 80)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -145,20 +163,26 @@ TEST(MappedHostResolverTest, SetRulesFromString) {
resolver->SetRulesFromString("map *.com baz , map *.net bar:60");
// Try resolving "www.google.com". Should be remapped to "baz".
- rv = resolver->Resolve(HostResolver::RequestInfo(
- HostPortPair("www.google.com", 80)),
- &address_list, callback.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
EXPECT_EQ("192.168.1.7:80", FirstAddress(address_list));
// Try resolving "chrome.net:80". Should be remapped to "bar:60".
- rv = resolver->Resolve(HostResolver::RequestInfo(
- HostPortPair("chrome.net", 80)),
- &address_list, callback.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("chrome.net", 80)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback.WaitForResult();
EXPECT_EQ(OK, rv);
@@ -196,18 +220,24 @@ TEST(MappedHostResolverTest, MapToError) {
// Try resolving www.google.com --> Should give an error.
TestCompletionCallback callback1;
- rv = resolver->Resolve(HostResolver::RequestInfo(
- HostPortPair("www.google.com", 80)),
- &address_list, callback1.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("www.google.com", 80)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback1.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv);
// Try resolving www.foo.com --> Should succeed.
TestCompletionCallback callback2;
- rv = resolver->Resolve(HostResolver::RequestInfo(
- HostPortPair("www.foo.com", 80)),
- &address_list, callback2.callback(), NULL,
- BoundNetLog());
+ rv = resolver->Resolve(
+ HostResolver::RequestInfo(HostPortPair("www.foo.com", 80)),
+ DEFAULT_PRIORITY,
+ &address_list,
+ callback2.callback(),
+ NULL,
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
rv = callback2.WaitForResult();
EXPECT_EQ(OK, rv);
diff --git a/chromium/net/dns/mdns_client.cc b/chromium/net/dns/mdns_client.cc
index 631b01a706e..d0273c5784a 100644
--- a/chromium/net/dns/mdns_client.cc
+++ b/chromium/net/dns/mdns_client.cc
@@ -4,14 +4,43 @@
#include "net/dns/mdns_client.h"
+#include "net/dns/dns_protocol.h"
#include "net/dns/mdns_client_impl.h"
namespace net {
+namespace {
+
+const char kMDnsMulticastGroupIPv4[] = "224.0.0.251";
+const char kMDnsMulticastGroupIPv6[] = "FF02::FB";
+
+IPEndPoint GetMDnsIPEndPoint(const char* address) {
+ IPAddressNumber multicast_group_number;
+ bool success = ParseIPLiteralToNumber(address,
+ &multicast_group_number);
+ DCHECK(success);
+ return IPEndPoint(multicast_group_number,
+ dns_protocol::kDefaultPortMulticast);
+}
+
+} // namespace
+
// static
scoped_ptr<MDnsClient> MDnsClient::CreateDefault() {
return scoped_ptr<MDnsClient>(
new MDnsClientImpl(MDnsConnection::SocketFactory::CreateDefault()));
}
+IPEndPoint GetMDnsIPEndPoint(AddressFamily address_family) {
+ switch (address_family) {
+ case ADDRESS_FAMILY_IPV4:
+ return GetMDnsIPEndPoint(kMDnsMulticastGroupIPv4);
+ case ADDRESS_FAMILY_IPV6:
+ return GetMDnsIPEndPoint(kMDnsMulticastGroupIPv6);
+ default:
+ NOTREACHED();
+ return IPEndPoint();
+ }
+}
+
} // namespace net
diff --git a/chromium/net/dns/mdns_client.h b/chromium/net/dns/mdns_client.h
index f12c6e292cd..71006d69b01 100644
--- a/chromium/net/dns/mdns_client.h
+++ b/chromium/net/dns/mdns_client.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/callback.h"
+#include "net/base/ip_endpoint.h"
#include "net/dns/dns_query.h"
#include "net/dns/dns_response.h"
#include "net/dns/record_parsed.h"
@@ -154,5 +155,7 @@ class NET_EXPORT MDnsClient {
static scoped_ptr<MDnsClient> CreateDefault();
};
+IPEndPoint NET_EXPORT GetMDnsIPEndPoint(AddressFamily address_family);
+
} // namespace net
#endif // NET_DNS_MDNS_CLIENT_H_
diff --git a/chromium/net/dns/mdns_client_impl.cc b/chromium/net/dns/mdns_client_impl.cc
index 8f79edf4cdf..1dfc21b37c6 100644
--- a/chromium/net/dns/mdns_client_impl.cc
+++ b/chromium/net/dns/mdns_client_impl.cc
@@ -24,8 +24,6 @@
namespace net {
namespace {
-const char kMDnsMulticastGroupIPv4[] = "224.0.0.251";
-const char kMDnsMulticastGroupIPv6[] = "FF02::FB";
const unsigned MDnsTransactionTimeoutSeconds = 3;
}
@@ -41,11 +39,6 @@ MDnsConnection::SocketHandler::~SocketHandler() {
}
int MDnsConnection::SocketHandler::Start() {
- int rv = BindSocket();
- if (rv != OK) {
- return rv;
- }
-
return DoLoop(0);
}
@@ -87,7 +80,7 @@ void MDnsConnection::SocketHandler::SendDone(int rv) {
// TODO(noamsml): Retry logic.
}
-int MDnsConnection::SocketHandler::BindSocket() {
+int MDnsConnection::SocketHandler::Bind() {
IPAddressNumber address_any(multicast_addr_.address().size());
IPEndPoint bind_endpoint(address_any, multicast_addr_.port());
@@ -102,41 +95,51 @@ int MDnsConnection::SocketHandler::BindSocket() {
return socket_->JoinGroup(multicast_addr_.address());
}
-MDnsConnection::MDnsConnection(MDnsConnection::SocketFactory* socket_factory,
- MDnsConnection::Delegate* delegate)
- : socket_handler_ipv4_(this,
- GetMDnsIPEndPoint(kMDnsMulticastGroupIPv4),
- socket_factory),
- socket_handler_ipv6_(this,
- GetMDnsIPEndPoint(kMDnsMulticastGroupIPv6),
- socket_factory),
+MDnsConnection::MDnsConnection(MDnsConnection::Delegate* delegate) :
delegate_(delegate) {
}
MDnsConnection::~MDnsConnection() {
}
-int MDnsConnection::Init() {
- int rv;
+bool MDnsConnection::Init(MDnsConnection::SocketFactory* socket_factory) {
+ // TODO(vitalybuka): crbug.com/297690 Make socket_factory return list
+ // of initialized sockets.
+ socket_handlers_.push_back(
+ new SocketHandler(this, GetMDnsIPEndPoint(ADDRESS_FAMILY_IPV4),
+ socket_factory));
+ socket_handlers_.push_back(
+ new SocketHandler(this, GetMDnsIPEndPoint(ADDRESS_FAMILY_IPV6),
+ socket_factory));
- rv = socket_handler_ipv4_.Start();
- if (rv != OK) return rv;
- rv = socket_handler_ipv6_.Start();
- if (rv != OK) return rv;
+ for (size_t i = 0; i < socket_handlers_.size();) {
+ if (socket_handlers_[i]->Bind() != OK) {
+ socket_handlers_.erase(socket_handlers_.begin() + i);
+ } else {
+ ++i;
+ }
+ }
- return OK;
+ // All unbound sockets need to be bound before processing untrusted input.
+ // This is done for security reasons, so that an attacker can't get an unbound
+ // socket.
+ for (size_t i = 0; i < socket_handlers_.size();) {
+ if (socket_handlers_[i]->Start() != OK) {
+ socket_handlers_.erase(socket_handlers_.begin() + i);
+ } else {
+ ++i;
+ }
+ }
+ return !socket_handlers_.empty();
}
-int MDnsConnection::Send(IOBuffer* buffer, unsigned size) {
- int rv;
-
- rv = socket_handler_ipv4_.Send(buffer, size);
- if (rv < OK && rv != ERR_IO_PENDING) return rv;
-
- rv = socket_handler_ipv6_.Send(buffer, size);
- if (rv < OK && rv != ERR_IO_PENDING) return rv;
-
- return OK;
+bool MDnsConnection::Send(IOBuffer* buffer, unsigned size) {
+ bool success = false;
+ for (size_t i = 0; i < socket_handlers_.size(); ++i) {
+ int rv = socket_handlers_[i]->Send(buffer, size);
+ success = success || (rv >= OK || rv == ERR_IO_PENDING);
+ }
+ return success;
}
void MDnsConnection::OnError(SocketHandler* loop,
@@ -146,15 +149,6 @@ void MDnsConnection::OnError(SocketHandler* loop,
delegate_->OnConnectionError(error);
}
-IPEndPoint MDnsConnection::GetMDnsIPEndPoint(const char* address) {
- IPAddressNumber multicast_group_number;
- bool success = ParseIPLiteralToNumber(address,
- &multicast_group_number);
- DCHECK(success);
- return IPEndPoint(multicast_group_number,
- dns_protocol::kDefaultPortMulticast);
-}
-
void MDnsConnection::OnDatagramReceived(
DnsResponse* response,
const IPEndPoint& recv_addr,
@@ -192,17 +186,16 @@ MDnsConnection::SocketFactory::CreateDefault() {
new MDnsConnectionSocketFactoryImpl);
}
-MDnsClientImpl::Core::Core(MDnsClientImpl* client,
- MDnsConnection::SocketFactory* socket_factory)
- : client_(client), connection_(new MDnsConnection(socket_factory, this)) {
+MDnsClientImpl::Core::Core(MDnsClientImpl* client)
+ : client_(client), connection_(new MDnsConnection(this)) {
}
MDnsClientImpl::Core::~Core() {
STLDeleteValues(&listeners_);
}
-bool MDnsClientImpl::Core::Init() {
- return connection_->Init() == OK;
+bool MDnsClientImpl::Core::Init(MDnsConnection::SocketFactory* socket_factory) {
+ return connection_->Init(socket_factory);
}
bool MDnsClientImpl::Core::SendQuery(uint16 rrtype, std::string name) {
@@ -213,7 +206,7 @@ bool MDnsClientImpl::Core::SendQuery(uint16 rrtype, std::string name) {
DnsQuery query(0, name_dns, rrtype);
query.set_flags(0); // Remove the RD flag from the query. It is unneeded.
- return connection_->Send(query.io_buffer(), query.io_buffer()->size()) == OK;
+ return connection_->Send(query.io_buffer(), query.io_buffer()->size());
}
void MDnsClientImpl::Core::HandlePacket(DnsResponse* response,
@@ -378,7 +371,7 @@ void MDnsClientImpl::Core::RemoveListener(MDnsListenerImpl* listener) {
observer_list_iterator->second->RemoveObserver(listener);
// Remove the observer list from the map if it is empty
- if (observer_list_iterator->second->size() == 0) {
+ if (!observer_list_iterator->second->might_have_observers()) {
// Schedule the actual removal for later in case the listener removal
// happens while iterating over the observer list.
base::MessageLoop::current()->PostTask(
@@ -389,7 +382,7 @@ void MDnsClientImpl::Core::RemoveListener(MDnsListenerImpl* listener) {
void MDnsClientImpl::Core::CleanupObserverList(const ListenerKey& key) {
ListenerMap::iterator found = listeners_.find(key);
- if (found != listeners_.end() && found->second->size() == 0) {
+ if (found != listeners_.end() && !found->second->might_have_observers()) {
delete found->second;
listeners_.erase(found);
}
@@ -442,8 +435,8 @@ MDnsClientImpl::~MDnsClientImpl() {
bool MDnsClientImpl::StartListening() {
DCHECK(!core_.get());
- core_.reset(new Core(this, socket_factory_.get()));
- if (!core_->Init()) {
+ core_.reset(new Core(this));
+ if (!core_->Init(socket_factory_.get())) {
core_.reset();
return false;
}
diff --git a/chromium/net/dns/mdns_client_impl.h b/chromium/net/dns/mdns_client_impl.h
index 9fe3f99e7dd..b69677bb747 100644
--- a/chromium/net/dns/mdns_client_impl.h
+++ b/chromium/net/dns/mdns_client_impl.h
@@ -11,6 +11,7 @@
#include <vector>
#include "base/cancelable_callback.h"
+#include "base/memory/scoped_vector.h"
#include "base/observer_list.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
@@ -43,13 +44,13 @@ class NET_EXPORT_PRIVATE MDnsConnection {
virtual ~Delegate() {}
};
- explicit MDnsConnection(SocketFactory* socket_factory,
- MDnsConnection::Delegate* delegate);
+ explicit MDnsConnection(MDnsConnection::Delegate* delegate);
virtual ~MDnsConnection();
- int Init();
- int Send(IOBuffer* buffer, unsigned size);
+ // Both methods return true if at least one of the socket handlers succeeded.
+ bool Init(MDnsConnection::SocketFactory* socket_factory);
+ bool Send(IOBuffer* buffer, unsigned size);
private:
class SocketHandler {
@@ -58,13 +59,13 @@ class NET_EXPORT_PRIVATE MDnsConnection {
const IPEndPoint& multicast_addr,
SocketFactory* socket_factory);
~SocketHandler();
- int DoLoop(int rv);
+ int Bind();
int Start();
int Send(IOBuffer* buffer, unsigned size);
private:
- int BindSocket();
+ int DoLoop(int rv);
void OnDatagramReceived(int rv);
// Callback for when sending a query has finished.
@@ -85,10 +86,8 @@ class NET_EXPORT_PRIVATE MDnsConnection {
void OnError(SocketHandler* loop, int error);
- IPEndPoint GetMDnsIPEndPoint(const char* address);
-
- SocketHandler socket_handler_ipv4_;
- SocketHandler socket_handler_ipv6_;
+ // Only socket handlers which successfully bound and started are kept.
+ ScopedVector<SocketHandler> socket_handlers_;
Delegate* delegate_;
@@ -105,12 +104,11 @@ class NET_EXPORT_PRIVATE MDnsClientImpl : public MDnsClient {
// invalidate the core.
class Core : public base::SupportsWeakPtr<Core>, MDnsConnection::Delegate {
public:
- Core(MDnsClientImpl* client,
- MDnsConnection::SocketFactory* socket_factory);
+ explicit Core(MDnsClientImpl* client);
virtual ~Core();
// Initialize the core. Returns true on success.
- bool Init();
+ bool Init(MDnsConnection::SocketFactory* socket_factory);
// Send a query with a specific rrtype and name. Returns true on success.
bool SendQuery(uint16 rrtype, std::string name);
diff --git a/chromium/net/dns/mdns_client_unittest.cc b/chromium/net/dns/mdns_client_unittest.cc
index 324b4dfbee0..f524a5401c7 100644
--- a/chromium/net/dns/mdns_client_unittest.cc
+++ b/chromium/net/dns/mdns_client_unittest.cc
@@ -1025,24 +1025,17 @@ class SimpleMockSocketFactory
}
virtual scoped_ptr<DatagramServerSocket> CreateSocket() OVERRIDE {
- scoped_ptr<MockMDnsDatagramServerSocket> socket(
- new StrictMock<MockMDnsDatagramServerSocket>);
- sockets_.push(socket.get());
- return socket.PassAs<DatagramServerSocket>();
+ MockMDnsDatagramServerSocket* socket = sockets_.back();
+ sockets_.weak_erase(sockets_.end() - 1);
+ return scoped_ptr<DatagramServerSocket>(socket);
}
- MockMDnsDatagramServerSocket* PopFirstSocket() {
- MockMDnsDatagramServerSocket* socket = sockets_.front();
- sockets_.pop();
- return socket;
- }
-
- size_t num_sockets() {
- return sockets_.size();
+ void PushSocket(MockMDnsDatagramServerSocket* socket) {
+ sockets_.push_back(socket);
}
private:
- std::queue<MockMDnsDatagramServerSocket*> sockets_;
+ ScopedVector<MockMDnsDatagramServerSocket> sockets_;
};
class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
@@ -1058,16 +1051,16 @@ class MockMDnsConnectionDelegate : public MDnsConnection::Delegate {
class MDnsConnectionTest : public ::testing::Test {
public:
- MDnsConnectionTest() : connection_(&factory_, &delegate_) {
+ MDnsConnectionTest() : connection_(&delegate_) {
}
protected:
// Follow successful connection initialization.
virtual void SetUp() OVERRIDE {
- ASSERT_EQ(2u, factory_.num_sockets());
-
- socket_ipv4_ = factory_.PopFirstSocket();
- socket_ipv6_ = factory_.PopFirstSocket();
+ socket_ipv4_ = new MockMDnsDatagramServerSocket;
+ socket_ipv6_ = new MockMDnsDatagramServerSocket;
+ factory_.PushSocket(socket_ipv6_);
+ factory_.PushSocket(socket_ipv4_);
}
bool InitConnection() {
@@ -1087,7 +1080,7 @@ class MDnsConnectionTest : public ::testing::Test {
EXPECT_CALL(*socket_ipv6_, JoinGroupInternal("ff02::fb"))
.WillOnce(Return(OK));
- return connection_.Init() == OK;
+ return connection_.Init(&factory_);
}
StrictMock<MockMDnsConnectionDelegate> delegate_;
diff --git a/chromium/net/dns/mock_host_resolver.cc b/chromium/net/dns/mock_host_resolver.cc
index b3d1489c9d7..25918ba3247 100644
--- a/chromium/net/dns/mock_host_resolver.cc
+++ b/chromium/net/dns/mock_host_resolver.cc
@@ -67,11 +67,13 @@ MockHostResolverBase::~MockHostResolverBase() {
}
int MockHostResolverBase::Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* handle,
const BoundNetLog& net_log) {
DCHECK(CalledOnValidThread());
+ last_request_priority_ = priority;
num_resolve_++;
size_t id = next_request_id_++;
int rv = ResolveFromIPLiteralOrCache(info, addresses);
@@ -135,7 +137,8 @@ void MockHostResolverBase::ResolveAllPending() {
// start id from 1 to distinguish from NULL RequestHandle
MockHostResolverBase::MockHostResolverBase(bool use_caching)
- : synchronous_mode_(false),
+ : last_request_priority_(DEFAULT_PRIORITY),
+ synchronous_mode_(false),
ondemand_mode_(false),
next_request_id_(1),
num_resolve_(0),
@@ -313,12 +316,14 @@ int RuleBasedHostResolverProc::Resolve(const std::string& host,
bool matches_address_family =
r->address_family == ADDRESS_FAMILY_UNSPECIFIED ||
r->address_family == address_family;
+ // Ignore HOST_RESOLVER_SYSTEM_ONLY, since it should have no impact on
+ // whether a rule matches.
+ HostResolverFlags flags = host_resolver_flags & ~HOST_RESOLVER_SYSTEM_ONLY;
// Flags match if all of the bitflags in host_resolver_flags are enabled
// in the rule's host_resolver_flags. However, the rule may have additional
// flags specified, in which case the flags should still be considered a
// match.
- bool matches_flags = (r->host_resolver_flags & host_resolver_flags) ==
- host_resolver_flags;
+ bool matches_flags = (r->host_resolver_flags & flags) == flags;
if (matches_flags && matches_address_family &&
MatchPattern(host, r->host_pattern)) {
if (r->latency_ms != 0) {
@@ -370,6 +375,7 @@ RuleBasedHostResolverProc* CreateCatchAllHostResolverProc() {
//-----------------------------------------------------------------------------
int HangingHostResolver::Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
diff --git a/chromium/net/dns/mock_host_resolver.h b/chromium/net/dns/mock_host_resolver.h
index 282521cc3b9..f8a424011a9 100644
--- a/chromium/net/dns/mock_host_resolver.h
+++ b/chromium/net/dns/mock_host_resolver.h
@@ -75,6 +75,7 @@ class MockHostResolverBase : public HostResolver,
// HostResolver methods:
virtual int Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
@@ -104,6 +105,12 @@ class MockHostResolverBase : public HostResolver,
return num_resolve_from_cache_;
}
+ // Returns the RequestPriority of the last call to Resolve() (or
+ // DEFAULT_PRIORITY if Resolve() hasn't been called yet).
+ RequestPriority last_request_priority() const {
+ return last_request_priority_;
+ }
+
protected:
explicit MockHostResolverBase(bool use_caching);
@@ -120,6 +127,7 @@ class MockHostResolverBase : public HostResolver,
// Resolve request stored in |requests_|. Pass rv to callback.
void ResolveNow(size_t id);
+ RequestPriority last_request_priority_;
bool synchronous_mode_;
bool ondemand_mode_;
scoped_refptr<RuleBasedHostResolverProc> rules_;
@@ -246,6 +254,7 @@ RuleBasedHostResolverProc* CreateCatchAllHostResolverProc();
class HangingHostResolver : public HostResolver {
public:
virtual int Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
diff --git a/chromium/net/dns/single_request_host_resolver.cc b/chromium/net/dns/single_request_host_resolver.cc
index 31ef4c56b6e..7974abafeef 100644
--- a/chromium/net/dns/single_request_host_resolver.cc
+++ b/chromium/net/dns/single_request_host_resolver.cc
@@ -25,9 +25,11 @@ SingleRequestHostResolver::~SingleRequestHostResolver() {
Cancel();
}
-int SingleRequestHostResolver::Resolve(
- const HostResolver::RequestInfo& info, AddressList* addresses,
- const CompletionCallback& callback, const BoundNetLog& net_log) {
+int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info,
+ RequestPriority priority,
+ AddressList* addresses,
+ const CompletionCallback& callback,
+ const BoundNetLog& net_log) {
DCHECK(addresses);
DCHECK_EQ(false, callback.is_null());
DCHECK(cur_request_callback_.is_null()) << "resolver already in use";
@@ -40,7 +42,7 @@ int SingleRequestHostResolver::Resolve(
callback.is_null() ? CompletionCallback() : callback_;
int rv = resolver_->Resolve(
- info, addresses, transient_callback, &request, net_log);
+ info, priority, addresses, transient_callback, &request, net_log);
if (rv == ERR_IO_PENDING) {
DCHECK_EQ(false, callback.is_null());
diff --git a/chromium/net/dns/single_request_host_resolver.h b/chromium/net/dns/single_request_host_resolver.h
index 52d01328911..3c8ef020edc 100644
--- a/chromium/net/dns/single_request_host_resolver.h
+++ b/chromium/net/dns/single_request_host_resolver.h
@@ -5,10 +5,18 @@
#ifndef NET_DNS_SINGLE_REQUEST_HOST_RESOLVER_H_
#define NET_DNS_SINGLE_REQUEST_HOST_RESOLVER_H_
+#include "base/basictypes.h"
+
+#include "net/base/completion_callback.h"
+#include "net/base/net_export.h"
+#include "net/base/request_priority.h"
#include "net/dns/host_resolver.h"
namespace net {
+class AddressList;
+class BoundNetLog;
+
// This class represents the task of resolving a hostname (or IP address
// literal) to an AddressList object. It wraps HostResolver to resolve only a
// single hostname at a time and cancels this request when going out of scope.
@@ -25,6 +33,7 @@ class NET_EXPORT SingleRequestHostResolver {
// Resolves the given hostname (or IP address literal), filling out the
// |addresses| object upon success. See HostResolver::Resolve() for details.
int Resolve(const HostResolver::RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
const BoundNetLog& net_log);
diff --git a/chromium/net/dns/single_request_host_resolver_unittest.cc b/chromium/net/dns/single_request_host_resolver_unittest.cc
index 1b0198f4fde..cc20bf3fe44 100644
--- a/chromium/net/dns/single_request_host_resolver_unittest.cc
+++ b/chromium/net/dns/single_request_host_resolver_unittest.cc
@@ -31,6 +31,7 @@ class HangingHostResolver : public HostResolver {
}
virtual int Resolve(const RequestInfo& info,
+ RequestPriority priority,
AddressList* addresses,
const CompletionCallback& callback,
RequestHandle* out_req,
@@ -77,7 +78,7 @@ TEST(SingleRequestHostResolverTest, NormalResolve) {
TestCompletionCallback callback;
HostResolver::RequestInfo request(HostPortPair("watsup", 90));
int rv = single_request_resolver.Resolve(
- request, &addrlist, callback.callback(), BoundNetLog());
+ request, DEFAULT_PRIORITY, &addrlist, callback.callback(), BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_EQ(OK, callback.WaitForResult());
@@ -97,8 +98,11 @@ TEST(SingleRequestHostResolverTest, Cancel) {
AddressList addrlist;
TestCompletionCallback callback;
HostResolver::RequestInfo request(HostPortPair("watsup", 90));
- int rv = single_request_resolver.Resolve(
- request, &addrlist, callback.callback(), BoundNetLog());
+ int rv = single_request_resolver.Resolve(request,
+ DEFAULT_PRIORITY,
+ &addrlist,
+ callback.callback(),
+ BoundNetLog());
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_TRUE(resolver.has_outstanding_request());
}