Chromium Code Reviews| 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 |