|  | // 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 |