network_configuration_handler.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
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/logging.h" 13#include "base/memory/ref_counted.h" 14#include "base/memory/scoped_ptr.h" 15#include "base/stl_util.h" 16#include "base/strings/stringprintf.h" 17#include "base/values.h" 18#include "chromeos/dbus/dbus_thread_manager.h" 19#include "chromeos/dbus/shill_manager_client.h" 20#include "chromeos/dbus/shill_profile_client.h" 21#include "chromeos/dbus/shill_service_client.h" 22#include "chromeos/network/network_event_log.h" 23#include "chromeos/network/network_state.h" 24#include "chromeos/network/network_state_handler.h" 25#include "dbus/object_path.h" 26#include "third_party/cros_system_api/dbus/service_constants.h" 27 28namespace chromeos { 29 30namespace { 31 32// Strip surrounding "" from keys (if present). 33std::string StripQuotations(const std::string& in_str) { 34 size_t len = in_str.length(); 35 if (len >= 2 && in_str[0] == '"' && in_str[len-1] == '"') 36 return in_str.substr(1, len-2); 37 return in_str; 38} 39 40void InvokeErrorCallback(const std::string& error, 41 const std::string& path, 42 const network_handler::ErrorCallback& error_callback) { 43 NET_LOG_ERROR(error, path); 44 if (error_callback.is_null()) 45 return; 46 scoped_ptr<base::DictionaryValue> error_data( 47 network_handler::CreateErrorData(path, error, "")); 48 error_callback.Run(error, error_data.Pass()); 49} 50 51void 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 // Get the correct name from WifiHex if necessary. 58 scoped_ptr<base::DictionaryValue> properties_copy(properties.DeepCopy()); 59 std::string name = NetworkState::GetNameFromProperties(properties); 60 if (!name.empty()) { 61 properties_copy->SetStringWithoutPathExpansion( 62 flimflam::kNameProperty, name); 63 } 64 network_handler::GetPropertiesCallback( 65 callback, error_callback, service_path, call_status, 66 *properties_copy.get()); 67} 68 69} // namespace 70 71// Helper class to request from Shill the profile entries associated with a 72// Service and delete the service from each profile. Triggers either 73// |callback| on success or |error_callback| on failure, and calls 74// |handler|->ProfileEntryDeleterCompleted() on completion to delete itself. 75class NetworkConfigurationHandler::ProfileEntryDeleter 76 : public base::SupportsWeakPtr<ProfileEntryDeleter> { 77 public: 78 ProfileEntryDeleter(NetworkConfigurationHandler* handler, 79 const std::string& service_path, 80 const base::Closure& callback, 81 const network_handler::ErrorCallback& error_callback) 82 : owner_(handler), 83 service_path_(service_path), 84 callback_(callback), 85 error_callback_(error_callback) { 86 } 87 88 void Run() { 89 DBusThreadManager::Get()->GetShillServiceClient()-> 90 GetLoadableProfileEntries( 91 dbus::ObjectPath(service_path_), 92 base::Bind(&ProfileEntryDeleter::GetProfileEntriesToDeleteCallback, 93 AsWeakPtr())); 94 } 95 96 private: 97 void GetProfileEntriesToDeleteCallback( 98 DBusMethodCallStatus call_status, 99 const base::DictionaryValue& profile_entries) { 100 if (call_status != DBUS_METHOD_CALL_SUCCESS) { 101 InvokeErrorCallback( 102 "GetLoadableProfileEntries Failed", service_path_, error_callback_); 103 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this. 104 return; 105 } 106 107 for (base::DictionaryValue::Iterator iter(profile_entries); 108 !iter.IsAtEnd(); iter.Advance()) { 109 std::string profile_path = StripQuotations(iter.key()); 110 std::string entry_path; 111 iter.value().GetAsString(&entry_path); 112 if (profile_path.empty() || entry_path.empty()) { 113 NET_LOG_ERROR("Failed to parse Profile Entry", base::StringPrintf( 114 "%s: %s", profile_path.c_str(), entry_path.c_str())); 115 continue; 116 } 117 if (profile_delete_entries_.count(profile_path) != 0) { 118 NET_LOG_ERROR("Multiple Profile Entries", base::StringPrintf( 119 "%s: %s", profile_path.c_str(), entry_path.c_str())); 120 continue; 121 } 122 NET_LOG_DEBUG("Delete Profile Entry", base::StringPrintf( 123 "%s: %s", profile_path.c_str(), entry_path.c_str())); 124 profile_delete_entries_[profile_path] = entry_path; 125 DBusThreadManager::Get()->GetShillProfileClient()->DeleteEntry( 126 dbus::ObjectPath(profile_path), 127 entry_path, 128 base::Bind(&ProfileEntryDeleter::ProfileEntryDeletedCallback, 129 AsWeakPtr(), profile_path, entry_path), 130 base::Bind(&ProfileEntryDeleter::ShillErrorCallback, 131 AsWeakPtr(), profile_path, entry_path)); 132 } 133 } 134 135 void ProfileEntryDeletedCallback(const std::string& profile_path, 136 const std::string& entry) { 137 NET_LOG_DEBUG("Profile Entry Deleted", base::StringPrintf( 138 "%s: %s", profile_path.c_str(), entry.c_str())); 139 profile_delete_entries_.erase(profile_path); 140 if (!profile_delete_entries_.empty()) 141 return; 142 // Run the callback if this is the last pending deletion. 143 if (!callback_.is_null()) 144 callback_.Run(); 145 // Request NetworkStateHandler manager update to update ServiceCompleteList. 146 owner_->network_state_handler_->UpdateManagerProperties(); 147 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this. 148 } 149 150 void ShillErrorCallback(const std::string& profile_path, 151 const std::string& entry, 152 const std::string& dbus_error_name, 153 const std::string& dbus_error_message) { 154 // Any Shill Error triggers a failure / error. 155 network_handler::ShillErrorCallbackFunction( 156 "GetLoadableProfileEntries Failed", profile_path, error_callback_, 157 dbus_error_name, dbus_error_message); 158 // Delete this even if there are pending deletions; any callbacks will 159 // safely become no-ops (by invalidating the WeakPtrs). 160 owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this. 161 } 162 163 NetworkConfigurationHandler* owner_; // Unowned 164 std::string service_path_; 165 base::Closure callback_; 166 network_handler::ErrorCallback error_callback_; 167 168 // Map of pending profile entry deletions, indexed by profile path. 169 std::map<std::string, std::string> profile_delete_entries_; 170 171 DISALLOW_COPY_AND_ASSIGN(ProfileEntryDeleter); 172}; 173 174// NetworkConfigurationHandler 175 176void NetworkConfigurationHandler::GetProperties( 177 const std::string& service_path, 178 const network_handler::DictionaryResultCallback& callback, 179 const network_handler::ErrorCallback& error_callback) const { 180 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( 181 dbus::ObjectPath(service_path), 182 base::Bind(&GetPropertiesCallback, 183 callback, error_callback, service_path)); 184} 185 186void NetworkConfigurationHandler::SetProperties( 187 const std::string& service_path, 188 const base::DictionaryValue& properties, 189 const base::Closure& callback, 190 const network_handler::ErrorCallback& error_callback) { 191 NET_LOG_USER("SetProperties", service_path); 192 DBusThreadManager::Get()->GetShillServiceClient()->SetProperties( 193 dbus::ObjectPath(service_path), 194 properties, 195 base::Bind(&NetworkConfigurationHandler::SetPropertiesSuccessCallback, 196 AsWeakPtr(), service_path, callback), 197 base::Bind(&NetworkConfigurationHandler::SetPropertiesErrorCallback, 198 AsWeakPtr(), service_path, error_callback)); 199} 200 201void NetworkConfigurationHandler::ClearProperties( 202 const std::string& service_path, 203 const std::vector<std::string>& names, 204 const base::Closure& callback, 205 const network_handler::ErrorCallback& error_callback) { 206 NET_LOG_USER("ClearProperties", service_path); 207 DBusThreadManager::Get()->GetShillServiceClient()->ClearProperties( 208 dbus::ObjectPath(service_path), 209 names, 210 base::Bind(&NetworkConfigurationHandler::ClearPropertiesSuccessCallback, 211 AsWeakPtr(), service_path, names, callback, error_callback), 212 base::Bind(&NetworkConfigurationHandler::ClearPropertiesErrorCallback, 213 AsWeakPtr(), service_path, error_callback)); 214} 215 216void NetworkConfigurationHandler::CreateConfiguration( 217 const base::DictionaryValue& properties, 218 const network_handler::StringResultCallback& callback, 219 const network_handler::ErrorCallback& error_callback) { 220 ShillManagerClient* manager = 221 DBusThreadManager::Get()->GetShillManagerClient(); 222 223 std::string type; 224 properties.GetStringWithoutPathExpansion(flimflam::kTypeProperty, &type); 225 // Shill supports ConfigureServiceForProfile only for network type WiFi. In 226 // all other cases, we have to rely on GetService for now. This is 227 // unproblematic for VPN (user profile only), but will lead to inconsistencies 228 // with WiMax, for example. 229 if (type == flimflam::kTypeWifi) { 230 std::string profile; 231 properties.GetStringWithoutPathExpansion(flimflam::kProfileProperty, 232 &profile); 233 manager->ConfigureServiceForProfile( 234 dbus::ObjectPath(profile), 235 properties, 236 base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback, 237 AsWeakPtr(), callback), 238 base::Bind(&network_handler::ShillErrorCallbackFunction, 239 "Config.CreateConfiguration Failed", "", error_callback)); 240 } else { 241 manager->ConfigureService( 242 properties, 243 base::Bind(&NetworkConfigurationHandler::RunCreateNetworkCallback, 244 AsWeakPtr(), callback), 245 base::Bind(&network_handler::ShillErrorCallbackFunction, 246 "Config.CreateConfiguration Failed", "", error_callback)); 247 } 248} 249 250void NetworkConfigurationHandler::RemoveConfiguration( 251 const std::string& service_path, 252 const base::Closure& callback, 253 const network_handler::ErrorCallback& error_callback) { 254 // Service.Remove is not reliable. Instead, request the profile entries 255 // for the service and remove each entry. 256 if (profile_entry_deleters_.count(service_path)) { 257 InvokeErrorCallback( 258 "RemoveConfiguration In-Progress", service_path, error_callback); 259 return; 260 } 261 NET_LOG_USER("Remove Configuration", service_path); 262 ProfileEntryDeleter* deleter = 263 new ProfileEntryDeleter(this, service_path, callback, error_callback); 264 profile_entry_deleters_[service_path] = deleter; 265 deleter->Run(); 266} 267 268// NetworkConfigurationHandler Private methods 269 270NetworkConfigurationHandler::NetworkConfigurationHandler() 271 : network_state_handler_(NULL) { 272} 273 274NetworkConfigurationHandler::~NetworkConfigurationHandler() { 275 STLDeleteContainerPairSecondPointers( 276 profile_entry_deleters_.begin(), profile_entry_deleters_.end()); 277} 278 279void NetworkConfigurationHandler::Init( 280 NetworkStateHandler* network_state_handler) { 281 network_state_handler_ = network_state_handler; 282} 283 284void NetworkConfigurationHandler::RunCreateNetworkCallback( 285 const network_handler::StringResultCallback& callback, 286 const dbus::ObjectPath& service_path) { 287 if (!callback.is_null()) 288 callback.Run(service_path.value()); 289 // This may also get called when CreateConfiguration is used to update an 290 // existing configuration, so request a service update just in case. 291 // TODO(pneubeck): Separate 'Create' and 'Update' calls and only trigger 292 // this on an update. 293 network_state_handler_->RequestUpdateForNetwork(service_path.value()); 294} 295 296void NetworkConfigurationHandler::ProfileEntryDeleterCompleted( 297 const std::string& service_path) { 298 std::map<std::string, ProfileEntryDeleter*>::iterator iter = 299 profile_entry_deleters_.find(service_path); 300 DCHECK(iter != profile_entry_deleters_.end()); 301 delete iter->second; 302 profile_entry_deleters_.erase(iter); 303} 304 305void NetworkConfigurationHandler::SetPropertiesSuccessCallback( 306 const std::string& service_path, 307 const base::Closure& callback) { 308 if (!callback.is_null()) 309 callback.Run(); 310 network_state_handler_->RequestUpdateForNetwork(service_path); 311} 312 313void NetworkConfigurationHandler::SetPropertiesErrorCallback( 314 const std::string& service_path, 315 const network_handler::ErrorCallback& error_callback, 316 const std::string& dbus_error_name, 317 const std::string& dbus_error_message) { 318 network_handler::ShillErrorCallbackFunction( 319 "Config.SetProperties Failed", 320 service_path, error_callback, 321 dbus_error_name, dbus_error_message); 322 // Some properties may have changed so request an update regardless. 323 network_state_handler_->RequestUpdateForNetwork(service_path); 324} 325 326void NetworkConfigurationHandler::ClearPropertiesSuccessCallback( 327 const std::string& service_path, 328 const std::vector<std::string>& names, 329 const base::Closure& callback, 330 const network_handler::ErrorCallback& error_callback, 331 const base::ListValue& result) { 332 const std::string kClearPropertiesFailedError("Error.ClearPropertiesFailed"); 333 DCHECK(names.size() == result.GetSize()) 334 << "Incorrect result size from ClearProperties."; 335 336 bool some_failed = false; 337 for (size_t i = 0; i < result.GetSize(); ++i) { 338 bool success = false; 339 result.GetBoolean(i, &success); 340 if (!success) { 341 NET_LOG_ERROR("ClearProperties Failed: " + names[i], service_path); 342 some_failed = true; 343 } 344 } 345 346 if (some_failed) { 347 if (!error_callback.is_null()) { 348 scoped_ptr<base::DictionaryValue> error_data( 349 network_handler::CreateErrorData( 350 service_path, kClearPropertiesFailedError, 351 base::StringPrintf("Errors: %" PRIuS, result.GetSize()))); 352 error_data->Set("errors", result.DeepCopy()); 353 scoped_ptr<base::ListValue> name_list(new base::ListValue); 354 name_list->AppendStrings(names); 355 error_data->Set("names", name_list.release()); 356 error_callback.Run(kClearPropertiesFailedError, error_data.Pass()); 357 } 358 } else if (!callback.is_null()) { 359 callback.Run(); 360 } 361 network_state_handler_->RequestUpdateForNetwork(service_path); 362} 363 364void NetworkConfigurationHandler::ClearPropertiesErrorCallback( 365 const std::string& service_path, 366 const network_handler::ErrorCallback& error_callback, 367 const std::string& dbus_error_name, 368 const std::string& dbus_error_message) { 369 network_handler::ShillErrorCallbackFunction( 370 "Config.ClearProperties Failed", 371 service_path, error_callback, 372 dbus_error_name, dbus_error_message); 373 // Some properties may have changed so request an update regardless. 374 network_state_handler_->RequestUpdateForNetwork(service_path); 375} 376 377// static 378NetworkConfigurationHandler* NetworkConfigurationHandler::InitializeForTest( 379 NetworkStateHandler* network_state_handler) { 380 NetworkConfigurationHandler* handler = new NetworkConfigurationHandler(); 381 handler->Init(network_state_handler); 382 return handler; 383} 384 385} // namespace chromeos 386