From 976d12f4e6fc60c9db7994fa3bfd2e3a1bf1eda9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Mon, 22 Sep 2025 21:57:51 +0200 Subject: [PATCH] Epolls are file descriptors (#3622) * net: Register epolls in file descriptor table * fstat: stub epoll, resolver * Fake async hostname resolution * net: epoll fixes * epoll: actually close the file descriptor --- CMakeLists.txt | 2 + src/core/file_sys/fs.cpp | 24 +++ src/core/file_sys/fs.h | 10 +- src/core/libraries/kernel/file_system.cpp | 8 +- src/core/libraries/network/net.cpp | 223 ++++++++++++++------ src/core/libraries/network/net.h | 2 +- src/core/libraries/network/net_epoll.h | 10 +- src/core/libraries/network/net_resolver.cpp | 39 ++++ src/core/libraries/network/net_resolver.h | 38 ++++ src/core/libraries/network/net_util.cpp | 31 +++ src/core/libraries/network/net_util.h | 5 + 11 files changed, 324 insertions(+), 68 deletions(-) create mode 100644 src/core/libraries/network/net_resolver.cpp create mode 100644 src/core/libraries/network/net_resolver.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ddca1aec..2a0abe7b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -382,6 +382,8 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp src/core/libraries/network/net_util.h src/core/libraries/network/net_epoll.cpp src/core/libraries/network/net_epoll.h + src/core/libraries/network/net_resolver.cpp + src/core/libraries/network/net_resolver.h src/core/libraries/network/net_error.h src/core/libraries/network/net.h src/core/libraries/network/ssl.cpp diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp index aa9feb1cc..2a0fa43dd 100644 --- a/src/core/file_sys/fs.cpp +++ b/src/core/file_sys/fs.cpp @@ -235,6 +235,30 @@ File* HandleTable::GetSocket(int d) { return file; } +File* HandleTable::GetEpoll(int d) { + std::scoped_lock lock{m_mutex}; + if (d < 0 || d >= m_files.size()) { + return nullptr; + } + auto file = m_files.at(d); + if (file->type != Core::FileSys::FileType::Epoll) { + return nullptr; + } + return file; +} + +File* HandleTable::GetResolver(int d) { + std::scoped_lock lock{m_mutex}; + if (d < 0 || d >= m_files.size()) { + return nullptr; + } + auto file = m_files.at(d); + if (file->type != Core::FileSys::FileType::Resolver) { + return nullptr; + } + return file; +} + File* HandleTable::GetFile(const std::filesystem::path& host_name) { for (auto* file : m_files) { if (file != nullptr && file->m_host_name == host_name) { diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index a4dd86ff9..599d9e823 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -15,7 +15,9 @@ namespace Libraries::Net { struct Socket; -} +struct Epoll; +struct Resolver; +} // namespace Libraries::Net namespace Core::FileSys { @@ -78,6 +80,8 @@ enum class FileType { Directory, Device, Socket, + Epoll, + Resolver }; struct File { @@ -90,6 +94,8 @@ struct File { std::shared_ptr directory; // only valid for type == Directory std::shared_ptr device; // only valid for type == Device std::shared_ptr socket; // only valid for type == Socket + std::shared_ptr epoll; // only valid for type == Epoll + std::shared_ptr resolver; // only valid for type == Resolver }; class HandleTable { @@ -101,6 +107,8 @@ public: void DeleteHandle(int d); File* GetFile(int d); File* GetSocket(int d); + File* GetEpoll(int d); + File* GetResolver(int d); File* GetFile(const std::filesystem::path& host_name); int GetFileDescriptor(File* file); diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 7a0cd4163..596b996db 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "common/assert.h" #include "common/error.h" @@ -701,8 +702,13 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) { // Socket functions handle errnos internally return file->socket->fstat(sb); } + case Core::FileSys::FileType::Epoll: + case Core::FileSys::FileType::Resolver: { + LOG_ERROR(Kernel_Fs, "(STUBBED) file type {}", magic_enum::enum_name(file->type.load())); + break; + } default: - UNREACHABLE(); + UNREACHABLE_MSG("{}", u32(file->type.load())); } return ORBIS_OK; } diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp index 378b6600b..4408e7bc6 100644 --- a/src/core/libraries/network/net.cpp +++ b/src/core/libraries/network/net.cpp @@ -22,6 +22,7 @@ #include "core/libraries/network/net.h" #include "net_epoll.h" #include "net_error.h" +#include "net_resolver.h" #include "net_util.h" #include "netctl.h" #include "sockets.h" @@ -621,16 +622,17 @@ int PS4_SYSV_ABI sceNetEpollAbort() { int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, OrbisNetId id, OrbisNetEpollEvent* event) { - auto epoll = Common::Singleton::Instance()->GetEpoll(epollid); - if (!epoll) { + auto file = FDTable::Instance()->GetEpoll(epollid); + if (!file) { *sceNetErrnoLoc() = ORBIS_NET_EBADF; return ORBIS_NET_ERROR_EBADF; } + auto epoll = file->epoll; LOG_WARNING(Lib_Net, "called, epollid = {} ({}), op = {}, id = {}", epollid, epoll->name, magic_enum::enum_name(op), id); auto find_id = [&](OrbisNetId id) { - return std::ranges::find_if(epoll->events, [&](const auto& el) { return el.first == id; }); + return std::ranges::find_if(epoll->events, [&](auto& el) { return el.first == id; }); }; switch (op) { @@ -644,17 +646,33 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or return ORBIS_NET_ERROR_EEXIST; } - auto file = FDTable::Instance()->GetSocket(id); + auto file = FDTable::Instance()->GetFile(id); if (!file) { *sceNetErrnoLoc() = ORBIS_NET_EBADF; - LOG_ERROR(Lib_Net, "socket id is invalid = {}", id); + LOG_ERROR(Lib_Net, "file id is invalid = {}", id); return ORBIS_NET_ERROR_EBADF; } - epoll_event native_event = {.events = ConvertEpollEventsIn(event->events), - .data = {.fd = id}}; - ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_ADD, *file->socket->Native(), &native_event) == - 0); - epoll->events.emplace_back(id, *event); + + switch (file->type) { + case Core::FileSys::FileType::Socket: { + epoll_event native_event = {.events = ConvertEpollEventsIn(event->events), + .data = {.fd = id}}; + ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_ADD, *file->socket->Native(), + &native_event) == 0); + epoll->events.emplace_back(id, *event); + break; + } + case Core::FileSys::FileType::Resolver: { + epoll->async_resolutions.emplace_back(id); + epoll->events.emplace_back(id, *event); + break; + } + default: { + LOG_ERROR(Lib_Net, "file type {} ({}) passed", magic_enum::enum_name(file->type.load()), + file->m_guest_name); + break; + } + } break; } case ORBIS_NET_EPOLL_CTL_MOD: { @@ -663,7 +681,33 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or return ORBIS_NET_ERROR_EINVAL; } - UNREACHABLE(); + const auto it = find_id(id); + if (it == epoll->events.end()) { + *sceNetErrnoLoc() = ORBIS_NET_EBADF; + return ORBIS_NET_ERROR_EBADF; + } + + auto file = FDTable::Instance()->GetFile(id); + if (!file) { + *sceNetErrnoLoc() = ORBIS_NET_EBADF; + LOG_ERROR(Lib_Net, "file id is invalid = {}", id); + return ORBIS_NET_ERROR_EBADF; + } + + switch (file->type) { + case Core::FileSys::FileType::Socket: { + epoll_event native_event = {.events = ConvertEpollEventsIn(event->events), + .data = {.fd = id}}; + ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_MOD, *file->socket->Native(), + &native_event) == 0); + *it = {id, *event}; + break; + } + default: + LOG_ERROR(Lib_Net, "file type {} ({}) passed", magic_enum::enum_name(file->type.load()), + file->m_guest_name); + break; + } break; } case ORBIS_NET_EPOLL_CTL_DEL: { @@ -678,14 +722,30 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or return ORBIS_NET_ERROR_EBADF; } - auto file = FDTable::Instance()->GetSocket(id); + auto file = FDTable::Instance()->GetFile(id); if (!file) { *sceNetErrnoLoc() = ORBIS_NET_EBADF; - LOG_ERROR(Lib_Net, "socket id is invalid = {}", id); + LOG_ERROR(Lib_Net, "file id is invalid = {}", id); return ORBIS_NET_ERROR_EBADF; } - ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_DEL, *file->socket->Native(), nullptr) == 0); - epoll->events.erase(it); + + switch (file->type) { + case Core::FileSys::FileType::Socket: { + ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_DEL, *file->socket->Native(), nullptr) == + 0); + epoll->events.erase(it); + break; + } + case Core::FileSys::FileType::Resolver: { + std::erase(epoll->async_resolutions, id); + epoll->events.erase(it); + break; + } + default: + LOG_ERROR(Lib_Net, "file type {} ({}) passed", magic_enum::enum_name(file->type.load()), + file->m_guest_name); + break; + } break; } default: @@ -703,46 +763,58 @@ int PS4_SYSV_ABI sceNetEpollCreate(const char* name, int flags) { return ORBIS_NET_ERROR_EINVAL; } - auto epoll = Common::Singleton::Instance()->CreateHandle(name); - - return epoll; + auto fd = FDTable::Instance()->CreateHandle(); + auto* epoll = FDTable::Instance()->GetFile(fd); + epoll->is_opened = true; + epoll->type = Core::FileSys::FileType::Epoll; + epoll->epoll = std::make_shared(name); + epoll->m_guest_name = name; + return fd; } int PS4_SYSV_ABI sceNetEpollDestroy(OrbisNetId epollid) { - auto epoll = Common::Singleton::Instance()->GetEpoll(epollid); - if (!epoll) { + auto file = FDTable::Instance()->GetEpoll(epollid); + if (!file) { *sceNetErrnoLoc() = ORBIS_NET_EBADF; return ORBIS_NET_ERROR_EBADF; } - LOG_INFO(Lib_Net, "called, epollid = {} ({})", epollid, epoll->name); + LOG_INFO(Lib_Net, "called, epollid = {} ({})", epollid, file->epoll->name); - epoll->Destroy(); + file->epoll->Destroy(); return ORBIS_OK; } int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, int maxevents, int timeout) { - auto epoll = Common::Singleton::Instance()->GetEpoll(epollid); - if (!epoll) { + auto file = FDTable::Instance()->GetEpoll(epollid); + if (!file) { *sceNetErrnoLoc() = ORBIS_NET_EBADF; return ORBIS_NET_ERROR_EBADF; } - + auto epoll = file->epoll; LOG_INFO(Lib_Net, "called, epollid = {} ({}), maxevents = {}, timeout = {}", epollid, epoll->name, maxevents, timeout); + int sockets_waited_on = (epoll->events.size() - epoll->async_resolutions.size()) > 0; + std::vector native_events{static_cast(maxevents)}; + int result = ORBIS_OK; + if (sockets_waited_on) { #ifdef __linux__ - const timespec epoll_timeout{.tv_sec = timeout / 1000000, - .tv_nsec = (timeout % 1000000) * 1000}; - int result = epoll_pwait2(epoll->epoll_fd, native_events.data(), maxevents, + const timespec epoll_timeout{.tv_sec = timeout / 1000000, + .tv_nsec = (timeout % 1000000) * 1000}; + result = epoll_pwait2(epoll->epoll_fd, native_events.data(), maxevents, timeout < 0 ? nullptr : &epoll_timeout, nullptr); #else - int result = epoll_wait(epoll->epoll_fd, native_events.data(), maxevents, + result = epoll_wait(epoll->epoll_fd, native_events.data(), maxevents, timeout < 0 ? timeout : timeout / 1000); #endif + } + + int i = 0; + if (result < 0) { LOG_ERROR(Lib_Net, "epoll_wait failed with {}", Common::GetLastErrorMsg()); switch (errno) { @@ -762,7 +834,7 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, } else if (result == 0) { LOG_DEBUG(Lib_Net, "timed out"); } else { - for (int i = 0; i < result; ++i) { + for (; i < result; ++i) { const auto& current_event = native_events[i]; LOG_DEBUG(Lib_Net, "native_event[{}] = ( .events = {}, .data = {:#x} )", i, current_event.events, current_event.data.u64); @@ -779,7 +851,36 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, } } - return result; + if (result >= 0) { + while (!epoll->async_resolutions.empty()) { + if (i == maxevents) { + break; + } + auto rid = epoll->async_resolutions.front(); + epoll->async_resolutions.pop_front(); + auto file = FDTable::Instance()->GetResolver(rid); + if (!file) { + LOG_ERROR(Lib_Net, "resolver {} does not exist", rid); + continue; + } + + file->resolver->Resolve(); + + const auto it = + std::ranges::find_if(epoll->events, [&](auto& el) { return el.first == rid; }); + ASSERT(it != epoll->events.end()); + events[i] = { + .events = ORBIS_NET_EPOLLDESCID, + .ident = static_cast(rid), + .data = it->second.data, + }; + LOG_DEBUG(Lib_Net, "event[{}] = ( .events = {:#x}, .ident = {}, .data = {:#x} )", i, + events[i].events, events[i].ident, events[i].data.data_u64); + ++i; + } + } + + return i; } int* PS4_SYSV_ABI sceNetErrnoLoc() { @@ -1255,18 +1356,30 @@ int PS4_SYSV_ABI sceNetResolverConnectDestroy() { } int PS4_SYSV_ABI sceNetResolverCreate(const char* name, int poolid, int flags) { - LOG_ERROR(Lib_Net, "(STUBBED) called, name = {}, poolid = {}, flags = {}", name, poolid, flags); - static int id = 1; - return id++; + LOG_INFO(Lib_Net, "name = {}, poolid = {}, flags = {}", name, poolid, flags); + + if (flags != 0) { + *sceNetErrnoLoc() = ORBIS_NET_EINVAL; + return ORBIS_NET_ERROR_EINVAL; + } + + auto fd = FDTable::Instance()->CreateHandle(); + auto* resolver = FDTable::Instance()->GetFile(fd); + resolver->is_opened = true; + resolver->type = Core::FileSys::FileType::Resolver; + resolver->resolver = std::make_shared(name, poolid, flags); + resolver->m_guest_name = name; + return fd; } int PS4_SYSV_ABI sceNetResolverDestroy(OrbisNetId resolverid) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); + LOG_ERROR(Lib_Net, "(STUBBED) called rid = {}", resolverid); return ORBIS_OK; } -int PS4_SYSV_ABI sceNetResolverGetError() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); +int PS4_SYSV_ABI sceNetResolverGetError(OrbisNetId resolverid, s32* status) { + LOG_ERROR(Lib_Net, "(STUBBED) called rid = {}", resolverid); + *status = 0; return ORBIS_OK; } @@ -1286,36 +1399,24 @@ int PS4_SYSV_ABI sceNetResolverStartNtoa(OrbisNetId resolverid, const char* host "called, resolverid = {}, hostname = {}, timeout = {}, retry = {}, flags = {}", resolverid, hostname, timeout, retry, flags); + auto file = FDTable::Instance()->GetResolver(resolverid); + if (!file) { + *sceNetErrnoLoc() = ORBIS_NET_EBADF; + return ORBIS_NET_ERROR_EBADF; + } + if ((flags & ORBIS_NET_RESOLVER_ASYNC) != 0) { - // moves processing to EpollWait - LOG_ERROR(Lib_Net, "async resolution is not implemented"); - *sceNetErrnoLoc() = ORBIS_NET_RESOLVER_EINTERNAL; - auto ret = -ORBIS_NET_RESOLVER_EINTERNAL | ORBIS_NET_ERROR_BASE; - return ret; + return file->resolver->ResolveAsync(hostname, addr, timeout, retry, flags); } - const addrinfo hints = { - .ai_flags = AI_V4MAPPED | AI_ADDRCONFIG, - .ai_family = AF_INET, - }; + auto* netinfo = Common::Singleton::Instance(); + auto ret = netinfo->ResolveHostname(hostname, addr); - addrinfo* info = nullptr; - auto gai_result = getaddrinfo(hostname, nullptr, &hints, &info); - - auto ret = ORBIS_OK; - if (gai_result != 0) { - // handle more errors - LOG_ERROR(Lib_Net, "address resolution for {} failed: {}", hostname, gai_result); - *sceNetErrnoLoc() = ORBIS_NET_ERETURN; - ret = -ORBIS_NET_ERETURN | ORBIS_NET_ERROR_BASE; - } else { - ASSERT(info && info->ai_addr); - in_addr resolved_addr = ((sockaddr_in*)info->ai_addr)->sin_addr; - LOG_DEBUG(Lib_Net, "resolved address for {}: {}", hostname, inet_ntoa(resolved_addr)); - addr->inaddr_addr = resolved_addr.s_addr; + if (ret != 0) { + *sceNetErrnoLoc() = ret; + ret = -ret | ORBIS_NET_ERROR_BASE; } - freeaddrinfo(info); return ret; } diff --git a/src/core/libraries/network/net.h b/src/core/libraries/network/net.h index 06f99800d..2f1339d0a 100644 --- a/src/core/libraries/network/net.h +++ b/src/core/libraries/network/net.h @@ -427,7 +427,7 @@ int PS4_SYSV_ABI sceNetResolverConnectCreate(); int PS4_SYSV_ABI sceNetResolverConnectDestroy(); int PS4_SYSV_ABI sceNetResolverCreate(const char* name, int poolid, int flags); int PS4_SYSV_ABI sceNetResolverDestroy(OrbisNetId resolverid); -int PS4_SYSV_ABI sceNetResolverGetError(); +int PS4_SYSV_ABI sceNetResolverGetError(OrbisNetId resolverid, s32* status); int PS4_SYSV_ABI sceNetResolverStartAton(); int PS4_SYSV_ABI sceNetResolverStartAton6(); int PS4_SYSV_ABI sceNetResolverStartNtoa(OrbisNetId resolverid, const char* hostname, diff --git a/src/core/libraries/network/net_epoll.h b/src/core/libraries/network/net_epoll.h index b4745fcab..37555484d 100644 --- a/src/core/libraries/network/net_epoll.h +++ b/src/core/libraries/network/net_epoll.h @@ -6,6 +6,7 @@ #include "common/types.h" #include "core/libraries/network/net.h" +#include #include #include @@ -28,8 +29,9 @@ using epoll_handle = int; struct Epoll { std::vector> events{}; - const char* name; + std::string name; epoll_handle epoll_fd; + std::deque async_resolutions{}; explicit Epoll(const char* name_) : name(name_), epoll_fd(epoll_create1(0)) { #ifdef _WIN32 @@ -37,7 +39,7 @@ struct Epoll { #else ASSERT(epoll_fd != -1); #endif - if (name == nullptr) { + if (name_ == nullptr) { name = "anon"; } } @@ -49,11 +51,11 @@ struct Epoll { void Destroy() noexcept { events.clear(); #ifdef _WIN32 - epoll_fd = nullptr; epoll_close(epoll_fd); + epoll_fd = nullptr; #else - epoll_fd = -1; close(epoll_fd); + epoll_fd = -1; #endif name = ""; destroyed = true; diff --git a/src/core/libraries/network/net_resolver.cpp b/src/core/libraries/network/net_resolver.cpp new file mode 100644 index 000000000..6571176df --- /dev/null +++ b/src/core/libraries/network/net_resolver.cpp @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/singleton.h" +#include "common/types.h" +#include "core/libraries/error_codes.h" +#include "net_error.h" +#include "net_resolver.h" +#include "net_util.h" + +namespace Libraries::Net { + +int Resolver::ResolveAsync(const char* hostname, OrbisNetInAddr* addr, int timeout, int retry, + int flags) { + std::scoped_lock lock{m_mutex}; + + if (async_resolution) { + *sceNetErrnoLoc() = ORBIS_NET_RESOLVER_EBUSY; + return ORBIS_NET_ERROR_RESOLVER_EBUSY; + } + + async_resolution = AsyncResolution{hostname, addr, timeout, retry, flags}; + + return ORBIS_OK; +} + +void Resolver::Resolve() { + if (async_resolution) { + auto* netinfo = Common::Singleton::Instance(); + auto ret = netinfo->ResolveHostname(async_resolution->hostname, async_resolution->addr); + + resolution_error = ret; + } else { + LOG_ERROR(Lib_Net, "async resolution has not been set-up"); + } +} + +} // namespace Libraries::Net diff --git a/src/core/libraries/network/net_resolver.h b/src/core/libraries/network/net_resolver.h new file mode 100644 index 000000000..34d7dc591 --- /dev/null +++ b/src/core/libraries/network/net_resolver.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" +#include "core/libraries/network/net.h" + +#include +#include + +namespace Libraries::Net { + +struct Resolver { +public: + Resolver(const char* name, int poolid, int flags) : name(name), poolid(poolid), flags(flags) {} + + int ResolveAsync(const char* hostname, OrbisNetInAddr* addr, int timeout, int retry, int flags); + void Resolve(); + +private: + struct AsyncResolution { + const char* hostname; + OrbisNetInAddr* addr; + int timeout; + int retry; + int flags; + }; + + std::string name; + int poolid; + int flags; + std::optional async_resolution{}; + int resolution_error = ORBIS_OK; + std::mutex m_mutex; +}; + +} // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/network/net_util.cpp b/src/core/libraries/network/net_util.cpp index fe3c1f540..de47f7bc1 100644 --- a/src/core/libraries/network/net_util.cpp +++ b/src/core/libraries/network/net_util.cpp @@ -36,6 +36,11 @@ typedef int net_socket; #include #include #include +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "net.h" +#include "net_error.h" #include "net_util.h" namespace NetUtil { @@ -367,4 +372,30 @@ bool NetUtilInternal::RetrieveIp() { return true; } +int NetUtilInternal::ResolveHostname(const char* hostname, Libraries::Net::OrbisNetInAddr* addr) { + const addrinfo hints = { + .ai_flags = AI_V4MAPPED | AI_ADDRCONFIG, + .ai_family = AF_INET, + }; + + addrinfo* info = nullptr; + auto gai_result = getaddrinfo(hostname, nullptr, &hints, &info); + + auto ret = ORBIS_OK; + if (gai_result != 0) { + // handle more errors + LOG_ERROR(Lib_Net, "address resolution for {} failed: {}", hostname, gai_result); + ret = ORBIS_NET_ERETURN; + } else { + ASSERT(info && info->ai_addr); + in_addr resolved_addr = ((sockaddr_in*)info->ai_addr)->sin_addr; + LOG_DEBUG(Lib_Net, "resolved address for {}: {}", hostname, inet_ntoa(resolved_addr)); + addr->inaddr_addr = resolved_addr.s_addr; + } + + freeaddrinfo(info); + + return ret; +} + } // namespace NetUtil \ No newline at end of file diff --git a/src/core/libraries/network/net_util.h b/src/core/libraries/network/net_util.h index 955e08f29..d8c6870f9 100644 --- a/src/core/libraries/network/net_util.h +++ b/src/core/libraries/network/net_util.h @@ -6,6 +6,10 @@ #include #include "common/types.h" +namespace Libraries::Net { +struct OrbisNetInAddr; +} + namespace NetUtil { class NetUtilInternal { @@ -29,5 +33,6 @@ public: bool RetrieveDefaultGateway(); bool RetrieveNetmask(); bool RetrieveIp(); + int ResolveHostname(const char* hostname, Libraries::Net::OrbisNetInAddr* addr); }; } // namespace NetUtil \ No newline at end of file