Skip to content

Source · fairmq/tools/

Network.cxxsource

Described in Configure channels, Helpers in fair::mq::tools.

fairmq/tools/Network.cxx179 lines · C++GitHub ↗
1/********************************************************************************2 * Copyright (C) 2017-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH  *3 *                                                                              *4 *              This software is distributed under the terms of the             *5 *              GNU Lesser General Public Licence (LGPL) version 3,             *6 *                  copied verbatim in the file "LICENSE"                       *7 ********************************************************************************/8 9#include <fairlogger/Logger.h>10#include <fairmq/tools/Network.h>11#include <fairmq/tools/Strings.h>12 13#ifndef _GNU_SOURCE14#define _GNU_SOURCE   // To get defns of NI_MAXSERV and NI_MAXHOST15#endif16 17#include <array>18#include <boost/algorithm/string.hpp>   // trim19#include <boost/asio.hpp>20#include <cstdio>21#include <exception>22#include <fstream>23#include <ifaddrs.h>24#include <iostream>25#include <map>26#include <netdb.h>27#include <stdexcept>28#include <string>29#include <sys/socket.h>30#include <sys/types.h>31 32using namespace std;33 34namespace fair::mq::tools {35 36// returns a map with network interface names as keys and their IP addresses as values37map<string, string> getHostIPs()38{39    map<string, string> addressMap;40    ifaddrs* ifaddr = nullptr;41    ifaddrs* ifa = nullptr;42    int s = 0;43    array<char, NI_MAXHOST> host{};44 45    if (getifaddrs(&ifaddr) == -1) {46        perror("getifaddrs");47        throw runtime_error("getifaddrs failed");48    }49 50    for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {51        if (ifa->ifa_addr == nullptr) {52            continue;53        }54 55        if (ifa->ifa_addr->sa_family == AF_INET) {56            s = getnameinfo(ifa->ifa_addr,57                            sizeof(sockaddr_in),58                            host.data(),59                            NI_MAXHOST,60                            nullptr,61                            0,62                            NI_NUMERICHOST);63            if (s != 0) {64                cout << "getnameinfo() failed: " << gai_strerror(s) << endl;65                throw runtime_error("getnameinfo() failed");66            }67 68            addressMap.insert({ifa->ifa_name, host.data()});69        }70    }71 72    freeifaddrs(ifaddr);73 74    return addressMap;75}76 77// get IP address of a given interface name78string getInterfaceIP(const string& interface)79{80    try {81        auto IPs = getHostIPs();82        if (IPs.count(interface) > 0) {83            return IPs[interface];84        }85        LOG(error) << "Could not find provided network interface: \""86                   << interface << "\"!, exiting.";87        return "";88    } catch (runtime_error& re) {89        cout << "could not get interface IP: " << re.what();90        return "";91    }92}93 94// get name of the default route interface95string getDefaultRouteNetworkInterface()96{97    const int BUFSIZE(128);98    array<char, BUFSIZE> buffer{};99    string interfaceName;100 101#ifdef __APPLE__   // MacOS102    unique_ptr<FILE, int (*)(FILE*)> file(103        popen("route -n get default | grep interface | cut -d \":\" -f 2", "r"), pclose);104#else   // Linux105    ifstream is("/proc/net/route");106    string line;107 108    // discard header109    getline(is, line);110 111    // check each line, until 00000000 destination is found112    while (!is.eof()) {113        getline(is, line);114        size_t pos = line.find('\t');115 116        if (pos == string::npos) {117            break;118        }119 120        if (line.substr(pos + 1, 8) == "00000000") {121            interfaceName = line.substr(0, pos);122            LOG(debug) << "Detected network interface name for the default route: "123                       << interfaceName;124            return interfaceName;125        }126    }127 128    LOG(debug) << "could not get network interface of the default route from /proc/net/route, "129                  "going to try via 'ip route'";130 131    unique_ptr<FILE, int (*)(FILE*)> file(132        popen("ip route | grep default | cut -d \" \" -f 5 | head -n 1", "r"), pclose);133#endif134 135    if (!file) {136        LOG(error) << "Could not detect default route network interface name - popen() failed!";137        return "";138    }139 140    while (feof(file.get()) == 0) {141        if (fgets(buffer.data(), BUFSIZE, file.get()) != nullptr) {142            interfaceName += buffer.data();143        }144    }145 146    boost::algorithm::trim(interfaceName);147 148    if (interfaceName.empty()) {149        LOG(debug) << "Could not detect default route network interface name from /proc/net/route "150                      "nor 'ip route'";151        throw DefaultRouteDetectionError("Could not detect default route network interface name "152                                         "from /proc/net/route nor 'ip route'");153    } else {154        LOG(debug) << "Detected network interface name for the default route: " << interfaceName;155    }156 157    return interfaceName;158}159 160string getIpFromHostname(const string& hostname)161try {162    boost::asio::io_context ioc;163    boost::asio::ip::tcp::resolver resolver(ioc);164 165    auto const result = resolver.resolve(boost::asio::ip::tcp::v4(), hostname, "");166 167    if (result.empty()) {168        LOG(warn) << "could not find ipv4 address for hostname '" << hostname << "'";169        return "";170    }171    return ToString(result.begin()->endpoint().address());172}173catch (std::exception const& ex)174{175    LOG(error) << "could not resolve hostname '" << hostname << "', reason: " << ex.what();176    return "";177}178 179}   // namespace fair::mq::tools