$treeview $search $mathjax $extrastylesheet
artdaq
v3_04_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 // This file (TCPConnect.cc) was created by Ron Rechenmacher <ron@fnal.gov> on 00002 // Apr 26, 2010. "TERMS AND CONDITIONS" governing this file are in the README 00003 // or COPYING file. If you do not have such a file, one can be obtained by 00004 // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000. 00005 // $RCSfile: TCPConnect.cpp,v $ 00006 // rev="$Revision: 1.4 $$Date: 2010/06/24 03:49:45 $"; 00007 00008 #define TRACE_NAME (app_name + "_TCPConnect").c_str() 00009 #include "artdaq/DAQdata/Globals.hh" 00010 00011 #include <stdio.h> // printf 00012 #include <sys/types.h> // socket, bind, listen, accept 00013 #include <sys/socket.h> // socket, bind, listen, accept 00014 #include <netinet/in.h> // struct sockaddr_in 00015 #include <stdlib.h> // exit 00016 #include <unistd.h> // close 00017 #include <string.h> // bzero 00018 #include <sys/socket.h> // inet_aton 00019 #include <netinet/in.h> // inet_aton 00020 #include <arpa/inet.h> // inet_aton 00021 #include <netdb.h> // gethostbyname 00022 00023 #include <ifaddrs.h> 00024 #include <linux/if_link.h> 00025 00026 #include <string> 00027 #include <regex> 00028 #include <map> 00029 00030 #include "artdaq/DAQdata/TCPConnect.hh" 00031 00032 // Return sts, put result in addr 00033 int ResolveHost(char const* host_in, in_addr& addr) 00034 { 00035 std::string host; 00036 struct hostent* hostent_sp; 00037 std::cmatch mm; 00038 // Note: the regex expression used by regex_match has an implied ^ and $ 00039 // at the beginning and end respectively. 00040 if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)"))) 00041 { 00042 host = mm[1].str(); 00043 } 00044 else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)"))) 00045 { 00046 host = std::string("127.0.0.1"); 00047 } 00048 else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}"))) 00049 { 00050 host = mm[1].str().c_str(); 00051 } 00052 else 00053 { 00054 host = std::string("127.0.0.1"); 00055 } 00056 TLOG(TLVL_INFO) << "Resolving host " << host; 00057 00058 bzero((char *)&addr, sizeof(addr)); 00059 00060 if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}"))) 00061 inet_aton(host.c_str(), &addr); 00062 else 00063 { 00064 hostent_sp = gethostbyname(host.c_str()); 00065 if (!hostent_sp) 00066 { 00067 perror("gethostbyname"); 00068 return (-1); 00069 } 00070 addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]); 00071 } 00072 return 0; 00073 } 00074 00075 int GetIPOfInterface(std::string interface_name, in_addr& addr) 00076 { 00077 int sts = 0; 00078 00079 TLOG(TLVL_INFO) << "Finding address for interface " << interface_name; 00080 00081 bzero((char *)&addr, sizeof(addr)); 00082 00083 struct ifaddrs *ifaddr, *ifa; 00084 00085 if (getifaddrs(&ifaddr) == -1) 00086 { 00087 perror("getifaddrs"); 00088 return -1; 00089 } 00090 00091 /* Walk through linked list, maintaining head pointer so we 00092 can free list later */ 00093 00094 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 00095 { 00096 if (ifa->ifa_addr == NULL) 00097 continue; 00098 00099 /* For an AF_INET* interface address, display the address */ 00100 00101 if (ifa->ifa_addr->sa_family == AF_INET) 00102 { 00103 auto if_addr = (struct sockaddr_in*) ifa->ifa_addr; 00104 00105 TLOG(15) << "IF: " << ifa->ifa_name << " Desired: " << interface_name << " IP: " << if_addr->sin_addr.s_addr; 00106 00107 if (std::string(ifa->ifa_name) == interface_name) 00108 { 00109 TLOG(TLVL_INFO) << "Interface " << ifa->ifa_name << " matches " << interface_name << " IP: " << if_addr->sin_addr.s_addr; 00110 memcpy(&addr, &if_addr->sin_addr, sizeof(addr)); 00111 break; 00112 } 00113 } 00114 } 00115 if (ifa == NULL) 00116 { 00117 TLOG(TLVL_WARNING) << "No matches for if " << interface_name << ", using 0.0.0.0"; 00118 inet_aton("0.0.0.0", &addr); 00119 sts = 2; 00120 } 00121 00122 freeifaddrs(ifaddr); 00123 00124 return sts; 00125 } 00126 00127 int AutodetectPrivateInterface(in_addr& addr) 00128 { 00129 00130 int sts = 0; 00131 00132 bzero((char *)&addr, sizeof(addr)); 00133 00134 struct ifaddrs *ifaddr, *ifa; 00135 00136 enum ip_preference : int { 00137 IP_192 = 1, 00138 IP_172 = 2, 00139 IP_10 = 3, 00140 IP_131 =4 00141 }; 00142 00143 struct in_addr addr_192, addr_172, addr_10, addr_131, nm_16, nm_12, nm_8; 00144 inet_aton("192.168.0.0", &addr_192); 00145 inet_aton("172.16.0.0", &addr_172); 00146 inet_aton("10.0.0.0", &addr_10); 00147 inet_aton("131.225.0.0", &addr_131); 00148 inet_aton("255.255.0.0", &nm_16); 00149 inet_aton("255.240.0.0", &nm_12); 00150 inet_aton("255.0.0.0", &nm_8); 00151 00152 std::map<ip_preference, in_addr> preference_map; 00153 00154 if (getifaddrs(&ifaddr) == -1) 00155 { 00156 perror("getifaddrs"); 00157 return -1; 00158 } 00159 00160 /* Walk through linked list, maintaining head pointer so we 00161 can free list later */ 00162 00163 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 00164 { 00165 if (ifa->ifa_addr == NULL) 00166 continue; 00167 00168 /* For an AF_INET* interface address, display the address */ 00169 00170 if (ifa->ifa_addr->sa_family == AF_INET) 00171 { 00172 auto if_addr = (struct sockaddr_in*) ifa->ifa_addr; 00173 00174 TLOG(15) << "IF: " << ifa->ifa_name << " IP: " << if_addr->sin_addr.s_addr; 00175 00176 if (preference_map.count(IP_192) == 0 && (if_addr->sin_addr.s_addr & nm_16.s_addr) == addr_192.s_addr) 00177 { 00178 preference_map[IP_192]; 00179 memcpy(&preference_map[IP_192], &if_addr->sin_addr, sizeof(addr)); 00180 } 00181 else if (preference_map.count(IP_172) == 0 && (if_addr->sin_addr.s_addr & nm_12.s_addr) == addr_172.s_addr) 00182 { 00183 preference_map[IP_172]; 00184 memcpy(&preference_map[IP_172], &if_addr->sin_addr, sizeof(addr)); 00185 } 00186 else if (preference_map.count(IP_10) == 0 && (if_addr->sin_addr.s_addr & nm_8.s_addr) == addr_10.s_addr) 00187 { 00188 preference_map[IP_10]; 00189 memcpy(&preference_map[IP_10], &if_addr->sin_addr, sizeof(addr)); 00190 } 00191 else if (preference_map.count(IP_131) == 0 && (if_addr->sin_addr.s_addr & nm_16.s_addr) == addr_131.s_addr) 00192 { 00193 preference_map[IP_131]; 00194 memcpy(&preference_map[IP_131], &if_addr->sin_addr, sizeof(addr)); 00195 } 00196 } 00197 } 00198 00199 if (preference_map.size() == 0) 00200 { 00201 TLOG(TLVL_WARNING) << "AutodetectPrivateInterface: No matches, using 0.0.0.0"; 00202 inet_aton("0.0.0.0", &addr); 00203 sts = 2; 00204 } 00205 else 00206 { 00207 TLOG(TLVL_INFO) << "AutodetectPrivateInterface: Using " << inet_ntoa(addr); 00208 memcpy(&addr, &preference_map.begin()->second, sizeof(addr)); 00209 } 00210 00211 freeifaddrs(ifaddr); 00212 00213 return sts; 00214 } 00215 00216 // Return sts, put result in addr 00217 int GetInterfaceForNetwork(char const* host_in, in_addr& addr) 00218 { 00219 std::string host; 00220 struct hostent* hostent_sp; 00221 std::cmatch mm; 00222 int sts = 0; 00223 // Note: the regex expression used by regex_match has an implied ^ and $ 00224 // at the beginning and end respectively. 00225 if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)"))) 00226 { 00227 host = mm[1].str(); 00228 } 00229 else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)"))) 00230 { 00231 host = std::string("127.0.0.1"); 00232 } 00233 else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}"))) 00234 { 00235 host = mm[1].str().c_str(); 00236 } 00237 else 00238 { 00239 host = std::string("127.0.0.1"); 00240 } 00241 TLOG(TLVL_INFO) << "Resolving ip " << host; 00242 00243 bzero((char *)&addr, sizeof(addr)); 00244 00245 if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}"))) 00246 { 00247 in_addr desired_host; 00248 inet_aton(host.c_str(), &desired_host); 00249 struct ifaddrs *ifaddr, *ifa; 00250 00251 if (getifaddrs(&ifaddr) == -1) 00252 { 00253 perror("getifaddrs"); 00254 return -1; 00255 } 00256 00257 /* Walk through linked list, maintaining head pointer so we 00258 can free list later */ 00259 00260 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 00261 { 00262 if (ifa->ifa_addr == NULL) 00263 continue; 00264 00265 /* For an AF_INET* interface address, display the address */ 00266 00267 if (ifa->ifa_addr->sa_family == AF_INET) 00268 { 00269 auto if_addr = (struct sockaddr_in*) ifa->ifa_addr; 00270 auto sa = (struct sockaddr_in *) ifa->ifa_netmask; 00271 00272 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; 00273 00274 if ((if_addr->sin_addr.s_addr & sa->sin_addr.s_addr) == (desired_host.s_addr & sa->sin_addr.s_addr)) 00275 { 00276 TLOG(TLVL_INFO) << "Using interface " << ifa->ifa_name; 00277 memcpy(&addr, &if_addr->sin_addr, sizeof(addr)); 00278 break; 00279 } 00280 } 00281 } 00282 if (ifa == NULL) 00283 { 00284 if (host != std::string("0.0.0.0")) 00285 TLOG(TLVL_WARNING) << "No matches for ip " << host << ", using 0.0.0.0"; 00286 inet_aton("0.0.0.0", &addr); 00287 sts = 2; 00288 } 00289 00290 freeifaddrs(ifaddr); 00291 } 00292 else 00293 { 00294 hostent_sp = gethostbyname(host.c_str()); 00295 if (!hostent_sp) 00296 { 00297 perror("gethostbyname"); 00298 return (-1); 00299 } 00300 addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]); 00301 } 00302 return sts; 00303 } 00304 00305 // Return sts, put result in sin 00306 int ResolveHost(char const* host_in, int dflt_port, sockaddr_in& sin) 00307 { 00308 int port; 00309 std::string host; 00310 struct hostent* hostent_sp; 00311 std::cmatch mm; 00312 // Note: the regex expression used by regex_match has an implied ^ and $ 00313 // at the beginning and end respectively. 00314 if (regex_match(host_in, mm, std::regex("([^:]+):(\\d+)"))) 00315 { 00316 host = mm[1].str(); 00317 port = strtoul(mm[2].str().c_str(), NULL, 0); 00318 } 00319 else if (regex_match(host_in, mm, std::regex(":{0,1}(\\d+)"))) 00320 { 00321 host = std::string("127.0.0.1"); 00322 port = strtoul(mm[1].str().c_str(), NULL, 0); 00323 } 00324 else if (regex_match(host_in, mm, std::regex("([^:]+):{0,1}"))) 00325 { 00326 host = mm[1].str().c_str(); 00327 port = dflt_port; 00328 } 00329 else 00330 { 00331 host = std::string("127.0.0.1"); 00332 port = dflt_port; 00333 } 00334 TLOG(TLVL_INFO) << "Resolving host " << host << ", on port " << port; 00335 00336 if (host == "localhost") host = "127.0.0.1"; 00337 00338 bzero((char *)&sin, sizeof(sin)); 00339 sin.sin_family = AF_INET; 00340 sin.sin_port = htons(port); // just a guess at an open port 00341 00342 if (regex_match(host.c_str(), mm, std::regex("\\d+(\\.\\d+){3}"))) 00343 inet_aton(host.c_str(), &sin.sin_addr); 00344 else 00345 { 00346 hostent_sp = gethostbyname(host.c_str()); 00347 if (!hostent_sp) 00348 { 00349 perror("gethostbyname"); 00350 return (-1); 00351 } 00352 sin.sin_addr = *(struct in_addr *)(hostent_sp->h_addr_list[0]); 00353 } 00354 return 0; 00355 } 00356 // return connection fd. 00357 // 00358 int TCPConnect(char const* host_in 00359 , int dflt_port 00360 , long flags 00361 , int sndbufsiz) 00362 { 00363 int s_fd, sts; 00364 struct sockaddr_in sin; 00365 00366 00367 s_fd = socket(PF_INET, SOCK_STREAM/*|SOCK_NONBLOCK*/, 0); // man socket,man TCP(7P) 00368 00369 if (s_fd == -1) 00370 { 00371 perror("socket error"); 00372 return (-1); 00373 } 00374 00375 sts = ResolveHost(host_in, dflt_port, sin); 00376 if (sts == -1) 00377 { 00378 close(s_fd); 00379 return -1; 00380 } 00381 00382 sts = connect(s_fd, (struct sockaddr *)&sin, sizeof(sin)); 00383 if (sts == -1) 00384 { 00385 //perror( "connect error" ); 00386 close(s_fd); 00387 return (-1); 00388 } 00389 00390 if (flags) 00391 { 00392 sts = fcntl(s_fd, F_SETFL, flags); 00393 TLOG(TLVL_TRACE) << "TCPConnect fcntl(fd=" << s_fd << ",flags=0x" << std::hex << flags << std::dec << ") =" << sts; 00394 } 00395 00396 if (sndbufsiz > 0) 00397 { 00398 int len; 00399 socklen_t lenlen = sizeof(len); 00400 len = 0; 00401 sts = getsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, &lenlen); 00402 TLOG(TLVL_DEBUG) << "TCPConnect SNDBUF initial: " << len << " sts/errno=" << sts << "/" << errno << " lenlen=" << lenlen; 00403 len = sndbufsiz; 00404 sts = setsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, lenlen); 00405 if (sts == -1) 00406 TLOG(TLVL_ERROR) << "Error with setsockopt SNDBUF " << errno; 00407 len = 0; 00408 sts = getsockopt(s_fd, SOL_SOCKET, SO_SNDBUF, &len, &lenlen); 00409 if (len < (sndbufsiz * 2)) 00410 TLOG(TLVL_WARNING) << "SNDBUF " << len << " not expected (" << sndbufsiz << " sts/errno=" << sts << "/" << errno << ")"; 00411 else 00412 TLOG(TLVL_DEBUG) << "SNDBUF " << len << " sts/errno=" << sts << "/" << errno; 00413 } 00414 return (s_fd); 00415 }