buffet: Start privet logic

Initialize privetd::Manager from buffet::Manager.
Added flag disable_privet to disable local APIs.
CloudDelegate still uses D-Bus to communicate with buffet.

BUG=brillo:1161
TEST=`FEATURES=test emerge-gizmo buffet`

Change-Id: Ic5d687f0e45d9be3c487a2f2b2de354f4b437441
Reviewed-on: https://chromium-review.googlesource.com/276602
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
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/etc/init/buffet.conf b/buffet/etc/init/buffet.conf
index ba4adb2..bd273c1 100644
--- a/buffet/etc/init/buffet.conf
+++ b/buffet/etc/init/buffet.conf
@@ -14,6 +14,10 @@
 env BUFFET_STATE_PATH=
 env BUFFET_CONFIG_PATH=
 env BUFFET_TEST_DEFINITIONS_PATH=
+env BUFFET_ENABLE_PING=false
+env BUFFET_DISABLE_SECURITY=false
+env BUFFET_DEVICE_WHITELIST=
+env BUFFET_DISABLE_PRIVET=false
 
 pre-start script
   mkdir -m 0755 -p /var/lib/buffet
@@ -28,7 +32,11 @@
     --config_path="${BUFFET_CONFIG_PATH}" \
     --state_path="${BUFFET_STATE_PATH}" \
     --test_definitions_path="${BUFFET_TEST_DEFINITIONS_PATH}" \
-    --enable_xmpp="${BUFFET_ENABLE_XMPP}"
+    --enable_xmpp="${BUFFET_ENABLE_XMPP}" \
+    --disable_security="${BUFFET_DISABLE_SECURITY}" \
+    --enable_ping="${BUFFET_ENABLE_PING}" \
+    --device_whitelist="${BUFFET_DEVICE_WHITELIST}" \
+    --disable_privet="${BUFFET_DISABLE_PRIVET}"
 
 # Wait for daemon to claim its D-Bus name before transitioning to started.
 post-start exec gdbus wait --system --timeout 30 org.chromium.Buffet
diff --git a/buffet/main.cc b/buffet/main.cc
index c7d44d0..3971abb 100644
--- a/buffet/main.cc
+++ b/buffet/main.cc
@@ -9,6 +9,7 @@
 #include <chromeos/dbus/exported_object_manager.h>
 #include <chromeos/daemons/dbus_daemon.h>
 #include <chromeos/flag_helper.h>
+#include <chromeos/strings/string_utils.h>
 #include <chromeos/syslog_logging.h>
 
 #include "buffet/dbus_constants.h"
@@ -23,31 +24,20 @@
 
 class Daemon final : public DBusServiceDaemon {
  public:
-  Daemon(const base::FilePath& config_path,
-         const base::FilePath& state_path,
-         const base::FilePath& test_definitions_path,
-         bool enable_xmpp)
-      : DBusServiceDaemon(kServiceName, kRootServicePath),
-        config_path_{config_path},
-        state_path_{state_path},
-        test_definitions_path_{test_definitions_path},
-        enable_xmpp_{enable_xmpp} {}
+  explicit Daemon(const buffet::Manager::Options& options)
+      : DBusServiceDaemon(kServiceName, kRootServicePath), options_{options} {}
 
  protected:
   void RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) override {
     manager_.reset(new buffet::Manager(object_manager_->AsWeakPtr()));
-    manager_->Start(
-        config_path_, state_path_, test_definitions_path_, enable_xmpp_,
-        sequencer->GetHandler("Manager.RegisterAsync() failed.", true));
+    manager_->Start(options_, sequencer);
   }
 
- private:
-  std::unique_ptr<buffet::Manager> manager_;
-  const base::FilePath config_path_;
-  const base::FilePath state_path_;
-  const base::FilePath test_definitions_path_;
-  const bool enable_xmpp_;
+  void OnShutdown(int* return_code) override { manager_->Stop(); }
 
+ private:
+  buffet::Manager::Options options_;
+  std::unique_ptr<buffet::Manager> manager_;
   DISALLOW_COPY_AND_ASSIGN(Daemon);
 };
 
@@ -71,6 +61,12 @@
                 "and state definitions.  For use in test only.");
   DEFINE_bool(enable_xmpp, true,
               "Connect to GCD via a persistent XMPP connection.");
+  DEFINE_bool(disable_privet, false, "disable Privet protocol");
+  DEFINE_bool(disable_security, false, "disable Privet security for tests");
+  DEFINE_bool(enable_ping, false, "enable test HTTP handler at /privet/ping");
+  DEFINE_string(device_whitelist, "",
+                "Comma separated list of network interfaces to monitor for "
+                "connectivity (an empty list enables all interfaces).");
   chromeos::FlagHelper::Init(argc, argv, "Privet protocol handler daemon");
   if (FLAGS_config_path.empty())
     FLAGS_config_path = kDefaultConfigFilePath;
@@ -81,9 +77,20 @@
     flags |= chromeos::kLogToStderr;
   chromeos::InitLog(flags);
 
-  buffet::Daemon daemon{base::FilePath{FLAGS_config_path},
-                        base::FilePath{FLAGS_state_path},
-                        base::FilePath{FLAGS_test_definitions_path},
-                        FLAGS_enable_xmpp};
+  auto device_whitelist =
+      chromeos::string_utils::Split(FLAGS_device_whitelist, ",", true, true);
+
+  buffet::Manager::Options options;
+  options.config_path = base::FilePath{FLAGS_config_path};
+  options.state_path = base::FilePath{FLAGS_state_path};
+  options.test_definitions_path = base::FilePath{FLAGS_test_definitions_path};
+  options.xmpp_enabled = FLAGS_enable_xmpp;
+  options.privet.disable_privet = FLAGS_disable_privet;
+  options.privet.disable_security = FLAGS_disable_security;
+  options.privet.enable_ping = FLAGS_enable_ping;
+  options.privet.device_whitelist.insert(device_whitelist.begin(),
+                                         device_whitelist.end());
+
+  buffet::Daemon daemon{options};
   return daemon.Run();
 }
diff --git a/buffet/manager.cc b/buffet/manager.cc
index 5b6a6e5..d9ddfaf 100644
--- a/buffet/manager.cc
+++ b/buffet/manager.cc
@@ -59,27 +59,23 @@
 Manager::~Manager() {
 }
 
-void Manager::Start(const base::FilePath& config_path,
-                    const base::FilePath& state_path,
-                    const base::FilePath& test_definitions_path,
-                    bool xmpp_enabled,
-                    const AsyncEventSequencer::CompletionAction& cb) {
+void Manager::Start(const Options& options, AsyncEventSequencer* sequencer) {
   command_manager_ =
       std::make_shared<CommandManager>(dbus_object_.GetObjectManager());
   command_manager_->AddOnCommandDefChanged(base::Bind(
       &Manager::OnCommandDefsChanged, weak_ptr_factory_.GetWeakPtr()));
   command_manager_->Startup(base::FilePath{"/etc/buffet"},
-                            test_definitions_path);
+                            options.test_definitions_path);
   state_change_queue_.reset(new StateChangeQueue(kMaxStateChangeQueueSize));
   state_manager_ = std::make_shared<StateManager>(state_change_queue_.get());
   state_manager_->AddOnChangedCallback(
       base::Bind(&Manager::OnStateChanged, weak_ptr_factory_.GetWeakPtr()));
   state_manager_->Startup();
 
-  std::unique_ptr<BuffetConfig> config{new BuffetConfig{state_path}};
+  std::unique_ptr<BuffetConfig> config{new BuffetConfig{options.state_path}};
   config->AddOnChangedCallback(
       base::Bind(&Manager::OnConfigChanged, weak_ptr_factory_.GetWeakPtr()));
-  config->Load(config_path);
+  config->Load(options.config_path);
 
   auto transport = chromeos::http::Transport::CreateDefault();
   transport->SetDefaultTimeout(base::TimeDelta::FromSeconds(
@@ -89,7 +85,7 @@
   // device info state data unencrypted.
   device_info_.reset(new DeviceRegistrationInfo(
       command_manager_, state_manager_, std::move(config), transport,
-      xmpp_enabled));
+      options.xmpp_enabled));
   device_info_->AddOnRegistrationChangedCallback(base::Bind(
       &Manager::OnRegistrationChanged, weak_ptr_factory_.GetWeakPtr()));
 
@@ -97,8 +93,36 @@
       device_info_->AsWeakPtr(), state_manager_, command_manager_});
 
   device_info_->Start();
+
   dbus_adaptor_.RegisterWithDBusObject(&dbus_object_);
-  dbus_object_.RegisterAsync(cb);
+  dbus_object_.RegisterAsync(
+      sequencer->GetHandler("Manager.RegisterAsync() failed.", true));
+
+  if (!options.privet.disable_privet)
+    StartPrivet(options.privet, sequencer);
+}
+
+void Manager::StartPrivet(const privetd::Manager::Options& options,
+                          AsyncEventSequencer* sequencer) {
+  privet_.reset(new privetd::Manager{});
+  privet_->Start(options, dbus_object_.GetBus(), sequencer);
+
+  if (privet_->GetWifiBootstrapManager()) {
+    privet_->GetWifiBootstrapManager()->RegisterStateListener(base::Bind(
+        &Manager::UpdateWiFiBootstrapState, weak_ptr_factory_.GetWeakPtr()));
+  } else {
+    UpdateWiFiBootstrapState(privetd::WifiBootstrapManager::kDisabled);
+  }
+
+  privet_->GetSecurityManager()->RegisterPairingListeners(
+      base::Bind(&Manager::OnPairingStart, weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&Manager::OnPairingEnd, weak_ptr_factory_.GetWeakPtr()));
+  // TODO(wiley) Watch for appropriate state variables from |cloud_delegate|.
+}
+
+void Manager::Stop() {
+  if (privet_)
+    privet_->OnShutdown();
 }
 
 void Manager::CheckDeviceRegistered(DBusMethodResponse<std::string> response) {
diff --git a/buffet/manager.h b/buffet/manager.h
index 781fa03..2f8fd66 100644
--- a/buffet/manager.h
+++ b/buffet/manager.h
@@ -52,12 +52,18 @@
           object_manager);
   ~Manager();
 
-  void Start(
-      const base::FilePath& config_path,
-      const base::FilePath& state_path,
-      const base::FilePath& test_definitions_path,
-      bool xmpp_enabled,
-      const chromeos::dbus_utils::AsyncEventSequencer::CompletionAction& cb);
+  struct Options {
+    base::FilePath config_path;
+    base::FilePath state_path;
+    base::FilePath test_definitions_path;
+    bool xmpp_enabled{true};
+    privetd::Manager::Options privet;
+  };
+
+  void Start(const Options& options,
+             chromeos::dbus_utils::AsyncEventSequencer* sequencer);
+
+  void Stop();
 
  private:
   // DBus methods:
@@ -99,6 +105,9 @@
       const chromeos::VariantDictionary& in_options) override;
   bool DisableGCDBootstrapping(chromeos::ErrorPtr* error) override;
 
+  void StartPrivet(const privetd::Manager::Options& options,
+                   chromeos::dbus_utils::AsyncEventSequencer* sequencer);
+
   void OnCommandDefsChanged();
   void OnStateChanged();
   void OnRegistrationChanged(RegistrationStatus status);
@@ -117,6 +126,7 @@
   std::shared_ptr<StateManager> state_manager_;
   std::unique_ptr<DeviceRegistrationInfo> device_info_;
   std::unique_ptr<BaseApiHandler> base_api_handler_;
+  std::unique_ptr<privetd::Manager> privet_;
 
   base::WeakPtrFactory<Manager> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(Manager);
diff --git a/buffet/privet/cloud_delegate.cc b/buffet/privet/cloud_delegate.cc
index 5003c9d..653bf5d 100644
--- a/buffet/privet/cloud_delegate.cc
+++ b/buffet/privet/cloud_delegate.cc
@@ -509,8 +509,10 @@
 
 // static
 std::unique_ptr<CloudDelegate> CloudDelegate::CreateDefault(
-    const scoped_refptr<dbus::Bus>& bus,
     bool is_gcd_setup_enabled) {
+  dbus::Bus::Options options;
+  options.bus_type = dbus::Bus::SYSTEM;
+  scoped_refptr<dbus::Bus> bus{new dbus::Bus{options}};
   return std::unique_ptr<CloudDelegateImpl>{
       new CloudDelegateImpl{bus, is_gcd_setup_enabled}};
 }
diff --git a/buffet/privet/cloud_delegate.h b/buffet/privet/cloud_delegate.h
index 0d027f9..75d0a63 100644
--- a/buffet/privet/cloud_delegate.h
+++ b/buffet/privet/cloud_delegate.h
@@ -131,7 +131,6 @@
 
   // Create default instance.
   static std::unique_ptr<CloudDelegate> CreateDefault(
-      const scoped_refptr<dbus::Bus>& bus,
       bool is_gcd_setup_enabled);
 
  private:
diff --git a/buffet/privet/privet_manager.cc b/buffet/privet/privet_manager.cc
index 36aaa7e..1471404 100644
--- a/buffet/privet/privet_manager.cc
+++ b/buffet/privet/privet_manager.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <set>
 #include <string>
-#include <sysexits.h>
 
 #include <base/bind.h>
 #include <base/command_line.h>
@@ -39,6 +38,7 @@
 #include "buffet/privet/security_manager.h"
 #include "buffet/privet/shill_client.h"
 #include "buffet/privet/wifi_bootstrap_manager.h"
+#include "buffet/dbus_constants.h"
 
 namespace privetd {
 
@@ -57,59 +57,60 @@
   return headers.empty() ? std::string() : headers.front();
 }
 
-const char kServiceName[] = "org.chromium.privetd";
-const char kRootPath[] = "/org/chromium/privetd";
-
 }  // namespace
 
-Manager::Manager(bool disable_security,
-                 bool enable_ping,
-                 const std::set<std::string>& device_whitelist,
-                 const base::FilePath& config_path,
-                 const base::FilePath& state_path)
-    : DBusServiceDaemon(kServiceName, kRootPath),
-      disable_security_(disable_security),
-      enable_ping_(enable_ping),
-      device_whitelist_(device_whitelist),
-      config_path_(config_path),
-      state_store_(new DaemonState(state_path)) {
+Manager::Manager() {
 }
 
-void Manager::RegisterDBusObjectsAsync(AsyncEventSequencer* sequencer) {
+Manager::~Manager() {
+}
+
+void Manager::Start(const Options& options,
+                    const scoped_refptr<dbus::Bus>& bus,
+                    AsyncEventSequencer* sequencer) {
+  disable_security_ = options.disable_security;
+
+  // TODO(vitalybuka): switch to BuffetConfig.
+  base::FilePath config_path{privetd::kDefaultConfigFilePath};
+  base::FilePath state_path{privetd::kDefaultStateFilePath};
+
+  state_store_.reset(new DaemonState(state_path));
   parser_.reset(new PrivetdConfigParser);
 
   chromeos::KeyValueStore config_store;
-  if (!config_store.Load(config_path_)) {
+  if (!config_store.Load(config_path)) {
     LOG(ERROR) << "Failed to read privetd config file from "
-               << config_path_.value();
+               << config_path.value();
   } else {
     CHECK(parser_->Parse(config_store)) << "Failed to read configuration file.";
   }
   state_store_->Init();
+
+  std::set<std::string> device_whitelist{options.device_whitelist};
   // This state store key doesn't exist naturally, but developers
   // sometime put it in their state store to cause the device to bring
   // up WiFi bootstrapping while being connected to an ethernet interface.
   std::string test_device_whitelist;
-  if (device_whitelist_.empty() &&
+  if (device_whitelist.empty() &&
       state_store_->GetString(kWiFiBootstrapInterfaces,
                               &test_device_whitelist)) {
     auto interfaces =
         chromeos::string_utils::Split(test_device_whitelist, ",", true, true);
-    device_whitelist_.insert(interfaces.begin(), interfaces.end());
+    device_whitelist.insert(interfaces.begin(), interfaces.end());
   }
   device_ = DeviceDelegate::CreateDefault();
-  cloud_ = CloudDelegate::CreateDefault(
-      bus_, parser_->gcd_bootstrap_mode() != GcdBootstrapMode::kDisabled);
+  cloud_ = CloudDelegate::CreateDefault(parser_->gcd_bootstrap_mode() !=
+                                        GcdBootstrapMode::kDisabled);
   cloud_observer_.Add(cloud_.get());
   security_.reset(new SecurityManager(parser_->pairing_modes(),
                                       parser_->embedded_code_path(),
                                       disable_security_));
   shill_client_.reset(new ShillClient(
-      bus_, device_whitelist_.empty() ? parser_->automatic_wifi_interfaces()
-                                      : device_whitelist_));
+      bus, device_whitelist.empty() ? parser_->automatic_wifi_interfaces()
+                                    : device_whitelist));
   shill_client_->RegisterConnectivityListener(
       base::Bind(&Manager::OnConnectivityChanged, base::Unretained(this)));
-  ap_manager_client_.reset(new ApManagerClient(bus_));
+  ap_manager_client_.reset(new ApManagerClient(bus));
 
   if (parser_->wifi_bootstrap_mode() != WiFiBootstrapMode::kDisabled) {
     VLOG(1) << "Enabling WiFi bootstrapping.";
@@ -121,19 +122,20 @@
     wifi_bootstrap_manager_->Init();
   }
 
-  peerd_client_.reset(new PeerdClient(bus_, device_.get(), cloud_.get(),
+  peerd_client_.reset(new PeerdClient(bus, device_.get(), cloud_.get(),
                                       wifi_bootstrap_manager_.get()));
 
   privet_handler_.reset(
       new PrivetHandler(cloud_.get(), device_.get(), security_.get(),
                         wifi_bootstrap_manager_.get(), peerd_client_.get()));
+
   web_server_.reset(new libwebserv::Server);
   web_server_->OnProtocolHandlerConnected(base::Bind(
       &Manager::OnProtocolHandlerConnected, weak_ptr_factory_.GetWeakPtr()));
   web_server_->OnProtocolHandlerDisconnected(base::Bind(
       &Manager::OnProtocolHandlerDisconnected, weak_ptr_factory_.GetWeakPtr()));
 
-  web_server_->Connect(bus_, kServiceName,
+  web_server_->Connect(bus, buffet::dbus_constants::kServiceName,
                        sequencer->GetHandler("Server::Connect failed.", true),
                        base::Bind(&base::DoNothing),
                        base::Bind(&base::DoNothing));
@@ -144,7 +146,7 @@
   web_server_->GetDefaultHttpsHandler()->AddHandlerCallback(
       "/privet/", "",
       base::Bind(&Manager::PrivetRequestHandler, base::Unretained(this)));
-  if (enable_ping_) {
+  if (options.enable_ping) {
     web_server_->GetDefaultHttpHandler()->AddHandlerCallback(
         "/privet/ping", chromeos::http::request_type::kGet,
         base::Bind(&Manager::HelloWorldHandler, base::Unretained(this)));
@@ -154,14 +156,13 @@
   }
 }
 
-void Manager::OnShutdown(int* return_code) {
+void Manager::OnShutdown() {
   web_server_->Disconnect();
-  DBusDaemon::OnShutdown(return_code);
 }
 
 void Manager::OnDeviceInfoChanged() {
   OnChanged();
-}
+};
 
 void Manager::PrivetRequestHandler(std::unique_ptr<Request> request,
                                    std::unique_ptr<Response> response) {
@@ -240,38 +241,3 @@
 }
 
 }  // namespace privetd
-
-int old_main(int argc, char* argv[]) {
-  DEFINE_bool(disable_security, false, "disable Privet security for tests");
-  DEFINE_bool(enable_ping, false, "enable test HTTP handler at /privet/ping");
-  DEFINE_bool(log_to_stderr, false, "log trace messages to stderr as well");
-  DEFINE_string(config_path, privetd::kDefaultConfigFilePath,
-                "Path to file containing config information.");
-  DEFINE_string(state_path, privetd::kDefaultStateFilePath,
-                "Path to file containing state information.");
-  DEFINE_string(device_whitelist, "",
-                "Comma separated list of network interfaces to monitor for "
-                "connectivity (an empty list enables all interfaces).");
-
-  chromeos::FlagHelper::Init(argc, argv, "Privet protocol handler daemon");
-
-  int flags = chromeos::kLogToSyslog;
-  if (FLAGS_log_to_stderr)
-    flags |= chromeos::kLogToStderr;
-  chromeos::InitLog(flags | chromeos::kLogHeader);
-
-  if (FLAGS_config_path.empty())
-    FLAGS_config_path = privetd::kDefaultConfigFilePath;
-
-  if (FLAGS_state_path.empty())
-    FLAGS_state_path = privetd::kDefaultStateFilePath;
-
-  auto device_whitelist =
-      chromeos::string_utils::Split(FLAGS_device_whitelist, ",", true, true);
-
-  privetd::Manager daemon(
-      FLAGS_disable_security, FLAGS_enable_ping,
-      std::set<std::string>(device_whitelist.begin(), device_whitelist.end()),
-      base::FilePath(FLAGS_config_path), base::FilePath(FLAGS_state_path));
-  return daemon.Run();
-}
diff --git a/buffet/privet/privet_manager.h b/buffet/privet/privet_manager.h
index 23e19d4..8130b9d 100644
--- a/buffet/privet/privet_manager.h
+++ b/buffet/privet/privet_manager.h
@@ -12,10 +12,14 @@
 
 #include <base/memory/weak_ptr.h>
 #include <base/scoped_observer.h>
-#include <chromeos/daemons/dbus_daemon.h>
 
 #include "buffet/privet/cloud_delegate.h"
 
+namespace buffet {
+class CommandManager;
+class DeviceRegistrationInfo;
+}
+
 namespace chromeos {
 namespace dbus_utils {
 class AsyncEventSequencer;
@@ -31,34 +35,43 @@
 
 namespace privetd {
 
-class PrivetdConfigParser;
-class DaemonState;
-class CloudDelegate;
-class DeviceDelegate;
-class SecurityManager;
-class ShillClient;
 class ApManagerClient;
-class WifiBootstrapManager;
+class CloudDelegate;
+class DaemonState;
+class DeviceDelegate;
 class PeerdClient;
 class PrivetHandler;
+class PrivetdConfigParser;
+class SecurityManager;
+class ShillClient;
+class WifiBootstrapManager;
 
-class Manager : public chromeos::DBusServiceDaemon,
-                public CloudDelegate::Observer {
+class Manager : public CloudDelegate::Observer {
  public:
-  Manager(bool disable_security,
-          bool enable_ping,
-          const std::set<std::string>& device_whitelist,
-          const base::FilePath& config_path,
-          const base::FilePath& state_path);
-  ~Manager() override;
+  struct Options {
+    bool disable_privet{false};
+    bool disable_security{false};
+    bool enable_ping{false};
+    std::set<std::string> device_whitelist;
+  };
 
-  void RegisterDBusObjectsAsync(
-      chromeos::dbus_utils::AsyncEventSequencer* sequencer) override;
+  Manager();
+  ~Manager();
 
-  void OnShutdown(int* return_code) override;
+  void Start(const Options& options,
+             const scoped_refptr<dbus::Bus>& bus,
+             chromeos::dbus_utils::AsyncEventSequencer* sequencer);
+
+  void OnShutdown();
 
   void OnDeviceInfoChanged() override;
 
+  privetd::WifiBootstrapManager* GetWifiBootstrapManager() {
+    return wifi_bootstrap_manager_.get();
+  }
+
+  privetd::SecurityManager* GetSecurityManager() { return security_.get(); }
+
  private:
   void PrivetRequestHandler(std::unique_ptr<libwebserv::Request> request,
                             std::unique_ptr<libwebserv::Response> response);
@@ -80,11 +93,8 @@
   void OnProtocolHandlerDisconnected(
       libwebserv::ProtocolHandler* protocol_handler);
 
-  bool disable_security_;
-  bool enable_ping_;
+  bool disable_security_{false};
   std::unique_ptr<PrivetdConfigParser> parser_;
-  std::set<std::string> device_whitelist_;
-  base::FilePath config_path_;
   std::unique_ptr<DaemonState> state_store_;
   std::unique_ptr<CloudDelegate> cloud_;
   std::unique_ptr<DeviceDelegate> device_;