void for_each_address(bool get_ipv4, bool get_ipv6, F fun) { ifaddrs* tmp = nullptr; if (getifaddrs(&tmp) != 0) { perror("getifaddrs"); return; } char buffer[INET6_ADDRSTRLEN]; std::unique_ptr<ifaddrs, decltype(freeifaddrs)*> ifs{tmp, freeifaddrs}; for (auto i = ifs.get(); i != nullptr; i = i->ifa_next) { auto family = fetch_addr_str(get_ipv4, get_ipv6, buffer, i->ifa_addr); if (family != AF_UNSPEC) fun(i->ifa_name, family == AF_INET ? protocol::ipv4 : protocol::ipv6, (i->ifa_flags & IFF_LOOPBACK) != 0, buffer); } }
void for_each_address(bool get_ipv4, bool get_ipv6, F fun) { ULONG tmp_size = 16 * 1024; // try 16kb buffer first IP_ADAPTER_ADDRESSES* tmp = nullptr; constexpr size_t max_tries = 3; size_t try_nr = 0; int retval = 0; do { if (tmp) free(tmp); tmp = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(tmp_size)); if (!tmp) CAF_RAISE_ERROR("malloc() failed"); retval = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nullptr, tmp, &tmp_size); } while (retval == ERROR_BUFFER_OVERFLOW && ++try_nr < max_tries); std::unique_ptr<IP_ADAPTER_ADDRESSES, decltype(free)*> ifs{tmp, free}; if (retval != NO_ERROR) { std::cerr << "Call to GetAdaptersAddresses failed with error: " << retval << std::endl; if (retval == ERROR_NO_DATA) { std::cerr << "No addresses were found for the requested parameters" << std::endl; } else { void* msgbuf = nullptr; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, retval, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msgbuf, 0, nullptr)) { printf("Error: %s", static_cast<char*>(msgbuf)); LocalFree(msgbuf); } } return; } char buffer[INET6_ADDRSTRLEN]; for (auto i = ifs.get(); i != nullptr; i = i->Next) { for (auto j = i->FirstUnicastAddress; j != nullptr; j = j->Next) { auto addr = j->Address.lpSockaddr; auto family = fetch_addr_str(get_ipv4, get_ipv6, buffer, addr); if (family != AF_UNSPEC) fun(i->AdapterName, family == AF_INET ? protocol::ipv4 : protocol::ipv6, false, buffer); } } }
maybe<std::pair<std::string, protocol>> interfaces::native_address(const std::string& host, maybe<protocol> preferred) { addrinfo hint; memset(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_STREAM; if (preferred) hint.ai_family = *preferred == protocol::ipv4 ? AF_INET : AF_INET6; addrinfo* tmp = nullptr; if (getaddrinfo(host.c_str(), nullptr, &hint, &tmp)) return none; std::unique_ptr<addrinfo, decltype(freeaddrinfo)*> addrs{tmp, freeaddrinfo}; char buffer[INET6_ADDRSTRLEN]; for (auto i = addrs.get(); i != nullptr; i = i->ai_next) { auto family = fetch_addr_str(true, true, buffer, i->ai_addr); if (family != AF_UNSPEC) return {{buffer, family == AF_INET ? protocol::ipv4 : protocol::ipv6}}; } return none; }