diff options
author | stevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-17 09:21:00 +0000 |
---|---|---|
committer | stevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-17 09:21:00 +0000 |
commit | 106ccd2ccd1ac30217f27541b515c4bb93f10707 (patch) | |
tree | 5e1051f37501d9894d47853529a8b564dd8da614 /chromeos | |
parent | ecf56301956369d9fa0f341a0001efe9efbc1cbd (diff) | |
download | chromium_src-106ccd2ccd1ac30217f27541b515c4bb93f10707.zip chromium_src-106ccd2ccd1ac30217f27541b515c4bb93f10707.tar.gz chromium_src-106ccd2ccd1ac30217f27541b515c4bb93f10707.tar.bz2 |
Provide Shill IP Address to myIpAddress()
On Chrome OS we need to get the IP Address to use for myIpAddress() from Shill since gethostname() returns localhost.
BUG=175652
TBR=sky@chromium.org
Review URL: https://codereview.chromium.org/238433003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277679 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos')
-rw-r--r-- | chromeos/chromeos.gyp | 3 | ||||
-rw-r--r-- | chromeos/network/device_state.h | 4 | ||||
-rw-r--r-- | chromeos/network/host_resolver_impl_chromeos.cc | 214 | ||||
-rw-r--r-- | chromeos/network/host_resolver_impl_chromeos.h | 80 | ||||
-rw-r--r-- | chromeos/network/host_resolver_impl_chromeos_unittest.cc | 171 | ||||
-rw-r--r-- | chromeos/network/network_state_handler.cc | 9 | ||||
-rw-r--r-- | chromeos/network/network_state_handler_observer.cc | 3 | ||||
-rw-r--r-- | chromeos/network/network_state_handler_observer.h | 4 |
8 files changed, 487 insertions, 1 deletions
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index 686b7ae..58aea83 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp @@ -276,6 +276,8 @@ 'network/device_state.h', 'network/geolocation_handler.cc', 'network/geolocation_handler.h', + 'network/host_resolver_impl_chromeos.cc', + 'network/host_resolver_impl_chromeos.h', 'network/managed_network_configuration_handler.cc', 'network/managed_network_configuration_handler.h', 'network/managed_network_configuration_handler_impl.cc', @@ -520,6 +522,7 @@ 'login/login_state_unittest.cc', 'network/client_cert_resolver_unittest.cc', 'network/geolocation_handler_unittest.cc', + 'network/host_resolver_impl_chromeos_unittest.cc', 'network/managed_network_configuration_handler_unittest.cc', 'network/network_cert_migrator_unittest.cc', 'network/network_change_notifier_chromeos_unittest.cc', diff --git a/chromeos/network/device_state.h b/chromeos/network/device_state.h index 5f4486d..3e8195b 100644 --- a/chromeos/network/device_state.h +++ b/chromeos/network/device_state.h @@ -49,10 +49,12 @@ class CHROMEOS_EXPORT DeviceState : public ManagedState { const std::string& mdn() const { return mdn_; } const CellularScanResults& scan_results() const { return scan_results_; } + // |ip_configs_| is kept up to date by NetworkStateHandler. + const base::DictionaryValue& ip_configs() const { return ip_configs_; } + // Do not use this. It exists temporarily for internet_options_handler.cc // which is being deprecated. const base::DictionaryValue& properties() const { return properties_; } - const base::DictionaryValue& ip_configs() const { return ip_configs_; } // Ethernet specific accessors bool eap_authentication_completed() const { diff --git a/chromeos/network/host_resolver_impl_chromeos.cc b/chromeos/network/host_resolver_impl_chromeos.cc new file mode 100644 index 0000000..ad946e5 --- /dev/null +++ b/chromeos/network/host_resolver_impl_chromeos.cc @@ -0,0 +1,214 @@ +// 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<HostResolverImplChromeOS>& resolver, + scoped_refptr<base::MessageLoopProxy> resolver_message_loop, + NetworkStateHandler* network_state_handler) { + new NetworkObserver(resolver, resolver_message_loop, network_state_handler); + } + + NetworkObserver(const base::WeakPtr<HostResolverImplChromeOS>& resolver, + scoped_refptr<base::MessageLoopProxy> 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<HostResolverImplChromeOS> resolver_; + scoped_refptr<base::MessageLoopProxy> resolver_message_loop_; + NetworkStateHandler* network_state_handler_; + base::WeakPtrFactory<NetworkObserver> weak_ptr_factory_resolver_thread_; + + DISALLOW_COPY_AND_ASSIGN(NetworkObserver); +}; + +// HostResolverImplChromeOS + +HostResolverImplChromeOS::HostResolverImplChromeOS( + scoped_refptr<base::MessageLoopProxy> 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<int>(info.address_family()) << "): " + << addresses->size() + << " IPv4: " << ipv4_address_ << " IPv6: " << ipv6_address_; + addresses->SetDefaultCanonicalName(); + return true; +} + +// static +scoped_ptr<net::HostResolver> HostResolverImplChromeOS::CreateSystemResolver( + const Options& options, + net::NetLog* net_log) { + return scoped_ptr<net::HostResolver>(new HostResolverImplChromeOS( + NetworkHandler::Get()->message_loop(), + NetworkHandler::Get()->network_state_handler(), + options, + net_log)); +} + +// static +scoped_ptr<net::HostResolver> +HostResolverImplChromeOS::CreateHostResolverForTest( + scoped_refptr<base::MessageLoopProxy> network_handler_message_loop, + NetworkStateHandler* network_state_handler) { + Options options; + return scoped_ptr<net::HostResolver>(new HostResolverImplChromeOS( + network_handler_message_loop, + network_state_handler, + options, + NULL)); +} + +} // namespace chromeos diff --git a/chromeos/network/host_resolver_impl_chromeos.h b/chromeos/network/host_resolver_impl_chromeos.h new file mode 100644 index 0000000..94f7712 --- /dev/null +++ b/chromeos/network/host_resolver_impl_chromeos.h @@ -0,0 +1,80 @@ +// 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. + +#ifndef CHROMEOS_NETWORK_HOST_RESOLVER_IMPL_CHROMEOS_H_ +#define CHROMEOS_NETWORK_HOST_RESOLVER_IMPL_CHROMEOS_H_ + +#include "base/memory/ref_counted.h" +#include "base/threading/thread_checker.h" +#include "chromeos/chromeos_export.h" +#include "net/dns/host_resolver_impl.h" + +namespace base { +class MessageLoopProxy; +} + +namespace chromeos { +class NetworkStateHandler; +} + +namespace chromeos { + +// HostResolverImplChromeOS overrides HostResolverImpl::Resolve in order to +// provide the correct IP addresses for localhost using the chromeos +// NetworkHandler interface. ('hostname' only returns 'localhost' on cros). + +class CHROMEOS_EXPORT HostResolverImplChromeOS : public net::HostResolverImpl { + public: + // ChromeOS specific implementation of HostResolver::CreateSystemResolver. + // Assumes NetworkHandler has been initialized. + // This is expected to be constructed on the same thread that Resolve() is + // called from, i.e. the IO thread, which is presumed to differ from the + // thread that NetworkStateHandler is called on, i.e. the UI thread. + static scoped_ptr<net::HostResolver> CreateSystemResolver( + const Options& options, + net::NetLog* net_log); + + // Creates a host resolver instance for testing. + static scoped_ptr<net::HostResolver> CreateHostResolverForTest( + scoped_refptr<base::MessageLoopProxy> network_handler_message_loop, + NetworkStateHandler* network_state_handler); + + virtual ~HostResolverImplChromeOS(); + + // HostResolverImpl + virtual int Resolve(const RequestInfo& info, + net::RequestPriority priority, + net::AddressList* addresses, + const net::CompletionCallback& callback, + RequestHandle* out_req, + const net::BoundNetLog& source_net_log) OVERRIDE; + + private: + friend class net::HostResolver; + class NetworkObserver; + + HostResolverImplChromeOS( + scoped_refptr<base::MessageLoopProxy> network_handler_message_loop, + NetworkStateHandler* network_state_handler, + const Options& options, + net::NetLog* net_log); + + void SetIPAddresses(const std::string& ipv4_address, + const std::string& ipv6_address); + + bool ResolveLocalIPAddress(const RequestInfo& info, + net::AddressList* addresses); + + std::string ipv4_address_; + std::string ipv6_address_; + base::ThreadChecker thread_checker_; + scoped_refptr<base::MessageLoopProxy> network_handler_message_loop_; + base::WeakPtrFactory<HostResolverImplChromeOS> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(HostResolverImplChromeOS); +}; + +} // namespace chromeos + +#endif // CHROMEOS_NETWORK_HOST_RESOLVER_IMPL_CHROMEOS_H_ diff --git a/chromeos/network/host_resolver_impl_chromeos_unittest.cc b/chromeos/network/host_resolver_impl_chromeos_unittest.cc new file mode 100644 index 0000000..535eec9 --- /dev/null +++ b/chromeos/network/host_resolver_impl_chromeos_unittest.cc @@ -0,0 +1,171 @@ +// 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/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "base/strings/stringprintf.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/shill_device_client.h" +#include "chromeos/dbus/shill_ipconfig_client.h" +#include "chromeos/dbus/shill_service_client.h" +#include "chromeos/network/device_state.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" +#include "dbus/object_path.h" +#include "net/base/net_errors.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace { + +const char kTestIPv4Address[] = "1.2.3.4"; +const char kTestIPv6Address[] = "1:2:3:4:5:6:7:8"; + +void DoNothingWithCallStatus(chromeos::DBusMethodCallStatus call_status) {} +void ErrorCallbackFunction(const std::string& error_name, + const std::string& error_message) { + LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message; +} +void ResolveCompletionCallback(int result) {} + +} // namespace + +class HostResolverImplChromeOSTest : public testing::Test { + public: + HostResolverImplChromeOSTest() {} + + virtual ~HostResolverImplChromeOSTest() {} + + virtual void SetUp() OVERRIDE { + chromeos::DBusThreadManager::InitializeWithStub(); + + network_state_handler_.reset( + chromeos::NetworkStateHandler::InitializeForTest()); + base::RunLoop().RunUntilIdle(); + + const chromeos::NetworkState* default_network = + network_state_handler_->DefaultNetwork(); + ASSERT_TRUE(default_network); + const chromeos::DeviceState* default_device = + network_state_handler_->GetDeviceState(default_network->device_path()); + ASSERT_TRUE(default_device); + SetDefaultIPConfigs(default_device->path()); + + // Create the host resolver from the IO message loop. + io_message_loop_.PostTask( + FROM_HERE, + base::Bind(&HostResolverImplChromeOSTest::InitializeHostResolver, + base::Unretained(this))); + io_message_loop_.RunUntilIdle(); + + // Run the main message loop to create the network observer and initialize + // the ip address values. + base::RunLoop().RunUntilIdle(); + } + + virtual void TearDown() OVERRIDE { + network_state_handler_.reset(); + chromeos::DBusThreadManager::Shutdown(); + } + + protected: + // Run from main (UI) message loop, calls Resolve on IO message loop. + int CallResolve(net::HostResolver::RequestInfo& info) { + io_message_loop_.PostTask( + FROM_HERE, + base::Bind(&HostResolverImplChromeOSTest::Resolve, + base::Unretained(this), + info)); + io_message_loop_.RunUntilIdle(); + return result_; + } + + net::AddressList addresses_; + int result_; + + private: + // Run from IO message loop. + void InitializeHostResolver() { + net::HostResolver::Options options; + host_resolver_ = + chromeos::HostResolverImplChromeOS::CreateHostResolverForTest( + base::MessageLoopProxy::current(), + network_state_handler_.get()); + } + + // Run from IO message loop. + void Resolve(net::HostResolver::RequestInfo info) { + result_ = host_resolver_->Resolve( + info, + net::DEFAULT_PRIORITY, + &addresses_, + base::Bind(&ResolveCompletionCallback), + NULL, + net_log_); + } + + void SetDefaultIPConfigs(const std::string& default_device_path) { + const std::string kTestIPv4ConfigPath("test_ip_v4_config_path"); + const std::string kTestIPv6ConfigPath("test_ip_v6_config_path"); + + SetIPConfig(kTestIPv4ConfigPath, shill::kTypeIPv4, kTestIPv4Address); + SetIPConfig(kTestIPv6ConfigPath, shill::kTypeIPv6, kTestIPv6Address); + base::RunLoop().RunUntilIdle(); + + base::ListValue ip_configs; + ip_configs.AppendString(kTestIPv4ConfigPath); + ip_configs.AppendString(kTestIPv6ConfigPath); + + chromeos::DBusThreadManager::Get()->GetShillDeviceClient()->SetProperty( + dbus::ObjectPath(default_device_path), + shill::kIPConfigsProperty, + ip_configs, + base::Bind(&base::DoNothing), + base::Bind(&ErrorCallbackFunction)); + base::RunLoop().RunUntilIdle(); + } + + void SetIPConfig(const std::string& path, + const std::string& method, + const std::string& address) { + chromeos::DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty( + dbus::ObjectPath(path), + shill::kAddressProperty, + base::StringValue(address), + base::Bind(&DoNothingWithCallStatus)); + chromeos::DBusThreadManager::Get()->GetShillIPConfigClient()->SetProperty( + dbus::ObjectPath(path), + shill::kMethodProperty, + base::StringValue(method), + base::Bind(&DoNothingWithCallStatus)); + } + + scoped_ptr<chromeos::NetworkStateHandler> network_state_handler_; + scoped_ptr<net::HostResolver> host_resolver_; + base::MessageLoop io_message_loop_; + net::BoundNetLog net_log_; + + DISALLOW_COPY_AND_ASSIGN(HostResolverImplChromeOSTest); +}; + +TEST_F(HostResolverImplChromeOSTest, Resolve) { + net::HostResolver::RequestInfo info( + net::HostPortPair(net::GetHostName(), 80)); + info.set_address_family(net::ADDRESS_FAMILY_IPV4); + EXPECT_EQ(net::OK, CallResolve(info)); + ASSERT_EQ(1u, addresses_.size()); + std::string expected = base::StringPrintf("%s:%d", kTestIPv4Address, 0); + EXPECT_EQ(expected, addresses_[0].ToString()); + + info.set_address_family(net::ADDRESS_FAMILY_IPV6); + EXPECT_EQ(net::OK, CallResolve(info)); + ASSERT_EQ(2u, addresses_.size()); + expected = base::StringPrintf("[%s]:%d", kTestIPv6Address, 0); + EXPECT_EQ(expected, addresses_[0].ToString()); + expected = base::StringPrintf("%s:%d", kTestIPv4Address, 0); + EXPECT_EQ(expected, addresses_[1].ToString()); +} diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index aa91883..e4e5f6e 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc @@ -60,6 +60,7 @@ NetworkStateHandler::NetworkStateHandler() { } NetworkStateHandler::~NetworkStateHandler() { + FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_, IsShuttingDown()); STLDeleteContainerPointers(network_list_.begin(), network_list_.end()); STLDeleteContainerPointers(device_list_.begin(), device_list_.end()); } @@ -658,11 +659,19 @@ void NetworkStateHandler::UpdateIPConfigProperties( if (!network) return; network->IPConfigPropertiesChanged(properties); + if (network->path() == default_network_path_) + NotifyDefaultNetworkChanged(network); } else if (type == ManagedState::MANAGED_TYPE_DEVICE) { DeviceState* device = GetModifiableDeviceState(path); if (!device) return; device->IPConfigPropertiesChanged(ip_config_path, properties); + if (!default_network_path_.empty()) { + const NetworkState* default_network = + GetNetworkState(default_network_path_); + if (default_network && default_network->device_path() == path) + NotifyDefaultNetworkChanged(default_network); + } } } diff --git a/chromeos/network/network_state_handler_observer.cc b/chromeos/network/network_state_handler_observer.cc index b0cab57..0914e6b 100644 --- a/chromeos/network/network_state_handler_observer.cc +++ b/chromeos/network/network_state_handler_observer.cc @@ -30,4 +30,7 @@ void NetworkStateHandlerObserver::NetworkPropertiesUpdated( const NetworkState* network) { } +void NetworkStateHandlerObserver::IsShuttingDown() { +} + } // namespace chromeos diff --git a/chromeos/network/network_state_handler_observer.h b/chromeos/network/network_state_handler_observer.h index ef33c6f..63910c4 100644 --- a/chromeos/network/network_state_handler_observer.h +++ b/chromeos/network/network_state_handler_observer.h @@ -44,6 +44,10 @@ class CHROMEOS_EXPORT NetworkStateHandlerObserver { // wifi strength. virtual void NetworkPropertiesUpdated(const NetworkState* network); + // Called just before NetworkStateHandler is destroyed so that observers + // can safely stop observing. + virtual void IsShuttingDown(); + private: DISALLOW_COPY_AND_ASSIGN(NetworkStateHandlerObserver); }; |