// Copyright 2017 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 "src/connectivity/network/mdns/service/mdns_service_impl.h"

#include <fuchsia/netstack/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/async/default.h>
#include <lib/sys/cpp/component_context.h>
#include <unistd.h>

#include "lib/fidl/cpp/type_converter.h"
#include "lib/fsl/types/type_converters.h"
#include "src/connectivity/network/mdns/service/mdns_fidl_util.h"
#include "src/connectivity/network/mdns/service/mdns_names.h"
#include "src/lib/fxl/logging.h"

namespace mdns {
namespace {

static const std::string kUnsetHostName = "fuchsia-unset-device-name";
static constexpr zx::duration kReadyPollingInterval = zx::sec(1);

std::string GetHostName() {
  char host_name_buffer[HOST_NAME_MAX + 1];
  int result = gethostname(host_name_buffer, sizeof(host_name_buffer));

  std::string host_name;

  if (result < 0) {
    FXL_LOG(ERROR) << "gethostname failed, " << strerror(errno);
    host_name = kUnsetHostName;
  } else {
    host_name = host_name_buffer;
  }

  return host_name;
}

}  // namespace

MdnsServiceImpl::MdnsServiceImpl(sys::ComponentContext* component_context)
    : component_context_(component_context),
      resolver_bindings_(this, "Resolver"),
      subscriber_bindings_(this, "Subscriber"),
      publisher_bindings_(this, "Publisher") {
  component_context_->outgoing()
      ->AddPublicService<fuchsia::net::mdns::Resolver>(fit::bind_member(
          &resolver_bindings_,
          &BindingSet<fuchsia::net::mdns::Resolver>::OnBindRequest));
  component_context_->outgoing()
      ->AddPublicService<fuchsia::net::mdns::Subscriber>(fit::bind_member(
          &subscriber_bindings_,
          &BindingSet<fuchsia::net::mdns::Subscriber>::OnBindRequest));
  component_context_->outgoing()
      ->AddPublicService<fuchsia::net::mdns::Publisher>(fit::bind_member(
          &publisher_bindings_,
          &BindingSet<fuchsia::net::mdns::Publisher>::OnBindRequest));
  Start();
}

MdnsServiceImpl::~MdnsServiceImpl() {}

void MdnsServiceImpl::Start() {
  std::string host_name = GetHostName();

  if (host_name == kUnsetHostName) {
    // Host name not set. Try again soon.
    async::PostDelayedTask(
        async_get_default_dispatcher(), [this]() { Start(); },
        kReadyPollingInterval);
    return;
  }

  config_.ReadConfigFiles(host_name);
  if (!config_.valid()) {
    FXL_LOG(FATAL) << "Invalid config file(s), terminating: "
                   << config_.error();
    return;
  }

  mdns_.Start(component_context_->svc()->Connect<fuchsia::netstack::Netstack>(),
              host_name, config_.addresses(), config_.perform_host_name_probe(),
              fit::bind_member(this, &MdnsServiceImpl::OnReady));
}

void MdnsServiceImpl::OnReady() {
  ready_ = true;

  // Publish as indicated in config files.
  for (auto& publication : config_.publications()) {
    PublishServiceInstance(
        publication.service_, publication.instance_,
        publication.publication_->Clone(), true,
        [this, service = publication.service_](
            fuchsia::net::mdns::Publisher_PublishServiceInstance_Result
                result) {
          if (result.is_err()) {
            FXL_LOG(ERROR) << "Failed to publish as " << service << ", result "
                           << static_cast<uint32_t>(result.err());
          }
        });
  }

  resolver_bindings_.OnReady();
  subscriber_bindings_.OnReady();
  publisher_bindings_.OnReady();
}

bool MdnsServiceImpl::PublishServiceInstance(
    std::string service_name, std::string instance_name,
    std::unique_ptr<Mdns::Publication> publication, bool perform_probe,
    PublishServiceInstanceCallback callback) {
  auto publisher = std::make_unique<SimplePublisher>(std::move(publication),
                                                     callback.share());

  if (!mdns_.PublishServiceInstance(service_name, instance_name, perform_probe,
                                    publisher.get())) {
    return false;
  }

  std::string instance_full_name =
      MdnsNames::LocalInstanceFullName(instance_name, service_name);

  // |Mdns| told us our instance is unique locally, so the full name should
  // not appear in our collection.
  FXL_DCHECK(publishers_by_instance_full_name_.find(instance_full_name) ==
             publishers_by_instance_full_name_.end());

  publishers_by_instance_full_name_.emplace(instance_full_name,
                                            std::move(publisher));

  return true;
}

void MdnsServiceImpl::ResolveHostName(std::string host, int64_t timeout_ns,
                                      ResolveHostNameCallback callback) {
  if (!MdnsNames::IsValidHostName(host)) {
    FXL_LOG(ERROR) << "ResolveHostName called with invalid host name " << host;
    callback(nullptr, nullptr);
    return;
  }

  mdns_.ResolveHostName(
      host, fxl::TimePoint::Now() + fxl::TimeDelta::FromNanoseconds(timeout_ns),
      [this, callback = std::move(callback)](
          const std::string& host, const inet::IpAddress& v4_address,
          const inet::IpAddress& v6_address) {
        callback(v4_address ? std::make_unique<fuchsia::net::Ipv4Address>(
                                  MdnsFidlUtil::CreateIpv4Address(v4_address))
                            : nullptr,
                 v6_address ? std::make_unique<fuchsia::net::Ipv6Address>(
                                  MdnsFidlUtil::CreateIpv6Address(v6_address))
                            : nullptr);
      });
}

void MdnsServiceImpl::SubscribeToService(
    std::string service,
    fidl::InterfaceHandle<fuchsia::net::mdns::ServiceSubscriber>
        subscriber_handle) {
  if (!MdnsNames::IsValidServiceName(service)) {
    FXL_LOG(ERROR) << "ResolveHostName called with invalid service name "
                   << service;
    return;
  }

  size_t id = next_subscriber_id_++;
  auto subscriber = std::make_unique<Subscriber>(
      std::move(subscriber_handle),
      [this, id]() { subscribers_by_id_.erase(id); });

  mdns_.SubscribeToService(service, subscriber.get());

  subscribers_by_id_.emplace(id, std::move(subscriber));
}

void MdnsServiceImpl::PublishServiceInstance(
    std::string service, std::string instance, bool perform_probe,
    fidl::InterfaceHandle<fuchsia::net::mdns::PublicationResponder>
        responder_handle,
    PublishServiceInstanceCallback callback) {
  FXL_DCHECK(responder_handle);

  if (!MdnsNames::IsValidServiceName(service)) {
    FXL_LOG(ERROR) << "PublishServiceInstance called with invalid service name "
                   << service;
    fuchsia::net::mdns::Publisher_PublishServiceInstance_Result result;
    result.set_err(fuchsia::net::mdns::Error::INVALID_SERVICE_NAME);
    callback(std::move(result));
    return;
  }

  if (!MdnsNames::IsValidInstanceName(instance)) {
    FXL_LOG(ERROR)
        << "PublishServiceInstance called with invalid instance name "
        << instance;
    fuchsia::net::mdns::Publisher_PublishServiceInstance_Result result;
    result.set_err(fuchsia::net::mdns::Error::INVALID_INSTANCE_NAME);
    callback(std::move(result));
    return;
  }

  auto responder_ptr = responder_handle.Bind();
  FXL_DCHECK(responder_ptr);

  std::string instance_full_name =
      MdnsNames::LocalInstanceFullName(instance, service);

  auto publisher = std::make_unique<ResponderPublisher>(
      std::move(responder_ptr), std::move(callback),
      [this, instance_full_name]() {
        publishers_by_instance_full_name_.erase(instance_full_name);
      });

  if (!mdns_.PublishServiceInstance(service, instance, perform_probe,
                                    publisher.get())) {
    fuchsia::net::mdns::Publisher_PublishServiceInstance_Result result;
    result.set_err(fuchsia::net::mdns::Error::ALREADY_PUBLISHED_LOCALLY);
    callback(std::move(result));
    return;
  }

  // |Mdns| told us our instance is unique locally, so the full name should
  // not appear in our collection.
  FXL_DCHECK(publishers_by_instance_full_name_.find(instance_full_name) ==
             publishers_by_instance_full_name_.end());

  publishers_by_instance_full_name_.emplace(instance_full_name,
                                            std::move(publisher));
}

////////////////////////////////////////////////////////////////////////////////
// MdnsServiceImpl::Subscriber implementation

MdnsServiceImpl::Subscriber::Subscriber(
    fidl::InterfaceHandle<fuchsia::net::mdns::ServiceSubscriber> handle,
    fit::closure deleter) {
  client_.Bind(std::move(handle));
  client_.set_error_handler(
      [this, deleter = std::move(deleter)](zx_status_t status) {
        client_.set_error_handler(nullptr);
        client_.Unbind();
        deleter();
      });
}

MdnsServiceImpl::Subscriber::~Subscriber() {}

void MdnsServiceImpl::Subscriber::InstanceDiscovered(
    const std::string& service, const std::string& instance,
    const inet::SocketAddress& v4_address,
    const inet::SocketAddress& v6_address, const std::vector<std::string>& text,
    uint16_t srv_priority, uint16_t srv_weight) {
  Entry entry{.type = EntryType::kInstanceDiscovered,
              .service_instance = fuchsia::net::mdns::ServiceInstance{
                  .service = service,
                  .instance = instance,
                  .text = fidl::VectorPtr<std::string>(text),
                  .srv_priority = srv_priority,
                  .srv_weight = srv_weight}};
  if (v4_address) {
    entry.service_instance.endpoints.push_back(
        MdnsFidlUtil::CreateEndpointV4(v4_address));
  }

  if (v6_address) {
    entry.service_instance.endpoints.push_back(
        MdnsFidlUtil::CreateEndpointV6(v6_address));
  }

  entries_.push(std::move(entry));
  MaybeSendNextEntry();
}

void MdnsServiceImpl::Subscriber::InstanceChanged(
    const std::string& service, const std::string& instance,
    const inet::SocketAddress& v4_address,
    const inet::SocketAddress& v6_address, const std::vector<std::string>& text,
    uint16_t srv_priority, uint16_t srv_weight) {
  Entry entry{.type = EntryType::kInstanceChanged,
              .service_instance = fuchsia::net::mdns::ServiceInstance{
                  .service = service,
                  .instance = instance,
                  .text = fidl::VectorPtr<std::string>(text),
                  .srv_priority = srv_priority,
                  .srv_weight = srv_weight}};
  if (v4_address) {
    entry.service_instance.endpoints.push_back(
        MdnsFidlUtil::CreateEndpointV4(v4_address));
  }

  if (v6_address) {
    entry.service_instance.endpoints.push_back(
        MdnsFidlUtil::CreateEndpointV6(v6_address));
  }

  entries_.push(std::move(entry));
  MaybeSendNextEntry();
}

void MdnsServiceImpl::Subscriber::InstanceLost(const std::string& service,
                                               const std::string& instance) {
  entries_.push({.type = EntryType::kInstanceLost,
                 .service_instance = fuchsia::net::mdns::ServiceInstance{
                     .service = service, .instance = instance}});
  MaybeSendNextEntry();
}

void MdnsServiceImpl::Subscriber::MaybeSendNextEntry() {
  FXL_DCHECK(pipeline_depth_ <= kMaxPipelineDepth);
  if (pipeline_depth_ == kMaxPipelineDepth || entries_.empty()) {
    return;
  }

  Entry& entry = entries_.front();
  auto on_reply =
      fit::bind_member(this, &MdnsServiceImpl::Subscriber::ReplyReceived);

  switch (entry.type) {
    case EntryType::kInstanceDiscovered:
      client_->OnInstanceDiscovered(std::move(entry.service_instance),
                                    std::move(on_reply));
      break;
    case EntryType::kInstanceChanged:
      client_->OnInstanceChanged(std::move(entry.service_instance),
                                 std::move(on_reply));
      break;
    case EntryType::kInstanceLost:
      client_->OnInstanceLost(entry.service_instance.service,
                              entry.service_instance.instance,
                              std::move(on_reply));
      break;
  }

  ++pipeline_depth_;
  entries_.pop();
}

void MdnsServiceImpl::Subscriber::ReplyReceived() {
  FXL_DCHECK(pipeline_depth_ != 0);
  --pipeline_depth_;
  MaybeSendNextEntry();
}

////////////////////////////////////////////////////////////////////////////////
// MdnsServiceImpl::SimplePublisher implementation

MdnsServiceImpl::SimplePublisher::SimplePublisher(
    std::unique_ptr<Mdns::Publication> publication,
    PublishServiceInstanceCallback callback)
    : publication_(std::move(publication)), callback_(std::move(callback)) {}

void MdnsServiceImpl::SimplePublisher::ReportSuccess(bool success) {
  fuchsia::net::mdns::Publisher_PublishServiceInstance_Result result;
  if (success) {
    result.set_response(
        fuchsia::net::mdns::Publisher_PublishServiceInstance_Response());
  } else {
    result.set_err(fuchsia::net::mdns::Error::ALREADY_PUBLISHED_ON_SUBNET);
  }

  callback_(std::move(result));
}

void MdnsServiceImpl::SimplePublisher::GetPublication(
    bool query, const std::string& subtype,
    fit::function<void(std::unique_ptr<Mdns::Publication>)> callback) {
  FXL_DCHECK(subtype.empty() || MdnsNames::IsValidSubtypeName(subtype));
  callback(publication_->Clone());
}

////////////////////////////////////////////////////////////////////////////////
// MdnsServiceImpl::ResponderPublisher implementation

MdnsServiceImpl::ResponderPublisher::ResponderPublisher(
    fuchsia::net::mdns::PublicationResponderPtr responder,
    PublishServiceInstanceCallback callback, fit::closure deleter)
    : responder_(std::move(responder)), callback_(std::move(callback)) {
  FXL_DCHECK(responder_);

  responder_.set_error_handler(
      [this, deleter = std::move(deleter)](zx_status_t status) {
        responder_.set_error_handler(nullptr);
        deleter();
      });

  responder_.events().SetSubtypes = [this](std::vector<std::string> subtypes) {
    for (auto& subtype : subtypes) {
      if (!MdnsNames::IsValidSubtypeName(subtype)) {
        FXL_LOG(ERROR) << "Invalid subtype " << subtype
                       << " passed in SetSubtypes event, closing connection.";
        responder_ = nullptr;
        Unpublish();
        return;
      }
    }

    SetSubtypes(std::move(subtypes));
  };

  responder_.events().Reannounce = [this]() { Reannounce(); };
}

void MdnsServiceImpl::ResponderPublisher::ReportSuccess(bool success) {
  fuchsia::net::mdns::Publisher_PublishServiceInstance_Result result;
  if (success) {
    result.set_response(
        fuchsia::net::mdns::Publisher_PublishServiceInstance_Response());
  } else {
    result.set_err(fuchsia::net::mdns::Error::ALREADY_PUBLISHED_ON_SUBNET);
  }

  callback_(std::move(result));
}

void MdnsServiceImpl::ResponderPublisher::GetPublication(
    bool query, const std::string& subtype,
    fit::function<void(std::unique_ptr<Mdns::Publication>)> callback) {
  FXL_DCHECK(subtype.empty() || MdnsNames::IsValidSubtypeName(subtype));
  FXL_DCHECK(responder_);
  responder_->OnPublication(
      query, subtype,
      [this, callback = std::move(callback)](
          fuchsia::net::mdns::PublicationPtr publication_ptr) {
        if (publication_ptr) {
          for (auto& text : publication_ptr->text) {
            if (!MdnsNames::IsValidTextString(text)) {
              FXL_LOG(ERROR) << "Invalid text string returned by "
                                "Responder.GetPublication, closing connection.";
              responder_ = nullptr;
              Unpublish();
              return;
            }
          }

          if (publication_ptr->ptr_ttl < ZX_SEC(1) ||
              publication_ptr->srv_ttl < ZX_SEC(1) ||
              publication_ptr->txt_ttl < ZX_SEC(1)) {
            FXL_LOG(ERROR) << "TTL less than one second returned by "
                              "Responder.GetPublication, closing connection.";
            responder_ = nullptr;
            Unpublish();
            return;
          }
        }

        callback(MdnsFidlUtil::Convert(publication_ptr));
      });
}

}  // namespace mdns
