// 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/shill_client.h"

#include <memory>
#include <set>
#include <utility>

#include <base/message_loop/message_loop.h>
#include <base/stl_util.h>
#include <brillo/any.h>
#include <brillo/errors/error.h>
#include <chromeos/dbus/service_constants.h>
#include <weave/enum_to_string.h>

#include "buffet/socket_stream.h"
#include "buffet/weave_error_conversion.h"

#ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
#include "buffet/ap_manager_client.h"
#endif  // BUFFET_USE_WIFI_BOOTSTRAPPING

using brillo::Any;
using brillo::VariantDictionary;
using dbus::ObjectPath;
using org::chromium::flimflam::DeviceProxy;
using org::chromium::flimflam::DeviceProxyInterface;
using org::chromium::flimflam::IPConfigProxy;
using org::chromium::flimflam::ServiceProxy;
using org::chromium::flimflam::ServiceProxyInterface;
using std::map;
using std::set;
using std::string;
using std::vector;
using weave::EnumToString;
using weave::provider::Network;

namespace buffet {

namespace {

const char kErrorDomain[] = "buffet";

void IgnoreDetachEvent() {}

bool GetStateForService(ServiceProxyInterface* service, string* state) {
  CHECK(service) << "|service| was nullptr in GetStateForService()";
  VariantDictionary properties;
  if (!service->GetProperties(&properties, nullptr)) {
    LOG(WARNING) << "Failed to read properties from service.";
    return false;
  }
  auto property_it = properties.find(shill::kStateProperty);
  if (property_it == properties.end()) {
    LOG(WARNING) << "No state found in service properties.";
    return false;
  }
  string new_state = property_it->second.TryGet<string>();
  if (new_state.empty()) {
    LOG(WARNING) << "Invalid state value.";
    return false;
  }
  *state = new_state;
  return true;
}

Network::State ShillServiceStateToNetworkState(const string& state) {
  // TODO(wiley) What does "unconfigured" mean in a world with multiple sets
  //             of WiFi credentials?
  // TODO(wiley) Detect disabled devices, update state appropriately.
  if (state.compare(shill::kStateOnline) == 0) {
    return Network::State::kOnline;
  }
  if ((state.compare(shill::kStateReady) == 0) ||
      (state.compare(shill::kStatePortal) == 0) ||
      (state.compare(shill::kStateAssociation) == 0) ||
      (state.compare(shill::kStateConfiguration) == 0)) {
    return Network::State::kConnecting;
  }
  if ((state.compare(shill::kStateFailure) == 0) ||
      (state.compare(shill::kStateActivationFailure) == 0)) {
    // TODO(wiley) Get error information off the service object.
    return Network::State::kError;
  }
  if ((state.compare(shill::kStateIdle) == 0) ||
      (state.compare(shill::kStateOffline) == 0) ||
      (state.compare(shill::kStateDisconnect) == 0)) {
    return Network::State::kOffline;
  }
  LOG(WARNING) << "Unknown state found: '" << state << "'";
  return Network::State::kOffline;
}

}  // namespace

ShillClient::ShillClient(const scoped_refptr<dbus::Bus>& bus,
                         const set<string>& device_whitelist, bool disable_xmpp)
    : bus_{bus},
      manager_proxy_{bus_},
      device_whitelist_{device_whitelist},
      disable_xmpp_{disable_xmpp} {
#ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
  ap_manager_client_.reset(new ApManagerClient(bus));
#endif  // BUFFET_USE_WIFI_BOOTSTRAPPING
  manager_proxy_.RegisterPropertyChangedSignalHandler(
      base::Bind(&ShillClient::OnManagerPropertyChange,
                 weak_factory_.GetWeakPtr()),
      base::Bind(&ShillClient::OnManagerPropertyChangeRegistration,
                 weak_factory_.GetWeakPtr()));
  auto owner_changed_cb = base::Bind(&ShillClient::OnShillServiceOwnerChange,
                                     weak_factory_.GetWeakPtr());
  bus_->GetObjectProxy(shill::kFlimflamServiceName, ObjectPath{"/"})
      ->SetNameOwnerChangedCallback(owner_changed_cb);
}

ShillClient::~ShillClient() {}

void ShillClient::Init() {
  VLOG(2) << "ShillClient::Init();";
  CleanupConnectingService();
  devices_.clear();
  connectivity_state_ = Network::State::kOffline;
  VariantDictionary properties;
  if (!manager_proxy_.GetProperties(&properties, nullptr)) {
    LOG(ERROR) << "Unable to get properties from Manager, waiting for "
                  "Manager to come back online.";
    return;
  }
  auto it = properties.find(shill::kDevicesProperty);
  CHECK(it != properties.end()) << "shill should always publish a device list.";
  OnManagerPropertyChange(shill::kDevicesProperty, it->second);
}

void ShillClient::Connect(const string& ssid,
                          const string& passphrase,
                          const weave::DoneCallback& callback) {
  if (connecting_service_) {
    weave::ErrorPtr error;
    weave::Error::AddTo(&error, FROM_HERE, kErrorDomain, "busy",
                        "Already connecting to WiFi network");
    base::MessageLoop::current()->PostTask(
        FROM_HERE, base::Bind(callback, base::Passed(&error)));
    return;
  }
  CleanupConnectingService();
  VariantDictionary service_properties;
  service_properties[shill::kTypeProperty] = Any{string{shill::kTypeWifi}};
  service_properties[shill::kSSIDProperty] = Any{ssid};
  if (passphrase.empty()) {
    service_properties[shill::kSecurityProperty] = Any{shill::kSecurityNone};
  } else {
    service_properties[shill::kPassphraseProperty] = Any{passphrase};
    service_properties[shill::kSecurityProperty] = Any{shill::kSecurityPsk};
  }
  service_properties[shill::kSaveCredentialsProperty] = Any{true};
  service_properties[shill::kAutoConnectProperty] = Any{true};
  ObjectPath service_path;
  brillo::ErrorPtr brillo_error;
  if (!manager_proxy_.ConfigureService(service_properties, &service_path,
                                       &brillo_error) ||
      !manager_proxy_.RequestScan(shill::kTypeWifi, &brillo_error)) {
    weave::ErrorPtr weave_error;
    ConvertError(*brillo_error, &weave_error);
    base::MessageLoop::current()->PostTask(
        FROM_HERE, base::Bind(callback, base::Passed(&weave_error)));
    return;
  }
  connecting_service_.reset(new ServiceProxy{bus_, service_path});
  connecting_service_->Connect(nullptr);
  connect_done_callback_ = callback;
  connecting_service_->RegisterPropertyChangedSignalHandler(
      base::Bind(&ShillClient::OnServicePropertyChange,
                 weak_factory_.GetWeakPtr(), service_path),
      base::Bind(&ShillClient::OnServicePropertyChangeRegistration,
                 weak_factory_.GetWeakPtr(), service_path));
  base::MessageLoop::current()->PostDelayedTask(
      FROM_HERE, base::Bind(&ShillClient::ConnectToServiceError,
                            weak_factory_.GetWeakPtr(), connecting_service_),
      base::TimeDelta::FromMinutes(1));
}

void ShillClient::ConnectToServiceError(
    std::shared_ptr<org::chromium::flimflam::ServiceProxy> connecting_service) {
  if (connecting_service != connecting_service_ ||
      connect_done_callback_.is_null()) {
    return;
  }
  std::string error = have_called_connect_ ? connecting_service_error_
                                           : shill::kErrorOutOfRange;
  if (error.empty())
    error = shill::kErrorInternal;
  OnErrorChangeForConnectingService(error);
}

Network::State ShillClient::GetConnectionState() const {
  return connectivity_state_;
}

void ShillClient::StartAccessPoint(const std::string& ssid) {
#ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
  ap_manager_client_->Start(ssid);
#endif  // BUFFET_USE_WIFI_BOOTSTRAPPING
}

void ShillClient::StopAccessPoint() {
#ifdef BUFFET_USE_WIFI_BOOTSTRAPPING
  ap_manager_client_->Stop();
#endif  // BUFFET_USE_WIFI_BOOTSTRAPPING
}

std::string ShillClient::GetIpAddress() {
  return ip_address_;
}

void ShillClient::AddConnectionChangedCallback(
    const ConnectionChangedCallback& listener) {
  connectivity_listeners_.push_back(listener);
}

bool ShillClient::IsMonitoredDevice(DeviceProxyInterface* device) {
  if (device_whitelist_.empty()) {
    return true;
  }
  VariantDictionary device_properties;
  if (!device->GetProperties(&device_properties, nullptr)) {
    LOG(ERROR) << "Devices without properties aren't whitelisted.";
    return false;
  }
  auto it = device_properties.find(shill::kInterfaceProperty);
  if (it == device_properties.end()) {
    LOG(ERROR) << "Failed to find interface property in device properties.";
    return false;
  }
  return ContainsKey(device_whitelist_, it->second.TryGet<string>());
}

void ShillClient::OnShillServiceOwnerChange(const string& old_owner,
                                            const string& new_owner) {
  VLOG(1) << "Shill service owner name changed to '" << new_owner << "'";
  if (new_owner.empty()) {
    CleanupConnectingService();
    devices_.clear();
    connectivity_state_ = Network::State::kOffline;
  } else {
    Init();  // New service owner means shill reset!
  }
}

void ShillClient::OnManagerPropertyChangeRegistration(const string& interface,
                                                      const string& signal_name,
                                                      bool success) {
  VLOG(3) << "Registered ManagerPropertyChange handler.";
  CHECK(success) << "privetd requires Manager signals.";
  VariantDictionary properties;
  if (!manager_proxy_.GetProperties(&properties, nullptr)) {
    LOG(ERROR) << "Unable to get properties from Manager, waiting for "
                  "Manager to come back online.";
    return;
  }
  auto it = properties.find(shill::kDevicesProperty);
  CHECK(it != properties.end()) << "Shill should always publish a device list.";
  OnManagerPropertyChange(shill::kDevicesProperty, it->second);
}

void ShillClient::OnManagerPropertyChange(const string& property_name,
                                          const Any& property_value) {
  if (property_name != shill::kDevicesProperty) {
    return;
  }
  VLOG(3) << "Manager's device list has changed.";
  // We're going to remove every device we haven't seen in the update.
  set<ObjectPath> device_paths_to_remove;
  for (const auto& kv : devices_) {
    device_paths_to_remove.insert(kv.first);
  }
  for (const auto& device_path : property_value.TryGet<vector<ObjectPath>>()) {
    if (!device_path.IsValid()) {
      LOG(ERROR) << "Ignoring invalid device path in Manager's device list.";
      return;
    }
    auto it = devices_.find(device_path);
    if (it != devices_.end()) {
      // Found an existing proxy.  Since the whitelist never changes,
      // this still a valid device.
      device_paths_to_remove.erase(device_path);
      continue;
    }
    std::unique_ptr<DeviceProxy> device{new DeviceProxy{bus_, device_path}};
    if (!IsMonitoredDevice(device.get())) {
      continue;
    }
    VLOG(3) << "Creating device proxy at " << device_path.value();
    devices_[device_path].device = std::move(device);
    // Register after adding to devices list as registration callback will be
    // invoked directly.
    devices_[device_path].device->RegisterPropertyChangedSignalHandler(
        base::Bind(&ShillClient::OnDevicePropertyChange,
                   weak_factory_.GetWeakPtr(), device_path),
        base::Bind(&ShillClient::OnDevicePropertyChangeRegistration,
                   weak_factory_.GetWeakPtr(), device_path));
  }

  // Clean up devices/services related to removed devices.
  if (!device_paths_to_remove.empty()) {
    for (const ObjectPath& device_path : device_paths_to_remove) {
      devices_.erase(device_path);
    }
    UpdateConnectivityState();
  }
}

void ShillClient::OnDevicePropertyChangeRegistration(
    const ObjectPath& device_path,
    const string& interface,
    const string& signal_name,
    bool success) {
  VLOG(3) << "Registered DevicePropertyChange handler.";
  auto it = devices_.find(device_path);
  if (it == devices_.end()) {
    return;
  }
  CHECK(success) << "Failed to subscribe to Device property changes.";
  DeviceProxyInterface* device = it->second.device.get();
  VariantDictionary properties;
  if (!device->GetProperties(&properties, nullptr)) {
    LOG(WARNING) << "Failed to get device properties?";
    return;
  }
  auto prop_it = properties.find(shill::kSelectedServiceProperty);
  if (prop_it == properties.end()) {
    LOG(WARNING) << "Failed to get device's selected service?";
    return;
  }
  OnDevicePropertyChange(device_path, shill::kSelectedServiceProperty,
                         prop_it->second);
}

void ShillClient::OnDevicePropertyChange(const ObjectPath& device_path,
                                         const string& property_name,
                                         const Any& property_value) {
  // We only care about selected services anyway.
  if (property_name != shill::kSelectedServiceProperty) {
    return;
  }
  // If the device isn't our list of whitelisted devices, ignore it.
  auto it = devices_.find(device_path);
  if (it == devices_.end()) {
    return;
  }
  DeviceState& device_state = it->second;
  ObjectPath service_path{property_value.TryGet<ObjectPath>()};
  if (!service_path.IsValid()) {
    LOG(ERROR) << "Device at " << device_path.value()
               << " selected invalid service path.";
    return;
  }
  VLOG(3) << "Device at " << it->first.value() << " has selected service at "
          << service_path.value();
  bool removed_old_service{false};
  if (device_state.selected_service) {
    if (device_state.selected_service->GetObjectPath() == service_path) {
      return;  // Spurious update?
    }
    device_state.selected_service.reset();
    device_state.service_state = Network::State::kOffline;
    removed_old_service = true;
  }
  std::shared_ptr<ServiceProxy> new_service;
  const bool reuse_connecting_service =
      service_path.value() != "/" && connecting_service_ &&
      connecting_service_->GetObjectPath() == service_path;
  bool register_service = false;
  if (reuse_connecting_service) {
    new_service = connecting_service_;
    // When we reuse the connecting service, we need to make sure that our
    // cached state is correct.  Normally, we do this by relying reading the
    // state when our signal handlers finish registering, but this may have
    // happened long in the past for the connecting service.
    string state;
    if (GetStateForService(new_service.get(), &state)) {
      device_state.service_state = ShillServiceStateToNetworkState(state);
    } else {
      LOG(WARNING) << "Failed to read properties from existing service "
                      "on selection.";
    }
  } else if (service_path.value() != "/") {
    // The device has selected a new service we haven't see before.
    new_service.reset(new ServiceProxy{bus_, service_path});
    register_service = true;
  }
  device_state.selected_service = new_service;
  if (reuse_connecting_service || removed_old_service) {
    UpdateConnectivityState();
  }
  if (register_service) {
    // Register after setting selected_service as registration callback will be
    // invoked directly.
    new_service->RegisterPropertyChangedSignalHandler(
        base::Bind(&ShillClient::OnServicePropertyChange,
                   weak_factory_.GetWeakPtr(), service_path),
        base::Bind(&ShillClient::OnServicePropertyChangeRegistration,
                   weak_factory_.GetWeakPtr(), service_path));
  }
}

void ShillClient::OnServicePropertyChangeRegistration(const ObjectPath& path,
                                                      const string& interface,
                                                      const string& signal_name,
                                                      bool success) {
  VLOG(3) << "OnServicePropertyChangeRegistration(" << path.value() << ");";
  ServiceProxy* service{nullptr};
  if (connecting_service_ && connecting_service_->GetObjectPath() == path) {
    // Note that the connecting service might also be a selected service.
    service = connecting_service_.get();
    if (!success)
      CleanupConnectingService();
  } else {
    for (const auto& kv : devices_) {
      if (kv.second.selected_service &&
          kv.second.selected_service->GetObjectPath() == path) {
        service = kv.second.selected_service.get();
        break;
      }
    }
  }
  if (service == nullptr || !success) {
    return;  // A failure or success for a proxy we no longer care about.
  }
  VariantDictionary properties;
  if (!service->GetProperties(&properties, nullptr)) {
    return;
  }
  // Give ourselves property changed signals for the initial property
  // values.
  for (auto name : {shill::kStateProperty, shill::kSignalStrengthProperty,
                    shill::kErrorProperty, shill::kIPConfigProperty}) {
    auto it = properties.find(name);
    if (it != properties.end())
      OnServicePropertyChange(path, name, it->second);
  }
}

void ShillClient::OnServicePropertyChange(const ObjectPath& service_path,
                                          const string& property_name,
                                          const Any& property_value) {
  VLOG(3) << "ServicePropertyChange(" << service_path.value() << ", "
          << property_name << ", ...);";

  bool is_connecting_service =
      connecting_service_ &&
      connecting_service_->GetObjectPath() == service_path;
  if (property_name == shill::kStateProperty) {
    const string state{property_value.TryGet<string>()};
    if (state.empty()) {
      VLOG(3) << "Invalid service state update.";
      return;
    }
    VLOG(3) << "New service state=" << state;
    OnStateChangeForSelectedService(service_path, state);
    if (is_connecting_service)
      OnStateChangeForConnectingService(state);
  } else if (property_name == shill::kSignalStrengthProperty) {
    VLOG(3) << "Signal strength=" << property_value.TryGet<uint8_t>();
    if (is_connecting_service)
      OnStrengthChangeForConnectingService(property_value.TryGet<uint8_t>());
  } else if (property_name == shill::kErrorProperty) {
    VLOG(3) << "Error=" << property_value.TryGet<std::string>();
    if (is_connecting_service)
      connecting_service_error_ = property_value.TryGet<std::string>();
  } else if (property_name == shill::kIPConfigProperty) {
    string device_path;
    for (const auto& kv : devices_) {
      if (kv.second.selected_service &&
          kv.second.selected_service->GetObjectPath() == service_path) {
        device_path = kv.first.value();
        break;
      }
    }
    OnIpConfigChange(property_value.TryGet<ObjectPath>(), device_path);
  }
}

void ShillClient::OnIpConfigChange(const ObjectPath& ip_config_path,
                                   const string& device_path) {
  IPConfigProxy ip_config(bus_.get(), ip_config_path);
  VariantDictionary properties;
  if (!ip_config.GetProperties(&properties, nullptr)) {
    LOG(WARNING) << "Failed to read properties from ipconfig.";
    return;
  }
  const auto it = properties.find(shill::kAddressProperty);
  if (it != properties.end()) {
    ip_address_ = it->second.TryGet<string>();
    LOG(INFO) << "IPConfigProperty address = " << ip_address_
              << " at " << device_path;
    base::MessageLoop::current()->PostTask(
        FROM_HERE, base::Bind(&ShillClient::NotifyConnectivityListeners,
                          weak_factory_.GetWeakPtr(),
                          GetConnectionState() == Network::State::kOnline));
  }
}

void ShillClient::OnStateChangeForConnectingService(const string& state) {
  switch (ShillServiceStateToNetworkState(state)) {
    case Network::State::kOnline: {
      auto callback = connect_done_callback_;
      connect_done_callback_.Reset();
      CleanupConnectingService();

      if (!callback.is_null())
        callback.Run(nullptr);
      break;
    }
    case Network::State::kError: {
      ConnectToServiceError(connecting_service_);
      break;
    }
    case Network::State::kOffline:
    case Network::State::kConnecting:
      break;
  }
}

void ShillClient::OnErrorChangeForConnectingService(const std::string& error) {
  if (error.empty())
    return;

  auto callback = connect_done_callback_;
  CleanupConnectingService();

  weave::ErrorPtr weave_error;
  weave::Error::AddTo(&weave_error, FROM_HERE, kErrorDomain, error,
                      "Failed to connect to WiFi network");

  if (!callback.is_null())
    callback.Run(std::move(weave_error));
}

void ShillClient::OnStrengthChangeForConnectingService(
    uint8_t signal_strength) {
  if (signal_strength == 0 || have_called_connect_) {
    return;
  }
  VLOG(1) << "Connecting service has signal. Calling Connect().";
  have_called_connect_ = true;
  // Failures here indicate that we've already connected,
  // or are connecting, or some other very unexciting thing.
  // Ignore all that, and rely on state changes to detect
  // connectivity.
  connecting_service_->Connect(nullptr);
}

void ShillClient::OnStateChangeForSelectedService(
    const ObjectPath& service_path,
    const string& state) {
  // Find the device/service pair responsible for this update
  VLOG(3) << "State for potentially selected service " << service_path.value()
          << " have changed to " << state;
  for (auto& kv : devices_) {
    if (kv.second.selected_service &&
        kv.second.selected_service->GetObjectPath() == service_path) {
      VLOG(3) << "Updated cached connection state for selected service.";
      kv.second.service_state = ShillServiceStateToNetworkState(state);
      UpdateConnectivityState();
      return;
    }
  }
}

void ShillClient::UpdateConnectivityState() {
  // Update the connectivity state of the device by picking the
  // state of the currently most connected selected service.
  Network::State new_connectivity_state{Network::State::kOffline};
  for (const auto& kv : devices_) {
    if (kv.second.service_state > new_connectivity_state) {
      new_connectivity_state = kv.second.service_state;
    }
  }
  VLOG(1) << "Connectivity changed: " << EnumToString(connectivity_state_)
          << " -> " << EnumToString(new_connectivity_state);
  // Notify listeners even if state changed to the same value. Listeners may
  // want to handle this event.
  connectivity_state_ = new_connectivity_state;
  // We may call UpdateConnectivityState whenever we mutate a data structure
  // such that our connectivity status could change.  However, we don't want
  // to allow people to call into ShillClient while some other operation is
  // underway.  Therefore, call our callbacks later, when we're in a good
  // state.
  base::MessageLoop::current()->PostTask(
      FROM_HERE, base::Bind(&ShillClient::NotifyConnectivityListeners,
                            weak_factory_.GetWeakPtr(),
                            GetConnectionState() == Network::State::kOnline));
}

void ShillClient::NotifyConnectivityListeners(bool am_online) {
  VLOG(3) << "Notifying connectivity listeners that online=" << am_online;
  for (const auto& listener : connectivity_listeners_)
    listener.Run();
}

void ShillClient::CleanupConnectingService() {
  if (connecting_service_) {
    connecting_service_->ReleaseObjectProxy(base::Bind(&IgnoreDetachEvent));
    connecting_service_.reset();
  }
  connect_done_callback_.Reset();
  have_called_connect_ = false;
}

void ShillClient::OpenSslSocket(const std::string& host,
                                uint16_t port,
                                const OpenSslSocketCallback& callback) {
  if (disable_xmpp_)
    return;
  std::unique_ptr<weave::Stream> raw_stream{
      SocketStream::ConnectBlocking(host, port)};
  if (!raw_stream) {
    brillo::ErrorPtr error;
    brillo::errors::system::AddSystemError(&error, FROM_HERE, errno);
    weave::ErrorPtr weave_error;
    ConvertError(*error.get(), &weave_error);
    base::MessageLoop::current()->PostTask(
        FROM_HERE, base::Bind(callback, nullptr, base::Passed(&weave_error)));
    return;
  }

  SocketStream::TlsConnect(std::move(raw_stream), host, callback);
}

}  // namespace buffet
