artdaq  v3_02_01
TCPConnect.cc
1 // This file (TCPConnect.cc) was created by Ron Rechenmacher <ron@fnal.gov> on
2 // Apr 26, 2010. "TERMS AND CONDITIONS" governing this file are in the README
3 // or COPYING file. If you do not have such a file, one can be obtained by
4 // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
5 // $RCSfile: TCPConnect.cpp,v $
6 // rev="$Revision: 1.4 $$Date: 2010/06/24 03:49:45 $";
7 
8 #define TRACE_NAME "TCPConnect"
9 
10 #include <stdio.h> // printf
11 #include <sys/types.h> // socket, bind, listen, accept
12 #include <sys/socket.h> // socket, bind, listen, accept
13 #include <netinet/in.h> // struct sockaddr_in
14 #include <stdlib.h> // exit
15 #include <unistd.h> // close
16 #include <string.h> // bzero
17 #include <sys/socket.h> // inet_aton
18 #include <netinet/in.h> // inet_aton
19 #include <arpa/inet.h> // inet_aton
20 #include <netdb.h> // gethostbyname
21 
22 #include <ifaddrs.h>
23 #include <linux/if_link.h>
24 
25 #include <string>
26 #include <regex>
27 #include <map>
28 
29 #include "artdaq/DAQdata/Globals.hh"
31 
32 // Return sts, put result in addr
33 int ResolveHost(char const* host_in, in_addr& addr)
34 {
35  std::string host;
36  struct hostent* hostent_sp;
37  std::cmatch mm;
38  // Note: the regex expression used by regex_match has an implied ^ and $
39  // at the beginning and end respectively.
40  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
41  {
42  host = mm[1].str();
43  }
44  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
45  {
46  host = std::string("127.0.0.1");
47  }
48  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
49  {
50  host = mm[1].str().c_str();
51  }
52  else
53  {
54  host = std::string("127.0.0.1");
55  }
56  TLOG(TLVL_INFO) << "Resolving host " << host;
57 
58  bzero((char *)&addr, sizeof(addr));
59 
60  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
61  inet_aton(host.c_str(), &addr);
62  else
63  {
64  hostent_sp = gethostbyname(host.c_str());
65  if (!hostent_sp)
66  {
67  perror("gethostbyname");
68  return (-1);
69  }
70  addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]);
71  }
72  return 0;
73 }
74 
75 int GetIPOfInterface(std::string interface_name, in_addr& addr)
76 {
77  int sts = 0;
78 
79  TLOG(TLVL_INFO) << "Finding address for interface " << interface_name;
80 
81  bzero((char *)&addr, sizeof(addr));
82 
83  struct ifaddrs *ifaddr, *ifa;
84 
85  if (getifaddrs(&ifaddr) == -1)
86  {
87  perror("getifaddrs");
88  return -1;
89  }
90 
91  /* Walk through linked list, maintaining head pointer so we
92  can free list later */
93 
94  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
95  {
96  if (ifa->ifa_addr == NULL)
97  continue;
98 
99  /* For an AF_INET* interface address, display the address */
100 
101  if (ifa->ifa_addr->sa_family == AF_INET)
102  {
103  auto if_addr = (struct sockaddr_in*) ifa->ifa_addr;
104 
105  TLOG(15) << "IF: " << ifa->ifa_name << " Desired: " << interface_name << " IP: " << if_addr->sin_addr.s_addr;
106 
107  if (std::string(ifa->ifa_name) == interface_name)
108  {
109  TLOG(TLVL_INFO) << "Interface " << ifa->ifa_name << " matches " << interface_name << " IP: " << if_addr->sin_addr.s_addr;
110  memcpy(&addr, &if_addr->sin_addr, sizeof(addr));
111  break;
112  }
113  }
114  }
115  if (ifa == NULL)
116  {
117  TLOG(TLVL_WARNING) << "No matches for if " << interface_name << ", using 0.0.0.0";
118  inet_aton("0.0.0.0", &addr);
119  sts = 2;
120  }
121 
122  freeifaddrs(ifaddr);
123 
124  return sts;
125 }
126 
127 int AutodetectPrivateInterface(in_addr& addr)
128 {
129 
130  int sts = 0;
131 
132  bzero((char *)&addr, sizeof(addr));
133 
134  struct ifaddrs *ifaddr, *ifa;
135 
136  enum ip_preference : int {
137  IP_192 = 1,
138  IP_172 = 2,
139  IP_10 = 3,
140  IP_131 =4
141  };
142 
143  struct in_addr addr_192, addr_172, addr_10, addr_131, nm_16, nm_12, nm_8;
144  inet_aton("192.168.0.0", &addr_192);
145  inet_aton("172.16.0.0", &addr_172);
146  inet_aton("10.0.0.0", &addr_10);
147  inet_aton("131.225.0.0", &addr_131);
148  inet_aton("255.255.0.0", &nm_16);
149  inet_aton("255.240.0.0", &nm_12);
150  inet_aton("255.0.0.0", &nm_8);
151 
152  std::map<ip_preference, in_addr> preference_map;
153 
154  if (getifaddrs(&ifaddr) == -1)
155  {
156  perror("getifaddrs");
157  return -1;
158  }
159 
160  /* Walk through linked list, maintaining head pointer so we
161  can free list later */
162 
163  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
164  {
165  if (ifa->ifa_addr == NULL)
166  continue;
167 
168  /* For an AF_INET* interface address, display the address */
169 
170  if (ifa->ifa_addr->sa_family == AF_INET)
171  {
172  auto if_addr = (struct sockaddr_in*) ifa->ifa_addr;
173 
174  TLOG(15) << "IF: " << ifa->ifa_name << " IP: " << if_addr->sin_addr.s_addr;
175 
176  if (preference_map.count(IP_192) == 0 && (if_addr->sin_addr.s_addr & nm_16.s_addr) == addr_192.s_addr)
177  {
178  preference_map[IP_192];
179  memcpy(&preference_map[IP_192], &if_addr->sin_addr, sizeof(addr));
180  }
181  else if (preference_map.count(IP_172) == 0 && (if_addr->sin_addr.s_addr & nm_12.s_addr) == addr_172.s_addr)
182  {
183  preference_map[IP_172];
184  memcpy(&preference_map[IP_172], &if_addr->sin_addr, sizeof(addr));
185  }
186  else if (preference_map.count(IP_10) == 0 && (if_addr->sin_addr.s_addr & nm_8.s_addr) == addr_10.s_addr)
187  {
188  preference_map[IP_10];
189  memcpy(&preference_map[IP_10], &if_addr->sin_addr, sizeof(addr));
190  }
191  else if (preference_map.count(IP_131) == 0 && (if_addr->sin_addr.s_addr & nm_16.s_addr) == addr_131.s_addr)
192  {
193  preference_map[IP_131];
194  memcpy(&preference_map[IP_131], &if_addr->sin_addr, sizeof(addr));
195  }
196  }
197  }
198 
199  if (preference_map.size() == 0)
200  {
201  TLOG(TLVL_WARNING) << "AutodetectPrivateInterface: No matches, using 0.0.0.0";
202  inet_aton("0.0.0.0", &addr);
203  sts = 2;
204  }
205  else
206  {
207  memcpy(&addr, &preference_map.begin()->second, sizeof(addr));
208  }
209 
210  freeifaddrs(ifaddr);
211 
212  return sts;
213 }
214 
215 // Return sts, put result in addr
216 int GetInterfaceForNetwork(char const* host_in, in_addr& addr)
217 {
218  std::string host;
219  struct hostent* hostent_sp;
220  std::cmatch mm;
221  int sts = 0;
222  // Note: the regex expression used by regex_match has an implied ^ and $
223  // at the beginning and end respectively.
224  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
225  {
226  host = mm[1].str();
227  }
228  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
229  {
230  host = std::string("127.0.0.1");
231  }
232  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
233  {
234  host = mm[1].str().c_str();
235  }
236  else
237  {
238  host = std::string("127.0.0.1");
239  }
240  TLOG(TLVL_INFO) << "Resolving ip " << host;
241 
242  bzero((char *)&addr, sizeof(addr));
243 
244  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
245  {
246  in_addr desired_host;
247  inet_aton(host.c_str(), &desired_host);
248  struct ifaddrs *ifaddr, *ifa;
249 
250  if (getifaddrs(&ifaddr) == -1)
251  {
252  perror("getifaddrs");
253  return -1;
254  }
255 
256  /* Walk through linked list, maintaining head pointer so we
257  can free list later */
258 
259  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
260  {
261  if (ifa->ifa_addr == NULL)
262  continue;
263 
264  /* For an AF_INET* interface address, display the address */
265 
266  if (ifa->ifa_addr->sa_family == AF_INET)
267  {
268  auto if_addr = (struct sockaddr_in*) ifa->ifa_addr;
269  auto sa = (struct sockaddr_in *) ifa->ifa_netmask;
270 
271  TLOG(15) << "IF: " << ifa->ifa_name << " Desired: " << desired_host.s_addr << " netmask: " << sa->sin_addr.s_addr << " this interface: " << if_addr->sin_addr.s_addr;
272 
273  if ((if_addr->sin_addr.s_addr & sa->sin_addr.s_addr) == (desired_host.s_addr & sa->sin_addr.s_addr))
274  {
275  TLOG(TLVL_INFO) << "Using interface " << ifa->ifa_name;
276  memcpy(&addr, &if_addr->sin_addr, sizeof(addr));
277  break;
278  }
279  }
280  }
281  if (ifa == NULL)
282  {
283  TLOG(TLVL_WARNING) << "No matches for ip " << host << ", using 0.0.0.0";
284  inet_aton("0.0.0.0", &addr);
285  sts = 2;
286  }
287 
288  freeifaddrs(ifaddr);
289  }
290  else
291  {
292  hostent_sp = gethostbyname(host.c_str());
293  if (!hostent_sp)
294  {
295  perror("gethostbyname");
296  return (-1);
297  }
298  addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]);
299  }
300  return sts;
301 }
302 
303 // Return sts, put result in sin
304 int ResolveHost(char const* host_in, int dflt_port, sockaddr_in& sin)
305 {
306  int port;
307  std::string host;
308  struct hostent* hostent_sp;
309  std::cmatch mm;
310  // Note: the regex expression used by regex_match has an implied ^ and $
311  // at the beginning and end respectively.
312  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
313  {
314  host = mm[1].str();
315  port = strtoul(mm[2].str().c_str(), NULL, 0);
316  }
317  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
318  {
319  host = std::string("127.0.0.1");
320  port = strtoul(mm[1].str().c_str(), NULL, 0);
321  }
322  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
323  {
324  host = mm[1].str().c_str();
325  port = dflt_port;
326  }
327  else
328  {
329  host = std::string("127.0.0.1");
330  port = dflt_port;
331  }
332  TLOG(TLVL_INFO) << "Resolving host " << host << ", on port " << port;
333 
334  if (host == "localhost") host = "127.0.0.1";
335 
336  bzero((char *)&sin, sizeof(sin));
337  sin.sin_family = AF_INET;
338  sin.sin_port = htons(port); // just a guess at an open port
339 
340  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
341  inet_aton(host.c_str(), &sin.sin_addr);
342  else
343  {
344  hostent_sp = gethostbyname(host.c_str());
345  if (!hostent_sp)
346  {
347  perror("gethostbyname");
348  return (-1);
349  }
350  sin.sin_addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]);
351  }
352  return 0;
353 }
354 // return connection fd.
355 //
356 int TCPConnect(char const* host_in
357  , int dflt_port
358  , long flags
359  , int sndbufsiz)
360 {
361  int s_fd, sts;
362  struct sockaddr_in sin;
363 
364 
365  s_fd = socket(PF_INET, SOCK_STREAM/*|SOCK_NONBLOCK*/, 0); // man socket,man TCP(7P)
366 
367  if (s_fd == -1)
368  {
369  perror("socket error");
370  return (-1);
371  }
372 
373  sts = ResolveHost(host_in, dflt_port, sin);
374  if (sts == -1)
375  {
376  close(s_fd);
377  return -1;
378  }
379 
380  sts = connect(s_fd, (struct sockaddr *)&sin, sizeof(sin));
381  if (sts == -1)
382  {
383  //perror( "connect error" );
384  close(s_fd);
385  return (-1);
386  }
387 
388  if (flags)
389  {
390  sts = fcntl(s_fd, F_SETFL, flags);
391  TLOG(TLVL_TRACE) << "TCPConnect fcntl(fd=" << s_fd << ",flags=0x" << std::hex << flags << std::dec << ") =" << sts;
392  }
393 
394  if (sndbufsiz > 0)
395  {
396  int len;
397  socklen_t lenlen = sizeof(len);
398  len = 0;
399  sts = getsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, &lenlen);
400  TLOG(TLVL_DEBUG) << "TCPConnect SNDBUF initial: " << len << " sts/errno=" << sts << "/" << errno << " lenlen=" << lenlen;
401  len = sndbufsiz;
402  sts = setsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, lenlen);
403  if (sts == -1)
404  TLOG(TLVL_ERROR) << "Error with setsockopt SNDBUF " << errno;
405  len = 0;
406  sts = getsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, &lenlen);
407  if (len < (sndbufsiz * 2))
408  TLOG(TLVL_WARNING) << "SNDBUF " << len << " not expected (" << sndbufsiz << " sts/errno=" << sts << "/" << errno << ")";
409  else
410  TLOG(TLVL_DEBUG) << "SNDBUF " << len << " sts/errno=" << sts << "/" << errno;
411  }
412  return (s_fd);
413 }
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
Definition: TCPConnect.cc:33
int TCPConnect(char const *host_in, int dflt_port, long flags=0, int sndbufsiz=0)
Connect to a host on a given port.
Definition: TCPConnect.cc:356
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.cc:216
int GetIPOfInterface(std::string interface_name, in_addr &addr)
Get the IP address associated with a given interface name.
Definition: TCPConnect.cc:75
int AutodetectPrivateInterface(in_addr &addr)
Pick a private IP address on this host.
Definition: TCPConnect.cc:127