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

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

Issue 6975027: Add metrics for DHCP WPAD feature. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Respond to review comments. Created 9 years, 7 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
« no previous file with comments | « net/proxy/dhcp_proxy_script_fetcher_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
8 #include "base/perftimer.h"
7 #include "net/base/net_errors.h" 9 #include "net/base/net_errors.h"
8 #include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h" 10 #include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h"
9 11
10 #include <winsock2.h> 12 #include <winsock2.h>
11 #include <iphlpapi.h> 13 #include <iphlpapi.h>
12 #pragma comment(lib, "iphlpapi.lib") 14 #pragma comment(lib, "iphlpapi.lib")
13 15
14 namespace { 16 namespace {
15 17
16 // How long to wait at maximum after we get results (a PAC file or 18 // How long to wait at maximum after we get results (a PAC file or
17 // knowledge that no PAC file is configured) from whichever network 19 // knowledge that no PAC file is configured) from whichever network
18 // adapter finishes first. 20 // adapter finishes first.
19 const int kMaxWaitAfterFirstResultMs = 400; 21 const int kMaxWaitAfterFirstResultMs = 400;
20 22
23 const int kGetAdaptersAddressesErrors[] = {
24 ERROR_ADDRESS_NOT_ASSOCIATED,
25 ERROR_BUFFER_OVERFLOW,
26 ERROR_INVALID_PARAMETER,
27 ERROR_NOT_ENOUGH_MEMORY,
28 ERROR_NO_DATA,
29 };
30
21 } // namespace 31 } // namespace
22 32
23 namespace net { 33 namespace net {
24 34
25 DhcpProxyScriptFetcherWin::DhcpProxyScriptFetcherWin( 35 DhcpProxyScriptFetcherWin::DhcpProxyScriptFetcherWin(
26 URLRequestContext* url_request_context) 36 URLRequestContext* url_request_context)
27 : state_(STATE_START), 37 : state_(STATE_START),
28 ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_callback_( 38 ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_callback_(
29 this, &DhcpProxyScriptFetcherWin::OnFetcherDone)), 39 this, &DhcpProxyScriptFetcherWin::OnFetcherDone)),
30 num_pending_fetchers_(0), 40 num_pending_fetchers_(0),
31 url_request_context_(url_request_context) { 41 url_request_context_(url_request_context) {
32 DCHECK(url_request_context_); 42 DCHECK(url_request_context_);
33 } 43 }
34 44
35 DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() { 45 DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() {
46 // Count as user-initiated if we are not yet in STATE_DONE.
36 Cancel(); 47 Cancel();
37 } 48 }
38 49
39 int DhcpProxyScriptFetcherWin::Fetch(string16* utf16_text, 50 int DhcpProxyScriptFetcherWin::Fetch(string16* utf16_text,
40 CompletionCallback* callback) { 51 CompletionCallback* callback) {
41 DCHECK(CalledOnValidThread()); 52 DCHECK(CalledOnValidThread());
42 if (state_ != STATE_START && state_ != STATE_DONE) { 53 if (state_ != STATE_START && state_ != STATE_DONE) {
43 NOTREACHED(); 54 NOTREACHED();
44 return ERR_UNEXPECTED; 55 return ERR_UNEXPECTED;
45 } 56 }
46 57
58 fetch_start_time_ = base::TimeTicks::Now();
59
47 std::set<std::string> adapter_names; 60 std::set<std::string> adapter_names;
48 if (!ImplGetCandidateAdapterNames(&adapter_names)) { 61 if (!ImplGetCandidateAdapterNames(&adapter_names)) {
49 return ERR_UNEXPECTED; 62 return ERR_UNEXPECTED;
50 } 63 }
51 if (adapter_names.empty()) { 64 if (adapter_names.empty()) {
52 return ERR_PAC_NOT_IN_DHCP; 65 return ERR_PAC_NOT_IN_DHCP;
53 } 66 }
54 67
55 state_ = STATE_NO_RESULTS; 68 state_ = STATE_NO_RESULTS;
56 69
57 client_callback_ = callback; 70 client_callback_ = callback;
58 destination_string_ = utf16_text; 71 destination_string_ = utf16_text;
59 72
60 for (std::set<std::string>::iterator it = adapter_names.begin(); 73 for (std::set<std::string>::iterator it = adapter_names.begin();
61 it != adapter_names.end(); 74 it != adapter_names.end();
62 ++it) { 75 ++it) {
63 DhcpProxyScriptAdapterFetcher* fetcher(ImplCreateAdapterFetcher()); 76 DhcpProxyScriptAdapterFetcher* fetcher(ImplCreateAdapterFetcher());
64 fetcher->Fetch(*it, &fetcher_callback_); 77 fetcher->Fetch(*it, &fetcher_callback_);
65 fetchers_.push_back(fetcher); 78 fetchers_.push_back(fetcher);
66 } 79 }
67 num_pending_fetchers_ = fetchers_.size(); 80 num_pending_fetchers_ = fetchers_.size();
68 81
69 return ERR_IO_PENDING; 82 return ERR_IO_PENDING;
70 } 83 }
71 84
72 void DhcpProxyScriptFetcherWin::Cancel() { 85 void DhcpProxyScriptFetcherWin::Cancel() {
73 DCHECK(CalledOnValidThread()); 86 DCHECK(CalledOnValidThread());
74 87
75 if (state_ != STATE_DONE) { 88 if (state_ != STATE_DONE) {
89 // We only count this stat if the cancel was explicitly initiated by
90 // our client, and if we weren't already in STATE_DONE.
91 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCancelTime",
92 base::TimeTicks::Now() - fetch_start_time_);
93 }
94
95 CancelImpl();
96 }
97
98 void DhcpProxyScriptFetcherWin::CancelImpl() {
99 DCHECK(CalledOnValidThread());
100
101 if (state_ != STATE_DONE) {
76 wait_timer_.Stop(); 102 wait_timer_.Stop();
77 state_ = STATE_DONE; 103 state_ = STATE_DONE;
78 104
79 for (FetcherVector::iterator it = fetchers_.begin(); 105 for (FetcherVector::iterator it = fetchers_.begin();
80 it != fetchers_.end(); 106 it != fetchers_.end();
81 ++it) { 107 ++it) {
82 (*it)->Cancel(); 108 (*it)->Cancel();
83 } 109 }
84 110
85 fetchers_.reset(); 111 fetchers_.reset();
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 if (state_ == STATE_NO_RESULTS) { 153 if (state_ == STATE_NO_RESULTS) {
128 state_ = STATE_SOME_RESULTS; 154 state_ = STATE_SOME_RESULTS;
129 wait_timer_.Start( 155 wait_timer_.Start(
130 base::TimeDelta::FromMilliseconds(ImplGetMaxWaitMs()), 156 base::TimeDelta::FromMilliseconds(ImplGetMaxWaitMs()),
131 this, &DhcpProxyScriptFetcherWin::OnWaitTimer); 157 this, &DhcpProxyScriptFetcherWin::OnWaitTimer);
132 } 158 }
133 } 159 }
134 160
135 void DhcpProxyScriptFetcherWin::OnWaitTimer() { 161 void DhcpProxyScriptFetcherWin::OnWaitTimer() {
136 DCHECK_EQ(state_, STATE_SOME_RESULTS); 162 DCHECK_EQ(state_, STATE_SOME_RESULTS);
163
164 // These are intended to help us understand whether our timeout may
165 // be too aggressive or not aggressive enough.
166 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumAdaptersAtWaitTimer",
167 fetchers_.size());
168 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer",
169 num_pending_fetchers_);
170
137 TransitionToDone(); 171 TransitionToDone();
138 } 172 }
139 173
140 void DhcpProxyScriptFetcherWin::TransitionToDone() { 174 void DhcpProxyScriptFetcherWin::TransitionToDone() {
141 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); 175 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS);
142 176
143 // Should have returned immediately at Fetch() if no adapters to check. 177 // Should have returned immediately at Fetch() if no adapters to check.
144 DCHECK(!fetchers_.empty()); 178 DCHECK(!fetchers_.empty());
145 179
146 // 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,
(...skipping 18 matching lines...) Expand all
165 ++it) { 199 ++it) {
166 if ((*it)->DidFinish()) { 200 if ((*it)->DidFinish()) {
167 result = (*it)->GetResult(); 201 result = (*it)->GetResult();
168 if (result != ERR_PAC_NOT_IN_DHCP) { 202 if (result != ERR_PAC_NOT_IN_DHCP) {
169 break; 203 break;
170 } 204 }
171 } 205 }
172 } 206 }
173 } 207 }
174 208
175 Cancel(); 209 CancelImpl();
176 DCHECK_EQ(state_, STATE_DONE); 210 DCHECK_EQ(state_, STATE_DONE);
177 DCHECK(fetchers_.empty()); 211 DCHECK(fetchers_.empty());
178 212
213 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCompletionTime",
214 base::TimeTicks::Now() - fetch_start_time_);
215
216 if (result != OK) {
217 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
218 "Net.DhcpWpadFetchError", std::abs(result), GetAllErrorCodesForUma());
219 }
220
179 client_callback_->Run(result); 221 client_callback_->Run(result);
180 } 222 }
181 223
182 DhcpProxyScriptAdapterFetcher* 224 DhcpProxyScriptAdapterFetcher*
183 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() { 225 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() {
184 return new DhcpProxyScriptAdapterFetcher(url_request_context_); 226 return new DhcpProxyScriptAdapterFetcher(url_request_context_);
185 } 227 }
186 228
187 bool DhcpProxyScriptFetcherWin::ImplGetCandidateAdapterNames( 229 bool DhcpProxyScriptFetcherWin::ImplGetCandidateAdapterNames(
188 std::set<std::string>* adapter_names) { 230 std::set<std::string>* adapter_names) {
189 return GetCandidateAdapterNames(adapter_names); 231 return GetCandidateAdapterNames(adapter_names);
190 } 232 }
191 233
192 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() { 234 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() {
193 return kMaxWaitAfterFirstResultMs; 235 return kMaxWaitAfterFirstResultMs;
194 } 236 }
195 237
196 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames( 238 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(
197 std::set<std::string>* adapter_names) { 239 std::set<std::string>* adapter_names) {
198 DCHECK(adapter_names); 240 DCHECK(adapter_names);
199 adapter_names->clear(); 241 adapter_names->clear();
200 242
201 // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to 243 // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to
202 // avoid reallocation. 244 // avoid reallocation.
203 ULONG adapters_size = 15000; 245 ULONG adapters_size = 15000;
204 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> adapters; 246 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> adapters;
205 ULONG error = ERROR_SUCCESS; 247 ULONG error = ERROR_SUCCESS;
206 int num_tries = 0; 248 int num_tries = 0;
249
250 PerfTimer time_api_access;
207 do { 251 do {
208 adapters.reset( 252 adapters.reset(
209 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size))); 253 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size)));
210 // Return only unicast addresses, and skip information we do not need. 254 // Return only unicast addresses, and skip information we do not need.
211 error = GetAdaptersAddresses(AF_UNSPEC, 255 error = GetAdaptersAddresses(AF_UNSPEC,
212 GAA_FLAG_SKIP_ANYCAST | 256 GAA_FLAG_SKIP_ANYCAST |
213 GAA_FLAG_SKIP_MULTICAST | 257 GAA_FLAG_SKIP_MULTICAST |
214 GAA_FLAG_SKIP_DNS_SERVER | 258 GAA_FLAG_SKIP_DNS_SERVER |
215 GAA_FLAG_SKIP_FRIENDLY_NAME, 259 GAA_FLAG_SKIP_FRIENDLY_NAME,
216 NULL, 260 NULL,
217 adapters.get(), 261 adapters.get(),
218 &adapters_size); 262 &adapters_size);
219 ++num_tries; 263 ++num_tries;
220 } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3); 264 } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3);
221 265
266 // This is primarily to validate our belief that the GetAdaptersAddresses API
267 // function is fast enough to call synchronously from the network thread.
268 UMA_HISTOGRAM_TIMES("Net.DhcpWpadGetAdaptersAddressesTime",
269 time_api_access.Elapsed());
270
271 if (error != ERROR_SUCCESS) {
272 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
273 "Net.DhcpWpadGetAdaptersAddressesError",
274 error,
275 base::CustomHistogram::ArrayToCustomRanges(
276 kGetAdaptersAddressesErrors,
277 arraysize(kGetAdaptersAddressesErrors)));
278 }
279
222 if (error == ERROR_NO_DATA) { 280 if (error == ERROR_NO_DATA) {
223 // There are no adapters that we care about. 281 // There are no adapters that we care about.
224 return true; 282 return true;
225 } 283 }
226 284
227 if (error != ERROR_SUCCESS) { 285 if (error != ERROR_SUCCESS) {
228 LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP."; 286 LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP.";
229 return false; 287 return false;
230 } 288 }
231 289
232 IP_ADAPTER_ADDRESSES* adapter = NULL; 290 IP_ADAPTER_ADDRESSES* adapter = NULL;
233 for (adapter = adapters.get(); adapter; adapter = adapter->Next) { 291 for (adapter = adapters.get(); adapter; adapter = adapter->Next) {
234 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) 292 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
235 continue; 293 continue;
236 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0) 294 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0)
237 continue; 295 continue;
238 296
239 DCHECK(adapter->AdapterName); 297 DCHECK(adapter->AdapterName);
240 adapter_names->insert(adapter->AdapterName); 298 adapter_names->insert(adapter->AdapterName);
241 } 299 }
242 300
243 return true; 301 return true;
244 } 302 }
245 303
246 } // namespace net 304 } // namespace net
OLDNEW
« no previous file with comments | « net/proxy/dhcp_proxy_script_fetcher_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698