📄 socketutils.cpp
字号:
/* File: SocketUtils.cpp Contains: Implements utility functions defined in SocketUtils.h */#include "SocketUtils.h"
#include <string.h>#ifndef __Win32__#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <sys/ioctl.h>#include <unistd.h>#include <sys/utsname.h>#endifusing namespace std;#ifdef SIOCGIFNUM#define USE_SIOCGIFNUM 1#endifUInt32 SocketUtils::sNumIPAddrs = 0;SocketUtils::IPAddrInfo* SocketUtils::sIPAddrInfoArray = NULL;//Version for all non-FreeBSD platforms.void SocketUtils::Initialize(Bool lookupDNSName){ return; //Armer 需要比较长的时间,既然暂时没有用到,故屏蔽#if defined(__Win32__) int tempSocket = ::socket(AF_INET, SOCK_DGRAM, 0); if (tempSocket == -1) return;#ifdef __Win32__ static const UInt32 kMaxAddrBufferSize = 20480; //modify by puzy 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, NULL, NULL); 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 //get the number of network addresses#if defined(USE_SIOCGIFNUM) if (::ioctl(tempSocket, SIOCGIFNUM, (char*)&sNumIPAddrs) == -1) { sNumIPAddrs = 64; }#else #error //error warnning#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 != NULL); ::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); /* 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 } 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 = NULL; 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 != NULL) { 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 = 20480; //modify by puzy 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__ int err = ::ioctl(tempSocket, SIOCGIFCONF, (char*)&ifc);#else #error#endif if (err == -1) return; ::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 = NULL; 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++; } //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; 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 = NULL; 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 != NULL) { 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; }}
void SocketUtils::Uninitialize()
{
// delete IPAddress array
for (UInt32 i = 0 ; i< sNumIPAddrs; i++)
{
if(sIPAddrInfoArray[i].fIPAddrStr.Len != 0)
delete[] sIPAddrInfoArray[i].fIPAddrStr.Ptr;
if(sIPAddrInfoArray[i].fDNSNameStr.Len != 0)
delete[] sIPAddrInfoArray[i].fDNSNameStr.Ptr;
}
// since sIPAddrInfoArray is allocated by UInt8 array
// so delete as UInt8 array
delete[] (UInt8 *)sIPAddrInfoArray;
}
#ifndef __Win32__Bool SocketUtils::IncrementIfReqIter(char** inIfReqIter, ifreq* ifr){ //returns true if successful, false otherwise *inIfReqIter += sizeof(ifr->ifr_name) + 0; { switch (ifr->ifr_addr.sa_family) { case AF_INET: *inIfReqIter += sizeof(struct sockaddr_in); break; default: *inIfReqIter += sizeof(struct sockaddr);// Assert(0);// sNumIPAddrs = 0;// return false; } } return true;}#endifBool SocketUtils::IsMulticastIPAddr(UInt32 inAddress){ return ((inAddress>>8) & 0x00f00000) == 0x00e00000; // multicast addresses == "class D" == 0xExxxxxxx == 1,1,1,0,<28 bits>}Bool SocketUtils::IsLocalIPAddr(UInt32 inAddress){ for (UInt32 x = 0; x < sNumIPAddrs; x++) if (sIPAddrInfoArray[x].fIPAddr == inAddress) return true; return false;}void SocketUtils::ConvertAddrToString(const struct in_addr& theAddr, string* ioStr){ *ioStr= inet_ntoa(theAddr);}UInt32 SocketUtils::ConvertStringToAddr(const char* inAddrStr){ return ntohl(::inet_addr(inAddrStr));}Bool SocketUtils::GetPeerInfo( Int32 vFD, std::string & vIP, UInt16 & vPort ){ struct sockaddr_in fRemoteAddr;#if __Win32__ int len = sizeof(fRemoteAddr);#else socklen_t len = sizeof(fRemoteAddr);#endif len=sizeof(fRemoteAddr); int err=::getpeername(vFD,(struct sockaddr*)&fRemoteAddr,&len); if(err != 0) return FALSE; vIP = inet_ntoa(fRemoteAddr.sin_addr); vPort = ntohs(fRemoteAddr.sin_port); return TRUE;}
//域名解析
UInt32 SocketUtils::HostNameToIP(const std::string& strHostName){
long lHostIp = 0;
struct hostent *psHost = NULL;
struct sockaddr_in saddr;
lHostIp = 0;
psHost = NULL;
memset(&saddr, 0, sizeof(struct sockaddr_in));
if ( ( lHostIp = inet_addr(strHostName.c_str()) ) != INADDR_NONE )
{
saddr.sin_addr.s_addr = lHostIp;
}
else if ( psHost = gethostbyname(strHostName.c_str()) )
{
memcpy(&saddr.sin_addr, psHost->h_addr, psHost->h_length);
}
else
{
printf("Failed getting Up server's IP with DNS");
}
return ntohl(saddr.sin_addr.s_addr);
}
std::string SocketUtils::HostNameToStringIP(const std::string& strHostName)
{
UInt32 nIP = HostNameToIP(strHostName);
return IPAddrToString(nIP);
}
std::string SocketUtils::IPAddrToString(unsigned long nIpAddr)
{
in_addr tmpAdd;
tmpAdd.s_addr = htonl(nIpAddr);
return inet_ntoa(tmpAdd);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -