1 // SuperTuxKart - a fun racing game with go-kart
2 // Copyright (C) 2020 SuperTuxKart-Team
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 3
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 #include "network/socket_address.hpp"
19 #include "network/network_config.hpp"
20 #include "network/stk_ipv6.hpp"
21 #include "utils/log.hpp"
22 #include "utils/string_utils.hpp"
23
24 #ifdef WIN32
25 # undef _WIN32_WINNT
26 # define _WIN32_WINNT 0x600
27 # include <iphlpapi.h>
28 #else
29 # include <ifaddrs.h>
30 # include <sys/ioctl.h>
31 # include <net/if.h>
32 # include <string.h>
33 # include <errno.h>
34 #endif
35
36 #if defined(WIN32)
37 # include "ws2tcpip.h"
38 # define inet_ntop InetNtop
39 #else
40 # include <arpa/inet.h>
41 # include <errno.h>
42 # include <sys/socket.h>
43 #endif
44
45 #include <sys/types.h>
46
47 // ----------------------------------------------------------------------------
48 bool SocketAddress::g_ignore_error_message = false;
49 // ----------------------------------------------------------------------------
50 /** IPv4 Constructor. */
SocketAddress(uint32_t ip,uint16_t port)51 SocketAddress::SocketAddress(uint32_t ip, uint16_t port)
52 {
53 clear();
54 setIP(ip);
55 setPort(port);
56 } // SocketAddress
57
58 // ----------------------------------------------------------------------------
59 /** IPv4 Constructor (4 bytes). */
SocketAddress(uint8_t b1,uint8_t b2,uint8_t b3,uint8_t b4,uint16_t port)60 SocketAddress::SocketAddress(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4,
61 uint16_t port)
62 : SocketAddress((b1 << 24) + (b2 << 16) + (b3 << 8) + b4, port)
63 {
64 } // SocketAddress(uint8_t,...)
65
66 // ----------------------------------------------------------------------------
67 /** ENetAddress constructor. */
SocketAddress(const ENetAddress & ea)68 SocketAddress::SocketAddress(const ENetAddress& ea)
69 {
70 #ifdef ENABLE_IPV6
71 if (isIPv6Socket())
72 {
73 m_family = AF_INET6;
74 m_sockaddr = {};
75 struct sockaddr_in6* in6 = (struct sockaddr_in6*)m_sockaddr.data();
76 in6->sin6_family = AF_INET6;
77 in6->sin6_port = htons(ea.port);
78 // We modify host to use 5 uint32_t (see enet.h)
79 memcpy(in6->sin6_addr.s6_addr, &ea.host.p0, 16);
80 in6->sin6_scope_id = ea.host.p4;
81 }
82 else
83 {
84 m_family = AF_INET;
85 setIP(htonl(ea.host.p0));
86 setPort(ea.port);
87 }
88 #else
89 m_family = AF_INET;
90 setIP(htonl(ea.host));
91 setPort(ea.port);
92 #endif
93 } // SocketAddress(const ENetAddress&)
94
95 // ----------------------------------------------------------------------------
96 /** String initialization (Can be IPv4, IPv6 or domain).
97 * \param str The address (can have a port with :)
98 * \param port_number The port number, default is 0 or overwritten if
99 * specified in str
100 * \param family AF_UNSPEC, AF_INET or AF_INET6 for example
101 */
init(const std::string & str,uint16_t port_number,short family)102 void SocketAddress::init(const std::string& str, uint16_t port_number,
103 short family)
104 {
105 clear();
106 if (str.empty())
107 {
108 Log::error("SocketAddress", "Empty address is specified.");
109 return;
110 }
111
112 std::string addr_str;
113 std::string port_str;
114
115 bool only_1_colon = false;
116 size_t colon_pos = std::string::npos;
117 // Check if only 1 colon, if so then it's either domain:port or IPv4:port
118 for (size_t i = 0; i < str.size(); i++)
119 {
120 if (str[i] == ':')
121 {
122 if (colon_pos == std::string::npos)
123 {
124 colon_pos = i;
125 only_1_colon = true;
126 }
127 else
128 only_1_colon = false;
129 }
130 }
131 if (only_1_colon)
132 {
133 addr_str = std::string(str, 0, colon_pos);
134 if (colon_pos + 1 < str.size())
135 port_str = std::string(str, colon_pos + 1, str.size());
136 else
137 port_str = StringUtils::toString(port_number);
138 }
139 else if (str[0] == '[')
140 {
141 // Handle [IPv6 address]:port format
142 size_t pos = str.find(']');
143 if (pos == std::string::npos || pos - 1 == 0)
144 {
145 Log::error("SocketAddress", "Invalid IPv6 address is specified.");
146 return;
147 }
148 addr_str = std::string(str, 1, pos - 1);
149 if (pos + 2 < str.size() && str[pos + 1] == ':')
150 port_str = std::string(str, pos + 2, str.size());
151 else
152 port_str = StringUtils::toString(port_number);
153 }
154 else
155 {
156 addr_str = str;
157 port_str = StringUtils::toString(port_number);
158 }
159
160 struct addrinfo hints;
161 struct addrinfo* res = NULL;
162 memset(&hints, 0, sizeof hints);
163 hints.ai_family = family;
164 hints.ai_socktype = SOCK_STREAM;
165
166 int status = getaddrinfo_compat(addr_str.c_str(), port_str.c_str(), &hints,
167 &res);
168 if (status != 0)
169 {
170 #ifdef WIN32
171 if (!g_ignore_error_message)
172 {
173 wchar_t msgbuf[256] = {};
174 DWORD flags =
175 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
176 FORMAT_MESSAGE_MAX_WIDTH_MASK;
177 FormatMessage(flags, NULL, WSAGetLastError(), 0, msgbuf,
178 sizeof(msgbuf) / sizeof(wchar_t), NULL);
179 Log::error("SocketAddress", "Error in getaddrinfo for "
180 "SocketAddress (str constructor) %s: %s",
181 str.c_str(), StringUtils::wideToUtf8(msgbuf).c_str());
182 }
183 #else
184 if (!g_ignore_error_message)
185 {
186 Log::error("SocketAddress", "Error in getaddrinfo for "
187 "SocketAddress (str constructor) %s: %s",
188 str.c_str(), gai_strerror(status));
189 }
190 #endif
191 return;
192 }
193 if (res == NULL)
194 {
195 if (!g_ignore_error_message)
196 Log::error("SocketAddress", "No address is resolved.");
197 return;
198 }
199
200 bool found = false;
201 bool ipv4_mapped = str.size() > 7 && str.compare(0, 7, "::ffff:") == 0;
202 for (struct addrinfo* addr = res; addr != NULL; addr = addr->ai_next)
203 {
204 switch (addr->ai_family)
205 {
206 case AF_INET:
207 memcpy(m_sockaddr.data(), addr->ai_addr, sizeof(sockaddr_in));
208 found = true;
209 break;
210 case AF_INET6:
211 if (ipv4_mapped ||
212 !isIPv4MappedAddress((const struct sockaddr_in6*)addr->ai_addr))
213 {
214 // OSX and iOS can return AF_INET6 with ::ffff:x.y.z.w for server
215 // with A record, skip them and make it only get real AAAA record
216 m_family = AF_INET6;
217 memcpy(m_sockaddr.data(), addr->ai_addr, sizeof(sockaddr_in6));
218 found = true;
219 }
220 break;
221 default:
222 break;
223 }
224 if (found)
225 break;
226 }
227 freeaddrinfo(res);
228 } // init
229
230 // ----------------------------------------------------------------------------
231 /** Returns the IPv4 address in decimal, it will handle IPv4 mapped IPv6
232 * address too. */
getIP() const233 uint32_t SocketAddress::getIP() const
234 {
235 if (m_family == AF_INET6)
236 {
237 sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
238 if (isIPv4MappedAddress(in6))
239 return ntohl(((in_addr*)(in6->sin6_addr.s6_addr + 12))->s_addr);
240 return 0;
241 }
242 else if (m_family == AF_INET)
243 {
244 sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
245 return ntohl(in->sin_addr.s_addr);
246 }
247 return 0;
248 } // getIP
249
250 // ----------------------------------------------------------------------------
251 /** Returns the port number. */
getPort() const252 uint16_t SocketAddress::getPort() const
253 {
254 if (m_family == AF_INET)
255 {
256 sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
257 return ntohs(in->sin_port);
258 }
259 else if (m_family == AF_INET6)
260 {
261 sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
262 return ntohs(in6->sin6_port);
263 }
264 return 0;
265 } // getPort
266
267 // ----------------------------------------------------------------------------
268 /** Sets the ip address. */
setIP(uint32_t ip)269 void SocketAddress::setIP(uint32_t ip)
270 {
271 if (m_family != AF_INET)
272 {
273 // Reset the structure if different family is used
274 clear();
275 }
276 sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
277 in->sin_addr.s_addr = htonl(ip);
278 } // setIP
279
280 // ----------------------------------------------------------------------------
281 /** Set the port. */
setPort(uint16_t port)282 void SocketAddress::setPort(uint16_t port)
283 {
284 if (m_family == AF_INET)
285 {
286 sockaddr_in* in = (sockaddr_in*)m_sockaddr.data();
287 in->sin_port = htons(port);
288 }
289 else if (m_family == AF_INET6)
290 {
291 sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
292 in6->sin6_port = htons(port);
293 }
294 } // setPort
295
296 // ----------------------------------------------------------------------------
297 /** Returns this IP address is localhost which its equal to any interface
298 * address. */
isPublicAddressLocalhost() const299 bool SocketAddress::isPublicAddressLocalhost() const
300 {
301 if (m_family == AF_INET && getIP() == 0)
302 return false;
303 if (isLoopback())
304 return true;
305 #ifndef WIN32
306 struct ifaddrs *addresses, *p;
307
308 if (getifaddrs(&addresses) == -1)
309 {
310 Log::warn("SocketAddress", "Error in getifaddrs");
311 return false;
312 }
313 bool is_local_host = false;
314 for (p = addresses; p; p = p->ifa_next)
315 {
316 if (p->ifa_addr == NULL)
317 continue;
318 if (p->ifa_addr->sa_family == AF_INET)
319 {
320 struct sockaddr_in *sa = (struct sockaddr_in*)p->ifa_addr;
321 if (htonl(sa->sin_addr.s_addr) == getIP())
322 {
323 is_local_host = true;
324 break;
325 }
326 }
327 else if (p->ifa_addr->sa_family == AF_INET6 && getFamily() == AF_INET6)
328 {
329 struct sockaddr_in6 addr = {};
330 memcpy(&addr, p->ifa_addr, sizeof(sockaddr_in6));
331 sockaddr_in6* my_in6 = (sockaddr_in6*)m_sockaddr.data();
332 addr.sin6_port = my_in6->sin6_port;
333 if (sameIPV6(my_in6, &addr))
334 {
335 is_local_host = true;
336 break;
337 }
338 }
339 }
340 freeifaddrs(addresses);
341 return is_local_host;
342 #else
343 // From docs from microsoft it recommends 15k size
344 const int WORKING_BUFFER_SIZE = 15000;
345 PIP_ADAPTER_ADDRESSES paddr = NULL;
346 unsigned long len = WORKING_BUFFER_SIZE;
347 int return_code = 0;
348 int iteration = 0;
349 do
350 {
351 paddr = (IP_ADAPTER_ADDRESSES*)malloc(len);
352 if (paddr == NULL)
353 return false;
354 long flags = 0;
355 return_code = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, paddr,
356 &len);
357 if (return_code == ERROR_BUFFER_OVERFLOW)
358 {
359 free(paddr);
360 paddr = NULL;
361 }
362 else
363 break;
364 iteration++;
365 } while ((return_code == ERROR_BUFFER_OVERFLOW) && (iteration < 10));
366
367 if (return_code == ERROR_BUFFER_OVERFLOW)
368 return false;
369
370 bool is_local_host = false;
371 for (IP_ADAPTER_ADDRESSES *p = paddr; p; p = p->Next)
372 {
373 if (is_local_host)
374 break;
375 if (p->OperStatus != IfOperStatusUp)
376 continue;
377
378 for (PIP_ADAPTER_UNICAST_ADDRESS unicast = p->FirstUnicastAddress;
379 unicast != NULL; unicast = unicast->Next)
380 {
381 if (unicast->Address.lpSockaddr->sa_family == AF_INET)
382 {
383 const sockaddr_in *sa = (sockaddr_in*)unicast->Address.lpSockaddr;
384 if (htonl(sa->sin_addr.s_addr) == getIP())
385 {
386 is_local_host = true;
387 break;
388 }
389 }
390 else if (unicast->Address.lpSockaddr->sa_family == AF_INET6 &&
391 getFamily() == AF_INET6)
392 {
393 struct sockaddr_in6 addr = {};
394 memcpy(&addr, unicast->Address.lpSockaddr, sizeof(sockaddr_in6));
395 sockaddr_in6* my_in6 = (sockaddr_in6*)m_sockaddr.data();
396 addr.sin6_port = my_in6->sin6_port;
397 if (sameIPV6(my_in6, &addr))
398 {
399 is_local_host = true;
400 break;
401 }
402 }
403 }
404 }
405 free(paddr);
406 return is_local_host;
407 #endif
408 } // isPublicAddressLocalhost
409
410 // ----------------------------------------------------------------------------
411 /** Returns if this IP is loopback (ie for IPv4 127.0.0.0/8, IPv6 ::1/128)
412 */
isLoopback() const413 bool SocketAddress::isLoopback() const
414 {
415 uint32_t ip = getIP();
416 if (ip != 0)
417 {
418 if (ip >> 24 == 0x7f)
419 return true;
420 }
421 else if (m_family == AF_INET6)
422 {
423 sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
424 uint8_t w0 = in6->sin6_addr.s6_addr[0];
425 uint8_t w1 = in6->sin6_addr.s6_addr[1];
426 uint8_t w2 = in6->sin6_addr.s6_addr[2];
427 uint8_t w3 = in6->sin6_addr.s6_addr[3];
428 uint8_t w4 = in6->sin6_addr.s6_addr[4];
429 uint8_t w5 = in6->sin6_addr.s6_addr[5];
430 uint8_t w6 = in6->sin6_addr.s6_addr[6];
431 uint8_t w7 = in6->sin6_addr.s6_addr[7];
432 uint8_t w8 = in6->sin6_addr.s6_addr[8];
433 uint8_t w9 = in6->sin6_addr.s6_addr[9];
434 uint8_t w10 = in6->sin6_addr.s6_addr[10];
435 uint8_t w11 = in6->sin6_addr.s6_addr[11];
436 uint8_t w12 = in6->sin6_addr.s6_addr[12];
437 uint8_t w13 = in6->sin6_addr.s6_addr[13];
438 uint8_t w14 = in6->sin6_addr.s6_addr[14];
439 uint8_t w15 = in6->sin6_addr.s6_addr[15];
440 if (w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0 && w4 == 0 &&
441 w5 == 0 && w6 == 0 && w7 == 0 && w8 == 0 && w9 == 0 &&
442 w10 == 0 && w11 == 0 && w12 == 0 && w13 == 0 && w14 == 0
443 && w15 == 1)
444 {
445 // ::1/128 Loopback
446 return true;
447 }
448 }
449 return false;
450 } // isLoopback
451
452 // ----------------------------------------------------------------------------
453 /** Returns if this IP address belongs to a LAN, i.e. is in 192.168* or
454 * 10*, 172.16-31.*, or is on the same host, i.e. 127*.
455 */
isLAN() const456 bool SocketAddress::isLAN() const
457 {
458 if (isLoopback())
459 return true;
460 uint32_t ip = getIP();
461 if (ip != 0)
462 {
463 // IPv4 test
464 if (ip >> 16 == 0xc0a8) // Check for 192.168.*
465 return true;
466 else if (ip >> 20 == 0xac1 ) // 172.16-31.*
467 return true;
468 else if (ip >> 24 == 0x0a ) // 10.*
469 return true;
470 }
471 else if (m_family == AF_INET6)
472 {
473 sockaddr_in6* in6 = (sockaddr_in6*)m_sockaddr.data();
474 uint8_t w0 = in6->sin6_addr.s6_addr[0];
475 uint8_t w1 = in6->sin6_addr.s6_addr[1];
476 uint16_t _16 = ((uint16_t)w0) << 8 | w1;
477 if (_16 >= 0xfc00 && _16 <= 0xfdff)
478 {
479 // fc00::/7 Unique Local Address (ULA)
480 return true;
481 }
482 if (_16 >= 0xfe80 && _16 <= 0xfebf)
483 {
484 // fe80::/10 Link-Local Address
485 return true;
486 }
487 }
488 return false;
489 } // isLAN
490
491 // ----------------------------------------------------------------------------
492 /** Compares if ip address and port are identical. */
operator ==(const SocketAddress & other) const493 bool SocketAddress::operator==(const SocketAddress& other) const
494 {
495 if (m_family == AF_INET && other.m_family == AF_INET)
496 {
497 sockaddr_in* in_a = (sockaddr_in*)m_sockaddr.data();
498 sockaddr_in* in_b = (sockaddr_in*)(other.m_sockaddr.data());
499 return in_a->sin_addr.s_addr == in_b->sin_addr.s_addr &&
500 in_a->sin_port == in_b->sin_port;
501 }
502 else if (m_family == AF_INET6 && other.m_family == AF_INET6)
503 {
504 sockaddr_in6* in6_a = (sockaddr_in6*)m_sockaddr.data();
505 sockaddr_in6* in6_b = (sockaddr_in6*)(other.m_sockaddr.data());
506 return sameIPV6(in6_a, in6_b);
507 }
508 return false;
509 } // operator==
510
511 // ----------------------------------------------------------------------------
512 /** Compares if ip address and port are not identical. */
operator !=(const SocketAddress & other) const513 bool SocketAddress::operator!=(const SocketAddress& other) const
514 {
515 if (m_family == AF_INET && other.m_family == AF_INET)
516 {
517 sockaddr_in* in_a = (sockaddr_in*)m_sockaddr.data();
518 sockaddr_in* in_b = (sockaddr_in*)(other.m_sockaddr.data());
519 return in_a->sin_addr.s_addr != in_b->sin_addr.s_addr ||
520 in_a->sin_port != in_b->sin_port;
521 }
522 else if (m_family == AF_INET6 && other.m_family == AF_INET6)
523 {
524 sockaddr_in6* in6_a = (sockaddr_in6*)m_sockaddr.data();
525 sockaddr_in6* in6_b = (sockaddr_in6*)(other.m_sockaddr.data());
526 return !sameIPV6(in6_a, in6_b);
527 }
528 return true;
529 } // operator!=
530
531 // ----------------------------------------------------------------------------
toString(bool show_port) const532 std::string SocketAddress::toString(bool show_port) const
533 {
534 std::string result;
535 uint32_t ip = getIP();
536 if (ip != 0 || m_family == AF_INET)
537 {
538 result = StringUtils::insertValues("%d.%d.%d.%d",
539 ((ip >> 24) & 0xff), ((ip >> 16) & 0xff),
540 ((ip >> 8) & 0xff), ((ip >> 0) & 0xff));
541 if (show_port)
542 result += ":" + StringUtils::toString(getPort());
543 }
544 else
545 {
546 result = getIPV6ReadableFromIn6((sockaddr_in6*)m_sockaddr.data());
547 if (show_port)
548 {
549 result.insert (0, 1, '[');
550 result += "]";
551 result += ":" + StringUtils::toString(getPort());
552 }
553 }
554 return result;
555 } // toString
556
557 // ----------------------------------------------------------------------------
convertForIPv6Socket(bool ipv6)558 void SocketAddress::convertForIPv6Socket(bool ipv6)
559 {
560 #ifdef ENABLE_IPV6
561 if (m_family == AF_INET && ipv6)
562 {
563 std::string ipv4 = toString(false/*show_port*/);
564 uint16_t port = getPort();
565 auto ip_type = NetworkConfig::get()->getIPType();
566 if (ip_type == NetworkConfig::IP_V6_NAT64)
567 {
568 ipv4 = NetworkConfig::get()->getNAT64Prefix() + ipv4;
569 }
570 else
571 {
572 // Assume the system has dual stack if it uses an IPv6 socket
573 ipv4 = std::string("::ffff:") + ipv4;
574 }
575 init(ipv4, port);
576 }
577 #endif
578 } // convertForIPv6Socket
579
580 // ----------------------------------------------------------------------------
581 /** Unit testing. Test various LAN patterns to verify that isLAN() works as
582 * expected.
583 */
unitTesting()584 void SocketAddress::unitTesting()
585 {
586 SocketAddress t1("192.168.0.0");
587 assert(t1.getIP() == (192u << 24) + (168u << 16));
588 assert(t1.isLAN());
589
590 SocketAddress t2("192.168.255.255");
591 assert(t2.getIP() == (192u << 24) + (168u << 16) + (255u << 8) + 255u);
592 assert(t2.isLAN());
593
594 SocketAddress t3("::ffff:193.168.0.1");
595 assert(t3.getIP() == (193u << 24) + (168u << 16) + 1);
596 assert(!t3.isLAN());
597
598 SocketAddress t4("192.167.255.255");
599 assert(t4.getIP() == (192u << 24) + (167u << 16) + (255u << 8) + 255u);
600 assert(!t4.isLAN());
601
602 SocketAddress t5("192.169.0.0");
603 assert(t5.getIP() == (192u << 24) + (169u << 16));
604 assert(!t5.isLAN());
605
606 SocketAddress t6("172.16.0.0");
607 assert(t6.getIP() == (172u << 24) + (16u << 16));
608 assert(t6.isLAN());
609
610 SocketAddress t7("172.31.255.255");
611 assert(t7.getIP() == (172u << 24) + (31u << 16) + (255u << 8) + 255u);
612 assert(t7.isLAN());
613
614 SocketAddress t8("172.15.255.255");
615 assert(t8.getIP() == (172u << 24) + (15u << 16) + (255u << 8) + 255u);
616 assert(!t8.isLAN());
617
618 SocketAddress t9("172.32.0.0");
619 assert(t9.getIP() == (172u << 24) + (32u << 16));
620 assert(!t9.isLAN());
621
622 SocketAddress t10("10.0.0.0");
623 assert(t10.getIP() == (10u << 24));
624 assert(t10.isLAN());
625
626 SocketAddress t11("10.255.255.255");
627 assert(t11.getIP() == (10u << 24) + (255u << 16) + (255u << 8) + 255u);
628 assert(t11.isLAN());
629
630 SocketAddress t12("9.255.255.255");
631 assert(t12.getIP() == (9u << 24) + (255u << 16) + (255u << 8) + 255u);
632 assert(!t12.isLAN());
633
634 SocketAddress t13("11.0.0.0");
635 assert(t13.getIP() == (11u << 24));
636 assert(!t13.isLAN());
637
638 SocketAddress t14("127.0.0.0");
639 assert(t14.getIP() == (127u << 24));
640 assert(t14.isLAN());
641
642 SocketAddress t15("::ffff:127.255.255.255");
643 assert(t15.getIP() == (127u << 24) + (255u << 16) + (255u << 8) + 255u);
644 assert(t15.isLAN());
645
646 SocketAddress t16("126.255.255.255");
647 assert(t16.getIP() == (126u << 24) + (255u << 16) + (255u << 8) + 255u);
648 assert(!t16.isLAN());
649
650 SocketAddress t17("128.0.0.0");
651 assert(t17.getIP() == (128u << 24));
652 assert(!t17.isLAN());
653
654 // Test constructors
655 SocketAddress t18("128.0.0.0");
656 assert(t18.getIP() == (128u << 24));
657 assert(t18.getPort() == 0);
658
659 SocketAddress t19("128.0.0.0", 1);
660 assert(t19.getIP() == (128u << 24));
661 assert(t19.getPort() == 1);
662
663 SocketAddress t20("128.0.0.0", 123);
664 assert(t20.getIP() == (128u << 24));
665 assert(t20.getPort() == 123);
666
667 SocketAddress v6_1("0:0:0:0:0:0:0:1");
668 assert(v6_1.isLAN());
669
670 SocketAddress v6_2("fe80::221:86ff:fea0:ce84");
671 assert(v6_2.isLAN());
672
673 SocketAddress v6_3("fdf8:f53b:82e4::53");
674 assert(v6_3.isLAN());
675
676 // Boundary test
677 // fc00::/7 Unique Local Address (ULA)
678 SocketAddress v6_4("fc00::");
679 assert(v6_4.isLAN());
680
681 SocketAddress v6_5("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
682 assert(v6_5.isLAN());
683
684 SocketAddress v6_6("fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
685 assert(!v6_6.isLAN());
686
687 SocketAddress v6_7("fe00::");
688 assert(!v6_7.isLAN());
689
690 // fe80::/10 Link-Local Address
691 SocketAddress v6_8("fe80::");
692 assert(v6_8.isLAN());
693
694 SocketAddress v6_9("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
695 assert(v6_9.isLAN());
696
697 SocketAddress v6_10("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
698 assert(!v6_10.isLAN());
699
700 SocketAddress v6_11("fec0::");
701 assert(!v6_11.isLAN());
702
703 SocketAddress ipv4_port("0.0.0.1:1");
704 assert(ipv4_port.getIP() == 1);
705 assert(ipv4_port.getPort() == 1);
706
707 SocketAddress ipv6_port("[::2]:1");
708 assert(ipv6_port.toString(false) == "::2");
709 assert(ipv6_port.getPort() == 1);
710
711 } // unitTesting
712
713 // ----------------------------------------------------------------------------
toENetAddress() const714 ENetAddress SocketAddress::toENetAddress() const
715 {
716 ENetAddress ea = {};
717 uint32_t ip = getIP();
718 #ifdef ENABLE_IPV6
719 if (isIPv6Socket())
720 {
721 struct sockaddr_in6* in6 = (struct sockaddr_in6*)m_sockaddr.data();
722 memcpy(&ea.host.p0, in6->sin6_addr.s6_addr, 16);
723 ea.host.p4 = in6->sin6_scope_id;
724 }
725 else
726 {
727 // because ENet wants little endian
728 ea.host.p0 = ((ip & 0xff000000) >> 24) +
729 ((ip & 0x00ff0000) >> 8) + ((ip & 0x0000ff00) << 8) +
730 ((ip & 0x000000ff) << 24);
731 }
732 #else
733 ea.host = ((ip & 0xff000000) >> 24) +
734 ((ip & 0x00ff0000) >> 8) + ((ip & 0x0000ff00) << 8) +
735 ((ip & 0x000000ff) << 24);
736 #endif
737 ea.port = getPort();
738 return ea;
739 } // toENetAddress
740