1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_PROXY_DHCP_PROXY_SCRIPT_FETCHER_WIN_H_ 6 #define NET_PROXY_DHCP_PROXY_SCRIPT_FETCHER_WIN_H_ 7 8 #include <set> 9 #include <string> 10 11 #include "base/memory/ref_counted.h" 12 #include "base/memory/scoped_vector.h" 13 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/threading/non_thread_safe.h" 15 #include "base/time/time.h" 16 #include "base/timer/timer.h" 17 #include "net/proxy/dhcp_proxy_script_fetcher.h" 18 19 namespace net { 20 21 class DhcpProxyScriptAdapterFetcher; 22 class URLRequestContext; 23 24 // Windows-specific implementation. 25 class NET_EXPORT_PRIVATE DhcpProxyScriptFetcherWin 26 : public DhcpProxyScriptFetcher, 27 public base::SupportsWeakPtr<DhcpProxyScriptFetcherWin>, 28 NON_EXPORTED_BASE(public base::NonThreadSafe) { 29 public: 30 // Creates a DhcpProxyScriptFetcherWin that issues requests through 31 // |url_request_context|. |url_request_context| must remain valid for 32 // the lifetime of DhcpProxyScriptFetcherWin. 33 explicit DhcpProxyScriptFetcherWin(URLRequestContext* url_request_context); 34 virtual ~DhcpProxyScriptFetcherWin(); 35 36 // DhcpProxyScriptFetcher implementation. 37 int Fetch(base::string16* utf16_text, 38 const net::CompletionCallback& callback) OVERRIDE; 39 void Cancel() OVERRIDE; 40 const GURL& GetPacURL() const OVERRIDE; 41 std::string GetFetcherName() const OVERRIDE; 42 43 // Sets |adapter_names| to contain the name of each network adapter on 44 // this machine that has DHCP enabled and is not a loop-back adapter. Returns 45 // false on error. 46 static bool GetCandidateAdapterNames(std::set<std::string>* adapter_names); 47 48 protected: 49 int num_pending_fetchers() const; 50 51 URLRequestContext* url_request_context() const; 52 53 // This inner class encapsulate work done on a worker pool thread. 54 // The class calls GetCandidateAdapterNames, which can take a couple of 55 // hundred milliseconds. 56 class NET_EXPORT_PRIVATE AdapterQuery 57 : public base::RefCountedThreadSafe<AdapterQuery> { 58 public: 59 AdapterQuery(); 60 virtual ~AdapterQuery(); 61 62 // This is the method that runs on the worker pool thread. 63 void GetCandidateAdapterNames(); 64 65 // This set is valid after GetCandidateAdapterNames has 66 // been run. Its lifetime is scoped by this object. 67 const std::set<std::string>& adapter_names() const; 68 69 protected: 70 // Virtual method introduced to allow unit testing. 71 virtual bool ImplGetCandidateAdapterNames( 72 std::set<std::string>* adapter_names); 73 74 private: 75 // This is constructed on the originating thread, then used on the 76 // worker thread, then used again on the originating thread only when 77 // the task has completed on the worker thread. No locking required. 78 std::set<std::string> adapter_names_; 79 80 DISALLOW_COPY_AND_ASSIGN(AdapterQuery); 81 }; 82 83 // Virtual methods introduced to allow unit testing. 84 virtual DhcpProxyScriptAdapterFetcher* ImplCreateAdapterFetcher(); 85 virtual AdapterQuery* ImplCreateAdapterQuery(); 86 virtual base::TimeDelta ImplGetMaxWait(); 87 virtual void ImplOnGetCandidateAdapterNamesDone() {} 88 89 private: 90 // Event/state transition handlers 91 void CancelImpl(); 92 void OnGetCandidateAdapterNamesDone(scoped_refptr<AdapterQuery> query); 93 void OnFetcherDone(int result); 94 void OnWaitTimer(); 95 void TransitionToDone(); 96 97 // This is the outer state machine for fetching PAC configuration from 98 // DHCP. It relies for sub-states on the state machine of the 99 // DhcpProxyScriptAdapterFetcher class. 100 // 101 // The goal of the implementation is to the following work in parallel 102 // for all network adapters that are using DHCP: 103 // a) Try to get the PAC URL configured in DHCP; 104 // b) If one is configured, try to fetch the PAC URL. 105 // c) Once this is done for all adapters, or a timeout has passed after 106 // it has completed for the fastest adapter, return the PAC file 107 // available for the most preferred network adapter, if any. 108 // 109 // The state machine goes from START->WAIT_ADAPTERS when it starts a 110 // worker thread to get the list of adapters with DHCP enabled. 111 // It then goes from WAIT_ADAPTERS->NO_RESULTS when it creates 112 // and starts an DhcpProxyScriptAdapterFetcher for each adapter. It goes 113 // from NO_RESULTS->SOME_RESULTS when it gets the first result; at this 114 // point a wait timer is started. It goes from SOME_RESULTS->DONE in 115 // two cases: All results are known, or the wait timer expired. A call 116 // to Cancel() will also go straight to DONE from any state. Any 117 // way the DONE state is entered, we will at that point cancel any 118 // outstanding work and return the best known PAC script or the empty 119 // string. 120 // 121 // The state machine is reset for each Fetch(), a call to which is 122 // only valid in states START and DONE, as only one Fetch() is 123 // allowed to be outstanding at any given time. 124 enum State { 125 STATE_START, 126 STATE_WAIT_ADAPTERS, 127 STATE_NO_RESULTS, 128 STATE_SOME_RESULTS, 129 STATE_DONE, 130 }; 131 132 // Current state of this state machine. 133 State state_; 134 135 // Vector, in Windows' network adapter preference order, of 136 // DhcpProxyScriptAdapterFetcher objects that are or were attempting 137 // to fetch a PAC file based on DHCP configuration. 138 typedef ScopedVector<DhcpProxyScriptAdapterFetcher> FetcherVector; 139 FetcherVector fetchers_; 140 141 // Number of fetchers we are waiting for. 142 int num_pending_fetchers_; 143 144 // Lets our client know we're done. Not valid in states START or DONE. 145 net::CompletionCallback callback_; 146 147 // Pointer to string we will write results to. Not valid in states 148 // START and DONE. 149 base::string16* destination_string_; 150 151 // PAC URL retrieved from DHCP, if any. Valid only in state STATE_DONE. 152 GURL pac_url_; 153 154 base::OneShotTimer<DhcpProxyScriptFetcherWin> wait_timer_; 155 156 URLRequestContext* const url_request_context_; 157 158 // NULL or the AdapterQuery currently in flight. 159 scoped_refptr<AdapterQuery> last_query_; 160 161 // Time |Fetch()| was last called, 0 if never. 162 base::TimeTicks fetch_start_time_; 163 164 DISALLOW_IMPLICIT_CONSTRUCTORS(DhcpProxyScriptFetcherWin); 165 }; 166 167 } // namespace net 168 169 #endif // NET_PROXY_DHCP_PROXY_SCRIPT_FETCHER_WIN_H_ 170