artdaq_mfextensions  v1_05_00
TCPConnect.hh
Go to the documentation of this file.
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.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 
42 inline int ResolveHost(char const* host_in, in_addr& addr)
43 {
44  std::string host;
45  struct hostent* hostent_sp;
46  std::cmatch mm;
47  // Note: the regex expression used by regex_match has an implied ^ and $
48  // at the beginning and end respectively.
49  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
50  {
51  host = mm[1].str();
52  }
53  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
54  {
55  host = std::string("127.0.0.1");
56  }
57  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
58  {
59  host = mm[1].str().c_str();
60  }
61  else
62  {
63  host = std::string("127.0.0.1");
64  }
65  TLOG(TLVL_INFO) << "Resolving host " << host;
66 
67  memset(&addr, 0, sizeof(addr));
68 
69  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
70  inet_aton(host.c_str(), &addr);
71  else
72  {
73  hostent_sp = gethostbyname(host.c_str());
74  if (!hostent_sp)
75  {
76  perror("gethostbyname");
77  return (-1);
78  }
79  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  return 0;
82 }
83 
90 inline int GetInterfaceForNetwork(char const* host_in, in_addr& addr)
91 {
92  std::string host;
93  struct hostent* hostent_sp;
94  std::cmatch mm;
95  int sts = 0;
96  // Note: the regex expression used by regex_match has an implied ^ and $
97  // at the beginning and end respectively.
98  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
99  {
100  host = mm[1].str();
101  }
102  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
103  {
104  host = std::string("127.0.0.1");
105  }
106  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
107  {
108  host = mm[1].str().c_str();
109  }
110  else
111  {
112  host = std::string("127.0.0.1");
113  }
114  TLOG(TLVL_INFO) << "Resolving ip " << host;
115 
116  memset(&addr, 0, sizeof(addr));
117 
118  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
119  {
120  in_addr desired_host;
121  inet_aton(host.c_str(), &desired_host);
122  struct ifaddrs *ifaddr, *ifa;
123 
124  if (getifaddrs(&ifaddr) == -1)
125  {
126  perror("getifaddrs");
127  return -1;
128  }
129 
130  /* Walk through linked list, maintaining head pointer so we
131  can free list later */
132 
133  for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
134  {
135  if (ifa->ifa_addr == nullptr) continue;
136 
137  /* For an AF_INET* interface address, display the address */
138 
139  if (ifa->ifa_addr->sa_family == AF_INET)
140  {
141  auto if_addr = reinterpret_cast<struct sockaddr_in*>(ifa->ifa_addr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
142  auto sa = reinterpret_cast<struct sockaddr_in*>(ifa->ifa_netmask);// NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
143 
144  TLOG(15) << "IF: " << ifa->ifa_name << " Desired: " << desired_host.s_addr
145  << " netmask: " << sa->sin_addr.s_addr << " this interface: " << if_addr->sin_addr.s_addr;
146 
147  if ((if_addr->sin_addr.s_addr & sa->sin_addr.s_addr) == (desired_host.s_addr & sa->sin_addr.s_addr))
148  {
149  TLOG(TLVL_INFO) << "Using interface " << ifa->ifa_name;
150  memcpy(&addr, &if_addr->sin_addr, sizeof(addr));
151  break;
152  }
153  }
154  }
155  if (ifa == nullptr)
156  {
157  TLOG(TLVL_WARNING) << "No matches for ip " << host << ", using 0.0.0.0";
158  inet_aton("0.0.0.0", &addr);
159  sts = 2;
160  }
161 
162  freeifaddrs(ifaddr);
163  }
164  else
165  {
166  hostent_sp = gethostbyname(host.c_str());
167  if (!hostent_sp)
168  {
169  perror("gethostbyname");
170  return (-1);
171  }
172  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  return sts;
175 }
176 
184 inline int ResolveHost(char const* host_in, int dflt_port, sockaddr_in& sin)
185 {
186  int port;
187  std::string host;
188  struct hostent* hostent_sp;
189  std::cmatch mm;
190  // Note: the regex expression used by regex_match has an implied ^ and $
191  // at the beginning and end respectively.
192  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
193  {
194  host = mm[1].str();
195  port = strtoul(mm[2].str().c_str(), nullptr, 0);
196  }
197  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
198  {
199  host = std::string("127.0.0.1");
200  port = strtoul(mm[1].str().c_str(), nullptr, 0);
201  }
202  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
203  {
204  host = mm[1].str().c_str();
205  port = dflt_port;
206  }
207  else
208  {
209  host = std::string("127.0.0.1");
210  port = dflt_port;
211  }
212  TLOG(TLVL_INFO) << "Resolving host " << host << ", on port " << port;
213 
214  if (host == "localhost") host = "127.0.0.1";
215 
216  memset(&sin, 0, sizeof(sin));
217  sin.sin_family = AF_INET;
218  sin.sin_port = htons(port); // just a guess at an open port
219 
220  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
221  inet_aton(host.c_str(), &sin.sin_addr);
222  else
223  {
224  hostent_sp = gethostbyname(host.c_str());
225  if (!hostent_sp)
226  {
227  perror("gethostbyname");
228  return (-1);
229  }
230  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  return 0;
233 }
234 
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_TRACE) << "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) << "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) << "SNDBUF " << len << " sts/errno=" << sts << "/" << errno;
295  }
296  return (s_fd);
297 }
298 
299 #endif // TCPConnect_hh
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
Definition: TCPConnect.hh:42
int TCPConnect(char const *host_in, int dflt_port, int64_t flags=0, int sndbufsiz=0)
Connect to a host on a given port.
Definition: TCPConnect.hh:243
int GetInterfaceForNetwork(char const *host_in, in_addr &addr)
Convert an IP address to the network address of the interface sharing the subnet mask.
Definition: TCPConnect.hh:90