diff --git a/.gitmodules b/.gitmodules index 25b5d307b..a3798e704 100644 --- a/.gitmodules +++ b/.gitmodules @@ -106,3 +106,9 @@ [submodule "externals/libusb"] path = externals/libusb url = https://github.com/libusb/libusb-cmake.git +[submodule "externals/wepoll"] + path = externals/wepoll + url = https://github.com/piscisaureus/wepoll.git +[submodule "externals/epoll-shim"] + path = externals/epoll-shim + url = https://github.com/jiixyj/epoll-shim.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 24a81243f..877a9c6da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -246,6 +246,7 @@ find_package(pugixml 1.14 CONFIG) find_package(libusb 1.0.27 MODULE) if (APPLE) find_package(date 3.0.1 CONFIG) + find_package(epoll-shim 3.14 CONFIG) endif() list(POP_BACK CMAKE_MODULE_PATH) @@ -378,6 +379,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 @@ -1173,7 +1176,7 @@ if (APPLE) endif() # Replacement for std::chrono::time_zone - target_link_libraries(shadps4 PRIVATE date::date-tz) + target_link_libraries(shadps4 PRIVATE date::date-tz epoll-shim) endif() if (ENABLE_QT_GUI) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 89b0fbfdd..4d7e3db04 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -140,6 +140,8 @@ endif() # sirit add_subdirectory(sirit) if (WIN32) + add_library(wepoll wepoll/wepoll.c) + target_include_directories(wepoll INTERFACE wepoll/) target_compile_options(sirit PUBLIC "-Wno-error=unused-command-line-argument") endif() @@ -229,4 +231,8 @@ if (APPLE) if (NOT TARGET MoltenVK) add_subdirectory(MoltenVK) endif() + + if (NOT TARGET epoll-shim) + add_subdirectory(epoll-shim) + endif() endif() diff --git a/externals/epoll-shim b/externals/epoll-shim new file mode 160000 index 000000000..18159584b --- /dev/null +++ b/externals/epoll-shim @@ -0,0 +1 @@ +Subproject commit 18159584bb3d17e601b9315a7398ace018251bdc diff --git a/externals/wepoll b/externals/wepoll new file mode 160000 index 000000000..0598a791b --- /dev/null +++ b/externals/wepoll @@ -0,0 +1 @@ +Subproject commit 0598a791bf9cbbf480793d778930fc635b044980 diff --git a/src/common/config.cpp b/src/common/config.cpp index a1b12ee5d..9caccac4d 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -47,6 +47,7 @@ static bool isShowSplash = false; static std::string isSideTrophy = "right"; static bool compatibilityData = false; static bool checkCompatibilityOnStartup = false; +static bool isConnectedToNetwork = false; // Input static int cursorState = HideCursorState::Idle; @@ -107,7 +108,7 @@ u32 m_language = 1; // english static std::string trophyKey = ""; // Expected number of items in the config file -static constexpr u64 total_entries = 54; +static constexpr u64 total_entries = 55; int getVolumeSlider() { return volumeSlider; @@ -353,6 +354,10 @@ bool getCheckCompatibilityOnStartup() { return checkCompatibilityOnStartup; } +bool getIsConnectedToNetwork() { + return isConnectedToNetwork; +} + void setGpuId(s32 selectedGpuId) { gpuId = selectedGpuId; } @@ -636,6 +641,9 @@ void load(const std::filesystem::path& path) { compatibilityData = toml::find_or(general, "compatibilityEnabled", compatibilityData); checkCompatibilityOnStartup = toml::find_or(general, "checkCompatibilityOnStartup", checkCompatibilityOnStartup); + + isConnectedToNetwork = + toml::find_or(general, "isConnectedToNetwork", isConnectedToNetwork); chooseHomeTab = toml::find_or(general, "chooseHomeTab", chooseHomeTab); entry_count += general.size(); @@ -830,6 +838,7 @@ void save(const std::filesystem::path& path) { data["General"]["sideTrophy"] = isSideTrophy; data["General"]["compatibilityEnabled"] = compatibilityData; data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup; + data["General"]["isConnectedToNetwork"] = isConnectedToNetwork; data["Input"]["cursorState"] = cursorState; data["Input"]["cursorHideTimeout"] = cursorHideTimeout; data["Input"]["useSpecialPad"] = useSpecialPad; @@ -926,6 +935,7 @@ void setDefaultValues() { isSideTrophy = "right"; compatibilityData = false; checkCompatibilityOnStartup = false; + isConnectedToNetwork = false; // Input cursorState = HideCursorState::Idle; diff --git a/src/common/config.h b/src/common/config.h index 4ace4d316..8eb17547c 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -111,6 +111,7 @@ std::filesystem::path GetSaveDataPath(); void setLoadGameSizeEnabled(bool enable); bool getCompatibilityEnabled(); bool getCheckCompatibilityOnStartup(); +bool getIsConnectedToNetwork(); std::string getUserName(); std::string getChooseHomeTab(); bool GetUseUnifiedInputConfig(); diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index 4a2aa56c1..714405493 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -11,6 +11,7 @@ #include "common/io_file.h" #include "common/logging/formatter.h" #include "core/devices/base_device.h" +#include "core/libraries/network/sockets.h" namespace Core::FileSys { @@ -77,6 +78,7 @@ enum class FileType { Regular, // standard file Directory, Device, + Socket, }; struct File { @@ -88,7 +90,8 @@ struct File { std::vector dirents; u32 dirents_index; std::mutex m_mutex; - std::shared_ptr device; // only valid for type == Device + std::shared_ptr device; // only valid for type == Device + std::shared_ptr socket; // only valid for type == Socket }; class HandleTable { diff --git a/src/core/libraries/kernel/equeue.cpp b/src/core/libraries/kernel/equeue.cpp index 4d1b116c5..a444b4ad6 100644 --- a/src/core/libraries/kernel/equeue.cpp +++ b/src/core/libraries/kernel/equeue.cpp @@ -6,6 +6,8 @@ #include "common/assert.h" #include "common/debug.h" #include "common/logging/log.h" +#include "common/singleton.h" +#include "core/file_sys/fs.h" #include "core/libraries/kernel/equeue.h" #include "core/libraries/kernel/orbis_error.h" #include "core/libraries/libs.h" @@ -412,6 +414,34 @@ int PS4_SYSV_ABI sceKernelDeleteTimerEvent(SceKernelEqueue eq, int id) { : ORBIS_KERNEL_ERROR_ENOENT; } +int PS4_SYSV_ABI sceKernelAddReadEvent(SceKernelEqueue eq, int fd, size_t size, void* udata) { + if (eq == nullptr) { + return ORBIS_KERNEL_ERROR_EBADF; + } + LOG_ERROR(Kernel_Event, "(DUMMY) eq = {}, fd = {}, size = {}, udata = {:#x}", eq->GetName(), fd, + size, reinterpret_cast(udata)); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(fd); + if (!file) { + return ORBIS_KERNEL_ERROR_EBADF; + } + + EqueueEvent event{}; + event.event.ident = static_cast(fd); + event.event.filter = SceKernelEvent::Filter::Read; + event.event.flags = SceKernelEvent::Flags::Add; + event.event.fflags = 0; + event.event.data = size; + event.event.udata = udata; + + if (!eq->AddEvent(event)) { + return ORBIS_KERNEL_ERROR_ENOMEM; + } + + return ORBIS_OK; +} + int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) { if (eq == nullptr) { return ORBIS_KERNEL_ERROR_EBADF; @@ -488,6 +518,7 @@ void RegisterEventQueue(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEqueue); LIB_FUNCTION("fzyMKs9kim0", "libkernel", 1, "libkernel", 1, 1, sceKernelWaitEqueue); LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData); + LIB_FUNCTION("VHCS3rCd0PM", "libkernel", 1, "libkernel", 1, 1, sceKernelAddReadEvent); LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent); LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge); LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent); diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 7b9f40262..f499a8661 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -23,6 +23,13 @@ #include "core/memory.h" #include "kernel.h" +#ifdef _WIN32 +#include +#include +#else +#include +#endif + namespace D = Core::Devices; using FactoryDevice = std::function(u32, const char*, int, u16)>; @@ -257,6 +264,8 @@ s32 PS4_SYSV_ABI close(s32 fd) { } if (file->type == Core::FileSys::FileType::Regular) { file->f.Close(); + } else if (file->type == Core::FileSys::FileType::Regular) { + file->socket->Close(); } file->is_opened = false; LOG_INFO(Kernel_Fs, "Closing {}", file->m_guest_name); @@ -294,6 +303,13 @@ s64 PS4_SYSV_ABI write(s32 fd, const void* buf, size_t nbytes) { return -1; } return result; + } else if (file->type == Core::FileSys::FileType::Socket) { + s64 result = file->socket->write(buf, nbytes); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; } return file->f.WriteRaw(buf, nbytes); @@ -475,6 +491,13 @@ s64 PS4_SYSV_ABI read(s32 fd, void* buf, size_t nbytes) { return -1; } return result; + } else if (file->type == Core::FileSys::FileType::Socket) { + s64 result = file->socket->read(buf, nbytes); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; } return ReadFile(file->f, buf, nbytes); } @@ -667,6 +690,14 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) { // TODO incomplete break; } + case Core::FileSys::FileType::Socket: { + s32 result = file->socket->fstat(sb); + if (result < 0) { + ErrSceToPosix(result); + return -1; + } + return result; + } default: UNREACHABLE(); } @@ -1055,6 +1086,240 @@ s32 PS4_SYSV_ABI sceKernelUnlink(const char* path) { return result; } +s32 PS4_SYSV_ABI posix_select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, + OrbisKernelTimeval* timeout) { + LOG_INFO(Kernel_Fs, "nfds = {}, readfds = {}, writefds = {}, exceptfds = {}, timeout = {}", + nfds, fmt::ptr(readfds), fmt::ptr(writefds), fmt::ptr(exceptfds), fmt::ptr(timeout)); + + fd_set read_host, write_host, except_host; + FD_ZERO(&read_host); + FD_ZERO(&write_host); + FD_ZERO(&except_host); + + auto* h = Common::Singleton::Instance(); + +#ifdef _WIN32 + + // Separate sockets for select() + for (auto i = 0; i < nfds; ++i) { + auto read = readfds && FD_ISSET(i, readfds); + auto write = writefds && FD_ISSET(i, writefds); + auto except = exceptfds && FD_ISSET(i, exceptfds); + if (read || write || except) { + LOG_INFO(Kernel_Fs, "guest fd {} expected", i); + auto* file = h->GetFile(i); + if (file == nullptr || + ((file->type == Core::FileSys::FileType::Regular && !file->f.IsOpen()) || + (file->type == Core::FileSys::FileType::Socket && !file->is_opened))) { + LOG_ERROR(Kernel_Fs, "fd {} is null or not opened", i); + *__Error() = POSIX_EBADF; + return -1; + } + + if (file->type != Core::FileSys::FileType::Socket) { + LOG_WARNING(Kernel_Fs, "fd {} is not a socket, ignoring", i); + continue; + } + + auto fd = [&] { + switch (file->type) { + case Core::FileSys::FileType::Socket: + return file->socket->Native(); + default: + UNREACHABLE(); + } + }(); + + if (read) { + FD_SET(fd, &read_host); + continue; + } + if (write) { + FD_SET(fd, &write_host); + continue; + } + if (except) { + FD_SET(fd, &except_host); + continue; + } + } + } + + int result = + select(0, &read_host, &write_host, &except_host, reinterpret_cast(timeout)); + int total_ready = result; + + for (int fd = 0; fd < nfds; ++fd) { + auto* file = h->GetFile(fd); + + if (file->type == Core::FileSys::FileType::Socket) { + auto sock = file->socket->Native(); + if (readfds && !(FD_ISSET(sock, &read_host))) { + FD_CLR(fd, &readfds); + } + if (writefds && !(FD_ISSET(sock, &write_host))) { + FD_CLR(fd, &writefds); + } + if (exceptfds && !(FD_ISSET(sock, &except_host))) { + FD_CLR(fd, &exceptfds); + } + continue; + } + + HANDLE h = (HANDLE)_get_osfhandle(fd); + DWORD type = GetFileType(h); + if (type == FILE_TYPE_UNKNOWN) + continue; + + // READ check + if (readfds && FD_ISSET(fd, readfds)) { + if (type == FILE_TYPE_PIPE) { + DWORD avail = 0; + if (PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL) && avail > 0) { + total_ready++; + } else { + FD_CLR(fd, readfds); + } + } else if (type == FILE_TYPE_DISK) { + char tmp; + long pos = _lseek(fd, 0, SEEK_CUR); + if (_read(fd, &tmp, 1) > 0) { + _lseek(fd, pos, SEEK_SET); + total_ready++; + } else { + FD_CLR(fd, readfds); + } + } + } + + // WRITE check + if (writefds && FD_ISSET(fd, writefds)) { + DWORD written = 0; + char dummy = 0; + BOOL writable = FALSE; + if (type == FILE_TYPE_PIPE) { + // Try writing 0 bytes to check if it's broken + writable = WriteFile(h, &dummy, 0, &written, NULL); + } else if (type == FILE_TYPE_DISK) { + writable = true; // Disk files are always "writable" + } + if (writable) { + total_ready++; + } else { + FD_CLR(fd, writefds); + } + } + + // EXCEPTION check + if (exceptfds && FD_ISSET(fd, exceptfds)) { + DWORD err = 0, size = sizeof(err); + BOOL error_detected = false; + + if (type == FILE_TYPE_PIPE) { + // Check broken pipe by trying non-blocking zero write + DWORD written; + char tmp = 0; + if (!WriteFile(h, &tmp, 0, &written, NULL)) { + DWORD e = GetLastError(); + if (e == ERROR_NO_DATA || e == ERROR_BROKEN_PIPE) { + error_detected = true; + } + } + } + + if (error_detected) { + total_ready++; + } else { + FD_CLR(fd, exceptfds); + } + } + } + + return total_ready; + +#else + + std::map host_to_guest; + int max_fd = 0; + + for (auto i = 0; i < nfds; ++i) { + auto read = readfds && FD_ISSET(i, readfds); + auto write = writefds && FD_ISSET(i, writefds); + auto except = exceptfds && FD_ISSET(i, exceptfds); + if (read || write || except) { + LOG_DEBUG(Kernel_Fs, "guest fd {} expected", i); + auto* file = h->GetFile(i); + if (file == nullptr || + ((file->type == Core::FileSys::FileType::Regular && !file->f.IsOpen()) || + (file->type == Core::FileSys::FileType::Socket && !file->is_opened))) { + LOG_ERROR(Kernel_Fs, "fd {} is null or not opened", i); + *__Error() = POSIX_EBADF; + return -1; + } + + int fd = [&] { + switch (file->type) { + case Core::FileSys::FileType::Regular: + return static_cast(file->f.GetFileMapping()); + case Core::FileSys::FileType::Socket: + return file->socket->Native(); + default: + UNREACHABLE(); + } + }(); + host_to_guest.emplace(fd, i); + + max_fd = std::max(max_fd, fd); + + if (read) { + FD_SET(fd, &read_host); + continue; + } + if (write) { + FD_SET(fd, &write_host); + continue; + } + if (except) { + FD_SET(fd, &except_host); + continue; + } + } + } + + int ret = select(max_fd + 1, &read_host, &write_host, &except_host, (timeval*)timeout); + LOG_DEBUG(Kernel_Fs, "select = {}", ret); + + if (ret > 0) { + if (readfds) { + FD_ZERO(readfds); + } + if (writefds) { + FD_ZERO(writefds); + } + if (exceptfds) { + FD_ZERO(exceptfds); + } + + for (auto i = 0; i < max_fd + 1; ++i) { + if (FD_ISSET(i, &read_host)) { + LOG_DEBUG(Kernel_Fs, "host fd {} (guest {}) ready for reading", i, host_to_guest[i]); + FD_SET(host_to_guest[i], readfds); + } + if (FD_ISSET(i, &write_host)) { + LOG_DEBUG(Kernel_Fs, "host fd {} (guest {}) ready for writing", i, host_to_guest[i]); + FD_SET(host_to_guest[i], writefds); + } + if (FD_ISSET(i, &except_host)) { + LOG_DEBUG(Kernel_Fs, "host fd {} (guest {}) ready for except", i, host_to_guest[i]); + FD_SET(host_to_guest[i], exceptfds); + } + } + } + + return ret; +#endif +} + void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1, open); LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open); @@ -1112,6 +1377,8 @@ void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite); LIB_FUNCTION("mBd4AfLP+u8", "libkernel", 1, "libkernel", 1, 1, sceKernelPwritev); LIB_FUNCTION("AUXVxWeJU-A", "libkernel", 1, "libkernel", 1, 1, sceKernelUnlink); + LIB_FUNCTION("T8fER+tIGgk", "libScePosix", 1, "libkernel", 1, 1, posix_select); + LIB_FUNCTION("T8fER+tIGgk", "libkernel", 1, "libkernel", 1, 1, posix_select); } } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index e18a91d05..ce028fe72 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -222,16 +222,18 @@ s32 PS4_SYSV_ABI posix_getpagesize() { s32 PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s, Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_DEBUG(Lib_Net, "s = {}", s); + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; s32 returncode = sock->GetSocketAddress(addr, paddrlen); if (returncode >= 0) { - LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode); + LOG_DEBUG(Lib_Net, "return code : {:#x}", (u32)returncode); return 0; } *Libraries::Kernel::__Error() = 0x20; @@ -299,11 +301,13 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("pxnCmagrtao", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_listen); LIB_FUNCTION("3e+4Iv7IJ8U", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_accept); LIB_FUNCTION("TU-d9PfIHPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_socket); + LIB_FUNCTION("fZOeZIOEmLw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_send); LIB_FUNCTION("oBr313PppNE", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto); + LIB_FUNCTION("Ez8xjo9UF4E", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recv); LIB_FUNCTION("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom); LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_setsockopt); - // LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, posix_getsockname); + LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, posix_getsockname); LIB_FUNCTION("KuOmgKoqCdY", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_bind); LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ... diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index e0c359f2c..e506c29e9 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -318,6 +318,10 @@ s32 PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) { return memory->IsStack(std::bit_cast(addr), start, end); } +u32 PS4_SYSV_ABI sceKernelIsAddressSanitizerEnabled() { + return ORBIS_OK; +} + s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, s32 numEntries, s32* numEntriesOut) { return sceKernelBatchMap2(entries, numEntries, numEntriesOut, @@ -689,6 +693,8 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType); LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize); LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack); + LIB_FUNCTION("jh+8XiK4LeE", "libkernel", 1, "libkernel", 1, 1, + sceKernelIsAddressSanitizerEnabled); LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory); LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory); LIB_FUNCTION("BQQniolj9tQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory2); diff --git a/src/core/libraries/kernel/threads/condvar.cpp b/src/core/libraries/kernel/threads/condvar.cpp index 0b0545ace..0d1ef5c6a 100644 --- a/src/core/libraries/kernel/threads/condvar.cpp +++ b/src/core/libraries/kernel/threads/condvar.cpp @@ -341,6 +341,8 @@ void RegisterCond(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("mKoTx03HRWA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_condattr_init); LIB_FUNCTION("dJcuQVn6-Iw", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_condattr_destroy); + LIB_FUNCTION("EjllaAqAPZo", "libScePosix", 1, "libkernel", 1, 1, + posix_pthread_condattr_setclock); LIB_FUNCTION("0TyVk4MSLt0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_init); LIB_FUNCTION("2MOy+rUfuhQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_signal); LIB_FUNCTION("RXXqi4CtF8w", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_destroy); diff --git a/src/core/libraries/kernel/threads/pthread.cpp b/src/core/libraries/kernel/threads/pthread.cpp index 59b427d22..0855c804e 100644 --- a/src/core/libraries/kernel/threads/pthread.cpp +++ b/src/core/libraries/kernel/threads/pthread.cpp @@ -324,6 +324,10 @@ PthreadT PS4_SYSV_ABI posix_pthread_self() { return g_curthread; } +void PS4_SYSV_ABI posix_pthread_set_name_np(PthreadT thread, const char* name) { + Common::SetCurrentThreadName(name); +} + void PS4_SYSV_ABI posix_pthread_yield() { std::this_thread::yield(); } @@ -332,6 +336,14 @@ void PS4_SYSV_ABI sched_yield() { std::this_thread::yield(); } +int PS4_SYSV_ABI posix_getpid() { +#ifdef _WIN32 + return GetCurrentProcessId(); +#else + return getpid(); +#endif +} + int PS4_SYSV_ABI posix_pthread_once(PthreadOnce* once_control, void PS4_SYSV_ABI (*init_routine)()) { for (;;) { @@ -644,9 +656,11 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("Jmi+9w9u0E4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_create_name_np); LIB_FUNCTION("lZzFeSxPl08", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setcancelstate); LIB_FUNCTION("a2P9wYGeZvc", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setprio); + LIB_FUNCTION("9vyP6Z7bqzc", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_rename_np); LIB_FUNCTION("FIs3-UQT9sg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_getschedparam); LIB_FUNCTION("Xs9hdiD7sAA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setschedparam); LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield); + LIB_FUNCTION("HoLVWNanBBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpid); // Posix-Kernel LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_once); @@ -669,6 +683,7 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("How7B8Oet6k", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_getname_np)); LIB_FUNCTION("3kg7rT0NQIs", "libkernel", 1, "libkernel", 1, 1, posix_pthread_exit); LIB_FUNCTION("aI+OeCz8xrQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self); + LIB_FUNCTION("oxMp8uPqa+U", "libkernel", 1, "libkernel", 1, 1, posix_pthread_set_name_np); LIB_FUNCTION("3PtV6p3QNX4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_equal); LIB_FUNCTION("T72hz6ffq08", "libkernel", 1, "libkernel", 1, 1, posix_pthread_yield); LIB_FUNCTION("EI-5-jlq2dE", "libkernel", 1, "libkernel", 1, 1, posix_pthread_getthreadid_np); @@ -676,6 +691,7 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("W0Hpm2X0uPE", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_setprio)); LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors); LIB_FUNCTION("6XG4B33N09g", "libkernel", 1, "libkernel", 1, 1, sched_yield); + LIB_FUNCTION("HoLVWNanBBc", "libkernel", 1, "libkernel", 1, 1, posix_getpid); LIB_FUNCTION("rcrVFJsQWRY", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadGetaffinity)); LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadSetaffinity)); } diff --git a/src/core/libraries/kernel/threads/pthread_attr.cpp b/src/core/libraries/kernel/threads/pthread_attr.cpp index e098b00a4..fd27fb3fe 100644 --- a/src/core/libraries/kernel/threads/pthread_attr.cpp +++ b/src/core/libraries/kernel/threads/pthread_attr.cpp @@ -289,10 +289,14 @@ int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const u64 mask) { void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) { // Posix LIB_FUNCTION("wtkt-teR1so", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_init); + LIB_FUNCTION("vQm4fDEsWi8", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_getstack); LIB_FUNCTION("2Q0z6rnBrTE", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_setstacksize); + LIB_FUNCTION("Ucsu-OK+els", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_get_np); LIB_FUNCTION("RtLRV-pBTTY", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_getschedpolicy); + LIB_FUNCTION("JarMIy8kKEY", "libkernel", 1, "libkernel", 1, 1, + posix_pthread_attr_setschedpolicy); LIB_FUNCTION("E+tyo3lp5Lw", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_setdetachstate); LIB_FUNCTION("zHchY8ft5pk", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_destroy); diff --git a/src/core/libraries/network/http.cpp b/src/core/libraries/network/http.cpp index f7cbed931..7d43c61a5 100644 --- a/src/core/libraries/network/http.cpp +++ b/src/core/libraries/network/http.cpp @@ -492,8 +492,9 @@ int PS4_SYSV_ABI sceHttpsFreeCaList() { return ORBIS_OK; } -int PS4_SYSV_ABI sceHttpsGetCaList() { - LOG_ERROR(Lib_Http, "(STUBBED) called"); +int PS4_SYSV_ABI sceHttpsGetCaList(int httpCtxId, OrbisHttpsCaList* list) { + LOG_ERROR(Lib_Http, "(DUMMY) called, httpCtxId = {}", httpCtxId); + list->certsNum = 0; return ORBIS_OK; } diff --git a/src/core/libraries/network/http.h b/src/core/libraries/network/http.h index cc9ca57af..228080207 100644 --- a/src/core/libraries/network/http.h +++ b/src/core/libraries/network/http.h @@ -4,6 +4,7 @@ #pragma once #include "common/types.h" +#include "core/libraries/network/ssl.h" namespace Core::Loader { class SymbolsResolver; @@ -24,6 +25,8 @@ struct OrbisHttpUriElement { u8 reserved[10]; }; +using OrbisHttpsCaList = Libraries::Ssl::OrbisSslCaList; + int PS4_SYSV_ABI sceHttpAbortRequest(); int PS4_SYSV_ABI sceHttpAbortRequestForce(); int PS4_SYSV_ABI sceHttpAbortWaitRequest(); @@ -120,7 +123,7 @@ int PS4_SYSV_ABI sceHttpSetResponseHeaderMaxSize(); int PS4_SYSV_ABI sceHttpSetSendTimeOut(); int PS4_SYSV_ABI sceHttpSetSocketCreationCallback(); int PS4_SYSV_ABI sceHttpsFreeCaList(); -int PS4_SYSV_ABI sceHttpsGetCaList(); +int PS4_SYSV_ABI sceHttpsGetCaList(int httpCtxId, OrbisHttpsCaList* list); int PS4_SYSV_ABI sceHttpsGetSslError(); int PS4_SYSV_ABI sceHttpsLoadCert(); int PS4_SYSV_ABI sceHttpsSetMinSslVersion(); diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp index 6df4f2f40..d90de1529 100644 --- a/src/core/libraries/network/net.cpp +++ b/src/core/libraries/network/net.cpp @@ -11,15 +11,20 @@ #endif #include +#include #include "common/assert.h" +#include "common/error.h" #include "common/logging/log.h" #include "common/singleton.h" +#include "core/file_sys/fs.h" #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" namespace Libraries::Net { @@ -72,6 +77,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 +176,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 +560,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 +675,156 @@ int PS4_SYSV_ABI sceNetEpollAbort() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetEpollControl() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); +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); + + auto epoll = Common::Singleton::Instance()->GetEpoll(epollid); + if (!epoll) { + return -ORBIS_NET_EBADF; + } + + auto find_id = [&](OrbisNetId id) { + return std::ranges::find_if(epoll->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) != epoll->events.end()) { + return -ORBIS_NET_EEXIST; + } + +#ifdef __linux__ + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(id); + if (!file || file->type != Core::FileSys::FileType::Socket) { + return -ORBIS_NET_EBADF; + } + const auto socket = file->socket; + epoll_event native_event = {.events = ConvertEpollEventsIn(event->events), + .data = {.fd = id}}; + ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_ADD, socket->Native(), &native_event) == 0); + LOG_DEBUG(Lib_Net, "epoll_ctl succeeded"); +#endif + epoll->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 == epoll->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 == epoll->events.end()) { + return -ORBIS_NET_EBADF; + } + +#ifdef __linux__ + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(id); + if (!file || file->type != Core::FileSys::FileType::Socket) { + return -ORBIS_NET_EBADF; + } + const auto socket = file->socket; + ASSERT(epoll_ctl(epoll->epoll_fd, EPOLL_CTL_DEL, socket->Native(), nullptr) == 0); +#endif + epoll->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; + } + + auto epoll = Common::Singleton::Instance()->CreateHandle(name); + + return epoll; +} + +int PS4_SYSV_ABI sceNetEpollDestroy(OrbisNetId epollid) { + LOG_INFO(Lib_Net, "called, epollid = {}", epollid); + + auto epoll = Common::Singleton::Instance()->GetEpoll(epollid); + if (!epoll) { + return -ORBIS_NET_EBADF; + } + + epoll->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"); + 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(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()); + 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( + epoll->events, [&](auto& el) { return el.first == current_event.data.fd; }); + ASSERT(it != epoll->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.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 +903,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 +926,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 +990,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 +1224,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 = {}", af); + const char* returnvalue = nullptr; switch (af) { case ORBIS_NET_AF_INET: @@ -1095,6 +1242,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,21 +1253,32 @@ 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 = {}", af, src, fmt::ptr(dst)); } return res; } -int PS4_SYSV_ABI sceNetInetPtonEx() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetInetPtonEx(int af, const char* src, void* dst, int flags) { + LOG_WARNING(Lib_Net, "ignored flags, redirecting to sceNetInetPton"); + return sceNetInetPton(af, src, dst); } int PS4_SYSV_ABI sceNetInetPtonWithScopeId() { @@ -1155,6 +1315,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 +1402,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 +1447,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 +1491,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; @@ -1388,12 +1556,13 @@ int PS4_SYSV_ABI sceNetResolverConnectDestroy() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetResolverCreate() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +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++; } -int PS4_SYSV_ABI sceNetResolverDestroy() { +int PS4_SYSV_ABI sceNetResolverDestroy(OrbisNetId resolverid) { LOG_ERROR(Lib_Net, "(STUBBED) called"); return ORBIS_OK; } @@ -1413,9 +1582,44 @@ int PS4_SYSV_ABI sceNetResolverStartAton6() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetResolverStartNtoa() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetResolverStartNtoa(OrbisNetId resolverid, const char* hostname, + OrbisNetInAddr* addr, int timeout, int retry, int flags) { + LOG_INFO(Lib_Net, + "called, resolverid = {}, hostname = {}, timeout = {}, retry = {}, flags = {}", + resolverid, hostname, timeout, retry, flags); + + 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; + } + + 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_strerror(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; + } + + freeaddrinfo(info); + return ret; } int PS4_SYSV_ABI sceNetResolverStartNtoa6() { @@ -1423,9 +1627,21 @@ int PS4_SYSV_ABI sceNetResolverStartNtoa6() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords(OrbisNetId resolverid, const char* hostname, + OrbisNetResolverInfo* info, int timeout, + int retry, int flags) { + LOG_WARNING(Lib_Net, "redirected to sceNetResolverStartNtoa"); + + OrbisNetInAddr addr{}; + auto result = sceNetResolverStartNtoa(resolverid, hostname, &addr, timeout, retry, flags); + + if (result == ORBIS_OK) { + info->addrs[0] = {.u = {.addr = addr}, .af = ORBIS_NET_AF_INET}; + info->records = 1; + info->recordsv4 = 1; + } + + return result; } int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx() { @@ -1437,6 +1653,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; @@ -1479,6 +1697,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; @@ -1522,6 +1742,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; @@ -1708,6 +1930,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; @@ -1750,6 +1974,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; @@ -1758,6 +1985,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 } @@ -1792,6 +2020,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; @@ -1834,6 +2064,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; @@ -2097,12 +2329,14 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("rMyh97BU5pY", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetMemoryPoolStats); LIB_FUNCTION("+S-2-jlpaBo", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetNameToIndex); LIB_FUNCTION("TCkRD0DWNLg", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetpeername); + LIB_FUNCTION("TXFFFiNldU8", "libScePosix", 1, "libkernel", 1, 1, sys_getpeername); LIB_FUNCTION("G3O2j9f5z00", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetRandom); LIB_FUNCTION("6Nx1hIQL9h8", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetRouteInfo); LIB_FUNCTION("hLuXdjHnhiI", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSockInfo); LIB_FUNCTION("Cidi9Y65mP8", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSockInfo6); LIB_FUNCTION("hoOAofhhRvE", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetsockname); LIB_FUNCTION("xphrZusl78E", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetsockopt); + LIB_FUNCTION("6O8EwYOgH9Y", "libScePosix", 1, "libkernel", 1, 1, sys_getsockopt); LIB_FUNCTION("GA5ZDaLtUBE", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetStatisticsInfo); LIB_FUNCTION("9mIcUExH34w", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetStatisticsInfoInternal); LIB_FUNCTION("p2vxsE2U3RQ", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSystemTime); diff --git a/src/core/libraries/network/net.h b/src/core/libraries/network/net.h index 7b6a5680c..396bab42d 100644 --- a/src/core/libraries/network/net.h +++ b/src/core/libraries/network/net.h @@ -38,6 +38,7 @@ enum OrbisNetProtocol : u32 { ORBIS_NET_IPPROTO_IGMP = 2, ORBIS_NET_IPPROTO_TCP = 6, ORBIS_NET_IPPROTO_UDP = 17, + ORBIS_NET_IPPROTO_IPV6 = 41, ORBIS_NET_SOL_SOCKET = 0xFFFF }; @@ -81,6 +82,25 @@ enum OrbisNetSocketOption : u32 { ORBIS_NET_SO_PRIORITY = 0x1203 }; +enum OrbisNetEpollFlag : u32 { + ORBIS_NET_EPOLL_CTL_ADD = 1, + ORBIS_NET_EPOLL_CTL_MOD = 2, + ORBIS_NET_EPOLL_CTL_DEL = 3, +}; + +enum OrbisNetEpollEvents : u32 { + ORBIS_NET_EPOLLIN = 0x1, + ORBIS_NET_EPOLLOUT = 0x2, + ORBIS_NET_EPOLLERR = 0x8, + ORBIS_NET_EPOLLHUP = 0x10, + ORBIS_NET_EPOLLDESCID = 0x10000, +}; + +enum OrbisNetResolverFlag : u32 { + ORBIS_NET_RESOLVER_ASYNC = 0x1, + ORBIS_NET_RESOLVER_START_NTOA_DISABLE_IPADDRESS = 0x10000, +}; + using OrbisNetId = s32; struct OrbisNetSockaddr { @@ -98,6 +118,12 @@ struct OrbisNetSockaddrIn { char sin_zero[6]; }; +using OrbisNetInAddr_t = u32; + +struct OrbisNetInAddr { + OrbisNetInAddr_t inaddr_addr; +}; + struct OrbisNetIovec { void* iov_base; u64 iov_len; @@ -113,6 +139,38 @@ struct OrbisNetMsghdr { int msg_flags; }; +union OrbisNetEpollData { + void* ptr; + u32 data_u32; + int fd; + u64 data_u64; +}; + +struct OrbisNetEpollEvent { + u32 events; + u32 pad; + u64 ident; + OrbisNetEpollData data; +}; + +union OrbisNetAddrUnion { + OrbisNetInAddr addr; + u8 addr6[16]; +}; + +struct OrbisNetResolverAddr { + OrbisNetAddrUnion u; + u32 af; + u32 pad[3]; +}; + +struct OrbisNetResolverInfo { + OrbisNetResolverAddr addrs[10]; + u32 records; + u32 recordsv4; + u32 pad[14]; +}; + int PS4_SYSV_ABI in6addr_any(); int PS4_SYSV_ABI in6addr_loopback(); int PS4_SYSV_ABI sce_net_dummy(); @@ -218,10 +276,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(); @@ -256,7 +316,7 @@ u16 PS4_SYSV_ABI sceNetHtons(u16 host16); const char* PS4_SYSV_ABI sceNetInetNtop(int af, const void* src, char* dst, u32 size); int PS4_SYSV_ABI sceNetInetNtopWithScopeId(); int PS4_SYSV_ABI sceNetInetPton(int af, const char* src, void* dst); -int PS4_SYSV_ABI sceNetInetPtonEx(); +int PS4_SYSV_ABI sceNetInetPtonEx(int af, const char* src, void* dst, int flags); int PS4_SYSV_ABI sceNetInetPtonWithScopeId(); int PS4_SYSV_ABI sceNetInfoDumpStart(); int PS4_SYSV_ABI sceNetInfoDumpStop(); @@ -282,14 +342,17 @@ int PS4_SYSV_ABI sceNetResolverConnect(); int PS4_SYSV_ABI sceNetResolverConnectAbort(); int PS4_SYSV_ABI sceNetResolverConnectCreate(); int PS4_SYSV_ABI sceNetResolverConnectDestroy(); -int PS4_SYSV_ABI sceNetResolverCreate(); -int PS4_SYSV_ABI sceNetResolverDestroy(); +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 sceNetResolverStartAton(); int PS4_SYSV_ABI sceNetResolverStartAton6(); -int PS4_SYSV_ABI sceNetResolverStartNtoa(); +int PS4_SYSV_ABI sceNetResolverStartNtoa(OrbisNetId resolverid, const char* hostname, + OrbisNetInAddr* addr, int timeout, int retry, int flags); int PS4_SYSV_ABI sceNetResolverStartNtoa6(); -int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords(); +int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords(OrbisNetId resolverid, const char* hostname, + OrbisNetResolverInfo* info, int timeout, + int retry, int flags); int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx(); int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags); int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags); diff --git a/src/core/libraries/network/net_ctl_obj.cpp b/src/core/libraries/network/net_ctl_obj.cpp index ad944cd9c..a295477b6 100644 --- a/src/core/libraries/network/net_ctl_obj.cpp +++ b/src/core/libraries/network/net_ctl_obj.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include "common/config.h" +#include "common/logging/log.h" #include "core/libraries/network/net_ctl_codes.h" #include "core/libraries/network/net_ctl_obj.h" #include "core/tls.h" @@ -44,18 +46,22 @@ s32 NetCtlInternal::RegisterNpToolkitCallback(OrbisNetCtlCallbackForNpToolkit fu void NetCtlInternal::CheckCallback() { std::scoped_lock lock{m_mutex}; + const auto event = Config::getIsConnectedToNetwork() ? ORBIS_NET_CTL_EVENT_TYPE_IPOBTAINED + : ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED; for (const auto [func, arg] : callbacks) { if (func != nullptr) { - Core::ExecuteGuest(func, ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED, arg); + Core::ExecuteGuest(func, event, arg); } } } void NetCtlInternal::CheckNpToolkitCallback() { std::scoped_lock lock{m_mutex}; + const auto event = Config::getIsConnectedToNetwork() ? ORBIS_NET_CTL_EVENT_TYPE_IPOBTAINED + : ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED; for (const auto [func, arg] : nptool_callbacks) { if (func != nullptr) { - Core::ExecuteGuest(func, ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED, arg); + Core::ExecuteGuest(func, event, arg); } } } diff --git a/src/core/libraries/network/net_epoll.cpp b/src/core/libraries/network/net_epoll.cpp new file mode 100644 index 000000000..e64c8ac64 --- /dev/null +++ b/src/core/libraries/network/net_epoll.cpp @@ -0,0 +1,72 @@ +// 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 epollid) { + std::scoped_lock lock{m_mutex}; + if (epollid >= epolls.size() || epolls[epollid].Destroyed()) { + return nullptr; + } + + return &epolls[epollid]; +} + +} // 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..c32db254b --- /dev/null +++ b/src/core/libraries/network/net_epoll.h @@ -0,0 +1,75 @@ +// 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 + +#ifdef _WIN32 +#include +#endif + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif + +namespace Libraries::Net { + +#ifdef _WIN32 +using epoll_handle = HANDLE; +#else +using epoll_handle = int; +#endif + +struct Epoll { + std::vector> events{}; + const char* name; + epoll_handle 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(); +#ifdef _WIN32 + epoll_close(epoll_fd); +#else + close(epoll_fd); +#endif + 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 diff --git a/src/core/libraries/network/net_util.cpp b/src/core/libraries/network/net_util.cpp index d0f0a81da..3e6aa9eeb 100644 --- a/src/core/libraries/network/net_util.cpp +++ b/src/core/libraries/network/net_util.cpp @@ -11,6 +11,7 @@ typedef int socklen_t; #else #include #include +#include #include #include #include @@ -21,9 +22,13 @@ typedef int socklen_t; typedef int net_socket; #endif #if defined(__APPLE__) -#include #include #endif +#if __linux__ +#include +#include +#include +#endif #include #include @@ -100,6 +105,8 @@ bool NetUtilInternal::RetrieveEthernetAddr() { } } + close(sock); + if (success) { memcpy(ether_address.data(), ifr.ifr_hwaddr.sa_data, 6); return true; @@ -107,4 +114,104 @@ bool NetUtilInternal::RetrieveEthernetAddr() { #endif return false; } + +const std::string& NetUtilInternal::GetDefaultGateway() const { + return default_gateway; +} + +bool NetUtilInternal::RetrieveDefaultGateway() { + std::scoped_lock lock{m_mutex}; + +#ifdef _WIN32 + +#elif defined(__APPLE__) + +#else + std::ifstream route{"/proc/net/route"}; + std::string line; + + std::getline(route, line); + while (std::getline(route, line)) { + std::istringstream iss{line}; + std::string iface, destination, gateway; + int flags; + + iss >> iface >> destination >> gateway >> std::hex >> flags; + + if (destination == "00000000") { + u64 default_gateway{}; + std::stringstream ss; + ss << std::hex << gateway; + ss >> default_gateway; + + in_addr addr; + addr.s_addr = default_gateway; + this->default_gateway = inet_ntoa(addr); + return true; + } + } +#endif + return false; +} + +const std::string& NetUtilInternal::GetNetmask() const { + return netmask; +} + +bool NetUtilInternal::RetrieveNetmask() { + std::scoped_lock lock{m_mutex}; + char netmaskStr[INET_ADDRSTRLEN]; + auto success = false; + +#ifdef _WIN32 + std::vector adapter_addresses(sizeof(IP_ADAPTER_ADDRESSES)); + ULONG size_infos = sizeof(IP_ADAPTER_ADDRESSES); + + if (GetAdaptersAddresses(AF_INET, 0, NULL, + reinterpret_cast(adapter_addresses.data()), + &size_infos) == ERROR_BUFFER_OVERFLOW) + adapter_addresses.resize(size_infos); + + if (GetAdaptersAddresses(AF_INET, 0, NULL, + reinterpret_cast(adapter_addresses.data()), + &size_infos) == NO_ERROR && + size_infos) { + PIP_ADAPTER_ADDRESSES adapter; + for (adapter = reinterpret_cast(adapter_addresses.data()); adapter; + adapter = adapter->Next) { + PIP_ADAPTER_UNICAST_ADDRESS unicast = adapter->FirstUnicastAddress; + if (unicast) { + ULONG prefix_length = unicast->OnLinkPrefixLength; + ULONG mask = prefix_length == 0 ? 0 : 0xFFFFFFFF << (32 - prefix_length); + in_addr addr{}; + addr.S_un.S_addr = htonl(mask); + inet_ntop(AF_INET, &addr, netmaskStr, INET_ADDRSTRLEN); + success = true; + } + } + } + +#else + ifaddrs* ifap; + + if (getifaddrs(&ifap) == 0) { + ifaddrs* p; + for (p = ifap; p; p = p->ifa_next) { + if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET) { + auto sa = reinterpret_cast(p->ifa_netmask); + inet_ntop(AF_INET, &sa->sin_addr, netmaskStr, INET_ADDRSTRLEN); + success = true; + } + } + } + + freeifaddrs(ifap); +#endif + + if (success) { + netmask = netmaskStr; + } + return success; +} + } // 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 be9dc15a1..fce55c2ff 100644 --- a/src/core/libraries/network/net_util.h +++ b/src/core/libraries/network/net_util.h @@ -15,10 +15,16 @@ public: private: std::array ether_address{}; + std::string default_gateway{}; + std::string netmask{}; std::mutex m_mutex; public: const std::array& GetEthernetAddr() const; + const std::string& GetDefaultGateway() const; + const std::string& GetNetmask() const; bool RetrieveEthernetAddr(); + bool RetrieveDefaultGateway(); + bool RetrieveNetmask(); }; } // namespace NetUtil \ No newline at end of file diff --git a/src/core/libraries/network/netctl.cpp b/src/core/libraries/network/netctl.cpp index 54a273dc3..4ba96fb1a 100644 --- a/src/core/libraries/network/netctl.cpp +++ b/src/core/libraries/network/netctl.cpp @@ -13,6 +13,7 @@ #endif #include +#include "common/config.h" #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" @@ -69,8 +70,8 @@ int PS4_SYSV_ABI sceNetBweUnregisterCallbackIpcInt() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetCtlGetInfoV6() { - LOG_ERROR(Lib_NetCtl, "(STUBBED) called"); +int PS4_SYSV_ABI sceNetCtlGetInfoV6(int code, void* param) { + LOG_ERROR(Lib_NetCtl, "(STUBBED) called, code = {}", code); return ORBIS_OK; } @@ -95,7 +96,9 @@ int PS4_SYSV_ABI sceNetCtlUnregisterCallbackV6() { } int PS4_SYSV_ABI sceNetCtlCheckCallback() { - LOG_DEBUG(Lib_NetCtl, "(STUBBED) called"); + LOG_DEBUG(Lib_NetCtl, "called"); + + netctl.CheckCallback(); return ORBIS_OK; } @@ -160,12 +163,14 @@ int PS4_SYSV_ABI sceNetCtlGetIfStat() { } int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) { + LOG_DEBUG(Lib_NetCtl, "code = {}", code); + auto* netinfo = Common::Singleton::Instance(); + switch (code) { case ORBIS_NET_CTL_INFO_DEVICE: info->device = ORBIS_NET_CTL_DEVICE_WIRED; break; case ORBIS_NET_CTL_INFO_ETHER_ADDR: { - auto* netinfo = Common::Singleton::Instance(); netinfo->RetrieveEthernetAddr(); memcpy(info->ether_addr.data, netinfo->GetEthernetAddr().data(), 6); } break; @@ -173,7 +178,8 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) { info->mtu = 1500; // default value break; case ORBIS_NET_CTL_INFO_LINK: - info->link = ORBIS_NET_CTL_LINK_DISCONNECTED; + info->link = Config::getIsConnectedToNetwork() ? ORBIS_NET_CTL_LINK_CONNECTED + : ORBIS_NET_CTL_LINK_DISCONNECTED; break; case ORBIS_NET_CTL_INFO_IP_ADDRESS: { strcpy(info->ip_address, @@ -193,11 +199,50 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) { } break; } - + case ORBIS_NET_CTL_INFO_PRIMARY_DNS: + strcpy(info->primary_dns, "1.1.1.1"); + break; + case ORBIS_NET_CTL_INFO_SECONDARY_DNS: + strcpy(info->secondary_dns, "1.1.1.1"); + break; + case ORBIS_NET_CTL_INFO_HTTP_PROXY_CONFIG: + info->http_proxy_config = 0; + break; + case ORBIS_NET_CTL_INFO_HTTP_PROXY_SERVER: + strcpy(info->http_proxy_server, "0.0.0.0"); + break; + case ORBIS_NET_CTL_INFO_HTTP_PROXY_PORT: + info->http_proxy_port = 0; + break; + case ORBIS_NET_CTL_INFO_IP_CONFIG: + info->ip_config = 1; // static + break; + case ORBIS_NET_CTL_INFO_DHCP_HOSTNAME: + // info-> = ; + break; + case ORBIS_NET_CTL_INFO_NETMASK: { + auto success = netinfo->RetrieveNetmask(); + if (success) { + strncpy(info->netmask, netinfo->GetNetmask().data(), sizeof(info->netmask)); + LOG_DEBUG(Lib_NetCtl, "netmask: {}", info->netmask); + } else { + LOG_WARNING(Lib_NetCtl, "netmask: failed to retrieve"); + } + break; + } + case ORBIS_NET_CTL_INFO_DEFAULT_ROUTE: { + auto success = netinfo->RetrieveDefaultGateway(); + if (success) { + strncpy(info->netmask, netinfo->GetDefaultGateway().data(), sizeof(info->netmask)); + LOG_DEBUG(Lib_NetCtl, "default gateway: {}", info->netmask); + } else { + LOG_WARNING(Lib_NetCtl, "default gateway: failed to retrieve"); + } + break; + } default: LOG_ERROR(Lib_NetCtl, "{} unsupported code", code); } - LOG_DEBUG(Lib_NetCtl, "(STUBBED) called"); return ORBIS_OK; } @@ -271,7 +316,10 @@ int PS4_SYSV_ABI sceNetCtlGetScanInfoForSsidScanIpcInt() { } int PS4_SYSV_ABI sceNetCtlGetState(int* state) { - *state = ORBIS_NET_CTL_STATE_DISCONNECTED; + LOG_DEBUG(Lib_NetCtl, "connected = {}", Config::getIsConnectedToNetwork()); + const auto current_state = Config::getIsConnectedToNetwork() ? ORBIS_NET_CTL_STATE_IPOBTAINED + : ORBIS_NET_CTL_STATE_DISCONNECTED; + *state = current_state; return ORBIS_OK; } @@ -296,7 +344,7 @@ int PS4_SYSV_ABI sceNetCtlGetWifiType() { } int PS4_SYSV_ABI sceNetCtlInit() { - LOG_ERROR(Lib_NetCtl, "(STUBBED) called"); + LOG_DEBUG(Lib_NetCtl, "called"); return ORBIS_OK; } @@ -309,12 +357,17 @@ int PS4_SYSV_ABI sceNetCtlRegisterCallback(OrbisNetCtlCallback func, void* arg, if (!func || !cid) { return ORBIS_NET_CTL_ERROR_INVALID_ADDR; } + s32 result = netctl.RegisterCallback(func, arg); + if (result < 0) { + LOG_DEBUG(Lib_NetCtl, "failed with {:#x}", result); return result; } else { + LOG_DEBUG(Lib_NetCtl, "*cid = {}", result); *cid = result; } + return ORBIS_OK; } @@ -384,7 +437,9 @@ int PS4_SYSV_ABI Func_D8DCB6973537A3DC() { } int PS4_SYSV_ABI sceNetCtlCheckCallbackForNpToolkit() { - LOG_DEBUG(Lib_NetCtl, "(STUBBED) called"); + LOG_DEBUG(Lib_NetCtl, "called"); + + netctl.CheckNpToolkitCallback(); return ORBIS_OK; } @@ -398,10 +453,14 @@ int PS4_SYSV_ABI sceNetCtlRegisterCallbackForNpToolkit(OrbisNetCtlCallbackForNpT if (!func || !cid) { return ORBIS_NET_CTL_ERROR_INVALID_ADDR; } + s32 result = netctl.RegisterNpToolkitCallback(func, arg); + if (result < 0) { + LOG_WARNING(Lib_NetCtl, "failed with {:#x}", result); return result; } else { + LOG_DEBUG(Lib_NetCtl, "*cid = {}", result); *cid = result; } return ORBIS_OK; diff --git a/src/core/libraries/network/netctl.h b/src/core/libraries/network/netctl.h index 7f139e8c3..a3efbaa59 100644 --- a/src/core/libraries/network/netctl.h +++ b/src/core/libraries/network/netctl.h @@ -79,7 +79,7 @@ int PS4_SYSV_ABI sceNetBweSetInternetConnectionTestResultIpcInt(); int PS4_SYSV_ABI sceNetBweStartInternetConnectionTestBandwidthTestIpcInt(); int PS4_SYSV_ABI sceNetBweStartInternetConnectionTestIpcInt(); int PS4_SYSV_ABI sceNetBweUnregisterCallbackIpcInt(); -int PS4_SYSV_ABI sceNetCtlGetInfoV6(); +int PS4_SYSV_ABI sceNetCtlGetInfoV6(int code, void* param); int PS4_SYSV_ABI sceNetCtlGetResultV6(); int PS4_SYSV_ABI sceNetCtlGetStateV6(); int PS4_SYSV_ABI sceNetCtlRegisterCallbackV6(); diff --git a/src/core/libraries/network/p2p_sockets.cpp b/src/core/libraries/network/p2p_sockets.cpp index 4f678dace..32b4b9f7a 100644 --- a/src/core/libraries/network/p2p_sockets.cpp +++ b/src/core/libraries/network/p2p_sockets.cpp @@ -57,4 +57,23 @@ int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { return 0; } +int P2PSocket::GetPeerName(OrbisNetSockaddr* addr, u32* namelen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return 0; +} + +int P2PSocket::read(void* buf, size_t len) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return 0; +} + +int P2PSocket::write(const void* buf, size_t len) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return 0; +} + +int P2PSocket::fstat(Libraries::Kernel::OrbisKernelStat* stat) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return 0; +} } // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/network/posix_sockets.cpp b/src/core/libraries/network/posix_sockets.cpp index 2df375262..330f4f4f2 100644 --- a/src/core/libraries/network/posix_sockets.cpp +++ b/src/core/libraries/network/posix_sockets.cpp @@ -2,7 +2,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include "common/error.h" +#include "core/libraries/kernel/file_system.h" #include "net.h" +#ifndef _WIN32 +#include +#endif #include "net_error.h" #include "sockets.h" @@ -108,6 +113,17 @@ static int ConvertReturnErrorCode(int retval) { return retval; } +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); + } +} + static int ConvertLevels(int level) { switch (level) { case ORBIS_NET_SOL_SOCKET: @@ -116,8 +132,13 @@ static int ConvertLevels(int level) { return IPPROTO_IP; case ORBIS_NET_IPPROTO_TCP: return IPPROTO_TCP; + case ORBIS_NET_IPPROTO_UDP: + return IPPROTO_UDP; + case ORBIS_NET_IPPROTO_IPV6: + return IPPROTO_IPV6; + default: + UNREACHABLE_MSG("unhandled socket level {}", level); } - return -1; } static void convertOrbisNetSockaddrToPosix(const OrbisNetSockaddr* src, sockaddr* dst) { @@ -142,6 +163,12 @@ static void convertPosixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) { memcpy(&dst_in->sin_addr, &src_in->sin_addr, 4); } +PosixSocket::PosixSocket(int domain, int type, int protocol) : Socket(domain, type, protocol) { + sock = socket(ConvertFamilies(domain), type, protocol); + LOG_DEBUG(Lib_Net, "socket = {}", sock); + socket_type = type; +} + int PosixSocket::Close() { std::scoped_lock lock{m_mutex}; #ifdef _WIN32 @@ -154,19 +181,27 @@ int PosixSocket::Close() { int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) { std::scoped_lock lock{m_mutex}; + sockaddr addr2; convertOrbisNetSockaddrToPosix(addr, &addr2); - return ConvertReturnErrorCode(::bind(sock, &addr2, sizeof(sockaddr_in))); + const auto result = ::bind(sock, &addr2, sizeof(addr2)); + LOG_DEBUG(Lib_Net, "raw bind result = {}, errno = {}", result, + result == -1 ? Common::GetLastErrorMsg() : "none"); + return ConvertReturnErrorCode(result); } int PosixSocket::Listen(int backlog) { std::scoped_lock lock{m_mutex}; + LOG_DEBUG(Lib_Net, "called"); + return ConvertReturnErrorCode(::listen(sock, backlog)); } int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, u32 tolen) { std::scoped_lock lock{m_mutex}; + LOG_DEBUG(Lib_Net, "called"); + if (to != nullptr) { sockaddr addr; convertOrbisNetSockaddrToPosix(to, &addr); @@ -180,6 +215,8 @@ int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetS int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) { std::scoped_lock lock{m_mutex}; + // LOG_DEBUG(Lib_Net, "len = {}, flags = {:#x}, from = {:#x}", len, flags, + // reinterpret_cast(from)); if (from != nullptr) { sockaddr addr; int res = recvfrom(sock, (char*)buf, len, flags, &addr, (socklen_t*)fromlen); @@ -193,15 +230,20 @@ int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) { std::scoped_lock lock{m_mutex}; + LOG_DEBUG(Lib_Net, "called"); + sockaddr addr2; - net_socket new_socket = ::accept(sock, &addr2, (socklen_t*)addrlen); + socklen_t len = sizeof(addr2); + net_socket new_socket = ::accept(sock, &addr2, &len); #ifdef _WIN32 if (new_socket != INVALID_SOCKET) { #else if (new_socket >= 0) { #endif - convertPosixSockaddrToOrbis(&addr2, addr); - *addrlen = sizeof(OrbisNetSockaddrIn); + if (addr && addrlen) { + convertPosixSockaddrToOrbis(&addr2, addr); + *addrlen = sizeof(OrbisNetSockaddrIn); + } return std::make_shared(new_socket); } return nullptr; @@ -209,13 +251,23 @@ SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) { int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) { std::scoped_lock lock{m_mutex}; + LOG_DEBUG(Lib_Net, "called"); + sockaddr addr2; convertOrbisNetSockaddrToPosix(addr, &addr2); - return ::connect(sock, &addr2, sizeof(sockaddr_in)); + int result = 0; + do { + result = ::connect(sock, &addr2, sizeof(sockaddr_in)); + LOG_DEBUG(Lib_Net, "raw connect result = {}, errno = {}", result, + result == -1 ? Common::GetLastErrorMsg() : "none"); + } while (result == -1 && (errno == EINTR || errno == EINPROGRESS)); + return ConvertReturnErrorCode(result); } int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { std::scoped_lock lock{m_mutex}; + LOG_DEBUG(Lib_Net, "called"); + sockaddr addr; convertOrbisNetSockaddrToPosix(name, &addr); if (name != nullptr) { @@ -229,6 +281,23 @@ int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { return res; } +int PosixSocket::GetPeerName(OrbisNetSockaddr* name, u32* namelen) { + std::scoped_lock lock{m_mutex}; + LOG_DEBUG(Lib_Net, "called"); + + sockaddr addr; + convertOrbisNetSockaddrToPosix(name, &addr); + if (name != nullptr) { + *namelen = sizeof(sockaddr_in); + } + int res = ::getpeername(sock, &addr, (socklen_t*)namelen); + if (res >= 0) { + convertPosixSockaddrToOrbis(&addr, name); + *namelen = sizeof(OrbisNetSockaddrIn); + } + return res; +} + #define CASE_SETSOCKOPT(opt) \ case ORBIS_NET_##opt: \ return ConvertReturnErrorCode(setsockopt(sock, level, opt, (const char*)optval, optlen)) @@ -242,8 +311,9 @@ int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { return 0 int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) { - std::scoped_lock lock{m_mutex}; level = ConvertLevels(level); + LOG_INFO(Lib_Net, "level = {}, optname = {}, optlen = {}", level, optname, optlen); + std::scoped_lock lock{m_mutex}; ::linger native_linger; if (level == SOL_SOCKET) { switch (optname) { @@ -392,4 +462,37 @@ int PosixSocket::GetSocketOptions(int level, int optname, void* optval, u32* opt return 0; } +int PosixSocket::fstat(Libraries::Kernel::OrbisKernelStat* sb) { +#ifdef _WIN32 + LOG_ERROR(Lib_Net, "(STUBBED) called"); + sb->st_mode = 0000777u | 0140000u; + return 0; +#else + struct stat st{}; + int result = ::fstat(sock, &st); + sb->st_mode = 0000777u | 0140000u; + sb->st_size = st.st_size; + sb->st_blocks = st.st_blocks; + sb->st_blksize = st.st_blksize; + // sb->st_flags = st.st_flags; + return result; +#endif +} + +int PosixSocket::read(void* buf, size_t len) { +#ifdef _WIN32 + return recv(sock, buf, len, 0); +#else + return ::read(sock, buf, len); +#endif +} + +int PosixSocket::write(const void* buf, size_t len) { +#ifdef _WIN32 + return send(sock, buf, len, 0); +#else + return ::write(sock, buf, len); +#endif +} + } // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/network/sockets.h b/src/core/libraries/network/sockets.h index c54e11e66..53d7cd98a 100644 --- a/src/core/libraries/network/sockets.h +++ b/src/core/libraries/network/sockets.h @@ -26,6 +26,10 @@ typedef int net_socket; #include #include "net.h" +namespace Libraries::Kernel { +struct OrbisKernelStat; +} + namespace Libraries::Net { struct Socket; @@ -51,6 +55,12 @@ struct Socket { u32* fromlen) = 0; virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0; virtual int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) = 0; + virtual int GetPeerName(OrbisNetSockaddr* addr, u32* namelen) = 0; + virtual int fstat(Libraries::Kernel::OrbisKernelStat* stat) = 0; + virtual int read(void* buf, size_t len) = 0; + virtual int write(const void* buf, size_t len) = 0; + virtual bool IsValid() const = 0; + virtual net_socket Native() const = 0; std::mutex m_mutex; }; @@ -65,10 +75,7 @@ struct PosixSocket : public Socket { int sockopt_ip_maxttl = 0; int sockopt_tcp_mss_to_advertise = 0; int socket_type; - explicit PosixSocket(int domain, int type, int protocol) - : Socket(domain, type, protocol), sock(socket(domain, type, protocol)) { - socket_type = type; - } + explicit PosixSocket(int domain, int type, int protocol); explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {} int Close() override; int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override; @@ -81,6 +88,16 @@ struct PosixSocket : public Socket { SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override; int Connect(const OrbisNetSockaddr* addr, u32 namelen) override; int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override; + int GetPeerName(OrbisNetSockaddr* addr, u32* namelen) override; + int fstat(Libraries::Kernel::OrbisKernelStat* stat) override; + int read(void* buf, size_t len) override; + int write(const void* buf, size_t len) override; + bool IsValid() const override { + return sock != -1; + } + net_socket Native() const override { + return sock; + } }; struct P2PSocket : public Socket { @@ -96,6 +113,16 @@ struct P2PSocket : public Socket { SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override; int Connect(const OrbisNetSockaddr* addr, u32 namelen) override; int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override; + int GetPeerName(OrbisNetSockaddr* addr, u32* namelen) override; + int read(void* buf, size_t len) override; + int write(const void* buf, size_t len) override; + int fstat(Libraries::Kernel::OrbisKernelStat* stat) override; + bool IsValid() const override { + return true; + } + net_socket Native() const override { + return {}; + } }; class NetInternal { diff --git a/src/core/libraries/network/ssl.cpp b/src/core/libraries/network/ssl.cpp index 1e013bc26..8d6e691d4 100644 --- a/src/core/libraries/network/ssl.cpp +++ b/src/core/libraries/network/ssl.cpp @@ -633,8 +633,17 @@ int PS4_SYSV_ABI sceSslFreeSslCertName() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSslGetCaCerts() { +struct OrbisSslCaCerts { + void* certs; + u64 num; + void* pool; +}; + +int PS4_SYSV_ABI sceSslGetCaCerts(int sslCtxId, OrbisSslCaCerts* certs) { LOG_ERROR(Lib_Ssl, "(STUBBED) called"); + certs->certs = nullptr; + certs->num = 0; + certs->pool = nullptr; return ORBIS_OK; } diff --git a/src/core/libraries/network/ssl.h b/src/core/libraries/network/ssl.h index 051c6363e..fd55f528e 100644 --- a/src/core/libraries/network/ssl.h +++ b/src/core/libraries/network/ssl.h @@ -11,6 +11,13 @@ class SymbolsResolver; namespace Libraries::Ssl { +struct OrbisSslCaCerts; + +struct OrbisSslCaList { + void* certs; + int certsNum; +}; + int PS4_SYSV_ABI CA_MGMT_allocCertDistinguishedName(); int PS4_SYSV_ABI CA_MGMT_certDistinguishedNameCompare(); int PS4_SYSV_ABI CA_MGMT_convertKeyBlobToPKCS8Key(); @@ -136,7 +143,7 @@ int PS4_SYSV_ABI sceSslEnableOptionInternal(); int PS4_SYSV_ABI sceSslFreeCaCerts(); int PS4_SYSV_ABI sceSslFreeCaList(); int PS4_SYSV_ABI sceSslFreeSslCertName(); -int PS4_SYSV_ABI sceSslGetCaCerts(); +int PS4_SYSV_ABI sceSslGetCaCerts(int sslCtxId, OrbisSslCaCerts* certs); int PS4_SYSV_ABI sceSslGetCaList(); int PS4_SYSV_ABI sceSslGetIssuerName(); int PS4_SYSV_ABI sceSslGetMemoryPoolStats(); diff --git a/src/core/libraries/network/ssl2.cpp b/src/core/libraries/network/ssl2.cpp index 701f091a3..4289a7382 100644 --- a/src/core/libraries/network/ssl2.cpp +++ b/src/core/libraries/network/ssl2.cpp @@ -128,8 +128,18 @@ int PS4_SYSV_ABI sceSslGetAlpnSelected() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSslGetCaCerts() { - LOG_ERROR(Lib_Ssl2, "(STUBBED) called"); +struct OrbisSslCaCerts { + void* certs; + u64 num; + void* pool; +}; + +int PS4_SYSV_ABI sceSslGetCaCerts(int sslCtxId, OrbisSslCaCerts* certs) { + // check if it is same as libSceSsl + LOG_ERROR(Lib_Ssl2, "(DUMMY) called"); + certs->certs = nullptr; + certs->num = 0; + certs->pool = nullptr; return ORBIS_OK; } diff --git a/src/core/libraries/network/sys_net.cpp b/src/core/libraries/network/sys_net.cpp index 087632159..a70a9358b 100644 --- a/src/core/libraries/network/sys_net.cpp +++ b/src/core/libraries/network/sys_net.cpp @@ -4,7 +4,9 @@ #include #include #include +#include "common/error.h" #include "common/singleton.h" +#include "core/file_sys/fs.h" #include "net_error.h" #include "sockets.h" #include "sys_net.h" @@ -12,13 +14,16 @@ namespace Libraries::Net { int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_WARNING(Lib_Net, "s = {}", s); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; int returncode = sock->Connect(addr, addrlen); if (returncode >= 0) { return returncode; @@ -28,13 +33,16 @@ int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 add return -1; } int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_DEBUG(Lib_Net, "s = {}, addr = {}, addrlen = {}", s, fmt::ptr(addr), addrlen); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; int returncode = sock->Bind(addr, addrlen); if (returncode >= 0) { return returncode; @@ -44,35 +52,62 @@ int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrle return -1; } int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { - *Libraries::Kernel::__Error() = ORBIS_NET_EBADF; - LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); - return -1; - } - auto new_sock = sock->Accept(addr, paddrlen); - if (!new_sock) { - *Libraries::Kernel::__Error() = ORBIS_NET_EBADF; - LOG_ERROR(Lib_Net, "error creating new socket for accepting"); - return -1; - } - auto id = ++netcall->next_sock_id; - netcall->socks.emplace(id, new_sock); - return id; -} -int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return -1; -} -int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_WARNING(Lib_Net, "(DUMMY) called"); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; + auto new_sock = sock->Accept(addr, paddrlen); + if (!new_sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_EBADF; + LOG_ERROR(Lib_Net, "error creating new socket for accepting: {}", + Common::GetLastErrorMsg()); + return -1; + } + u32 handle = h->CreateHandle(); + auto* new_file = h->GetFile(handle); + new_file->is_opened = true; + new_file->type = Core::FileSys::FileType::Socket; + new_file->socket = new_sock; + return handle; +} + +int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { + LOG_WARNING(Lib_Net, "(DUMMY) called"); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + auto sock = file->socket; + int returncode = sock->GetPeerName(addr, paddrlen); + if (returncode >= 0) { + return returncode; + } + *Libraries::Kernel::__Error() = returncode; + LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); + return -1; +} + +int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { + LOG_WARNING(Lib_Net, "(DUMMY) called"); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + auto sock = file->socket; int returncode = sock->GetSocketAddress(addr, paddrlen); if (returncode >= 0) { return returncode; @@ -82,13 +117,16 @@ int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* padd return -1; } int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_WARNING(Lib_Net, "(DUMMY) called"); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; int returncode = sock->GetSocketOptions(level, optname, optval, optlen); if (returncode >= 0) { return returncode; @@ -98,13 +136,16 @@ int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optv return -1; } int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_DEBUG(Lib_Net, "s = {}, backlog = {}", s, backlog); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; int returncode = sock->Listen(backlog); if (returncode >= 0) { return returncode; @@ -113,16 +154,21 @@ int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog) { LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); return -1; } + int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval, u32 optlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_WARNING(Lib_Net, "netId = {}", s); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; int returncode = sock->SetSocketOptions(level, optname, optval, optlen); + LOG_INFO(Lib_Net, "returncode = {}", returncode); if (returncode >= 0) { return returncode; } @@ -145,9 +191,16 @@ int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protoc switch (type) { case ORBIS_NET_SOCK_STREAM: case ORBIS_NET_SOCK_DGRAM: - case ORBIS_NET_SOCK_RAW: - sock = std::make_shared(family, type, protocol); + case ORBIS_NET_SOCK_RAW: { + const auto typed_socket = std::make_shared(family, type, protocol); + if (!typed_socket->IsValid()) { + *Libraries::Kernel::__Error() = ORBIS_NET_EPROTONOSUPPORT; + return -1; + } + + sock = std::move(typed_socket); break; + } case ORBIS_NET_SOCK_DGRAM_P2P: case ORBIS_NET_SOCK_STREAM_P2P: sock = std::make_shared(family, type, protocol); @@ -155,10 +208,16 @@ int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protoc default: UNREACHABLE_MSG("Unknown type {}", type); } - auto* netcall = Common::Singleton::Instance(); - auto id = ++netcall->next_sock_id; - netcall->socks.emplace(id, sock); - return id; + auto* h = Common::Singleton::Instance(); + u32 handle = h->CreateHandle(); + auto* file = h->GetFile(handle); + file->is_opened = true; + file->type = Core::FileSys::FileType::Socket; + file->socket = sock; + // auto* netcall = Common::Singleton::Instance(); + // auto id = ++netcall->next_sock_id; + // netcall->socks.emplace(id, sock); + return handle; } int PS4_SYSV_ABI sys_socket(int family, int type, int protocol) { return sys_socketex(nullptr, family, type, protocol); @@ -168,14 +227,19 @@ int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags) { return -1; } int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_INFO(Lib_Net, "called, s = {}", s); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; + file->is_opened = false; int returncode = sock->Close(); + h->DeleteHandle(s); if (returncode >= 0) { return returncode; } @@ -183,15 +247,23 @@ int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) { LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); return -1; } + +int PS4_SYSV_ABI sys_send(OrbisNetId s, const void* buf, u64 len, int flags) { + return sys_sendto(s, buf, len, flags, nullptr, 0); +} + int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags, const OrbisNetSockaddr* addr, u32 addrlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + LOG_WARNING(Lib_Net, "s = {}, len = {}, flags = {:#x}, addrlen = {}", s, len, flags, addrlen); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; int returncode = sock->SendPacket(buf, len, flags, addr, addrlen); if (returncode >= 0) { return returncode; @@ -204,24 +276,33 @@ int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) LOG_ERROR(Lib_Net, "(STUBBED) called"); return -1; } -int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr, + +ssize_t PS4_SYSV_ABI sys_recv(OrbisNetId s, void* buf, u64 len, int flags) { + return sys_recvfrom(s, buf, len, flags, nullptr, 0); +} + +ssize_t PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr, u32* paddrlen) { - auto* netcall = Common::Singleton::Instance(); - auto sock = netcall->FindSocket(s); - if (!sock) { + // LOG_INFO(Lib_Net, "s = {}, buf = {:#x}, len = {}, flags = {:#x}", s, + // reinterpret_cast(buf), len, flags); + + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(s); + if (!file || file->type != Core::FileSys::FileType::Socket) { *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); return -1; } + auto sock = file->socket; int returncode = sock->ReceivePacket(buf, len, flags, addr, paddrlen); if (returncode >= 0) { return returncode; } *Libraries::Kernel::__Error() = returncode; - LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); + // LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); return -1; } -int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) { +ssize_t PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) { LOG_ERROR(Lib_Net, "(STUBBED) called"); return -1; } diff --git a/src/core/libraries/network/sys_net.h b/src/core/libraries/network/sys_net.h index 4366ea0f8..927c9ebab 100644 --- a/src/core/libraries/network/sys_net.h +++ b/src/core/libraries/network/sys_net.h @@ -11,7 +11,7 @@ namespace Libraries::Net { int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen); int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen); int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen); -int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen); +int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen); int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen); int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen); int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog); @@ -22,10 +22,12 @@ int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protoc int PS4_SYSV_ABI sys_socket(int family, int type, int protocol); int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags); int PS4_SYSV_ABI sys_socketclose(OrbisNetId s); +int PS4_SYSV_ABI sys_send(OrbisNetId s, const void* buf, u64 len, int flags); int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags, const OrbisNetSockaddr* addr, u32 addrlen); int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags); -int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr, +ssize_t PS4_SYSV_ABI sys_recv(OrbisNetId s, void* buf, u64 len, int flags); +ssize_t PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr, u32* paddrlen); -int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags); +ssize_t PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags); } // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/np_manager/np_manager.cpp b/src/core/libraries/np_manager/np_manager.cpp index b161a5a50..eab738e9f 100644 --- a/src/core/libraries/np_manager/np_manager.cpp +++ b/src/core/libraries/np_manager/np_manager.cpp @@ -2545,14 +2545,18 @@ struct NpStateCallbackForNpToolkit { NpStateCallbackForNpToolkit NpStateCbForNp; int PS4_SYSV_ABI sceNpCheckCallbackForLib() { - LOG_DEBUG(Lib_NpManager, "(STUBBED) called"); + LOG_DEBUG(Lib_NpManager, "called"); + + const auto state = Config::getPSNSignedIn() ? OrbisNpState::SignedIn : OrbisNpState::SignedOut; + + NpStateCbForNp.func(1, state, NpStateCbForNp.userdata); return ORBIS_OK; } int PS4_SYSV_ABI sceNpRegisterStateCallbackForToolkit(OrbisNpStateCallbackForNpToolkit callback, void* userdata) { static int id = 0; - LOG_ERROR(Lib_NpManager, "(STUBBED) called"); + LOG_WARNING(Lib_NpManager, "(DUMMY) called"); NpStateCbForNp.func = callback; NpStateCbForNp.userdata = userdata; return id; diff --git a/src/core/libraries/web_browser_dialog/webbrowserdialog.cpp b/src/core/libraries/web_browser_dialog/webbrowserdialog.cpp index 0b1206249..96ea8ecbe 100644 --- a/src/core/libraries/web_browser_dialog/webbrowserdialog.cpp +++ b/src/core/libraries/web_browser_dialog/webbrowserdialog.cpp @@ -4,6 +4,7 @@ #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" +#include "core/libraries/system/commondialog.h" #include "core/libraries/web_browser_dialog/webbrowserdialog.h" namespace Libraries::WebBrowserDialog { @@ -25,7 +26,7 @@ s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult() { s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus() { LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called"); - return ORBIS_OK; + return (s32)Libraries::CommonDialog::Status::INITIALIZED; } s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize() { diff --git a/src/emulator.cpp b/src/emulator.cpp index 9485b0e23..7e6b36cf1 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -134,6 +134,8 @@ void Emulator::Run(std::filesystem::path file, const std::vector ar LOG_INFO(Config, "General LogType: {}", Config::getLogType()); LOG_INFO(Config, "General isNeo: {}", Config::isNeoModeConsole()); + LOG_INFO(Config, "General isConnectedToNetwork: {}", Config::getIsConnectedToNetwork()); + LOG_INFO(Config, "General isPsnSignedIn: {}", Config::getPSNSignedIn()); LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu()); LOG_INFO(Config, "GPU readbacks: {}", Config::readbacks()); LOG_INFO(Config, "GPU readbackLinearImages: {}", Config::readbackLinearImages());