This source file includes following definitions.
- url_request_context_
- Cancel
- CancelImpl
- OnGetCandidateAdapterNamesDone
- GetFetcherName
- GetPacURL
- OnFetcherDone
- OnWaitTimer
- TransitionToDone
- num_pending_fetchers
- url_request_context
- GetTaskRunner
- ImplCreateAdapterFetcher
- ImplCreateAdapterQuery
- ImplGetMaxWait
- GetCandidateAdapterNames
- GetCandidateAdapterNames
- adapter_names
- ImplGetCandidateAdapterNames
#include "net/proxy/dhcp_proxy_script_fetcher_win.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/metrics/histogram.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/timer/elapsed_timer.h"
#include "net/base/net_errors.h"
#include "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h"
#include <winsock2.h>
#include <iphlpapi.h>
#pragma comment(lib, "iphlpapi.lib")
namespace {
const int kMaxDhcpLookupThreads = 12;
const int kMaxWaitAfterFirstResultMs = 400;
const int kGetAdaptersAddressesErrors[] = {
ERROR_ADDRESS_NOT_ASSOCIATED,
ERROR_BUFFER_OVERFLOW,
ERROR_INVALID_PARAMETER,
ERROR_NOT_ENOUGH_MEMORY,
ERROR_NO_DATA,
};
}
namespace net {
DhcpProxyScriptFetcherWin::DhcpProxyScriptFetcherWin(
URLRequestContext* url_request_context)
: state_(STATE_START),
num_pending_fetchers_(0),
destination_string_(NULL),
url_request_context_(url_request_context) {
DCHECK(url_request_context_);
worker_pool_ = new base::SequencedWorkerPool(kMaxDhcpLookupThreads,
"PacDhcpLookup");
}
DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() {
Cancel();
worker_pool_->Shutdown();
}
int DhcpProxyScriptFetcherWin::Fetch(base::string16* utf16_text,
const CompletionCallback& callback) {
DCHECK(CalledOnValidThread());
if (state_ != STATE_START && state_ != STATE_DONE) {
NOTREACHED();
return ERR_UNEXPECTED;
}
fetch_start_time_ = base::TimeTicks::Now();
state_ = STATE_WAIT_ADAPTERS;
callback_ = callback;
destination_string_ = utf16_text;
last_query_ = ImplCreateAdapterQuery();
GetTaskRunner()->PostTaskAndReply(
FROM_HERE,
base::Bind(
&DhcpProxyScriptFetcherWin::AdapterQuery::GetCandidateAdapterNames,
last_query_.get()),
base::Bind(
&DhcpProxyScriptFetcherWin::OnGetCandidateAdapterNamesDone,
AsWeakPtr(),
last_query_));
return ERR_IO_PENDING;
}
void DhcpProxyScriptFetcherWin::Cancel() {
DCHECK(CalledOnValidThread());
if (state_ != STATE_DONE) {
UMA_HISTOGRAM_TIMES("Net.DhcpWpadCancelTime",
base::TimeTicks::Now() - fetch_start_time_);
}
CancelImpl();
}
void DhcpProxyScriptFetcherWin::CancelImpl() {
DCHECK(CalledOnValidThread());
if (state_ != STATE_DONE) {
callback_.Reset();
wait_timer_.Stop();
state_ = STATE_DONE;
for (FetcherVector::iterator it = fetchers_.begin();
it != fetchers_.end();
++it) {
(*it)->Cancel();
}
fetchers_.clear();
}
}
void DhcpProxyScriptFetcherWin::OnGetCandidateAdapterNamesDone(
scoped_refptr<AdapterQuery> query) {
DCHECK(CalledOnValidThread());
if (query.get() != last_query_.get())
return;
last_query_ = NULL;
ImplOnGetCandidateAdapterNamesDone();
if (state_ != STATE_WAIT_ADAPTERS)
return;
state_ = STATE_NO_RESULTS;
const std::set<std::string>& adapter_names = query->adapter_names();
if (adapter_names.empty()) {
TransitionToDone();
return;
}
for (std::set<std::string>::const_iterator it = adapter_names.begin();
it != adapter_names.end();
++it) {
DhcpProxyScriptAdapterFetcher* fetcher(ImplCreateAdapterFetcher());
fetcher->Fetch(
*it, base::Bind(&DhcpProxyScriptFetcherWin::OnFetcherDone,
base::Unretained(this)));
fetchers_.push_back(fetcher);
}
num_pending_fetchers_ = fetchers_.size();
}
std::string DhcpProxyScriptFetcherWin::GetFetcherName() const {
DCHECK(CalledOnValidThread());
return "win";
}
const GURL& DhcpProxyScriptFetcherWin::GetPacURL() const {
DCHECK(CalledOnValidThread());
DCHECK_EQ(state_, STATE_DONE);
return pac_url_;
}
void DhcpProxyScriptFetcherWin::OnFetcherDone(int result) {
DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS);
if (--num_pending_fetchers_ == 0) {
TransitionToDone();
return;
}
for (FetcherVector::iterator it = fetchers_.begin();
it != fetchers_.end();
++it) {
bool did_finish = (*it)->DidFinish();
int result = (*it)->GetResult();
if (did_finish && result == OK) {
TransitionToDone();
return;
}
if (!did_finish || result != ERR_PAC_NOT_IN_DHCP) {
break;
}
}
if (state_ == STATE_NO_RESULTS) {
state_ = STATE_SOME_RESULTS;
wait_timer_.Start(FROM_HERE,
ImplGetMaxWait(), this, &DhcpProxyScriptFetcherWin::OnWaitTimer);
}
}
void DhcpProxyScriptFetcherWin::OnWaitTimer() {
DCHECK_EQ(state_, STATE_SOME_RESULTS);
UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumAdaptersAtWaitTimer",
fetchers_.size());
UMA_HISTOGRAM_COUNTS_100("Net.DhcpWpadNumPendingAdaptersAtWaitTimer",
num_pending_fetchers_);
TransitionToDone();
}
void DhcpProxyScriptFetcherWin::TransitionToDone() {
DCHECK(state_ == STATE_NO_RESULTS || state_ == STATE_SOME_RESULTS);
int result = ERR_PAC_NOT_IN_DHCP;
if (!fetchers_.empty()) {
result = ERR_ABORTED;
for (FetcherVector::iterator it = fetchers_.begin();
it != fetchers_.end();
++it) {
if ((*it)->DidFinish() && (*it)->GetResult() == OK) {
result = OK;
*destination_string_ = (*it)->GetPacScript();
pac_url_ = (*it)->GetPacURL();
break;
}
}
if (result != OK) {
destination_string_->clear();
for (FetcherVector::iterator it = fetchers_.begin();
it != fetchers_.end();
++it) {
if ((*it)->DidFinish()) {
result = (*it)->GetResult();
if (result != ERR_PAC_NOT_IN_DHCP) {
break;
}
}
}
}
}
CompletionCallback callback = callback_;
CancelImpl();
DCHECK_EQ(state_, STATE_DONE);
DCHECK(fetchers_.empty());
DCHECK(callback_.is_null());
UMA_HISTOGRAM_TIMES("Net.DhcpWpadCompletionTime",
base::TimeTicks::Now() - fetch_start_time_);
if (result != OK) {
UMA_HISTOGRAM_CUSTOM_ENUMERATION(
"Net.DhcpWpadFetchError", std::abs(result), GetAllErrorCodesForUma());
}
callback.Run(result);
}
int DhcpProxyScriptFetcherWin::num_pending_fetchers() const {
return num_pending_fetchers_;
}
URLRequestContext* DhcpProxyScriptFetcherWin::url_request_context() const {
return url_request_context_;
}
scoped_refptr<base::TaskRunner> DhcpProxyScriptFetcherWin::GetTaskRunner() {
return worker_pool_->GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
}
DhcpProxyScriptAdapterFetcher*
DhcpProxyScriptFetcherWin::ImplCreateAdapterFetcher() {
return new DhcpProxyScriptAdapterFetcher(url_request_context_,
GetTaskRunner());
}
DhcpProxyScriptFetcherWin::AdapterQuery*
DhcpProxyScriptFetcherWin::ImplCreateAdapterQuery() {
return new AdapterQuery();
}
base::TimeDelta DhcpProxyScriptFetcherWin::ImplGetMaxWait() {
return base::TimeDelta::FromMilliseconds(kMaxWaitAfterFirstResultMs);
}
bool DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(
std::set<std::string>* adapter_names) {
DCHECK(adapter_names);
adapter_names->clear();
ULONG adapters_size = 15000;
scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> adapters;
ULONG error = ERROR_SUCCESS;
int num_tries = 0;
base::ElapsedTimer time_api_access;
do {
adapters.reset(static_cast<IP_ADAPTER_ADDRESSES*>(malloc(adapters_size)));
error = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST |
GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER |
GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
adapters.get(),
&adapters_size);
++num_tries;
} while (error == ERROR_BUFFER_OVERFLOW && num_tries <= 3);
UMA_HISTOGRAM_TIMES("Net.DhcpWpadGetAdaptersAddressesTime",
time_api_access.Elapsed());
if (error != ERROR_SUCCESS) {
UMA_HISTOGRAM_CUSTOM_ENUMERATION(
"Net.DhcpWpadGetAdaptersAddressesError",
error,
base::CustomHistogram::ArrayToCustomRanges(
kGetAdaptersAddressesErrors,
arraysize(kGetAdaptersAddressesErrors)));
}
if (error == ERROR_NO_DATA) {
return true;
}
if (error != ERROR_SUCCESS) {
LOG(WARNING) << "Unexpected error retrieving WPAD configuration from DHCP.";
return false;
}
IP_ADAPTER_ADDRESSES* adapter = NULL;
for (adapter = adapters.get(); adapter; adapter = adapter->Next) {
if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
continue;
if ((adapter->Flags & IP_ADAPTER_DHCP_ENABLED) == 0)
continue;
DCHECK(adapter->AdapterName);
adapter_names->insert(adapter->AdapterName);
}
return true;
}
DhcpProxyScriptFetcherWin::AdapterQuery::AdapterQuery() {
}
DhcpProxyScriptFetcherWin::AdapterQuery::~AdapterQuery() {
}
void DhcpProxyScriptFetcherWin::AdapterQuery::GetCandidateAdapterNames() {
ImplGetCandidateAdapterNames(&adapter_names_);
}
const std::set<std::string>&
DhcpProxyScriptFetcherWin::AdapterQuery::adapter_names() const {
return adapter_names_;
}
bool DhcpProxyScriptFetcherWin::AdapterQuery::ImplGetCandidateAdapterNames(
std::set<std::string>* adapter_names) {
return DhcpProxyScriptFetcherWin::GetCandidateAdapterNames(adapter_names);
}
}