| 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 | |