From 5e92e0e02a2e6f7ff003e00ca80c32b2e85e6979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 27 Oct 2026 23:13:36 +0100 Subject: [PATCH] sceNetAdhoc: Fix the built-in relay's thread Join the old relay thread before starting a new one (assigning to a joinable std::thread terminates), don't map the UPnP port when another relay already has it, sleep the intended interval (the elapsed time was subtracted the wrong way round), use one worker per pool, and guard the log helper against empty messages. Drop the warning that the built-in server doesn't support relay. Co-Authored-By: Claude Opus 5.5 --- Core/HLE/sceNetAdhoc.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 26721657ae..1a912393e6 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -2074,7 +2074,7 @@ static void aemu_postoffice_server_log(const char *format, ...) { va_start(args, format); int len = vsnprintf(log_buf, sizeof(log_buf), format, args); va_end(args); - if (len < 1024 && log_buf[len - 1] == '\n') { + if (len > 0 && len < (int)sizeof(log_buf) && log_buf[len - 1] == '\n') { log_buf[len - 1] = '\0'; } INFO_LOG(Log::sceNet, "%s", log_buf); @@ -2094,6 +2094,9 @@ void __NetAdhocInit() { if (adhocServerThread.joinable()) { adhocServerThread.join(); } + if (relayThread.joinable()) { + relayThread.join(); + } if (g_Config.bEnableWlan && g_Config.bEnableAdhocServer) { adhocServerRunning = true; adhocServerThread = std::thread(proAdhocServerThread, SERVER_PORT); @@ -2111,15 +2114,22 @@ void __NetAdhocInit() { * from ppsspp's adhocctl server */ config.strict_mode = false; + // One worker per pool is plenty for a server that sees a handful of players. + config.num_threads = 1; aemu_postoffice_server::Server relay_server(config); + if (relay_server.pump() == aemu_postoffice_server::ServerPumpStatus::LISTEN_SOCK_DEAD) { + // Most likely another relay already has the port. + WARN_LOG(Log::sceNet, "RelayServer: Couldn't listen on TCP port %u", config.port); + return; + } - UPnP_Add(IP_PROTOCOL_TCP, AEMU_POSTOFFICE_PORT); + UPnP_Add(IP_PROTOCOL_TCP, config.port); - INFO_LOG(Log::sceNet, "RelayServer: Listening for Connections on TCP Port %u", AEMU_POSTOFFICE_PORT); + INFO_LOG(Log::sceNet, "RelayServer: Listening for Connections on TCP Port %u", config.port); while (adhocServerRunning) { - auto now = std::chrono::high_resolution_clock::now(); + auto start = std::chrono::steady_clock::now(); auto pump_status = relay_server.pump(); auto wait_time = std::chrono::milliseconds(8); if (pump_status == aemu_postoffice_server::ServerPumpStatus::LISTEN_SOCK_DEAD) { @@ -2128,15 +2138,12 @@ void __NetAdhocInit() { if (pump_status == aemu_postoffice_server::ServerPumpStatus::IDLE) { wait_time = std::chrono::milliseconds(100); } - auto time_taken = now - std::chrono::high_resolution_clock::now(); - if (time_taken < wait_time) { - std::this_thread::sleep_for(wait_time - time_taken); - } + std::this_thread::sleep_until(start + wait_time); } INFO_LOG(Log::sceNet, "RelayServer: Shutdown complete"); - UPnP_Remove(IP_PROTOCOL_TCP, AEMU_POSTOFFICE_PORT); + UPnP_Remove(IP_PROTOCOL_TCP, config.port); }); } } @@ -2159,10 +2166,6 @@ u32 sceNetAdhocInit(MIPSState *mips) { g_OSD.Show(OSDType::MESSAGE_WARNING, n->T("Built-in adhoc server does not currently support UDP"), 20.0f, "udp built-in server warning"); } - if (serverHasRelay && g_Config.bEnableAdhocServer && isLocalServer) { - g_OSD.Show(OSDType::MESSAGE_WARNING, n->T("Built-in adhoc server does not currently support relay"), 20.0f, "relay built-in server warning"); - } - if (g_Config.bEnableWlan) { std::string_view modeStr = serverHasRelay ? n->T("Relay server mode") : n->T("P2P mode"); g_OSD.Show(OSDType::MESSAGE_INFO, ApplySafeSubstitutions("%1: %2", n->T("Ad Hoc multiplayer"), modeStr), 0.0f, "adhoc started");