00001
00002
00003
00004
00005
00006
00007
00008 #define TRACE_NAME (app_name + "_TCPConnect").c_str()
00009 #include "artdaq/DAQdata/Globals.hh"
00010
00011 #include <stdio.h>
00012 #include <sys/types.h>
00013 #include <sys/socket.h>
00014 #include <netinet/in.h>
00015 #include <stdlib.h>
00016 #include <unistd.h>
00017 #include <string.h>
00018 #include <sys/socket.h>
00019 #include <netinet/in.h>
00020 #include <arpa/inet.h>
00021 #include <netdb.h>
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
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
00039
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
00092
00093
00094 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
00095 {
00096 if (ifa->ifa_addr == NULL)
00097 continue;
00098
00099
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
00161
00162
00163 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
00164 {
00165 if (ifa->ifa_addr == NULL)
00166 continue;
00167
00168
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
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
00224
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
00258
00259
00260 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
00261 {
00262 if (ifa->ifa_addr == NULL)
00263 continue;
00264
00265
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
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
00313
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);
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
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, 0);
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
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 }