// 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 <errno.h>
#include <fcntl.h>
#include <fidl/fuchsia.hardware.sysmem/cpp/fidl.h>
#include <fidl/fuchsia.sysmem/cpp/fidl.h>
#include <fidl/fuchsia.sysmem2/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/task.h>
#include <lib/async/cpp/wait.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/fdio/watcher.h>
#include <lib/fidl/cpp/channel.h>
#include <lib/fit/function.h>
#include <lib/sysmem-connector/sysmem-connector.h>
#include <lib/zx/channel.h>
#include <lib/zx/process.h>
#include <stdio.h>
#include <threads.h>

#include <queue>

#include <fbl/auto_lock.h>
#include <fbl/mutex.h>
#include <fbl/unique_fd.h>

// The actual sysmem FIDL server is in the sysmem driver.  The code that watches
// for the driver and sends sysmem service requests to the driver is in
// ulib/sysmem-connector.  The code here just needs to queue requests to
// sysmem-connector.

// Clients interact with sysmem-connector using a C ABI, but we want to use C++
// for the implementation.  We have SysmemConnector inherit from an empty
// sysmem_connector struct just to make the SysmemConnector class officially be
// a class not a struct, and to make the SysmemConnector name consistent with
// C++ coding conventions, and have member names with "_" at the end consistent
// with coding conventions, etc.
//
// Every instance of sysmem_connector is actually a SysmemConnector and vice
// versa.
struct sysmem_connector {
  // Intentionally declared as empty; never instantiated; see SysmemConnector.
};
class SysmemConnector : public sysmem_connector {
  // public in this case just means public to this file.  The interface is via
  // the functions declared in lib/sysmem-connector/sysmem-connector.h.
 public:
  SysmemConnector(const char* sysmem_directory_path, bool terminate_on_sysmem_connection_failure);
  zx_status_t Start();

  using QueueItem = std::variant<fidl::ServerEnd<fuchsia_sysmem::Allocator>,
                                 fidl::ServerEnd<fuchsia_sysmem2::Allocator>,
                                 fidl::ClientEnd<fuchsia_io::Directory>>;

  void Queue(QueueItem&& queue_item);
  void Stop();

 private:
  void Post(fit::closure to_run);

  zx_status_t DeviceAdded(int dirfd, int event, const char* filename);

  bool ConnectToSysmemDriver();

  void ProcessQueue();

  void OnSysmemPeerClosed(async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
                          const zx_packet_signal_t* signal);

  //
  // Set once during construction + Start(), never set again.
  //

  // directory of device instances
  const char* sysmem_directory_path_{};
  async::Loop process_queue_loop_;
  thrd_t process_queue_thrd_{};
  bool terminate_on_sysmem_connection_failure_ = false;

  //
  // Only touched from process_queue_loop_'s one thread.
  //

  fidl::ClientEnd<fuchsia_hardware_sysmem::DriverConnector> driver_connector_client_;
  async::WaitMethod<SysmemConnector, &SysmemConnector::OnSysmemPeerClosed> wait_sysmem_peer_closed_;

  //
  // Synchronized using lock_.
  //

  fbl::Mutex lock_;
  std::queue<QueueItem> connection_requests_ __TA_GUARDED(lock_);
};

SysmemConnector::SysmemConnector(const char* sysmem_directory_path,
                                 bool terminate_on_sysmem_connection_failure)
    : sysmem_directory_path_(sysmem_directory_path),
      process_queue_loop_(&kAsyncLoopConfigNoAttachToCurrentThread),
      terminate_on_sysmem_connection_failure_(terminate_on_sysmem_connection_failure),
      wait_sysmem_peer_closed_(this) {
  ZX_DEBUG_ASSERT(sysmem_directory_path_);
}

zx_status_t SysmemConnector::Start() {
  // The process_queue_thrd_ is filled out before any code that checks it runs on the thread,
  // because the current thread is the only thread that triggers anything to happen on the thread
  // being created here, and that is only done after process_queue_thrd_ is filled out by the
  // current thread.
  const zx_status_t status =
      process_queue_loop_.StartThread("SysmemConnector-ProcessQueue", &process_queue_thrd_);
  if (status != ZX_OK) {
    printf("sysmem-connector: process_queue_loop_.StartThread(): %s\n",
           zx_status_get_string(status));
    return status;
  }
  // Establish initial connection to sysmem driver async.
  Post([this] { ConnectToSysmemDriver(); });
  return ZX_OK;
}

void SysmemConnector::Queue(QueueItem&& queue_item) {
  ZX_DEBUG_ASSERT(thrd_current() != process_queue_thrd_);
  bool trigger_needed;
  {  // scope lock
    const fbl::AutoLock lock(&lock_);
    trigger_needed = connection_requests_.empty();
    connection_requests_.emplace(std::move(queue_item));
  }  // ~lock
  if (trigger_needed) {
    Post([this] { ProcessQueue(); });
  }
}

void SysmemConnector::Stop() {
  ZX_DEBUG_ASSERT(thrd_current() != process_queue_thrd_);
  process_queue_loop_.Quit();
  process_queue_loop_.JoinThreads();
  process_queue_loop_.Shutdown();
}

void SysmemConnector::Post(fit::closure to_run) {
  const zx_status_t status = async::PostTask(process_queue_loop_.dispatcher(), std::move(to_run));
  // We don't expect this post to ever fail.
  ZX_ASSERT_MSG(status == ZX_OK, "%s", zx_status_get_string(status));
}

zx_status_t SysmemConnector::DeviceAdded(int dirfd, int event, const char* filename) {
  ZX_DEBUG_ASSERT(thrd_current() == process_queue_thrd_);
  if (std::string_view{filename} == ".") {
    return ZX_OK;
  }
  if (event != WATCH_EVENT_ADD_FILE) {
    // Keep going on IDLE or REMOVE.  There's nothing else useful that the
    // current thread can do until a sysmem device instance is available,
    // and we don't have any reason to attempt to directly handle any
    // REMOVE(s) since we'll do fdio_watch_directory() again later from
    // scratch instead.
    return ZX_OK;
  }

  {
    const fdio_cpp::UnownedFdioCaller caller(dirfd);
    zx::result status = component::ConnectAt<fuchsia_hardware_sysmem::DriverConnector>(
        caller.borrow_as<fuchsia_io::Directory>(), filename);
    if (status.is_error()) {
      printf("sysmem-connector: component::ConnectAt(%s, %s): %s\n", sysmem_directory_path_,
             filename, status.status_string());
      // If somehow connecting to this device instance fails, keep watching for
      // another device instance.
      return ZX_OK;
    }
    driver_connector_client_ = std::move(status.value());
  }

  if (terminate_on_sysmem_connection_failure_) {
    wait_sysmem_peer_closed_.set_trigger(ZX_CHANNEL_PEER_CLOSED);
    wait_sysmem_peer_closed_.set_object(driver_connector_client_.channel().get());
    const zx_status_t status = wait_sysmem_peer_closed_.Begin(process_queue_loop_.dispatcher());
    ZX_ASSERT_MSG(status == ZX_OK, "async::WaitMethod<OnSysmemPeerClosed>::Begin: %s",
                  zx_status_get_string(status));
    // Cancel() doesn't need to be called anywhere because this process will
    // terminate immediately if the wait ever completes.
  }

  char process_name[ZX_MAX_NAME_LEN];
  const zx_status_t status =
      zx::process::self()->get_property(ZX_PROP_NAME, process_name, sizeof(process_name));
  ZX_ASSERT_MSG(status == ZX_OK, "%s", zx_status_get_string(status));
  printf("sysmem-connector: %s connected to sysmem driver %s\n", process_name, filename);

  return ZX_ERR_STOP;
}

bool SysmemConnector::ConnectToSysmemDriver() {
  ZX_DEBUG_ASSERT(thrd_current() == process_queue_thrd_);
  ZX_DEBUG_ASSERT(!driver_connector_client_);

  fbl::unique_fd sysmem_dir_fd;
  {
    const int fd = open(sysmem_directory_path_, O_DIRECTORY | O_RDONLY);
    if (fd < 0) {
      if (terminate_on_sysmem_connection_failure_) {
        ZX_PANIC("open(%s): %s", sysmem_directory_path_, strerror(errno));
      } else {
        printf("sysmem-connector: open(%s): %s\n", sysmem_directory_path_, strerror(errno));
      }
      return false;
    }
    sysmem_dir_fd.reset(fd);
  }
  ZX_DEBUG_ASSERT(sysmem_dir_fd);

  // Returns ZX_ERR_STOP as soon as one of the 000, 001 device instances is
  // found.  We rely on those to go away if the corresponding sysmem instance
  // is no longer operational, so that we don't find them when we call
  // ConnectToSysmemDriver() again upon discovering that we can't send to a
  // previous device instance.  When terminate_on_sysmem_connection_failure_,
  // there won't be any instances after 000 fails because sysmem_connector will
  // terminate and sysmem_connector is a critical process.
  //
  // TODO(dustingreen): Currently if this watch never finds a sysmem device
  // instance, then sysmem_connector_release() will block forever.  This can
  // be fixed once it's feasible to use DeviceWatcher (or similar) here
  // instead (currently DeviceWatcher is in garnet not zircon).
  const zx_status_t status = fdio_watch_directory(
      sysmem_dir_fd.get(),
      [](int dirfd, int event, const char* fn, void* cookie) {
        ZX_DEBUG_ASSERT(cookie);
        SysmemConnector* connector = static_cast<SysmemConnector*>(cookie);
        return connector->DeviceAdded(dirfd, event, fn);
      },
      ZX_TIME_INFINITE, this);
  if (status != ZX_ERR_STOP) {
    if (terminate_on_sysmem_connection_failure_) {
      ZX_PANIC("fdio_watch_directory(%s): %s", sysmem_directory_path_,
               zx_status_get_string(status));
    } else {
      printf("sysmem-connector: fdio_watch_directory(%s): %s\n", sysmem_directory_path_,
             zx_status_get_string(status));
    }
    return false;
  }
  ZX_DEBUG_ASSERT(driver_connector_client_);
  return true;
}

namespace {

// Helpers from the reference documentation for std::visit<>, to allow
// visit-by-overload of the std::variant<> returned by GetLastReference():
template <class... Ts>
struct overloaded : Ts... {
  using Ts::operator()...;
};
// explicit deduction guide (not needed as of C++20)
template <class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;

}  // namespace

void SysmemConnector::ProcessQueue() {
  ZX_DEBUG_ASSERT(thrd_current() == process_queue_thrd_);
  while (true) {
    QueueItem queue_item;
    {  // scope lock
      const fbl::AutoLock lock(&lock_);
      if (connection_requests_.empty()) {
        return;
      }
      queue_item = std::move(connection_requests_.front());
      connection_requests_.pop();
    }  // ~lock

    if (!driver_connector_client_) {
      if (!ConnectToSysmemDriver()) {
        // ~queue_item - we'll try again to connect to a sysmem instance next
        // time a request comes in, but any given request gets a max of one
        // attempt to connect to a sysmem device instance, in case attempts to
        // find a sysmem device instance are just failing.
        return;
      }
    }
    ZX_DEBUG_ASSERT(driver_connector_client_);

    const auto [name, status] = std::visit(
        overloaded{
            [this](fidl::ServerEnd<fuchsia_sysmem::Allocator> allocator_request) {
              return std::make_pair("ConnectV1", fidl::WireCall(driver_connector_client_)
                                                     ->ConnectV1(std::move(allocator_request))
                                                     .status());
            },
            [this](fidl::ServerEnd<fuchsia_sysmem2::Allocator> allocator_request) {
              return std::make_pair("ConnectV2", fidl::WireCall(driver_connector_client_)
                                                     ->ConnectV2(std::move(allocator_request))
                                                     .status());
            },
            [this](fidl::ClientEnd<fuchsia_io::Directory> service_directory) {
              return std::make_pair("SetAuxServiceDirectory",
                                    fidl::WireCall(driver_connector_client_)
                                        ->SetAuxServiceDirectory(std::move(service_directory))
                                        .status());
            }},
        std::move(queue_item));
    if (status != ZX_OK) {
      printf("sysmem-connector: fuchsia.sysmem/DriverConnect.%s: %s\n", name,
             zx_status_get_string(status));
      driver_connector_client_.reset();
    }
  }
}

void SysmemConnector::OnSysmemPeerClosed(async_dispatcher_t* dispatcher, async::WaitBase* wait,
                                         zx_status_t status, const zx_packet_signal_t* signal) {
  // Else we wouldn't have started the wait that is now completing.
  ZX_ASSERT(terminate_on_sysmem_connection_failure_);
  // Any other wait status is unexpected, so terminate this process.
  ZX_ASSERT_MSG(status == ZX_OK, "%s", zx_status_get_string(status));
  // This signal is set because we only waited on this signal.
  ZX_ASSERT_MSG((signal->observed & ZX_CHANNEL_PEER_CLOSED) != 0, "0x%x", signal->observed);
  // Terminate sysmem_connector, which is a critical process, so this will do a hard reboot.
  ZX_PANIC(
      "sysmem_connector's connection to sysmem has closed; sysmem driver failed - "
      "terminating process to trigger reboot.");
}

zx_status_t sysmem_connector_init(const char* sysmem_directory_path,
                                  bool terminate_on_sysmem_connection_failure,
                                  sysmem_connector_t** out_connector) {
  SysmemConnector* connector =
      new SysmemConnector(sysmem_directory_path, terminate_on_sysmem_connection_failure);
  const zx_status_t status = connector->Start();
  if (status != ZX_OK) {
    printf("sysmem_connector_init() connector->Start() failed - status: %s\n",
           zx_status_get_string(status));
    return status;
  }
  *out_connector = connector;
  return ZX_OK;
}

void sysmem_connector_queue_connection_request_v1(sysmem_connector_t* connector_param,
                                                  zx_handle_t allocator_request_param) {
  zx::channel allocator_request(allocator_request_param);
  ZX_DEBUG_ASSERT(connector_param);
  ZX_DEBUG_ASSERT(allocator_request);
  SysmemConnector* connector = static_cast<SysmemConnector*>(connector_param);
  connector->Queue(fidl::ServerEnd<fuchsia_sysmem::Allocator>{std::move(allocator_request)});
}

void sysmem_connector_queue_connection_request_v2(sysmem_connector_t* connector_param,
                                                  zx_handle_t allocator_request_param) {
  zx::channel allocator_request(allocator_request_param);
  ZX_DEBUG_ASSERT(connector_param);
  ZX_DEBUG_ASSERT(allocator_request);
  SysmemConnector* connector = static_cast<SysmemConnector*>(connector_param);
  connector->Queue(fidl::ServerEnd<fuchsia_sysmem2::Allocator>{std::move(allocator_request)});
}

void sysmem_connector_queue_service_directory(sysmem_connector_t* connector_param,
                                              zx_handle_t service_directory_param) {
  printf("sysmem_connector_queue_service_directory\n");
  zx::channel service_directory(service_directory_param);
  ZX_DEBUG_ASSERT(connector_param);
  ZX_DEBUG_ASSERT(service_directory);
  SysmemConnector* connector = static_cast<SysmemConnector*>(connector_param);
  connector->Queue(fidl::ClientEnd<fuchsia_io::Directory>{std::move(service_directory)});
}

void sysmem_connector_release(sysmem_connector_t* connector_param) {
  ZX_DEBUG_ASSERT(connector_param);
  SysmemConnector* connector = static_cast<SysmemConnector*>(connector_param);
  connector->Stop();
  delete connector;
}
