Chromium Code Reviews| Index: net/base/host_resolver_impl.cc |
| diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc |
| index ecbbd582a75879344fd00f2818483e55c5100466..b8077eb4064bfc38fbb8da6654fd0cb3c7a25ae9 100644 |
| --- a/net/base/host_resolver_impl.cc |
| +++ b/net/base/host_resolver_impl.cc |
| @@ -24,7 +24,6 @@ |
| #include "base/message_loop_proxy.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/metrics/histogram.h" |
| -#include "base/rand_util.h" |
| #include "base/stl_util.h" |
| #include "base/string_util.h" |
| #include "base/threading/worker_pool.h" |
| @@ -40,12 +39,11 @@ |
| #include "net/base/net_errors.h" |
| #include "net/base/net_log.h" |
| #include "net/base/net_util.h" |
| +#include "net/dns/dns_client.h" |
| #include "net/dns/dns_config_service.h" |
| #include "net/dns/dns_protocol.h" |
| #include "net/dns/dns_response.h" |
| -#include "net/dns/dns_session.h" |
| #include "net/dns/dns_transaction.h" |
| -#include "net/socket/client_socket_factory.h" |
| #if defined(OS_WIN) |
| #include "net/base/winsock_init.h" |
| @@ -1205,6 +1203,21 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job { |
| base::TimeDelta()); |
| } |
| + // Attempts to serve the job from HOSTS. Returns true if succeeded and |
| + // this Job was destroyed. |
| + bool ServeFromHosts() { |
| + DCHECK_GT(num_active_requests(), 0u); |
| + AddressList addr_list; |
| + if (resolver_->ServeFromHosts(key(), |
| + requests_.front()->info(), |
| + &addr_list)) { |
| + // This will destroy the Job. |
| + CompleteRequests(OK, addr_list, base::TimeDelta()); |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| private: |
| RequestPriority priority() const { |
| return priority_tracker_.highest_priority(); |
| @@ -1231,7 +1244,7 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job { |
| net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_STARTED, NULL); |
| // Job::Start must not complete synchronously. |
| - if (resolver_->dns_transaction_factory_.get()) { |
| + if (resolver_->HaveDnsConfig()) { |
| StartDnsTask(); |
| } else { |
| StartProcTask(); |
| @@ -1270,8 +1283,9 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job { |
| } |
| void StartDnsTask() { |
| + DCHECK(resolver_->HaveDnsConfig()); |
| dns_task_.reset(new DnsTask( |
| - resolver_->dns_transaction_factory_.get(), |
| + resolver_->dns_client_->GetTransactionFactory(), |
| key_, |
| base::Bind(&Job::OnDnsTaskComplete, base::Unretained(this)), |
| net_log_)); |
| @@ -1292,6 +1306,10 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job { |
| if (net_error != OK) { |
| dns_task_.reset(); |
| + |
| + // TODO(szym): Run ServeFromHosts now if nsswitch.conf says so. |
| + // http://crbug.com/117655 |
| + |
| // TODO(szym): Some net errors indicate lack of connectivity. Starting |
| // ProcTask in that case is a waste of time. |
| StartProcTask(); |
| @@ -1344,9 +1362,11 @@ class HostResolverImpl::Job : public PrioritizedDispatcher::Job { |
| net_log_.EndEventWithNetErrorCode(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB, |
| net_error); |
| + DCHECK(!requests_.empty()); |
| + |
| // We are the only consumer of |list|, so we can safely change the port |
| // without copy-on-write. This pays off, when job has only one request. |
| - if (net_error == OK && !requests_.empty()) |
| + if (net_error == OK) |
| MutableSetPort(requests_.front()->info().port(), &list); |
| if ((net_error != ERR_ABORTED) && |
| @@ -1424,6 +1444,7 @@ HostResolverImpl::HostResolverImpl( |
| max_queued_jobs_(job_limits.total_jobs * 100u), |
| proc_params_(proc_params), |
| default_address_family_(ADDRESS_FAMILY_UNSPECIFIED), |
| + dns_client_(NULL), |
| dns_config_service_(dns_config_service.Pass()), |
| ipv6_probe_monitoring_(false), |
| additional_resolver_flags_(0), |
| @@ -1452,8 +1473,10 @@ HostResolverImpl::HostResolverImpl( |
| NetworkChangeNotifier::AddDNSObserver(this); |
| #endif |
| - if (dns_config_service_.get()) |
| + if (dns_config_service_.get()) { |
| dns_config_service_->AddObserver(this); |
| + dns_client_ = DnsClient::CreateClient(net_log_); |
| + } |
| } |
| HostResolverImpl::~HostResolverImpl() { |
| @@ -1552,9 +1575,17 @@ int HostResolverImpl::ResolveHelper(const Key& key, |
| int net_error = ERR_UNEXPECTED; |
| if (ResolveAsIP(key, info, &net_error, addresses)) |
| return net_error; |
| - net_error = ERR_DNS_CACHE_MISS; |
| - ServeFromCache(key, info, request_net_log, &net_error, addresses); |
| - return net_error; |
| + if (ServeFromCache(key, info, &net_error, addresses)) { |
| + request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL); |
| + return net_error; |
| + } |
| + // TODO(szym): Do not do this if nsswitch.conf instructs not to. |
| + // http://crbug.com/117655 |
| + if (ServeFromHosts(key, info, addresses)) { |
| + request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT, NULL); |
| + return OK; |
| + } |
| + return ERR_DNS_CACHE_MISS; |
| } |
| int HostResolverImpl::ResolveFromCache(const RequestInfo& info, |
| @@ -1637,7 +1668,6 @@ bool HostResolverImpl::ResolveAsIP(const Key& key, |
| bool HostResolverImpl::ServeFromCache(const Key& key, |
| const RequestInfo& info, |
| - const BoundNetLog& request_net_log, |
| int* net_error, |
| AddressList* addresses) { |
| DCHECK(addresses); |
| @@ -1650,13 +1680,43 @@ bool HostResolverImpl::ServeFromCache(const Key& key, |
| if (!cache_entry) |
| return false; |
| - request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT, NULL); |
| + |
| *net_error = cache_entry->error; |
| if (*net_error == OK) |
| *addresses = CreateAddressListUsingPort(cache_entry->addrlist, info.port()); |
| return true; |
| } |
| +bool HostResolverImpl::ServeFromHosts(const Key& key, |
| + const RequestInfo& info, |
| + AddressList* addresses) { |
| + DCHECK(addresses); |
| + if (!HaveDnsConfig()) |
| + return false; |
| + |
| + // If address_family is ADDRESS_FAMILY_UNSPECIFIED other implementations |
|
mmenke
2012/03/13 15:56:27
nit: |address_family|
|
| + // (glibc and c-ares) return the first matching line. We have more |
| + // flexibility, but lose implicit ordering. |
| + // TODO(szym) http://crbug.com/117850 |
| + const DnsHosts& hosts = dns_client_->GetConfig()->hosts; |
| + DnsHosts::const_iterator it = hosts.find( |
| + DnsHostsKey(key.hostname, |
| + key.address_family == ADDRESS_FAMILY_UNSPECIFIED ? |
| + ADDRESS_FAMILY_IPV4 : key.address_family)); |
| + |
| + if (it == hosts.end()) { |
| + if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED) |
| + return false; |
| + |
| + it = hosts.find(DnsHostsKey(key.hostname, ADDRESS_FAMILY_IPV6)); |
| + if (it == hosts.end()) |
| + return false; |
| + } |
| + |
| + *addresses = AddressList::CreateFromIPAddress(it->second, info.port()); |
| + return true; |
| +} |
| + |
| void HostResolverImpl::CacheResult(const Key& key, |
| int net_error, |
| const AddressList& addr_list, |
| @@ -1734,6 +1794,24 @@ void HostResolverImpl::AbortAllInProgressJobs() { |
| } |
| } |
| +void HostResolverImpl::TryServingAllJobsFromHosts() { |
| + if (!HaveDnsConfig()) |
| + return; |
| + |
| + // TODO(szym): Do not do this if nsswitch.conf instructs not to. |
| + // http://crbug.com/117655 |
| + |
| + // Life check to bail once |this| is deleted. |
| + base::WeakPtr<HostResolverImpl> self = AsWeakPtr(); |
| + |
| + for (JobMap::iterator it = jobs_.begin(); self && it != jobs_.end(); ) { |
| + Job* job = it->second; |
| + ++it; |
| + // This could remove |job| from |jobs_|, but iterator will remain valid. |
| + job->ServeFromHosts(); |
| + } |
| +} |
| + |
| void HostResolverImpl::OnIPAddressChanged() { |
| if (cache_.get()) |
| cache_->clear(); |
| @@ -1769,20 +1847,22 @@ void HostResolverImpl::OnDNSChanged(unsigned detail) { |
| void HostResolverImpl::OnConfigChanged(const DnsConfig& dns_config) { |
| // We want a new factory in place, before we Abort running Jobs, so that the |
| // newly started jobs use the new factory. |
| - bool had_factory = (dns_transaction_factory_.get() != NULL); |
| - if (dns_config.IsValid()) { |
| - dns_transaction_factory_ = DnsTransactionFactory::CreateFactory( |
| - new DnsSession(dns_config, |
| - ClientSocketFactory::GetDefaultFactory(), |
| - base::Bind(&base::RandInt), |
| - net_log_)); |
| - } else { |
| - dns_transaction_factory_.reset(); |
| - } |
| + DCHECK(dns_client_.get()); |
| + |
| + bool had_factory = (dns_client_->GetConfig() != NULL); |
| + dns_client_->SetConfig(dns_config); |
| + |
| // Don't Abort running Jobs unless they were running on DnsTransaction. |
| // TODO(szym): This will change once http://crbug.com/114827 is fixed. |
| if (had_factory) |
| OnDNSChanged(NetworkChangeNotifier::CHANGE_DNS_SETTINGS); |
| + |
| + if (dns_config.IsValid()) |
| + TryServingAllJobsFromHosts(); |
|
mmenke
2012/03/13 15:56:27
If OnDNSChanged results in the destruction of |thi
szym
2012/03/13 18:14:29
Good catch. I'll add a self check.
|
| +} |
| + |
| +bool HostResolverImpl::HaveDnsConfig() const { |
| + return (dns_client_.get() != NULL) && (dns_client_->GetConfig() != NULL); |
| } |
| } // namespace net |