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