Home | History | Annotate | Download | only in network
      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).
     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 
     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 
     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 
     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 
     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:
    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 
    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:
    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 
    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 
    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 
    207 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 
    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 
    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 
    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 
    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 
    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 
    338 NetworkConfigurationHandler::NetworkConfigurationHandler()
    339     : network_state_handler_(NULL) {
    340 }
    341 
    342 NetworkConfigurationHandler::~NetworkConfigurationHandler() {
    343   STLDeleteContainerPairSecondPointers(
    344       profile_entry_deleters_.begin(), profile_entry_deleters_.end());
    345 }
    346 
    347 void NetworkConfigurationHandler::Init(
    348     NetworkStateHandler* network_state_handler) {
    349   network_state_handler_ = network_state_handler;
    350 }
    351 
    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 
    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 
    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 
    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 
    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 
    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
    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