| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/metrics/histogram.h" | |
| 10 #include "base/threading/sequenced_worker_pool.h" | 9 #include "base/threading/sequenced_worker_pool.h" |
| 11 #include "base/timer/elapsed_timer.h" | |
| 12 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
| 13 #include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h" | 11 #include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h" |
| 14 | 12 |
| 15 #include <winsock2.h> | 13 #include <winsock2.h> |
| 16 #include <iphlpapi.h> | 14 #include <iphlpapi.h> |
| 17 #pragma comment(lib, "iphlpapi.lib") | 15 #pragma comment(lib, "iphlpapi.lib") |
| 18 | 16 |
| 19 namespace { | 17 namespace { |
| 20 | 18 |
| 21 // How many threads to use at maximum to do DHCP lookups. This is | 19 // How many threads to use at maximum to do DHCP lookups. This is |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 } | 74 } |
| 77 | 75 |
| 78 int DhcpProxyScriptFetcherWin::Fetch(base::string16* utf16_text, | 76 int DhcpProxyScriptFetcherWin::Fetch(base::string16* utf16_text, |
| 79 const CompletionCallback& callback) { | 77 const CompletionCallback& callback) { |
| 80 DCHECK(CalledOnValidThread()); | 78 DCHECK(CalledOnValidThread()); |
| 81 if (state_ != STATE_START && state_ != STATE_DONE) { | 79 if (state_ != STATE_START && state_ != STATE_DONE) { |
| 82 NOTREACHED(); | 80 NOTREACHED(); |
| 83 return ERR_UNEXPECTED; | 81 return ERR_UNEXPECTED; |
| 84 } | 82 } |
| 85 | 83 |
| 86 fetch_start_time_ = base::TimeTicks::Now(); | |
| 87 | |
| 88 state_ = STATE_WAIT_ADAPTERS; | 84 state_ = STATE_WAIT_ADAPTERS; |
| 89 callback_ = callback; | 85 callback_ = callback; |
| 90 destination_string_ = utf16_text; | 86 destination_string_ = utf16_text; |
| 91 | 87 |
| 92 last_query_ = ImplCreateAdapterQuery(); | 88 last_query_ = ImplCreateAdapterQuery(); |
| 93 GetTaskRunner()->PostTaskAndReply( | 89 GetTaskRunner()->PostTaskAndReply( |
| 94 FROM_HERE, | 90 FROM_HERE, |
| 95 base::Bind( | 91 base::Bind( |
| 96 &DhcpProxyScriptFetcherWin::AdapterQuery::GetCandidateAdapterNames, | 92 &DhcpProxyScriptFetcherWin::AdapterQuery::GetCandidateAdapterNames, |
| 97 last_query_.get()), | 93 last_query_.get()), |
| 98 base::Bind( | 94 base::Bind( |
| 99 &DhcpProxyScriptFetcherWin::OnGetCandidateAdapterNamesDone, | 95 &DhcpProxyScriptFetcherWin::OnGetCandidateAdapterNamesDone, |
| 100 AsWeakPtr(), | 96 AsWeakPtr(), |
| 101 last_query_)); | 97 last_query_)); |
| 102 | 98 |
| 103 return ERR_IO_PENDING; | 99 return ERR_IO_PENDING; |
| 104 } | 100 } |
| 105 | 101 |
| 106 void DhcpProxyScriptFetcherWin::Cancel() { | 102 void DhcpProxyScriptFetcherWin::Cancel() { |
| 107 DCHECK(CalledOnValidThread()); | 103 DCHECK(CalledOnValidThread()); |
| 108 | 104 |
| 109 if (state_ != STATE_DONE) { | |
| 110 // We only count this stat if the cancel was explicitly initiated by | |
| 111 // our client, and if we weren't already in STATE_DONE. | |
| 112 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCancelTime", | |
| 113 base::TimeTicks::Now() - fetch_start_time_); | |
| 114 } | |
| 115 | |
| 116 CancelImpl(); | 105 CancelImpl(); |
| 117 } | 106 } |
| 118 | 107 |
| 119 void DhcpProxyScriptFetcherWin::CancelImpl() { | 108 void DhcpProxyScriptFetcherWin::CancelImpl() { |
| 120 DCHECK(CalledOnValidThread()); | 109 DCHECK(CalledOnValidThread()); |
| 121 | 110 |
| 122 if (state_ != STATE_DONE) { | 111 if (state_ != STATE_DONE) { |
| 123 callback_.Reset(); | 112 callback_.Reset(); |
| 124 wait_timer_.Stop(); | 113 wait_timer_.Stop(); |
| 125 state_ = STATE_DONE; | 114 state_ = STATE_DONE; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 if (state_ == STATE_NO_RESULTS) { | 203 if (state_ == STATE_NO_RESULTS) { |
| 215 state_ = STATE_SOME_RESULTS; | 204 state_ = STATE_SOME_RESULTS; |
| 216 wait_timer_.Start(FROM_HERE, | 205 wait_timer_.Start(FROM_HERE, |
| 217 ImplGetMaxWait(), this, &DhcpProxyScriptFetcherWin::OnWaitTimer); | 206 ImplGetMaxWait(), this, &DhcpProxyScriptFetcherWin::OnWaitTimer); |
| 218 } | 207 } |
| 219 } | 208 } |
| 220 | 209 |
| 221 void DhcpProxyScriptFetcherWin::OnWaitTimer() { | 210 void DhcpProxyScriptFetcherWin::OnWaitTimer() { |
| 222 DCHECK_EQ(state_, STATE_SOME_RESULTS); | 211 DCHECK_EQ(state_, STATE_SOME_RESULTS); |
| 223 | 212 |
| 224 // These are intended to help us understand whether our timeout may | |
| 225 // be too aggressive or not aggressive enough. | |
| 226 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumAdaptersAtWaitTimer", | |
| 227 fetchers_.size()); | |
| 228 UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer", | |
| 229 num_pending_fetchers_); | |
| 230 | |
| 231 TransitionToDone(); | 213 TransitionToDone(); |
| 232 } | 214 } |
| 233 | 215 |
| 234 void DhcpProxyScriptFetcherWin::TransitionToDone() { | 216 void DhcpProxyScriptFetcherWin::TransitionToDone() { |
| 235 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); | 217 DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS); |
| 236 | 218 |
| 237 int result = ERR_PAC_NOT_IN_DHCP; // Default if no fetchers. | 219 int result = ERR_PAC_NOT_IN_DHCP; // Default if no fetchers. |
| 238 if (!fetchers_.empty()) { | 220 if (!fetchers_.empty()) { |
| 239 // Scan twice for the result; once through the whole list for success, | 221 // Scan twice for the result; once through the whole list for success, |
| 240 // then if no success, return result for most preferred network adapter, | 222 // then if no success, return result for most preferred network adapter, |
| (...skipping 24 matching lines...) Expand all Loading... |
| 265 } | 247 } |
| 266 } | 248 } |
| 267 } | 249 } |
| 268 | 250 |
| 269 CompletionCallback callback = callback_; | 251 CompletionCallback callback = callback_; |
| 270 CancelImpl(); | 252 CancelImpl(); |
| 271 DCHECK_EQ(state_, STATE_DONE); | 253 DCHECK_EQ(state_, STATE_DONE); |
| 272 DCHECK(fetchers_.empty()); | 254 DCHECK(fetchers_.empty()); |
| 273 DCHECK(callback_.is_null()); // Invariant of data. | 255 DCHECK(callback_.is_null()); // Invariant of data. |
| 274 | 256 |
| 275 UMA_HISTOGRAM_TIMES("Net.DhcpWpadCompletionTime", | |
| 276 base::TimeTicks::Now() - fetch_start_time_); | |
| 277 | |
| 278 if (result != OK) { | |
| 279 UMA_HISTOGRAM_CUSTOM_ENUMERATION( | |
| 280 "Net.DhcpWpadFetchError", std::abs(result), GetAllErrorCodesForUma()); | |
| 281 } | |
| 282 | |
| 283 // We may be deleted re-entrantly within this outcall. | 257 // We may be deleted re-entrantly within this outcall. |
| 284 callback.Run(result); | 258 callback.Run(result); |
| 285 } | 259 } |
| 286 | 260 |
| 287 int DhcpProxyScriptFetcherWin::num_pending_fetchers() const { | 261 int DhcpProxyScriptFetcherWin::num_pending_fetchers() const { |
| 288 return num_pending_fetchers_; | 262 return num_pending_fetchers_; |
| 289 } | 263 } |
| 290 | 264 |
| 291 URLRequestContext* DhcpProxyScriptFetcherWin::url_request_context() const { | 265 URLRequestContext* DhcpProxyScriptFetcherWin::url_request_context() const { |
| 292 return url_request_context_; | 266 return url_request_context_; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 317 DCHECK(adapter_names); | 291 DCHECK(adapter_names); |
| 318 adapter_names->clear(); | 292 adapter_names->clear(); |
| 319 | 293 |
| 320 // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to | 294 // The GetAdaptersAddresses MSDN page recommends using a size of 15000 to |
| 321 // avoid reallocation. | 295 // avoid reallocation. |
| 322 ULONG adapters_size = 15000; | 296 ULONG adapters_size = 15000; |
| 323 scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> adapters; | 297 scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> adapters; |
| 324 ULONG error = ERROR_SUCCESS; | 298 ULONG error = ERROR_SUCCESS; |
| 325 int num_tries = 0; | 299 int num_tries = 0; |
| 326 | 300 |
| 327 base::ElapsedTimer time_api_access; | |
| 328 do { | 301 do { |
| 329 adapters.reset(static_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size))); | 302 adapters.reset(static_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size))); |
| 330 // Return only unicast addresses, and skip information we do not need. | 303 // Return only unicast addresses, and skip information we do not need. |
| 331 error = GetAdaptersAddresses(AF_UNSPEC, | 304 error = GetAdaptersAddresses(AF_UNSPEC, |
| 332 GAA_FLAG_SKIP_ANYCAST | | 305 GAA_FLAG_SKIP_ANYCAST | |
| 333 GAA_FLAG_SKIP_MULTICAST | | 306 GAA_FLAG_SKIP_MULTICAST | |
| 334 GAA_FLAG_SKIP_DNS_SERVER | | 307 GAA_FLAG_SKIP_DNS_SERVER | |
| 335 GAA_FLAG_SKIP_FRIENDLY_NAME, | 308 GAA_FLAG_SKIP_FRIENDLY_NAME, |
| 336 NULL, | 309 NULL, |
| 337 adapters.get(), | 310 adapters.get(), |
| 338 &adapters_size); | 311 &adapters_size); |
| 339 ++num_tries; | 312 ++num_tries; |
| 340 } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3); | 313 } while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3); |
| 341 | 314 |
| 342 // This is primarily to validate our belief that the GetAdaptersAddresses API | |
| 343 // function is fast enough to call synchronously from the network thread. | |
| 344 UMA_HISTOGRAM_TIMES("Net.DhcpWpadGetAdaptersAddressesTime", | |
| 345 time_api_access.Elapsed()); | |
| 346 | |
| 347 if (error != ERROR_SUCCESS) { | |
| 348 UMA_HISTOGRAM_CUSTOM_ENUMERATION( | |
| 349 "Net.DhcpWpadGetAdaptersAddressesError", | |
| 350 error, | |
| 351 base::CustomHistogram::ArrayToCustomRanges( | |
| 352 kGetAdaptersAddressesErrors, | |
| 353 arraysize(kGetAdaptersAddressesErrors))); | |
| 354 } | |
| 355 | |
| 356 if (error == ERROR_NO_DATA) { | 315 if (error == ERROR_NO_DATA) { |
| 357 // There are no adapters that we care about. | 316 // There are no adapters that we care about. |
| 358 return true; | 317 return true; |
| 359 } | 318 } |
| 360 | 319 |
| 361 if (error != ERROR_SUCCESS) { | 320 if (error != ERROR_SUCCESS) { |
| 362 LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP."; | 321 LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP."; |
| 363 return false; | 322 return false; |
| 364 } | 323 } |
| 365 | 324 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 391 DhcpProxyScriptFetcherWin::AdapterQuery::adapter_names() const { | 350 DhcpProxyScriptFetcherWin::AdapterQuery::adapter_names() const { |
| 392 return adapter_names_; | 351 return adapter_names_; |
| 393 } | 352 } |
| 394 | 353 |
| 395 bool DhcpProxyScriptFetcherWin::AdapterQuery::ImplGetCandidateAdapterNames( | 354 bool DhcpProxyScriptFetcherWin::AdapterQuery::ImplGetCandidateAdapterNames( |
| 396 std::set<std::string>* adapter_names) { | 355 std::set<std::string>* adapter_names) { |
| 397 return DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(adapter_names); | 356 return DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(adapter_names); |
| 398 } | 357 } |
| 399 | 358 |
| 400 } // namespace net | 359 } // namespace net |
| OLD | NEW |