network_state.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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_state.h" 6 7#include "base/i18n/icu_encoding_detection.h" 8#include "base/i18n/icu_string_conversions.h" 9#include "base/string_util.h" 10#include "base/stringprintf.h" 11#include "base/strings/string_number_conversions.h" 12#include "base/strings/utf_string_conversion_utils.h" 13#include "base/values.h" 14#include "chromeos/network/network_event_log.h" 15#include "third_party/cros_system_api/dbus/service_constants.h" 16 17namespace { 18 19const char kLogModule[] = "NetworkState"; 20 21bool ConvertListValueToStringVector(const base::ListValue& string_list, 22 std::vector<std::string>* result) { 23 for (size_t i = 0; i < string_list.GetSize(); ++i) { 24 std::string str; 25 if (!string_list.GetString(i, &str)) 26 return false; 27 result->push_back(str); 28 } 29 return true; 30} 31 32// Replace non UTF8 characters in |str| with a replacement character. 33std::string ValidateUTF8(const std::string& str) { 34 std::string result; 35 for (int32 index = 0; index < static_cast<int32>(str.size()); ++index) { 36 uint32 code_point_out; 37 bool is_unicode_char = base::ReadUnicodeCharacter(str.c_str(), str.size(), 38 &index, &code_point_out); 39 const uint32 kFirstNonControlChar = 0x20; 40 if (is_unicode_char && (code_point_out >= kFirstNonControlChar)) { 41 base::WriteUnicodeCharacter(code_point_out, &result); 42 } else { 43 const uint32 kReplacementChar = 0xFFFD; 44 // Puts kReplacementChar if character is a control character [0,0x20) 45 // or is not readable UTF8. 46 base::WriteUnicodeCharacter(kReplacementChar, &result); 47 } 48 } 49 return result; 50} 51 52} // namespace 53 54namespace chromeos { 55 56NetworkState::NetworkState(const std::string& path) 57 : ManagedState(MANAGED_TYPE_NETWORK, path), 58 auto_connect_(false), 59 favorite_(false), 60 priority_(0), 61 signal_strength_(0), 62 connectable_(false), 63 passphrase_required_(false), 64 activate_over_non_cellular_networks_(false), 65 cellular_out_of_credits_(false) { 66} 67 68NetworkState::~NetworkState() { 69} 70 71bool NetworkState::PropertyChanged(const std::string& key, 72 const base::Value& value) { 73 // Keep care that these properties are the same as in |GetProperties|. 74 if (ManagedStatePropertyChanged(key, value)) 75 return true; 76 if (key == flimflam::kSignalStrengthProperty) { 77 return GetIntegerValue(key, value, &signal_strength_); 78 } else if (key == flimflam::kStateProperty) { 79 return GetStringValue(key, value, &connection_state_); 80 } else if (key == flimflam::kConnectableProperty) { 81 return GetBooleanValue(key, value, &connectable_); 82 } else if (key == flimflam::kPassphraseRequiredProperty) { 83 return GetBooleanValue(key, value, &passphrase_required_); 84 } else if (key == flimflam::kErrorProperty) { 85 return GetStringValue(key, value, &error_); 86 } else if (key == IPConfigProperty(flimflam::kAddressProperty)) { 87 return GetStringValue(key, value, &ip_address_); 88 } else if (key == IPConfigProperty(flimflam::kNameServersProperty)) { 89 dns_servers_.clear(); 90 const base::ListValue* dns_servers; 91 if (value.GetAsList(&dns_servers) && 92 ConvertListValueToStringVector(*dns_servers, &dns_servers_)) 93 return true; 94 } else if (key == flimflam::kActivationStateProperty) { 95 return GetStringValue(key, value, &activation_state_); 96 } else if (key == flimflam::kRoamingStateProperty) { 97 return GetStringValue(key, value, &roaming_); 98 } else if (key == flimflam::kSecurityProperty) { 99 return GetStringValue(key, value, &security_); 100 } else if (key == flimflam::kAutoConnectProperty) { 101 return GetBooleanValue(key, value, &auto_connect_); 102 } else if (key == flimflam::kFavoriteProperty) { 103 return GetBooleanValue(key, value, &favorite_); 104 } else if (key == flimflam::kPriorityProperty) { 105 return GetIntegerValue(key, value, &priority_); 106 } else if (key == flimflam::kNetworkTechnologyProperty) { 107 return GetStringValue(key, value, &technology_); 108 } else if (key == flimflam::kDeviceProperty) { 109 return GetStringValue(key, value, &device_path_); 110 } else if (key == flimflam::kGuidProperty) { 111 return GetStringValue(key, value, &guid_); 112 } else if (key == flimflam::kProfileProperty) { 113 return GetStringValue(key, value, &profile_path_); 114 } else if (key == shill::kActivateOverNonCellularNetworkProperty) { 115 return GetBooleanValue(key, value, &activate_over_non_cellular_networks_); 116 } else if (key == shill::kOutOfCreditsProperty) { 117 return GetBooleanValue(key, value, &cellular_out_of_credits_); 118 } else if (key == flimflam::kWifiHexSsid) { 119 return GetStringValue(key, value, &hex_ssid_); 120 } else if (key == flimflam::kCountryProperty) { 121 // TODO(stevenjb): This is currently experimental. If we find a case where 122 // base::DetectEncoding() fails in UpdateName(), where country_code_ is 123 // set, figure out whether we can use country_code_ with ConvertToUtf8(). 124 // crbug.com/233267. 125 return GetStringValue(key, value, &country_code_); 126 } 127 return false; 128} 129 130void NetworkState::InitialPropertiesReceived() { 131 UpdateName(); 132} 133 134void NetworkState::GetProperties(base::DictionaryValue* dictionary) const { 135 // Keep care that these properties are the same as in |PropertyChanged|. 136 dictionary->SetStringWithoutPathExpansion(flimflam::kNameProperty, name()); 137 dictionary->SetStringWithoutPathExpansion(flimflam::kTypeProperty, type()); 138 dictionary->SetIntegerWithoutPathExpansion(flimflam::kSignalStrengthProperty, 139 signal_strength_); 140 dictionary->SetStringWithoutPathExpansion(flimflam::kStateProperty, 141 connection_state_); 142 dictionary->SetBooleanWithoutPathExpansion(flimflam::kConnectableProperty, 143 connectable_); 144 dictionary->SetBooleanWithoutPathExpansion( 145 flimflam::kPassphraseRequiredProperty, passphrase_required_); 146 dictionary->SetStringWithoutPathExpansion(flimflam::kErrorProperty, 147 error_); 148 base::DictionaryValue* ipconfig_properties = new DictionaryValue; 149 ipconfig_properties->SetStringWithoutPathExpansion(flimflam::kAddressProperty, 150 ip_address_); 151 base::ListValue* name_servers = new ListValue; 152 name_servers->AppendStrings(dns_servers_); 153 ipconfig_properties->SetWithoutPathExpansion(flimflam::kNameServersProperty, 154 name_servers); 155 dictionary->SetWithoutPathExpansion(shill::kIPConfigProperty, 156 ipconfig_properties); 157 158 dictionary->SetStringWithoutPathExpansion(flimflam::kActivationStateProperty, 159 activation_state_); 160 dictionary->SetStringWithoutPathExpansion(flimflam::kRoamingStateProperty, 161 roaming_); 162 dictionary->SetStringWithoutPathExpansion(flimflam::kSecurityProperty, 163 security_); 164 dictionary->SetBooleanWithoutPathExpansion(flimflam::kAutoConnectProperty, 165 auto_connect_); 166 dictionary->SetBooleanWithoutPathExpansion(flimflam::kFavoriteProperty, 167 favorite_); 168 dictionary->SetIntegerWithoutPathExpansion(flimflam::kPriorityProperty, 169 priority_); 170 dictionary->SetStringWithoutPathExpansion( 171 flimflam::kNetworkTechnologyProperty, 172 technology_); 173 dictionary->SetStringWithoutPathExpansion(flimflam::kDeviceProperty, 174 device_path_); 175 dictionary->SetStringWithoutPathExpansion(flimflam::kGuidProperty, guid_); 176 dictionary->SetStringWithoutPathExpansion(flimflam::kProfileProperty, 177 profile_path_); 178 dictionary->SetBooleanWithoutPathExpansion( 179 shill::kActivateOverNonCellularNetworkProperty, 180 activate_over_non_cellular_networks_); 181 dictionary->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty, 182 cellular_out_of_credits_); 183} 184 185bool NetworkState::IsConnectedState() const { 186 return StateIsConnected(connection_state_); 187} 188 189bool NetworkState::IsConnectingState() const { 190 return StateIsConnecting(connection_state_); 191} 192 193void NetworkState::UpdateName() { 194 if (hex_ssid_.empty()) { 195 // Validate name for UTF8. 196 std::string valid_ssid = ValidateUTF8(name()); 197 if (valid_ssid != name()) { 198 set_name(valid_ssid); 199 network_event_log::AddEntry( 200 kLogModule, "UpdateName", 201 base::StringPrintf("%s: UTF8: %s", path().c_str(), name().c_str())); 202 } 203 return; 204 } 205 206 std::string ssid; 207 std::vector<uint8> raw_ssid_bytes; 208 if (base::HexStringToBytes(hex_ssid_, &raw_ssid_bytes)) { 209 ssid = std::string(raw_ssid_bytes.begin(), raw_ssid_bytes.end()); 210 } else { 211 std::string desc = base::StringPrintf("%s: Error processing: %s", 212 path().c_str(), hex_ssid_.c_str()); 213 network_event_log::AddEntry(kLogModule, "UpdateName", desc); 214 LOG(ERROR) << desc; 215 ssid = name(); 216 } 217 218 if (IsStringUTF8(ssid)) { 219 if (ssid != name()) { 220 set_name(ssid); 221 network_event_log::AddEntry( 222 kLogModule, "UpdateName", 223 base::StringPrintf("%s: UTF8: %s", path().c_str(), name().c_str())); 224 } 225 return; 226 } 227 228 // Detect encoding and convert to UTF-8. 229 std::string encoding; 230 if (!base::DetectEncoding(ssid, &encoding)) { 231 // TODO(stevenjb): Test this. See comment in PropertyChanged() under 232 // flimflam::kCountryProperty. 233 encoding = country_code_; 234 } 235 if (!encoding.empty()) { 236 std::string utf8_ssid; 237 if (base::ConvertToUtf8AndNormalize(ssid, encoding, &utf8_ssid)) { 238 set_name(utf8_ssid); 239 network_event_log::AddEntry( 240 kLogModule, "UpdateName", 241 base::StringPrintf("%s: Encoding=%s: %s", path().c_str(), 242 encoding.c_str(), name().c_str())); 243 return; 244 } 245 } 246 247 // Unrecognized encoding. Only use raw bytes if name_ is empty. 248 if (name().empty()) 249 set_name(ssid); 250 network_event_log::AddEntry( 251 kLogModule, "UpdateName", 252 base::StringPrintf("%s: Unrecognized Encoding=%s: %s", path().c_str(), 253 encoding.c_str(), name().c_str())); 254} 255 256// static 257bool NetworkState::StateIsConnected(const std::string& connection_state) { 258 return (connection_state == flimflam::kStateReady || 259 connection_state == flimflam::kStateOnline || 260 connection_state == flimflam::kStatePortal); 261} 262 263// static 264bool NetworkState::StateIsConnecting(const std::string& connection_state) { 265 return (connection_state == flimflam::kStateAssociation || 266 connection_state == flimflam::kStateConfiguration || 267 connection_state == flimflam::kStateCarrier); 268} 269 270// static 271std::string NetworkState::IPConfigProperty(const char* key) { 272 return base::StringPrintf("%s.%s", shill::kIPConfigProperty, key); 273} 274 275} // namespace chromeos 276