artdaq  v3_02_00
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 
28 #include "artdaq/DAQdata/Globals.hh"
30 
31 // Return sts, put result in addr
32 int ResolveHost(char const* host_in, in_addr& addr)
33 {
34  std::string host;
35  struct hostent* hostent_sp;
36  std::cmatch mm;
37  // Note: the regex expression used by regex_match has an implied ^ and $
38  // at the beginning and end respectively.
39  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
40  {
41  host = mm[1].str();
42  }
43  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
44  {
45  host = std::string("127.0.0.1");
46  }
47  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
48  {
49  host = mm[1].str().c_str();
50  }
51  else
52  {
53  host = std::string("127.0.0.1");
54  }
55  TLOG(TLVL_INFO) << "Resolving host " << host;
56 
57  bzero((char *)&addr, sizeof(addr));
58 
59  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
60  inet_aton(host.c_str(), &addr);
61  else
62  {
63  hostent_sp = gethostbyname(host.c_str());
64  if (!hostent_sp)
65  {
66  perror("gethostbyname");
67  return (-1);
68  }
69  addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]);
70  }
71  return 0;
72 }
73 
74 // Return sts, put result in addr
75 int GetInterfaceForNetwork(char const* host_in, in_addr& addr)
76 {
77  std::string host;
78  struct hostent* hostent_sp;
79  std::cmatch mm;
80  int sts = 0;
81  // Note: the regex expression used by regex_match has an implied ^ and $
82  // at the beginning and end respectively.
83  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
84  {
85  host = mm[1].str();
86  }
87  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
88  {
89  host = std::string("127.0.0.1");
90  }
91  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
92  {
93  host = mm[1].str().c_str();
94  }
95  else
96  {
97  host = std::string("127.0.0.1");
98  }
99  TLOG(TLVL_INFO) << "Resolving ip " << host;
100 
101  bzero((char *)&addr, sizeof(addr));
102 
103  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
104  {
105  in_addr desired_host;
106  inet_aton(host.c_str(), &desired_host);
107  struct ifaddrs *ifaddr, *ifa;
108 
109  if (getifaddrs(&ifaddr) == -1)
110  {
111  perror("getifaddrs");
112  return -1;
113  }
114 
115  /* Walk through linked list, maintaining head pointer so we
116  can free list later */
117 
118  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
119  {
120  if (ifa->ifa_addr == NULL)
121  continue;
122 
123  /* For an AF_INET* interface address, display the address */
124 
125  if (ifa->ifa_addr->sa_family == AF_INET)
126  {
127  auto if_addr = (struct sockaddr_in*) ifa->ifa_addr;
128  auto sa = (struct sockaddr_in *) ifa->ifa_netmask;
129 
130  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;
131 
132  if ((if_addr->sin_addr.s_addr & sa->sin_addr.s_addr) == (desired_host.s_addr & sa->sin_addr.s_addr))
133  {
134  TLOG(TLVL_INFO) << "Using interface " << ifa->ifa_name;
135  memcpy(&addr, &if_addr->sin_addr, sizeof(addr));
136  break;
137  }
138  }
139  }
140  if (ifa == NULL)
141  {
142  TLOG(TLVL_WARNING) << "No matches for ip " << host << ", using 0.0.0.0";
143  inet_aton("0.0.0.0", &addr);
144  sts = 2;
145  }
146 
147  freeifaddrs(ifaddr);
148  }
149  else
150  {
151  hostent_sp = gethostbyname(host.c_str());
152  if (!hostent_sp)
153  {
154  perror("gethostbyname");
155  return (-1);
156  }
157  addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]);
158  }
159  return sts;
160 }
161 
162 // Return sts, put result in sin
163 int ResolveHost(char const* host_in, int dflt_port, sockaddr_in& sin)
164 {
165  int port;
166  std::string host;
167  struct hostent* hostent_sp;
168  std::cmatch mm;
169  // Note: the regex expression used by regex_match has an implied ^ and $
170  // at the beginning and end respectively.
171  if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)")))
172  {
173  host = mm[1].str();
174  port = strtoul(mm[2].str().c_str(), NULL, 0);
175  }
176  else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)")))
177  {
178  host = std::string("127.0.0.1");
179  port = strtoul(mm[1].str().c_str(), NULL, 0);
180  }
181  else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}")))
182  {
183  host = mm[1].str().c_str();
184  port = dflt_port;
185  }
186  else
187  {
188  host = std::string("127.0.0.1");
189  port = dflt_port;
190  }
191  TLOG(TLVL_INFO) << "Resolving host " << host << ", on port " << std::to_string(port);
192 
193  if (host == "localhost") host = "127.0.0.1";
194 
195  bzero((char *)&sin, sizeof(sin));
196  sin.sin_family = AF_INET;
197  sin.sin_port = htons(port); // just a guess at an open port
198 
199  if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}")))
200  inet_aton(host.c_str(), &sin.sin_addr);
201  else
202  {
203  hostent_sp = gethostbyname(host.c_str());
204  if (!hostent_sp)
205  {
206  perror("gethostbyname");
207  return (-1);
208  }
209  sin.sin_addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]);
210  }
211  return 0;
212 }
213 // return connection fd.
214 //
215 int TCPConnect(char const* host_in
216  , int dflt_port
217  , long flags
218  , int sndbufsiz)
219 {
220  int s_fd, sts;
221  struct sockaddr_in sin;
222 
223 
224  s_fd = socket(PF_INET, SOCK_STREAM/*|SOCK_NONBLOCK*/, 0); // man socket,man TCP(7P)
225 
226  if (s_fd == -1)
227  {
228  perror("socket error");
229  return (-1);
230  }
231 
232  sts = ResolveHost(host_in, dflt_port, sin);
233  if (sts == -1)
234  {
235  close(s_fd);
236  return -1;
237  }
238 
239  sts = connect(s_fd, (struct sockaddr *)&sin, sizeof(sin));
240  if (sts == -1)
241  {
242  //perror( "connect error" );
243  close(s_fd);
244  return (-1);
245  }
246 
247  if (flags)
248  {
249  sts = fcntl(s_fd, F_SETFL, flags);
250  TLOG(TLVL_TRACE) << "TCPConnect fcntl(fd=" << s_fd << ",flags=0x" << std::hex << flags << std::dec << ") =" << sts;
251  }
252 
253  if (sndbufsiz > 0)
254  {
255  int len;
256  socklen_t lenlen = sizeof(len);
257  len = 0;
258  sts = getsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, &lenlen);
259  TLOG(TLVL_DEBUG) << "TCPConnect SNDBUF initial: " << len << " sts/errno=" << sts << "/" << errno << " lenlen=" << lenlen;
260  len = sndbufsiz;
261  sts = setsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, lenlen);
262  if (sts == -1)
263  TLOG(TLVL_ERROR) << "Error with setsockopt SNDBUF " << errno;
264  len = 0;
265  sts = getsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, &lenlen);
266  if (len < (sndbufsiz * 2))
267  TLOG(TLVL_WARNING) << "SNDBUF " << len << " not expected (" << sndbufsiz << " sts/errno=" << sts << "/" << errno;
268  else
269  TLOG(TLVL_DEBUG) << "SNDBUF " << len << " sts/errno=" << sts << "/" << errno;
270  }
271  return (s_fd);
272 }
int ResolveHost(char const *host_in, in_addr &addr)
Convert a string hostname to a in_addr suitable for socket communication.
Definition: TCPConnect.cc:32
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:215
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:75