/*** 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 GetAddressesForFamily(ULONG uFamily) { static const auto kDefSize = 15 * 1024; 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 = ::GetAdaptersAddresses(uFamily, dwFlags, NULL, 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 {}; } AU_NOINLINE void AddressesToList(AuSPtr pAddresses, AuList> &adaptersOut) { auto pCurrAddresses = pAddresses.get(); adaptersOut.clear(); while (pCurrAddresses) { 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; } 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; } 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; } } #endif static void PrecacheAdapters() { auto pAdaptersV4 = GetAddressesForFamily(AF_INET); auto pAdaptersV6 = GetAddressesForFamily(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 } }