diff --git a/CMakeLists.txt b/CMakeLists.txt index 24a81243f..c180cc061 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,6 +378,8 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp src/core/libraries/network/net_ctl_codes.h src/core/libraries/network/net_util.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_error.h src/core/libraries/network/net.h src/core/libraries/network/ssl.cpp diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp index e4f1a8e0d..6d2efef3e 100644 --- a/src/core/libraries/network/net.cpp +++ b/src/core/libraries/network/net.cpp @@ -20,45 +20,15 @@ #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" #include "core/libraries/network/net.h" +#include "net_epoll.h" #include "net_error.h" #include "net_util.h" #include "netctl.h" #include "sockets.h" #include "sys_net.h" -#ifdef __linux__ -#include -#endif namespace Libraries::Net { -struct Epoll { - std::vector> events{}; - const char* name; - int epoll_fd; - - explicit Epoll(const char* name_) : name(name_), epoll_fd(epoll_create1(0)) { - ASSERT(epoll_fd != -1); - } - - bool Destroyed() const noexcept { - return destroyed; - } - - void Destroy() noexcept { - events.clear(); - close(epoll_fd); - epoll_fd = -1; - name = nullptr; - destroyed = true; - } - -private: - bool destroyed{}; -}; - -std::vector epolls; -std::mutex epolls_mutex; - static thread_local int32_t net_errno = 0; static bool g_isNetInitialized = true; // TODO init it properly @@ -705,50 +675,18 @@ int PS4_SYSV_ABI sceNetEpollAbort() { return ORBIS_OK; } -u32 ConvertEpollEventsIn(u32 orbis_events) { - u32 ret = 0; - - if ((orbis_events & ORBIS_NET_EPOLLIN) != 0) { - ret |= EPOLLIN; - } - if ((orbis_events & ORBIS_NET_EPOLLOUT) != 0) { - ret |= EPOLLOUT; - } - - return ret; -} - -u32 ConvertEpollEventsOut(u32 epoll_events) { - u32 ret = 0; - - if ((epoll_events & EPOLLIN) != 0) { - ret |= ORBIS_NET_EPOLLIN; - } - if ((epoll_events & EPOLLOUT) != 0) { - ret |= ORBIS_NET_EPOLLOUT; - } - if ((epoll_events & EPOLLERR) != 0) { - ret |= ORBIS_NET_EPOLLERR; - } - if ((epoll_events & EPOLLHUP) != 0) { - ret |= ORBIS_NET_EPOLLHUP; - } - - return ret; -} - int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, OrbisNetId id, OrbisNetEpollEvent* event) { LOG_WARNING(Lib_Net, "called, epollid = {}, op = {}, id = {}", epollid, magic_enum::enum_name(op), id); - std::scoped_lock lock{epolls_mutex}; - if (epollid >= epolls.size() || epolls[epollid].Destroyed()) { + auto epoll = Common::Singleton::Instance()->GetEpoll(epollid); + if (!epoll) { return -ORBIS_NET_EBADF; } auto find_id = [&](OrbisNetId id) { - return std::ranges::find_if(epolls[epollid].events, + return std::ranges::find_if(epoll->events, [&](const auto& el) { return el.first == id; }); }; @@ -757,7 +695,7 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or if (event == nullptr) { return -ORBIS_NET_EINVAL; } - if (find_id(id) != epolls[epollid].events.end()) { + if (find_id(id) != epoll->events.end()) { return -ORBIS_NET_EEXIST; } @@ -771,10 +709,11 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or const auto socket = file->socket; epoll_event native_event = {.events = ConvertEpollEventsIn(event->events), .data = {.fd = id}}; - ASSERT(epoll_ctl(epolls[epollid].epoll_fd, EPOLL_CTL_ADD, socket->Native(), + ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_ADD, socket->Native(), &native_event) == 0); + LOG_DEBUG(Lib_Net, "epoll_ctl succeeded"); #endif - epolls[epollid].events.emplace_back(id, *event); + epoll->events.emplace_back(id, *event); break; } case ORBIS_NET_EPOLL_CTL_MOD: { @@ -783,7 +722,7 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or } auto it = find_id(id); - if (it == epolls[epollid].events.end()) { + if (it == epoll->events.end()) { return -ORBIS_NET_EEXIST; } @@ -797,15 +736,15 @@ int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, Or } auto it = find_id(id); - if (it == epolls[epollid].events.end()) { + if (it == epoll->events.end()) { return -ORBIS_NET_EBADF; } #ifdef __linux__ const auto socket = Common::Singleton::Instance()->socks[id]; - ASSERT(epoll_ctl(epolls[epollid].epoll_fd, EPOLL_CTL_DEL, socket->Native(), nullptr) == 0); + ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_DEL, socket->Native(), nullptr) == 0); #endif - epolls[epollid].events.erase(it); + epoll->events.erase(it); break; } default: @@ -821,30 +760,20 @@ int PS4_SYSV_ABI sceNetEpollCreate(const char* name, int flags) { return -ORBIS_NET_EINVAL; } - std::scoped_lock lock{epolls_mutex}; - if (auto it = std::ranges::find_if(epolls, [](const Epoll& e) { return e.Destroyed(); }); - it != epolls.end()) { - *it = Epoll(name); - const auto ret = std::distance(epolls.begin(), it); - LOG_DEBUG(Lib_Net, "epollid = {}", ret); - return ret; - } else { - epolls.emplace_back(name); - const auto ret = epolls.size() - 1; - LOG_DEBUG(Lib_Net, "epollid = {}", ret); - return ret; - } + auto epoll = Common::Singleton::Instance()->CreateHandle(name); + + return epoll; } int PS4_SYSV_ABI sceNetEpollDestroy(OrbisNetId epollid) { LOG_INFO(Lib_Net, "called, epollid = {}", epollid); - std::scoped_lock lock{epolls_mutex}; - if (epollid >= epolls.size() || epolls[epollid].Destroyed()) { + auto epoll = Common::Singleton::Instance()->GetEpoll(epollid); + if (!epoll) { return -ORBIS_NET_EBADF; } - epolls[epollid].Destroy(); + epoll->Destroy(); return ORBIS_OK; } @@ -854,13 +783,13 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, LOG_WARNING(Lib_Net, "called, epollid = {}, maxevents = {}, timeout = {}", epollid, maxevents, timeout); - std::scoped_lock lock{epolls_mutex}; - if (epollid >= epolls.size() || epolls[epollid].Destroyed()) { + auto epoll = Common::Singleton::Instance()->GetEpoll(epollid); + if (!epoll) { return -ORBIS_NET_EBADF; } #ifdef __linux__ std::vector native_events{static_cast(maxevents)}; - int result = epoll_wait(epolls[epollid].epoll_fd, native_events.data(), maxevents, + int result = epoll_wait(epoll->epoll_fd, native_events.data(), maxevents, timeout == -1 ? timeout : timeout / 1000); if (result < 0) { LOG_ERROR(Lib_Net, "epoll_wait failed with {}", Common::GetLastErrorMsg()); @@ -873,10 +802,10 @@ int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, const auto& current_event = native_events[i]; LOG_INFO(Lib_Net, "native_event[{}] = ( .events = {}, .data = {:#x} )", i, current_event.events, current_event.data.u64); - const auto it = std::ranges::find_if(epolls[epollid].events, [&](auto& el) { + const auto it = std::ranges::find_if(epoll->events, [&](auto& el) { return el.first == current_event.data.fd; }); - ASSERT(it != epolls[epollid].events.end()); + ASSERT(it != epoll->events.end()); events[i] = { .events = ConvertEpollEventsOut(current_event.events), .ident = static_cast(current_event.data.fd), diff --git a/src/core/libraries/network/net_epoll.cpp b/src/core/libraries/network/net_epoll.cpp new file mode 100644 index 000000000..1c7bf3dbb --- /dev/null +++ b/src/core/libraries/network/net_epoll.cpp @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/types.h" +#include "net_epoll.h" + +namespace Libraries::Net { + +u32 ConvertEpollEventsIn(u32 orbis_events) { + u32 ret = 0; + + if ((orbis_events & ORBIS_NET_EPOLLIN) != 0) { + ret |= EPOLLIN; + } + if ((orbis_events & ORBIS_NET_EPOLLOUT) != 0) { + ret |= EPOLLOUT; + } + + return ret; +} + +u32 ConvertEpollEventsOut(u32 epoll_events) { + u32 ret = 0; + + if ((epoll_events & EPOLLIN) != 0) { + ret |= ORBIS_NET_EPOLLIN; + } + if ((epoll_events & EPOLLOUT) != 0) { + ret |= ORBIS_NET_EPOLLOUT; + } + if ((epoll_events & EPOLLERR) != 0) { + ret |= ORBIS_NET_EPOLLERR; + } + if ((epoll_events & EPOLLHUP) != 0) { + ret |= ORBIS_NET_EPOLLHUP; + } + + return ret; +} + +int EpollTable::CreateHandle(const char* name) { + std::scoped_lock lock{m_mutex}; + + if (auto it = std::ranges::find_if(epolls, [](const Epoll& e) { return e.Destroyed(); }); + it != epolls.end()) { + *it = Epoll(name); + const auto ret = std::distance(epolls.begin(), it); + LOG_DEBUG(Lib_Net, "epollid = {}", ret); + return ret; + } else { + epolls.emplace_back(name); + const auto ret = epolls.size() - 1; + LOG_DEBUG(Lib_Net, "epollid = {}", ret); + return ret; + } +} + +void EpollTable::DeleteHandle(int d) { + UNREACHABLE(); + +} + +Epoll* EpollTable::GetEpoll(int d) { + UNREACHABLE(); +} + +} // namespace Libraries::Net diff --git a/src/core/libraries/network/net_epoll.h b/src/core/libraries/network/net_epoll.h new file mode 100644 index 000000000..c34e2d4b6 --- /dev/null +++ b/src/core/libraries/network/net_epoll.h @@ -0,0 +1,61 @@ +// 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 +#include + +#ifdef __linux__ +#include +#endif + +namespace Libraries::Net { + +struct Epoll { + std::vector> events{}; + const char* name; + int epoll_fd; + + explicit Epoll(const char* name_) : name(name_), epoll_fd(epoll_create1(0)) { + ASSERT(epoll_fd != -1); + } + + bool Destroyed() const noexcept { + return destroyed; + } + + void Destroy() noexcept { + events.clear(); + close(epoll_fd); + epoll_fd = -1; + name = nullptr; + destroyed = true; + } + +private: + bool destroyed{}; +}; + + +u32 ConvertEpollEventsIn(u32 orbis_events); +u32 ConvertEpollEventsOut(u32 epoll_events); + +class EpollTable { +public: + EpollTable() = default; + virtual ~EpollTable() = default; + + int CreateHandle(const char* name); + void DeleteHandle(int d); + Epoll* GetEpoll(int d); + +private: + std::vector epolls; + std::mutex m_mutex; +}; + +} // namespace Libraries::Net \ No newline at end of file