// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/dns/host_resolver_mojo.h" #include #include "mojo/public/cpp/bindings/binding.h" #include "net/base/address_list.h" #include "net/base/net_errors.h" #include "net/dns/mojo_host_type_converters.h" #include "net/log/net_log.h" namespace net { namespace { // Default TTL for successful host resolutions. const int kCacheEntryTTLSeconds = 5; // Default TTL for unsuccessful host resolutions. const int kNegativeCacheEntryTTLSeconds = 0; HostCache::Key CacheKeyForRequest(const HostResolver::RequestInfo& info) { return HostCache::Key(info.hostname(), info.address_family(), info.host_resolver_flags()); } } // namespace class HostResolverMojo::Job : public interfaces::HostResolverRequestClient { public: Job(const HostCache::Key& key, AddressList* addresses, const CompletionCallback& callback, mojo::InterfaceRequest request, base::WeakPtr host_cache); private: // interfaces::HostResolverRequestClient override. void ReportResult(int32_t error, interfaces::AddressListPtr address_list) override; // Mojo error handler. void OnConnectionError(); const HostCache::Key key_; AddressList* addresses_; CompletionCallback callback_; mojo::Binding binding_; base::WeakPtr host_cache_; }; HostResolverMojo::HostResolverMojo(Impl* impl) : impl_(impl), host_cache_(HostCache::CreateDefaultCache()), host_cache_weak_factory_(host_cache_.get()) { } HostResolverMojo::~HostResolverMojo() = default; int HostResolverMojo::Resolve(const RequestInfo& info, RequestPriority priority, AddressList* addresses, const CompletionCallback& callback, RequestHandle* request_handle, const BoundNetLog& source_net_log) { DCHECK(thread_checker_.CalledOnValidThread()); DVLOG(1) << "Resolve " << info.host_port_pair().ToString(); HostCache::Key key = CacheKeyForRequest(info); int cached_result = ResolveFromCacheInternal(info, key, addresses); if (cached_result != ERR_DNS_CACHE_MISS) { DVLOG(1) << "Resolved " << info.host_port_pair().ToString() << " from cache"; return cached_result; } interfaces::HostResolverRequestClientPtr handle; *request_handle = new Job(key, addresses, callback, mojo::GetProxy(&handle), host_cache_weak_factory_.GetWeakPtr()); impl_->ResolveDns(interfaces::HostResolverRequestInfo::From(info), std::move(handle)); return ERR_IO_PENDING; } int HostResolverMojo::ResolveFromCache(const RequestInfo& info, AddressList* addresses, const BoundNetLog& source_net_log) { DCHECK(thread_checker_.CalledOnValidThread()); DVLOG(1) << "ResolveFromCache " << info.host_port_pair().ToString(); return ResolveFromCacheInternal(info, CacheKeyForRequest(info), addresses); } void HostResolverMojo::CancelRequest(RequestHandle req) { DCHECK(thread_checker_.CalledOnValidThread()); // Deleting the Job closes the HostResolverRequestClient connection, // signalling cancellation of the request. delete static_cast(req); } HostCache* HostResolverMojo::GetHostCache() { return host_cache_.get(); } int HostResolverMojo::ResolveFromCacheInternal(const RequestInfo& info, const HostCache::Key& key, AddressList* addresses) { if (!info.allow_cached_response()) return ERR_DNS_CACHE_MISS; const HostCache::Entry* entry = host_cache_->Lookup(key, base::TimeTicks::Now()); if (!entry) return ERR_DNS_CACHE_MISS; *addresses = AddressList::CopyWithPort(entry->addrlist, info.port()); return entry->error; } HostResolverMojo::Job::Job( const HostCache::Key& key, AddressList* addresses, const CompletionCallback& callback, mojo::InterfaceRequest request, base::WeakPtr host_cache) : key_(key), addresses_(addresses), callback_(callback), binding_(this, std::move(request)), host_cache_(host_cache) { binding_.set_connection_error_handler(base::Bind( &HostResolverMojo::Job::OnConnectionError, base::Unretained(this))); } void HostResolverMojo::Job::ReportResult( int32_t error, interfaces::AddressListPtr address_list) { if (error == OK && address_list) *addresses_ = address_list->To(); if (host_cache_) { base::TimeDelta ttl = base::TimeDelta::FromSeconds( error == OK ? kCacheEntryTTLSeconds : kNegativeCacheEntryTTLSeconds); HostCache::Entry entry(error, *addresses_, ttl); host_cache_->Set(key_, entry, base::TimeTicks::Now(), ttl); } callback_.Run(error); delete this; } void HostResolverMojo::Job::OnConnectionError() { ReportResult(ERR_FAILED, interfaces::AddressListPtr()); } } // namespace net