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