diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp index bbdf0338c..22fec11e9 100644 --- a/src/core/libraries/network/net.cpp +++ b/src/core/libraries/network/net.cpp @@ -11,7 +11,9 @@ #endif #include +#include #include "common/assert.h" +#include "common/error.h" #include "common/logging/log.h" #include "common/singleton.h" #include "core/libraries/error_codes.h" @@ -20,10 +22,42 @@ #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 @@ -72,6 +106,8 @@ OrbisNetId PS4_SYSV_ABI sceNetAccept(OrbisNetId s, OrbisNetSockaddr* addr, u32* if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "(DUMMY) called"); + int result; int err; int positiveErr; @@ -169,6 +205,8 @@ int PS4_SYSV_ABI sceNetBind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addr if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_INFO(Lib_Net, "called, s = {}", s); + int result; int err; int positiveErr; @@ -551,6 +589,8 @@ int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 a if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "s = {}", s); + int result; int err; int positiveErr; @@ -664,28 +704,190 @@ int PS4_SYSV_ABI sceNetEpollAbort() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetEpollControl() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); +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()) { + return -ORBIS_NET_EBADF; + } + + auto find_id = [&](OrbisNetId id) { + return std::ranges::find_if(epolls[epollid].events, + [&](const auto& el) { return el.first == id; }); + }; + + switch (op) { + case ORBIS_NET_EPOLL_CTL_ADD: { + if (event == nullptr) { + return -ORBIS_NET_EINVAL; + } + if (find_id(id) != epolls[epollid].events.end()) { + return -ORBIS_NET_EEXIST; + } + +#ifdef __linux__ + const auto socket = Common::Singleton::Instance()->socks[id]; + epoll_event native_event = {.events = ConvertEpollEventsIn(event->events), + .data = {.fd = id}}; + ASSERT(epoll_ctl(epolls[epollid].epoll_fd, EPOLL_CTL_ADD, socket->Native(), + &native_event) == 0); +#endif + epolls[epollid].events.emplace_back(id, *event); + break; + } + case ORBIS_NET_EPOLL_CTL_MOD: { + if (event == nullptr) { + return -ORBIS_NET_EINVAL; + } + + auto it = find_id(id); + if (it == epolls[epollid].events.end()) { + return -ORBIS_NET_EEXIST; + } + + it->second = *event; + UNREACHABLE(); + break; + } + case ORBIS_NET_EPOLL_CTL_DEL: { + if (event != nullptr) { + return -ORBIS_NET_EINVAL; + } + + auto it = find_id(id); + if (it == epolls[epollid].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); +#endif + epolls[epollid].events.erase(it); + break; + } + default: + return -ORBIS_NET_EINVAL; + } + return ORBIS_OK; } -int PS4_SYSV_ABI sceNetEpollCreate() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); +int PS4_SYSV_ABI sceNetEpollCreate(const char* name, int flags) { + LOG_WARNING(Lib_Net, "called, name = {}, flags = {}", name, flags); + if (flags != 0) { + 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; + } +} + +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()) { + return -ORBIS_NET_EBADF; + } + + epolls[epollid].Destroy(); + return ORBIS_OK; } -int PS4_SYSV_ABI sceNetEpollDestroy() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; -} +int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, int maxevents, + int timeout) { + LOG_WARNING(Lib_Net, "called, epollid = {}, maxevents = {}, timeout = {}", epollid, maxevents, + timeout); -int PS4_SYSV_ABI sceNetEpollWait() { - LOG_TRACE(Lib_Net, "(STUBBED) called"); + std::scoped_lock lock{epolls_mutex}; + if (epollid >= epolls.size() || epolls[epollid].Destroyed()) { + 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, + timeout == -1 ? timeout : timeout / 1000); + if (result < 0) { + LOG_ERROR(Lib_Net, "epoll_wait failed with {}", Common::GetLastErrorMsg()); + return 0; + } else if (result == 0) { + LOG_DEBUG(Lib_Net, "timed out"); + return 0; + } else { + for (int i = 0; i < result; ++i) { + 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) { + return el.first == current_event.data.fd; + }); + ASSERT(it != epolls[epollid].events.end()); + events[i] = { + .events = ConvertEpollEventsOut(current_event.events), + .ident = static_cast(current_event.data.fd), + .data = it->second.data, + }; + LOG_INFO(Lib_Net, "event[{}] = ( .events = {:#x}, .ident = {}, .data = {:#x} )", i, + events[i].events, events[i].ident, events[i].data.u64); + } + return result; + } +#else + UNREACHABLE_MSG("sadness"); +#endif return ORBIS_OK; } int* PS4_SYSV_ABI sceNetErrnoLoc() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); + LOG_TRACE(Lib_Net, "called"); return &net_errno; } @@ -764,6 +966,8 @@ int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, LOG_ERROR(Lib_Net, "addr is null!"); return ORBIS_NET_EINVAL; } + LOG_DEBUG(Lib_Net, "called"); + auto* netinfo = Common::Singleton::Instance(); netinfo->RetrieveEthernetAddr(); memcpy(addr->data, netinfo->GetEthernetAddr().data(), 6); @@ -785,6 +989,8 @@ int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* pa if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "(DUMMY) called"); + int result; int err; int positiveErr; @@ -847,6 +1053,8 @@ int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* pa if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_INFO(Lib_Net, "called, s = {}", s); + int result; int err; int positiveErr; @@ -1079,6 +1287,8 @@ const char* PS4_SYSV_ABI sceNetInetNtop(int af, const void* src, char* dst, u32 LOG_ERROR(Lib_Net, "returned ORBIS_NET_ENOSPC"); return nullptr; } + LOG_DEBUG(Lib_Net, "called, af = {}"); + const char* returnvalue = nullptr; switch (af) { case ORBIS_NET_AF_INET: @@ -1095,6 +1305,8 @@ const char* PS4_SYSV_ABI sceNetInetNtop(int af, const void* src, char* dst, u32 if (returnvalue == nullptr) { *sceNetErrnoLoc() = ORBIS_NET_ENOSPC; LOG_ERROR(Lib_Net, "returned ORBIS_NET_ENOSPC"); + } else { + LOG_DEBUG(Lib_Net, "returned {}", dst); } return returnvalue; } @@ -1104,14 +1316,25 @@ int PS4_SYSV_ABI sceNetInetNtopWithScopeId() { return ORBIS_OK; } +static int ConvertFamilies(int family) { + switch (family) { + case ORBIS_NET_AF_INET: + return AF_INET; + case ORBIS_NET_AF_INET6: + return AF_INET6; + default: + UNREACHABLE_MSG("unsupported socket family {}", family); + } +} + int PS4_SYSV_ABI sceNetInetPton(int af, const char* src, void* dst) { #ifdef WIN32 int res = InetPtonA(af, src, dst); #else - int res = inet_pton(af, src, dst); + int res = inet_pton(ConvertFamilies(af), src, dst); #endif if (res < 0) { - UNREACHABLE(); + UNREACHABLE_MSG("af = {}, src = {}, dst = {:#x}", af, src, reinterpret_cast(dst)); } return res; } @@ -1155,6 +1378,8 @@ int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog) { if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "(DUMMY) called"); + int result; int err; int positiveErr; @@ -1240,6 +1465,8 @@ int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags) { if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "called, s = {}, len = {}, flags = {}", s, len, flags); + int result; int err; int positiveErr; @@ -1283,6 +1510,8 @@ int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, Orb if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + // LOG_INFO(Lib_Net, "called, s = {}, len = {}, flags = {}", s, len, flags); + int result; int err; int positiveErr; @@ -1325,6 +1554,8 @@ int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) { if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "(DUMMY) called"); + int result; int err; int positiveErr; @@ -1469,6 +1700,8 @@ int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags) { if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "called, s = {}, len = {}, flags = {}", s, len, flags); + int result; int err; int positiveErr; @@ -1511,6 +1744,8 @@ int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flag if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "(DUMMY) called"); + int result; int err; int positiveErr; @@ -1554,6 +1789,8 @@ int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags, if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "(DUMMY) called"); + int result; int err; int positiveErr; @@ -1740,6 +1977,8 @@ int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how) { if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "(DUMMY) called"); + int result; int err; int positiveErr; @@ -1782,6 +2021,9 @@ OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_INFO(Lib_Net, "name = {}, family = {}, type = {}, protocol = {}", name ? name : "no-named", + family, type, protocol); + int result; int err; int positiveErr; @@ -1790,6 +2032,7 @@ OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int result = sys_socketex(name, family, type, protocol); if (result >= 0) { + LOG_INFO(Lib_Net, "netId = {}", result); return result; // Success } @@ -1824,6 +2067,8 @@ int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags) { if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_WARNING(Lib_Net, "(DUMMY) called"); + int result; int err; int positiveErr; @@ -1866,6 +2111,8 @@ int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s) { if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } + LOG_INFO(Lib_Net, "netId = {}", s); + int result; int err; int positiveErr; diff --git a/src/core/libraries/network/net.h b/src/core/libraries/network/net.h index 626719328..2b7d42cfe 100644 --- a/src/core/libraries/network/net.h +++ b/src/core/libraries/network/net.h @@ -257,10 +257,12 @@ int PS4_SYSV_ABI sceNetDumpRead(); int PS4_SYSV_ABI sceNetDuplicateIpStart(); int PS4_SYSV_ABI sceNetDuplicateIpStop(); int PS4_SYSV_ABI sceNetEpollAbort(); -int PS4_SYSV_ABI sceNetEpollControl(); -int PS4_SYSV_ABI sceNetEpollCreate(); -int PS4_SYSV_ABI sceNetEpollDestroy(); -int PS4_SYSV_ABI sceNetEpollWait(); +int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, OrbisNetId id, + OrbisNetEpollEvent* event); +int PS4_SYSV_ABI sceNetEpollCreate(const char* name, int flags); +int PS4_SYSV_ABI sceNetEpollDestroy(OrbisNetId epollid); +int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, int maxevents, + int timeout); int* PS4_SYSV_ABI sceNetErrnoLoc(); int PS4_SYSV_ABI sceNetEtherNtostr(); int PS4_SYSV_ABI sceNetEtherStrton();