359 lines
10 KiB
C++
359 lines
10 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuNetAdapter.NT.cpp
|
|
Date: 2022-11-14
|
|
Author: Reece
|
|
***/
|
|
#include "Networking.hpp"
|
|
#include "AuNetAdapter.hpp"
|
|
#include "AuNetEndpoint.hpp"
|
|
|
|
#include <winsock2.h>
|
|
#include <iphlpapi.h>
|
|
|
|
namespace Aurora::IO::Net
|
|
{
|
|
static AuList<AuSPtr<INetAdapter>> gIpv4Adapters;
|
|
static AuList<AuSPtr<INetAdapter>> gIpv6Adapters;
|
|
|
|
AuString NetAdapter::GetHostname()
|
|
{
|
|
wchar_t buffer[256];
|
|
#if defined(AURORA_PLATFORM_WIN32)
|
|
DWORD dwLength { AuArraySize(buffer) };
|
|
|
|
if (!::GetComputerNameExW(ComputerNameDnsHostname, buffer, &dwLength))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
return AuLocale::ConvertFromWChar(buffer, dwLength);
|
|
#else
|
|
int iLength { AuArraySize(buffer) };
|
|
|
|
if (!(iLength = ::GetHostNameW(buffer, iLength)))
|
|
{
|
|
return {};
|
|
}
|
|
|
|
return AuLocale::ConvertFromWChar(buffer, iLength);
|
|
#endif
|
|
}
|
|
|
|
#if defined(AURORA_PLATFORM_WIN32)
|
|
|
|
AuSPtr<IP_ADAPTER_ADDRESSES_XP> GetAddressesForFamilyXP(ULONG uFamily)
|
|
{
|
|
static const auto kDefSize = 15 * 1024;
|
|
|
|
if (!pGetAdaptersAddresses)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
AuSPtr<IP_ADAPTER_ADDRESSES_XP> pAddresses;
|
|
DWORD outBufLen { kDefSize };
|
|
DWORD dwRetVal;
|
|
|
|
DWORD dwFlags = AuSwInfo::IsWindowsXPSP1OrGreater() ? GAA_FLAG_INCLUDE_PREFIX : 0;
|
|
DWORD dwIterations {};
|
|
do
|
|
{
|
|
pAddresses = AuReinterpretCast<IP_ADAPTER_ADDRESSES_XP>(AuMakeSharedArray<AuUInt8>(kDefSize));
|
|
SysAssert(pAddresses);
|
|
|
|
dwRetVal = pGetAdaptersAddresses(uFamily, dwFlags, NULL, (IP_ADAPTER_ADDRESSES *)(pAddresses.get()), &outBufLen);
|
|
|
|
if (dwRetVal == 0)
|
|
{
|
|
break;
|
|
}
|
|
else if (dwRetVal != ERROR_BUFFER_OVERFLOW)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
SysPushErrorNet("Fail");
|
|
break;
|
|
}
|
|
|
|
dwIterations++;
|
|
|
|
}
|
|
while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (dwIterations < 5));
|
|
|
|
return dwRetVal == NO_ERROR ? pAddresses : AuSPtr<IP_ADAPTER_ADDRESSES_XP> {};
|
|
}
|
|
|
|
AuSPtr<IP_ADAPTER_ADDRESSES_LH> GetAddressesForFamilyLH(ULONG uFamily)
|
|
{
|
|
static const auto kDefSize = 15 * 1024;
|
|
|
|
if (!pGetAdaptersAddresses)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
AuSPtr<IP_ADAPTER_ADDRESSES_LH> pAddresses;
|
|
DWORD outBufLen { kDefSize };
|
|
DWORD dwRetVal;
|
|
|
|
DWORD dwFlags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS;
|
|
DWORD dwIterations {};
|
|
do
|
|
{
|
|
pAddresses = AuReinterpretCast<IP_ADAPTER_ADDRESSES_LH>(AuMakeSharedArray<AuUInt8>(kDefSize));
|
|
SysAssert(pAddresses);
|
|
|
|
dwRetVal = pGetAdaptersAddresses(uFamily, dwFlags, NULL, (IP_ADAPTER_ADDRESSES *)(pAddresses.get()), &outBufLen);
|
|
|
|
if (dwRetVal == 0)
|
|
{
|
|
break;
|
|
}
|
|
else if (dwRetVal != ERROR_BUFFER_OVERFLOW)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
SysPushErrorNet("Fail");
|
|
break;
|
|
}
|
|
|
|
dwIterations++;
|
|
|
|
}
|
|
while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (dwIterations < 5));
|
|
|
|
return dwRetVal == NO_ERROR ? pAddresses : AuSPtr<IP_ADAPTER_ADDRESSES_LH> {};
|
|
}
|
|
|
|
template <typename T>
|
|
AU_NOINLINE void AddressesToList(AuSPtr<T> pAddresses, AuList<AuSPtr<INetAdapter>> &adaptersOut)
|
|
{
|
|
auto pCurrAddresses = pAddresses.get();
|
|
|
|
adaptersOut.clear();
|
|
|
|
while (pCurrAddresses)
|
|
{
|
|
if (pCurrAddresses->Length != sizeof(T))
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto pAdapter = AuMakeSharedThrow<NetAdapter>();
|
|
auto &adapter = *pAdapter.get();
|
|
adapter.device = pCurrAddresses->AdapterName;
|
|
adapter.name = AuLocale::ConvertFromWChar(pCurrAddresses->FriendlyName);
|
|
|
|
AuMemcpy(adapter.mac.begin(), pCurrAddresses->PhysicalAddress, pCurrAddresses->PhysicalAddressLength);
|
|
|
|
adapter.mtu = pCurrAddresses->Mtu;
|
|
|
|
auto pUnicast = pCurrAddresses->FirstUnicastAddress;
|
|
if (pUnicast)
|
|
{
|
|
NetEndpoint ep;
|
|
if (pUnicast->Address.iSockaddrLength <= sizeof(ep.hint))
|
|
{
|
|
AuMemcpy(ep.hint, pUnicast->Address.lpSockaddr, pUnicast->Address.iSockaddrLength);
|
|
DeoptimizeEndpoint(ep);
|
|
}
|
|
|
|
adapter.address = ep.ip;
|
|
}
|
|
|
|
auto pMulticast = pCurrAddresses->FirstMulticastAddress;
|
|
if (pMulticast)
|
|
{
|
|
NetEndpoint ep;
|
|
if (pMulticast->Address.iSockaddrLength <= sizeof(ep.hint))
|
|
{
|
|
AuMemcpy(ep.hint, pMulticast->Address.lpSockaddr, pMulticast->Address.iSockaddrLength);
|
|
DeoptimizeEndpoint(ep);
|
|
}
|
|
|
|
adapter.broadcast = ep.ip;
|
|
}
|
|
|
|
{
|
|
switch (pCurrAddresses->IfType)
|
|
{
|
|
case IF_TYPE_OTHER:
|
|
adapter.eNetworkType = EAdapterType::eOther;
|
|
break;
|
|
case IF_TYPE_ETHERNET_CSMACD:
|
|
adapter.eNetworkType = EAdapterType::eEthernet;
|
|
break;
|
|
case IF_TYPE_IEEE80211:
|
|
adapter.eNetworkType = EAdapterType::eIEEE80211;
|
|
break;
|
|
case IF_TYPE_ISO88025_TOKENRING:
|
|
adapter.eNetworkType = EAdapterType::eTokenRing;
|
|
break;
|
|
case IF_TYPE_SOFTWARE_LOOPBACK:
|
|
adapter.eNetworkType = EAdapterType::eLoopback;
|
|
break;
|
|
case IF_TYPE_TUNNEL:
|
|
adapter.eNetworkType = EAdapterType::eTunnel;
|
|
break;
|
|
}
|
|
}
|
|
|
|
adapter.eNetworkStatus = pCurrAddresses->OperStatus == IfOperStatusUp ?
|
|
EAdapterStatus::eUp :
|
|
EAdapterStatus::eDown;
|
|
|
|
auto pAnycast = pCurrAddresses->FirstAnycastAddress;
|
|
if (pAnycast)
|
|
{
|
|
NetEndpoint ep;
|
|
if (pAnycast->Address.iSockaddrLength <= sizeof(ep.hint))
|
|
{
|
|
AuMemcpy(ep.hint, pAnycast->Address.lpSockaddr, pAnycast->Address.iSockaddrLength);
|
|
DeoptimizeEndpoint(ep);
|
|
}
|
|
|
|
adapter.anycast = ep.ip;
|
|
}
|
|
|
|
if constexpr (!AuIsSame_v<T, _IP_ADAPTER_ADDRESSES_XP>)
|
|
{
|
|
auto pGateway = pCurrAddresses->FirstGatewayAddress;
|
|
if (pGateway)
|
|
{
|
|
NetEndpoint ep;
|
|
if (pGateway->Address.iSockaddrLength <= sizeof(ep.hint))
|
|
{
|
|
AuMemcpy(ep.hint, pGateway->Address.lpSockaddr, pGateway->Address.iSockaddrLength);
|
|
DeoptimizeEndpoint(ep);
|
|
}
|
|
|
|
adapter.gateway = ep.ip;
|
|
}
|
|
|
|
adapter.dhcp = pCurrAddresses->Dhcpv4Enabled;
|
|
adapter.uTransmitBytesPerSec = pCurrAddresses->TransmitLinkSpeed / 8;
|
|
adapter.uReceiveBytesPerSec = pCurrAddresses->ReceiveLinkSpeed / 8;
|
|
}
|
|
|
|
if (adapter.address.Value().ip == EIPProtocol::eIPProtocolV4)
|
|
{
|
|
adapter.index = pCurrAddresses->IfIndex;
|
|
}
|
|
else
|
|
{
|
|
adapter.index = adaptersOut.size();
|
|
}
|
|
|
|
auto pDnsServers = pCurrAddresses->FirstDnsServerAddress;
|
|
if (pDnsServers)
|
|
{
|
|
do
|
|
{
|
|
NetEndpoint ep;
|
|
if (pDnsServers->Address.iSockaddrLength <= sizeof(ep.hint))
|
|
{
|
|
AuMemcpy(ep.hint, pDnsServers->Address.lpSockaddr, pDnsServers->Address.iSockaddrLength);
|
|
DeoptimizeEndpoint(ep);
|
|
}
|
|
|
|
adapter.dns.push_back(ep.ip);
|
|
}
|
|
while ((pDnsServers = pDnsServers->Next));
|
|
}
|
|
|
|
adaptersOut.push_back(pAdapter);
|
|
|
|
pCurrAddresses = pCurrAddresses->Next;
|
|
}
|
|
}
|
|
|
|
static void FixupXPGatewaysIPv4()
|
|
{
|
|
IP_ADAPTER_INFO info[16];
|
|
DWORD size { sizeof(info) };
|
|
IP_ADAPTER_INFO *pAdapter {};
|
|
|
|
if (!pGetAdaptersInfo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ULONG error;
|
|
if ((error = pGetAdaptersInfo(info, &size)) != NO_ERROR)
|
|
{
|
|
if (error == ERROR_NO_DATA)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SysPushErrorNet("GetAdaptersInfo failed");
|
|
return;
|
|
}
|
|
|
|
if (size == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto pIPAddrTable = info;
|
|
while (pIPAddrTable)
|
|
{
|
|
for (auto &pAdapter : gIpv4Adapters)
|
|
{
|
|
auto pAdapterEx = AuStaticCast<NetAdapter>(pAdapter);
|
|
|
|
if (pAdapterEx->device == AuString(pIPAddrTable->AdapterName))
|
|
{
|
|
pAdapterEx->dhcp = pIPAddrTable->DhcpEnabled;
|
|
pAdapterEx->gateway = IPAddress(pIPAddrTable->GatewayList.IpAddress.String);
|
|
}
|
|
}
|
|
|
|
pIPAddrTable = pIPAddrTable->Next;
|
|
}
|
|
}
|
|
|
|
static void PrecacheAdapters()
|
|
{
|
|
if (AuSwInfo::IsWindowsXPAny())
|
|
{
|
|
auto pAdaptersV4 = GetAddressesForFamilyXP(AF_INET);
|
|
auto pAdaptersV6 = GetAddressesForFamilyXP(AF_INET6);
|
|
AddressesToList(pAdaptersV4, gIpv4Adapters);
|
|
AddressesToList(pAdaptersV6, gIpv6Adapters);
|
|
FixupXPGatewaysIPv4();
|
|
}
|
|
else
|
|
{
|
|
auto pAdaptersV4 = GetAddressesForFamilyLH(AF_INET);
|
|
auto pAdaptersV6 = GetAddressesForFamilyLH(AF_INET6);
|
|
AddressesToList(pAdaptersV4, gIpv4Adapters);
|
|
AddressesToList(pAdaptersV6, gIpv6Adapters);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
AuList<AuSPtr<INetAdapter>> NetAdapter::GetIPv4s()
|
|
{
|
|
#if defined(AURORA_PLATFORM_WIN32)
|
|
PrecacheAdapters();
|
|
return gIpv4Adapters;
|
|
#else
|
|
return {};
|
|
#endif
|
|
}
|
|
|
|
AuList<AuSPtr<INetAdapter>> NetAdapter::GetIPv6s()
|
|
{
|
|
#if defined(AURORA_PLATFORM_WIN32)
|
|
return gIpv6Adapters;
|
|
#else
|
|
return {};
|
|
#endif
|
|
}
|
|
} |