From 2652fedef0de056d63f15ccf8efd3ed3138334a2 Mon Sep 17 00:00:00 2001 From: LunaMoo Date: Sun, 31 Mar 2019 10:35:52 +0200 Subject: [PATCH] Add more adhoc hackery. But without the kernel thread hackery as it breaks stuff. --- Core/Compatibility.cpp | 2 ++ Core/Compatibility.h | 2 ++ Core/HLE/proAdhoc.cpp | 18 ++++++------- Core/HLE/proAdhocServer.cpp | 51 ++++++++++++++++++++++--------------- Core/HLE/sceNet.cpp | 10 ++++++-- Core/HLE/sceNetAdhoc.cpp | 18 ++++++++----- assets/compat.ini | 29 +++++++++++++++++++++ 7 files changed, 91 insertions(+), 39 deletions(-) diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index 8d5374d305..b6680d2c80 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -69,6 +69,8 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "MGS2AcidHack", &flags_.MGS2AcidHack); CheckSetting(iniFile, gameID, "SonicRivalsHack", &flags_.SonicRivalsHack); CheckSetting(iniFile, gameID, "AdhocHackDisableNBSwitch", &flags_.AdhocHackDisableNBSwitch); + CheckSetting(iniFile, gameID, "AdhocHackStopFriendClear", &flags_.AdhocHackStopFriendClear); + CheckSetting(iniFile, gameID, "AdhocHackPhantasyStarOffset", &flags_.AdhocHackPhantasyStarOffset); CheckSetting(iniFile, gameID, "BlockTransferAllowCreateFB", &flags_.BlockTransferAllowCreateFB); CheckSetting(iniFile, gameID, "YugiohSaveFix", &flags_.YugiohSaveFix); CheckSetting(iniFile, gameID, "ForceUMDDelay", &flags_.ForceUMDDelay); diff --git a/Core/Compatibility.h b/Core/Compatibility.h index fd641b4604..d53a6b9a1c 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -69,6 +69,8 @@ struct CompatFlags { bool MGS2AcidHack; bool SonicRivalsHack; bool AdhocHackDisableNBSwitch; + bool AdhocHackStopFriendClear; + bool AdhocHackPhantasyStarOffset; bool BlockTransferAllowCreateFB; bool YugiohSaveFix; bool ForceUMDDelay; diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 430836bd68..829f8eff3a 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -919,7 +919,7 @@ void AfterMatchingMipsCall::run(MipsCall &call) { //u32 v0 = currentMIPS->r[MIPS_REG_V0]; if (__IsInInterrupt()) ERROR_LOG(SCENET, "AfterMatchingMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", context->id, EventID); //while (__IsInInterrupt()) sleep_ms(1); // Must not sleep inside callback handler - context->eventlock->lock(); //peerlock.lock(); + //context->eventlock->lock(); //peerlock.lock(); //SceNetAdhocMatchingContext * context = findMatchingContext(ID); //if (context != NULL) { @@ -1493,14 +1493,14 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ setsockopt(metasocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); setsockopt(metasocket, SOL_SOCKET, SO_DONTROUTE, (const char*)&on, sizeof(on)); // Prepare Local Address Information - /* - + struct sockaddr_in local; - + memset(&local, 0, sizeof(local)); - + local.sin_family = AF_INET; - + local.sin_addr = serverIp; - + local.sin_addr.S_un.S_un_b.s_b4 = PPSSPP_ID; - + //local.sin_port = 0; - + */ + /* + struct sockaddr_in local; + memset(&local, 0, sizeof(local)); + local.sin_family = AF_INET; + local.sin_addr = serverIp; + local.sin_addr.S_un.S_un_b.s_b4 = PPSSPP_ID; + //local.sin_port = 0; + */ ((struct sockaddr_in *)&localIP)->sin_port = 0; // Bind Local Address to Socket iResult = bind(metasocket, (struct sockaddr *)&localIP, sizeof(sockaddr)); diff --git a/Core/HLE/proAdhocServer.cpp b/Core/HLE/proAdhocServer.cpp index 3c3922abf4..84dc131564 100644 --- a/Core/HLE/proAdhocServer.cpp +++ b/Core/HLE/proAdhocServer.cpp @@ -507,13 +507,13 @@ void login_user_stream(int fd, uint32_t ip) // Enough Space available if(_db_user_count < SERVER_USER_MAXIMUM) { - // Check IP Duplication + // Check IP Duplication as current AdhocServer doesn't receives/broadcasts binded port information having more than 1 players using the same IP will only cause communication interference (sometimes clients bind to specific port on some games) since Reusable port will share the socket buffer when one already read the data the other can't read it anymore (no longer in buffer) SceNetAdhocctlUserNode * u = _db_user; while(u != NULL && u->resolver.ip != ip) u = u->next; if (u != NULL) { // IP Already existed uint8_t * ip4 = (uint8_t *)&u->resolver.ip; - INFO_LOG(SCENET, "AdhocServer: Already Existing IP: %u.%u.%u.%u\n", ip4[0], ip4[1], ip4[2], ip4[3]); + WARN_LOG(SCENET, "AdhocServer: Already Existing IP: %u.%u.%u.%u\n", ip4[0], ip4[1], ip4[2], ip4[3]); } // Unique IP Address @@ -558,7 +558,7 @@ void login_user_stream(int fd, uint32_t ip) } } - // Duplicate IP, Allocation Error or not enough space - Close Stream + // Duplicate IP/MAC, Allocation Error or not enough space - Close Stream closesocket(fd); } @@ -587,20 +587,20 @@ void login_user_data(SceNetAdhocctlUserNode * user, SceNetAdhocctlLoginPacketC2S while (u != NULL && !IsMatch(u->resolver.mac, data->mac)) u = u->next; if (u != NULL) { // MAC Already existed /* - + u32_le sip = user->resolver.ip; - + // 127.0.0.1 should be replaced with LAN/WAN IP whenever available to make sure remote players can communicate with current (local) player - + // It might be better if the client connects to AdhocServer using the correct interface instead of automatically changing the IP which might not be accurate on multihomed computer. - + if (sip == 0x0100007f) { - + char str[256]; - + gethostname(str, 256); - + u8 *pip = (u8*)&sip; - + struct hostent *pHost = 0; - + pHost = gethostbyname(str); - + if (pHost->h_addrtype == AF_INET && pHost->h_addr_list[0] != NULL) pip = (u8*)pHost->h_addr_list[0]; - + user->resolver.ip = *(u32_le*)pip; - + WARN_LOG(SCENET, "AdhocServer: Replacing IP %u.%u.%u.%u with %u.%u.%u.%u", ((u8*)&sip)[0], ((u8*)&sip)[1], ((u8*)&sip)[2], ((u8*)&sip)[3], pip[0], pip[1], pip[2], pip[3]); - + } - + */ + u32_le sip = user->resolver.ip; + // 127.0.0.1 should be replaced with LAN/WAN IP whenever available to make sure remote players can communicate with current (local) player + // It might be better if the client connects to AdhocServer using the correct interface instead of automatically changing the IP which might not be accurate on multihomed computer. + if (sip == 0x0100007f) { + char str[256]; + gethostname(str, 256); + u8 *pip = (u8*)&sip; + struct hostent *pHost = 0; + pHost = gethostbyname(str); + if (pHost->h_addrtype == AF_INET && pHost->h_addr_list[0] != NULL) pip = (u8*)pHost->h_addr_list[0]; + user->resolver.ip = *(u32_le*)pip; + WARN_LOG(SCENET, "AdhocServer: Replacing IP %u.%u.%u.%u with %u.%u.%u.%u", ((u8*)&sip)[0], ((u8*)&sip)[1], ((u8*)&sip)[2], ((u8*)&sip)[3], pip[0], pip[1], pip[2], pip[3]); + } + */ uint8_t * ip4 = (uint8_t *)&u->resolver.ip; WARN_LOG(SCENET, "AdhocServer: Already Existing MAC: %02X:%02X:%02X:%02X:%02X:%02X [%u.%u.%u.%u]\n", data->mac.data[0], data->mac.data[1], data->mac.data[2], data->mac.data[3], data->mac.data[4], data->mac.data[5], ip4[0], ip4[1], ip4[2], ip4[3]); } @@ -1817,9 +1817,16 @@ int create_listen_socket(uint16_t port) struct sockaddr_in local; memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; - local.sin_addr.s_addr = INADDR_ANY; + local.sin_addr.s_addr = INADDR_ANY; // bind to all network adapter local.sin_port = htons(port); + //Should only bind to specific IP for the 2nd or more instance of PPSSPP to prevent communication interference issue when sharing the same port. Doesn't work well when PPSSPP_ID reseted everytime emulation restarted. + /* + if (PPSSPP_ID > 1) { + local.sin_addr = ((sockaddr_in *)&localIP)->sin_addr; + } + */ + // Bind Local Address to Socket int bindresult = bind(fd, (struct sockaddr *)&local, sizeof(local)); @@ -1893,10 +1900,12 @@ int server_loop(int server) u32_le sip = addr.sin_addr.s_addr; /* if (sip == 0x0100007f) { //127.0.0.1 should be replaced with LAN/WAN IP whenever available - char str[100]; - gethostname(str, 100); + char str[256]; + gethostname(str, 256); u8 *pip = (u8*)&sip; - if (gethostbyname(str)->h_addrtype == AF_INET && gethostbyname(str)->h_addr_list[0] != NULL) pip = (u8*)gethostbyname(str)->h_addr_list[0]; + struct hostent *pHost = 0; + pHost = gethostbyname(str); + if (pHost->h_addrtype == AF_INET && pHost->h_addr_list[0] != NULL) pip = (u8*)pHost->h_addr_list[0]; sip = *(u32_le*)pip; WARN_LOG(SCENET, "AdhocServer: Replacing IP %s with %u.%u.%u.%u", inet_ntoa(addr.sin_addr), pip[0], pip[1], pip[2], pip[3]); } diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 37a233dc0c..ead1be3124 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -212,7 +212,9 @@ static void __ResetInitNetLib() { void __NetInit() { portOffset = g_Config.iPortOffset; - PPSSPP_ID = getInstanceNumber(); // This should be called when program started instead of when the game started/reseted + //if (PPSSPP_ID == 0) { // Each instance should use the same ID (and IP) once it's automatically assigned for consistency reason, But doesn't work well if PPSSPP_ID reseted everytime emulation restarted + PPSSPP_ID = getInstanceNumber(); // This should be called when program started instead of when the game started/reseted + //} InitLocalIP(); INFO_LOG(SCENET, "LocalHost IP will be %s", inet_ntoa(((sockaddr_in *)&localIP)->sin_addr)); //net::Init(); @@ -220,8 +222,12 @@ void __NetInit() { } void __NetShutdown() { - PPSSPPIDCleanup(); //This should be called when program exited, otherwise everytime emulation restarted PPSSPP_ID will reset causing more than one instance might have the same ID and IP. __ResetInitNetLib(); + //net::Shutdown(); +#ifdef _MSC_VER + WSACleanup(); +#endif + PPSSPPIDCleanup(); //This should be called when program exited, otherwise everytime emulation restarted PPSSPP_ID will reset causing more than one instance might have the same ID and IP. } static void __UpdateApctlHandlers(int oldState, int newState, int flag, int error) { diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index f1e6e8ffbe..d509ad30f7 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -1082,12 +1082,14 @@ static u32 sceNetAdhocctlDisconnect() { // Multithreading Lock //peerlock.lock(); - // Clear Peer List - freeFriendsRecursive(friends); - INFO_LOG(SCENET, "Cleared Peer List."); + if (!PSP_CoreParameter().compat.flags().AdhocHackStopFriendClear) { + // Clear Peer List + freeFriendsRecursive(friends); + INFO_LOG(SCENET, "Cleared Peer List."); - // Delete Peer Reference - friends = NULL; + // Delete Peer Reference + friends = NULL; + } // Clear Group List //freeGroupsRecursive(networks); @@ -1642,8 +1644,10 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, // Valid Ports if (!isPTPPortInUse(sport) /*&& dport != 0*/) { - //sport 0 should be shifted back to 0 when using offset Phantasy Star Portable 2 use this - if (sport == 0) sport = -(int)portOffset; + if(PSP_CoreParameter().compat.flags().AdhocHackPhantasyStarOffset) { + //sport 0 should be shifted back to 0 when using offset Phantasy Star Portable 2 use this + if (sport == 0) sport = -(int)portOffset; + } // Valid Arguments if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0) { // Create Infrastructure Socket diff --git a/assets/compat.ini b/assets/compat.ini index abad5142a2..1b582dbee0 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -549,6 +549,35 @@ ULJS00250 = true ULJS19048 = true NPJH50107 = true +[AdhocHackStopFriendClear] +# Just in case, no known use-case for now. + +[AdhocHackPhantasyStarOffset] +# Phantasy Star Portable +ULJM05309 = true +ULUS10410 = true +ULES01218 = true +ULJM08023 = true +ULES01218 = true +# Phantasy Star Portable 1 Demo +NPUH90023 = true +# Phantasy Star Portable 2 +ULES01439 = true +ULUS10529 = true +ULJM05493 = true +NPJH50043 = true +ULJM08030 = true +NPUH90023 = true +ULJM91014 = true +NPJH90002 = true +ULJM05732 = true +NPJH50332 = true +# Phantasy Star Portable 2 JP Demo +ULJM91018 = true +NPJH90062 = true +# Phantasy Star Portable Infinity Demo +NPJH90157 = true # Infinity demo + [BlockTransferAllowCreateFB] NPJH50686 = true # Digimon Adventures (JP, and English patches...)