// Copyright 2018 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 "vm_tools/notificationd/notification_shell_client.h"

#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <memory>
#include <string>
#include <utility>

#include <base/bind.h>
#include <base/callback_helpers.h>
#include <base/check.h>
#include <base/check_op.h>
#include <base/logging.h>
#include <base/memory/ptr_util.h>
#include <base/strings/string_util.h>
#include <base/threading/thread_task_runner_handle.h>
#include <linux/virtwl.h>
#include <wayland-client.h>
#include <wayland-util.h>

namespace {

// Callback for checking whether it's called. Used in
// NotificationShellClient::WaitForSync().
void SyncCallback(void* data, wl_callback* callback, uint32_t serial) {
  *static_cast<bool*>(data) = true;
}
constexpr wl_callback_listener kSyncListener = {SyncCallback};

// Wraps wl_callback in a std::unique_ptr.
struct WlCallbackDeleter {
  void operator()(wl_callback* callback) { wl_callback_destroy(callback); }
};
using WlCallback = std::unique_ptr<wl_callback, WlCallbackDeleter>;

// Buffer size of the message used for ioctl to virtwl.
constexpr size_t kBufferSize = 4096;

}  // namespace

namespace vm_tools {
namespace notificationd {

NotificationShellClient::NotificationClient::NotificationClient(
    zcr_notification_shell_notification_v1* proxy,
    const std::string& notification_key,
    NotificationShellClient* shell_client)
    : proxy_(proxy),
      notification_key_(notification_key),
      shell_client_(shell_client) {
  // zcr_notification_shell_notification_v1_add_listener method is automatically
  // generated by wayland-scanner according to the
  // vm_tools/notificationd/protocol/notification-shell-unstable-v1.xml
  zcr_notification_shell_notification_v1_add_listener(
      proxy_.get(), &notification_listener_, this);
}

void NotificationShellClient::NotificationClient::Close() {
  DCHECK(proxy_);
  // zcr_notification_shell_notification_v1_close method is automatically
  // generated by wayland-scanner according to the
  // vm_tools/notificationd/protocol/notification-shell-unstable-v1.xml
  zcr_notification_shell_notification_v1_close(proxy_.get());
}

void NotificationShellClient::NotificationClient::HandleNotificationClosedEvent(
    bool by_user) {
  shell_client_->HandleNotificationClosedEvent(notification_key_, by_user);
}

void NotificationShellClient::NotificationClient::
    HandleNotificationClickedEvent(int32_t button_index) {
  shell_client_->HandleNotificationClickedEvent(notification_key_,
                                                button_index);
}

void NotificationShellClient::NotificationClient::
    HandleNotificationClosedEventCallback(
        void* data,
        zcr_notification_shell_notification_v1* notification_proxy,
        uint32_t by_user) {
  static_cast<
      vm_tools::notificationd::NotificationShellClient::NotificationClient*>(
      data)
      ->HandleNotificationClosedEvent(by_user);
}

void NotificationShellClient::NotificationClient::
    HandleNotificationClickedEventCallback(
        void* data,
        zcr_notification_shell_notification_v1* notification_proxy,
        int32_t button_index) {
  static_cast<
      vm_tools::notificationd::NotificationShellClient::NotificationClient*>(
      data)
      ->HandleNotificationClickedEvent(button_index);
}

NotificationShellClient::NotificationShellClient(
    NotificationShellInterface* interface, base::Closure quit_closure)
    : interface_(interface), quit_closure_(std::move(quit_closure)) {}

void NotificationShellClient::OnEventReadable() {
  if (wl_event_loop_dispatch(event_loop_.get(), 0) < 0) {
    PLOG(ERROR) << "Failed to dispatch event loop for wayland";
    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
  }
}

// static
std::unique_ptr<NotificationShellClient> NotificationShellClient::Create(
    const std::string& display_name,
    const std::string& virtwl_device,
    NotificationShellInterface* interface,
    base::Closure quit_closure) {
  auto client = base::WrapUnique(
      new NotificationShellClient(interface, std::move(quit_closure)));

  if (!client->Init(display_name.empty() ? nullptr : display_name.c_str(),
                    virtwl_device.empty() ? nullptr : virtwl_device.c_str()))
    return nullptr;

  return client;
}

bool NotificationShellClient::Init(const char* display_name,
                                   const char* virtwl_device) {
  event_loop_.reset(wl_event_loop_create());
  event_loop_fd_.reset(wl_event_loop_get_fd(event_loop_.get()));
  if (!event_loop_fd_.is_valid()) {
    PLOG(ERROR) << "Could not get wayland event loop fd";
    return false;
  }

  watcher_ = base::FileDescriptorWatcher::WatchReadable(
      event_loop_fd_.get(),
      base::BindRepeating(&NotificationShellClient::OnEventReadable,
                          base::Unretained(this)));
  if (!watcher_) {
    LOG(ERROR) << "Failed to watch event loop fd";
    return false;
  }

  if (virtwl_device) {
    const base::ScopedFD virtwl_fd(open(virtwl_device, O_RDWR | O_CLOEXEC));
    if (!virtwl_fd.is_valid()) {
      PLOG(ERROR) << "Could not open " << virtwl_device;
      return false;
    }

    int fds[2] = {};
    // Connection to virtwl channel.
    if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds)) {
      PLOG(ERROR) << "Failed to create socket pair";
      return false;
    }
    virtwl_socket_fd_.reset(fds[0]);
    const auto virtwl_display_fd = fds[1];

    virtwl_ioctl_new new_ctx = {
        .type = VIRTWL_IOCTL_NEW_CTX,
        .fd = -1,
        .flags = 0,
        .size = 0,
    };
    if (ioctl(virtwl_fd.get(), VIRTWL_IOCTL_NEW, &new_ctx)) {
      PLOG(ERROR) << "Failed to create virtwl context";
      return false;
    }
    virtwl_ctx_fd_.reset(new_ctx.fd);

    wl_event_loop_add_fd(event_loop_.get(), virtwl_socket_fd_.get(),
                         WL_EVENT_READABLE, HandleVirtwlSocketEventCallback,
                         this);
    wl_event_loop_add_fd(event_loop_.get(), virtwl_ctx_fd_.get(),
                         WL_EVENT_READABLE, HandleVirtwlCtxEventCallback, this);

    // The |display_| takes ownership of |virtwl_display_fd| and will close it
    // when |display_| is destroyed.
    display_.reset(wl_display_connect_to_fd(virtwl_display_fd));
  } else {
    display_.reset(wl_display_connect(display_name));
  }

  if (!display_) {
    LOG(ERROR) << "Failed to connect to the display";
    return false;
  }

  wl_event_loop_add_fd(event_loop_.get(), wl_display_get_fd(display_.get()),
                       WL_EVENT_READABLE, HandleEventCallback, this);

  wl_registry_add_listener(wl_display_get_registry(display_.get()),
                           &registry_listener_, this);

  // We use WaitForSync method instead of wl_display_roundtrip because we have
  // to handle message forwarding to/from virtwl in single-thread when virtwl is
  // used, which can be invoked by observing |event_loop_|. Calling
  // wl_display_roundtrip, which does not handle |event_loop_|, causes deadlock
  // because HandleVirtwlCtxEvent and HandleVirtwlSocketEvent are never called.
  WaitForSync();

  if (!proxy_) {
    LOG(ERROR) << "Server is missing the zcr_notification_shell_v1 interface";
    return false;
  }

  return true;
}

void NotificationShellClient::WaitForSync() {
  const WlCallback callback(wl_display_sync(display_.get()));
  DCHECK(callback);

  bool done = false;
  wl_callback_add_listener(callback.get(), &::kSyncListener, &done);
  wl_display_flush(display_.get());

  while (!done)
    wl_event_loop_dispatch(event_loop_.get(), -1 /*no timeout*/);
}

bool NotificationShellClient::CreateNotification(
    const std::string& title,
    const std::string& message,
    const std::string& display_source,
    const std::string& notification_key,
    const std::vector<std::string>& buttons) {
  DCHECK(proxy_);

  // Convert vector of strings to wl_array
  wl_array buttons_wl_array;
  wl_array_init(&buttons_wl_array);
  for (const auto& button : buttons) {
    const auto size = button.length() + 1;
    base::strlcpy(static_cast<char*>(wl_array_add(&buttons_wl_array, size)),
                  button.c_str(), size);
  }

  // zcr_notification_shell_v1_create_notification method is automatically
  // generated by wayland-scanner according to the
  // vm_tools/notificationd/protocol/notification-shell-unstable-v1.xml
  auto* notification_proxy = zcr_notification_shell_v1_create_notification(
      proxy_.get(), title.c_str(), message.c_str(), display_source.c_str(),
      notification_key.c_str(), &buttons_wl_array);

  wl_array_release(&buttons_wl_array);

  // The notification client takes ownership of |notification_proxy|
  notification_clients_[notification_key] =
      std::make_unique<NotificationClient>(notification_proxy, notification_key,
                                           this);

  wl_display_flush(display_.get());
  return true;
}

bool NotificationShellClient::CloseNotification(
    const std::string& notification_key) {
  DCHECK(proxy_);

  auto notification = notification_clients_.find(notification_key);
  if (notification == notification_clients_.end()) {
    LOG(ERROR) << "Invalid notification key";
    return false;
  }
  notification->second->Close();

  wl_display_flush(display_.get());
  return true;
}

void NotificationShellClient::HandleNotificationClosedEvent(
    const std::string& notification_key, bool by_user) {
  interface_->OnClosed(notification_key, by_user);

  auto notification = notification_clients_.find(notification_key);
  DCHECK(notification != notification_clients_.end());
  notification_clients_.erase(notification);
}

void NotificationShellClient::HandleNotificationClickedEvent(
    const std::string& notification_key, int32_t button_index) {
  interface_->OnClicked(notification_key, button_index);
}

void NotificationShellClient::HandleRegistry(wl_registry* registry,
                                             int32_t id,
                                             const char* interface,
                                             uint32_t version) {
  if (std::string(interface) == "zcr_notification_shell_v1") {
    proxy_.reset(static_cast<zcr_notification_shell_v1*>(wl_registry_bind(
        registry, id, &zcr_notification_shell_v1_interface, 1)));
  }
}

int NotificationShellClient::HandleEvent(uint32_t mask) {
  if (mask & WL_EVENT_HANGUP) {
    LOG(ERROR) << "Wayland connection hung up";
    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
    return -1;
  }
  if (mask & WL_EVENT_ERROR) {
    LOG(ERROR) << "Wayland connection error occurred";
    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
    return -1;
  }

  int count = 0;
  if (mask & WL_EVENT_READABLE)
    count = wl_display_dispatch(display_.get());

  if (mask == 0) {
    count = wl_display_dispatch_pending(display_.get());
    wl_display_flush(display_.get());
  }

  return count;
}

void NotificationShellClient::HandleVirtwlCtxEvent() {
  // virtwl_ioctl_txn::data, which is the last element of the structure, is
  // defined as zero-length array. So, we allocate the space for that by casting
  // a buffer array (|ioctl_buffer|) into the structure (|ioctl_recv|).
  uint8_t ioctl_buffer[kBufferSize] = {};
  virtwl_ioctl_txn* ioctl_recv =
      reinterpret_cast<virtwl_ioctl_txn*>(ioctl_buffer);

  // virtwl_ioctl_txn::len is the reserved size of the data element
  // (virtwl_ioctl_txn::data). Because the data element is zero-length array,
  // the size can be calculated by subtracting the header size from the total
  // buffer size used for initializing the structure.
  ioctl_recv->len = sizeof(ioctl_buffer) - sizeof(virtwl_ioctl_txn);

  if (ioctl(virtwl_ctx_fd_.get(), VIRTWL_IOCTL_RECV, ioctl_recv)) {
    LOG(ERROR) << "Failed to receive data from virtwl context";
    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
  }

  iovec buffer_iov = {.iov_base = &ioctl_recv->data,
                      .iov_len = ioctl_recv->len};

  msghdr msg = {.msg_iov = &buffer_iov, .msg_iovlen = 1, .msg_controllen = 0};

  const auto bytes = sendmsg(virtwl_socket_fd_.get(), &msg, MSG_NOSIGNAL);
  DCHECK_EQ(bytes, ioctl_recv->len);

  // Count how many FDs the kernel gave us. We do not forwards FDs in
  // notificationd. If any FDs are included in ioctl_recv, we just ignore them.
  // We can do this because noification shell protocol does not use FDs.
  size_t fd_count = 0;
  for (; fd_count < VIRTWL_SEND_MAX_ALLOCS; ++fd_count) {
    if (ioctl_recv->fds[fd_count] < 0)
      break;
  }

  DCHECK_EQ(fd_count, 0);
}

void NotificationShellClient::HandleVirtwlSocketEvent() {
  // virtwl_ioctl_txn::data, which is the last element of the structure, is
  // defined as zero-length array. So, we allocate the space for that by casting
  // a buffer array (|ioctl_buffer|) into the structure (|ioctl_recv|).
  uint8_t ioctl_buffer[kBufferSize] = {};
  virtwl_ioctl_txn* ioctl_send =
      reinterpret_cast<virtwl_ioctl_txn*>(ioctl_buffer);

  for (int i = 0; i < VIRTWL_SEND_MAX_ALLOCS; ++i)
    ioctl_send->fds[i] = -1;

  // iovec::iov_len is the reserved size of iovec::iov_base. Because the data
  // element in virtwl_ioctl_txn is defined as zero-length array, its size can
  // be calculated by subtracting the header size from the total buffer size
  // used for initializing the structure.
  iovec buffer_iov = {
      .iov_base = &ioctl_send->data,
      .iov_len = sizeof(ioctl_buffer) - sizeof(virtwl_ioctl_txn)};

  uint8_t fd_buffer[CMSG_LEN(sizeof(int) * VIRTWL_SEND_MAX_ALLOCS)] = {};
  msghdr msg = {.msg_iov = &buffer_iov,
                .msg_iovlen = 1,
                .msg_control = fd_buffer,
                .msg_controllen = sizeof(fd_buffer)};

  const auto bytes = recvmsg(virtwl_socket_fd_.get(), &msg, 0);
  DCHECK_GT(bytes, 0);

  // The data were extracted from the recvmsg call into the ioctl_send
  // structure which we now pass along to the kernel.
  ioctl_send->len = bytes;
  auto ret = ioctl(virtwl_ctx_fd_.get(), VIRTWL_IOCTL_SEND, ioctl_send);
  DCHECK_EQ(ret, 0);

  // We do not forwards FDs in notificationd. If any FDs are included in msg,
  // we just ignore them. We can do this because noification shell protocol does
  // not use FDs.
  size_t fd_count = 0;
  for (auto* cmsg = msg.msg_controllen != 0 ? CMSG_FIRSTHDR(&msg) : nullptr;
       cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
    if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
      continue;

    const auto cmsg_fd_count = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
    fd_count += cmsg_fd_count;
  }
  DCHECK_EQ(fd_count, 0);
}

int NotificationShellClient::HandleEventCallback(int fd,
                                                 uint32_t mask,
                                                 void* data) {
  return static_cast<vm_tools::notificationd::NotificationShellClient*>(data)
      ->HandleEvent(mask);
}

void NotificationShellClient::HandleRegistryCallback(void* data,
                                                     wl_registry* registry,
                                                     uint32_t id,
                                                     const char* interface,
                                                     uint32_t version) {
  static_cast<vm_tools::notificationd::NotificationShellClient*>(data)
      ->HandleRegistry(registry, id, interface, version);
}

int NotificationShellClient::HandleVirtwlSocketEventCallback(int fd,
                                                             uint32_t mask,
                                                             void* data) {
  static_cast<vm_tools::notificationd::NotificationShellClient*>(data)
      ->HandleVirtwlSocketEvent();
  return 1;
}

int NotificationShellClient::HandleVirtwlCtxEventCallback(int fd,
                                                          uint32_t mask,
                                                          void* data) {
  static_cast<vm_tools::notificationd::NotificationShellClient*>(data)
      ->HandleVirtwlCtxEvent();
  return 1;
}

}  // namespace notificationd
}  // namespace vm_tools
