/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuNetResolver.NT.cpp Date: 2022-8-17 Author: Reece ***/ #include "Networking.hpp" #include "AuNetResolver.NT.hpp" #include "AuNetEndpoint.hpp" namespace Aurora::IO::Net { NetResolver::NetResolver(const AuSPtr &pWorker) : pWorker_(pWorker) { } NetResolver::NetResolver(const AuSPtr &pWorker, const AuSPtr, NetError>> &pCompletion) : pCompletion_(pCompletion), pWorker_(pWorker) { } NetResolver::~NetResolver() { } bool NetResolver::Start() { ADDRINFOEXW infoEx { 0 }; int iInfoEx { 0 }; if (this->bA && this->bAAAA) { infoEx.ai_family = AF_UNSPEC; //infoEx.ai_flags = AI_ALL; } else if (this->bA && !this->bAAAA) { infoEx.ai_family = AF_INET; } else if (this->bAAAA) { infoEx.ai_family = AF_INET6; //infoEx.ai_flags = AI_V4MAPPED; // beats returning nothing... } else { return false; } int iRet {}; HANDLE hHandle = NULL; if (pGetAddrInfoExCancel) { iRet = GetAddrInfoExW(AuLocale::ConvertFromUTF8(this->hostname).data(), nullptr, NS_DNS, nullptr, &infoEx, &this->resultHandle_, nullptr, &this->overlapped, NULL, &hHandle); } else { iRet = GetAddrInfoExW(AuLocale::ConvertFromUTF8(this->hostname).data(), nullptr, NS_DNS, nullptr, &infoEx, &this->resultHandle_, nullptr, nullptr, nullptr, nullptr); } this->hName_ = hHandle; return this->FinishOperationEx(AuSharedFromThis(), this->pWorker_, iRet == 0, iRet); } void NetResolver::SetCompletion(const AuSPtr, NetError>> &callback) { this->pCompletion_ = callback; } void NetResolver::OnOverlappedComplete() { if (AuExchange(this->bHasCompleted_, true)) { return; } if (this->Unpack()) { if (this->pCompletion_) { try { this->pCompletion_->OnSuccess((void *)&this->processedIps_); } catch (...) { SysPushErrorCatch(); } } } else { if (this->pCompletion_) { try { this->error_ = ENetworkError::eAsyncError; this->pCompletion_->OnFailure((void *)&this->error_); } catch (...) { SysPushErrorCatch(); } } } } void NetResolver::OnOverlappedFailure(const NetError &error) { this->error_ = error; if (this->pCompletion_) { try { this->pCompletion_->OnFailure((void *)&this->error_); } catch (...) { SysPushErrorCatch(); } } this->bHasCompleted_ = true; } bool NetResolver::HasFinished() { return this->bHasCompleted_; } void NetResolver::Cancel() { auto hHandle = AuExchange(this->hName_, (HANDLE)NULL); if (hHandle != NULL) { if (pGetAddrInfoExCancel) { pGetAddrInfoExCancel(&hHandle); } } while (!this->HasComplete()) { IOYield(); } } const NetError &NetResolver::GetError() { return this->error_; } bool NetResolver::Unpack() { auto pCurrent = this->resultHandle_; while (pCurrent) { NetEndpoint endpoint; AuMemcpy(endpoint.hint, pCurrent->ai_addr, pCurrent->ai_addrlen); DeoptimizeEndpoint(endpoint); if (!AuTryInsert(this->processedIps_, endpoint.ip)) { return false; } pCurrent = pCurrent->ai_next; } if (this->resultHandle_) { ::FreeAddrInfoExW(this->resultHandle_); } return true; } }