From 97a3f1df91c46fba3f7b70945f9b2defff9919ac Mon Sep 17 00:00:00 2001 From: Katharine Chui Date: Tue, 13 Jan 2026 02:13:18 +0100 Subject: [PATCH] implement nonblock ptp connect --- Core/Core.cpp | 5 --- Core/HLE/proAdhoc.cpp | 45 ++++++++++++++++----- Core/HLE/proAdhoc.h | 1 + Core/HLE/sceNetAdhoc.cpp | 85 ++++++++++++++++++++++++++++++++++------ 4 files changed, 111 insertions(+), 25 deletions(-) diff --git a/Core/Core.cpp b/Core/Core.cpp index 4ef56724f2..639ed65ba1 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -45,8 +45,6 @@ #include "GPU/GPU.h" #include "GPU/GPUCommon.h" -#include "ext/aemu_postoffice/client/postoffice_client.h" - // Step command to execute next static std::mutex g_stepMutex; @@ -158,9 +156,6 @@ void Core_NotifyLifecycle(CoreLifecycle stage) { void Core_Stop() { Core_ResetException(); Core_UpdateState(CORE_POWERDOWN); - - // close all active aemu postoffice sessions if exist - aemu_post_office_init(); } void Core_UpdateState(CoreState newState) { diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index ae384fd0a6..4076885d31 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -57,6 +57,8 @@ #include "Core/HLE/NetAdhocCommon.h" +#include "ext/aemu_postoffice/client/postoffice_client.h" + #ifdef _WIN32 #undef errno #define errno WSAGetLastError() @@ -418,17 +420,42 @@ void deleteAllAdhocSockets() { // Active Socket if (adhocSockets[i] != NULL) { auto sock = adhocSockets[i]; - int fd = -1; - if (sock->type == SOCK_PTP) - fd = sock->data.ptp.id; - else if (sock->type == SOCK_PDP) - fd = sock->data.pdp.id; + if (g_Config.bServerHasRelay){ + if (sock->type == SOCK_PTP){ + // sync + if (sock->connect_threads != NULL){ + while(sock->connect_threads->size() != 0){ + sock->connect_threads->at(sock->connect_threads->size() - 1).join(); + sock->connect_threads->pop_back(); + } + delete sock->connect_threads; + } + void *socket = sock->postoffice_handle; + if (socket != NULL){ + if (sock->data.ptp.state == ADHOC_PTP_STATE_LISTEN){ + ptp_listen_close(socket); + }else{ + ptp_close(socket); + } + } + }else{ + if (sock->postoffice_handle != NULL){ + pdp_delete(sock->postoffice_handle); + } + } + }else{ + int fd = -1; + if (sock->type == SOCK_PTP) + fd = sock->data.ptp.id; + else if (sock->type == SOCK_PDP) + fd = sock->data.pdp.id; - if (fd > 0) { - // Close Socket - shutdown(fd, SD_RECEIVE); - closesocket(fd); + if (fd > 0) { + // Close Socket + shutdown(fd, SD_RECEIVE); + closesocket(fd); + } } // Free Memory free(adhocSockets[i]); diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index e93845ef2a..7bbf127c3f 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -329,6 +329,7 @@ typedef struct AdhocSocket { SceNetAdhocPtpStat ptp; } data; void *postoffice_handle; // aemu_postoffice mode handle + std::vector *connect_threads; } PACK AdhocSocket; // Gamemode Optional Peer Buffer Data diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 259ffec16a..17627f8754 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -1021,6 +1021,7 @@ static int ptp_accept_postoffice(int idx, SceNetEtherAddr *saddr, uint16_t *spor internal->data.ptp.snd_sb_cc = adhocSockets[idx]->data.ptp.snd_sb_cc; internal->data.ptp.id = AEMU_POSTOFFICE_ID; internal->flags = 0; + internal->connect_threads = NULL; AdhocSocket **slot = NULL; int i; @@ -3778,6 +3779,27 @@ int RecreatePtpSocket(int ptpId) { return 0; } +static uint16_t get_random_unused_ptp_port(){ + uint16_t test_port = rand() % 65534 + 1; + auto port_in_use = [&test_port] { + for (int i = 0; i < MAX_SOCKET; i++){ + if (adhocSockets[i] != NULL && + adhocSockets[i]->type == SOCK_PTP && + test_port == adhocSockets[i]->data.ptp.lport) + { + return true; + } + } + return false; + }; + + while(port_in_use()){ + test_port = rand() % 65534 + 1; + } + + return test_port; +} + static int ptp_open_postoffice(const SceNetEtherAddr *saddr, uint16_t sport, const SceNetEtherAddr *daddr, uint16_t dport, uint32_t bufsize){ AdhocSocket *internal = (AdhocSocket *)malloc(sizeof(AdhocSocket)); if (internal == NULL){ @@ -3789,13 +3811,14 @@ static int ptp_open_postoffice(const SceNetEtherAddr *saddr, uint16_t sport, con internal->postoffice_handle = NULL; internal->data.ptp.state = ADHOC_PTP_STATE_CLOSED; internal->data.ptp.laddr = *saddr; - internal->data.ptp.lport = sport; + internal->data.ptp.lport = sport == 0 ? get_random_unused_ptp_port() : sport; internal->data.ptp.paddr = *daddr; internal->data.ptp.pport = dport; internal->data.ptp.rcv_sb_cc = bufsize; internal->data.ptp.snd_sb_cc = 0; internal->data.ptp.id = AEMU_POSTOFFICE_ID; internal->flags = 0; + internal->connect_threads = new std::vector(); AdhocSocket **slot = NULL; int i; @@ -3852,7 +3875,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, } // Random Port required - if (sport == 0) { + if (sport == 0 && !g_Config.bServerHasRelay) { isClient = true; //sport 0 should be shifted back to 0 when using offset Phantasy Star Portable 2 use this sport = -static_cast(portOffset); @@ -4235,23 +4258,51 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int } static int ptp_connect_postoffice(int idx, uint32_t timeout, int nonblock){ + INFO_LOG(Log::sceNet, "%s: id %d timeout %u nonblock %d", __func__, idx + 1, timeout, nonblock); AdhocSocket *internal = adhocSockets[idx]; + // Phantasy Star Portable 2 will try to reconnect even when previous connect already success, so we should return success too if it's already connected if (internal->data.ptp.state == ADHOC_PTP_STATE_ESTABLISHED) return 0; - uint64_t begin = CoreTiming::GetGlobalTimeUsScaled(); - uint64_t end = begin + timeout; - struct aemu_post_office_sock_addr addr; addr.addr = g_adhocServerIP.in.sin_addr.s_addr; addr.port = htons(AEMU_POSTOFFICE_PORT); - void *ptp_socket = NULL; + if (nonblock || timeout != 0){ + // TODO actual notify based timeout + int timeout_return = nonblock ? SCE_NET_ADHOC_ERROR_WOULD_BLOCK : SCE_NET_ADHOC_ERROR_TIMEOUT; + + if (internal->data.ptp.state == ADHOC_PTP_STATE_CLOSED){ + while(internal->connect_threads->size() != 0){ + internal->connect_threads->at(internal->connect_threads->size() - 1).join(); + internal->connect_threads->pop_back(); + } + + internal->data.ptp.state = ADHOC_PTP_STATE_SYN_SENT; + + internal->connect_threads->push_back(std::thread([internal, addr, idx] { + int state; + void *ptp_socket = ptp_connect_v4(&addr, (const char *)&internal->data.ptp.laddr, internal->data.ptp.lport + portOffset, (const char *)&internal->data.ptp.paddr, internal->data.ptp.pport + portOffset, &state); + if (ptp_socket == NULL){ + ERROR_LOG(Log::sceNet, "%s: failed connecting to ptp socket, %d", __func__, state); + internal->data.ptp.state = ADHOC_PTP_STATE_CLOSED; + return; + } + internal->postoffice_handle = ptp_socket; + INFO_LOG(Log::sceNet, "%s: connected ptp socket with id %d %p", __func__, idx + 1, internal->postoffice_handle); + internal->data.ptp.state = ADHOC_PTP_STATE_ESTABLISHED; + return; + })); + + return timeout_return; + } + // ADHOC_PTP_STATE_SYN_SENT + return timeout_return; + } - // note that postoffice connect was designed to be a blocked operation, if the other side don't accept, or listen session not found, the server will kick us out int state; - ptp_socket = ptp_connect_v4(&addr, (const char *)&internal->data.ptp.laddr, internal->data.ptp.lport + portOffset, (const char *)&internal->data.ptp.paddr, internal->data.ptp.pport + portOffset, &state); + void *ptp_socket = ptp_connect_v4(&addr, (const char *)&internal->data.ptp.laddr, internal->data.ptp.lport + portOffset, (const char *)&internal->data.ptp.paddr, internal->data.ptp.pport + portOffset, &state); if (ptp_socket == NULL){ ERROR_LOG(Log::sceNet, "%s: failed connecting to ptp socket, %d", __func__, state); return SCE_NET_ADHOC_ERROR_CONNECTION_REFUSED; @@ -4409,12 +4460,23 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) { static int ptp_close_postoffice(int idx){ AdhocSocket *internal = adhocSockets[idx]; + + // sync + if (internal->connect_threads != NULL){ + while(internal->connect_threads->size() != 0){ + internal->connect_threads->at(internal->connect_threads->size() - 1).join(); + internal->connect_threads->pop_back(); + } + + delete internal->connect_threads; + } + void *socket = internal->postoffice_handle; if (socket != NULL){ - if (internal->data.ptp.state == ADHOC_PTP_STATE_ESTABLISHED){ - ptp_close(socket); - }else if (internal->data.ptp.state == ADHOC_PTP_STATE_LISTEN){ + if (internal->data.ptp.state == ADHOC_PTP_STATE_LISTEN){ ptp_listen_close(socket); + }else{ + ptp_close(socket); } } adhocSockets[idx] = NULL; @@ -4497,6 +4559,7 @@ static int ptp_listen_postoffice(const SceNetEtherAddr *saddr, uint16_t sport, u internal->data.ptp.snd_sb_cc = 0; internal->data.ptp.id = AEMU_POSTOFFICE_ID; internal->flags = 0; + internal->connect_threads = NULL; AdhocSocket **slot = NULL; int i;