Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Adhoc] Fix frozen (0 FPS) issue on Kao Challengers and Asterix & Obelix XX #14106

Merged
merged 2 commits into from
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions Core/HLE/proAdhoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ uint16_t portOffset;
uint32_t minSocketTimeoutUS;
uint32_t fakePoolSize = 0;
SceNetAdhocMatchingContext * contexts = NULL;
char* dummyPeekBuf64k = NULL;
int dummyPeekBuf64kSize = 65536;
int one = 1;
bool friendFinderRunning = false;
SceNetAdhocctlPeerInfo * friends = NULL;
Expand Down Expand Up @@ -1908,12 +1910,7 @@ u_long getAvailToRecv(int sock, int udpBufferSize) {
return 0;

if (udpBufferSize > 0 && n > 0) {
// TODO: Cap number of bytes of full DGRAM message(s) up to buffer size
char buf[8];
// Each recv can only received one message, not sure how to read the next pending msg without actually receiving the first one
err = recvfrom(sock, buf, sizeof(buf), MSG_PEEK | MSG_NOSIGNAL | MSG_TRUNC, NULL, NULL);
if (err >= 0)
return (u_long)err;
// TODO: Cap number of bytes of full DGRAM message(s) up to buffer size, but may cause Warriors Orochi 2 to get FPS drops
}
return n;
}
Expand Down
4 changes: 4 additions & 0 deletions Core/HLE/proAdhoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#undef EISCONN
#undef EALREADY
#undef ETIMEDOUT
#undef EOPNOTSUPP
#define errno WSAGetLastError()
#define ESHUTDOWN WSAESHUTDOWN
#define ECONNABORTED WSAECONNABORTED
Expand All @@ -77,6 +78,7 @@
#define EISCONN WSAEISCONN
#define EALREADY WSAEALREADY
#define ETIMEDOUT WSAETIMEDOUT
#define EOPNOTSUPP WSAEOPNOTSUPP
inline bool connectInProgress(int errcode){ return (errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS || errcode == WSAEALREADY); }
inline bool isDisconnected(int errcode) { return (errcode == WSAECONNRESET || errcode == WSAECONNABORTED || errcode == WSAESHUTDOWN); }
#else
Expand Down Expand Up @@ -915,6 +917,8 @@ extern int defaultWlanChannel; // Default WLAN Channel for Auto, JPCSP uses 11

extern uint32_t fakePoolSize;
extern SceNetAdhocMatchingContext * contexts;
extern char* dummyPeekBuf64k;
extern int dummyPeekBuf64kSize;
extern int one;
extern bool friendFinderRunning;
extern SceNetAdhocctlPeerInfo * friends;
Expand Down
3 changes: 3 additions & 0 deletions Core/HLE/sceNet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ void __NetInit() {
g_adhocServerIP.in.sin_port = htons(SERVER_PORT); //27312 // Maybe read this from config too
g_adhocServerIP.in.sin_addr.s_addr = INADDR_NONE;

dummyPeekBuf64k = (char*)malloc(dummyPeekBuf64kSize);
InitLocalhostIP();

SceNetEtherAddr mac;
Expand Down Expand Up @@ -235,6 +236,8 @@ void __NetShutdown() {

// 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();

free(dummyPeekBuf64k);
}

static void __UpdateApctlHandlers(u32 oldState, u32 newState, u32 flag, u32 error) {
Expand Down
12 changes: 10 additions & 2 deletions Core/HLE/sceNetAdhoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,11 @@ int DoBlockingPdpRecv(int uid, AdhocSocketRequest& req, s64& result) {
memset(&sin, 0, sizeof(sin));
socklen_t sinlen = sizeof(sin);

int ret = recvfrom(uid, (char*)req.buffer, *req.length, MSG_PEEK | MSG_NOSIGNAL | MSG_TRUNC, (sockaddr*)&sin, &sinlen);
// On Windows: MSG_TRUNC are not supported on recvfrom (socket error WSAEOPNOTSUPP), so we use dummy buffer as an alternative
int ret = recvfrom(uid, dummyPeekBuf64k, dummyPeekBuf64kSize, MSG_PEEK | MSG_NOSIGNAL, (sockaddr*)&sin, &sinlen);
int sockerr = errno;
if (ret > 0 && *req.length > 0)
memcpy(req.buffer, dummyPeekBuf64k, std::min(ret, *req.length));

// Note: UDP must not be received partially, otherwise leftover data in socket's buffer will be discarded
if (ret >= 0 && ret <= *req.length) {
Expand Down Expand Up @@ -483,6 +486,7 @@ int DoBlockingPdpRecv(int uid, AdhocSocketRequest& req, s64& result) {
}
result = ERROR_NET_ADHOC_NOT_ENOUGH_SPACE;
}
// FIXME: Blocking operation with infinite timeout(0) should never get a TIMEOUT error, right? May be we should return INVALID_ARG instead if it was infinite timeout (0)?
else
result = ERROR_NET_ADHOC_TIMEOUT; // ERROR_NET_ADHOC_INVALID_ARG; // ERROR_NET_ADHOC_DISCONNECTED

Expand Down Expand Up @@ -1689,7 +1693,11 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *

// Receive Data. PDP always sent in full size or nothing(failed), recvfrom will always receive in full size as requested (blocking) or failed (non-blocking). If available UDP data is larger than buffer, excess data is lost.
// Should peek first for the available data size if it's more than len return ERROR_NET_ADHOC_NOT_ENOUGH_SPACE along with required size in len to prevent losing excess data
received = recvfrom(pdpsocket.id, (char*)buf, *len, MSG_PEEK | MSG_NOSIGNAL | MSG_TRUNC, (sockaddr*)&sin, &sinlen);
// On Windows: MSG_TRUNC are not supported on recvfrom (socket error WSAEOPNOTSUPP), so we use dummy buffer as an alternative
received = recvfrom(pdpsocket.id, dummyPeekBuf64k, dummyPeekBuf64kSize, MSG_PEEK | MSG_NOSIGNAL, (sockaddr*)&sin, &sinlen);
if (received > 0 && *len > 0)
memcpy(buf, dummyPeekBuf64k, std::min(received, *len));

if (received != SOCKET_ERROR && *len < received) {
WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", id, getLocalPort(pdpsocket.id), received, *len, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
*len = received;
Expand Down