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