Line data Source code
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 : @return `*this`
113 : */
114 : ipv6_address&
115 : operator=(
116 : ipv6_address const&) = default;
117 :
118 : /** Construct from an array of bytes.
119 :
120 : This function constructs an address
121 : from the array in `bytes`, which is
122 : interpreted in big-endian.
123 :
124 : @param bytes The value to construct from.
125 : */
126 : BOOST_URL_DECL
127 : ipv6_address(
128 : bytes_type const& bytes) noexcept;
129 :
130 : /** Construct from an IPv4 address.
131 :
132 : This function constructs an IPv6 address
133 : from the IPv4 address `addr`. The resulting
134 : address is an IPv4-Mapped IPv6 Address.
135 :
136 : @param addr The address to construct from.
137 :
138 : @par Specification
139 : @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2"
140 : >2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
141 : */
142 : BOOST_URL_DECL
143 : ipv6_address(
144 : ipv4_address const& addr) noexcept;
145 :
146 : /** Construct from a string.
147 :
148 : This function constructs an address from
149 : the string `s`, which must contain a valid
150 : IPv6 address string or else an exception
151 : is thrown.
152 :
153 : @note For a non-throwing parse function,
154 : use @ref parse_ipv6_address.
155 :
156 : @par Exception Safety
157 : Exceptions thrown on invalid input.
158 :
159 : @throw system_error
160 : The input failed to parse correctly.
161 :
162 : @param s The string to parse.
163 :
164 : @par Specification
165 : @li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.2"
166 : >3.2.2. Host (rfc3986)</a>
167 :
168 : @see
169 : @ref parse_ipv6_address.
170 : */
171 : BOOST_URL_DECL
172 : ipv6_address(
173 : core::string_view s);
174 :
175 : /** Return the address as bytes, in network byte order
176 :
177 : @return The address as an array of bytes.
178 : */
179 : bytes_type
180 120 : to_bytes() const noexcept
181 : {
182 120 : return addr_;
183 : }
184 :
185 : /** Return the address as a string.
186 :
187 : The returned string does not
188 : contain surrounding square brackets.
189 :
190 : When called with no arguments, the
191 : return type is `std::string`.
192 : Otherwise, the return type and style
193 : of output is determined by which string
194 : token is passed.
195 :
196 : @par Example
197 : @code
198 : ipv6_address::bytes_type b = {{
199 : 0, 1, 0, 2, 0, 3, 0, 4,
200 : 0, 5, 0, 6, 0, 7, 0, 8 }};
201 : ipv6_address a(b);
202 : assert(a.to_string() == "1:2:3:4:5:6:7:8");
203 : assert( ipv4_address(0x01020304).to_string() == "1.2.3.4" );
204 : @endcode
205 :
206 : @par Complexity
207 : Constant.
208 :
209 : @par Exception Safety
210 : Strong guarantee.
211 : Calls to allocate may throw.
212 : String tokens may throw exceptions.
213 :
214 : @return The return type of the string token.
215 : If the token parameter is omitted, then
216 : a new `std::string` is returned.
217 : Otherwise, the function return type
218 : is the result type of the token.
219 :
220 : @param token An optional string token.
221 :
222 : @par Specification
223 : @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.2">
224 : 2.2. Text Representation of Addresses (rfc4291)</a>
225 : */
226 : template<BOOST_URL_STRTOK_TPARAM>
227 : BOOST_URL_STRTOK_RETURN
228 38 : to_string(
229 : BOOST_URL_STRTOK_ARG(token)) const
230 : {
231 38 : to_string_impl(token);
232 38 : return token.result();
233 : }
234 :
235 : /** Write a dotted decimal string representing the address to a buffer
236 :
237 : The resulting buffer is not null-terminated.
238 :
239 : @throw std::length_error `dest_size < ipv6_address::max_str_len`
240 :
241 : @return The formatted string
242 :
243 : @param dest The buffer in which to write,
244 : which must have at least `dest_size` space.
245 :
246 : @param dest_size The size of the output buffer.
247 : */
248 : BOOST_URL_DECL
249 : core::string_view
250 : to_buffer(
251 : char* dest,
252 : std::size_t dest_size) const;
253 :
254 : /** Return true if the address is unspecified
255 :
256 : The address 0:0:0:0:0:0:0:0 is called the
257 : unspecified address. It indicates the
258 : absence of an address.
259 :
260 : @return `true` if the address is unspecified
261 :
262 : @par Specification
263 : @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.2">
264 : 2.5.2. The Unspecified Address (rfc4291)</a>
265 : */
266 : BOOST_URL_DECL
267 : bool
268 : is_unspecified() const noexcept;
269 :
270 : /** Return true if the address is a loopback address
271 :
272 : The unicast address 0:0:0:0:0:0:0:1 is called
273 : the loopback address. It may be used by a node
274 : to send an IPv6 packet to itself.
275 :
276 : @return `true` if the address is a loopback address
277 :
278 : @par Specification
279 : @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
280 : 2.5.3. The Loopback Address (rfc4291)</a>
281 : */
282 : BOOST_URL_DECL
283 : bool
284 : is_loopback() const noexcept;
285 :
286 : /** Return true if the address is a mapped IPv4 address
287 :
288 : This address type is used to represent the
289 : addresses of IPv4 nodes as IPv6 addresses.
290 :
291 : @return `true` if the address is a mapped IPv4 address
292 :
293 : @par Specification
294 : @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2">
295 : 2.5.5.2. IPv4-Mapped IPv6 Address (rfc4291)</a>
296 : */
297 : BOOST_URL_DECL
298 : bool
299 : is_v4_mapped() const noexcept;
300 :
301 : /** Return true if two addresses are equal
302 :
303 : @param a1 The first address to compare.
304 : @param a2 The second address to compare.
305 : @return `true` if the addresses are equal
306 : */
307 : friend
308 : bool
309 81 : operator==(
310 : ipv6_address const& a1,
311 : ipv6_address const& a2) noexcept
312 : {
313 81 : return a1.addr_ == a2.addr_;
314 : }
315 :
316 : /** Return true if two addresses are not equal
317 :
318 : @param a1 The first address to compare.
319 : @param a2 The second address to compare.
320 : @return `true` if the addresses are not equal
321 : */
322 : friend
323 : bool
324 4 : operator!=(
325 : ipv6_address const& a1,
326 : ipv6_address const& a2) noexcept
327 : {
328 4 : return !( a1 == a2 );
329 : }
330 :
331 : /** Return an address object that represents the loopback address
332 :
333 : The unicast address 0:0:0:0:0:0:0:1 is called
334 : the loopback address. It may be used by a node
335 : to send an IPv6 packet to itself.
336 :
337 : @par Specification
338 : @li <a href="https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.3">
339 : 2.5.3. The Loopback Address (rfc4291)</a>
340 :
341 : @return The loopback address.
342 : */
343 : BOOST_URL_DECL
344 : static
345 : ipv6_address
346 : loopback() noexcept;
347 :
348 : /** Format the address to an output stream
349 :
350 : This hidden friend function writes the
351 : address to an output stream using
352 : standard notation.
353 :
354 : @return The output stream, for chaining.
355 :
356 : @param os The output stream to write to.
357 :
358 : @param addr The address to write.
359 : */
360 : friend
361 : std::ostream&
362 1 : operator<<(
363 : std::ostream& os,
364 : ipv6_address const& addr)
365 : {
366 : char buf[ipv6_address::max_str_len];
367 1 : auto const s = addr.to_buffer(
368 : buf, sizeof(buf));
369 1 : os << s;
370 1 : return os;
371 : }
372 :
373 :
374 : private:
375 : BOOST_URL_DECL
376 : std::size_t
377 : print_impl(
378 : char* dest) const noexcept;
379 :
380 : BOOST_URL_DECL
381 : void
382 : to_string_impl(
383 : string_token::arg& t) const;
384 :
385 : bytes_type addr_{{}};
386 : };
387 :
388 : /** Format the address to an output stream
389 :
390 : This function writes the address to an
391 : output stream using standard notation.
392 :
393 : @return The output stream, for chaining.
394 :
395 : @param os The output stream to write to.
396 :
397 : @param addr The address to write.
398 : */
399 : std::ostream&
400 : operator<<(
401 : std::ostream& os,
402 : ipv6_address const& addr);
403 :
404 : //------------------------------------------------
405 :
406 : /** Parse a string containing an IPv6 address.
407 :
408 : This function attempts to parse the string
409 : as an IPv6 address and returns a result
410 : containing the address upon success, or
411 : an error code if the string does not contain
412 : a valid IPv6 address.
413 :
414 : @par Exception Safety
415 : Throws nothing.
416 :
417 : @return A result containing the address.
418 :
419 : @param s The string to parse.
420 : */
421 : BOOST_URL_DECL
422 : system::result<ipv6_address>
423 : parse_ipv6_address(
424 : core::string_view s) noexcept;
425 :
426 : } // urls
427 : } // boost
428 :
429 : #endif
|