// 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/lib/inet/socket_address.h"

#include <endian.h>

#include <sstream>

namespace inet {

// static
const SocketAddress SocketAddress::kInvalid;

SocketAddress::SocketAddress() { std::memset(&v6_, 0, sizeof(v6_)); }

SocketAddress::SocketAddress(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, IpPort port) {
  std::memset(&v4_, 0, sizeof(v4_));
  v4_.sin_family = AF_INET;
  v4_.sin_port = port.as_in_port_t();
  uint8_t* bytes = reinterpret_cast<uint8_t*>(&v4_.sin_addr);
  bytes[0] = b0;
  bytes[1] = b1;
  bytes[2] = b2;
  bytes[3] = b3;
}

SocketAddress::SocketAddress(in_addr_t addr, IpPort port) {
  std::memset(&v4_, 0, sizeof(v4_));
  v4_.sin_family = AF_INET;
  v4_.sin_port = port.as_in_port_t();
  v4_.sin_addr.s_addr = addr;
}

SocketAddress::SocketAddress(const sockaddr_in& addr) {
  FX_DCHECK(addr.sin_family == AF_INET);
  v4_ = addr;
}

SocketAddress::SocketAddress(uint16_t w0, uint16_t w1, uint16_t w2, uint16_t w3, uint16_t w4,
                             uint16_t w5, uint16_t w6, uint16_t w7, IpPort port) {
  std::memset(&v6_, 0, sizeof(v6_));
  v6_.sin6_family = AF_INET6;
  v6_.sin6_port = port.as_in_port_t();
  uint16_t* words = v6_.sin6_addr.s6_addr16;
  words[0] = htobe16(w0);
  words[1] = htobe16(w1);
  words[2] = htobe16(w2);
  words[3] = htobe16(w3);
  words[4] = htobe16(w4);
  words[5] = htobe16(w5);
  words[6] = htobe16(w6);
  words[7] = htobe16(w7);
}

SocketAddress::SocketAddress(uint16_t w0, uint16_t w7, IpPort port) {
  std::memset(&v6_, 0, sizeof(v6_));
  v6_.sin6_family = AF_INET6;
  v6_.sin6_port = port.as_in_port_t();
  uint16_t* words = v6_.sin6_addr.s6_addr16;
  words[0] = htobe16(w0);
  words[7] = htobe16(w7);
}

SocketAddress::SocketAddress(const in6_addr& addr, IpPort port) {
  std::memset(&v6_, 0, sizeof(v6_));
  v6_.sin6_family = AF_INET6;
  v6_.sin6_port = port.as_in_port_t();
  v6_.sin6_addr = addr;
}

SocketAddress::SocketAddress(const sockaddr_in6& addr) {
  FX_DCHECK(addr.sin6_family == AF_INET6);
  v6_ = addr;
}

void SocketAddress::Build(const IpAddress& addr, IpPort port, uint32_t scope_id) {
  if (!addr.is_valid()) {
    std::memset(&v6_, 0, sizeof(v6_));
    return;
  }

  if (addr.is_v4()) {
    std::memset(&v4_, 0, sizeof(v4_));
    v4_.sin_family = AF_INET;
    v4_.sin_port = port.as_in_port_t();
    v4_.sin_addr = addr.as_in_addr();
  } else {
    std::memset(&v6_, 0, sizeof(v6_));
    v6_.sin6_family = AF_INET6;
    v6_.sin6_port = port.as_in_port_t();
    v6_.sin6_addr = addr.as_in6_addr();
    v6_.sin6_scope_id = scope_id;
  }
}

SocketAddress::SocketAddress(const IpAddress& addr, IpPort port, uint32_t scope_id) {
  Build(addr, port, scope_id);
}

SocketAddress::SocketAddress(const sockaddr_storage& addr) {
  FX_DCHECK(addr.ss_family == AF_INET || addr.ss_family == AF_INET6);
  if (addr.ss_family == AF_INET) {
    v4_ = *reinterpret_cast<const sockaddr_in*>(&addr);
  } else {
    v6_ = *reinterpret_cast<const sockaddr_in6*>(&addr);
  }
}

SocketAddress::SocketAddress(const fuchsia::netstack::SocketAddress* addr)
    : SocketAddress(IpAddress(&addr->addr), IpPort::From_uint16_t(addr->port)) {
  FX_DCHECK(addr != nullptr);
}

SocketAddress::SocketAddress(const fuchsia::net::SocketAddress* addr) : SocketAddress() {
  FX_DCHECK(addr != nullptr);
  switch (addr->Which()) {
    case fuchsia::net::SocketAddress::kIpv4:
      Build(IpAddress(&addr->ipv4().address), IpPort::From_uint16_t(addr->ipv4().port), 0);
      break;
    case fuchsia::net::SocketAddress::kIpv6:
      Build(IpAddress(&addr->ipv6().address), IpPort::From_uint16_t(addr->ipv6().port),
            static_cast<uint32_t>(addr->ipv6().zone_index));
      break;
    case fuchsia::net::SocketAddress::Invalid:
      break;
  }
}

SocketAddress::SocketAddress(const fuchsia::net::Ipv4SocketAddress* addr)
    : SocketAddress(IpAddress(&addr->address), IpPort::From_uint16_t(addr->port)) {
  FX_DCHECK(addr != nullptr);
}

SocketAddress::SocketAddress(const fuchsia::net::Ipv6SocketAddress* addr) {
  FX_DCHECK(addr != nullptr);
  Build(IpAddress(&addr->address), IpPort::From_uint16_t(addr->port),
        static_cast<uint32_t>(addr->zone_index));
}

std::string SocketAddress::ToString() const {
  std::ostringstream os;
  os << *this;
  return os.str();
}

std::ostream& operator<<(std::ostream& os, const SocketAddress& value) {
  if (!value.is_valid()) {
    return os << "<invalid>";
  }

  return os << value.address() << ":" << value.port();
}

}  // namespace inet
