// // Created on: 6/8/21 #include "IP4Address.hpp" #include #include #include #if defined(_WIN32) #define NOMINMAX #include #include #include #include #pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "IPHLPAPI.lib") constexpr auto WORKING_BUFFER_SIZE = 15000; constexpr auto MAX_TRIES = 3; #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #else #include #include #include #include #include #include #endif using namespace std::string_literals ; //================================================================================= // string manipulation, in case strutil is not available. Enables this to be standalone //================================================================================= //================================================================================= auto trim(const std::string &value) ->std::string { auto rvalue = std::string() ; auto startpos = value.find_first_not_of(" \t\r\n\f"); if(startpos!= std::string::npos){ rvalue = value.substr(startpos); auto endpos = rvalue.find_last_not_of(" \t\r\n\f"); if (endpos != std::string::npos) { rvalue = rvalue.substr(0,endpos+1) ; } } return rvalue ; } //================================================================================= auto parse(const std::string &value, const std::string &separator=".") ->std::vector{ auto rvalue = std::vector() ; auto subject = trim(value) ; auto position = subject.find(separator) ; if (position == std::string::npos){ // It coulnd't find the separator rvalue.push_back(subject); } else { while (position != std::string::npos){ auto parsed = trim(subject.substr(0,position)) ; rvalue.push_back(parsed); subject = subject.substr(position+separator.size()) ; position = subject.find(separator); } subject = trim(subject); rvalue.push_back(subject); } return rvalue ; } //================================================================================= auto strip(const std::string &value, const std::string &identifier="//") -> std::string { auto position = value.find(identifier); return value.substr(0,position) ; } //================================================================================= auto split(const std::string &value, const std::string &identifier="=") -> std::pair{ auto position = value.find(identifier); auto pos1 = trim(value.substr(0,position)) ; auto pos2 = trim(value.substr(position+identifier.size())); return std::make_pair(pos1, pos2); } //================================================================================= // ip4addr_t //================================================================================= //================================================================================= const std::vector ip4addr_t::lanips{ ip4addr_t("10.*.*.*"s),ip4addr_t("192.168.*.*"s),ip4addr_t("172.16.*.*"s),ip4addr_t("172.17.*.*"s), ip4addr_t("172.18.*.*"s),ip4addr_t("172.19.*.*"s),ip4addr_t("172.20.*.*"s),ip4addr_t("172.21.*.*"s), ip4addr_t("172.22.*.*"s),ip4addr_t("172.23.*.*"s),ip4addr_t("172.241.*.*"s),ip4addr_t("172.25.*.*"s), ip4addr_t("172.26.*.*"s),ip4addr_t("172.27.*.*"s),ip4addr_t("172.28.*.*"s),ip4addr_t("172.29.*.*"s), ip4addr_t("172.30.*.*"s),ip4addr_t("172.31.*.*"s) } ; //================================================================================= const std::vector ip4addr_t::localips{ ip4addr_t("127.*.*.*") }; //================================================================================= const std::vector ip4addr_t::apipaips{ ip4addr_t("169.254.*.*") }; auto ip4addr_t::exact(const ip4addr_t& value) const ->bool { auto rvalue = true ; for (auto i = 0; i<4;++i) { if (components[i] != value.components[i]){ rvalue = false ; break; } } return rvalue ; } //============================================================== auto ip4addr_t::match(std::uint32_t value, bool bigendian) const ->int { auto ptr = reinterpret_cast(&value) ; if (!bigendian){ std::reverse(ptr, ptr+4); } auto match = 0 ; for (const auto &comp : components){ match += 1 ; if ((comp != "*") && !comp.empty()) { try { if (std::stoi(comp) != *ptr) { match -=1 ; break; } } catch(...) { // the value couldn't be converted match -=1; break; } } } return match ; } //============================================================== auto ip4addr_t::match(const ip4addr_t &value) const ->int { auto rvalue = 0 ; for (auto i = 0 ; i<4 ; ++i){ rvalue = i+1 ; if (!(((value.components[i] == "*") || value.components[i].empty()) || ((components[i] == "*") || components[i].empty()))){ // Neither are wild, we have to match them if ( value.components[i] != components[i]) { rvalue = rvalue -1 ; break; } } } return rvalue ; } //========================================================= ip4addr_t::ip4addr_t(const std::string &value ){ components.fill("*"s); auto values = parse(value) ; switch (value.size()) { default: case 4: components[3] = values[3] ; [[fallthrough]]; case 3: components[2] = values[2] ; [[fallthrough]]; case 2: components[1] = values[1] ; [[fallthrough]]; case 1: components[0] = values[0] ; [[fallthrough]]; case 0: break; } } //========================================================= ip4addr_t::ip4addr_t(std::uint32_t addr,bool bigendian ){ components.fill("*"s); auto ptr = reinterpret_cast(&addr); if (!bigendian) { std::reverse(ptr, ptr+4); } for (auto i=0 ; i<4 ;++i) { components[i] = std::to_string(ptr[i]) ; } } //========================================================= auto ip4addr_t::ipaddr(bool bigendian) const ->std::uint32_t { auto rvalue = std::uint32_t(0) ; auto ptr = reinterpret_cast(&rvalue); for (auto i=0 ; i<4 ; ++i){ auto value = std::uint8_t(0) ; try { value = static_cast(std::stoi(components[i])) ; } catch(...){ throw std::runtime_error("Error converting ip to a number"s); } ptr[i] = value ; } if (!bigendian){ std::reverse(ptr, ptr+4); } return rvalue ; } //========================================================= // This assumes the value is in big endian auto ip4addr_t::operator==(std::uint32_t value) const ->bool { return match(value)==4 ; } //========================================================= auto ip4addr_t::operator==(const ip4addr_t &value) const ->bool { return match(value)==4 ; } //========================================================= auto ip4addr_t::type() const ->ip4type_t { auto rvalue = ip4type_t::wan ; try { auto iter = std::find_if(lanips.begin(),lanips.end(),[this](const ip4addr_t& ip){ return *this == ip ; }); if (iter!= lanips.end()){ rvalue = ip4type_t::lan ; } else{ auto iter = std::find_if(localips.begin(),localips.end(),[this](const ip4addr_t& ip){ return *this == ip ; }); if (iter !=localips.end()){ rvalue = ip4type_t::local ; } else { auto iter = std::find_if(apipaips.begin(),apipaips.end(),[this](const ip4addr_t& ip){ return *this == ip ; }); if (iter !=apipaips.end()){ rvalue = ip4type_t::apipa ; } } } } catch(...) { rvalue = ip4type_t::invalid ; } return rvalue ; } //========================================================= auto ip4addr_t::description() const ->std::string { auto ip = std::string() ; for (auto &value : components){ ip += value + "."s ; } return ip.substr(0,ip.size()-1) ; } //================================================================================= // ip4list_t //================================================================================= //================================================================================= ip4list_t::ip4list_t(const std::string &filename) { if (!filename.empty()){ load(filename) ; } } //================================================================================= auto ip4list_t::bestmatch(const ip4addr_t &value) const ->std::pair { auto matches = std::vector>() ; for (const auto &addr: ipaddresses){ auto comp = addr.match(value); matches.push_back(std::make_pair(addr, comp)); } std::sort(matches.begin(),matches.end(),[](const std::pair &lhs, const std::pair &rhs){ return lhs.second < rhs.second ; }); return *matches.rbegin(); } //================================================================================= auto ip4list_t::bestmatch(std::uint32_t value, bool bigendian ) const ->std::pair { auto ptr = reinterpret_cast(&value); if (!bigendian){ std::reverse(ptr, ptr+4); } auto matches = std::vector>() ; for (const auto &addr: ipaddresses){ auto comp = addr.match(value); matches.push_back(std::make_pair(addr, comp)); } std::sort(matches.begin(),matches.end(),[](const std::pair &lhs, const std::pair &rhs){ return lhs.second < rhs.second ; }); return *matches.rbegin(); } //================================================================================= auto ip4list_t::add(const ip4addr_t &value) ->void { ipaddresses.push_back(value); } //================================================================================= auto ip4list_t::remove(const ip4addr_t &value) ->void { auto iter = std::find_if(ipaddresses.begin(),ipaddresses.end(),[value](const ip4addr_t &entry){ return value.exact(entry); }); if (iter != ipaddresses.end()){ ipaddresses.erase(iter) ; } } //================================================================================= auto ip4list_t::size() const ->size_t { return ipaddresses.size() ; } //================================================================================= auto ip4list_t::load(const std::string &filename) ->bool { auto rvalue = false ; enum state_t {section,startsection,data}; ipaddresses.clear() ; auto input = std::ifstream(filename); if (input.is_open()){ rvalue = true ; char inputline[4096] ; auto state = state_t::section ; while (input.good() && !input.eof()) { input.getline(inputline, 4095); if (input.gcount()>0) { inputline[input.gcount()]=0 ; auto line = trim(strip(std::string(inputline))) ; if (!line.empty()){ // look for a section switch (static_cast(state)){ case static_cast(state_t::section): { if (line[0] == '['){ if (line[line.size()-1] == ']'){ // it is a section! line = trim(line.substr(1,line.find("]")-1)); // apparently we dont look at this? state = state_t::startsection; } } break; } case static_cast(state_t::startsection):{ if (line[0] == '{') { state = state_t::data ; } break; } case static_cast(state_t::data):{ if (line[0] != '}') { auto [key,value] = split(line,"=") ; if ((key=="ip") || (key=="IP") || (key=="Ip") || (key=="iP")) { ipaddresses.push_back(ip4addr_t(value)); } } else { state = state_t::section; } } } } } } } return rvalue ; } //================================================================================= auto ip4list_t::ips() const ->const std::vector& { return ipaddresses; } //================================================================================= auto ip4list_t::ips() -> std::vector&{ return ipaddresses; } // Unfortunately, the approach here for the unix/windows is almost totally // different, so effectively, to completely different routines #if defined(_WIN32) //================================================================================= auto ip4list_t::available() ->ip4list_t{ /* Note: could also use malloc() and free() */ ip4list_t rvalue; std::string device ; ip4addr_t device_address ; /* Declare and initialize variables */ DWORD dwSize = 0; DWORD dwRetVal = 0; unsigned int i = 0; // Set the flags to pass to GetAdaptersAddresses ULONG flags = GAA_FLAG_INCLUDE_PREFIX; // default to unspecified address family (both) ULONG family = AF_INET; LPVOID lpMsgBuf = NULL; PIP_ADAPTER_ADDRESSES pAddresses = NULL; ULONG outBufLen = 0; ULONG Iterations = 0; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; IP_ADAPTER_DNS_SERVER_ADDRESS* pDnServer = NULL; IP_ADAPTER_PREFIX* pPrefix = NULL; // Allocate a 15 KB buffer to start with. outBufLen = WORKING_BUFFER_SIZE; do { pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen); if (pAddresses == nullptr) { throw std::runtime_error("Memory allocation files for IP_ADAPTER_ADDRESSES"); } dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); if (dwRetVal == ERROR_BUFFER_OVERFLOW) { FREE(pAddresses); pAddresses = NULL; } else { break; } Iterations++; } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES)); if (dwRetVal == NO_ERROR) { // If successful, output some information from the data we received pCurrAddresses = pAddresses; while (pCurrAddresses) { pUnicast = pCurrAddresses->FirstUnicastAddress; if (pUnicast != nullptr) { if (pUnicast->Address.lpSockaddr->sa_family == AF_INET) { for (i = 0; pUnicast != nullptr; i++) { const int friendlen = 200; char friendly[friendlen]; std::memset(friendly, 0, friendlen); sockaddr_in* sa_in = (sockaddr_in*)pUnicast->Address.lpSockaddr; device_address = ip4addr_t(sa_in->sin_addr.S_un.S_addr ); if (device_address.type() != ip4addr_t::ip4type_t::apipa) { //ourdevice.address = inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen); BOOL conv = false; device = ""; if (WideCharToMultiByte(CP_UTF8, 0, pCurrAddresses->FriendlyName, -1, friendly, friendlen, 0, &conv)> 0) { device = friendly; } if (!device.empty()){ // The device has a name, might be intersted if (device.find("(WSL)")== std::string::npos){ // we dont want a psuedo WSL device on windows rvalue.add(device_address) ; } } } pUnicast = pUnicast->Next; } } } pCurrAddresses = pCurrAddresses->Next; } } else { if (dwRetVal != ERROR_NO_DATA) { if (pAddresses) FREE(pAddresses); throw std::runtime_error("Unable to get address info"); } } if (pAddresses) { FREE(pAddresses); } return rvalue; } #else auto ip4list_t::available() ->ip4list_t { ip4list_t rvalue ; struct ifaddrs * ifAddrStruct=NULL; struct ifaddrs * ifa=NULL; void * tmpAddrPtr=NULL; ip4addr_t device_address ; getifaddrs(&ifAddrStruct); for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) { continue; } if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 // is a valid IP4 Address tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; auto holder = *reinterpret_cast(ifa->ifa_addr); auto addr = ip4addr_t(holder.sin_addr.s_addr); if (addr.type() != ip4addr_t::ip4type_t::apipa){ rvalue.add(addr); } } } if (ifAddrStruct!=NULL) { freeifaddrs(ifAddrStruct); } return rvalue ; } #endif #if 0 #include "ConfigOS.h" #include #include #include #include #include #include #include #if PLATFORM == WINDOWS #include #include #include #include #pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "IPHLPAPI.lib") #define WORKING_BUFFER_SIZE 15000 #define MAX_TRIES 3 #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #else #include #include #include #include #include #endif //+++++++++++++++++++++++++++++++++++++++++++++++++++ // // Methods for IP4Address // //+++++++++++++++++++++++++++++++++++++++++++++++++++ // const std::vector IP4Address::_privateIPs = {IP4Address("10.*.*.*"),IP4Address("192.168.*.*"), IP4Address("172.16.*.*"),IP4Address("172.17.*.*"), IP4Address("172.18.*.*"),IP4Address("172.19.*.*"), IP4Address("172.20.*.*"),IP4Address("172.21.*.*"),IP4Address("172.22.*.*"),IP4Address("172.23.*.*"), IP4Address("172.241.*.*"),IP4Address("172.25.*.*"),IP4Address("172.26.*.*"),IP4Address("172.27.*.*"), IP4Address("172.28.*.*"),IP4Address("172.29.*.*"),IP4Address("172.30.*.*"),IP4Address("172.31.*.*") }; const IP4Address IP4Address::_localIP = IP4Address("127.*.*.*"); const IP4Address IP4Address::_APIPA = IP4Address("169.254.*.*"); std::vector IP4Address::_myIPs = std::vector() ; IP4Address IP4Address::_externalIP =IP4Address("*.*.*.*"); //============================================================================ void IP4Address::loadIPs() { _myIPs = available(); } //===================================================================== void IP4Address::setExternal(const std::string &address) { IP4Address::_externalIP = lookup(address); } //===================================================================== std::vector IP4Address::parseIP(const std::string &ip) { // Examples: 192.168.1.0 // 192..1.0 // 192.*.1.0 std::vector rvalue ; std::string::size_type startloc = 0 ; std::string::size_type endloc =ip.size(); std::size_t increment = 0 ; for (increment = 0; increment<3;increment++) { if (startloc >= ip.size()){ endloc = std::string::npos; } else { endloc = ip.find(".",startloc) ; } std::string entry ; entry = ""; // Coudn't find it if (endloc== std::string::npos) { if (startloc < ip.size()){ entry = ip.substr(startloc); } } else { entry = ip.substr(startloc,endloc-startloc); } if (entry.empty()){ entry = "*"; } rvalue.push_back(entry); if (endloc == std::string::npos){ break; } startloc = endloc + 1 ; } if (increment <3) { for (auto i = increment + 1 ; i < 4; i++){ rvalue.push_back("*"); } } else { // just need to find the last std::string entry; if (startloc < ip.size()){ entry = ip.substr(startloc); } if (entry.empty()){ entry = "*"; } rvalue.push_back(entry); } return rvalue ; } //==================================================================== unsigned int IP4Address::createIP(const std::string &ip){ auto values = parseIP(ip); std::vector numbers ; numbers.resize(4,0); for (auto i = 0 ; i < 4 ; i++){ if (values[i] !="*"){ numbers[i] = static_cast(std::stoi(values[i])) ; } } return *reinterpret_cast(numbers.data()); } //==================================================================== std::string IP4Address::string() const { return _components[0] + "." + _components[1]+ "." + _components[2] + "." + _components[3]; } //==================================================================== IP4Address::IP4Address() { _components.resize(4,"*"); } //==================================================================== IP4Address::IP4Address(unsigned int address) : IP4Address() { _components.clear(); _components.push_back(std::to_string(((address>>24)&0xFF))) ; _components.push_back(std::to_string(((address>>16)&0xFF))) ; _components.push_back(std::to_string(((address>>8)&0xFF))) ; _components.push_back(std::to_string(((address)&0xFF))) ; } //==================================================================== IP4Address::IP4Address(const std::string &address) : IP4Address(){ _components = parseIP(address); } //==================================================================== IP4Address& IP4Address::operator=(const std::string &address){ _components.clear(); _components = parseIP(address); return *this; } //==================================================================== IP4Address& IP4Address::operator=(const unsigned int &address){ _components.clear(); _components.push_back(std::to_string(((address>>24)&0xFF))) ; _components.push_back(std::to_string(((address>>16)&0xFF))) ; _components.push_back(std::to_string(((address>>8)&0xFF))) ; _components.push_back(std::to_string(((address)&0xFF))) ; return *this; } //========================================================================= std::vector IP4Address::deviceIPs() { return _myIPs; } //========================================================================= std::string IP4Address::externalIP() { return _externalIP.string(); } //==================================================================== bool IP4Address::operator==(const IP4Address &address) const { return match(address,4); } //==================================================================== bool IP4Address::operator!=(const IP4Address &address) const { return !match(address,4); } //==================================================================== bool IP4Address::match(const IP4Address &address, int level) const { for (auto i = 0 ; i < level ; i++){ if (!((_components[i] =="*") || (address._components[i]=="*"))){ if (_components[i] != address._components[i]) { return false ; } } } return true ; } //===================================================================== IP4Address::typeIP IP4Address::type(bool notmine ) const{ // Check for a match! if (!notmine){ for (auto &entry: _myIPs){ if (entry == *this){ return mine; } } } if (_externalIP == *this) { return mine ; } if (*this == _localIP){ return local; } if (*this == _APIPA){ return apipa ; } for (auto &entry: _privateIPs){ if (entry == *this){ return lan; } } return wan; } //============================================================================ IP4Address IP4Address::respond(IP4Address &address){ // get the type auto ttype = address.type(false); if (ttype == mine) { // respond with local host return IP4Address("127.0.0.1"); } else if (ttype == lan){ return bestMatch(address); } return IP4Address::_externalIP; } //=================================================================== const IP4Address& IP4Address::bestMatch(const IP4Address &address){ if (_myIPs.size() == 0){ return _externalIP; } auto matchcount = 0 ; auto index = -1; for (auto i = 0 ; i < _myIPs.size() ; i++){ auto count = 0 ; for (auto j= 0 ; j<4 ; j++) { if (_myIPs[i]._components[j] != address._components[j]) { break; } count = count + 1 ; } if (count >= matchcount){ index = i ; matchcount = count ; } } if (matchcount == 0){ return _externalIP; } else { return _myIPs[index]; } } //==================================================================== unsigned int IP4Address::littleEndian() const { return convert(3,-1); } //==================================================================== unsigned int IP4Address::bigEndian() const{ return convert(0,1); } //==================================================================== unsigned int IP4Address::convert(int start, int increment) const{ unsigned int address =0; auto count = start ; for (auto &entry: _components){ unsigned int temp =0; try { temp = static_cast(std::stoi(entry)); } catch(...) { temp = 0 ; } address = (temp << (count*8) ) | address; count = count +increment ; } return address ; } //==================================================================== bool IP4Address::valid() const { for (auto &entry : _components){ if (entry != "*"){ try { auto value = std::stoi(entry) ; if( (value <0 ) || (value>255)) { return false ; } } catch(...) { return false ; } } } return true ; } //==================================================================== IP4Address IP4Address::lookup(const std::string& address){ struct addrinfo hints; struct addrinfo *result, *rp; std::memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ #if PLATFORM == WINDOWS WSAData wsdata; int startresult = WSAStartup(MAKEWORD(2, 2), &wsdata); if (startresult != 0) { throw std::runtime_error(std::string("Error start Winsock: ") + std::to_string(startresult)); } #endif int status = getaddrinfo(address.c_str(), nullptr, &hints, &result); if (status != 0) { #if PLATFORM == WINDOWS WSACleanup(); #endif return IP4Address(address); /* #if PLATFORM == WINDOWS WSACleanup(); throw std::runtime_error(std::string("Error on DNS lookup for ") + address+std::string(" : ") + std::to_string(WSAGetLastError())); #else throw std::runtime_error(std::string("Error on DNS lookup for ") + address+std::string(" : ")+std::string(gai_strerror(status))); #endif */ } else { for (rp = result; rp != nullptr; rp = rp->ai_next) { if (rp->ai_family == AF_INET){ sockaddr_in adr = *reinterpret_cast(rp->ai_addr); auto number = ntohl(adr.sin_addr.s_addr); freeaddrinfo(result); #if PLATFORM == WINDOWS WSACleanup(); #endif return IP4Address(number) ; } } freeaddrinfo(result); return IP4Address(); } } // Unfortunately, the approach here for the unix/windows is almost totally // different, so effectively, to completely different routines #if PLATFORM == WINDOWS //==================================================================== std::vector IP4Address::available() { /* Note: could also use malloc() and free() */ std::vector rvalue; std::string device ; IP4Address device_address ; /* Declare and initialize variables */ DWORD dwSize = 0; DWORD dwRetVal = 0; unsigned int i = 0; // Set the flags to pass to GetAdaptersAddresses ULONG flags = GAA_FLAG_INCLUDE_PREFIX; // default to unspecified address family (both) ULONG family = AF_INET; LPVOID lpMsgBuf = NULL; PIP_ADAPTER_ADDRESSES pAddresses = NULL; ULONG outBufLen = 0; ULONG Iterations = 0; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; IP_ADAPTER_DNS_SERVER_ADDRESS* pDnServer = NULL; IP_ADAPTER_PREFIX* pPrefix = NULL; // Allocate a 15 KB buffer to start with. outBufLen = WORKING_BUFFER_SIZE; do { pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen); if (pAddresses == nullptr) { throw std::runtime_error("Memory allocation files for IP_ADAPTER_ADDRESSES"); } dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen); if (dwRetVal == ERROR_BUFFER_OVERFLOW) { FREE(pAddresses); pAddresses = NULL; } else { break; } Iterations++; } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES)); if (dwRetVal == NO_ERROR) { // If successful, output some information from the data we received pCurrAddresses = pAddresses; while (pCurrAddresses) { pUnicast = pCurrAddresses->FirstUnicastAddress; if (pUnicast != nullptr) { if (pUnicast->Address.lpSockaddr->sa_family == AF_INET) { for (i = 0; pUnicast != nullptr; i++) { const int friendlen = 200; char friendly[friendlen]; std::memset(friendly, 0, friendlen); sockaddr_in* sa_in = (sockaddr_in*)pUnicast->Address.lpSockaddr; device_address = IP4Address(ntohl(sa_in->sin_addr.S_un.S_addr )); if (device_address != _APIPA) { //ourdevice.address = inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen); BOOL conv = false; device = ""; if (WideCharToMultiByte(CP_UTF8, 0, pCurrAddresses->FriendlyName, -1, friendly, friendlen, 0, &conv)> 0) { device = friendly; } if (!device.empty()){ // The device has a name, might be intersted if (device.find("(WSL)")== std::string::npos){ // we dont want a psuedo WSL device on windows rvalue.push_back(device_address) ; } } } pUnicast = pUnicast->Next; } } } pCurrAddresses = pCurrAddresses->Next; } } else { if (dwRetVal != ERROR_NO_DATA) { if (pAddresses) FREE(pAddresses); throw std::runtime_error("Unable to get address info"); } } if (pAddresses) { FREE(pAddresses); } return rvalue; } #else std::vector IP4Address::available() { std::vector rvalue ; struct ifaddrs * ifAddrStruct=NULL; struct ifaddrs * ifa=NULL; void * tmpAddrPtr=NULL; IP4Address device_address ; getifaddrs(&ifAddrStruct); for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) { continue; } if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 // is a valid IP4 Address tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; auto holder = *reinterpret_cast(ifa->ifa_addr); auto addr = IP4Address(ntohl(holder.sin_addr.s_addr)); if (addr != _APIPA){ rvalue.push_back(addr); } } } if (ifAddrStruct!=NULL) { freeifaddrs(ifAddrStruct); } return rvalue ; } #endif #endif