Merge pull request #13318 from ANR2ME/net_blocking

Simulate blocking behavior using non-blocking on networking
This commit is contained in:
Henrik Rydgård 2020-09-04 09:25:33 +02:00 committed by GitHub
commit 619009be93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1343 additions and 559 deletions

View file

@ -18,17 +18,20 @@
#if defined(_WIN32)
#include "Common/CommonWindows.h"
#endif
#include <TimeUtil.h>
#include "i18n/i18n.h"
#include "Common/Serialize/Serializer.h"
#include "Common/Serialize/SerializeFuncs.h"
#include "Core/Config.h"
#include "Core/MemMapHelpers.h"
#include "Core/Util/PPGeDraw.h"
#include "Core/HLE/sceKernelMemory.h"
#include "Core/HLE/sceCtrl.h"
#include "Core/HLE/sceUtility.h"
#include <Core/HLE/sceNet.h>
#include "Core/HLE/sceNet.h"
#include "Core/HLE/sceNetAdhoc.h"
#include "Core/Dialog/PSPNetconfDialog.h"
#include <ext/native/util/text/utf8.h>
#include "ext/native/util/text/utf8.h"
#define NETCONF_CONNECT_APNET 0
@ -42,8 +45,15 @@ static const float FONT_SCALE = 0.65f;
// Needs testing.
const static int NET_INIT_DELAY_US = 300000;
const static int NET_SHUTDOWN_DELAY_US = 26000;
const static int NET_SHUTDOWN_DELAY_US = 260000;
const static int NET_RUNNING_DELAY_US = 1000000; // KHBBS is showing adhoc dialog for about 3-4 seconds, but feels too long, so we're faking it to 1 sec instead to let players read the text
const static int NET_CONNECT_TIMEOUT = 5000000;
struct ScanInfos {
s32_le sz;
SceNetAdhocctlScanInfoEmu si;
} PACK;
PSPNetconfDialog::PSPNetconfDialog() {
}
@ -78,6 +88,11 @@ int PSPNetconfDialog::Init(u32 paramAddr) {
cancelButtonFlag = CTRL_CIRCLE;
}
connResult = -1;
scanInfosAddr = 0;
scanStep = 0;
startTime = (u64)(real_time_now() * 1000000.0);
StartFade(true);
return 0;
}
@ -114,7 +129,7 @@ void PSPNetconfDialog::DisplayMessage(std::string text1, std::string text2a, std
// Without the scrollbar, we have 350 total pixels.
float WRAP_WIDTH = 300.0f;
if (UTF8StringNonASCIICount(text1.c_str()) >= text1.size() / 4) {
if (UTF8StringNonASCIICount(text1.c_str()) >= (int)text1.size() / 4) {
WRAP_WIDTH = 336.0f;
if (text1.size() > 12) {
messageStyle.scale = 0.6f;
@ -182,12 +197,20 @@ void PSPNetconfDialog::DisplayMessage(std::string text1, std::string text2a, std
PPGeScissor(0, (int)(centerY - h2 - 2), 480, (int)(centerY + h2 + 2));
PPGeDrawTextWrapped(text1.c_str(), 240.0f, centerY - h2 - scrollPos_, WRAP_WIDTH, 0, messageStyle);
if (text2a != "")
PPGeDrawTextWrapped(text2a.c_str(), 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleRight);
if (text2a != "") {
if (text2b != "")
PPGeDrawTextWrapped(text2a.c_str(), 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleRight);
else
PPGeDrawTextWrapped(text2a.c_str(), 240.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyle);
}
if (text2b != "")
PPGeDrawTextWrapped(text2b.c_str(), 240.0f + 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + marginTop, WRAP_WIDTH, 0, messageStyleLeft);
if (text3a != "")
PPGeDrawTextWrapped(text3a.c_str(), 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleRight);
if (text3a != "") {
if (text3b != "")
PPGeDrawTextWrapped(text3a.c_str(), 240.0f - 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleRight);
else
PPGeDrawTextWrapped(text3a.c_str(), 240.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyle);
}
if (text3b != "")
PPGeDrawTextWrapped(text3b.c_str(), 240.0f + 5.0f, centerY - h2 - scrollPos_ + totalHeight1 + totalHeight2 + marginTop, WRAP_WIDTH, 0, messageStyleLeft);
PPGeScissorReset();
@ -229,6 +252,7 @@ int PSPNetconfDialog::Update(int animSpeed) {
UpdateButtons();
auto di = GetI18NCategory("Dialog");
auto err = GetI18NCategory("Error");
u64 now = (u64)(real_time_now() * 1000000.0);
// It seems JPCSP doesn't check for NETCONF_STATUS_APNET
if (request.netAction == NETCONF_CONNECT_APNET || request.netAction == NETCONF_STATUS_APNET || request.netAction == NETCONF_CONNECT_APNET_LAST) {
@ -310,6 +334,7 @@ int PSPNetconfDialog::Update(int animSpeed) {
}
else if (request.netAction == NETCONF_CONNECT_ADHOC || request.netAction == NETCONF_CREATE_ADHOC || request.netAction == NETCONF_JOIN_ADHOC) {
int state = NetAdhocctl_GetState();
bool timedout = (state == ADHOCCTL_STATE_DISCONNECTED && now - startTime > NET_CONNECT_TIMEOUT);
UpdateFade(animSpeed);
StartDraw();
@ -317,18 +342,104 @@ int PSPNetconfDialog::Update(int animSpeed) {
DrawBanner();
DrawIndicator();
std::string channel = std::to_string(g_Config.iWlanAdhocChannel);
if (g_Config.iWlanAdhocChannel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC)
channel = "Automatic";
if (timedout) {
// FIXME: Do we need to show error message?
DisplayMessage(di->T("InternalError", "An internal error has occurred.") + StringFromFormat("\n(%08X)", connResult));
DisplayButtons(DS_BUTTON_CANCEL, di->T("Back"));
}
else {
std::string channel = std::to_string(g_Config.iWlanAdhocChannel);
if (g_Config.iWlanAdhocChannel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC)
channel = "Automatic";
DisplayMessage(di->T("ConnectingChannel", "Connecting.\nPlease wait...\n\nChannel")+std::string(" ")+di->T(channel));
DisplayMessage(di->T("ConnectingPleaseWait", "Connecting.\nPlease wait..."), di->T("Channel") + std::string(" ") + di->T(channel));
// Only Join mode is showing Cancel button on KHBBS and the button will fade out before the dialog is fading out, probably because it's already connected thus can't be canceled anymore
if (request.netAction == NETCONF_JOIN_ADHOC)
DisplayButtons(DS_BUTTON_CANCEL, di->T("Cancel"));
// Only Join mode is showing Cancel button on KHBBS and the button will fade out before the dialog is fading out, probably because it's already connected thus can't be canceled anymore
if (request.netAction == NETCONF_JOIN_ADHOC)
DisplayButtons(DS_BUTTON_CANCEL, di->T("Cancel"));
if (state == ADHOCCTL_STATE_DISCONNECTED && request.NetconfData.IsValid()) {
connResult = sceNetAdhocctlCreate(request.NetconfData->groupName);
// KHBBS will first enter the arena using NETCONF_CONNECT_ADHOC (auto-create group when not exist yet?), but when the event started the event's creator use NETCONF_CREATE_ADHOC while the joining players use NETCONF_JOIN_ADHOC
if (request.NetconfData.IsValid()) {
if (state == ADHOCCTL_STATE_DISCONNECTED) {
switch (request.netAction)
{
case NETCONF_CREATE_ADHOC:
if (connResult < 0) {
connResult = sceNetAdhocctlCreate(request.NetconfData->groupName);
}
break;
case NETCONF_JOIN_ADHOC:
// FIXME: Should we Scan for a matching group first before Joining a Group (like adhoc games normally do)? Or Is it really allowed to join non-existing group?
if (scanStep == 0) {
if (sceNetAdhocctlScan() >= 0) {
u32 structsz = sizeof(ScanInfos);
if (Memory::IsValidAddress(scanInfosAddr))
userMemory.Free(scanInfosAddr);
scanInfosAddr = userMemory.Alloc(structsz, false, "NetconfScanInfo");
Memory::Write_U32(sizeof(SceNetAdhocctlScanInfoEmu), scanInfosAddr);
scanStep = 1;
}
}
else if (scanStep == 1) {
s32 sz = Memory::Read_U32(scanInfosAddr);
// Get required buffer size
if (sceNetAdhocctlGetScanInfo(scanInfosAddr, 0) >= 0) {
s32 reqsz = Memory::Read_U32(scanInfosAddr);
if (reqsz > sz) {
sz = reqsz;
if (Memory::IsValidAddress(scanInfosAddr))
userMemory.Free(scanInfosAddr);
u32 structsz = sz + sizeof(s32);
scanInfosAddr = userMemory.Alloc(structsz, false, "NetconfScanInfo");
Memory::Write_U32(sz, scanInfosAddr);
}
if (reqsz > 0) {
if (sceNetAdhocctlGetScanInfo(scanInfosAddr, scanInfosAddr + sizeof(s32)) >= 0) {
ScanInfos* scanInfos = (ScanInfos*)Memory::GetPointer(scanInfosAddr);
int n = scanInfos->sz / sizeof(SceNetAdhocctlScanInfoEmu);
// Assuming returned SceNetAdhocctlScanInfoEmu(s) are contagious where next is pointing to current addr + sizeof(SceNetAdhocctlScanInfoEmu)
while (n > 0) {
SceNetAdhocctlScanInfoEmu* si = (SceNetAdhocctlScanInfoEmu*)Memory::GetPointer(scanInfosAddr + sizeof(s32) + sizeof(SceNetAdhocctlScanInfoEmu) * (n - 1LL));
if (memcmp(si->group_name.data, request.NetconfData->groupName, ADHOCCTL_GROUPNAME_LEN) == 0) {
// Moving found group info to the front so we can use it on sceNetAdhocctlJoin easily
memcpy((char*)scanInfos + sizeof(s32), si, sizeof(SceNetAdhocctlScanInfoEmu));
scanStep = 2;
break;
}
n--;
}
// Target group not found, try to scan again later
if (n <= 0) {
scanStep = 0;
}
}
}
// No group found, try to scan again later
else {
scanStep = 0;
}
}
}
else if (scanStep == 2) {
if (connResult < 0) {
connResult = sceNetAdhocctlJoin(scanInfosAddr + sizeof(s32));
if (connResult >= 0) {
// We are done!
if (Memory::IsValidAddress(scanInfosAddr))
userMemory.Free(scanInfosAddr);
scanInfosAddr = 0;
}
}
}
break;
default:
if (connResult < 0) {
connResult = sceNetAdhocctlConnect(request.NetconfData->groupName);
}
break;
}
}
}
}
// The Netconf dialog stays visible until the network reaches
@ -342,12 +453,20 @@ int PSPNetconfDialog::Update(int animSpeed) {
else if (GetStatus() == SCE_UTILITY_STATUS_FINISHED) {
StartFade(false);
}
// Let's not leaks any memory
if (Memory::IsValidAddress(scanInfosAddr))
userMemory.Free(scanInfosAddr);
scanInfosAddr = 0;
}
if (request.netAction == NETCONF_JOIN_ADHOC && IsButtonPressed(cancelButtonFlag)) {
if ((request.netAction == NETCONF_JOIN_ADHOC || timedout) && IsButtonPressed(cancelButtonFlag)) {
StartFade(false);
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, NET_SHUTDOWN_DELAY_US);
request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT;
// Let's not leaks any memory
if (Memory::IsValidAddress(scanInfosAddr))
userMemory.Free(scanInfosAddr);
scanInfosAddr = 0;
}
EndDraw();
@ -374,11 +493,25 @@ int PSPNetconfDialog::Shutdown(bool force) {
void PSPNetconfDialog::DoState(PointerWrap &p) {
PSPDialog::DoState(p);
auto s = p.Section("PSPNetconfigDialog", 0, 1);
auto s = p.Section("PSPNetconfigDialog", 0, 2);
if (!s)
return;
Do(p, request);
if (s >= 2) {
Do(p, scanInfosAddr);
Do(p, scanStep);
Do(p, connResult);
}
else {
scanInfosAddr = 0;
scanStep = 0;
connResult = -1;
}
if (p.mode == p.MODE_READ) {
startTime = 0;
}
}
pspUtilityDialogCommon* PSPNetconfDialog::GetCommonParam()

View file

@ -34,6 +34,7 @@ struct SceUtilityNetconfParam {
int netWifiSpot; // Flag to allow WIFI connections
};
class PSPNetconfDialog: public PSPDialog {
public:
PSPNetconfDialog();
@ -57,11 +58,15 @@ private:
SceUtilityNetconfParam request = {};
u32 requestAddr = 0;
int connResult = 0;
int connResult = -1;
bool hideNotice = false;
int yesnoChoice = 0;
float scrollPos_ = 0.0f;
int framesUpHeld_ = 0;
int framesDownHeld_ = 0;
u32 scanInfosAddr = 0;
int scanStep = 0;
u64 startTime = 0;
};

View file

@ -43,6 +43,7 @@
#include "Core/HLE/sceKernelInterrupt.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceKernelMemory.h"
#include "Core/HLE/sceNetAdhoc.h"
#include "Core/Instance.h"
#include "proAdhoc.h"
@ -55,7 +56,9 @@ bool friendFinderRunning = false;
SceNetAdhocctlPeerInfo * friends = NULL;
SceNetAdhocctlScanInfo * networks = NULL;
SceNetAdhocctlScanInfo * newnetworks = NULL;
int threadStatus = ADHOCCTL_STATE_DISCONNECTED;
u64 adhocctlStartTime = 0;
int adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
int adhocConnectionType = ADHOC_CONNECT;
int actionAfterAdhocMipsCall;
int actionAfterMatchingMipsCall;
@ -70,6 +73,7 @@ std::thread friendFinderThread;
std::recursive_mutex peerlock;
SceNetAdhocPdpStat * pdp[255];
SceNetAdhocPtpStat * ptp[255];
std::map<int, int> ptpConnectCount;
std::vector<std::string> chatLog;
std::string name = "";
std::string incoming = "";
@ -209,6 +213,28 @@ SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC) {
return peer;
}
int IsSocketReady(int fd, bool readfd, bool writefd, int* errorcode, int timeoutUS) {
fd_set readfds, writefds;
timeval tval;
FD_ZERO(&readfds);
writefds = readfds;
if (readfd) {
FD_SET(fd, &readfds);
}
if (writefd) {
FD_SET(fd, &writefds);
}
tval.tv_sec = timeoutUS / 1000000;
tval.tv_usec = timeoutUS % 1000000;
int ret = select(fd + 1, &readfds, &writefds, nullptr, &tval);
if (errorcode != nullptr)
*errorcode = errno;
return ret;
}
void changeBlockingMode(int fd, int nonblocking) {
unsigned long on = 1;
unsigned long off = 0;
@ -320,6 +346,7 @@ void deleteAllPTP() {
// Delete Reference
ptp[i] = NULL;
ptpConnectCount.erase(i);
}
}
}
@ -1173,12 +1200,14 @@ void sendChat(std::string chatString) {
message = chatString.substr(0, 60); // 64 return chat variable corrupted is it out of memory?
strcpy(chat.message, message.c_str());
//Send Chat Messages
int chatResult = send(metasocket, (const char *)&chat, sizeof(chat), 0);
NOTICE_LOG(SCENET, "Send Chat %s to Adhoc Server", chat.message);
name = g_Config.sNickName.c_str();
chatLog.push_back(name.substr(0, 8) + ": " + chat.message);
if (chatScreenVisible) {
updateChatScreen = true;
if (IsSocketReady(metasocket, false, true) > 0) {
int chatResult = send(metasocket, (const char*)&chat, sizeof(chat), 0);
NOTICE_LOG(SCENET, "Send Chat %s to Adhoc Server", chat.message);
name = g_Config.sNickName.c_str();
chatLog.push_back(name.substr(0, 8) + ": " + chat.message);
if (chatScreenVisible) {
updateChatScreen = true;
}
}
}
}
@ -1227,47 +1256,66 @@ int friendFinder(){
// Reconnect when disconnected while Adhocctl is still inited
if (metasocket == (int)INVALID_SOCKET && netAdhocctlInited) {
if (g_Config.bEnableWlan && initNetwork(&product_code) == 0) {
networkInited = true;
}
}
if (networkInited) {
// Ping Server
now = real_time_now() * 1000000.0; // Use real_time_now()*1000000.0 instead of CoreTiming::GetGlobalTimeUsScaled() if the game gets disconnected from AdhocServer too soon when FPS wasn't stable
if (now - lastping >= PSP_ADHOCCTL_PING_TIMEOUT) { // We may need to use lower interval to prevent getting timeout at Pro Adhoc Server through internet
// original code : ((sceKernelGetSystemTimeWide() - lastping) >= ADHOCCTL_PING_TIMEOUT)
// Update Ping Time
lastping = now;
// Prepare Packet
uint8_t opcode = OPCODE_PING;
// Send Ping to Server, may failed with socket error 10054/10053 if someone else with the same IP already connected to AdHoc Server (the server might need to be modified to differentiate MAC instead of IP)
int iResult = send(metasocket, (const char*)&opcode, 1, 0);
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "FriendFinder: Socket Error (%i) when sending OPCODE_PING", errno);
if (g_Config.bEnableWlan) {
if (initNetwork(&product_code) == 0) {
networkInited = true;
INFO_LOG(SCENET, "FriendFinder: Network [RE]Initialized");
}
else {
networkInited = false;
shutdown(metasocket, SD_BOTH);
closesocket(metasocket);
metasocket = (int)INVALID_SOCKET;
}
}
}
// Wait for Incoming Data
int received = recv(metasocket, (char*)(rx + rxpos), sizeof(rx) - rxpos, 0);
if (networkInited) {
// Ping Server
now = real_time_now() * 1000000.0; // Use real_time_now()*1000000.0 instead of CoreTiming::GetGlobalTimeUsScaled() if the game gets disconnected from AdhocServer too soon when FPS wasn't stable
// original code : ((sceKernelGetSystemTimeWide() - lastping) >= ADHOCCTL_PING_TIMEOUT)
if (now - lastping >= PSP_ADHOCCTL_PING_TIMEOUT) { // We may need to use lower interval to prevent getting timeout at Pro Adhoc Server through internet
// Prepare Packet
uint8_t opcode = OPCODE_PING;
// Free Network Lock
//_freeNetworkLock();
// Send Ping to Server, may failed with socket error 10054/10053 if someone else with the same IP already connected to AdHoc Server (the server might need to be modified to differentiate MAC instead of IP)
if (IsSocketReady(metasocket, false, true) > 0) {
int iResult = send(metasocket, (const char*)&opcode, 1, 0);
int error = errno;
// KHBBS seems to be getting error 10053 often
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "FriendFinder: Socket Error (%i) when sending OPCODE_PING", error);
if (error != EAGAIN && error != EWOULDBLOCK) {
networkInited = false;
shutdown(metasocket, SD_BOTH);
closesocket(metasocket);
metasocket = (int)INVALID_SOCKET;
}
}
else {
// Update Ping Time
lastping = now;
DEBUG_LOG(SCENET, "FriendFinder: Sending OPCODE_PING (%llu)", now);
}
}
}
// Received Data
if (received > 0) {
// Fix Position
rxpos += received;
// Check for Incoming Data
if (IsSocketReady(metasocket, true, false) > 0) {
int received = recv(metasocket, (char*)(rx + rxpos), sizeof(rx) - rxpos, 0);
// Log Incoming Traffic
//printf("Received %d Bytes of Data from Server\n", received);
INFO_LOG(SCENET, "Received %d Bytes of Data from Adhoc Server", received);
// Free Network Lock
//_freeNetworkLock();
// Received Data
if (received > 0) {
// Fix Position
rxpos += received;
// Log Incoming Traffic
//printf("Received %d Bytes of Data from Server\n", received);
INFO_LOG(SCENET, "Received %d Bytes of Data from Adhoc Server", received);
}
}
// Handle Packets
@ -1280,6 +1328,9 @@ int friendFinder(){
SceNetAdhocctlConnectBSSIDPacketS2C* packet = (SceNetAdhocctlConnectBSSIDPacketS2C*)rx;
INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT_BSSID [%s]", mac2str(&packet->mac).c_str());
// Update User BSSID
parameter.bssid.mac_addr = packet->mac; // This packet seems to contains Adhoc Group Creator's BSSID (similar to AP's BSSID) so it shouldn't get mixed up with local MAC address
// From JPCSP: Some games have problems when the PSP_ADHOCCTL_EVENT_CONNECTED is sent too quickly after connecting to a network. The connection will be set CONNECTED with a small delay (200ms or 200us?)
/*if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) {
setState(ADHOCCTL_STATE_GAMEMODE);
@ -1290,12 +1341,10 @@ int friendFinder(){
notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0);
}*/
// Update User BSSID
parameter.bssid.mac_addr = packet->mac; // This packet seems to contains Adhoc Group Creator's BSSID (similar to AP's BSSID) so it shouldn't get mixed up with local MAC address
// Notify Event Handlers
//notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0);
notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0);
// Change State
threadStatus = ADHOCCTL_STATE_CONNECTED;
//threadStatus = ADHOCCTL_STATE_CONNECTED;
// Give time a little time
//sceKernelDelayThread(adhocEventDelayMS * 1000);
//sleep_ms(adhocEventDelayMS);
@ -1492,14 +1541,14 @@ int friendFinder(){
peerlock.unlock();
// Notify Event Handlers
//notifyAdhocctlHandlers(ADHOCCTL_EVENT_SCAN, 0);
notifyAdhocctlHandlers(ADHOCCTL_EVENT_SCAN, 0);
//int i = 0; for(; i < ADHOCCTL_MAX_HANDLER; i++)
//{
// // Active Handler
// if(_event_handler[i] != NULL) _event_handler[i](ADHOCCTL_EVENT_SCAN, 0, _event_args[i]);
//}
// Change State
threadStatus = ADHOCCTL_STATE_DISCONNECTED;
//threadStatus = ADHOCCTL_STATE_DISCONNECTED;
// Give time a little time
//sceKernelDelayThread(adhocEventDelayMS * 1000);
//sleep_ms(adhocEventDelayMS);
@ -1522,7 +1571,7 @@ int friendFinder(){
// Groups/Networks should be deallocated isn't?
// Prevent the games from having trouble to reInitiate Adhoc (the next NetInit -> PdpCreate after NetTerm)
threadStatus = ADHOCCTL_STATE_DISCONNECTED;
adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
// Log Shutdown
INFO_LOG(SCENET, "FriendFinder: End of Friend Finder Thread");
@ -1559,7 +1608,8 @@ int getLocalIp(sockaddr_in* SocketAddress) {
struct sockaddr_in localAddr;
localAddr.sin_addr.s_addr = INADDR_ANY;
socklen_t addrLen = sizeof(localAddr);
if (SOCKET_ERROR != getsockname(metasocket, (struct sockaddr*) & localAddr, &addrLen)) {
int ret = getsockname(metasocket, (struct sockaddr*)&localAddr, &addrLen);
if (SOCKET_ERROR != ret) {
if (isLocalServer) {
localAddr.sin_addr = g_localhostIP.in.sin_addr;
}
@ -1838,6 +1888,10 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
return SOCKET_ERROR;
}
setSockKeepAlive(metasocket, true);
// Disable Nagle Algo to prevent delaying small packets
setSockNoDelay(metasocket, 1);
// Switch to Nonblocking Behaviour
changeBlockingMode(metasocket, 1);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
@ -1894,19 +1948,14 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
product_code.type = adhoc_id->type;
memcpy(product_code.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
// Switch to Nonblocking Behaviour
changeBlockingMode(metasocket, 1);
// Connect to Adhoc Server
server_addr.sin_addr = serverIp;
int errorcode = 0;
int cnt = 0;
while ((iResult = connect(metasocket, (sockaddr*)&server_addr, sizeof(server_addr))) == SOCKET_ERROR && (errorcode = errno) != EISCONN && cnt < adhocDefaultTimeout) {
sleep_ms(1);
cnt++;
}
// Switch back to Blocking Behaviour
changeBlockingMode(metasocket, 0);
if (iResult == SOCKET_ERROR && errorcode != EISCONN) {
iResult = connect(metasocket, (sockaddr*)&server_addr, sizeof(server_addr));
errorcode = errno;
if (iResult == SOCKET_ERROR && errorcode != EISCONN && (IsSocketReady(metasocket, true, true, nullptr, adhocDefaultTimeout * 1000) <= 0)) {
char buffer[512];
snprintf(buffer, sizeof(buffer), "Socket error (%i) when connecting to AdhocServer [%s/%s:%u]", errorcode, g_Config.proAdhocServer.c_str(), inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port));
ERROR_LOG(SCENET, "%s", buffer);
@ -1923,8 +1972,9 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
strncpy((char *)&packet.name.data, g_Config.sNickName.c_str(), ADHOCCTL_NICKNAME_LEN);
packet.name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0;
memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
IsSocketReady(metasocket, false, true, nullptr, adhocDefaultTimeout * 1000);
int sent = send(metasocket, (char*)&packet, sizeof(packet), 0);
changeBlockingMode(metasocket, 1); // Change to non-blocking
if (sent > 0) {
socklen_t addrLen = sizeof(LocalIP);
memset(&LocalIP, 0, addrLen);

View file

@ -49,7 +49,6 @@
#include "Core/MemMap.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/HLEHelperThread.h"
#include "Core/HLE/sceNetAdhoc.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/sceKernel.h"
#include "Core/HLE/sceKernelMutex.h"
@ -253,14 +252,16 @@ typedef struct SceNetAdhocctlParameter {
SceNetAdhocctlNickname nickname;
} PACK SceNetAdhocctlParameter;
// Peer Information
// Peer Information (internal use only)
typedef struct SceNetAdhocctlPeerInfo {
SceNetAdhocctlPeerInfo * next;
SceNetAdhocctlNickname nickname;
SceNetEtherAddr mac_addr;
u32_le ip_addr;
uint8_t padding[2];
u16_le padding;
u32_le flags;
u64_le last_recv; // Need to use the same method with sceKernelGetSystemTimeWide (ie. CoreTiming::GetGlobalTimeUsScaled) to prevent timing issue (ie. in game timeout)
u32_le ip_addr; // internal use only
} PACK SceNetAdhocctlPeerInfo;
// Peer Information with u32 pointers
@ -268,8 +269,8 @@ typedef struct SceNetAdhocctlPeerInfoEmu {
u32_le next; // Changed the pointer to u32
SceNetAdhocctlNickname nickname;
SceNetEtherAddr mac_addr;
u32_le ip_addr; //jpcsp wrote 6bytes of 0x11 for this & padding
u16 padding; // Changed the padding to u16
u16_le padding; //00 00
u32_le flags; //00 04 00 00 // State of the peer? Or related to sceNetAdhocAuth_CF4D9BED ?
u64_le last_recv; // Need to use the same method with sceKernelGetSystemTimeWide (ie. CoreTiming::GetGlobalTimeUsScaled) to prevent timing issue (ie. in game timeout)
} PACK SceNetAdhocctlPeerInfoEmu;
@ -827,6 +828,7 @@ extern std::thread friendFinderThread;
extern std::recursive_mutex peerlock;
extern SceNetAdhocPdpStat * pdp[255];
extern SceNetAdhocPtpStat * ptp[255];
extern std::map<int, int> ptpConnectCount;
union SockAddrIN4 {
sockaddr addr;
@ -846,10 +848,19 @@ extern SceNetAdhocMatchingContext * contexts;
extern int one;
extern bool friendFinderRunning;
extern SceNetAdhocctlPeerInfo * friends;
extern SceNetAdhocctlScanInfo * networks;
extern int threadStatus;
extern SceNetAdhocctlScanInfo * networks;
extern u64 adhocctlStartTime;
extern int adhocctlState;
extern int adhocConnectionType;
// End of Aux vars
enum AdhocConnectionType : int
{
ADHOC_CONNECT = 0,
ADHOC_CREATE = 1,
ADHOC_JOIN = 2,
};
// Check if Matching callback is running
bool IsMatchingInCallback(SceNetAdhocMatchingContext * context);
bool SetMatchingInCallback(SceNetAdhocMatchingContext* context, bool IsInCB);
@ -917,6 +928,14 @@ extern int newChat;
*/
SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC);
/**
* Get the Readability(ie. recv) and/or Writability(ie. send) of a socket
* @param fd File Descriptor of the socket
* @param timeout in usec (micro seconds), 0 = non-blocking
* @return > 0 = ready, 0 = timeout, -1 = error (errorcode only represent error of select and doesn't represent error of the socket)
*/
int IsSocketReady(int fd, bool readfd, bool writefd, int* errorcode = nullptr, int timeoutUS = 0);
/**
* Changes the Blocking Mode of the socket
* @param fd File Descriptor of the socket

View file

@ -2075,7 +2075,7 @@ int server_loop(int server)
sleep_ms(1);
// Don't do anything if it's paused, otherwise the log will be flooded
while (adhocServerRunning && Core_IsStepping()) sleep_ms(1);
while (adhocServerRunning && Core_IsStepping() && coreState != CORE_POWERDOWN) sleep_ms(1);
}
// Free User Database Memory

View file

@ -81,6 +81,7 @@ const WaitTypeNames waitTypeNames[] = {
{ WAITTYPE_VMEM, "Volatile Mem" },
{ WAITTYPE_ASYNCIO, "AsyncIO" },
{ WAITTYPE_MICINPUT, "Microphone input"},
{ WAITTYPE_NET, "Network"},
};
const char *getWaitTypeName(WaitType type)

View file

@ -107,6 +107,7 @@ enum WaitType : int
WAITTYPE_VMEM = 22,
WAITTYPE_ASYNCIO = 23,
WAITTYPE_MICINPUT = 24, // fake
WAITTYPE_NET = 25, // fake
NUM_WAITTYPES
};

View file

@ -162,7 +162,7 @@ void __NetInit() {
SceNetEtherAddr mac;
getLocalMac(&mac);
INFO_LOG(SCENET, "LocalHost IP will be %s [%s]", inet_ntoa(g_localhostIP.in.sin_addr), mac2str(&mac).c_str());
NOTICE_LOG(SCENET, "LocalHost IP will be %s [%s]", inet_ntoa(g_localhostIP.in.sin_addr), mac2str(&mac).c_str());
// TODO: May be we should initialize & cleanup somewhere else than here for PortManager to be used as general purpose for whatever port forwarding PPSSPP needed
__UPnPInit();
@ -200,6 +200,15 @@ void notifyApctlHandlers(int oldState, int newState, int flag, int error) {
__UpdateApctlHandlers(oldState, newState, flag, error);
}
void netValidateLoopMemory() {
// Allocate Memory if it wasn't valid/allocated after loaded from old SaveState
if (!apctlThreadHackAddr || (apctlThreadHackAddr && strcmp("apctlThreadHack", kernelMemory.GetBlockTag(apctlThreadHackAddr)) != 0)) {
u32 blockSize = sizeof(apctlThreadCode);
apctlThreadHackAddr = kernelMemory.Alloc(blockSize, false, "apctlThreadHack");
if (apctlThreadHackAddr) Memory::Memcpy(apctlThreadHackAddr, apctlThreadCode, sizeof(apctlThreadCode));
}
}
// This feels like a dubious proposition, mostly...
void __NetDoState(PointerWrap &p) {
auto s = p.Section("sceNet", 1, 4);
@ -244,19 +253,15 @@ void __NetDoState(PointerWrap &p) {
apctlThreadHackAddr = 0;
apctlThreadID = 0;
}
// Let's not change "Inited" value when Loading SaveState in the middle of multiplayer to prevent memory & port leaks
if (p.mode == p.MODE_READ) {
// Let's not change "Inited" value when Loading SaveState in the middle of multiplayer to prevent memory & port leaks
netApctlInited = cur_netApctlInited;
netInetInited = cur_netInetInited;
netInited = cur_netInited;
// Previously, this wasn't being saved. It needs its own space.
if (!apctlThreadHackAddr || (apctlThreadHackAddr && strcmp("apctlThreadHack", kernelMemory.GetBlockTag(apctlThreadHackAddr)) != 0)) {
u32 blockSize = sizeof(apctlThreadCode);
apctlThreadHackAddr = kernelMemory.Alloc(blockSize, false, "apctlThreadHack");
}
// Restore Apctl Loop MIPS code to prevent crashes after loading from SaveState
if (apctlThreadHackAddr) Memory::Memcpy(apctlThreadHackAddr, apctlThreadCode, sizeof(apctlThreadCode));
// Discard leftover events
apctlEvents.clear();
}
}
@ -469,7 +474,7 @@ void __NetApctlCallbacks()
// Must be delayed long enough whenever there is a pending callback.
sceKernelDelayThread(delayus);
hleSkipDeadbeef();;
hleSkipDeadbeef();
}
static inline u32 AllocUser(u32 size, bool fromTop, const char *name) {
@ -582,6 +587,7 @@ static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netini
// Clear Socket Translator Memory
memset(&pdp, 0, sizeof(pdp));
memset(&ptp, 0, sizeof(ptp));
ptpConnectCount.clear();
return hleLogSuccessI(SCENET, 0);
}
@ -776,6 +782,7 @@ static int sceNetApctlInit(int stackSize, int initPriority) {
truncate_cpy(netApctlInfo.subNetMask, sizeof(netApctlInfo.subNetMask), "0.0.0.0");
// Create APctl fake-Thread
netValidateLoopMemory();
apctlThreadID = __KernelCreateThread("ApctlThread", __KernelGetCurThreadModuleId(), apctlThreadHackAddr, initPriority, stackSize, PSP_THREAD_ATTR_USER, 0, true);
if (apctlThreadID > 0) {
__KernelStartThread(apctlThreadID, 0, 0);

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,7 @@
#pragma once
#include <deque>
#include "Core/HLE/proAdhoc.h"
#ifdef _MSC_VER
@ -29,6 +30,44 @@ typedef struct MatchingArgs {
#pragma pack(pop)
#endif
struct AdhocctlRequest {
u8 opcode;
SceNetAdhocctlGroupName group;
};
struct AdhocSendTarget {
u32 ip;
u16 port; // original port
};
struct AdhocSendTargets {
int length;
std::deque<AdhocSendTarget> peers;
bool isBroadcast;
};
struct AdhocSocketRequest {
int type;
int id; // PDP/PTP socket id
void* buffer;
s32_le* length;
u32 timeout;
u64 startTime;
SceNetEtherAddr* remoteMAC;
u16_le* remotePort;
};
enum AdhocSocketRequestType : int
{
PTP_CONNECT = 0,
PTP_ACCEPT = 1,
PTP_SEND = 2,
PTP_RECV = 3,
PDP_SEND = 4,
PDP_RECV = 5,
ADHOC_POLL_SOCKET = 6,
};
class PointerWrap;
void Register_sceNetAdhoc();
@ -41,7 +80,18 @@ void __UpdateAdhocctlHandlers(u32 flags, u32 error);
void __UpdateMatchingHandler(MatchingArgs params);
// I have to call this from netdialog
int sceNetAdhocctlGetState(u32 ptrToStatus);
int sceNetAdhocctlCreate(const char * groupName);
int sceNetAdhocctlConnect(const char* groupName);
int sceNetAdhocctlJoin(u32 scanInfoAddr);
int sceNetAdhocctlScan();
int sceNetAdhocctlGetScanInfo(u32 sizeAddr, u32 bufAddr);
int NetAdhocMatching_Term();
int NetAdhocctl_Term();
int NetAdhocctl_GetState();
int NetAdhocctl_Create(const char* groupName);
int NetAdhoc_Term();
// May need to use these from sceNet.cpp
extern bool netAdhocInited;
@ -60,7 +110,3 @@ extern u32_le dummyThreadCode[3];
extern u32 matchingThreadHackAddr;
extern u32_le matchingThreadCode[3];
int NetAdhocMatching_Term();
int NetAdhocctl_Term();
int NetAdhocctl_GetState();
int NetAdhoc_Term();