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; | 66 state_ = STATE_WAIT_ADAPTERS; |
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; | |
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 15 matching lines...) Expand all Loading... |
106 for (FetcherVector::iterator it = fetchers_.begin(); | 97 for (FetcherVector::iterator it = fetchers_.begin(); |
107 it != fetchers_.end(); | 98 it != fetchers_.end(); |
108 ++it) { | 99 ++it) { |
109 (*it)->Cancel(); | 100 (*it)->Cancel(); |
110 } | 101 } |
111 | 102 |
112 fetchers_.reset(); | 103 fetchers_.reset(); |
113 } | 104 } |
114 } | 105 } |
115 | 106 |
| 107 void DhcpProxyScriptFetcherWin::OnGetCandidateAdapterNamesDone( |
| 108 const std::set<std::string>& adapter_names) { |
| 109 DCHECK(CalledOnValidThread()); |
| 110 |
| 111 // We may have been cancelled. |
| 112 if (state_ != STATE_WAIT_ADAPTERS) |
| 113 return; |
| 114 |
| 115 state_ = STATE_NO_RESULTS; |
| 116 |
| 117 if (adapter_names.empty()) { |
| 118 TransitionToDone(); |
| 119 return; |
| 120 } |
| 121 |
| 122 for (std::set<std::string>::const_iterator it = adapter_names.begin(); |
| 123 it != adapter_names.end(); |
| 124 ++it) { |
| 125 DhcpProxyScriptAdapterFetcher* fetcher(ImplCreateAdapterFetcher()); |
| 126 fetcher->Fetch(*it, &fetcher_callback_); |
| 127 fetchers_.push_back(fetcher); |
| 128 } |
| 129 num_pending_fetchers_ = fetchers_.size(); |
| 130 } |
| 131 |
116 std::string DhcpProxyScriptFetcherWin::GetFetcherName() const { | 132 std::string DhcpProxyScriptFetcherWin::GetFetcherName() const { |
117 DCHECK(CalledOnValidThread()); | 133 DCHECK(CalledOnValidThread()); |
118 return "win"; | 134 return "win"; |
119 } | 135 } |
120 | 136 |
121 const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const { | 137 const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const { |
122 DCHECK(CalledOnValidThread()); | 138 DCHECK(CalledOnValidThread()); |
123 DCHECK_EQ(state_, STATE_DONE); | 139 DCHECK_EQ(state_, STATE_DONE); |
124 | 140 |
125 return pac_url_; | 141 return pac_url_; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 fetchers_.size()); | 184 fetchers_.size()); |
169 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer", | 185 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer", |
170 num_pending_fetchers_); | 186 num_pending_fetchers_); |
171 | 187 |
172 TransitionToDone(); | 188 TransitionToDone(); |
173 } | 189 } |
174 | 190 |
175 void DhcpProxyScriptFetcherWin::TransitionToDone() { | 191 void DhcpProxyScriptFetcherWin::TransitionToDone() { |
176 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); | 192 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); |
177 | 193 |
178 // Should have returned immediately at Fetch() if no adapters to check. | 194 int result = ERR_PAC_NOT_IN_DHCP; // Default if no fetchers. |
179 DCHECK(!fetchers_.empty()); | 195 if (!fetchers_.empty()) { |
180 | 196 // Scan twice for the result; once through the whole list for success, |
181 // Scan twice for the result; once through the whole list for success, | 197 // then if no success, return result for most preferred network adapter, |
182 // then if no success, return result for most preferred network adapter, | 198 // preferring "real" network errors to the ERR_PAC_NOT_IN_DHCP error. |
183 // preferring "real" network errors to the ERR_PAC_NOT_IN_DHCP error. | 199 // Default to ERR_ABORTED if no fetcher completed. |
184 // Default to ERR_ABORTED if no fetcher completed. | 200 result = ERR_ABORTED; |
185 int result = ERR_ABORTED; | |
186 for (FetcherVector::iterator it = fetchers_.begin(); | |
187 it != fetchers_.end(); | |
188 ++it) { | |
189 if ((*it)->DidFinish() && (*it)->GetResult() == OK) { | |
190 result = OK; | |
191 *destination_string_ = (*it)->GetPacScript(); | |
192 pac_url_ = (*it)->GetPacURL(); | |
193 break; | |
194 } | |
195 } | |
196 if (result != OK) { | |
197 destination_string_->clear(); | |
198 for (FetcherVector::iterator it = fetchers_.begin(); | 201 for (FetcherVector::iterator it = fetchers_.begin(); |
199 it != fetchers_.end(); | 202 it != fetchers_.end(); |
200 ++it) { | 203 ++it) { |
201 if ((*it)->DidFinish()) { | 204 if ((*it)->DidFinish() && (*it)->GetResult() == OK) { |
202 result = (*it)->GetResult(); | 205 result = OK; |
203 if (result != ERR_PAC_NOT_IN_DHCP) { | 206 *destination_string_ = (*it)->GetPacScript(); |
204 break; | 207 pac_url_ = (*it)->GetPacURL(); |
| 208 break; |
| 209 } |
| 210 } |
| 211 if (result != OK) { |
| 212 destination_string_->clear(); |
| 213 for (FetcherVector::iterator it = fetchers_.begin(); |
| 214 it != fetchers_.end(); |
| 215 ++it) { |
| 216 if ((*it)->DidFinish()) { |
| 217 result = (*it)->GetResult(); |
| 218 if (result != ERR_PAC_NOT_IN_DHCP) { |
| 219 break; |
| 220 } |
205 } | 221 } |
206 } | 222 } |
207 } | 223 } |
208 } | 224 } |
209 | 225 |
210 CompletionCallback* callback = client_callback_; | 226 CompletionCallback* callback = client_callback_; |
211 CancelImpl(); | 227 CancelImpl(); |
212 DCHECK_EQ(state_, STATE_DONE); | 228 DCHECK_EQ(state_, STATE_DONE); |
213 DCHECK(fetchers_.empty()); | 229 DCHECK(fetchers_.empty()); |
214 DCHECK(!client_callback_); // Invariant of data. | 230 DCHECK(!client_callback_); // Invariant of data. |
(...skipping 16 matching lines...) Expand all Loading... |
231 | 247 |
232 URLRequestContext* DhcpProxyScriptFetcherWin::url_request_context() const { | 248 URLRequestContext* DhcpProxyScriptFetcherWin::url_request_context() const { |
233 return url_request_context_; | 249 return url_request_context_; |
234 } | 250 } |
235 | 251 |
236 DhcpProxyScriptAdapterFetcher* | 252 DhcpProxyScriptAdapterFetcher* |
237 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() { | 253 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() { |
238 return new DhcpProxyScriptAdapterFetcher(url_request_context_); | 254 return new DhcpProxyScriptAdapterFetcher(url_request_context_); |
239 } | 255 } |
240 | 256 |
241 bool DhcpProxyScriptFetcherWin::ImplGetCandidateAdapterNames( | 257 DhcpProxyScriptFetcherWin::WorkerThread* |
242 std::set<std::string>* adapter_names) { | 258 DhcpProxyScriptFetcherWin::ImplCreateWorkerThread( |
243 return GetCandidateAdapterNames(adapter_names); | 259 const base::WeakPtr<DhcpProxyScriptFetcherWin>& owner) { |
| 260 return new WorkerThread(owner); |
244 } | 261 } |
245 | 262 |
246 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() { | 263 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() { |
247 return kMaxWaitAfterFirstResultMs; | 264 return kMaxWaitAfterFirstResultMs; |
248 } | 265 } |
249 | 266 |
250 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames( | 267 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames( |
251 std::set<std::string>* adapter_names) { | 268 std::set<std::string>* adapter_names) { |
252 DCHECK(adapter_names); | 269 DCHECK(adapter_names); |
253 adapter_names->clear(); | 270 adapter_names->clear(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0) | 323 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0) |
307 continue; | 324 continue; |
308 | 325 |
309 DCHECK(adapter->AdapterName); | 326 DCHECK(adapter->AdapterName); |
310 adapter_names->insert(adapter->AdapterName); | 327 adapter_names->insert(adapter->AdapterName); |
311 } | 328 } |
312 | 329 |
313 return true; | 330 return true; |
314 } | 331 } |
315 | 332 |
| 333 DhcpProxyScriptFetcherWin::WorkerThread::WorkerThread( |
| 334 const base::WeakPtr<DhcpProxyScriptFetcherWin>& owner) { |
| 335 Init(owner); |
| 336 } |
| 337 |
| 338 DhcpProxyScriptFetcherWin::WorkerThread::~WorkerThread() { |
| 339 } |
| 340 |
| 341 void DhcpProxyScriptFetcherWin::WorkerThread::Start() { |
| 342 bool succeeded = base::WorkerPool::PostTask( |
| 343 FROM_HERE, |
| 344 NewRunnableMethod( |
| 345 this, |
| 346 &DhcpProxyScriptFetcherWin::WorkerThread::ThreadFunc), |
| 347 true); |
| 348 DCHECK(succeeded); |
| 349 } |
| 350 |
| 351 void DhcpProxyScriptFetcherWin::WorkerThread::ThreadFunc() { |
| 352 ImplGetCandidateAdapterNames(&adapter_names_); |
| 353 |
| 354 bool succeeded = origin_loop_->PostTask( |
| 355 FROM_HERE, |
| 356 NewRunnableMethod( |
| 357 this, |
| 358 &DhcpProxyScriptFetcherWin::WorkerThread::OnThreadDone)); |
| 359 DCHECK(succeeded); |
| 360 } |
| 361 |
| 362 void DhcpProxyScriptFetcherWin::WorkerThread::OnThreadDone() { |
| 363 DCHECK(thread_checker_.CalledOnValidThread()); |
| 364 if (owner_) |
| 365 owner_->OnGetCandidateAdapterNamesDone(adapter_names_); |
| 366 } |
| 367 |
| 368 DhcpProxyScriptFetcherWin::WorkerThread::WorkerThread() { |
| 369 } |
| 370 |
| 371 void DhcpProxyScriptFetcherWin::WorkerThread::Init( |
| 372 const base::WeakPtr<DhcpProxyScriptFetcherWin>& owner) { |
| 373 owner_ = owner; |
| 374 origin_loop_ = base::MessageLoopProxy::CreateForCurrentThread(); |
| 375 } |
| 376 |
| 377 bool DhcpProxyScriptFetcherWin::WorkerThread::ImplGetCandidateAdapterNames( |
| 378 std::set<std::string>* adapter_names) { |
| 379 return DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(adapter_names); |
| 380 } |
| 381 |
316 } // namespace net | 382 } // namespace net |
OLD | NEW |