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