barrier/src/gui/src/win32/DefaultInterfaceIP.cpp

101 lines
3.1 KiB
C++

// REQUIRES: Ws2_32.lib, Iphlpapi.lib
// REQUIRES: WSAStartup(..)
// see comments regarding WSAAddressToStringA in address_string(..)
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <iphlpapi.h>
#include <string>
#include "HeapResource.h"
namespace Debauchee
{
static ULONG get_addresses(IP_ADAPTER_ADDRESSES * addresses, PULONG sz)
{
return GetAdaptersAddresses(AF_INET,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL, addresses, sz);
}
static std::string address_string(const SOCKET_ADDRESS& address)
{
// planning to use this with Qt but QString does not have a c'tor
// for wide strings so we need to force the ANSI API here
DWORD szStrAddress = 1023;
char strAddress[1024];
if (WSAAddressToStringA(address.lpSockaddr, address.iSockaddrLength, NULL, strAddress, &szStrAddress)) {
return "";
}
return strAddress;
}
static std::string first_unicast_address(IP_ADAPTER_UNICAST_ADDRESS * unicast)
{
while (unicast) {
auto address = address_string(unicast->Address);
if (!address.empty()) {
return address;
}
unicast = unicast->Next;
}
return std::string();
}
static bool is_useable_interface(const IP_ADAPTER_ADDRESSES * ifa)
{
return
// is an ethernet or wireless interface AND
(ifa->IfType == IF_TYPE_ETHERNET_CSMACD || ifa->IfType == IF_TYPE_IEEE80211) &&
// is up
ifa->OperStatus == IfOperStatusUp;
}
static std::string default_ip_address(const IP_ADAPTER_ADDRESSES * next)
{
std::string wirelessAddress;
for ( ; next; next = next->Next) {
if (!is_useable_interface(next)) {
continue;
}
std::string address = first_unicast_address(next->FirstUnicastAddress);
if (address.empty()) {
continue;
}
// take first wired address right away
if (next->IfType == IF_TYPE_ETHERNET_CSMACD) {
return address;
}
// save first wireless address to be used if we don't find a wired one
if (wirelessAddress.empty()) {
wirelessAddress = address;
}
}
return wirelessAddress;
}
std::string default_interface_ip()
{
const ULONG DefaultSzAddresses = 15 * 1024; // 15k recommended by msdn
ULONG szAddresses = DefaultSzAddresses;
HeapResource<IP_ADAPTER_ADDRESSES> addresses(GetProcessHeap(), 0, DefaultSzAddresses);
if (addresses.is_valid()) {
ULONG result;
while (ERROR_BUFFER_OVERFLOW == (result = get_addresses(addresses, &szAddresses))) {
// add more space in case more adapters have shown up
szAddresses += DefaultSzAddresses;
swap(addresses, HeapResource<IP_ADAPTER_ADDRESSES>(GetProcessHeap(), 0, szAddresses));
if (!addresses.is_valid()) {
break;
}
}
if (result == ERROR_SUCCESS) {
return default_ip_address(addresses);
}
}
return std::string();
}
}