UsenetSearch/src/Dns.cpp

101 lines
2.7 KiB
C++

/*
Copyright© 2021 John Sennesael
UsenetSearch is Free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
UsenetSearch is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with UsenetSearch. If not, see <https://www.gnu.org/licenses/>.
*/
#include "usenetsearch/Dns.h"
#include "usenetsearch/Logger.h"
#include <sys/socket.h>
#include <cerrno>
#include <thread>
namespace usenetsearch {
std::vector<struct addrinfo> DnsResolve(
const std::string& host,
int port,
const std::chrono::milliseconds& timeOut)
{
std::vector<struct addrinfo> results;
struct addrinfo* firstResult = nullptr;
struct addrinfo hints{};
struct addrinfo* result = nullptr;
hints.ai_family = AF_UNSPEC; // ipv6 or ipv4
hints.ai_flags = AI_V4MAPPED | AI_ALL;
const auto start_time = std::chrono::system_clock::now();
while (true)
{
// Handle timeout.
const auto time = std::chrono::system_clock::now();
const auto deltaT =
std::chrono::duration_cast<std::chrono::milliseconds>(
time - start_time
);
if (deltaT > timeOut) break;
// Try to resolve.
const int getAddrInfoResult = getaddrinfo(
host.c_str(),
std::to_string(port).c_str(),
&hints,
&result
);
firstResult = result;
if (getAddrInfoResult == EAI_AGAIN)
{
std::this_thread::sleep_for(std::chrono::milliseconds{500});
continue;
}
if (getAddrInfoResult == 0)
{
break; // success
}
else
{
Logger::Get().Fatal<DnsResolveException>(
LOGID("Dns"),
"Could not resolve host " + host + ": - Error ("
+ std::to_string(getAddrInfoResult) + ") - "
+ gai_strerror(getAddrInfoResult)
);
}
}
if (result == nullptr)
{
Logger::Get().Fatal<DnsResolveException>(
LOGID("Dns"),
"Timed out trying to resolve host: " + host
);
}
while (result != nullptr)
{
results.emplace_back(*result);
result = result->ai_next;
}
if (firstResult != nullptr)
{
freeaddrinfo(firstResult);
}
return results;
}
} // namespace usenetsearch