network_configuration_handler.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
1// Copyright (c) 2012 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/network_configuration_handler.h"
6
7#include <string>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/logging.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/scoped_ptr.h"
14#include "base/values.h"
15#include "chromeos/dbus/dbus_method_call_status.h"
16#include "chromeos/dbus/dbus_thread_manager.h"
17#include "chromeos/dbus/shill_manager_client.h"
18#include "chromeos/dbus/shill_service_client.h"
19#include "chromeos/network/network_state_handler.h"
20#include "dbus/object_path.h"
21#include "third_party/cros_system_api/dbus/service_constants.h"
22
23namespace chromeos {
24
25namespace {
26
27// None of these error messages are user-facing: they should only appear in
28// logs.
29const char kErrorsListTag[] = "errors";
30const char kClearPropertiesFailedError[] = "Error.ClearPropertiesFailed";
31const char kClearPropertiesFailedErrorMessage[] = "Clear properties failed";
32const char kDBusFailedError[] = "Error.DBusFailed";
33const char kDBusFailedErrorMessage[] = "DBus call failed.";
34
35void ClearPropertiesCallback(
36    const std::vector<std::string>& names,
37    const std::string& service_path,
38    const base::Closure& callback,
39    const network_handler::ErrorCallback& error_callback,
40    const base::ListValue& result) {
41  bool some_failed = false;
42  for (size_t i = 0; i < result.GetSize(); ++i) {
43    bool success;
44    if (result.GetBoolean(i, &success)) {
45      if (!success) {
46        some_failed = true;
47        break;
48      }
49    } else {
50      NOTREACHED() << "Result garbled from ClearProperties";
51    }
52  }
53
54  if (some_failed) {
55    DCHECK(names.size() == result.GetSize())
56        << "Result wrong size from ClearProperties.";
57    scoped_ptr<base::DictionaryValue> error_data(
58        network_handler::CreateErrorData(service_path,
59                                         kClearPropertiesFailedError,
60                                         kClearPropertiesFailedErrorMessage));
61    LOG(ERROR) << "ClearPropertiesCallback failed for service path: "
62               << service_path;
63    error_data->Set("errors", result.DeepCopy());
64    scoped_ptr<base::ListValue> name_list(new base::ListValue);
65    name_list->AppendStrings(names);
66    error_data->Set("names", name_list.release());
67    error_callback.Run(kClearPropertiesFailedError, error_data.Pass());
68  } else {
69    callback.Run();
70  }
71}
72
73// Used to translate the dbus dictionary callback into one that calls
74// the error callback if we have a failure.
75void RunCallbackWithDictionaryValue(
76    const network_handler::DictionaryResultCallback& callback,
77    const network_handler::ErrorCallback& error_callback,
78    const std::string& service_path,
79    DBusMethodCallStatus call_status,
80    const base::DictionaryValue& value) {
81  if (call_status != DBUS_METHOD_CALL_SUCCESS) {
82    scoped_ptr<base::DictionaryValue> error_data(
83        network_handler::CreateErrorData(service_path,
84                                         kDBusFailedError,
85                                         kDBusFailedErrorMessage));
86    LOG(ERROR) << "CallbackWithDictionaryValue failed for service path: "
87               << service_path;
88    error_callback.Run(kDBusFailedError, error_data.Pass());
89  } else {
90    callback.Run(service_path, value);
91  }
92}
93
94void IgnoreObjectPathCallback(const base::Closure& callback,
95                              const dbus::ObjectPath& object_path) {
96  callback.Run();
97}
98
99}  // namespace
100
101void NetworkConfigurationHandler::GetProperties(
102    const std::string& service_path,
103    const network_handler::DictionaryResultCallback& callback,
104    const network_handler::ErrorCallback& error_callback) const {
105  DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
106      dbus::ObjectPath(service_path),
107      base::Bind(&RunCallbackWithDictionaryValue,
108                 callback,
109                 error_callback,
110                 service_path));
111}
112
113void NetworkConfigurationHandler::SetProperties(
114    const std::string& service_path,
115    const base::DictionaryValue& properties,
116    const base::Closure& callback,
117    const network_handler::ErrorCallback& error_callback) const {
118  DBusThreadManager::Get()->GetShillManagerClient()->ConfigureService(
119      properties,
120      base::Bind(&IgnoreObjectPathCallback, callback),
121      base::Bind(&network_handler::ShillErrorCallbackFunction,
122                 service_path, error_callback));
123  network_state_handler_->RequestUpdateForNetwork(service_path);
124}
125
126void NetworkConfigurationHandler::ClearProperties(
127    const std::string& service_path,
128    const std::vector<std::string>& names,
129    const base::Closure& callback,
130    const network_handler::ErrorCallback& error_callback) {
131  DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties(
132      dbus::ObjectPath(service_path),
133      names,
134      base::Bind(&ClearPropertiesCallback,
135                 names,
136                 service_path,
137                 callback,
138                 error_callback),
139      base::Bind(&network_handler::ShillErrorCallbackFunction,
140                 service_path, error_callback));
141}
142
143void NetworkConfigurationHandler::CreateConfiguration(
144    const base::DictionaryValue& properties,
145    const network_handler::StringResultCallback& callback,
146    const network_handler::ErrorCallback& error_callback) {
147  ShillManagerClient* manager =
148      DBusThreadManager::Get()->GetShillManagerClient();
149
150  std::string type;
151  properties.GetStringWithoutPathExpansion(flimflam::kTypeProperty, &type);
152  // Shill supports ConfigureServiceForProfile only for network type WiFi. In
153  // all other cases, we have to rely on GetService for now. This is
154  // unproblematic for VPN (user profile only), but will lead to inconsistencies
155  // with WiMax, for example.
156  if (type == flimflam::kTypeWifi) {
157    std::string profile;
158    properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty,
159                                             &profile);
160    manager->ConfigureServiceForProfile(
161        dbus::ObjectPath(profile),
162        properties,
163        base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback,
164                   AsWeakPtr(), callback),
165        base::Bind(&network_handler::ShillErrorCallbackFunction,
166                   "", error_callback));
167  } else {
168    manager->GetService(
169        properties,
170        base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback,
171                   AsWeakPtr(), callback),
172        base::Bind(&network_handler::ShillErrorCallbackFunction,
173                   "", error_callback));
174  }
175}
176
177void NetworkConfigurationHandler::RemoveConfiguration(
178    const std::string& service_path,
179    const base::Closure& callback,
180    const network_handler::ErrorCallback& error_callback) const {
181  DBusThreadManager::Get()->GetShillServiceClient()->Remove(
182      dbus::ObjectPath(service_path),
183      callback,
184      base::Bind(&network_handler::ShillErrorCallbackFunction,
185                 service_path, error_callback));
186}
187
188NetworkConfigurationHandler::NetworkConfigurationHandler()
189    : network_state_handler_(NULL) {
190}
191
192NetworkConfigurationHandler::~NetworkConfigurationHandler() {
193}
194
195void NetworkConfigurationHandler::Init(
196    NetworkStateHandler* network_state_handler) {
197  network_state_handler_ = network_state_handler;
198}
199
200void NetworkConfigurationHandler::RunCreateNetworkCallback(
201    const network_handler::StringResultCallback& callback,
202    const dbus::ObjectPath& service_path) {
203  callback.Run(service_path.value());
204  // This may also get called when CreateConfiguration is used to update an
205  // existing configuration, so request a service update just in case.
206  // TODO(pneubeck): Separate 'Create' and 'Update' calls and only trigger
207  // this on an update.
208  network_state_handler_->RequestUpdateForNetwork(service_path.value());
209}
210
211// static
212NetworkConfigurationHandler* NetworkConfigurationHandler::InitializeForTest(
213    NetworkStateHandler* network_state_handler) {
214  NetworkConfigurationHandler* handler = new NetworkConfigurationHandler();
215  handler->Init(network_state_handler);
216  return handler;
217}
218
219}  // namespace chromeos
220