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

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: Diff to right base. 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 unsigned long 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 // We use this as a placeholder (in our result code UMA histogram)
31 // for any error we don't specifically include in this enumeration.
32 ERROR_GEN_FAILURE,
33 };
34
35 std::vector<int> GetAllGetAdaptersAddressesErrors() {
36 std::vector<int> errors;
37 for (size_t i = 0; i < arraysize(kGetAdaptersAddressesErrors); ++i) {
38 int error_code = kGetAdaptersAddressesErrors[i];
39 errors.push_back(error_code);
40 // Also add N+1 for each error, so the bucket that contains our expected
41 // error is of size 1. That way if we get unexpected error codes, they
42 // won't fall into the same buckets as the expected ones.
43 errors.push_back(error_code + 1);
44 }
45 return errors;
46 }
47
48 // Returns the passed-in error code if it is in kGetAdaptersAddressesErrors,
49 // otherwise ERROR_GEN_FAILURE.
50 unsigned long EnsureGetAdaptersAddressesError(unsigned long error_code) {
eroman%chromium.org 2011/05/18 20:33:27 It shouldn't be necessary to map unexpected errors
Jói 2011/05/19 14:39:49 Ah, I misunderstood how the UMA enumerations worke
51 for (size_t i = 0; i < arraysize(kGetAdaptersAddressesErrors); ++i) {
52 if (error_code == kGetAdaptersAddressesErrors[i])
53 return error_code;
54 }
55 return ERROR_GEN_FAILURE;
56 }
57
21 } // namespace 58 } // namespace
22 59
23 namespace net { 60 namespace net {
24 61
25 DhcpProxyScriptFetcherWin::DhcpProxyScriptFetcherWin( 62 DhcpProxyScriptFetcherWin::DhcpProxyScriptFetcherWin(
26 URLRequestContext* url_request_context) 63 URLRequestContext* url_request_context)
27 : state_(STATE_START), 64 : state_(STATE_START),
28 ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_callback_( 65 ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_callback_(
29 this, &DhcpProxyScriptFetcherWin::OnFetcherDone)), 66 this, &DhcpProxyScriptFetcherWin::OnFetcherDone)),
30 num_pending_fetchers_(0), 67 num_pending_fetchers_(0),
31 url_request_context_(url_request_context) { 68 url_request_context_(url_request_context) {
32 DCHECK(url_request_context_); 69 DCHECK(url_request_context_);
33 } 70 }
34 71
35 DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() { 72 DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() {
36 Cancel(); 73 // Count as user-initiated if we are not yet in STATE_DONE.
74 CancelImpl(true);
37 } 75 }
38 76
39 int DhcpProxyScriptFetcherWin::Fetch(string16* utf16_text, 77 int DhcpProxyScriptFetcherWin::Fetch(string16* utf16_text,
40 CompletionCallback* callback) { 78 CompletionCallback* callback) {
41 DCHECK(CalledOnValidThread()); 79 DCHECK(CalledOnValidThread());
42 if (state_ != STATE_START && state_ != STATE_DONE) { 80 if (state_ != STATE_START && state_ != STATE_DONE) {
43 NOTREACHED(); 81 NOTREACHED();
44 return ERR_UNEXPECTED; 82 return ERR_UNEXPECTED;
45 } 83 }
46 84
85 fetch_start_time_ = base::TimeTicks::Now();
86
47 std::set<std::string> adapter_names; 87 std::set<std::string> adapter_names;
48 if (!ImplGetCandidateAdapterNames(&adapter_names)) { 88 if (!ImplGetCandidateAdapterNames(&adapter_names)) {
49 return ERR_UNEXPECTED; 89 return ERR_UNEXPECTED;
50 } 90 }
51 if (adapter_names.empty()) { 91 if (adapter_names.empty()) {
52 return ERR_PAC_NOT_IN_DHCP; 92 return ERR_PAC_NOT_IN_DHCP;
53 } 93 }
54 94
55 state_ = STATE_NO_RESULTS; 95 state_ = STATE_NO_RESULTS;
56 96
57 client_callback_ = callback; 97 client_callback_ = callback;
58 destination_string_ = utf16_text; 98 destination_string_ = utf16_text;
59 99
60 for (std::set<std::string>::iterator it = adapter_names.begin(); 100 for (std::set<std::string>::iterator it = adapter_names.begin();
61 it != adapter_names.end(); 101 it != adapter_names.end();
62 ++it) { 102 ++it) {
63 DhcpProxyScriptAdapterFetcher* fetcher(ImplCreateAdapterFetcher()); 103 DhcpProxyScriptAdapterFetcher* fetcher(ImplCreateAdapterFetcher());
64 fetcher->Fetch(*it, &fetcher_callback_); 104 fetcher->Fetch(*it, &fetcher_callback_);
65 fetchers_.push_back(fetcher); 105 fetchers_.push_back(fetcher);
66 } 106 }
67 num_pending_fetchers_ = fetchers_.size(); 107 num_pending_fetchers_ = fetchers_.size();
68 108
69 return ERR_IO_PENDING; 109 return ERR_IO_PENDING;
70 } 110 }
71 111
72 void DhcpProxyScriptFetcherWin::Cancel() { 112 void DhcpProxyScriptFetcherWin::Cancel() {
113 CancelImpl(true);
114 }
115
116 void DhcpProxyScriptFetcherWin::CancelImpl(bool user_initiated) {
73 DCHECK(CalledOnValidThread()); 117 DCHECK(CalledOnValidThread());
74 118
75 if (state_ != STATE_DONE) { 119 if (state_ != STATE_DONE) {
76 wait_timer_.Stop(); 120 wait_timer_.Stop();
77 state_ = STATE_DONE; 121 state_ = STATE_DONE;
78 122
79 for (FetcherVector::iterator it = fetchers_.begin(); 123 for (FetcherVector::iterator it = fetchers_.begin();
80 it != fetchers_.end(); 124 it != fetchers_.end();
81 ++it) { 125 ++it) {
82 (*it)->Cancel(); 126 (*it)->Cancel();
83 } 127 }
84 128
85 fetchers_.reset(); 129 fetchers_.reset();
130
131 if (user_initiated) {
132 // We only count this stat if the cancel was explicitly initiated by
133 // our client, and if we weren't already in STATE_DONE.
134 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCancelTime",
eroman%chromium.org 2011/05/18 20:33:27 I am not sure how useful the cancelation info will
Jói 2011/05/19 14:39:49 Yeah - once I start seeing the stats I'll remove t
135 base::TimeTicks::Now() - fetch_start_time_);
136 }
86 } 137 }
87 } 138 }
88 139
89 std::string DhcpProxyScriptFetcherWin::GetFetcherName() const { 140 std::string DhcpProxyScriptFetcherWin::GetFetcherName() const {
90 DCHECK(CalledOnValidThread()); 141 DCHECK(CalledOnValidThread());
91 return "win"; 142 return "win";
92 } 143 }
93 144
94 const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const { 145 const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const {
95 DCHECK(CalledOnValidThread()); 146 DCHECK(CalledOnValidThread());
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 if (state_ == STATE_NO_RESULTS) { 178 if (state_ == STATE_NO_RESULTS) {
128 state_ = STATE_SOME_RESULTS; 179 state_ = STATE_SOME_RESULTS;
129 wait_timer_.Start( 180 wait_timer_.Start(
130 base::TimeDelta::FromMilliseconds(ImplGetMaxWaitMs()), 181 base::TimeDelta::FromMilliseconds(ImplGetMaxWaitMs()),
131 this, &DhcpProxyScriptFetcherWin::OnWaitTimer); 182 this, &DhcpProxyScriptFetcherWin::OnWaitTimer);
132 } 183 }
133 } 184 }
134 185
135 void DhcpProxyScriptFetcherWin::OnWaitTimer() { 186 void DhcpProxyScriptFetcherWin::OnWaitTimer() {
136 DCHECK_EQ(state_, STATE_SOME_RESULTS); 187 DCHECK_EQ(state_, STATE_SOME_RESULTS);
188
189 // These are intended to help us understand whether our timeout may
190 // be too aggressive or not aggressive enough.
191 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumAdaptersAtWaitTimer",
192 fetchers_.size());
193 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer",
194 num_pending_fetchers_);
195
137 TransitionToDone(); 196 TransitionToDone();
138 } 197 }
139 198
140 void DhcpProxyScriptFetcherWin::TransitionToDone() { 199 void DhcpProxyScriptFetcherWin::TransitionToDone() {
141 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); 200 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS);
142 201
143 // Should have returned immediately at Fetch() if no adapters to check. 202 // Should have returned immediately at Fetch() if no adapters to check.
144 DCHECK(!fetchers_.empty()); 203 DCHECK(!fetchers_.empty());
145 204
146 // Scan twice for the result; once through the whole list for success, 205 // Scan twice for the result; once through the whole list for success,
(...skipping 18 matching lines...) Expand all
165 ++it) { 224 ++it) {
166 if ((*it)->DidFinish()) { 225 if ((*it)->DidFinish()) {
167 result = (*it)->GetResult(); 226 result = (*it)->GetResult();
168 if (result != ERR_PAC_NOT_IN_DHCP) { 227 if (result != ERR_PAC_NOT_IN_DHCP) {
169 break; 228 break;
170 } 229 }
171 } 230 }
172 } 231 }
173 } 232 }
174 233
175 Cancel(); 234 CancelImpl(false);
176 DCHECK_EQ(state_, STATE_DONE); 235 DCHECK_EQ(state_, STATE_DONE);
177 DCHECK(fetchers_.empty()); 236 DCHECK(fetchers_.empty());
178 237
238 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCompletionTime",
239 base::TimeTicks::Now() - fetch_start_time_);
240
241 if (result != OK) {
242 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
243 "Net.DhcpWpadFetchError", std::abs(result), GetAllErrorCodesForUma());
244 }
245
179 client_callback_->Run(result); 246 client_callback_->Run(result);
180 } 247 }
181 248
182 DhcpProxyScriptAdapterFetcher* 249 DhcpProxyScriptAdapterFetcher*
183 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() { 250 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() {
184 return new DhcpProxyScriptAdapterFetcher(url_request_context_); 251 return new DhcpProxyScriptAdapterFetcher(url_request_context_);
185 } 252 }
186 253
187 bool DhcpProxyScriptFetcherWin::ImplGetCandidateAdapterNames( 254 bool DhcpProxyScriptFetcherWin::ImplGetCandidateAdapterNames(
188 std::set<std::string>* adapter_names) { 255 std::set<std::string>* adapter_names) {
189 return GetCandidateAdapterNames(adapter_names); 256 return GetCandidateAdapterNames(adapter_names);
190 } 257 }
191 258
192 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() { 259 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() {
193 return kMaxWaitAfterFirstResultMs; 260 return kMaxWaitAfterFirstResultMs;
194 } 261 }
195 262
196 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames( 263 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(
197 std::set<std::string>* adapter_names) { 264 std::set<std::string>* adapter_names) {
198 DCHECK(adapter_names); 265 DCHECK(adapter_names);
199 adapter_names->clear(); 266 adapter_names->clear();
200 267
201 // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to 268 // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to
202 // avoid reallocation. 269 // avoid reallocation.
203 ULONG adapters_size = 15000; 270 ULONG adapters_size = 15000;
204 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> adapters; 271 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> adapters;
205 ULONG error = ERROR_SUCCESS; 272 ULONG error = ERROR_SUCCESS;
206 int num_tries = 0; 273 int num_tries = 0;
274
275 PerfTimer time_api_access;
207 do { 276 do {
208 adapters.reset( 277 adapters.reset(
209 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size))); 278 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size)));
210 // Return only unicast addresses, and skip information we do not need. 279 // Return only unicast addresses, and skip information we do not need.
211 error = GetAdaptersAddresses(AF_UNSPEC, 280 error = GetAdaptersAddresses(AF_UNSPEC,
212 GAA_FLAG_SKIP_ANYCAST | 281 GAA_FLAG_SKIP_ANYCAST |
213 GAA_FLAG_SKIP_MULTICAST | 282 GAA_FLAG_SKIP_MULTICAST |
214 GAA_FLAG_SKIP_DNS_SERVER | 283 GAA_FLAG_SKIP_DNS_SERVER |
215 GAA_FLAG_SKIP_FRIENDLY_NAME, 284 GAA_FLAG_SKIP_FRIENDLY_NAME,
216 NULL, 285 NULL,
217 adapters.get(), 286 adapters.get(),
218 &adapters_size); 287 &adapters_size);
219 ++num_tries; 288 ++num_tries;
220 } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3); 289 } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3);
221 290
291 // This is primarily to validate our belief that the GetAdaptersAddresses API
292 // function is fast enough to call synchronously from the network thread.
293 UMA_HISTOGRAM_TIMES("Net.DhcpWpadGetAdaptersAddressesTime",
294 time_api_access.Elapsed());
295
296 if (error != ERROR_SUCCESS) {
297 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.DhcpWpadGetAdaptersAddressesError",
298 EnsureGetAdaptersAddressesError(error),
299 GetAllGetAdaptersAddressesErrors());
300 }
301
222 if (error == ERROR_NO_DATA) { 302 if (error == ERROR_NO_DATA) {
223 // There are no adapters that we care about. 303 // There are no adapters that we care about.
224 return true; 304 return true;
225 } 305 }
226 306
227 if (error != ERROR_SUCCESS) { 307 if (error != ERROR_SUCCESS) {
228 LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP."; 308 LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP.";
229 return false; 309 return false;
230 } 310 }
231 311
232 IP_ADAPTER_ADDRESSES* adapter = NULL; 312 IP_ADAPTER_ADDRESSES* adapter = NULL;
233 for (adapter = adapters.get(); adapter; adapter = adapter->Next) { 313 for (adapter = adapters.get(); adapter; adapter = adapter->Next) {
234 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) 314 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
235 continue; 315 continue;
236 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0) 316 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0)
237 continue; 317 continue;
238 318
239 DCHECK(adapter->AdapterName); 319 DCHECK(adapter->AdapterName);
240 adapter_names->insert(adapter->AdapterName); 320 adapter_names->insert(adapter->AdapterName);
241 } 321 }
242 322
243 return true; 323 return true;
244 } 324 }
245 325
246 } // namespace net 326 } // 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