mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-08 20:58:41 +00:00
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
This commit is contained in:
committed by
GitHub
parent
50a3081084
commit
976d12f4e6
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<Directories::BaseDirectory> directory; // only valid for type == Directory
|
||||
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
|
||||
std::shared_ptr<Libraries::Net::Socket> socket; // only valid for type == Socket
|
||||
std::shared_ptr<Libraries::Net::Epoll> epoll; // only valid for type == Epoll
|
||||
std::shared_ptr<Libraries::Net::Resolver> 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);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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<EpollTable>::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<EpollTable>::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<Epoll>(name);
|
||||
epoll->m_guest_name = name;
|
||||
return fd;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetEpollDestroy(OrbisNetId epollid) {
|
||||
auto epoll = Common::Singleton<EpollTable>::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<EpollTable>::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<epoll_event> native_events{static_cast<size_t>(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<u64>(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<Resolver>(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<NetUtil::NetUtilInternal>::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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/network/net.h"
|
||||
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
@@ -28,8 +29,9 @@ using epoll_handle = int;
|
||||
|
||||
struct Epoll {
|
||||
std::vector<std::pair<u32 /*netId*/, OrbisNetEpollEvent>> events{};
|
||||
const char* name;
|
||||
std::string name;
|
||||
epoll_handle epoll_fd;
|
||||
std::deque<u32> 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;
|
||||
|
||||
39
src/core/libraries/network/net_resolver.cpp
Normal file
39
src/core/libraries/network/net_resolver.cpp
Normal file
@@ -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<NetUtil::NetUtilInternal>::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
|
||||
38
src/core/libraries/network/net_resolver.h
Normal file
38
src/core/libraries/network/net_resolver.h
Normal file
@@ -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 <mutex>
|
||||
#include <vector>
|
||||
|
||||
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<AsyncResolution> async_resolution{};
|
||||
int resolution_error = ORBIS_OK;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
} // namespace Libraries::Net
|
||||
@@ -36,6 +36,11 @@ typedef int net_socket;
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
#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
|
||||
@@ -6,6 +6,10 @@
|
||||
#include <mutex>
|
||||
#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
|
||||
Reference in New Issue
Block a user