#include "pch.h"
#include "System/String.h"
#include "System/Net/Dns.h"
#include "System/ArgumentException.h"
#include "System/Net/Sockets/SocketException.h"
#include <vector>
#include <mutex>

#if defined(_WIN32)
    #include <winsock2.h>
    #include <ws2tcpip.h>
#else
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <cstring>
#endif

namespace DotNetDupe {
    namespace System {
        namespace Net {

            void Dns::InitializeSockets() {
#if defined(_WIN32)
                static bool bInitialized = false;
                static std::mutex mutexInit;
                std::lock_guard<std::mutex> lock(mutexInit);
                if (!bInitialized) {
                    WSADATA wsaData;
                    int iErr = WSAStartup(MAKEWORD(2, 2), &wsaData);
                    if (iErr != 0) {
                        throw Sockets::SocketException(iErr, "WSAStartup failed in Dns initialization.");
                    }
                    bInitialized = true;
                }
#endif
            }

            static std::vector<String> CollectIpv4Addresses(struct addrinfo* result) {
                std::vector<String> addresses;
                for (struct addrinfo* ptr = result; ptr != nullptr; ptr = ptr->ai_next) {
                    if (ptr->ai_family == AF_INET) {
                        auto* ipv4 = reinterpret_cast<struct sockaddr_in*>(ptr->ai_addr);
                        char ipAddress[INET_ADDRSTRLEN];
                        inet_ntop(AF_INET, &(ipv4->sin_addr), ipAddress, INET_ADDRSTRLEN);
                        addresses.push_back(String(ipAddress));
                    }
                }
                return addresses;
            }

            static struct addrinfo* ResolveHostAddrInfo(const char* host) {
                struct addrinfo hints;
                std::memset(&hints, 0, sizeof(hints));
                hints.ai_family = AF_INET;
                hints.ai_socktype = SOCK_STREAM;
                struct addrinfo* result = nullptr;
                if (getaddrinfo(host, nullptr, &hints, &result) != 0) {
                    throw Sockets::SocketException(-1, "Failed to resolve host.");
                }
                return result;
            }

            Array<String> Dns::GetHostAddresses(const String& hostName) {
                if (hostName.IsEmpty()) throw ArgumentException("hostName cannot be empty.");
                InitializeSockets();
                struct addrinfo* result = ResolveHostAddrInfo(hostName.GetRawString());
                std::vector<String> addresses = CollectIpv4Addresses(result);
                freeaddrinfo(result);
                if (addresses.empty()) throw Sockets::SocketException(-1, String("No addresses found for host."));
                Array<String> arrAddresses(static_cast<int>(addresses.size()));
                for (size_t i = 0; i < addresses.size(); ++i) arrAddresses[static_cast<int>(i)] = addresses[i];
                return arrAddresses;
            }
        }
    }
}

Generated by OpenCppCoverage (Version: 0.9.9.0)