- add sources.
[platform/framework/web/crosswalk.git] / src / chromeos / network / shill_property_util.cc
1 // Copyright 2013 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/shill_property_util.h"
6
7 #include "base/i18n/icu_encoding_detection.h"
8 #include "base/i18n/icu_string_conversions.h"
9 #include "base/json/json_writer.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversion_utils.h"
14 #include "base/values.h"
15 #include "chromeos/network/network_event_log.h"
16 #include "chromeos/network/network_ui_data.h"
17 #include "chromeos/network/onc/onc_utils.h"
18 #include "third_party/cros_system_api/dbus/service_constants.h"
19
20 namespace chromeos {
21
22 namespace shill_property_util {
23
24 namespace {
25
26 // Replace non UTF8 characters in |str| with a replacement character.
27 std::string ValidateUTF8(const std::string& str) {
28   std::string result;
29   for (int32 index = 0; index < static_cast<int32>(str.size()); ++index) {
30     uint32 code_point_out;
31     bool is_unicode_char = base::ReadUnicodeCharacter(
32         str.c_str(), str.size(), &index, &code_point_out);
33     const uint32 kFirstNonControlChar = 0x20;
34     if (is_unicode_char && (code_point_out >= kFirstNonControlChar)) {
35       base::WriteUnicodeCharacter(code_point_out, &result);
36     } else {
37       const uint32 kReplacementChar = 0xFFFD;
38       // Puts kReplacementChar if character is a control character [0,0x20)
39       // or is not readable UTF8.
40       base::WriteUnicodeCharacter(kReplacementChar, &result);
41     }
42   }
43   return result;
44 }
45
46 // If existent and non-empty, copies the string at |key| from |source| to
47 // |dest|. Returns true if the string was copied.
48 bool CopyStringFromDictionary(const base::DictionaryValue& source,
49                               const std::string& key,
50                               base::DictionaryValue* dest) {
51   std::string string_value;
52   if (!source.GetStringWithoutPathExpansion(key, &string_value) ||
53       string_value.empty())
54     return false;
55   dest->SetStringWithoutPathExpansion(key, string_value);
56   return true;
57 }
58
59 }  // namespace
60
61 void SetSSID(const std::string ssid, base::DictionaryValue* properties) {
62   std::string hex_ssid = base::HexEncode(ssid.c_str(), ssid.size());
63   properties->SetStringWithoutPathExpansion(shill::kWifiHexSsid, hex_ssid);
64 }
65
66 std::string GetSSIDFromProperties(const base::DictionaryValue& properties,
67                                   bool* unknown_encoding) {
68   if (unknown_encoding)
69     *unknown_encoding = false;
70   std::string hex_ssid;
71   properties.GetStringWithoutPathExpansion(shill::kWifiHexSsid, &hex_ssid);
72
73   if (hex_ssid.empty()) {
74     NET_LOG_ERROR("GetSSIDFromProperties", "No HexSSID set.");
75     return std::string();
76   }
77
78   std::string ssid;
79   std::vector<uint8> raw_ssid_bytes;
80   if (base::HexStringToBytes(hex_ssid, &raw_ssid_bytes)) {
81     ssid = std::string(raw_ssid_bytes.begin(), raw_ssid_bytes.end());
82     NET_LOG_DEBUG(
83         "GetSSIDFromProperties",
84         base::StringPrintf("%s, SSID: %s", hex_ssid.c_str(), ssid.c_str()));
85   } else {
86     NET_LOG_ERROR("GetSSIDFromProperties",
87                   base::StringPrintf("Error processing: %s", hex_ssid.c_str()));
88     return std::string();
89   }
90
91   if (IsStringUTF8(ssid))
92     return ssid;
93
94   // Detect encoding and convert to UTF-8.
95   std::string encoding;
96   if (!base::DetectEncoding(ssid, &encoding)) {
97     // TODO(stevenjb): This is currently experimental. If we find a case where
98     // base::DetectEncoding() fails, we need to figure out whether we can use
99     // country_code with ConvertToUtf8(). crbug.com/233267.
100     properties.GetStringWithoutPathExpansion(shill::kCountryProperty,
101                                              &encoding);
102   }
103   std::string utf8_ssid;
104   if (!encoding.empty() &&
105       base::ConvertToUtf8AndNormalize(ssid, encoding, &utf8_ssid)) {
106     if (utf8_ssid != ssid) {
107       NET_LOG_DEBUG(
108           "GetSSIDFromProperties",
109           base::StringPrintf(
110               "Encoding=%s: %s", encoding.c_str(), utf8_ssid.c_str()));
111     }
112     return utf8_ssid;
113   }
114
115   if (unknown_encoding)
116     *unknown_encoding = true;
117   NET_LOG_DEBUG(
118       "GetSSIDFromProperties",
119       base::StringPrintf("Unrecognized Encoding=%s", encoding.c_str()));
120   return ssid;
121 }
122
123 std::string GetNameFromProperties(const std::string& service_path,
124                                   const base::DictionaryValue& properties) {
125   std::string name;
126   properties.GetStringWithoutPathExpansion(shill::kNameProperty, &name);
127
128   std::string validated_name = ValidateUTF8(name);
129   if (validated_name != name) {
130     NET_LOG_DEBUG("GetNameFromProperties",
131                   base::StringPrintf("Validated name %s: UTF8: %s",
132                                      service_path.c_str(),
133                                      validated_name.c_str()));
134   }
135
136   std::string type;
137   properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
138   if (!NetworkTypePattern::WiFi().MatchesType(type))
139     return validated_name;
140
141   bool unknown_ssid_encoding = false;
142   std::string ssid = GetSSIDFromProperties(properties, &unknown_ssid_encoding);
143   if (ssid.empty())
144     NET_LOG_ERROR("GetNameFromProperties", "No SSID set: " + service_path);
145
146   // Use |validated_name| if |ssid| is empty.
147   // And if the encoding of the SSID is unknown, use |ssid|, which contains raw
148   // bytes in that case, only if |validated_name| is empty.
149   if (ssid.empty() || (unknown_ssid_encoding && !validated_name.empty()))
150     return validated_name;
151
152   if (ssid != validated_name) {
153     NET_LOG_DEBUG("GetNameFromProperties",
154                   base::StringPrintf("%s: SSID: %s, Name: %s",
155                                      service_path.c_str(),
156                                      ssid.c_str(),
157                                      validated_name.c_str()));
158   }
159   return ssid;
160 }
161
162 scoped_ptr<NetworkUIData> GetUIDataFromValue(const base::Value& ui_data_value) {
163   std::string ui_data_str;
164   if (!ui_data_value.GetAsString(&ui_data_str))
165     return scoped_ptr<NetworkUIData>();
166   if (ui_data_str.empty())
167     return make_scoped_ptr(new NetworkUIData());
168   scoped_ptr<base::DictionaryValue> ui_data_dict(
169       chromeos::onc::ReadDictionaryFromJson(ui_data_str));
170   if (!ui_data_dict)
171     return scoped_ptr<NetworkUIData>();
172   return make_scoped_ptr(new NetworkUIData(*ui_data_dict));
173 }
174
175 scoped_ptr<NetworkUIData> GetUIDataFromProperties(
176     const base::DictionaryValue& shill_dictionary) {
177   const base::Value* ui_data_value = NULL;
178   shill_dictionary.GetWithoutPathExpansion(shill::kUIDataProperty,
179                                            &ui_data_value);
180   if (!ui_data_value) {
181     VLOG(2) << "Dictionary has no UIData entry.";
182     return scoped_ptr<NetworkUIData>();
183   }
184   scoped_ptr<NetworkUIData> ui_data = GetUIDataFromValue(*ui_data_value);
185   if (!ui_data)
186     LOG(ERROR) << "UIData is not a valid JSON dictionary.";
187   return ui_data.Pass();
188 }
189
190 void SetUIData(const NetworkUIData& ui_data,
191                base::DictionaryValue* shill_dictionary) {
192   base::DictionaryValue ui_data_dict;
193   ui_data.FillDictionary(&ui_data_dict);
194   std::string ui_data_blob;
195   base::JSONWriter::Write(&ui_data_dict, &ui_data_blob);
196   shill_dictionary->SetStringWithoutPathExpansion(shill::kUIDataProperty,
197                                                   ui_data_blob);
198 }
199
200 bool CopyIdentifyingProperties(const base::DictionaryValue& service_properties,
201                                base::DictionaryValue* dest) {
202   bool success = true;
203
204   // GUID is optional.
205   CopyStringFromDictionary(service_properties, shill::kGuidProperty, dest);
206
207   std::string type;
208   service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
209   success &= !type.empty();
210   dest->SetStringWithoutPathExpansion(shill::kTypeProperty, type);
211   if (type == shill::kTypeWifi) {
212     success &= CopyStringFromDictionary(
213         service_properties, shill::kSecurityProperty, dest);
214     success &=
215         CopyStringFromDictionary(service_properties, shill::kWifiHexSsid, dest);
216     success &= CopyStringFromDictionary(
217         service_properties, shill::kModeProperty, dest);
218   } else if (type == shill::kTypeVPN) {
219     success &= CopyStringFromDictionary(
220         service_properties, shill::kNameProperty, dest);
221     // VPN Provider values are read from the "Provider" dictionary, but written
222     // with the keys "Provider.Type" and "Provider.Host".
223     const base::DictionaryValue* provider_properties = NULL;
224     if (!service_properties.GetDictionaryWithoutPathExpansion(
225              shill::kProviderProperty, &provider_properties)) {
226       NET_LOG_ERROR("CopyIdentifyingProperties", "Missing VPN provider dict");
227       return false;
228     }
229     std::string vpn_provider_type;
230     provider_properties->GetStringWithoutPathExpansion(shill::kTypeProperty,
231                                                        &vpn_provider_type);
232     success &= !vpn_provider_type.empty();
233     dest->SetStringWithoutPathExpansion(shill::kProviderTypeProperty,
234                                         vpn_provider_type);
235
236     std::string vpn_provider_host;
237     provider_properties->GetStringWithoutPathExpansion(shill::kHostProperty,
238                                                        &vpn_provider_host);
239     success &= !vpn_provider_host.empty();
240     dest->SetStringWithoutPathExpansion(shill::kProviderHostProperty,
241                                         vpn_provider_host);
242   } else if (type == shill::kTypeEthernet || type == shill::kTypeEthernetEap) {
243     // Ethernet and EthernetEAP don't have any additional identifying
244     // properties.
245   } else {
246     NOTREACHED() << "Unsupported network type " << type;
247     success = false;
248   }
249   if (!success)
250     NET_LOG_ERROR("CopyIdentifyingProperties", "Missing required properties");
251   return success;
252 }
253
254 }  // namespace shill_property_util
255
256 namespace {
257
258 const char kPatternDefault[] = "PatternDefault";
259 const char kPatternEthernet[] = "PatternEthernet";
260 const char kPatternWireless[] = "PatternWireless";
261 const char kPatternMobile[] = "PatternMobile";
262 const char kPatternNonVirtual[] = "PatternNonVirtual";
263
264 enum NetworkTypeBitFlag {
265   kNetworkTypeNone = 0,
266   kNetworkTypeEthernet = 1 << 0,
267   kNetworkTypeWifi = 1 << 1,
268   kNetworkTypeWimax = 1 << 2,
269   kNetworkTypeCellular = 1 << 3,
270   kNetworkTypeVPN = 1 << 4,
271   kNetworkTypeEthernetEap = 1 << 5
272 };
273
274 struct ShillToBitFlagEntry {
275   const char* shill_network_type;
276   NetworkTypeBitFlag bit_flag;
277 } shill_type_to_flag[] = {
278   { shill::kTypeEthernet, kNetworkTypeEthernet },
279   { shill::kTypeEthernetEap, kNetworkTypeEthernetEap },
280   { shill::kTypeWifi, kNetworkTypeWifi },
281   { shill::kTypeWimax, kNetworkTypeWimax },
282   { shill::kTypeCellular, kNetworkTypeCellular },
283   { shill::kTypeVPN, kNetworkTypeVPN }
284 };
285
286 NetworkTypeBitFlag ShillNetworkTypeToFlag(const std::string& shill_type) {
287   for (size_t i = 0; i < arraysize(shill_type_to_flag); ++i) {
288     if (shill_type_to_flag[i].shill_network_type == shill_type)
289       return shill_type_to_flag[i].bit_flag;
290   }
291   NET_LOG_ERROR("ShillNetworkTypeToFlag", "Unknown type: " + shill_type);
292   return kNetworkTypeNone;
293 }
294
295 }  // namespace
296
297 // static
298 NetworkTypePattern NetworkTypePattern::Default() {
299   return NetworkTypePattern(~0);
300 }
301
302 // static
303 NetworkTypePattern NetworkTypePattern::Wireless() {
304   return NetworkTypePattern(kNetworkTypeWifi | kNetworkTypeWimax |
305                             kNetworkTypeCellular);
306 }
307
308 // static
309 NetworkTypePattern NetworkTypePattern::Mobile() {
310   return NetworkTypePattern(kNetworkTypeCellular | kNetworkTypeWimax);
311 }
312
313 // static
314 NetworkTypePattern NetworkTypePattern::NonVirtual() {
315   return NetworkTypePattern(~kNetworkTypeVPN);
316 }
317
318 // static
319 NetworkTypePattern NetworkTypePattern::Ethernet() {
320   return NetworkTypePattern(kNetworkTypeEthernet);
321 }
322
323 // static
324 NetworkTypePattern NetworkTypePattern::WiFi() {
325   return NetworkTypePattern(kNetworkTypeWifi);
326 }
327
328 // static
329 NetworkTypePattern NetworkTypePattern::Cellular() {
330   return NetworkTypePattern(kNetworkTypeCellular);
331 }
332
333 // static
334 NetworkTypePattern NetworkTypePattern::VPN() {
335   return NetworkTypePattern(kNetworkTypeVPN);
336 }
337
338 // static
339 NetworkTypePattern NetworkTypePattern::Wimax() {
340   return NetworkTypePattern(kNetworkTypeWimax);
341 }
342
343 // static
344 NetworkTypePattern NetworkTypePattern::Primitive(
345     const std::string& shill_network_type) {
346   return NetworkTypePattern(ShillNetworkTypeToFlag(shill_network_type));
347 }
348
349 bool NetworkTypePattern::Equals(const NetworkTypePattern& other) const {
350   return pattern_ == other.pattern_;
351 }
352
353 bool NetworkTypePattern::MatchesType(
354     const std::string& shill_network_type) const {
355   return MatchesPattern(Primitive(shill_network_type));
356 }
357
358 bool NetworkTypePattern::MatchesPattern(
359     const NetworkTypePattern& other_pattern) const {
360   if (Equals(other_pattern))
361     return true;
362
363   return pattern_ & other_pattern.pattern_;
364 }
365
366 std::string NetworkTypePattern::ToDebugString() const {
367   if (Equals(Default()))
368     return kPatternDefault;
369   if (Equals(Ethernet()))
370     return kPatternEthernet;
371   if (Equals(Wireless()))
372     return kPatternWireless;
373   if (Equals(Mobile()))
374     return kPatternMobile;
375   if (Equals(NonVirtual()))
376     return kPatternNonVirtual;
377
378   std::string str;
379   for (size_t i = 0; i < arraysize(shill_type_to_flag); ++i) {
380     if (!(pattern_ & shill_type_to_flag[i].bit_flag))
381       continue;
382     if (!str.empty())
383       str += "|";
384     str += shill_type_to_flag[i].shill_network_type;
385   }
386   return str;
387 }
388
389 NetworkTypePattern::NetworkTypePattern(int pattern) : pattern_(pattern) {}
390
391 }  // namespace chromeos