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.
5 #include "chromeos/network/network_state.h"
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"
19 const char kLogModule
[] = "NetworkState";
21 bool ConvertListValueToStringVector(const base::ListValue
& string_list
,
22 std::vector
<std::string
>* result
) {
23 for (size_t i
= 0; i
< string_list
.GetSize(); ++i
) {
25 if (!string_list
.GetString(i
, &str
))
27 result
->push_back(str
);
32 // Replace non UTF8 characters in |str| with a replacement character.
33 std::string
ValidateUTF8(const std::string
& str
) {
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
);
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
);
56 NetworkState::NetworkState(const std::string
& path
)
57 : ManagedState(MANAGED_TYPE_NETWORK
, path
),
62 activate_over_non_cellular_networks_(false),
63 cellular_out_of_credits_(false) {
66 NetworkState::~NetworkState() {
69 bool NetworkState::PropertyChanged(const std::string
& key
,
70 const base::Value
& value
) {
71 // Keep care that these properties are the same as in |GetProperties|.
72 if (ManagedStatePropertyChanged(key
, value
))
74 if (key
== flimflam::kSignalStrengthProperty
) {
75 return GetIntegerValue(key
, value
, &signal_strength_
);
76 } else if (key
== flimflam::kStateProperty
) {
77 return GetStringValue(key
, value
, &connection_state_
);
78 } else if (key
== flimflam::kErrorProperty
) {
79 return GetStringValue(key
, value
, &error_
);
80 } else if (key
== IPConfigProperty(flimflam::kAddressProperty
)) {
81 return GetStringValue(key
, value
, &ip_address_
);
82 } else if (key
== IPConfigProperty(flimflam::kNameServersProperty
)) {
84 const base::ListValue
* dns_servers
;
85 if (value
.GetAsList(&dns_servers
) &&
86 ConvertListValueToStringVector(*dns_servers
, &dns_servers_
))
88 } else if (key
== flimflam::kActivationStateProperty
) {
89 return GetStringValue(key
, value
, &activation_state_
);
90 } else if (key
== flimflam::kRoamingStateProperty
) {
91 return GetStringValue(key
, value
, &roaming_
);
92 } else if (key
== flimflam::kSecurityProperty
) {
93 return GetStringValue(key
, value
, &security_
);
94 } else if (key
== flimflam::kAutoConnectProperty
) {
95 return GetBooleanValue(key
, value
, &auto_connect_
);
96 } else if (key
== flimflam::kFavoriteProperty
) {
97 return GetBooleanValue(key
, value
, &favorite_
);
98 } else if (key
== flimflam::kPriorityProperty
) {
99 return GetIntegerValue(key
, value
, &priority_
);
100 } else if (key
== flimflam::kNetworkTechnologyProperty
) {
101 return GetStringValue(key
, value
, &technology_
);
102 } else if (key
== flimflam::kDeviceProperty
) {
103 return GetStringValue(key
, value
, &device_path_
);
104 } else if (key
== flimflam::kGuidProperty
) {
105 return GetStringValue(key
, value
, &guid_
);
106 } else if (key
== flimflam::kProfileProperty
) {
107 return GetStringValue(key
, value
, &profile_path_
);
108 } else if (key
== shill::kActivateOverNonCellularNetworkProperty
) {
109 return GetBooleanValue(key
, value
, &activate_over_non_cellular_networks_
);
110 } else if (key
== shill::kOutOfCreditsProperty
) {
111 return GetBooleanValue(key
, value
, &cellular_out_of_credits_
);
112 } else if (key
== flimflam::kWifiHexSsid
) {
113 return GetStringValue(key
, value
, &hex_ssid_
);
114 } else if (key
== flimflam::kCountryProperty
) {
115 // TODO(stevenjb): This is currently experimental. If we find a case where
116 // base::DetectEncoding() fails in UpdateName(), where country_code_ is
117 // set, figure out whether we can use country_code_ with ConvertToUtf8().
119 return GetStringValue(key
, value
, &country_code_
);
124 void NetworkState::InitialPropertiesReceived() {
128 void NetworkState::GetProperties(base::DictionaryValue
* dictionary
) const {
129 // Keep care that these properties are the same as in |PropertyChanged|.
130 dictionary
->SetStringWithoutPathExpansion(flimflam::kNameProperty
, name());
131 dictionary
->SetStringWithoutPathExpansion(flimflam::kTypeProperty
, type());
132 dictionary
->SetIntegerWithoutPathExpansion(flimflam::kSignalStrengthProperty
,
134 dictionary
->SetStringWithoutPathExpansion(flimflam::kStateProperty
,
136 dictionary
->SetStringWithoutPathExpansion(flimflam::kErrorProperty
,
138 base::DictionaryValue
* ipconfig_properties
= new DictionaryValue
;
139 ipconfig_properties
->SetStringWithoutPathExpansion(flimflam::kAddressProperty
,
141 base::ListValue
* name_servers
= new ListValue
;
142 name_servers
->AppendStrings(dns_servers());
143 ipconfig_properties
->SetWithoutPathExpansion(flimflam::kNameServersProperty
,
145 dictionary
->SetWithoutPathExpansion(shill::kIPConfigProperty
,
146 ipconfig_properties
);
148 dictionary
->SetStringWithoutPathExpansion(flimflam::kActivationStateProperty
,
150 dictionary
->SetStringWithoutPathExpansion(flimflam::kRoamingStateProperty
,
152 dictionary
->SetStringWithoutPathExpansion(flimflam::kSecurityProperty
,
154 dictionary
->SetBooleanWithoutPathExpansion(flimflam::kAutoConnectProperty
,
156 dictionary
->SetBooleanWithoutPathExpansion(flimflam::kFavoriteProperty
,
158 dictionary
->SetIntegerWithoutPathExpansion(flimflam::kPriorityProperty
,
160 dictionary
->SetStringWithoutPathExpansion(
161 flimflam::kNetworkTechnologyProperty
,
163 dictionary
->SetStringWithoutPathExpansion(flimflam::kDeviceProperty
,
165 dictionary
->SetStringWithoutPathExpansion(flimflam::kGuidProperty
, guid());
166 dictionary
->SetStringWithoutPathExpansion(flimflam::kProfileProperty
,
168 dictionary
->SetBooleanWithoutPathExpansion(
169 shill::kActivateOverNonCellularNetworkProperty
,
170 activate_over_non_cellular_networks());
171 dictionary
->SetBooleanWithoutPathExpansion(shill::kOutOfCreditsProperty
,
172 cellular_out_of_credits());
175 bool NetworkState::IsConnectedState() const {
176 return StateIsConnected(connection_state_
);
179 bool NetworkState::IsConnectingState() const {
180 return StateIsConnecting(connection_state_
);
183 void NetworkState::UpdateName() {
184 if (hex_ssid_
.empty()) {
185 // Validate name for UTF8.
186 std::string valid_ssid
= ValidateUTF8(name());
187 if (valid_ssid
!= name()) {
188 set_name(valid_ssid
);
189 network_event_log::AddEntry(
190 kLogModule
, "UpdateName",
191 base::StringPrintf("%s: UTF8: %s", path().c_str(), name().c_str()));
197 std::vector
<uint8
> raw_ssid_bytes
;
198 if (base::HexStringToBytes(hex_ssid_
, &raw_ssid_bytes
)) {
199 ssid
= std::string(raw_ssid_bytes
.begin(), raw_ssid_bytes
.end());
201 std::string desc
= base::StringPrintf("%s: Error processing: %s",
202 path().c_str(), hex_ssid_
.c_str());
203 network_event_log::AddEntry(kLogModule
, "UpdateName", desc
);
208 if (IsStringUTF8(ssid
)) {
209 if (ssid
!= name()) {
211 network_event_log::AddEntry(
212 kLogModule
, "UpdateName",
213 base::StringPrintf("%s: UTF8: %s", path().c_str(), name().c_str()));
218 // Detect encoding and convert to UTF-8.
219 std::string encoding
;
220 if (!base::DetectEncoding(ssid
, &encoding
)) {
221 // TODO(stevenjb): Test this. See comment in PropertyChanged() under
222 // flimflam::kCountryProperty.
223 encoding
= country_code_
;
225 if (!encoding
.empty()) {
226 std::string utf8_ssid
;
227 if (base::ConvertToUtf8AndNormalize(ssid
, encoding
, &utf8_ssid
)) {
229 network_event_log::AddEntry(
230 kLogModule
, "UpdateName",
231 base::StringPrintf("%s: Encoding=%s: %s", path().c_str(),
232 encoding
.c_str(), name().c_str()));
237 // Unrecognized encoding. Only use raw bytes if name_ is empty.
240 network_event_log::AddEntry(
241 kLogModule
, "UpdateName",
242 base::StringPrintf("%s: Unrecognized Encoding=%s: %s", path().c_str(),
243 encoding
.c_str(), name().c_str()));
247 bool NetworkState::StateIsConnected(const std::string
& connection_state
) {
248 return (connection_state
== flimflam::kStateReady
||
249 connection_state
== flimflam::kStateOnline
||
250 connection_state
== flimflam::kStatePortal
);
254 bool NetworkState::StateIsConnecting(const std::string
& connection_state
) {
255 return (connection_state
== flimflam::kStateAssociation
||
256 connection_state
== flimflam::kStateConfiguration
||
257 connection_state
== flimflam::kStateCarrier
);
261 std::string
NetworkState::IPConfigProperty(const char* key
) {
262 return base::StringPrintf("%s.%s", shill::kIPConfigProperty
, key
);
265 } // namespace chromeos