This commit is contained in:
Marcin Mikołajczyk 2025-07-20 22:53:21 +03:00 committed by GitHub
commit 513d32f51b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 1391 additions and 139 deletions

6
.gitmodules vendored
View File

@ -106,3 +106,9 @@
[submodule "externals/libusb"] [submodule "externals/libusb"]
path = externals/libusb path = externals/libusb
url = https://github.com/libusb/libusb-cmake.git 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

View File

@ -246,6 +246,7 @@ find_package(pugixml 1.14 CONFIG)
find_package(libusb 1.0.27 MODULE) find_package(libusb 1.0.27 MODULE)
if (APPLE) if (APPLE)
find_package(date 3.0.1 CONFIG) find_package(date 3.0.1 CONFIG)
find_package(epoll-shim 3.14 CONFIG)
endif() endif()
list(POP_BACK CMAKE_MODULE_PATH) 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_ctl_codes.h
src/core/libraries/network/net_util.cpp src/core/libraries/network/net_util.cpp
src/core/libraries/network/net_util.h 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_error.h
src/core/libraries/network/net.h src/core/libraries/network/net.h
src/core/libraries/network/ssl.cpp src/core/libraries/network/ssl.cpp
@ -1173,7 +1176,7 @@ if (APPLE)
endif() endif()
# Replacement for std::chrono::time_zone # 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() endif()
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)

View File

@ -140,6 +140,8 @@ endif()
# sirit # sirit
add_subdirectory(sirit) add_subdirectory(sirit)
if (WIN32) 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") target_compile_options(sirit PUBLIC "-Wno-error=unused-command-line-argument")
endif() endif()
@ -229,4 +231,8 @@ if (APPLE)
if (NOT TARGET MoltenVK) if (NOT TARGET MoltenVK)
add_subdirectory(MoltenVK) add_subdirectory(MoltenVK)
endif() endif()
if (NOT TARGET epoll-shim)
add_subdirectory(epoll-shim)
endif()
endif() endif()

1
externals/epoll-shim vendored Submodule

@ -0,0 +1 @@
Subproject commit 18159584bb3d17e601b9315a7398ace018251bdc

1
externals/wepoll vendored Submodule

@ -0,0 +1 @@
Subproject commit 0598a791bf9cbbf480793d778930fc635b044980

View File

@ -47,6 +47,7 @@ static bool isShowSplash = false;
static std::string isSideTrophy = "right"; static std::string isSideTrophy = "right";
static bool compatibilityData = false; static bool compatibilityData = false;
static bool checkCompatibilityOnStartup = false; static bool checkCompatibilityOnStartup = false;
static bool isConnectedToNetwork = false;
// Input // Input
static int cursorState = HideCursorState::Idle; static int cursorState = HideCursorState::Idle;
@ -107,7 +108,7 @@ u32 m_language = 1; // english
static std::string trophyKey = ""; static std::string trophyKey = "";
// Expected number of items in the config file // Expected number of items in the config file
static constexpr u64 total_entries = 54; static constexpr u64 total_entries = 55;
int getVolumeSlider() { int getVolumeSlider() {
return volumeSlider; return volumeSlider;
@ -353,6 +354,10 @@ bool getCheckCompatibilityOnStartup() {
return checkCompatibilityOnStartup; return checkCompatibilityOnStartup;
} }
bool getIsConnectedToNetwork() {
return isConnectedToNetwork;
}
void setGpuId(s32 selectedGpuId) { void setGpuId(s32 selectedGpuId) {
gpuId = selectedGpuId; gpuId = selectedGpuId;
} }
@ -636,6 +641,9 @@ void load(const std::filesystem::path& path) {
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", compatibilityData); compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", compatibilityData);
checkCompatibilityOnStartup = toml::find_or<bool>(general, "checkCompatibilityOnStartup", checkCompatibilityOnStartup = toml::find_or<bool>(general, "checkCompatibilityOnStartup",
checkCompatibilityOnStartup); checkCompatibilityOnStartup);
isConnectedToNetwork =
toml::find_or<bool>(general, "isConnectedToNetwork", isConnectedToNetwork);
chooseHomeTab = toml::find_or<std::string>(general, "chooseHomeTab", chooseHomeTab); chooseHomeTab = toml::find_or<std::string>(general, "chooseHomeTab", chooseHomeTab);
entry_count += general.size(); entry_count += general.size();
@ -830,6 +838,7 @@ void save(const std::filesystem::path& path) {
data["General"]["sideTrophy"] = isSideTrophy; data["General"]["sideTrophy"] = isSideTrophy;
data["General"]["compatibilityEnabled"] = compatibilityData; data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup; data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
data["General"]["isConnectedToNetwork"] = isConnectedToNetwork;
data["Input"]["cursorState"] = cursorState; data["Input"]["cursorState"] = cursorState;
data["Input"]["cursorHideTimeout"] = cursorHideTimeout; data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
data["Input"]["useSpecialPad"] = useSpecialPad; data["Input"]["useSpecialPad"] = useSpecialPad;
@ -926,6 +935,7 @@ void setDefaultValues() {
isSideTrophy = "right"; isSideTrophy = "right";
compatibilityData = false; compatibilityData = false;
checkCompatibilityOnStartup = false; checkCompatibilityOnStartup = false;
isConnectedToNetwork = false;
// Input // Input
cursorState = HideCursorState::Idle; cursorState = HideCursorState::Idle;

View File

@ -111,6 +111,7 @@ std::filesystem::path GetSaveDataPath();
void setLoadGameSizeEnabled(bool enable); void setLoadGameSizeEnabled(bool enable);
bool getCompatibilityEnabled(); bool getCompatibilityEnabled();
bool getCheckCompatibilityOnStartup(); bool getCheckCompatibilityOnStartup();
bool getIsConnectedToNetwork();
std::string getUserName(); std::string getUserName();
std::string getChooseHomeTab(); std::string getChooseHomeTab();
bool GetUseUnifiedInputConfig(); bool GetUseUnifiedInputConfig();

View File

@ -11,6 +11,7 @@
#include "common/io_file.h" #include "common/io_file.h"
#include "common/logging/formatter.h" #include "common/logging/formatter.h"
#include "core/devices/base_device.h" #include "core/devices/base_device.h"
#include "core/libraries/network/sockets.h"
namespace Core::FileSys { namespace Core::FileSys {
@ -77,6 +78,7 @@ enum class FileType {
Regular, // standard file Regular, // standard file
Directory, Directory,
Device, Device,
Socket,
}; };
struct File { struct File {
@ -89,6 +91,7 @@ struct File {
u32 dirents_index; u32 dirents_index;
std::mutex m_mutex; std::mutex m_mutex;
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
std::shared_ptr<Libraries::Net::Socket> socket; // only valid for type == Socket
}; };
class HandleTable { class HandleTable {

View File

@ -6,6 +6,8 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/logging/log.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/equeue.h"
#include "core/libraries/kernel/orbis_error.h" #include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
@ -412,6 +414,34 @@ int PS4_SYSV_ABI sceKernelDeleteTimerEvent(SceKernelEqueue eq, int id) {
: ORBIS_KERNEL_ERROR_ENOENT; : 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<u64>(udata));
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(fd);
if (!file) {
return ORBIS_KERNEL_ERROR_EBADF;
}
EqueueEvent event{};
event.event.ident = static_cast<u64>(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) { int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
if (eq == nullptr) { if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF; 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("jpFjmgAC5AE", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEqueue);
LIB_FUNCTION("fzyMKs9kim0", "libkernel", 1, "libkernel", 1, 1, sceKernelWaitEqueue); LIB_FUNCTION("fzyMKs9kim0", "libkernel", 1, "libkernel", 1, 1, sceKernelWaitEqueue);
LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData); 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("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent);
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge); LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent); LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);

View File

@ -23,6 +23,13 @@
#include "core/memory.h" #include "core/memory.h"
#include "kernel.h" #include "kernel.h"
#ifdef _WIN32
#include <io.h>
#include <winsock2.h>
#else
#include <sys/select.h>
#endif
namespace D = Core::Devices; namespace D = Core::Devices;
using FactoryDevice = std::function<std::shared_ptr<D::BaseDevice>(u32, const char*, int, u16)>; using FactoryDevice = std::function<std::shared_ptr<D::BaseDevice>(u32, const char*, int, u16)>;
@ -257,6 +264,8 @@ s32 PS4_SYSV_ABI close(s32 fd) {
} }
if (file->type == Core::FileSys::FileType::Regular) { if (file->type == Core::FileSys::FileType::Regular) {
file->f.Close(); file->f.Close();
} else if (file->type == Core::FileSys::FileType::Regular) {
file->socket->Close();
} }
file->is_opened = false; file->is_opened = false;
LOG_INFO(Kernel_Fs, "Closing {}", file->m_guest_name); 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 -1;
} }
return result; 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<u8>(buf, nbytes); return file->f.WriteRaw<u8>(buf, nbytes);
@ -475,6 +491,13 @@ s64 PS4_SYSV_ABI read(s32 fd, void* buf, size_t nbytes) {
return -1; return -1;
} }
return result; 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); return ReadFile(file->f, buf, nbytes);
} }
@ -667,6 +690,14 @@ s32 PS4_SYSV_ABI fstat(s32 fd, OrbisKernelStat* sb) {
// TODO incomplete // TODO incomplete
break; break;
} }
case Core::FileSys::FileType::Socket: {
s32 result = file->socket->fstat(sb);
if (result < 0) {
ErrSceToPosix(result);
return -1;
}
return result;
}
default: default:
UNREACHABLE(); UNREACHABLE();
} }
@ -1055,6 +1086,240 @@ s32 PS4_SYSV_ABI sceKernelUnlink(const char* path) {
return result; 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<Core::FileSys::HandleTable>::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<timeval*>(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<int, int> 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<int>(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) { void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1, open); LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1, open);
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_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("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite);
LIB_FUNCTION("mBd4AfLP+u8", "libkernel", 1, "libkernel", 1, 1, sceKernelPwritev); LIB_FUNCTION("mBd4AfLP+u8", "libkernel", 1, "libkernel", 1, 1, sceKernelPwritev);
LIB_FUNCTION("AUXVxWeJU-A", "libkernel", 1, "libkernel", 1, 1, sceKernelUnlink); 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 } // namespace Libraries::Kernel

View File

@ -222,16 +222,18 @@ s32 PS4_SYSV_ABI posix_getpagesize() {
s32 PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s, s32 PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s,
Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) { Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) {
auto* netcall = Common::Singleton<Libraries::Net::NetInternal>::Instance(); LOG_DEBUG(Lib_Net, "s = {}", s);
auto sock = netcall->FindSocket(s); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
if (!sock) { auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
s32 returncode = sock->GetSocketAddress(addr, paddrlen); s32 returncode = sock->GetSocketAddress(addr, paddrlen);
if (returncode >= 0) { if (returncode >= 0) {
LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode); LOG_DEBUG(Lib_Net, "return code : {:#x}", (u32)returncode);
return 0; return 0;
} }
*Libraries::Kernel::__Error() = 0x20; *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("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("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("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("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("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom);
LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1, LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1,
Libraries::Net::sys_setsockopt); 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("KuOmgKoqCdY", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_bind);
LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1, LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1,
Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ... Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ...

View File

@ -318,6 +318,10 @@ s32 PS4_SYSV_ABI sceKernelIsStack(void* addr, void** start, void** end) {
return memory->IsStack(std::bit_cast<VAddr>(addr), start, end); return memory->IsStack(std::bit_cast<VAddr>(addr), start, end);
} }
u32 PS4_SYSV_ABI sceKernelIsAddressSanitizerEnabled() {
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, s32 numEntries, s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, s32 numEntries,
s32* numEntriesOut) { s32* numEntriesOut) {
return sceKernelBatchMap2(entries, numEntries, 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("BC+OG5m9+bw", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemoryType);
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize); LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack); 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("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory); LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
LIB_FUNCTION("BQQniolj9tQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory2); LIB_FUNCTION("BQQniolj9tQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory2);

View File

@ -341,6 +341,8 @@ void RegisterCond(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("mKoTx03HRWA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_condattr_init); LIB_FUNCTION("mKoTx03HRWA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_condattr_init);
LIB_FUNCTION("dJcuQVn6-Iw", "libScePosix", 1, "libkernel", 1, 1, LIB_FUNCTION("dJcuQVn6-Iw", "libScePosix", 1, "libkernel", 1, 1,
posix_pthread_condattr_destroy); 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("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("2MOy+rUfuhQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_signal);
LIB_FUNCTION("RXXqi4CtF8w", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_destroy); LIB_FUNCTION("RXXqi4CtF8w", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_destroy);

View File

@ -324,6 +324,10 @@ PthreadT PS4_SYSV_ABI posix_pthread_self() {
return g_curthread; 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() { void PS4_SYSV_ABI posix_pthread_yield() {
std::this_thread::yield(); std::this_thread::yield();
} }
@ -332,6 +336,14 @@ void PS4_SYSV_ABI sched_yield() {
std::this_thread::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, int PS4_SYSV_ABI posix_pthread_once(PthreadOnce* once_control,
void PS4_SYSV_ABI (*init_routine)()) { void PS4_SYSV_ABI (*init_routine)()) {
for (;;) { 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("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("lZzFeSxPl08", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setcancelstate);
LIB_FUNCTION("a2P9wYGeZvc", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setprio); 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("FIs3-UQT9sg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_getschedparam);
LIB_FUNCTION("Xs9hdiD7sAA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setschedparam); LIB_FUNCTION("Xs9hdiD7sAA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setschedparam);
LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield); LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield);
LIB_FUNCTION("HoLVWNanBBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpid);
// Posix-Kernel // Posix-Kernel
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_once); 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("How7B8Oet6k", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_getname_np));
LIB_FUNCTION("3kg7rT0NQIs", "libkernel", 1, "libkernel", 1, 1, posix_pthread_exit); 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("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("3PtV6p3QNX4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_equal);
LIB_FUNCTION("T72hz6ffq08", "libkernel", 1, "libkernel", 1, 1, posix_pthread_yield); 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); 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("W0Hpm2X0uPE", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_setprio));
LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors); LIB_FUNCTION("rNhWz+lvOMU", "libkernel", 1, "libkernel", 1, 1, _sceKernelSetThreadDtors);
LIB_FUNCTION("6XG4B33N09g", "libkernel", 1, "libkernel", 1, 1, sched_yield); 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("rcrVFJsQWRY", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadGetaffinity));
LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadSetaffinity)); LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, ORBIS(scePthreadSetaffinity));
} }

View File

@ -289,10 +289,14 @@ int PS4_SYSV_ABI scePthreadAttrSetaffinity(PthreadAttrT* attr, const u64 mask) {
void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) { void RegisterThreadAttr(Core::Loader::SymbolsResolver* sym) {
// Posix // Posix
LIB_FUNCTION("wtkt-teR1so", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_init); 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, LIB_FUNCTION("2Q0z6rnBrTE", "libScePosix", 1, "libkernel", 1, 1,
posix_pthread_attr_setstacksize); 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, LIB_FUNCTION("RtLRV-pBTTY", "libScePosix", 1, "libkernel", 1, 1,
posix_pthread_attr_getschedpolicy); 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, LIB_FUNCTION("E+tyo3lp5Lw", "libScePosix", 1, "libkernel", 1, 1,
posix_pthread_attr_setdetachstate); posix_pthread_attr_setdetachstate);
LIB_FUNCTION("zHchY8ft5pk", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_destroy); LIB_FUNCTION("zHchY8ft5pk", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_destroy);

View File

@ -492,8 +492,9 @@ int PS4_SYSV_ABI sceHttpsFreeCaList() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceHttpsGetCaList() { int PS4_SYSV_ABI sceHttpsGetCaList(int httpCtxId, OrbisHttpsCaList* list) {
LOG_ERROR(Lib_Http, "(STUBBED) called"); LOG_ERROR(Lib_Http, "(DUMMY) called, httpCtxId = {}", httpCtxId);
list->certsNum = 0;
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include "common/types.h" #include "common/types.h"
#include "core/libraries/network/ssl.h"
namespace Core::Loader { namespace Core::Loader {
class SymbolsResolver; class SymbolsResolver;
@ -24,6 +25,8 @@ struct OrbisHttpUriElement {
u8 reserved[10]; u8 reserved[10];
}; };
using OrbisHttpsCaList = Libraries::Ssl::OrbisSslCaList;
int PS4_SYSV_ABI sceHttpAbortRequest(); int PS4_SYSV_ABI sceHttpAbortRequest();
int PS4_SYSV_ABI sceHttpAbortRequestForce(); int PS4_SYSV_ABI sceHttpAbortRequestForce();
int PS4_SYSV_ABI sceHttpAbortWaitRequest(); int PS4_SYSV_ABI sceHttpAbortWaitRequest();
@ -120,7 +123,7 @@ int PS4_SYSV_ABI sceHttpSetResponseHeaderMaxSize();
int PS4_SYSV_ABI sceHttpSetSendTimeOut(); int PS4_SYSV_ABI sceHttpSetSendTimeOut();
int PS4_SYSV_ABI sceHttpSetSocketCreationCallback(); int PS4_SYSV_ABI sceHttpSetSocketCreationCallback();
int PS4_SYSV_ABI sceHttpsFreeCaList(); 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 sceHttpsGetSslError();
int PS4_SYSV_ABI sceHttpsLoadCert(); int PS4_SYSV_ABI sceHttpsLoadCert();
int PS4_SYSV_ABI sceHttpsSetMinSslVersion(); int PS4_SYSV_ABI sceHttpsSetMinSslVersion();

View File

@ -11,15 +11,20 @@
#endif #endif
#include <core/libraries/kernel/kernel.h> #include <core/libraries/kernel/kernel.h>
#include <magic_enum/magic_enum.hpp>
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "core/file_sys/fs.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/network/net.h" #include "core/libraries/network/net.h"
#include "net_epoll.h"
#include "net_error.h" #include "net_error.h"
#include "net_util.h" #include "net_util.h"
#include "netctl.h" #include "netctl.h"
#include "sockets.h"
#include "sys_net.h" #include "sys_net.h"
namespace Libraries::Net { namespace Libraries::Net {
@ -72,6 +77,8 @@ OrbisNetId PS4_SYSV_ABI sceNetAccept(OrbisNetId s, OrbisNetSockaddr* addr, u32*
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "(DUMMY) called");
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -169,6 +176,8 @@ int PS4_SYSV_ABI sceNetBind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addr
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_INFO(Lib_Net, "called, s = {}", s);
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -551,6 +560,8 @@ int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 a
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "s = {}", s);
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -664,28 +675,156 @@ int PS4_SYSV_ABI sceNetEpollAbort() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetEpollControl() { int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, OrbisNetId id,
LOG_ERROR(Lib_Net, "(STUBBED) called"); OrbisNetEpollEvent* event) {
LOG_WARNING(Lib_Net, "called, epollid = {}, op = {}, id = {}", epollid,
magic_enum::enum_name(op), id);
auto epoll = Common::Singleton<EpollTable>::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<Core::FileSys::HandleTable>::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<Core::FileSys::HandleTable>::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; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetEpollCreate() { int PS4_SYSV_ABI sceNetEpollCreate(const char* name, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); LOG_WARNING(Lib_Net, "called, name = {}, flags = {}", name, flags);
if (flags != 0) {
return -ORBIS_NET_EINVAL;
}
auto epoll = Common::Singleton<EpollTable>::Instance()->CreateHandle(name);
return epoll;
}
int PS4_SYSV_ABI sceNetEpollDestroy(OrbisNetId epollid) {
LOG_INFO(Lib_Net, "called, epollid = {}", epollid);
auto epoll = Common::Singleton<EpollTable>::Instance()->GetEpoll(epollid);
if (!epoll) {
return -ORBIS_NET_EBADF;
}
epoll->Destroy();
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetEpollDestroy() { int PS4_SYSV_ABI sceNetEpollWait(OrbisNetId epollid, OrbisNetEpollEvent* events, int maxevents,
LOG_ERROR(Lib_Net, "(STUBBED) called"); int timeout) {
return ORBIS_OK; LOG_WARNING(Lib_Net, "called, epollid = {}, maxevents = {}, timeout = {}", epollid, maxevents,
} timeout);
int PS4_SYSV_ABI sceNetEpollWait() { auto epoll = Common::Singleton<EpollTable>::Instance()->GetEpoll(epollid);
LOG_TRACE(Lib_Net, "(STUBBED) called"); if (!epoll) {
return -ORBIS_NET_EBADF;
}
#ifdef __linux__
std::vector<epoll_event> native_events{static_cast<size_t>(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<u64>(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; return ORBIS_OK;
} }
int* PS4_SYSV_ABI sceNetErrnoLoc() { int* PS4_SYSV_ABI sceNetErrnoLoc() {
LOG_ERROR(Lib_Net, "(STUBBED) called"); LOG_TRACE(Lib_Net, "called");
return &net_errno; return &net_errno;
} }
@ -764,6 +903,8 @@ int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr,
LOG_ERROR(Lib_Net, "addr is null!"); LOG_ERROR(Lib_Net, "addr is null!");
return ORBIS_NET_EINVAL; return ORBIS_NET_EINVAL;
} }
LOG_DEBUG(Lib_Net, "called");
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance(); auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
netinfo->RetrieveEthernetAddr(); netinfo->RetrieveEthernetAddr();
memcpy(addr->data, netinfo->GetEthernetAddr().data(), 6); 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) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "(DUMMY) called");
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -847,6 +990,8 @@ int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* pa
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_INFO(Lib_Net, "called, s = {}", s);
int result; int result;
int err; int err;
int positiveErr; 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"); LOG_ERROR(Lib_Net, "returned ORBIS_NET_ENOSPC");
return nullptr; return nullptr;
} }
LOG_DEBUG(Lib_Net, "called, af = {}", af);
const char* returnvalue = nullptr; const char* returnvalue = nullptr;
switch (af) { switch (af) {
case ORBIS_NET_AF_INET: 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) { if (returnvalue == nullptr) {
*sceNetErrnoLoc() = ORBIS_NET_ENOSPC; *sceNetErrnoLoc() = ORBIS_NET_ENOSPC;
LOG_ERROR(Lib_Net, "returned ORBIS_NET_ENOSPC"); LOG_ERROR(Lib_Net, "returned ORBIS_NET_ENOSPC");
} else {
LOG_DEBUG(Lib_Net, "returned {}", dst);
} }
return returnvalue; return returnvalue;
} }
@ -1104,21 +1253,32 @@ int PS4_SYSV_ABI sceNetInetNtopWithScopeId() {
return ORBIS_OK; 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) { int PS4_SYSV_ABI sceNetInetPton(int af, const char* src, void* dst) {
#ifdef WIN32 #ifdef WIN32
int res = InetPtonA(af, src, dst); int res = InetPtonA(af, src, dst);
#else #else
int res = inet_pton(af, src, dst); int res = inet_pton(ConvertFamilies(af), src, dst);
#endif #endif
if (res < 0) { if (res < 0) {
UNREACHABLE(); UNREACHABLE_MSG("af = {}, src = {}, dst = {}", af, src, fmt::ptr(dst));
} }
return res; return res;
} }
int PS4_SYSV_ABI sceNetInetPtonEx() { int PS4_SYSV_ABI sceNetInetPtonEx(int af, const char* src, void* dst, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); LOG_WARNING(Lib_Net, "ignored flags, redirecting to sceNetInetPton");
return ORBIS_OK; return sceNetInetPton(af, src, dst);
} }
int PS4_SYSV_ABI sceNetInetPtonWithScopeId() { int PS4_SYSV_ABI sceNetInetPtonWithScopeId() {
@ -1155,6 +1315,8 @@ int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog) {
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "(DUMMY) called");
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1240,6 +1402,8 @@ int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags) {
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "called, s = {}, len = {}, flags = {}", s, len, flags);
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1283,6 +1447,8 @@ int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, Orb
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
// LOG_INFO(Lib_Net, "called, s = {}, len = {}, flags = {}", s, len, flags);
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1325,6 +1491,8 @@ int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) {
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "(DUMMY) called");
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1388,12 +1556,13 @@ int PS4_SYSV_ABI sceNetResolverConnectDestroy() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetResolverCreate() { int PS4_SYSV_ABI sceNetResolverCreate(const char* name, int poolid, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); LOG_ERROR(Lib_Net, "(STUBBED) called, name = {}, poolid = {}, flags = {}", name, poolid, flags);
return ORBIS_OK; static int id = 1;
return id++;
} }
int PS4_SYSV_ABI sceNetResolverDestroy() { int PS4_SYSV_ABI sceNetResolverDestroy(OrbisNetId resolverid) {
LOG_ERROR(Lib_Net, "(STUBBED) called"); LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
@ -1413,9 +1582,44 @@ int PS4_SYSV_ABI sceNetResolverStartAton6() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetResolverStartNtoa() { int PS4_SYSV_ABI sceNetResolverStartNtoa(OrbisNetId resolverid, const char* hostname,
LOG_ERROR(Lib_Net, "(STUBBED) called"); OrbisNetInAddr* addr, int timeout, int retry, int flags) {
return ORBIS_OK; 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() { int PS4_SYSV_ABI sceNetResolverStartNtoa6() {
@ -1423,9 +1627,21 @@ int PS4_SYSV_ABI sceNetResolverStartNtoa6() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords() { int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords(OrbisNetId resolverid, const char* hostname,
LOG_ERROR(Lib_Net, "(STUBBED) called"); OrbisNetResolverInfo* info, int timeout,
return ORBIS_OK; 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() { 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) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "called, s = {}, len = {}, flags = {}", s, len, flags);
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1479,6 +1697,8 @@ int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flag
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "(DUMMY) called");
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1522,6 +1742,8 @@ int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags,
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "(DUMMY) called");
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1708,6 +1930,8 @@ int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how) {
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "(DUMMY) called");
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1750,6 +1974,9 @@ OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_INFO(Lib_Net, "name = {}, family = {}, type = {}, protocol = {}", name ? name : "no-named",
family, type, protocol);
int result; int result;
int err; int err;
int positiveErr; 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); result = sys_socketex(name, family, type, protocol);
if (result >= 0) { if (result >= 0) {
LOG_INFO(Lib_Net, "netId = {}", result);
return result; // Success return result; // Success
} }
@ -1792,6 +2020,8 @@ int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags) {
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_WARNING(Lib_Net, "(DUMMY) called");
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -1834,6 +2064,8 @@ int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s) {
if (!g_isNetInitialized) { if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT; return ORBIS_NET_ERROR_ENOTINIT;
} }
LOG_INFO(Lib_Net, "netId = {}", s);
int result; int result;
int err; int err;
int positiveErr; int positiveErr;
@ -2097,12 +2329,14 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("rMyh97BU5pY", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetMemoryPoolStats); LIB_FUNCTION("rMyh97BU5pY", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetMemoryPoolStats);
LIB_FUNCTION("+S-2-jlpaBo", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetNameToIndex); LIB_FUNCTION("+S-2-jlpaBo", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetNameToIndex);
LIB_FUNCTION("TCkRD0DWNLg", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetpeername); 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("G3O2j9f5z00", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetRandom);
LIB_FUNCTION("6Nx1hIQL9h8", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetRouteInfo); LIB_FUNCTION("6Nx1hIQL9h8", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetRouteInfo);
LIB_FUNCTION("hLuXdjHnhiI", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSockInfo); LIB_FUNCTION("hLuXdjHnhiI", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSockInfo);
LIB_FUNCTION("Cidi9Y65mP8", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSockInfo6); LIB_FUNCTION("Cidi9Y65mP8", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSockInfo6);
LIB_FUNCTION("hoOAofhhRvE", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetsockname); LIB_FUNCTION("hoOAofhhRvE", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetsockname);
LIB_FUNCTION("xphrZusl78E", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetsockopt); 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("GA5ZDaLtUBE", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetStatisticsInfo);
LIB_FUNCTION("9mIcUExH34w", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetStatisticsInfoInternal); LIB_FUNCTION("9mIcUExH34w", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetStatisticsInfoInternal);
LIB_FUNCTION("p2vxsE2U3RQ", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSystemTime); LIB_FUNCTION("p2vxsE2U3RQ", "libSceNet", 1, "libSceNet", 1, 1, sceNetGetSystemTime);

View File

@ -38,6 +38,7 @@ enum OrbisNetProtocol : u32 {
ORBIS_NET_IPPROTO_IGMP = 2, ORBIS_NET_IPPROTO_IGMP = 2,
ORBIS_NET_IPPROTO_TCP = 6, ORBIS_NET_IPPROTO_TCP = 6,
ORBIS_NET_IPPROTO_UDP = 17, ORBIS_NET_IPPROTO_UDP = 17,
ORBIS_NET_IPPROTO_IPV6 = 41,
ORBIS_NET_SOL_SOCKET = 0xFFFF ORBIS_NET_SOL_SOCKET = 0xFFFF
}; };
@ -81,6 +82,25 @@ enum OrbisNetSocketOption : u32 {
ORBIS_NET_SO_PRIORITY = 0x1203 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; using OrbisNetId = s32;
struct OrbisNetSockaddr { struct OrbisNetSockaddr {
@ -98,6 +118,12 @@ struct OrbisNetSockaddrIn {
char sin_zero[6]; char sin_zero[6];
}; };
using OrbisNetInAddr_t = u32;
struct OrbisNetInAddr {
OrbisNetInAddr_t inaddr_addr;
};
struct OrbisNetIovec { struct OrbisNetIovec {
void* iov_base; void* iov_base;
u64 iov_len; u64 iov_len;
@ -113,6 +139,38 @@ struct OrbisNetMsghdr {
int msg_flags; 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_any();
int PS4_SYSV_ABI in6addr_loopback(); int PS4_SYSV_ABI in6addr_loopback();
int PS4_SYSV_ABI sce_net_dummy(); 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 sceNetDuplicateIpStart();
int PS4_SYSV_ABI sceNetDuplicateIpStop(); int PS4_SYSV_ABI sceNetDuplicateIpStop();
int PS4_SYSV_ABI sceNetEpollAbort(); int PS4_SYSV_ABI sceNetEpollAbort();
int PS4_SYSV_ABI sceNetEpollControl(); int PS4_SYSV_ABI sceNetEpollControl(OrbisNetId epollid, OrbisNetEpollFlag op, OrbisNetId id,
int PS4_SYSV_ABI sceNetEpollCreate(); OrbisNetEpollEvent* event);
int PS4_SYSV_ABI sceNetEpollDestroy(); int PS4_SYSV_ABI sceNetEpollCreate(const char* name, int flags);
int PS4_SYSV_ABI sceNetEpollWait(); 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 sceNetErrnoLoc();
int PS4_SYSV_ABI sceNetEtherNtostr(); int PS4_SYSV_ABI sceNetEtherNtostr();
int PS4_SYSV_ABI sceNetEtherStrton(); 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); const char* PS4_SYSV_ABI sceNetInetNtop(int af, const void* src, char* dst, u32 size);
int PS4_SYSV_ABI sceNetInetNtopWithScopeId(); int PS4_SYSV_ABI sceNetInetNtopWithScopeId();
int PS4_SYSV_ABI sceNetInetPton(int af, const char* src, void* dst); 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 sceNetInetPtonWithScopeId();
int PS4_SYSV_ABI sceNetInfoDumpStart(); int PS4_SYSV_ABI sceNetInfoDumpStart();
int PS4_SYSV_ABI sceNetInfoDumpStop(); int PS4_SYSV_ABI sceNetInfoDumpStop();
@ -282,14 +342,17 @@ int PS4_SYSV_ABI sceNetResolverConnect();
int PS4_SYSV_ABI sceNetResolverConnectAbort(); int PS4_SYSV_ABI sceNetResolverConnectAbort();
int PS4_SYSV_ABI sceNetResolverConnectCreate(); int PS4_SYSV_ABI sceNetResolverConnectCreate();
int PS4_SYSV_ABI sceNetResolverConnectDestroy(); int PS4_SYSV_ABI sceNetResolverConnectDestroy();
int PS4_SYSV_ABI sceNetResolverCreate(); int PS4_SYSV_ABI sceNetResolverCreate(const char* name, int poolid, int flags);
int PS4_SYSV_ABI sceNetResolverDestroy(); int PS4_SYSV_ABI sceNetResolverDestroy(OrbisNetId resolverid);
int PS4_SYSV_ABI sceNetResolverGetError(); int PS4_SYSV_ABI sceNetResolverGetError();
int PS4_SYSV_ABI sceNetResolverStartAton(); int PS4_SYSV_ABI sceNetResolverStartAton();
int PS4_SYSV_ABI sceNetResolverStartAton6(); 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 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 sceNetResolverStartNtoaMultipleRecordsEx();
int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags); 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); int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags);

View File

@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm> #include <algorithm>
#include "common/config.h"
#include "common/logging/log.h"
#include "core/libraries/network/net_ctl_codes.h" #include "core/libraries/network/net_ctl_codes.h"
#include "core/libraries/network/net_ctl_obj.h" #include "core/libraries/network/net_ctl_obj.h"
#include "core/tls.h" #include "core/tls.h"
@ -44,18 +46,22 @@ s32 NetCtlInternal::RegisterNpToolkitCallback(OrbisNetCtlCallbackForNpToolkit fu
void NetCtlInternal::CheckCallback() { void NetCtlInternal::CheckCallback() {
std::scoped_lock lock{m_mutex}; 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) { for (const auto [func, arg] : callbacks) {
if (func != nullptr) { if (func != nullptr) {
Core::ExecuteGuest(func, ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED, arg); Core::ExecuteGuest(func, event, arg);
} }
} }
} }
void NetCtlInternal::CheckNpToolkitCallback() { void NetCtlInternal::CheckNpToolkitCallback() {
std::scoped_lock lock{m_mutex}; 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) { for (const auto [func, arg] : nptool_callbacks) {
if (func != nullptr) { if (func != nullptr) {
Core::ExecuteGuest(func, ORBIS_NET_CTL_EVENT_TYPE_DISCONNECTED, arg); Core::ExecuteGuest(func, event, arg);
} }
} }
} }

View File

@ -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

View File

@ -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 <mutex>
#include <vector>
#ifdef _WIN32
#include <wepoll.h>
#endif
#if defined(__linux__) || defined(__APPLE__)
#include <sys/epoll.h>
#include <unistd.h>
#endif
namespace Libraries::Net {
#ifdef _WIN32
using epoll_handle = HANDLE;
#else
using epoll_handle = int;
#endif
struct Epoll {
std::vector<std::pair<u32 /*netId*/, OrbisNetEpollEvent>> 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<Epoll> epolls;
std::mutex m_mutex;
};
} // namespace Libraries::Net

View File

@ -11,6 +11,7 @@ typedef int socklen_t;
#else #else
#include <cerrno> #include <cerrno>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <ifaddrs.h>
#include <net/if.h> #include <net/if.h>
#include <netdb.h> #include <netdb.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -21,9 +22,13 @@ typedef int socklen_t;
typedef int net_socket; typedef int net_socket;
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
#include <ifaddrs.h>
#include <net/if_dl.h> #include <net/if_dl.h>
#endif #endif
#if __linux__
#include <fstream>
#include <iostream>
#include <sstream>
#endif
#include <map> #include <map>
#include <memory> #include <memory>
@ -100,6 +105,8 @@ bool NetUtilInternal::RetrieveEthernetAddr() {
} }
} }
close(sock);
if (success) { if (success) {
memcpy(ether_address.data(), ifr.ifr_hwaddr.sa_data, 6); memcpy(ether_address.data(), ifr.ifr_hwaddr.sa_data, 6);
return true; return true;
@ -107,4 +114,104 @@ bool NetUtilInternal::RetrieveEthernetAddr() {
#endif #endif
return false; 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<u8> adapter_addresses(sizeof(IP_ADAPTER_ADDRESSES));
ULONG size_infos = sizeof(IP_ADAPTER_ADDRESSES);
if (GetAdaptersAddresses(AF_INET, 0, NULL,
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_addresses.data()),
&size_infos) == ERROR_BUFFER_OVERFLOW)
adapter_addresses.resize(size_infos);
if (GetAdaptersAddresses(AF_INET, 0, NULL,
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_addresses.data()),
&size_infos) == NO_ERROR &&
size_infos) {
PIP_ADAPTER_ADDRESSES adapter;
for (adapter = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(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<sockaddr_in*>(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 } // namespace NetUtil

View File

@ -15,10 +15,16 @@ public:
private: private:
std::array<u8, 6> ether_address{}; std::array<u8, 6> ether_address{};
std::string default_gateway{};
std::string netmask{};
std::mutex m_mutex; std::mutex m_mutex;
public: public:
const std::array<u8, 6>& GetEthernetAddr() const; const std::array<u8, 6>& GetEthernetAddr() const;
const std::string& GetDefaultGateway() const;
const std::string& GetNetmask() const;
bool RetrieveEthernetAddr(); bool RetrieveEthernetAddr();
bool RetrieveDefaultGateway();
bool RetrieveNetmask();
}; };
} // namespace NetUtil } // namespace NetUtil

View File

@ -13,6 +13,7 @@
#endif #endif
#include <common/singleton.h> #include <common/singleton.h>
#include "common/config.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
@ -69,8 +70,8 @@ int PS4_SYSV_ABI sceNetBweUnregisterCallbackIpcInt() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNetCtlGetInfoV6() { int PS4_SYSV_ABI sceNetCtlGetInfoV6(int code, void* param) {
LOG_ERROR(Lib_NetCtl, "(STUBBED) called"); LOG_ERROR(Lib_NetCtl, "(STUBBED) called, code = {}", code);
return ORBIS_OK; return ORBIS_OK;
} }
@ -95,7 +96,9 @@ int PS4_SYSV_ABI sceNetCtlUnregisterCallbackV6() {
} }
int PS4_SYSV_ABI sceNetCtlCheckCallback() { int PS4_SYSV_ABI sceNetCtlCheckCallback() {
LOG_DEBUG(Lib_NetCtl, "(STUBBED) called"); LOG_DEBUG(Lib_NetCtl, "called");
netctl.CheckCallback();
return ORBIS_OK; return ORBIS_OK;
} }
@ -160,12 +163,14 @@ int PS4_SYSV_ABI sceNetCtlGetIfStat() {
} }
int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) { int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
LOG_DEBUG(Lib_NetCtl, "code = {}", code);
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
switch (code) { switch (code) {
case ORBIS_NET_CTL_INFO_DEVICE: case ORBIS_NET_CTL_INFO_DEVICE:
info->device = ORBIS_NET_CTL_DEVICE_WIRED; info->device = ORBIS_NET_CTL_DEVICE_WIRED;
break; break;
case ORBIS_NET_CTL_INFO_ETHER_ADDR: { case ORBIS_NET_CTL_INFO_ETHER_ADDR: {
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
netinfo->RetrieveEthernetAddr(); netinfo->RetrieveEthernetAddr();
memcpy(info->ether_addr.data, netinfo->GetEthernetAddr().data(), 6); memcpy(info->ether_addr.data, netinfo->GetEthernetAddr().data(), 6);
} break; } break;
@ -173,7 +178,8 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
info->mtu = 1500; // default value info->mtu = 1500; // default value
break; break;
case ORBIS_NET_CTL_INFO_LINK: 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; break;
case ORBIS_NET_CTL_INFO_IP_ADDRESS: { case ORBIS_NET_CTL_INFO_IP_ADDRESS: {
strcpy(info->ip_address, strcpy(info->ip_address,
@ -193,11 +199,50 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
} }
break; 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: default:
LOG_ERROR(Lib_NetCtl, "{} unsupported code", code); LOG_ERROR(Lib_NetCtl, "{} unsupported code", code);
} }
LOG_DEBUG(Lib_NetCtl, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
@ -271,7 +316,10 @@ int PS4_SYSV_ABI sceNetCtlGetScanInfoForSsidScanIpcInt() {
} }
int PS4_SYSV_ABI sceNetCtlGetState(int* state) { 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; return ORBIS_OK;
} }
@ -296,7 +344,7 @@ int PS4_SYSV_ABI sceNetCtlGetWifiType() {
} }
int PS4_SYSV_ABI sceNetCtlInit() { int PS4_SYSV_ABI sceNetCtlInit() {
LOG_ERROR(Lib_NetCtl, "(STUBBED) called"); LOG_DEBUG(Lib_NetCtl, "called");
return ORBIS_OK; return ORBIS_OK;
} }
@ -309,12 +357,17 @@ int PS4_SYSV_ABI sceNetCtlRegisterCallback(OrbisNetCtlCallback func, void* arg,
if (!func || !cid) { if (!func || !cid) {
return ORBIS_NET_CTL_ERROR_INVALID_ADDR; return ORBIS_NET_CTL_ERROR_INVALID_ADDR;
} }
s32 result = netctl.RegisterCallback(func, arg); s32 result = netctl.RegisterCallback(func, arg);
if (result < 0) { if (result < 0) {
LOG_DEBUG(Lib_NetCtl, "failed with {:#x}", result);
return result; return result;
} else { } else {
LOG_DEBUG(Lib_NetCtl, "*cid = {}", result);
*cid = result; *cid = result;
} }
return ORBIS_OK; return ORBIS_OK;
} }
@ -384,7 +437,9 @@ int PS4_SYSV_ABI Func_D8DCB6973537A3DC() {
} }
int PS4_SYSV_ABI sceNetCtlCheckCallbackForNpToolkit() { int PS4_SYSV_ABI sceNetCtlCheckCallbackForNpToolkit() {
LOG_DEBUG(Lib_NetCtl, "(STUBBED) called"); LOG_DEBUG(Lib_NetCtl, "called");
netctl.CheckNpToolkitCallback();
return ORBIS_OK; return ORBIS_OK;
} }
@ -398,10 +453,14 @@ int PS4_SYSV_ABI sceNetCtlRegisterCallbackForNpToolkit(OrbisNetCtlCallbackForNpT
if (!func || !cid) { if (!func || !cid) {
return ORBIS_NET_CTL_ERROR_INVALID_ADDR; return ORBIS_NET_CTL_ERROR_INVALID_ADDR;
} }
s32 result = netctl.RegisterNpToolkitCallback(func, arg); s32 result = netctl.RegisterNpToolkitCallback(func, arg);
if (result < 0) { if (result < 0) {
LOG_WARNING(Lib_NetCtl, "failed with {:#x}", result);
return result; return result;
} else { } else {
LOG_DEBUG(Lib_NetCtl, "*cid = {}", result);
*cid = result; *cid = result;
} }
return ORBIS_OK; return ORBIS_OK;

View File

@ -79,7 +79,7 @@ int PS4_SYSV_ABI sceNetBweSetInternetConnectionTestResultIpcInt();
int PS4_SYSV_ABI sceNetBweStartInternetConnectionTestBandwidthTestIpcInt(); int PS4_SYSV_ABI sceNetBweStartInternetConnectionTestBandwidthTestIpcInt();
int PS4_SYSV_ABI sceNetBweStartInternetConnectionTestIpcInt(); int PS4_SYSV_ABI sceNetBweStartInternetConnectionTestIpcInt();
int PS4_SYSV_ABI sceNetBweUnregisterCallbackIpcInt(); 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 sceNetCtlGetResultV6();
int PS4_SYSV_ABI sceNetCtlGetStateV6(); int PS4_SYSV_ABI sceNetCtlGetStateV6();
int PS4_SYSV_ABI sceNetCtlRegisterCallbackV6(); int PS4_SYSV_ABI sceNetCtlRegisterCallbackV6();

View File

@ -57,4 +57,23 @@ int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
return 0; 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 } // namespace Libraries::Net

View File

@ -2,7 +2,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <common/assert.h> #include <common/assert.h>
#include "common/error.h"
#include "core/libraries/kernel/file_system.h"
#include "net.h" #include "net.h"
#ifndef _WIN32
#include <sys/stat.h>
#endif
#include "net_error.h" #include "net_error.h"
#include "sockets.h" #include "sockets.h"
@ -108,6 +113,17 @@ static int ConvertReturnErrorCode(int retval) {
return 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) { static int ConvertLevels(int level) {
switch (level) { switch (level) {
case ORBIS_NET_SOL_SOCKET: case ORBIS_NET_SOL_SOCKET:
@ -116,8 +132,13 @@ static int ConvertLevels(int level) {
return IPPROTO_IP; return IPPROTO_IP;
case ORBIS_NET_IPPROTO_TCP: case ORBIS_NET_IPPROTO_TCP:
return 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) { 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); 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() { int PosixSocket::Close() {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
#ifdef _WIN32 #ifdef _WIN32
@ -154,19 +181,27 @@ int PosixSocket::Close() {
int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) { int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
sockaddr addr2; sockaddr addr2;
convertOrbisNetSockaddrToPosix(addr, &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) { int PosixSocket::Listen(int backlog) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
LOG_DEBUG(Lib_Net, "called");
return ConvertReturnErrorCode(::listen(sock, backlog)); return ConvertReturnErrorCode(::listen(sock, backlog));
} }
int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
u32 tolen) { u32 tolen) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
LOG_DEBUG(Lib_Net, "called");
if (to != nullptr) { if (to != nullptr) {
sockaddr addr; sockaddr addr;
convertOrbisNetSockaddrToPosix(to, &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, int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from,
u32* fromlen) { u32* fromlen) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
// LOG_DEBUG(Lib_Net, "len = {}, flags = {:#x}, from = {:#x}", len, flags,
// reinterpret_cast<u64>(from));
if (from != nullptr) { if (from != nullptr) {
sockaddr addr; sockaddr addr;
int res = recvfrom(sock, (char*)buf, len, flags, &addr, (socklen_t*)fromlen); 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) { SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
LOG_DEBUG(Lib_Net, "called");
sockaddr addr2; 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 #ifdef _WIN32
if (new_socket != INVALID_SOCKET) { if (new_socket != INVALID_SOCKET) {
#else #else
if (new_socket >= 0) { if (new_socket >= 0) {
#endif #endif
if (addr && addrlen) {
convertPosixSockaddrToOrbis(&addr2, addr); convertPosixSockaddrToOrbis(&addr2, addr);
*addrlen = sizeof(OrbisNetSockaddrIn); *addrlen = sizeof(OrbisNetSockaddrIn);
}
return std::make_shared<PosixSocket>(new_socket); return std::make_shared<PosixSocket>(new_socket);
} }
return nullptr; return nullptr;
@ -209,13 +251,23 @@ SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) { int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
LOG_DEBUG(Lib_Net, "called");
sockaddr addr2; sockaddr addr2;
convertOrbisNetSockaddrToPosix(addr, &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) { int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
LOG_DEBUG(Lib_Net, "called");
sockaddr addr; sockaddr addr;
convertOrbisNetSockaddrToPosix(name, &addr); convertOrbisNetSockaddrToPosix(name, &addr);
if (name != nullptr) { if (name != nullptr) {
@ -229,6 +281,23 @@ int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
return res; 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) \ #define CASE_SETSOCKOPT(opt) \
case ORBIS_NET_##opt: \ case ORBIS_NET_##opt: \
return ConvertReturnErrorCode(setsockopt(sock, level, opt, (const char*)optval, optlen)) return ConvertReturnErrorCode(setsockopt(sock, level, opt, (const char*)optval, optlen))
@ -242,8 +311,9 @@ int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
return 0 return 0
int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) { int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
std::scoped_lock lock{m_mutex};
level = ConvertLevels(level); level = ConvertLevels(level);
LOG_INFO(Lib_Net, "level = {}, optname = {}, optlen = {}", level, optname, optlen);
std::scoped_lock lock{m_mutex};
::linger native_linger; ::linger native_linger;
if (level == SOL_SOCKET) { if (level == SOL_SOCKET) {
switch (optname) { switch (optname) {
@ -392,4 +462,37 @@ int PosixSocket::GetSocketOptions(int level, int optname, void* optval, u32* opt
return 0; 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 } // namespace Libraries::Net

View File

@ -26,6 +26,10 @@ typedef int net_socket;
#include <mutex> #include <mutex>
#include "net.h" #include "net.h"
namespace Libraries::Kernel {
struct OrbisKernelStat;
}
namespace Libraries::Net { namespace Libraries::Net {
struct Socket; struct Socket;
@ -51,6 +55,12 @@ struct Socket {
u32* fromlen) = 0; u32* fromlen) = 0;
virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0; virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0;
virtual int GetSocketAddress(OrbisNetSockaddr* name, 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; std::mutex m_mutex;
}; };
@ -65,10 +75,7 @@ struct PosixSocket : public Socket {
int sockopt_ip_maxttl = 0; int sockopt_ip_maxttl = 0;
int sockopt_tcp_mss_to_advertise = 0; int sockopt_tcp_mss_to_advertise = 0;
int socket_type; int socket_type;
explicit PosixSocket(int domain, int type, int protocol) explicit PosixSocket(int domain, int type, int protocol);
: Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {
socket_type = type;
}
explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {} explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {}
int Close() override; int Close() override;
int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) 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; SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
int Connect(const OrbisNetSockaddr* addr, u32 namelen) override; int Connect(const OrbisNetSockaddr* addr, u32 namelen) override;
int GetSocketAddress(OrbisNetSockaddr* name, 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 { struct P2PSocket : public Socket {
@ -96,6 +113,16 @@ struct P2PSocket : public Socket {
SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override; SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
int Connect(const OrbisNetSockaddr* addr, u32 namelen) override; int Connect(const OrbisNetSockaddr* addr, u32 namelen) override;
int GetSocketAddress(OrbisNetSockaddr* name, 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 { class NetInternal {

View File

@ -633,8 +633,17 @@ int PS4_SYSV_ABI sceSslFreeSslCertName() {
return ORBIS_OK; 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"); LOG_ERROR(Lib_Ssl, "(STUBBED) called");
certs->certs = nullptr;
certs->num = 0;
certs->pool = nullptr;
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -11,6 +11,13 @@ class SymbolsResolver;
namespace Libraries::Ssl { namespace Libraries::Ssl {
struct OrbisSslCaCerts;
struct OrbisSslCaList {
void* certs;
int certsNum;
};
int PS4_SYSV_ABI CA_MGMT_allocCertDistinguishedName(); int PS4_SYSV_ABI CA_MGMT_allocCertDistinguishedName();
int PS4_SYSV_ABI CA_MGMT_certDistinguishedNameCompare(); int PS4_SYSV_ABI CA_MGMT_certDistinguishedNameCompare();
int PS4_SYSV_ABI CA_MGMT_convertKeyBlobToPKCS8Key(); 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 sceSslFreeCaCerts();
int PS4_SYSV_ABI sceSslFreeCaList(); int PS4_SYSV_ABI sceSslFreeCaList();
int PS4_SYSV_ABI sceSslFreeSslCertName(); 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 sceSslGetCaList();
int PS4_SYSV_ABI sceSslGetIssuerName(); int PS4_SYSV_ABI sceSslGetIssuerName();
int PS4_SYSV_ABI sceSslGetMemoryPoolStats(); int PS4_SYSV_ABI sceSslGetMemoryPoolStats();

View File

@ -128,8 +128,18 @@ int PS4_SYSV_ABI sceSslGetAlpnSelected() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceSslGetCaCerts() { struct OrbisSslCaCerts {
LOG_ERROR(Lib_Ssl2, "(STUBBED) called"); 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; return ORBIS_OK;
} }

View File

@ -4,7 +4,9 @@
#include <common/assert.h> #include <common/assert.h>
#include <common/logging/log.h> #include <common/logging/log.h>
#include <core/libraries/kernel/kernel.h> #include <core/libraries/kernel/kernel.h>
#include "common/error.h"
#include "common/singleton.h" #include "common/singleton.h"
#include "core/file_sys/fs.h"
#include "net_error.h" #include "net_error.h"
#include "sockets.h" #include "sockets.h"
#include "sys_net.h" #include "sys_net.h"
@ -12,13 +14,16 @@
namespace Libraries::Net { namespace Libraries::Net {
int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) { int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); LOG_WARNING(Lib_Net, "s = {}", s);
auto sock = netcall->FindSocket(s);
if (!sock) { auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
int returncode = sock->Connect(addr, addrlen); int returncode = sock->Connect(addr, addrlen);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; return returncode;
@ -28,13 +33,16 @@ int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 add
return -1; return -1;
} }
int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) { int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); LOG_DEBUG(Lib_Net, "s = {}, addr = {}, addrlen = {}", s, fmt::ptr(addr), addrlen);
auto sock = netcall->FindSocket(s);
if (!sock) { auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
int returncode = sock->Bind(addr, addrlen); int returncode = sock->Bind(addr, addrlen);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; return returncode;
@ -44,35 +52,62 @@ int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrle
return -1; return -1;
} }
int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); LOG_WARNING(Lib_Net, "(DUMMY) called");
auto sock = netcall->FindSocket(s);
if (!sock) { auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
*Libraries::Kernel::__Error() = ORBIS_NET_EBADF; auto* file = h->GetFile(s);
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); if (!file || file->type != Core::FileSys::FileType::Socket) {
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<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; 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<Core::FileSys::HandleTable>::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<Core::FileSys::HandleTable>::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); int returncode = sock->GetSocketAddress(addr, paddrlen);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; return returncode;
@ -82,13 +117,16 @@ int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* padd
return -1; return -1;
} }
int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) { int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); LOG_WARNING(Lib_Net, "(DUMMY) called");
auto sock = netcall->FindSocket(s);
if (!sock) { auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
int returncode = sock->GetSocketOptions(level, optname, optval, optlen); int returncode = sock->GetSocketOptions(level, optname, optval, optlen);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; return returncode;
@ -98,13 +136,16 @@ int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optv
return -1; return -1;
} }
int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog) { int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); LOG_DEBUG(Lib_Net, "s = {}, backlog = {}", s, backlog);
auto sock = netcall->FindSocket(s);
if (!sock) { auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
int returncode = sock->Listen(backlog); int returncode = sock->Listen(backlog);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; 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); LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1; return -1;
} }
int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval, int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval,
u32 optlen) { u32 optlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); LOG_WARNING(Lib_Net, "netId = {}", s);
auto sock = netcall->FindSocket(s);
if (!sock) { auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
int returncode = sock->SetSocketOptions(level, optname, optval, optlen); int returncode = sock->SetSocketOptions(level, optname, optval, optlen);
LOG_INFO(Lib_Net, "returncode = {}", returncode);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; return returncode;
} }
@ -145,9 +191,16 @@ int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protoc
switch (type) { switch (type) {
case ORBIS_NET_SOCK_STREAM: case ORBIS_NET_SOCK_STREAM:
case ORBIS_NET_SOCK_DGRAM: case ORBIS_NET_SOCK_DGRAM:
case ORBIS_NET_SOCK_RAW: case ORBIS_NET_SOCK_RAW: {
sock = std::make_shared<PosixSocket>(family, type, protocol); const auto typed_socket = std::make_shared<PosixSocket>(family, type, protocol);
if (!typed_socket->IsValid()) {
*Libraries::Kernel::__Error() = ORBIS_NET_EPROTONOSUPPORT;
return -1;
}
sock = std::move(typed_socket);
break; break;
}
case ORBIS_NET_SOCK_DGRAM_P2P: case ORBIS_NET_SOCK_DGRAM_P2P:
case ORBIS_NET_SOCK_STREAM_P2P: case ORBIS_NET_SOCK_STREAM_P2P:
sock = std::make_shared<P2PSocket>(family, type, protocol); sock = std::make_shared<P2PSocket>(family, type, protocol);
@ -155,10 +208,16 @@ int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protoc
default: default:
UNREACHABLE_MSG("Unknown type {}", type); UNREACHABLE_MSG("Unknown type {}", type);
} }
auto* netcall = Common::Singleton<NetInternal>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto id = ++netcall->next_sock_id; u32 handle = h->CreateHandle();
netcall->socks.emplace(id, sock); auto* file = h->GetFile(handle);
return id; file->is_opened = true;
file->type = Core::FileSys::FileType::Socket;
file->socket = sock;
// auto* netcall = Common::Singleton<NetInternal>::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) { int PS4_SYSV_ABI sys_socket(int family, int type, int protocol) {
return sys_socketex(nullptr, family, type, protocol); return sys_socketex(nullptr, family, type, protocol);
@ -168,14 +227,19 @@ int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags) {
return -1; return -1;
} }
int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) { int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); LOG_INFO(Lib_Net, "called, s = {}", s);
auto sock = netcall->FindSocket(s);
if (!sock) { auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
file->is_opened = false;
int returncode = sock->Close(); int returncode = sock->Close();
h->DeleteHandle(s);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; return returncode;
} }
@ -183,15 +247,23 @@ int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) {
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1; 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, int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
const OrbisNetSockaddr* addr, u32 addrlen) { const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); LOG_WARNING(Lib_Net, "s = {}, len = {}, flags = {:#x}, addrlen = {}", s, len, flags, addrlen);
auto sock = netcall->FindSocket(s);
if (!sock) { auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
int returncode = sock->SendPacket(buf, len, flags, addr, addrlen); int returncode = sock->SendPacket(buf, len, flags, addr, addrlen);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; 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"); LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1; 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) { u32* paddrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance(); // LOG_INFO(Lib_Net, "s = {}, buf = {:#x}, len = {}, flags = {:#x}", s,
auto sock = netcall->FindSocket(s); // reinterpret_cast<u64>(buf), len, flags);
if (!sock) {
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(s);
if (!file || file->type != Core::FileSys::FileType::Socket) {
*Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1; return -1;
} }
auto sock = file->socket;
int returncode = sock->ReceivePacket(buf, len, flags, addr, paddrlen); int returncode = sock->ReceivePacket(buf, len, flags, addr, paddrlen);
if (returncode >= 0) { if (returncode >= 0) {
return returncode; return returncode;
} }
*Libraries::Kernel::__Error() = 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; 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"); LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1; return -1;
} }

View File

@ -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_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_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_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_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_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen);
int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog); 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_socket(int family, int type, int protocol);
int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags); int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags);
int PS4_SYSV_ABI sys_socketclose(OrbisNetId s); 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, int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
const OrbisNetSockaddr* addr, u32 addrlen); const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags); 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); 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 } // namespace Libraries::Net

View File

@ -2545,14 +2545,18 @@ struct NpStateCallbackForNpToolkit {
NpStateCallbackForNpToolkit NpStateCbForNp; NpStateCallbackForNpToolkit NpStateCbForNp;
int PS4_SYSV_ABI sceNpCheckCallbackForLib() { 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; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpRegisterStateCallbackForToolkit(OrbisNpStateCallbackForNpToolkit callback, int PS4_SYSV_ABI sceNpRegisterStateCallbackForToolkit(OrbisNpStateCallbackForNpToolkit callback,
void* userdata) { void* userdata) {
static int id = 0; static int id = 0;
LOG_ERROR(Lib_NpManager, "(STUBBED) called"); LOG_WARNING(Lib_NpManager, "(DUMMY) called");
NpStateCbForNp.func = callback; NpStateCbForNp.func = callback;
NpStateCbForNp.userdata = userdata; NpStateCbForNp.userdata = userdata;
return id; return id;

View File

@ -4,6 +4,7 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/system/commondialog.h"
#include "core/libraries/web_browser_dialog/webbrowserdialog.h" #include "core/libraries/web_browser_dialog/webbrowserdialog.h"
namespace Libraries::WebBrowserDialog { namespace Libraries::WebBrowserDialog {
@ -25,7 +26,7 @@ s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult() {
s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus() { s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called"); LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK; return (s32)Libraries::CommonDialog::Status::INITIALIZED;
} }
s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize() { s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize() {

View File

@ -134,6 +134,8 @@ void Emulator::Run(std::filesystem::path file, const std::vector<std::string> ar
LOG_INFO(Config, "General LogType: {}", Config::getLogType()); LOG_INFO(Config, "General LogType: {}", Config::getLogType());
LOG_INFO(Config, "General isNeo: {}", Config::isNeoModeConsole()); 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 isNullGpu: {}", Config::nullGpu());
LOG_INFO(Config, "GPU readbacks: {}", Config::readbacks()); LOG_INFO(Config, "GPU readbacks: {}", Config::readbacks());
LOG_INFO(Config, "GPU readbackLinearImages: {}", Config::readbackLinearImages()); LOG_INFO(Config, "GPU readbackLinearImages: {}", Config::readbackLinearImages());