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

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. Fix memory overwrite. 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 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() {
36 Cancel(); 46 // Count as user-initiated if we are not yet in STATE_DONE.
47 CancelImpl(true);
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() {
86 CancelImpl(true);
87 }
88
89 void DhcpProxyScriptFetcherWin::CancelImpl(bool user_initiated) {
jar (doing other things) 2011/05/23 19:37:52 Please switch to using an enumerated type, rather
Jói 2011/05/24 00:58:38 I don't think an enumerated type would be warrante
73 DCHECK(CalledOnValidThread()); 90 DCHECK(CalledOnValidThread());
74 91
75 if (state_ != STATE_DONE) { 92 if (state_ != STATE_DONE) {
76 wait_timer_.Stop(); 93 wait_timer_.Stop();
77 state_ = STATE_DONE; 94 state_ = STATE_DONE;
78 95
79 for (FetcherVector::iterator it = fetchers_.begin(); 96 for (FetcherVector::iterator it = fetchers_.begin();
80 it != fetchers_.end(); 97 it != fetchers_.end();
81 ++it) { 98 ++it) {
82 (*it)->Cancel(); 99 (*it)->Cancel();
83 } 100 }
84 101
85 fetchers_.reset(); 102 fetchers_.reset();
103
104 if (user_initiated) {
105 // We only count this stat if the cancel was explicitly initiated by
106 // our client, and if we weren't already in STATE_DONE.
107 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCancelTime",
108 base::TimeTicks::Now() - fetch_start_time_);
109 }
86 } 110 }
87 } 111 }
88 112
89 std::string DhcpProxyScriptFetcherWin::GetFetcherName() const { 113 std::string DhcpProxyScriptFetcherWin::GetFetcherName() const {
90 DCHECK(CalledOnValidThread()); 114 DCHECK(CalledOnValidThread());
91 return "win"; 115 return "win";
92 } 116 }
93 117
94 const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const { 118 const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const {
95 DCHECK(CalledOnValidThread()); 119 DCHECK(CalledOnValidThread());
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 if (state_ == STATE_NO_RESULTS) { 151 if (state_ == STATE_NO_RESULTS) {
128 state_ = STATE_SOME_RESULTS; 152 state_ = STATE_SOME_RESULTS;
129 wait_timer_.Start( 153 wait_timer_.Start(
130 base::TimeDelta::FromMilliseconds(ImplGetMaxWaitMs()), 154 base::TimeDelta::FromMilliseconds(ImplGetMaxWaitMs()),
131 this, &DhcpProxyScriptFetcherWin::OnWaitTimer); 155 this, &DhcpProxyScriptFetcherWin::OnWaitTimer);
132 } 156 }
133 } 157 }
134 158
135 void DhcpProxyScriptFetcherWin::OnWaitTimer() { 159 void DhcpProxyScriptFetcherWin::OnWaitTimer() {
136 DCHECK_EQ(state_, STATE_SOME_RESULTS); 160 DCHECK_EQ(state_, STATE_SOME_RESULTS);
161
162 // These are intended to help us understand whether our timeout may
163 // be too aggressive or not aggressive enough.
164 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumAdaptersAtWaitTimer",
165 fetchers_.size());
166 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer",
167 num_pending_fetchers_);
168
137 TransitionToDone(); 169 TransitionToDone();
138 } 170 }
139 171
140 void DhcpProxyScriptFetcherWin::TransitionToDone() { 172 void DhcpProxyScriptFetcherWin::TransitionToDone() {
141 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); 173 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS);
142 174
143 // Should have returned immediately at Fetch() if no adapters to check. 175 // Should have returned immediately at Fetch() if no adapters to check.
144 DCHECK(!fetchers_.empty()); 176 DCHECK(!fetchers_.empty());
145 177
146 // Scan twice for the result; once through the whole list for success, 178 // Scan twice for the result; once through the whole list for success,
(...skipping 18 matching lines...) Expand all
165 ++it) { 197 ++it) {
166 if ((*it)->DidFinish()) { 198 if ((*it)->DidFinish()) {
167 result = (*it)->GetResult(); 199 result = (*it)->GetResult();
168 if (result != ERR_PAC_NOT_IN_DHCP) { 200 if (result != ERR_PAC_NOT_IN_DHCP) {
169 break; 201 break;
170 } 202 }
171 } 203 }
172 } 204 }
173 } 205 }
174 206
175 Cancel(); 207 CancelImpl(false);
176 DCHECK_EQ(state_, STATE_DONE); 208 DCHECK_EQ(state_, STATE_DONE);
177 DCHECK(fetchers_.empty()); 209 DCHECK(fetchers_.empty());
178 210
211 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCompletionTime",
212 base::TimeTicks::Now() - fetch_start_time_);
213
214 if (result != OK) {
215 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
216 "Net.DhcpWpadFetchError", std::abs(result), GetAllErrorCodesForUma());
217 }
218
179 client_callback_->Run(result); 219 client_callback_->Run(result);
180 } 220 }
181 221
182 DhcpProxyScriptAdapterFetcher* 222 DhcpProxyScriptAdapterFetcher*
183 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() { 223 DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() {
184 return new DhcpProxyScriptAdapterFetcher(url_request_context_); 224 return new DhcpProxyScriptAdapterFetcher(url_request_context_);
185 } 225 }
186 226
187 bool DhcpProxyScriptFetcherWin::ImplGetCandidateAdapterNames( 227 bool DhcpProxyScriptFetcherWin::ImplGetCandidateAdapterNames(
188 std::set<std::string>* adapter_names) { 228 std::set<std::string>* adapter_names) {
189 return GetCandidateAdapterNames(adapter_names); 229 return GetCandidateAdapterNames(adapter_names);
190 } 230 }
191 231
192 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() { 232 int DhcpProxyScriptFetcherWin::ImplGetMaxWaitMs() {
193 return kMaxWaitAfterFirstResultMs; 233 return kMaxWaitAfterFirstResultMs;
194 } 234 }
195 235
196 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames( 236 bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(
197 std::set<std::string>* adapter_names) { 237 std::set<std::string>* adapter_names) {
198 DCHECK(adapter_names); 238 DCHECK(adapter_names);
199 adapter_names->clear(); 239 adapter_names->clear();
200 240
201 // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to 241 // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to
202 // avoid reallocation. 242 // avoid reallocation.
203 ULONG adapters_size = 15000; 243 ULONG adapters_size = 15000;
204 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> adapters; 244 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> adapters;
205 ULONG error = ERROR_SUCCESS; 245 ULONG error = ERROR_SUCCESS;
206 int num_tries = 0; 246 int num_tries = 0;
247
248 PerfTimer time_api_access;
207 do { 249 do {
208 adapters.reset( 250 adapters.reset(
209 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size))); 251 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size)));
210 // Return only unicast addresses, and skip information we do not need. 252 // Return only unicast addresses, and skip information we do not need.
211 error = GetAdaptersAddresses(AF_UNSPEC, 253 error = GetAdaptersAddresses(AF_UNSPEC,
212 GAA_FLAG_SKIP_ANYCAST | 254 GAA_FLAG_SKIP_ANYCAST |
213 GAA_FLAG_SKIP_MULTICAST | 255 GAA_FLAG_SKIP_MULTICAST |
214 GAA_FLAG_SKIP_DNS_SERVER | 256 GAA_FLAG_SKIP_DNS_SERVER |
215 GAA_FLAG_SKIP_FRIENDLY_NAME, 257 GAA_FLAG_SKIP_FRIENDLY_NAME,
216 NULL, 258 NULL,
217 adapters.get(), 259 adapters.get(),
218 &adapters_size); 260 &adapters_size);
219 ++num_tries; 261 ++num_tries;
220 } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3); 262 } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3);
221 263
264 // This is primarily to validate our belief that the GetAdaptersAddresses API
265 // function is fast enough to call synchronously from the network thread.
266 UMA_HISTOGRAM_TIMES("Net.DhcpWpadGetAdaptersAddressesTime",
267 time_api_access.Elapsed());
268
269 if (error != ERROR_SUCCESS) {
270 UMA_HISTOGRAM_CUSTOM_ENUMERATION(
271 "Net.DhcpWpadGetAdaptersAddressesError",
272 error,
273 base::CustomHistogram::ArrayToCustomRanges(
274 kGetAdaptersAddressesErrors,
275 arraysize(kGetAdaptersAddressesErrors)));
276 }
277
222 if (error == ERROR_NO_DATA) { 278 if (error == ERROR_NO_DATA) {
223 // There are no adapters that we care about. 279 // There are no adapters that we care about.
224 return true; 280 return true;
225 } 281 }
226 282
227 if (error != ERROR_SUCCESS) { 283 if (error != ERROR_SUCCESS) {
228 LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP."; 284 LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP.";
229 return false; 285 return false;
230 } 286 }
231 287
232 IP_ADAPTER_ADDRESSES* adapter = NULL; 288 IP_ADAPTER_ADDRESSES* adapter = NULL;
233 for (adapter = adapters.get(); adapter; adapter = adapter->Next) { 289 for (adapter = adapters.get(); adapter; adapter = adapter->Next) {
234 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) 290 if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
235 continue; 291 continue;
236 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0) 292 if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0)
237 continue; 293 continue;
238 294
239 DCHECK(adapter->AdapterName); 295 DCHECK(adapter->AdapterName);
240 adapter_names->insert(adapter->AdapterName); 296 adapter_names->insert(adapter->AdapterName);
241 } 297 }
242 298
243 return true; 299 return true;
244 } 300 }
245 301
246 } // namespace net 302 } // namespace net
OLDNEW
« net/proxy/dhcp_proxy_script_fetcher_win.h ('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