Program Listing for File Netio3Backend.cpp
↰ Return to documentation for file (Netio3Backend.cpp)
#include "netio3-backend/Netio3Backend.hpp"
#include <cstddef>
#include <cstring>
#include <functional>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <utility>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "BackendAsyncmsg/BackendAsyncmsg.hpp"
#include "BackendLibfabric/BackendLibfabric.hpp"
#include "BackendLibfabric/BackendLibfabricConnectionless.hpp"
netio3::EndPointAddress::EndPointAddress(const std::string& ip, unsigned short port) :
m_ip(ip), m_ip_numeric{convert_ip(m_ip)}, m_port(port)
{}
netio3::EndPointAddress::EndPointAddress(const std::string& str)
{
const auto cpos = str.find(':');
m_ip = str.substr(0, cpos);
if (cpos != std::string::npos) {
m_port = std::stoi(str.substr(cpos + 1));
} else {
m_port = 0;
}
m_ip_numeric = convert_ip(m_ip);
}
netio3::EndPointAddress::EndPointAddress(const sockaddr* addr, std::size_t addrlen)
{
std::array<char, NI_MAXHOST> namebuf{};
std::array<char, NI_MAXSERV> servbuf{};
const int errcode = getnameinfo(addr,
addrlen,
namebuf.data(),
namebuf.size(),
servbuf.data(),
servbuf.size(),
NI_NUMERICHOST | NI_NUMERICSERV);
if (errcode != 0) {
if (errcode != EAI_SYSTEM) {
throw std::invalid_argument(std::format("getnameinfo failed: {}", gai_strerror(errcode)));
} else {
throw std::invalid_argument(std::format("getnameinfo for {} failed: {}",
namebuf.data(),
utility::error_message(errno)));
}
}
m_ip = namebuf.data();
m_port = static_cast<unsigned short>(std::stoi(servbuf.data()));
m_ip_numeric = convert_ip(m_ip);
}
sockaddr_storage netio3::EndPointAddress::to_sockaddr_storage() const
{
// Try IPv4 first
auto addr4 = sockaddr_in{};
addr4.sin_family = AF_INET;
addr4.sin_port = htons(m_port);
if (inet_pton(AF_INET, m_ip.c_str(), &addr4.sin_addr) == 1) {
// Successfully parsed as IPv4
sockaddr_storage storage{};
std::memcpy(&storage, &addr4, sizeof(addr4));
return storage;
}
// Try IPv6
auto addr6 = sockaddr_in6{};
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(m_port);
if (inet_pton(AF_INET6, m_ip.c_str(), &addr6.sin6_addr) == 1) {
// Successfully parsed as IPv6
sockaddr_storage storage{};
std::memcpy(&storage, &addr6, sizeof(addr6));
return storage;
}
// Neither IPv4 nor IPv6 worked
throw std::invalid_argument(
std::format("Invalid IP address format (neither IPv4 nor IPv6): {}", m_ip));
}
bool netio3::EndPointAddress::is_ipv4() const
{
struct in_addr addr;
return inet_pton(AF_INET, m_ip.c_str(), &addr) == 1;
}
bool netio3::EndPointAddress::is_ipv6() const
{
struct in6_addr addr;
return inet_pton(AF_INET6, m_ip.c_str(), &addr) == 1;
}
std::uint64_t netio3::EndPointAddress::convert_ip(const std::string& ip)
{
std::uint32_t ip_numeric_v4{};
if (inet_pton(AF_INET, ip.data(), &ip_numeric_v4) == 1) {
return static_cast<std::uint64_t>(ip_numeric_v4);
}
struct in6_addr ipv6_addr;
if (inet_pton(AF_INET6, ip.data(), &ipv6_addr) == 1) {
std::hash<std::string> hasher;
return hasher(ip);
}
throw std::invalid_argument(std::format("Invalid IP address format: {}", ip));
}
netio3::NetworkBackend::NetworkBackend(NetworkConfig config,
std::shared_ptr<BaseEventLoop> evloop) :
m_config{std::move(config)}, m_evloop{std::move(evloop)}
{}
std::unique_ptr<netio3::NetworkBackend> netio3::NetworkBackend::create(
NetworkType type,
const NetworkConfig& config,
const std::shared_ptr<BaseEventLoop>& evloop)
{
switch (type) {
case NetworkType::LIBFABRIC:
switch (config.mode) {
case NetworkMode::RDM:
return std::make_unique<libfabric::BackendLibfabricConnectionless>(config, evloop);
default:
return std::make_unique<libfabric::BackendLibfabric>(config, evloop);
}
case NetworkType::ASYNCMSG:
return std::make_unique<asyncmsg::BackendAsyncmsg>(config, evloop);
default:
throw std::invalid_argument("Error: unknown network type.");
}
}
namespace netio3 {
std::ostream& operator<<(std::ostream& stream, const EndPointAddress& val)
{
return stream << val.m_ip << ":" << val.m_port;
}
std::ostream& operator<<(std::ostream& stream, const NetworkConfig& cfg)
{
return stream << "{mode=" << static_cast<int>(cfg.mode) << "}";
}
} // namespace netio3