100.00% Lines (9/9) 100.00% Functions (5/5)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2026 Vinnie Falco (vinnie.falco@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 4   // Distributed under the Boost Software License, Version 1.0. (See accompanying
5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/corosio 7   // Official repository: https://github.com/cppalliance/corosio
8   // 8   //
9   9  
10   #ifndef BOOST_COROSIO_IPV6_ADDRESS_HPP 10   #ifndef BOOST_COROSIO_IPV6_ADDRESS_HPP
11   #define BOOST_COROSIO_IPV6_ADDRESS_HPP 11   #define BOOST_COROSIO_IPV6_ADDRESS_HPP
12   12  
13   #include <boost/corosio/detail/config.hpp> 13   #include <boost/corosio/detail/config.hpp>
14   14  
15   #include <boost/capy/io_result.hpp> 15   #include <boost/capy/io_result.hpp>
16   16  
17   #include <array> 17   #include <array>
18   #include <iosfwd> 18   #include <iosfwd>
19   #include <string> 19   #include <string>
20   #include <string_view> 20   #include <string_view>
21   #include <system_error> 21   #include <system_error>
22   22  
23   namespace boost::corosio { 23   namespace boost::corosio {
24   24  
25   class ipv4_address; 25   class ipv4_address;
26   26  
27   /** An IP version 6 style address. 27   /** An IP version 6 style address.
28   28  
29   Objects of this type are used to construct, 29   Objects of this type are used to construct,
30   parse, and manipulate IP version 6 addresses. 30   parse, and manipulate IP version 6 addresses.
31   31  
32   @par BNF 32   @par BNF
33   @code 33   @code
34   IPv6address = 6( h16 ":" ) ls32 34   IPv6address = 6( h16 ":" ) ls32
35   / "::" 5( h16 ":" ) ls32 35   / "::" 5( h16 ":" ) ls32
36   / [ h16 ] "::" 4( h16 ":" ) ls32 36   / [ h16 ] "::" 4( h16 ":" ) ls32
37   / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 37   / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
38   / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 38   / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
39   / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 39   / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
40   / [ *4( h16 ":" ) h16 ] "::" ls32 40   / [ *4( h16 ":" ) h16 ] "::" ls32
41   / [ *5( h16 ":" ) h16 ] "::" h16 41   / [ *5( h16 ":" ) h16 ] "::" h16
42   / [ *6( h16 ":" ) h16 ] "::" 42   / [ *6( h16 ":" ) h16 ] "::"
43   43  
44   ls32 = ( h16 ":" h16 ) / IPv4address 44   ls32 = ( h16 ":" h16 ) / IPv4address
45   ; least-significant 32 bits of address 45   ; least-significant 32 bits of address
46   46  
47   h16 = 1*4HEXDIG 47   h16 = 1*4HEXDIG
48   ; 16 bits of address represented in hexadecimal 48   ; 16 bits of address represented in hexadecimal
49   @endcode 49   @endcode
50   50  
51   @par Specification 51   @par Specification
52   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291" 52   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291"
53   >IP Version 6 Addressing Architecture (rfc4291)</a> 53   >IP Version 6 Addressing Architecture (rfc4291)</a>
54   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2" 54   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
55   >3.2.2. Host (rfc3986)</a> 55   >3.2.2. Host (rfc3986)</a>
56   56  
57   @see 57   @see
58   @ref ipv4_address, 58   @ref ipv4_address,
59   @ref make_ipv6_address. 59   @ref make_ipv6_address.
60   */ 60   */
61   class BOOST_COROSIO_DECL ipv6_address 61   class BOOST_COROSIO_DECL ipv6_address
62   { 62   {
63   std::array<unsigned char, 16> addr_{}; 63   std::array<unsigned char, 16> addr_{};
64   64  
65   public: 65   public:
66   /** The number of characters in the longest possible IPv6 string. 66   /** The number of characters in the longest possible IPv6 string.
67   67  
68   The longest IPv6 address is: 68   The longest IPv6 address is:
69   @code 69   @code
70   ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 70   ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
71   @endcode 71   @endcode
72   or with IPv4-mapped: 72   or with IPv4-mapped:
73   @code 73   @code
74   ::ffff:255.255.255.255 74   ::ffff:255.255.255.255
75   @endcode 75   @endcode
76   */ 76   */
77   static constexpr std::size_t max_str_len = 49; 77   static constexpr std::size_t max_str_len = 49;
78   78  
79   /** The type used to represent an address as an array of bytes. 79   /** The type used to represent an address as an array of bytes.
80   80  
81   Octets are stored in network byte order. 81   Octets are stored in network byte order.
82   */ 82   */
83   using bytes_type = std::array<unsigned char, 16>; 83   using bytes_type = std::array<unsigned char, 16>;
84   84  
85   /** Default constructor. 85   /** Default constructor.
86   86  
87   Constructs the unspecified address (::). 87   Constructs the unspecified address (::).
88   88  
89   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2" 89   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2"
90   >2.5.2. The Unspecified Address</a> 90   >2.5.2. The Unspecified Address</a>
91   91  
92   @see 92   @see
93   @ref is_unspecified 93   @ref is_unspecified
94   */ 94   */
HITCBC 95   151309 ipv6_address() = default; 95   185208 ipv6_address() = default;
96   96  
97   /** Copy constructor. 97   /** Copy constructor.
98   */ 98   */
99   ipv6_address(ipv6_address const&) = default; 99   ipv6_address(ipv6_address const&) = default;
100   100  
101   /** Copy assignment. 101   /** Copy assignment.
102   102  
103   @return A reference to this object. 103   @return A reference to this object.
104   */ 104   */
105   ipv6_address& operator=(ipv6_address const&) = default; 105   ipv6_address& operator=(ipv6_address const&) = default;
106   106  
107   /** Construct from an array of bytes. 107   /** Construct from an array of bytes.
108   108  
109   This function constructs an address 109   This function constructs an address
110   from the array in `bytes`, which is 110   from the array in `bytes`, which is
111   interpreted in big-endian. 111   interpreted in big-endian.
112   112  
113   @param bytes The value to construct from. 113   @param bytes The value to construct from.
114   */ 114   */
115   explicit ipv6_address(bytes_type const& bytes) noexcept; 115   explicit ipv6_address(bytes_type const& bytes) noexcept;
116   116  
117   /** Construct from an IPv4 address. 117   /** Construct from an IPv4 address.
118   118  
119   This function constructs an IPv6 address 119   This function constructs an IPv6 address
120   from the IPv4 address `addr`. The resulting 120   from the IPv4 address `addr`. The resulting
121   address is an IPv4-Mapped IPv6 Address. 121   address is an IPv4-Mapped IPv6 Address.
122   122  
123   @param addr The address to construct from. 123   @param addr The address to construct from.
124   124  
125   @par Specification 125   @par Specification
126   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2" 126   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"
127   >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a> 127   >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
128   */ 128   */
129   explicit ipv6_address(ipv4_address const& addr) noexcept; 129   explicit ipv6_address(ipv4_address const& addr) noexcept;
130   130  
131   /** Construct from a string. 131   /** Construct from a string.
132   132  
133   This function constructs an address from 133   This function constructs an address from
134   the string `s`, which must contain a valid 134   the string `s`, which must contain a valid
135   IPv6 address string or else an exception 135   IPv6 address string or else an exception
136   is thrown. 136   is thrown.
137   137  
138   @note For a non-throwing parse function, 138   @note For a non-throwing parse function,
139   use @ref make_ipv6_address. 139   use @ref make_ipv6_address.
140   140  
141   @par Exception Safety 141   @par Exception Safety
142   Exceptions thrown on invalid input. 142   Exceptions thrown on invalid input.
143   143  
144   @throws std::system_error `errc::invalid_argument` if the input 144   @throws std::system_error `errc::invalid_argument` if the input
145   failed to parse correctly. 145   failed to parse correctly.
146   146  
147   @param s The string to parse. 147   @param s The string to parse.
148   148  
149   @par Specification 149   @par Specification
150   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2" 150   @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
151   >3.2.2. Host (rfc3986)</a> 151   >3.2.2. Host (rfc3986)</a>
152   152  
153   @see 153   @see
154   @ref make_ipv6_address. 154   @ref make_ipv6_address.
155   */ 155   */
156   explicit ipv6_address(std::string_view s); 156   explicit ipv6_address(std::string_view s);
157   157  
158   /** Return the address as bytes, in network byte order. 158   /** Return the address as bytes, in network byte order.
159   159  
160   @return The address as an array of bytes. 160   @return The address as an array of bytes.
161   */ 161   */
HITCBC 162   66 bytes_type to_bytes() const noexcept 162   66 bytes_type to_bytes() const noexcept
163   { 163   {
HITCBC 164   66 return addr_; 164   66 return addr_;
165   } 165   }
166   166  
167   /** Return the address as a string. 167   /** Return the address as a string.
168   168  
169   The returned string does not 169   The returned string does not
170   contain surrounding square brackets. 170   contain surrounding square brackets.
171   171  
172   @par Example 172   @par Example
173   @code 173   @code
174   ipv6_address::bytes_type b = {{ 174   ipv6_address::bytes_type b = {{
175   0, 1, 0, 2, 0, 3, 0, 4, 175   0, 1, 0, 2, 0, 3, 0, 4,
176   0, 5, 0, 6, 0, 7, 0, 8 }}; 176   0, 5, 0, 6, 0, 7, 0, 8 }};
177   ipv6_address a(b); 177   ipv6_address a(b);
178   assert(a.to_string() == "1:2:3:4:5:6:7:8"); 178   assert(a.to_string() == "1:2:3:4:5:6:7:8");
179   @endcode 179   @endcode
180   180  
181   @return The address as a string. 181   @return The address as a string.
182   182  
183   @par Specification 183   @par Specification
184   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2"> 184   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
185   2.2. Text Representation of Addresses (rfc4291)</a> 185   2.2. Text Representation of Addresses (rfc4291)</a>
186   */ 186   */
187   std::string to_string() const; 187   std::string to_string() const;
188   188  
189   /** Write a string representing the address to a buffer. 189   /** Write a string representing the address to a buffer.
190   190  
191   The resulting buffer is not null-terminated. 191   The resulting buffer is not null-terminated.
192   192  
193   @throw std::length_error `dest_size < ipv6_address::max_str_len` 193   @throw std::length_error `dest_size < ipv6_address::max_str_len`
194   194  
195   @return The formatted string view. 195   @return The formatted string view.
196   196  
197   @param dest The buffer in which to write, 197   @param dest The buffer in which to write,
198   which must have at least `dest_size` space. 198   which must have at least `dest_size` space.
199   199  
200   @param dest_size The size of the output buffer. 200   @param dest_size The size of the output buffer.
201   */ 201   */
202   std::string_view to_buffer(char* dest, std::size_t dest_size) const; 202   std::string_view to_buffer(char* dest, std::size_t dest_size) const;
203   203  
204   /** Return true if the address is unspecified. 204   /** Return true if the address is unspecified.
205   205  
206   The address 0:0:0:0:0:0:0:0 is called the 206   The address 0:0:0:0:0:0:0:0 is called the
207   unspecified address. It indicates the 207   unspecified address. It indicates the
208   absence of an address. 208   absence of an address.
209   209  
210   @return `true` if the address is unspecified. 210   @return `true` if the address is unspecified.
211   211  
212   @par Specification 212   @par Specification
213   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2"> 213   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2">
214   2.5.2. The Unspecified Address (rfc4291)</a> 214   2.5.2. The Unspecified Address (rfc4291)</a>
215   */ 215   */
216   bool is_unspecified() const noexcept; 216   bool is_unspecified() const noexcept;
217   217  
218   /** Return true if the address is a loopback address. 218   /** Return true if the address is a loopback address.
219   219  
220   The unicast address 0:0:0:0:0:0:0:1 is called 220   The unicast address 0:0:0:0:0:0:0:1 is called
221   the loopback address. It may be used by a node 221   the loopback address. It may be used by a node
222   to send an IPv6 packet to itself. 222   to send an IPv6 packet to itself.
223   223  
224   @return `true` if the address is a loopback address. 224   @return `true` if the address is a loopback address.
225   225  
226   @par Specification 226   @par Specification
227   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3"> 227   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
228   2.5.3. The Loopback Address (rfc4291)</a> 228   2.5.3. The Loopback Address (rfc4291)</a>
229   */ 229   */
230   bool is_loopback() const noexcept; 230   bool is_loopback() const noexcept;
231   231  
232   /** Return true if the address is a mapped IPv4 address. 232   /** Return true if the address is a mapped IPv4 address.
233   233  
234   This address type is used to represent the 234   This address type is used to represent the
235   addresses of IPv4 nodes as IPv6 addresses. 235   addresses of IPv4 nodes as IPv6 addresses.
236   236  
237   @return `true` if the address is a mapped IPv4 address. 237   @return `true` if the address is a mapped IPv4 address.
238   238  
239   @par Specification 239   @par Specification
240   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"> 240   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2">
241   2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a> 241   2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
242   */ 242   */
243   bool is_v4_mapped() const noexcept; 243   bool is_v4_mapped() const noexcept;
244   244  
245   /** Return true if the address is a multicast address. 245   /** Return true if the address is a multicast address.
246   246  
247   IPv6 multicast addresses have the prefix ff00::/8. 247   IPv6 multicast addresses have the prefix ff00::/8.
248   248  
249   @return `true` if the address is a multicast address. 249   @return `true` if the address is a multicast address.
250   250  
251   @par Specification 251   @par Specification
252   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.7"> 252   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.7">
253   2.7. Multicast Addresses (rfc4291)</a> 253   2.7. Multicast Addresses (rfc4291)</a>
254   */ 254   */
255   bool is_multicast() const noexcept; 255   bool is_multicast() const noexcept;
256   256  
257   /** Return true if two addresses are equal. 257   /** Return true if two addresses are equal.
258   258  
259   @return `true` if the addresses are equal. 259   @return `true` if the addresses are equal.
260   */ 260   */
261   friend bool 261   friend bool
HITCBC 262   28 operator==(ipv6_address const& a1, ipv6_address const& a2) noexcept 262   28 operator==(ipv6_address const& a1, ipv6_address const& a2) noexcept
263   { 263   {
HITCBC 264   28 return a1.addr_ == a2.addr_; 264   28 return a1.addr_ == a2.addr_;
265   } 265   }
266   266  
267   /** Return true if two addresses are not equal. 267   /** Return true if two addresses are not equal.
268   268  
269   @return `true` if the addresses are not equal. 269   @return `true` if the addresses are not equal.
270   */ 270   */
271   friend bool 271   friend bool
HITCBC 272   2 operator!=(ipv6_address const& a1, ipv6_address const& a2) noexcept 272   2 operator!=(ipv6_address const& a1, ipv6_address const& a2) noexcept
273   { 273   {
HITCBC 274   2 return a1.addr_ != a2.addr_; 274   2 return a1.addr_ != a2.addr_;
275   } 275   }
276   276  
277   /** Return an address object that represents the unspecified address. 277   /** Return an address object that represents the unspecified address.
278   278  
279   The address 0:0:0:0:0:0:0:0 (::) may be used to bind a socket 279   The address 0:0:0:0:0:0:0:0 (::) may be used to bind a socket
280   to all available interfaces. 280   to all available interfaces.
281   281  
282   @return The unspecified address (::). 282   @return The unspecified address (::).
283   */ 283   */
HITCBC 284   9 static ipv6_address any() noexcept 284   9 static ipv6_address any() noexcept
285   { 285   {
HITCBC 286   9 return ipv6_address(); 286   9 return ipv6_address();
287   } 287   }
288   288  
289   /** Return an address object that represents the loopback address. 289   /** Return an address object that represents the loopback address.
290   290  
291   The unicast address 0:0:0:0:0:0:0:1 is called 291   The unicast address 0:0:0:0:0:0:0:1 is called
292   the loopback address. It may be used by a node 292   the loopback address. It may be used by a node
293   to send an IPv6 packet to itself. 293   to send an IPv6 packet to itself.
294   294  
295   @par Specification 295   @par Specification
296   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3"> 296   @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
297   2.5.3. The Loopback Address (rfc4291)</a> 297   2.5.3. The Loopback Address (rfc4291)</a>
298   298  
299   @return The loopback address (::1). 299   @return The loopback address (::1).
300   */ 300   */
301   static ipv6_address loopback() noexcept; 301   static ipv6_address loopback() noexcept;
302   302  
303   /** Format the address to an output stream. 303   /** Format the address to an output stream.
304   304  
305   This function writes the address to an 305   This function writes the address to an
306   output stream using standard notation. 306   output stream using standard notation.
307   307  
308   @return The output stream, for chaining. 308   @return The output stream, for chaining.
309   309  
310   @param os The output stream to write to. 310   @param os The output stream to write to.
311   311  
312   @param addr The address to write. 312   @param addr The address to write.
313   */ 313   */
314   friend BOOST_COROSIO_DECL std::ostream& 314   friend BOOST_COROSIO_DECL std::ostream&
315   operator<<(std::ostream& os, ipv6_address const& addr); 315   operator<<(std::ostream& os, ipv6_address const& addr);
316   316  
317   private: 317   private:
318   std::size_t print_impl(char* dest) const noexcept; 318   std::size_t print_impl(char* dest) const noexcept;
319   }; 319   };
320   320  
321   /** Create an IPv6 address from a string. 321   /** Create an IPv6 address from a string.
322   322  
323   This function attempts to parse the string 323   This function attempts to parse the string
324   as an IPv6 address and returns an error code 324   as an IPv6 address and returns an error code
325   if the string does not contain a valid IPv6 address. 325   if the string does not contain a valid IPv6 address.
326   326  
327   @par Exception Safety 327   @par Exception Safety
328   Throws nothing. 328   Throws nothing.
329   329  
330   @param s The string to parse. 330   @param s The string to parse.
331   @return The error code, empty on success, and the parsed 331   @return The error code, empty on success, and the parsed
332   address — default-constructed on failure. 332   address — default-constructed on failure.
333   */ 333   */
334   [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<ipv6_address> 334   [[nodiscard]] BOOST_COROSIO_DECL capy::io_result<ipv6_address>
335   make_ipv6_address(std::string_view s) noexcept; 335   make_ipv6_address(std::string_view s) noexcept;
336   336  
337   } // namespace boost::corosio 337   } // namespace boost::corosio
338   338  
339   #endif 339   #endif