/* Copyright 2016, Ableton AG, Berlin. All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * If you would like to incorporate Link into a proprietary software application, * please contact . */ #pragma once #include #include #include #include #include #include #include #pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "ws2_32.lib") namespace ableton { namespace platforms { namespace windows { namespace detail { // RAII type to make [get,free]ifaddrs function pairs exception safe class GetIfAddrs { public: GetIfAddrs() { const int MAX_TRIES = 3; // MSFT recommendation const int WORKING_BUFFER_SIZE = 15000; // MSFT recommendation DWORD adapter_addrs_buffer_size = WORKING_BUFFER_SIZE; for (int i = 0; i < MAX_TRIES; i++) { adapter_addrs = (IP_ADAPTER_ADDRESSES*)malloc(adapter_addrs_buffer_size); assert(adapter_addrs); DWORD error = ::GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, adapter_addrs, &adapter_addrs_buffer_size); if (error == ERROR_SUCCESS) { break; } // if buffer too small, use new buffer size in next iteration if (error == ERROR_BUFFER_OVERFLOW) { free(adapter_addrs); adapter_addrs = NULL; continue; } } } ~GetIfAddrs() { if (adapter_addrs) free(adapter_addrs); } // RAII must not copy GetIfAddrs(GetIfAddrs&) = delete; GetIfAddrs& operator=(GetIfAddrs&) = delete; template void withIfAddrs(Function f) { if (adapter_addrs) f(*adapter_addrs); } private: IP_ADAPTER_ADDRESSES* adapter_addrs; IP_ADAPTER_ADDRESSES* adapter; }; } // namespace detail struct ScanIpIfAddrs { // Scan active network interfaces and return corresponding addresses // for all ip-based interfaces. std::vector<::asio::ip::address> operator()() { std::vector<::asio::ip::address> addrs; detail::GetIfAddrs getIfAddrs; getIfAddrs.withIfAddrs([&addrs](const IP_ADAPTER_ADDRESSES& interfaces) { const IP_ADAPTER_ADDRESSES* networkInterface; for (networkInterface = &interfaces; networkInterface; networkInterface = networkInterface->Next) { for (IP_ADAPTER_UNICAST_ADDRESS* address = networkInterface->FirstUnicastAddress; NULL != address; address = address->Next) { auto family = address->Address.lpSockaddr->sa_family; if (AF_INET == family) { // IPv4 SOCKADDR_IN* addr4 = reinterpret_cast(address->Address.lpSockaddr); auto bytes = reinterpret_cast(&addr4->sin_addr); addrs.emplace_back(asio::makeAddress<::asio::ip::address_v4>(bytes)); } else if (AF_INET6 == family) { SOCKADDR_IN6* addr6 = reinterpret_cast(address->Address.lpSockaddr); auto bytes = reinterpret_cast(&addr6->sin6_addr); addrs.emplace_back(asio::makeAddress<::asio::ip::address_v6>(bytes)); } } } }); return addrs; } }; } // namespace windows } // namespace platforms } // namespace ableton