LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/artdaq-mfextensions/mfextensions/Receivers/detail - TCPConnect.hh (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 0.0 % 90 0
Test Date: 2025-09-04 00:45:34 Functions: 0.0 % 9 0

            Line data    Source code
       1              : #ifndef TCPConnect_hh
       2              : #define TCPConnect_hh
       3              : #include <arpa/inet.h>  // inet_aton
       4              : #include <netdb.h>      // gethostbyname
       5              : #include <netinet/in.h>
       6              : #include <netinet/in.h>  // struct sockaddr_in
       7              : #include <netinet/in.h>  // inet_aton
       8              : #include <sys/socket.h>  // socket, bind, listen, accept
       9              : #include <sys/socket.h>  // inet_aton
      10              : #include <sys/types.h>   // socket, bind, listen, accept
      11              : #include <unistd.h>      // close
      12              : #include <cstdio>        // printf
      13              : #include <cstdlib>       // exit
      14              : #include <cstring>       // bzero
      15              : 
      16              : #include <ifaddrs.h>
      17              : #include <linux/if_link.h>
      18              : 
      19              : #include <regex>
      20              : #include <string>
      21              : 
      22              : #include "TRACE/trace.h"
      23              : 
      24              : // This file (TCPConnect.hh) was created by Ron Rechenmacher <ron@fnal.gov> on
      25              : // Sep 15, 2016. "TERMS AND CONDITIONS" governing this file are in the README
      26              : // or COPYING file. If you do not have such a file, one can be obtained by
      27              : // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
      28              : // $RCSfile: .emacs.gnu,v $
      29              : // rev="$Revision: 1.30 $$Date: 2016/03/01 14:27:27 $";
      30              : 
      31              : /**
      32              :  * \file TCPConnect.hh
      33              :  * Provides utility functions for connecting TCP sockets
      34              :  */
      35              : 
      36              : /**
      37              :  * \brief Convert a string hostname to a in_addr suitable for socket communication
      38              :  * \param host_in Name or IP of host to resolve
      39              :  * \param[out] addr in_addr object populated with resolved host
      40              :  * \return 0 if success, -1 if gethostbyname fails
      41              :  */
      42            0 : inline int ResolveHost(char const* host_in, in_addr& addr)
      43              : {
      44            0 :         std::string host;
      45              :         struct hostent* hostent_sp;
      46            0 :         std::cmatch mm;
      47              :         //  Note: the regex expression used by regex_match has an implied ^ and $
      48              :         //        at the beginning and end respectively.
      49            0 :         if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
      50              :         {
      51            0 :                 host = mm[1].str();
      52              :         }
      53            0 :         else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
      54              :         {
      55            0 :                 host = std::string("127.0.0.1");
      56              :         }
      57            0 :         else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
      58              :         {
      59            0 :                 host = mm[1].str().c_str();
      60              :         }
      61              :         else
      62              :         {
      63            0 :                 host = std::string("127.0.0.1");
      64              :         }
      65            0 :         TLOG(TLVL_INFO) << "Resolving host " << host;
      66              : 
      67            0 :         memset(&addr, 0, sizeof(addr));
      68              : 
      69            0 :         if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
      70            0 :                 inet_aton(host.c_str(), &addr);
      71              :         else
      72              :         {
      73            0 :                 hostent_sp = gethostbyname(host.c_str());
      74            0 :                 if (!hostent_sp)
      75              :                 {
      76            0 :                         perror("gethostbyname");
      77            0 :                         return (-1);
      78              :                 }
      79            0 :                 addr = *reinterpret_cast<struct in_addr*>(hostent_sp->h_addr_list[0]);  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-reinterpret-cast)
      80              :         }
      81            0 :         return 0;
      82            0 : }
      83              : 
      84              : /**
      85              :  * \brief Convert an IP address to the network address of the interface sharing the subnet mask
      86              :  * \param host_in IP to resolve
      87              :  * \param[out] addr in_addr object populated with resolved host
      88              :  * \return 0 if success, -1 if gethostbyname fails, 2 if defaulted to 0.0.0.0 (No matching interfaces)
      89              :  */
      90            0 : inline int GetInterfaceForNetwork(char const* host_in, in_addr& addr)
      91              : {
      92            0 :         std::string host;
      93              :         struct hostent* hostent_sp;
      94            0 :         std::cmatch mm;
      95            0 :         int sts = 0;
      96              :         //  Note: the regex expression used by regex_match has an implied ^ and $
      97              :         //        at the beginning and end respectively.
      98            0 :         if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
      99              :         {
     100            0 :                 host = mm[1].str();
     101              :         }
     102            0 :         else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
     103              :         {
     104            0 :                 host = std::string("127.0.0.1");
     105              :         }
     106            0 :         else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
     107              :         {
     108            0 :                 host = mm[1].str().c_str();
     109              :         }
     110              :         else
     111              :         {
     112            0 :                 host = std::string("127.0.0.1");
     113              :         }
     114            0 :         TLOG(TLVL_INFO) << "Resolving ip " << host;
     115              : 
     116            0 :         memset(&addr, 0, sizeof(addr));
     117              : 
     118            0 :         if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
     119              :         {
     120              :                 in_addr desired_host;
     121            0 :                 inet_aton(host.c_str(), &desired_host);
     122              :                 struct ifaddrs *ifaddr, *ifa;
     123              : 
     124            0 :                 if (getifaddrs(&ifaddr) == -1)
     125              :                 {
     126            0 :                         perror("getifaddrs");
     127            0 :                         return -1;
     128              :                 }
     129              : 
     130              :                 /* Walk through linked list, maintaining head pointer so we
     131              :         can free list later */
     132              : 
     133            0 :                 for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
     134              :                 {
     135            0 :                         if (ifa->ifa_addr == nullptr) continue;
     136              : 
     137              :                         /* For an AF_INET* interface address, display the address */
     138              : 
     139            0 :                         if (ifa->ifa_addr->sa_family == AF_INET)
     140              :                         {
     141            0 :                                 auto if_addr = reinterpret_cast<struct sockaddr_in*>(ifa->ifa_addr);  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
     142            0 :                                 auto sa = reinterpret_cast<struct sockaddr_in*>(ifa->ifa_netmask);    // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
     143              : 
     144            0 :                                 TLOG(TLVL_DEBUG + 40) << "IF: " << ifa->ifa_name << " Desired: " << desired_host.s_addr
     145            0 :                                                       << " netmask: " << sa->sin_addr.s_addr << " this interface: " << if_addr->sin_addr.s_addr;
     146              : 
     147            0 :                                 if ((if_addr->sin_addr.s_addr & sa->sin_addr.s_addr) == (desired_host.s_addr & sa->sin_addr.s_addr))
     148              :                                 {
     149            0 :                                         TLOG(TLVL_INFO) << "Using interface " << ifa->ifa_name;
     150            0 :                                         memcpy(&addr, &if_addr->sin_addr, sizeof(addr));
     151            0 :                                         break;
     152              :                                 }
     153              :                         }
     154              :                 }
     155            0 :                 if (ifa == nullptr)
     156              :                 {
     157            0 :                         TLOG(TLVL_WARNING) << "No matches for ip " << host << ", using 0.0.0.0";
     158            0 :                         inet_aton("0.0.0.0", &addr);
     159            0 :                         sts = 2;
     160              :                 }
     161              : 
     162            0 :                 freeifaddrs(ifaddr);
     163              :         }
     164              :         else
     165              :         {
     166            0 :                 hostent_sp = gethostbyname(host.c_str());
     167            0 :                 if (!hostent_sp)
     168              :                 {
     169            0 :                         perror("gethostbyname");
     170            0 :                         return (-1);
     171              :                 }
     172            0 :                 addr = *reinterpret_cast<struct in_addr*>(hostent_sp->h_addr_list[0]);  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic)
     173              :         }
     174            0 :         return sts;
     175            0 : }
     176              : 
     177              : /**
     178              :  * \brief Convert a string hostname and port to a sockaddr_in suitable for socket communication
     179              :  * \param host_in Name or IP of host to resolve
     180              :  * \param dflt_port POrt to populate in output
     181              :  * \param[out] sin sockaddr_in object populated with resolved host and port
     182              :  * \return 0 if success, -1 if gethostbyname fails
     183              :  */
     184            0 : inline int ResolveHost(char const* host_in, int dflt_port, sockaddr_in& sin)
     185              : {
     186              :         int port;
     187            0 :         std::string host;
     188              :         struct hostent* hostent_sp;
     189            0 :         std::cmatch mm;
     190              :         //  Note: the regex expression used by regex_match has an implied ^ and $
     191              :         //        at the beginning and end respectively.
     192            0 :         if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
     193              :         {
     194            0 :                 host = mm[1].str();
     195            0 :                 port = strtoul(mm[2].str().c_str(), nullptr, 0);
     196              :         }
     197            0 :         else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
     198              :         {
     199            0 :                 host = std::string("127.0.0.1");
     200            0 :                 port = strtoul(mm[1].str().c_str(), nullptr, 0);
     201              :         }
     202            0 :         else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
     203              :         {
     204            0 :                 host = mm[1].str().c_str();
     205            0 :                 port = dflt_port;
     206              :         }
     207              :         else
     208              :         {
     209            0 :                 host = std::string("127.0.0.1");
     210            0 :                 port = dflt_port;
     211              :         }
     212            0 :         TLOG(TLVL_INFO) << "Resolving host " << host << ", on port " << port;
     213              : 
     214            0 :         if (host == "localhost") host = "127.0.0.1";
     215              : 
     216            0 :         memset(&sin, 0, sizeof(sin));
     217            0 :         sin.sin_family = AF_INET;
     218            0 :         sin.sin_port = htons(port);  // just a guess at an open port
     219              : 
     220            0 :         if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
     221            0 :                 inet_aton(host.c_str(), &sin.sin_addr);
     222              :         else
     223              :         {
     224            0 :                 hostent_sp = gethostbyname(host.c_str());
     225            0 :                 if (!hostent_sp)
     226              :                 {
     227            0 :                         perror("gethostbyname");
     228            0 :                         return (-1);
     229              :                 }
     230            0 :                 sin.sin_addr = *reinterpret_cast<struct in_addr*>(hostent_sp->h_addr_list[0]);  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast,cppcoreguidelines-pro-bounds-pointer-arithmetic)
     231              :         }
     232            0 :         return 0;
     233            0 : }
     234              : 
     235              : /**
     236              :  * \brief Connect to a host on a given port
     237              :  * \param host_in Name or IP of the host to connect to
     238              :  * \param dflt_port Port to connect to
     239              :  * \param flags TCP flags to use for the socket
     240              :  * \param sndbufsiz Size of the send buffer. Set to 0 for automatic send buffer management
     241              :  * \return File descriptor of connected socket.
     242              :  */
     243              : inline int TCPConnect(char const* host_in, int dflt_port, int64_t flags = 0, int sndbufsiz = 0)
     244              : {
     245              :         int s_fd, sts;
     246              :         struct sockaddr_in sin;
     247              : 
     248              :         s_fd = socket(PF_INET, SOCK_STREAM /*|SOCK_NONBLOCK*/, 0);  // man socket,man TCP(7P)
     249              : 
     250              :         if (s_fd == -1)
     251              :         {
     252              :                 perror("socket error");
     253              :                 return (-1);
     254              :         }
     255              : 
     256              :         sts = ResolveHost(host_in, dflt_port, sin);
     257              :         if (sts == -1)
     258              :         {
     259              :                 close(s_fd);
     260              :                 return -1;
     261              :         }
     262              : 
     263              :         sts = connect(s_fd, reinterpret_cast<struct sockaddr*>(&sin), sizeof(sin));  // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
     264              :         if (sts == -1)
     265              :         {
     266              :                 // perror( "connect error" );
     267              :                 close(s_fd);
     268              :                 return (-1);
     269              :         }
     270              : 
     271              :         if (flags)
     272              :         {
     273              :                 sts = fcntl(s_fd, F_SETFL, flags);
     274              :                 TLOG(TLVL_DEBUG + 33) << "TCPConnect fcntl(fd=" << s_fd << ",flags=0x" << std::hex << flags << std::dec << ") =" << sts;
     275              :         }
     276              : 
     277              :         if (sndbufsiz > 0)
     278              :         {
     279              :                 int len;
     280              :                 socklen_t lenlen = sizeof(len);
     281              :                 len = 0;
     282              :                 sts = getsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, &lenlen);
     283              :                 TLOG(TLVL_DEBUG + 32) << "TCPConnect SNDBUF initial: " << len << " sts/errno=" << sts << "/" << errno
     284              :                                       << " lenlen=" << lenlen;
     285              :                 len = sndbufsiz;
     286              :                 sts = setsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, lenlen);
     287              :                 if (sts == -1) TLOG(TLVL_ERROR) << "Error with setsockopt SNDBUF " << errno;
     288              :                 len = 0;
     289              :                 sts = getsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, &lenlen);
     290              :                 if (len < (sndbufsiz * 2))
     291              :                         TLOG(TLVL_WARNING) << "SNDBUF " << len << " not expected (" << sndbufsiz << " sts/errno=" << sts << "/" << errno
     292              :                                            << ")";
     293              :                 else
     294              :                         TLOG(TLVL_DEBUG + 32) << "SNDBUF " << len << " sts/errno=" << sts << "/" << errno;
     295              :         }
     296              :         return (s_fd);
     297              : }
     298              : 
     299              : #endif  // TCPConnect_hh
        

Generated by: LCOV version 2.0-1