buffet: Move privetd sources into buffet

No functional changes, only renaming, fixed include paths and include
guards to avoid resubmit warnings.

BUG=brillo:1161
CQ-DEPEND=CL:276521
TEST=none

Change-Id: Icacff92aef47fdd46542bc96eba3ffbb4df6241a
Reviewed-on: https://chromium-review.googlesource.com/276319
Reviewed-by: Vitaly Buka <vitalybuka@chromium.org>
Commit-Queue: Vitaly Buka <vitalybuka@chromium.org>
Tested-by: Vitaly Buka <vitalybuka@chromium.org>
diff --git a/buffet/privet/wifi_bootstrap_manager.cc b/buffet/privet/wifi_bootstrap_manager.cc
new file mode 100644
index 0000000..6c2bc4f
--- /dev/null
+++ b/buffet/privet/wifi_bootstrap_manager.cc
@@ -0,0 +1,293 @@
+// Copyright 2014 The Chromium OS 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 "buffet/privet/wifi_bootstrap_manager.h"
+
+#include <base/logging.h>
+#include <base/memory/weak_ptr.h>
+#include <base/message_loop/message_loop.h>
+#include <chromeos/bind_lambda.h>
+#include <chromeos/key_value_store.h>
+
+#include "buffet/privet/ap_manager_client.h"
+#include "buffet/privet/constants.h"
+#include "buffet/privet/shill_client.h"
+
+namespace privetd {
+
+WifiBootstrapManager::WifiBootstrapManager(DaemonState* state_store,
+                                           ShillClient* shill_client,
+                                           ApManagerClient* ap_manager_client,
+                                           CloudDelegate* gcd,
+                                           uint32_t connect_timeout_seconds,
+                                           uint32_t bootstrap_timeout_seconds,
+                                           uint32_t monitor_timeout_seconds)
+    : state_store_(state_store),
+      shill_client_(shill_client),
+      ap_manager_client_(ap_manager_client),
+      ssid_generator_(gcd, this),
+      connect_timeout_seconds_(connect_timeout_seconds),
+      bootstrap_timeout_seconds_(bootstrap_timeout_seconds),
+      monitor_timeout_seconds_(monitor_timeout_seconds) {
+  cloud_observer_.Add(gcd);
+}
+
+void WifiBootstrapManager::Init() {
+  CHECK(!is_initialized_);
+  std::string ssid = ssid_generator_.GenerateSsid();
+  if (ssid.empty())
+    return;  // Delay initialization until ssid_generator_ is ready.
+  chromeos::KeyValueStore state_store;
+  if (!state_store_->GetBoolean(state_key::kWifiHasBeenBootstrapped,
+                                &have_ever_been_bootstrapped_) ||
+      !state_store_->GetString(state_key::kWifiLastConfiguredSSID,
+                               &last_configured_ssid_)) {
+    have_ever_been_bootstrapped_ = false;
+  }
+  UpdateConnectionState();
+  shill_client_->RegisterConnectivityListener(
+      base::Bind(&WifiBootstrapManager::OnConnectivityChange,
+                 lifetime_weak_factory_.GetWeakPtr()));
+  if (!have_ever_been_bootstrapped_) {
+    StartBootstrapping();
+  } else {
+    StartMonitoring();
+  }
+  is_initialized_ = true;
+}
+
+void WifiBootstrapManager::RegisterStateListener(
+    const StateListener& listener) {
+  // Notify about current state.
+  listener.Run(state_);
+  state_listeners_.push_back(listener);
+}
+
+void WifiBootstrapManager::StartBootstrapping() {
+  if (shill_client_->AmOnline()) {
+    // If one of the devices we monitor for connectivity is online, we need not
+    // start an AP.  For most devices, this is a situation which happens in
+    // testing when we have an ethernet connection.  If you need to always
+    // start an AP to bootstrap WiFi credentials, then add your WiFi interface
+    // to the device whitelist.
+    StartMonitoring();
+    return;
+  }
+
+  UpdateState(kBootstrapping);
+  if (have_ever_been_bootstrapped_) {
+    // If we have been configured before, we'd like to periodically take down
+    // our AP and find out if we can connect again.  Many kinds of failures are
+    // transient, and having an AP up prohibits us from connecting as a client.
+    base::MessageLoop::current()->PostDelayedTask(
+        FROM_HERE, base::Bind(&WifiBootstrapManager::OnBootstrapTimeout,
+                              tasks_weak_factory_.GetWeakPtr()),
+        base::TimeDelta::FromSeconds(bootstrap_timeout_seconds_));
+  }
+  // TODO(vitalybuka): Add SSID probing.
+  std::string ssid = ssid_generator_.GenerateSsid();
+  CHECK(!ssid.empty());
+  ap_manager_client_->Start(ssid);
+}
+
+void WifiBootstrapManager::EndBootstrapping() {
+  ap_manager_client_->Stop();
+}
+
+void WifiBootstrapManager::StartConnecting(const std::string& ssid,
+                                           const std::string& passphrase) {
+  VLOG(1) << "WiFi is attempting to connect. (ssid=" << ssid
+          << ", pass=" << passphrase << ").";
+  UpdateState(kConnecting);
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE, base::Bind(&WifiBootstrapManager::OnConnectTimeout,
+                            tasks_weak_factory_.GetWeakPtr()),
+      base::TimeDelta::FromSeconds(connect_timeout_seconds_));
+  shill_client_->ConnectToService(
+      ssid, passphrase, base::Bind(&WifiBootstrapManager::OnConnectSuccess,
+                                   tasks_weak_factory_.GetWeakPtr(), ssid),
+      nullptr);
+}
+
+void WifiBootstrapManager::EndConnecting() {
+}
+
+void WifiBootstrapManager::StartMonitoring() {
+  VLOG(1) << "Monitoring connectivity.";
+  // We already have a callback in place with |shill_client_| to update our
+  // connectivity state.  See OnConnectivityChange().
+  UpdateState(kMonitoring);
+}
+
+void WifiBootstrapManager::EndMonitoring() {
+}
+
+void WifiBootstrapManager::UpdateState(State new_state) {
+  VLOG(3) << "Switching state from " << state_ << " to " << new_state;
+  // Abort irrelevant tasks.
+  tasks_weak_factory_.InvalidateWeakPtrs();
+
+  switch (state_) {
+    case kDisabled:
+      break;
+    case kBootstrapping:
+      EndBootstrapping();
+      break;
+    case kMonitoring:
+      EndMonitoring();
+      break;
+    case kConnecting:
+      EndConnecting();
+      break;
+  }
+
+  if (new_state != state_) {
+    state_ = new_state;
+    // Post with weak ptr to avoid notification after this object destroyed.
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE, base::Bind(&WifiBootstrapManager::NotifyStateListeners,
+                              lifetime_weak_factory_.GetWeakPtr(), new_state));
+  } else {
+    VLOG(3) << "Not notifying listeners of state change, "
+            << "because the states are the same.";
+  }
+}
+
+void WifiBootstrapManager::NotifyStateListeners(State new_state) const {
+  for (const StateListener& listener : state_listeners_)
+    listener.Run(new_state);
+}
+
+const ConnectionState& WifiBootstrapManager::GetConnectionState() const {
+  return connection_state_;
+}
+
+const SetupState& WifiBootstrapManager::GetSetupState() const {
+  return setup_state_;
+}
+
+bool WifiBootstrapManager::ConfigureCredentials(const std::string& ssid,
+                                                const std::string& passphrase,
+                                                chromeos::ErrorPtr* error) {
+  setup_state_ = SetupState{SetupState::kInProgress};
+  // TODO(vitalybuka): Find more reliable way to finish request or move delay
+  // into PrivetHandler as it's very HTTP specific.
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE, base::Bind(&WifiBootstrapManager::StartConnecting,
+                            tasks_weak_factory_.GetWeakPtr(), ssid, passphrase),
+      base::TimeDelta::FromSeconds(kSetupDelaySeconds));
+  return true;
+}
+
+std::string WifiBootstrapManager::GetCurrentlyConnectedSsid() const {
+  // TODO(vitalybuka): Get from shill, if possible.
+  return last_configured_ssid_;
+}
+
+std::string WifiBootstrapManager::GetHostedSsid() const {
+  return ap_manager_client_->GetSsid();
+}
+
+std::set<WifiType> WifiBootstrapManager::GetTypes() const {
+  // TODO(wiley) This should do some system work to figure this out.
+  return {WifiType::kWifi24};
+}
+
+void WifiBootstrapManager::OnDeviceInfoChanged() {
+  // Initialization was delayed until buffet is ready.
+  if (!is_initialized_)
+    Init();
+}
+
+void WifiBootstrapManager::OnConnectSuccess(const std::string& ssid) {
+  VLOG(1) << "Wifi was connected successfully";
+  have_ever_been_bootstrapped_ = true;
+  last_configured_ssid_ = ssid;
+  state_store_->SetBoolean(state_key::kWifiHasBeenBootstrapped,
+                           have_ever_been_bootstrapped_);
+  state_store_->SetString(state_key::kWifiLastConfiguredSSID,
+                          last_configured_ssid_);
+  state_store_->Save();
+  setup_state_ = SetupState{SetupState::kSuccess};
+  StartMonitoring();
+}
+
+void WifiBootstrapManager::OnBootstrapTimeout() {
+  VLOG(1) << "Bootstrapping has timed out.";
+  StartMonitoring();
+}
+
+void WifiBootstrapManager::OnConnectTimeout() {
+  VLOG(1) << "Wifi timed out while connecting";
+  chromeos::ErrorPtr error;
+  chromeos::Error::AddTo(&error, FROM_HERE, errors::kDomain,
+                         errors::kInvalidState,
+                         "Failed to connect to provided network");
+  setup_state_ = SetupState{std::move(error)};
+  StartBootstrapping();
+}
+
+void WifiBootstrapManager::OnConnectivityChange(bool is_connected) {
+  VLOG(3) << "ConnectivityChanged: " << is_connected;
+  UpdateConnectionState();
+
+  if (state_ == kBootstrapping) {
+    StartMonitoring();
+    return;
+  }
+  if (state_ == kMonitoring) {
+    if (is_connected) {
+      tasks_weak_factory_.InvalidateWeakPtrs();
+    } else {
+      // Tasks queue may have more than one OnMonitorTimeout enqueued. The
+      // first one could be executed as it would change the state and abort the
+      // rest.
+      base::MessageLoop::current()->PostDelayedTask(
+          FROM_HERE, base::Bind(&WifiBootstrapManager::OnMonitorTimeout,
+                                tasks_weak_factory_.GetWeakPtr()),
+          base::TimeDelta::FromSeconds(monitor_timeout_seconds_));
+    }
+  }
+}
+
+void WifiBootstrapManager::OnMonitorTimeout() {
+  VLOG(1) << "Spent too long offline.  Entering bootstrap mode.";
+  // TODO(wiley) Retrieve relevant errors from shill.
+  StartBootstrapping();
+}
+
+void WifiBootstrapManager::UpdateConnectionState() {
+  connection_state_ = ConnectionState{ConnectionState::kUnconfigured};
+  if (!have_ever_been_bootstrapped_) {
+    return;
+  }
+  ServiceState service_state{shill_client_->GetConnectionState()};
+  switch (service_state) {
+    case ServiceState::kOffline:
+      connection_state_ = ConnectionState{ConnectionState::kOffline};
+      return;
+    case ServiceState::kFailure: {
+      // TODO(wiley) Pull error information from somewhere.
+      chromeos::ErrorPtr error;
+      chromeos::Error::AddTo(&error, FROM_HERE, errors::kDomain,
+                             errors::kInvalidState, "Unknown WiFi error");
+      connection_state_ = ConnectionState{std::move(error)};
+      return;
+    }
+    case ServiceState::kConnecting:
+      connection_state_ = ConnectionState{ConnectionState::kConnecting};
+      return;
+    case ServiceState::kConnected:
+      connection_state_ = ConnectionState{ConnectionState::kOnline};
+      return;
+  }
+  chromeos::ErrorPtr error;
+  chromeos::Error::AddToPrintf(
+      &error, FROM_HERE, errors::kDomain, errors::kInvalidState,
+      "Unknown state returned from ShillClient: %s",
+      ServiceStateToString(service_state).c_str());
+  connection_state_ = ConnectionState{std::move(error)};
+}
+
+}  // namespace privetd