From d907906c74ee1fa3bfdb1db8d383eefee4aac33e Mon Sep 17 00:00:00 2001 From: ANR2ME Date: Thu, 28 Jan 2021 22:38:49 +0700 Subject: [PATCH] Fix connection issue on Dynasty Warriors (Shin Sangoku Musou) games when playing with more than 2 players. --- Core/HLE/proAdhoc.cpp | 13 ++++++++----- Core/HLE/proAdhoc.h | 4 +++- Core/HLE/sceNetAdhoc.cpp | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 5a0ec169a7..83667278d4 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -128,16 +128,19 @@ bool isPDPPortInUse(uint16_t port) { return false; } -bool isPTPPortInUse(uint16_t port, bool forListen) { +bool isPTPPortInUse(uint16_t port, bool forListen, SceNetEtherAddr* dstmac, uint16_t dstport) { // Iterate Sockets for (int i = 0; i < MAX_SOCKET; i++) { auto sock = adhocSockets[i]; if (sock != NULL && sock->type == SOCK_PTP) - // It's allowed to Listen and Open the same PTP port, But it's not allowed to Listen or Open the same PTP port twice. - if (sock->data.ptp.lport == port && - ((forListen && sock->data.ptp.state == ADHOC_PTP_STATE_LISTEN) || - (!forListen && sock->data.ptp.state != ADHOC_PTP_STATE_LISTEN))) + // It's allowed to Listen and Open the same PTP port, But it's not allowed to Listen or Open the same PTP port twice (unless destination mac or port are different). + if (sock->data.ptp.lport == port && + ((forListen && sock->data.ptp.state == ADHOC_PTP_STATE_LISTEN) || + (!forListen && sock->data.ptp.state != ADHOC_PTP_STATE_LISTEN && + sock->data.ptp.pport == dstport && dstmac != nullptr && isMacMatch(&sock->data.ptp.paddr, dstmac)))) + { return true; + } } // Unused Port return false; diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 660c0ff1c6..b9415c80c8 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -972,9 +972,11 @@ bool isPDPPortInUse(uint16_t port); * Check whether PTP Port is in use or not (only sockets with non-Listening state will be considered as in use) * @param port To-be-checked Port Number * @param forListen to check for listening or non-listening port + * @param dstmac destination address (non-listening only) + * @param dstport destination port (non-listening only) * @return 1 if in use or... 0 */ -bool isPTPPortInUse(uint16_t port, bool forListen); +bool isPTPPortInUse(uint16_t port, bool forListen, SceNetEtherAddr* dstmac = nullptr, uint16_t dstport = 0); // Convert MAC address to string std::string mac2str(SceNetEtherAddr* mac); diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index c8c11c9931..2999aa8329 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -3103,7 +3103,7 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, // Valid Addresses. FIXME: MAC only valid after successful attempt to Create/Connect/Join a Group? (ie. adhocctlCurrentMode != ADHOCCTL_MODE_NONE) if ((adhocctlCurrentMode != ADHOCCTL_MODE_NONE) && saddr != NULL && isLocalMAC(saddr) && daddr != NULL && !isBroadcastMAC(daddr) && !isZeroMAC(daddr)) { // Dissidia 012 will try to reOpen the port without Closing the old one first when PtpConnect failed to try again. - if (isPTPPortInUse(sport, false)) { + if (isPTPPortInUse(sport, false, daddr, dport)) { // FIXME: When PORT_IN_USE error occured it seems the index to the socket id also increased, which means it tries to create & bind the socket first and then closes it due to failed to bind return hleLogDebug(SCENET, ERROR_NET_ADHOC_PORT_IN_USE, "port in use"); }