3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "network/networkexceptions.h"
30 #include "util/string.h"
31 #include "util/numeric.h"
32 #include "constants.h"
38 // Without this some of the network functions are not found on mingw
40 #define _WIN32_WINNT 0x0501
45 #define LAST_SOCKET_ERR() WSAGetLastError()
46 typedef SOCKET socket_t;
47 typedef int socklen_t;
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
55 #include <arpa/inet.h>
56 #define LAST_SOCKET_ERR() (errno)
66 memset(&m_address, 0, sizeof(m_address));
69 Address::Address(u32 address, u16 port)
71 memset(&m_address, 0, sizeof(m_address));
76 Address::Address(u8 a, u8 b, u8 c, u8 d, u16 port)
78 memset(&m_address, 0, sizeof(m_address));
79 setAddress(a, b, c, d);
83 Address::Address(const IPv6AddressBytes *ipv6_bytes, u16 port)
85 memset(&m_address, 0, sizeof(m_address));
86 setAddress(ipv6_bytes);
90 // Equality (address family, IP and port must be equal)
91 bool Address::operator==(const Address &other)
93 if (other.m_addr_family != m_addr_family || other.m_port != m_port)
96 if (m_addr_family == AF_INET) {
97 return m_address.ipv4.s_addr == other.m_address.ipv4.s_addr;
100 if (m_addr_family == AF_INET6) {
101 return memcmp(m_address.ipv6.s6_addr,
102 other.m_address.ipv6.s6_addr, 16) == 0;
108 void Address::Resolve(const char *name)
110 if (!name || name[0] == 0) {
111 if (m_addr_family == AF_INET)
112 setAddress(static_cast<u32>(0));
113 else if (m_addr_family == AF_INET6)
114 setAddress(static_cast<IPv6AddressBytes*>(nullptr));
118 struct addrinfo *resolved, hints;
119 memset(&hints, 0, sizeof(hints));
122 if (g_settings->getBool("enable_ipv6")) {
123 // AF_UNSPEC allows both IPv6 and IPv4 addresses to be returned
124 hints.ai_family = AF_UNSPEC;
126 hints.ai_family = AF_INET;
130 int e = getaddrinfo(name, NULL, &hints, &resolved);
132 throw ResolveError(gai_strerror(e));
135 if (resolved->ai_family == AF_INET) {
136 struct sockaddr_in *t = (struct sockaddr_in *)resolved->ai_addr;
137 m_addr_family = AF_INET;
138 m_address.ipv4 = t->sin_addr;
139 } else if (resolved->ai_family == AF_INET6) {
140 struct sockaddr_in6 *t = (struct sockaddr_in6 *)resolved->ai_addr;
141 m_addr_family = AF_INET6;
142 m_address.ipv6 = t->sin6_addr;
146 freeaddrinfo(resolved);
149 // IP address -> textual representation
150 std::string Address::serializeString() const
152 // windows XP doesnt have inet_ntop, maybe use better func
154 if (m_addr_family == AF_INET) {
155 return inet_ntoa(m_address.ipv4);
156 } else if (m_addr_family == AF_INET6) {
157 std::ostringstream os;
159 for (int i = 0; i < 16; i += 2) {
160 u16 section = (m_address.ipv6.s6_addr[i] << 8) |
161 (m_address.ipv6.s6_addr[i + 1]);
171 char str[INET6_ADDRSTRLEN];
172 if (inet_ntop(m_addr_family, (void*) &m_address, str, sizeof(str)) == nullptr)
178 struct in_addr Address::getAddress() const
180 return m_address.ipv4;
183 struct in6_addr Address::getAddress6() const
185 return m_address.ipv6;
188 u16 Address::getPort() const
193 bool Address::isZero() const
195 if (m_addr_family == AF_INET) {
196 return m_address.ipv4.s_addr == 0;
199 if (m_addr_family == AF_INET6) {
200 static const char zero[16] = {0};
201 return memcmp(m_address.ipv6.s6_addr, zero, 16) == 0;
207 void Address::setAddress(u32 address)
209 m_addr_family = AF_INET;
210 m_address.ipv4.s_addr = htonl(address);
213 void Address::setAddress(u8 a, u8 b, u8 c, u8 d)
215 u32 addr = (a << 24) | (b << 16) | (c << 8) | d;
219 void Address::setAddress(const IPv6AddressBytes *ipv6_bytes)
221 m_addr_family = AF_INET6;
223 memcpy(m_address.ipv6.s6_addr, ipv6_bytes->bytes, 16);
225 memset(m_address.ipv6.s6_addr, 0, 16);
228 void Address::setPort(u16 port)
233 void Address::print(std::ostream& s) const
235 if (m_addr_family == AF_INET6)
236 s << "[" << serializeString() << "]:" << m_port;
237 else if (m_addr_family == AF_INET)
238 s << serializeString() << ":" << m_port;
243 bool Address::isLocalhost() const
246 static const u8 localhost_bytes[] = {
247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
248 static const u8 mapped_ipv4_localhost[] = {
249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 0};
251 auto addr = m_address.ipv6.s6_addr;
253 return memcmp(addr, localhost_bytes, 16) == 0 ||
254 memcmp(addr, mapped_ipv4_localhost, 13) == 0;
257 auto addr = ntohl(m_address.ipv4.s_addr);
258 return (addr >> 24) == 0x7f;