1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
// 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
|