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