140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
329a82b08SSunitha Harish #pragma once
43ccb3adbSEd Tanous #include "dbus_singleton.hpp"
53ccb3adbSEd Tanous #include "logging.hpp"
63ccb3adbSEd Tanous
7*d7857201SEd Tanous #include <sys/socket.h>
8*d7857201SEd Tanous
9*d7857201SEd Tanous #include <boost/asio/io_context.hpp>
1029a82b08SSunitha Harish #include <boost/asio/ip/address.hpp>
11*d7857201SEd Tanous #include <boost/asio/ip/address_v4.hpp>
12*d7857201SEd Tanous #include <boost/asio/ip/address_v6.hpp>
137e8890c5SCarson Labrado #include <boost/asio/ip/tcp.hpp>
14*d7857201SEd Tanous #include <boost/system/errc.hpp>
1529a82b08SSunitha Harish
1629a82b08SSunitha Harish #include <charconv>
17*d7857201SEd Tanous #include <cstdint>
18*d7857201SEd Tanous #include <string>
19*d7857201SEd Tanous #include <string_view>
20*d7857201SEd Tanous #include <system_error>
21*d7857201SEd Tanous #include <tuple>
22*d7857201SEd Tanous #include <vector>
2329a82b08SSunitha Harish
2429a82b08SSunitha Harish namespace async_resolve
2529a82b08SSunitha Harish {
2629a82b08SSunitha Harish
endpointFromResolveTuple(const std::vector<uint8_t> & ipAddress,boost::asio::ip::tcp::endpoint & endpoint)27e1452beaSEd Tanous inline bool endpointFromResolveTuple(const std::vector<uint8_t>& ipAddress,
28e1452beaSEd Tanous boost::asio::ip::tcp::endpoint& endpoint)
29e1452beaSEd Tanous {
30e1452beaSEd Tanous if (ipAddress.size() == 4) // ipv4 address
31e1452beaSEd Tanous {
3262598e31SEd Tanous BMCWEB_LOG_DEBUG("ipv4 address");
33e1452beaSEd Tanous boost::asio::ip::address_v4 ipv4Addr(
34e1452beaSEd Tanous {ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3]});
35e1452beaSEd Tanous endpoint.address(ipv4Addr);
36e1452beaSEd Tanous }
37e1452beaSEd Tanous else if (ipAddress.size() == 16) // ipv6 address
38e1452beaSEd Tanous {
3962598e31SEd Tanous BMCWEB_LOG_DEBUG("ipv6 address");
40e1452beaSEd Tanous boost::asio::ip::address_v6 ipv6Addr(
41e1452beaSEd Tanous {ipAddress[0], ipAddress[1], ipAddress[2], ipAddress[3],
42e1452beaSEd Tanous ipAddress[4], ipAddress[5], ipAddress[6], ipAddress[7],
43e1452beaSEd Tanous ipAddress[8], ipAddress[9], ipAddress[10], ipAddress[11],
44e1452beaSEd Tanous ipAddress[12], ipAddress[13], ipAddress[14], ipAddress[15]});
45e1452beaSEd Tanous endpoint.address(ipv6Addr);
46e1452beaSEd Tanous }
47e1452beaSEd Tanous else
48e1452beaSEd Tanous {
4962598e31SEd Tanous BMCWEB_LOG_ERROR("Resolve failed to fetch the IP address");
50e1452beaSEd Tanous return false;
51e1452beaSEd Tanous }
52e1452beaSEd Tanous return true;
53e1452beaSEd Tanous }
54e1452beaSEd Tanous
5529a82b08SSunitha Harish class Resolver
5629a82b08SSunitha Harish {
5729a82b08SSunitha Harish public:
58f8ca6d79SEd Tanous // unused io param used to keep interface identical to
59f8ca6d79SEd Tanous // boost::asio::tcp:::resolver
Resolver(boost::asio::io_context &)60f8ca6d79SEd Tanous explicit Resolver(boost::asio::io_context& /*io*/) {}
6129a82b08SSunitha Harish
6229a82b08SSunitha Harish ~Resolver() = default;
6329a82b08SSunitha Harish
64ecd6a3a2SEd Tanous Resolver(const Resolver&) = delete;
65ecd6a3a2SEd Tanous Resolver(Resolver&&) = delete;
66ecd6a3a2SEd Tanous Resolver& operator=(const Resolver&) = delete;
67ecd6a3a2SEd Tanous Resolver& operator=(Resolver&&) = delete;
68ecd6a3a2SEd Tanous
69f8ca6d79SEd Tanous using results_type = std::vector<boost::asio::ip::tcp::endpoint>;
70f8ca6d79SEd Tanous
7129a82b08SSunitha Harish template <typename ResolveHandler>
72f8ca6d79SEd Tanous // This function is kept using snake case so that it is interoperable with
73f8ca6d79SEd Tanous // boost::asio::ip::tcp::resolver
74f8ca6d79SEd Tanous // NOLINTNEXTLINE(readability-identifier-naming)
async_resolve(std::string_view host,std::string_view port,ResolveHandler && handler)75a716aa74SEd Tanous void async_resolve(std::string_view host, std::string_view port,
7629a82b08SSunitha Harish ResolveHandler&& handler)
7729a82b08SSunitha Harish {
7862598e31SEd Tanous BMCWEB_LOG_DEBUG("Trying to resolve: {}:{}", host, port);
79f8ca6d79SEd Tanous
80f8ca6d79SEd Tanous uint16_t portNum = 0;
81f8ca6d79SEd Tanous
82f8ca6d79SEd Tanous auto it = std::from_chars(&*port.begin(), &*port.end(), portNum);
83f8ca6d79SEd Tanous if (it.ec != std::errc())
84f8ca6d79SEd Tanous {
8562598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to get the Port");
86f8ca6d79SEd Tanous handler(std::make_error_code(std::errc::invalid_argument),
87f8ca6d79SEd Tanous results_type{});
88f8ca6d79SEd Tanous
89f8ca6d79SEd Tanous return;
90f8ca6d79SEd Tanous }
91f8ca6d79SEd Tanous
9229a82b08SSunitha Harish uint64_t flag = 0;
9329a82b08SSunitha Harish crow::connections::systemBus->async_method_call(
94a716aa74SEd Tanous [host{std::string(host)}, portNum,
958cb2c024SEd Tanous handler = std::forward<ResolveHandler>(handler)](
965e7e2dc5SEd Tanous const boost::system::error_code& ec,
9729a82b08SSunitha Harish const std::vector<
9829a82b08SSunitha Harish std::tuple<int32_t, int32_t, std::vector<uint8_t>>>& resp,
9929a82b08SSunitha Harish const std::string& hostName, const uint64_t flagNum) {
100f8ca6d79SEd Tanous results_type endpointList;
10129a82b08SSunitha Harish if (ec)
10229a82b08SSunitha Harish {
10362598e31SEd Tanous BMCWEB_LOG_ERROR("Resolve failed: {}", ec.message());
10429a82b08SSunitha Harish handler(ec, endpointList);
10529a82b08SSunitha Harish return;
10629a82b08SSunitha Harish }
10762598e31SEd Tanous BMCWEB_LOG_DEBUG("ResolveHostname returned: {}:{}", hostName,
10862598e31SEd Tanous flagNum);
10929a82b08SSunitha Harish // Extract the IP address from the response
110f8ca6d79SEd Tanous for (const std::tuple<int32_t, int32_t, std::vector<uint8_t>>&
111f8ca6d79SEd Tanous resolveList : resp)
11229a82b08SSunitha Harish {
11329a82b08SSunitha Harish boost::asio::ip::tcp::endpoint endpoint;
114f8ca6d79SEd Tanous endpoint.port(portNum);
115e1452beaSEd Tanous if (!endpointFromResolveTuple(std::get<2>(resolveList),
116e1452beaSEd Tanous endpoint))
117e1452beaSEd Tanous {
118e1452beaSEd Tanous boost::system::error_code ecErr = make_error_code(
119e1452beaSEd Tanous boost::system::errc::address_not_available);
120e1452beaSEd Tanous handler(ecErr, endpointList);
121e1452beaSEd Tanous }
12262598e31SEd Tanous BMCWEB_LOG_DEBUG("resolved endpoint is : {}",
12362598e31SEd Tanous endpoint.address().to_string());
12429a82b08SSunitha Harish endpointList.push_back(endpoint);
12529a82b08SSunitha Harish }
12629a82b08SSunitha Harish // All the resolved data is filled in the endpointList
12729a82b08SSunitha Harish handler(ec, endpointList);
12829a82b08SSunitha Harish },
12929a82b08SSunitha Harish "org.freedesktop.resolve1", "/org/freedesktop/resolve1",
13029a82b08SSunitha Harish "org.freedesktop.resolve1.Manager", "ResolveHostname", 0, host,
13129a82b08SSunitha Harish AF_UNSPEC, flag);
13229a82b08SSunitha Harish }
13329a82b08SSunitha Harish };
13429a82b08SSunitha Harish
13529a82b08SSunitha Harish } // namespace async_resolve
136