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