InetAddress.cc revision 246b2f80
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");
1124ca08a8SShuo Chenstatic_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0");
1224ca08a8SShuo Chenstatic_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0");
1324ca08a8SShuo Chenstatic_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2");
1424ca08a8SShuo Chenstatic_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2");
155b543c9cSShuo Chen
16aafef3ccSShuo ChenInetAddress::InetAddress(StringArg ip, uint16_t port)
17aafef3ccSShuo Chen{
1824ca08a8SShuo Chen  setPort(port);
1924ca08a8SShuo Chen
2024ca08a8SShuo Chen  int result = 0;
2124ca08a8SShuo Chen  if (strchr(ip.c_str(), ':') == NULL)
2224ca08a8SShuo Chen  {
2324ca08a8SShuo Chen    result = ::inet_pton(AF_INET, ip.c_str(), &addr_.sin_addr);
24246b2f80SShuo Chen    addr_.sin_family = AF_INET;
2524ca08a8SShuo Chen  }
2624ca08a8SShuo Chen  else
2724ca08a8SShuo Chen  {
2824ca08a8SShuo Chen    result = ::inet_pton(AF_INET6, ip.c_str(), &addr6_.sin6_addr);
29246b2f80SShuo Chen    addr6_.sin6_family = AF_INET6;
3024ca08a8SShuo Chen  }
3124ca08a8SShuo Chen
3224ca08a8SShuo Chen  assert(result == 1 && "Invalid IP format");
33aafef3ccSShuo Chen}
34efbfdb0cSShuo Chen
3524ca08a8SShuo ChenInetAddress::InetAddress(uint16_t port, bool ipv6)
36efbfdb0cSShuo Chen{
3724ca08a8SShuo Chen  static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0");
3824ca08a8SShuo Chen  static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0");
3924ca08a8SShuo Chen  bool loopbackOnly = false;
4024ca08a8SShuo Chen  if (ipv6)
4124ca08a8SShuo Chen  {
4224ca08a8SShuo Chen    memZero(&addr6_, sizeof addr6_);
4324ca08a8SShuo Chen    addr6_.sin6_family = AF_INET6;
4424ca08a8SShuo Chen    in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any;
4524ca08a8SShuo Chen    addr6_.sin6_addr = ip;
4624ca08a8SShuo Chen    addr6_.sin6_port = htons(port);
4724ca08a8SShuo Chen  }
4824ca08a8SShuo Chen  else
4924ca08a8SShuo Chen  {
5024ca08a8SShuo Chen    memZero(&addr_, sizeof addr_);
5124ca08a8SShuo Chen    addr_.sin_family = AF_INET;
5224ca08a8SShuo Chen    in_addr_t ip = loopbackOnly ? INADDR_LOOPBACK : INADDR_ANY;
5324ca08a8SShuo Chen    addr_.sin_addr.s_addr = htonl(ip);
5424ca08a8SShuo Chen    addr_.sin_port = htons(port);
5524ca08a8SShuo Chen  }
5624ca08a8SShuo Chen}
5724ca08a8SShuo Chen
5824ca08a8SShuo ChenInetAddress::InetAddress(const struct sockaddr& saddr)
5924ca08a8SShuo Chen{
6024ca08a8SShuo Chen  if (saddr.sa_family == AF_INET)
6124ca08a8SShuo Chen  {
6224ca08a8SShuo Chen    memcpy(&addr_, &saddr, sizeof addr_);
6324ca08a8SShuo Chen  }
6424ca08a8SShuo Chen  else if (saddr.sa_family == AF_INET6)
6524ca08a8SShuo Chen  {
6624ca08a8SShuo Chen    memcpy(&addr6_, &saddr, sizeof addr6_);
6724ca08a8SShuo Chen  }
6824ca08a8SShuo Chen  else
6924ca08a8SShuo Chen  {
7024ca08a8SShuo Chen    assert(false);
7124ca08a8SShuo Chen  }
72efbfdb0cSShuo Chen}
735b543c9cSShuo Chen
745b543c9cSShuo Chenstd::string InetAddress::toIp() const
755b543c9cSShuo Chen{
7624ca08a8SShuo Chen  char buf[64] = "";
7724ca08a8SShuo Chen  static_assert(sizeof buf >= INET_ADDRSTRLEN);
7824ca08a8SShuo Chen  static_assert(sizeof buf >= INET6_ADDRSTRLEN);
7924ca08a8SShuo Chen
8024ca08a8SShuo Chen  if (family() == AF_INET)
8124ca08a8SShuo Chen  {
8224ca08a8SShuo Chen    ::inet_ntop(AF_INET, &addr_.sin_addr, buf, static_cast<socklen_t>(sizeof buf));
8324ca08a8SShuo Chen  }
8424ca08a8SShuo Chen  else if (family() == AF_INET6)
8524ca08a8SShuo Chen  {
8624ca08a8SShuo Chen    ::inet_ntop(AF_INET6, &addr6_.sin6_addr, buf, static_cast<socklen_t>(sizeof buf));
8724ca08a8SShuo Chen  }
8824ca08a8SShuo Chen
895b543c9cSShuo Chen  return buf;
905b543c9cSShuo Chen}
915b543c9cSShuo Chen
925b543c9cSShuo Chenstd::string InetAddress::toIpPort() const
935b543c9cSShuo Chen{
9424ca08a8SShuo Chen  char buf[32] = "";
9524ca08a8SShuo Chen  snprintf(buf, sizeof buf, ":%u", port());
96e0ccc29fSShuo Chen
97e0ccc29fSShuo Chen  if (family() == AF_INET6)
98e0ccc29fSShuo Chen    return "[" + toIp() + "]" + buf;
99e0ccc29fSShuo Chen
10024ca08a8SShuo Chen  return toIp() + buf;
1015b543c9cSShuo Chen}
1025b543c9cSShuo Chen
10324ca08a8SShuo Chenbool InetAddress::operator==(const InetAddress& rhs) const
104503bffb0SShuo Chen{
10524ca08a8SShuo Chen  if (family() == rhs.family())
106503bffb0SShuo Chen  {
10724ca08a8SShuo Chen    if (family() == AF_INET)
108503bffb0SShuo Chen    {
10924ca08a8SShuo Chen      return addr_.sin_port == rhs.addr_.sin_port &&
11024ca08a8SShuo Chen          addr_.sin_addr.s_addr == rhs.addr_.sin_addr.s_addr;
111503bffb0SShuo Chen    }
11224ca08a8SShuo Chen    else if (family() == AF_INET6)
113503bffb0SShuo Chen    {
11424ca08a8SShuo Chen      return addr6_.sin6_port == rhs.addr6_.sin6_port &&
11524ca08a8SShuo Chen          memcmp(&addr6_.sin6_addr, &rhs.addr6_.sin6_addr, sizeof addr6_.sin6_addr) == 0;
116503bffb0SShuo Chen    }
117503bffb0SShuo Chen  }
118503bffb0SShuo Chen  return false;
119503bffb0SShuo Chen}
120503bffb0SShuo Chen
12124ca08a8SShuo Chen// static
12224ca08a8SShuo Chenbool InetAddress::resolve(StringArg hostname, uint16_t port, InetAddress* out)
1235b543c9cSShuo Chen{
1245b543c9cSShuo Chen  assert(out);
12524ca08a8SShuo Chen  std::vector<InetAddress> addrs = resolveAll(hostname, port);
12624ca08a8SShuo Chen
12724ca08a8SShuo Chen  if (addrs.empty())
12824ca08a8SShuo Chen    return false;
12924ca08a8SShuo Chen
13024ca08a8SShuo Chen  // Read the first result
13124ca08a8SShuo Chen  *out = addrs[0];
13224ca08a8SShuo Chen
13324ca08a8SShuo Chen  return true;
13424ca08a8SShuo Chen}
13524ca08a8SShuo Chen
13624ca08a8SShuo Chen// static
13724ca08a8SShuo Chenstd::vector<InetAddress> InetAddress::resolveAll(StringArg hostname, uint16_t port)
13824ca08a8SShuo Chen{
13924ca08a8SShuo Chen  std::vector<InetAddress> addrs;
14024ca08a8SShuo Chen
14124ca08a8SShuo Chen  struct addrinfo* result = NULL;
14224ca08a8SShuo Chen  int error = getaddrinfo(hostname.c_str(), NULL, NULL, &result);
14324ca08a8SShuo Chen  if (error != 0)
1445b543c9cSShuo Chen  {
14524ca08a8SShuo Chen    if (error == EAI_SYSTEM)
14624ca08a8SShuo Chen    {
14724ca08a8SShuo Chen      perror("InetAddress::resolve");
14824ca08a8SShuo Chen    }
14924ca08a8SShuo Chen    else
15024ca08a8SShuo Chen    {
15124ca08a8SShuo Chen      fprintf(stderr, "InetAddress::resolve: %s\n", gai_strerror(error));
15224ca08a8SShuo Chen    }
15324ca08a8SShuo Chen    return addrs;
1545b543c9cSShuo Chen  }
15524ca08a8SShuo Chen
15624ca08a8SShuo Chen  assert(result);
15724ca08a8SShuo Chen  std::unique_ptr<struct addrinfo, decltype(&freeaddrinfo)> freeResult(result, freeaddrinfo);
15824ca08a8SShuo Chen
15924ca08a8SShuo Chen  for (struct addrinfo* ai = result; ai != NULL; ai = ai->ai_next)
1605b543c9cSShuo Chen  {
16124ca08a8SShuo Chen    InetAddress addr(*ai->ai_addr);
16224ca08a8SShuo Chen    addr.setPort(port);
16324ca08a8SShuo Chen    addrs.push_back(addr);
1645b543c9cSShuo Chen  }
16524ca08a8SShuo Chen  return addrs;
1665b543c9cSShuo Chen}
167