1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chromeos/network/host_resolver_impl_chromeos.h"
6
7#include "base/message_loop/message_loop_proxy.h"
8#include "base/sys_info.h"
9#include "base/values.h"
10#include "chromeos/network/device_state.h"
11#include "chromeos/network/network_handler.h"
12#include "chromeos/network/network_state.h"
13#include "chromeos/network/network_state_handler.h"
14#include "chromeos/network/network_state_handler_observer.h"
15#include "net/base/address_list.h"
16#include "net/base/net_errors.h"
17#include "net/base/net_util.h"
18#include "third_party/cros_system_api/dbus/service_constants.h"
19
20namespace chromeos {
21
22// HostResolverImplChromeOS::NetworkStateHandlerObserver
23//
24// An instance of this class is created on the NetworkHandler (UI) thread and
25// manages its own lifetime, destroying itself when NetworkStateHandlerObserver
26// ::IsShuttingDown() gets called.
27
28class HostResolverImplChromeOS::NetworkObserver
29    : public chromeos::NetworkStateHandlerObserver {
30 public:
31  static void Create(
32      const base::WeakPtr<HostResolverImplChromeOS>& resolver,
33      scoped_refptr<base::MessageLoopProxy> resolver_message_loop,
34      NetworkStateHandler* network_state_handler) {
35    new NetworkObserver(resolver, resolver_message_loop, network_state_handler);
36  }
37
38  NetworkObserver(const base::WeakPtr<HostResolverImplChromeOS>& resolver,
39                  scoped_refptr<base::MessageLoopProxy> resolver_message_loop,
40                  NetworkStateHandler* network_state_handler)
41      : resolver_(resolver),
42        resolver_message_loop_(resolver_message_loop),
43        network_state_handler_(network_state_handler),
44        weak_ptr_factory_resolver_thread_(this) {
45    network_state_handler_->AddObserver(this, FROM_HERE);
46    DefaultNetworkChanged(network_state_handler_->DefaultNetwork());
47  }
48
49 private:
50  virtual ~NetworkObserver() {
51    network_state_handler_->RemoveObserver(this, FROM_HERE);
52  }
53
54  // NetworkStateHandlerObserver
55  virtual void DefaultNetworkChanged(const NetworkState* network) OVERRIDE {
56    if (!network) {
57      DVLOG(2) << "DefaultNetworkChanged: No Network.";
58      CallResolverSetIpAddress("", "");
59      return;
60    }
61    std::string ipv4_address, ipv6_address;
62    const DeviceState* device_state =
63        network_state_handler_->GetDeviceState(network->device_path());
64    if (!device_state) {
65      LOG_IF(ERROR, base::SysInfo::IsRunningOnChromeOS())
66          << "DefaultNetworkChanged: Network missing device: "
67          << network->path();
68      CallResolverSetIpAddress("", "");
69      return;
70    }
71    for (base::DictionaryValue::Iterator iter(device_state->ip_configs());
72         !iter.IsAtEnd(); iter.Advance()) {
73      const base::DictionaryValue* ip_config;
74      if (!iter.value().GetAsDictionary(&ip_config)) {
75        LOG(ERROR) << "Badly formatted IPConfigs: " << network->path();
76        continue;
77      }
78      std::string method, address;
79      if (ip_config->GetString(shill::kMethodProperty, &method) &&
80          ip_config->GetString(shill::kAddressProperty, &address)) {
81        if (method == shill::kTypeIPv4 || method == shill::kTypeDHCP)
82          ipv4_address = address;
83        else if (method == shill::kTypeIPv6 || method == shill::kTypeDHCP6)
84          ipv6_address = address;
85      } else {
86        LOG(ERROR) << "DefaultNetworkChanged: IPConfigs missing properties: "
87                   << network->path();
88      }
89    }
90    DVLOG(2) << "DefaultNetworkChanged: " << network->name()
91             << " IPv4: " << ipv4_address << " IPv6: " << ipv6_address;
92    CallResolverSetIpAddress(ipv4_address, ipv6_address);
93  }
94
95  virtual void IsShuttingDown() OVERRIDE {
96    delete this;
97  }
98
99  void CallResolverSetIpAddress(const std::string& ipv4_address,
100                                const std::string& ipv6_address) {
101    resolver_message_loop_->PostTask(
102        FROM_HERE,
103        base::Bind(&NetworkObserver::SetIpAddressOnResolverThread,
104                   weak_ptr_factory_resolver_thread_.GetWeakPtr(),
105                   ipv4_address, ipv6_address));
106  }
107
108  void SetIpAddressOnResolverThread(const std::string& ipv4_address,
109                                    const std::string& ipv6_address) {
110    if (resolver_)
111      resolver_->SetIPAddresses(ipv4_address, ipv6_address);
112  }
113
114  base::WeakPtr<HostResolverImplChromeOS> resolver_;
115  scoped_refptr<base::MessageLoopProxy> resolver_message_loop_;
116  NetworkStateHandler* network_state_handler_;
117  base::WeakPtrFactory<NetworkObserver> weak_ptr_factory_resolver_thread_;
118
119  DISALLOW_COPY_AND_ASSIGN(NetworkObserver);
120};
121
122// HostResolverImplChromeOS
123
124HostResolverImplChromeOS::HostResolverImplChromeOS(
125    scoped_refptr<base::MessageLoopProxy> network_handler_message_loop,
126    NetworkStateHandler* network_state_handler,
127    const Options& options,
128    net::NetLog* net_log)
129    : HostResolverImpl(options, net_log),
130      network_handler_message_loop_(network_handler_message_loop),
131      weak_ptr_factory_(this) {
132  network_handler_message_loop->PostTask(
133      FROM_HERE,
134      base::Bind(&NetworkObserver::Create,
135                 weak_ptr_factory_.GetWeakPtr(),
136                 base::MessageLoopProxy::current(),
137                 network_state_handler));
138}
139
140HostResolverImplChromeOS::~HostResolverImplChromeOS() {
141}
142
143int HostResolverImplChromeOS::Resolve(const RequestInfo& info,
144                                      net::RequestPriority priority,
145                                      net::AddressList* addresses,
146                                      const net::CompletionCallback& callback,
147                                      RequestHandle* out_req,
148                                      const net::BoundNetLog& source_net_log) {
149  DCHECK(thread_checker_.CalledOnValidThread());
150  if (ResolveLocalIPAddress(info, addresses))
151    return net::OK;
152  return net::HostResolverImpl::Resolve(
153      info, priority, addresses, callback, out_req, source_net_log);
154}
155
156void HostResolverImplChromeOS::SetIPAddresses(const std::string& ipv4_address,
157                                              const std::string& ipv6_address) {
158  DCHECK(thread_checker_.CalledOnValidThread());
159  ipv4_address_ = ipv4_address;
160  ipv6_address_ = ipv6_address;
161}
162
163bool HostResolverImplChromeOS::ResolveLocalIPAddress(
164    const RequestInfo& info,
165    net::AddressList* addresses) {
166  DCHECK(thread_checker_.CalledOnValidThread());
167  if (!info.is_my_ip_address() || ipv4_address_.empty())
168    return false;
169
170  // Use IPConfig data for localhost address lookup.
171  addresses->clear();
172
173  if (info.address_family() != net::ADDRESS_FAMILY_IPV4 &&
174      !ipv6_address_.empty()) {
175    net::IPAddressNumber ipv6;
176    if (net::ParseIPLiteralToNumber(ipv6_address_, &ipv6))
177      addresses->push_back(net::IPEndPoint(ipv6, 0));
178  }
179
180  net::IPAddressNumber ipv4;
181  if (net::ParseIPLiteralToNumber(ipv4_address_, &ipv4))
182    addresses->push_back(net::IPEndPoint(ipv4, 0));
183
184  DVLOG(2) << "ResolveLocalIPAddress("
185           << static_cast<int>(info.address_family()) << "): "
186           << addresses->size()
187           << " IPv4: " << ipv4_address_ << " IPv6: " << ipv6_address_;
188  addresses->SetDefaultCanonicalName();
189  return true;
190}
191
192// static
193scoped_ptr<net::HostResolver> HostResolverImplChromeOS::CreateSystemResolver(
194    const Options& options,
195    net::NetLog* net_log) {
196  return scoped_ptr<net::HostResolver>(new HostResolverImplChromeOS(
197      NetworkHandler::Get()->message_loop(),
198      NetworkHandler::Get()->network_state_handler(),
199      options,
200      net_log));
201}
202
203// static
204scoped_ptr<net::HostResolver>
205HostResolverImplChromeOS::CreateHostResolverForTest(
206    scoped_refptr<base::MessageLoopProxy> network_handler_message_loop,
207    NetworkStateHandler* network_state_handler) {
208  Options options;
209  return scoped_ptr<net::HostResolver>(new HostResolverImplChromeOS(
210      network_handler_message_loop,
211      network_state_handler,
212      options,
213      NULL));
214}
215
216}  // namespace chromeos
217