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