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