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