Sleds/gluster_status/Network.cpp

170 lines
5.0 KiB
C++

/*
Copyright (c) 2014 IOnU Security Inc. All rights reserved
Created February 2014 by Kendrick Webster
Network.cpp - implementation for Network.h
*/
#include <string.h>
#include <netdb.h>
#include "Network.h"
using ionu::network::ADDRESS_STRING_LENGTH;
using ionu::network::CAddress;
//-----------------------------------------------------------------------------------
// Address to string conversion
//-----------------------------------------------------------------------------------
std::string ionu::network::IP4AddressString(struct in_addr s)
{
return std::string(inet_ntoa(s));
}
std::string ionu::network::IP4AddressString(uint32_t a)
{
struct in_addr s;
s.s_addr = a;
return IP4AddressString(s);
}
std::string ionu::network::IP4AddressString(CAddress a)
{
return IP4AddressString(a.addr);
}
std::string ionu::network::IP4AddressString(const struct sockaddr_in& a)
{
return IP4AddressString(a.sin_addr.s_addr);
}
//-----------------------------------------------------------------------------------
// Host name lookup
//-----------------------------------------------------------------------------------
static bool isAddressUsable(const struct addrinfo* a, int family, int socktype)
{
return ((a->ai_family == family) && (a->ai_socktype == socktype));
}
constexpr const char* SA_TYPE_SELECTED = "(selected)";
constexpr const char* SA_TYPE_IGNORED = "(ignored) ";
constexpr const char* SA_TYPE_NOT_SELECTED = "..........";
static void showAddress(const struct addrinfo* a, unsigned int index, const char* type, Log::severity_t dump_loglevel)
{
char addrstr[ADDRESS_STRING_LENGTH];
void* src = NULL;
switch (a->ai_family)
{
case AF_INET:
src = &(reinterpret_cast<struct sockaddr_in*>(a->ai_addr)->sin_addr);
break;
case AF_INET6:
src = &(reinterpret_cast<struct sockaddr_in6*>(a->ai_addr)->sin6_addr);
break;
}
switch (a->ai_family)
{
case AF_INET:
case AF_INET6:
if (inet_ntop(a->ai_family, src, addrstr, sizeof(addrstr)))
{
logprintf(dump_loglevel, "address %2d %s %s", index, type, addrstr);
}
break;
default:
logprintf(dump_loglevel, "address %2d %s AF_?(%d)", index, type, a->ai_family);
break;
}
}
// sets <ca> to the <i>'th (0-based) usable address (skipping/ignoring unusable addresses) in list <a>,
// logs the list using <dump_loglevel> (which can be set to Log::ignore if logging is not wanted)
static success_t selectUsableAddress(
unsigned int i, // 0-based index into a virtual list containing usable elements of <a>
int socktype, // SOCK_DGRAM, SOCK_STREAM, etc.
const struct addrinfo* a, // list returned by getaddrinfo
CAddress& ca, // result (output)
Log::severity_t dump_loglevel) // log severity for dumping address list/selection
{
success_t r = FAILURE;
unsigned int j = 0, n = 0;
struct sockaddr_in* addr;
while (NULL != a)
{
++j;
if (isAddressUsable(a, AF_INET, socktype))
{
if (i == n)
{
showAddress(a, j, SA_TYPE_SELECTED, dump_loglevel);
addr = reinterpret_cast<struct sockaddr_in *>(a->ai_addr);
ca.addr = addr->sin_addr.s_addr;
ca.port = addr->sin_port;
r = SUCCESS;
}
else
{
showAddress(a, j, SA_TYPE_NOT_SELECTED, dump_loglevel);
}
++n;
}
else
{
showAddress(a, j, SA_TYPE_IGNORED, dump_loglevel);
}
a = a->ai_next;
}
return r;
}
success_t ionu::network::HostToAddress(const CHost& h, CAddress& a,
int socktype, Log::severity_t trace_loglevel, Log::severity_t error_loglevel)
{
struct addrinfo hints, *result;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = socktype;
logprintf(trace_loglevel, "Resolving host \"%s\" ...", h.host.c_str());
int r = getaddrinfo(h.host.c_str(), NULL, &hints, &result);
if (0 != r)
{
logprintf(error_loglevel, "getaddrinfo: %s", gai_strerror(r));
return FAILURE;
}
success_t s = selectUsableAddress(0, socktype, result, a, trace_loglevel);
freeaddrinfo(result);
if (FAILURE == s)
{
logprintf(error_loglevel, "unable to resolve host \"%s\"", h.host.c_str());
return FAILURE;
}
a.port = htons(h.port);
return SUCCESS;
}
success_t ionu::network::HostListToAddressList(const host_list_t& hl, address_list_t& al,
int socktype, Log::severity_t trace_loglevel, Log::severity_t error_loglevel)
{
al.clear();
success_t r = SUCCESS;
for (const CHost& h: hl)
{
CAddress a;
if (FAILURE == HostToAddress(h, a, socktype, trace_loglevel, error_loglevel))
{
r = FAILURE;
}
else
{
al.push_back(a);
}
}
return r;
}