blob: f72fc6f3f8117f0c2a058e08e2fa99ffea3d828e [file] [log] [blame]
// Copyright (c) 2012 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 <memory>
#include <set>
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "net/base/completion_once_callback.h"
#include "net/base/net_export.h"
#include "net/log/net_log_with_source.h"
#include "net/proxy_resolution/dhcp_pac_file_fetcher.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace base {
class TaskRunner;
namespace net {
struct DhcpAdapterNamesLoggingInfo;
class DhcpPacFileAdapterFetcher;
class URLRequestContext;
// Windows-specific implementation.
class NET_EXPORT_PRIVATE DhcpPacFileFetcherWin
: public DhcpPacFileFetcher,
public base::SupportsWeakPtr<DhcpPacFileFetcherWin> {
// Creates a DhcpPacFileFetcherWin that issues requests through
// |url_request_context|. |url_request_context| must remain valid for
// the lifetime of DhcpPacFileFetcherWin.
explicit DhcpPacFileFetcherWin(URLRequestContext* url_request_context);
~DhcpPacFileFetcherWin() override;
// DhcpPacFileFetcher implementation.
int Fetch(base::string16* utf16_text,
CompletionOnceCallback callback,
const NetLogWithSource& net_log,
const NetworkTrafficAnnotationTag traffic_annotation) override;
void Cancel() override;
void OnShutdown() override;
const GURL& GetPacURL() const override;
std::string GetFetcherName() const override;
// Sets |adapter_names| to contain the name of each network adapter on
// this machine that has DHCP enabled and is not a loop-back adapter. May
// optionally update |info| (if non-null) with information for logging.
// Returns false on error.
static bool GetCandidateAdapterNames(std::set<std::string>* adapter_names,
DhcpAdapterNamesLoggingInfo* info);
int num_pending_fetchers() const;
URLRequestContext* url_request_context() const;
scoped_refptr<base::TaskRunner> GetTaskRunner();
// This inner class encapsulate work done on a worker pool thread.
// The class calls GetCandidateAdapterNames, which can take a couple of
// hundred milliseconds.
class NET_EXPORT_PRIVATE AdapterQuery
: public base::RefCountedThreadSafe<AdapterQuery> {
// This is the method that runs on the worker pool thread.
void GetCandidateAdapterNames();
// This set is valid after GetCandidateAdapterNames has
// been run. Its lifetime is scoped by this object.
const std::set<std::string>& adapter_names() const;
DhcpAdapterNamesLoggingInfo* logging_info() { return logging_info_.get(); }
// Virtual method introduced to allow unit testing.
virtual bool ImplGetCandidateAdapterNames(
std::set<std::string>* adapter_names,
DhcpAdapterNamesLoggingInfo* info);
friend class base::RefCountedThreadSafe<AdapterQuery>;
virtual ~AdapterQuery();
// These are constructed on the originating thread, then used on the
// worker thread, then used again on the originating thread only when
// the task has completed on the worker thread. No locking required.
std::set<std::string> adapter_names_;
std::unique_ptr<DhcpAdapterNamesLoggingInfo> logging_info_;
// Virtual methods introduced to allow unit testing.
virtual DhcpPacFileAdapterFetcher* ImplCreateAdapterFetcher();
virtual AdapterQuery* ImplCreateAdapterQuery();
virtual base::TimeDelta ImplGetMaxWait();
virtual void ImplOnGetCandidateAdapterNamesDone() {}
// Event/state transition handlers
void CancelImpl();
void OnGetCandidateAdapterNamesDone(
scoped_refptr<AdapterQuery> query,
const NetworkTrafficAnnotationTag traffic_annotation);
void OnFetcherDone(size_t fetcher_i, int result);
void OnWaitTimer();
void TransitionToDone();
// This is the outer state machine for fetching PAC configuration from
// DHCP. It relies for sub-states on the state machine of the
// DhcpPacFileAdapterFetcher class.
// The goal of the implementation is to the following work in parallel
// for all network adapters that are using DHCP:
// a) Try to get the PAC URL configured in DHCP;
// b) If one is configured, try to fetch the PAC URL.
// c) Once this is done for all adapters, or a timeout has passed after
// it has completed for the fastest adapter, return the PAC file
// available for the most preferred network adapter, if any.
// The state machine goes from START->WAIT_ADAPTERS when it starts a
// worker thread to get the list of adapters with DHCP enabled.
// It then goes from WAIT_ADAPTERS->NO_RESULTS when it creates
// and starts an DhcpPacFileAdapterFetcher for each adapter. It goes
// from NO_RESULTS->SOME_RESULTS when it gets the first result; at this
// point a wait timer is started. It goes from SOME_RESULTS->DONE in
// two cases: All results are known, or the wait timer expired. A call
// to Cancel() will also go straight to DONE from any state. Any
// way the DONE state is entered, we will at that point cancel any
// outstanding work and return the best known PAC script or the empty
// string.
// The state machine is reset for each Fetch(), a call to which is
// only valid in states START and DONE, as only one Fetch() is
// allowed to be outstanding at any given time.
enum State {
// Vector, in Windows' network adapter preference order, of
// DhcpPacFileAdapterFetcher objects that are or were attempting
// to fetch a PAC file based on DHCP configuration.
using FetcherVector = std::vector<std::unique_ptr<DhcpPacFileAdapterFetcher>>;
FetcherVector fetchers_;
// Current state of this state machine.
State state_;
// The following members are associated with the latest call to Fetch().
// Number of fetchers we are waiting for.
int num_pending_fetchers_;
// Lets our client know we're done. Not valid in states START or DONE.
CompletionOnceCallback callback_;
// The NetLog to use for the current Fetch().
NetLogWithSource net_log_;
// Pointer to string we will write results to. Not valid in states
// START and DONE.
base::string16* destination_string_;
// PAC URL retrieved from DHCP, if any. Valid only in state STATE_DONE.
GURL pac_url_;
base::OneShotTimer wait_timer_;
// Set to nullptr on cancellation.
URLRequestContext* url_request_context_;
// NULL or the AdapterQuery currently in flight.
scoped_refptr<AdapterQuery> last_query_;
// TaskRunner used for all DHCP lookup tasks.
const scoped_refptr<base::TaskRunner> task_runner_;
} // namespace net