blob: e46d599a7794b24fc29c0f5ff345a99e48ba5b38 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/network/host_resolver_impl_chromeos.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/sys_info.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "chromeos/network/device_state.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/network_state_handler_observer.h"
#include "net/base/address_list.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
// HostResolverImplChromeOS::NetworkStateHandlerObserver
//
// An instance of this class is created on the NetworkHandler (UI) thread and
// manages its own lifetime, destroying itself when NetworkStateHandlerObserver
// ::OnShuttingDown() gets called.
class HostResolverImplChromeOS::NetworkObserver
: public chromeos::NetworkStateHandlerObserver {
public:
static void Create(
const base::WeakPtr<HostResolverImplChromeOS>& resolver,
scoped_refptr<base::SingleThreadTaskRunner> resolver_task_runner,
NetworkStateHandler* network_state_handler) {
new NetworkObserver(resolver, resolver_task_runner, network_state_handler);
}
NetworkObserver(
const base::WeakPtr<HostResolverImplChromeOS>& resolver,
scoped_refptr<base::SingleThreadTaskRunner> resolver_task_runner,
NetworkStateHandler* network_state_handler)
: resolver_(resolver),
resolver_task_runner_(resolver_task_runner),
network_state_handler_(network_state_handler),
weak_ptr_factory_resolver_thread_(this) {
network_state_handler_->AddObserver(this, FROM_HERE);
DefaultNetworkChanged(network_state_handler_->DefaultNetwork());
}
private:
~NetworkObserver() override {
network_state_handler_->RemoveObserver(this, FROM_HERE);
}
// NetworkStateHandlerObserver
void DefaultNetworkChanged(const NetworkState* network) override {
if (!network) {
DVLOG(2) << "DefaultNetworkChanged: No Network.";
CallResolverSetIpAddress("", "");
return;
}
std::string ipv4_address, ipv6_address;
const DeviceState* device_state =
network_state_handler_->GetDeviceState(network->device_path());
if (!device_state) {
LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS())
<< "DefaultNetworkChanged: Network missing device: "
<< network->path();
CallResolverSetIpAddress("", "");
return;
}
for (base::DictionaryValue::Iterator iter(device_state->ip_configs());
!iter.IsAtEnd(); iter.Advance()) {
const base::DictionaryValue* ip_config;
if (!iter.value().GetAsDictionary(&ip_config)) {
LOG(ERROR) << "Badly formatted IPConfigs: " << network->path();
continue;
}
std::string method, address;
if (ip_config->GetString(shill::kMethodProperty, &method) &&
ip_config->GetString(shill::kAddressProperty, &address)) {
if (method == shill::kTypeIPv4 || method == shill::kTypeDHCP)
ipv4_address = address;
else if (method == shill::kTypeIPv6 || method == shill::kTypeDHCP6)
ipv6_address = address;
} else {
LOG(ERROR) << "DefaultNetworkChanged: IPConfigs missing properties: "
<< network->path();
}
}
DVLOG(2) << "DefaultNetworkChanged: " << network->name()
<< " IPv4: " << ipv4_address << " IPv6: " << ipv6_address;
CallResolverSetIpAddress(ipv4_address, ipv6_address);
}
void OnShuttingDown() override { delete this; }
void CallResolverSetIpAddress(const std::string& ipv4_address,
const std::string& ipv6_address) {
resolver_task_runner_->PostTask(
FROM_HERE, base::Bind(&NetworkObserver::SetIpAddressOnResolverThread,
weak_ptr_factory_resolver_thread_.GetWeakPtr(),
ipv4_address, ipv6_address));
}
void SetIpAddressOnResolverThread(const std::string& ipv4_address,
const std::string& ipv6_address) {
if (resolver_)
resolver_->SetIPAddresses(ipv4_address, ipv6_address);
}
base::WeakPtr<HostResolverImplChromeOS> resolver_;
scoped_refptr<base::SingleThreadTaskRunner> resolver_task_runner_;
NetworkStateHandler* network_state_handler_;
base::WeakPtrFactory<NetworkObserver> weak_ptr_factory_resolver_thread_;
DISALLOW_COPY_AND_ASSIGN(NetworkObserver);
};
// HostResolverImplChromeOS
HostResolverImplChromeOS::HostResolverImplChromeOS(
scoped_refptr<base::SingleThreadTaskRunner> network_handler_task_runner,
NetworkStateHandler* network_state_handler,
const Options& options,
net::NetLog* net_log)
: HostResolverImpl(options, net_log),
network_handler_task_runner_(network_handler_task_runner),
weak_ptr_factory_(this) {
network_handler_task_runner->PostTask(
FROM_HERE,
base::Bind(&NetworkObserver::Create, weak_ptr_factory_.GetWeakPtr(),
base::ThreadTaskRunnerHandle::Get(), network_state_handler));
}
HostResolverImplChromeOS::~HostResolverImplChromeOS() {
}
int HostResolverImplChromeOS::Resolve(const RequestInfo& info,
net::RequestPriority priority,
net::AddressList* addresses,
const net::CompletionCallback& callback,
RequestHandle* out_req,
const net::BoundNetLog& source_net_log) {
DCHECK(thread_checker_.CalledOnValidThread());
if (ResolveLocalIPAddress(info, addresses))
return net::OK;
return net::HostResolverImpl::Resolve(
info, priority, addresses, callback, out_req, source_net_log);
}
void HostResolverImplChromeOS::SetIPAddresses(const std::string& ipv4_address,
const std::string& ipv6_address) {
DCHECK(thread_checker_.CalledOnValidThread());
ipv4_address_ = ipv4_address;
ipv6_address_ = ipv6_address;
}
bool HostResolverImplChromeOS::ResolveLocalIPAddress(
const RequestInfo& info,
net::AddressList* addresses) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!info.is_my_ip_address() || ipv4_address_.empty())
return false;
// Use IPConfig data for localhost address lookup.
addresses->clear();
if (info.address_family() != net::ADDRESS_FAMILY_IPV4 &&
!ipv6_address_.empty()) {
net::IPAddress ipv6;
if (ipv6.AssignFromIPLiteral(ipv6_address_))
addresses->push_back(net::IPEndPoint(ipv6, 0));
}
net::IPAddress ipv4;
if (ipv4.AssignFromIPLiteral(ipv4_address_))
addresses->push_back(net::IPEndPoint(ipv4, 0));
DVLOG(2) << "ResolveLocalIPAddress("
<< static_cast<int>(info.address_family()) << "): "
<< addresses->size()
<< " IPv4: " << ipv4_address_ << " IPv6: " << ipv6_address_;
addresses->SetDefaultCanonicalName();
return true;
}
// static
std::unique_ptr<net::HostResolver>
HostResolverImplChromeOS::CreateSystemResolver(const Options& options,
net::NetLog* net_log) {
return std::unique_ptr<net::HostResolver>(new HostResolverImplChromeOS(
NetworkHandler::Get()->task_runner(),
NetworkHandler::Get()->network_state_handler(), options, net_log));
}
// static
std::unique_ptr<net::HostResolver>
HostResolverImplChromeOS::CreateHostResolverForTest(
scoped_refptr<base::SingleThreadTaskRunner> network_handler_task_runner,
NetworkStateHandler* network_state_handler) {
Options options;
return std::unique_ptr<net::HostResolver>(new HostResolverImplChromeOS(
network_handler_task_runner, network_state_handler, options, NULL));
}
} // namespace chromeos