// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include "util/network-util.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <limits.h>
#include <algorithm>
#include <sstream>
#include <random>
#include <vector>
#include <boost/algorithm/string.hpp>

#include "exec/kudu-util.h"
#include "kudu/util/net/sockaddr.h"
#include "util/debug-util.h"
#include "util/error-util.h"
#include <util/string-parser.h>

#include "common/names.h"

using boost::algorithm::is_any_of;
using boost::algorithm::split;
using std::find;
using std::random_device;

#ifdef __APPLE__
// OS X does not seem to have a similar limitation as Linux and thus the
// macro is not defined.
#define HOST_NAME_MAX 64
#endif

namespace impala {

const string LOCALHOST_IP_STR("127.0.0.1");

Status GetHostname(string* hostname) {
  char name[HOST_NAME_MAX];
  int ret = gethostname(name, HOST_NAME_MAX);
  if (ret != 0) {
    string error_msg = GetStrErrMsg();
    stringstream ss;
    ss << "Could not get hostname: " << error_msg;
    return Status(ss.str());
  }
  *hostname = string(name);
  return Status::OK();
}

Status HostnameToIpAddr(const Hostname& hostname, IpAddr* ip){
  // Try to resolve via the operating system.
  vector<IpAddr> addresses;
  addrinfo hints;
  memset(&hints, 0, sizeof(struct addrinfo));
  hints.ai_family = AF_INET; // IPv4 addresses only
  hints.ai_socktype = SOCK_STREAM;

  struct addrinfo* addr_info;
  if (getaddrinfo(hostname.c_str(), NULL, &hints, &addr_info) != 0) {
    stringstream ss;
    ss << "Could not find IPv4 address for: " << hostname;
    return Status(ss.str());
  }

  addrinfo* it = addr_info;
  while (it != NULL) {
    char addr_buf[64];
    const char* result =
        inet_ntop(AF_INET, &((sockaddr_in*)it->ai_addr)->sin_addr, addr_buf, 64);
    if (result == NULL) {
      stringstream ss;
      ss << "Could not convert IPv4 address for: " << hostname;
      freeaddrinfo(addr_info);
      return Status(ss.str());
    }
    addresses.push_back(string(addr_buf));
    it = it->ai_next;
  }

  freeaddrinfo(addr_info);

  if (addresses.empty()) {
    stringstream ss;
    ss << "Could not convert IPv4 address for: " << hostname;
    return Status(ss.str());
  }

  // RFC 3484 only specifies a partial order for the result of getaddrinfo() so we need to
  // sort the addresses before picking the first non-localhost one.
  sort(addresses.begin(), addresses.end());

  // Try to find a non-localhost address, otherwise just use the first IP address
  // returned.
  *ip = addresses[0];
  if (!FindFirstNonLocalhost(addresses, ip)) {
    VLOG(3) << "Only localhost addresses found for " << hostname;
  }
  return Status::OK();
}

bool IsResolvedAddress(const TNetworkAddress& addr) {
  kudu::Sockaddr sock;
  return sock.ParseString(addr.hostname, addr.port).ok();
}

bool FindFirstNonLocalhost(const vector<string>& addresses, string* addr) {
  for (const string& candidate: addresses) {
    if (candidate != LOCALHOST_IP_STR) {
      *addr = candidate;
      return true;
    }
  }

  return false;
}

TNetworkAddress MakeNetworkAddress(const string& hostname, int port) {
  TNetworkAddress ret;
  ret.__set_hostname(hostname);
  ret.__set_port(port);
  return ret;
}

TNetworkAddress MakeNetworkAddress(const string& address) {
  vector<string> tokens;
  split(tokens, address, is_any_of(":"));
  TNetworkAddress ret;
  if (tokens.size() == 1) {
    ret.__set_hostname(tokens[0]);
    ret.port = 0;
    return ret;
  }
  if (tokens.size() != 2) return ret;
  ret.__set_hostname(tokens[0]);
  StringParser::ParseResult parse_result;
  int32_t port = StringParser::StringToInt<int32_t>(
      tokens[1].data(), tokens[1].length(), &parse_result);
  if (parse_result != StringParser::PARSE_SUCCESS) return ret;
  ret.__set_port(port);
  return ret;
}

bool IsWildcardAddress(const string& ipaddress) {
  return ipaddress == "0.0.0.0";
}

string TNetworkAddressToString(const TNetworkAddress& address) {
  stringstream ss;
  ss << address.hostname << ":" << dec << address.port;
  return ss.str();
}

string NetworkAddressPBToString(const NetworkAddressPB& address) {
  stringstream ss;
  ss << address.hostname() << ":" << dec << address.port();
  return ss.str();
}

TNetworkAddress FromNetworkAddressPB(const NetworkAddressPB& address) {
  TNetworkAddress t_address;
  t_address.__set_hostname(address.hostname());
  t_address.__set_port(address.port());
  return t_address;
}

/// Pick a random port in the range of ephemeral ports
/// https://tools.ietf.org/html/rfc6335
int FindUnusedEphemeralPort() {
  static uint32_t LOWER = 49152, UPPER = 65000;
  random_device rd;
  srand(rd());

  int sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd < 0) return -1;
  struct sockaddr_in server_address;
  bzero(reinterpret_cast<char*>(&server_address), sizeof(server_address));
  server_address.sin_family = AF_INET;
  server_address.sin_addr.s_addr = INADDR_ANY;
  for (int tries = 0; tries < 100; ++tries) {
    int port = LOWER + rand() % (UPPER - LOWER);
    server_address.sin_port = htons(port);
    if (bind(sockfd, reinterpret_cast<struct sockaddr*>(&server_address),
        sizeof(server_address)) == 0) {
      close(sockfd);
      return port;
    }
  }
  close(sockfd);
  return -1;
}

Status TNetworkAddressToSockaddr(const TNetworkAddress& address,
    kudu::Sockaddr* sockaddr) {
  DCHECK(IsResolvedAddress(address));
  KUDU_RETURN_IF_ERROR(
      sockaddr->ParseString(TNetworkAddressToString(address), address.port),
      "Failed to parse address to Kudu Sockaddr.");
  return Status::OK();
}

}
