// Copyright 2019 The Fuchsia 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 "sandbox_service.h"

#include <lib/async/task.h>
#include <lib/sys/cpp/service_directory.h>
#include <zircon/status.h>

#include <random>

#include "src/lib/fxl/strings/string_printf.h"

namespace netemul {

class SandboxBinding : public fuchsia::netemul::sandbox::Sandbox {
 public:
  using FSandbox = fuchsia::netemul::sandbox::Sandbox;
  using OnDestroyedCallback = fit::function<void(const SandboxBinding*)>;

  SandboxBinding(fidl::InterfaceRequest<FSandbox> req,
                 fuchsia::sys::EnvironmentControllerPtr env_controller,
                 fuchsia::sys::EnvironmentPtr environment, std::unique_ptr<async::Loop> loop,
                 SandboxService* parent)
      : loop_(std::move(loop)),
        binding_(this),
        parent_env_(std::move(environment)),
        parent_env_ctlr_(std::move(env_controller)),
        parent_(parent) {
    binding_.set_error_handler([this](zx_status_t err) { BindingClosed(); });

    parent_env_ctlr_.set_error_handler([this](zx_status_t err) {
      FX_LOGS(ERROR) << "Lost connection to parent environment controller: "
                     << zx_status_get_string(err);
      BindingClosed();
    });

    parent_env_.set_error_handler([this](zx_status_t err) {
      FX_LOGS(ERROR) << "Lost connection to parent environment: " << zx_status_get_string(err);
      BindingClosed();
    });

    parent_env_ctlr_.events().OnCreated = [this, req = std::move(req)]() mutable {
      binding_.Bind(std::move(req), loop_->dispatcher());
    };

    if (loop_->StartThread("sandbox-thread") != ZX_OK) {
      FX_LOGS(ERROR) << "Failed to start thread for sandbox";
      parent_->BindingClosed(this);
      return;
    }
  }

  ~SandboxBinding() {
    // Sandbox binding can't be destroyed on the thread of its loop,
    // it'll cause a deadlock upon loop destruction
    ZX_ASSERT(loop_->dispatcher() != async_get_default_dispatcher());
    // Shutdown the loop before destroying any of the bindings.
    loop_->Shutdown();
  }

  void CreateEnvironment(fidl::InterfaceRequest<ManagedEnvironment::FManagedEnvironment> req,
                         ManagedEnvironment::Options options) override {
    auto root = ManagedEnvironment::CreateRoot(parent_env_, shared_env(), std::move(options));
    root->SetRunningCallback(
        [root = root.get(), req = std::move(req)]() mutable { root->Bind(std::move(req)); });

    environments_.push_back(std::move(root));
  }

  // Gets this sandbox's NetworkContext
  void GetNetworkContext(fidl::InterfaceRequest<::fuchsia::netemul::network::NetworkContext>
                             network_context) override {
    shared_env()->network_context().GetHandler()(std::move(network_context));
  };

  // Gets this sandbox's SyncManager
  void GetSyncManager(
      fidl::InterfaceRequest<fuchsia::netemul::sync::SyncManager> sync_manager) override {
    shared_env()->sync_manager().GetHandler()(std::move(sync_manager));
  };

 private:
  std::shared_ptr<SandboxEnv>& shared_env() {
    ZX_ASSERT(async_get_default_dispatcher() == loop_->dispatcher());
    if (!shared_env_) {
      shared_env_ = std::make_shared<SandboxEnv>(sys::ServiceDirectory::CreateFromNamespace());
      shared_env_->set_devfs_enabled(true);
    }
    return shared_env_;
  }

  void BindingClosed() {
    // can only be called from within the dispatcher loop
    ZX_ASSERT(loop_->dispatcher() == async_get_default_dispatcher());
    // we don't care about environment anymore.
    // unbinding will prevent the error handlers from firing
    // when we destroy the dispatcher.
    parent_env_.Unbind();
    parent_env_ctlr_.Unbind();
    // get rid of child environments and shared services:
    environments_.clear();
    shared_env_ = nullptr;
    parent_->BindingClosed(this);
  }

  std::unique_ptr<async::Loop> loop_;
  std::shared_ptr<SandboxEnv> shared_env_;
  fidl::Binding<FSandbox> binding_;
  std::vector<std::unique_ptr<ManagedEnvironment>> environments_;
  fuchsia::sys::EnvironmentPtr parent_env_;
  fuchsia::sys::EnvironmentControllerPtr parent_env_ctlr_;
  // Pointer to parent SandboxService. Not owned.
  SandboxService* parent_;

  FXL_DISALLOW_COPY_AND_ASSIGN(SandboxBinding);
};

void SandboxService::BindingClosed(netemul::SandboxBinding* binding) {
  async::PostTask(dispatcher_, [binding, this]() {
    for (auto i = bindings_.begin(); i != bindings_.end(); i++) {
      if (i->get() == binding) {
        bindings_.erase(i);
        return;
      }
    }
  });
}

fidl::InterfaceRequestHandler<fuchsia::netemul::sandbox::Sandbox> SandboxService::GetHandler() {
  return [this](fidl::InterfaceRequest<fuchsia::netemul::sandbox::Sandbox> req) {
    // Create each SandboxBinding in its own thread.
    // A common usage pattern for SandboxService is to connect to the
    // service in each test in a rust create test suite. Rust crate tests
    // run in parallel, so enclosing each binding in its own thread will
    // makes a bit more sense to service everything independently.
    auto loop = std::make_unique<async::Loop>(&kAsyncLoopConfigNoAttachToCurrentThread);

    fuchsia::sys::EnvironmentPtr env;
    fuchsia::sys::EnvironmentControllerPtr env_ctlr;
    parent_env_->CreateNestedEnvironment(
        env.NewRequest(loop->dispatcher()), env_ctlr.NewRequest(loop->dispatcher()),
        fxl::StringPrintf("netemul-%08X-%08X", random_, counter_++), nullptr,
        fuchsia::sys::EnvironmentOptions{
            .inherit_parent_services = true,
            .use_parent_runners = true,
            .kill_on_oom = true,
            .delete_storage_on_death = true,
        });

    bindings_.push_back(std::make_unique<SandboxBinding>(std::move(req), std::move(env_ctlr),
                                                         std::move(env), std::move(loop), this));
  };
}

SandboxService::SandboxService(async_dispatcher_t* dispatcher)
    : dispatcher_(dispatcher), counter_(0) {
  std::random_device dev;
  std::uniform_int_distribution<uint32_t> rd(0, 0xFFFFFFFF);
  random_ = rd(dev);

  auto services = sys::ServiceDirectory::CreateFromNamespace();
  services->Connect(parent_env_.NewRequest(dispatcher));
}

SandboxService::~SandboxService() = default;

}  // namespace netemul
