// 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/message_loop/message_loop_proxy.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/net_errors.h" #include "net/base/net_util.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 // ::IsShuttingDown() gets called. class HostResolverImplChromeOS::NetworkObserver : public chromeos::NetworkStateHandlerObserver { public: static void Create( const base::WeakPtr& resolver, scoped_refptr resolver_message_loop, NetworkStateHandler* network_state_handler) { new NetworkObserver(resolver, resolver_message_loop, network_state_handler); } NetworkObserver(const base::WeakPtr& resolver, scoped_refptr resolver_message_loop, NetworkStateHandler* network_state_handler) : resolver_(resolver), resolver_message_loop_(resolver_message_loop), 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: virtual ~NetworkObserver() { network_state_handler_->RemoveObserver(this, FROM_HERE); } // NetworkStateHandlerObserver virtual 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(ERROR) << "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); } virtual void IsShuttingDown() OVERRIDE { delete this; } void CallResolverSetIpAddress(const std::string& ipv4_address, const std::string& ipv6_address) { resolver_message_loop_->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 resolver_; scoped_refptr resolver_message_loop_; NetworkStateHandler* network_state_handler_; base::WeakPtrFactory weak_ptr_factory_resolver_thread_; DISALLOW_COPY_AND_ASSIGN(NetworkObserver); }; // HostResolverImplChromeOS HostResolverImplChromeOS::HostResolverImplChromeOS( scoped_refptr network_handler_message_loop, NetworkStateHandler* network_state_handler, const Options& options, net::NetLog* net_log) : HostResolverImpl(options, net_log), network_handler_message_loop_(network_handler_message_loop), weak_ptr_factory_(this) { network_handler_message_loop->PostTask( FROM_HERE, base::Bind(&NetworkObserver::Create, weak_ptr_factory_.GetWeakPtr(), base::MessageLoopProxy::current(), 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.hostname() != net::GetHostName() || 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::IPAddressNumber ipv6; if (net::ParseIPLiteralToNumber(ipv6_address_, &ipv6)) addresses->push_back(net::IPEndPoint(ipv6, 0)); } net::IPAddressNumber ipv4; if (net::ParseIPLiteralToNumber(ipv4_address_, &ipv4)) addresses->push_back(net::IPEndPoint(ipv4, 0)); DVLOG(2) << "ResolveLocalIPAddress(" << static_cast(info.address_family()) << "): " << addresses->size() << " IPv4: " << ipv4_address_ << " IPv6: " << ipv6_address_; addresses->SetDefaultCanonicalName(); return true; } // static scoped_ptr HostResolverImplChromeOS::CreateSystemResolver( const Options& options, net::NetLog* net_log) { return scoped_ptr(new HostResolverImplChromeOS( NetworkHandler::Get()->message_loop(), NetworkHandler::Get()->network_state_handler(), options, net_log)); } // static scoped_ptr HostResolverImplChromeOS::CreateHostResolverForTest( scoped_refptr network_handler_message_loop, NetworkStateHandler* network_state_handler) { Options options; return scoped_ptr(new HostResolverImplChromeOS( network_handler_message_loop, network_state_handler, options, NULL)); } } // namespace chromeos