Skip to content

Commit

Permalink
Merge pull request #19880 from hrydgard/online-resolver-refactor
Browse files Browse the repository at this point in the history
sceNetResolver and sockopt refactoring
  • Loading branch information
hrydgard authored Jan 17, 2025
2 parents ea36cb7 + 4757f8c commit 2502d7b
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 286 deletions.
5 changes: 5 additions & 0 deletions Common/Net/SocketCompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
extern "C" struct hostent *gethostbyname(const char *name);
#endif // defined(HAVE_LIBNX) || PPSSPP_PLATFORM(SWITCH)

#if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE)
// Missing toolchain define
#define INADDR_NONE 0xFFFFFFFF
#endif

// TODO: move this to some common set
#if PPSSPP_PLATFORM(WINDOWS)
#undef ESHUTDOWN
Expand Down
2 changes: 1 addition & 1 deletion Core/HLE/NetInetConstants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ int convertSockoptNamePSP2Host(int optname, int level) {
#endif
}
}
return hleLogError(Log::sceNet, optname, "Unknown PSP's SockOpt Name (Level = %08x)", level);
return hleLogError(Log::sceNet, optname, "Unknown or unsupported PSP's SockOpt Name (Level = %08x)", level);
}

int convertSockoptNameHost2PSP(int optname, int level) {
Expand Down
3 changes: 2 additions & 1 deletion Core/HLE/NetInetConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,10 @@ enum {
#define PSP_NET_INET_SO_RCVTIMEO 0x1006 // receive timeout
#define PSP_NET_INET_SO_ERROR 0x1007 // get error status and clear
#define PSP_NET_INET_SO_TYPE 0x1008 // get socket type
#define PSP_NET_INET_SO_NBIO 0x1009 // SO_NONBLOCK ? // set to non-blocking I/O mode (on true, returning 0x80 when retrieved using getsockopt?)
#define PSP_NET_INET_SO_NBIO 0x1009 // SO_NONBLOCK ? // set to non-blocking I/O mode (on true, returning 0x80 when retrieved using getsockopt?). Unclear if correct.
#define PSP_NET_INET_SO_BIO 0x100a // set to blocking I/O mode (not using the optval just like SO_NBIO?)
//#define PSP_NET_INET_SO_NONBLOCK 0x100b // set to blocking or non-blocking I/O mode (using the optval)
#define PSP_NET_INET_SO_NOSIGPIPE 0x1022 // WARNING: SPECULATION

// User-settable options (used with setsockopt)
#define PSP_NET_INET_TCP_NODELAY 0x01 // don't delay send to coalesce packets
Expand Down
33 changes: 14 additions & 19 deletions Core/HLE/sceNet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@
#include "Core/HLE/sceNetInet.h"
#include "Core/HLE/sceNetResolver.h"

#if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE)
// Missing toolchain define
#define INADDR_NONE 0xFFFFFFFF
#endif

bool netInited;

u32 netDropRate = 0;
Expand All @@ -67,8 +62,6 @@ u32 netThread2Addr = 0;

static struct SceNetMallocStat netMallocStat;

static std::map<int, NetResolver> netResolvers;

static std::map<int, ApctlHandler> apctlHandlers;

std::string defaultNetConfigName = "NetConf";
Expand Down Expand Up @@ -201,20 +194,22 @@ bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) {
const JsonNode *workingIdsNode = game.getArray("known_working_ids");
const JsonNode *otherIdsNode = game.getArray("other_ids");
const JsonNode *notWorkingIdsNode = game.getArray("not_working_ids");
if (!workingIdsNode) {
if (!workingIdsNode && !otherIdsNode && !notWorkingIdsNode) {
// We ignore this game.
continue;
}

bool found = false;

std::vector<std::string> ids;
JsonGet(workingIdsNode->value).getStringVector(&ids);
for (auto &id : ids) {
if (id == gameID) {
found = true;
dns->state = InfraGameState::Working;
break;
if (workingIdsNode) {
JsonGet(workingIdsNode->value).getStringVector(&ids);
for (auto &id : ids) {
if (id == gameID) {
found = true;
dns->state = InfraGameState::Working;
break;
}
}
}
if (!found && notWorkingIdsNode) {
Expand All @@ -229,7 +224,7 @@ bool LoadDNSForGameID(std::string_view gameID, InfraDNSConfig *dns) {
}
}
if (!found && otherIdsNode) {
// Check the "other" array, not sure what we do with these.
// Check the "other" array, we're gonna try this, but less confidently :P
JsonGet(otherIdsNode->value).getStringVector(&ids);
for (auto &id : ids) {
if (id == gameID) {
Expand Down Expand Up @@ -405,7 +400,7 @@ void __NetShutdown() {
// Network Cleanup
Net_Term();

SceNetResolver::Shutdown();
__NetResolverShutdown();
__NetInetShutdown();
__NetApctlShutdown();
__ResetInitNetLib();
Expand Down Expand Up @@ -500,7 +495,7 @@ void __NetDoState(PointerWrap &p) {
// Discard leftover events
apctlEvents.clear();
// Discard created resolvers for now (since i'm not sure whether the information in the struct is sufficient or not, and we don't support multi-threading yet anyway)
SceNetResolver::Shutdown();
__NetResolverShutdown();
}
}

Expand Down Expand Up @@ -994,10 +989,10 @@ void NetApctl_InitInfo(int confId) {
// The reason we need autoconfig is that private Servers may need to use custom DNS Server - and most games are now
// best played on private servers (only a few official ones remain, if any).
if (g_Config.bInfrastructureAutoDNS) {
INFO_LOG(Log::sceNet, "Responding to game query with AutoDNS address");
INFO_LOG(Log::sceNet, "Responding to game query with AutoDNS address: %s", g_infraDNSConfig.dns.c_str());
truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), g_infraDNSConfig.dns);
} else {
INFO_LOG(Log::sceNet, "Responding to game query with manual DNS address");
INFO_LOG(Log::sceNet, "Responding to game query with manual DNS address: %s", g_Config.sInfrastructureDNSServer.c_str());
truncate_cpy(netApctlInfo.primaryDns, sizeof(netApctlInfo.primaryDns), g_Config.sInfrastructureDNSServer);
}

Expand Down
69 changes: 38 additions & 31 deletions Core/HLE/sceNetInet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,39 +458,46 @@ static int sceNetInetSetsockopt(int socket, int level, int optname, u32 optvalPt

timeval tval{};
// TODO: Ignoring SO_NBIO/SO_NONBLOCK flag if we always use non-blocking mode (ie. simulated blocking mode)
if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_NBIO) {
inetSock->nonblocking = optval;
return hleLogSuccessI(Log::sceNet, 0);
}
// FIXME: Should we ignore SO_BROADCAST flag since we are using fake broadcast (ie. only broadcast to friends),
// But Infrastructure/Online play might need to use broadcast for SSDP and to support LAN MP with real PSP
/*else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_BROADCAST) {
//memcpy(&sock->so_broadcast, (int*)optval, std::min(sizeof(sock->so_broadcast), optlen));
return hleLogSuccessI(Log::sceNet, 0);
}*/
// TODO: Ignoring SO_REUSEADDR flag to prevent disrupting multiple-instance feature
else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_REUSEADDR) {
//memcpy(&sock->reuseaddr, (int*)optval, std::min(sizeof(sock->reuseaddr), optlen));
return hleLogSuccessI(Log::sceNet, 0);
}
// TODO: Ignoring SO_REUSEPORT flag to prevent disrupting multiple-instance feature (not sure if PSP has SO_REUSEPORT or not tho, defined as 15 on Android)
else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_REUSEPORT) { // 15
//memcpy(&sock->reuseport, (int*)optval, std::min(sizeof(sock->reuseport), optlen));
return hleLogSuccessI(Log::sceNet, 0);
}
// TODO: Ignoring SO_NOSIGPIPE flag to prevent crashing PPSSPP (not sure if PSP has NOSIGPIPE or not tho, defined as 0x1022 on Darwin)
else if (level == PSP_NET_INET_SOL_SOCKET && optname == 0x1022) { // PSP_NET_INET_SO_NOSIGPIPE ?
//memcpy(&sock->nosigpipe, (int*)optval, std::min(sizeof(sock->nosigpipe), optlen));
return hleLogSuccessI(Log::sceNet, 0);
}
// It seems UNO game will try to set socket buffer size with a very large size and ended getting error (-1), so we should also limit the buffer size to replicate PSP behavior
else if (level == PSP_NET_INET_SOL_SOCKET && (optname == PSP_NET_INET_SO_RCVBUF || optname == PSP_NET_INET_SO_SNDBUF)) { // PSP_NET_INET_SO_NOSIGPIPE ?
// TODO: For SOCK_STREAM max buffer size is 8 Mb on BSD, while max SOCK_DGRAM is 65535 minus the IP & UDP Header size
if (optval > 8 * 1024 * 1024) {
UpdateErrnoFromHost(ENOBUFS, __FUNCTION__); // FIXME: return ENOBUFS for SOCK_STREAM, and EINVAL for SOCK_DGRAM
return hleLogError(Log::sceNet, -1, "buffer size too large?");
if (level == PSP_NET_INET_SOL_SOCKET) {
switch (optname) {
case PSP_NET_INET_SO_NBIO:
inetSock->nonblocking = optval;
return hleLogSuccessI(Log::sceNet, 0);
// FIXME: Should we ignore SO_BROADCAST flag since we are using fake broadcast (ie. only broadcast to friends),
// But Infrastructure/Online play might need to use broadcast for SSDP and to support LAN MP with real PSP
/*else if (level == PSP_NET_INET_SOL_SOCKET && optname == PSP_NET_INET_SO_BROADCAST) {
//memcpy(&sock->so_broadcast, (int*)optval, std::min(sizeof(sock->so_broadcast), optlen));
return hleLogSuccessI(Log::sceNet, 0);
}*/
// TODO: Ignoring SO_REUSEADDR flag to prevent disrupting multiple-instance feature
case PSP_NET_INET_SO_REUSEADDR:
//memcpy(&sock->reuseaddr, (int*)optval, std::min(sizeof(sock->reuseaddr), optlen));
return hleLogSuccessI(Log::sceNet, 0);

// TODO: Ignoring SO_REUSEPORT flag to prevent disrupting multiple-instance feature (not sure if PSP has SO_REUSEPORT or not tho, defined as 15 on Android)
case PSP_NET_INET_SO_REUSEPORT: // 15
//memcpy(&sock->reuseport, (int*)optval, std::min(sizeof(sock->reuseport), optlen));
return hleLogSuccessI(Log::sceNet, 0);

// TODO: Ignoring SO_NOSIGPIPE flag to prevent crashing PPSSPP (not sure if PSP has NOSIGPIPE or not tho, defined as 0x1022 on Darwin)
case PSP_NET_INET_SO_NOSIGPIPE: // WARNING: Not sure about this one. But we definitely don't want signals, so we ignore it.
//memcpy(&sock->nosigpipe, (int*)optval, std::min(sizeof(sock->nosigpipe), optlen));
return hleLogWarning(Log::sceNet, 0, "NOSIGPIPE should never be modified (should always be off)");

// It seems UNO game will try to set socket buffer size with a very large size and ended getting error (-1), so we should also limit the buffer size to replicate PSP behavior
case PSP_NET_INET_SO_RCVBUF:
case PSP_NET_INET_SO_SNDBUF: // PSP_NET_INET_SO_NOSIGPIPE ?
// TODO: For SOCK_STREAM max buffer size is 8 Mb on BSD, while max SOCK_DGRAM is 65535 minus the IP & UDP Header size
if (optval > 8 * 1024 * 1024) {
UpdateErrnoFromHost(ENOBUFS, __FUNCTION__); // FIXME: return ENOBUFS for SOCK_STREAM, and EINVAL for SOCK_DGRAM
return hleLogError(Log::sceNet, -1, "buffer size too large?");
}
break;
default:
break;
}
}

int retval = 0;
// PSP timeout are a single 32bit value (micro seconds)
if (level == PSP_NET_INET_SOL_SOCKET && optval && (optname == PSP_NET_INET_SO_RCVTIMEO || optname == PSP_NET_INET_SO_SNDTIMEO)) {
Expand Down
Loading

0 comments on commit 2502d7b

Please sign in to comment.