Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: net/proxy/dhcp_proxy_script_fetcher_win.cc

Issue 7189016: Do GetAdaptersAddresses on a worker thread. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix handling of cancellation. Add regression test. Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/proxy/dhcp_proxy_script_fetcher_win.h ('k') | net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698