// Copyright 2018 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 "endpoint.h"

#include <fcntl.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <zircon/status.h>
#include <zircon/types.h>

#include <random>
#include <unordered_set>
#include <vector>

#include "ethernet_client.h"
#include "ethertap_client.h"
#include "network_context.h"

namespace netemul {

namespace impl {

class EndpointImpl : public data::Consumer {
 public:
  explicit EndpointImpl(Endpoint::Config config)
      : config_(std::move(config)), weak_ptr_factory_(this) {}

  decltype(auto) GetPointer() { return weak_ptr_factory_.GetWeakPtr(); }

  void CloneConfig(Endpoint::Config* config) { config_.Clone(config); }

  const Endpoint::Config& config() const { return config_; }

  std::vector<data::BusConsumer::Ptr>& sinks() { return sinks_; }

  void SetClosedCallback(fit::closure cb) { closed_callback_ = std::move(cb); }

  virtual zx_status_t Setup(const std::string& name, bool start_online,
                            const NetworkContext& context) = 0;

  virtual void SetLinkUp(bool up, fit::callback<void()> done) = 0;

  virtual fuchsia::netemul::network::DeviceConnection GetDevice() = 0;

  virtual void ServeDevice(zx::channel req) = 0;

  static fuchsia::net::MacAddress RandomMac(const std::string& str_seed) {
    fuchsia::net::MacAddress ret;
    std::vector<uint8_t> sseed(str_seed.begin(), str_seed.end());
    std::seed_seq seed(sseed.begin(), sseed.end());
    std::independent_bits_engine<std::default_random_engine, CHAR_BIT, uint8_t> rnd(seed);
    std::generate(ret.octets.begin(), ret.octets.end(), rnd);
    // Force mac to be unicast (bit 0 is 0) and locally administered (bit 1 is 1).
    ret.octets[0] = (ret.octets[0] & 0xFC) | (0x02);
    return ret;
  }

 protected:
  void Closed() {
    if (closed_callback_) {
      closed_callback_();
    }
  }

  void ForwardData(const void* data, size_t len) {
    auto self = weak_ptr_factory_.GetWeakPtr();
    for (auto i = sinks_.begin(); i != sinks_.end();) {
      if (*i) {
        (*i)->Consume(data, len, self);
        ++i;
      } else {
        // The sink was freed, remove it from the list.
        i = sinks_.erase(i);
      }
    }
  }

 private:
  Endpoint::Config config_;
  std::vector<data::BusConsumer::Ptr> sinks_;
  fxl::WeakPtrFactory<data::Consumer> weak_ptr_factory_;
  fit::callback<void()> closed_callback_;
};

class EthertapImpl : public EndpointImpl {
 public:
  explicit EthertapImpl(Endpoint::Config config) : EndpointImpl(std::move(config)) {}

  zx_status_t Setup(const std::string& name, bool start_online,
                    const NetworkContext& context) override {
    EthertapConfig tap_cfg;
    if (config().mac) {
      tap_cfg.tap_cfg.mac.octets = config().mac->octets;
    } else {
      // if mac is not provided, random mac is assigned with a seed based on
      // name
      tap_cfg.RandomLocalUnicast(name);
    }

    tap_cfg.name = name;
    tap_cfg.tap_cfg.mtu = config().mtu;
    fuchsia::hardware::ethernet::MacAddress mac;
    tap_cfg.tap_cfg.mac.Clone(&mac);
    tap_cfg.tap_cfg.options = fuchsia::hardware::ethertap::OPT_REPORT_PARAM;
    if (start_online) {
      tap_cfg.tap_cfg.options |= fuchsia::hardware::ethertap::OPT_ONLINE;
    }
    tap_cfg.devfs_root = context.ConnectDevfs();
    zx_status_t status = EthertapClient::Create(std::move(tap_cfg), &ethertap_);
    if (status != ZX_OK) {
      return status;
    }

    auto devfs_root = context.ConnectDevfs();
    if (devfs_root.is_valid()) {
      ethernet_factory_ = std::make_unique<EthernetClientFactory>(
          EthernetClientFactory::kDevfsEthernetRoot, std::move(devfs_root));
    } else {
      ethernet_factory_ = std::make_unique<EthernetClientFactory>();
    }

    // We add a 2 min timeout to this so that it's easier to debug problems with enumerating devices
    // from devfs. By default, MountPointWithMAC would hang forever and would make debugging
    // problems here really hard.
    ethernet_mount_path_ = ethernet_factory_->MountPointWithMAC(mac, zx::sec(120));

    // can't find mount path for ethernet!!
    if (ethernet_mount_path_.empty()) {
      fprintf(stderr, "Failed to locate ethertap device %s %02X:%02X:%02X:%02X:%02X:%02X\n",
              name.c_str(), mac.octets[0], mac.octets[1], mac.octets[2], mac.octets[3],
              mac.octets[4], mac.octets[5]);
      return ZX_ERR_INTERNAL;
    }

    ethertap_->SetPacketCallback(
        [this](std::vector<uint8_t> data) { ForwardData(&data[0], data.size()); });

    ethertap_->SetPeerClosedCallback([this]() { Closed(); });
    return ZX_OK;
  }

  void SetLinkUp(bool up, fit::callback<void()> done) override {
    ethertap_->SetLinkUp(up);
    done();
  }

  fuchsia::netemul::network::DeviceConnection GetDevice() override {
    fidl::InterfaceHandle<fuchsia::hardware::ethernet::Device> ret;
    if (ethernet_factory_) {
      if (ethernet_factory_->Connect(ethernet_mount_path_, ret.NewRequest()) != ZX_OK) {
        // if it didn't succeed, release the request and reset:
        ret = nullptr;
      }
    }
    return fuchsia::netemul::network::DeviceConnection::WithEthernet(std::move(ret));
  }

  void ServeDevice(zx::channel channel) override {
    if (ethernet_factory_) {
      ethernet_factory_->Connect(
          ethernet_mount_path_,
          fidl::InterfaceRequest<fuchsia::hardware::ethernet::Device>(std::move(channel)));
    }
  }

  void Consume(const void* data, size_t len) override {
    auto status = ethertap_->Send(data, len);
    if (status != ZX_OK) {
      fprintf(stderr, "ethertap couldn't push data: %s\n", zx_status_get_string(status));
    }
  }

 private:
  std::string ethernet_mount_path_;
  std::unique_ptr<EthernetClientFactory> ethernet_factory_;
  std::unique_ptr<EthertapClient> ethertap_;
};

class NetworkDeviceImpl : public EndpointImpl, public fuchsia::hardware::network::DeviceInstance {
 public:
  explicit NetworkDeviceImpl(Endpoint::Config config) : EndpointImpl(std::move(config)) {}

  zx_status_t Setup(const std::string& name, bool start_online,
                    const NetworkContext& context) override {
    auto tun_ctl = context.ConnectNetworkTun().BindSync();
    if (!tun_ctl.is_bound()) {
      return ZX_ERR_INTERNAL;
    }
    fuchsia::net::tun::DeviceConfig tun_config;

    tun_config.mutable_base()->set_mtu(config().mtu);
    tun_config.mutable_base()->set_rx_types({fuchsia::hardware::network::FrameType::ETHERNET});
    tun_config.mutable_base()->set_tx_types({fuchsia::hardware::network::FrameTypeSupport{
        .type = fuchsia::hardware::network::FrameType::ETHERNET,
        .features = fuchsia::hardware::network::FRAME_FEATURES_RAW,
        .supported_flags = fuchsia::hardware::network::TxFlags()}});
    if (config().mac) {
      config().mac->Clone(tun_config.mutable_mac());
    } else {
      tun_config.set_mac(RandomMac(name));
    }
    tun_config.set_blocking(true);
    tun_config.set_online(start_online);

    zx_status_t status = tun_ctl->CreateDevice(std::move(tun_config), tun_device_.NewRequest());
    if (status != ZX_OK) {
      return status;
    }
    tun_device_.set_error_handler([this](zx_status_t err) { Closed(); });

    ListenForFrames();
    return ZX_OK;
  }

  void SetLinkUp(bool up, fit::callback<void()> done) override {
    tun_device_->SetOnline(up, [cb = std::move(done)]() mutable { cb(); });
  }

  fuchsia::netemul::network::DeviceConnection GetDevice() override {
    fidl::InterfaceHandle<fuchsia::hardware::network::DeviceInstance> dev;
    ServeDevice(dev.NewRequest().TakeChannel());
    return fuchsia::netemul::network::DeviceConnection::WithNetworkDevice(std::move(dev));
  }

  void ServeDevice(zx::channel req) override {
    instance_bindings_.AddBinding(
        this, fidl::InterfaceRequest<fuchsia::hardware::network::DeviceInstance>(std::move(req)));
  }

  void Consume(const void* data, size_t len) override {
    if (!tun_device_.is_bound()) {
      return;
    }
    auto* p = static_cast<const uint8_t*>(data);
    fuchsia::net::tun::Frame frame;
    frame.set_frame_type(fuchsia::hardware::network::FrameType::ETHERNET);
    frame.set_data(std::vector<uint8_t>(p, p + len));
    tun_device_->WriteFrame(std::move(frame), [](fit::result<void, zx_status_t> status) {
      if (status.is_error()) {
        FX_LOGS(WARNING) << "Failed to send data to network device: "
                         << zx_status_get_string(status.error());
      }
    });
  }

  void GetDevice(::fidl::InterfaceRequest<fuchsia::hardware::network::Device> device) override {
    if (!tun_device_.is_bound()) {
      return;
    }

    fuchsia::net::tun::Protocols protos;
    protos.set_network_device(std::move(device));
    tun_device_->ConnectProtocols(std::move(protos));
  }

  void GetMacAddressing(
      fidl::InterfaceRequest<fuchsia::hardware::network::MacAddressing> mac) override {
    if (!tun_device_.is_bound()) {
      return;
    }
    fuchsia::net::tun::Protocols protos;
    protos.set_mac_addressing(std::move(mac));
    tun_device_->ConnectProtocols(std::move(protos));
  }

 private:
  void ListenForFrames() {
    if (!tun_device_.is_bound()) {
      return;
    }
    tun_device_->ReadFrame([this](fuchsia::net::tun::Device_ReadFrame_Result result) {
      if (result.is_response()) {
        auto& data = result.response().frame.data();
        ForwardData(&data[0], data.size());
      } else {
        FX_LOGS(ERROR) << "ReadFrame from Tun Device failed " << zx_status_get_string(result.err());
      }

      // Listen again for the next frame.
      ListenForFrames();
    });
  }

  fuchsia::net::tun::DevicePtr tun_device_;
  fidl::BindingSet<fuchsia::hardware::network::DeviceInstance> instance_bindings_;
};

std::unique_ptr<EndpointImpl> MakeImpl(Endpoint::Config config) {
  switch (config.backing) {
    case Endpoint::Backing::ETHERTAP:
      return std::make_unique<EthertapImpl>(std::move(config));
    case Endpoint::Backing::NETWORK_DEVICE:
      return std::make_unique<NetworkDeviceImpl>(std::move(config));
  }
}

}  // namespace impl

Endpoint::Endpoint(NetworkContext* context, std::string name, Endpoint::Config config)
    : impl_(impl::MakeImpl(std::move(config))), parent_(context), name_(std::move(name)) {
  auto close_handler = [this]() {
    if (closed_callback_) {
      // bubble up the problem
      closed_callback_(*this);
    }
  };

  impl_->SetClosedCallback(close_handler);
  bindings_.set_empty_set_handler(close_handler);
}

zx_status_t Endpoint::Startup(const NetworkContext& context, bool start_online) {
  return impl_->Setup(name_, start_online, context);
}

Endpoint::~Endpoint() = default;

void Endpoint::GetConfig(Endpoint::GetConfigCallback callback) {
  Config config;
  impl_->CloneConfig(&config);
  callback(std::move(config));
}

void Endpoint::GetName(Endpoint::GetNameCallback callback) { callback(name_); }

void Endpoint::SetLinkUp(bool up, Endpoint::SetLinkUpCallback callback) {
  impl_->SetLinkUp(up, std::move(callback));
}

void Endpoint::GetDevice(Endpoint::GetDeviceCallback callback) { callback(impl_->GetDevice()); }

void Endpoint::GetProxy(fidl::InterfaceRequest<FProxy> proxy) {
  proxy_bindings_.AddBinding(this, std::move(proxy), parent_->dispatcher());
}

void Endpoint::ServeDevice(zx::channel channel) { impl_->ServeDevice(std::move(channel)); }

void Endpoint::Bind(fidl::InterfaceRequest<FEndpoint> req) {
  bindings_.AddBinding(this, std::move(req), parent_->dispatcher());
}

zx_status_t Endpoint::InstallSink(data::BusConsumer::Ptr sink, data::Consumer::Ptr* src) {
  // just forbid install if sink is already in our list:
  auto& sinks = impl_->sinks();
  for (auto& i : sinks) {
    if (i.get() == sink.get()) {
      return ZX_ERR_ALREADY_BOUND;
    }
  }
  impl_->sinks().emplace_back(std::move(sink));
  *src = impl_->GetPointer();
  return ZX_OK;
}

zx_status_t Endpoint::RemoveSink(data::BusConsumer::Ptr sink, data::Consumer::Ptr* src) {
  auto& sinks = impl_->sinks();
  for (auto i = sinks.begin(); i != sinks.end(); i++) {
    if (i->get() == sink.get()) {
      sinks.erase(i);
      *src = impl_->GetPointer();
      return ZX_OK;
    }
  }
  return ZX_ERR_NOT_FOUND;
}

void Endpoint::SetClosedCallback(Endpoint::EndpointClosedCallback cb) {
  closed_callback_ = std::move(cb);
}

}  // namespace netemul
