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