- add sources.
[platform/framework/web/crosswalk.git] / src / chromeos / network / network_configuration_handler.cc
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_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"
28
29 namespace chromeos {
30
31 namespace {
32
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;
39 }
40
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);
48 }
49
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);
62   }
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());
72   }
73 }
74
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);
85 }
86
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;
97 }
98
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);
108   }
109 }
110
111 }  // namespace
112
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) {
128   }
129
130   void Run() {
131     DBusThreadManager::Get()->GetShillServiceClient()->
132         GetLoadableProfileEntries(
133             dbus::ObjectPath(service_path_),
134             base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback,
135                        AsWeakPtr()));
136   }
137
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;
147     }
148
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;
158       }
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;
163       }
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));
174     }
175   }
176
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.
190   }
191
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.
203   }
204
205   NetworkConfigurationHandler* owner_;  // Unowned
206   std::string service_path_;
207   base::Closure callback_;
208   network_handler::ErrorCallback error_callback_;
209
210   // Map of pending profile entry deletions, indexed by profile path.
211   std::map<std::string, std::string> profile_delete_entries_;
212
213   DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter);
214 };
215
216 // NetworkConfigurationHandler
217
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));
226 }
227
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;
237   }
238   NET_LOG_USER("SetProperties", service_path);
239   LogConfigProperties("SetProperty", service_path, properties);
240
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));
248 }
249
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;
259   }
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);
264   }
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));
272 }
273
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;
288   }
289
290   NET_LOG_USER("CreateConfiguration", type);
291   LogConfigProperties("Configure", type, properties);
292
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",
305                  "",
306                  error_callback));
307 }
308
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;
319   }
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();
325 }
326
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));
341 }
342
343 // NetworkConfigurationHandler Private methods
344
345 NetworkConfigurationHandler::NetworkConfigurationHandler()
346     : network_state_handler_(NULL) {
347 }
348
349 NetworkConfigurationHandler::~NetworkConfigurationHandler() {
350   STLDeleteContainerPairSecondPointers(
351       profile_entry_deleters_.begin(), profile_entry_deleters_.end());
352 }
353
354 void NetworkConfigurationHandler::Init(
355     NetworkStateHandler* network_state_handler) {
356   network_state_handler_ = network_state_handler;
357 }
358
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());
369 }
370
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);
378 }
379
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);
386 }
387
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);
399 }
400
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.";
410
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;
418     }
419   }
420
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());
432     }
433   } else if (!callback.is_null()) {
434     callback.Run();
435   }
436   network_state_handler_->RequestUpdateForNetwork(service_path);
437 }
438
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);
450 }
451
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;
458 }
459
460 }  // namespace chromeos