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

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