4#include "Stroika/Foundation/StroikaPreComp.h"
6#if qStroika_Foundation_Common_Platform_Windows
13#include "Stroika/Foundation/Containers/Collection.h"
15#include "Stroika/Foundation/Execution/Exceptions.h"
16#if qStroika_Foundation_Common_Platform_Windows
17#include "Platform/Windows/WinSock.h"
18#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
26using namespace Stroika::Foundation::Memory;
27using namespace Stroika::Foundation::IO;
30#if qStroika_Foundation_Common_Platform_Windows
33#pragma comment(lib, "Ws2_32.lib")
36#if qStroika_Foundation_Common_Platform_Windows && (NTDDI_VERSION < NTDDI_VISTA)
38 int inet_pton (
int af,
const char* src,
void* dst)
40 IO::Network::Platform::Windows::WinSock::AssureStarted ();
41 struct sockaddr_storage ss{};
42 int size =
sizeof (ss);
43 wchar_t src_copy[INET6_ADDRSTRLEN + 1];
46 for (; *si !=
'\0'; ++si) {
47 src_copy[si - src] = *si;
48 if (si - src >= INET6_ADDRSTRLEN) {
52 src_copy[si - src] =
'\0';
54 if (::WSAStringToAddressW (src_copy, af, NULL, (
struct sockaddr*)&ss, &size) == 0) {
57 *(
struct in_addr*)dst = ((
struct sockaddr_in*)&ss)->sin_addr;
60 *(
struct in6_addr*)dst = ((
struct sockaddr_in6*)&ss)->sin6_addr;
66 const char* inet_ntop (
int af,
const void* src,
char* dst, socklen_t size)
68 IO::Network::Platform::Windows::WinSock::AssureStarted ();
69 struct sockaddr_storage ss{};
73 ((
struct sockaddr_in*)&ss)->sin_addr = *(
struct in_addr*)src;
76 ((
struct sockaddr_in6*)&ss)->sin6_addr = *(
struct in6_addr*)src;
82 unsigned long s = size;
83 DWORD d = WSAAddressToStringW ((
struct sockaddr*)&ss,
sizeof (ss), NULL, buf.begin (), &s);
85 const wchar_t* si = buf.begin ();
86 Assert (s <=
size_t (size));
87 for (; si < buf.begin () + s; ++si) {
88 dst[si - buf.begin ()] =
static_cast<char> (*si);
89 if (si - buf.begin () >= size) {
93 dst[si - buf.begin ()] =
'\0';
109 : fAddressFamily_{AddressFamily::UNKNOWN}
111 if (not s.empty ()) {
112 if (af == AddressFamily::UNKNOWN) {
114 if (s.find (
'.') != string::npos) {
115 af = AddressFamily::V4;
117 else if (s.find (
':') != string::npos) {
118 af = AddressFamily::V6;
123 case AddressFamily::V4: {
124 if (::inet_pton (AF_INET, s.c_str (), &fV4_) == 0) {
128 fAddressFamily_ = af;
130 case AddressFamily::V6: {
131 if (::inet_pton (AF_INET6, s.c_str (), &fV6_) == 0) {
135 fAddressFamily_ = af;
164 vector<bool> InternetAddress::As<vector<bool>> ()
const
166 if (GetAddressSize ().has_value ()) {
167 size_t sz = *GetAddressSize ();
169 result.reserve (sz * 8);
170 for (uint8_t b : As<vector<uint8_t>> ()) {
173 for (
unsigned int i = 0; i < 8; ++i) {
174 result.push_back (BitSubstring (b, 7 - i, 7 - i + 1));
180 return vector<bool>{};
184 String InternetAddress::As<String> ()
const
186 switch (fAddressFamily_) {
187 case AddressFamily::UNKNOWN: {
190 case AddressFamily::V4: {
191 char buf[INET_ADDRSTRLEN];
192 const char* result = ::inet_ntop (AF_INET, &fV4_, buf,
sizeof (buf));
193 Assert (result !=
nullptr);
194 Assert (::strlen (buf) <
sizeof (buf));
195 Assert (result == buf);
198 case AddressFamily::V6: {
199 char buf[INET6_ADDRSTRLEN];
200 const char* result = ::inet_ntop (AF_INET6, &fV6_, buf,
sizeof (buf));
201 Assert (result !=
nullptr);
202 Assert (result == buf);
203 Assert (::strlen (buf) <
sizeof (buf));
217 Require (not empty ());
218 switch (fAddressFamily_) {
219 case AddressFamily::V4: {
221 array<uint8_t, 4> octets = As<array<uint8_t, 4>> ();
222 return octets[0] == 0x7f and octets[1] == 0x0 and octets[2] == 0x0;
224 case AddressFamily::V6: {
225 return fV6_.s6_addr[0] == 0 and fV6_.s6_addr[1] == 0 and fV6_.s6_addr[2] == 0 and fV6_.s6_addr[3] == 0 and
226 fV6_.s6_addr[4] == 0 and fV6_.s6_addr[5] == 0 and fV6_.s6_addr[6] == 0 and fV6_.s6_addr[7] == 0 and
227 fV6_.s6_addr[8] == 0 and fV6_.s6_addr[9] == 0 and fV6_.s6_addr[10] == 0 and fV6_.s6_addr[11] == 0 and
228 fV6_.s6_addr[12] == 0 and fV6_.s6_addr[13] == 0 and fV6_.s6_addr[14] == 0 and fV6_.s6_addr[15] == 1;
237 Require (not empty ());
238 switch (fAddressFamily_) {
239 case AddressFamily::V4: {
242 Assert (kMinLinkLocal_ < kMaxLinkLocal_);
243 return kMinLinkLocal_ <= *
this and *
this <= kMaxLinkLocal_;
245 case AddressFamily::V6: {
246 return fV6_.s6_addr[0] == 0xfe and fV6_.s6_addr[1] == 0x80 and fV6_.s6_addr[2] == 0x0 and fV6_.s6_addr[3] == 0x0 and
247 fV6_.s6_addr[4] == 0x0 and fV6_.s6_addr[5] == 0x0 and fV6_.s6_addr[6] == 0x0 and fV6_.s6_addr[7] == 0x0;
256 switch (fAddressFamily_) {
257 case AddressFamily::V4: {
270 array<uint8_t, 4> octets = As<array<uint8_t, 4>> ();
271 if (octets[0] == 10) {
274 if (octets[0] == 172 and (octets[1] & 0xf0) == 16) {
277 if (octets[0] == 192 and octets[1] == 168) {
282 case AddressFamily::V6: {
292 bool result = (fV6_.s6_addr[0] == 0xfc or fV6_.s6_addr[0] == 0xfd) and fV6_.s6_addr[1] == 0x0;
302 Require (not empty ());
303 switch (fAddressFamily_) {
304 case AddressFamily::V4: {
307 array<uint8_t, 4> octets = As<array<uint8_t, 4>> ();
308 return 224 <= octets[0] and octets[0] <= 239;
310 case AddressFamily::V6: {
311 return fV6_.s6_addr[0] == 0xff;
320 if (GetAddressFamily () == family) {
323 if (GetAddressFamily () == AddressFamily::V4 and family == AddressFamily::V6) {
327 array<uint8_t, 4> octets = As<array<uint8_t, 4>> ();
328 return InternetAddress{in6_addr{{{0x20, 0x02, octets[0], octets[1], octets[2], octets[3]}}}};
330 else if (GetAddressFamily () == AddressFamily::V6 and family == AddressFamily::V4) {
336 in6_addr tmp = As<in6_addr> ();
337 if (tmp.s6_addr[0] == 0x20 and tmp.s6_addr[1] == 0x02) {
338 return InternetAddress{tmp.s6_addr[2], tmp.s6_addr[3], tmp.s6_addr[4], tmp.s6_addr[5]};
347 if (V4::kAddrAny == *
this) {
348 return "INADDR_ANY"sv;
350 if (V6::kAddrAny == *
this) {
351 return "in6addr_any"sv;
353 if (V4::kLocalhost == *
this) {
354 return "localhost"sv;
356 if (V6::kLocalhost == *
this) {
357 return "v6-localhost"sv;
359 if (V6::kV4MappedLocalhost == *
this) {
360 return "v4-localhost-As-v6"sv;
362 return As<String> ();
365InternetAddress InternetAddress::KeepSignificantBits (
unsigned int significantBits)
const
369 unsigned int sigBitsLeft = significantBits;
370 for (uint8_t b : this->As<vector<uint8_t>> ()) {
371 if (sigBitsLeft >= 8) {
376 unsigned int topBit = 8;
377 unsigned int botBit = topBit - sigBitsLeft;
378 r.
push_back (BitSubstring<uint8_t> (b, botBit, topBit) << botBit);
387 vector<uint8_t> addressAsArrayOfBytes = As<vector<uint8_t>> ();
388 Require (addressAsArrayOfBytes.size () >= 4);
389 size_t idx = addressAsArrayOfBytes.size () - 1;
391 unsigned int bytePart = o % 256;
393 unsigned int sum = addressAsArrayOfBytes[idx] + bytePart;
394 addressAsArrayOfBytes[idx] = sum % 256;
395 o += (sum / 256) * 256;
409 vector<uint8_t> addressAsArrayOfBytes = As<vector<uint8_t>> ();
410 Require (addressAsArrayOfBytes.size () >= 4);
411 Require (o <= addressAsArrayOfBytes.size () * 8);
412 size_t idx = addressAsArrayOfBytes.size () - 1;
413 unsigned int bitsRemaining = o;
415 while (bitsRemaining != 0) {
416 Assert (idx > 0 and idx < addressAsArrayOfBytes.size ());
417 auto nBits = Math::AtMost (bitsRemaining, 8u);
418 addressAsArrayOfBytes[idx] = addressAsArrayOfBytes[idx] | Memory::BitSubstring<uint8_t> (0xff, 0, nBits);
420 bitsRemaining -= nBits;
434 result += V4::kAddrAny;
437 result += V6::kAddrAny;
439 return move (result);
451 result += V4::kLocalhost;
454 result += V6::kLocalhost;
456 return move (result);
#define RequireNotReached()
#define AssertNotReached()
String is like std::u32string, except it is much easier to use, often much more space efficient,...
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
nonvirtual bool IsPrivateAddress() const
nonvirtual String ToString() const
constexpr InternetAddress()
nonvirtual InternetAddress PinLowOrderBitsToMax(unsigned int o) const
offset this IP Address by 'o' by setting the low order 'o' bits to the maximum value
nonvirtual bool IsLinkLocalAddress() const
nonvirtual optional< InternetAddress > AsAddressFamily(AddressFamily family) const
nonvirtual bool IsLocalhostAddress() const
nonvirtual InternetAddress Offset(uint64_t o) const
offset this IP Address by 'o' discrete addresses (positive only, unsigned offset).
nonvirtual bool IsMulticastAddress() const
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual void push_back(Common::ArgByValueType< T > e)
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
bool SupportIPV4(IPVersionSupport flag)
bool SupportIPV6(IPVersionSupport flag)
Traversal::Iterable< InternetAddress > InternetAddresses_Localhost(InternetProtocol::IP::IPVersionSupport ipSupport=InternetProtocol::IP::IPVersionSupport::eDEFAULT)
Traversal::Iterable< InternetAddress > InternetAddresses_Any(InternetProtocol::IP::IPVersionSupport ipSupport=InternetProtocol::IP::IPVersionSupport::eDEFAULT)
Memory::BLOB operator()(const T &t) const