mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 00:31:14 +00:00
223 lines
6.7 KiB
C++
223 lines
6.7 KiB
C++
#ifndef FAIRMQTOOLS_H_
|
|
#define FAIRMQTOOLS_H_
|
|
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE // To get defns of NI_MAXSERV and NI_MAXHOST
|
|
#endif
|
|
|
|
#include "FairMQLogger.h"
|
|
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <netdb.h>
|
|
#include <ifaddrs.h>
|
|
#include <stdio.h>
|
|
|
|
#include <boost/algorithm/string.hpp> // trim
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <iostream>
|
|
#include <type_traits>
|
|
#include <array>
|
|
|
|
using namespace std;
|
|
|
|
namespace FairMQ
|
|
{
|
|
namespace tools
|
|
{
|
|
|
|
// make_unique implementation, until C++14 is default
|
|
template<typename T, typename ...Args>
|
|
unique_ptr<T> make_unique(Args&& ...args)
|
|
{
|
|
return unique_ptr<T>(new T(forward<Args>(args)...));
|
|
}
|
|
|
|
// returns a map with network interface names as keys and their IP addresses as values
|
|
int getHostIPs(map<string, string>& addressMap)
|
|
{
|
|
struct ifaddrs *ifaddr, *ifa;
|
|
int s;
|
|
char host[NI_MAXHOST];
|
|
|
|
if (getifaddrs(&ifaddr) == -1)
|
|
{
|
|
perror("getifaddrs");
|
|
return -1;
|
|
}
|
|
|
|
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
|
|
{
|
|
if (ifa->ifa_addr == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET)
|
|
{
|
|
s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
|
if (s != 0)
|
|
{
|
|
cout << "getnameinfo() failed: " << gai_strerror(s) << endl;
|
|
return -1;
|
|
}
|
|
|
|
addressMap.insert(pair<string, string>(ifa->ifa_name, host));
|
|
}
|
|
}
|
|
freeifaddrs(ifaddr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// get IP address of a given interface name
|
|
string getInterfaceIP(string interface)
|
|
{
|
|
map<string, string> IPs;
|
|
FairMQ::tools::getHostIPs(IPs);
|
|
if (IPs.count(interface))
|
|
{
|
|
return IPs[interface];
|
|
}
|
|
else
|
|
{
|
|
LOG(ERROR) << "Could not find provided network interface: \"" << interface << "\"!, exiting.";
|
|
return "";
|
|
}
|
|
}
|
|
|
|
// get name of the default route interface
|
|
string getDefaultRouteNetworkInterface()
|
|
{
|
|
array<char, 128> buffer;
|
|
string interfaceName;
|
|
|
|
#ifdef __APPLE__ // MacOS
|
|
unique_ptr<FILE, decltype(pclose) *> file(popen("route -n get default | grep interface | cut -d \":\" -f 2", "r"), pclose);
|
|
#else // Linux
|
|
unique_ptr<FILE, decltype(pclose) *> file(popen("ip route | grep default | cut -d \" \" -f 5", "r"), pclose);
|
|
#endif
|
|
|
|
if (!file)
|
|
{
|
|
LOG(ERROR) << "Could not detect default route network interface name - popen() failed!";
|
|
return "";
|
|
}
|
|
|
|
while (!feof(file.get()))
|
|
{
|
|
if (fgets(buffer.data(), 128, file.get()) != NULL)
|
|
{
|
|
interfaceName += buffer.data();
|
|
}
|
|
}
|
|
|
|
boost::algorithm::trim(interfaceName);
|
|
|
|
if (interfaceName == "")
|
|
{
|
|
LOG(ERROR) << "Could not detect default route network interface name";
|
|
}
|
|
else
|
|
{
|
|
LOG(DEBUG) << "Detected network interface name for the default route: " << interfaceName;
|
|
}
|
|
|
|
return interfaceName;
|
|
}
|
|
|
|
#if defined(__GNUC__) || defined(__GNUG__)
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Weffc++"
|
|
#endif
|
|
// below are SFINAE template functions to check for function member signatures of class
|
|
namespace details
|
|
{
|
|
// test, at compile time, whether T has BindSendHeader member function with returned type R and argument ...Args type
|
|
template<class T, class Sig, class=void>
|
|
struct has_BindSendHeader : false_type {};
|
|
|
|
template<class T, class R, class... Args>
|
|
struct has_BindSendHeader
|
|
<T, R(Args...), typename enable_if<
|
|
is_convertible<decltype(declval<T>().BindSendHeader(declval<Args>()...)), R>::value || is_same<R, void>::value>::type
|
|
>:true_type {};
|
|
|
|
// test, at compile time, whether T has BindGetSocketNumber member function with returned type R and argument ...Args type
|
|
template<class T, class Sig, class=void>
|
|
struct has_BindGetSocketNumber : false_type {};
|
|
|
|
template<class T, class R, class... Args>
|
|
struct has_BindGetSocketNumber
|
|
<T, R(Args...), typename enable_if<
|
|
is_convertible<decltype(declval<T>().BindGetSocketNumber(declval<Args>()...)), R>::value || is_same<R, void>::value>::type
|
|
>:true_type {};
|
|
|
|
// test, at compile time, whether T has GetHeader member function with returned type R and argument ...Args type
|
|
template<class T, class Sig, class=void>
|
|
struct has_GetHeader : false_type {};
|
|
|
|
template<class T, class R, class... Args>
|
|
struct has_GetHeader
|
|
<T, R(Args...), typename enable_if<
|
|
is_convertible<decltype(declval<T>().GetHeader(declval<Args>()...)), R>::value || is_same<R, void>::value>::type
|
|
>:true_type {};
|
|
|
|
// test, at compile time, whether T has BindGetCurrentIndex member function with returned type R and argument ...Args type
|
|
template<class T, class Sig, class=void>
|
|
struct has_BindGetCurrentIndex : false_type {};
|
|
|
|
template<class T, class R, class... Args>
|
|
struct has_BindGetCurrentIndex
|
|
<T, R(Args...), typename enable_if<
|
|
is_convertible<decltype(declval<T>().BindGetCurrentIndex(declval<Args>()...)), R>::value || is_same<R, void>::value>::type
|
|
>:true_type {};
|
|
|
|
|
|
|
|
} // end namespace details
|
|
#if defined(__GNUC__) || defined(__GNUG__)
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
// Alias template of the above structs
|
|
template<class T, class Sig>
|
|
using has_BindSendHeader = integral_constant<bool, details::has_BindSendHeader<T, Sig>::value>;
|
|
|
|
template<class T, class Sig>
|
|
using has_BindGetSocketNumber = integral_constant<bool, details::has_BindGetSocketNumber<T, Sig>::value>;
|
|
|
|
template<class T, class Sig>
|
|
using has_GetHeader = integral_constant<bool, details::has_GetHeader<T, Sig>::value>;
|
|
|
|
template<class T, class Sig>
|
|
using has_BindGetCurrentIndex = integral_constant<bool, details::has_BindGetCurrentIndex<T, Sig>::value>;
|
|
|
|
// enable_if Alias template
|
|
template<typename T>
|
|
using enable_if_has_BindSendHeader = typename enable_if<has_BindSendHeader<T, void(int)>::value, int>::type;
|
|
template<typename T>
|
|
using enable_if_hasNot_BindSendHeader = typename enable_if<!has_BindSendHeader<T, void(int)>::value, int>::type;
|
|
|
|
template<typename T>
|
|
using enable_if_has_BindGetSocketNumber = typename enable_if<has_BindGetSocketNumber<T, int()>::value, int>::type;
|
|
template<typename T>
|
|
using enable_if_hasNot_BindGetSocketNumber = typename enable_if<!has_BindGetSocketNumber<T, int()>::value, int>::type;
|
|
|
|
template<typename T>
|
|
using enable_if_has_BindGetCurrentIndex = typename enable_if<has_BindGetCurrentIndex<T, int()>::value, int>::type;
|
|
template<typename T>
|
|
using enable_if_hasNot_BindGetCurrentIndex = typename enable_if<!has_BindGetCurrentIndex<T, int()>::value, int>::type;
|
|
|
|
template<typename T>
|
|
using enable_if_has_GetHeader = typename enable_if<has_GetHeader<T, int()>::value, int>::type;
|
|
template<typename T>
|
|
using enable_if_hasNot_GetHeader = typename enable_if<!has_GetHeader<T, int()>::value, int>::type;
|
|
|
|
} // namespace tools
|
|
} // namespace FairMQ
|
|
|
|
#endif
|