• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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.h"
25 #include "chromeos/network/network_state_handler.h"
26 #include "chromeos/network/shill_property_util.h"
27 #include "dbus/object_path.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
29 
30 namespace chromeos {
31 
32 namespace {
33 
34 // Strip surrounding "" from keys (if present).
StripQuotations(const std::string & in_str)35 std::string StripQuotations(const std::string& in_str) {
36   size_t len = in_str.length();
37   if (len >= 2 && in_str[0] == '"' && in_str[len-1] == '"')
38     return in_str.substr(1, len-2);
39   return in_str;
40 }
41 
InvokeErrorCallback(const std::string & service_path,const network_handler::ErrorCallback & error_callback,const std::string & error_name)42 void InvokeErrorCallback(const std::string& service_path,
43                          const network_handler::ErrorCallback& error_callback,
44                          const std::string& error_name) {
45   std::string error_msg = "Config Error: " + error_name;
46   NET_LOG_ERROR(error_msg, service_path);
47   network_handler::RunErrorCallback(
48       error_callback, service_path, error_name, error_msg);
49 }
50 
GetPropertiesCallback(const network_handler::DictionaryResultCallback & callback,const network_handler::ErrorCallback & error_callback,const std::string & service_path,DBusMethodCallStatus call_status,const base::DictionaryValue & properties)51 void GetPropertiesCallback(
52     const network_handler::DictionaryResultCallback& callback,
53     const network_handler::ErrorCallback& error_callback,
54     const std::string& service_path,
55     DBusMethodCallStatus call_status,
56     const base::DictionaryValue& properties) {
57   if (call_status != DBUS_METHOD_CALL_SUCCESS) {
58     // Because network services are added and removed frequently, we will see
59     // failures regularly, so don't log these.
60     network_handler::RunErrorCallback(error_callback,
61                                       service_path,
62                                       network_handler::kDBusFailedError,
63                                       network_handler::kDBusFailedErrorMessage);
64     return;
65   }
66   if (callback.is_null())
67     return;
68 
69   // Get the correct name from WifiHex if necessary.
70   scoped_ptr<base::DictionaryValue> properties_copy(properties.DeepCopy());
71   std::string name =
72       shill_property_util::GetNameFromProperties(service_path, properties);
73   if (!name.empty())
74     properties_copy->SetStringWithoutPathExpansion(shill::kNameProperty, name);
75   callback.Run(service_path, *properties_copy.get());
76 }
77 
SetNetworkProfileErrorCallback(const std::string & service_path,const std::string & profile_path,const network_handler::ErrorCallback & error_callback,const std::string & dbus_error_name,const std::string & dbus_error_message)78 void SetNetworkProfileErrorCallback(
79     const std::string& service_path,
80     const std::string& profile_path,
81     const network_handler::ErrorCallback& error_callback,
82     const std::string& dbus_error_name,
83     const std::string& dbus_error_message) {
84   network_handler::ShillErrorCallbackFunction(
85       "Config.SetNetworkProfile Failed: " + profile_path,
86       service_path, error_callback,
87       dbus_error_name, dbus_error_message);
88 }
89 
LogConfigProperties(const std::string & desc,const std::string & path,const base::DictionaryValue & properties)90 void LogConfigProperties(const std::string& desc,
91                          const std::string& path,
92                          const base::DictionaryValue& properties) {
93   for (base::DictionaryValue::Iterator iter(properties);
94        !iter.IsAtEnd(); iter.Advance()) {
95     std::string v = "******";
96     if (!shill_property_util::IsPassphraseKey(iter.key()))
97       base::JSONWriter::Write(&iter.value(), &v);
98     NET_LOG_DEBUG(desc,  path + "." + iter.key() + "=" + v);
99   }
100 }
101 
102 }  // namespace
103 
104 // Helper class to request from Shill the profile entries associated with a
105 // Service and delete the service from each profile. Triggers either
106 // |callback| on success or |error_callback| on failure, and calls
107 // |handler|->ProfileEntryDeleterCompleted() on completion to delete itself.
108 class NetworkConfigurationHandler::ProfileEntryDeleter
109     : public base::SupportsWeakPtr<ProfileEntryDeleter> {
110  public:
ProfileEntryDeleter(NetworkConfigurationHandler * handler,const std::string & service_path,const base::Closure & callback,const network_handler::ErrorCallback & error_callback)111   ProfileEntryDeleter(NetworkConfigurationHandler* handler,
112                       const std::string& service_path,
113                       const base::Closure& callback,
114                       const network_handler::ErrorCallback& error_callback)
115       : owner_(handler),
116         service_path_(service_path),
117         callback_(callback),
118         error_callback_(error_callback) {
119   }
120 
Run()121   void Run() {
122     DBusThreadManager::Get()->GetShillServiceClient()->
123         GetLoadableProfileEntries(
124             dbus::ObjectPath(service_path_),
125             base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback,
126                        AsWeakPtr()));
127   }
128 
129  private:
GetProfileEntriesToDeleteCallback(DBusMethodCallStatus call_status,const base::DictionaryValue & profile_entries)130   void GetProfileEntriesToDeleteCallback(
131       DBusMethodCallStatus call_status,
132       const base::DictionaryValue& profile_entries) {
133     if (call_status != DBUS_METHOD_CALL_SUCCESS) {
134       InvokeErrorCallback(
135           service_path_, error_callback_, "GetLoadableProfileEntriesFailed");
136       owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
137       return;
138     }
139 
140     for (base::DictionaryValue::Iterator iter(profile_entries);
141          !iter.IsAtEnd(); iter.Advance()) {
142       std::string profile_path = StripQuotations(iter.key());
143       std::string entry_path;
144       iter.value().GetAsString(&entry_path);
145       if (profile_path.empty() || entry_path.empty()) {
146         NET_LOG_ERROR("Failed to parse Profile Entry", base::StringPrintf(
147             "%s: %s", profile_path.c_str(), entry_path.c_str()));
148         continue;
149       }
150       if (profile_delete_entries_.count(profile_path) != 0) {
151         NET_LOG_ERROR("Multiple Profile Entries", base::StringPrintf(
152             "%s: %s", profile_path.c_str(), entry_path.c_str()));
153         continue;
154       }
155       NET_LOG_DEBUG("Delete Profile Entry", base::StringPrintf(
156           "%s: %s", profile_path.c_str(), entry_path.c_str()));
157       profile_delete_entries_[profile_path] = entry_path;
158       DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry(
159           dbus::ObjectPath(profile_path),
160           entry_path,
161           base::Bind(&ProfileEntryDeleter::ProfileEntryDeletedCallback,
162                      AsWeakPtr(), profile_path, entry_path),
163           base::Bind(&ProfileEntryDeleter::ShillErrorCallback,
164                      AsWeakPtr(), profile_path, entry_path));
165     }
166   }
167 
ProfileEntryDeletedCallback(const std::string & profile_path,const std::string & entry)168   void ProfileEntryDeletedCallback(const std::string& profile_path,
169                                    const std::string& entry) {
170     NET_LOG_DEBUG("Profile Entry Deleted", base::StringPrintf(
171         "%s: %s", profile_path.c_str(), entry.c_str()));
172     profile_delete_entries_.erase(profile_path);
173     if (!profile_delete_entries_.empty())
174       return;
175     // Run the callback if this is the last pending deletion.
176     if (!callback_.is_null())
177       callback_.Run();
178     owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
179   }
180 
ShillErrorCallback(const std::string & profile_path,const std::string & entry,const std::string & dbus_error_name,const std::string & dbus_error_message)181   void ShillErrorCallback(const std::string& profile_path,
182                           const std::string& entry,
183                           const std::string& dbus_error_name,
184                           const std::string& dbus_error_message) {
185     // Any Shill Error triggers a failure / error.
186     network_handler::ShillErrorCallbackFunction(
187         "GetLoadableProfileEntries Failed", profile_path, error_callback_,
188         dbus_error_name, dbus_error_message);
189     // Delete this even if there are pending deletions; any callbacks will
190     // safely become no-ops (by invalidating the WeakPtrs).
191     owner_->ProfileEntryDeleterCompleted(service_path_);  // Deletes this.
192   }
193 
194   NetworkConfigurationHandler* owner_;  // Unowned
195   std::string service_path_;
196   base::Closure callback_;
197   network_handler::ErrorCallback error_callback_;
198 
199   // Map of pending profile entry deletions, indexed by profile path.
200   std::map<std::string, std::string> profile_delete_entries_;
201 
202   DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter);
203 };
204 
205 // NetworkConfigurationHandler
206 
GetProperties(const std::string & service_path,const network_handler::DictionaryResultCallback & callback,const network_handler::ErrorCallback & error_callback) const207 void NetworkConfigurationHandler::GetProperties(
208     const std::string& service_path,
209     const network_handler::DictionaryResultCallback& callback,
210     const network_handler::ErrorCallback& error_callback) const {
211   NET_LOG_USER("GetProperties", service_path);
212   DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
213       dbus::ObjectPath(service_path),
214       base::Bind(&GetPropertiesCallback,
215                  callback, error_callback, service_path));
216 }
217 
SetProperties(const std::string & service_path,const base::DictionaryValue & properties,const base::Closure & callback,const network_handler::ErrorCallback & error_callback)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())
225       callback.Run();
226     return;
227   }
228   NET_LOG_USER("SetProperties", service_path);
229   LogConfigProperties("SetProperty", service_path, properties);
230 
231   DBusThreadManager::Get()->GetShillServiceClient()->SetProperties(
232       dbus::ObjectPath(service_path),
233       properties,
234       base::Bind(&NetworkConfigurationHandler::SetPropertiesSuccessCallback,
235                  AsWeakPtr(), service_path, callback),
236       base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback,
237                  AsWeakPtr(), service_path, error_callback));
238 }
239 
ClearProperties(const std::string & service_path,const std::vector<std::string> & names,const base::Closure & callback,const network_handler::ErrorCallback & 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) {
245   if (names.empty()) {
246     if (!callback.is_null())
247       callback.Run();
248     return;
249   }
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);
254   }
255   DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties(
256       dbus::ObjectPath(service_path),
257       names,
258       base::Bind(&NetworkConfigurationHandler::ClearPropertiesSuccessCallback,
259                  AsWeakPtr(), service_path, names, callback),
260       base::Bind(&NetworkConfigurationHandler::ClearPropertiesErrorCallback,
261                  AsWeakPtr(), service_path, error_callback));
262 }
263 
CreateConfiguration(const base::DictionaryValue & properties,const network_handler::StringResultCallback & callback,const network_handler::ErrorCallback & 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();
270   std::string type;
271   properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
272   DCHECK(!type.empty());
273   if (NetworkTypePattern::Ethernet().MatchesType(type)) {
274     InvokeErrorCallback(
275         shill_property_util::GetNetworkIdFromProperties(properties),
276         error_callback,
277         "ConfigureServiceForProfile: Invalid type: " + type);
278     return;
279   }
280 
281   NET_LOG_USER("CreateConfiguration: " + type,
282                shill_property_util::GetNetworkIdFromProperties(properties));
283   LogConfigProperties("Configure", type, properties);
284 
285   std::string profile;
286   properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
287                                            &profile);
288   DCHECK(!profile.empty());
289   manager->ConfigureServiceForProfile(
290       dbus::ObjectPath(profile),
291       properties,
292       base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback,
293                  AsWeakPtr(),
294                  callback),
295       base::Bind(&network_handler::ShillErrorCallbackFunction,
296                  "Config.CreateConfiguration Failed",
297                  "",
298                  error_callback));
299 }
300 
RemoveConfiguration(const std::string & service_path,const base::Closure & callback,const network_handler::ErrorCallback & error_callback)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)) {
308     InvokeErrorCallback(
309         service_path, error_callback, "RemoveConfigurationInProgress");
310     return;
311   }
312 
313   NET_LOG_USER("Remove Configuration", service_path);
314   ProfileEntryDeleter* deleter =
315       new ProfileEntryDeleter(this, service_path, callback, error_callback);
316   profile_entry_deleters_[service_path] = deleter;
317   deleter->Run();
318 }
319 
SetNetworkProfile(const std::string & service_path,const std::string & profile_path,const base::Closure & callback,const network_handler::ErrorCallback & error_callback)320 void NetworkConfigurationHandler::SetNetworkProfile(
321     const std::string& service_path,
322     const std::string& profile_path,
323     const base::Closure& callback,
324     const network_handler::ErrorCallback& error_callback) {
325   NET_LOG_USER("SetNetworkProfile", service_path + ": " + profile_path);
326   base::StringValue profile_path_value(profile_path);
327   DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
328       dbus::ObjectPath(service_path),
329       shill::kProfileProperty,
330       profile_path_value,
331       callback,
332       base::Bind(&SetNetworkProfileErrorCallback,
333                  service_path, profile_path, error_callback));
334 }
335 
336 // NetworkConfigurationHandler Private methods
337 
NetworkConfigurationHandler()338 NetworkConfigurationHandler::NetworkConfigurationHandler()
339     : network_state_handler_(NULL) {
340 }
341 
~NetworkConfigurationHandler()342 NetworkConfigurationHandler::~NetworkConfigurationHandler() {
343   STLDeleteContainerPairSecondPointers(
344       profile_entry_deleters_.begin(), profile_entry_deleters_.end());
345 }
346 
Init(NetworkStateHandler * network_state_handler)347 void NetworkConfigurationHandler::Init(
348     NetworkStateHandler* network_state_handler) {
349   network_state_handler_ = network_state_handler;
350 }
351 
RunCreateNetworkCallback(const network_handler::StringResultCallback & callback,const dbus::ObjectPath & service_path)352 void NetworkConfigurationHandler::RunCreateNetworkCallback(
353     const network_handler::StringResultCallback& callback,
354     const dbus::ObjectPath& service_path) {
355   if (!callback.is_null())
356     callback.Run(service_path.value());
357   // This may also get called when CreateConfiguration is used to update an
358   // existing configuration, so request a service update just in case.
359   // TODO(pneubeck): Separate 'Create' and 'Update' calls and only trigger
360   // this on an update.
361   network_state_handler_->RequestUpdateForNetwork(service_path.value());
362 }
363 
ProfileEntryDeleterCompleted(const std::string & service_path)364 void NetworkConfigurationHandler::ProfileEntryDeleterCompleted(
365     const std::string& service_path) {
366   std::map<std::string, ProfileEntryDeleter*>::iterator iter =
367       profile_entry_deleters_.find(service_path);
368   DCHECK(iter != profile_entry_deleters_.end());
369   delete iter->second;
370   profile_entry_deleters_.erase(iter);
371 }
372 
SetPropertiesSuccessCallback(const std::string & service_path,const base::Closure & callback)373 void NetworkConfigurationHandler::SetPropertiesSuccessCallback(
374     const std::string& service_path,
375     const base::Closure& callback) {
376   if (!callback.is_null())
377     callback.Run();
378   network_state_handler_->RequestUpdateForNetwork(service_path);
379 }
380 
SetPropertiesErrorCallback(const std::string & service_path,const network_handler::ErrorCallback & error_callback,const std::string & dbus_error_name,const std::string & dbus_error_message)381 void NetworkConfigurationHandler::SetPropertiesErrorCallback(
382     const std::string& service_path,
383     const network_handler::ErrorCallback& error_callback,
384     const std::string& dbus_error_name,
385     const std::string& dbus_error_message) {
386   network_handler::ShillErrorCallbackFunction(
387       "Config.SetProperties Failed",
388       service_path, error_callback,
389       dbus_error_name, dbus_error_message);
390   // Some properties may have changed so request an update regardless.
391   network_state_handler_->RequestUpdateForNetwork(service_path);
392 }
393 
ClearPropertiesSuccessCallback(const std::string & service_path,const std::vector<std::string> & names,const base::Closure & callback,const base::ListValue & result)394 void NetworkConfigurationHandler::ClearPropertiesSuccessCallback(
395     const std::string& service_path,
396     const std::vector<std::string>& names,
397     const base::Closure& callback,
398     const base::ListValue& result) {
399   const std::string kClearPropertiesFailedError("Error.ClearPropertiesFailed");
400   DCHECK(names.size() == result.GetSize())
401       << "Incorrect result size from ClearProperties.";
402 
403   for (size_t i = 0; i < result.GetSize(); ++i) {
404     bool success = false;
405     result.GetBoolean(i, &success);
406     if (!success) {
407       // If a property was cleared that has never been set, the clear will fail.
408       // We do not track which properties have been set, so just log the error.
409       NET_LOG_ERROR("ClearProperties Failed: " + names[i], service_path);
410     }
411   }
412 
413   if (!callback.is_null())
414     callback.Run();
415   network_state_handler_->RequestUpdateForNetwork(service_path);
416 }
417 
ClearPropertiesErrorCallback(const std::string & service_path,const network_handler::ErrorCallback & error_callback,const std::string & dbus_error_name,const std::string & dbus_error_message)418 void NetworkConfigurationHandler::ClearPropertiesErrorCallback(
419     const std::string& service_path,
420     const network_handler::ErrorCallback& error_callback,
421     const std::string& dbus_error_name,
422     const std::string& dbus_error_message) {
423   network_handler::ShillErrorCallbackFunction(
424       "Config.ClearProperties Failed",
425       service_path, error_callback,
426       dbus_error_name, dbus_error_message);
427   // Some properties may have changed so request an update regardless.
428   network_state_handler_->RequestUpdateForNetwork(service_path);
429 }
430 
431 // static
InitializeForTest(NetworkStateHandler * network_state_handler)432 NetworkConfigurationHandler* NetworkConfigurationHandler::InitializeForTest(
433     NetworkStateHandler* network_state_handler) {
434   NetworkConfigurationHandler* handler = new NetworkConfigurationHandler();
435   handler->Init(network_state_handler);
436   return handler;
437 }
438 
439 }  // namespace chromeos
440