|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // SPDX-FileCopyrightText: Copyright OpenBMC Authors | 
|  | #pragma once | 
|  | #include "dbus_utility.hpp" | 
|  | #include "logging.hpp" | 
|  |  | 
|  | #include <sys/socket.h> | 
|  |  | 
|  | #include <boost/asio/io_context.hpp> | 
|  | #include <boost/asio/ip/address.hpp> | 
|  | #include <boost/asio/ip/address_v4.hpp> | 
|  | #include <boost/asio/ip/address_v6.hpp> | 
|  | #include <boost/asio/ip/tcp.hpp> | 
|  | #include <boost/system/errc.hpp> | 
|  |  | 
|  | #include <charconv> | 
|  | #include <cstdint> | 
|  | #include <string> | 
|  | #include <string_view> | 
|  | #include <system_error> | 
|  | #include <tuple> | 
|  | #include <vector> | 
|  |  | 
|  | namespace async_resolve | 
|  | { | 
|  |  | 
|  | inline bool endpointFromResolveTuple(const std::vector<uint8_t>& ipAddress, | 
|  | boost::asio::ip::tcp::endpoint& endpoint) | 
|  | { | 
|  | if (ipAddress.size() == 4) // ipv4 address | 
|  | { | 
|  | BMCWEB_LOG_DEBUG("ipv4 address"); | 
|  | boost::asio::ip::address_v4 ipv4Addr( | 
|  | {ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3]}); | 
|  | endpoint.address(ipv4Addr); | 
|  | } | 
|  | else if (ipAddress.size() == 16) // ipv6 address | 
|  | { | 
|  | BMCWEB_LOG_DEBUG("ipv6 address"); | 
|  | boost::asio::ip::address_v6 ipv6Addr( | 
|  | {ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3], | 
|  | ipAddress[4], ipAddress[5], ipAddress[6], ipAddress[7], | 
|  | ipAddress[8], ipAddress[9], ipAddress[10], ipAddress[11], | 
|  | ipAddress[12], ipAddress[13], ipAddress[14], ipAddress[15]}); | 
|  | endpoint.address(ipv6Addr); | 
|  | } | 
|  | else | 
|  | { | 
|  | BMCWEB_LOG_ERROR("Resolve failed to fetch the IP address"); | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | class Resolver | 
|  | { | 
|  | public: | 
|  | // unused io param used to keep interface identical to | 
|  | // boost::asio::tcp:::resolver | 
|  | explicit Resolver(boost::asio::io_context& /*io*/) {} | 
|  |  | 
|  | ~Resolver() = default; | 
|  |  | 
|  | Resolver(const Resolver&) = delete; | 
|  | Resolver(Resolver&&) = delete; | 
|  | Resolver& operator=(const Resolver&) = delete; | 
|  | Resolver& operator=(Resolver&&) = delete; | 
|  |  | 
|  | using results_type = std::vector<boost::asio::ip::tcp::endpoint>; | 
|  |  | 
|  | template <typename ResolveHandler> | 
|  | // This function is kept using snake case so that it is interoperable with | 
|  | // boost::asio::ip::tcp::resolver | 
|  | // NOLINTNEXTLINE(readability-identifier-naming) | 
|  | void async_resolve(std::string_view host, std::string_view port, | 
|  | ResolveHandler&& handler) | 
|  | { | 
|  | BMCWEB_LOG_DEBUG("Trying to resolve: {}:{}", host, port); | 
|  |  | 
|  | uint16_t portNum = 0; | 
|  |  | 
|  | auto it = std::from_chars(&*port.begin(), &*port.end(), portNum); | 
|  | if (it.ec != std::errc()) | 
|  | { | 
|  | BMCWEB_LOG_ERROR("Failed to get the Port"); | 
|  | handler(std::make_error_code(std::errc::invalid_argument), | 
|  | results_type{}); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | uint64_t flag = 0; | 
|  | dbus::utility::async_method_call( | 
|  | [host{std::string(host)}, portNum, | 
|  | handler = std::forward<ResolveHandler>(handler)]( | 
|  | const boost::system::error_code& ec, | 
|  | const std::vector< | 
|  | std::tuple<int32_t, int32_t, std::vector<uint8_t>>>& resp, | 
|  | const std::string& hostName, const uint64_t flagNum) { | 
|  | results_type endpointList; | 
|  | if (ec) | 
|  | { | 
|  | BMCWEB_LOG_ERROR("Resolve failed: {}", ec.message()); | 
|  | handler(ec, endpointList); | 
|  | return; | 
|  | } | 
|  | BMCWEB_LOG_DEBUG("ResolveHostname returned: {}:{}", hostName, | 
|  | flagNum); | 
|  | // Extract the IP address from the response | 
|  | for (const std::tuple<int32_t, int32_t, std::vector<uint8_t>>& | 
|  | resolveList : resp) | 
|  | { | 
|  | boost::asio::ip::tcp::endpoint endpoint; | 
|  | endpoint.port(portNum); | 
|  | if (!endpointFromResolveTuple(std::get<2>(resolveList), | 
|  | endpoint)) | 
|  | { | 
|  | boost::system::error_code ecErr = make_error_code( | 
|  | boost::system::errc::address_not_available); | 
|  | handler(ecErr, endpointList); | 
|  | } | 
|  | BMCWEB_LOG_DEBUG("resolved endpoint is : {}", | 
|  | endpoint.address().to_string()); | 
|  | endpointList.push_back(endpoint); | 
|  | } | 
|  | // All the resolved data is filled in the endpointList | 
|  | handler(ec, endpointList); | 
|  | }, | 
|  | "org.freedesktop.resolve1", "/org/freedesktop/resolve1", | 
|  | "org.freedesktop.resolve1.Manager", "ResolveHostname", 0, host, | 
|  | AF_UNSPEC, flag); | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // namespace async_resolve |