Commit d44b4acc authored by Joseph Noir's avatar Joseph Noir

Add function to resolve hosts to IP address

parent 617cd5ea
...@@ -11,6 +11,7 @@ set(LIBCAF_NET_SRCS ...@@ -11,6 +11,7 @@ set(LIBCAF_NET_SRCS
src/datagram_socket.cpp src/datagram_socket.cpp
src/endpoint_manager.cpp src/endpoint_manager.cpp
src/host.cpp src/host.cpp
src/ip.cpp
src/multiplexer.cpp src/multiplexer.cpp
src/network_socket.cpp src/network_socket.cpp
src/pipe_socket.cpp src/pipe_socket.cpp
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <string>
#include <vector>
#include "caf/fwd.hpp"
namespace caf {
namespace net {
namespace ip {
/// Returns all IP addresses of to `host` (if any).
std::vector<ip_address> resolve(string_view host);
/// Returns the hostname of this device.
std::string hostname();
} // namespace ip
} // namespace net
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <cstddef>
#include <string>
#include <utility>
#include <vector>
#include "caf/config.hpp"
#include "caf/detail/socket_sys_includes.hpp"
#include "caf/error.hpp"
#include "caf/ip_address.hpp"
#include "caf/logger.hpp"
#include "caf/string_view.hpp"
// clang-format off
#ifdef CAF_WINDOWS
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0600
# endif
# include <iphlpapi.h>
#else
# include <net/if.h>
# include <netdb.h>
# include <ifaddrs.h>
# include <sys/ioctl.h>
# include <sys/types.h>
#endif
// clang-format on
#ifndef HOST_NAME_MAX
# define HOST_NAME_MAX 255
#endif
using std::pair;
using std::string;
using std::vector;
namespace caf {
namespace net {
namespace ip {
namespace {
void* fetch_in_addr(int family, sockaddr* addr) {
if (family == AF_INET)
return &reinterpret_cast<sockaddr_in*>(addr)->sin_addr;
return &reinterpret_cast<sockaddr_in6*>(addr)->sin6_addr;
}
// TODO: Use getnameinfo instead?
int fetch_addr_str(bool get_ipv4, bool get_ipv6, char (&buf)[INET6_ADDRSTRLEN],
sockaddr* addr) {
if (addr == nullptr)
return AF_UNSPEC;
auto family = addr->sa_family;
auto in_addr = fetch_in_addr(family, addr);
return ((family == AF_INET && get_ipv4) || (family == AF_INET6 && get_ipv6))
&& inet_ntop(family, in_addr, buf, INET6_ADDRSTRLEN) == buf
? family
: AF_UNSPEC;
}
} // namespace
std::vector<ip_address> resolve(string_view host) {
addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_socktype = SOCK_STREAM;
hint.ai_family = AF_UNSPEC;
if (host.empty())
hint.ai_flags = AI_PASSIVE;
addrinfo* tmp = nullptr;
std::string host_str{host.begin(), host.end()};
if (getaddrinfo(host_str.c_str(), nullptr, &hint, &tmp) != 0)
return {};
std::unique_ptr<addrinfo, decltype(freeaddrinfo)*> addrs{tmp, freeaddrinfo};
char buffer[INET6_ADDRSTRLEN];
std::vector<ip_address> results;
for (auto i = addrs.get(); i != nullptr; i = i->ai_next) {
auto family = fetch_addr_str(true, true, buffer, i->ai_addr);
if (family != AF_UNSPEC) {
ip_address ip;
if (auto err = parse(buffer, ip))
CAF_LOG_ERROR("could not parse IP address: " << buffer);
else
results.emplace_back(ip);
}
}
// TODO: Should we just prefer ipv6 or use a config option?
// std::stable_sort(std::begin(results), std::end(results),
// [](const ip_address& lhs, const ip_address& rhs) {
// return !lhs.embeds_v4() && rhs.embeds_v4();
// });
return results;
}
#ifdef CAF_WINDOWS
std::string hostname() {
TCHAR buf[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = MAX_COMPUTERNAME_LENGTH;
GetComputerName(buf, &size);
return buf;
}
#else // CAF_WINDOWS
std::string hostname() {
char buf[HOST_NAME_MAX + 1];
buf[HOST_NAME_MAX] = '\0';
gethostname(buf, HOST_NAME_MAX);
gethostbyname(buf);
return buf;
}
#endif // CAF_WINDOWS
} // namespace ip
} // namespace net
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2019 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE ip
#include "caf/net/ip.hpp"
#include "caf/ipv4_address.hpp"
#include "caf/ip_address.hpp"
#include "caf/test/dsl.hpp"
using namespace caf;
using namespace caf::net;
CAF_TEST(resolve) {
ip_address v4_local{make_ipv4_address(127, 0, 0, 1)};
ip_address v6_local{{0}, {0x1}};
auto addrs = ip::resolve("localhost");
CAF_CHECK(!addrs.empty());
auto contains = [&](ip_address x) {
return std::find(std::begin(addrs), std::end(addrs), x) != std::end(addrs);
};
CAF_CHECK(contains(v4_local) || contains(v6_local));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment