OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/proxy/dhcp_proxy_script_fetcher_win.h" | 5 #include "net/proxy/dhcp_proxy_script_fetcher_win.h" |
6 | 6 |
7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
8 #include "base/perftimer.h" | 8 #include "base/perftimer.h" |
9 #include "base/threading/worker_pool.h" | |
9 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
10 #include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h" | 11 #include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h" |
11 | 12 |
12 #include <winsock2.h> | 13 #include <winsock2.h> |
13 #include <iphlpapi.h> | 14 #include <iphlpapi.h> |
14 #pragma comment(lib, "iphlpapi.lib") | 15 #pragma comment(lib, "iphlpapi.lib") |
15 | 16 |
16 namespace { | 17 namespace { |
17 | 18 |
18 // How long to wait at maximum after we get results (a PAC file or | 19 // How long to wait at maximum after we get results (a PAC file or |
(...skipping 19 matching lines...) Expand all Loading... | |
38 ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_callback_( | 39 ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_callback_( |
39 this, &DhcpProxyScriptFetcherWin::OnFetcherDone)), | 40 this, &DhcpProxyScriptFetcherWin::OnFetcherDone)), |
40 num_pending_fetchers_(0), | 41 num_pending_fetchers_(0), |
41 url_request_context_(url_request_context) { | 42 url_request_context_(url_request_context) { |
42 DCHECK(url_request_context_); | 43 DCHECK(url_request_context_); |
43 } | 44 } |
44 | 45 |
45 DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() { | 46 DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() { |
46 // Count as user-initiated if we are not yet in STATE_DONE. | 47 // Count as user-initiated if we are not yet in STATE_DONE. |
47 Cancel(); | 48 Cancel(); |
49 | |
50 // The WeakPtr we passed to the worker thread may be destroyed on the | |
51 // worker thread. This detaches any outstanding WeakPtr state from | |
52 // the current thread. | |
53 base::SupportsWeakPtr<DhcpProxyScriptFetcherWin>::DetachFromThread(); | |
48 } | 54 } |
49 | 55 |
50 int DhcpProxyScriptFetcherWin::Fetch(string16* utf16_text, | 56 int DhcpProxyScriptFetcherWin::Fetch(string16* utf16_text, |
51 CompletionCallback* callback) { | 57 CompletionCallback* callback) { |
52 DCHECK(CalledOnValidThread()); | 58 DCHECK(CalledOnValidThread()); |
53 if (state_ != STATE_START && state_ != STATE_DONE) { | 59 if (state_ != STATE_START && state_ != STATE_DONE) { |
54 NOTREACHED(); | 60 NOTREACHED(); |
55 return ERR_UNEXPECTED; | 61 return ERR_UNEXPECTED; |
56 } | 62 } |
57 | 63 |
58 fetch_start_time_ = base::TimeTicks::Now(); | 64 fetch_start_time_ = base::TimeTicks::Now(); |
59 | 65 |
60 std::set<std::string> adapter_names; | |
61 if (!ImplGetCandidateAdapterNames(&adapter_names)) { | |
62 return ERR_UNEXPECTED; | |
63 } | |
64 if (adapter_names.empty()) { | |
65 return ERR_PAC_NOT_IN_DHCP; | |
66 } | |
67 | |
68 state_ = STATE_NO_RESULTS; | 66 state_ = STATE_NO_RESULTS; |
69 | |
70 client_callback_ = callback; | 67 client_callback_ = callback; |
71 destination_string_ = utf16_text; | 68 destination_string_ = utf16_text; |
72 | 69 |
73 for (std::set<std::string>::iterator it = adapter_names.begin(); | 70 worker_thread_ = ImplCreateWorkerThread(AsWeakPtr()); |
74 it != adapter_names.end(); | 71 worker_thread_->Start(); |
75 ++it) { | |
76 DhcpProxyScriptAdapterFetcher* fetcher(ImplCreateAdapterFetcher()); | |
77 fetcher->Fetch(*it, &fetcher_callback_); | |
78 fetchers_.push_back(fetcher); | |
79 } | |
80 num_pending_fetchers_ = fetchers_.size(); | |
81 | 72 |
82 return ERR_IO_PENDING; | 73 return ERR_IO_PENDING; |
83 } | 74 } |
84 | 75 |
85 void DhcpProxyScriptFetcherWin::Cancel() { | 76 void DhcpProxyScriptFetcherWin::Cancel() { |
86 DCHECK(CalledOnValidThread()); | 77 DCHECK(CalledOnValidThread()); |
87 | 78 |
88 if (state_ != STATE_DONE) { | 79 if (state_ != STATE_DONE) { |
89 // We only count this stat if the cancel was explicitly initiated by | 80 // We only count this stat if the cancel was explicitly initiated by |
90 // our client, and if we weren't already in STATE_DONE. | 81 // our client, and if we weren't already in STATE_DONE. |
(...skipping 14 matching lines...) Expand all Loading... | |
105 for (FetcherVector::iterator it = fetchers_.begin(); | 96 for (FetcherVector::iterator it = fetchers_.begin(); |
106 it != fetchers_.end(); | 97 it != fetchers_.end(); |
107 ++it) { | 98 ++it) { |
108 (*it)->Cancel(); | 99 (*it)->Cancel(); |
109 } | 100 } |
110 | 101 |
111 fetchers_.reset(); | 102 fetchers_.reset(); |
112 } | 103 } |
113 } | 104 } |
114 | 105 |
106 void DhcpProxyScriptFetcherWin::OnGetCandidateAdapterNamesDone( | |
107 const std::set<std::string>& adapter_names) { | |
108 if (adapter_names.empty()) { | |
109 TransitionToDone(); | |
110 return; | |
111 } | |
112 | |
113 for (std::set<std::string>::const_iterator it = adapter_names.begin(); | |
114 it != adapter_names.end(); | |
115 ++it) { | |
116 DhcpProxyScriptAdapterFetcher* fetcher(ImplCreateAdapterFetcher()); | |
117 fetcher->Fetch(*it, &fetcher_callback_); | |
118 fetchers_.push_back(fetcher); | |
119 } | |
120 num_pending_fetchers_ = fetchers_.size(); | |
121 } | |
122 | |
115 std::string DhcpProxyScriptFetcherWin::GetFetcherName() const { | 123 std::string DhcpProxyScriptFetcherWin::GetFetcherName() const { |
116 DCHECK(CalledOnValidThread()); | 124 DCHECK(CalledOnValidThread()); |
117 return "win"; | 125 return "win"; |
118 } | 126 } |
119 | 127 |
120 const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const { | 128 const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const { |
121 DCHECK(CalledOnValidThread()); | 129 DCHECK(CalledOnValidThread()); |
122 DCHECK_EQ(state_, STATE_DONE); | 130 DCHECK_EQ(state_, STATE_DONE); |
123 | 131 |
124 return pac_url_; | 132 return pac_url_; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
167 fetchers_.size()); | 175 fetchers_.size()); |
168 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer", | 176 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer", |
169 num_pending_fetchers_); | 177 num_pending_fetchers_); |
170 | 178 |
171 TransitionToDone(); | 179 TransitionToDone(); |
172 } | 180 } |
173 | 181 |
174 void DhcpProxyScriptFetcherWin::TransitionToDone() { | 182 void DhcpProxyScriptFetcherWin::TransitionToDone() { |
175 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); | 183 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); |
176 | 184 |
177 // Should have returned immediately at Fetch() if no adapters to check. | 185 int result = ERR_PAC_NOT_IN_DHCP; // Default if no fetchers. |
178 DCHECK(!fetchers_.empty()); | 186 if (!fetchers_.empty()) { |
179 | 187 // Scan twice for the result; once through the whole list for success, |
180 // Scan twice for the result; once through the whole list for success, | 188 // then if no success, return result for most preferred network adapter, |
181 // then if no success, return result for most preferred network adapter, | 189 // preferring "real" network errors to the ERR_PAC_NOT_IN_DHCP error. |
182 // preferring "real" network errors to the ERR_PAC_NOT_IN_DHCP error. | 190 // Default to ERR_ABORTED if no fetcher completed. |
183 // Default to ERR_ABORTED if no fetcher completed. | 191 result = ERR_ABORTED; |
184 int result = ERR_ABORTED; | |
185 for (FetcherVector::iterator it = fetchers_.begin(); | |
186 it != fetchers_.end(); | |
187 ++it) { | |
188 if ((*it)->DidFinish() && (*it)->GetResult() == OK) { | |
189 result = OK; | |
190 *destination_string_ = (*it)->GetPacScript(); | |
191 pac_url_ = (*it)->GetPacURL(); | |
192 break; | |
193 } | |
194 } | |
195 if (result != OK) { | |
196 destination_string_->clear(); | |
197 for (FetcherVector::iterator it = fetchers_.begin(); | 192 for (FetcherVector::iterator it = fetchers_.begin(); |
198 it != fetchers_.end(); | 193 it != fetchers_.end(); |
199 ++it) { | 194 ++it) { |
200 if ((*it)->DidFinish()) { | 195 if ((*it)->DidFinish() && (*it)->GetResult() == OK) { |
201 result = (*it)->GetResult(); | 196 result = OK; |
202 if (result != ERR_PAC_NOT_IN_DHCP) { | 197 *destination_string_ = (*it)->GetPacScript(); |
203 break; | 198 pac_url_ = (*it)->GetPacURL(); |
199 break; | |
200 } | |
201 } | |
202 if (result != OK) { | |
203 destination_string_->clear(); | |
204 for (FetcherVector::iterator it = fetchers_.begin(); | |
205 it != fetchers_.end(); | |
206 ++it) { | |
207 if ((*it)->DidFinish()) { | |
208 result = (*it)->GetResult(); | |
209 if (result != ERR_PAC_NOT_IN_DHCP) { | |
210 break; | |
211 } | |
204 } | 212 } |
205 } | 213 } |
206 } | 214 } |
207 } | 215 } |
208 | 216 |
209 CancelImpl(); | 217 CancelImpl(); |
210 DCHECK_EQ(state_, STATE_DONE); | 218 DCHECK_EQ(state_, STATE_DONE); |
211 DCHECK(fetchers_.empty()); | 219 DCHECK(fetchers_.empty()); |
212 | 220 |
213 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCompletionTime", | 221 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCompletionTime", |
(...skipping 13 matching lines...) Expand all Loading... | |
227 | 235 |
228 URLRequestContext* DhcpProxyScriptFetcherWin::url_request_context() const { | 236 URLRequestContext* DhcpProxyScriptFetcherWin::url_request_context() const { |
229 return url_request_context_; | 237 return url_request_context_; |
230 } | 238 } |
231 | 239 |
232 DhcpProxyScriptAdapterFetcher* | 240 DhcpProxyScriptAdapterFetcher* |
233 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() { | 241 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() { |
234 return new DhcpProxyScriptAdapterFetcher(url_request_context_); | 242 return new DhcpProxyScriptAdapterFetcher(url_request_context_); |
235 } | 243 } |
236 | 244 |
237 bool DhcpProxyScriptFetcherWin::ImplGetCandidateAdapterNames( | 245 DhcpProxyScriptFetcherWin::WorkerThread* |
238 std::set<std::string>* adapter_names) { | 246 DhcpProxyScriptFetcherWin::ImplCreateWorkerThread( |
239 return GetCandidateAdapterNames(adapter_names); | 247 const base::WeakPtr<DhcpProxyScriptFetcherWin>& owner) { |
248 return new WorkerThread(owner); | |
240 } | 249 } |
241 | 250 |
242 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() { | 251 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() { |
243 return kMaxWaitAfterFirstResultMs; | 252 return kMaxWaitAfterFirstResultMs; |
244 } | 253 } |
245 | 254 |
246 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames( | 255 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames( |
247 std::set<std::string>* adapter_names) { | 256 std::set<std::string>* adapter_names) { |
248 DCHECK(adapter_names); | 257 DCHECK(adapter_names); |
249 adapter_names->clear(); | 258 adapter_names->clear(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0) | 311 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0) |
303 continue; | 312 continue; |
304 | 313 |
305 DCHECK(adapter->AdapterName); | 314 DCHECK(adapter->AdapterName); |
306 adapter_names->insert(adapter->AdapterName); | 315 adapter_names->insert(adapter->AdapterName); |
307 } | 316 } |
308 | 317 |
309 return true; | 318 return true; |
310 } | 319 } |
311 | 320 |
321 DhcpProxyScriptFetcherWin::WorkerThread::WorkerThread( | |
322 const base::WeakPtr<DhcpProxyScriptFetcherWin>& owner) { | |
323 Init(owner); | |
324 } | |
325 | |
326 DhcpProxyScriptFetcherWin::WorkerThread::~WorkerThread() { | |
327 } | |
328 | |
329 void DhcpProxyScriptFetcherWin::WorkerThread::Start() { | |
330 bool succeeded = base::WorkerPool::PostTask( | |
331 FROM_HERE, | |
332 NewRunnableMethod( | |
333 this, | |
334 &DhcpProxyScriptFetcherWin::WorkerThread::ThreadFunc), | |
335 true); | |
336 DCHECK(succeeded); | |
337 } | |
338 | |
339 void DhcpProxyScriptFetcherWin::WorkerThread::ThreadFunc() { | |
340 ImplGetCandidateAdapterNames(&adapter_names_); | |
341 | |
342 bool succeeded = origin_loop_->PostTask( | |
343 FROM_HERE, | |
344 NewRunnableMethod( | |
345 this, | |
346 &DhcpProxyScriptFetcherWin::WorkerThread::OnThreadDone)); | |
347 DCHECK(succeeded); | |
348 } | |
349 | |
350 void DhcpProxyScriptFetcherWin::WorkerThread::OnThreadDone() { | |
351 DCHECK(thread_checker_.CalledOnValidThread()); | |
352 if (owner_) | |
353 owner_->OnGetCandidateAdapterNamesDone(adapter_names_); | |
eroman
2011/06/21 03:02:54
How is cancellation handled?
I understand that if
| |
354 } | |
355 | |
356 DhcpProxyScriptFetcherWin::WorkerThread::WorkerThread() { | |
357 } | |
358 | |
359 void DhcpProxyScriptFetcherWin::WorkerThread::Init( | |
360 const base::WeakPtr<DhcpProxyScriptFetcherWin>& owner) { | |
361 owner_ = owner; | |
362 origin_loop_ = base::MessageLoopProxy::CreateForCurrentThread(); | |
363 } | |
364 | |
365 bool DhcpProxyScriptFetcherWin::WorkerThread::ImplGetCandidateAdapterNames( | |
366 std::set<std::string>* adapter_names) { | |
367 return DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(adapter_names); | |
368 } | |
369 | |
312 } // namespace net | 370 } // namespace net |
OLD | NEW |