| 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 |