/*** 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 #include namespace Aurora::IO::Net { static AuList> gIpv4Adapters; static AuList> gIpv6Adapters; AuString NetAdapter::GetHostname() { #if defined(AURORA_PLATFORM_WIN32) wchar_t buffer[128]; DWORD dwLength { AuArraySize(buffer) }; if (!::GetComputerNameExW(ComputerNameDnsHostname, buffer, &dwLength)) { return {}; } return AuLocale::ConvertFromWChar(buffer, dwLength); #else return ""; #endif } #if defined(AURORA_PLATFORM_WIN32) AuSPtr GetAddressesForFamilyXP(ULONG uFamily) { static const auto kDefSize = 15 * 1024; if (!pGetAdaptersAddresses) { return {}; } AuSPtr pAddresses; DWORD outBufLen { kDefSize }; DWORD dwRetVal; DWORD dwFlags = AuSwInfo::IsWindowsXPSP1OrGreater() ? GAA_FLAG_INCLUDE_PREFIX : 0; DWORD dwIterations {}; do { pAddresses = AuReinterpretCast(AuMakeSharedArray(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 {}; } AuSPtr GetAddressesForFamilyLH(ULONG uFamily) { static const auto kDefSize = 15 * 1024; if (!pGetAdaptersAddresses) { return {}; } AuSPtr pAddresses; DWORD outBufLen { kDefSize }; DWORD dwRetVal; DWORD dwFlags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS; DWORD dwIterations {}; do { pAddresses = AuReinterpretCast(AuMakeSharedArray(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 {}; } template AU_NOINLINE void AddressesToList(AuSPtr pAddresses, AuList> &adaptersOut) { auto pCurrAddresses = pAddresses.get(); adaptersOut.clear(); while (pCurrAddresses) { if (pCurrAddresses->Length != sizeof(T)) { return; } auto pAdapter = AuMakeSharedThrow(); auto &adapter = *pAdapter.get(); adapter.device = pCurrAddresses->AdapterName; adapter.name = AuLocale::ConvertFromWChar(pCurrAddresses->FriendlyName); 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; } 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) { 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; } } if (adapter.address.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[128]; 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(pAdapter); if (pAdapterEx->device == AuString(pIPAddrTable->AdapterName)) { pAdapterEx->gateway = IPAddress(pIPAddrTable->GatewayList.IpAddress.String); } } pIPAddrTable = pIPAddrTable->Next; } } #endif 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); } } AuList> NetAdapter::GetIPv4s() { #if defined(AURORA_PLATFORM_WIN32) PrecacheAdapters(); return gIpv4Adapters; #else return {}; #endif } AuList> NetAdapter::GetIPv6s() { #if defined(AURORA_PLATFORM_WIN32) return gIpv6Adapters; #else return {}; #endif } }