1 /******************************************************************************* 2 * Copyright (C) 2004-2008 Intel Corp. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 10 * - Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * - Neither the name of Intel Corp. nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 *******************************************************************************/ 30 31 #ifdef HAVE_CONFIG_H 32 #include "config.h" 33 #endif 34 35 #include "ATNetworkTool.h" 36 #include <sstream> 37 #include <algorithm> 38 #include <cerrno> 39 #include <net/if.h> 40 #include <netdb.h> 41 42 #ifdef __sun 43 #include <arpa/inet.h> 44 #include <sys/sockio.h> 45 #include <stdio.h> 46 #include <stropts.h> 47 #else 48 #include <ifaddrs.h> 49 #endif // __sun 50 51 #include <unistd.h> 52 #include <fcntl.h> 53 54 bool ATNetworkTool::GetHostNameDomain(const char *name, std::string &domain) 55 { 56 const char *domp = strchr(name, '.'); 57 if (domp) { 58 domp++; 59 if (*domp) { 60 #ifdef LMS_NET_DEBUG 61 printf("D: %s\n", domp); 62 #endif 63 domain = domp; 64 return true; 65 } 66 } 67 return false; 68 } 69 70 bool ATNetworkTool::GetHentDomain(struct hostent *hent, std::string &domain) 71 { 72 if (NULL == hent) { 73 return false; 74 } 75 if (NULL == hent->h_name) { 76 return false; 77 } 78 79 #ifdef LMS_NET_DEBUG 80 printf("N: %s\n", hent->h_name); 81 #endif 82 if (ATNetworkTool::GetHostNameDomain(hent->h_name, domain)) { 83 return true; 84 } 85 86 if (NULL != hent->h_aliases) { 87 for (char **ssx = hent->h_aliases; ssx && *ssx; ssx++) { 88 #ifdef LMS_NET_DEBUG 89 printf("A: %s\n", *ssx); 90 #endif 91 if (ATNetworkTool::GetHostNameDomain(*ssx, domain)) { 92 return true; 93 } 94 } 95 } 96 return false; 97 } 98 99 bool ATNetworkTool::GetIPDomain(const ATAddress &ip, std::string &domain, int &error) 100 { 101 char hbuf[NI_MAXHOST]; 102 103 if (0 != (error = getnameinfo(ip.addr(), ip.size(), 104 hbuf, sizeof(hbuf), 105 NULL, 0, 106 NI_NAMEREQD))) { 107 return false; 108 } 109 110 return ATNetworkTool::GetHostNameDomain(hbuf, domain); 111 } 112 113 int ATNetworkTool::GetLocalIPs(ATAddressList &addresses, int &error, int family, bool withloopback) 114 { 115 struct ifaddrs *ifap; 116 117 #ifdef __sun 118 119 char buf[1024]; 120 struct ifconf ifc; 121 struct ifreq *ifr; 122 int sock; 123 int nInterfaces; 124 int i; 125 126 addresses.clear(); 127 128 sock = socket(AF_INET, SOCK_DGRAM, 0); 129 if(sock < 0) 130 { 131 perror("socket"); 132 return 1; 133 } 134 135 /* Query available interfaces. */ 136 ifc.ifc_len = sizeof(buf); 137 ifc.ifc_buf = buf; 138 if(ioctl(sock, SIOCGIFCONF, &ifc) < 0) 139 { 140 perror("ioctl(SIOCGIFCONF)"); 141 close(sock); 142 return 1; 143 } 144 145 /* Iterate through the list of interfaces. */ 146 ifr = ifc.ifc_req; 147 nInterfaces = ifc.ifc_len / sizeof(struct ifreq); 148 for(i = 0; i < nInterfaces; i++) 149 { 150 struct ifreq *item = &ifr[i]; 151 152 if (item->ifr_flags & IFF_LOOPBACK) 153 continue; 154 155 addresses.insert(&item->ifr_addr); 156 } 157 158 close(sock); 159 160 #else // ! __sun 161 162 if (0 != getifaddrs(&ifap)) { 163 error = errno; 164 return -1; 165 } 166 167 addresses.clear(); 168 for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) { 169 if (NULL == ifa->ifa_addr) { 170 continue; 171 } 172 if ((ifa->ifa_flags & IFF_UP) == 0) { 173 continue; 174 } 175 if ((!withloopback) && 176 (((ifa->ifa_flags & IFF_LOOPBACK) != 0) || 177 ((ifa->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) == 0))) { 178 continue; 179 } 180 181 if (AF_UNSPEC != family) { 182 if (ATNetworkTool::AF_XINETX == family) { 183 if (!ATAddress::saIsInet(ifa->ifa_addr)) { 184 continue; 185 } 186 } else { 187 if (ifa->ifa_addr->sa_family != family) { 188 continue; 189 } 190 } 191 } 192 193 addresses.insert(ifa->ifa_addr); 194 } 195 freeifaddrs(ifap); 196 197 #endif // __sun 198 199 return 0; 200 } 201 202 int ATNetworkTool::GetLocalNetDomains(ATDomainMap &domains, int &error, int family) 203 { 204 int ret; 205 ATAddressList addresses; 206 207 if (0 != (ret = ATNetworkTool::GetLocalIPs(addresses, error, family))) { 208 return ret; 209 } 210 211 domains.clear(); 212 ATAddressList::iterator aend = addresses.end(); 213 for (ATAddressList::iterator ait = addresses.begin(); 214 ait != aend; 215 ait++) 216 { 217 std::string domain; 218 if (ATNetworkTool::GetIPDomain(*ait, domain, error)) { 219 domains[*ait] = domain; 220 } 221 } 222 return 0; 223 } 224 225 int ATNetworkTool::GetSockDomain(int sock, std::string &domain, int &error) 226 { 227 struct sockaddr_storage ss; 228 socklen_t salen = sizeof(ss); 229 struct sockaddr *sa; 230 231 sa = (struct sockaddr *)&ss; 232 233 if (getsockname(sock, sa, &salen) != 0) { 234 error = errno; 235 return -1; 236 } 237 238 if (ATNetworkTool::GetIPDomain(sa, domain, error)) { 239 return 1; 240 } 241 return 0; 242 } 243 244 int ATNetworkTool::GetSockPeerIPs(int sock, ATAddressList &addresses, int &error, 245 int family, bool zeroport) 246 { 247 struct sockaddr_storage ss; 248 socklen_t salen = sizeof(ss); 249 struct sockaddr *sa; 250 struct addrinfo hints, *paddr, *paddrp; 251 252 sa = (struct sockaddr *)&ss; 253 254 if (getpeername(sock, sa, &salen) != 0) { 255 error = errno; 256 return -1; 257 } 258 259 char hbuf[NI_MAXHOST]; 260 char pbuf[NI_MAXSERV]; 261 if (0 != (error = getnameinfo(sa, salen, 262 hbuf, sizeof(hbuf), 263 pbuf, sizeof(pbuf), 264 0))) { 265 return -1; 266 } 267 268 memset(&hints, 0, sizeof(hints)); 269 if (ATNetworkTool::AF_XINETX == family) { 270 hints.ai_family = PF_UNSPEC; 271 } else { 272 hints.ai_family = family; 273 } 274 hints.ai_socktype = SOCK_STREAM; 275 if (0 != (error = getaddrinfo(hbuf, pbuf, &hints, &paddrp))) { 276 return -1; 277 } 278 addresses.clear(); 279 for (paddr = paddrp; paddr; paddr = paddr->ai_next) { 280 if (ATNetworkTool::AF_XINETX == family) { 281 if (!ATAddress::saIsInet(paddr->ai_addr)) { 282 continue; 283 } 284 } 285 if (zeroport) { 286 addresses.insert(ATAddress(paddr->ai_addr, 0)); 287 } else { 288 addresses.insert(paddr->ai_addr); 289 } 290 } 291 freeaddrinfo(paddrp); 292 return 0; 293 } 294 295 int ATNetworkTool::IsSockPeerLocal(int sock, int &error, int family) 296 { 297 ATAddressList localAddresses; 298 ATAddressList targAddresses; 299 300 if (0 != ATNetworkTool::GetSockPeerIPs(sock, targAddresses, error, 301 family, true)) { 302 return -1; 303 } 304 if (0 != ATNetworkTool::GetLocalIPs(localAddresses, error, 305 family, true)) { 306 return -1; 307 } 308 if (std::includes(localAddresses.begin(), localAddresses.end(), 309 targAddresses.begin(), targAddresses.end())) { 310 return 1; 311 } 312 return 0; 313 } 314 315 int ATNetworkTool::CloseSocket(int s) 316 { 317 shutdown(s, SHUT_RDWR); 318 return close(s); 319 } 320 321 int ATNetworkTool::CreateSocket(const struct addrinfo *addr, int &error) 322 { 323 return ATNetworkTool::CreateSocket(addr->ai_addr, addr->ai_addrlen, 324 error, 325 addr->ai_family, addr->ai_socktype, 326 addr->ai_protocol); 327 } 328 329 int ATNetworkTool::CreateSocket(const struct sockaddr *addr, socklen_t addrlen, 330 int &error, 331 int family, int socktype, int protocol) 332 { 333 int s = socket(family, socktype, protocol); 334 if (s < 0) { 335 error = errno; 336 return -1; 337 } 338 339 if (socktype != SOCK_DGRAM) { 340 linger l; 341 l.l_onoff = 0; 342 l.l_linger = 0; 343 if (setsockopt(s, SOL_SOCKET, SO_LINGER, 344 (char *)&l, sizeof(l)) == -1) { 345 error = errno; 346 close(s); 347 return -1; 348 } 349 } 350 351 if (bind(s, addr, addrlen) == -1) { 352 error = errno; 353 close(s); 354 return -1; 355 } 356 357 return s; 358 } 359 360 int ATNetworkTool::ConnectSocket(struct addrinfo *addr, 361 int &error, bool loopback) 362 { 363 return ATNetworkTool::ConnectSocket(addr->ai_addr, addr->ai_addrlen, 364 error, loopback, 365 addr->ai_family, addr->ai_socktype, 366 addr->ai_protocol); 367 } 368 369 int ATNetworkTool::ConnectSocket(const struct sockaddr *addr, socklen_t addrlen, 370 int &error, bool loopback, 371 int family, int socktype, int protocol) 372 { 373 struct addrinfo hints, *paddr, *paddrp; 374 int oks = -1; 375 376 memset(&hints, 0, sizeof(hints)); 377 if (ATNetworkTool::AF_XINETX == family) { 378 hints.ai_family = PF_UNSPEC; 379 } else { 380 hints.ai_family = family; 381 } 382 hints.ai_socktype = socktype; 383 hints.ai_protocol = protocol; 384 #ifdef AI_NUMERICSERV 385 hints.ai_flags |= AI_NUMERICSERV; 386 #endif 387 if (!loopback) { 388 hints.ai_flags |= AI_PASSIVE; 389 } 390 if ((error = getaddrinfo(NULL, "0", &hints, &paddrp)) != 0) { 391 return -1; 392 } 393 for (paddr = paddrp; paddr; paddr = paddr->ai_next) { 394 if (ATNetworkTool::AF_XINETX == family) { 395 if (!ATAddress::saIsInet(paddr->ai_addr)) { 396 continue; 397 } 398 } 399 400 int s = ATNetworkTool::CreateSocket(paddr, error); 401 if (s < 0) { 402 continue; 403 } 404 405 if (connect(s, addr, addrlen) != 0) { 406 error = errno; 407 ATNetworkTool::CloseSocket(s); 408 continue; 409 } 410 411 oks = s; 412 break; 413 } 414 freeaddrinfo(paddrp); 415 return oks; 416 } 417 418 int ATNetworkTool::CreateServerSocket(in_port_t port, 419 int &error, 420 bool loopback, bool nonblocking, 421 int family, int socktype, int protocol, 422 int backlog) 423 { 424 std::stringstream ssport; 425 426 ssport << port; 427 return ATNetworkTool::CreateServerSocket(ssport.str().c_str(), 428 error, 429 loopback, nonblocking, 430 family, socktype, protocol, 431 backlog); 432 } 433 434 int ATNetworkTool::CreateServerSocket(const char *port, 435 int &error, 436 bool loopback, bool nonblocking, 437 int family, int socktype, int protocol, 438 int backlog) 439 { 440 ATSocketList sockets; 441 int s = -1; 442 443 int num = ATNetworkTool::CreateServerSockets(sockets, port, 444 error, 445 loopback, nonblocking, 446 family, socktype, protocol, 447 backlog, true); 448 if ((num > 0) && (sockets.size() > 0)) { 449 s = sockets[0]; 450 } 451 sockets.clear(); 452 return s; 453 } 454 455 456 int ATNetworkTool::CreateServerSockets(ATSocketList &sockets, in_port_t port, 457 int &error, 458 bool loopback, bool nonblocking, 459 int family, int socktype, int protocol, 460 int backlog, bool one) 461 { 462 std::stringstream ssport; 463 464 ssport << port; 465 return ATNetworkTool::CreateServerSockets(sockets, ssport.str().c_str(), 466 error, 467 loopback, nonblocking, 468 family, socktype, protocol, 469 backlog, one); 470 } 471 472 int ATNetworkTool::CreateServerSockets(ATSocketList &sockets, const char *port, 473 int &error, 474 bool loopback, bool nonblocking, 475 int family, int socktype, int protocol, 476 int backlog, bool one) 477 { 478 struct addrinfo hints, *paddr, *paddrp; 479 int num = 0; 480 481 memset(&hints, 0, sizeof(hints)); 482 if (ATNetworkTool::AF_XINETX == family) { 483 hints.ai_family = PF_UNSPEC; 484 } else { 485 hints.ai_family = family; 486 } 487 hints.ai_socktype = socktype; 488 hints.ai_protocol = protocol; 489 #ifdef AI_NUMERICSERV 490 hints.ai_flags |= AI_NUMERICSERV; 491 #endif 492 if (!loopback) { 493 hints.ai_flags |= AI_PASSIVE; 494 } 495 if ((error = getaddrinfo(NULL, port, &hints, &paddrp)) != 0) { 496 return -1; 497 } 498 for (paddr = paddrp; paddr; paddr = paddr->ai_next) { 499 if (ATNetworkTool::AF_XINETX == family) { 500 if (!ATAddress::saIsInet(paddr->ai_addr)) { 501 continue; 502 } 503 } 504 505 int s = ATNetworkTool::CreateServerSocket(paddr, error, 506 nonblocking, 507 backlog); 508 if (s < 0) { 509 continue; 510 } 511 sockets.push_back(s); 512 num++; 513 if (one) { 514 break; 515 } 516 } 517 freeaddrinfo(paddrp); 518 return num; 519 } 520 521 int ATNetworkTool::CreateServerSocket(const struct addrinfo *addr, int &error, 522 bool nonblocking, int backlog) 523 { 524 int s = ATNetworkTool::CreateSocket(addr, error); 525 if (s < 0) { 526 return -1; 527 } 528 529 if (nonblocking) { 530 ATNetworkTool::SetNonBlocking(s); 531 } 532 533 if (listen(s, backlog) == -1) { 534 error = errno; 535 ATNetworkTool::CloseSocket(s); 536 return -1; 537 } 538 539 return s; 540 } 541 542 int ATNetworkTool::SetNonBlocking(int s, bool block) 543 { 544 if (block) { 545 return fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK); 546 } else { 547 return fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK); 548 } 549 } 550 551 int ATNetworkTool::ConnectToSocket(int sock, int &error, bool loopback, 552 int socktype, int protocol) 553 { 554 struct sockaddr_storage ss; 555 socklen_t addrLen = sizeof(ss); 556 struct sockaddr *sa = (struct sockaddr *)&ss; 557 558 if (getsockname(sock, sa, &addrLen) != 0) { 559 error = errno; 560 return -1; 561 } 562 int s = ATNetworkTool::ConnectSocket(sa, addrLen, 563 error, loopback, 564 sa->sa_family, 565 socktype, protocol); 566 if (s < 0) { 567 return -1; 568 } 569 return s; 570 } 571 572 int ATNetworkTool::Connect(const char *host, in_port_t port, 573 int &error, 574 int family, int socktype, int protocol) 575 { 576 std::stringstream ssport; 577 578 ssport << port; 579 580 return ATNetworkTool::Connect(host, ssport.str().c_str(), error, 581 family, socktype, protocol); 582 } 583 584 int ATNetworkTool::Connect(const char *host, const char *port, 585 int &error, 586 int family, int socktype, int protocol) 587 { 588 struct addrinfo hints, *paddr, *paddrp; 589 int oks = -1; 590 591 if (socktype != SOCK_DGRAM) { 592 socktype = SOCK_STREAM; 593 } 594 595 memset(&hints, 0, sizeof(hints)); 596 if (ATNetworkTool::AF_XINETX == family) { 597 hints.ai_family = PF_UNSPEC; 598 } else { 599 hints.ai_family = family; 600 } 601 hints.ai_socktype = socktype; 602 hints.ai_protocol = protocol; 603 hints.ai_flags = AI_NUMERICHOST; 604 #ifdef AI_NUMERICSERV 605 hints.ai_flags |= AI_NUMERICSERV; 606 #endif 607 if ((error = getaddrinfo(host, port, &hints, &paddrp)) != 0) { 608 memset(&hints, 0, sizeof(hints)); 609 if (ATNetworkTool::AF_XINETX == family) { 610 hints.ai_family = PF_UNSPEC; 611 } else { 612 hints.ai_family = family; 613 } 614 hints.ai_socktype = socktype; 615 hints.ai_protocol = protocol; 616 #ifdef AI_NUMERICSERV 617 hints.ai_flags |= AI_NUMERICSERV; 618 #endif 619 if ((error = getaddrinfo(host, port, &hints, &paddrp)) != 0) { 620 return -1; 621 } 622 } 623 for (paddr = paddrp; paddr; paddr = paddr->ai_next) { 624 if (ATNetworkTool::AF_XINETX == family) { 625 if (!ATAddress::saIsInet(paddr->ai_addr)) { 626 continue; 627 } 628 } 629 630 int s = ATNetworkTool::ConnectSocket(paddr, error); 631 if (s < 0) { 632 continue; 633 } 634 oks = s; 635 break; 636 } 637 freeaddrinfo(paddrp); 638 return oks; 639 } 640 641 int ATNetworkTool::ConnectLoopback(in_port_t port, 642 int &error, 643 int family, int socktype, int protocol) 644 { 645 std::stringstream ssport; 646 647 ssport << port; 648 649 return ATNetworkTool::ConnectLoopback(ssport.str().c_str(), error, 650 family, socktype, protocol); 651 } 652 653 int ATNetworkTool::ConnectLoopback(const char *port, 654 int &error, 655 int family, int socktype, int protocol) 656 { 657 struct addrinfo hints, *paddr, *paddrp; 658 int oks = -1; 659 660 if (socktype != SOCK_DGRAM) { 661 socktype = SOCK_STREAM; 662 } 663 664 memset(&hints, 0, sizeof(hints)); 665 if (ATNetworkTool::AF_XINETX == family) { 666 hints.ai_family = PF_UNSPEC; 667 } else { 668 hints.ai_family = family; 669 } 670 hints.ai_socktype = socktype; 671 hints.ai_protocol = protocol; 672 #ifdef AI_NUMERICSERV 673 hints.ai_flags |= AI_NUMERICSERV; 674 #endif 675 if ((error = getaddrinfo(NULL, port, &hints, &paddrp)) != 0) { 676 return -1; 677 } 678 for (paddr = paddrp; paddr; paddr = paddr->ai_next) { 679 if (ATNetworkTool::AF_XINETX == family) { 680 if (!ATAddress::saIsInet(paddr->ai_addr)) { 681 continue; 682 } 683 } 684 685 int s = ATNetworkTool::ConnectSocket(paddr, error, true); 686 if (s < 0) { 687 continue; 688 } 689 oks = s; 690 break; 691 } 692 freeaddrinfo(paddrp); 693 return oks; 694 } 695 696 unsigned int ATNetworkTool::GetLocalPort(int sock) 697 { 698 struct sockaddr_storage ss; 699 socklen_t addrLen = sizeof(ss); 700 struct sockaddr *sa = (struct sockaddr *)&ss; 701 702 if (getsockname(sock, sa, &addrLen) != 0) { 703 return 0; 704 } 705 switch (sa->sa_family) { 706 case AF_INET6: 707 return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); 708 break; 709 case AF_INET: 710 return ntohs(((struct sockaddr_in *)sa)->sin_port); 711 break; 712 } 713 return 0; 714 } 715 716 int ATNetworkTool::Accept(int s, ATAddress &address, 717 int &error, bool nonblocking) 718 { 719 struct sockaddr_storage saddr; 720 socklen_t addrLen = sizeof(saddr); 721 struct sockaddr *addr = (struct sockaddr *)&saddr; 722 723 int s_new = accept(s, addr, &addrLen); 724 if (s_new == -1) { 725 error = errno; 726 return -1; 727 } 728 729 address = addr; 730 731 ATNetworkTool::SetNonBlocking(s_new, nonblocking); 732 733 return s_new; 734 } 735 736