1efbfdb0cSShuo Chen#include "InetAddress.h"
2efbfdb0cSShuo Chen
324ca08a8SShuo Chen#include <memory>
424ca08a8SShuo Chen
55b543c9cSShuo Chen#include <assert.h>
65b543c9cSShuo Chen#include <arpa/inet.h>
724ca08a8SShuo Chen#include <netdb.h>
824ca08a8SShuo Chen
924ca08a8SShuo Chenstatic_assert(sizeof(InetAddress) == sizeof(struct sockaddr_in6),
1024ca08a8SShuo Chen              "InetAddress is same size as sockaddr_in6");
1114ca1249SShuo Chen#ifdef __linux
1224ca08a8SShuo Chenstatic_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0");
1324ca08a8SShuo Chenstatic_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0");
14e146b157SShuo Chen#endif
15e146b157SShuo Chenstatic_assert(offsetof(sockaddr_in, sin_family) == offsetof(sockaddr_in6, sin6_family),
16e146b157SShuo Chen              "sin_family/sin6_family offset");
1724ca08a8SShuo Chenstatic_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2");
1824ca08a8SShuo Chenstatic_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2");
195b543c9cSShuo Chen
20aafef3ccSShuo ChenInetAddress::InetAddress(StringArg ip, uint16_t port)
21aafef3ccSShuo Chen{
2224ca08a8SShuo Chen  setPort(port);
2324ca08a8SShuo Chen
2424ca08a8SShuo Chen  int result = 0;
2524ca08a8SShuo Chen  if (strchr(ip.c_str(), ':') == NULL)
2624ca08a8SShuo Chen  {
2724ca08a8SShuo Chen    result = ::inet_pton(AF_INET, ip.c_str(), &addr_.sin_addr);
28246b2f80SShuo Chen    addr_.sin_family = AF_INET;
2924ca08a8SShuo Chen  }
3024ca08a8SShuo Chen  else
3124ca08a8SShuo Chen  {
3224ca08a8SShuo Chen    result = ::inet_pton(AF_INET6, ip.c_str(), &addr6_.sin6_addr);
33246b2f80SShuo Chen    addr6_.sin6_family = AF_INET6;
3424ca08a8SShuo Chen  }
3524ca08a8SShuo Chen
3624ca08a8SShuo Chen  assert(result == 1 && "Invalid IP format");
37aafef3ccSShuo Chen}
38efbfdb0cSShuo Chen
3924ca08a8SShuo ChenInetAddress::InetAddress(uint16_t port, bool ipv6)
40efbfdb0cSShuo Chen{
4124ca08a8SShuo Chen  static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0");
4224ca08a8SShuo Chen  static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0");
4324ca08a8SShuo Chen  bool loopbackOnly = false;
4424ca08a8SShuo Chen  if (ipv6)
4524ca08a8SShuo Chen  {
4624ca08a8SShuo Chen    memZero(&addr6_, sizeof addr6_);
4724ca08a8SShuo Chen    addr6_.sin6_family = AF_INET6;
4824ca08a8SShuo Chen    in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any;
4924ca08a8SShuo Chen    addr6_.sin6_addr = ip;
5024ca08a8SShuo Chen    addr6_.sin6_port = htons(port);
5124ca08a8SShuo Chen  }
5224ca08a8SShuo Chen  else
5324ca08a8SShuo Chen  {
5424ca08a8SShuo Chen    memZero(&addr_, sizeof addr_);
5524ca08a8SShuo Chen    addr_.sin_family = AF_INET;
5624ca08a8SShuo Chen    in_addr_t ip = loopbackOnly ? INADDR_LOOPBACK : INADDR_ANY;
5724ca08a8SShuo Chen    addr_.sin_addr.s_addr = htonl(ip);
5824ca08a8SShuo Chen    addr_.sin_port = htons(port);
5924ca08a8SShuo Chen  }
6024ca08a8SShuo Chen}
6124ca08a8SShuo Chen
6224ca08a8SShuo ChenInetAddress::InetAddress(const struct sockaddr& saddr)
6324ca08a8SShuo Chen{
6424ca08a8SShuo Chen  if (saddr.sa_family == AF_INET)
6524ca08a8SShuo Chen  {
6624ca08a8SShuo Chen    memcpy(&addr_, &saddr, sizeof addr_);
6724ca08a8SShuo Chen  }
6824ca08a8SShuo Chen  else if (saddr.sa_family == AF_INET6)
6924ca08a8SShuo Chen  {
7024ca08a8SShuo Chen    memcpy(&addr6_, &saddr, sizeof addr6_);
7124ca08a8SShuo Chen  }
7224ca08a8SShuo Chen  else
7324ca08a8SShuo Chen  {
7424ca08a8SShuo Chen    assert(false);
7524ca08a8SShuo Chen  }
76efbfdb0cSShuo Chen}
775b543c9cSShuo Chen
785b543c9cSShuo Chenstd::string InetAddress::toIp() const
795b543c9cSShuo Chen{
8024ca08a8SShuo Chen  char buf[64] = "";
8124ca08a8SShuo Chen  static_assert(sizeof buf >= INET_ADDRSTRLEN);
8224ca08a8SShuo Chen  static_assert(sizeof buf >= INET6_ADDRSTRLEN);
8324ca08a8SShuo Chen
8424ca08a8SShuo Chen  if (family() == AF_INET)
8524ca08a8SShuo Chen  {
8624ca08a8SShuo Chen    ::inet_ntop(AF_INET, &addr_.sin_addr, buf, static_cast<socklen_t>(sizeof buf));
8724ca08a8SShuo Chen  }
8824ca08a8SShuo Chen  else if (family() == AF_INET6)
8924ca08a8SShuo Chen  {
9024ca08a8SShuo Chen    ::inet_ntop(AF_INET6, &addr6_.sin6_addr, buf, static_cast<socklen_t>(sizeof buf));
9124ca08a8SShuo Chen  }
9224ca08a8SShuo Chen
935b543c9cSShuo Chen  return buf;
945b543c9cSShuo Chen}
955b543c9cSShuo Chen
965b543c9cSShuo Chenstd::string InetAddress::toIpPort() const
975b543c9cSShuo Chen{
9824ca08a8SShuo Chen  char buf[32] = "";
9924ca08a8SShuo Chen  snprintf(buf, sizeof buf, ":%u", port());
100e0ccc29fSShuo Chen
101e0ccc29fSShuo Chen  if (family() == AF_INET6)
102e0ccc29fSShuo Chen    return "[" + toIp() + "]" + buf;
103e0ccc29fSShuo Chen
10424ca08a8SShuo Chen  return toIp() + buf;
1055b543c9cSShuo Chen}
1065b543c9cSShuo Chen
10724ca08a8SShuo Chenbool InetAddress::operator==(const InetAddress& rhs) const
108503bffb0SShuo Chen{
10924ca08a8SShuo Chen  if (family() == rhs.family())
110503bffb0SShuo Chen  {
11124ca08a8SShuo Chen    if (family() == AF_INET)
112503bffb0SShuo Chen    {
11324ca08a8SShuo Chen      return addr_.sin_port == rhs.addr_.sin_port &&
11424ca08a8SShuo Chen          addr_.sin_addr.s_addr == rhs.addr_.sin_addr.s_addr;
115503bffb0SShuo Chen    }
11624ca08a8SShuo Chen    else if (family() == AF_INET6)
117503bffb0SShuo Chen    {
11824ca08a8SShuo Chen      return addr6_.sin6_port == rhs.addr6_.sin6_port &&
11924ca08a8SShuo Chen          memcmp(&addr6_.sin6_addr, &rhs.addr6_.sin6_addr, sizeof addr6_.sin6_addr) == 0;
120503bffb0SShuo Chen    }
121503bffb0SShuo Chen  }
122503bffb0SShuo Chen  return false;
123503bffb0SShuo Chen}
124503bffb0SShuo Chen
12524ca08a8SShuo Chen// static
12624ca08a8SShuo Chenbool InetAddress::resolve(StringArg hostname, uint16_t port, InetAddress* out)
1275b543c9cSShuo Chen{
1285b543c9cSShuo Chen  assert(out);
12924ca08a8SShuo Chen  std::vector<InetAddress> addrs = resolveAll(hostname, port);
13024ca08a8SShuo Chen
13124ca08a8SShuo Chen  if (addrs.empty())
13224ca08a8SShuo Chen    return false;
13324ca08a8SShuo Chen
13424ca08a8SShuo Chen  // Read the first result
13524ca08a8SShuo Chen  *out = addrs[0];
13624ca08a8SShuo Chen
13724ca08a8SShuo Chen  return true;
13824ca08a8SShuo Chen}
13924ca08a8SShuo Chen
14024ca08a8SShuo Chen// static
14124ca08a8SShuo Chenstd::vector<InetAddress> InetAddress::resolveAll(StringArg hostname, uint16_t port)
14224ca08a8SShuo Chen{
14324ca08a8SShuo Chen  std::vector<InetAddress> addrs;
14424ca08a8SShuo Chen
14524ca08a8SShuo Chen  struct addrinfo* result = NULL;
14624ca08a8SShuo Chen  int error = getaddrinfo(hostname.c_str(), NULL, NULL, &result);
14724ca08a8SShuo Chen  if (error != 0)
1485b543c9cSShuo Chen  {
14924ca08a8SShuo Chen    if (error == EAI_SYSTEM)
15024ca08a8SShuo Chen    {
15124ca08a8SShuo Chen      perror("InetAddress::resolve");
15224ca08a8SShuo Chen    }
15324ca08a8SShuo Chen    else
15424ca08a8SShuo Chen    {
15524ca08a8SShuo Chen      fprintf(stderr, "InetAddress::resolve: %s\n", gai_strerror(error));
15624ca08a8SShuo Chen    }
15724ca08a8SShuo Chen    return addrs;
1585b543c9cSShuo Chen  }
15924ca08a8SShuo Chen
16024ca08a8SShuo Chen  assert(result);
16124ca08a8SShuo Chen  std::unique_ptr<struct addrinfo, decltype(&freeaddrinfo)> freeResult(result, freeaddrinfo);
16224ca08a8SShuo Chen
16324ca08a8SShuo Chen  for (struct addrinfo* ai = result; ai != NULL; ai = ai->ai_next)
1645b543c9cSShuo Chen  {
16524ca08a8SShuo Chen    InetAddress addr(*ai->ai_addr);
16624ca08a8SShuo Chen    addr.setPort(port);
16724ca08a8SShuo Chen    addrs.push_back(addr);
1685b543c9cSShuo Chen  }
16924ca08a8SShuo Chen  return addrs;
1705b543c9cSShuo Chen}
171