From 040eee1aa49b49df4698d83a05af57c220127fd1 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 13:36:04 +0200 Subject: Adding upstream version 2.2.0. Signed-off-by: Daniel Baumann --- src/lib/asiolink/io_address.cc | 189 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 src/lib/asiolink/io_address.cc (limited to 'src/lib/asiolink/io_address.cc') diff --git a/src/lib/asiolink/io_address.cc b/src/lib/asiolink/io_address.cc new file mode 100644 index 0000000..7f7134d --- /dev/null +++ b/src/lib/asiolink/io_address.cc @@ -0,0 +1,189 @@ +// Copyright (C) 2010-2020 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include +#include +#include + +#include +// moved to container_hash on recent boost versions (backward compatible) +#include + +#include // for some IPC/network system calls +#include +#include +#include + +using namespace boost::asio; +using boost::asio::ip::udp; +using boost::asio::ip::tcp; + +using namespace std; + +namespace isc { +namespace asiolink { + +// XXX: we cannot simply construct the address in the initialization list, +// because we'd like to throw our own exception on failure. +IOAddress::IOAddress(const std::string& address_str) { + boost::system::error_code err; + asio_address_ = ip::address::from_string(address_str, err); + if (err) { + isc_throw(IOError, "Failed to convert string to address '" + << address_str << "': " << err.message()); + } +} + +IOAddress::IOAddress(const boost::asio::ip::address& asio_address) : + asio_address_(asio_address) +{} + +IOAddress::IOAddress(uint32_t v4address): + asio_address_(boost::asio::ip::address_v4(v4address)) { + +} + +string +IOAddress::toText() const { + return (asio_address_.to_string()); +} + +IOAddress +IOAddress::fromBytes(short family, const uint8_t* data) { + if (data == NULL) { + isc_throw(BadValue, "NULL pointer received."); + } else + if ( (family != AF_INET) && (family != AF_INET6) ) { + isc_throw(BadValue, "Invalid family type. Only AF_INET and AF_INET6" + << "are supported"); + } + + BOOST_STATIC_ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN); + char addr_str[INET6_ADDRSTRLEN]; + inet_ntop(family, data, addr_str, INET6_ADDRSTRLEN); + return IOAddress(string(addr_str)); +} + +std::vector +IOAddress::toBytes() const { + if (asio_address_.is_v4()) { + const boost::asio::ip::address_v4::bytes_type bytes4 = + asio_address_.to_v4().to_bytes(); + return (std::vector(bytes4.begin(), bytes4.end())); + } + + // Not V4 address, so must be a V6 address (else we could never construct + // this object). + const boost::asio::ip::address_v6::bytes_type bytes6 = + asio_address_.to_v6().to_bytes(); + return (std::vector(bytes6.begin(), bytes6.end())); +} + +short +IOAddress::getFamily() const { + if (asio_address_.is_v4()) { + return (AF_INET); + } else { + return (AF_INET6); + } +} + +bool +IOAddress::isV6LinkLocal() const { + if (!asio_address_.is_v6()) { + return (false); + } + return (asio_address_.to_v6().is_link_local()); +} + +bool +IOAddress::isV6Multicast() const { + if (!asio_address_.is_v6()) { + return (false); + } + return (asio_address_.to_v6().is_multicast()); +} + +uint32_t +IOAddress::toUint32() const { + if (asio_address_.is_v4()) { + return (asio_address_.to_v4().to_ulong()); + } else { + isc_throw(BadValue, "Can't convert " << toText() + << " address to IPv4."); + } +} + +std::ostream& +operator<<(std::ostream& os, const IOAddress& address) { + os << address.toText(); + return (os); +} + +IOAddress +IOAddress::subtract(const IOAddress& a, const IOAddress& b) { + if (a.getFamily() != b.getFamily()) { + isc_throw(BadValue, "Both addresses have to be the same family"); + } + if (a.isV4()) { + // Subtracting v4 is easy. We have a conversion function to uint32_t. + return (IOAddress(a.toUint32() - b.toUint32())); + } else { + // v6 is more involved. + + // Let's extract the raw data first. + vector a_vec = a.toBytes(); + vector b_vec = b.toBytes(); + + // ... and prepare the result + vector result(V6ADDRESS_LEN,0); + + // Carry is a boolean, but to avoid its frequent casting, let's + // use uint8_t. Also, some would prefer to call it borrow, but I prefer + // carry. Somewhat relevant discussion here: + // http://en.wikipedia.org/wiki/Carry_flag#Carry_flag_vs._Borrow_flag + uint8_t carry = 0; + + // Now perform subtraction with borrow. + for (int i = a_vec.size() - 1; i >= 0; --i) { + result[i] = a_vec[i] - b_vec[i] - carry; + carry = (a_vec[i] < b_vec[i] + carry); + } + + return (fromBytes(AF_INET6, &result[0])); + } +} + +IOAddress +IOAddress::increase(const IOAddress& addr) { + std::vector packed(addr.toBytes()); + + // Start increasing the least significant byte + for (int i = packed.size() - 1; i >= 0; --i) { + // if we haven't overflowed (0xff -> 0x0), than we are done + if (++packed[i] != 0) { + break; + } + } + + return (IOAddress::fromBytes(addr.getFamily(), &packed[0])); +} + +size_t +hash_value(const IOAddress& address) { + if (address.isV4()) { + boost::hash hasher; + return (hasher(address.toUint32())); + } else { + boost::hash > hasher; + return (hasher(address.toBytes())); + } +} + +} // namespace asiolink +} // namespace isc -- cgit v1.2.3