// Copyright (c) 2006-2008 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.
#ifndef NET_BASE_HOST_RESOLVER_IMPL_H_
#define NET_BASE_HOST_RESOLVER_IMPL_H_
#include <string>
#include <vector>
#include "base/scoped_ptr.h"
#include "net/base/host_cache.h"
#include "net/base/host_resolver.h"
#include "net/base/host_resolver_proc.h"
#include "net/base/network_change_notifier.h"
namespace net {
// For each hostname that is requested, HostResolver creates a
// HostResolverImpl::Job. This job gets dispatched to a thread in the global
// WorkerPool, where it runs SystemHostResolverProc(). If requests for that same
// host are made while the job is already outstanding, then they are attached
// to the existing job rather than creating a new one. This avoids doing
// parallel resolves for the same host.
//
// The way these classes fit together is illustrated by:
//
//
// +----------- HostResolverImpl -------------+
// | | |
// Job Job Job
// (for host1, fam1) (for host2, fam2) (for hostx, famx)
// / | | / | | / | |
// Request ... Request Request ... Request Request ... Request
// (port1) (port2) (port3) (port4) (port5) (portX)
//
//
// When a HostResolverImpl::Job finishes its work in the threadpool, the
// callbacks of each waiting request are run on the origin thread.
//
// Thread safety: This class is not threadsafe, and must only be called
// from one thread!
//
// The HostResolverImpl enforces |max_jobs_| as the maximum number of concurrent
// threads.
//
// Requests are ordered in the queue based on their priority.
class HostResolverImpl : public HostResolver,
public NetworkChangeNotifier::Observer {
public:
// The index into |job_pools_| for the various job pools. Pools with a higher
// index have lower priority.
//
// Note: This is currently unused, since there is a single pool
// for all requests.
enum JobPoolIndex {
POOL_NORMAL = 0,
POOL_COUNT,
};
// Creates a HostResolver that first uses the local cache |cache|, and then
// falls back to |resolver_proc|.
//
// If |cache| is NULL, then no caching is used. Otherwise we take
// ownership of the |cache| pointer, and will free it during destructor.
//
// |resolver_proc| is used to perform the actual resolves; it must be
// thread-safe since it is run from multiple worker threads. If
// |resolver_proc| is NULL then the default host resolver procedure is
// used (which is SystemHostResolverProc except if overridden).
// |notifier| must outlive HostResolverImpl. It can optionally be NULL, in
// which case HostResolverImpl will not respond to network changes.
// |max_jobs| specifies the maximum number of threads that the host resolver
// will use. Use SetPoolConstraints() to specify finer-grain settings.
HostResolverImpl(HostResolverProc* resolver_proc,
HostCache* cache,
NetworkChangeNotifier* notifier,
size_t max_jobs);
// HostResolver methods:
virtual int Resolve(const RequestInfo& info,
AddressList* addresses,
CompletionCallback* callback,
RequestHandle* out_req,
LoadLog* load_log);
virtual void CancelRequest(RequestHandle req);
virtual void AddObserver(HostResolver::Observer* observer);
virtual void RemoveObserver(HostResolver::Observer* observer);
// TODO(eroman): temp hack for http://crbug.com/15513
virtual void Shutdown();
virtual void SetDefaultAddressFamily(AddressFamily address_family) {
default_address_family_ = address_family;
}
virtual bool IsHostResolverImpl() { return true; }
// Returns the cache this resolver uses, or NULL if caching is disabled.
HostCache* cache() { return cache_.get(); }
// Clears the request trace log.
void ClearRequestsTrace();
// Starts/ends capturing requests to a trace log.
void EnableRequestsTracing(bool enable);
bool IsRequestsTracingEnabled() const;
// Returns a copy of the requests trace log, or NULL if there is none.
scoped_refptr<LoadLog> GetRequestsTrace();
// Applies a set of constraints for requests that belong to the specified
// pool. NOTE: Don't call this after requests have been already been started.
//
// |pool_index| -- Specifies which pool these constraints should be applied
// to.
// |max_outstanding_jobs| -- How many concurrent jobs are allowed for this
// pool.
// |max_pending_requests| -- How many requests can be enqueued for this pool
// before we start dropping requests. Dropped
// requests fail with
// ERR_HOST_RESOLVER_QUEUE_TOO_LARGE.
void SetPoolConstraints(JobPoolIndex pool_index,
size_t max_outstanding_jobs,
size_t max_pending_requests);
private:
class Job;
class JobPool;
class Request;
class RequestsTrace;
typedef std::vector<Request*> RequestsList;
typedef HostCache::Key Key;
typedef std::map<Key, scoped_refptr<Job> > JobMap;
typedef std::vector<HostResolver::Observer*> ObserversList;
// If any completion callbacks are pending when the resolver is destroyed,
// the host resolutions are cancelled, and the completion callbacks will not
// be called.
virtual ~HostResolverImpl();
// Returns the HostResolverProc to use for this instance.
HostResolverProc* effective_resolver_proc() const {
return resolver_proc_ ?
resolver_proc_.get() : HostResolverProc::GetDefault();
}
// Adds a job to outstanding jobs list.
void AddOutstandingJob(Job* job);
// Returns the outstanding job for |key|, or NULL if there is none.
Job* FindOutstandingJob(const Key& key);
// Removes |job| from the outstanding jobs list.
void RemoveOutstandingJob(Job* job);
// Callback for when |job| has completed with |error| and |addrlist|.
void OnJobComplete(Job* job, int error, const AddressList& addrlist);
// Called when a request has just been started.
void OnStartRequest(LoadLog* load_log,
int request_id,
const RequestInfo& info);
// Called when a request has just completed (before its callback is run).
void OnFinishRequest(LoadLog* load_log,
int request_id,
const RequestInfo& info,
int error);
// Called when a request has been cancelled.
void OnCancelRequest(LoadLog* load_log,
int request_id,
const RequestInfo& info);
// NetworkChangeNotifier::Observer methods:
virtual void OnIPAddressChanged();
// Returns true if the constraints for |pool| are met, and a new job can be
// created for this pool.
bool CanCreateJobForPool(const JobPool& pool) const;
// Returns the index of the pool that request |req| maps to.
static JobPoolIndex GetJobPoolIndexForRequest(const Request* req);
JobPool* GetPoolForRequest(const Request* req) {
return job_pools_[GetJobPoolIndexForRequest(req)];
}
// Starts up to 1 job given the current pool constraints. This job
// may have multiple requests attached to it.
void ProcessQueuedRequests();
// Attaches |req| to a new job, and starts it. Returns that job.
Job* CreateAndStartJob(Request* req);
// Adds a pending request |req| to |pool|.
int EnqueueRequest(JobPool* pool, Request* req);
// Cache of host resolution results.
scoped_ptr<HostCache> cache_;
// Map from hostname to outstanding job.
JobMap jobs_;
// Maximum number of concurrent jobs allowed, across all pools.
size_t max_jobs_;
// The information to track pending requests for a JobPool, as well as
// how many outstanding jobs the pool already has, and its constraints.
JobPool* job_pools_[POOL_COUNT];
// The job that OnJobComplete() is currently processing (needed in case
// HostResolver gets deleted from within the callback).
scoped_refptr<Job> cur_completing_job_;
// The observers to notify when a request starts/ends.
ObserversList observers_;
// Monotonically increasing ID number to assign to the next request.
// Observers are the only consumers of this ID number.
int next_request_id_;
// Monotonically increasing ID number to assign to the next job.
// The only consumer of this ID is the requests tracing code.
int next_job_id_;
// The procedure to use for resolving host names. This will be NULL, except
// in the case of unit-tests which inject custom host resolving behaviors.
scoped_refptr<HostResolverProc> resolver_proc_;
// Address family to use when the request doesn't specify one.
AddressFamily default_address_family_;
// TODO(eroman): temp hack for http://crbug.com/15513
bool shutdown_;
NetworkChangeNotifier* const network_change_notifier_;
scoped_refptr<RequestsTrace> requests_trace_;
DISALLOW_COPY_AND_ASSIGN(HostResolverImpl);
};
} // namespace net
#endif // NET_BASE_HOST_RESOLVER_IMPL_H_