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