InetAddress.cc revision e146b157
1#include "InetAddress.h"
2
3#include <memory>
4
5#include <assert.h>
6#include <arpa/inet.h>
7#include <netdb.h>
8
9static_assert(sizeof(InetAddress) == sizeof(struct sockaddr_in6),
10              "InetAddress is same size as sockaddr_in6");
11#ifdef linux
12static_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0");
13static_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0");
14#endif
15static_assert(offsetof(sockaddr_in, sin_family) == offsetof(sockaddr_in6, sin6_family),
16              "sin_family/sin6_family offset");
17static_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2");
18static_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2");
19
20InetAddress::InetAddress(StringArg ip, uint16_t port)
21{
22  setPort(port);
23
24  int result = 0;
25  if (strchr(ip.c_str(), ':') == NULL)
26  {
27    result = ::inet_pton(AF_INET, ip.c_str(), &addr_.sin_addr);
28    addr_.sin_family = AF_INET;
29  }
30  else
31  {
32    result = ::inet_pton(AF_INET6, ip.c_str(), &addr6_.sin6_addr);
33    addr6_.sin6_family = AF_INET6;
34  }
35
36  assert(result == 1 && "Invalid IP format");
37}
38
39InetAddress::InetAddress(uint16_t port, bool ipv6)
40{
41  static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0");
42  static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0");
43  bool loopbackOnly = false;
44  if (ipv6)
45  {
46    memZero(&addr6_, sizeof addr6_);
47    addr6_.sin6_family = AF_INET6;
48    in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any;
49    addr6_.sin6_addr = ip;
50    addr6_.sin6_port = htons(port);
51  }
52  else
53  {
54    memZero(&addr_, sizeof addr_);
55    addr_.sin_family = AF_INET;
56    in_addr_t ip = loopbackOnly ? INADDR_LOOPBACK : INADDR_ANY;
57    addr_.sin_addr.s_addr = htonl(ip);
58    addr_.sin_port = htons(port);
59  }
60}
61
62InetAddress::InetAddress(const struct sockaddr& saddr)
63{
64  if (saddr.sa_family == AF_INET)
65  {
66    memcpy(&addr_, &saddr, sizeof addr_);
67  }
68  else if (saddr.sa_family == AF_INET6)
69  {
70    memcpy(&addr6_, &saddr, sizeof addr6_);
71  }
72  else
73  {
74    assert(false);
75  }
76}
77
78std::string InetAddress::toIp() const
79{
80  char buf[64] = "";
81  static_assert(sizeof buf >= INET_ADDRSTRLEN);
82  static_assert(sizeof buf >= INET6_ADDRSTRLEN);
83
84  if (family() == AF_INET)
85  {
86    ::inet_ntop(AF_INET, &addr_.sin_addr, buf, static_cast<socklen_t>(sizeof buf));
87  }
88  else if (family() == AF_INET6)
89  {
90    ::inet_ntop(AF_INET6, &addr6_.sin6_addr, buf, static_cast<socklen_t>(sizeof buf));
91  }
92
93  return buf;
94}
95
96std::string InetAddress::toIpPort() const
97{
98  char buf[32] = "";
99  snprintf(buf, sizeof buf, ":%u", port());
100
101  if (family() == AF_INET6)
102    return "[" + toIp() + "]" + buf;
103
104  return toIp() + buf;
105}
106
107bool InetAddress::operator==(const InetAddress& rhs) const
108{
109  if (family() == rhs.family())
110  {
111    if (family() == AF_INET)
112    {
113      return addr_.sin_port == rhs.addr_.sin_port &&
114          addr_.sin_addr.s_addr == rhs.addr_.sin_addr.s_addr;
115    }
116    else if (family() == AF_INET6)
117    {
118      return addr6_.sin6_port == rhs.addr6_.sin6_port &&
119          memcmp(&addr6_.sin6_addr, &rhs.addr6_.sin6_addr, sizeof addr6_.sin6_addr) == 0;
120    }
121  }
122  return false;
123}
124
125// static
126bool InetAddress::resolve(StringArg hostname, uint16_t port, InetAddress* out)
127{
128  assert(out);
129  std::vector<InetAddress> addrs = resolveAll(hostname, port);
130
131  if (addrs.empty())
132    return false;
133
134  // Read the first result
135  *out = addrs[0];
136
137  return true;
138}
139
140// static
141std::vector<InetAddress> InetAddress::resolveAll(StringArg hostname, uint16_t port)
142{
143  std::vector<InetAddress> addrs;
144
145  struct addrinfo* result = NULL;
146  int error = getaddrinfo(hostname.c_str(), NULL, NULL, &result);
147  if (error != 0)
148  {
149    if (error == EAI_SYSTEM)
150    {
151      perror("InetAddress::resolve");
152    }
153    else
154    {
155      fprintf(stderr, "InetAddress::resolve: %s\n", gai_strerror(error));
156    }
157    return addrs;
158  }
159
160  assert(result);
161  std::unique_ptr<struct addrinfo, decltype(&freeaddrinfo)> freeResult(result, freeaddrinfo);
162
163  for (struct addrinfo* ai = result; ai != NULL; ai = ai->ai_next)
164  {
165    InetAddress addr(*ai->ai_addr);
166    addr.setPort(port);
167    addrs.push_back(addr);
168  }
169  return addrs;
170}
171