Less strict CHECK for DeviceCapabilities results.
[chromium-blink-merge.git] / chromeos / network / network_configuration_handler.cc
blobff81dee84805d5593f011e9e802e93429e93b383
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.
5 #include "chromeos/network/network_configuration_handler.h"
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/format_macros.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/stl_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/shill_manager_client.h"
21 #include "chromeos/dbus/shill_profile_client.h"
22 #include "chromeos/dbus/shill_service_client.h"
23 #include "chromeos/network/network_event_log.h"
24 #include "chromeos/network/network_state_handler.h"
25 #include "chromeos/network/shill_property_util.h"
26 #include "dbus/object_path.h"
27 #include "third_party/cros_system_api/dbus/service_constants.h"
29 namespace chromeos {
31 namespace {
33 // Strip surrounding "" from keys (if present).
34 std::string StripQuotations(const std::string& in_str) {
35 size_t len = in_str.length();
36 if (len >= 2 && in_str[0] == '"' && in_str[len-1] == '"')
37 return in_str.substr(1, len-2);
38 return in_str;
41 void InvokeErrorCallback(const std::string& service_path,
42 const network_handler::ErrorCallback& error_callback,
43 const std::string& error_name) {
44 std::string error_msg = "Config Error: " + error_name;
45 NET_LOG_ERROR(error_msg, service_path);
46 network_handler::RunErrorCallback(
47 error_callback, service_path, error_name, error_msg);
50 void GetPropertiesCallback(
51 const network_handler::DictionaryResultCallback& callback,
52 const network_handler::ErrorCallback& error_callback,
53 const std::string& service_path,
54 DBusMethodCallStatus call_status,
55 const base::DictionaryValue& properties) {
56 // Get the correct name from WifiHex if necessary.
57 scoped_ptr<base::DictionaryValue> properties_copy(properties.DeepCopy());
58 std::string name =
59 shill_property_util::GetNameFromProperties(service_path, properties);
60 if (!name.empty()) {
61 properties_copy->SetStringWithoutPathExpansion(shill::kNameProperty, name);
63 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
64 // Because network services are added and removed frequently, we will see
65 // failures regularly, so don't log these.
66 network_handler::RunErrorCallback(error_callback,
67 service_path,
68 network_handler::kDBusFailedError,
69 network_handler::kDBusFailedErrorMessage);
70 } else if (!callback.is_null()) {
71 callback.Run(service_path, *properties_copy.get());
75 void SetNetworkProfileErrorCallback(
76 const std::string& service_path,
77 const std::string& profile_path,
78 const network_handler::ErrorCallback& error_callback,
79 const std::string& dbus_error_name,
80 const std::string& dbus_error_message) {
81 network_handler::ShillErrorCallbackFunction(
82 "Config.SetNetworkProfile Failed: " + profile_path,
83 service_path, error_callback,
84 dbus_error_name, dbus_error_message);
87 bool IsPassphrase(const std::string& key) {
88 return key == shill::kEapPrivateKeyPasswordProperty ||
89 key == shill::kEapPasswordProperty ||
90 key == shill::kL2tpIpsecPasswordProperty ||
91 key == shill::kOpenVPNPasswordProperty ||
92 key == shill::kPassphraseProperty ||
93 key == shill::kOpenVPNOTPProperty ||
94 key == shill::kEapPrivateKeyProperty ||
95 key == shill::kEapPinProperty ||
96 key == shill::kApnPasswordProperty;
99 void LogConfigProperties(const std::string& desc,
100 const std::string& path,
101 const base::DictionaryValue& properties) {
102 for (base::DictionaryValue::Iterator iter(properties);
103 !iter.IsAtEnd(); iter.Advance()) {
104 std::string v = "******";
105 if (!IsPassphrase(iter.key()))
106 base::JSONWriter::Write(&iter.value(), &v);
107 NET_LOG_DEBUG(desc, path + "." + iter.key() + "=" + v);
111 } // namespace
113 // Helper class to request from Shill the profile entries associated with a
114 // Service and delete the service from each profile. Triggers either
115 // |callback| on success or |error_callback| on failure, and calls
116 // |handler|->ProfileEntryDeleterCompleted() on completion to delete itself.
117 class NetworkConfigurationHandler::ProfileEntryDeleter
118 : public base::SupportsWeakPtr<ProfileEntryDeleter> {
119 public:
120 ProfileEntryDeleter(NetworkConfigurationHandler* handler,
121 const std::string& service_path,
122 const base::Closure& callback,
123 const network_handler::ErrorCallback& error_callback)
124 : owner_(handler),
125 service_path_(service_path),
126 callback_(callback),
127 error_callback_(error_callback) {
130 void Run() {
131 DBusThreadManager::Get()->GetShillServiceClient()->
132 GetLoadableProfileEntries(
133 dbus::ObjectPath(service_path_),
134 base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback,
135 AsWeakPtr()));
138 private:
139 void GetProfileEntriesToDeleteCallback(
140 DBusMethodCallStatus call_status,
141 const base::DictionaryValue& profile_entries) {
142 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
143 InvokeErrorCallback(
144 service_path_, error_callback_, "GetLoadableProfileEntriesFailed");
145 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this.
146 return;
149 for (base::DictionaryValue::Iterator iter(profile_entries);
150 !iter.IsAtEnd(); iter.Advance()) {
151 std::string profile_path = StripQuotations(iter.key());
152 std::string entry_path;
153 iter.value().GetAsString(&entry_path);
154 if (profile_path.empty() || entry_path.empty()) {
155 NET_LOG_ERROR("Failed to parse Profile Entry", base::StringPrintf(
156 "%s: %s", profile_path.c_str(), entry_path.c_str()));
157 continue;
159 if (profile_delete_entries_.count(profile_path) != 0) {
160 NET_LOG_ERROR("Multiple Profile Entries", base::StringPrintf(
161 "%s: %s", profile_path.c_str(), entry_path.c_str()));
162 continue;
164 NET_LOG_DEBUG("Delete Profile Entry", base::StringPrintf(
165 "%s: %s", profile_path.c_str(), entry_path.c_str()));
166 profile_delete_entries_[profile_path] = entry_path;
167 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
168 dbus::ObjectPath(profile_path),
169 entry_path,
170 base::Bind(&ProfileEntryDeleter::ProfileEntryDeletedCallback,
171 AsWeakPtr(), profile_path, entry_path),
172 base::Bind(&ProfileEntryDeleter::ShillErrorCallback,
173 AsWeakPtr(), profile_path, entry_path));
177 void ProfileEntryDeletedCallback(const std::string& profile_path,
178 const std::string& entry) {
179 NET_LOG_DEBUG("Profile Entry Deleted", base::StringPrintf(
180 "%s: %s", profile_path.c_str(), entry.c_str()));
181 profile_delete_entries_.erase(profile_path);
182 if (!profile_delete_entries_.empty())
183 return;
184 // Run the callback if this is the last pending deletion.
185 if (!callback_.is_null())
186 callback_.Run();
187 // Request NetworkStateHandler manager update to update ServiceCompleteList.
188 owner_->network_state_handler_->UpdateManagerProperties();
189 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this.
192 void ShillErrorCallback(const std::string& profile_path,
193 const std::string& entry,
194 const std::string& dbus_error_name,
195 const std::string& dbus_error_message) {
196 // Any Shill Error triggers a failure / error.
197 network_handler::ShillErrorCallbackFunction(
198 "GetLoadableProfileEntries Failed", profile_path, error_callback_,
199 dbus_error_name, dbus_error_message);
200 // Delete this even if there are pending deletions; any callbacks will
201 // safely become no-ops (by invalidating the WeakPtrs).
202 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this.
205 NetworkConfigurationHandler* owner_; // Unowned
206 std::string service_path_;
207 base::Closure callback_;
208 network_handler::ErrorCallback error_callback_;
210 // Map of pending profile entry deletions, indexed by profile path.
211 std::map<std::string, std::string> profile_delete_entries_;
213 DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter);
216 // NetworkConfigurationHandler
218 void NetworkConfigurationHandler::GetProperties(
219 const std::string& service_path,
220 const network_handler::DictionaryResultCallback& callback,
221 const network_handler::ErrorCallback& error_callback) const {
222 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
223 dbus::ObjectPath(service_path),
224 base::Bind(&GetPropertiesCallback,
225 callback, error_callback, service_path));
228 void NetworkConfigurationHandler::SetProperties(
229 const std::string& service_path,
230 const base::DictionaryValue& properties,
231 const base::Closure& callback,
232 const network_handler::ErrorCallback& error_callback) {
233 if (properties.empty()) {
234 if (!callback.is_null())
235 callback.Run();
236 return;
238 NET_LOG_USER("SetProperties", service_path);
239 LogConfigProperties("SetProperty", service_path, properties);
241 DBusThreadManager::Get()->GetShillServiceClient()->SetProperties(
242 dbus::ObjectPath(service_path),
243 properties,
244 base::Bind(&NetworkConfigurationHandler::SetPropertiesSuccessCallback,
245 AsWeakPtr(), service_path, callback),
246 base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback,
247 AsWeakPtr(), service_path, error_callback));
250 void NetworkConfigurationHandler::ClearProperties(
251 const std::string& service_path,
252 const std::vector<std::string>& names,
253 const base::Closure& callback,
254 const network_handler::ErrorCallback& error_callback) {
255 if (names.empty()) {
256 if (!callback.is_null())
257 callback.Run();
258 return;
260 NET_LOG_USER("ClearProperties", service_path);
261 for (std::vector<std::string>::const_iterator iter = names.begin();
262 iter != names.end(); ++iter) {
263 NET_LOG_DEBUG("ClearProperty", service_path + "." + *iter);
265 DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties(
266 dbus::ObjectPath(service_path),
267 names,
268 base::Bind(&NetworkConfigurationHandler::ClearPropertiesSuccessCallback,
269 AsWeakPtr(), service_path, names, callback, error_callback),
270 base::Bind(&NetworkConfigurationHandler::ClearPropertiesErrorCallback,
271 AsWeakPtr(), service_path, error_callback));
274 void NetworkConfigurationHandler::CreateConfiguration(
275 const base::DictionaryValue& properties,
276 const network_handler::StringResultCallback& callback,
277 const network_handler::ErrorCallback& error_callback) {
278 ShillManagerClient* manager =
279 DBusThreadManager::Get()->GetShillManagerClient();
280 std::string type;
281 properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
282 if (NetworkTypePattern::Ethernet().MatchesType(type)) {
283 InvokeErrorCallback(
284 "" /* no service path */,
285 error_callback,
286 "ConfigureServiceForProfile is not implemented for Ethernet");
287 return;
290 NET_LOG_USER("CreateConfiguration", type);
291 LogConfigProperties("Configure", type, properties);
293 std::string profile;
294 properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
295 &profile);
296 DCHECK(!profile.empty());
297 manager->ConfigureServiceForProfile(
298 dbus::ObjectPath(profile),
299 properties,
300 base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback,
301 AsWeakPtr(),
302 callback),
303 base::Bind(&network_handler::ShillErrorCallbackFunction,
304 "Config.CreateConfiguration Failed",
306 error_callback));
309 void NetworkConfigurationHandler::RemoveConfiguration(
310 const std::string& service_path,
311 const base::Closure& callback,
312 const network_handler::ErrorCallback& error_callback) {
313 // Service.Remove is not reliable. Instead, request the profile entries
314 // for the service and remove each entry.
315 if (ContainsKey(profile_entry_deleters_,service_path)) {
316 InvokeErrorCallback(
317 service_path, error_callback, "RemoveConfigurationInProgress");
318 return;
320 NET_LOG_USER("Remove Configuration", service_path);
321 ProfileEntryDeleter* deleter =
322 new ProfileEntryDeleter(this, service_path, callback, error_callback);
323 profile_entry_deleters_[service_path] = deleter;
324 deleter->Run();
327 void NetworkConfigurationHandler::SetNetworkProfile(
328 const std::string& service_path,
329 const std::string& profile_path,
330 const base::Closure& callback,
331 const network_handler::ErrorCallback& error_callback) {
332 NET_LOG_USER("SetNetworkProfile", service_path + ": " + profile_path);
333 base::StringValue profile_path_value(profile_path);
334 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
335 dbus::ObjectPath(service_path),
336 shill::kProfileProperty,
337 profile_path_value,
338 callback,
339 base::Bind(&SetNetworkProfileErrorCallback,
340 service_path, profile_path, error_callback));
343 // NetworkConfigurationHandler Private methods
345 NetworkConfigurationHandler::NetworkConfigurationHandler()
346 : network_state_handler_(NULL) {
349 NetworkConfigurationHandler::~NetworkConfigurationHandler() {
350 STLDeleteContainerPairSecondPointers(
351 profile_entry_deleters_.begin(), profile_entry_deleters_.end());
354 void NetworkConfigurationHandler::Init(
355 NetworkStateHandler* network_state_handler) {
356 network_state_handler_ = network_state_handler;
359 void NetworkConfigurationHandler::RunCreateNetworkCallback(
360 const network_handler::StringResultCallback& callback,
361 const dbus::ObjectPath& service_path) {
362 if (!callback.is_null())
363 callback.Run(service_path.value());
364 // This may also get called when CreateConfiguration is used to update an
365 // existing configuration, so request a service update just in case.
366 // TODO(pneubeck): Separate 'Create' and 'Update' calls and only trigger
367 // this on an update.
368 network_state_handler_->RequestUpdateForNetwork(service_path.value());
371 void NetworkConfigurationHandler::ProfileEntryDeleterCompleted(
372 const std::string& service_path) {
373 std::map<std::string, ProfileEntryDeleter*>::iterator iter =
374 profile_entry_deleters_.find(service_path);
375 DCHECK(iter != profile_entry_deleters_.end());
376 delete iter->second;
377 profile_entry_deleters_.erase(iter);
380 void NetworkConfigurationHandler::SetPropertiesSuccessCallback(
381 const std::string& service_path,
382 const base::Closure& callback) {
383 if (!callback.is_null())
384 callback.Run();
385 network_state_handler_->RequestUpdateForNetwork(service_path);
388 void NetworkConfigurationHandler::SetPropertiesErrorCallback(
389 const std::string& service_path,
390 const network_handler::ErrorCallback& error_callback,
391 const std::string& dbus_error_name,
392 const std::string& dbus_error_message) {
393 network_handler::ShillErrorCallbackFunction(
394 "Config.SetProperties Failed",
395 service_path, error_callback,
396 dbus_error_name, dbus_error_message);
397 // Some properties may have changed so request an update regardless.
398 network_state_handler_->RequestUpdateForNetwork(service_path);
401 void NetworkConfigurationHandler::ClearPropertiesSuccessCallback(
402 const std::string& service_path,
403 const std::vector<std::string>& names,
404 const base::Closure& callback,
405 const network_handler::ErrorCallback& error_callback,
406 const base::ListValue& result) {
407 const std::string kClearPropertiesFailedError("Error.ClearPropertiesFailed");
408 DCHECK(names.size() == result.GetSize())
409 << "Incorrect result size from ClearProperties.";
411 bool some_failed = false;
412 for (size_t i = 0; i < result.GetSize(); ++i) {
413 bool success = false;
414 result.GetBoolean(i, &success);
415 if (!success) {
416 NET_LOG_ERROR("ClearProperties Failed: " + names[i], service_path);
417 some_failed = true;
421 if (some_failed) {
422 if (!error_callback.is_null()) {
423 scoped_ptr<base::DictionaryValue> error_data(
424 network_handler::CreateErrorData(
425 service_path, kClearPropertiesFailedError,
426 base::StringPrintf("Errors: %" PRIuS, result.GetSize())));
427 error_data->Set("errors", result.DeepCopy());
428 scoped_ptr<base::ListValue> name_list(new base::ListValue);
429 name_list->AppendStrings(names);
430 error_data->Set("names", name_list.release());
431 error_callback.Run(kClearPropertiesFailedError, error_data.Pass());
433 } else if (!callback.is_null()) {
434 callback.Run();
436 network_state_handler_->RequestUpdateForNetwork(service_path);
439 void NetworkConfigurationHandler::ClearPropertiesErrorCallback(
440 const std::string& service_path,
441 const network_handler::ErrorCallback& error_callback,
442 const std::string& dbus_error_name,
443 const std::string& dbus_error_message) {
444 network_handler::ShillErrorCallbackFunction(
445 "Config.ClearProperties Failed",
446 service_path, error_callback,
447 dbus_error_name, dbus_error_message);
448 // Some properties may have changed so request an update regardless.
449 network_state_handler_->RequestUpdateForNetwork(service_path);
452 // static
453 NetworkConfigurationHandler* NetworkConfigurationHandler::InitializeForTest(
454 NetworkStateHandler* network_state_handler) {
455 NetworkConfigurationHandler* handler = new NetworkConfigurationHandler();
456 handler->Init(network_state_handler);
457 return handler;
460 } // namespace chromeos