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"
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"
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);
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 if (call_status
!= DBUS_METHOD_CALL_SUCCESS
) {
57 // Because network services are added and removed frequently, we will see
58 // failures regularly, so don't log these.
59 network_handler::RunErrorCallback(error_callback
,
61 network_handler::kDBusFailedError
,
62 network_handler::kDBusFailedErrorMessage
);
65 if (callback
.is_null())
68 // Get the correct name from WifiHex if necessary.
69 scoped_ptr
<base::DictionaryValue
> properties_copy(properties
.DeepCopy());
71 shill_property_util::GetNameFromProperties(service_path
, properties
);
73 properties_copy
->SetStringWithoutPathExpansion(shill::kNameProperty
, name
);
74 callback
.Run(service_path
, *properties_copy
.get());
77 void SetNetworkProfileErrorCallback(
78 const std::string
& service_path
,
79 const std::string
& profile_path
,
80 const network_handler::ErrorCallback
& error_callback
,
81 const std::string
& dbus_error_name
,
82 const std::string
& dbus_error_message
) {
83 network_handler::ShillErrorCallbackFunction(
84 "Config.SetNetworkProfile Failed: " + profile_path
,
85 service_path
, error_callback
,
86 dbus_error_name
, dbus_error_message
);
89 void LogConfigProperties(const std::string
& desc
,
90 const std::string
& path
,
91 const base::DictionaryValue
& properties
) {
92 for (base::DictionaryValue::Iterator
iter(properties
);
93 !iter
.IsAtEnd(); iter
.Advance()) {
94 std::string v
= "******";
95 if (!shill_property_util::IsPassphraseKey(iter
.key()))
96 base::JSONWriter::Write(&iter
.value(), &v
);
97 NET_LOG_DEBUG(desc
, path
+ "." + iter
.key() + "=" + v
);
103 // Helper class to request from Shill the profile entries associated with a
104 // Service and delete the service from each profile. Triggers either
105 // |callback| on success or |error_callback| on failure, and calls
106 // |handler|->ProfileEntryDeleterCompleted() on completion to delete itself.
107 class NetworkConfigurationHandler::ProfileEntryDeleter
108 : public base::SupportsWeakPtr
<ProfileEntryDeleter
> {
110 ProfileEntryDeleter(NetworkConfigurationHandler
* handler
,
111 const std::string
& service_path
,
112 const base::Closure
& callback
,
113 const network_handler::ErrorCallback
& error_callback
)
115 service_path_(service_path
),
117 error_callback_(error_callback
) {
121 DBusThreadManager::Get()->GetShillServiceClient()->
122 GetLoadableProfileEntries(
123 dbus::ObjectPath(service_path_
),
124 base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback
,
129 void GetProfileEntriesToDeleteCallback(
130 DBusMethodCallStatus call_status
,
131 const base::DictionaryValue
& profile_entries
) {
132 if (call_status
!= DBUS_METHOD_CALL_SUCCESS
) {
134 service_path_
, error_callback_
, "GetLoadableProfileEntriesFailed");
135 owner_
->ProfileEntryDeleterCompleted(service_path_
); // Deletes this.
139 for (base::DictionaryValue::Iterator
iter(profile_entries
);
140 !iter
.IsAtEnd(); iter
.Advance()) {
141 std::string profile_path
= StripQuotations(iter
.key());
142 std::string entry_path
;
143 iter
.value().GetAsString(&entry_path
);
144 if (profile_path
.empty() || entry_path
.empty()) {
145 NET_LOG_ERROR("Failed to parse Profile Entry", base::StringPrintf(
146 "%s: %s", profile_path
.c_str(), entry_path
.c_str()));
149 if (profile_delete_entries_
.count(profile_path
) != 0) {
150 NET_LOG_ERROR("Multiple Profile Entries", base::StringPrintf(
151 "%s: %s", profile_path
.c_str(), entry_path
.c_str()));
154 NET_LOG_DEBUG("Delete Profile Entry", base::StringPrintf(
155 "%s: %s", profile_path
.c_str(), entry_path
.c_str()));
156 profile_delete_entries_
[profile_path
] = entry_path
;
157 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
158 dbus::ObjectPath(profile_path
),
160 base::Bind(&ProfileEntryDeleter::ProfileEntryDeletedCallback
,
161 AsWeakPtr(), profile_path
, entry_path
),
162 base::Bind(&ProfileEntryDeleter::ShillErrorCallback
,
163 AsWeakPtr(), profile_path
, entry_path
));
167 void ProfileEntryDeletedCallback(const std::string
& profile_path
,
168 const std::string
& entry
) {
169 NET_LOG_DEBUG("Profile Entry Deleted", base::StringPrintf(
170 "%s: %s", profile_path
.c_str(), entry
.c_str()));
171 profile_delete_entries_
.erase(profile_path
);
172 if (!profile_delete_entries_
.empty())
174 // Run the callback if this is the last pending deletion.
175 if (!callback_
.is_null())
177 // Request NetworkStateHandler manager update to update ServiceCompleteList.
178 owner_
->network_state_handler_
->UpdateManagerProperties();
179 owner_
->ProfileEntryDeleterCompleted(service_path_
); // Deletes this.
182 void ShillErrorCallback(const std::string
& profile_path
,
183 const std::string
& entry
,
184 const std::string
& dbus_error_name
,
185 const std::string
& dbus_error_message
) {
186 // Any Shill Error triggers a failure / error.
187 network_handler::ShillErrorCallbackFunction(
188 "GetLoadableProfileEntries Failed", profile_path
, error_callback_
,
189 dbus_error_name
, dbus_error_message
);
190 // Delete this even if there are pending deletions; any callbacks will
191 // safely become no-ops (by invalidating the WeakPtrs).
192 owner_
->ProfileEntryDeleterCompleted(service_path_
); // Deletes this.
195 NetworkConfigurationHandler
* owner_
; // Unowned
196 std::string service_path_
;
197 base::Closure callback_
;
198 network_handler::ErrorCallback error_callback_
;
200 // Map of pending profile entry deletions, indexed by profile path.
201 std::map
<std::string
, std::string
> profile_delete_entries_
;
203 DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter
);
206 // NetworkConfigurationHandler
208 void NetworkConfigurationHandler::GetProperties(
209 const std::string
& service_path
,
210 const network_handler::DictionaryResultCallback
& callback
,
211 const network_handler::ErrorCallback
& error_callback
) const {
212 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
213 dbus::ObjectPath(service_path
),
214 base::Bind(&GetPropertiesCallback
,
215 callback
, error_callback
, service_path
));
218 void NetworkConfigurationHandler::SetProperties(
219 const std::string
& service_path
,
220 const base::DictionaryValue
& properties
,
221 const base::Closure
& callback
,
222 const network_handler::ErrorCallback
& error_callback
) {
223 if (properties
.empty()) {
224 if (!callback
.is_null())
228 NET_LOG_USER("SetProperties", service_path
);
229 LogConfigProperties("SetProperty", service_path
, properties
);
231 DBusThreadManager::Get()->GetShillServiceClient()->SetProperties(
232 dbus::ObjectPath(service_path
),
234 base::Bind(&NetworkConfigurationHandler::SetPropertiesSuccessCallback
,
235 AsWeakPtr(), service_path
, callback
),
236 base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback
,
237 AsWeakPtr(), service_path
, error_callback
));
240 void NetworkConfigurationHandler::ClearProperties(
241 const std::string
& service_path
,
242 const std::vector
<std::string
>& names
,
243 const base::Closure
& callback
,
244 const network_handler::ErrorCallback
& error_callback
) {
246 if (!callback
.is_null())
250 NET_LOG_USER("ClearProperties", service_path
);
251 for (std::vector
<std::string
>::const_iterator iter
= names
.begin();
252 iter
!= names
.end(); ++iter
) {
253 NET_LOG_DEBUG("ClearProperty", service_path
+ "." + *iter
);
255 DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties(
256 dbus::ObjectPath(service_path
),
258 base::Bind(&NetworkConfigurationHandler::ClearPropertiesSuccessCallback
,
259 AsWeakPtr(), service_path
, names
, callback
),
260 base::Bind(&NetworkConfigurationHandler::ClearPropertiesErrorCallback
,
261 AsWeakPtr(), service_path
, error_callback
));
264 void NetworkConfigurationHandler::CreateConfiguration(
265 const base::DictionaryValue
& properties
,
266 const network_handler::StringResultCallback
& callback
,
267 const network_handler::ErrorCallback
& error_callback
) {
268 ShillManagerClient
* manager
=
269 DBusThreadManager::Get()->GetShillManagerClient();
271 properties
.GetStringWithoutPathExpansion(shill::kTypeProperty
, &type
);
272 DCHECK(!type
.empty());
273 if (NetworkTypePattern::Ethernet().MatchesType(type
)) {
275 shill_property_util::GetNetworkIdFromProperties(properties
),
277 "ConfigureServiceForProfile: Invalid type: " + type
);
281 NET_LOG_USER("CreateConfiguration: " + type
,
282 shill_property_util::GetNetworkIdFromProperties(properties
));
283 LogConfigProperties("Configure", type
, properties
);
286 properties
.GetStringWithoutPathExpansion(shill::kProfileProperty
,
288 DCHECK(!profile
.empty());
289 manager
->ConfigureServiceForProfile(
290 dbus::ObjectPath(profile
),
292 base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback
,
295 base::Bind(&network_handler::ShillErrorCallbackFunction
,
296 "Config.CreateConfiguration Failed",
301 void NetworkConfigurationHandler::RemoveConfiguration(
302 const std::string
& service_path
,
303 const base::Closure
& callback
,
304 const network_handler::ErrorCallback
& error_callback
) {
305 // Service.Remove is not reliable. Instead, request the profile entries
306 // for the service and remove each entry.
307 if (ContainsKey(profile_entry_deleters_
,service_path
)) {
309 service_path
, error_callback
, "RemoveConfigurationInProgress");
312 NET_LOG_USER("Remove Configuration", service_path
);
313 ProfileEntryDeleter
* deleter
=
314 new ProfileEntryDeleter(this, service_path
, callback
, error_callback
);
315 profile_entry_deleters_
[service_path
] = deleter
;
319 void NetworkConfigurationHandler::SetNetworkProfile(
320 const std::string
& service_path
,
321 const std::string
& profile_path
,
322 const base::Closure
& callback
,
323 const network_handler::ErrorCallback
& error_callback
) {
324 NET_LOG_USER("SetNetworkProfile", service_path
+ ": " + profile_path
);
325 base::StringValue
profile_path_value(profile_path
);
326 DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
327 dbus::ObjectPath(service_path
),
328 shill::kProfileProperty
,
331 base::Bind(&SetNetworkProfileErrorCallback
,
332 service_path
, profile_path
, error_callback
));
335 // NetworkConfigurationHandler Private methods
337 NetworkConfigurationHandler::NetworkConfigurationHandler()
338 : network_state_handler_(NULL
) {
341 NetworkConfigurationHandler::~NetworkConfigurationHandler() {
342 STLDeleteContainerPairSecondPointers(
343 profile_entry_deleters_
.begin(), profile_entry_deleters_
.end());
346 void NetworkConfigurationHandler::Init(
347 NetworkStateHandler
* network_state_handler
) {
348 network_state_handler_
= network_state_handler
;
351 void NetworkConfigurationHandler::RunCreateNetworkCallback(
352 const network_handler::StringResultCallback
& callback
,
353 const dbus::ObjectPath
& service_path
) {
354 if (!callback
.is_null())
355 callback
.Run(service_path
.value());
356 // This may also get called when CreateConfiguration is used to update an
357 // existing configuration, so request a service update just in case.
358 // TODO(pneubeck): Separate 'Create' and 'Update' calls and only trigger
359 // this on an update.
360 network_state_handler_
->RequestUpdateForNetwork(service_path
.value());
363 void NetworkConfigurationHandler::ProfileEntryDeleterCompleted(
364 const std::string
& service_path
) {
365 std::map
<std::string
, ProfileEntryDeleter
*>::iterator iter
=
366 profile_entry_deleters_
.find(service_path
);
367 DCHECK(iter
!= profile_entry_deleters_
.end());
369 profile_entry_deleters_
.erase(iter
);
372 void NetworkConfigurationHandler::SetPropertiesSuccessCallback(
373 const std::string
& service_path
,
374 const base::Closure
& callback
) {
375 if (!callback
.is_null())
377 network_state_handler_
->RequestUpdateForNetwork(service_path
);
380 void NetworkConfigurationHandler::SetPropertiesErrorCallback(
381 const std::string
& service_path
,
382 const network_handler::ErrorCallback
& error_callback
,
383 const std::string
& dbus_error_name
,
384 const std::string
& dbus_error_message
) {
385 network_handler::ShillErrorCallbackFunction(
386 "Config.SetProperties Failed",
387 service_path
, error_callback
,
388 dbus_error_name
, dbus_error_message
);
389 // Some properties may have changed so request an update regardless.
390 network_state_handler_
->RequestUpdateForNetwork(service_path
);
393 void NetworkConfigurationHandler::ClearPropertiesSuccessCallback(
394 const std::string
& service_path
,
395 const std::vector
<std::string
>& names
,
396 const base::Closure
& callback
,
397 const base::ListValue
& result
) {
398 const std::string
kClearPropertiesFailedError("Error.ClearPropertiesFailed");
399 DCHECK(names
.size() == result
.GetSize())
400 << "Incorrect result size from ClearProperties.";
402 for (size_t i
= 0; i
< result
.GetSize(); ++i
) {
403 bool success
= false;
404 result
.GetBoolean(i
, &success
);
406 // If a property was cleared that has never been set, the clear will fail.
407 // We do not track which properties have been set, so just log the error.
408 NET_LOG_ERROR("ClearProperties Failed: " + names
[i
], service_path
);
412 if (!callback
.is_null())
414 network_state_handler_
->RequestUpdateForNetwork(service_path
);
417 void NetworkConfigurationHandler::ClearPropertiesErrorCallback(
418 const std::string
& service_path
,
419 const network_handler::ErrorCallback
& error_callback
,
420 const std::string
& dbus_error_name
,
421 const std::string
& dbus_error_message
) {
422 network_handler::ShillErrorCallbackFunction(
423 "Config.ClearProperties Failed",
424 service_path
, error_callback
,
425 dbus_error_name
, dbus_error_message
);
426 // Some properties may have changed so request an update regardless.
427 network_state_handler_
->RequestUpdateForNetwork(service_path
);
431 NetworkConfigurationHandler
* NetworkConfigurationHandler::InitializeForTest(
432 NetworkStateHandler
* network_state_handler
) {
433 NetworkConfigurationHandler
* handler
= new NetworkConfigurationHandler();
434 handler
->Init(network_state_handler
);
438 } // namespace chromeos