diff --git a/CMakeLists.txt b/CMakeLists.txt index e36c1f280..f55767611 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -371,11 +371,19 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp src/core/libraries/network/net_ctl_obj.cpp src/core/libraries/network/net_ctl_obj.h src/core/libraries/network/net_ctl_codes.h + src/core/libraries/network/net_util.cpp + src/core/libraries/network/net_util.h + src/core/libraries/network/net_error.h src/core/libraries/network/net.h src/core/libraries/network/ssl.cpp src/core/libraries/network/ssl.h src/core/libraries/network/ssl2.cpp src/core/libraries/network/ssl2.h + src/core/libraries/network/sys_net.cpp + src/core/libraries/network/sys_net.h + src/core/libraries/network/posix_sockets.cpp + src/core/libraries/network/p2p_sockets.cpp + src/core/libraries/network/sockets.h ) set(AVPLAYER_LIB src/core/libraries/avplayer/avplayer_common.cpp diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index 33602bfe8..959a8605a 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -24,6 +24,7 @@ #include "core/libraries/kernel/threads/exception.h" #include "core/libraries/kernel/time.h" #include "core/libraries/libs.h" +#include "core/libraries/network/sys_net.h" #ifdef _WIN64 #include @@ -196,10 +197,6 @@ const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() { return path; } -int PS4_SYSV_ABI posix_connect() { - return -1; -} - int PS4_SYSV_ABI _sigprocmask() { return ORBIS_OK; } @@ -225,7 +222,6 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) { LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl); LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord); - LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, posix_connect); LIB_FUNCTION("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask); LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate); LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail); @@ -234,6 +230,25 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1, sceLibcHeapGetTraceInfo); + + // network + LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_connect); + LIB_FUNCTION("TU-d9PfIHPM", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_socketex); + LIB_FUNCTION("KuOmgKoqCdY", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_bind); + LIB_FUNCTION("pxnCmagrtao", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_listen); + LIB_FUNCTION("3e+4Iv7IJ8U", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_accept); + LIB_FUNCTION("TU-d9PfIHPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_socket); + LIB_FUNCTION("oBr313PppNE", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto); + LIB_FUNCTION("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom); + LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1, + Libraries::Net::sys_setsockopt); + LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, + Libraries::Net::sys_getsockname); + LIB_FUNCTION("KuOmgKoqCdY", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_bind); + LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1, + Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ... + LIB_FUNCTION("4n51s0zEf0c", "libScePosix", 1, "libkernel", 1, 1, + Libraries::Net::sceNetInetPton); // TODO fix it to sys_ ... } } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/kernel.h b/src/core/libraries/kernel/kernel.h index 58911727d..4d68aa357 100644 --- a/src/core/libraries/kernel/kernel.h +++ b/src/core/libraries/kernel/kernel.h @@ -18,6 +18,7 @@ namespace Libraries::Kernel { void ErrSceToPosix(int result); int ErrnoToSceKernelError(int e); void SetPosixErrno(int e); +int* PS4_SYSV_ABI __Error(); template struct WrapperImpl; diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp index 161fc5214..1f024277f 100644 --- a/src/core/libraries/network/net.cpp +++ b/src/core/libraries/network/net.cpp @@ -10,16 +10,24 @@ #include #endif +#include #include "common/assert.h" #include "common/logging/log.h" +#include "common/singleton.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" #include "core/libraries/network/net.h" +#include "net_error.h" +#include "net_util.h" +#include "netctl.h" +#include "sys_net.h" namespace Libraries::Net { static thread_local int32_t net_errno = 0; +static bool g_isNetInitialized = true; // TODO init it properly + int PS4_SYSV_ABI in6addr_any() { LOG_ERROR(Lib_Net, "(STUBBED) called"); return ORBIS_OK; @@ -61,8 +69,45 @@ int PS4_SYSV_ABI sce_net_in6addr_nodelocal_allnodes() { } OrbisNetId PS4_SYSV_ABI sceNetAccept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_accept(s, addr, paddrlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetAddrConfig6GetInfo() { @@ -121,8 +166,45 @@ int PS4_SYSV_ABI sceNetBandwidthControlSetPolicy() { } int PS4_SYSV_ABI sceNetBind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_bind(s, addr, addrlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetClearDnsCache() { @@ -465,9 +547,46 @@ int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetConnect() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_connect(s, addr, addrlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetControl() { @@ -640,8 +759,15 @@ int PS4_SYSV_ABI sceNetGetIfnameNumList() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetGetMacAddress() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); +int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags) { + if (addr == nullptr) { + LOG_ERROR(Lib_Net, "addr is null!"); + return ORBIS_NET_EINVAL; + } + auto* netinfo = Common::Singleton::Instance(); + netinfo->RetrieveEthernetAddr(); + memcpy(addr->data, netinfo->GetEthernetAddr().data(), 6); + return ORBIS_OK; } @@ -655,9 +781,46 @@ int PS4_SYSV_ABI sceNetGetNameToIndex() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetGetpeername() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_getpeername(s, addr, paddrlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetGetRandom() { @@ -681,13 +844,87 @@ int PS4_SYSV_ABI sceNetGetSockInfo6() { } int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_getsockname(s, addr, paddrlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetGetsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_getsockopt(s, level, optname, optval, optlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetGetStatisticsInfo() { @@ -781,9 +1018,46 @@ int PS4_SYSV_ABI sceNetIoctl() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetListen() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_listen(s, backlog); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetMemoryAllocate() { @@ -829,20 +1103,131 @@ int PS4_SYSV_ABI sceNetPppoeStop() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetRecv() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_recvfrom(s, buf, len, flags | 0x40000000, nullptr, 0); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } -int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags, - OrbisNetSockaddr* addr, u32* paddrlen) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr, + u32* paddrlen) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_recvfrom(s, buf, len, flags | 0x40000000, addr, paddrlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } -int PS4_SYSV_ABI sceNetRecvmsg() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_recvmsg(s, msg, flags | 0x40000000); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetResolverAbort() { @@ -915,19 +1300,131 @@ int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetSend() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_sendto(s, buf, len, flags | 0x40020000, nullptr, 0); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } -int PS4_SYSV_ABI sceNetSendmsg() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_sendmsg(s, msg, flags | 0x40020000); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } -int PS4_SYSV_ABI sceNetSendto() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags, + const OrbisNetSockaddr* addr, u32 addrlen) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_sendto(s, buf, len, flags | 0x40020000, addr, addrlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetSetDns6Info() { @@ -950,9 +1447,47 @@ int PS4_SYSV_ABI sceNetSetDnsInfoToKernel() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetSetsockopt() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval, + u32 optlen) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_setsockopt(s, level, optname, optval, optlen); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetShowIfconfig() { @@ -1035,24 +1570,172 @@ int PS4_SYSV_ABI sceNetShowRouteWithMemory() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNetShutdown() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_shutdown(s, how); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } -int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_socketex(name, family, type, protocol); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } -int PS4_SYSV_ABI sceNetSocketAbort() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_netabort(s, flags); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } -int PS4_SYSV_ABI sceNetSocketClose() { - LOG_ERROR(Lib_Net, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s) { + if (!g_isNetInitialized) { + return ORBIS_NET_ERROR_ENOTINIT; + } + int result; + int err; + int positiveErr; + + do { + result = sys_socketclose(s); + + if (result >= 0) { + return result; // Success + } + + err = *Libraries::Kernel::__Error(); // Standard errno + + // Convert to positive error for comparison + int positiveErr = (err < 0) ? -err : err; + + if ((positiveErr & 0xfff0000) != 0) { + // Unknown/fatal error range + *sceNetErrnoLoc() = ORBIS_NET_ERETURN; + return -positiveErr; + } + + // Retry if interrupted + } while (positiveErr == ORBIS_NET_EINTR); + + if (positiveErr == ORBIS_NET_EADDRINUSE) { + result = -ORBIS_NET_EBADF; + } else if (positiveErr == ORBIS_NET_EALREADY) { + result = -ORBIS_NET_EINTR; + } else { + result = -positiveErr; + } + + *sceNetErrnoLoc() = -result; + + return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code } int PS4_SYSV_ABI sceNetSyncCreate() { diff --git a/src/core/libraries/network/net.h b/src/core/libraries/network/net.h index beef38b56..812ee6bd7 100644 --- a/src/core/libraries/network/net.h +++ b/src/core/libraries/network/net.h @@ -4,6 +4,7 @@ #pragma once #include "common/types.h" +#include "netctl.h" namespace Core::Loader { class SymbolsResolver; @@ -19,6 +20,63 @@ class SymbolsResolver; namespace Libraries::Net { +enum OrbisNetSocketType : u32 { + ORBIS_NET_SOCK_STREAM = 1, + ORBIS_NET_SOCK_DGRAM = 2, + ORBIS_NET_SOCK_RAW = 3, + ORBIS_NET_SOCK_DGRAM_P2P = 6, + ORBIS_NET_SOCK_STREAM_P2P = 10 +}; + +enum OrbisNetProtocol : u32 { + ORBIS_NET_IPPROTO_IP = 0, + ORBIS_NET_IPPROTO_ICMP = 1, + ORBIS_NET_IPPROTO_IGMP = 2, + ORBIS_NET_IPPROTO_TCP = 6, + ORBIS_NET_IPPROTO_UDP = 17, + ORBIS_NET_SOL_SOCKET = 0xFFFF +}; + +enum OrbisNetSocketOption : u32 { + /* IP */ + ORBIS_NET_IP_HDRINCL = 2, + ORBIS_NET_IP_TOS = 3, + ORBIS_NET_IP_TTL = 4, + ORBIS_NET_IP_MULTICAST_IF = 9, + ORBIS_NET_IP_MULTICAST_TTL = 10, + ORBIS_NET_IP_MULTICAST_LOOP = 11, + ORBIS_NET_IP_ADD_MEMBERSHIP = 12, + ORBIS_NET_IP_DROP_MEMBERSHIP = 13, + ORBIS_NET_IP_TTLCHK = 23, + ORBIS_NET_IP_MAXTTL = 24, + /* TCP */ + ORBIS_NET_TCP_NODELAY = 1, + ORBIS_NET_TCP_MAXSEG = 2, + ORBIS_NET_TCP_MSS_TO_ADVERTISE = 3, + /* SOCKET */ + ORBIS_NET_SO_REUSEADDR = 0x00000004, + ORBIS_NET_SO_KEEPALIVE = 0x00000008, + ORBIS_NET_SO_BROADCAST = 0x00000020, + ORBIS_NET_SO_LINGER = 0x00000080, + ORBIS_NET_SO_REUSEPORT = 0x00000200, + ORBIS_NET_SO_ONESBCAST = 0x00010000, + ORBIS_NET_SO_USECRYPTO = 0x00020000, + ORBIS_NET_SO_USESIGNATURE = 0x00040000, + ORBIS_NET_SO_SNDBUF = 0x1001, + ORBIS_NET_SO_RCVBUF = 0x1002, + ORBIS_NET_SO_ERROR = 0x1007, + ORBIS_NET_SO_TYPE = 0x1008, + ORBIS_NET_SO_SNDTIMEO = 0x1105, + ORBIS_NET_SO_RCVTIMEO = 0x1106, + ORBIS_NET_SO_ERROR_EX = 0x1107, + ORBIS_NET_SO_ACCEPTTIMEO = 0x1108, + ORBIS_NET_SO_CONNECTTIMEO = 0x1109, + ORBIS_NET_SO_NBIO = 0x1200, + ORBIS_NET_SO_POLICY = 0x1201, + ORBIS_NET_SO_NAME = 0x1202, + ORBIS_NET_SO_PRIORITY = 0x1203 +}; + using OrbisNetId = s32; struct OrbisNetSockaddr { @@ -27,6 +85,30 @@ struct OrbisNetSockaddr { char sa_data[14]; }; +struct OrbisNetSockaddrIn { + u8 sin_len; + u8 sin_family; + u16 sin_port; + u32 sin_addr; + u16 sin_vport; + char sin_zero[6]; +}; + +struct OrbisNetIovec { + void* iov_base; + u64 iov_len; +}; + +struct OrbisNetMsghdr { + void* msg_name; + u32 msg_namelen; + OrbisNetIovec* msg_iov; + int msg_iovlen; + void* msg_control; + u32 msg_controllen; + int msg_flags; +}; + int PS4_SYSV_ABI in6addr_any(); int PS4_SYSV_ABI in6addr_loopback(); int PS4_SYSV_ABI sce_net_dummy(); @@ -116,7 +198,7 @@ int PS4_SYSV_ABI sceNetConfigWlanInfraLeave(); int PS4_SYSV_ABI sceNetConfigWlanInfraScanJoin(); int PS4_SYSV_ABI sceNetConfigWlanScan(); int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig(); -int PS4_SYSV_ABI sceNetConnect(); +int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen); int PS4_SYSV_ABI sceNetControl(); int PS4_SYSV_ABI sceNetDhcpdStart(); int PS4_SYSV_ABI sceNetDhcpdStop(); @@ -151,10 +233,10 @@ int PS4_SYSV_ABI sceNetGetIfList(); int PS4_SYSV_ABI sceNetGetIfListOnce(); int PS4_SYSV_ABI sceNetGetIfName(); int PS4_SYSV_ABI sceNetGetIfnameNumList(); -int PS4_SYSV_ABI sceNetGetMacAddress(); +int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags); int PS4_SYSV_ABI sceNetGetMemoryPoolStats(); int PS4_SYSV_ABI sceNetGetNameToIndex(); -int PS4_SYSV_ABI sceNetGetpeername(); +int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen); int PS4_SYSV_ABI sceNetGetRandom(); int PS4_SYSV_ABI sceNetGetRouteInfo(); int PS4_SYSV_ABI sceNetGetSockInfo(); @@ -177,7 +259,7 @@ int PS4_SYSV_ABI sceNetInfoDumpStop(); int PS4_SYSV_ABI sceNetInit(); int PS4_SYSV_ABI sceNetInitParam(); int PS4_SYSV_ABI sceNetIoctl(); -int PS4_SYSV_ABI sceNetListen(); +int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog); int PS4_SYSV_ABI sceNetMemoryAllocate(); int PS4_SYSV_ABI sceNetMemoryFree(); u32 PS4_SYSV_ABI sceNetNtohl(u32 net32); @@ -187,10 +269,10 @@ int PS4_SYSV_ABI sceNetPoolCreate(const char* name, int size, int flags); int PS4_SYSV_ABI sceNetPoolDestroy(); int PS4_SYSV_ABI sceNetPppoeStart(); int PS4_SYSV_ABI sceNetPppoeStop(); -int PS4_SYSV_ABI sceNetRecv(); -int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags, - OrbisNetSockaddr* addr, u32* paddrlen); -int PS4_SYSV_ABI sceNetRecvmsg(); +int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags); +int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr, + u32* paddrlen); +int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags); int PS4_SYSV_ABI sceNetResolverAbort(); int PS4_SYSV_ABI sceNetResolverConnect(); int PS4_SYSV_ABI sceNetResolverConnectAbort(); @@ -205,14 +287,16 @@ int PS4_SYSV_ABI sceNetResolverStartNtoa(); int PS4_SYSV_ABI sceNetResolverStartNtoa6(); int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords(); int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx(); -int PS4_SYSV_ABI sceNetSend(); -int PS4_SYSV_ABI sceNetSendmsg(); -int PS4_SYSV_ABI sceNetSendto(); +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 sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags, + const OrbisNetSockaddr* addr, u32 addrlen); int PS4_SYSV_ABI sceNetSetDns6Info(); int PS4_SYSV_ABI sceNetSetDns6InfoToKernel(); int PS4_SYSV_ABI sceNetSetDnsInfo(); int PS4_SYSV_ABI sceNetSetDnsInfoToKernel(); -int PS4_SYSV_ABI sceNetSetsockopt(); +int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval, + u32 optlen); int PS4_SYSV_ABI sceNetShowIfconfig(); int PS4_SYSV_ABI sceNetShowIfconfigForBuffer(); int PS4_SYSV_ABI sceNetShowIfconfigWithMemory(); @@ -229,10 +313,10 @@ int PS4_SYSV_ABI sceNetShowRoute6ForBuffer(); int PS4_SYSV_ABI sceNetShowRoute6WithMemory(); int PS4_SYSV_ABI sceNetShowRouteForBuffer(); int PS4_SYSV_ABI sceNetShowRouteWithMemory(); -int PS4_SYSV_ABI sceNetShutdown(); -int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol); -int PS4_SYSV_ABI sceNetSocketAbort(); -int PS4_SYSV_ABI sceNetSocketClose(); +int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how); +OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol); +int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags); +int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s); int PS4_SYSV_ABI sceNetSyncCreate(); int PS4_SYSV_ABI sceNetSyncDestroy(); int PS4_SYSV_ABI sceNetSyncGet(); diff --git a/src/core/libraries/network/net_error.h b/src/core/libraries/network/net_error.h new file mode 100644 index 000000000..ab65300c0 --- /dev/null +++ b/src/core/libraries/network/net_error.h @@ -0,0 +1,162 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +// net errno codes +constexpr int ORBIS_NET_EPERM = 1; +constexpr int ORBIS_NET_ENOENT = 2; +constexpr int ORBIS_NET_EINTR = 4; +constexpr int ORBIS_NET_EBADF = 9; +constexpr int ORBIS_NET_EACCES = 13; +constexpr int ORBIS_NET_EFAULT = 14; +constexpr int ORBIS_NET_ENOTBLK = 15; +constexpr int ORBIS_NET_EBUSY = 16; +constexpr int ORBIS_NET_EEXIST = 17; +constexpr int ORBIS_NET_ENODEV = 19; +constexpr int ORBIS_NET_EINVAL = 22; +constexpr int ORBIS_NET_EMFILE = 24; +constexpr int ORBIS_NET_ENOSPC = 28; +constexpr int ORBIS_NET_EPIPE = 32; +constexpr int ORBIS_NET_EAGAIN = 35; +constexpr int ORBIS_NET_EWOULDBLOCK = 35; +constexpr int ORBIS_NET_EINPROGRESS = 36; +constexpr int ORBIS_NET_EALREADY = 37; +constexpr int ORBIS_NET_ENOTSOCK = 38; +constexpr int ORBIS_NET_EDESTADDRREQ = 39; +constexpr int ORBIS_NET_EMSGSIZE = 40; +constexpr int ORBIS_NET_EPROTOTYPE = 41; +constexpr int ORBIS_NET_ENOPROTOOPT = 42; +constexpr int ORBIS_NET_EPROTONOSUPPORT = 43; +constexpr int ORBIS_NET_EOPNOTSUPP = 45; +constexpr int ORBIS_NET_EAFNOSUPPORT = 47; +constexpr int ORBIS_NET_EADDRINUSE = 48; +constexpr int ORBIS_NET_EADDRNOTAVAIL = 49; +constexpr int ORBIS_NET_ENETDOWN = 50; +constexpr int ORBIS_NET_ENETUNREACH = 51; +constexpr int ORBIS_NET_ENETRESET = 52; +constexpr int ORBIS_NET_ECONNABORTED = 53; +constexpr int ORBIS_NET_ECONNRESET = 54; +constexpr int ORBIS_NET_EISCONN = 56; +constexpr int ORBIS_NET_ENOTCONN = 57; +constexpr int ORBIS_NET_ETOOMANYREFS = 59; +constexpr int ORBIS_NET_ETIMEDOUT = 60; +constexpr int ORBIS_NET_ECONNREFUSED = 61; +constexpr int ORBIS_NET_ELOOP = 62; +constexpr int ORBIS_NET_ENAMETOOLONG = 63; +constexpr int ORBIS_NET_EHOSTDOWN = 64; +constexpr int ORBIS_NET_EHOSTUNREACH = 65; +constexpr int ORBIS_NET_ENOTEMPTY = 66; +constexpr int ORBIS_NET_EPROCUNAVAIL = 76; +constexpr int ORBIS_NET_EPROTO = 92; +constexpr int ORBIS_NET_EADHOC = 160; +constexpr int ORBIS_NET_EINACTIVEDISABLED = 163; +constexpr int ORBIS_NET_ENODATA = 164; +constexpr int ORBIS_NET_EDESC = 165; +constexpr int ORBIS_NET_EDESCTIMEDOUT = 166; +constexpr int ORBIS_NET_ENOTINIT = 200; +constexpr int ORBIS_NET_ENOLIBMEM = 201; +constexpr int ORBIS_NET_ECALLBACK = 203; +constexpr int ORBIS_NET_EINTERNAL = 204; +constexpr int ORBIS_NET_ERETURN = 205; +constexpr int ORBIS_NET_ENOALLOCMEM = 206; + +// errno for dns resolver +constexpr int ORBIS_NET_RESOLVER_EINTERNAL = 220; +constexpr int ORBIS_NET_RESOLVER_EBUSY = 221; +constexpr int ORBIS_NET_RESOLVER_ENOSPACE = 222; +constexpr int ORBIS_NET_RESOLVER_EPACKET = 223; +constexpr int ORBIS_NET_RESOLVER_ENODNS = 225; +constexpr int ORBIS_NET_RESOLVER_ETIMEDOUT = 226; +constexpr int ORBIS_NET_RESOLVER_ENOSUPPORT = 227; +constexpr int ORBIS_NET_RESOLVER_EFORMAT = 228; +constexpr int ORBIS_NET_RESOLVER_ESERVERFAILURE = 229; +constexpr int ORBIS_NET_RESOLVER_ENOHOST = 230; +constexpr int ORBIS_NET_RESOLVER_ENOTIMPLEMENTED = 231; +constexpr int ORBIS_NET_RESOLVER_ESERVERREFUSED = 232; +constexpr int ORBIS_NET_RESOLVER_ENORECORD = 233; +constexpr int ORBIS_NET_RESOLVER_EALIGNMENT = 234; + +// common errno +constexpr int ORBIS_NET_ENOMEM = 12; +constexpr int ORBIS_NET_ENOBUFS = 55; + +// error codes +constexpr int ORBIS_NET_ERROR_BASE = 0x80410100; // not existed used for calculation +constexpr int ORBIS_NET_ERROR_EPERM = 0x80410101; +constexpr int ORBIS_NET_ERROR_ENOENT = 0x80410102; +constexpr int ORBIS_NET_ERROR_EINTR = 0x80410104; +constexpr int ORBIS_NET_ERROR_EBADF = 0x80410109; +constexpr int ORBIS_NET_ERROR_ENOMEM = 0x8041010c; +constexpr int ORBIS_NET_ERROR_EACCES = 0x8041010d; +constexpr int ORBIS_NET_ERROR_EFAULT = 0x8041010e; +constexpr int ORBIS_NET_ERROR_ENOTBLK = 0x8041010f; +constexpr int ORBIS_NET_ERROR_EEXIST = 0x80410111; +constexpr int ORBIS_NET_ERROR_ENODEV = 0x80410113; +constexpr int ORBIS_NET_ERROR_EINVAL = 0x80410116; +constexpr int ORBIS_NET_ERROR_ENFILE = 0x80410117; +constexpr int ORBIS_NET_ERROR_EMFILE = 0x80410118; +constexpr int ORBIS_NET_ERROR_ENOSPC = 0x8041011c; +constexpr int ORBIS_NET_ERROR_EPIPE = 0x80410120; +constexpr int ORBIS_NET_ERROR_EAGAIN = 0x80410123; +constexpr int ORBIS_NET_ERROR_EWOULDBLOCK = 0x80410123; +constexpr int ORBIS_NET_ERROR_EINPROGRESS = 0x80410124; +constexpr int ORBIS_NET_ERROR_EALREADY = 0x80410125; +constexpr int ORBIS_NET_ERROR_ENOTSOCK = 0x80410126; +constexpr int ORBIS_NET_ERROR_EDESTADDRREQ = 0x80410127; +constexpr int ORBIS_NET_ERROR_EMSGSIZE = 0x80410128; +constexpr int ORBIS_NET_ERROR_EPROTOTYPE = 0x80410129; +constexpr int ORBIS_NET_ERROR_ENOPROTOOPT = 0x8041012a; +constexpr int ORBIS_NET_ERROR_EPROTONOSUPPORT = 0x8041012b; +constexpr int ORBIS_NET_ERROR_EOPNOTSUPP = 0x8041012d; +constexpr int ORBIS_NET_ERROR_EPFNOSUPPORT = 0x8041012e; +constexpr int ORBIS_NET_ERROR_EAFNOSUPPORT = 0x8041012f; +constexpr int ORBIS_NET_ERROR_EADDRINUSE = 0x80410130; +constexpr int ORBIS_NET_ERROR_EADDRNOTAVAIL = 0x80410131; +constexpr int ORBIS_NET_ERROR_ENETDOWN = 0x80410132; +constexpr int ORBIS_NET_ERROR_ENETUNREACH = 0x80410133; +constexpr int ORBIS_NET_ERROR_ENETRESET = 0x80410134; +constexpr int ORBIS_NET_ERROR_ECONNABORTED = 0x80410135; +constexpr int ORBIS_NET_ERROR_ECONNRESET = 0x80410136; +constexpr int ORBIS_NET_ERROR_ENOBUFS = 0x80410137; +constexpr int ORBIS_NET_ERROR_EISCONN = 0x80410138; +constexpr int ORBIS_NET_ERROR_ENOTCONN = 0x80410139; +constexpr int ORBIS_NET_ERROR_ESHUTDOWN = 0x8041013a; +constexpr int ORBIS_NET_ERROR_ETOOMANYREFS = 0x8041013b; +constexpr int ORBIS_NET_ERROR_ETIMEDOUT = 0x8041013c; +constexpr int ORBIS_NET_ERROR_ECONNREFUSED = 0x8041013d; +constexpr int ORBIS_NET_ERROR_ELOOP = 0x8041013e; +constexpr int ORBIS_NET_ERROR_ENAMETOOLONG = 0x8041013f; +constexpr int ORBIS_NET_ERROR_EHOSTDOWN = 0x80410140; +constexpr int ORBIS_NET_ERROR_EHOSTUNREACH = 0x80410141; +constexpr int ORBIS_NET_ERROR_ENOTEMPTY = 0x80410142; +constexpr int ORBIS_NET_ERROR_EPROCUNAVAIL = 0x8041014C; +constexpr int ORBIS_NET_ERROR_ECANCELED = 0x80410157; +constexpr int ORBIS_NET_ERROR_EPROTO = 0x8041015C; +constexpr int ORBIS_NET_ERROR_EADHOC = 0x804101a0; +constexpr int ORBIS_NET_ERROR_ERESERVED161 = 0x804101a1; +constexpr int ORBIS_NET_ERROR_ERESERVED162 = 0x804101a2; +constexpr int ORBIS_NET_ERROR_EINACTIVEDISABLED = 0x804101a3; +constexpr int ORBIS_NET_ERROR_ENODATA = 0x804101a4; +constexpr int ORBIS_NET_ERROR_EDESC = 0x804101a5; +constexpr int ORBIS_NET_ERROR_EDESCTIMEDOUT = 0x804101a6; +constexpr int ORBIS_NET_ERROR_ENOTINIT = 0x804101c8; +constexpr int ORBIS_NET_ERROR_ENOLIBMEM = 0x804101c9; +constexpr int ORBIS_NET_ERROR_ECALLBACK = 0x804101cb; +constexpr int ORBIS_NET_ERROR_EINTERNAL = 0x804101cc; +constexpr int ORBIS_NET_ERROR_ERETURN = 0x804101cd; +constexpr int ORBIS_NET_ERROR_ENOALLOCMEM = 0x804101ce; +constexpr int ORBIS_NET_ERROR_RESOLVER_EINTERNAL = 0x804101dc; +constexpr int ORBIS_NET_ERROR_RESOLVER_EBUSY = 0x804101dd; +constexpr int ORBIS_NET_ERROR_RESOLVER_ENOSPACE = 0x804101de; +constexpr int ORBIS_NET_ERROR_RESOLVER_EPACKET = 0x804101df; +constexpr int ORBIS_NET_ERROR_RESOLVER_ENODNS = 0x804101e1; +constexpr int ORBIS_NET_ERROR_RESOLVER_ETIMEDOUT = 0x804101e2; +constexpr int ORBIS_NET_ERROR_RESOLVER_ENOSUPPORT = 0x804101e3; +constexpr int ORBIS_NET_ERROR_RESOLVER_EFORMAT = 0x804101e4; +constexpr int ORBIS_NET_ERROR_RESOLVER_ESERVERFAILURE = 0x804101e5; +constexpr int ORBIS_NET_ERROR_RESOLVER_ENOHOST = 0x804101e6; +constexpr int ORBIS_NET_ERROR_RESOLVER_ENOTIMPLEMENTED = 0x804101e7; +constexpr int ORBIS_NET_ERROR_RESOLVER_ESERVERREFUSED = 0x804101e8; +constexpr int ORBIS_NET_ERROR_RESOLVER_ENORECORD = 0x804101e9; +constexpr int ORBIS_NET_ERROR_RESOLVER_EALIGNMENT = 0x804101ea; diff --git a/src/core/libraries/network/net_util.cpp b/src/core/libraries/network/net_util.cpp new file mode 100644 index 000000000..d0f0a81da --- /dev/null +++ b/src/core/libraries/network/net_util.cpp @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef _WIN32 +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#include +#include +#include +typedef SOCKET net_socket; +typedef int socklen_t; +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +typedef int net_socket; +#endif +#if defined(__APPLE__) +#include +#include +#endif + +#include +#include +#include +#include +#include +#include "net_util.h" + +namespace NetUtil { + +const std::array& NetUtilInternal::GetEthernetAddr() const { + return ether_address; +} + +bool NetUtilInternal::RetrieveEthernetAddr() { + std::scoped_lock lock{m_mutex}; +#ifdef _WIN32 + std::vector adapter_infos(sizeof(IP_ADAPTER_INFO)); + ULONG size_infos = sizeof(IP_ADAPTER_INFO); + + if (GetAdaptersInfo(reinterpret_cast(adapter_infos.data()), &size_infos) == + ERROR_BUFFER_OVERFLOW) + adapter_infos.resize(size_infos); + + if (GetAdaptersInfo(reinterpret_cast(adapter_infos.data()), &size_infos) == + NO_ERROR && + size_infos) { + PIP_ADAPTER_INFO info = reinterpret_cast(adapter_infos.data()); + memcpy(ether_address.data(), info[0].Address, 6); + return true; + } +#elif defined(__APPLE__) + ifaddrs* ifap; + + if (getifaddrs(&ifap) == 0) { + ifaddrs* p; + for (p = ifap; p; p = p->ifa_next) { + if (p->ifa_addr->sa_family == AF_LINK) { + sockaddr_dl* sdp = reinterpret_cast(p->ifa_addr); + memcpy(ether_address.data(), sdp->sdl_data + sdp->sdl_nlen, 6); + freeifaddrs(ifap); + return true; + } + } + freeifaddrs(ifap); + } +#else + ifreq ifr; + ifconf ifc; + char buf[1024]; + int success = 0; + + int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + if (sock == -1) + return false; + + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) + return false; + + ifreq* it = ifc.ifc_req; + const ifreq* const end = it + (ifc.ifc_len / sizeof(ifreq)); + + for (; it != end; ++it) { + strcpy(ifr.ifr_name, it->ifr_name); + if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) { + if (!(ifr.ifr_flags & IFF_LOOPBACK)) { + if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) { + success = 1; + break; + } + } + } + } + + if (success) { + memcpy(ether_address.data(), ifr.ifr_hwaddr.sa_data, 6); + return true; + } +#endif + return false; +} +} // namespace NetUtil \ No newline at end of file diff --git a/src/core/libraries/network/net_util.h b/src/core/libraries/network/net_util.h new file mode 100644 index 000000000..be9dc15a1 --- /dev/null +++ b/src/core/libraries/network/net_util.h @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "common/types.h" + +namespace NetUtil { + +class NetUtilInternal { +public: + explicit NetUtilInternal() = default; + ~NetUtilInternal() = default; + +private: + std::array ether_address{}; + std::mutex m_mutex; + +public: + const std::array& GetEthernetAddr() const; + bool RetrieveEthernetAddr(); +}; +} // namespace NetUtil \ No newline at end of file diff --git a/src/core/libraries/network/netctl.cpp b/src/core/libraries/network/netctl.cpp index 00d980663..38225c48c 100644 --- a/src/core/libraries/network/netctl.cpp +++ b/src/core/libraries/network/netctl.cpp @@ -12,11 +12,13 @@ #include #endif +#include #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" #include "core/libraries/network/net_ctl_codes.h" #include "core/libraries/network/netctl.h" +#include "net_util.h" namespace Libraries::NetCtl { @@ -162,6 +164,14 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) { case ORBIS_NET_CTL_INFO_DEVICE: info->device = ORBIS_NET_CTL_DEVICE_WIRED; break; + case ORBIS_NET_CTL_INFO_ETHER_ADDR: { + auto* netinfo = Common::Singleton::Instance(); + netinfo->RetrieveEthernetAddr(); + memcpy(info->ether_addr.data, netinfo->GetEthernetAddr().data(), 6); + } break; + case ORBIS_NET_CTL_INFO_MTU: + info->mtu = 1500; // default value + break; case ORBIS_NET_CTL_INFO_LINK: info->link = ORBIS_NET_CTL_LINK_DISCONNECTED; break; @@ -183,6 +193,7 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) { } break; } + default: LOG_ERROR(Lib_NetCtl, "{} unsupported code", code); } diff --git a/src/core/libraries/network/netctl.h b/src/core/libraries/network/netctl.h index 4992fffa9..203c75822 100644 --- a/src/core/libraries/network/netctl.h +++ b/src/core/libraries/network/netctl.h @@ -49,8 +49,26 @@ union OrbisNetCtlInfo { // GetInfo codes constexpr int ORBIS_NET_CTL_INFO_DEVICE = 1; +constexpr int ORBIS_NET_CTL_INFO_ETHER_ADDR = 2; +constexpr int ORBIS_NET_CTL_INFO_MTU = 3; constexpr int ORBIS_NET_CTL_INFO_LINK = 4; +constexpr int ORBIS_NET_CTL_INFO_BSSID = 5; +constexpr int ORBIS_NET_CTL_INFO_SSID = 6; +constexpr int ORBIS_NET_CTL_INFO_WIFI_SECURITY = 7; +constexpr int ORBIS_NET_CTL_INFO_RSSI_DBM = 8; +constexpr int ORBIS_NET_CTL_INFO_RSSI_PERCENTAGE = 9; +constexpr int ORBIS_NET_CTL_INFO_CHANNEL = 10; +constexpr int ORBIS_NET_CTL_INFO_IP_CONFIG = 11; +constexpr int ORBIS_NET_CTL_INFO_DHCP_HOSTNAME = 12; +constexpr int ORBIS_NET_CTL_INFO_PPPOE_AUTH_NAME = 13; constexpr int ORBIS_NET_CTL_INFO_IP_ADDRESS = 14; +constexpr int ORBIS_NET_CTL_INFO_NETMASK = 15; +constexpr int ORBIS_NET_CTL_INFO_DEFAULT_ROUTE = 16; +constexpr int ORBIS_NET_CTL_INFO_PRIMARY_DNS = 17; +constexpr int ORBIS_NET_CTL_INFO_SECONDARY_DNS = 18; +constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_CONFIG = 19; +constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_SERVER = 20; +constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_PORT = 21; int PS4_SYSV_ABI sceNetBweCheckCallbackIpcInt(); int PS4_SYSV_ABI sceNetBweClearEventIpcInt(); diff --git a/src/core/libraries/network/p2p_sockets.cpp b/src/core/libraries/network/p2p_sockets.cpp new file mode 100644 index 000000000..e9b710bb3 --- /dev/null +++ b/src/core/libraries/network/p2p_sockets.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include "net.h" +#include "net_error.h" +#include "sockets.h" + +namespace Libraries::Net { + +int P2PSocket::Close() { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} +int P2PSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} +int P2PSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} + +int P2PSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} + +int P2PSocket::Listen(int backlog) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} + +int P2PSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, + u32 tolen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} + +int P2PSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} + +SocketPtr P2PSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return nullptr; +} + +int P2PSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} + +int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} + +} // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/network/posix_sockets.cpp b/src/core/libraries/network/posix_sockets.cpp new file mode 100644 index 000000000..140e4fd22 --- /dev/null +++ b/src/core/libraries/network/posix_sockets.cpp @@ -0,0 +1,359 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include "net.h" +#include "net_error.h" +#include "sockets.h" + +namespace Libraries::Net { + +#ifdef _WIN32 +#define ERROR_CASE(errname) \ + case (WSA##errname): \ + return ORBIS_NET_ERROR_##errname; +#else +#define ERROR_CASE(errname) \ + case (errname): \ + return ORBIS_NET_ERROR_##errname; +#endif + +static int ConvertReturnErrorCode(int retval) { + if (retval < 0) { +#ifdef _WIN32 + switch (WSAGetLastError()) { +#else + switch (errno) { +#endif +#ifndef _WIN32 // These errorcodes don't exist in WinSock + ERROR_CASE(EPERM) + ERROR_CASE(ENOENT) + // ERROR_CASE(ESRCH) + // ERROR_CASE(EIO) + // ERROR_CASE(ENXIO) + // ERROR_CASE(E2BIG) + // ERROR_CASE(ENOEXEC) + // ERROR_CASE(EDEADLK) + ERROR_CASE(ENOMEM) + // ERROR_CASE(ECHILD) + // ERROR_CASE(EBUSY) + ERROR_CASE(EEXIST) + // ERROR_CASE(EXDEV) + ERROR_CASE(ENODEV) + // ERROR_CASE(ENOTDIR) + // ERROR_CASE(EISDIR) + ERROR_CASE(ENFILE) + // ERROR_CASE(ENOTTY) + // ERROR_CASE(ETXTBSY) + // ERROR_CASE(EFBIG) + ERROR_CASE(ENOSPC) + // ERROR_CASE(ESPIPE) + // ERROR_CASE(EROFS) + // ERROR_CASE(EMLINK) + ERROR_CASE(EPIPE) + // ERROR_CASE(EDOM) + // ERROR_CASE(ERANGE) + // ERROR_CASE(ENOLCK) + // ERROR_CASE(ENOSYS) + // ERROR_CASE(EIDRM) + // ERROR_CASE(EOVERFLOW) + // ERROR_CASE(EILSEQ) + // ERROR_CASE(ENOTSUP) + ERROR_CASE(ECANCELED) + // ERROR_CASE(EBADMSG) + ERROR_CASE(ENODATA) + // ERROR_CASE(ENOSR) + // ERROR_CASE(ENOSTR) + // ERROR_CASE(ETIME) +#endif + ERROR_CASE(EINTR) + ERROR_CASE(EBADF) + ERROR_CASE(EACCES) + ERROR_CASE(EFAULT) + ERROR_CASE(EINVAL) + ERROR_CASE(EMFILE) + ERROR_CASE(EWOULDBLOCK) + ERROR_CASE(EINPROGRESS) + ERROR_CASE(EALREADY) + ERROR_CASE(ENOTSOCK) + ERROR_CASE(EDESTADDRREQ) + ERROR_CASE(EMSGSIZE) + ERROR_CASE(EPROTOTYPE) + ERROR_CASE(ENOPROTOOPT) + ERROR_CASE(EPROTONOSUPPORT) +#if defined(__APPLE__) || defined(_WIN32) + ERROR_CASE(EOPNOTSUPP) +#endif + ERROR_CASE(EAFNOSUPPORT) + ERROR_CASE(EADDRINUSE) + ERROR_CASE(EADDRNOTAVAIL) + ERROR_CASE(ENETDOWN) + ERROR_CASE(ENETUNREACH) + ERROR_CASE(ENETRESET) + ERROR_CASE(ECONNABORTED) + ERROR_CASE(ECONNRESET) + ERROR_CASE(ENOBUFS) + ERROR_CASE(EISCONN) + ERROR_CASE(ENOTCONN) + ERROR_CASE(ETIMEDOUT) + ERROR_CASE(ECONNREFUSED) + ERROR_CASE(ELOOP) + ERROR_CASE(ENAMETOOLONG) + ERROR_CASE(EHOSTUNREACH) + ERROR_CASE(ENOTEMPTY) + } + return ORBIS_NET_ERROR_EINTERNAL; + } + // if it is 0 or positive return it as it is + return retval; +} + +static int ConvertLevels(int level) { + switch (level) { + case ORBIS_NET_SOL_SOCKET: + return SOL_SOCKET; + case ORBIS_NET_IPPROTO_IP: + return IPPROTO_IP; + case ORBIS_NET_IPPROTO_TCP: + return IPPROTO_TCP; + } + return -1; +} + +static void convertOrbisNetSockaddrToPosix(const OrbisNetSockaddr* src, sockaddr* dst) { + if (src == nullptr || dst == nullptr) + return; + memset(dst, 0, sizeof(sockaddr)); + const OrbisNetSockaddrIn* src_in = (const OrbisNetSockaddrIn*)src; + sockaddr_in* dst_in = (sockaddr_in*)dst; + dst_in->sin_family = src_in->sin_family; + dst_in->sin_port = src_in->sin_port; + memcpy(&dst_in->sin_addr, &src_in->sin_addr, 4); +} + +static void convertPosixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) { + if (src == nullptr || dst == nullptr) + return; + memset(dst, 0, sizeof(OrbisNetSockaddr)); + OrbisNetSockaddrIn* dst_in = (OrbisNetSockaddrIn*)dst; + sockaddr_in* src_in = (sockaddr_in*)src; + dst_in->sin_family = static_cast(src_in->sin_family); + dst_in->sin_port = src_in->sin_port; + memcpy(&dst_in->sin_addr, &src_in->sin_addr, 4); +} + +int PosixSocket::Close() { +#ifdef _WIN32 + auto out = closesocket(sock); +#else + auto out = ::close(sock); +#endif + return ConvertReturnErrorCode(out); +} + +int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) { + sockaddr addr2; + convertOrbisNetSockaddrToPosix(addr, &addr2); + return ConvertReturnErrorCode(::bind(sock, &addr2, sizeof(sockaddr_in))); +} + +int PosixSocket::Listen(int backlog) { + return ConvertReturnErrorCode(::listen(sock, backlog)); +} + +int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, + u32 tolen) { + if (to != nullptr) { + sockaddr addr; + convertOrbisNetSockaddrToPosix(to, &addr); + return ConvertReturnErrorCode( + sendto(sock, (const char*)msg, len, flags, &addr, sizeof(sockaddr_in))); + } else { + return ConvertReturnErrorCode(send(sock, (const char*)msg, len, flags)); + } +} + +int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, + u32* fromlen) { + if (from != nullptr) { + sockaddr addr; + int res = recvfrom(sock, (char*)buf, len, flags, &addr, (socklen_t*)fromlen); + convertPosixSockaddrToOrbis(&addr, from); + *fromlen = sizeof(OrbisNetSockaddrIn); + return ConvertReturnErrorCode(res); + } else { + return ConvertReturnErrorCode(recv(sock, (char*)buf, len, flags)); + } +} + +SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) { + sockaddr addr2; + net_socket new_socket = ::accept(sock, &addr2, (socklen_t*)addrlen); +#ifdef _WIN32 + if (new_socket != INVALID_SOCKET) { +#else + if (new_socket >= 0) { +#endif + convertPosixSockaddrToOrbis(&addr2, addr); + *addrlen = sizeof(OrbisNetSockaddrIn); + return std::make_shared(new_socket); + } + return nullptr; +} + +int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) { + sockaddr addr2; + convertOrbisNetSockaddrToPosix(addr, &addr2); + return ::connect(sock, &addr2, sizeof(sockaddr_in)); +} + +int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { + sockaddr addr; + convertOrbisNetSockaddrToPosix(name, &addr); + if (name != nullptr) { + *namelen = sizeof(sockaddr_in); + } + int res = getsockname(sock, &addr, (socklen_t*)namelen); + if (res >= 0) { + convertPosixSockaddrToOrbis(&addr, name); + *namelen = sizeof(OrbisNetSockaddrIn); + } + return res; +} + +#define CASE_SETSOCKOPT(opt) \ + case ORBIS_NET_##opt: \ + return ConvertReturnErrorCode(setsockopt(sock, level, opt, (const char*)optval, optlen)) + +#define CASE_SETSOCKOPT_VALUE(opt, value) \ + case opt: \ + if (optlen != sizeof(*value)) { \ + return ORBIS_NET_ERROR_EFAULT; \ + } \ + memcpy(value, optval, optlen); \ + return 0 + +int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) { + level = ConvertLevels(level); + if (level == SOL_SOCKET) { + switch (optname) { + CASE_SETSOCKOPT(SO_REUSEADDR); + CASE_SETSOCKOPT(SO_KEEPALIVE); + CASE_SETSOCKOPT(SO_BROADCAST); + CASE_SETSOCKOPT(SO_LINGER); + CASE_SETSOCKOPT(SO_SNDBUF); + CASE_SETSOCKOPT(SO_RCVBUF); + CASE_SETSOCKOPT(SO_SNDTIMEO); + CASE_SETSOCKOPT(SO_RCVTIMEO); + CASE_SETSOCKOPT(SO_ERROR); + CASE_SETSOCKOPT(SO_TYPE); + CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_REUSEPORT, &sockopt_so_reuseport); + CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_ONESBCAST, &sockopt_so_onesbcast); + CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_USECRYPTO, &sockopt_so_usecrypto); + CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_USESIGNATURE, &sockopt_so_usesignature); + case ORBIS_NET_SO_NAME: + return ORBIS_NET_ERROR_EINVAL; // don't support set for name + case ORBIS_NET_SO_NBIO: { + if (optlen != sizeof(sockopt_so_nbio)) { + return ORBIS_NET_ERROR_EFAULT; + } + memcpy(&sockopt_so_nbio, optval, optlen); +#ifdef _WIN32 + static_assert(sizeof(u_long) == sizeof(sockopt_so_nbio), + "type used for ioctlsocket value does not have the expected size"); + return ConvertReturnErrorCode(ioctlsocket(sock, FIONBIO, (u_long*)&sockopt_so_nbio)); +#else + return ConvertReturnErrorCode(ioctl(sock, FIONBIO, &sockopt_so_nbio)); +#endif + } + } + } else if (level == IPPROTO_IP) { + switch (optname) { + CASE_SETSOCKOPT(IP_HDRINCL); + CASE_SETSOCKOPT(IP_TOS); + CASE_SETSOCKOPT(IP_TTL); + CASE_SETSOCKOPT(IP_MULTICAST_IF); + CASE_SETSOCKOPT(IP_MULTICAST_TTL); + CASE_SETSOCKOPT(IP_MULTICAST_LOOP); + CASE_SETSOCKOPT(IP_ADD_MEMBERSHIP); + CASE_SETSOCKOPT(IP_DROP_MEMBERSHIP); + CASE_SETSOCKOPT_VALUE(ORBIS_NET_IP_TTLCHK, &sockopt_ip_ttlchk); + CASE_SETSOCKOPT_VALUE(ORBIS_NET_IP_MAXTTL, &sockopt_ip_maxttl); + } + } else if (level == IPPROTO_TCP) { + switch (optname) { + CASE_SETSOCKOPT(TCP_NODELAY); + CASE_SETSOCKOPT(TCP_MAXSEG); + CASE_SETSOCKOPT_VALUE(ORBIS_NET_TCP_MSS_TO_ADVERTISE, &sockopt_tcp_mss_to_advertise); + } + } + + UNREACHABLE_MSG("Unknown level ={} optname ={}", level, optname); + return 0; +} + +#define CASE_GETSOCKOPT(opt) \ + case ORBIS_NET_##opt: { \ + socklen_t optlen_temp = *optlen; \ + auto retval = \ + ConvertReturnErrorCode(getsockopt(sock, level, opt, (char*)optval, &optlen_temp)); \ + *optlen = optlen_temp; \ + return retval; \ + } +#define CASE_GETSOCKOPT_VALUE(opt, value) \ + case opt: \ + if (*optlen < sizeof(value)) { \ + *optlen = sizeof(value); \ + return ORBIS_NET_ERROR_EFAULT; \ + } \ + *optlen = sizeof(value); \ + *(decltype(value)*)optval = value; \ + return 0; + +int PosixSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) { + level = ConvertLevels(level); + if (level == SOL_SOCKET) { + switch (optname) { + CASE_GETSOCKOPT(SO_REUSEADDR); + CASE_GETSOCKOPT(SO_KEEPALIVE); + CASE_GETSOCKOPT(SO_BROADCAST); + CASE_GETSOCKOPT(SO_LINGER); + CASE_GETSOCKOPT(SO_SNDBUF); + CASE_GETSOCKOPT(SO_RCVBUF); + CASE_GETSOCKOPT(SO_SNDTIMEO); + CASE_GETSOCKOPT(SO_RCVTIMEO); + CASE_GETSOCKOPT(SO_ERROR); + CASE_GETSOCKOPT(SO_TYPE); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_NBIO, sockopt_so_nbio); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_REUSEPORT, sockopt_so_reuseport); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_ONESBCAST, sockopt_so_onesbcast); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_USECRYPTO, sockopt_so_usecrypto); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_USESIGNATURE, sockopt_so_usesignature); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_NAME, + (char)0); // writes an empty string to the output buffer + } + } else if (level == IPPROTO_IP) { + switch (optname) { + CASE_GETSOCKOPT(IP_HDRINCL); + CASE_GETSOCKOPT(IP_TOS); + CASE_GETSOCKOPT(IP_TTL); + CASE_GETSOCKOPT(IP_MULTICAST_IF); + CASE_GETSOCKOPT(IP_MULTICAST_TTL); + CASE_GETSOCKOPT(IP_MULTICAST_LOOP); + CASE_GETSOCKOPT(IP_ADD_MEMBERSHIP); + CASE_GETSOCKOPT(IP_DROP_MEMBERSHIP); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_IP_TTLCHK, sockopt_ip_ttlchk); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_IP_MAXTTL, sockopt_ip_maxttl); + } + } else if (level == IPPROTO_TCP) { + switch (optname) { + CASE_GETSOCKOPT(TCP_NODELAY); + CASE_GETSOCKOPT(TCP_MAXSEG); + CASE_GETSOCKOPT_VALUE(ORBIS_NET_TCP_MSS_TO_ADVERTISE, sockopt_tcp_mss_to_advertise); + } + } + UNREACHABLE_MSG("Unknown level ={} optname ={}", level, optname); + return 0; +} + +} // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/network/sockets.h b/src/core/libraries/network/sockets.h new file mode 100644 index 000000000..e41671d88 --- /dev/null +++ b/src/core/libraries/network/sockets.h @@ -0,0 +1,112 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef _WIN32 +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#include +#include +#include +typedef SOCKET net_socket; +typedef int socklen_t; +#else +#include +#include +#include +#include +#include +#include +#include +#include +typedef int net_socket; +#endif +#include +#include +#include +#include "net.h" + +namespace Libraries::Net { + +struct Socket; + +typedef std::shared_ptr SocketPtr; + +struct Socket { + explicit Socket(int domain, int type, int protocol) {} + virtual ~Socket() = default; + virtual int Close() = 0; + virtual int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) = 0; + virtual int GetSocketOptions(int level, int optname, void* optval, u32* optlen) = 0; + virtual int Bind(const OrbisNetSockaddr* addr, u32 addrlen) = 0; + virtual int Listen(int backlog) = 0; + virtual int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, + u32 tolen) = 0; + virtual SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) = 0; + virtual int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, + u32* fromlen) = 0; + virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0; + virtual int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) = 0; +}; + +struct PosixSocket : public Socket { + net_socket sock; + int sockopt_so_reuseport = 0; + int sockopt_so_onesbcast = 0; + int sockopt_so_usecrypto = 0; + int sockopt_so_usesignature = 0; + int sockopt_so_nbio = 0; + int sockopt_ip_ttlchk = 0; + int sockopt_ip_maxttl = 0; + int sockopt_tcp_mss_to_advertise = 0; + explicit PosixSocket(int domain, int type, int protocol) + : Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {} + explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {} + int Close() override; + int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override; + int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override; + int Bind(const OrbisNetSockaddr* addr, u32 addrlen) override; + int Listen(int backlog) override; + int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, + u32 tolen) override; + int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) override; + SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override; + int Connect(const OrbisNetSockaddr* addr, u32 namelen) override; + int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override; +}; + +struct P2PSocket : public Socket { + explicit P2PSocket(int domain, int type, int protocol) : Socket(domain, type, protocol) {} + int Close() override; + int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override; + int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override; + int Bind(const OrbisNetSockaddr* addr, u32 addrlen) override; + int Listen(int backlog) override; + int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, + u32 tolen) override; + int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) override; + SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override; + int Connect(const OrbisNetSockaddr* addr, u32 namelen) override; + int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override; +}; + +class NetInternal { +public: + explicit NetInternal() = default; + ~NetInternal() = default; + SocketPtr FindSocket(int sockid) { + std::scoped_lock lock{m_mutex}; + const auto it = socks.find(sockid); + if (it != socks.end()) { + return it->second; + } + return 0; + } + +public: + std::mutex m_mutex; + typedef std::map NetSockets; + NetSockets socks; + int next_sock_id = 0; +}; +} // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/network/sys_net.cpp b/src/core/libraries/network/sys_net.cpp new file mode 100644 index 000000000..fbf2a2456 --- /dev/null +++ b/src/core/libraries/network/sys_net.cpp @@ -0,0 +1,229 @@ +#include "sys_net.h" +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include "common/singleton.h" +#include "net_error.h" +#include "sockets.h" +#include "sys_net.h" + +namespace Libraries::Net { + +int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->Connect(addr, addrlen); + 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_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->Bind(addr, addrlen); + 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_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + auto new_sock = sock->Accept(addr, paddrlen); + if (!new_sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_EBADF; + LOG_ERROR(Lib_Net, "error creating new socket for accepting"); + return -1; + } + auto id = ++netcall->next_sock_id; + netcall->socks.emplace(id, new_sock); + return id; +} +int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} +int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->GetSocketAddress(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_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->GetSocketOptions(level, optname, optval, optlen); + 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_listen(OrbisNetId s, int backlog) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->Listen(backlog); + 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_setsockopt(OrbisNetId s, int level, int optname, const void* optval, + u32 optlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->SetSocketOptions(level, optname, optval, optlen); + 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_shutdown(OrbisNetId s, int how) { + return -1; +} +int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protocol) { + if (name == nullptr) { + LOG_INFO(Lib_Net, "name = no-named family = {} type = {} protocol = {}", family, type, + protocol); + } else { + LOG_INFO(Lib_Net, "name = {} family = {} type = {} protocol = {}", std::string(name), + family, type, protocol); + } + SocketPtr sock; + switch (type) { + case ORBIS_NET_SOCK_STREAM: + case ORBIS_NET_SOCK_DGRAM: + case ORBIS_NET_SOCK_RAW: + sock = std::make_shared(family, type, protocol); + break; + case ORBIS_NET_SOCK_DGRAM_P2P: + case ORBIS_NET_SOCK_STREAM_P2P: + sock = std::make_shared(family, type, protocol); + break; + default: + UNREACHABLE_MSG("Unknown type {}", type); + } + auto* netcall = Common::Singleton::Instance(); + auto id = ++netcall->next_sock_id; + netcall->socks.emplace(id, sock); + return id; +} +int PS4_SYSV_ABI sys_socket(int family, int type, int protocol) { + return sys_socketex(nullptr, family, type, protocol); +} +int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} +int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->Close(); + 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_sendto(OrbisNetId s, const void* buf, u64 len, int flags, + const OrbisNetSockaddr* addr, u32 addrlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->SendPacket(buf, len, flags, addr, addrlen); + 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_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} +int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr, + u32* paddrlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->ReceivePacket(buf, len, flags, addr, paddrlen); + if (returncode >= 0) { + return returncode; + } + *Libraries::Kernel::__Error() = returncode; + LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); + return -1; +} +int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) { + LOG_ERROR(Lib_Net, "(STUBBED) called"); + return -1; +} +} // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/network/sys_net.h b/src/core/libraries/network/sys_net.h new file mode 100644 index 000000000..4366ea0f8 --- /dev/null +++ b/src/core/libraries/network/sys_net.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" +#include "net.h" + +namespace Libraries::Net { + +int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen); +int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen); +int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen); +int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen); +int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen); +int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen); +int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog); +int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval, + u32 optlen); +int PS4_SYSV_ABI sys_shutdown(OrbisNetId s, int how); +int PS4_SYSV_ABI sys_socketex(const char* name, 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_socketclose(OrbisNetId s); +int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags, + const OrbisNetSockaddr* addr, u32 addrlen); +int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags); +int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr, + u32* paddrlen); +int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags); +} // namespace Libraries::Net \ No newline at end of file diff --git a/src/emulator.cpp b/src/emulator.cpp index 1a71b99cb..5c20353df 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -16,6 +16,9 @@ #ifdef ENABLE_DISCORD_RPC #include "common/discord_rpc_handler.h" #endif +#ifdef _WIN32 +#include +#endif #include "common/elf_info.h" #include "common/ntapi.h" #include "common/path_util.h" @@ -46,6 +49,10 @@ Emulator::Emulator() { #ifdef _WIN32 Common::NtApi::Initialize(); SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); + // need to init this in order for winsock2 to work + WORD versionWanted = MAKEWORD(2, 2); + WSADATA wsaData; + WSAStartup(versionWanted, &wsaData); #endif // Create stdin/stdout/stderr