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