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