From ee0b0fce6cf67b74e193ae65823a323e261f0deb Mon Sep 17 00:00:00 2001 From: White Blood Cell Date: Sat, 16 Dec 2023 17:22:40 -0800 Subject: [PATCH 1/9] sceNetInet and sceNetResolver support. Co-authored-by: AdamN --- CMakeLists.txt | 20 + Core/Config.cpp | 11 + Core/Config.h | 2 + Core/Core.vcxproj | 12 + Core/Core.vcxproj.filters | 39 ++ Core/HLE/FunctionWrappers.h | 20 + Core/HLE/HLETables.cpp | 4 + Core/HLE/proAdhoc.h | 1 + Core/HLE/sceNet.cpp | 249 ++------- Core/HLE/sceNet.h | 49 +- Core/HLE/sceNetApctl.cpp | 3 + Core/HLE/sceNetApctl.h | 3 + Core/HLE/sceNetInet.cpp | 1026 +++++++++++++++++++++++++++++++++++ Core/HLE/sceNetInet.h | 61 +++ Core/HLE/sceNetResolver.cpp | 312 +++++++++++ Core/HLE/sceNetResolver.h | 74 +++ Core/MemMap.h | 9 + Core/Net/InetCommon.cpp | 54 ++ Core/Net/InetCommon.h | 12 + Core/Net/NetResolver.cpp | 3 + Core/Net/NetResolver.h | 32 ++ Core/Net/SceSocket.cpp | 3 + Core/Net/SceSocket.h | 195 +++++++ ext/rcheevos | 2 +- 24 files changed, 1954 insertions(+), 242 deletions(-) create mode 100644 Core/HLE/sceNetApctl.cpp create mode 100644 Core/HLE/sceNetApctl.h create mode 100644 Core/HLE/sceNetInet.cpp create mode 100644 Core/HLE/sceNetInet.h create mode 100644 Core/HLE/sceNetResolver.cpp create mode 100644 Core/HLE/sceNetResolver.h create mode 100644 Core/Net/InetCommon.cpp create mode 100644 Core/Net/InetCommon.h create mode 100644 Core/Net/NetResolver.cpp create mode 100644 Core/Net/NetResolver.h create mode 100644 Core/Net/SceSocket.cpp create mode 100644 Core/Net/SceSocket.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fd67639ecd..ba41313c14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,6 +192,9 @@ if(USE_CCACHE) include(ccache) endif() +# TODO: stop hardcoding this before PR +# set(USING_QT_UI ON) + if(UNIX AND NOT (APPLE OR ANDROID) AND VULKAN) if(USING_X11_VULKAN) message("Using X11 for Vulkan") @@ -2251,6 +2254,12 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/sceNetAdhoc.h Core/HLE/sceNetAdhocMatching.cpp Core/HLE/sceNetAdhocMatching.h + Core/HLE/sceNetInet.cpp + Core/HLE/sceNetInet.h + Core/HLE/sceNetApctl.cpp + Core/HLE/sceNetApctl.h + Core/HLE/sceNetResolver.cpp + Core/HLE/sceNetResolver.h Core/HLE/proAdhoc.h Core/HLE/proAdhoc.cpp Core/HLE/proAdhocServer.h @@ -2378,6 +2387,12 @@ add_library(${CoreLibName} ${CoreLinkType} Core/MIPS/MIPSAsm.h Core/MIPS/MIPSTracer.cpp Core/MIPS/MIPSTracer.h + Core/Net/InetCommon.cpp + Core/Net/InetCommon.h + Core/Net/NetResolver.cpp + Core/Net/NetResolver.h + Core/Net/SceSocket.cpp + Core/Net/SceSocket.h Core/MemFault.cpp Core/MemFault.h Core/MemMap.cpp @@ -2467,6 +2482,11 @@ include_directories(ext/libchdr/include) target_link_libraries(${CoreLibName} Common native chdr kirk cityhash sfmt19937 xbrz xxhash rcheevos minimp3 at3_standalone lua ${GlslangLibs} ${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS}) +# Winsock +if(WIN32) + target_link_libraries(${CoreLibName} ws2_32 winhttp) +endif() + if(NOT HTTPS_NOT_AVAILABLE) target_link_libraries(${CoreLibName} naett) if(WIN32) diff --git a/Core/Config.cpp b/Core/Config.cpp index 66f9ab7419..3fdc4c2169 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1244,6 +1244,10 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { mPostShaderSetting[key] = std::stof(value); } + const Section *hostOverrideSetting = iniFile.GetOrCreateSection("HostAliases"); + // TODO: relocate me before PR + mHostToAlias = hostOverrideSetting->ToMap(); + // Load post process shader names vPostShaderNames.clear(); for (const auto& it : postShaderChain->ToMap()) { @@ -1376,6 +1380,13 @@ bool Config::Save(const char *saveReason) { } } + // TODO: relocate me before PR + Section *hostOverrideSetting = iniFile.GetOrCreateSection("HostAliases"); + hostOverrideSetting->Clear(); + for (auto& it : mHostToAlias) { + hostOverrideSetting->Set(it.first.c_str(), it.second.c_str()); + } + Section *control = iniFile.GetOrCreateSection("Control"); control->Delete("DPadRadius"); diff --git a/Core/Config.h b/Core/Config.h index 6fa7fd23b6..a54a24665f 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -458,6 +458,7 @@ public: // Networking std::string proAdhocServer; bool bEnableWlan; + std::map mHostToAlias; // TODO: mPostShaderSetting bool bEnableAdhocServer; bool bEnableUPnP; bool bUPnPUseOriginalPort; @@ -482,6 +483,7 @@ public: int iFirmwareVersion; bool bBypassOSKWithKeyboard; + // Virtual reality bool bEnableVR; bool bEnable6DoF; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 8f0a6a16fd..a3db7b3d1e 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -572,6 +572,9 @@ + + + @@ -625,6 +628,9 @@ + + + @@ -1185,6 +1191,9 @@ + + + @@ -1211,6 +1220,9 @@ + + + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 6e5e2f17a0..9923894b3e 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -94,6 +94,9 @@ {067e3128-3aaf-4ed1-b19e-bab11606abe7} + + {f1b3f688-26eb-4121-9914-e9e19ab04bcd} + @@ -1321,6 +1324,24 @@ Dialog + + HLE\Libraries + + + HLE\Libraries + + + HLE\Libraries + + + Net + + + Net + + + Net + @@ -2121,6 +2142,24 @@ Dialog + + HLE\Libraries + + + HLE\Libraries + + + HLE\Libraries + + + Net + + + Net + + + Net + diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index d745818338..a8ab014f9f 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -438,11 +438,21 @@ template void WrapI_IIIUI() { RETURN(retval); } +template void WrapI_IIIUU() { + int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); + RETURN(retval); +} + template void WrapI_IUUII() { int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)); RETURN(retval); } +template void WrapI_IUUIII() { + int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); + RETURN(retval); +} + template void WrapI_ICIUU() { int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); RETURN(retval); @@ -699,6 +709,11 @@ template void WrapI_IUUUUU() { RETURN(retval); } +template void WrapI_IUUIUU() { + int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); + RETURN(retval); +} + template void WrapI_IUII() { int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); RETURN(retval); @@ -755,6 +770,11 @@ template void WrapI_IUUU() { RETURN(retval); } +template void WrapI_IUUI() { + int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); + RETURN(retval); +} + template void WrapI_IUU() { int retval = func(PARAM(0), PARAM(1), PARAM(2)); RETURN(retval); diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 4735322c40..b91c1e60fe 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -81,6 +81,8 @@ #include "sceSfmt19937.h" #include "sceG729.h" #include "KUBridge.h" +#include "sceNetInet.h" +#include "sceNetResolver.h" #define N(s) s @@ -313,6 +315,8 @@ void RegisterAllModules() { Register_mp4msv(); Register_InterruptManagerForKernel(); Register_sceSircs(); + Register_sceNetInet(); + Register_sceNetResolver(); // add new modules here. } diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 245418af66..fc353ec341 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -53,6 +53,7 @@ #include "Core/HLE/sceKernelMutex.h" #include "Core/HLE/sceUtility.h" +// TODO: move this to some common set #ifdef _WIN32 #undef errno #undef ESHUTDOWN diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 9423b02030..65b6527106 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -20,13 +20,20 @@ #include #include #include +#elif _WIN32 +#include +#pragma comment(lib, "ws2_32.lib") #endif +// TODO: fixme move Core/Net to Common/Net +#include "Common/Net/Resolve.h" +#include "Core/Net/InetCommon.h" #include "Common/Data/Text/Parsers.h" #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" #include "Common/Serialize/SerializeMap.h" +#include "Core/Config.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceKernelMemory.h" @@ -44,6 +51,12 @@ #include "Core/HLE/sceNetAdhoc.h" #include "Core/HLE/sceNetAdhocMatching.h" #include "Core/HLE/sceNet.h" + +#include +#include + +#include "sceNetInet.h" +#include "sceNetResolver.h" #include "Core/HLE/sceNp.h" #include "Core/CoreTiming.h" #include "Core/Instance.h" @@ -54,7 +67,6 @@ #endif bool netInited; -bool netInetInited; u32 netDropRate = 0; u32 netDropDuration = 0; @@ -131,6 +143,26 @@ void InitLocalhostIP() { isLocalServer = (!strcasecmp(serverStr.c_str(), "localhost") || serverStr.find("127.") == 0); } +static bool __PlatformNetInit() { +#ifdef _WIN32 + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + // TODO: log + return false; + } +#else + return true; +#endif +} + +static bool __PlatformNetShutdown() { +#ifdef _WIN32 + return WSACleanup() == 0; +#else + return true; +#endif +} + static void __ApctlState(u64 userdata, int cyclesLate) { SceUID threadID = userdata >> 32; int uid = (int)(userdata & 0xFFFFFFFF); @@ -176,7 +208,7 @@ void __NetApctlInit() { static void __ResetInitNetLib() { netInited = false; - netInetInited = false; + // netInetInited = false; memset(&netMallocStat, 0, sizeof(netMallocStat)); memset(¶meter, 0, sizeof(parameter)); @@ -211,7 +243,8 @@ void __NetInit() { SceNetEtherAddr mac; getLocalMac(&mac); INFO_LOG(Log::sceNet, "LocalHost IP will be %s [%s]", ip2str(g_localhostIP.in.sin_addr).c_str(), mac2str(&mac).c_str()); - + + __PlatformNetInit(); // TODO: May be we should initialize & cleanup somewhere else than here for PortManager to be used as general purpose for whatever port forwarding PPSSPP needed __UPnPInit(); @@ -233,12 +266,16 @@ void __NetShutdown() { // Network Cleanup Net_Term(); + SceNetResolver::Shutdown(); + SceNetInet::Shutdown(); __NetApctlShutdown(); __ResetInitNetLib(); // Since PortManager supposed to be general purpose for whatever port forwarding PPSSPP needed, may be we shouldn't clear & restore ports in here? it will be cleared and restored by PortManager's destructor when exiting PPSSPP anyway __UPnPShutdown(); + __PlatformNetShutdown(); + free(dummyPeekBuf64k); } @@ -268,11 +305,11 @@ void __NetDoState(PointerWrap &p) { return; auto cur_netInited = netInited; - auto cur_netInetInited = netInetInited; + // auto cur_netInetInited = netInetInited; auto cur_netApctlInited = netApctlInited; Do(p, netInited); - Do(p, netInetInited); + // Do(p, netInetInited); Do(p, netApctlInited); Do(p, apctlHandlers); Do(p, netMallocStat); @@ -317,11 +354,13 @@ void __NetDoState(PointerWrap &p) { if (p.mode == p.MODE_READ) { // Let's not change "Inited" value when Loading SaveState in the middle of multiplayer to prevent memory & port leaks netApctlInited = cur_netApctlInited; - netInetInited = cur_netInetInited; + // netInetInited = cur_netInetInited; netInited = cur_netInited; // Discard leftover events apctlEvents.clear(); + // Discard created resolvers + SceNetResolver::Shutdown(); } } @@ -795,21 +834,6 @@ static int sceNetGetMallocStat(u32 statPtr) { return 0; } -static int sceNetInetInit() { - ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetInit()"); - if (netInetInited) return ERROR_NET_INET_ALREADY_INITIALIZED; - netInetInited = true; - - return 0; -} - -int sceNetInetTerm() { - ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetTerm()"); - netInetInited = false; - - return 0; -} - void NetApctl_InitInfo() { memset(&netApctlInfo, 0, sizeof(netApctlInfo)); // Set dummy/fake values, these probably not suppose to have valid info before connected to an AP, right? @@ -823,7 +847,8 @@ void NetApctl_InitInfo() { if (netApctlInfo.channel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) netApctlInfo.channel = defaultWlanChannel; // Get Local IP Address sockaddr_in sockAddr; - getLocalIp(&sockAddr); // This will be valid IP, we probably not suppose to have a valid IP before connected to any AP, right? + socklen_t socklen = sizeof(sockaddr_in); + getDefaultOutboundSockaddr(sockAddr, socklen); // This will be valid IP, we probably not suppose to have a valid IP before connected to any AP, right? char ipstr[INET_ADDRSTRLEN] = "127.0.0.1"; // Patapon 3 seems to try to get current IP using ApctlGetInfo() right after ApctlInit(), what kind of IP should we use as default before ApctlConnect()? it shouldn't be a valid IP, right? inet_ntop(AF_INET, &sockAddr.sin_addr, ipstr, sizeof(ipstr)); truncate_cpy(netApctlInfo.ip, sizeof(netApctlInfo.ip), ipstr); @@ -985,6 +1010,7 @@ static int sceNetApctlGetInfo(int code, u32 pInfoAddr) { if (!Memory::IsValidRange(pInfoAddr, 4)) return hleLogError(Log::sceNet, -1, "apctl invalid arg"); Memory::WriteUnchecked_U32(netApctlInfo.useProxy, pInfoAddr); + // Memory::WriteUnchecked_U32(1, pInfoAddr); NotifyMemInfo(MemBlockFlags::WRITE, pInfoAddr, 4, "NetApctlGetInfo"); break; case PSP_NET_APCTL_INFO_PROXY_URL: @@ -1084,107 +1110,6 @@ static int sceNetApctlDelHandler(u32 handlerID) { return NetApctl_DelHandler(handlerID); } -static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { - ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetInetAton(%s, %08x)", hostname, addrPtr); - return -1; -} - -int sceNetInetPoll(void *fds, u32 nfds, int timeout) { // timeout in miliseconds - DEBUG_LOG(Log::sceNet, "UNTESTED sceNetInetPoll(%p, %d, %i) at %08x", fds, nfds, timeout, currentMIPS->pc); - int retval = -1; - SceNetInetPollfd *fdarray = (SceNetInetPollfd *)fds; // SceNetInetPollfd/pollfd, sceNetInetPoll() have similarity to BSD poll() but pollfd have different size on 64bit -//#ifdef _WIN32 - //WSAPoll only available for Vista or newer, so we'll use an alternative way for XP since Windows doesn't have poll function like *NIX - if (nfds > FD_SETSIZE) return -1; - fd_set readfds, writefds, exceptfds; - FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); - for (int i = 0; i < (s32)nfds; i++) { - if (fdarray[i].events & (INET_POLLRDNORM)) FD_SET(fdarray[i].fd, &readfds); // (POLLRDNORM | POLLIN) - if (fdarray[i].events & (INET_POLLWRNORM)) FD_SET(fdarray[i].fd, &writefds); // (POLLWRNORM | POLLOUT) - //if (fdarray[i].events & (ADHOC_EV_ALERT)) // (POLLRDBAND | POLLPRI) // POLLERR - FD_SET(fdarray[i].fd, &exceptfds); - fdarray[i].revents = 0; - } - timeval tmout; - tmout.tv_sec = timeout / 1000; // seconds - tmout.tv_usec = (timeout % 1000) * 1000; // microseconds - retval = select(nfds, &readfds, &writefds, &exceptfds, &tmout); - if (retval < 0) return -1; - retval = 0; - for (int i = 0; i < (s32)nfds; i++) { - if (FD_ISSET(fdarray[i].fd, &readfds)) fdarray[i].revents |= INET_POLLRDNORM; //POLLIN - if (FD_ISSET(fdarray[i].fd, &writefds)) fdarray[i].revents |= INET_POLLWRNORM; //POLLOUT - fdarray[i].revents &= fdarray[i].events; - if (FD_ISSET(fdarray[i].fd, &exceptfds)) fdarray[i].revents |= ADHOC_EV_ALERT; // POLLPRI; // POLLERR; // can be raised on revents regardless of events bitmask? - if (fdarray[i].revents) retval++; - } -//#else - /* - // Doesn't work properly yet - pollfd *fdtmp = (pollfd *)malloc(sizeof(pollfd) * nfds); - // Note: sizeof(pollfd) = 16bytes in 64bit and 8bytes in 32bit, while sizeof(SceNetInetPollfd) is always 8bytes - for (int i = 0; i < (s32)nfds; i++) { - fdtmp[i].fd = fdarray[i].fd; - fdtmp[i].events = 0; - if (fdarray[i].events & INET_POLLRDNORM) fdtmp[i].events |= (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI); - if (fdarray[i].events & INET_POLLWRNORM) fdtmp[i].events |= (POLLOUT | POLLWRNORM | POLLWRBAND); - fdtmp[i].revents = 0; - fdarray[i].revents = 0; - } - retval = poll(fdtmp, (nfds_t)nfds, timeout); //retval = WSAPoll(fdarray, nfds, timeout); - for (int i = 0; i < (s32)nfds; i++) { - if (fdtmp[i].revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) fdarray[i].revents |= INET_POLLRDNORM; - if (fdtmp[i].revents & (POLLOUT | POLLWRNORM | POLLWRBAND)) fdarray[i].revents |= INET_POLLWRNORM; - fdarray[i].revents &= fdarray[i].events; - if (fdtmp[i].revents & POLLERR) fdarray[i].revents |= POLLERR; //INET_POLLERR // can be raised on revents regardless of events bitmask? - } - free(fdtmp); - */ -//#endif - return retval; -} - -static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, u32 flags) { - ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetRecv(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); - return -1; -} - -static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, u32 flags) { - ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetSend(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); - return -1; -} - -static int sceNetInetGetErrno() { - ERROR_LOG(Log::sceNet, "UNTESTED sceNetInetGetErrno()"); - int error = errno; - switch (error) { - case ETIMEDOUT: - return INET_ETIMEDOUT; - case EISCONN: - return INET_EISCONN; - case EINPROGRESS: - return INET_EINPROGRESS; - //case EAGAIN: - // return INET_EAGAIN; - } - return error; //-1; -} - -static int sceNetInetSocket(int domain, int type, int protocol) { - ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetSocket(%i, %i, %i)", domain, type, protocol); - return -1; -} - -static int sceNetInetSetsockopt(int socket, int level, int optname, u32 optvalPtr, int optlen) { - ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, level, optname, optvalPtr, optlen); - return -1; -} - -static int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLength) { - ERROR_LOG(Log::sceNet, "UNIMPL sceNetInetConnect(%i, %08x, %i)", socket, sockAddrInternetPtr, addressLength); - return -1; -} - int sceNetApctlConnect(int connIndex) { WARN_LOG(Log::sceNet, "UNTESTED %s(%i)", __FUNCTION__, connIndex); // Is this connIndex is the index to the scanning's result data or sceNetApctlGetBSSDescIDListUser result? @@ -1374,12 +1299,6 @@ static int sceNetApctlGetBSSDescEntry2(int entryId, int infoId, u32 resultAddr) return NetApctl_GetBSSDescEntryUser(entryId, infoId, resultAddr); } -static int sceNetResolverInit() -{ - ERROR_LOG(Log::sceNet, "UNIMPL %s()", __FUNCTION__); - return 0; -} - static int sceNetApctlAddInternalHandler(u32 handlerPtr, u32 handlerArg) { ERROR_LOG(Log::sceNet, "UNIMPL %s(%08x, %08x)", __FUNCTION__, handlerPtr, handlerArg); // This seems to be a 2nd kind of handler @@ -1433,46 +1352,38 @@ static int sceNetApctl_lib2_C20A144C(int connIndex, u32 ps3MacAddressPtr) { return sceNetApctlConnect(connIndex); } - -static int sceNetUpnpInit(int unknown1,int unknown2) -{ +static int sceNetUpnpInit(int unknown1,int unknown2) { ERROR_LOG_REPORT_ONCE(sceNetUpnpInit, Log::sceNet, "UNIMPLsceNetUpnpInit %d,%d",unknown1,unknown2); return 0; } -static int sceNetUpnpStart() -{ +static int sceNetUpnpStart() { ERROR_LOG(Log::sceNet, "UNIMPLsceNetUpnpStart"); return 0; } -static int sceNetUpnpStop() -{ +static int sceNetUpnpStop() { ERROR_LOG(Log::sceNet, "UNIMPLsceNetUpnpStop"); return 0; } -static int sceNetUpnpTerm() -{ +static int sceNetUpnpTerm() { ERROR_LOG(Log::sceNet, "UNIMPLsceNetUpnpTerm"); return 0; } -static int sceNetUpnpGetNatInfo() -{ +static int sceNetUpnpGetNatInfo() { ERROR_LOG(Log::sceNet, "UNIMPLsceNetUpnpGetNatInfo"); return 0; } -static int sceNetGetDropRate(u32 dropRateAddr, u32 dropDurationAddr) -{ +static int sceNetGetDropRate(u32 dropRateAddr, u32 dropDurationAddr) { Memory::Write_U32(netDropRate, dropRateAddr); Memory::Write_U32(netDropDuration, dropDurationAddr); return hleLogSuccessInfoI(Log::sceNet, 0); } -static int sceNetSetDropRate(u32 dropRate, u32 dropDuration) -{ +static int sceNetSetDropRate(u32 dropRate, u32 dropDuration) { netDropRate = dropRate; netDropDuration = dropDuration; return hleLogSuccessInfoI(Log::sceNet, 0); @@ -1489,54 +1400,6 @@ const HLEFunction sceNet[] = { {0XAD6844C6, &WrapI_I, "sceNetThreadAbort", 'i', "i" }, }; -const HLEFunction sceNetResolver[] = { - {0X224C5F44, nullptr, "sceNetResolverStartNtoA", '?', "" }, - {0X244172AF, nullptr, "sceNetResolverCreate", '?', "" }, - {0X94523E09, nullptr, "sceNetResolverDelete", '?', "" }, - {0XF3370E61, &WrapI_V, "sceNetResolverInit", 'i', "" }, - {0X808F6063, nullptr, "sceNetResolverStop", '?', "" }, - {0X6138194A, nullptr, "sceNetResolverTerm", '?', "" }, - {0X629E2FB7, nullptr, "sceNetResolverStartAtoN", '?', "" }, - {0X14C17EF9, nullptr, "sceNetResolverStartNtoAAsync", '?', "" }, - {0XAAC09184, nullptr, "sceNetResolverStartAtoNAsync", '?', "" }, - {0X12748EB9, nullptr, "sceNetResolverWaitAsync", '?', "" }, - {0X4EE99358, nullptr, "sceNetResolverPollAsync", '?', "" }, -}; - -const HLEFunction sceNetInet[] = { - {0X17943399, &WrapI_V, "sceNetInetInit", 'i', "" }, - {0X4CFE4E56, nullptr, "sceNetInetShutdown", '?', "" }, - {0XA9ED66B9, &WrapI_V, "sceNetInetTerm", 'i', "" }, - {0X8B7B220F, &WrapI_III, "sceNetInetSocket", 'i', "iii" }, - {0X2FE71FE7, &WrapI_IIIUI, "sceNetInetSetsockopt", 'i', "iiixi"}, - {0X4A114C7C, nullptr, "sceNetInetGetsockopt", '?', "" }, - {0X410B34AA, &WrapI_IUI, "sceNetInetConnect", 'i', "ixi" }, - {0X805502DD, nullptr, "sceNetInetCloseWithRST", '?', "" }, - {0XD10A1A7A, nullptr, "sceNetInetListen", '?', "" }, - {0XDB094E1B, nullptr, "sceNetInetAccept", '?', "" }, - {0XFAABB1DD, &WrapI_VUI, "sceNetInetPoll", 'i', "pxi" }, - {0X5BE8D595, nullptr, "sceNetInetSelect", '?', "" }, - {0X8D7284EA, nullptr, "sceNetInetClose", '?', "" }, - {0XCDA85C99, &WrapI_IUUU, "sceNetInetRecv", 'i', "ixxx" }, - {0XC91142E4, nullptr, "sceNetInetRecvfrom", '?', "" }, - {0XEECE61D2, nullptr, "sceNetInetRecvmsg", '?', "" }, - {0X7AA671BC, &WrapI_IUUU, "sceNetInetSend", 'i', "ixxx" }, - {0X05038FC7, nullptr, "sceNetInetSendto", '?', "" }, - {0X774E36F4, nullptr, "sceNetInetSendmsg", '?', "" }, - {0XFBABE411, &WrapI_V, "sceNetInetGetErrno", 'i', "" }, - {0X1A33F9AE, nullptr, "sceNetInetBind", '?', "" }, - {0XB75D5B0A, nullptr, "sceNetInetInetAddr", '?', "" }, - {0X1BDF5D13, &WrapI_CU, "sceNetInetInetAton", 'i', "sx" }, - {0XD0792666, nullptr, "sceNetInetInetNtop", '?', "" }, - {0XE30B8C19, nullptr, "sceNetInetInetPton", '?', "" }, - {0X8CA3A97E, nullptr, "sceNetInetGetPspError", '?', "" }, - {0XE247B6D6, nullptr, "sceNetInetGetpeername", '?', "" }, - {0X162E6FD5, nullptr, "sceNetInetGetsockname", '?', "" }, - {0X80A21ABD, nullptr, "sceNetInetSocketAbort", '?', "" }, - {0X39B0C7D3, nullptr, "sceNetInetGetUdpcbstat", '?', "" }, - {0XB3888AD4, nullptr, "sceNetInetGetTcpcbstat", '?', "" }, -}; - const HLEFunction sceNetApctl[] = { {0XCFB957C6, &WrapI_I, "sceNetApctlConnect", 'i', "i" }, {0X24FE91A1, &WrapI_V, "sceNetApctlDisconnect", 'i', "" }, @@ -1588,8 +1451,6 @@ const HLEFunction sceNetIfhandle[] = { void Register_sceNet() { RegisterModule("sceNet", ARRAY_SIZE(sceNet), sceNet); - RegisterModule("sceNetResolver", ARRAY_SIZE(sceNetResolver), sceNetResolver); - RegisterModule("sceNetInet", ARRAY_SIZE(sceNetInet), sceNetInet); RegisterModule("sceNetApctl", ARRAY_SIZE(sceNetApctl), sceNetApctl); } diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index d34ab560dd..cbc2cd17f5 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -17,7 +17,6 @@ #pragma once -#include #include "Core/HLE/proAdhoc.h" // Using constants instead of numbers for readability reason, since PSP_THREAD_ATTR_KERNEL/USER is located in sceKernelThread.cpp instead of sceKernelThread.h @@ -32,14 +31,8 @@ #define PSP_SO_REUSEPORT 0x0200 #define PSP_SO_NBIO 0x1009 -// Infrastructure Errno Numbers -#define INET_EAGAIN 0x0B -#define INET_ETIMEDOUT 0x74 -#define INET_EINPROGRESS 0x77 -#define INET_EISCONN 0x7F - // On-Demand Nonblocking Flag -#define INET_MSG_DONTWAIT 0x80 +// #define INET_MSG_DONTWAIT 0x80 // Event Flags #define INET_POLLRDNORM 0x0040 @@ -64,19 +57,6 @@ enum { ERROR_NET_CORE_80211_NO_BSS = 0x80410106, ERROR_NET_CORE_80211_NO_AVAIL_BSS = 0x80410107, - // pspnet_inet - ERROR_NET_INET_ALREADY_INITIALIZED = 0x80410201, - ERROR_NET_INET_SOCKET_BUSY = 0x80410202, - ERROR_NET_INET_CONFIG_INVALID_ARG = 0x80410203, - ERROR_NET_INET_GET_IFADDR = 0x80410204, - ERROR_NET_INET_SET_IFADDR = 0x80410205, - ERROR_NET_INET_DEL_IFADDR = 0x80410206, - ERROR_NET_INET_NO_DEFAULT_ROUTE = 0x80410207, - ERROR_NET_INET_GET_ROUTE = 0x80410208, - ERROR_NET_INET_SET_ROUTE = 0x80410209, - ERROR_NET_INET_FLUSH_ROUTE = 0x8041020a, - ERROR_NET_INET_INVALID_ARG = 0x8041020b, - // pspnet_poeclient ERROR_NET_POECLIENT_INIT = 0x80410301, ERROR_NET_POECLIENT_NO_PADO = 0x80410302, @@ -90,31 +70,6 @@ enum { ERROR_NET_POECLIENT_TERMINATE = 0x8041030a, ERROR_NET_POECLIENT_NOT_STARTED = 0x8041030b, - // pspnet_resolver - ERROR_NET_RESOLVER_NOT_TERMINATED = 0x80410401, - ERROR_NET_RESOLVER_NO_DNS_SERVER = 0x80410402, - ERROR_NET_RESOLVER_INVALID_PTR = 0x80410403, - ERROR_NET_RESOLVER_INVALID_BUFLEN = 0x80410404, - ERROR_NET_RESOLVER_INVALID_ID = 0x80410405, - ERROR_NET_RESOLVER_ID_MAX = 0x80410406, - ERROR_NET_RESOLVER_NO_MEM = 0x80410407, - ERROR_NET_RESOLVER_BAD_ID = 0x80410408, // ERROR_NET_RESOLVER_ID_NOT_FOUND - ERROR_NET_RESOLVER_CTX_BUSY = 0x80410409, - ERROR_NET_RESOLVER_ALREADY_STOPPED = 0x8041040a, - ERROR_NET_RESOLVER_NOT_SUPPORTED = 0x8041040b, - ERROR_NET_RESOLVER_BUF_NO_SPACE = 0x8041040c, - ERROR_NET_RESOLVER_INVALID_PACKET = 0x8041040d, - ERROR_NET_RESOLVER_STOPPED = 0x8041040e, - ERROR_NET_RESOLVER_SOCKET = 0x8041040f, - ERROR_NET_RESOLVER_TIMEOUT = 0x80410410, - ERROR_NET_RESOLVER_NO_RECORD = 0x80410411, - ERROR_NET_RESOLVER_RES_PACKET_FORMAT = 0x80410412, - ERROR_NET_RESOLVER_RES_SERVER_FAILURE = 0x80410413, - ERROR_NET_RESOLVER_INVALID_HOST = 0x80410414, // ERROR_NET_RESOLVER_NO_HOST - ERROR_NET_RESOLVER_RES_NOT_IMPLEMENTED = 0x80410415, - ERROR_NET_RESOLVER_RES_SERVER_REFUSED = 0x80410416, - ERROR_NET_RESOLVER_INTERNAL = 0x80410417, - // pspnet_dhcp ERROR_NET_DHCP_INVALID_PACKET = 0x80410501, ERROR_NET_DHCP_NO_SERVER = 0x80410502, @@ -310,7 +265,7 @@ private: }; extern bool netInited; -extern bool netInetInited; +// extern bool netInetInited; extern bool netApctlInited; extern u32 netApctlState; extern SceNetApctlInfoInternal netApctlInfo; diff --git a/Core/HLE/sceNetApctl.cpp b/Core/HLE/sceNetApctl.cpp new file mode 100644 index 0000000000..acf79bda58 --- /dev/null +++ b/Core/HLE/sceNetApctl.cpp @@ -0,0 +1,3 @@ +// TODO: move apctl here + +#include "sceNetApctl.h" diff --git a/Core/HLE/sceNetApctl.h b/Core/HLE/sceNetApctl.h new file mode 100644 index 0000000000..e6b22d6505 --- /dev/null +++ b/Core/HLE/sceNetApctl.h @@ -0,0 +1,3 @@ +#pragma once + +// TODO: move sceNetApctl here \ No newline at end of file diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp new file mode 100644 index 0000000000..2c8d61aa16 --- /dev/null +++ b/Core/HLE/sceNetInet.cpp @@ -0,0 +1,1026 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#if __linux__ || __APPLE__ || defined(__OpenBSD__) +#include +#include +#include +#include +#endif + +#include "Common/Net/Resolve.h" +#include "Common/Data/Text/Parsers.h" + +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Core/Config.h" +#include "Core/HLE/HLE.h" +#include "Core/HLE/FunctionWrappers.h" +#include "Core/MIPS/MIPS.h" +#include "Core/MemMapHelpers.h" + +#include "Core/HLE/proAdhoc.h" +#include "Core/HLE/sceNet.h" +#include "Core/HLE/sceNetInet.h" + +#include +#include + +#include "Core/HLE/sceNp.h" +#include "Core/Reporting.h" +// TODO: move Core/Net +#include "Core/Net/InetCommon.h" +#include "Core/Net/SceSocket.h" +#include "Core/Util/PortManager.h" + +#if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) +// Missing toolchain define +#define INADDR_NONE 0xFFFFFFFF +#elif PPSSPP_PLATFORM(WINDOWS) +#pragma comment(lib, "ws2_32.lib") +#define close closesocket +#define ERROR_WHEN_NONBLOCKING_CALL_OCCURS WSAEWOULDBLOCK +using netBufferType = char; +#else +#define ERROR_WHEN_NONBLOCKING_CALL_OCCURS EWOULDBLOCK +#include +using netBufferType = void; +#endif + +// TODO: socket domain +// TODO: socket level +// TODO: ignore reuseaddr (option) +// TODO: ignore port (option) +// TODO: ignore SO_NOSIGPIPE +// TODO: timeouts (PSP_NET_INET_SO_SNDTIMEO) + +struct SceTimeval { + u32 tv_sec; /* Seconds. */ + u32 tv_usec; /* Microseconds. */ +}; + +class SceFdSetOperations { +public: + typedef long int fdMask; + static constexpr int gFdsBitsCount = 8 * static_cast(sizeof(fdMask)); + + struct FdSet { + fdMask mFdsBits[256 / gFdsBitsCount]; + }; + + static void Set(FdSet *sceFdSetBits, int socket) { + sceFdSetBits->mFdsBits[Position(socket)] |= ConvertToMask(socket); + } + + static bool IsSet(const FdSet *sceFdSetBits, int socket) { + return (sceFdSetBits->mFdsBits[Position(socket)] & ConvertToMask(socket)) != 0; + } + + static void Clear(FdSet *sceFdSetBits, int socket) { + sceFdSetBits->mFdsBits[Position(socket)] &= ~ConvertToMask(socket); + } + + static void Zero(FdSet *sceFdSetBits) { + memset(sceFdSetBits->mFdsBits, 0, sizeof(FdSet)); + } + +private: + static int Position(const int socket) { + return socket / gFdsBitsCount; + } + + static int ConvertToMask(const int socket) { + return static_cast(1UL << (socket % gFdsBitsCount)); + } +}; + +// static int getLastPlatformError() { +// #if PPSSPP_PLATFORM(WINDOWS) +// return WSAGetLastError(); +// #else +// return errno; +// #endif +// } + +static bool sceSockaddrToNativeSocketAddr(sockaddr_in &dest, u32 sockAddrInternetPtr, size_t addressLength) { + const auto sceNetSockaddrIn = Memory::GetTypedPointerRange(sockAddrInternetPtr, addressLength); + if (sceNetSockaddrIn == nullptr || addressLength == 0) { + return false; + } + + memset(&dest, 0, sizeof(dest)); + dest.sin_family = sceNetSockaddrIn->sin_family; + dest.sin_port = sceNetSockaddrIn->sin_port; + dest.sin_addr.s_addr = sceNetSockaddrIn->sin_addr; + DEBUG_LOG(SCENET, "sceSockaddrToNativeSocketAddr: Family %i, port %i, addr %s, len %i", dest.sin_family, ntohs(dest.sin_port), ip2str(dest.sin_addr, false).c_str(), sceNetSockaddrIn->sin_len); + return true; +} + +static bool writeSockAddrInToSceSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, sockaddr_in src) { + const auto sceNetSocklenPtr = reinterpret_cast(Memory::GetPointerWrite(destAddrLenPtr)); + u32 sceNetSocklen = 0; + if (sceNetSocklenPtr != nullptr) { + sceNetSocklen = *sceNetSocklenPtr; + } + const auto sceNetSockaddrIn = Memory::GetTypedPointerWriteRange(destAddrPtr, sceNetSocklen); + if (sceNetSockaddrIn == nullptr) { + return false; + } + INFO_LOG(SCENET, "writeSockAddrInToSceSockAddr: %lu vs %i", sizeof(SceNetInetSockaddrIn), sceNetSocklen); + if (sceNetSocklenPtr) { + *sceNetSocklenPtr = std::min(sceNetSocklen, sizeof(SceNetInetSockaddr)); + } + if (sceNetSocklen >= 1) { + sceNetSockaddrIn->sin_len = sceNetSocklen; + } + if (sceNetSocklen >= 2) { + sceNetSockaddrIn->sin_family = src.sin_family; + } + if (sceNetSocklen >= 4) { + sceNetSockaddrIn->sin_port = src.sin_port; + } + if (sceNetSocklen >= 8) { + sceNetSockaddrIn->sin_addr = src.sin_addr.s_addr; + } + return true; +} + +static int setBlockingMode(int nativeSocketId, bool nonblocking) { +#if PPSSPP_PLATFORM(WINDOWS) + unsigned long val = nonblocking ? 1 : 0; + return ioctlsocket(fd, FIONBIO, &val); +#else + // Change to Non-Blocking Mode + if (nonblocking) { + return fcntl(nativeSocketId, F_SETFL, O_NONBLOCK); + } else { + const int flags = fcntl(nativeSocketId, F_GETFL); + + // Remove Non-Blocking Flag + return fcntl(nativeSocketId, F_SETFL, flags & ~O_NONBLOCK); + } +#endif +} + +static int sceNetInetInit() { + ERROR_LOG(SCENET, "UNTESTED sceNetInetInit()"); + return SceNetInet::Init() ? 0 : ERROR_NET_INET_ALREADY_INITIALIZED; +} + +int sceNetInetTerm() { + ERROR_LOG(SCENET, "UNTESTED sceNetInetTerm()"); + SceNetInet::Shutdown(); + return 0; +} + +static int sceNetInetSocket(int domain, int type, int protocol) { + ERROR_LOG(SCENET, "UNTESTED sceNetInetSocket(%i, %i, %i)", domain, type, protocol); + auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const int nativeSocketId = socket(domain, type, protocol); + const auto sceSocket = sceNetInet->CreateAndAssociateSceSocket(nativeSocketId); + + if (!sceSocket) { + close(nativeSocketId); + return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new SceSocket for native socket id %i, closing"); + } + + return sceSocket->GetSceSocketId(); +} + +static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optvalPtr, u32 optlenPtr) { + WARN_LOG(SCENET, "UNTESTED sceNetInetGetsockopt(%i, %i, %i, %08x, %08x)", socket, level, inetOptname, optvalPtr, optlenPtr); + + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto sceSocket = sceNetInet->GetSceSocket(socket); + if (!sceSocket) { + ERROR_LOG(SCENET, "sceNetInetGetsockopt: Attempting to operate on unmapped socket %i", socket); + return -1; + } + + if (!sceSocket->IsSockoptNameAllowed(inetOptname)) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); + } + + const auto optname = SceSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); + if (optname != inetOptname) { + DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); + } + + // TODO: implement non-blocking + const auto nativeSocketId = sceSocket->GetNativeSocketId(); + +#if PPSSPP_PLATFORM(WINDOWS) + auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); +#else + auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); +#endif + if (optlen == nullptr) { + ERROR_LOG(SCENET, "[%i] sceNetInetGetsockopt: Invalid pointer %08x", nativeSocketId, optlenPtr); + return -1; + } + + const auto optval = Memory::GetTypedPointerWriteRange(optvalPtr, *optlen); + if (optval == nullptr) { + ERROR_LOG(SCENET, "[%i] sceNetInetGetsockopt: Invalid pointer range %08x (size %i)", nativeSocketId, optvalPtr, *optlen); + return -1; + } + + const int ret = getsockopt(nativeSocketId, SOL_SOCKET, optname, optval, optlen); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + ERROR_LOG(SCENET, "[%i] sceNetInetGetsockopt returned error %i: %s", nativeSocketId, error, strerror(error)); + } + return ret; +} + +static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optvalPtr, int optlen) { + WARN_LOG_ONCE(sceNetInetSetsockopt, SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, level, inetOptname, optvalPtr, optlen); + + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto sceSocket = sceNetInet->GetSceSocket(socket); + if (!sceSocket) { + ERROR_LOG(SCENET, "sceNetInetSetsockopt: Attempting to operate on unmapped socket %i", socket); + return -1; + } + + if (!sceSocket->IsSockoptNameAllowed(inetOptname)) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); + } + + const auto optname = SceSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); + if (optname != inetOptname) { + DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); + } + + // If optlens of != sizeof(u32) are created, split out the handling into separate functions for readability + if (optlen != sizeof(u32)) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "[%i]: Unhandled optlen %i for optname %04x", sceSocket->GetNativeSocketId(), optlen, inetOptname); + } + + auto optval = Memory::Read_U32(optvalPtr); + const auto nativeSocketId = sceSocket->GetNativeSocketId(); + INFO_LOG(SCENET, "[%i] setsockopt_u32(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, level, optname, optval); + + switch (optname) { + // Unmatched PSP functions - no direct equivalent + case INET_SO_NONBLOCK: { + const bool nonblocking = optval != 0; + sceSocket->SetNonBlocking(nonblocking); + INFO_LOG(SCENET, "[%i] setsockopt_u32: Set non-blocking=%i", nativeSocketId, nonblocking); + if (setBlockingMode(nativeSocketId, nonblocking) != 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + ERROR_LOG(SCENET, "[%i] Failed to set to non-blocking: %i: %s", nativeSocketId, error, strerror(error)); + } + return 0; + } + // Matched PSP functions - may be different optname constants (which would have been translated) but the handling the same or similar + // case SO_BROADCAST: { + // INFO_LOG(SCENET, "UNTESTED SCE_SO_BROADCAST sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, level, optname, optval, 4); + // int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); + // if (ret < 0) { + // const auto error = getLastError(); + // INFO_LOG(SCENET, "setsockopt_u32: Got error %i: %s on socket %i", error, strerror(error), nativeSocketId); + // } else { + // INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); + // } + // return 0; + // } + default: { + INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, level, optname, optval, 4); + int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); + INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); + return ret; + } + } +} + +static int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLength) { + WARN_LOG_ONCE(sceNetInetConnect, SCENET, "UNTESTED sceNetInetConnect(%i, %08x, %i, %i)", socket, sockAddrInternetPtr, Memory::Read_U32(sockAddrInternetPtr), addressLength); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + int nativeSocketId; + if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + ERROR_LOG(SCENET, "sceNetInetConnect: Attempting to operate on unmapped socket %i", socket); + return -1; + } + + sockaddr_in convertedSockaddr{}; + if (!sceSockaddrToNativeSocketAddr(convertedSockaddr, sockAddrInternetPtr, addressLength)) { + ERROR_LOG(SCENET, "[%i] sceNetInetConnect: Error translating sceSockaddr to native sockaddr", socket); + return -1; + } + + DEBUG_LOG(SCENET, "[%i] sceNetInetConnect: Connecting to %s on %i", nativeSocketId, ip2str(convertedSockaddr.sin_addr, false).c_str(), ntohs(convertedSockaddr.sin_port)); + + int ret = connect(nativeSocketId, reinterpret_cast(&convertedSockaddr), sizeof(convertedSockaddr)); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, ret, "[%i] %s: Error connecting %i: %s", nativeSocketId, __func__, error, strerror(error)); + } + return hleLogSuccessI(SCENET, ret); +} + +static int sceNetInetListen(int socket, int backlog) { + WARN_LOG_ONCE(sceNetInetListen, SCENET, "UNTESTED %s(%i, %i)", __func__, socket, backlog); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + int nativeSocketId; + if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + ERROR_LOG(SCENET, "sceNetInetConnect: Attempting to operate on unmapped socket %i", socket); + return -1; + } + + // TODO: here + if (backlog == PSP_NET_INET_SOMAXCONN) { + backlog = SOMAXCONN; + } + + const int ret = listen(socket, backlog); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, ret, "[%i] %s: Error listening %i: %s", nativeSocketId, __func__, error, strerror(error)); + } + return hleLogSuccessI(SCENET, ret); +} + +static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { + WARN_LOG_ONCE(sceNetInetListen, SCENET, "UNTESTED %s(%i, %08x, %08x)", __func__, socket, addrPtr, addrLenPtr); + + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + int nativeSocketId; + if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + ERROR_LOG(SCENET, "sceNetInetConnect: Attempting to operate on unmapped socket %i", socket); + return -1; + } + + sockaddr_in sockaddrIn{}; + socklen_t socklen; + int ret = accept(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + if (error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { + hleLogError(SCENET, ret, "[%i] %s: Encountered error %i: %s", nativeSocketId, __func__, error, strerror(error)); + } + return ret; + } + + if (addrPtr != 0 && !writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + hleLogError(SCENET, ret, "[%i] %s: Encountered error trying to write to addrPtr, probably invalid memory range"); + } + return hleLogSuccessI(SCENET, ret); +} + +int sceNetInetPoll(void *fds, u32 nfds, int timeout) { // timeout in miliseconds + DEBUG_LOG(SCENET, "UNTESTED sceNetInetPoll(%p, %d, %i) at %08x", fds, nfds, timeout, currentMIPS->pc); + const auto fdarray = static_cast(fds); // SceNetInetPollfd/pollfd, sceNetInetPoll() have similarity to BSD poll() but pollfd have different size on 64bit +//#ifdef _WIN32 + //WSAPoll only available for Vista or newer, so we'll use an alternative way for XP since Windows doesn't have poll function like *NIX + if (nfds > FD_SETSIZE) { + ERROR_LOG(SCENET, "sceNetInetPoll: nfds=%i is greater than FD_SETSIZE=%i, unable to poll", nfds, FD_SETSIZE); + return -1; + } + fd_set readfds, writefds, exceptfds; + FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); + for (int i = 0; i < static_cast(nfds); i++) { + if (fdarray[i].events & (INET_POLLRDNORM)) + FD_SET(fdarray[i].fd, &readfds); // (POLLRDNORM | POLLIN) + if (fdarray[i].events & (INET_POLLWRNORM)) + FD_SET(fdarray[i].fd, &writefds); // (POLLWRNORM | POLLOUT) + //if (fdarray[i].events & (ADHOC_EV_ALERT)) // (POLLRDBAND | POLLPRI) // POLLERR + FD_SET(fdarray[i].fd, &exceptfds); + fdarray[i].revents = 0; + } + timeval tmout{}; + tmout.tv_sec = timeout / 1000; // seconds + tmout.tv_usec = (timeout % 1000) * 1000; // microseconds + const int ret = select(nfds, &readfds, &writefds, &exceptfds, &tmout); + if (ret < 0) + return -1; + int eventCount = 0; + for (int i = 0; i < static_cast(nfds); i++) { + if (FD_ISSET(fdarray[i].fd, &readfds)) + fdarray[i].revents |= INET_POLLRDNORM; //POLLIN + if (FD_ISSET(fdarray[i].fd, &writefds)) + fdarray[i].revents |= INET_POLLWRNORM; //POLLOUT + fdarray[i].revents &= fdarray[i].events; + if (FD_ISSET(fdarray[i].fd, &exceptfds)) + fdarray[i].revents |= ADHOC_EV_ALERT; // POLLPRI; // POLLERR; // can be raised on revents regardless of events bitmask? + if (fdarray[i].revents) + eventCount++; + } +//#else + /* + // Doesn't work properly yet + pollfd *fdtmp = (pollfd *)malloc(sizeof(pollfd) * nfds); + // Note: sizeof(pollfd) = 16bytes in 64bit and 8bytes in 32bit, while sizeof(SceNetInetPollfd) is always 8bytes + for (int i = 0; i < (s32)nfds; i++) { + fdtmp[i].fd = fdarray[i].fd; + fdtmp[i].events = 0; + if (fdarray[i].events & INET_POLLRDNORM) fdtmp[i].events |= (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI); + if (fdarray[i].events & INET_POLLWRNORM) fdtmp[i].events |= (POLLOUT | POLLWRNORM | POLLWRBAND); + fdtmp[i].revents = 0; + fdarray[i].revents = 0; + } + retval = poll(fdtmp, (nfds_t)nfds, timeout); //retval = WSAPoll(fdarray, nfds, timeout); + for (int i = 0; i < (s32)nfds; i++) { + if (fdtmp[i].revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) fdarray[i].revents |= INET_POLLRDNORM; + if (fdtmp[i].revents & (POLLOUT | POLLWRNORM | POLLWRBAND)) fdarray[i].revents |= INET_POLLWRNORM; + fdarray[i].revents &= fdarray[i].events; + if (fdtmp[i].revents & POLLERR) fdarray[i].revents |= POLLERR; //INET_POLLERR // can be raised on revents regardless of events bitmask? + } + free(fdtmp); + */ +//#endif + return eventCount; +} + +static int sceNetInetSelect(int maxfd, u32 readFdsPtr, u32 writeFdsPtr, u32 exceptFdsPtr, u32 timeoutPtr) { + WARN_LOG_ONCE(sceNetInetSelect, SCENET, "UNTESTED sceNetInetSelect(%i, %08x, %08x, %08x, %08x)", maxfd, readFdsPtr, writeFdsPtr, exceptFdsPtr, timeoutPtr); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + int recomputedMaxFd = 1; + fd_set readFds; + sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, readFds, readFdsPtr); + fd_set writeFds; + sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, writeFds, writeFdsPtr); + fd_set exceptFds; + sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, exceptFds, exceptFdsPtr); + + timeval tv{}; + if (timeoutPtr != 0) { + const auto sceTimeval = Memory::GetTypedPointerRange(timeoutPtr, sizeof(SceTimeval)); + if (sceTimeval != nullptr) { + tv.tv_sec = sceTimeval->tv_sec; + tv.tv_usec = sceTimeval->tv_usec; + DEBUG_LOG(SCENET, "sceNetInetSelect: Timeout seconds=%lu, useconds=%lu", tv.tv_sec, tv.tv_usec); + } else { + WARN_LOG(SCENET, "sceNetInetSelect: Encountered invalid timeout value, continuing anyway"); + } + } + + // Since the fd_set structs are allocated on the stack (and always so), only pass in their pointers if the input pointer is non-null + const int ret = select(recomputedMaxFd, readFdsPtr != 0 ? &readFds : nullptr, writeFdsPtr != 0 ? &writeFds : nullptr, exceptFdsPtr != 0 ? &exceptFds : nullptr, timeoutPtr != 0 ? &tv : nullptr); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + ERROR_LOG(SCENET, "sceNetInetSelect: Received error from select() %i: %s", error, strerror(error)); + } + + INFO_LOG(SCENET, "sceNetInetSelect: select() returned %i", ret); + return hleDelayResult(ret, "TODO: unhack", 300); +} + +static int sceNetInetClose(int socket) { + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto sceSocket = sceNetInet->GetSceSocket(socket); + if (!sceSocket) { + WARN_LOG(SCENET, "sceNetInetClose: Attempting to close socket %i which does not exist", socket); + return -1; + } + + const int ret = close(sceSocket->GetNativeSocketId()); + if (!sceNetInet->EraseNativeSocket(socket)) { + ERROR_LOG(SCENET, "sceNetInetClose: Unable to clear mapping of sceSocketId->nativeSocketId, was there contention?"); + return -1; + } + + return ret; +} + +static u32 sceNetInetInetAddr(const char *hostname) { + ERROR_LOG(SCENET, "UNTESTED sceNetInetInetAddr(%s)", hostname); + in_addr inAddr{}; + // TODO: de-dupe +#if PPSSPP_PLATFORM(WINDOWS) + const int ret = inet_pton(AF_INET, hostname, &inAddr); +#else + const int ret = inet_aton(hostname, &inAddr); +#endif + if (ret != 0) { + return inAddr.s_addr; + } + return ret; +} + +static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { + ERROR_LOG(SCENET, "UNTESTED %s(%s, %08x)", __func__, hostname, addrPtr); + if (!Memory::IsValidAddress(addrPtr)) { + ERROR_LOG(SCENET, "sceNetInetInetAton: Invalid addrPtr: %08x", addrPtr); + return -1; + } + + in_addr inAddr{}; +#if PPSSPP_PLATFORM(WINDOWS) + const int ret = inet_pton(AF_INET, hostname, &inAddr); +#else + const int ret = inet_aton(hostname, &inAddr); +#endif + if (ret != 0) { + Memory::Write_U32(inAddr.s_addr, addrPtr); + } + return ret; +} + +static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 dstBufSize) { + ERROR_LOG(SCENET, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, addressFamily, srcPtr, dstBufPtr, dstBufSize); + + const auto srcSockaddrIn = Memory::GetTypedPointerWriteRange(srcPtr, sizeof(SceNetInetSockaddrIn)); + if (srcSockaddrIn == nullptr) { + return hleLogError(SCENET, 0, "%s: Invalid memory range for srcPtr %08x", __func__, srcPtr); + } + + const auto dstBuf = Memory::GetTypedPointerWriteRange(dstBufPtr, dstBufSize); + if (dstBuf == nullptr) { + return hleLogError(SCENET, 0, "%s: Invalid memory range for dstBufPtr %08x, size %i", __func__, dstBufPtr, dstBufSize); + } + + if (!dstBufSize) { + return hleLogError(SCENET, 0, "%s: dstBufSize must be > 0", __func__); + } + + // TODO: convert address family + if (inet_ntop(addressFamily, reinterpret_cast(srcSockaddrIn), dstBuf, dstBufSize) == nullptr) { + // Allow partial output in case it's desired for some reason + } + + return hleLogSuccessX(SCENET, dstBufPtr); +} + +static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { + ERROR_LOG(SCENET, "UNTESTED sceNetInetGetsockname(%i, %08x, %08x)", socket, addrPtr, addrLenPtr); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + int nativeSocketId; + if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + ERROR_LOG(SCENET, "sceNetInetGetsockname: Requested socket %i which does not exist", socket); + return -1; + } + + sockaddr_in sockaddrIn{}; + socklen_t socklen = sizeof(sockaddr_in); + const int ret = getsockname(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + ERROR_LOG(SCENET, "[%i] sceNetInetGetsockname: Failed to execute getsockname %i: %s", nativeSocketId, error, strerror(error)); + return ret; + } + + if (!writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + ERROR_LOG(SCENET, "[%i] sceNetInetGetsockname: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId); + return -1; + } + return ret; +} + +static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { + WARN_LOG_ONCE(sceNetInetRecv, SCENET, "UNTESTED sceNetInetRecv(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto sceSocket = sceNetInet->GetSceSocket(socket); + if (!sceSocket) { + WARN_LOG(SCENET, "sceNetInetClose: Attempting to close socket %i which does not exist", socket); + return -1; + } + + const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); + if (dstBuf == nullptr) { + return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "sceNetInetRecv: Invalid pointer %08x (size %i)", bufPtr, bufLen); + } + + // TODO: debug log the API calls + const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); + + const int ret = recv(sceSocket->GetNativeSocketId(), dstBuf, bufLen, nativeFlags); + if (ret < 0) { + if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { + ERROR_LOG(SCENET, "[%i]: %s: recv() encountered error %i: %s", socket, __func__, error, strerror(error)); + } + } + return ret; +} + +static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 fromAddr, u32 fromLenAddr) { + WARN_LOG_ONCE(sceNetInetRecvFrom, SCENET, "UNTESTED sceNetInetRecvfrom(%i, %08x, %i, %08x, %08x, %08x)", socket, bufPtr, bufLen, flags, fromAddr, fromLenAddr); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto sceSocket = sceNetInet->GetSceSocket(socket); + if (!sceSocket) { + ERROR_LOG(SCENET, "sceNetInetRecvfrom: Attempting to operate on unmapped socket %i", socket); + return -1; + } + + // DEBUG_LOG(SCENET, "sceNetInetRecvfrom(%i, %08x, %i, %08x, %08x, %08x)", socket, bufPtr, bufLen, flags, fromAddr, fromLenAddr); + + const auto nativeSocketId = sceSocket->GetNativeSocketId(); + const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); + if (dstBuf == nullptr) { + ERROR_LOG(SCENET, "[%i] sceNetInetRecvfrom: Invalid pointer range: %08x (size %i)", socket, bufPtr, bufLen); + return -1; + } + + const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); + sockaddr_in sockaddrIn{}; + socklen_t socklen = sizeof(sockaddr_in); + Memory::Memset(bufPtr, 0, bufLen, "sceNetInetRecvfrom"); + + const int ret = recvfrom(nativeSocketId, dstBuf, bufLen, nativeFlags, reinterpret_cast(&sockaddrIn), &socklen); + + if (ret < 0) { + if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + error != 0 && error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { + WARN_LOG(SCENET, "[%i] sceNetInetRecvfrom: Received error %i: %s", nativeSocketId, error, strerror(error)); + } + return hleDelayResult(ret, "TODO: unhack", 500); + } + + if (ret > 0) { + if (!writeSockAddrInToSceSockAddr(fromAddr, fromLenAddr, sockaddrIn)) { + ERROR_LOG(SCENET, "[%i] sceNetInetRecvfrom: Error writing native sockaddr to sceSockaddr", nativeSocketId); + } + INFO_LOG(SCENET, "[%i] sceNetInetRecvfrom: Got %i bytes from recvfrom", nativeSocketId, ret); + } + return hleDelayResult(ret, "TODO: unhack", 500); +} + +static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { + WARN_LOG_ONCE(sceNetInetSend, SCENET, "UNTESTED sceNetInetSend(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto sceSocket = sceNetInet->GetSceSocket(socket); + if (!sceSocket) { + ERROR_LOG(SCENET, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return -1; + } + + const auto resolvedPtr = Memory::GetTypedPointerRange(bufPtr, bufLen); + if (resolvedPtr == nullptr) { + ERROR_LOG(SCENET, "[%i] %s: Invalid pointer range: %08x (size %i)", socket, __func__, bufPtr, bufLen); + return -1; + } + + const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); + + const int ret = send(sceSocket->GetNativeSocketId(), resolvedPtr, bufLen, nativeFlags); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + ERROR_LOG(SCENET, "[%i]: %s: send() encountered error %i: %s", socket, __func__, error, strerror(error)); + } + + return ret; +} + +static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 toAddr, u32 toLen) { + ERROR_LOG_ONCE(sceNetInetSendto, SCENET, "UNTESTED sceNetInetSendto(%i, %08x, %i, %08x, %08x, %i)", socket, bufPtr, bufLen, flags, toAddr, toLen); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto sceSocket = sceNetInet->GetSceSocket(socket); + if (!sceSocket) { + ERROR_LOG(SCENET, "sceNetInetSendto: Attempting to operate on unmapped socket %i", socket); + return -1; + } + + const int nativeSocketId = sceSocket->GetNativeSocketId(); + const auto srcBuf = Memory::GetTypedPointerRange(bufPtr, bufLen); + if (srcBuf == nullptr) { + ERROR_LOG(SCENET, "[%i] sceNetInetSendto: Invalid pointer range: %08x (size %i)", socket, bufPtr, bufLen); + return -1; + } + + const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); + sockaddr_in convertedSockAddr{}; + if (!sceSockaddrToNativeSocketAddr(convertedSockAddr, toAddr, toLen)) { + ERROR_LOG(SCENET, "[%i] sceNetInetSendto: Unable to translate sceSockAddr to native sockaddr", nativeSocketId); + return -1; + } + + // TODO: improve debug log + DEBUG_LOG(SCENET, "[%i] sceNetInetSendto: Writing %i bytes to %s on port %i", nativeSocketId, bufLen, ip2str(convertedSockAddr.sin_addr, false).c_str(), ntohs(convertedSockAddr.sin_port)); + + const int ret = sendto(nativeSocketId, srcBuf, bufLen, nativeFlags, reinterpret_cast(&convertedSockAddr), sizeof(sockaddr_in)); + DEBUG_LOG(SCENET, "[%i] sceNetInetSendto: sendto returned %i", nativeSocketId, ret); + + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + WARN_LOG(SCENET, "[%i] sceNetInetSendto: Got error %i=%s", nativeSocketId, error, strerror(error)); + } + + return ret; +} + +static int sceNetInetGetErrno() { + ERROR_LOG_ONCE(sceNetInetGetErrno, SCENET, "UNTESTED sceNetInetGetErrno()"); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto nativeError = sceNetInet->GetLastError(); + if (nativeError != ERROR_WHEN_NONBLOCKING_CALL_OCCURS && nativeError != 0) { + INFO_LOG(SCENET, "Requested sceNetInetGetErrno %i=%s", nativeError, strerror(nativeError)); + } + + // TODO: consider moving below function to SceNetInet + return SceSocket::TranslateNativeErrorToInetError(nativeError); +} + +static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { + WARN_LOG_ONCE(sceNetInetSend, SCENET, "UNTESTED sceNetInetBind(%i, %08x, %08x)", socket, addrPtr, addrLen); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto sceSocket = sceNetInet->GetSceSocket(socket); + if (!sceSocket) { + ERROR_LOG(SCENET, "sceNetInetBind: Attempting to operate on unmapped socket %i", socket); + return -1; + } + const int nativeSocketId = sceSocket->GetNativeSocketId(); + +#if PPSSPP_PLATFORM(LINUX) + // Set broadcast + // TODO: move broadcast SceSocket + int broadcastEnabled = 1; + int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, &broadcastEnabled, sizeof(broadcastEnabled)); + + // Set reuseport / reuseaddr by default + // TODO: evaluate + int opt = 1; +#if defined(SO_REUSEPORT) + setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); +#endif + setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); +#elif PPSSPP_PLATFORM(WINDOWS) + // Set broadcast + // TODO: move broadcast SceSocket + int broadcastEnabled = 1; + int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&broadcastEnabled), sizeof(broadcastEnabled)); + int opt = 1; + setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)); +#endif + + sockaddr_in convertedSockaddr{}; + if (!sceSockaddrToNativeSocketAddr(convertedSockaddr, addrPtr, addrLen)) { + ERROR_LOG(SCENET, "[%i] Error translating sceSockaddr to native sockaddr", nativeSocketId); + return -1; + } + socklen_t socklen = sizeof(convertedSockaddr); + + // Get default outbound sockaddr when INADDR_ANY or INADDR_BROADCAST are used + if (const auto addr = convertedSockaddr.sin_addr.s_addr; addr == INADDR_ANY || addr == INADDR_BROADCAST) { + if (!getDefaultOutboundSockaddr(convertedSockaddr, socklen)) { + WARN_LOG(SCENET, "Failed to get default bound address"); + return -1; + } + } + + // TODO: check whether setting to blocking and then non-blocking is valid + setBlockingMode(nativeSocketId, false); + INFO_LOG(SCENET, "[%i] Binding to family %i, port %i, addr %s sockoptRet %i", nativeSocketId, convertedSockaddr.sin_family, ntohs(convertedSockaddr.sin_port), ip2str(convertedSockaddr.sin_addr, false).c_str(), sockoptRet); + const int ret = bind(nativeSocketId, reinterpret_cast(&convertedSockaddr), socklen); + INFO_LOG(SCENET, "Bind returned %i for fd=%i", ret, nativeSocketId); + setBlockingMode(nativeSocketId, sceSocket->IsNonBlocking()); + + // Set UPnP + const auto port = ntohs(convertedSockaddr.sin_port); + switch (sceSocket->GetProtocol()) { + case INET_PROTOCOL_TCP: { + UPnP_Add(IP_PROTOCOL_TCP, port, port); + break; + } + case INET_PROTOCOL_UDP: { + UPnP_Add(IP_PROTOCOL_UDP, port, port); + break; + } + default: { + WARN_LOG(SCENET, "[%i]: Unknown IP protocol %04x when attempting to set up UPnP port forwarding", nativeSocketId, sceSocket->GetProtocol()); + break; + } + } + return ret; +} + +// TODO: fix retmasks +const HLEFunction sceNetInet[] = { + {0X17943399, &WrapI_V, "sceNetInetInit", 'i', "" }, + {0X4CFE4E56, nullptr, "sceNetInetShutdown", '?', "" }, + {0XA9ED66B9, &WrapI_V, "sceNetInetTerm", 'i', "" }, + {0X8B7B220F, &WrapI_III, "sceNetInetSocket", 'i', "iii" }, + {0X4A114C7C, &WrapI_IIIUU, "sceNetInetGetsockopt", 'i', "iiixx"}, + {0X2FE71FE7, &WrapI_IIIUI, "sceNetInetSetsockopt", 'i', "iiixi"}, + {0X410B34AA, &WrapI_IUI, "sceNetInetConnect", 'i', "ixi" }, + {0X805502DD, nullptr, "sceNetInetCloseWithRST", '?', "" }, + {0XD10A1A7A, &WrapI_II, "sceNetInetListen", '?', "" }, + {0XDB094E1B, &WrapI_IUU, "sceNetInetAccept", '?', "" }, + {0XFAABB1DD, &WrapI_VUI, "sceNetInetPoll", 'i', "pxi" }, + {0X5BE8D595, &WrapI_IUUUU, "sceNetInetSelect", 'i', "ixxxx"}, + {0X8D7284EA, &WrapI_I, "sceNetInetClose", '?', "" }, + {0XCDA85C99, &WrapI_IUUI, "sceNetInetRecv", 'i', "ixxi" }, + {0XC91142E4, &WrapI_IUUIUU, "sceNetInetRecvfrom", 'i', "ixxxxx"}, + {0XEECE61D2, nullptr, "sceNetInetRecvmsg", '?', "" }, + {0X7AA671BC, &WrapI_IUUI, "sceNetInetSend", 'i', "ixxx" }, + {0X05038FC7, &WrapI_IUUIUU, "sceNetInetSendto", 'i', "ixxxxx"}, + {0X774E36F4, nullptr, "sceNetInetSendmsg", '?', "" }, + {0XFBABE411, &WrapI_V, "sceNetInetGetErrno", 'i', "" }, + {0X1A33F9AE, &WrapI_IUU, "sceNetInetBind", 'i', "" }, + {0XB75D5B0A, &WrapU_C, "sceNetInetInetAddr", 'u', "p" }, + {0X1BDF5D13, &WrapI_CU, "sceNetInetInetAton", 'i', "sx" }, + {0XD0792666, &WrapU_IUUU, "sceNetInetInetNtop", '?', "" }, + {0XE30B8C19, nullptr, "sceNetInetInetPton", '?', "" }, + {0X8CA3A97E, nullptr, "sceNetInetGetPspError", '?', "" }, + {0XE247B6D6, nullptr, "sceNetInetGetpeername", '?', "" }, + {0X162E6FD5, &WrapI_IUU, "sceNetInetGetsockname", '?', "" }, + {0X80A21ABD, nullptr, "sceNetInetSocketAbort", '?', "" }, + {0X39B0C7D3, nullptr, "sceNetInetGetUdpcbstat", '?', "" }, + {0XB3888AD4, nullptr, "sceNetInetGetTcpcbstat", '?', "" }, +}; + +std::shared_ptr SceNetInet::gInstance; +std::shared_mutex SceNetInet::gLock; + +bool SceNetInet::Init() { + auto lock = std::unique_lock(gLock); + if (gInstance) + return false; + gInstance = std::make_shared(); + return true; +} + +bool SceNetInet::Shutdown() { + auto lock = std::unique_lock(gLock); + if (!gInstance) + return false; + gInstance->CloseAllRemainingSockets(); + gInstance = nullptr; + return true; +} + +int SceNetInet::GetLastError() { + auto lock = std::shared_lock(mLock); + return mLastError; +} + +void SceNetInet::SetLastError(const int error) { + auto lock = std::unique_lock(mLock); + mLastError = error; +} + +int SceNetInet::SetLastErrorToMatchPlatform() { + int error; +#if PPSSPP_PLATFORM(WINDOWS) + error = WSAGetLastError(); +#else + error = errno; +#endif + SetLastError(error); + return error; +} + +std::shared_ptr SceNetInet::CreateAndAssociateSceSocket(int nativeSocketId) { + auto lock = std::unique_lock(mLock); + + int sceSocketId = ++mCurrentSceSocketId; + if (const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); it != mSceSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to re-associate socket from already-associated sceSocketId: %i", __func__, sceSocketId); + return nullptr; + } + auto sceSocket = std::make_shared(sceSocketId, nativeSocketId); + mSceSocketIdToNativeSocket.emplace(sceSocketId, sceSocket); + return sceSocket; +} + +std::shared_ptr SceNetInet::GetSceSocket(int sceSocketId) { + auto lock = std::shared_lock(mLock); + + const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); + if (it == mSceSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to get unassociated socket from sceSocketId: %i", __func__, sceSocketId); + return nullptr; + } + + return it->second; +} + +bool SceNetInet::GetNativeSocketIdForSceSocketId(int& nativeSocketId, int sceSocketId) { + const auto sceSocket = GetSceSocket(sceSocketId); + if (!sceSocket) + return false; + nativeSocketId = sceSocket->GetNativeSocketId(); + return true; +} + +bool SceNetInet::EraseNativeSocket(int sceSocketId) { + auto lock = std::unique_lock(mLock); + + const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); + if (it == mSceSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to delete unassociated socket from sceSocketId: %i", __func__, sceSocketId); + return false; + } + mSceSocketIdToNativeSocket.erase(it); + return true; +} + +bool SceNetInet::TranslateSceFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, u32 fdsPtr) const { + if (fdsPtr == 0) { + // Allow nullptr to be used without failing + return true; + } + + FD_ZERO(&destFdSet); + const auto sceFdSet = Memory::GetTypedPointerRange(fdsPtr, sizeof(SceFdSetOperations::FdSet)); + if (sceFdSet == nullptr) { + ERROR_LOG(SCENET, "%s: Invalid fdsPtr %08x", __func__, fdsPtr); + return false; + } + + int setSize = 0; + for (auto& it : mSceSocketIdToNativeSocket) { + const auto sceSocket = it.first; + const auto nativeSocketId = it.second->GetNativeSocketId(); + if (nativeSocketId + 1 > maxFd) { + maxFd = nativeSocketId + 1; + } + if (SceFdSetOperations::IsSet(sceFdSet, sceSocket)) { + if (++setSize > FD_SETSIZE) { + ERROR_LOG(SCENET, "%s: Encountered input FD_SET which is greater than max supported size %i", __func__, setSize); + return false; + } + DEBUG_LOG(SCENET, "%s: Translating input %i into %i", __func__, sceSocket, nativeSocketId); + FD_SET(nativeSocketId, &destFdSet); + } + } + + DEBUG_LOG(SCENET, "%s: Translated %i sockets", __func__, setSize); + return true; +} + +void SceNetInet::CloseAllRemainingSockets() const { + for (auto& it : mSceSocketIdToNativeSocket) { + if (!it.second) { + continue; + } + close(it.second->GetNativeSocketId()); + } +} + +void Register_sceNetInet() { + RegisterModule("sceNetInet", ARRAY_SIZE(sceNetInet), sceNetInet); +} diff --git a/Core/HLE/sceNetInet.h b/Core/HLE/sceNetInet.h new file mode 100644 index 0000000000..db2301e303 --- /dev/null +++ b/Core/HLE/sceNetInet.h @@ -0,0 +1,61 @@ +#pragma once + +#include "Core/HLE/HLE.h" +#include "Core/Net/SceSocket.h" + +#if PPSSPP_PLATFORM(WINDOWS) +#include +#endif + +#include +#include +#include + + +enum { + // pspnet_inet + ERROR_NET_INET_ALREADY_INITIALIZED = 0x80410201, + ERROR_NET_INET_SOCKET_BUSY = 0x80410202, + ERROR_NET_INET_CONFIG_INVALID_ARG = 0x80410203, + ERROR_NET_INET_GET_IFADDR = 0x80410204, + ERROR_NET_INET_SET_IFADDR = 0x80410205, + ERROR_NET_INET_DEL_IFADDR = 0x80410206, + ERROR_NET_INET_NO_DEFAULT_ROUTE = 0x80410207, + ERROR_NET_INET_GET_ROUTE = 0x80410208, + ERROR_NET_INET_SET_ROUTE = 0x80410209, + ERROR_NET_INET_FLUSH_ROUTE = 0x8041020a, + ERROR_NET_INET_INVALID_ARG = 0x8041020b, +}; + +class SceNetInet { +public: + static bool Init(); + static bool Shutdown(); + static std::shared_ptr Get() { + return gInstance; + } + + // TODO: document + + int GetLastError(); + void SetLastError(int error); + int SetLastErrorToMatchPlatform(); + std::shared_ptr CreateAndAssociateSceSocket(int nativeSocketId); + std::shared_ptr GetSceSocket(int sceSocketId); + bool GetNativeSocketIdForSceSocketId(int &nativeSocketId, int sceSocketId); + bool EraseNativeSocket(int sceSocketId); + bool TranslateSceFdSetToNativeFdSet(int& maxFd, fd_set &destFdSet, u32 fdsPtr) const; + +private: + void CloseAllRemainingSockets() const; + + static std::shared_ptr gInstance; + static std::shared_mutex gLock; + + int mLastError = 0; + std::unordered_map> mSceSocketIdToNativeSocket; + int mCurrentSceSocketId = 0; + std::shared_mutex mLock; +}; + +void Register_sceNetInet(); diff --git a/Core/HLE/sceNetResolver.cpp b/Core/HLE/sceNetResolver.cpp new file mode 100644 index 0000000000..df2bc483f1 --- /dev/null +++ b/Core/HLE/sceNetResolver.cpp @@ -0,0 +1,312 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#if __linux__ || __APPLE__ || defined(__OpenBSD__) +#include +#include +#include +#include +#endif + +// TODO: fixme move Core/Net to Common/Net +#include "Common/Net/Resolve.h" +#include "Core/Net/InetCommon.h" +#include "Common/Data/Text/Parsers.h" + +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Common/Serialize/SerializeMap.h" +#include "Core/Config.h" +#include "Core/HLE/HLE.h" +#include "Core/HLE/FunctionWrappers.h" +#include "Core/HLE/sceKernelMemory.h" +#include "Core/MIPS/MIPS.h" +#include "Core/Config.h" +#include "Core/MemMapHelpers.h" +#include "Core/Util/PortManager.h" + +#include "sceKernel.h" +#include "sceKernelThread.h" +#include "sceKernelMutex.h" +#include "sceUtility.h" + +#include "Core/HLE/proAdhoc.h" +#include "Core/HLE/sceNetResolver.h" + +#include +#include + +#include "sceNet.h" +#include "Core/HLE/sceNp.h" +#include "Core/Reporting.h" +#include "Core/Instance.h" +#include "Core/Net/SceSocket.h" + +#if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) +// Missing toolchain define +#define INADDR_NONE 0xFFFFFFFF +#endif + +static int sceNetResolverInit() { + ERROR_LOG(SCENET, "UNTESTED %s()", __FUNCTION__); + g_Config.mHostToAlias["socomftb2.psp.online.scea.com"] = "67.222.156.250"; + g_Config.mHostToAlias["socompsp-prod.muis.pdonline.scea.com"] = "67.222.156.250"; + SceNetResolver::Init(); + return 0; +} + +static int sceNetResolverTerm() { + ERROR_LOG(SCENET, "UNTESTED %s()", __FUNCTION__); + SceNetResolver::Shutdown(); + return 0; +} + +// Note: timeouts are in seconds +int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { + auto sceNetResolver = SceNetResolver::Get(); + if (!sceNetResolver) { + return hleLogError(SCENET, ERROR_NET_RESOLVER_STOPPED, "Net Resolver Subsystem Shutdown: Resolver %i", + resolverId); + } + + const auto resolver = sceNetResolver->GetNetResolver(resolverId); + if (resolver == nullptr) { + return hleLogError(SCENET, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + } + + addrinfo* resolved = nullptr; + std::string err, hostname = std::string(safe_string(Memory::GetCharPointer(hostnamePtr))); + SockAddrIN4 addr{}; + addr.in.sin_addr.s_addr = INADDR_NONE; + + // Flag resolver as in-progress - not relevant for sync functions but potentially relevant for async + resolver->SetIsRunning(true); + + // Resolve any aliases + if (g_Config.mHostToAlias.find(hostname) != g_Config.mHostToAlias.end()) { + const std::string& alias = g_Config.mHostToAlias[hostname]; + INFO_LOG(SCENET, "%s - Resolved alias %s from hostname %s", __FUNCTION__, alias.c_str(), hostname.c_str()); + hostname = alias; + } + + // Attempt to execute a DNS resolution + if (!net::DNSResolve(hostname, "", &resolved, err)) { + // TODO: Return an error based on the outputted "err" (unfortunately it's already converted to string) + return hleLogError(SCENET, ERROR_NET_RESOLVER_INVALID_HOST, "DNS Error Resolving %s (%s)\n", hostname.c_str(), + err.c_str()); + } + + // If successful, write to memory + if (resolved != nullptr) { + for (auto ptr = resolved; ptr != nullptr; ptr = ptr->ai_next) { + switch (ptr->ai_family) { + case AF_INET: + addr.in = *(sockaddr_in *) ptr->ai_addr; + break; + } + } + net::DNSResolveFree(resolved); + + Memory::Write_U32(addr.in.sin_addr.s_addr, inAddrPtr); + INFO_LOG(SCENET, "%s - Hostname: %s => IPv4: %s", __FUNCTION__, hostname.c_str(), + ip2str(addr.in.sin_addr, false).c_str()); + } + + // Flag resolver as complete + resolver->SetIsRunning(false); + return 0; +} + +static int sceNetResolverStartNtoA(int resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { + for (int attempt = 0; attempt < retry; ++attempt) { + if (const int status = NetResolver_StartNtoA(resolverId, hostnamePtr, inAddrPtr, timeout, retry); status >= 0) { + return status; + } + } + return -1; +} + +static int sceNetResolverStartNtoAAsync(int resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { + ERROR_LOG_REPORT_ONCE(sceNetResolverStartNtoAAsync, SCENET, "UNIMPL %s(%d, %08x, %08x, %d, %d) at %08x", + __FUNCTION__, resolverId, hostnamePtr, inAddrPtr, timeout, retry, currentMIPS->pc); + return NetResolver_StartNtoA(resolverId, hostnamePtr, inAddrPtr, timeout, retry); +} + +static int sceNetResolverPollAsync(int resolverId, u32 unknown) { + ERROR_LOG_REPORT_ONCE(sceNetResolverPollAsync, SCENET, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, + unknown, currentMIPS->pc); + // TODO: Implement after confirming that this returns the state of resolver.isRunning + return 0; +} + +static int sceNetResolverWaitAsync(int resolverId, u32 unknown) { + ERROR_LOG_REPORT_ONCE(sceNetResolverWaitAsync, SCENET, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, + unknown, currentMIPS->pc); + // TODO: Implement after confirming that this blocks current thread until resolver.isRunning flips to false + return 0; +} + +static int sceNetResolverStartAtoN(int resolverId, u32 inAddr, u32 hostnamePtr, int hostnameLength, int timeout, + int retry) { + ERROR_LOG_REPORT_ONCE(sceNetResolverStartAtoN, SCENET, "UNIMPL %s(%d, %08x[%s], %08x, %i, %i, %i) at %08x", + __FUNCTION__, resolverId, inAddr, ip2str(*(in_addr*)&inAddr, false).c_str(), hostnamePtr, + hostnameLength, timeout, retry, currentMIPS->pc); + // TODO: Implement via getnameinfo + return 0; +} + +static int sceNetResolverStartAtoNAsync(int resolverId, u32 inAddr, u32 hostnamePtr, int hostnameLength, int timeout, + int retry) { + ERROR_LOG_REPORT_ONCE(sceNetResolverStartAtoNAsync, SCENET, "UNIMPL %s(%d, %08x[%s], %08x, %i, %i, %i) at %08x", + __FUNCTION__, resolverId, inAddr, ip2str(*(in_addr*)&inAddr, false).c_str(), hostnamePtr, + hostnameLength, timeout, retry, currentMIPS->pc); + return 0; +} + +static int sceNetResolverCreate(u32 resolverIdPtr, u32 bufferPtr, int bufferLen) { + WARN_LOG(SCENET, "UNTESTED %s(%08x[%d], %08x, %d) at %08x", __FUNCTION__, resolverIdPtr, + Memory::Read_U32(resolverIdPtr), bufferPtr, bufferLen, currentMIPS->pc); + if (!Memory::IsValidRange(resolverIdPtr, 4)) + return hleLogError(SCENET, ERROR_NET_RESOLVER_INVALID_PTR, "Invalid Ptr: %08x", resolverIdPtr); + + if (Memory::IsValidRange(bufferPtr, 4) && bufferLen < 1) + return hleLogError(SCENET, ERROR_NET_RESOLVER_INVALID_BUFLEN, "Invalid Buffer Length: %i", bufferLen); + + auto sceNetResolver = SceNetResolver::Get(); + if (!sceNetResolver) + return hleLogError(SCENET, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped"); + + const auto resolver = sceNetResolver->CreateNetResolver(bufferPtr, bufferLen); + + Memory::Write_U32(resolver->GetId(), resolverIdPtr); + return 0; +} + +static int sceNetResolverStop(u32 resolverId) { + auto sceNetResolver = SceNetResolver::Get(); + if (!sceNetResolver) { + return hleLogError(SCENET, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", + resolverId); + } + + const auto resolver = sceNetResolver->GetNetResolver(resolverId); + + WARN_LOG(SCENET, "UNTESTED %s(%d) at %08x", __FUNCTION__, resolverId, currentMIPS->pc); + if (resolver == nullptr) + return hleLogError(SCENET, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + + if (!resolver->GetIsRunning()) + return hleLogError(SCENET, ERROR_NET_RESOLVER_ALREADY_STOPPED, "Resolver Already Stopped (Id: %i)", resolverId); + + resolver->SetIsRunning(false); + return 0; +} + +static int sceNetResolverDelete(u32 resolverId) { + WARN_LOG(SCENET, "UNTESTED %s(%d) at %08x", __FUNCTION__, resolverId, currentMIPS->pc); + + auto sceNetResolver = SceNetResolver::Get(); + if (!sceNetResolver) + return hleLogError(SCENET, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", + resolverId); + + if (!sceNetResolver->DeleteNetResolver(resolverId)) + return hleLogError(SCENET, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + + return 0; +} + +const HLEFunction sceNetResolver[] = { + {0X224C5F44, &WrapI_IUUII, "sceNetResolverStartNtoA", 'i', "ixxii"}, + {0X244172AF, &WrapI_UUI, "sceNetResolverCreate", 'i', "xxi"}, + {0X94523E09, &WrapI_U, "sceNetResolverDelete", 'i', "i"}, + {0XF3370E61, &WrapI_V, "sceNetResolverInit", 'i', ""}, + {0X808F6063, &WrapI_U, "sceNetResolverStop", 'i', "i"}, + {0X6138194A, &WrapI_V, "sceNetResolverTerm", 'i', ""}, + {0X629E2FB7, &WrapI_IUUIII, "sceNetResolverStartAtoN", 'i', "ixxiii"}, + {0X14C17EF9, &WrapI_IUUII, "sceNetResolverStartNtoAAsync", 'i', "ixxii"}, + {0XAAC09184, &WrapI_IUUIII, "sceNetResolverStartAtoNAsync", 'i', "ixxiii"}, + {0X12748EB9, &WrapI_IU, "sceNetResolverWaitAsync", 'i', "ix"}, + {0X4EE99358, &WrapI_IU, "sceNetResolverPollAsync", 'i', "ix"}, +}; + +std::shared_ptr SceNetResolver::gInstance; +std::shared_mutex SceNetResolver::gLock; + +void SceNetResolver::Init() { + auto lock = std::unique_lock(gLock); + gInstance = std::make_shared(); +} + +void SceNetResolver::Shutdown() { + auto lock = std::unique_lock(gLock); + gInstance = nullptr; +} + +std::shared_ptr SceNetResolver::Get() { + auto lock = std::shared_lock(gLock); + return gInstance; +} + +std::shared_ptr SceNetResolver::GetNetResolver(u32 resolverId) { + std::shared_lock lock(mNetResolversLock); + const auto it = mNetResolvers.find(resolverId); + return it != mNetResolvers.end() ? it->second : nullptr; +} + +std::shared_ptr SceNetResolver::CreateNetResolver(u32 bufferPtr, u32 bufferLen) { + // TODO: Consider using SceUidManager instead of this 1-indexed id + // TODO: Implement ERROR_NET_RESOLVER_ID_MAX (possibly 32?) + std::unique_lock lock(mNetResolversLock); + int currentNetResolverId = mCurrentNetResolverId++; + return mNetResolvers[currentNetResolverId] = std::make_shared( + currentNetResolverId, // id + bufferPtr, // bufferPtr + bufferLen // bufferLen + ); +} + +bool SceNetResolver::TerminateNetResolver(u32 resolverId) { + const auto netResolver = GetNetResolver(resolverId); + if (netResolver == nullptr) { + return false; + } + netResolver->SetIsRunning(false); + return true; +} + +bool SceNetResolver::DeleteNetResolver(u32 resolverId) { + std::unique_lock lock(mNetResolversLock); + const auto it = mNetResolvers.find(resolverId); + if (it == mNetResolvers.end()) { + return false; + } + mNetResolvers.erase(it); + return true; +} + +void SceNetResolver::ClearNetResolvers() { + std::unique_lock lock(mNetResolversLock); + for (auto &[first, second]: mNetResolvers) { + second->SetIsRunning(false); + } + mNetResolvers.clear(); +} + +void Register_sceNetResolver() { + RegisterModule("sceNetResolver", ARRAY_SIZE(sceNetResolver), sceNetResolver); +} diff --git a/Core/HLE/sceNetResolver.h b/Core/HLE/sceNetResolver.h new file mode 100644 index 0000000000..5c32ab2adb --- /dev/null +++ b/Core/HLE/sceNetResolver.h @@ -0,0 +1,74 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once +#include +#include + +#include "Core/Net/NetResolver.h" + +class SceNetResolver; + +enum { + // pspnet_resolver + ERROR_NET_RESOLVER_NOT_TERMINATED = 0x80410401, + ERROR_NET_RESOLVER_NO_DNS_SERVER = 0x80410402, + ERROR_NET_RESOLVER_INVALID_PTR = 0x80410403, + ERROR_NET_RESOLVER_INVALID_BUFLEN = 0x80410404, + ERROR_NET_RESOLVER_INVALID_ID = 0x80410405, + ERROR_NET_RESOLVER_ID_MAX = 0x80410406, + ERROR_NET_RESOLVER_NO_MEM = 0x80410407, + ERROR_NET_RESOLVER_BAD_ID = 0x80410408, // ERROR_NET_RESOLVER_ID_NOT_FOUND + ERROR_NET_RESOLVER_CTX_BUSY = 0x80410409, + ERROR_NET_RESOLVER_ALREADY_STOPPED = 0x8041040a, + ERROR_NET_RESOLVER_NOT_SUPPORTED = 0x8041040b, + ERROR_NET_RESOLVER_BUF_NO_SPACE = 0x8041040c, + ERROR_NET_RESOLVER_INVALID_PACKET = 0x8041040d, + ERROR_NET_RESOLVER_STOPPED = 0x8041040e, + ERROR_NET_RESOLVER_SOCKET = 0x8041040f, + ERROR_NET_RESOLVER_TIMEOUT = 0x80410410, + ERROR_NET_RESOLVER_NO_RECORD = 0x80410411, + ERROR_NET_RESOLVER_RES_PACKET_FORMAT = 0x80410412, + ERROR_NET_RESOLVER_RES_SERVER_FAILURE = 0x80410413, + ERROR_NET_RESOLVER_INVALID_HOST = 0x80410414, // ERROR_NET_RESOLVER_NO_HOST + ERROR_NET_RESOLVER_RES_NOT_IMPLEMENTED = 0x80410415, + ERROR_NET_RESOLVER_RES_SERVER_REFUSED = 0x80410416, + ERROR_NET_RESOLVER_INTERNAL = 0x80410417, +}; + +class SceNetResolver { +public: + static void Init(); + static void Shutdown(); + static std::shared_ptr Get(); + + std::shared_ptr GetNetResolver(u32 resolverId); + std::shared_ptr CreateNetResolver(u32 bufferPtr, u32 bufferLen); + bool TerminateNetResolver(u32 resolverId); + bool DeleteNetResolver(u32 resolverId); + void ClearNetResolvers(); + +private: + static std::shared_ptr gInstance; + static std::shared_mutex gLock; + + int mCurrentNetResolverId = 1; + std::unordered_map> mNetResolvers; + std::shared_mutex mNetResolversLock; +}; + +void Register_sceNetResolver(); \ No newline at end of file diff --git a/Core/MemMap.h b/Core/MemMap.h index a22a68b973..03a77bc954 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -248,7 +248,16 @@ u8* GetPointerWrite(const u32 address); const u8* GetPointer(const u32 address); u8 *GetPointerWriteRange(const u32 address, const u32 size); +template +T* GetTypedPointerWriteRange(const u32 address, const u32 size) { + return reinterpret_cast(GetPointerWriteRange(address, size)); +} + const u8 *GetPointerRange(const u32 address, const u32 size); +template +const T* GetTypedPointerRange(const u32 address, const u32 size) { + return reinterpret_cast(GetPointerRange(address, size)); +} bool IsRAMAddress(const u32 address); inline bool IsVRAMAddress(const u32 address) { diff --git a/Core/Net/InetCommon.cpp b/Core/Net/InetCommon.cpp new file mode 100644 index 0000000000..5969240b1b --- /dev/null +++ b/Core/Net/InetCommon.cpp @@ -0,0 +1,54 @@ +// TODO: license + +#if __linux__ || __APPLE__ || defined(__OpenBSD__) +#include +#include +#include +#include +#endif + +// TODO: fixme move Core/Net to Common/Net +#include "Common/Net/Resolve.h" +#include "Core/Net/InetCommon.h" +#include "Common/Data/Text/Parsers.h" + +#include "Common/Serialize/Serializer.h" +#include "Core/Config.h" +#include "Core/HLE/HLE.h" +#include "Core/MemMapHelpers.h" + +#include "Core/HLE/proAdhoc.h" + +#include +#include + +#include "Core/HLE/sceNp.h" + +#if PPSSPP_PLATFORM(WINDOWS) +#define close closesocket +#endif + +bool getDefaultOutboundSockaddr(sockaddr_in& destSockaddrIn, socklen_t& destSocklen) { + auto fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) { + ERROR_LOG(SCENET, "getSockAddrFromDefaultSocket: Failed to open socket (%s)", strerror(errno)); + return false; + } + sockaddr_in connectingTo; + memset(&connectingTo, 0, sizeof(connectingTo)); + connectingTo.sin_family = AF_INET; + connectingTo.sin_port = htons(53); + connectingTo.sin_addr.s_addr = 0x08080808; + if (connect(fd, (sockaddr*) &connectingTo, sizeof(connectingTo)) < 0) { + ERROR_LOG(SCENET, "getSockAddrFromDefaultSocket: Failed to connect to Google (%s)", strerror(errno)); + close(fd); + return false; + } + if (getsockname(fd, (sockaddr*) &destSockaddrIn, &destSocklen) < 0) { + ERROR_LOG(SCENET, "getSockAddrFromDefaultSocket: Failed to execute getsockname (%s)", strerror(errno)); + close(fd); + return false; + } + close(fd); + return true; +} diff --git a/Core/Net/InetCommon.h b/Core/Net/InetCommon.h new file mode 100644 index 0000000000..647bf8f345 --- /dev/null +++ b/Core/Net/InetCommon.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Core/HLE/HLE.h" + +#if PPSSPP_PLATFORM(WINDOWS) +#include +#include +#else +#include +#endif + +bool getDefaultOutboundSockaddr(sockaddr_in& destSockaddrIn, socklen_t& destSocklen); diff --git a/Core/Net/NetResolver.cpp b/Core/Net/NetResolver.cpp new file mode 100644 index 0000000000..ec9b79e6a9 --- /dev/null +++ b/Core/Net/NetResolver.cpp @@ -0,0 +1,3 @@ +#include "NetResolver.h" + +// TODO: remove me if the functions remain inlined \ No newline at end of file diff --git a/Core/Net/NetResolver.h b/Core/Net/NetResolver.h new file mode 100644 index 0000000000..effa453c90 --- /dev/null +++ b/Core/Net/NetResolver.h @@ -0,0 +1,32 @@ +#pragma once + +#include "CommonTypes.h" + +class NetResolver { +public: + NetResolver(const NetResolver& other) = default; + + NetResolver() : + mId(0), + mIsRunning(false), + mBufferAddr(0), + mBufferLen(0) {} + + NetResolver(const int id, const u32 bufferAddr, const int bufferLen) : + mId(id), + mIsRunning(false), + mBufferAddr(bufferAddr), + mBufferLen(bufferLen) {} + + int GetId() const { return mId; } + + bool GetIsRunning() const { return mIsRunning; } + + void SetIsRunning(const bool isRunning) { this->mIsRunning = isRunning; } + +private: + int mId; + bool mIsRunning; + u32 mBufferAddr; + u32 mBufferLen; +}; diff --git a/Core/Net/SceSocket.cpp b/Core/Net/SceSocket.cpp new file mode 100644 index 0000000000..c155401f3b --- /dev/null +++ b/Core/Net/SceSocket.cpp @@ -0,0 +1,3 @@ +// TODO: remove me if the functions remain inlined + +#include "SceSocket.h" diff --git a/Core/Net/SceSocket.h b/Core/Net/SceSocket.h new file mode 100644 index 0000000000..e458600b09 --- /dev/null +++ b/Core/Net/SceSocket.h @@ -0,0 +1,195 @@ +#pragma once + +#include +#include +#include + +#include "Log.h" + +enum Protocol { + INET_PROTOCOL_UDP = SOCK_DGRAM, + INET_PROTOCOL_TCP = SOCK_STREAM +}; + +// TODO: INET_ +enum InetSocketOptionName { + // TODO: also specify minimum socket size + INET_SO_ACCEPTCONN = 0x0002, // socket has had listen() + INET_SO_REUSEADDR = 0x0004, // allow local address reuse + INET_SO_KEEPALIVE = 0x0008, // keep connections alive + INET_SO_DONTROUTE = 0x0010, // just use interface addresses + INET_SO_BROADCAST = 0x0020, // permit sending of broadcast msgs + INET_SO_USELOOPBACK = 0x0040, // bypass hardware when possible + INET_SO_LINGER = 0x0080, // linger on close if data present + INET_SO_OOBINLINE = 0x0100, // leave received OOB data in line + INET_SO_REUSEPORT = 0x0200, // allow local address & port reuse + INET_SO_TIMESTAMP = 0x0400, // timestamp received dgram traffic + INET_SO_ONESBCAST = 0x0800, // allow broadcast to 255.255.255.255 + INET_SO_SNDBUF = 0x1001, // send buffer size + INET_SO_RCVBUF = 0x1002, // receive buffer size + INET_SO_SNDLOWAT = 0x1003, // send low-water mark + INET_SO_RCVLOWAT = 0x1004, // receive low-water mark + INET_SO_SNDTIMEO = 0x1005, // send timeout + INET_SO_RCVTIMEO = 0x1006, // receive timeout + INET_SO_ERROR = 0x1007, // get error status and clear + INET_SO_TYPE = 0x1008, // get socket type + INET_SO_OVERFLOWED = 0x1009, // datagrams: return packets dropped + INET_SO_NONBLOCK = 0x1009, // non-blocking I/O +}; + +// TODO: Handle commented out options +static std::unordered_map gInetSocketOptnameToNativeOptname = { + { INET_SO_ACCEPTCONN, SO_ACCEPTCONN }, + { INET_SO_REUSEADDR, SO_REUSEADDR }, + { INET_SO_KEEPALIVE, SO_KEEPALIVE }, + { INET_SO_DONTROUTE, SO_DONTROUTE }, + { INET_SO_BROADCAST, SO_BROADCAST }, + // { INET_SO_USELOOPBACK, INET_SO_USELOOPBACK }, + { INET_SO_LINGER, SO_LINGER }, + { INET_SO_OOBINLINE, SO_OOBINLINE }, + { INET_SO_REUSEPORT, SO_REUSEPORT }, + { INET_SO_TIMESTAMP, SO_TIMESTAMP }, + // { INET_SO_ONESBCAST, INET_SO_ONESBCAST }, + { INET_SO_SNDBUF, SO_SNDBUF }, + { INET_SO_RCVBUF, SO_RCVBUF }, + { INET_SO_SNDLOWAT, SO_SNDLOWAT }, + { INET_SO_RCVLOWAT, SO_RCVLOWAT }, + { INET_SO_SNDTIMEO, SO_SNDTIMEO }, + { INET_SO_RCVTIMEO, SO_RCVTIMEO }, + { INET_SO_ERROR, SO_ERROR }, + { INET_SO_TYPE, SO_TYPE }, + // { INET_SO_OVERFLOWED, INET_SO_OVERFLOWED }, + { INET_SO_NONBLOCK, INET_SO_NONBLOCK }, +}; + +enum InetLimit { + PSP_NET_INET_SOMAXCONN = 128, +}; + +enum InetMessageFlag { + INET_MSG_OOB = 1, + INET_MSG_PEEK = 1 << 1, + INET_MSG_DONTROUTE = 1 << 2, + INET_MSG_EOR = 1 << 3, + INET_MSG_TRUNC = 1 << 4, + INET_MSG_CTRUNC = 1 << 5, + INET_MSG_WAITALL = 1 << 6, + INET_MSG_DONTWAIT = 1 << 7, + INET_MSG_BCAST = 1 << 8, + INET_MSG_MCAST = 1 << 9 +}; + +// TODO: move to better place +static std::unordered_map gInetMessageFlagToNativeMessageFlag = { + { INET_MSG_OOB, MSG_OOB }, + { INET_MSG_PEEK, MSG_PEEK }, + { INET_MSG_DONTROUTE, MSG_DONTROUTE }, +#if defined(MSG_EOR) + { INET_MSG_EOR, MSG_EOR }, +#endif + { INET_MSG_TRUNC, MSG_TRUNC }, + { INET_MSG_CTRUNC, MSG_CTRUNC }, + { INET_MSG_WAITALL, MSG_WAITALL }, + { INET_MSG_DONTWAIT, MSG_DONTWAIT }, +#if defined(MSG_BCAST) + { INET_MSG_BCAST, MSG_BCAST }, +#endif +#if defined(MSG_MCAST) + { INET_MSG_MCAST, MSG_MCAST }, +#endif +}; + +enum InetErrorCode { + INET_EINPROGRESS = 119, +}; + +static std::unordered_map gNativeErrorCodeToInetErrorCode = { + { EINPROGRESS, INET_EINPROGRESS } +}; + +// TODO: document +class SceSocket { +public: + SceSocket(int sceSocketId, int nativeSocketId) : mSceSocketId(sceSocketId), mNativeSocketId(nativeSocketId) {} + + int GetSceSocketId() const { + return mSceSocketId; + } + + int GetNativeSocketId() const { + return mNativeSocketId; + } + + // TODO: get mask of options + + bool IsNonBlocking() const { + return mNonBlocking; + } + + void SetNonBlocking(const bool nonBlocking) { + mNonBlocking = nonBlocking; + } + + Protocol GetProtocol() const { + return mProtocol; + } + + void SetProtocol(const Protocol protocol) { + mProtocol = protocol; + } + + // TODO: Move me + static bool IsSockoptNameAllowed(const int optname) { + return gInetSocketOptnameToNativeOptname.find(static_cast(optname)) != gInetSocketOptnameToNativeOptname.end(); + } + + // TODO: rename this or the other + static int TranslateInetOptnameToNativeOptname(const InetSocketOptionName inetOptname) { + const auto it = gInetSocketOptnameToNativeOptname.find(inetOptname); + if (it == gInetSocketOptnameToNativeOptname.end()) { + return inetOptname; + } + return it->second; + } + + int TranslateInetFlagsToNativeFlags(const int messageFlags) const { + int nativeFlags = 0; // The actual platform flags + int foundFlags = 0; // The inet equivalent of the native flags, used to verify that no remaining flags need to be set + for (const auto [inetFlag, nativeFlag] : gInetMessageFlagToNativeMessageFlag) { + if ((messageFlags & inetFlag) != 0) { + nativeFlags |= nativeFlag; + foundFlags |= inetFlag; + } + } + +#if !PPSSPP_PLATFORM(WINDOWS) + if (this->IsNonBlocking()) { + nativeFlags |= MSG_DONTWAIT; + } +#endif + + // Check for any inet flags which were not successfully mapped into a native flag + if (const int missingFlags = messageFlags & ~foundFlags; missingFlags != 0) { + for (int i = 0; i < sizeof(int) * 8; i++) { + if (const int val = 1 << i; (missingFlags & val) != 0) { + DEBUG_LOG(Log::sceNet, "Encountered unsupported platform flag at bit %i (actual value %04x), undefined behavior may ensue.", i, val); + } + } + } + // DEBUG_LOG(SCENET, "Translated %04x to %04x", messageFlags, nativeFlags); + return nativeFlags; + } + + static int TranslateNativeErrorToInetError(const int nativeError) { + if (const auto it = gNativeErrorCodeToInetErrorCode.find(nativeError); + it != gNativeErrorCodeToInetErrorCode.end()) { + return it->second; + } + return nativeError; + } +private: + int mSceSocketId; + int mNativeSocketId; + Protocol mProtocol; + bool mNonBlocking = false; +}; diff --git a/ext/rcheevos b/ext/rcheevos index 32917bdddf..3a91a58605 160000 --- a/ext/rcheevos +++ b/ext/rcheevos @@ -1 +1 @@ -Subproject commit 32917bdddf4982e62047862c6633e7671aaaf2cb +Subproject commit 3a91a58605c0fb05833a228dbb674357b0e65a09 From dfd4b996bfb75fce5e9c6b4fa8e1f7ce963034d7 Mon Sep 17 00:00:00 2001 From: White Blood Cell Date: Tue, 26 Dec 2023 11:53:43 -0800 Subject: [PATCH 2/9] Implement sceNetInetGetpeername and sceNetInetGetsockname as per anr2mes impl and begin converting ERROR_LOGS into hleLogError + ensuring last error is set. --- Core/HLE/FunctionWrappers.h | 5 + Core/HLE/sceNetInet.cpp | 220 ++++++++++++++++++++++++------------ Core/Net/InetCommon.cpp | 6 +- Core/Net/SceSocket.h | 6 + 4 files changed, 162 insertions(+), 75 deletions(-) diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index a8ab014f9f..c1af60f5b4 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -820,6 +820,11 @@ template void WrapI_ICI() { RETURN(retval); } +template void WrapI_ICU() { + int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2)); + RETURN(retval); +} + template void WrapI_IVVVVUI(){ u32 retval = func(PARAM(0), Memory::GetPointerWrite(PARAM(1)), Memory::GetPointerWrite(PARAM(2)), Memory::GetPointerWrite(PARAM(3)), Memory::GetPointerWrite(PARAM(4)), PARAM(5), PARAM(6) ); RETURN(retval); diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index 2c8d61aa16..c1ca667e30 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -47,6 +47,8 @@ #include "Core/Net/SceSocket.h" #include "Core/Util/PortManager.h" +#define SCENET Log::sceNet + #if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) // Missing toolchain define #define INADDR_NONE 0xFFFFFFFF @@ -188,7 +190,7 @@ int sceNetInetTerm() { } static int sceNetInetSocket(int domain, int type, int protocol) { - ERROR_LOG(SCENET, "UNTESTED sceNetInetSocket(%i, %i, %i)", domain, type, protocol); + WARN_LOG_ONCE(sceNetInetSocket, SCENET, "UNTESTED sceNetInetSocket(%i, %i, %i)", domain, type, protocol); auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); @@ -199,7 +201,8 @@ static int sceNetInetSocket(int domain, int type, int protocol) { if (!sceSocket) { close(nativeSocketId); - return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new SceSocket for native socket id %i, closing"); + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new SceSocket for native socket id %i, closing", __func__, nativeSocketId); } return sceSocket->GetSceSocketId(); @@ -215,11 +218,12 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv const auto sceSocket = sceNetInet->GetSceSocket(socket); if (!sceSocket) { - ERROR_LOG(SCENET, "sceNetInetGetsockopt: Attempting to operate on unmapped socket %i", socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } if (!sceSocket->IsSockoptNameAllowed(inetOptname)) { + sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); } @@ -228,7 +232,6 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); } - // TODO: implement non-blocking const auto nativeSocketId = sceSocket->GetNativeSocketId(); #if PPSSPP_PLATFORM(WINDOWS) @@ -237,20 +240,21 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); #endif if (optlen == nullptr) { - ERROR_LOG(SCENET, "[%i] sceNetInetGetsockopt: Invalid pointer %08x", nativeSocketId, optlenPtr); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer %08x", nativeSocketId, __func__, optlenPtr); } const auto optval = Memory::GetTypedPointerWriteRange(optvalPtr, *optlen); if (optval == nullptr) { - ERROR_LOG(SCENET, "[%i] sceNetInetGetsockopt: Invalid pointer range %08x (size %i)", nativeSocketId, optvalPtr, *optlen); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range %08x (size %i)", nativeSocketId, __func__, optvalPtr, *optlen); } + // TODO: implement non-blocking sockopt const int ret = getsockopt(nativeSocketId, SOL_SOCKET, optname, optval, optlen); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "[%i] sceNetInetGetsockopt returned error %i: %s", nativeSocketId, error, strerror(error)); + return hleLogError(SCENET, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error)); } return ret; } @@ -265,11 +269,12 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv const auto sceSocket = sceNetInet->GetSceSocket(socket); if (!sceSocket) { - ERROR_LOG(SCENET, "sceNetInetSetsockopt: Attempting to operate on unmapped socket %i", socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } if (!sceSocket->IsSockoptNameAllowed(inetOptname)) { + sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); } @@ -280,7 +285,8 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv // If optlens of != sizeof(u32) are created, split out the handling into separate functions for readability if (optlen != sizeof(u32)) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "[%i]: Unhandled optlen %i for optname %04x", sceSocket->GetNativeSocketId(), optlen, inetOptname); + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "[%i]: %s: Unhandled optlen %i for optname %04x", sceSocket->GetNativeSocketId(), __func__, optlen, inetOptname); } auto optval = Memory::Read_U32(optvalPtr); @@ -299,18 +305,6 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv } return 0; } - // Matched PSP functions - may be different optname constants (which would have been translated) but the handling the same or similar - // case SO_BROADCAST: { - // INFO_LOG(SCENET, "UNTESTED SCE_SO_BROADCAST sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, level, optname, optval, 4); - // int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); - // if (ret < 0) { - // const auto error = getLastError(); - // INFO_LOG(SCENET, "setsockopt_u32: Got error %i: %s on socket %i", error, strerror(error), nativeSocketId); - // } else { - // INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); - // } - // return 0; - // } default: { INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, level, optname, optval, 4); int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); @@ -329,14 +323,14 @@ static int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLen int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { - ERROR_LOG(SCENET, "sceNetInetConnect: Attempting to operate on unmapped socket %i", socket); - return -1; + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } sockaddr_in convertedSockaddr{}; if (!sceSockaddrToNativeSocketAddr(convertedSockaddr, sockAddrInternetPtr, addressLength)) { - ERROR_LOG(SCENET, "[%i] sceNetInetConnect: Error translating sceSockaddr to native sockaddr", socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i] %s: Error translating sceSockaddr to native sockaddr", nativeSocketId, __func__); } DEBUG_LOG(SCENET, "[%i] sceNetInetConnect: Connecting to %s on %i", nativeSocketId, ip2str(convertedSockaddr.sin_addr, false).c_str(), ntohs(convertedSockaddr.sin_port)); @@ -358,8 +352,8 @@ static int sceNetInetListen(int socket, int backlog) { int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { - ERROR_LOG(SCENET, "sceNetInetConnect: Attempting to operate on unmapped socket %i", socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } // TODO: here @@ -385,8 +379,8 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { - ERROR_LOG(SCENET, "sceNetInetConnect: Attempting to operate on unmapped socket %i", socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } sockaddr_in sockaddrIn{}; @@ -401,7 +395,8 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { } if (addrPtr != 0 && !writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { - hleLogError(SCENET, ret, "[%i] %s: Encountered error trying to write to addrPtr, probably invalid memory range"); + sceNetInet->SetLastError(EFAULT); + hleLogError(SCENET, ret, "[%i] %s: Encountered error trying to write to addrPtr, probably invalid memory range", nativeSocketId, __func__); } return hleLogSuccessI(SCENET, ret); } @@ -516,21 +511,26 @@ static int sceNetInetClose(int socket) { const auto sceSocket = sceNetInet->GetSceSocket(socket); if (!sceSocket) { - WARN_LOG(SCENET, "sceNetInetClose: Attempting to close socket %i which does not exist", socket); - return -1; + sceNetInet->SetLastError(EINVAL); + return hleLogWarning(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); } const int ret = close(sceSocket->GetNativeSocketId()); if (!sceNetInet->EraseNativeSocket(socket)) { - ERROR_LOG(SCENET, "sceNetInetClose: Unable to clear mapping of sceSocketId->nativeSocketId, was there contention?"); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Unable to clear mapping of sceSocketId->nativeSocketId, was there contention?", __func__); } - return ret; } static u32 sceNetInetInetAddr(const char *hostname) { ERROR_LOG(SCENET, "UNTESTED sceNetInetInetAddr(%s)", hostname); + + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + in_addr inAddr{}; // TODO: de-dupe #if PPSSPP_PLATFORM(WINDOWS) @@ -539,6 +539,7 @@ static u32 sceNetInetInetAddr(const char *hostname) { const int ret = inet_aton(hostname, &inAddr); #endif if (ret != 0) { + sceNetInet->SetLastErrorToMatchPlatform(); return inAddr.s_addr; } return ret; @@ -546,9 +547,15 @@ static u32 sceNetInetInetAddr(const char *hostname) { static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { ERROR_LOG(SCENET, "UNTESTED %s(%s, %08x)", __func__, hostname, addrPtr); + + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + if (!Memory::IsValidAddress(addrPtr)) { - ERROR_LOG(SCENET, "sceNetInetInetAton: Invalid addrPtr: %08x", addrPtr); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Invalid addrPtr: %08x", __func__, addrPtr); } in_addr inAddr{}; @@ -564,19 +571,27 @@ static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { } static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 dstBufSize) { - ERROR_LOG(SCENET, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, addressFamily, srcPtr, dstBufPtr, dstBufSize); + WARN_LOG_ONCE(sceNetInetInetNtop, SCENET, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, addressFamily, srcPtr, dstBufPtr, dstBufSize); + + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } const auto srcSockaddrIn = Memory::GetTypedPointerWriteRange(srcPtr, sizeof(SceNetInetSockaddrIn)); if (srcSockaddrIn == nullptr) { + sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, 0, "%s: Invalid memory range for srcPtr %08x", __func__, srcPtr); } const auto dstBuf = Memory::GetTypedPointerWriteRange(dstBufPtr, dstBufSize); if (dstBuf == nullptr) { + sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, 0, "%s: Invalid memory range for dstBufPtr %08x, size %i", __func__, dstBufPtr, dstBufSize); } if (!dstBufSize) { + sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, 0, "%s: dstBufSize must be > 0", __func__); } @@ -584,11 +599,39 @@ static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 if (inet_ntop(addressFamily, reinterpret_cast(srcSockaddrIn), dstBuf, dstBufSize) == nullptr) { // Allow partial output in case it's desired for some reason } - return hleLogSuccessX(SCENET, dstBufPtr); } -static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { +static int sceNetInetInetPton(int addressFamily, const char *hostname, u32 dstBufPtr) { + WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, addressFamily, hostname, dstBufPtr); + + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + const auto srcSockaddrIn = Memory::GetTypedPointerWriteRange(srcPtr, sizeof(SceNetInetSockaddrIn)); + if (srcSockaddrIn == nullptr) { + return hleLogError(SCENET, 0, "%s: Invalid memory range for srcPtr %08x", __func__, srcPtr); + } + + // IPv4, the only supported address family on PSP, will always be 32 bits + const auto dstBuf = Memory::GetTypedPointerWriteRange(dstBufPtr, sizeof(u32)); + if (dstBuf == nullptr) { + return hleLogError(SCENET, 0, "%s: Invalid memory range for dstBufPtr %08x, size %i", __func__, dstBufPtr, dstBufSize); + } + + // TODO: convert address family + // TODO: If af does not contain a valid address family, -1 is returned and errno is set to EAFNOSUPPORT. + const int ret = inet_pton(addressFamily, reinterpret_cast(srcSockaddrIn), dstBuf); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, ret, "%s: inet_pton returned %i: %s", __func__, sceNetInet->GetLastError(), strerror(error)); + } + return hleLogSuccessI(SCENET, ret); +} + +static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { ERROR_LOG(SCENET, "UNTESTED sceNetInetGetsockname(%i, %08x, %08x)", socket, addrPtr, addrLenPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -597,7 +640,41 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { - ERROR_LOG(SCENET, "sceNetInetGetsockname: Requested socket %i which does not exist", socket); + ERROR_LOG(SCENET, "%s: Requested socket %i which does not exist", __func__, socket); + return -1; + } + + // Write PSP sockaddr to native sockaddr in preparation of getpeername + sockaddr_in sockaddrIn{}; + socklen_t socklen = sizeof(sockaddr_in); + if (!sceSockaddrToNativeSocketAddr(sockaddrIn, addrPtr, addrLenPtr)) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i]: %s: Encountered invalid addrPtr %08x and/or invalid addrLenPtr %08x", nativeSocketId, addrPtr, addrLenPtr); + } + + const int ret = getpeername(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, ret, "[%i] %s: Failed to execute getpeername %i: %s", nativeSocketId, __func__, error, strerror(error)); + } + + if (!writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getpeername to SceNetInetSockaddrIn", nativeSocketId, __func__); + } + return ret; +} + +static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { + ERROR_LOG(SCENET, "UNTESTED %s(%i, %08x, %08x)", __func__, socket, addrPtr, addrLenPtr); + const auto sceNetInet = SceNetInet::Get(); + if (!sceNetInet) { + return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + } + + int nativeSocketId; + if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + ERROR_LOG(SCENET, "%s: Requested socket %i which does not exist", __func__, socket); return -1; } @@ -606,13 +683,11 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { const int ret = getsockname(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "[%i] sceNetInetGetsockname: Failed to execute getsockname %i: %s", nativeSocketId, error, strerror(error)); - return ret; + return hleLogError(SCENET, ret, "[%i] %s: Failed to execute getsockname %i: %s", nativeSocketId, __func__, error, strerror(error)); } if (!writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { - ERROR_LOG(SCENET, "[%i] sceNetInetGetsockname: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId); - return -1; + return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId, __func__); } return ret; } @@ -656,23 +731,21 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 const auto sceSocket = sceNetInet->GetSceSocket(socket); if (!sceSocket) { - ERROR_LOG(SCENET, "sceNetInetRecvfrom: Attempting to operate on unmapped socket %i", socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - // DEBUG_LOG(SCENET, "sceNetInetRecvfrom(%i, %08x, %i, %08x, %08x, %08x)", socket, bufPtr, bufLen, flags, fromAddr, fromLenAddr); - const auto nativeSocketId = sceSocket->GetNativeSocketId(); const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); if (dstBuf == nullptr) { - ERROR_LOG(SCENET, "[%i] sceNetInetRecvfrom: Invalid pointer range: %08x (size %i)", socket, bufPtr, bufLen); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); } const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); sockaddr_in sockaddrIn{}; socklen_t socklen = sizeof(sockaddr_in); - Memory::Memset(bufPtr, 0, bufLen, "sceNetInetRecvfrom"); + Memory::Memset(bufPtr, 0, bufLen, __func__); const int ret = recvfrom(nativeSocketId, dstBuf, bufLen, nativeFlags, reinterpret_cast(&sockaddrIn), &socklen); @@ -702,14 +775,14 @@ static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { const auto sceSocket = sceNetInet->GetSceSocket(socket); if (!sceSocket) { - ERROR_LOG(SCENET, "%s: Attempting to operate on unmapped socket %i", __func__, socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } const auto resolvedPtr = Memory::GetTypedPointerRange(bufPtr, bufLen); if (resolvedPtr == nullptr) { - ERROR_LOG(SCENET, "[%i] %s: Invalid pointer range: %08x (size %i)", socket, __func__, bufPtr, bufLen); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", socket, __func__, bufPtr, bufLen); } const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); @@ -717,10 +790,9 @@ static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { const int ret = send(sceSocket->GetNativeSocketId(), resolvedPtr, bufLen, nativeFlags); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "[%i]: %s: send() encountered error %i: %s", socket, __func__, error, strerror(error)); + return hleLogError(SCENET, ret, "[%i]: %s: send() encountered error %i: %s", socket, __func__, error, strerror(error)); } - - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 toAddr, u32 toLen) { @@ -732,8 +804,8 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t const auto sceSocket = sceNetInet->GetSceSocket(socket); if (!sceSocket) { - ERROR_LOG(SCENET, "sceNetInetSendto: Attempting to operate on unmapped socket %i", socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } const int nativeSocketId = sceSocket->GetNativeSocketId(); @@ -789,9 +861,10 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { const auto sceSocket = sceNetInet->GetSceSocket(socket); if (!sceSocket) { - ERROR_LOG(SCENET, "sceNetInetBind: Attempting to operate on unmapped socket %i", socket); - return -1; + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } + const int nativeSocketId = sceSocket->GetNativeSocketId(); #if PPSSPP_PLATFORM(LINUX) @@ -882,10 +955,10 @@ const HLEFunction sceNetInet[] = { {0X1A33F9AE, &WrapI_IUU, "sceNetInetBind", 'i', "" }, {0XB75D5B0A, &WrapU_C, "sceNetInetInetAddr", 'u', "p" }, {0X1BDF5D13, &WrapI_CU, "sceNetInetInetAton", 'i', "sx" }, - {0XD0792666, &WrapU_IUUU, "sceNetInetInetNtop", '?', "" }, - {0XE30B8C19, nullptr, "sceNetInetInetPton", '?', "" }, + {0XD0792666, &WrapU_IUUU, "sceNetInetInetNtop", '?', "" }, + {0XE30B8C19, &WrapI_ICU, "sceNetInetInetPton", '?', "" }, {0X8CA3A97E, nullptr, "sceNetInetGetPspError", '?', "" }, - {0XE247B6D6, nullptr, "sceNetInetGetpeername", '?', "" }, + {0XE247B6D6, &WrapI_IUU,"sceNetInetGetpeername", '?', "" }, {0X162E6FD5, &WrapI_IUU, "sceNetInetGetsockname", '?', "" }, {0X80A21ABD, nullptr, "sceNetInetSocketAbort", '?', "" }, {0X39B0C7D3, nullptr, "sceNetInetGetUdpcbstat", '?', "" }, @@ -897,16 +970,18 @@ std::shared_mutex SceNetInet::gLock; bool SceNetInet::Init() { auto lock = std::unique_lock(gLock); - if (gInstance) + if (gInstance) { return false; + } gInstance = std::make_shared(); return true; } bool SceNetInet::Shutdown() { auto lock = std::unique_lock(gLock); - if (!gInstance) + if (!gInstance) { return false; + } gInstance->CloseAllRemainingSockets(); gInstance = nullptr; return true; @@ -922,6 +997,7 @@ void SceNetInet::SetLastError(const int error) { mLastError = error; } +// TODO: ensure this is applied to every function int SceNetInet::SetLastErrorToMatchPlatform() { int error; #if PPSSPP_PLATFORM(WINDOWS) diff --git a/Core/Net/InetCommon.cpp b/Core/Net/InetCommon.cpp index 5969240b1b..29909fd04e 100644 --- a/Core/Net/InetCommon.cpp +++ b/Core/Net/InetCommon.cpp @@ -31,7 +31,7 @@ bool getDefaultOutboundSockaddr(sockaddr_in& destSockaddrIn, socklen_t& destSocklen) { auto fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { - ERROR_LOG(SCENET, "getSockAddrFromDefaultSocket: Failed to open socket (%s)", strerror(errno)); + ERROR_LOG(Log::sceNet, "getSockAddrFromDefaultSocket: Failed to open socket (%s)", strerror(errno)); return false; } sockaddr_in connectingTo; @@ -40,12 +40,12 @@ bool getDefaultOutboundSockaddr(sockaddr_in& destSockaddrIn, socklen_t& destSock connectingTo.sin_port = htons(53); connectingTo.sin_addr.s_addr = 0x08080808; if (connect(fd, (sockaddr*) &connectingTo, sizeof(connectingTo)) < 0) { - ERROR_LOG(SCENET, "getSockAddrFromDefaultSocket: Failed to connect to Google (%s)", strerror(errno)); + ERROR_LOG(Log::sceNet, "getSockAddrFromDefaultSocket: Failed to connect to Google (%s)", strerror(errno)); close(fd); return false; } if (getsockname(fd, (sockaddr*) &destSockaddrIn, &destSocklen) < 0) { - ERROR_LOG(SCENET, "getSockAddrFromDefaultSocket: Failed to execute getsockname (%s)", strerror(errno)); + ERROR_LOG(Log::sceNet, "getSockAddrFromDefaultSocket: Failed to execute getsockname (%s)", strerror(errno)); close(fd); return false; } diff --git a/Core/Net/SceSocket.h b/Core/Net/SceSocket.h index e458600b09..1110ca8bb1 100644 --- a/Core/Net/SceSocket.h +++ b/Core/Net/SceSocket.h @@ -1,8 +1,13 @@ #pragma once +#include "ppsspp_config.h" + #include #include + +#if !PPSSPP_PLATFORM(WINDOWS) #include +#endif #include "Log.h" @@ -187,6 +192,7 @@ public: } return nativeError; } + private: int mSceSocketId; int mNativeSocketId; From 87de5b6385391a7f1a1312677788a2d5e74f6b36 Mon Sep 17 00:00:00 2001 From: White Blood Cell Date: Wed, 27 Dec 2023 10:12:32 -0800 Subject: [PATCH 3/9] Add header to sceNetInet and audit hleLogError calls for SetLastError. --- CMakeLists.txt | 4 +- Core/Core.vcxproj | 4 +- Core/Core.vcxproj.filters | 4 +- Core/HLE/sceNet.h | 22 -- Core/HLE/sceNetInet.cpp | 433 ++++++++++++--------- Core/HLE/sceNetInet.h | 38 +- Core/HLE/sceNetResolver.cpp | 48 +-- Core/Net/{SceSocket.cpp => InetSocket.cpp} | 2 +- Core/Net/{SceSocket.h => InetSocket.h} | 11 +- 9 files changed, 318 insertions(+), 248 deletions(-) rename Core/Net/{SceSocket.cpp => InetSocket.cpp} (68%) rename Core/Net/{SceSocket.h => InetSocket.h} (96%) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba41313c14..e55181ac92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2391,8 +2391,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/Net/InetCommon.h Core/Net/NetResolver.cpp Core/Net/NetResolver.h - Core/Net/SceSocket.cpp - Core/Net/SceSocket.h + Core/Net/InetSocket.cpp + Core/Net/InetSocket.h Core/MemFault.cpp Core/MemFault.h Core/MemMap.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index a3db7b3d1e..1c783385e5 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -629,8 +629,8 @@ + - @@ -1221,8 +1221,8 @@ + - diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 9923894b3e..f0c86bbc6d 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1339,7 +1339,7 @@ Net - + Net @@ -2157,7 +2157,7 @@ Net - + Net diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index cbc2cd17f5..043ffd2773 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -176,28 +176,6 @@ enum { #ifdef _MSC_VER #pragma pack(push,1) #endif -// Sockaddr -typedef struct SceNetInetSockaddr { - uint8_t sa_len; - uint8_t sa_family; - uint8_t sa_data[14]; -} PACK SceNetInetSockaddr; - -// Sockaddr_in -typedef struct SceNetInetSockaddrIn { - uint8_t sin_len; - uint8_t sin_family; - u16_le sin_port; //uint16_t - u32_le sin_addr; //uint32_t - uint8_t sin_zero[8]; -} PACK SceNetInetSockaddrIn; - -// Polling Event Field -typedef struct SceNetInetPollfd { //similar format to pollfd in 32bit (pollfd in 64bit have different size) - s32_le fd; - s16_le events; - s16_le revents; -} PACK SceNetInetPollfd; typedef struct ProductStruct { // Similar to SceNetAdhocctlAdhocId ? s32_le unknown; // Unknown, set to 0 // Product Type ? diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index c1ca667e30..3291c068d4 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -44,7 +44,7 @@ #include "Core/Reporting.h" // TODO: move Core/Net #include "Core/Net/InetCommon.h" -#include "Core/Net/SceSocket.h" +#include "Core/Net/InetSocket.h" #include "Core/Util/PortManager.h" #define SCENET Log::sceNet @@ -70,12 +70,43 @@ using netBufferType = void; // TODO: ignore SO_NOSIGPIPE // TODO: timeouts (PSP_NET_INET_SO_SNDTIMEO) -struct SceTimeval { +/** + * @file sceNetInet.cpp + * + * @brief A shim for SceNetInet functions to operate over native POSIX sockets. These POSIX socket implementations are + * largely standarized and consistent between platforms with the exception of Windows which uses Winsock2 which itself + * is similar enough. + * + * Glossary: + * - Inet: Anything with is prefaced with Inet, regardless of case, is the PSP variant of the function / structure / etc. + * + * Standards: + * - C++-style implementations are preferred over C-style implementations when applicable (see SceFdSetOperations) for + * an example which implements fd_set and FD_* functions using C++-style code. + * - The last error is implemented within SceNetInet itself and is not a direct passthrough from the platforms errno + * implementation. + * - Invalid arguments (unmapped sockets, invalid options / flags etc) are mapped to EINVAL. + * - Invalid memory regions are mapped to EFAULT. + * - hleLogError should be used to return errors. + * - hleLogSuccess* should be used to return success, with optional messages. These message formattings have > 0 + * overhead so be mindful of their usage. + * - SceNetInet must have SetLastError called in all error cases except when SceNetInet itself is not initialized. + * - DEBUG_LOG should be used where it makes sense. + * - Comments must be left to indicate the intent of each section of each function. The comments should be short and + * concise while not mentioning any specific games or similar in particular. Mention the constraints that came from + * the game. + * - Explicit mappings should be used over implicit passthrough. Cases which are not known to work for PSP should be + * mapped to an EINVAL error unless it is demonstrated to work as expected. + * - It should not be possible for a game to crash the application via any shim; think what would happen if every + * parameter is randomized. + */ + +struct PspInetTimeval { u32 tv_sec; /* Seconds. */ u32 tv_usec; /* Microseconds. */ }; -class SceFdSetOperations { +class PspInetFdSetOperations { public: typedef long int fdMask; static constexpr int gFdsBitsCount = 8 * static_cast(sizeof(fdMask)); @@ -84,20 +115,20 @@ public: fdMask mFdsBits[256 / gFdsBitsCount]; }; - static void Set(FdSet *sceFdSetBits, int socket) { - sceFdSetBits->mFdsBits[Position(socket)] |= ConvertToMask(socket); + static void Set(FdSet &sceFdSetBits, int socket) { + sceFdSetBits.mFdsBits[Position(socket)] |= ConvertToMask(socket); } - static bool IsSet(const FdSet *sceFdSetBits, int socket) { - return (sceFdSetBits->mFdsBits[Position(socket)] & ConvertToMask(socket)) != 0; + static bool IsSet(const FdSet &sceFdSetBits, int socket) { + return (sceFdSetBits.mFdsBits[Position(socket)] & ConvertToMask(socket)) != 0; } - static void Clear(FdSet *sceFdSetBits, int socket) { - sceFdSetBits->mFdsBits[Position(socket)] &= ~ConvertToMask(socket); + static void Clear(FdSet &sceFdSetBits, int socket) { + sceFdSetBits.mFdsBits[Position(socket)] &= ~ConvertToMask(socket); } - static void Zero(FdSet *sceFdSetBits) { - memset(sceFdSetBits->mFdsBits, 0, sizeof(FdSet)); + static void Zero(FdSet &sceFdSetBits) { + memset(sceFdSetBits.mFdsBits, 0, sizeof(FdSet)); } private: @@ -110,29 +141,22 @@ private: } }; -// static int getLastPlatformError() { -// #if PPSSPP_PLATFORM(WINDOWS) -// return WSAGetLastError(); -// #else -// return errno; -// #endif -// } - -static bool sceSockaddrToNativeSocketAddr(sockaddr_in &dest, u32 sockAddrInternetPtr, size_t addressLength) { - const auto sceNetSockaddrIn = Memory::GetTypedPointerRange(sockAddrInternetPtr, addressLength); - if (sceNetSockaddrIn == nullptr || addressLength == 0) { +static bool inetSockaddrToNativeSocketAddr(sockaddr_in &dest, u32 sockAddrInternetPtr, size_t addressLength) { + const auto inetSockaddrIn = Memory::GetTypedPointerRange(sockAddrInternetPtr, addressLength); + if (inetSockaddrIn == nullptr || addressLength == 0) { return false; } + // Clear dest of any existing data and copy relevant fields from inet sockaddr_in memset(&dest, 0, sizeof(dest)); - dest.sin_family = sceNetSockaddrIn->sin_family; - dest.sin_port = sceNetSockaddrIn->sin_port; - dest.sin_addr.s_addr = sceNetSockaddrIn->sin_addr; - DEBUG_LOG(SCENET, "sceSockaddrToNativeSocketAddr: Family %i, port %i, addr %s, len %i", dest.sin_family, ntohs(dest.sin_port), ip2str(dest.sin_addr, false).c_str(), sceNetSockaddrIn->sin_len); + dest.sin_family = inetSockaddrIn->sin_family; + dest.sin_port = inetSockaddrIn->sin_port; + dest.sin_addr.s_addr = inetSockaddrIn->sin_addr; + DEBUG_LOG(SCENET, "sceSockaddrToNativeSocketAddr: Family %i, port %i, addr %s, len %i", dest.sin_family, ntohs(dest.sin_port), ip2str(dest.sin_addr, false).c_str(), inetSockaddrIn->sin_len); return true; } -static bool writeSockAddrInToSceSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, sockaddr_in src) { +static bool writeSockAddrInToInetSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, sockaddr_in src) { const auto sceNetSocklenPtr = reinterpret_cast(Memory::GetPointerWrite(destAddrLenPtr)); u32 sceNetSocklen = 0; if (sceNetSocklenPtr != nullptr) { @@ -142,7 +166,7 @@ static bool writeSockAddrInToSceSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, so if (sceNetSockaddrIn == nullptr) { return false; } - INFO_LOG(SCENET, "writeSockAddrInToSceSockAddr: %lu vs %i", sizeof(SceNetInetSockaddrIn), sceNetSocklen); + DEBUG_LOG(SCENET, "writeSockAddrInToSceSockAddr: %lu vs %i", sizeof(SceNetInetSockaddrIn), sceNetSocklen); if (sceNetSocklenPtr) { *sceNetSocklenPtr = std::min(sceNetSocklen, sizeof(SceNetInetSockaddr)); } @@ -196,16 +220,25 @@ static int sceNetInetSocket(int domain, int type, int protocol) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const int nativeSocketId = socket(domain, type, protocol); - const auto sceSocket = sceNetInet->CreateAndAssociateSceSocket(nativeSocketId); + // TODO: translate domain, type and protocol if applicable - if (!sceSocket) { - close(nativeSocketId); - sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new SceSocket for native socket id %i, closing", __func__, nativeSocketId); + // Attempt to open socket + const int nativeSocketId = socket(domain, type, protocol); + if (nativeSocketId < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, -1, "%s: Unable to open socket(%i, %i, %i) with error %i: %s", __func__, domain, type, protocol, error, strerror(error)); } - return sceSocket->GetSceSocketId(); + // Map opened socket to an inet socket which is 1-indexed + const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId); + + // Close opened socket if such a socket exists + if (!inetSocket) { + close(nativeSocketId); + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new InetSocket for native socket id %i, closing", __func__, nativeSocketId); + } + return inetSocket->GetInetSocketId(); } static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optvalPtr, u32 optlenPtr) { @@ -216,23 +249,23 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { - sceNetInet->SetLastError(EFAULT); + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { + sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - if (!sceSocket->IsSockoptNameAllowed(inetOptname)) { + if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); } - const auto optname = SceSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); + const auto optname = InetSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); if (optname != inetOptname) { DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); } - const auto nativeSocketId = sceSocket->GetNativeSocketId(); + const auto nativeSocketId = inetSocket->GetNativeSocketId(); #if PPSSPP_PLATFORM(WINDOWS) auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); @@ -250,7 +283,8 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range %08x (size %i)", nativeSocketId, __func__, optvalPtr, *optlen); } - // TODO: implement non-blocking sockopt + // TODO: implement non-blocking getsockopt + // TODO: implement SOL const int ret = getsockopt(nativeSocketId, SOL_SOCKET, optname, optval, optlen); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); @@ -267,18 +301,20 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - if (!sceSocket->IsSockoptNameAllowed(inetOptname)) { + const auto nativeSocketId = inetSocket->GetNativeSocketId(); + + if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); + return hleLogError(SCENET, -1, "[%i] %s: Unknown optname %04x", nativeSocketId, __func__, inetOptname); } - const auto optname = SceSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); + const auto optname = InetSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); if (optname != inetOptname) { DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); } @@ -286,29 +322,38 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv // If optlens of != sizeof(u32) are created, split out the handling into separate functions for readability if (optlen != sizeof(u32)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "[%i]: %s: Unhandled optlen %i for optname %04x", sceSocket->GetNativeSocketId(), __func__, optlen, inetOptname); + return hleLogError(SCENET, -1, "[%i]: %s: Unhandled optlen %i for optname %04x", nativeSocketId, __func__, optlen, inetOptname); + } + + if (!Memory::IsValidAddress(optvalPtr)) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i]: %s: Invalid address %08x for optval", nativeSocketId, __func__, optvalPtr); } auto optval = Memory::Read_U32(optvalPtr); - const auto nativeSocketId = sceSocket->GetNativeSocketId(); - INFO_LOG(SCENET, "[%i] setsockopt_u32(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, level, optname, optval); + DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, level, optname, optval); switch (optname) { // Unmatched PSP functions - no direct equivalent case INET_SO_NONBLOCK: { const bool nonblocking = optval != 0; - sceSocket->SetNonBlocking(nonblocking); + inetSocket->SetNonBlocking(nonblocking); INFO_LOG(SCENET, "[%i] setsockopt_u32: Set non-blocking=%i", nativeSocketId, nonblocking); if (setBlockingMode(nativeSocketId, nonblocking) != 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "[%i] Failed to set to non-blocking: %i: %s", nativeSocketId, error, strerror(error)); + ERROR_LOG(SCENET, "[%i] %s: Failed to set to non-blocking with error %i: %s", nativeSocketId, __func__, error, strerror(error)); } return 0; } + // Functions with identical structs to native functions default: { INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, level, optname, optval, 4); - int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); + const int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, optname, optval, error, strerror(error)); + } return ret; } } @@ -322,19 +367,21 @@ static int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLen } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } + // Translate inet sockaddr to native sockaddr sockaddr_in convertedSockaddr{}; - if (!sceSockaddrToNativeSocketAddr(convertedSockaddr, sockAddrInternetPtr, addressLength)) { + if (!inetSockaddrToNativeSocketAddr(convertedSockaddr, sockAddrInternetPtr, addressLength)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Error translating sceSockaddr to native sockaddr", nativeSocketId, __func__); } DEBUG_LOG(SCENET, "[%i] sceNetInetConnect: Connecting to %s on %i", nativeSocketId, ip2str(convertedSockaddr.sin_addr, false).c_str(), ntohs(convertedSockaddr.sin_port)); + // Attempt to connect using translated sockaddr int ret = connect(nativeSocketId, reinterpret_cast(&convertedSockaddr), sizeof(convertedSockaddr)); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); @@ -351,16 +398,17 @@ static int sceNetInetListen(int socket, int backlog) { } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - // TODO: here + // Map PSP_NET_INET_SOMAXCONN (128) to platform SOMAXCONN if (backlog == PSP_NET_INET_SOMAXCONN) { backlog = SOMAXCONN; } + // Attempt to listen using either backlog, or SOMAXCONN as per above const int ret = listen(socket, backlog); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); @@ -378,23 +426,26 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } + // Attempt to accept a connection which will provide us with a sockaddrIn containing remote connection details sockaddr_in sockaddrIn{}; socklen_t socklen; - int ret = accept(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); + const int ret = accept(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); if (ret < 0) { - const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - if (error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { + // Ensure that ERROR_WHEN_NONBLOCKING_CALL_OCCURS is not mapped to an hleLogError + if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { hleLogError(SCENET, ret, "[%i] %s: Encountered error %i: %s", nativeSocketId, __func__, error, strerror(error)); } return ret; } - if (addrPtr != 0 && !writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + // Don't call writeSockAddrInToInetSockAddr when addrPtr is 0, otherwise do and send false to EFAULT + if (addrPtr != 0 && !writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { sceNetInet->SetLastError(EFAULT); hleLogError(SCENET, ret, "[%i] %s: Encountered error trying to write to addrPtr, probably invalid memory range", nativeSocketId, __func__); } @@ -472,23 +523,25 @@ static int sceNetInetSelect(int maxfd, u32 readFdsPtr, u32 writeFdsPtr, u32 exce return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } + // Translate all input fd_sets to native fd_sets. None of these will be nullptr and so this needs to be checked later. int recomputedMaxFd = 1; fd_set readFds; - sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, readFds, readFdsPtr); + sceNetInet->TranslateInetFdSetToNativeFdSet(recomputedMaxFd, readFds, readFdsPtr); fd_set writeFds; - sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, writeFds, writeFdsPtr); + sceNetInet->TranslateInetFdSetToNativeFdSet(recomputedMaxFd, writeFds, writeFdsPtr); fd_set exceptFds; - sceNetInet->TranslateSceFdSetToNativeFdSet(recomputedMaxFd, exceptFds, exceptFdsPtr); + sceNetInet->TranslateInetFdSetToNativeFdSet(recomputedMaxFd, exceptFds, exceptFdsPtr); + // Convert timeval when applicable timeval tv{}; if (timeoutPtr != 0) { - const auto sceTimeval = Memory::GetTypedPointerRange(timeoutPtr, sizeof(SceTimeval)); - if (sceTimeval != nullptr) { - tv.tv_sec = sceTimeval->tv_sec; - tv.tv_usec = sceTimeval->tv_usec; - DEBUG_LOG(SCENET, "sceNetInetSelect: Timeout seconds=%lu, useconds=%lu", tv.tv_sec, tv.tv_usec); + const auto inetTimeval = Memory::GetTypedPointerRange(timeoutPtr, sizeof(PspInetTimeval)); + if (inetTimeval != nullptr) { + tv.tv_sec = inetTimeval->tv_sec; + tv.tv_usec = inetTimeval->tv_usec; + DEBUG_LOG(SCENET, "%s: Timeout seconds=%lu, useconds=%lu", __func__, tv.tv_sec, tv.tv_usec); } else { - WARN_LOG(SCENET, "sceNetInetSelect: Encountered invalid timeout value, continuing anyway"); + WARN_LOG(SCENET, "%s: Encountered invalid timeout value, continuing anyway", __func__); } } @@ -496,11 +549,11 @@ static int sceNetInetSelect(int maxfd, u32 readFdsPtr, u32 writeFdsPtr, u32 exce const int ret = select(recomputedMaxFd, readFdsPtr != 0 ? &readFds : nullptr, writeFdsPtr != 0 ? &writeFds : nullptr, exceptFdsPtr != 0 ? &exceptFds : nullptr, timeoutPtr != 0 ? &tv : nullptr); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "sceNetInetSelect: Received error from select() %i: %s", error, strerror(error)); + ERROR_LOG(SCENET, "%s: Received error from select() %i: %s", __func__, error, strerror(error)); } - INFO_LOG(SCENET, "sceNetInetSelect: select() returned %i", ret); - return hleDelayResult(ret, "TODO: unhack", 300); + INFO_LOG(SCENET, "%s: select() returned %i", __func__, ret); + return hleDelayResult(ret, "TODO: unhack", 500); } static int sceNetInetClose(int socket) { @@ -509,16 +562,16 @@ static int sceNetInetClose(int socket) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EINVAL); return hleLogWarning(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); } - const int ret = close(sceSocket->GetNativeSocketId()); + const int ret = close(inetSocket->GetNativeSocketId()); if (!sceNetInet->EraseNativeSocket(socket)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "%s: Unable to clear mapping of sceSocketId->nativeSocketId, was there contention?", __func__); + return hleLogError(SCENET, -1, "%s: Unable to clear mapping of inetSocketId->nativeSocketId, was there contention?", __func__); } return ret; } @@ -553,20 +606,32 @@ static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } + if (hostname == nullptr) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "%s: Invalid hostname: %08x", __func__, hostname); + } + if (!Memory::IsValidAddress(addrPtr)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Invalid addrPtr: %08x", __func__, addrPtr); } + // Convert the input hostname into an inaddr in_addr inAddr{}; #if PPSSPP_PLATFORM(WINDOWS) + // Use inet_pton to accomplish the same behavior on Winsock2 which is missing inet_aton const int ret = inet_pton(AF_INET, hostname, &inAddr); #else const int ret = inet_aton(hostname, &inAddr); #endif - if (ret != 0) { - Memory::Write_U32(inAddr.s_addr, addrPtr); + + if (ret == 0) { + // inet_aton does not set errno when an error occurs, so neither should we + return hleLogError(SCENET, ret, "%s: Invalid hostname %s", __func__, hostname); } + + // Write back to addrPtr if ret is != 0 + Memory::Write_U32(inAddr.s_addr, addrPtr); return ret; } @@ -602,28 +667,29 @@ static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 return hleLogSuccessX(SCENET, dstBufPtr); } -static int sceNetInetInetPton(int addressFamily, const char *hostname, u32 dstBufPtr) { - WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, addressFamily, hostname, dstBufPtr); +static int sceNetInetInetPton(int addressFamily, const char *hostname, u32 dstPtr) { + WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, addressFamily, hostname, dstPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto srcSockaddrIn = Memory::GetTypedPointerWriteRange(srcPtr, sizeof(SceNetInetSockaddrIn)); - if (srcSockaddrIn == nullptr) { - return hleLogError(SCENET, 0, "%s: Invalid memory range for srcPtr %08x", __func__, srcPtr); + if (hostname == nullptr) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, 0, "%s: Invalid memory range for hostname %08x", __func__, hostname); } // IPv4, the only supported address family on PSP, will always be 32 bits - const auto dstBuf = Memory::GetTypedPointerWriteRange(dstBufPtr, sizeof(u32)); - if (dstBuf == nullptr) { - return hleLogError(SCENET, 0, "%s: Invalid memory range for dstBufPtr %08x, size %i", __func__, dstBufPtr, dstBufSize); + const auto dst = Memory::GetTypedPointerWriteRange(dstPtr, sizeof(u32)); + if (dst == nullptr) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, 0, "%s: Invalid memory range for dstPtr %08x, size %i", __func__, dstPtr, sizeof(u32)); } // TODO: convert address family // TODO: If af does not contain a valid address family, -1 is returned and errno is set to EAFNOSUPPORT. - const int ret = inet_pton(addressFamily, reinterpret_cast(srcSockaddrIn), dstBuf); + const int ret = inet_pton(addressFamily, hostname, dst); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); return hleLogError(SCENET, ret, "%s: inet_pton returned %i: %s", __func__, sceNetInet->GetLastError(), strerror(error)); @@ -639,7 +705,7 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { ERROR_LOG(SCENET, "%s: Requested socket %i which does not exist", __func__, socket); return -1; } @@ -647,7 +713,7 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { // Write PSP sockaddr to native sockaddr in preparation of getpeername sockaddr_in sockaddrIn{}; socklen_t socklen = sizeof(sockaddr_in); - if (!sceSockaddrToNativeSocketAddr(sockaddrIn, addrPtr, addrLenPtr)) { + if (!inetSockaddrToNativeSocketAddr(sockaddrIn, addrPtr, addrLenPtr)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i]: %s: Encountered invalid addrPtr %08x and/or invalid addrLenPtr %08x", nativeSocketId, addrPtr, addrLenPtr); } @@ -658,7 +724,8 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { return hleLogError(SCENET, ret, "[%i] %s: Failed to execute getpeername %i: %s", nativeSocketId, __func__, error, strerror(error)); } - if (!writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + // Write output of getpeername to the input addrPtr + if (!writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getpeername to SceNetInetSockaddrIn", nativeSocketId, __func__); } @@ -673,11 +740,12 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { } int nativeSocketId; - if (!sceNetInet->GetNativeSocketIdForSceSocketId(nativeSocketId, socket)) { - ERROR_LOG(SCENET, "%s: Requested socket %i which does not exist", __func__, socket); - return -1; + if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "%s: Requested socket %i which does not exist", __func__, socket); } + // Set sockaddrIn to the result of getsockname sockaddr_in sockaddrIn{}; socklen_t socklen = sizeof(sockaddr_in); const int ret = getsockname(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); @@ -686,7 +754,9 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { return hleLogError(SCENET, ret, "[%i] %s: Failed to execute getsockname %i: %s", nativeSocketId, __func__, error, strerror(error)); } - if (!writeSockAddrInToSceSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + // Write output of getsockname to the input addrPtr + if (!writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { + sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId, __func__); } return ret; @@ -699,23 +769,24 @@ static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { - WARN_LOG(SCENET, "sceNetInetClose: Attempting to close socket %i which does not exist", socket); + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { + WARN_LOG(SCENET, "%s: Attempting to close socket %i which does not exist", __func__, socket); return -1; } + const auto nativeSocketId = inetSocket->GetNativeSocketId(); const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); if (dstBuf == nullptr) { - return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "sceNetInetRecv: Invalid pointer %08x (size %i)", bufPtr, bufLen); + return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); } - // TODO: debug log the API calls - const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); - - const int ret = recv(sceSocket->GetNativeSocketId(), dstBuf, bufLen, nativeFlags); + const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); + const int ret = recv(nativeSocketId, dstBuf, bufLen, nativeFlags); + DEBUG_LOG(SCENET, "[%i] %s: Called recv with buf size %i which returned %i", nativeSocketId, __func__, bufLen, ret); if (ret < 0) { - if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { + if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { ERROR_LOG(SCENET, "[%i]: %s: recv() encountered error %i: %s", socket, __func__, error, strerror(error)); } } @@ -729,65 +800,66 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - const auto nativeSocketId = sceSocket->GetNativeSocketId(); + const auto nativeSocketId = inetSocket->GetNativeSocketId(); const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); if (dstBuf == nullptr) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); } - const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); + // Translate PSP flags to native flags and prepare sockaddrIn to receive peer address + const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); sockaddr_in sockaddrIn{}; socklen_t socklen = sizeof(sockaddr_in); Memory::Memset(bufPtr, 0, bufLen, __func__); const int ret = recvfrom(nativeSocketId, dstBuf, bufLen, nativeFlags, reinterpret_cast(&sockaddrIn), &socklen); - if (ret < 0) { if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); error != 0 && error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { - WARN_LOG(SCENET, "[%i] sceNetInetRecvfrom: Received error %i: %s", nativeSocketId, error, strerror(error)); + WARN_LOG(SCENET, "[%i] %s: Received error %i: %s", nativeSocketId, __func__, error, strerror(error)); } return hleDelayResult(ret, "TODO: unhack", 500); } + // If ret was successful, write peer sockaddr to input fromAddr if (ret > 0) { - if (!writeSockAddrInToSceSockAddr(fromAddr, fromLenAddr, sockaddrIn)) { - ERROR_LOG(SCENET, "[%i] sceNetInetRecvfrom: Error writing native sockaddr to sceSockaddr", nativeSocketId); + if (!writeSockAddrInToInetSockAddr(fromAddr, fromLenAddr, sockaddrIn)) { + ERROR_LOG(SCENET, "[%i] %s: Error writing native sockaddr to sceSockaddr", nativeSocketId, __func__); } - INFO_LOG(SCENET, "[%i] sceNetInetRecvfrom: Got %i bytes from recvfrom", nativeSocketId, ret); + INFO_LOG(SCENET, "[%i] %s: Got %i bytes from recvfrom", nativeSocketId, __func__, ret); } return hleDelayResult(ret, "TODO: unhack", 500); } static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { - WARN_LOG_ONCE(sceNetInetSend, SCENET, "UNTESTED sceNetInetSend(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); + WARN_LOG_ONCE(sceNetInetSend, SCENET, "UNTESTED %s(%i, %08x, %i, %08x)", __func__, socket, bufPtr, bufLen, flags); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - const auto resolvedPtr = Memory::GetTypedPointerRange(bufPtr, bufLen); - if (resolvedPtr == nullptr) { + const auto buf = Memory::GetTypedPointerRange(bufPtr, bufLen); + if (buf == nullptr) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", socket, __func__, bufPtr, bufLen); } - const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); - - const int ret = send(sceSocket->GetNativeSocketId(), resolvedPtr, bufLen, nativeFlags); + // Translate PSP flags to native flags and send + const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); + const int ret = send(inetSocket->GetNativeSocketId(), buf, bufLen, nativeFlags); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); return hleLogError(SCENET, ret, "[%i]: %s: send() encountered error %i: %s", socket, __func__, error, strerror(error)); @@ -802,35 +874,35 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - const int nativeSocketId = sceSocket->GetNativeSocketId(); + const int nativeSocketId = inetSocket->GetNativeSocketId(); const auto srcBuf = Memory::GetTypedPointerRange(bufPtr, bufLen); if (srcBuf == nullptr) { - ERROR_LOG(SCENET, "[%i] sceNetInetSendto: Invalid pointer range: %08x (size %i)", socket, bufPtr, bufLen); + ERROR_LOG(SCENET, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); return -1; } - const int nativeFlags = sceSocket->TranslateInetFlagsToNativeFlags(flags); + // Translate PSP flags to native flags and convert toAddr to native addr + const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); sockaddr_in convertedSockAddr{}; - if (!sceSockaddrToNativeSocketAddr(convertedSockAddr, toAddr, toLen)) { - ERROR_LOG(SCENET, "[%i] sceNetInetSendto: Unable to translate sceSockAddr to native sockaddr", nativeSocketId); + if (!inetSockaddrToNativeSocketAddr(convertedSockAddr, toAddr, toLen)) { + ERROR_LOG(SCENET, "[%i] %s: Unable to translate sceSockAddr to native sockaddr", nativeSocketId, __func__); return -1; } - // TODO: improve debug log - DEBUG_LOG(SCENET, "[%i] sceNetInetSendto: Writing %i bytes to %s on port %i", nativeSocketId, bufLen, ip2str(convertedSockAddr.sin_addr, false).c_str(), ntohs(convertedSockAddr.sin_port)); + DEBUG_LOG(SCENET, "[%i] %s: Writing %i bytes to %s on port %i", nativeSocketId, __func__, bufLen, ip2str(convertedSockAddr.sin_addr, false).c_str(), ntohs(convertedSockAddr.sin_port)); const int ret = sendto(nativeSocketId, srcBuf, bufLen, nativeFlags, reinterpret_cast(&convertedSockAddr), sizeof(sockaddr_in)); - DEBUG_LOG(SCENET, "[%i] sceNetInetSendto: sendto returned %i", nativeSocketId, ret); + DEBUG_LOG(SCENET, "[%i] %s: sendto returned %i", nativeSocketId, __func__, ret); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - WARN_LOG(SCENET, "[%i] sceNetInetSendto: Got error %i=%s", nativeSocketId, error, strerror(error)); + WARN_LOG(SCENET, "[%i] %s: Got error %i=%s", nativeSocketId, __func__, error, strerror(error)); } return ret; @@ -845,11 +917,10 @@ static int sceNetInetGetErrno() { const auto nativeError = sceNetInet->GetLastError(); if (nativeError != ERROR_WHEN_NONBLOCKING_CALL_OCCURS && nativeError != 0) { - INFO_LOG(SCENET, "Requested sceNetInetGetErrno %i=%s", nativeError, strerror(nativeError)); + INFO_LOG(SCENET, "Requested %s %i=%s", __func__, nativeError, strerror(nativeError)); } - // TODO: consider moving below function to SceNetInet - return SceSocket::TranslateNativeErrorToInetError(nativeError); + return InetSocket::TranslateNativeErrorToInetError(nativeError); } static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { @@ -859,17 +930,17 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - const auto sceSocket = sceNetInet->GetSceSocket(socket); - if (!sceSocket) { + const auto inetSocket = sceNetInet->GetInetSocket(socket); + if (!inetSocket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } - const int nativeSocketId = sceSocket->GetNativeSocketId(); + const int nativeSocketId = inetSocket->GetNativeSocketId(); #if PPSSPP_PLATFORM(LINUX) // Set broadcast - // TODO: move broadcast SceSocket + // TODO: move broadcast InetSocket int broadcastEnabled = 1; int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, &broadcastEnabled, sizeof(broadcastEnabled)); @@ -882,15 +953,16 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #elif PPSSPP_PLATFORM(WINDOWS) // Set broadcast - // TODO: move broadcast SceSocket + // TODO: move broadcast InetSocket int broadcastEnabled = 1; int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&broadcastEnabled), sizeof(broadcastEnabled)); int opt = 1; setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)); #endif + // Convert PSP bind addr to native bind addr sockaddr_in convertedSockaddr{}; - if (!sceSockaddrToNativeSocketAddr(convertedSockaddr, addrPtr, addrLen)) { + if (!inetSockaddrToNativeSocketAddr(convertedSockaddr, addrPtr, addrLen)) { ERROR_LOG(SCENET, "[%i] Error translating sceSockaddr to native sockaddr", nativeSocketId); return -1; } @@ -909,11 +981,11 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { INFO_LOG(SCENET, "[%i] Binding to family %i, port %i, addr %s sockoptRet %i", nativeSocketId, convertedSockaddr.sin_family, ntohs(convertedSockaddr.sin_port), ip2str(convertedSockaddr.sin_addr, false).c_str(), sockoptRet); const int ret = bind(nativeSocketId, reinterpret_cast(&convertedSockaddr), socklen); INFO_LOG(SCENET, "Bind returned %i for fd=%i", ret, nativeSocketId); - setBlockingMode(nativeSocketId, sceSocket->IsNonBlocking()); + setBlockingMode(nativeSocketId, inetSocket->IsNonBlocking()); // Set UPnP const auto port = ntohs(convertedSockaddr.sin_port); - switch (sceSocket->GetProtocol()) { + switch (inetSocket->GetProtocol()) { case INET_PROTOCOL_TCP: { UPnP_Add(IP_PROTOCOL_TCP, port, port); break; @@ -922,8 +994,9 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { UPnP_Add(IP_PROTOCOL_UDP, port, port); break; } + // TODO: Unknown IP protocol 000f when attempting to set up UPnP port forwarding default: { - WARN_LOG(SCENET, "[%i]: Unknown IP protocol %04x when attempting to set up UPnP port forwarding", nativeSocketId, sceSocket->GetProtocol()); + WARN_LOG(SCENET, "[%i]: Unknown IP protocol %04x when attempting to set up UPnP port forwarding", nativeSocketId, inetSocket->GetProtocol()); break; } } @@ -958,12 +1031,12 @@ const HLEFunction sceNetInet[] = { {0XD0792666, &WrapU_IUUU, "sceNetInetInetNtop", '?', "" }, {0XE30B8C19, &WrapI_ICU, "sceNetInetInetPton", '?', "" }, {0X8CA3A97E, nullptr, "sceNetInetGetPspError", '?', "" }, - {0XE247B6D6, &WrapI_IUU,"sceNetInetGetpeername", '?', "" }, + {0XE247B6D6, &WrapI_IUU, "sceNetInetGetpeername", '?', "" }, {0X162E6FD5, &WrapI_IUU, "sceNetInetGetsockname", '?', "" }, {0X80A21ABD, nullptr, "sceNetInetSocketAbort", '?', "" }, {0X39B0C7D3, nullptr, "sceNetInetGetUdpcbstat", '?', "" }, {0XB3888AD4, nullptr, "sceNetInetGetTcpcbstat", '?', "" }, -}; +};; std::shared_ptr SceNetInet::gInstance; std::shared_mutex SceNetInet::gLock; @@ -997,7 +1070,6 @@ void SceNetInet::SetLastError(const int error) { mLastError = error; } -// TODO: ensure this is applied to every function int SceNetInet::SetLastErrorToMatchPlatform() { int error; #if PPSSPP_PLATFORM(WINDOWS) @@ -1009,77 +1081,75 @@ int SceNetInet::SetLastErrorToMatchPlatform() { return error; } -std::shared_ptr SceNetInet::CreateAndAssociateSceSocket(int nativeSocketId) { +std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId) { auto lock = std::unique_lock(mLock); - int sceSocketId = ++mCurrentSceSocketId; - if (const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); it != mSceSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to re-associate socket from already-associated sceSocketId: %i", __func__, sceSocketId); + int inetSocketId = ++mCurrentInetSocketId; + if (const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); it != mInetSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to re-associate socket from already-associated inetSocketId: %i", __func__, inetSocketId); return nullptr; } - auto sceSocket = std::make_shared(sceSocketId, nativeSocketId); - mSceSocketIdToNativeSocket.emplace(sceSocketId, sceSocket); - return sceSocket; + auto inetSocket = std::make_shared(inetSocketId, nativeSocketId); + mInetSocketIdToNativeSocket.emplace(inetSocketId, inetSocket); + return inetSocket; } -std::shared_ptr SceNetInet::GetSceSocket(int sceSocketId) { +std::shared_ptr SceNetInet::GetInetSocket(int inetSocketId) { auto lock = std::shared_lock(mLock); - const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); - if (it == mSceSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to get unassociated socket from sceSocketId: %i", __func__, sceSocketId); + const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); + if (it == mInetSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to get unassociated socket from inetSocketId: %i", __func__, inetSocketId); return nullptr; } return it->second; } -bool SceNetInet::GetNativeSocketIdForSceSocketId(int& nativeSocketId, int sceSocketId) { - const auto sceSocket = GetSceSocket(sceSocketId); - if (!sceSocket) +bool SceNetInet::GetNativeSocketIdForInetSocketId(int& nativeSocketId, int inetSocketId) { + const auto inetSocket = GetInetSocket(inetSocketId); + if (!inetSocket) return false; - nativeSocketId = sceSocket->GetNativeSocketId(); + nativeSocketId = inetSocket->GetNativeSocketId(); return true; } -bool SceNetInet::EraseNativeSocket(int sceSocketId) { +bool SceNetInet::EraseNativeSocket(int inetSocketId) { auto lock = std::unique_lock(mLock); - const auto it = mSceSocketIdToNativeSocket.find(sceSocketId); - if (it == mSceSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to delete unassociated socket from sceSocketId: %i", __func__, sceSocketId); + const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); + if (it == mInetSocketIdToNativeSocket.end()) { + WARN_LOG(SCENET, "%s: Attempted to delete unassociated socket from inetSocketId: %i", __func__, inetSocketId); return false; } - mSceSocketIdToNativeSocket.erase(it); + mInetSocketIdToNativeSocket.erase(it); return true; } -bool SceNetInet::TranslateSceFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, u32 fdsPtr) const { +bool SceNetInet::TranslateInetFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, u32 fdsPtr) const { if (fdsPtr == 0) { // Allow nullptr to be used without failing return true; } FD_ZERO(&destFdSet); - const auto sceFdSet = Memory::GetTypedPointerRange(fdsPtr, sizeof(SceFdSetOperations::FdSet)); + const auto sceFdSet = Memory::GetTypedPointerRange(fdsPtr, sizeof(PspInetFdSetOperations::FdSet)); if (sceFdSet == nullptr) { ERROR_LOG(SCENET, "%s: Invalid fdsPtr %08x", __func__, fdsPtr); return false; } int setSize = 0; - for (auto& it : mSceSocketIdToNativeSocket) { - const auto sceSocket = it.first; + for (auto& it : mInetSocketIdToNativeSocket) { + const auto inetSocket = it.first; const auto nativeSocketId = it.second->GetNativeSocketId(); - if (nativeSocketId + 1 > maxFd) { - maxFd = nativeSocketId + 1; - } - if (SceFdSetOperations::IsSet(sceFdSet, sceSocket)) { + maxFd = std::max(nativeSocketId + 1, maxFd); + if (PspInetFdSetOperations::IsSet(*sceFdSet, inetSocket)) { if (++setSize > FD_SETSIZE) { ERROR_LOG(SCENET, "%s: Encountered input FD_SET which is greater than max supported size %i", __func__, setSize); return false; } - DEBUG_LOG(SCENET, "%s: Translating input %i into %i", __func__, sceSocket, nativeSocketId); + DEBUG_LOG(SCENET, "%s: Translating input %i into %i", __func__, inetSocket, nativeSocketId); FD_SET(nativeSocketId, &destFdSet); } } @@ -1089,14 +1159,13 @@ bool SceNetInet::TranslateSceFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, u } void SceNetInet::CloseAllRemainingSockets() const { - for (auto& it : mSceSocketIdToNativeSocket) { - if (!it.second) { - continue; + for (const auto &[first, second] : mInetSocketIdToNativeSocket) { + if (second) { + close(second->GetNativeSocketId()); } - close(it.second->GetNativeSocketId()); } } void Register_sceNetInet() { - RegisterModule("sceNetInet", ARRAY_SIZE(sceNetInet), sceNetInet); + RegisterModule("sceNetInet", std::size(sceNetInet), sceNetInet); } diff --git a/Core/HLE/sceNetInet.h b/Core/HLE/sceNetInet.h index db2301e303..584ec77109 100644 --- a/Core/HLE/sceNetInet.h +++ b/Core/HLE/sceNetInet.h @@ -1,7 +1,7 @@ #pragma once #include "Core/HLE/HLE.h" -#include "Core/Net/SceSocket.h" +#include "Core/Net/InetSocket.h" #if PPSSPP_PLATFORM(WINDOWS) #include @@ -11,6 +11,28 @@ #include #include +// Sockaddr +typedef struct SceNetInetSockaddr { + uint8_t sa_len; + uint8_t sa_family; + uint8_t sa_data[14]; +} PACK SceNetInetSockaddr; + +// Sockaddr_in +typedef struct SceNetInetSockaddrIn { + uint8_t sin_len; + uint8_t sin_family; + u16_le sin_port; //uint16_t + u32_le sin_addr; //uint32_t + uint8_t sin_zero[8]; +} PACK SceNetInetSockaddrIn; + +// Polling Event Field +typedef struct SceNetInetPollfd { //similar format to pollfd in 32bit (pollfd in 64bit have different size) + s32_le fd; + s16_le events; + s16_le revents; +} PACK SceNetInetPollfd; enum { // pspnet_inet @@ -40,11 +62,11 @@ public: int GetLastError(); void SetLastError(int error); int SetLastErrorToMatchPlatform(); - std::shared_ptr CreateAndAssociateSceSocket(int nativeSocketId); - std::shared_ptr GetSceSocket(int sceSocketId); - bool GetNativeSocketIdForSceSocketId(int &nativeSocketId, int sceSocketId); - bool EraseNativeSocket(int sceSocketId); - bool TranslateSceFdSetToNativeFdSet(int& maxFd, fd_set &destFdSet, u32 fdsPtr) const; + std::shared_ptr CreateAndAssociateInetSocket(int nativeSocketId); + std::shared_ptr GetInetSocket(int inetSocketId); + bool GetNativeSocketIdForInetSocketId(int &nativeSocketId, int inetSocketId); + bool EraseNativeSocket(int inetSocketId); + bool TranslateInetFdSetToNativeFdSet(int& maxFd, fd_set &destFdSet, u32 fdsPtr) const; private: void CloseAllRemainingSockets() const; @@ -53,8 +75,8 @@ private: static std::shared_mutex gLock; int mLastError = 0; - std::unordered_map> mSceSocketIdToNativeSocket; - int mCurrentSceSocketId = 0; + std::unordered_map> mInetSocketIdToNativeSocket; + int mCurrentInetSocketId = 0; std::shared_mutex mLock; }; diff --git a/Core/HLE/sceNetResolver.cpp b/Core/HLE/sceNetResolver.cpp index df2bc483f1..970dafee58 100644 --- a/Core/HLE/sceNetResolver.cpp +++ b/Core/HLE/sceNetResolver.cpp @@ -54,7 +54,7 @@ #include "Core/HLE/sceNp.h" #include "Core/Reporting.h" #include "Core/Instance.h" -#include "Core/Net/SceSocket.h" +#include "Core/Net/InetSocket.h" #if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE) // Missing toolchain define @@ -62,7 +62,7 @@ #endif static int sceNetResolverInit() { - ERROR_LOG(SCENET, "UNTESTED %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNTESTED %s()", __FUNCTION__); g_Config.mHostToAlias["socomftb2.psp.online.scea.com"] = "67.222.156.250"; g_Config.mHostToAlias["socompsp-prod.muis.pdonline.scea.com"] = "67.222.156.250"; SceNetResolver::Init(); @@ -70,7 +70,7 @@ static int sceNetResolverInit() { } static int sceNetResolverTerm() { - ERROR_LOG(SCENET, "UNTESTED %s()", __FUNCTION__); + ERROR_LOG(Log::sceNet, "UNTESTED %s()", __FUNCTION__); SceNetResolver::Shutdown(); return 0; } @@ -79,13 +79,13 @@ static int sceNetResolverTerm() { int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { auto sceNetResolver = SceNetResolver::Get(); if (!sceNetResolver) { - return hleLogError(SCENET, ERROR_NET_RESOLVER_STOPPED, "Net Resolver Subsystem Shutdown: Resolver %i", + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Net Resolver Subsystem Shutdown: Resolver %i", resolverId); } const auto resolver = sceNetResolver->GetNetResolver(resolverId); if (resolver == nullptr) { - return hleLogError(SCENET, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); } addrinfo* resolved = nullptr; @@ -99,14 +99,14 @@ int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int ti // Resolve any aliases if (g_Config.mHostToAlias.find(hostname) != g_Config.mHostToAlias.end()) { const std::string& alias = g_Config.mHostToAlias[hostname]; - INFO_LOG(SCENET, "%s - Resolved alias %s from hostname %s", __FUNCTION__, alias.c_str(), hostname.c_str()); + INFO_LOG(Log::sceNet, "%s - Resolved alias %s from hostname %s", __FUNCTION__, alias.c_str(), hostname.c_str()); hostname = alias; } // Attempt to execute a DNS resolution if (!net::DNSResolve(hostname, "", &resolved, err)) { // TODO: Return an error based on the outputted "err" (unfortunately it's already converted to string) - return hleLogError(SCENET, ERROR_NET_RESOLVER_INVALID_HOST, "DNS Error Resolving %s (%s)\n", hostname.c_str(), + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_HOST, "DNS Error Resolving %s (%s)\n", hostname.c_str(), err.c_str()); } @@ -122,7 +122,7 @@ int NetResolver_StartNtoA(u32 resolverId, u32 hostnamePtr, u32 inAddrPtr, int ti net::DNSResolveFree(resolved); Memory::Write_U32(addr.in.sin_addr.s_addr, inAddrPtr); - INFO_LOG(SCENET, "%s - Hostname: %s => IPv4: %s", __FUNCTION__, hostname.c_str(), + INFO_LOG(Log::sceNet, "%s - Hostname: %s => IPv4: %s", __FUNCTION__, hostname.c_str(), ip2str(addr.in.sin_addr, false).c_str()); } @@ -141,20 +141,20 @@ static int sceNetResolverStartNtoA(int resolverId, u32 hostnamePtr, u32 inAddrPt } static int sceNetResolverStartNtoAAsync(int resolverId, u32 hostnamePtr, u32 inAddrPtr, int timeout, int retry) { - ERROR_LOG_REPORT_ONCE(sceNetResolverStartNtoAAsync, SCENET, "UNIMPL %s(%d, %08x, %08x, %d, %d) at %08x", + ERROR_LOG_REPORT_ONCE(sceNetResolverStartNtoAAsync, Log::sceNet, "UNIMPL %s(%d, %08x, %08x, %d, %d) at %08x", __FUNCTION__, resolverId, hostnamePtr, inAddrPtr, timeout, retry, currentMIPS->pc); return NetResolver_StartNtoA(resolverId, hostnamePtr, inAddrPtr, timeout, retry); } static int sceNetResolverPollAsync(int resolverId, u32 unknown) { - ERROR_LOG_REPORT_ONCE(sceNetResolverPollAsync, SCENET, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, + ERROR_LOG_REPORT_ONCE(sceNetResolverPollAsync, Log::sceNet, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, unknown, currentMIPS->pc); // TODO: Implement after confirming that this returns the state of resolver.isRunning return 0; } static int sceNetResolverWaitAsync(int resolverId, u32 unknown) { - ERROR_LOG_REPORT_ONCE(sceNetResolverWaitAsync, SCENET, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, + ERROR_LOG_REPORT_ONCE(sceNetResolverWaitAsync, Log::sceNet, "UNIMPL %s(%d, %08x) at %08x", __FUNCTION__, resolverId, unknown, currentMIPS->pc); // TODO: Implement after confirming that this blocks current thread until resolver.isRunning flips to false return 0; @@ -162,7 +162,7 @@ static int sceNetResolverWaitAsync(int resolverId, u32 unknown) { static int sceNetResolverStartAtoN(int resolverId, u32 inAddr, u32 hostnamePtr, int hostnameLength, int timeout, int retry) { - ERROR_LOG_REPORT_ONCE(sceNetResolverStartAtoN, SCENET, "UNIMPL %s(%d, %08x[%s], %08x, %i, %i, %i) at %08x", + ERROR_LOG_REPORT_ONCE(sceNetResolverStartAtoN, Log::sceNet, "UNIMPL %s(%d, %08x[%s], %08x, %i, %i, %i) at %08x", __FUNCTION__, resolverId, inAddr, ip2str(*(in_addr*)&inAddr, false).c_str(), hostnamePtr, hostnameLength, timeout, retry, currentMIPS->pc); // TODO: Implement via getnameinfo @@ -171,24 +171,24 @@ static int sceNetResolverStartAtoN(int resolverId, u32 inAddr, u32 hostnamePtr, static int sceNetResolverStartAtoNAsync(int resolverId, u32 inAddr, u32 hostnamePtr, int hostnameLength, int timeout, int retry) { - ERROR_LOG_REPORT_ONCE(sceNetResolverStartAtoNAsync, SCENET, "UNIMPL %s(%d, %08x[%s], %08x, %i, %i, %i) at %08x", + ERROR_LOG_REPORT_ONCE(sceNetResolverStartAtoNAsync, Log::sceNet, "UNIMPL %s(%d, %08x[%s], %08x, %i, %i, %i) at %08x", __FUNCTION__, resolverId, inAddr, ip2str(*(in_addr*)&inAddr, false).c_str(), hostnamePtr, hostnameLength, timeout, retry, currentMIPS->pc); return 0; } static int sceNetResolverCreate(u32 resolverIdPtr, u32 bufferPtr, int bufferLen) { - WARN_LOG(SCENET, "UNTESTED %s(%08x[%d], %08x, %d) at %08x", __FUNCTION__, resolverIdPtr, + WARN_LOG(Log::sceNet, "UNTESTED %s(%08x[%d], %08x, %d) at %08x", __FUNCTION__, resolverIdPtr, Memory::Read_U32(resolverIdPtr), bufferPtr, bufferLen, currentMIPS->pc); if (!Memory::IsValidRange(resolverIdPtr, 4)) - return hleLogError(SCENET, ERROR_NET_RESOLVER_INVALID_PTR, "Invalid Ptr: %08x", resolverIdPtr); + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_PTR, "Invalid Ptr: %08x", resolverIdPtr); if (Memory::IsValidRange(bufferPtr, 4) && bufferLen < 1) - return hleLogError(SCENET, ERROR_NET_RESOLVER_INVALID_BUFLEN, "Invalid Buffer Length: %i", bufferLen); + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_INVALID_BUFLEN, "Invalid Buffer Length: %i", bufferLen); auto sceNetResolver = SceNetResolver::Get(); if (!sceNetResolver) - return hleLogError(SCENET, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped"); + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped"); const auto resolver = sceNetResolver->CreateNetResolver(bufferPtr, bufferLen); @@ -199,33 +199,33 @@ static int sceNetResolverCreate(u32 resolverIdPtr, u32 bufferPtr, int bufferLen) static int sceNetResolverStop(u32 resolverId) { auto sceNetResolver = SceNetResolver::Get(); if (!sceNetResolver) { - return hleLogError(SCENET, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", resolverId); } const auto resolver = sceNetResolver->GetNetResolver(resolverId); - WARN_LOG(SCENET, "UNTESTED %s(%d) at %08x", __FUNCTION__, resolverId, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED %s(%d) at %08x", __FUNCTION__, resolverId, currentMIPS->pc); if (resolver == nullptr) - return hleLogError(SCENET, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); if (!resolver->GetIsRunning()) - return hleLogError(SCENET, ERROR_NET_RESOLVER_ALREADY_STOPPED, "Resolver Already Stopped (Id: %i)", resolverId); + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_ALREADY_STOPPED, "Resolver Already Stopped (Id: %i)", resolverId); resolver->SetIsRunning(false); return 0; } static int sceNetResolverDelete(u32 resolverId) { - WARN_LOG(SCENET, "UNTESTED %s(%d) at %08x", __FUNCTION__, resolverId, currentMIPS->pc); + WARN_LOG(Log::sceNet, "UNTESTED %s(%d) at %08x", __FUNCTION__, resolverId, currentMIPS->pc); auto sceNetResolver = SceNetResolver::Get(); if (!sceNetResolver) - return hleLogError(SCENET, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_STOPPED, "Resolver Subsystem Stopped (Resolver Id: %i)", resolverId); if (!sceNetResolver->DeleteNetResolver(resolverId)) - return hleLogError(SCENET, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); + return hleLogError(Log::sceNet, ERROR_NET_RESOLVER_BAD_ID, "Bad Resolver Id: %i", resolverId); return 0; } diff --git a/Core/Net/SceSocket.cpp b/Core/Net/InetSocket.cpp similarity index 68% rename from Core/Net/SceSocket.cpp rename to Core/Net/InetSocket.cpp index c155401f3b..945ecd077e 100644 --- a/Core/Net/SceSocket.cpp +++ b/Core/Net/InetSocket.cpp @@ -1,3 +1,3 @@ // TODO: remove me if the functions remain inlined -#include "SceSocket.h" +#include "InetSocket.h" diff --git a/Core/Net/SceSocket.h b/Core/Net/InetSocket.h similarity index 96% rename from Core/Net/SceSocket.h rename to Core/Net/InetSocket.h index 1110ca8bb1..1b1f458fc9 100644 --- a/Core/Net/SceSocket.h +++ b/Core/Net/InetSocket.h @@ -113,12 +113,12 @@ static std::unordered_map gNativeErrorCodeToInetErrorCode = }; // TODO: document -class SceSocket { +class InetSocket { public: - SceSocket(int sceSocketId, int nativeSocketId) : mSceSocketId(sceSocketId), mNativeSocketId(nativeSocketId) {} + InetSocket(int sceSocketId, int nativeSocketId) : mInetSocketId(sceSocketId), mNativeSocketId(nativeSocketId) {} - int GetSceSocketId() const { - return mSceSocketId; + int GetInetSocketId() const { + return mInetSocketId; } int GetNativeSocketId() const { @@ -185,6 +185,7 @@ public: return nativeFlags; } + // TODO: consider moving to SceNetInet static int TranslateNativeErrorToInetError(const int nativeError) { if (const auto it = gNativeErrorCodeToInetErrorCode.find(nativeError); it != gNativeErrorCodeToInetErrorCode.end()) { @@ -194,7 +195,7 @@ public: } private: - int mSceSocketId; + int mInetSocketId; int mNativeSocketId; Protocol mProtocol; bool mNonBlocking = false; From 7c342316ec894dc71354cb58d0378f65238dbe90 Mon Sep 17 00:00:00 2001 From: White Blood Cell Date: Wed, 27 Dec 2023 10:19:46 -0800 Subject: [PATCH 4/9] Fix bad formatting in CMakeLists. --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e55181ac92..c772d47e8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,9 +192,6 @@ if(USE_CCACHE) include(ccache) endif() -# TODO: stop hardcoding this before PR -# set(USING_QT_UI ON) - if(UNIX AND NOT (APPLE OR ANDROID) AND VULKAN) if(USING_X11_VULKAN) message("Using X11 for Vulkan") From 66b801c1ef96e47563ac07e41a9ce7fd76c8740e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 4 Jan 2025 18:02:53 +0100 Subject: [PATCH 5/9] Add to the rest of the build systems --- UWP/CoreUWP/CoreUWP.vcxproj | 12 +++++++++ UWP/CoreUWP/CoreUWP.vcxproj.filters | 39 +++++++++++++++++++++++++++++ android/jni/Android.mk | 6 +++++ libretro/Makefile.common | 6 +++++ 4 files changed, 63 insertions(+) diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index 36d298c658..4d60951372 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -177,6 +177,9 @@ + + + @@ -314,6 +317,9 @@ + + + @@ -433,6 +439,9 @@ + + + @@ -608,6 +617,9 @@ + + + diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters index d9483b71af..e6172e3d0f 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj.filters +++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters @@ -86,6 +86,9 @@ {1ad7ee67-c496-4709-bf98-cad322fe5d97} + + {4341253d-564e-490a-9780-179786e7ab2a} + @@ -1211,6 +1214,24 @@ Dialog + + HLE + + + HLE + + + HLE + + + Net + + + Net + + + Net + @@ -1909,6 +1930,24 @@ Dialog + + HLE + + + HLE + + + HLE + + + Net + + + Net + + + Net + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index a363969cf6..6d93211ad5 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -510,6 +510,9 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/MIPS/IR/IRNativeCommon.cpp \ $(SRC)/Core/MIPS/IR/IRPassSimplify.cpp \ $(SRC)/Core/MIPS/IR/IRRegCache.cpp \ + $(SRC)/Core/Net/InetCommon.cpp \ + $(SRC)/Core/Net/InetSocket.cpp \ + $(SRC)/Core/Net/NetResolver.cpp \ $(SRC)/GPU/Math3D.cpp \ $(SRC)/GPU/GPU.cpp \ $(SRC)/GPU/GPUCommon.cpp \ @@ -709,6 +712,9 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/HLE/proAdhocServer.cpp \ $(SRC)/Core/HLE/sceNetAdhoc.cpp \ $(SRC)/Core/HLE/sceNetAdhocMatching.cpp \ + $(SRC)/Core/HLE/sceNetApctl.cpp \ + $(SRC)/Core/HLE/sceNetInet.cpp \ + $(SRC)/Core/HLE/sceNetResolver.cpp \ $(SRC)/Core/HLE/sceOpenPSID.cpp \ $(SRC)/Core/HLE/sceP3da.cpp \ $(SRC)/Core/HLE/sceMt19937.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 7826895f91..008747f162 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -739,6 +739,9 @@ SOURCES_CXX += \ $(COREDIR)/HLE/sceNet.cpp \ $(COREDIR)/HLE/sceNetAdhoc.cpp \ $(COREDIR)/HLE/sceNetAdhocMatching.cpp \ + $(COREDIR)/HLE/sceNetApctl.cpp \ + $(COREDIR)/HLE/sceNetInet.cpp \ + $(COREDIR)/HLE/sceNetResolver.cpp \ $(COREDIR)/HLE/proAdhocServer.cpp \ $(COREDIR)/HLE/proAdhoc.cpp \ $(COREDIR)/HLE/sceOpenPSID.cpp \ @@ -811,6 +814,9 @@ SOURCES_CXX += \ $(COREDIR)/MemFault.cpp \ $(COREDIR)/MemMap.cpp \ $(COREDIR)/MemMapFunctions.cpp \ + $(COREDIR)/Net/InetCommon.cpp \ + $(COREDIR)/Net/InetSocket.cpp \ + $(COREDIR)/Net/NetResolver.cpp \ $(COREDIR)/PSPLoaders.cpp \ $(COREDIR)/Replay.cpp \ $(COREDIR)/Reporting.cpp \ From 4bc79481da69a015873be4ac178f5cb9e2d1abf8 Mon Sep 17 00:00:00 2001 From: White Blood Cell Date: Wed, 27 Dec 2023 11:46:35 -0800 Subject: [PATCH 6/9] Translate all input parameters to socket(). --- Core/HLE/sceNetInet.cpp | 278 +++++++++++++++++++++++++++++----------- Core/HLE/sceNetInet.h | 56 +++++++- 2 files changed, 258 insertions(+), 76 deletions(-) diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index 3291c068d4..8e272f1d84 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -203,34 +203,59 @@ static int setBlockingMode(int nativeSocketId, bool nonblocking) { } static int sceNetInetInit() { - ERROR_LOG(SCENET, "UNTESTED sceNetInetInit()"); - return SceNetInet::Init() ? 0 : ERROR_NET_INET_ALREADY_INITIALIZED; + ERROR_LOG(SCENET, "UNTESTED sceNetInetInit()"); + return SceNetInet::Init() ? 0 : ERROR_NET_INET_ALREADY_INITIALIZED; } int sceNetInetTerm() { - ERROR_LOG(SCENET, "UNTESTED sceNetInetTerm()"); + ERROR_LOG(SCENET, "UNTESTED sceNetInetTerm()"); SceNetInet::Shutdown(); - return 0; + return hleLogSuccessI(SCENET, 0); } -static int sceNetInetSocket(int domain, int type, int protocol) { - WARN_LOG_ONCE(sceNetInetSocket, SCENET, "UNTESTED sceNetInetSocket(%i, %i, %i)", domain, type, protocol); +static int sceNetInetSocket(int inetAddressFamily, int inetType, int inetProtocol) { + WARN_LOG_ONCE(sceNetInetSocket, SCENET, "UNTESTED sceNetInetSocket(%i, %i, %i)", inetAddressFamily, inetType, inetProtocol); auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } - // TODO: translate domain, type and protocol if applicable + // Translate address family, type, and protocol. There is some complexity around the type in particular where + // flags are able to be encoded in the most significant bits. + + int nativeAddressFamily; + if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { + sceNetInet->SetLastError(EAFNOSUPPORT); + return hleLogError(SCENET, -1, "%s: Unable to translate inet address family %i", __func__, inetAddressFamily); + } + + int nativeType; + bool nonBlocking; + if (!SceNetInet::TranslateInetSocketTypeToNative(nativeType, nonBlocking, inetType)) { + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "%s: Unable to translate inet type %08x", __func__, inetType); + } + + int nativeProtocol; + if (!SceNetInet::TranslateInetProtocolToNative(nativeProtocol, inetProtocol)) { + sceNetInet->SetLastError(EPROTONOSUPPORT); + return hleLogError(SCENET, -1, "%s: Unable to translate inet protocol %i", __func__, inetProtocol); + } // Attempt to open socket - const int nativeSocketId = socket(domain, type, protocol); + const int nativeSocketId = socket(nativeAddressFamily, nativeType, nativeProtocol); if (nativeSocketId < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, -1, "%s: Unable to open socket(%i, %i, %i) with error %i: %s", __func__, domain, type, protocol, error, strerror(error)); + return hleLogError(SCENET, -1, "%s: Unable to open socket(%i, %i, %i) with error %i: %s", __func__, nativeAddressFamily, nativeType, nativeProtocol, error, strerror(error)); } // Map opened socket to an inet socket which is 1-indexed - const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId); + const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId, nonBlocking); + + // Set non-blocking mode since the translation function does not translate non-blocking mode due to platform incompatibilities + if (nonBlocking) { + setBlockingMode(nativeSocketId, true); + } // Close opened socket if such a socket exists if (!inetSocket) { @@ -241,8 +266,8 @@ static int sceNetInetSocket(int domain, int type, int protocol) { return inetSocket->GetInetSocketId(); } -static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optvalPtr, u32 optlenPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetInetGetsockopt(%i, %i, %i, %08x, %08x)", socket, level, inetOptname, optvalPtr, optlenPtr); +static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname, u32 optvalPtr, u32 optlenPtr) { + WARN_LOG(SCENET, "UNTESTED sceNetInetGetsockopt(%i, %i, %i, %08x, %08x)", socket, inetSocketLevel, inetOptname, optvalPtr, optlenPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -255,6 +280,14 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } + const auto nativeSocketId = inetSocket->GetNativeSocketId(); + + int nativeSocketLevel; + if (!SceNetInet::TranslateInetSocketLevelToNative(nativeSocketLevel, inetSocketLevel)) { + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); + } + if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); @@ -265,8 +298,6 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); } - const auto nativeSocketId = inetSocket->GetNativeSocketId(); - #if PPSSPP_PLATFORM(WINDOWS) auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); #else @@ -283,18 +314,31 @@ static int sceNetInetGetsockopt(int socket, int level, int inetOptname, u32 optv return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range %08x (size %i)", nativeSocketId, __func__, optvalPtr, *optlen); } - // TODO: implement non-blocking getsockopt - // TODO: implement SOL - const int ret = getsockopt(nativeSocketId, SOL_SOCKET, optname, optval, optlen); - if (ret < 0) { - const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error)); + switch (optname) { + // No direct equivalents + case INET_SO_NONBLOCK: { + if (*optlen != sizeof(u32)) { + sceNetInet->SetLastError(EFAULT); + return hleLogError(SCENET, -1, "[%i] %s: Invalid optlen %i for INET_SO_NONBLOCK", nativeSocketId, __func__, *optlen); + } + Memory::Write_U32(optvalPtr, inetSocket->IsNonBlocking() ? 1 : 0); + return hleLogSuccessI(SCENET, 0); + } + // Direct 1:1 mappings + default: { + // TODO: implement non-blocking getsockopt + const int ret = getsockopt(nativeSocketId, nativeSocketLevel, optname, optval, optlen); + if (ret < 0) { + const auto error = sceNetInet->SetLastErrorToMatchPlatform(); + return hleLogError(SCENET, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error)); + } + return hleLogSuccessI(SCENET, ret); + } } - return ret; } -static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optvalPtr, int optlen) { - WARN_LOG_ONCE(sceNetInetSetsockopt, SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, level, inetOptname, optvalPtr, optlen); +static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname, u32 optvalPtr, int optlen) { + WARN_LOG_ONCE(sceNetInetSetsockopt, SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, inetSocketLevel, inetOptname, optvalPtr, optlen); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -309,6 +353,12 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv const auto nativeSocketId = inetSocket->GetNativeSocketId(); + int nativeSocketLevel; + if (!SceNetInet::TranslateInetSocketLevelToNative(nativeSocketLevel, inetSocketLevel)) { + sceNetInet->SetLastError(EINVAL); + return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); + } + if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { sceNetInet->SetLastError(EINVAL); return hleLogError(SCENET, -1, "[%i] %s: Unknown optname %04x", nativeSocketId, __func__, inetOptname); @@ -331,7 +381,7 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv } auto optval = Memory::Read_U32(optvalPtr); - DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, level, optname, optval); + DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, nativeSocketLevel, optname, optval); switch (optname) { // Unmatched PSP functions - no direct equivalent @@ -343,18 +393,18 @@ static int sceNetInetSetsockopt(int socket, int level, int inetOptname, u32 optv const auto error = sceNetInet->SetLastErrorToMatchPlatform(); ERROR_LOG(SCENET, "[%i] %s: Failed to set to non-blocking with error %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return 0; + return hleLogSuccessI(SCENET, 0); } // Functions with identical structs to native functions default: { - INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, level, optname, optval, 4); - const int ret = setsockopt(nativeSocketId, SOL_SOCKET, optname, reinterpret_cast(&optval), sizeof(optval)); + INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, nativeSocketLevel, optname, optval, 4); + const int ret = setsockopt(nativeSocketId, nativeSocketLevel, optname, reinterpret_cast(&optval), sizeof(optval)); INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); return hleLogError(SCENET, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, optname, optval, error, strerror(error)); } - return ret; + return hleLogSuccessI(SCENET, ret); } } } @@ -441,7 +491,7 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { hleLogError(SCENET, ret, "[%i] %s: Encountered error %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return ret; + return hleLogSuccessI(SCENET, ret); } // Don't call writeSockAddrInToInetSockAddr when addrPtr is 0, otherwise do and send false to EFAULT @@ -573,7 +623,7 @@ static int sceNetInetClose(int socket) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "%s: Unable to clear mapping of inetSocketId->nativeSocketId, was there contention?", __func__); } - return ret; + return hleLogSuccessI(SCENET, ret); } static u32 sceNetInetInetAddr(const char *hostname) { @@ -585,7 +635,6 @@ static u32 sceNetInetInetAddr(const char *hostname) { } in_addr inAddr{}; - // TODO: de-dupe #if PPSSPP_PLATFORM(WINDOWS) const int ret = inet_pton(AF_INET, hostname, &inAddr); #else @@ -595,7 +644,7 @@ static u32 sceNetInetInetAddr(const char *hostname) { sceNetInet->SetLastErrorToMatchPlatform(); return inAddr.s_addr; } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { @@ -632,11 +681,11 @@ static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { // Write back to addrPtr if ret is != 0 Memory::Write_U32(inAddr.s_addr, addrPtr); - return ret; + return hleLogSuccessI(SCENET, ret); } -static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 dstBufSize) { - WARN_LOG_ONCE(sceNetInetInetNtop, SCENET, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, addressFamily, srcPtr, dstBufPtr, dstBufSize); +static u32 sceNetInetInetNtop(int inetAddressFamily, u32 srcPtr, u32 dstBufPtr, u32 dstBufSize) { + WARN_LOG_ONCE(sceNetInetInetNtop, SCENET, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, inetAddressFamily, srcPtr, dstBufPtr, dstBufSize); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -660,15 +709,20 @@ static u32 sceNetInetInetNtop(int addressFamily, u32 srcPtr, u32 dstBufPtr, u32 return hleLogError(SCENET, 0, "%s: dstBufSize must be > 0", __func__); } - // TODO: convert address family - if (inet_ntop(addressFamily, reinterpret_cast(srcSockaddrIn), dstBuf, dstBufSize) == nullptr) { + int nativeAddressFamily; + if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { + sceNetInet->SetLastError(EAFNOSUPPORT); + return hleLogError(SCENET, 0, "%s: Unknown address family %04x", __func__, inetAddressFamily); + } + + if (inet_ntop(nativeAddressFamily, reinterpret_cast(srcSockaddrIn), dstBuf, dstBufSize) == nullptr) { // Allow partial output in case it's desired for some reason } return hleLogSuccessX(SCENET, dstBufPtr); } -static int sceNetInetInetPton(int addressFamily, const char *hostname, u32 dstPtr) { - WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, addressFamily, hostname, dstPtr); +static int sceNetInetInetPton(int inetAddressFamily, const char *hostname, u32 dstPtr) { + WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, inetAddressFamily, hostname, dstPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { @@ -687,9 +741,14 @@ static int sceNetInetInetPton(int addressFamily, const char *hostname, u32 dstPt return hleLogError(SCENET, 0, "%s: Invalid memory range for dstPtr %08x, size %i", __func__, dstPtr, sizeof(u32)); } - // TODO: convert address family - // TODO: If af does not contain a valid address family, -1 is returned and errno is set to EAFNOSUPPORT. - const int ret = inet_pton(addressFamily, hostname, dst); + // Translate inet address family to native + int nativeAddressFamily; + if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { + sceNetInet->SetLastError(EAFNOSUPPORT); + return hleLogError(SCENET, 0, "%s: Unknown address family %04x", __func__, inetAddressFamily); + } + + const int ret = inet_pton(inetAddressFamily, hostname, dst); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); return hleLogError(SCENET, ret, "%s: inet_pton returned %i: %s", __func__, sceNetInet->GetLastError(), strerror(error)); @@ -729,7 +788,7 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getpeername to SceNetInetSockaddrIn", nativeSocketId, __func__); } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { @@ -759,7 +818,7 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { sceNetInet->SetLastError(EFAULT); return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId, __func__); } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { @@ -790,7 +849,7 @@ static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { ERROR_LOG(SCENET, "[%i]: %s: recv() encountered error %i: %s", socket, __func__, error, strerror(error)); } } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 fromAddr, u32 fromLenAddr) { @@ -905,7 +964,7 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t WARN_LOG(SCENET, "[%i] %s: Got error %i=%s", nativeSocketId, __func__, error, strerror(error)); } - return ret; + return hleLogSuccessI(SCENET, ret); } static int sceNetInetGetErrno() { @@ -938,28 +997,6 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { const int nativeSocketId = inetSocket->GetNativeSocketId(); -#if PPSSPP_PLATFORM(LINUX) - // Set broadcast - // TODO: move broadcast InetSocket - int broadcastEnabled = 1; - int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, &broadcastEnabled, sizeof(broadcastEnabled)); - - // Set reuseport / reuseaddr by default - // TODO: evaluate - int opt = 1; -#if defined(SO_REUSEPORT) - setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt)); -#endif - setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); -#elif PPSSPP_PLATFORM(WINDOWS) - // Set broadcast - // TODO: move broadcast InetSocket - int broadcastEnabled = 1; - int sockoptRet = setsockopt(nativeSocketId, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&broadcastEnabled), sizeof(broadcastEnabled)); - int opt = 1; - setsockopt(nativeSocketId, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&opt), sizeof(opt)); -#endif - // Convert PSP bind addr to native bind addr sockaddr_in convertedSockaddr{}; if (!inetSockaddrToNativeSocketAddr(convertedSockaddr, addrPtr, addrLen)) { @@ -978,7 +1015,7 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { // TODO: check whether setting to blocking and then non-blocking is valid setBlockingMode(nativeSocketId, false); - INFO_LOG(SCENET, "[%i] Binding to family %i, port %i, addr %s sockoptRet %i", nativeSocketId, convertedSockaddr.sin_family, ntohs(convertedSockaddr.sin_port), ip2str(convertedSockaddr.sin_addr, false).c_str(), sockoptRet); + INFO_LOG(SCENET, "[%i] Binding to family %i, port %i, addr %s", nativeSocketId, convertedSockaddr.sin_family, ntohs(convertedSockaddr.sin_port), ip2str(convertedSockaddr.sin_addr, false).c_str()); const int ret = bind(nativeSocketId, reinterpret_cast(&convertedSockaddr), socklen); INFO_LOG(SCENET, "Bind returned %i for fd=%i", ret, nativeSocketId); setBlockingMode(nativeSocketId, inetSocket->IsNonBlocking()); @@ -1000,7 +1037,7 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { break; } } - return ret; + return hleLogSuccessI(SCENET, ret); } // TODO: fix retmasks @@ -1040,6 +1077,32 @@ const HLEFunction sceNetInet[] = { std::shared_ptr SceNetInet::gInstance; std::shared_mutex SceNetInet::gLock; +std::unordered_map SceNetInet::gInetAddressFamilyToNativeAddressFamily = +{ + { PSP_NET_INET_AF_UNSPEC, AF_UNSPEC }, + { PSP_NET_INET_AF_LOCAL, AF_UNIX }, + { PSP_NET_INET_AF_INET, AF_INET }, +}; +std::unordered_map SceNetInet::gInetSocketTypeToNativeSocketType = +{ + { PSP_NET_INET_SOCK_STREAM, SOCK_STREAM }, + { PSP_NET_INET_SOCK_DGRAM, SOCK_DGRAM }, + { PSP_NET_INET_SOCK_RAW, SOCK_RAW }, + { PSP_NET_INET_SOCK_RDM, SOCK_RDM }, + { PSP_NET_INET_SOCK_SEQPACKET, SOCK_SEQPACKET }, +}; +std::unordered_map SceNetInet::gInetProtocolToNativeProtocol = +{ + { PSP_NET_INET_IPPROTO_IP, IPPROTO_IP }, + { PSP_NET_INET_IPPROTO_ICMP, IPPROTO_ICMP }, + { PSP_NET_INET_IPPROTO_IGMP, IPPROTO_IGMP }, + { PSP_NET_INET_IPPROTO_TCP, IPPROTO_TCP }, + { PSP_NET_INET_IPPROTO_EGP, IPPROTO_EGP }, + { PSP_NET_INET_IPPROTO_PUP, IPPROTO_PUP }, + { PSP_NET_INET_IPPROTO_UDP, IPPROTO_UDP }, + { PSP_NET_INET_IPPROTO_IDP, IPPROTO_IDP }, + { PSP_NET_INET_IPPROTO_RAW, IPPROTO_RAW }, +}; bool SceNetInet::Init() { auto lock = std::unique_lock(gLock); @@ -1060,6 +1123,69 @@ bool SceNetInet::Shutdown() { return true; } +bool SceNetInet::TranslateInetAddressFamilyToNative(int &destAddressFamily, int srcAddressFamily) { + const auto it = gInetAddressFamilyToNativeAddressFamily.find(static_cast(srcAddressFamily)); + if (it == gInetAddressFamilyToNativeAddressFamily.end()) { + return false; + } + destAddressFamily = it->second; + return true; +} + +bool SceNetInet::TranslateInetSocketLevelToNative(int &destSocketLevel, int srcSocketLevel) { + if (srcSocketLevel != PSP_NET_INET_SOL_SOCKET) { + return false; + } + destSocketLevel = SOL_SOCKET; + return true; +} + +bool SceNetInet::TranslateInetSocketTypeToNative(int &destSocketType, bool &destNonBlocking, int srcSocketType) { + // First, take the base socket type + const int baseSocketType = static_cast(srcSocketType & PSP_NET_INET_SOCK_TYPE_MASK); + const auto it = gInetSocketTypeToNativeSocketType.find(static_cast(baseSocketType)); + if (it == gInetSocketTypeToNativeSocketType.end()) { + return false; + } + // Set base value for dest + destSocketType = it->second; + // Find any flags which are set, noting that this highly depends on the native platform and unknowns are ignored + const int srcFlags = srcSocketType & PSP_NET_INET_SOCK_FLAGS_MASK; +#if defined(SOCK_DCCP) + if ((srcFlags & PSP_NET_INET_SOCK_DCCP) != 0) { + destSocketType |= SOCK_DCCP; + } +#endif +#if defined(SOCK_PACKET) + if ((srcFlags & PSP_NET_INET_SOCK_PACKET) != 0) { + destSocketType |= SOCK_PACKET; + } +#endif +#if defined(SOCK_CLOEXEC) + if ((srcFlags & PSP_NET_INET_SOCK_CLOEXEC) != 0) { + destSocketType |= SOCK_CLOEXEC; + } +#endif + if ((srcFlags & PSP_NET_INET_SOCK_NONBLOCK) != 0) { + destNonBlocking = true; + } +#if defined(SOCK_NOSIGPIPE) + if ((srcFlags & PSP_NET_INET_SOCK_NOSIGPIPE) != 0) { + destSocketType |= SOCK_NOSIGPIPE; + } +#endif + return true; +} + +bool SceNetInet::TranslateInetProtocolToNative(int &destProtocol, int srcProtocol) { + const auto it = gInetProtocolToNativeProtocol.find(static_cast(srcProtocol)); + if (it == gInetProtocolToNativeProtocol.end()) { + return false; + } + destProtocol = it->second; + return true; +} + int SceNetInet::GetLastError() { auto lock = std::shared_lock(mLock); return mLastError; @@ -1081,7 +1207,7 @@ int SceNetInet::SetLastErrorToMatchPlatform() { return error; } -std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId) { +std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId, bool nonBlocking) { auto lock = std::unique_lock(mLock); int inetSocketId = ++mCurrentInetSocketId; @@ -1090,6 +1216,7 @@ std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeS return nullptr; } auto inetSocket = std::make_shared(inetSocketId, nativeSocketId); + inetSocket->SetNonBlocking(nonBlocking); mInetSocketIdToNativeSocket.emplace(inetSocketId, inetSocket); return inetSocket; } @@ -1102,14 +1229,14 @@ std::shared_ptr SceNetInet::GetInetSocket(int inetSocketId) { WARN_LOG(SCENET, "%s: Attempted to get unassociated socket from inetSocketId: %i", __func__, inetSocketId); return nullptr; } - return it->second; } bool SceNetInet::GetNativeSocketIdForInetSocketId(int& nativeSocketId, int inetSocketId) { const auto inetSocket = GetInetSocket(inetSocketId); - if (!inetSocket) + if (!inetSocket) { return false; + } nativeSocketId = inetSocket->GetNativeSocketId(); return true; } @@ -1160,9 +1287,10 @@ bool SceNetInet::TranslateInetFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, void SceNetInet::CloseAllRemainingSockets() const { for (const auto &[first, second] : mInetSocketIdToNativeSocket) { - if (second) { - close(second->GetNativeSocketId()); + if (!second) { + continue; } + close(second->GetNativeSocketId()); } } diff --git a/Core/HLE/sceNetInet.h b/Core/HLE/sceNetInet.h index 584ec77109..b5998ce737 100644 --- a/Core/HLE/sceNetInet.h +++ b/Core/HLE/sceNetInet.h @@ -49,6 +49,48 @@ enum { ERROR_NET_INET_INVALID_ARG = 0x8041020b, }; +enum PspInetAddressFamily { + PSP_NET_INET_AF_UNSPEC = 0, + PSP_NET_INET_AF_LOCAL = 1, + PSP_NET_INET_AF_INET = 2, +}; + +enum PspInetSocketLevel { + PSP_NET_INET_SOL_SOCKET = 0xFFFF, +}; + +enum PspInetSocketType { + PSP_NET_INET_SOCK_STREAM = 1, + PSP_NET_INET_SOCK_DGRAM = 2, + PSP_NET_INET_SOCK_RAW = 3, + PSP_NET_INET_SOCK_RDM = 4, + PSP_NET_INET_SOCK_SEQPACKET = 5, + PSP_NET_INET_SOCK_DCCP = 6, + PSP_NET_INET_SOCK_PACKET = 10, + PSP_NET_INET_SOCK_TYPE_MASK = 0xF, +}; + +enum PspInetSocketTypeFlag { + PSP_NET_INET_SOCK_CLOEXEC = 0x10000000, + PSP_NET_INET_SOCK_NONBLOCK = 0x20000000, + PSP_NET_INET_SOCK_NOSIGPIPE = 0x40000000, + PSP_NET_INET_SOCK_FLAGS_MASK = 0xF0000000, +}; + +// TODO: revisit protocols, not all are necessary +enum PspInetProtocol { + PSP_NET_INET_IPPROTO_IP = 0, // dummy for IP + PSP_NET_INET_IPPROTO_UNSPEC = 0, // 0 will defaulted to the only existing protocol for that particular domain/family and type + PSP_NET_INET_IPPROTO_ICMP = 1, // control message protocol + PSP_NET_INET_IPPROTO_IGMP = 2, // group mgmt protocol + PSP_NET_INET_IPPROTO_TCP = 6, // tcp + PSP_NET_INET_IPPROTO_EGP = 8, // exterior gateway protocol + PSP_NET_INET_IPPROTO_PUP = 12, // pup + PSP_NET_INET_IPPROTO_UDP = 17, // user datagram protocol + PSP_NET_INET_IPPROTO_IDP = 22, // xns idp + PSP_NET_INET_IPPROTO_RAW = 255, // raw IP packet +}; + class SceNetInet { public: static bool Init(); @@ -57,12 +99,20 @@ public: return gInstance; } + // TODO: document that errno should be set to EAFNOSUPPORT when this returns false + static bool TranslateInetAddressFamilyToNative(int &destAddressFamily, int srcAddressFamily); + static inline bool TranslateInetSocketLevelToNative(int &destSocketLevel, int srcSocketLevel); + // TODO: document that errno should be set to ESOMETHING when this returns false + static bool TranslateInetSocketTypeToNative(int &destSocketType, bool &destNonBlocking, int srcSocketType); + // TODO: document that errno should be set to EPROTONOSUPPORT when this returns false + static bool TranslateInetProtocolToNative(int &destProtocol, int srcProtocol); + // TODO: document int GetLastError(); void SetLastError(int error); int SetLastErrorToMatchPlatform(); - std::shared_ptr CreateAndAssociateInetSocket(int nativeSocketId); + std::shared_ptr CreateAndAssociateInetSocket(int nativeSocketId, bool nonBlocking); std::shared_ptr GetInetSocket(int inetSocketId); bool GetNativeSocketIdForInetSocketId(int &nativeSocketId, int inetSocketId); bool EraseNativeSocket(int inetSocketId); @@ -73,6 +123,10 @@ private: static std::shared_ptr gInstance; static std::shared_mutex gLock; + static std::unordered_map gInetAddressFamilyToNativeAddressFamily; + // TODO: document that this does not include flags + static std::unordered_map gInetSocketTypeToNativeSocketType; + static std::unordered_map gInetProtocolToNativeProtocol; int mLastError = 0; std::unordered_map> mInetSocketIdToNativeSocket; From 727203e88f609bbd914c8ce4660315b3f93156c4 Mon Sep 17 00:00:00 2001 From: White Blood Cell Date: Wed, 27 Dec 2023 12:13:07 -0800 Subject: [PATCH 7/9] Move flags and other constants from InetSocket onto SceNetInet. --- Core/HLE/sceNetInet.cpp | 182 ++++++++++++++++++++++++++-------- Core/HLE/sceNetInet.h | 58 ++++++++++- Core/Net/InetSocket.h | 215 +++++----------------------------------- 3 files changed, 220 insertions(+), 235 deletions(-) diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index 8e272f1d84..dd1ba4d05f 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -250,7 +250,7 @@ static int sceNetInetSocket(int inetAddressFamily, int inetType, int inetProtoco } // Map opened socket to an inet socket which is 1-indexed - const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId, nonBlocking); + const auto inetSocket = sceNetInet->CreateAndAssociateInetSocket(nativeSocketId, nativeProtocol, nonBlocking); // Set non-blocking mode since the translation function does not translate non-blocking mode due to platform incompatibilities if (nonBlocking) { @@ -276,7 +276,7 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { - sceNetInet->SetLastError(EINVAL); + sceNetInet->SetLastError(EBADF); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } @@ -288,14 +288,14 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); } - if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { - sceNetInet->SetLastError(EINVAL); + int nativeOptname; + if (!SceNetInet::TranslateInetOptnameToNativeOptname(nativeOptname, inetOptname)) { + sceNetInet->SetLastError(ENOPROTOOPT); return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); } - const auto optname = InetSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); - if (optname != inetOptname) { - DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); + if (nativeOptname != inetOptname) { + DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, nativeOptname); } #if PPSSPP_PLATFORM(WINDOWS) @@ -314,7 +314,7 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range %08x (size %i)", nativeSocketId, __func__, optvalPtr, *optlen); } - switch (optname) { + switch (nativeOptname) { // No direct equivalents case INET_SO_NONBLOCK: { if (*optlen != sizeof(u32)) { @@ -327,7 +327,7 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname // Direct 1:1 mappings default: { // TODO: implement non-blocking getsockopt - const int ret = getsockopt(nativeSocketId, nativeSocketLevel, optname, optval, optlen); + const int ret = getsockopt(nativeSocketId, nativeSocketLevel, nativeOptname, optval, optlen); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); return hleLogError(SCENET, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error)); @@ -347,7 +347,7 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { - sceNetInet->SetLastError(EFAULT); + sceNetInet->SetLastError(EBADF); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } @@ -359,14 +359,14 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); } - if (!inetSocket->IsSockoptNameAllowed(inetOptname)) { - sceNetInet->SetLastError(EINVAL); + int nativeOptname; + if (!SceNetInet::TranslateInetOptnameToNativeOptname(nativeOptname, inetOptname)) { + sceNetInet->SetLastError(ENOPROTOOPT); return hleLogError(SCENET, -1, "[%i] %s: Unknown optname %04x", nativeSocketId, __func__, inetOptname); } - const auto optname = InetSocket::TranslateInetOptnameToNativeOptname(static_cast(inetOptname)); - if (optname != inetOptname) { - DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, optname); + if (nativeOptname != inetOptname) { + DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, nativeOptname); } // If optlens of != sizeof(u32) are created, split out the handling into separate functions for readability @@ -381,9 +381,9 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname } auto optval = Memory::Read_U32(optvalPtr); - DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, nativeSocketLevel, optname, optval); + DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, nativeSocketLevel, nativeOptname, optval); - switch (optname) { + switch (nativeOptname) { // Unmatched PSP functions - no direct equivalent case INET_SO_NONBLOCK: { const bool nonblocking = optval != 0; @@ -397,12 +397,12 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname } // Functions with identical structs to native functions default: { - INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, nativeSocketLevel, optname, optval, 4); - const int ret = setsockopt(nativeSocketId, nativeSocketLevel, optname, reinterpret_cast(&optval), sizeof(optval)); + INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, nativeSocketLevel, nativeOptname, optval, 4); + const int ret = setsockopt(nativeSocketId, nativeSocketLevel, nativeOptname, reinterpret_cast(&optval), sizeof(optval)); INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, optname, optval, error, strerror(error)); + return hleLogError(SCENET, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, nativeOptname, optval, error, strerror(error)); } return hleLogSuccessI(SCENET, ret); } @@ -614,7 +614,7 @@ static int sceNetInetClose(int socket) { const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { - sceNetInet->SetLastError(EINVAL); + sceNetInet->SetLastError(EBADF); return hleLogWarning(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); } @@ -830,8 +830,8 @@ static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { - WARN_LOG(SCENET, "%s: Attempting to close socket %i which does not exist", __func__, socket); - return -1; + sceNetInet->SetLastError(EBADF); + return hleLogError(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); } const auto nativeSocketId = inetSocket->GetNativeSocketId(); @@ -840,7 +840,7 @@ static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); } - const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); + const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking()); const int ret = recv(nativeSocketId, dstBuf, bufLen, nativeFlags); DEBUG_LOG(SCENET, "[%i] %s: Called recv with buf size %i which returned %i", nativeSocketId, __func__, bufLen, ret); if (ret < 0) { @@ -861,7 +861,7 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { - sceNetInet->SetLastError(EFAULT); + sceNetInet->SetLastError(EBADF); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } @@ -873,7 +873,7 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 } // Translate PSP flags to native flags and prepare sockaddrIn to receive peer address - const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); + const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking()); sockaddr_in sockaddrIn{}; socklen_t socklen = sizeof(sockaddr_in); Memory::Memset(bufPtr, 0, bufLen, __func__); @@ -906,7 +906,7 @@ static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { - sceNetInet->SetLastError(EFAULT); + sceNetInet->SetLastError(EBADF); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } @@ -917,7 +917,7 @@ static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { } // Translate PSP flags to native flags and send - const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); + const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking()); const int ret = send(inetSocket->GetNativeSocketId(), buf, bufLen, nativeFlags); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); @@ -935,7 +935,7 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { - sceNetInet->SetLastError(EFAULT); + sceNetInet->SetLastError(EBADF); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } @@ -947,7 +947,7 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t } // Translate PSP flags to native flags and convert toAddr to native addr - const int nativeFlags = inetSocket->TranslateInetFlagsToNativeFlags(flags); + const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking()); sockaddr_in convertedSockAddr{}; if (!inetSockaddrToNativeSocketAddr(convertedSockAddr, toAddr, toLen)) { ERROR_LOG(SCENET, "[%i] %s: Unable to translate sceSockAddr to native sockaddr", nativeSocketId, __func__); @@ -979,7 +979,7 @@ static int sceNetInetGetErrno() { INFO_LOG(SCENET, "Requested %s %i=%s", __func__, nativeError, strerror(nativeError)); } - return InetSocket::TranslateNativeErrorToInetError(nativeError); + return SceNetInet::TranslateNativeErrorToInetError(nativeError); } static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { @@ -991,7 +991,7 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { - sceNetInet->SetLastError(EFAULT); + sceNetInet->SetLastError(EBADF); return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } @@ -1023,12 +1023,13 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { // Set UPnP const auto port = ntohs(convertedSockaddr.sin_port); switch (inetSocket->GetProtocol()) { - case INET_PROTOCOL_TCP: { - UPnP_Add(IP_PROTOCOL_TCP, port, port); + case IPPROTO_UDP: { + UPnP_Add(IP_PROTOCOL_UDP, port, port); break; } - case INET_PROTOCOL_UDP: { - UPnP_Add(IP_PROTOCOL_UDP, port, port); + case IPPROTO_IP: + case IPPROTO_TCP: { + UPnP_Add(IP_PROTOCOL_TCP, port, port); break; } // TODO: Unknown IP protocol 000f when attempting to set up UPnP port forwarding @@ -1076,23 +1077,24 @@ const HLEFunction sceNetInet[] = { };; std::shared_ptr SceNetInet::gInstance; + std::shared_mutex SceNetInet::gLock; -std::unordered_map SceNetInet::gInetAddressFamilyToNativeAddressFamily = -{ + +std::unordered_map SceNetInet::gInetAddressFamilyToNativeAddressFamily = { { PSP_NET_INET_AF_UNSPEC, AF_UNSPEC }, { PSP_NET_INET_AF_LOCAL, AF_UNIX }, { PSP_NET_INET_AF_INET, AF_INET }, }; -std::unordered_map SceNetInet::gInetSocketTypeToNativeSocketType = -{ + +std::unordered_map SceNetInet::gInetSocketTypeToNativeSocketType = { { PSP_NET_INET_SOCK_STREAM, SOCK_STREAM }, { PSP_NET_INET_SOCK_DGRAM, SOCK_DGRAM }, { PSP_NET_INET_SOCK_RAW, SOCK_RAW }, { PSP_NET_INET_SOCK_RDM, SOCK_RDM }, { PSP_NET_INET_SOCK_SEQPACKET, SOCK_SEQPACKET }, }; -std::unordered_map SceNetInet::gInetProtocolToNativeProtocol = -{ + +std::unordered_map SceNetInet::gInetProtocolToNativeProtocol = { { PSP_NET_INET_IPPROTO_IP, IPPROTO_IP }, { PSP_NET_INET_IPPROTO_ICMP, IPPROTO_ICMP }, { PSP_NET_INET_IPPROTO_IGMP, IPPROTO_IGMP }, @@ -1104,6 +1106,54 @@ std::unordered_map SceNetInet::gInetProtocolToNativeProtoc { PSP_NET_INET_IPPROTO_RAW, IPPROTO_RAW }, }; +// TODO: commented out optnames +std::unordered_map SceNetInet::gInetSocketOptnameToNativeOptname = { + { INET_SO_ACCEPTCONN, SO_ACCEPTCONN }, + { INET_SO_REUSEADDR, SO_REUSEADDR }, + { INET_SO_KEEPALIVE, SO_KEEPALIVE }, + { INET_SO_DONTROUTE, SO_DONTROUTE }, + { INET_SO_BROADCAST, SO_BROADCAST }, + // { INET_SO_USELOOPBACK, INET_SO_USELOOPBACK }, + { INET_SO_LINGER, SO_LINGER }, + { INET_SO_OOBINLINE, SO_OOBINLINE }, + { INET_SO_REUSEPORT, SO_REUSEPORT }, + { INET_SO_TIMESTAMP, SO_TIMESTAMP }, + // { INET_SO_ONESBCAST, INET_SO_ONESBCAST }, + { INET_SO_SNDBUF, SO_SNDBUF }, + { INET_SO_RCVBUF, SO_RCVBUF }, + { INET_SO_SNDLOWAT, SO_SNDLOWAT }, + { INET_SO_RCVLOWAT, SO_RCVLOWAT }, + { INET_SO_SNDTIMEO, SO_SNDTIMEO }, + { INET_SO_RCVTIMEO, SO_RCVTIMEO }, + { INET_SO_ERROR, SO_ERROR }, + { INET_SO_TYPE, SO_TYPE }, + // { INET_SO_OVERFLOWED, INET_SO_OVERFLOWED }, + { INET_SO_NONBLOCK, INET_SO_NONBLOCK }, +}; + +std::unordered_map SceNetInet::gInetMessageFlagToNativeMessageFlag = { + { INET_MSG_OOB, MSG_OOB }, + { INET_MSG_PEEK, MSG_PEEK }, + { INET_MSG_DONTROUTE, MSG_DONTROUTE }, +#if defined(MSG_EOR) + { INET_MSG_EOR, MSG_EOR }, +#endif + { INET_MSG_TRUNC, MSG_TRUNC }, + { INET_MSG_CTRUNC, MSG_CTRUNC }, + { INET_MSG_WAITALL, MSG_WAITALL }, + { INET_MSG_DONTWAIT, MSG_DONTWAIT }, +#if defined(MSG_BCAST) + { INET_MSG_BCAST, MSG_BCAST }, +#endif +#if defined(MSG_MCAST) + { INET_MSG_MCAST, MSG_MCAST }, +#endif +}; + +std::unordered_map SceNetInet::gNativeErrorCodeToInetErrorCode = { + { EINPROGRESS, INET_EINPROGRESS } +}; + bool SceNetInet::Init() { auto lock = std::unique_lock(gLock); if (gInstance) { @@ -1186,6 +1236,50 @@ bool SceNetInet::TranslateInetProtocolToNative(int &destProtocol, int srcProtoco return true; } +bool SceNetInet::TranslateInetOptnameToNativeOptname(int &destOptname, const int inetOptname) { + const auto it = gInetSocketOptnameToNativeOptname.find(static_cast(inetOptname)); + if (it == gInetSocketOptnameToNativeOptname.end()) { + return false; + } + destOptname = it->second; + return true; +} + +int SceNetInet::TranslateInetFlagsToNativeFlags(const int messageFlags, const bool nonBlocking) { + int nativeFlags = 0; // The actual platform flags + int foundFlags = 0; // The inet equivalent of the native flags, used to verify that no remaining flags need to be set + for (const auto [inetFlag, nativeFlag] : gInetMessageFlagToNativeMessageFlag) { + if ((messageFlags & inetFlag) != 0) { + nativeFlags |= nativeFlag; + foundFlags |= inetFlag; + } + } + +#if !PPSSPP_PLATFORM(WINDOWS) + if (nonBlocking) { + nativeFlags |= MSG_DONTWAIT; + } +#endif + + // Check for any inet flags which were not successfully mapped into a native flag + if (const int missingFlags = messageFlags & ~foundFlags; missingFlags != 0) { + for (int i = 0; i < sizeof(int) * 8; i++) { + if (const int val = 1 << i; (missingFlags & val) != 0) { + DEBUG_LOG(SCENET, "Encountered unsupported platform flag at bit %i (actual value %04x), undefined behavior may ensue.", i, val); + } + } + } + return nativeFlags; +} + +int SceNetInet::TranslateNativeErrorToInetError(const int nativeError) { + if (const auto it = gNativeErrorCodeToInetErrorCode.find(nativeError); + it != gNativeErrorCodeToInetErrorCode.end()) { + return it->second; + } + return nativeError; +} + int SceNetInet::GetLastError() { auto lock = std::shared_lock(mLock); return mLastError; @@ -1207,7 +1301,7 @@ int SceNetInet::SetLastErrorToMatchPlatform() { return error; } -std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId, bool nonBlocking) { +std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeSocketId, int protocol, bool nonBlocking) { auto lock = std::unique_lock(mLock); int inetSocketId = ++mCurrentInetSocketId; @@ -1215,7 +1309,7 @@ std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeS WARN_LOG(SCENET, "%s: Attempted to re-associate socket from already-associated inetSocketId: %i", __func__, inetSocketId); return nullptr; } - auto inetSocket = std::make_shared(inetSocketId, nativeSocketId); + auto inetSocket = std::make_shared(inetSocketId, nativeSocketId, protocol, nonBlocking); inetSocket->SetNonBlocking(nonBlocking); mInetSocketIdToNativeSocket.emplace(inetSocketId, inetSocket); return inetSocket; diff --git a/Core/HLE/sceNetInet.h b/Core/HLE/sceNetInet.h index b5998ce737..ea21af767d 100644 --- a/Core/HLE/sceNetInet.h +++ b/Core/HLE/sceNetInet.h @@ -91,6 +91,53 @@ enum PspInetProtocol { PSP_NET_INET_IPPROTO_RAW = 255, // raw IP packet }; +// TODO: INET_ +enum PspInetSocketOptionName { + // TODO: also specify minimum socket size + INET_SO_ACCEPTCONN = 0x0002, // socket has had listen() + INET_SO_REUSEADDR = 0x0004, // allow local address reuse + INET_SO_KEEPALIVE = 0x0008, // keep connections alive + INET_SO_DONTROUTE = 0x0010, // just use interface addresses + INET_SO_BROADCAST = 0x0020, // permit sending of broadcast msgs + INET_SO_USELOOPBACK = 0x0040, // bypass hardware when possible + INET_SO_LINGER = 0x0080, // linger on close if data present + INET_SO_OOBINLINE = 0x0100, // leave received OOB data in line + INET_SO_REUSEPORT = 0x0200, // allow local address & port reuse + INET_SO_TIMESTAMP = 0x0400, // timestamp received dgram traffic + INET_SO_ONESBCAST = 0x0800, // allow broadcast to 255.255.255.255 + INET_SO_SNDBUF = 0x1001, // send buffer size + INET_SO_RCVBUF = 0x1002, // receive buffer size + INET_SO_SNDLOWAT = 0x1003, // send low-water mark + INET_SO_RCVLOWAT = 0x1004, // receive low-water mark + INET_SO_SNDTIMEO = 0x1005, // send timeout + INET_SO_RCVTIMEO = 0x1006, // receive timeout + INET_SO_ERROR = 0x1007, // get error status and clear + INET_SO_TYPE = 0x1008, // get socket type + INET_SO_OVERFLOWED = 0x1009, // datagrams: return packets dropped + INET_SO_NONBLOCK = 0x1009, // non-blocking I/O +}; + +enum PspInetLimit { + PSP_NET_INET_SOMAXCONN = 128, +}; + +enum PspInetMessageFlag { + INET_MSG_OOB = 1, + INET_MSG_PEEK = 1 << 1, + INET_MSG_DONTROUTE = 1 << 2, + INET_MSG_EOR = 1 << 3, + INET_MSG_TRUNC = 1 << 4, + INET_MSG_CTRUNC = 1 << 5, + INET_MSG_WAITALL = 1 << 6, + INET_MSG_DONTWAIT = 1 << 7, + INET_MSG_BCAST = 1 << 8, + INET_MSG_MCAST = 1 << 9 +}; + +enum InetErrorCode { + INET_EINPROGRESS = 119, +}; + class SceNetInet { public: static bool Init(); @@ -106,13 +153,17 @@ public: static bool TranslateInetSocketTypeToNative(int &destSocketType, bool &destNonBlocking, int srcSocketType); // TODO: document that errno should be set to EPROTONOSUPPORT when this returns false static bool TranslateInetProtocolToNative(int &destProtocol, int srcProtocol); + // TODO: document that errno should be set to EPROTONOSUPPORT when this returns false + static bool TranslateInetOptnameToNativeOptname(int &destOptname, int inetOptname); + static int TranslateInetFlagsToNativeFlags(int messageFlags, bool nonBlocking); + static int TranslateNativeErrorToInetError(int nativeError); // TODO: document int GetLastError(); void SetLastError(int error); int SetLastErrorToMatchPlatform(); - std::shared_ptr CreateAndAssociateInetSocket(int nativeSocketId, bool nonBlocking); + std::shared_ptr CreateAndAssociateInetSocket(int nativeSocketId, int protocol, bool nonBlocking); std::shared_ptr GetInetSocket(int inetSocketId); bool GetNativeSocketIdForInetSocketId(int &nativeSocketId, int inetSocketId); bool EraseNativeSocket(int inetSocketId); @@ -127,6 +178,11 @@ private: // TODO: document that this does not include flags static std::unordered_map gInetSocketTypeToNativeSocketType; static std::unordered_map gInetProtocolToNativeProtocol; + // TODO: Handle commented out options + static std::unordered_map gInetSocketOptnameToNativeOptname; + static std::unordered_map gInetMessageFlagToNativeMessageFlag; + + static std::unordered_map gNativeErrorCodeToInetErrorCode; int mLastError = 0; std::unordered_map> mInetSocketIdToNativeSocket; diff --git a/Core/Net/InetSocket.h b/Core/Net/InetSocket.h index 1b1f458fc9..25a36b2e87 100644 --- a/Core/Net/InetSocket.h +++ b/Core/Net/InetSocket.h @@ -1,202 +1,37 @@ #pragma once -#include "ppsspp_config.h" - -#include -#include - -#if !PPSSPP_PLATFORM(WINDOWS) -#include -#endif - -#include "Log.h" - -enum Protocol { - INET_PROTOCOL_UDP = SOCK_DGRAM, - INET_PROTOCOL_TCP = SOCK_STREAM -}; - -// TODO: INET_ -enum InetSocketOptionName { - // TODO: also specify minimum socket size - INET_SO_ACCEPTCONN = 0x0002, // socket has had listen() - INET_SO_REUSEADDR = 0x0004, // allow local address reuse - INET_SO_KEEPALIVE = 0x0008, // keep connections alive - INET_SO_DONTROUTE = 0x0010, // just use interface addresses - INET_SO_BROADCAST = 0x0020, // permit sending of broadcast msgs - INET_SO_USELOOPBACK = 0x0040, // bypass hardware when possible - INET_SO_LINGER = 0x0080, // linger on close if data present - INET_SO_OOBINLINE = 0x0100, // leave received OOB data in line - INET_SO_REUSEPORT = 0x0200, // allow local address & port reuse - INET_SO_TIMESTAMP = 0x0400, // timestamp received dgram traffic - INET_SO_ONESBCAST = 0x0800, // allow broadcast to 255.255.255.255 - INET_SO_SNDBUF = 0x1001, // send buffer size - INET_SO_RCVBUF = 0x1002, // receive buffer size - INET_SO_SNDLOWAT = 0x1003, // send low-water mark - INET_SO_RCVLOWAT = 0x1004, // receive low-water mark - INET_SO_SNDTIMEO = 0x1005, // send timeout - INET_SO_RCVTIMEO = 0x1006, // receive timeout - INET_SO_ERROR = 0x1007, // get error status and clear - INET_SO_TYPE = 0x1008, // get socket type - INET_SO_OVERFLOWED = 0x1009, // datagrams: return packets dropped - INET_SO_NONBLOCK = 0x1009, // non-blocking I/O -}; - -// TODO: Handle commented out options -static std::unordered_map gInetSocketOptnameToNativeOptname = { - { INET_SO_ACCEPTCONN, SO_ACCEPTCONN }, - { INET_SO_REUSEADDR, SO_REUSEADDR }, - { INET_SO_KEEPALIVE, SO_KEEPALIVE }, - { INET_SO_DONTROUTE, SO_DONTROUTE }, - { INET_SO_BROADCAST, SO_BROADCAST }, - // { INET_SO_USELOOPBACK, INET_SO_USELOOPBACK }, - { INET_SO_LINGER, SO_LINGER }, - { INET_SO_OOBINLINE, SO_OOBINLINE }, - { INET_SO_REUSEPORT, SO_REUSEPORT }, - { INET_SO_TIMESTAMP, SO_TIMESTAMP }, - // { INET_SO_ONESBCAST, INET_SO_ONESBCAST }, - { INET_SO_SNDBUF, SO_SNDBUF }, - { INET_SO_RCVBUF, SO_RCVBUF }, - { INET_SO_SNDLOWAT, SO_SNDLOWAT }, - { INET_SO_RCVLOWAT, SO_RCVLOWAT }, - { INET_SO_SNDTIMEO, SO_SNDTIMEO }, - { INET_SO_RCVTIMEO, SO_RCVTIMEO }, - { INET_SO_ERROR, SO_ERROR }, - { INET_SO_TYPE, SO_TYPE }, - // { INET_SO_OVERFLOWED, INET_SO_OVERFLOWED }, - { INET_SO_NONBLOCK, INET_SO_NONBLOCK }, -}; - -enum InetLimit { - PSP_NET_INET_SOMAXCONN = 128, -}; - -enum InetMessageFlag { - INET_MSG_OOB = 1, - INET_MSG_PEEK = 1 << 1, - INET_MSG_DONTROUTE = 1 << 2, - INET_MSG_EOR = 1 << 3, - INET_MSG_TRUNC = 1 << 4, - INET_MSG_CTRUNC = 1 << 5, - INET_MSG_WAITALL = 1 << 6, - INET_MSG_DONTWAIT = 1 << 7, - INET_MSG_BCAST = 1 << 8, - INET_MSG_MCAST = 1 << 9 -}; - -// TODO: move to better place -static std::unordered_map gInetMessageFlagToNativeMessageFlag = { - { INET_MSG_OOB, MSG_OOB }, - { INET_MSG_PEEK, MSG_PEEK }, - { INET_MSG_DONTROUTE, MSG_DONTROUTE }, -#if defined(MSG_EOR) - { INET_MSG_EOR, MSG_EOR }, -#endif - { INET_MSG_TRUNC, MSG_TRUNC }, - { INET_MSG_CTRUNC, MSG_CTRUNC }, - { INET_MSG_WAITALL, MSG_WAITALL }, - { INET_MSG_DONTWAIT, MSG_DONTWAIT }, -#if defined(MSG_BCAST) - { INET_MSG_BCAST, MSG_BCAST }, -#endif -#if defined(MSG_MCAST) - { INET_MSG_MCAST, MSG_MCAST }, -#endif -}; - -enum InetErrorCode { - INET_EINPROGRESS = 119, -}; - -static std::unordered_map gNativeErrorCodeToInetErrorCode = { - { EINPROGRESS, INET_EINPROGRESS } -}; - // TODO: document class InetSocket { public: - InetSocket(int sceSocketId, int nativeSocketId) : mInetSocketId(sceSocketId), mNativeSocketId(nativeSocketId) {} + InetSocket(int sceSocketId, int nativeSocketId, int protocol, bool nonBlocking) : + mInetSocketId(sceSocketId), + mNativeSocketId(nativeSocketId), + mProtocol(protocol), + mNonBlocking(nonBlocking) {} - int GetInetSocketId() const { - return mInetSocketId; - } + int GetInetSocketId() const { + return mInetSocketId; + } - int GetNativeSocketId() const { - return mNativeSocketId; - } + int GetNativeSocketId() const { + return mNativeSocketId; + } - // TODO: get mask of options + bool IsNonBlocking() const { + return mNonBlocking; + } - bool IsNonBlocking() const { - return mNonBlocking; - } - - void SetNonBlocking(const bool nonBlocking) { - mNonBlocking = nonBlocking; - } - - Protocol GetProtocol() const { - return mProtocol; - } - - void SetProtocol(const Protocol protocol) { - mProtocol = protocol; - } - - // TODO: Move me - static bool IsSockoptNameAllowed(const int optname) { - return gInetSocketOptnameToNativeOptname.find(static_cast(optname)) != gInetSocketOptnameToNativeOptname.end(); - } - - // TODO: rename this or the other - static int TranslateInetOptnameToNativeOptname(const InetSocketOptionName inetOptname) { - const auto it = gInetSocketOptnameToNativeOptname.find(inetOptname); - if (it == gInetSocketOptnameToNativeOptname.end()) { - return inetOptname; - } - return it->second; - } - - int TranslateInetFlagsToNativeFlags(const int messageFlags) const { - int nativeFlags = 0; // The actual platform flags - int foundFlags = 0; // The inet equivalent of the native flags, used to verify that no remaining flags need to be set - for (const auto [inetFlag, nativeFlag] : gInetMessageFlagToNativeMessageFlag) { - if ((messageFlags & inetFlag) != 0) { - nativeFlags |= nativeFlag; - foundFlags |= inetFlag; - } - } - -#if !PPSSPP_PLATFORM(WINDOWS) - if (this->IsNonBlocking()) { - nativeFlags |= MSG_DONTWAIT; - } -#endif - - // Check for any inet flags which were not successfully mapped into a native flag - if (const int missingFlags = messageFlags & ~foundFlags; missingFlags != 0) { - for (int i = 0; i < sizeof(int) * 8; i++) { - if (const int val = 1 << i; (missingFlags & val) != 0) { - DEBUG_LOG(Log::sceNet, "Encountered unsupported platform flag at bit %i (actual value %04x), undefined behavior may ensue.", i, val); - } - } - } - // DEBUG_LOG(SCENET, "Translated %04x to %04x", messageFlags, nativeFlags); - return nativeFlags; - } - - // TODO: consider moving to SceNetInet - static int TranslateNativeErrorToInetError(const int nativeError) { - if (const auto it = gNativeErrorCodeToInetErrorCode.find(nativeError); - it != gNativeErrorCodeToInetErrorCode.end()) { - return it->second; - } - return nativeError; - } + void SetNonBlocking(const bool nonBlocking) { + mNonBlocking = nonBlocking; + } + // TODO: document that this is the native protocol + int GetProtocol() const { + return mProtocol; + } private: - int mInetSocketId; - int mNativeSocketId; - Protocol mProtocol; - bool mNonBlocking = false; + int mInetSocketId; + int mNativeSocketId; + int mProtocol; + bool mNonBlocking = false; }; From f4ee69f7be20b78224dbe2391539c95c7239fab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 4 Jan 2025 17:41:36 +0100 Subject: [PATCH 8/9] Buildfixes --- Core/HLE/sceNet.cpp | 3 +- Core/HLE/sceNetInet.cpp | 318 ++++++++++++++++++++-------------------- 2 files changed, 158 insertions(+), 163 deletions(-) diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 65b6527106..4c20186116 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -150,9 +150,8 @@ static bool __PlatformNetInit() { // TODO: log return false; } -#else - return true; #endif + return true; } static bool __PlatformNetShutdown() { diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index dd1ba4d05f..75e0421d29 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -152,7 +152,7 @@ static bool inetSockaddrToNativeSocketAddr(sockaddr_in &dest, u32 sockAddrIntern dest.sin_family = inetSockaddrIn->sin_family; dest.sin_port = inetSockaddrIn->sin_port; dest.sin_addr.s_addr = inetSockaddrIn->sin_addr; - DEBUG_LOG(SCENET, "sceSockaddrToNativeSocketAddr: Family %i, port %i, addr %s, len %i", dest.sin_family, ntohs(dest.sin_port), ip2str(dest.sin_addr, false).c_str(), inetSockaddrIn->sin_len); + DEBUG_LOG(Log::sceNet, "sceSockaddrToNativeSocketAddr: Family %i, port %i, addr %s, len %i", dest.sin_family, ntohs(dest.sin_port), ip2str(dest.sin_addr, false).c_str(), inetSockaddrIn->sin_len); return true; } @@ -166,7 +166,7 @@ static bool writeSockAddrInToInetSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, s if (sceNetSockaddrIn == nullptr) { return false; } - DEBUG_LOG(SCENET, "writeSockAddrInToSceSockAddr: %lu vs %i", sizeof(SceNetInetSockaddrIn), sceNetSocklen); + DEBUG_LOG(Log::sceNet, "writeSockAddrInToSceSockAddr size: %d vs %d", (int)sizeof(SceNetInetSockaddrIn), sceNetSocklen); if (sceNetSocklenPtr) { *sceNetSocklenPtr = std::min(sceNetSocklen, sizeof(SceNetInetSockaddr)); } @@ -203,21 +203,21 @@ static int setBlockingMode(int nativeSocketId, bool nonblocking) { } static int sceNetInetInit() { - ERROR_LOG(SCENET, "UNTESTED sceNetInetInit()"); + ERROR_LOG(Log::sceNet, "UNTESTED sceNetInetInit()"); return SceNetInet::Init() ? 0 : ERROR_NET_INET_ALREADY_INITIALIZED; } int sceNetInetTerm() { - ERROR_LOG(SCENET, "UNTESTED sceNetInetTerm()"); + ERROR_LOG(Log::sceNet, "UNTESTED sceNetInetTerm()"); SceNetInet::Shutdown(); - return hleLogSuccessI(SCENET, 0); + return hleLogSuccessI(Log::sceNet, 0); } static int sceNetInetSocket(int inetAddressFamily, int inetType, int inetProtocol) { - WARN_LOG_ONCE(sceNetInetSocket, SCENET, "UNTESTED sceNetInetSocket(%i, %i, %i)", inetAddressFamily, inetType, inetProtocol); + WARN_LOG_ONCE(sceNetInetSocket, Log::sceNet, "UNTESTED sceNetInetSocket(%i, %i, %i)", inetAddressFamily, inetType, inetProtocol); auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } // Translate address family, type, and protocol. There is some complexity around the type in particular where @@ -226,27 +226,27 @@ static int sceNetInetSocket(int inetAddressFamily, int inetType, int inetProtoco int nativeAddressFamily; if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { sceNetInet->SetLastError(EAFNOSUPPORT); - return hleLogError(SCENET, -1, "%s: Unable to translate inet address family %i", __func__, inetAddressFamily); + return hleLogError(Log::sceNet, -1, "%s: Unable to translate inet address family %i", __func__, inetAddressFamily); } int nativeType; bool nonBlocking; if (!SceNetInet::TranslateInetSocketTypeToNative(nativeType, nonBlocking, inetType)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, -1, "%s: Unable to translate inet type %08x", __func__, inetType); + return hleLogError(Log::sceNet, -1, "%s: Unable to translate inet type %08x", __func__, inetType); } int nativeProtocol; if (!SceNetInet::TranslateInetProtocolToNative(nativeProtocol, inetProtocol)) { sceNetInet->SetLastError(EPROTONOSUPPORT); - return hleLogError(SCENET, -1, "%s: Unable to translate inet protocol %i", __func__, inetProtocol); + return hleLogError(Log::sceNet, -1, "%s: Unable to translate inet protocol %i", __func__, inetProtocol); } // Attempt to open socket const int nativeSocketId = socket(nativeAddressFamily, nativeType, nativeProtocol); if (nativeSocketId < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, -1, "%s: Unable to open socket(%i, %i, %i) with error %i: %s", __func__, nativeAddressFamily, nativeType, nativeProtocol, error, strerror(error)); + return hleLogError(Log::sceNet, -1, "%s: Unable to open socket(%i, %i, %i) with error %i: %s", __func__, nativeAddressFamily, nativeType, nativeProtocol, error, strerror(error)); } // Map opened socket to an inet socket which is 1-indexed @@ -261,23 +261,23 @@ static int sceNetInetSocket(int inetAddressFamily, int inetType, int inetProtoco if (!inetSocket) { close(nativeSocketId); sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new InetSocket for native socket id %i, closing", __func__, nativeSocketId); + return hleLogError(Log::sceNet, ERROR_NET_INET_INVALID_ARG, "%s: Unable to create new InetSocket for native socket id %i, closing", __func__, nativeSocketId); } return inetSocket->GetInetSocketId(); } static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname, u32 optvalPtr, u32 optlenPtr) { - WARN_LOG(SCENET, "UNTESTED sceNetInetGetsockopt(%i, %i, %i, %08x, %08x)", socket, inetSocketLevel, inetOptname, optvalPtr, optlenPtr); + WARN_LOG(Log::sceNet, "UNTESTED sceNetInetGetsockopt(%i, %i, %i, %08x, %08x)", socket, inetSocketLevel, inetOptname, optvalPtr, optlenPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { sceNetInet->SetLastError(EBADF); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } const auto nativeSocketId = inetSocket->GetNativeSocketId(); @@ -285,33 +285,29 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname int nativeSocketLevel; if (!SceNetInet::TranslateInetSocketLevelToNative(nativeSocketLevel, inetSocketLevel)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); + return hleLogError(Log::sceNet, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); } int nativeOptname; if (!SceNetInet::TranslateInetOptnameToNativeOptname(nativeOptname, inetOptname)) { sceNetInet->SetLastError(ENOPROTOOPT); - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Unknown optname %04x", inetOptname); } if (nativeOptname != inetOptname) { - DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, nativeOptname); + DEBUG_LOG(Log::sceNet, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, nativeOptname); } -#if PPSSPP_PLATFORM(WINDOWS) - auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); -#else - auto optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); -#endif - if (optlen == nullptr) { + socklen_t *optlen = reinterpret_cast(Memory::GetPointerWrite(optlenPtr)); + if (!optlen) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer %08x", nativeSocketId, __func__, optlenPtr); + return hleLogError(Log::sceNet, -1, "[%i] %s: Invalid pointer %08x", nativeSocketId, __func__, optlenPtr); } const auto optval = Memory::GetTypedPointerWriteRange(optvalPtr, *optlen); if (optval == nullptr) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range %08x (size %i)", nativeSocketId, __func__, optvalPtr, *optlen); + return hleLogError(Log::sceNet, -1, "[%i] %s: Invalid pointer range %08x (size %i)", nativeSocketId, __func__, optvalPtr, *optlen); } switch (nativeOptname) { @@ -319,10 +315,10 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname case INET_SO_NONBLOCK: { if (*optlen != sizeof(u32)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i] %s: Invalid optlen %i for INET_SO_NONBLOCK", nativeSocketId, __func__, *optlen); + return hleLogError(Log::sceNet, -1, "[%i] %s: Invalid optlen %i for INET_SO_NONBLOCK", nativeSocketId, __func__, *optlen); } Memory::Write_U32(optvalPtr, inetSocket->IsNonBlocking() ? 1 : 0); - return hleLogSuccessI(SCENET, 0); + return hleLogSuccessI(Log::sceNet, 0); } // Direct 1:1 mappings default: { @@ -330,25 +326,25 @@ static int sceNetInetGetsockopt(int socket, int inetSocketLevel, int inetOptname const int ret = getsockopt(nativeSocketId, nativeSocketLevel, nativeOptname, optval, optlen); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error)); + return hleLogError(Log::sceNet, ret, "[%i] %s: returned error %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } } } static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname, u32 optvalPtr, int optlen) { - WARN_LOG_ONCE(sceNetInetSetsockopt, SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, inetSocketLevel, inetOptname, optvalPtr, optlen); + WARN_LOG_ONCE(sceNetInetSetsockopt, Log::sceNet, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %08x, %i)", socket, inetSocketLevel, inetOptname, optvalPtr, optlen); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { sceNetInet->SetLastError(EBADF); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } const auto nativeSocketId = inetSocket->GetNativeSocketId(); @@ -356,101 +352,101 @@ static int sceNetInetSetsockopt(int socket, int inetSocketLevel, int inetOptname int nativeSocketLevel; if (!SceNetInet::TranslateInetSocketLevelToNative(nativeSocketLevel, inetSocketLevel)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); + return hleLogError(Log::sceNet, -1, "[%i] %s: Unknown socket level %04x", nativeSocketId, __func__, inetSocketLevel); } int nativeOptname; if (!SceNetInet::TranslateInetOptnameToNativeOptname(nativeOptname, inetOptname)) { sceNetInet->SetLastError(ENOPROTOOPT); - return hleLogError(SCENET, -1, "[%i] %s: Unknown optname %04x", nativeSocketId, __func__, inetOptname); + return hleLogError(Log::sceNet, -1, "[%i] %s: Unknown optname %04x", nativeSocketId, __func__, inetOptname); } if (nativeOptname != inetOptname) { - DEBUG_LOG(SCENET, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, nativeOptname); + DEBUG_LOG(Log::sceNet, "sceNetInetSetsockopt: Translated optname %04x into %04x", inetOptname, nativeOptname); } // If optlens of != sizeof(u32) are created, split out the handling into separate functions for readability if (optlen != sizeof(u32)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, -1, "[%i]: %s: Unhandled optlen %i for optname %04x", nativeSocketId, __func__, optlen, inetOptname); + return hleLogError(Log::sceNet, -1, "[%i]: %s: Unhandled optlen %i for optname %04x", nativeSocketId, __func__, optlen, inetOptname); } if (!Memory::IsValidAddress(optvalPtr)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i]: %s: Invalid address %08x for optval", nativeSocketId, __func__, optvalPtr); + return hleLogError(Log::sceNet, -1, "[%i]: %s: Invalid address %08x for optval", nativeSocketId, __func__, optvalPtr); } auto optval = Memory::Read_U32(optvalPtr); - DEBUG_LOG(SCENET, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, nativeSocketLevel, nativeOptname, optval); + DEBUG_LOG(Log::sceNet, "[%i] setsockopt(%i, %i, %i, %i)", nativeSocketId, nativeSocketId, nativeSocketLevel, nativeOptname, optval); switch (nativeOptname) { // Unmatched PSP functions - no direct equivalent case INET_SO_NONBLOCK: { const bool nonblocking = optval != 0; inetSocket->SetNonBlocking(nonblocking); - INFO_LOG(SCENET, "[%i] setsockopt_u32: Set non-blocking=%i", nativeSocketId, nonblocking); + INFO_LOG(Log::sceNet, "[%i] setsockopt_u32: Set non-blocking=%i", nativeSocketId, nonblocking); if (setBlockingMode(nativeSocketId, nonblocking) != 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "[%i] %s: Failed to set to non-blocking with error %i: %s", nativeSocketId, __func__, error, strerror(error)); + ERROR_LOG(Log::sceNet, "[%i] %s: Failed to set to non-blocking with error %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return hleLogSuccessI(SCENET, 0); + return hleLogSuccessI(Log::sceNet, 0); } // Functions with identical structs to native functions default: { - INFO_LOG(SCENET, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, nativeSocketLevel, nativeOptname, optval, 4); + INFO_LOG(Log::sceNet, "UNTESTED sceNetInetSetsockopt(%i, %i, %i, %u, %i)", nativeSocketId, nativeSocketLevel, nativeOptname, optval, 4); const int ret = setsockopt(nativeSocketId, nativeSocketLevel, nativeOptname, reinterpret_cast(&optval), sizeof(optval)); - INFO_LOG(SCENET, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); + INFO_LOG(Log::sceNet, "setsockopt_u32: setsockopt returned %i for %i", ret, nativeSocketId); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, nativeOptname, optval, error, strerror(error)); + return hleLogError(Log::sceNet, ret, "[%i] %s: Failed to set optname %04x to %08x with error %i: %s", nativeSocketId, __func__, nativeOptname, optval, error, strerror(error)); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } } } static int sceNetInetConnect(int socket, u32 sockAddrInternetPtr, int addressLength) { - WARN_LOG_ONCE(sceNetInetConnect, SCENET, "UNTESTED sceNetInetConnect(%i, %08x, %i, %i)", socket, sockAddrInternetPtr, Memory::Read_U32(sockAddrInternetPtr), addressLength); + WARN_LOG_ONCE(sceNetInetConnect, Log::sceNet, "UNTESTED sceNetInetConnect(%i, %08x, %i, %i)", socket, sockAddrInternetPtr, Memory::Read_U32(sockAddrInternetPtr), addressLength); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } // Translate inet sockaddr to native sockaddr sockaddr_in convertedSockaddr{}; if (!inetSockaddrToNativeSocketAddr(convertedSockaddr, sockAddrInternetPtr, addressLength)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i] %s: Error translating sceSockaddr to native sockaddr", nativeSocketId, __func__); + return hleLogError(Log::sceNet, -1, "[%i] %s: Error translating sceSockaddr to native sockaddr", nativeSocketId, __func__); } - DEBUG_LOG(SCENET, "[%i] sceNetInetConnect: Connecting to %s on %i", nativeSocketId, ip2str(convertedSockaddr.sin_addr, false).c_str(), ntohs(convertedSockaddr.sin_port)); + DEBUG_LOG(Log::sceNet, "[%i] sceNetInetConnect: Connecting to %s on %i", nativeSocketId, ip2str(convertedSockaddr.sin_addr, false).c_str(), ntohs(convertedSockaddr.sin_port)); // Attempt to connect using translated sockaddr int ret = connect(nativeSocketId, reinterpret_cast(&convertedSockaddr), sizeof(convertedSockaddr)); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: Error connecting %i: %s", nativeSocketId, __func__, error, strerror(error)); + return hleLogError(Log::sceNet, ret, "[%i] %s: Error connecting %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetListen(int socket, int backlog) { - WARN_LOG_ONCE(sceNetInetListen, SCENET, "UNTESTED %s(%i, %i)", __func__, socket, backlog); + WARN_LOG_ONCE(sceNetInetListen, Log::sceNet, "UNTESTED %s(%i, %i)", __func__, socket, backlog); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } // Map PSP_NET_INET_SOMAXCONN (128) to platform SOMAXCONN @@ -462,23 +458,23 @@ static int sceNetInetListen(int socket, int backlog) { const int ret = listen(socket, backlog); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: Error listening %i: %s", nativeSocketId, __func__, error, strerror(error)); + return hleLogError(Log::sceNet, ret, "[%i] %s: Error listening %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { - WARN_LOG_ONCE(sceNetInetListen, SCENET, "UNTESTED %s(%i, %08x, %08x)", __func__, socket, addrPtr, addrLenPtr); + WARN_LOG_ONCE(sceNetInetListen, Log::sceNet, "UNTESTED %s(%i, %08x, %08x)", __func__, socket, addrPtr, addrLenPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } // Attempt to accept a connection which will provide us with a sockaddrIn containing remote connection details @@ -489,26 +485,26 @@ static int sceNetInetAccept(int socket, u32 addrPtr, u32 addrLenPtr) { // Ensure that ERROR_WHEN_NONBLOCKING_CALL_OCCURS is not mapped to an hleLogError if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { - hleLogError(SCENET, ret, "[%i] %s: Encountered error %i: %s", nativeSocketId, __func__, error, strerror(error)); + hleLogError(Log::sceNet, ret, "[%i] %s: Encountered error %i: %s", nativeSocketId, __func__, error, strerror(error)); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } // Don't call writeSockAddrInToInetSockAddr when addrPtr is 0, otherwise do and send false to EFAULT if (addrPtr != 0 && !writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { sceNetInet->SetLastError(EFAULT); - hleLogError(SCENET, ret, "[%i] %s: Encountered error trying to write to addrPtr, probably invalid memory range", nativeSocketId, __func__); + hleLogError(Log::sceNet, ret, "[%i] %s: Encountered error trying to write to addrPtr, probably invalid memory range", nativeSocketId, __func__); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } int sceNetInetPoll(void *fds, u32 nfds, int timeout) { // timeout in miliseconds - DEBUG_LOG(SCENET, "UNTESTED sceNetInetPoll(%p, %d, %i) at %08x", fds, nfds, timeout, currentMIPS->pc); + DEBUG_LOG(Log::sceNet, "UNTESTED sceNetInetPoll(%p, %d, %i) at %08x", fds, nfds, timeout, currentMIPS->pc); const auto fdarray = static_cast(fds); // SceNetInetPollfd/pollfd, sceNetInetPoll() have similarity to BSD poll() but pollfd have different size on 64bit //#ifdef _WIN32 //WSAPoll only available for Vista or newer, so we'll use an alternative way for XP since Windows doesn't have poll function like *NIX if (nfds > FD_SETSIZE) { - ERROR_LOG(SCENET, "sceNetInetPoll: nfds=%i is greater than FD_SETSIZE=%i, unable to poll", nfds, FD_SETSIZE); + ERROR_LOG(Log::sceNet, "sceNetInetPoll: nfds=%i is greater than FD_SETSIZE=%i, unable to poll", nfds, FD_SETSIZE); return -1; } fd_set readfds, writefds, exceptfds; @@ -567,10 +563,10 @@ int sceNetInetPoll(void *fds, u32 nfds, int timeout) { // timeout in miliseconds } static int sceNetInetSelect(int maxfd, u32 readFdsPtr, u32 writeFdsPtr, u32 exceptFdsPtr, u32 timeoutPtr) { - WARN_LOG_ONCE(sceNetInetSelect, SCENET, "UNTESTED sceNetInetSelect(%i, %08x, %08x, %08x, %08x)", maxfd, readFdsPtr, writeFdsPtr, exceptFdsPtr, timeoutPtr); + WARN_LOG_ONCE(sceNetInetSelect, Log::sceNet, "UNTESTED sceNetInetSelect(%i, %08x, %08x, %08x, %08x)", maxfd, readFdsPtr, writeFdsPtr, exceptFdsPtr, timeoutPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } // Translate all input fd_sets to native fd_sets. None of these will be nullptr and so this needs to be checked later. @@ -589,9 +585,9 @@ static int sceNetInetSelect(int maxfd, u32 readFdsPtr, u32 writeFdsPtr, u32 exce if (inetTimeval != nullptr) { tv.tv_sec = inetTimeval->tv_sec; tv.tv_usec = inetTimeval->tv_usec; - DEBUG_LOG(SCENET, "%s: Timeout seconds=%lu, useconds=%lu", __func__, tv.tv_sec, tv.tv_usec); + DEBUG_LOG(Log::sceNet, "%s: Timeout seconds=%lu, useconds=%lu", __func__, tv.tv_sec, tv.tv_usec); } else { - WARN_LOG(SCENET, "%s: Encountered invalid timeout value, continuing anyway", __func__); + WARN_LOG(Log::sceNet, "%s: Encountered invalid timeout value, continuing anyway", __func__); } } @@ -599,39 +595,39 @@ static int sceNetInetSelect(int maxfd, u32 readFdsPtr, u32 writeFdsPtr, u32 exce const int ret = select(recomputedMaxFd, readFdsPtr != 0 ? &readFds : nullptr, writeFdsPtr != 0 ? &writeFds : nullptr, exceptFdsPtr != 0 ? &exceptFds : nullptr, timeoutPtr != 0 ? &tv : nullptr); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - ERROR_LOG(SCENET, "%s: Received error from select() %i: %s", __func__, error, strerror(error)); + ERROR_LOG(Log::sceNet, "%s: Received error from select() %i: %s", __func__, error, strerror(error)); } - INFO_LOG(SCENET, "%s: select() returned %i", __func__, ret); + INFO_LOG(Log::sceNet, "%s: select() returned %i", __func__, ret); return hleDelayResult(ret, "TODO: unhack", 500); } static int sceNetInetClose(int socket) { const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { sceNetInet->SetLastError(EBADF); - return hleLogWarning(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); + return hleLogWarning(Log::sceNet, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); } const int ret = close(inetSocket->GetNativeSocketId()); if (!sceNetInet->EraseNativeSocket(socket)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "%s: Unable to clear mapping of inetSocketId->nativeSocketId, was there contention?", __func__); + return hleLogError(Log::sceNet, -1, "%s: Unable to clear mapping of inetSocketId->nativeSocketId, was there contention?", __func__); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static u32 sceNetInetInetAddr(const char *hostname) { - ERROR_LOG(SCENET, "UNTESTED sceNetInetInetAddr(%s)", hostname); + ERROR_LOG(Log::sceNet, "UNTESTED sceNetInetInetAddr(%s)", hostname); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } in_addr inAddr{}; @@ -644,25 +640,25 @@ static u32 sceNetInetInetAddr(const char *hostname) { sceNetInet->SetLastErrorToMatchPlatform(); return inAddr.s_addr; } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { - ERROR_LOG(SCENET, "UNTESTED %s(%s, %08x)", __func__, hostname, addrPtr); + ERROR_LOG(Log::sceNet, "UNTESTED %s(%s, %08x)", __func__, hostname, addrPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } if (hostname == nullptr) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "%s: Invalid hostname: %08x", __func__, hostname); + return hleLogError(Log::sceNet, -1, "%s: Invalid hostname: %08x", __func__, hostname); } if (!Memory::IsValidAddress(addrPtr)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "%s: Invalid addrPtr: %08x", __func__, addrPtr); + return hleLogError(Log::sceNet, -1, "%s: Invalid addrPtr: %08x", __func__, addrPtr); } // Convert the input hostname into an inaddr @@ -676,96 +672,96 @@ static int sceNetInetInetAton(const char *hostname, u32 addrPtr) { if (ret == 0) { // inet_aton does not set errno when an error occurs, so neither should we - return hleLogError(SCENET, ret, "%s: Invalid hostname %s", __func__, hostname); + return hleLogError(Log::sceNet, ret, "%s: Invalid hostname %s", __func__, hostname); } // Write back to addrPtr if ret is != 0 Memory::Write_U32(inAddr.s_addr, addrPtr); - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static u32 sceNetInetInetNtop(int inetAddressFamily, u32 srcPtr, u32 dstBufPtr, u32 dstBufSize) { - WARN_LOG_ONCE(sceNetInetInetNtop, SCENET, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, inetAddressFamily, srcPtr, dstBufPtr, dstBufSize); + WARN_LOG_ONCE(sceNetInetInetNtop, Log::sceNet, "UNTESTED %s(%i, %08x, %08x, %i)", __func__, inetAddressFamily, srcPtr, dstBufPtr, dstBufSize); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto srcSockaddrIn = Memory::GetTypedPointerWriteRange(srcPtr, sizeof(SceNetInetSockaddrIn)); if (srcSockaddrIn == nullptr) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, 0, "%s: Invalid memory range for srcPtr %08x", __func__, srcPtr); + return hleLogError(Log::sceNet, 0, "%s: Invalid memory range for srcPtr %08x", __func__, srcPtr); } const auto dstBuf = Memory::GetTypedPointerWriteRange(dstBufPtr, dstBufSize); if (dstBuf == nullptr) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, 0, "%s: Invalid memory range for dstBufPtr %08x, size %i", __func__, dstBufPtr, dstBufSize); + return hleLogError(Log::sceNet, 0, "%s: Invalid memory range for dstBufPtr %08x, size %i", __func__, dstBufPtr, dstBufSize); } if (!dstBufSize) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, 0, "%s: dstBufSize must be > 0", __func__); + return hleLogError(Log::sceNet, 0, "%s: dstBufSize must be > 0", __func__); } int nativeAddressFamily; if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { sceNetInet->SetLastError(EAFNOSUPPORT); - return hleLogError(SCENET, 0, "%s: Unknown address family %04x", __func__, inetAddressFamily); + return hleLogError(Log::sceNet, 0, "%s: Unknown address family %04x", __func__, inetAddressFamily); } if (inet_ntop(nativeAddressFamily, reinterpret_cast(srcSockaddrIn), dstBuf, dstBufSize) == nullptr) { // Allow partial output in case it's desired for some reason } - return hleLogSuccessX(SCENET, dstBufPtr); + return hleLogSuccessX(Log::sceNet, dstBufPtr); } static int sceNetInetInetPton(int inetAddressFamily, const char *hostname, u32 dstPtr) { - WARN_LOG_ONCE(sceNetInetInetPton, SCENET, "UNTESTED %s(%i, %s, %08x)", __func__, inetAddressFamily, hostname, dstPtr); + WARN_LOG_ONCE(sceNetInetInetPton, Log::sceNet, "UNTESTED %s(%i, %s, %08x)", __func__, inetAddressFamily, hostname, dstPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } if (hostname == nullptr) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, 0, "%s: Invalid memory range for hostname %08x", __func__, hostname); + return hleLogError(Log::sceNet, 0, "%s: Invalid memory range for hostname %08x", __func__, hostname); } // IPv4, the only supported address family on PSP, will always be 32 bits const auto dst = Memory::GetTypedPointerWriteRange(dstPtr, sizeof(u32)); if (dst == nullptr) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, 0, "%s: Invalid memory range for dstPtr %08x, size %i", __func__, dstPtr, sizeof(u32)); + return hleLogError(Log::sceNet, 0, "%s: Invalid memory range for dstPtr %08x, size %i", __func__, dstPtr, sizeof(u32)); } // Translate inet address family to native int nativeAddressFamily; if (!SceNetInet::TranslateInetAddressFamilyToNative(nativeAddressFamily, inetAddressFamily)) { sceNetInet->SetLastError(EAFNOSUPPORT); - return hleLogError(SCENET, 0, "%s: Unknown address family %04x", __func__, inetAddressFamily); + return hleLogError(Log::sceNet, 0, "%s: Unknown address family %04x", __func__, inetAddressFamily); } const int ret = inet_pton(inetAddressFamily, hostname, dst); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "%s: inet_pton returned %i: %s", __func__, sceNetInet->GetLastError(), strerror(error)); + return hleLogError(Log::sceNet, ret, "%s: inet_pton returned %i: %s", __func__, sceNetInet->GetLastError(), strerror(error)); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { - ERROR_LOG(SCENET, "UNTESTED sceNetInetGetsockname(%i, %08x, %08x)", socket, addrPtr, addrLenPtr); + ERROR_LOG(Log::sceNet, "UNTESTED sceNetInetGetsockname(%i, %08x, %08x)", socket, addrPtr, addrLenPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { - ERROR_LOG(SCENET, "%s: Requested socket %i which does not exist", __func__, socket); + ERROR_LOG(Log::sceNet, "%s: Requested socket %i which does not exist", __func__, socket); return -1; } @@ -774,34 +770,34 @@ static int sceNetInetGetpeername(int socket, u32 addrPtr, u32 addrLenPtr) { socklen_t socklen = sizeof(sockaddr_in); if (!inetSockaddrToNativeSocketAddr(sockaddrIn, addrPtr, addrLenPtr)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i]: %s: Encountered invalid addrPtr %08x and/or invalid addrLenPtr %08x", nativeSocketId, addrPtr, addrLenPtr); + return hleLogError(Log::sceNet, -1, "[%i]: %s: Encountered invalid addrPtr %08x and/or invalid addrLenPtr %08x", nativeSocketId, addrPtr, addrLenPtr); } const int ret = getpeername(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: Failed to execute getpeername %i: %s", nativeSocketId, __func__, error, strerror(error)); + return hleLogError(Log::sceNet, ret, "[%i] %s: Failed to execute getpeername %i: %s", nativeSocketId, __func__, error, strerror(error)); } // Write output of getpeername to the input addrPtr if (!writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getpeername to SceNetInetSockaddrIn", nativeSocketId, __func__); + return hleLogError(Log::sceNet, -1, "[%i] %s: Failed to write results of getpeername to SceNetInetSockaddrIn", nativeSocketId, __func__); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { - ERROR_LOG(SCENET, "UNTESTED %s(%i, %08x, %08x)", __func__, socket, addrPtr, addrLenPtr); + ERROR_LOG(Log::sceNet, "UNTESTED %s(%i, %08x, %08x)", __func__, socket, addrPtr, addrLenPtr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } int nativeSocketId; if (!sceNetInet->GetNativeSocketIdForInetSocketId(nativeSocketId, socket)) { sceNetInet->SetLastError(EINVAL); - return hleLogError(SCENET, -1, "%s: Requested socket %i which does not exist", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Requested socket %i which does not exist", __func__, socket); } // Set sockaddrIn to the result of getsockname @@ -810,66 +806,66 @@ static int sceNetInetGetsockname(int socket, u32 addrPtr, u32 addrLenPtr) { const int ret = getsockname(nativeSocketId, reinterpret_cast(&sockaddrIn), &socklen); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i] %s: Failed to execute getsockname %i: %s", nativeSocketId, __func__, error, strerror(error)); + return hleLogError(Log::sceNet, ret, "[%i] %s: Failed to execute getsockname %i: %s", nativeSocketId, __func__, error, strerror(error)); } // Write output of getsockname to the input addrPtr if (!writeSockAddrInToInetSockAddr(addrPtr, addrLenPtr, sockaddrIn)) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i] %s: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId, __func__); + return hleLogError(Log::sceNet, -1, "[%i] %s: Failed to write results of getsockname to SceNetInetSockaddrIn", nativeSocketId, __func__); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetRecv(int socket, u32 bufPtr, u32 bufLen, int flags) { - WARN_LOG_ONCE(sceNetInetRecv, SCENET, "UNTESTED sceNetInetRecv(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); + WARN_LOG_ONCE(sceNetInetRecv, Log::sceNet, "UNTESTED sceNetInetRecv(%i, %08x, %i, %08x)", socket, bufPtr, bufLen, flags); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { sceNetInet->SetLastError(EBADF); - return hleLogError(SCENET, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to close socket %i which does not exist", __func__, socket); } const auto nativeSocketId = inetSocket->GetNativeSocketId(); const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); if (dstBuf == nullptr) { - return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); + return hleLogError(Log::sceNet, -1, "[%i] %s: Invalid pointer %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); } const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking()); const int ret = recv(nativeSocketId, dstBuf, bufLen, nativeFlags); - DEBUG_LOG(SCENET, "[%i] %s: Called recv with buf size %i which returned %i", nativeSocketId, __func__, bufLen, ret); + DEBUG_LOG(Log::sceNet, "[%i] %s: Called recv with buf size %i which returned %i", nativeSocketId, __func__, bufLen, ret); if (ret < 0) { if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { - ERROR_LOG(SCENET, "[%i]: %s: recv() encountered error %i: %s", socket, __func__, error, strerror(error)); + ERROR_LOG(Log::sceNet, "[%i]: %s: recv() encountered error %i: %s", socket, __func__, error, strerror(error)); } } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 fromAddr, u32 fromLenAddr) { - WARN_LOG_ONCE(sceNetInetRecvFrom, SCENET, "UNTESTED sceNetInetRecvfrom(%i, %08x, %i, %08x, %08x, %08x)", socket, bufPtr, bufLen, flags, fromAddr, fromLenAddr); + WARN_LOG_ONCE(sceNetInetRecvFrom, Log::sceNet, "UNTESTED sceNetInetRecvfrom(%i, %08x, %i, %08x, %08x, %08x)", socket, bufPtr, bufLen, flags, fromAddr, fromLenAddr); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { sceNetInet->SetLastError(EBADF); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } const auto nativeSocketId = inetSocket->GetNativeSocketId(); const auto dstBuf = Memory::GetTypedPointerWriteRange(bufPtr, bufLen); if (dstBuf == nullptr) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); + return hleLogError(Log::sceNet, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); } // Translate PSP flags to native flags and prepare sockaddrIn to receive peer address @@ -882,7 +878,7 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 if (ret < 0) { if (const auto error = sceNetInet->SetLastErrorToMatchPlatform(); error != 0 && error != ERROR_WHEN_NONBLOCKING_CALL_OCCURS) { - WARN_LOG(SCENET, "[%i] %s: Received error %i: %s", nativeSocketId, __func__, error, strerror(error)); + WARN_LOG(Log::sceNet, "[%i] %s: Received error %i: %s", nativeSocketId, __func__, error, strerror(error)); } return hleDelayResult(ret, "TODO: unhack", 500); } @@ -890,30 +886,30 @@ static int sceNetInetRecvfrom(int socket, u32 bufPtr, u32 bufLen, int flags, u32 // If ret was successful, write peer sockaddr to input fromAddr if (ret > 0) { if (!writeSockAddrInToInetSockAddr(fromAddr, fromLenAddr, sockaddrIn)) { - ERROR_LOG(SCENET, "[%i] %s: Error writing native sockaddr to sceSockaddr", nativeSocketId, __func__); + ERROR_LOG(Log::sceNet, "[%i] %s: Error writing native sockaddr to sceSockaddr", nativeSocketId, __func__); } - INFO_LOG(SCENET, "[%i] %s: Got %i bytes from recvfrom", nativeSocketId, __func__, ret); + INFO_LOG(Log::sceNet, "[%i] %s: Got %i bytes from recvfrom", nativeSocketId, __func__, ret); } return hleDelayResult(ret, "TODO: unhack", 500); } static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { - WARN_LOG_ONCE(sceNetInetSend, SCENET, "UNTESTED %s(%i, %08x, %i, %08x)", __func__, socket, bufPtr, bufLen, flags); + WARN_LOG_ONCE(sceNetInetSend, Log::sceNet, "UNTESTED %s(%i, %08x, %i, %08x)", __func__, socket, bufPtr, bufLen, flags); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { sceNetInet->SetLastError(EBADF); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } const auto buf = Memory::GetTypedPointerRange(bufPtr, bufLen); if (buf == nullptr) { sceNetInet->SetLastError(EFAULT); - return hleLogError(SCENET, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", socket, __func__, bufPtr, bufLen); + return hleLogError(Log::sceNet, -1, "[%i] %s: Invalid pointer range: %08x (size %i)", socket, __func__, bufPtr, bufLen); } // Translate PSP flags to native flags and send @@ -921,28 +917,28 @@ static int sceNetInetSend(int socket, u32 bufPtr, u32 bufLen, int flags) { const int ret = send(inetSocket->GetNativeSocketId(), buf, bufLen, nativeFlags); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - return hleLogError(SCENET, ret, "[%i]: %s: send() encountered error %i: %s", socket, __func__, error, strerror(error)); + return hleLogError(Log::sceNet, ret, "[%i]: %s: send() encountered error %i: %s", socket, __func__, error, strerror(error)); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 toAddr, u32 toLen) { - ERROR_LOG_ONCE(sceNetInetSendto, SCENET, "UNTESTED sceNetInetSendto(%i, %08x, %i, %08x, %08x, %i)", socket, bufPtr, bufLen, flags, toAddr, toLen); + ERROR_LOG_ONCE(sceNetInetSendto, Log::sceNet, "UNTESTED sceNetInetSendto(%i, %08x, %i, %08x, %08x, %i)", socket, bufPtr, bufLen, flags, toAddr, toLen); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { sceNetInet->SetLastError(EBADF); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } const int nativeSocketId = inetSocket->GetNativeSocketId(); const auto srcBuf = Memory::GetTypedPointerRange(bufPtr, bufLen); if (srcBuf == nullptr) { - ERROR_LOG(SCENET, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); + ERROR_LOG(Log::sceNet, "[%i] %s: Invalid pointer range: %08x (size %i)", nativeSocketId, __func__, bufPtr, bufLen); return -1; } @@ -950,49 +946,49 @@ static int sceNetInetSendto(int socket, u32 bufPtr, u32 bufLen, int flags, u32 t const int nativeFlags = SceNetInet::TranslateInetFlagsToNativeFlags(flags, inetSocket->IsNonBlocking()); sockaddr_in convertedSockAddr{}; if (!inetSockaddrToNativeSocketAddr(convertedSockAddr, toAddr, toLen)) { - ERROR_LOG(SCENET, "[%i] %s: Unable to translate sceSockAddr to native sockaddr", nativeSocketId, __func__); + ERROR_LOG(Log::sceNet, "[%i] %s: Unable to translate sceSockAddr to native sockaddr", nativeSocketId, __func__); return -1; } - DEBUG_LOG(SCENET, "[%i] %s: Writing %i bytes to %s on port %i", nativeSocketId, __func__, bufLen, ip2str(convertedSockAddr.sin_addr, false).c_str(), ntohs(convertedSockAddr.sin_port)); + DEBUG_LOG(Log::sceNet, "[%i] %s: Writing %i bytes to %s on port %i", nativeSocketId, __func__, bufLen, ip2str(convertedSockAddr.sin_addr, false).c_str(), ntohs(convertedSockAddr.sin_port)); const int ret = sendto(nativeSocketId, srcBuf, bufLen, nativeFlags, reinterpret_cast(&convertedSockAddr), sizeof(sockaddr_in)); - DEBUG_LOG(SCENET, "[%i] %s: sendto returned %i", nativeSocketId, __func__, ret); + DEBUG_LOG(Log::sceNet, "[%i] %s: sendto returned %i", nativeSocketId, __func__, ret); if (ret < 0) { const auto error = sceNetInet->SetLastErrorToMatchPlatform(); - WARN_LOG(SCENET, "[%i] %s: Got error %i=%s", nativeSocketId, __func__, error, strerror(error)); + WARN_LOG(Log::sceNet, "[%i] %s: Got error %i=%s", nativeSocketId, __func__, error, strerror(error)); } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } static int sceNetInetGetErrno() { - ERROR_LOG_ONCE(sceNetInetGetErrno, SCENET, "UNTESTED sceNetInetGetErrno()"); + ERROR_LOG_ONCE(sceNetInetGetErrno, Log::sceNet, "UNTESTED sceNetInetGetErrno()"); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto nativeError = sceNetInet->GetLastError(); if (nativeError != ERROR_WHEN_NONBLOCKING_CALL_OCCURS && nativeError != 0) { - INFO_LOG(SCENET, "Requested %s %i=%s", __func__, nativeError, strerror(nativeError)); + INFO_LOG(Log::sceNet, "Requested %s %i=%s", __func__, nativeError, strerror(nativeError)); } return SceNetInet::TranslateNativeErrorToInetError(nativeError); } static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { - WARN_LOG_ONCE(sceNetInetSend, SCENET, "UNTESTED sceNetInetBind(%i, %08x, %08x)", socket, addrPtr, addrLen); + WARN_LOG_ONCE(sceNetInetSend, Log::sceNet, "UNTESTED sceNetInetBind(%i, %08x, %08x)", socket, addrPtr, addrLen); const auto sceNetInet = SceNetInet::Get(); if (!sceNetInet) { - return hleLogError(SCENET, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); + return hleLogError(Log::sceNet, ERROR_NET_INET_CONFIG_INVALID_ARG, "Inet Subsystem Not Running - Use sceNetInetInit"); } const auto inetSocket = sceNetInet->GetInetSocket(socket); if (!inetSocket) { sceNetInet->SetLastError(EBADF); - return hleLogError(SCENET, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); + return hleLogError(Log::sceNet, -1, "%s: Attempting to operate on unmapped socket %i", __func__, socket); } const int nativeSocketId = inetSocket->GetNativeSocketId(); @@ -1000,7 +996,7 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { // Convert PSP bind addr to native bind addr sockaddr_in convertedSockaddr{}; if (!inetSockaddrToNativeSocketAddr(convertedSockaddr, addrPtr, addrLen)) { - ERROR_LOG(SCENET, "[%i] Error translating sceSockaddr to native sockaddr", nativeSocketId); + ERROR_LOG(Log::sceNet, "[%i] Error translating sceSockaddr to native sockaddr", nativeSocketId); return -1; } socklen_t socklen = sizeof(convertedSockaddr); @@ -1008,16 +1004,16 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { // Get default outbound sockaddr when INADDR_ANY or INADDR_BROADCAST are used if (const auto addr = convertedSockaddr.sin_addr.s_addr; addr == INADDR_ANY || addr == INADDR_BROADCAST) { if (!getDefaultOutboundSockaddr(convertedSockaddr, socklen)) { - WARN_LOG(SCENET, "Failed to get default bound address"); + WARN_LOG(Log::sceNet, "Failed to get default bound address"); return -1; } } // TODO: check whether setting to blocking and then non-blocking is valid setBlockingMode(nativeSocketId, false); - INFO_LOG(SCENET, "[%i] Binding to family %i, port %i, addr %s", nativeSocketId, convertedSockaddr.sin_family, ntohs(convertedSockaddr.sin_port), ip2str(convertedSockaddr.sin_addr, false).c_str()); + INFO_LOG(Log::sceNet, "[%i] Binding to family %i, port %i, addr %s", nativeSocketId, convertedSockaddr.sin_family, ntohs(convertedSockaddr.sin_port), ip2str(convertedSockaddr.sin_addr, false).c_str()); const int ret = bind(nativeSocketId, reinterpret_cast(&convertedSockaddr), socklen); - INFO_LOG(SCENET, "Bind returned %i for fd=%i", ret, nativeSocketId); + INFO_LOG(Log::sceNet, "Bind returned %i for fd=%i", ret, nativeSocketId); setBlockingMode(nativeSocketId, inetSocket->IsNonBlocking()); // Set UPnP @@ -1034,11 +1030,11 @@ static int sceNetInetBind(int socket, u32 addrPtr, u32 addrLen) { } // TODO: Unknown IP protocol 000f when attempting to set up UPnP port forwarding default: { - WARN_LOG(SCENET, "[%i]: Unknown IP protocol %04x when attempting to set up UPnP port forwarding", nativeSocketId, inetSocket->GetProtocol()); + WARN_LOG(Log::sceNet, "[%i]: Unknown IP protocol %04x when attempting to set up UPnP port forwarding", nativeSocketId, inetSocket->GetProtocol()); break; } } - return hleLogSuccessI(SCENET, ret); + return hleLogSuccessI(Log::sceNet, ret); } // TODO: fix retmasks @@ -1306,7 +1302,7 @@ std::shared_ptr SceNetInet::CreateAndAssociateInetSocket(int nativeS int inetSocketId = ++mCurrentInetSocketId; if (const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); it != mInetSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to re-associate socket from already-associated inetSocketId: %i", __func__, inetSocketId); + WARN_LOG(Log::sceNet, "%s: Attempted to re-associate socket from already-associated inetSocketId: %i", __func__, inetSocketId); return nullptr; } auto inetSocket = std::make_shared(inetSocketId, nativeSocketId, protocol, nonBlocking); @@ -1320,7 +1316,7 @@ std::shared_ptr SceNetInet::GetInetSocket(int inetSocketId) { const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); if (it == mInetSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to get unassociated socket from inetSocketId: %i", __func__, inetSocketId); + WARN_LOG(Log::sceNet, "%s: Attempted to get unassociated socket from inetSocketId: %i", __func__, inetSocketId); return nullptr; } return it->second; @@ -1340,7 +1336,7 @@ bool SceNetInet::EraseNativeSocket(int inetSocketId) { const auto it = mInetSocketIdToNativeSocket.find(inetSocketId); if (it == mInetSocketIdToNativeSocket.end()) { - WARN_LOG(SCENET, "%s: Attempted to delete unassociated socket from inetSocketId: %i", __func__, inetSocketId); + WARN_LOG(Log::sceNet, "%s: Attempted to delete unassociated socket from inetSocketId: %i", __func__, inetSocketId); return false; } mInetSocketIdToNativeSocket.erase(it); @@ -1356,7 +1352,7 @@ bool SceNetInet::TranslateInetFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, FD_ZERO(&destFdSet); const auto sceFdSet = Memory::GetTypedPointerRange(fdsPtr, sizeof(PspInetFdSetOperations::FdSet)); if (sceFdSet == nullptr) { - ERROR_LOG(SCENET, "%s: Invalid fdsPtr %08x", __func__, fdsPtr); + ERROR_LOG(Log::sceNet, "%s: Invalid fdsPtr %08x", __func__, fdsPtr); return false; } @@ -1367,15 +1363,15 @@ bool SceNetInet::TranslateInetFdSetToNativeFdSet(int &maxFd, fd_set& destFdSet, maxFd = std::max(nativeSocketId + 1, maxFd); if (PspInetFdSetOperations::IsSet(*sceFdSet, inetSocket)) { if (++setSize > FD_SETSIZE) { - ERROR_LOG(SCENET, "%s: Encountered input FD_SET which is greater than max supported size %i", __func__, setSize); + ERROR_LOG(Log::sceNet, "%s: Encountered input FD_SET which is greater than max supported size %i", __func__, setSize); return false; } - DEBUG_LOG(SCENET, "%s: Translating input %i into %i", __func__, inetSocket, nativeSocketId); + DEBUG_LOG(Log::sceNet, "%s: Translating input %i into %i", __func__, inetSocket, nativeSocketId); FD_SET(nativeSocketId, &destFdSet); } } - DEBUG_LOG(SCENET, "%s: Translated %i sockets", __func__, setSize); + DEBUG_LOG(Log::sceNet, "%s: Translated %i sockets", __func__, setSize); return true; } From df63e194643d7aaaade4406a07ab03fc8da30392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 4 Jan 2025 17:41:18 +0100 Subject: [PATCH 9/9] Warning fixes, Windows compat hacks --- Core/HLE/sceNetInet.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceNetInet.cpp b/Core/HLE/sceNetInet.cpp index 75e0421d29..035cec0610 100644 --- a/Core/HLE/sceNetInet.cpp +++ b/Core/HLE/sceNetInet.cpp @@ -142,7 +142,7 @@ private: }; static bool inetSockaddrToNativeSocketAddr(sockaddr_in &dest, u32 sockAddrInternetPtr, size_t addressLength) { - const auto inetSockaddrIn = Memory::GetTypedPointerRange(sockAddrInternetPtr, addressLength); + const auto inetSockaddrIn = Memory::GetTypedPointerRange(sockAddrInternetPtr, (u32)addressLength); if (inetSockaddrIn == nullptr || addressLength == 0) { return false; } @@ -188,7 +188,7 @@ static bool writeSockAddrInToInetSockAddr(u32 destAddrPtr, u32 destAddrLenPtr, s static int setBlockingMode(int nativeSocketId, bool nonblocking) { #if PPSSPP_PLATFORM(WINDOWS) unsigned long val = nonblocking ? 1 : 0; - return ioctlsocket(fd, FIONBIO, &val); + return ioctlsocket(nativeSocketId, FIONBIO, &val); #else // Change to Non-Blocking Mode if (nonblocking) { @@ -1102,6 +1102,13 @@ std::unordered_map SceNetInet::gInetProtocolToNativeProtoc { PSP_NET_INET_IPPROTO_RAW, IPPROTO_RAW }, }; +// Windows compat workarounds (ugly! may not work!) +#if PPSSPP_PLATFORM(WINDOWS) +#define SO_REUSEPORT (SO_BROADCAST|SO_REUSEADDR) +#define SO_TIMESTAMP 0 +#define MSG_DONTWAIT 0 +#endif + // TODO: commented out optnames std::unordered_map SceNetInet::gInetSocketOptnameToNativeOptname = { { INET_SO_ACCEPTCONN, SO_ACCEPTCONN }, @@ -1261,7 +1268,7 @@ int SceNetInet::TranslateInetFlagsToNativeFlags(const int messageFlags, const bo if (const int missingFlags = messageFlags & ~foundFlags; missingFlags != 0) { for (int i = 0; i < sizeof(int) * 8; i++) { if (const int val = 1 << i; (missingFlags & val) != 0) { - DEBUG_LOG(SCENET, "Encountered unsupported platform flag at bit %i (actual value %04x), undefined behavior may ensue.", i, val); + DEBUG_LOG(Log::sceNet, "Encountered unsupported platform flag at bit %i (actual value %04x), undefined behavior may ensue.", i, val); } } }