| // Copyright 2015 The Weave Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "src/privet/wifi_ssid_generator.h" | 
 |  | 
 | #include <bitset> | 
 |  | 
 | #include <base/bind.h> | 
 | #include <base/rand_util.h> | 
 | #include <base/strings/string_number_conversions.h> | 
 | #include <base/strings/stringprintf.h> | 
 |  | 
 | #include "src/privet/cloud_delegate.h" | 
 | #include "src/privet/device_delegate.h" | 
 | #include "src/privet/wifi_delegate.h" | 
 |  | 
 | namespace weave { | 
 | namespace privet { | 
 |  | 
 | namespace { | 
 |  | 
 | const int kDeviceNameSize = 20; | 
 | // [DeviceName+Idx <= 20].[modelID == 5][flags == 2]prv | 
 | const char kSsidFormat[] = "%s %s.%5.5s%2.2sprv"; | 
 |  | 
 | const char base64chars[] = | 
 |     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 
 |  | 
 | bool IsSetupNeeded(const ConnectionState& state) { | 
 |   if (state.error()) | 
 |     return true; | 
 |   switch (state.status()) { | 
 |     case ConnectionState::kUnconfigured: | 
 |       return true; | 
 |     case ConnectionState::kDisabled: | 
 |     case ConnectionState::kConnecting: | 
 |     case ConnectionState::kOnline: | 
 |     case ConnectionState::kOffline: | 
 |       return false; | 
 |   } | 
 |   CHECK(false); | 
 |   return false; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | WifiSsidGenerator::WifiSsidGenerator(const CloudDelegate* cloud, | 
 |                                      const WifiDelegate* wifi) | 
 |     : gcd_(cloud), wifi_(wifi), get_random_(base::Bind(&base::RandInt, 0, 99)) { | 
 |   CHECK(gcd_); | 
 | } | 
 |  | 
 | std::string WifiSsidGenerator::GenerateFlags() const { | 
 |   return GenerateFlagsInternal(false); | 
 | } | 
 |  | 
 | std::string WifiSsidGenerator::GenerateFlagsInternal(bool for_ssid) const { | 
 |   std::bitset<6> flags1; | 
 |   // Device needs WiFi configuration. | 
 |   flags1[0] = wifi_ && IsSetupNeeded(wifi_->GetConnectionState()); | 
 |   // Device needs GCD registration. | 
 |   flags1[1] = IsSetupNeeded(gcd_->GetConnectionState()); | 
 |  | 
 |   std::bitset<6> flags2; | 
 |  | 
 |   // Device is discoverable over WiFi. | 
 |   flags2[0] = for_ssid || (wifi_ && !wifi_->GetHostedSsid().empty()); | 
 |  | 
 |   std::string result{2, base64chars[0]}; | 
 |   result[0] = base64chars[flags1.to_ulong()]; | 
 |   result[1] = base64chars[flags2.to_ulong()]; | 
 |   return result; | 
 | } | 
 |  | 
 | std::string WifiSsidGenerator::GenerateSsid() const { | 
 |   std::string name = gcd_->GetName(); | 
 |   std::string model_id = gcd_->GetModelId(); | 
 |   std::string idx = base::IntToString(get_random_.Run()); | 
 |   name = name.substr(0, kDeviceNameSize - idx.size() - 1); | 
 |   CHECK_EQ(5u, model_id.size()); | 
 |  | 
 |   std::string result = | 
 |       base::StringPrintf(kSsidFormat, name.c_str(), idx.c_str(), | 
 |                          model_id.c_str(), GenerateFlagsInternal(true).c_str()); | 
 |   CHECK_EQ(result[result.size() - 11], '.'); | 
 |   return result; | 
 | } | 
 |  | 
 | void WifiSsidGenerator::SetRandomForTests(int n) { | 
 |   get_random_ = base::Bind(&base::RandInt, n, n); | 
 | } | 
 |  | 
 | }  // namespace privet | 
 | }  // namespace weave |