1 | // |
2 | // ip/impl/address_v6.ipp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
6 | // |
7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
9 | // |
10 | |
11 | #ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP |
12 | #define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP |
13 | |
14 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
15 | # pragma once |
16 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
17 | |
18 | #include <boost/asio/detail/config.hpp> |
19 | #include <cstring> |
20 | #include <stdexcept> |
21 | #include <typeinfo> |
22 | #include <boost/asio/detail/socket_ops.hpp> |
23 | #include <boost/asio/detail/throw_error.hpp> |
24 | #include <boost/asio/detail/throw_exception.hpp> |
25 | #include <boost/asio/error.hpp> |
26 | #include <boost/asio/ip/address_v6.hpp> |
27 | #include <boost/asio/ip/bad_address_cast.hpp> |
28 | |
29 | #include <boost/asio/detail/push_options.hpp> |
30 | |
31 | namespace boost { |
32 | namespace asio { |
33 | namespace ip { |
34 | |
35 | address_v6::address_v6() noexcept |
36 | : addr_(), |
37 | scope_id_(0) |
38 | { |
39 | } |
40 | |
41 | address_v6::address_v6(const address_v6::bytes_type& bytes, |
42 | scope_id_type scope) |
43 | : scope_id_(scope) |
44 | { |
45 | #if UCHAR_MAX > 0xFF |
46 | for (std::size_t i = 0; i < bytes.size(); ++i) |
47 | { |
48 | if (bytes[i] > 0xFF) |
49 | { |
50 | std::out_of_range ex("address_v6 from bytes_type" ); |
51 | boost::asio::detail::throw_exception(ex); |
52 | } |
53 | } |
54 | #endif // UCHAR_MAX > 0xFF |
55 | |
56 | using namespace std; // For memcpy. |
57 | memcpy(dest: addr_.s6_addr, src: bytes.data(), n: 16); |
58 | } |
59 | |
60 | address_v6::address_v6(const address_v6& other) noexcept |
61 | : addr_(other.addr_), |
62 | scope_id_(other.scope_id_) |
63 | { |
64 | } |
65 | |
66 | address_v6::address_v6(address_v6&& other) noexcept |
67 | : addr_(other.addr_), |
68 | scope_id_(other.scope_id_) |
69 | { |
70 | } |
71 | |
72 | address_v6& address_v6::operator=(const address_v6& other) noexcept |
73 | { |
74 | addr_ = other.addr_; |
75 | scope_id_ = other.scope_id_; |
76 | return *this; |
77 | } |
78 | |
79 | address_v6& address_v6::operator=(address_v6&& other) noexcept |
80 | { |
81 | addr_ = other.addr_; |
82 | scope_id_ = other.scope_id_; |
83 | return *this; |
84 | } |
85 | |
86 | address_v6::bytes_type address_v6::to_bytes() const noexcept |
87 | { |
88 | using namespace std; // For memcpy. |
89 | bytes_type bytes; |
90 | memcpy(dest: bytes.data(), src: addr_.s6_addr, n: 16); |
91 | return bytes; |
92 | } |
93 | |
94 | std::string address_v6::to_string() const |
95 | { |
96 | boost::system::error_code ec; |
97 | char addr_str[boost::asio::detail::max_addr_v6_str_len]; |
98 | const char* addr = |
99 | boost::asio::detail::socket_ops::inet_ntop( |
100 | BOOST_ASIO_OS_DEF(AF_INET6), src: &addr_, dest: addr_str, |
101 | length: boost::asio::detail::max_addr_v6_str_len, scope_id: scope_id_, ec); |
102 | if (addr == 0) |
103 | boost::asio::detail::throw_error(err: ec); |
104 | return addr; |
105 | } |
106 | |
107 | #if !defined(BOOST_ASIO_NO_DEPRECATED) |
108 | std::string address_v6::to_string(boost::system::error_code& ec) const |
109 | { |
110 | char addr_str[boost::asio::detail::max_addr_v6_str_len]; |
111 | const char* addr = |
112 | boost::asio::detail::socket_ops::inet_ntop( |
113 | BOOST_ASIO_OS_DEF(AF_INET6), src: &addr_, dest: addr_str, |
114 | length: boost::asio::detail::max_addr_v6_str_len, scope_id: scope_id_, ec); |
115 | if (addr == 0) |
116 | return std::string(); |
117 | return addr; |
118 | } |
119 | |
120 | address_v4 address_v6::to_v4() const |
121 | { |
122 | if (!is_v4_mapped() && !is_v4_compatible()) |
123 | { |
124 | bad_address_cast ex; |
125 | boost::asio::detail::throw_exception(e: ex); |
126 | } |
127 | |
128 | address_v4::bytes_type v4_bytes = { ._M_elems: { addr_.s6_addr[12], |
129 | addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; |
130 | return address_v4(v4_bytes); |
131 | } |
132 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
133 | |
134 | bool address_v6::is_loopback() const noexcept |
135 | { |
136 | return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) |
137 | && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) |
138 | && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) |
139 | && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) |
140 | && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) |
141 | && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) |
142 | && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) |
143 | && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); |
144 | } |
145 | |
146 | bool address_v6::is_unspecified() const noexcept |
147 | { |
148 | return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) |
149 | && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) |
150 | && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) |
151 | && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) |
152 | && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) |
153 | && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) |
154 | && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) |
155 | && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); |
156 | } |
157 | |
158 | bool address_v6::is_link_local() const noexcept |
159 | { |
160 | return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0x80)); |
161 | } |
162 | |
163 | bool address_v6::is_site_local() const noexcept |
164 | { |
165 | return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0xc0)); |
166 | } |
167 | |
168 | bool address_v6::is_v4_mapped() const noexcept |
169 | { |
170 | return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) |
171 | && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) |
172 | && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) |
173 | && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) |
174 | && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) |
175 | && (addr_.s6_addr[10] == 0xff) && (addr_.s6_addr[11] == 0xff)); |
176 | } |
177 | |
178 | #if !defined(BOOST_ASIO_NO_DEPRECATED) |
179 | bool address_v6::is_v4_compatible() const |
180 | { |
181 | return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) |
182 | && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) |
183 | && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) |
184 | && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) |
185 | && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) |
186 | && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) |
187 | && !((addr_.s6_addr[12] == 0) |
188 | && (addr_.s6_addr[13] == 0) |
189 | && (addr_.s6_addr[14] == 0) |
190 | && ((addr_.s6_addr[15] == 0) || (addr_.s6_addr[15] == 1)))); |
191 | } |
192 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
193 | |
194 | bool address_v6::is_multicast() const noexcept |
195 | { |
196 | return (addr_.s6_addr[0] == 0xff); |
197 | } |
198 | |
199 | bool address_v6::is_multicast_global() const noexcept |
200 | { |
201 | return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x0e)); |
202 | } |
203 | |
204 | bool address_v6::is_multicast_link_local() const noexcept |
205 | { |
206 | return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x02)); |
207 | } |
208 | |
209 | bool address_v6::is_multicast_node_local() const noexcept |
210 | { |
211 | return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x01)); |
212 | } |
213 | |
214 | bool address_v6::is_multicast_org_local() const noexcept |
215 | { |
216 | return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x08)); |
217 | } |
218 | |
219 | bool address_v6::is_multicast_site_local() const noexcept |
220 | { |
221 | return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x05)); |
222 | } |
223 | |
224 | bool operator==(const address_v6& a1, const address_v6& a2) noexcept |
225 | { |
226 | using namespace std; // For memcmp. |
227 | return memcmp(s1: &a1.addr_, s2: &a2.addr_, |
228 | n: sizeof(boost::asio::detail::in6_addr_type)) == 0 |
229 | && a1.scope_id_ == a2.scope_id_; |
230 | } |
231 | |
232 | bool operator<(const address_v6& a1, const address_v6& a2) noexcept |
233 | { |
234 | using namespace std; // For memcmp. |
235 | int memcmp_result = memcmp(s1: &a1.addr_, s2: &a2.addr_, |
236 | n: sizeof(boost::asio::detail::in6_addr_type)); |
237 | if (memcmp_result < 0) |
238 | return true; |
239 | if (memcmp_result > 0) |
240 | return false; |
241 | return a1.scope_id_ < a2.scope_id_; |
242 | } |
243 | |
244 | address_v6 address_v6::loopback() noexcept |
245 | { |
246 | address_v6 tmp; |
247 | tmp.addr_.s6_addr[15] = 1; |
248 | return tmp; |
249 | } |
250 | |
251 | #if !defined(BOOST_ASIO_NO_DEPRECATED) |
252 | address_v6 address_v6::v4_mapped(const address_v4& addr) |
253 | { |
254 | address_v4::bytes_type v4_bytes = addr.to_bytes(); |
255 | bytes_type v6_bytes = { ._M_elems: { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, |
256 | v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; |
257 | return address_v6(v6_bytes); |
258 | } |
259 | |
260 | address_v6 address_v6::v4_compatible(const address_v4& addr) |
261 | { |
262 | address_v4::bytes_type v4_bytes = addr.to_bytes(); |
263 | bytes_type v6_bytes = { ._M_elems: { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
264 | v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; |
265 | return address_v6(v6_bytes); |
266 | } |
267 | #endif // !defined(BOOST_ASIO_NO_DEPRECATED) |
268 | |
269 | address_v6 make_address_v6(const char* str) |
270 | { |
271 | boost::system::error_code ec; |
272 | address_v6 addr = make_address_v6(str, ec); |
273 | boost::asio::detail::throw_error(err: ec); |
274 | return addr; |
275 | } |
276 | |
277 | address_v6 make_address_v6(const char* str, |
278 | boost::system::error_code& ec) noexcept |
279 | { |
280 | address_v6::bytes_type bytes; |
281 | unsigned long scope_id = 0; |
282 | if (boost::asio::detail::socket_ops::inet_pton( |
283 | BOOST_ASIO_OS_DEF(AF_INET6), src: str, dest: &bytes[0], scope_id: &scope_id, ec) <= 0) |
284 | return address_v6(); |
285 | return address_v6(bytes, scope_id); |
286 | } |
287 | |
288 | address_v6 make_address_v6(const std::string& str) |
289 | { |
290 | return make_address_v6(str: str.c_str()); |
291 | } |
292 | |
293 | address_v6 make_address_v6(const std::string& str, |
294 | boost::system::error_code& ec) noexcept |
295 | { |
296 | return make_address_v6(str: str.c_str(), ec); |
297 | } |
298 | |
299 | #if defined(BOOST_ASIO_HAS_STRING_VIEW) |
300 | |
301 | address_v6 make_address_v6(string_view str) |
302 | { |
303 | return make_address_v6(str: static_cast<std::string>(str)); |
304 | } |
305 | |
306 | address_v6 make_address_v6(string_view str, |
307 | boost::system::error_code& ec) noexcept |
308 | { |
309 | return make_address_v6(str: static_cast<std::string>(str), ec); |
310 | } |
311 | |
312 | #endif // defined(BOOST_ASIO_HAS_STRING_VIEW) |
313 | |
314 | address_v4 make_address_v4( |
315 | v4_mapped_t, const address_v6& v6_addr) |
316 | { |
317 | if (!v6_addr.is_v4_mapped()) |
318 | { |
319 | bad_address_cast ex; |
320 | boost::asio::detail::throw_exception(e: ex); |
321 | } |
322 | |
323 | address_v6::bytes_type v6_bytes = v6_addr.to_bytes(); |
324 | address_v4::bytes_type v4_bytes = { ._M_elems: { v6_bytes[12], |
325 | v6_bytes[13], v6_bytes[14], v6_bytes[15] } }; |
326 | return address_v4(v4_bytes); |
327 | } |
328 | |
329 | address_v6 make_address_v6( |
330 | v4_mapped_t, const address_v4& v4_addr) |
331 | { |
332 | address_v4::bytes_type v4_bytes = v4_addr.to_bytes(); |
333 | address_v6::bytes_type v6_bytes = { ._M_elems: { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
334 | 0xFF, 0xFF, v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; |
335 | return address_v6(v6_bytes); |
336 | } |
337 | |
338 | } // namespace ip |
339 | } // namespace asio |
340 | } // namespace boost |
341 | |
342 | #include <boost/asio/detail/pop_options.hpp> |
343 | |
344 | #endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP |
345 | |