// Copyright (c) 2011 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_ #pragma once #include <vector> #include "base/memory/scoped_ptr.h" #include "base/threading/non_thread_safe.h" #include "net/base/capturing_net_log.h" #include "net/base/host_cache.h" #include "net/base/host_resolver.h" #include "net/base/host_resolver_proc.h" #include "net/base/net_log.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 base::NonThreadSafe, public NetworkChangeNotifier::IPAddressObserver { 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). // |max_jobs| specifies the maximum number of threads that the host resolver // will use. Use SetPoolConstraints() to specify finer-grain settings. // // |net_log| must remain valid for the life of the HostResolverImpl. HostResolverImpl(HostResolverProc* resolver_proc, HostCache* cache, size_t max_jobs, NetLog* net_log); // 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(); // Continuously observe whether IPv6 is supported, and set the allowable // address family to IPv4 iff IPv6 is not supported. void ProbeIPv6Support(); // Returns the cache this resolver uses, or NULL if caching is disabled. HostCache* cache() { return cache_.get(); } // 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); // HostResolver methods: virtual int Resolve(const RequestInfo& info, AddressList* addresses, CompletionCallback* callback, RequestHandle* out_req, const BoundNetLog& source_net_log); virtual void CancelRequest(RequestHandle req); virtual void AddObserver(HostResolver::Observer* observer); virtual void RemoveObserver(HostResolver::Observer* observer); // Set address family, and disable IPv6 probe support. virtual void SetDefaultAddressFamily(AddressFamily address_family); virtual AddressFamily GetDefaultAddressFamily() const; virtual HostResolverImpl* GetAsHostResolverImpl(); // TODO(eroman): hack for http://crbug.com/15513 virtual void Shutdown(); private: class Job; class JobPool; class IPv6ProbeJob; class Request; typedef std::vector<Request*> RequestsList; typedef HostCache::Key Key; typedef std::map<Key, scoped_refptr<Job> > JobMap; typedef std::vector<HostResolver::Observer*> ObserversList; // 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 |net_error| and |addrlist|. void OnJobComplete(Job* job, int net_error, int os_error, const AddressList& addrlist); // Aborts |job|. Same as OnJobComplete() except does not remove |job| // from |jobs_| and does not cache the result (ERR_ABORTED). void AbortJob(Job* job); // Used by both OnJobComplete() and AbortJob(); void OnJobCompleteInternal(Job* job, int net_error, int os_error, const AddressList& addrlist); // Called when a request has just been started. void OnStartRequest(const BoundNetLog& source_net_log, const BoundNetLog& request_net_log, int request_id, const RequestInfo& info); // Called when a request has just completed (before its callback is run). void OnFinishRequest(const BoundNetLog& source_net_log, const BoundNetLog& request_net_log, int request_id, const RequestInfo& info, int net_error, int os_error); // Called when a request has been cancelled. void OnCancelRequest(const BoundNetLog& source_net_log, const BoundNetLog& request_net_log, int request_id, const RequestInfo& info); // Notify IPv6ProbeJob not to call back, and discard reference to the job. void DiscardIPv6ProbeJob(); // Callback from IPv6 probe activity. void IPv6ProbeSetDefaultAddressFamily(AddressFamily address_family); // 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(); // Returns the (hostname, address_family) key to use for |info|, choosing an // "effective" address family by inheriting the resolver's default address // family when the request leaves it unspecified. Key GetEffectiveKeyForRequest(const RequestInfo& info) const; // 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); // Cancels all jobs. void CancelAllJobs(); // Aborts all in progress jobs (but might start new ones). void AbortAllInProgressJobs(); // NetworkChangeNotifier::IPAddressObserver methods: virtual void OnIPAddressChanged(); // 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): hack for http://crbug.com/15513 bool shutdown_; // Indicate if probing is done after each network change event to set address // family. // When false, explicit setting of address family is used. bool ipv6_probe_monitoring_; // The last un-cancelled IPv6ProbeJob (if any). scoped_refptr<IPv6ProbeJob> ipv6_probe_job_; // Any resolver flags that should be added to a request by default. HostResolverFlags additional_resolver_flags_; NetLog* net_log_; DISALLOW_COPY_AND_ASSIGN(HostResolverImpl); }; } // namespace net #endif // NET_BASE_HOST_RESOLVER_IMPL_H_