1 /* Copyright 2016, Ableton AG, Berlin. All rights reserved. 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 2 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * 16 * If you would like to incorporate Link into a proprietary software application, 17 * please contact <link-devs@ableton.com>. 18 */ 19 20 #pragma once 21 22 #include <ableton/platforms/asio/AsioWrapper.hpp> 23 #include <ableton/platforms/asio/Util.hpp> 24 #include <iphlpapi.h> 25 #include <stdio.h> 26 #include <vector> 27 #include <winsock2.h> 28 #include <ws2tcpip.h> 29 30 #pragma comment(lib, "iphlpapi.lib") 31 #pragma comment(lib, "ws2_32.lib") 32 33 namespace ableton 34 { 35 namespace platforms 36 { 37 namespace windows 38 { 39 namespace detail 40 { 41 // RAII type to make [get,free]ifaddrs function pairs exception safe 42 class GetIfAddrs 43 { 44 public: GetIfAddrs()45 GetIfAddrs() 46 { 47 const int MAX_TRIES = 3; // MSFT recommendation 48 const int WORKING_BUFFER_SIZE = 15000; // MSFT recommendation 49 50 DWORD adapter_addrs_buffer_size = WORKING_BUFFER_SIZE; 51 for (int i = 0; i < MAX_TRIES; i++) 52 { 53 adapter_addrs = (IP_ADAPTER_ADDRESSES*)malloc(adapter_addrs_buffer_size); 54 assert(adapter_addrs); 55 56 DWORD error = ::GetAdaptersAddresses(AF_UNSPEC, 57 GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER 58 | GAA_FLAG_SKIP_FRIENDLY_NAME, 59 NULL, adapter_addrs, &adapter_addrs_buffer_size); 60 61 if (error == ERROR_SUCCESS) 62 { 63 break; 64 } 65 // if buffer too small, use new buffer size in next iteration 66 if (error == ERROR_BUFFER_OVERFLOW) 67 { 68 free(adapter_addrs); 69 adapter_addrs = NULL; 70 continue; 71 } 72 } 73 } ~GetIfAddrs()74 ~GetIfAddrs() 75 { 76 if (adapter_addrs) 77 free(adapter_addrs); 78 } 79 80 // RAII must not copy 81 GetIfAddrs(GetIfAddrs&) = delete; 82 GetIfAddrs& operator=(GetIfAddrs&) = delete; 83 84 template <typename Function> withIfAddrs(Function f)85 void withIfAddrs(Function f) 86 { 87 if (adapter_addrs) 88 f(*adapter_addrs); 89 } 90 91 private: 92 IP_ADAPTER_ADDRESSES* adapter_addrs; 93 IP_ADAPTER_ADDRESSES* adapter; 94 }; 95 96 } // namespace detail 97 98 struct ScanIpIfAddrs 99 { 100 // Scan active network interfaces and return corresponding addresses 101 // for all ip-based interfaces. operator ()ableton::platforms::windows::ScanIpIfAddrs102 std::vector<::asio::ip::address> operator()() 103 { 104 std::vector<::asio::ip::address> addrs; 105 106 detail::GetIfAddrs getIfAddrs; 107 getIfAddrs.withIfAddrs([&addrs](const IP_ADAPTER_ADDRESSES& interfaces) { 108 const IP_ADAPTER_ADDRESSES* networkInterface; 109 for (networkInterface = &interfaces; networkInterface; 110 networkInterface = networkInterface->Next) 111 { 112 for (IP_ADAPTER_UNICAST_ADDRESS* address = networkInterface->FirstUnicastAddress; 113 NULL != address; address = address->Next) 114 { 115 auto family = address->Address.lpSockaddr->sa_family; 116 if (AF_INET == family) 117 { 118 // IPv4 119 SOCKADDR_IN* addr4 = 120 reinterpret_cast<SOCKADDR_IN*>(address->Address.lpSockaddr); 121 auto bytes = reinterpret_cast<const char*>(&addr4->sin_addr); 122 addrs.emplace_back(asio::makeAddress<::asio::ip::address_v4>(bytes)); 123 } 124 else if (AF_INET6 == family) 125 { 126 SOCKADDR_IN6* addr6 = 127 reinterpret_cast<SOCKADDR_IN6*>(address->Address.lpSockaddr); 128 auto bytes = reinterpret_cast<const char*>(&addr6->sin6_addr); 129 addrs.emplace_back(asio::makeAddress<::asio::ip::address_v6>(bytes)); 130 } 131 } 132 } 133 }); 134 return addrs; 135 } 136 }; 137 138 } // namespace windows 139 } // namespace platforms 140 } // namespace ableton 141