Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
InternetAddress.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_IO_Network_InternetAddress_h_
5#define _Stroika_Foundation_IO_Network_InternetAddress_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <compare>
10#include <optional>
11
12#if qStroika_Foundation_Common_Platform_POSIX
13#include <arpa/inet.h>
14#include <sys/socket.h> // for AF_INET etc
15#elif qStroika_Foundation_Common_Platform_Windows
16#include <WinSock2.h>
17
18#include <in6addr.h>
19#include <inaddr.h>
20#endif
21
23#include "Stroika/Foundation/Common/Common.h"
24#include "Stroika/Foundation/DataExchange/DefaultSerializer.h"
25#include "Stroika/Foundation/IO/Network/InternetProtocol/IP.h"
28
29/**
30 * \file
31 *
32 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
33 *
34 * TODO:
35 * @todo If possible (I think yes) have method on InternetAddress() to return Scope (like local , global etc).
36 *
37 * enum Scope {
38 * Interface-Local (0x1)
39 * Link-Local (0x2)
40 * Admin-Local (0x4) // MULTICAST ONLY
41 * Site-Local (0x5) (AKA - probably better name 'Unique Local Addresses')
42 * Organization-Local (0x8) // MULTICAST ONLY
43 * Global (0xE)
44 * };
45 *
46 * Note - there is the Scope, and then the ScoeeID (not sure?)
47 * IPAddress.ScopeId
48 * http://msdn.microsoft.com/en-us/library/system.net.ipaddress.scopeid(v=vs.110).aspx
49 *
50 * @todo Also add IPAddress.IsIPv4MappedToIPv6 Property
51 * http://msdn.microsoft.com/en-us/library/system.net.ipaddress.isipv4mappedtoipv6(v=vs.110).aspx
52 * IPAddress.IsIPv6LinkLocal
53 * http://msdn.microsoft.com/en-us/library/system.net.ipaddress.isipv6linklocal(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
54 *
55 * @todo Future versions may support converting from IPV4 address to IPV6 by assigning an
56 * IPV4 and saying As<in6_addr> ()? Or maybe have ToIPV6() method?
57 */
58
60
61 using Characters::String;
62
63 /**
64 * v4 ip addr as a long.
65 */
66#if qStroika_Foundation_Common_Platform_POSIX
67 using in_addr_t = ::in_addr_t;
68#else
69 using in_addr_t = uint32_t;
70#endif
71
72 /**
73 * InternetAddress represents an internet IP address. Its easily convertible to/from
74 * the variety of POSIX/Berkley socket formats.
75 *
76 * InternetAddress supports either IPv4 or IPv6 format addresses.
77 *
78 * InternetAddress objects can be rendered in either network byte order or host byte order,
79 * but overwhelmingly APIs use network byte order, so that is the default, and the internal
80 * representation.
81 *
82 * Also, for IPv6 addresses, since they can be represented as bytes, or shorts, or longs,
83 * its ambiguous what host byte order might mean, so no 'host byte order' API is provided
84 * for IPv6 addresses: just network byte order.
85 *
86 * \note When constructing or extracting arrays/vectors etc from an InternetAddress, the high order
87 * (most significant) octet come before the lower order octets (so b[0] is high order byte). The ByteOrder enum
88 * can generally be used when assigning/extracting structures from the internet address object.
89 *
90 * \note Site-Local addresses
91 * This class provides no support for site-local addresses because they have been deprecated
92 * in http://www.ietf.org/rfc/rfc3879.txt
93 *
94 * TODO:
95 * \todo Consider if InternetAddress CTOR should allow empty method, and default CTOR?
96 *
97 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
98 * static_assert (totally_ordered<InternetAddress>);
99 */
101 public:
102 /**
103 * @see Common::Endian
104 * @see Common::EndianConverter
105 */
106 enum class ByteOrder {
107 Network,
108 Host,
109
110 eDEFAULT = Network,
111
112 Stroika_Define_Enum_Bounds (Network, Host)
113 };
114
115 public:
116 /**
117 * This can be V4, V6, or UNKNOWN. The value of this flag is the internet af_family type (e.g. AF_INET).
118 */
119 enum class AddressFamily {
120 UNKNOWN = AF_UNSPEC,
121 V4 = AF_INET,
122 V6 = AF_INET6,
123 };
124
125 public:
126 /**
127 * A handy way to access the octets of an IPv4 address without worry about endian stuff.
128 *
129 * \note prior to Stroika v2.1d13, this was tuple<uint8_t,uint8_t,uint8_t,uint8_t>;
130 */
131 using IPv4AddressOctets = array<uint8_t, 4>;
132
133 public:
134 /**
135 * A handy way to access the octets of an IPv6 address without worry about endian stuff.
136 */
137 using IPv6AddressOctets = array<uint8_t, 16>;
138
139 public:
140 /**
141 * InternetAddress (const string& s, AddressFamily af = AddressFamily::UNKNOWN);
142 * InternetAddress (const String& s, AddressFamily af = AddressFamily::UNKNOWN);
143 * Construct an InternetAddress object from a string (with optionally specified address family).
144 * If the address is unparsable according to the rules specified, an exception will be thrown.
145 *
146 * \note This does NOT lookup hostnames (like www.google.com or localhost). It must be a numeric
147 * form of an internet address. Use IO::Network::DNS::kThe.GetHostAddresses () instead.
148 *
149 * \note also this parser doesn't support surrounding spaces, so Trim () first.
150 *
151 * constexpr InternetAddress (const in_addr_t& i);
152 * InternetAddress (const in_addr_t& i, ByteOrder byteOrder);
153 * Construct an InternetAddress from in_addr_t (v4 ip addr as a long).
154 * Note that provided in_addr must already be in network order (unless explicit byte order provided as argument)
155 *
156 * constexpr InternetAddress (const in_addr& i);
157 * InternetAddress (const in_addr& i, ByteOrder byteOrder);
158 * Construct an InternetAddress from in_addr - V4 address.
159 * Note that provided in_addr must already be in network order (unless explicit byte order provided as argument)
160 *
161 * constexpr InternetAddress (byte octet1, byte octet2, byte octet3, byte octet4);
162 * constexpr InternetAddress (uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4);
163 * Construct an InternetAddress V4 address in A.B.C.D octet form.
164 *
165 * constexpr InternetAddress (const in6_addr& i);
166 * Construct an InternetAddress from in6_addr - V6 address.
167 *
168 * InternetAddress (Traversal::Iterable<uint8_t> octets, AddressFamily af);
169 * InternetAddress (Traversal::Iterable<byte> octets, AddressFamily af);
170 * Construct an InternetAddress octets, either 4 or 16 in length, and which must agree with provided address-family
171 *
172 * \note Constructors taking array/vector arguments, expect bytes with high order data
173 * first in array.
174 */
175 constexpr InternetAddress ();
176 constexpr InternetAddress (const InternetAddress&) noexcept = default;
177 constexpr InternetAddress (InternetAddress&&) noexcept = default;
178 explicit InternetAddress (const string& s, AddressFamily af = AddressFamily::UNKNOWN);
179 explicit InternetAddress (const string_view& s, AddressFamily af = AddressFamily::UNKNOWN);
180 explicit InternetAddress (const char* s, AddressFamily af = AddressFamily::UNKNOWN);
181 explicit InternetAddress (const String& s, AddressFamily af = AddressFamily::UNKNOWN);
182 constexpr InternetAddress (const in_addr_t& i);
183 InternetAddress (const in_addr_t& i, ByteOrder byteOrder);
184 constexpr InternetAddress (const in_addr& i);
185 InternetAddress (const in_addr& i, ByteOrder byteOrder);
186 constexpr InternetAddress (byte octet1, byte octet2, byte octet3, byte octet4);
187 constexpr InternetAddress (uint8_t octet1, uint8_t octet2, uint8_t octet3, uint8_t octet4);
188 constexpr InternetAddress (array<uint8_t, 4> octets, AddressFamily af = AddressFamily::V4);
189 constexpr InternetAddress (array<byte, 4> octets, AddressFamily af = AddressFamily::V4);
190 constexpr InternetAddress (const in6_addr& i);
191 constexpr InternetAddress (array<uint8_t, 16> octets, AddressFamily af = AddressFamily::V6);
192 constexpr InternetAddress (array<byte, 16> octets, AddressFamily af = AddressFamily::V6);
193 template <ranges::range ITERABLE_OF_UINT8OrByte>
194 InternetAddress (ITERABLE_OF_UINT8OrByte octets, AddressFamily af)
195 requires (Traversal::IIterableOfTo<ITERABLE_OF_UINT8OrByte, byte> or Traversal::IIterableOfTo<ITERABLE_OF_UINT8OrByte, uint8_t>);
196
197 public:
198 constexpr InternetAddress& operator= (const InternetAddress&) noexcept = default;
199 constexpr InternetAddress& operator= (InternetAddress&&) noexcept = default;
200
201 public:
202 /**
203 * Check if unspecified internet address.
204 * @see clear()
205 */
206 nonvirtual constexpr bool empty () const;
207
208 public:
209 /**
210 * Make it empty().
211 * @see empty()
212 */
213 nonvirtual void clear ();
214
215 public:
216 /**
217 * This can be V4, V6, or UNKNOWN, and iff UNKNOWN, then empty () will return true.
218 */
219 nonvirtual constexpr AddressFamily GetAddressFamily () const;
220
221 public:
222 /**
223 * Converts - if possible - to the given address family. So for example, to IPv6.
224 *
225 * \note - there are many ways to convert from IPv4 to IPv6, and this uses "6to4" - https://en.wikipedia.org/wiki/6to4
226 */
227 nonvirtual optional<InternetAddress> AsAddressFamily (AddressFamily family) const;
228
229 public:
230 /**
231 * The size in bytes of the raw address.
232 */
233 nonvirtual constexpr optional<size_t> GetAddressSize () const;
234
235 public:
236 /**
237 * InternetAddress::min () is the smallest allowed InternetAddress. This is mostly useful as a sentinel (better to use optional)
238 * or for sorting.
239 */
240 static constexpr InternetAddress min ();
241
242 public:
243 /**
244 * InternetAddress::min () is the smallest allowed InternetAddress. This is mostly useful as a sentinel (better to use optional)
245 * or for sorting.
246 */
247 static constexpr InternetAddress max ();
248
249 public:
250 /**
251 * Only specifically specialized variants are supported. As<T> supported variants include:
252 * As<String> ();
253 * As<in_addr_t> (); // qStroika_Foundation_Common_Platform_POSIX ONLY
254 * As<in_addr> (); // GetAddressFamily () == V4 only
255 * As<array<byte,4>> (); // GetAddressFamily () == V4 only
256 * As<array<uint8_t,4>> (); // GetAddressFamily () == V4 only
257 * As<IPv4AddressOctets> // GetAddressFamily () == V4 only (alias)
258 * As<in6_addr> (); // GetAddressFamily () == V6 only
259 * As<array<byte,16>> (); // GetAddressFamily () == V6 only
260 * As<array<uint8_t,16>> (); // GetAddressFamily () == V6 only
261 * As<IPv6AddressOctets> // GetAddressFamily () == V6 only (alias)
262 * As<vector<byte>> (); // if (AddressFamily not V4 or V6) may return empty vector
263 * As<vector<uint8_t>> (); // if (AddressFamily not V4 or V6) may return empty vector
264 * As<vector<bool>> (); // if (AddressFamily not V4 or V6) may return empty vector; (returns 'bits' mapped into array indexes - high order bit of high order byte first)
265 *
266 * Note that returned in_addr, in_addr_t addresses already in network byte order (for the no-arg overload).
267 *
268 * As<T> (ByteOrder) is only defined for T==in_addr, and then the byte order is determined by the parameter.
269 *
270 * As<array<...>> or As<vector<>>... returns high order bytes first.
271 *
272 * As<array<byte,4>> () returns the high order (in this case 'network') byte
273 * in the first part of the array, so
274 * Assert (InternetAddress { 1, 2, 3, 4 }.As<array<byte,4>> ()[0] == 1);
275 *
276 * \note As<String> () will always produce a numerical representation, whereas ToString () - will sometimes produce
277 * a textual shortcut, like "INADDR_ANY".
278 *
279 * \note As (ByteOrder) overload only applies to certain types (structured types) where byte order might make sense,
280 * and is not allowed for arrays (which are always returned high order elements first in the array).
281 */
282 template <typename T>
283 nonvirtual T As () const;
284 template <typename T>
285 nonvirtual T As (ByteOrder byteOrder) const;
286
287 public:
288 /**
289 */
290 nonvirtual strong_ordering operator<=> (const InternetAddress& rhs) const;
291
292 public:
293 /**
294 */
295 nonvirtual bool operator== (const InternetAddress& rhs) const;
296
297 public:
298 /**
299 * @see Characters::ToString ()
300 *
301 * \note As<String> () will always produce a numerical representation, whereas ToString () - will sometimes produce
302 * a textual shortcut, like "INADDR_ANY".
303 */
304 nonvirtual String ToString () const;
305
306 public:
307 /**
308 */
309 nonvirtual InternetAddress KeepSignificantBits (unsigned int significantBits) const;
310
311 public:
312 /**
313 * \brief offset this IP Address by 'o' discrete addresses (positive only, unsigned offset).
314 *
315 * @todo support different kinds of offsets
316 * @todo document/follow appropriate overflow behavior
317 *
318 * @see PinLowOrderBitsToMax ()
319 */
320 nonvirtual InternetAddress Offset (uint64_t o) const;
321
322 public:
323 /**
324 * \brief offset this IP Address by 'o' by setting the low order 'o' bits to the maximum value
325 *
326 * @see Offset ()
327 */
328 nonvirtual InternetAddress PinLowOrderBitsToMax (unsigned int o) const;
329
330 public:
331 /**
332 * \pre not empty ()
333 *
334 * Return true iff the given address is a localhost IP address (typically 127.0.0.1, but can be anything
335 * in that class C range, or ::1, for IPv6 or that range).
336 *
337 * This might be better called 'loopback' address. This is NOT for link-local addresses.
338 */
339 nonvirtual bool IsLocalhostAddress () const;
340
341 public:
342 /**
343 * Returns true iff the address is an 'link local' address. In IPv4 this means 169.254.0.1
344 * through 169.254.255.254, and in IPv6 these are fe80::/64. These are used for autoconf
345 * when there is no DHCP server, as in http://tools.ietf.org/html/rfc3927
346 */
347 nonvirtual bool IsLinkLocalAddress () const;
348
349 public:
350 /**
351 * \pre not empty ()
352 * Return true iff the given address is a private IP address (non-routable).
353 * This is sometimes also called Unique Local Addresses (especially in IPv6).
354 */
355 nonvirtual bool IsPrivateAddress () const;
356
357 public:
358 /**
359 * \pre not empty ()
360 * Return true iff the given address is a mutlicast IP address.
361 */
362 nonvirtual bool IsMulticastAddress () const;
363
364 private:
365 // @todo debug why this cannot be constexpr in clang++-10-debug-libc++-c++2a builds - issue is comparing strong_ordering elts?? crazy
366 static strong_ordering TWC_ (const InternetAddress& lhs, const InternetAddress& rhs); // utility code share between c++17 and c++20 versions
367
368 private:
369 AddressFamily fAddressFamily_;
370 union {
371 // EACH Stored in network byte order
372 in_addr fV4_;
373 in6_addr fV6_;
374 array<uint8_t, 4> fArray_4_uint_;
375 array<byte, 4> fArray_4_byte_;
376 array<uint8_t, 16> fArray_16_uint_;
377 array<byte, 16> fArray_16_byte_;
378 };
379 };
380 static_assert (totally_ordered<InternetAddress>);
381
382 /**
383 * IN_ADDR_ANY
384 * This address is a wildcard, matching any address.
385 *
386 * \note Cannot declare here cuz then declaration and definition differ, and cannot define here because we have
387 * the constexpr CTOR methods in the .inl file.
388 *
389 * namespace V4 { constexpr InternetAddress kAddrAny{in_addr{}}; }
390 * namespace V6 { constexpr InternetAddress kAddrAny{in6_addr{}}; }
391 */
392
393 /**
394 * LOCALHOST address
395 * this address is for the current machine on its loopback interface.
396 *
397 * \note Cannot declare here cuz then declaration and definition differ, and cannot define here because we have
398 * the constexpr CTOR methods in the .inl file.
399 *
400 * namespace V4 { constexpr InternetAddress kLocalhost{0x7f, 0x0, 0x0, 0x1}; }
401 * namespace V6 { constexpr InternetAddress kLocalhost{in6_addr{{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}}}; }
402 */
403
404 /**
405 * v4 localhost address rendered as v6 (mapped).
406 *
407 * \note Cannot declare here cuz then declaration and definition differ, and cannot define here because we have
408 * the constexpr CTOR methods in the .inl file.
409 *
410 * namespace V6 { constexpr InternetAddress kV4MappedLocalhost{in6_addr{{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1}}}}; }
411 */
412
413 /**
414 * Return kAddrAny - both the IPv4 and IPv6 variants (depending on ipSupport argument) - which defaults to both.
415 */
417 InternetAddresses_Any (InternetProtocol::IP::IPVersionSupport ipSupport = InternetProtocol::IP::IPVersionSupport::eDEFAULT);
418
419 /**
420 * Return kLocalhost - both the IPv4 and IPv6 variants (depending on ipSupport argument) - which defaults to both.
421 */
423 InternetAddresses_Localhost (InternetProtocol::IP::IPVersionSupport ipSupport = InternetProtocol::IP::IPVersionSupport::eDEFAULT);
424
425}
426
427namespace std {
428 template <>
429 struct hash<Stroika::Foundation::IO::Network::InternetAddress> {
430 size_t operator() (const Stroika::Foundation::IO::Network::InternetAddress& arg) const;
431 };
432}
434 template <>
435 struct DefaultSerializer<Stroika::Foundation::IO::Network::InternetAddress> {
437 };
438}
439
441
442 template <>
443 struct DefaultOpenness<IO::Network::InternetAddress> : ExplicitOpenness<Openness::eClosed, Openness::eClosed> {};
444 template <>
445 struct DefaultDifferenceTypes<IO::Network::InternetAddress> : ExplicitDifferenceTypes<int, unsigned int> {};
446 template <>
447 struct Default<IO::Network::InternetAddress> : ExplicitOpennessAndDifferenceType<IO::Network::InternetAddress> {
448 using InternetAddress = IO::Network::InternetAddress;
449
450 static const InternetAddress kLowerBound;
451 static const InternetAddress kUpperBound;
452
453 static InternetAddress GetNext (InternetAddress n);
454 static InternetAddress GetPrevious (InternetAddress n);
455
456 static constexpr auto Difference (Common::ArgByValueType<value_type> lhs, Common::ArgByValueType<value_type> rhs) -> SignedDifferenceType;
457 };
458
459}
460
461/*
462 ********************************************************************************
463 ***************************** Implementation Details ***************************
464 ********************************************************************************
465 */
466#include "InternetAddress.inl"
467
468#endif /*_Stroika_Foundation_IO_Network_InternetAddress_h_*/
#define Stroika_Define_Enum_Bounds(FIRST_ITEM, LAST_ITEM)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual constexpr optional< size_t > GetAddressSize() const
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 optional< InternetAddress > AsAddressFamily(AddressFamily family) const
nonvirtual constexpr AddressFamily GetAddressFamily() const
nonvirtual InternetAddress Offset(uint64_t o) const
offset this IP Address by 'o' discrete addresses (positive only, unsigned offset).
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
Definition TypeHints.h:32
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)
STL namespace.
This defines the default openness for a given type T, except for specializaitons. This is used by Exp...
Definition Range.h:81