static isc_result_t internal_next(isc_interfaceiter_t *iter) { #ifdef HAVE_TRUCLUSTER int clua_result; #endif #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) if (iter->mode == 6) { iter->result6 = internal_next6(iter); if (iter->result6 != ISC_R_NOMORE) return (iter->result6); if (iter->first6) { iter->first6 = ISC_FALSE; return (ISC_R_SUCCESS); } } #endif #ifdef HAVE_TRUCLUSTER if (!iter->clua_done) { clua_result = clua_getaliasaddress(&iter->clua_sa, &iter->clua_context); if (clua_result != CLUA_SUCCESS) iter->clua_done = ISC_TRUE; return (ISC_R_SUCCESS); } #endif return (internal_next4(iter)); }
static void internal_first(isc_interfaceiter_t *iter) { #ifdef HAVE_TRUCLUSTER int clua_result; #endif iter->pos = 0; #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) iter->pos6 = 0; if (iter->result6 == ISC_R_NOMORE) iter->result6 = ISC_R_SUCCESS; iter->first6 = ISC_TRUE; #endif #ifdef HAVE_TRUCLUSTER iter->clua_context = 0; clua_result = clua_getaliasaddress(&iter->clua_sa, &iter->clua_context); iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS); #endif #ifdef __linux linux_if_inet6_first(iter); #endif }
void SocketUtils::Initialize(bool lookupDNSName) { #if defined(__Win32__) || defined(USE_SIOCGIFNUM) int tempSocket = ::socket(AF_INET, SOCK_DGRAM, 0); if (tempSocket == -1) return; #ifdef __Win32__ static const UInt32 kMaxAddrBufferSize = 2048; char inBuffer[kMaxAddrBufferSize]; char outBuffer[kMaxAddrBufferSize]; UInt32 theReturnedSize = 0; // // Use the WSAIoctl function call to get a list of IP addresses int theErr = ::WSAIoctl(tempSocket, SIO_GET_INTERFACE_LIST, inBuffer, kMaxAddrBufferSize, outBuffer, kMaxAddrBufferSize, &theReturnedSize, nullptr, nullptr); Assert(theErr == 0); if (theErr != 0) return; Assert((theReturnedSize % sizeof(INTERFACE_INFO)) == 0); LPINTERFACE_INFO addrListP = (LPINTERFACE_INFO)&outBuffer[0]; sNumIPAddrs = theReturnedSize / sizeof(INTERFACE_INFO); #else #if defined(USE_SIOCGIFNUM) if (::ioctl(tempSocket, SIOCGIFNUM, (char*)&sNumIPAddrs) == -1) { #ifdef MAXIFS sNumIPAddrs = MAXIFS; #else sNumIPAddrs = 64; #endif } #else #error #endif struct ifconf ifc; ::memset(&ifc, 0, sizeof(ifc)); ifc.ifc_len = sNumIPAddrs * sizeof(struct ifreq); ifc.ifc_buf = (caddr_t)new struct ifreq[sNumIPAddrs]; Assert(ifc.ifc_buf != nullptr); ::memset(ifc.ifc_buf, '\0', ifc.ifc_len); int theErr = ::ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc); Assert(theErr == 0); if (theErr != 0) return; struct ifreq* ifr = (struct ifreq*)ifc.ifc_buf; #endif //allocate the IPAddrInfo array. Unfortunately we can't allocate this //array the proper way due to a GCC bug UInt8* addrInfoMem = new UInt8[sizeof(IPAddrInfo) * sNumIPAddrs]; ::memset(addrInfoMem, 0, sizeof(IPAddrInfo) * sNumIPAddrs); sIPAddrInfoArray = (IPAddrInfo*)addrInfoMem; //for (UInt32 addrCount = 0; addrCount < sNumIPAddrs; addrCount++) UInt32 currentIndex = 0; for (UInt32 theIfCount = sNumIPAddrs, addrCount = 0; addrCount < theIfCount; addrCount++) { #ifdef __Win32__ // We *should* count the loopback interface as a valid interface. //if (addrListP[addrCount].iiFlags & IFF_LOOPBACK) //{ // Don't count loopback addrs // sNumIPAddrs--; // continue; //} //if (addrListP[addrCount].iiFlags & IFF_LOOPBACK) // if (lookupDNSName) // The playlist broadcaster doesn't care // Assert(addrCount > 0); // If the loopback interface is interface 0, we've got problems struct sockaddr_in* theAddr = (struct sockaddr_in*)&addrListP[addrCount].iiAddress; #elif defined(USE_SIOCGIFNUM) if (ifr[addrCount].ifr_addr.sa_family != AF_INET) { sNumIPAddrs--; continue; } struct ifreq ifrf; ::memset(&ifrf, 0, sizeof(ifrf)); ::strncpy(ifrf.ifr_name, ifr[addrCount].ifr_name, sizeof(ifrf.ifr_name)); theErr = ::ioctl(tempSocket, SIOCGIFFLAGS, (char *)&ifrf); Assert(theErr != -1); #ifndef __solaris__ /* Skip things which aren't interesting */ if ((ifrf.ifr_flags & IFF_UP) == 0 || (ifrf.ifr_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) == 0) { sNumIPAddrs--; continue; } if (ifrf.ifr_flags & IFF_LOOPBACK) { Assert(addrCount > 0); // If the loopback interface is interface 0, we've got problems } #endif struct sockaddr_in* theAddr = (struct sockaddr_in*)&ifr[addrCount].ifr_addr; #if 0 puts(ifr[addrCount].ifr_name); #endif #else #error #endif char* theAddrStr = ::inet_ntoa(theAddr->sin_addr); //store the IP addr sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(theAddr->sin_addr.s_addr); //store the IP addr as a string sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr); sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAddrStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr); struct hostent* theDNSName = nullptr; if (lookupDNSName) //convert this addr to a dns name, and store it { theDNSName = ::gethostbyaddr((char *)&theAddr->sin_addr, sizeof(theAddr->sin_addr), AF_INET); } if (theDNSName != nullptr) { sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name); sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name); } else { //if we failed to look up the DNS name, just store the IP addr as a string sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAddrStr.Len; sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr); } //move onto the next array index currentIndex++; } #ifdef __Win32__ ::closesocket(tempSocket); #elif defined(USE_SIOCGIFNUM) delete[] ifc.ifc_buf; close(tempSocket); #else #error #endif #else // !__Win32__ //Most of this code is similar to the SIOCGIFCONF code presented in Stevens, //Unix Network Programming, section 16.6 //Use the SIOCGIFCONF ioctl call to iterate through the network interfaces static const UInt32 kMaxAddrBufferSize = 2048; struct ifconf ifc; ::memset(&ifc, 0, sizeof(ifc)); struct ifreq* ifr; char buffer[kMaxAddrBufferSize]; int tempSocket = ::socket(AF_INET, SOCK_DGRAM, 0); if (tempSocket == -1) return; ifc.ifc_len = kMaxAddrBufferSize; ifc.ifc_buf = buffer; #if __linux__ || __linuxppc__ || __solaris__ || __MacOSX__ || __sgi__ || __osf__ int err = ::ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc); #elif __FreeBSD__ int err = ::ioctl(tempSocket, OSIOCGIFCONF, (char*)&ifc); #else #error #endif if (err == -1) return; #if __FreeBSD__ int netdev1, netdev2; struct ifreq *netdevifr; netdevifr = ifc.ifc_req; netdev1 = ifc.ifc_len / sizeof(struct ifreq); for (netdev2 = netdev1 - 1; netdev2 >= 0; netdev2--) { if (ioctl(tempSocket, SIOCGIFADDR, &netdevifr[netdev2]) != 0) continue; } #endif close(tempSocket); tempSocket = -1; //walk through the list of IP addrs twice. Once to find out how many, //the second time to actually grab their information char* ifReqIter = nullptr; sNumIPAddrs = 0; for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);) { ifr = (struct ifreq*)ifReqIter; if (!SocketUtils::IncrementIfReqIter(&ifReqIter, ifr)) return; // Some platforms have lo as the first interface, so we have code to // work around this problem below //if (::strncmp(ifr->ifr_name, "lo", 2) == 0) // Assert(sNumIPAddrs > 0); // If the loopback interface is interface 0, we've got problems //Only count interfaces in the AF_INET family. if (ifr->ifr_addr.sa_family == AF_INET) sNumIPAddrs++; } #ifdef TRUCLUSTER int clusterAliases = 0; if (clu_is_member()) { /* loading the vector table */ if (clua_getaliasaddress_vector == nullptr) { clucall_stat clustat; struct sockaddr_in sin; clustat = clucall_load("libclua.so", clua_vectors); int context = 0; clua_status_t addr_err; if (clua_getaliasaddress_vector != nullptr) while ((addr_err = clua_getaliasaddress ((struct sockaddr*)&sin, &context)) == CLUA_SUCCESS) { sNumIPAddrs++; clusterAliases++; } } } #endif // TRUCLUSTER //allocate the IPAddrInfo array. Unfortunately we can't allocate this //array the proper way due to a GCC bug UInt8* addrInfoMem = new UInt8[sizeof(IPAddrInfo) * sNumIPAddrs]; ::memset(addrInfoMem, 0, sizeof(IPAddrInfo) * sNumIPAddrs); sIPAddrInfoArray = (IPAddrInfo*)addrInfoMem; //Now extract all the necessary information about each interface //and put it into the array UInt32 currentIndex = 0; #ifdef TRUCLUSTER // Do these cluster aliases first so they'll be first in the list if (clusterAliases > 0) { int context = 0; struct sockaddr_in sin; clua_status_t addr_err; while ((addr_err = clua_getaliasaddress((struct sockaddr*)&sin, &context)) == CLUA_SUCCESS) { char* theAddrStr = ::inet_ntoa(sin.sin_addr); //store the IP addr sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(sin.sin_addr.s_addr); //store the IP addr as a string sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr); sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAddrStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr); //convert this addr to a dns name, and store it struct hostent* theDNSName = ::gethostbyaddr((char *)&sin.sin_addr, sizeof(sin.sin_addr), AF_INET); if (theDNSName != nullptr) { sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name); sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name); } else { //if we failed to look up the DNS name, just store the IP addr as a string sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAddrStr.Len; sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr); } currentIndex++; } } #endif // TRUCLUSTER for (ifReqIter = buffer; ifReqIter < (buffer + ifc.ifc_len);) { ifr = (struct ifreq*)ifReqIter; if (!SocketUtils::IncrementIfReqIter(&ifReqIter, ifr)) { Assert(0);//we should have already detected this error return; } //Only count interfaces in the AF_INET family if (ifr->ifr_addr.sa_family == AF_INET) { struct sockaddr_in* addrPtr = (struct sockaddr_in*)&ifr->ifr_addr; char* theAddrStr = ::inet_ntoa(addrPtr->sin_addr); //store the IP addr sIPAddrInfoArray[currentIndex].fIPAddr = ntohl(addrPtr->sin_addr.s_addr); //store the IP addr as a string sIPAddrInfoArray[currentIndex].fIPAddrStr.Len = ::strlen(theAddrStr); sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fIPAddrStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr, theAddrStr); struct hostent* theDNSName = nullptr; if (lookupDNSName) //convert this addr to a dns name, and store it { theDNSName = ::gethostbyaddr((char *)&addrPtr->sin_addr, sizeof(addrPtr->sin_addr), AF_INET); } if (theDNSName != nullptr) { sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = ::strlen(theDNSName->h_name); sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, theDNSName->h_name); } else { //if we failed to look up the DNS name, just store the IP addr as a string sIPAddrInfoArray[currentIndex].fDNSNameStr.Len = sIPAddrInfoArray[currentIndex].fIPAddrStr.Len; sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr = new char[sIPAddrInfoArray[currentIndex].fDNSNameStr.Len + 2]; ::strcpy(sIPAddrInfoArray[currentIndex].fDNSNameStr.Ptr, sIPAddrInfoArray[currentIndex].fIPAddrStr.Ptr); } //move onto the next array index currentIndex++; } } Assert(currentIndex == sNumIPAddrs); #endif // // If LocalHost is the first element in the array, switch it to be the second. // The first element is supposed to be the "default" interface on the machine, // which should really always be en0. if ((sNumIPAddrs > 1) && (::strcmp(sIPAddrInfoArray[0].fIPAddrStr.Ptr, "127.0.0.1") == 0)) { UInt32 tempIP = sIPAddrInfoArray[1].fIPAddr; sIPAddrInfoArray[1].fIPAddr = sIPAddrInfoArray[0].fIPAddr; sIPAddrInfoArray[0].fIPAddr = tempIP; StrPtrLen tempIPStr(sIPAddrInfoArray[1].fIPAddrStr); sIPAddrInfoArray[1].fIPAddrStr = sIPAddrInfoArray[0].fIPAddrStr; sIPAddrInfoArray[0].fIPAddrStr = tempIPStr; StrPtrLen tempDNSStr(sIPAddrInfoArray[1].fDNSNameStr); sIPAddrInfoArray[1].fDNSNameStr = sIPAddrInfoArray[0].fDNSNameStr; sIPAddrInfoArray[0].fDNSNameStr = tempDNSStr; } }