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