Adhoc: Stop waiting for a login that has already failed

sceNetAdhocctlInit waits until the friend finder has logged into the adhoc
server, polling in emulated time but giving up only after 5s of wall time.
The friend finder makes one attempt per login request, and it too waited
the full 5s on a connection that had already been refused, because it
only looked for success. Now it checks the socket error and gives up at
once, and records the failure so the wait ends with it.

In headless, which runs far ahead of real time, Gods Eater Burst sat in
this wait for its whole run.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-09-29 12:37:48 -06:00
1 parent 2cd84012d0
commit 7ec860c24f
4 files changed
+21 -1

No files matched your search

+1
View File
@@ -45,3 +45,4 @@ u32 matchingThreadHackAddr = 0;
u32_le matchingThreadCode[3];
bool g_adhocServerConnected = false;
std::atomic<bool> g_adhocServerLoginFailed(false);
+4
View File
@@ -20,6 +20,7 @@
#include "CommonTypes.h"
#include "Swap.h"
#include <atomic>
#include <mutex>
extern u32 dummyThreadHackAddr;
@@ -52,5 +53,8 @@ extern u32 matchingThreadHackAddr;
extern u32_le matchingThreadCode[3];
extern bool g_adhocServerConnected;
// Set by the friend finder when its attempt to connect and log in for the latest login request
// failed, so a caller waiting on that login can stop waiting.
extern std::atomic<bool> g_adhocServerLoginFailed;
constexpr u32 defaultLastRecvDelta = 10000; //10000 usec worked well for games published by Falcom (ie. Ys vs Sora Kiseki, Vantage Master Portable)
+11
View File
@@ -1420,6 +1420,7 @@ int friendFinder() {
}
else {
g_adhocServerConnected = false;
g_adhocServerLoginFailed = true;
shutdown((int)metasocket, SD_BOTH);
closesocket((int)metasocket);
metasocket = (int)INVALID_SOCKET;
@@ -2251,6 +2252,16 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
return iResult;
done = (IsSocketReady((int)metasocket, false, true) > 0);
if (done) {
// Writable can also mean the attempt failed (refused, say). Then there's no point
// waiting out the timeout.
int soError = 0;
socklen_t soErrorLen = sizeof(soError);
if (getsockopt((int)metasocket, SOL_SOCKET, SO_ERROR, (char *)&soError, &soErrorLen) == 0 && soError != 0) {
errorcode = soError;
break;
}
}
struct sockaddr_in sin;
socklen_t sinlen = sizeof(sin);
memset(&sin, 0, sinlen);
+5 -1
View File
@@ -560,7 +560,8 @@ static void __AdhocctlNotify(u64 userdata, int cyclesLate) {
}
// Retry until successfully sent. Login packet sent after successfully connected to Adhoc Server (indicated by networkInited), so we're not sending Login again here
if ((req.opcode == OPCODE_LOGIN && !g_adhocServerConnected) || (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK))) {
// A login stops waiting early once the friend finder has tried and failed to connect.
if ((req.opcode == OPCODE_LOGIN && !g_adhocServerConnected && !g_adhocServerLoginFailed) || (ret == SOCKET_ERROR && (sockerr == EAGAIN || sockerr == EWOULDBLOCK))) {
u64 now = (u64)(time_now_d() * 1000000.0);
if (now - adhocctlStartTime <= static_cast<u64>(adhocDefaultTimeout) + 500) {
// Try again in another 0.5ms until timedout.
@@ -2001,6 +2002,7 @@ int sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) {
adhocctlEvents.clear();
netAdhocctlInited = true; //needed for cleanup during AdhocctlTerm even when it failed to connect to Adhoc Server (since it's being faked as success)
g_adhocServerLoginFailed = false;
isAdhocctlNeedLogin = true;
// Create fake PSP Thread for callback
@@ -3191,6 +3193,7 @@ int sceNetAdhocctlScan() {
// Only scan when in Disconnected state, otherwise AdhocServer will kick you out
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED && !isAdhocctlBusy) {
isAdhocctlBusy = true;
g_adhocServerLoginFailed = false;
isAdhocctlNeedLogin = true;
adhocctlState = ADHOCCTL_STATE_SCANNING;
adhocctlCurrentMode = ADHOCCTL_MODE_NORMAL;
@@ -3684,6 +3687,7 @@ int NetAdhocctl_Create(const char *groupName) {
// Disconnected State
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED && !isAdhocctlBusy) {
isAdhocctlBusy = true;
g_adhocServerLoginFailed = false;
isAdhocctlNeedLogin = true;
// Set Network Name