Index: net/base/host_resolver.cc |
=================================================================== |
--- net/base/host_resolver.cc (revision 18360) |
+++ net/base/host_resolver.cc (working copy) |
@@ -22,6 +22,7 @@ |
#include "base/time.h" |
#include "base/worker_pool.h" |
#include "net/base/address_list.h" |
+#include "net/base/dns_resolution_observer.h" |
#include "net/base/net_errors.h" |
#if defined(OS_LINUX) |
@@ -178,8 +179,10 @@ |
class HostResolver::Request { |
public: |
- Request(CompletionCallback* callback, AddressList* addresses, int port) |
- : job_(NULL), callback_(callback), addresses_(addresses), port_(port) {} |
+ Request(int id, const RequestInfo& info, CompletionCallback* callback, |
+ AddressList* addresses) |
+ : id_(id), info_(info), job_(NULL), callback_(callback), |
+ addresses_(addresses) {} |
// Mark the request as cancelled. |
void Cancel() { |
@@ -200,19 +203,33 @@ |
void OnComplete(int error, const AddressList& addrlist) { |
if (error == OK) |
- addresses_->SetFrom(addrlist, port_); |
+ addresses_->SetFrom(addrlist, port()); |
callback_->Run(error); |
} |
int port() const { |
- return port_; |
+ return info_.port(); |
} |
Job* job() const { |
return job_; |
} |
+ int id() const { |
+ return id_; |
+ } |
+ |
+ const RequestInfo& info() const { |
+ return info_; |
+ } |
+ |
private: |
+ // Unique ID for this request. Used by observers to identify requests. |
+ int id_; |
+ |
+ // The request info that started the request. |
+ RequestInfo info_; |
+ |
// The resolve job (running in worker pool) that this request is dependent on. |
Job* job_; |
@@ -222,9 +239,6 @@ |
// The address list to save result into. |
AddressList* addresses_; |
- // The desired port number for the socket addresses. |
- int port_; |
- |
DISALLOW_COPY_AND_ASSIGN(Request); |
}; |
@@ -369,7 +383,7 @@ |
//----------------------------------------------------------------------------- |
HostResolver::HostResolver(int max_cache_entries, int cache_duration_ms) |
- : cache_(max_cache_entries, cache_duration_ms) { |
+ : cache_(max_cache_entries, cache_duration_ms), next_request_id_(0) { |
#if defined(OS_WIN) |
EnsureWinsockInit(); |
#endif |
@@ -388,40 +402,51 @@ |
// TODO(eroman): Don't create cache entries for hostnames which are simply IP |
// address literals. |
-int HostResolver::Resolve(const std::string& hostname, int port, |
+int HostResolver::Resolve(const RequestInfo& info, |
AddressList* addresses, |
CompletionCallback* callback, |
Request** out_req) { |
+ // Choose a unique ID number for observers to see. |
+ int request_id = next_request_id_++; |
+ |
+ // Notify registered observers. |
+ NotifyObserversStartRequest(request_id, info); |
+ |
// If we have an unexpired cache entry, use it. |
- const HostCache::Entry* cache_entry = cache_.Lookup( |
- hostname, base::TimeTicks::Now()); |
- if (cache_entry) { |
- addresses->SetFrom(cache_entry->addrlist, port); |
- return OK; |
+ if (info.allow_cached_response()) { |
+ const HostCache::Entry* cache_entry = cache_.Lookup( |
+ info.hostname(), base::TimeTicks::Now()); |
+ if (cache_entry) { |
+ addresses->SetFrom(cache_entry->addrlist, info.port()); |
+ return OK; |
+ } |
} |
// If no callback was specified, do a synchronous resolution. |
if (!callback) { |
struct addrinfo* results; |
- int error = ResolveAddrInfo(host_mapper, hostname, &results); |
+ int error = ResolveAddrInfo(host_mapper, info.hostname(), &results); |
// Adopt the address list. |
AddressList addrlist; |
if (error == OK) { |
addrlist.Adopt(results); |
- addrlist.SetPort(port); |
+ addrlist.SetPort(info.port()); |
*addresses = addrlist; |
} |
// Write to cache. |
- cache_.Set(hostname, error, addrlist, base::TimeTicks::Now()); |
+ cache_.Set(info.hostname(), error, addrlist, base::TimeTicks::Now()); |
+ // Notify registered observers. |
+ NotifyObserversFinishRequest(request_id, info, error); |
+ |
return error; |
} |
// Create a handle for this request, and pass it back to the user if they |
// asked for it (out_req != NULL). |
- Request* req = new Request(callback, addresses, port); |
+ Request* req = new Request(request_id, info, callback, addresses); |
if (out_req) |
*out_req = req; |
@@ -429,14 +454,14 @@ |
// calling "getaddrinfo(hostname)" on a worker thread. |
scoped_refptr<Job> job; |
- // If there is already an outstanding job to resolve |hostname|, use it. |
- // This prevents starting concurrent resolves for the same hostname. |
- job = FindOutstandingJob(hostname); |
+ // If there is already an outstanding job to resolve |info.hostname()|, use |
+ // it. This prevents starting concurrent resolves for the same hostname. |
+ job = FindOutstandingJob(info.hostname()); |
if (job) { |
job->AddRequest(req); |
} else { |
// Create a new job for this request. |
- job = new Job(this, hostname); |
+ job = new Job(this, info.hostname()); |
job->AddRequest(req); |
AddOutstandingJob(job); |
// TODO(eroman): Bound the total number of concurrent jobs. |
@@ -457,6 +482,20 @@ |
req->Cancel(); |
} |
+void HostResolver::AddObserver(DnsResolutionObserver* observer) { |
+ observers_.push_back(observer); |
+} |
+ |
+void HostResolver::RemoveObserver(DnsResolutionObserver* observer) { |
+ ObserversList::iterator it = |
+ std::find(observers_.begin(), observers_.end(), observer); |
+ |
+ // Observer must exist. |
+ DCHECK(it != observers_.end()); |
+ |
+ observers_.erase(it); |
+} |
+ |
void HostResolver::AddOutstandingJob(Job* job) { |
scoped_refptr<Job>& found_job = jobs_[job->host()]; |
DCHECK(!found_job); |
@@ -497,6 +536,10 @@ |
Request* req = *it; |
if (!req->was_cancelled()) { |
DCHECK_EQ(job, req->job()); |
+ |
+ // Notify registered observers. |
+ NotifyObserversFinishRequest(req->id(), req->info(), error); |
+ |
req->OnComplete(error, addrlist); |
// Check if the job was cancelled as a result of running the callback. |
@@ -509,6 +552,24 @@ |
cur_completing_job_ = NULL; |
} |
+void HostResolver::NotifyObserversStartRequest(int request_id, |
+ const RequestInfo& info) { |
+ for (ObserversList::iterator it = observers_.begin(); |
+ it != observers_.end(); ++it) { |
+ (*it)->OnStartResolution(request_id, info); |
+ } |
+} |
+ |
+void HostResolver::NotifyObserversFinishRequest(int request_id, |
+ const RequestInfo& info, |
+ int error) { |
+ bool was_resolved = error == OK; |
+ for (ObserversList::iterator it = observers_.begin(); |
+ it != observers_.end(); ++it) { |
+ (*it)->OnFinishResolutionWithStatus(request_id, was_resolved, info); |
+ } |
+} |
+ |
//----------------------------------------------------------------------------- |
SingleRequestHostResolver::SingleRequestHostResolver(HostResolver* resolver) |
@@ -526,10 +587,9 @@ |
} |
} |
-int SingleRequestHostResolver::Resolve( |
- const std::string& hostname, int port, |
- AddressList* addresses, |
- CompletionCallback* callback) { |
+int SingleRequestHostResolver::Resolve(const HostResolver::RequestInfo& info, |
+ AddressList* addresses, |
+ CompletionCallback* callback) { |
DCHECK(!cur_request_ && !cur_request_callback_) << "resolver already in use"; |
HostResolver::Request* request = NULL; |
@@ -538,8 +598,7 @@ |
// we can clear out |cur_request_*|. |
CompletionCallback* transient_callback = callback ? &callback_ : NULL; |
- int rv = resolver_->Resolve( |
- hostname, port, addresses, transient_callback, &request); |
+ int rv = resolver_->Resolve(info, addresses, transient_callback, &request); |
if (rv == ERR_IO_PENDING) { |
// Cleared in OnResolveCompletion(). |