mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #13318 from ANR2ME/net_blocking
Simulate blocking behavior using non-blocking on networking
This commit is contained in:
commit
619009be93
10 changed files with 1343 additions and 559 deletions
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -107,6 +107,7 @@ enum WaitType : int
|
|||
WAITTYPE_VMEM = 22,
|
||||
WAITTYPE_ASYNCIO = 23,
|
||||
WAITTYPE_MICINPUT = 24, // fake
|
||||
WAITTYPE_NET = 25, // fake
|
||||
|
||||
NUM_WAITTYPES
|
||||
};
|
||||
|
|
|
@ -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
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue