Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) | ||
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/boostorg/url | ||
9 | // | ||
10 | |||
11 | #ifndef BOOST_URL_IPV6_ADDRESS_HPP | ||
12 | #define BOOST_URL_IPV6_ADDRESS_HPP | ||
13 | |||
14 | #include <boost/url/detail/config.hpp> | ||
15 | #include <boost/url/error.hpp> | ||
16 | #include <boost/url/error_types.hpp> | ||
17 | #include <boost/core/detail/string_view.hpp> | ||
18 | #include <boost/url/grammar/string_token.hpp> | ||
19 | #include <array> | ||
20 | #include <cstdint> | ||
21 | #include <iosfwd> | ||
22 | |||
23 | namespace boost { | ||
24 | namespace urls { | ||
25 | |||
26 | #ifndef BOOST_URL_DOCS | ||
27 | class ipv4_address; | ||
28 | #endif | ||
29 | |||
30 | /** An IP version 6 style address. | ||
31 | |||
32 | Objects of this type are used to construct, | ||
33 | parse, and manipulate IP version 6 addresses. | ||
34 | |||
35 | @par BNF | ||
36 | @code | ||
37 | IPv6address = 6( h16 ":" ) ls32 | ||
38 | / "::" 5( h16 ":" ) ls32 | ||
39 | / [ h16 ] "::" 4( h16 ":" ) ls32 | ||
40 | / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 | ||
41 | / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 | ||
42 | / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 | ||
43 | / [ *4( h16 ":" ) h16 ] "::" ls32 | ||
44 | / [ *5( h16 ":" ) h16 ] "::" h16 | ||
45 | / [ *6( h16 ":" ) h16 ] "::" | ||
46 | |||
47 | ls32 = ( h16 ":" h16 ) / IPv4address | ||
48 | ; least-significant 32 bits of address | ||
49 | |||
50 | h16 = 1*4HEXDIG | ||
51 | ; 16 bits of address represented in hexadecimal | ||
52 | @endcode | ||
53 | |||
54 | @par Specification | ||
55 | @li <a href="https://datatracker.ietf.org/doc/html/rfc4291" | ||
56 | >IP Version 6 Addressing Architecture (rfc4291)</a> | ||
57 | @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2" | ||
58 | >3.2.2. Host (rfc3986)</a> | ||
59 | |||
60 | @see | ||
61 | @ref ipv4_address, | ||
62 | @ref parse_ipv6_address. | ||
63 | */ | ||
64 | class ipv6_address | ||
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 | |||
74 | @see | ||
75 | @ref to_buffer. | ||
76 | */ | ||
77 | // ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | ||
78 | // ::ffff:255.255.255.255 | ||
79 | // 12345678901234567890123456789012345678901234567890 | ||
80 | // 1 2 3 4 | ||
81 | static | ||
82 | constexpr | ||
83 | std::size_t max_str_len = 49; | ||
84 | |||
85 | /** The type used to represent an address as an array of bytes. | ||
86 | |||
87 | Octets are stored in network byte order. | ||
88 | */ | ||
89 | using bytes_type = std::array< | ||
90 | unsigned char, 16>; | ||
91 | |||
92 | /** Constructor. | ||
93 | |||
94 | Default constructed objects represent | ||
95 | the unspecified address. | ||
96 | |||
97 | @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2" | ||
98 | >2.5.2. The Unspecified Address</a> | ||
99 | |||
100 | @see | ||
101 | @ref is_unspecified | ||
102 | */ | ||
103 | 96 | ipv6_address() = default; | |
104 | |||
105 | /** Constructor. | ||
106 | */ | ||
107 | ipv6_address( | ||
108 | ipv6_address const&) = default; | ||
109 | |||
110 | /** Copy Assignment | ||
111 | */ | ||
112 | ipv6_address& | ||
113 | operator=( | ||
114 | ipv6_address const&) = default; | ||
115 | |||
116 | /** Construct from an array of bytes. | ||
117 | |||
118 | This function constructs an address | ||
119 | from the array in `bytes`, which is | ||
120 | interpreted in big-endian. | ||
121 | |||
122 | @param bytes The value to construct from. | ||
123 | */ | ||
124 | BOOST_URL_DECL | ||
125 | ipv6_address( | ||
126 | bytes_type const& bytes) noexcept; | ||
127 | |||
128 | /** Construct from an IPv4 address. | ||
129 | |||
130 | This function constructs an IPv6 address | ||
131 | from the IPv4 address `addr`. The resulting | ||
132 | address is an IPv4-Mapped IPv6 Address. | ||
133 | |||
134 | @param addr The address to construct from. | ||
135 | |||
136 | @par Specification | ||
137 | @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2" | ||
138 | >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a> | ||
139 | */ | ||
140 | BOOST_URL_DECL | ||
141 | ipv6_address( | ||
142 | ipv4_address const& addr) noexcept; | ||
143 | |||
144 | /** Construct from a string. | ||
145 | |||
146 | This function constructs an address from | ||
147 | the string `s`, which must contain a valid | ||
148 | IPv6 address string or else an exception | ||
149 | is thrown. | ||
150 | |||
151 | @note For a non-throwing parse function, | ||
152 | use @ref parse_ipv6_address. | ||
153 | |||
154 | @par Exception Safety | ||
155 | Exceptions thrown on invalid input. | ||
156 | |||
157 | @throw system_error | ||
158 | The input failed to parse correctly. | ||
159 | |||
160 | @param s The string to parse. | ||
161 | |||
162 | @par Specification | ||
163 | @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2" | ||
164 | >3.2.2. Host (rfc3986)</a> | ||
165 | |||
166 | @see | ||
167 | @ref parse_ipv6_address. | ||
168 | */ | ||
169 | BOOST_URL_DECL | ||
170 | ipv6_address( | ||
171 | core::string_view s); | ||
172 | |||
173 | /** Return the address as bytes, in network byte order | ||
174 | */ | ||
175 | bytes_type | ||
176 | 120 | to_bytes() const noexcept | |
177 | { | ||
178 | 120 | return addr_; | |
179 | } | ||
180 | |||
181 | /** Return the address as a string. | ||
182 | |||
183 | The returned string does not | ||
184 | contain surrounding square brackets. | ||
185 | |||
186 | When called with no arguments, the | ||
187 | return type is `std::string`. | ||
188 | Otherwise, the return type and style | ||
189 | of output is determined by which string | ||
190 | token is passed. | ||
191 | |||
192 | @par Example | ||
193 | @code | ||
194 | ipv6_address::bytes_type b = {{ | ||
195 | 0, 1, 0, 2, 0, 3, 0, 4, | ||
196 | 0, 5, 0, 6, 0, 7, 0, 8 }}; | ||
197 | ipv6_address a(b); | ||
198 | assert(a.to_string() == "1:2:3:4:5:6:7:8"); | ||
199 | assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" ); | ||
200 | @endcode | ||
201 | |||
202 | @par Complexity | ||
203 | Constant. | ||
204 | |||
205 | @par Exception Safety | ||
206 | Strong guarantee. | ||
207 | Calls to allocate may throw. | ||
208 | String tokens may throw exceptions. | ||
209 | |||
210 | @return The return type of the string token. | ||
211 | If the token parameter is omitted, then | ||
212 | a new `std::string` is returned. | ||
213 | Otherwise, the function return type | ||
214 | is the result type of the token. | ||
215 | |||
216 | @param token An optional string token. | ||
217 | |||
218 | @par Specification | ||
219 | @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2"> | ||
220 | 2.2. Text Representation of Addresses (rfc4291)</a> | ||
221 | */ | ||
222 | template<BOOST_URL_STRTOK_TPARAM> | ||
223 | BOOST_URL_STRTOK_RETURN | ||
224 | 38 | to_string( | |
225 | BOOST_URL_STRTOK_ARG(token)) const | ||
226 | { | ||
227 | 38 | to_string_impl(token); | |
228 | 38 | return token.result(); | |
229 | } | ||
230 | |||
231 | /** Write a dotted decimal string representing the address to a buffer | ||
232 | |||
233 | The resulting buffer is not null-terminated. | ||
234 | |||
235 | @throw std::length_error `dest_size < ipv6_address::max_str_len` | ||
236 | |||
237 | @return The formatted string | ||
238 | |||
239 | @param dest The buffer in which to write, | ||
240 | which must have at least `dest_size` space. | ||
241 | |||
242 | @param dest_size The size of the output buffer. | ||
243 | */ | ||
244 | BOOST_URL_DECL | ||
245 | core::string_view | ||
246 | to_buffer( | ||
247 | char* dest, | ||
248 | std::size_t dest_size) const; | ||
249 | |||
250 | /** Return true if the address is unspecified | ||
251 | |||
252 | The address 0:0:0:0:0:0:0:0 is called the | ||
253 | unspecified address. It indicates the | ||
254 | absence of an address. | ||
255 | |||
256 | @par Specification | ||
257 | @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2"> | ||
258 | 2.5.2. The Unspecified Address (rfc4291)</a> | ||
259 | */ | ||
260 | BOOST_URL_DECL | ||
261 | bool | ||
262 | is_unspecified() const noexcept; | ||
263 | |||
264 | /** Return true if the address is a loopback address | ||
265 | |||
266 | The unicast address 0:0:0:0:0:0:0:1 is called | ||
267 | the loopback address. It may be used by a node | ||
268 | to send an IPv6 packet to itself. | ||
269 | |||
270 | @par Specification | ||
271 | @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3"> | ||
272 | 2.5.3. The Loopback Address (rfc4291)</a> | ||
273 | */ | ||
274 | BOOST_URL_DECL | ||
275 | bool | ||
276 | is_loopback() const noexcept; | ||
277 | |||
278 | /** Return true if the address is a mapped IPv4 address | ||
279 | |||
280 | This address type is used to represent the | ||
281 | addresses of IPv4 nodes as IPv6 addresses. | ||
282 | |||
283 | @par Specification | ||
284 | @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"> | ||
285 | 2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a> | ||
286 | */ | ||
287 | BOOST_URL_DECL | ||
288 | bool | ||
289 | is_v4_mapped() const noexcept; | ||
290 | |||
291 | /** Return true if two addresses are equal | ||
292 | */ | ||
293 | friend | ||
294 | bool | ||
295 | 81 | operator==( | |
296 | ipv6_address const& a1, | ||
297 | ipv6_address const& a2) noexcept | ||
298 | { | ||
299 | 81 | return a1.addr_ == a2.addr_; | |
300 | } | ||
301 | |||
302 | /** Return true if two addresses are not equal | ||
303 | */ | ||
304 | friend | ||
305 | bool | ||
306 | 4 | operator!=( | |
307 | ipv6_address const& a1, | ||
308 | ipv6_address const& a2) noexcept | ||
309 | { | ||
310 | 4 | return !( a1 == a2 ); | |
311 | } | ||
312 | |||
313 | /** Return an address object that represents the loopback address | ||
314 | |||
315 | The unicast address 0:0:0:0:0:0:0:1 is called | ||
316 | the loopback address. It may be used by a node | ||
317 | to send an IPv6 packet to itself. | ||
318 | |||
319 | @par Specification | ||
320 | @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3"> | ||
321 | 2.5.3. The Loopback Address (rfc4291)</a> | ||
322 | */ | ||
323 | BOOST_URL_DECL | ||
324 | static | ||
325 | ipv6_address | ||
326 | loopback() noexcept; | ||
327 | |||
328 | // hidden friend | ||
329 | friend | ||
330 | std::ostream& | ||
331 | 1 | operator<<( | |
332 | std::ostream& os, | ||
333 | ipv6_address const& addr) | ||
334 | { | ||
335 | char buf[ipv6_address::max_str_len]; | ||
336 | auto const s = addr.to_buffer( | ||
337 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | buf, sizeof(buf)); |
338 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | os << s; |
339 | 1 | return os; | |
340 | } | ||
341 | |||
342 | |||
343 | private: | ||
344 | BOOST_URL_DECL | ||
345 | std::size_t | ||
346 | print_impl( | ||
347 | char* dest) const noexcept; | ||
348 | |||
349 | BOOST_URL_DECL | ||
350 | void | ||
351 | to_string_impl( | ||
352 | string_token::arg& t) const; | ||
353 | |||
354 | bytes_type addr_{{}}; | ||
355 | }; | ||
356 | |||
357 | /** Format the address to an output stream | ||
358 | |||
359 | This function writes the address to an | ||
360 | output stream using standard notation. | ||
361 | |||
362 | @return The output stream, for chaining. | ||
363 | |||
364 | @param os The output stream to write to. | ||
365 | |||
366 | @param addr The address to write. | ||
367 | */ | ||
368 | std::ostream& | ||
369 | operator<<( | ||
370 | std::ostream& os, | ||
371 | ipv6_address const& addr); | ||
372 | |||
373 | //------------------------------------------------ | ||
374 | |||
375 | /** Parse a string containing an IPv6 address. | ||
376 | |||
377 | This function attempts to parse the string | ||
378 | as an IPv6 address and returns a result | ||
379 | containing the address upon success, or | ||
380 | an error code if the string does not contain | ||
381 | a valid IPv6 address. | ||
382 | |||
383 | @par Exception Safety | ||
384 | Throws nothing. | ||
385 | |||
386 | @return A result containing the address. | ||
387 | |||
388 | @param s The string to parse. | ||
389 | */ | ||
390 | BOOST_URL_DECL | ||
391 | system::result<ipv6_address> | ||
392 | parse_ipv6_address( | ||
393 | core::string_view s) noexcept; | ||
394 | |||
395 | } // urls | ||
396 | } // boost | ||
397 | |||
398 | #endif | ||
399 |