mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Fix communication issue with Adhoc Server where ping to the Adhoc Server sometimes getting socket error 10053 and disconnected from Adhoc Server
This commit is contained in:
parent
97904d7149
commit
a05da1a8c5
4 changed files with 219 additions and 141 deletions
|
@ -43,6 +43,7 @@
|
||||||
#include "Core/HLE/sceKernelInterrupt.h"
|
#include "Core/HLE/sceKernelInterrupt.h"
|
||||||
#include "Core/HLE/sceKernelThread.h"
|
#include "Core/HLE/sceKernelThread.h"
|
||||||
#include "Core/HLE/sceKernelMemory.h"
|
#include "Core/HLE/sceKernelMemory.h"
|
||||||
|
#include "Core/HLE/sceNetAdhoc.h"
|
||||||
#include "Core/Instance.h"
|
#include "Core/Instance.h"
|
||||||
#include "proAdhoc.h"
|
#include "proAdhoc.h"
|
||||||
|
|
||||||
|
@ -212,13 +213,26 @@ SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC) {
|
||||||
return peer;
|
return peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getNonBlockingFlag(int fd) {
|
int IsSocketReady(int fd, bool readfd, bool writefd, int* errorcode, int timeoutUS) {
|
||||||
#ifdef _WIN32
|
fd_set readfds, writefds;
|
||||||
return 0;
|
timeval tval;
|
||||||
#else
|
|
||||||
int sockflag = fcntl(fd, F_GETFL, O_NONBLOCK);
|
FD_ZERO(&readfds);
|
||||||
return sockflag & O_NONBLOCK;
|
writefds = readfds;
|
||||||
#endif
|
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) {
|
void changeBlockingMode(int fd, int nonblocking) {
|
||||||
|
@ -1186,14 +1200,14 @@ void sendChat(std::string chatString) {
|
||||||
message = chatString.substr(0, 60); // 64 return chat variable corrupted is it out of memory?
|
message = chatString.substr(0, 60); // 64 return chat variable corrupted is it out of memory?
|
||||||
strcpy(chat.message, message.c_str());
|
strcpy(chat.message, message.c_str());
|
||||||
//Send Chat Messages
|
//Send Chat Messages
|
||||||
changeBlockingMode(metasocket, 0);
|
if (IsSocketReady(metasocket, false, true) > 0) {
|
||||||
int chatResult = send(metasocket, (const char *)&chat, sizeof(chat), 0);
|
int chatResult = send(metasocket, (const char*)&chat, sizeof(chat), 0);
|
||||||
changeBlockingMode(metasocket, 1);
|
NOTICE_LOG(SCENET, "Send Chat %s to Adhoc Server", chat.message);
|
||||||
NOTICE_LOG(SCENET, "Send Chat %s to Adhoc Server", chat.message);
|
name = g_Config.sNickName.c_str();
|
||||||
name = g_Config.sNickName.c_str();
|
chatLog.push_back(name.substr(0, 8) + ": " + chat.message);
|
||||||
chatLog.push_back(name.substr(0, 8) + ": " + chat.message);
|
if (chatScreenVisible) {
|
||||||
if (chatScreenVisible) {
|
updateChatScreen = true;
|
||||||
updateChatScreen = true;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1242,49 +1256,66 @@ int friendFinder(){
|
||||||
|
|
||||||
// Reconnect when disconnected while Adhocctl is still inited
|
// Reconnect when disconnected while Adhocctl is still inited
|
||||||
if (metasocket == (int)INVALID_SOCKET && netAdhocctlInited) {
|
if (metasocket == (int)INVALID_SOCKET && netAdhocctlInited) {
|
||||||
if (g_Config.bEnableWlan && initNetwork(&product_code) == 0) {
|
if (g_Config.bEnableWlan) {
|
||||||
networkInited = true;
|
if (initNetwork(&product_code) == 0) {
|
||||||
}
|
networkInited = true;
|
||||||
}
|
INFO_LOG(SCENET, "FriendFinder: Network [RE]Initialized");
|
||||||
|
}
|
||||||
if (networkInited) {
|
else {
|
||||||
// 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)
|
|
||||||
changeBlockingMode(metasocket, 0);
|
|
||||||
int iResult = send(metasocket, (const char*)&opcode, 1, 0);
|
|
||||||
changeBlockingMode(metasocket, 1);
|
|
||||||
if (iResult == SOCKET_ERROR) {
|
|
||||||
ERROR_LOG(SCENET, "FriendFinder: Socket Error (%i) when sending OPCODE_PING", errno);
|
|
||||||
networkInited = false;
|
networkInited = false;
|
||||||
shutdown(metasocket, SD_BOTH);
|
shutdown(metasocket, SD_BOTH);
|
||||||
closesocket(metasocket);
|
closesocket(metasocket);
|
||||||
metasocket = (int)INVALID_SOCKET;
|
metasocket = (int)INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for Incoming Data
|
if (networkInited) {
|
||||||
int received = recv(metasocket, (char*)(rx + rxpos), sizeof(rx) - rxpos, 0);
|
// 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
|
// 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)
|
||||||
//_freeNetworkLock();
|
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
|
// Check for Incoming Data
|
||||||
if (received > 0) {
|
if (IsSocketReady(metasocket, true, false) > 0) {
|
||||||
// Fix Position
|
int received = recv(metasocket, (char*)(rx + rxpos), sizeof(rx) - rxpos, 0);
|
||||||
rxpos += received;
|
|
||||||
|
|
||||||
// Log Incoming Traffic
|
// Free Network Lock
|
||||||
//printf("Received %d Bytes of Data from Server\n", received);
|
//_freeNetworkLock();
|
||||||
INFO_LOG(SCENET, "Received %d Bytes of Data from Adhoc Server", received);
|
|
||||||
|
// 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
|
// Handle Packets
|
||||||
|
@ -1297,6 +1328,9 @@ int friendFinder(){
|
||||||
SceNetAdhocctlConnectBSSIDPacketS2C* packet = (SceNetAdhocctlConnectBSSIDPacketS2C*)rx;
|
SceNetAdhocctlConnectBSSIDPacketS2C* packet = (SceNetAdhocctlConnectBSSIDPacketS2C*)rx;
|
||||||
|
|
||||||
INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT_BSSID [%s]", mac2str(&packet->mac).c_str());
|
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?)
|
// 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) {
|
/*if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) {
|
||||||
setState(ADHOCCTL_STATE_GAMEMODE);
|
setState(ADHOCCTL_STATE_GAMEMODE);
|
||||||
|
@ -1307,8 +1341,6 @@ int friendFinder(){
|
||||||
notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0);
|
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
|
// Notify Event Handlers
|
||||||
notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0);
|
notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0);
|
||||||
// Change State
|
// Change State
|
||||||
|
@ -1576,9 +1608,7 @@ int getLocalIp(sockaddr_in* SocketAddress) {
|
||||||
struct sockaddr_in localAddr;
|
struct sockaddr_in localAddr;
|
||||||
localAddr.sin_addr.s_addr = INADDR_ANY;
|
localAddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
socklen_t addrLen = sizeof(localAddr);
|
socklen_t addrLen = sizeof(localAddr);
|
||||||
changeBlockingMode(metasocket, 0);
|
|
||||||
int ret = getsockname(metasocket, (struct sockaddr*)&localAddr, &addrLen);
|
int ret = getsockname(metasocket, (struct sockaddr*)&localAddr, &addrLen);
|
||||||
changeBlockingMode(metasocket, 1);
|
|
||||||
if (SOCKET_ERROR != ret) {
|
if (SOCKET_ERROR != ret) {
|
||||||
if (isLocalServer) {
|
if (isLocalServer) {
|
||||||
localAddr.sin_addr = g_localhostIP.in.sin_addr;
|
localAddr.sin_addr = g_localhostIP.in.sin_addr;
|
||||||
|
@ -1858,6 +1888,10 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
|
||||||
return SOCKET_ERROR;
|
return SOCKET_ERROR;
|
||||||
}
|
}
|
||||||
setSockKeepAlive(metasocket, true);
|
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;
|
struct sockaddr_in server_addr;
|
||||||
server_addr.sin_family = AF_INET;
|
server_addr.sin_family = AF_INET;
|
||||||
|
@ -1914,17 +1948,14 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
|
||||||
product_code.type = adhoc_id->type;
|
product_code.type = adhoc_id->type;
|
||||||
memcpy(product_code.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
|
memcpy(product_code.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
|
||||||
|
|
||||||
// Switch to Nonblocking Behaviour
|
|
||||||
changeBlockingMode(metasocket, 1);
|
|
||||||
// Connect to Adhoc Server
|
// Connect to Adhoc Server
|
||||||
server_addr.sin_addr = serverIp;
|
server_addr.sin_addr = serverIp;
|
||||||
int errorcode = 0;
|
int errorcode = 0;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
while ((iResult = connect(metasocket, (sockaddr*)&server_addr, sizeof(server_addr))) == SOCKET_ERROR && (errorcode = errno) != EISCONN && cnt < adhocDefaultTimeout) {
|
iResult = connect(metasocket, (sockaddr*)&server_addr, sizeof(server_addr));
|
||||||
sleep_ms(1);
|
errorcode = errno;
|
||||||
cnt++;
|
|
||||||
}
|
if (iResult == SOCKET_ERROR && errorcode != EISCONN && (IsSocketReady(metasocket, true, true, nullptr, adhocDefaultTimeout * 1000) <= 0)) {
|
||||||
if (iResult == SOCKET_ERROR && errorcode != EISCONN) {
|
|
||||||
char buffer[512];
|
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));
|
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);
|
ERROR_LOG(SCENET, "%s", buffer);
|
||||||
|
@ -1941,9 +1972,9 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
|
||||||
strncpy((char *)&packet.name.data, g_Config.sNickName.c_str(), ADHOCCTL_NICKNAME_LEN);
|
strncpy((char *)&packet.name.data, g_Config.sNickName.c_str(), ADHOCCTL_NICKNAME_LEN);
|
||||||
packet.name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0;
|
packet.name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0;
|
||||||
memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
|
memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
|
||||||
changeBlockingMode(metasocket, 0);
|
|
||||||
|
IsSocketReady(metasocket, false, true, nullptr, adhocDefaultTimeout * 1000);
|
||||||
int sent = send(metasocket, (char*)&packet, sizeof(packet), 0);
|
int sent = send(metasocket, (char*)&packet, sizeof(packet), 0);
|
||||||
changeBlockingMode(metasocket, 1);
|
|
||||||
if (sent > 0) {
|
if (sent > 0) {
|
||||||
socklen_t addrLen = sizeof(LocalIP);
|
socklen_t addrLen = sizeof(LocalIP);
|
||||||
memset(&LocalIP, 0, addrLen);
|
memset(&LocalIP, 0, addrLen);
|
||||||
|
|
|
@ -49,7 +49,6 @@
|
||||||
#include "Core/MemMap.h"
|
#include "Core/MemMap.h"
|
||||||
#include "Core/HLE/HLE.h"
|
#include "Core/HLE/HLE.h"
|
||||||
#include "Core/HLE/HLEHelperThread.h"
|
#include "Core/HLE/HLEHelperThread.h"
|
||||||
#include "Core/HLE/sceNetAdhoc.h"
|
|
||||||
#include "Core/HLE/sceKernelThread.h"
|
#include "Core/HLE/sceKernelThread.h"
|
||||||
#include "Core/HLE/sceKernel.h"
|
#include "Core/HLE/sceKernel.h"
|
||||||
#include "Core/HLE/sceKernelMutex.h"
|
#include "Core/HLE/sceKernelMutex.h"
|
||||||
|
@ -928,11 +927,12 @@ extern int newChat;
|
||||||
SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC);
|
SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Non-Blocking Mode of the socket
|
* Get the Readability(ie. recv) and/or Writability(ie. send) of a socket
|
||||||
* @param fd File Descriptor of the socket
|
* @param fd File Descriptor of the socket
|
||||||
* @return 1 for non-blocking, 0 for blocking
|
* @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 getNonBlockingFlag(int fd);
|
int IsSocketReady(int fd, bool readfd, bool writefd, int* errorcode = nullptr, int timeoutUS = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the Blocking Mode of the socket
|
* Changes the Blocking Mode of the socket
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
#include "Core/HLE/sceKernelMemory.h"
|
#include "Core/HLE/sceKernelMemory.h"
|
||||||
#include "Core/HLE/sceKernelModule.h"
|
#include "Core/HLE/sceKernelModule.h"
|
||||||
#include "Core/HLE/sceKernelInterrupt.h"
|
#include "Core/HLE/sceKernelInterrupt.h"
|
||||||
#include "Core/HLE/proAdhoc.h"
|
|
||||||
#include "Core/HLE/sceNetAdhoc.h"
|
#include "Core/HLE/sceNetAdhoc.h"
|
||||||
#include "Core/HLE/sceNet.h"
|
#include "Core/HLE/sceNet.h"
|
||||||
#include "Core/HLE/proAdhocServer.h"
|
#include "Core/HLE/proAdhocServer.h"
|
||||||
|
@ -63,7 +62,7 @@ static bool netAdhocMatchingInited;
|
||||||
int netAdhocMatchingStarted = 0;
|
int netAdhocMatchingStarted = 0;
|
||||||
int adhocDefaultTimeout = 2000; //5000 ms
|
int adhocDefaultTimeout = 2000; //5000 ms
|
||||||
int adhocExtraPollDelayMS = 10; //10
|
int adhocExtraPollDelayMS = 10; //10
|
||||||
int adhocEventPollDelayMS = 100; //100
|
int adhocEventPollDelayMS = 100; //100; Seems to be the same with PSP_ADHOCCTL_RECV_TIMEOUT
|
||||||
int adhocMatchingEventDelayMS = 30; //30
|
int adhocMatchingEventDelayMS = 30; //30
|
||||||
int adhocEventDelayMS = 300; //500; This will affect the duration of "Connecting..." dialog/message box in .Hack//Link and Naruto Ultimate Ninja Heroes 3
|
int adhocEventDelayMS = 300; //500; This will affect the duration of "Connecting..." dialog/message box in .Hack//Link and Naruto Ultimate Ninja Heroes 3
|
||||||
|
|
||||||
|
@ -78,6 +77,7 @@ int IsAdhocctlInCB = 0;
|
||||||
|
|
||||||
int adhocctlNotifyEvent = -1;
|
int adhocctlNotifyEvent = -1;
|
||||||
int adhocSocketNotifyEvent = -1;
|
int adhocSocketNotifyEvent = -1;
|
||||||
|
std::map<int, AdhocctlRequest> adhocctlRequests;
|
||||||
std::map<int, AdhocSocketRequest> adhocSocketRequests;
|
std::map<int, AdhocSocketRequest> adhocSocketRequests;
|
||||||
std::map<int, AdhocSendTargets> sendTargetPeers;
|
std::map<int, AdhocSendTargets> sendTargetPeers;
|
||||||
|
|
||||||
|
@ -129,9 +129,51 @@ static void __AdhocctlNotify(u64 userdata, int cyclesLate) {
|
||||||
|
|
||||||
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error);
|
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error);
|
||||||
if (waitID == 0 || error != 0)
|
if (waitID == 0 || error != 0)
|
||||||
return; // FIXME: Is it safe to exit here like this without re-scheduling the event? Will this event be triggered again? What will happen to the result i might want to change if exited here?
|
return;
|
||||||
|
|
||||||
int waitVal = __KernelGetWaitValue(threadID, error); // FIXME: Is this value going to be a valid value if waitID == 0? or it's a value belonged to other event?
|
// Socket not found?! Should never happened! but if it ever happen should we just exit here or need to wake the thread first?
|
||||||
|
if (adhocctlRequests.find(uid) == adhocctlRequests.end()) {
|
||||||
|
WARN_LOG(SCENET, "sceNetAdhocctl Socket WaitID(%i) not found!", uid);
|
||||||
|
//__KernelResumeThreadFromWait(threadID, ERROR_NET_ADHOCCTL_BUSY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdhocctlRequest& req = adhocctlRequests[uid];
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
SceNetAdhocctlConnectPacketC2S packet;
|
||||||
|
memset(&packet, 0, sizeof(packet));
|
||||||
|
packet.base.opcode = req.opcode;
|
||||||
|
packet.group = req.group;
|
||||||
|
|
||||||
|
switch (req.opcode)
|
||||||
|
{
|
||||||
|
case OPCODE_CONNECT:
|
||||||
|
len = sizeof(packet);
|
||||||
|
break;
|
||||||
|
case OPCODE_SCAN:
|
||||||
|
case OPCODE_DISCONNECT:
|
||||||
|
len = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send Packet if it wasn't succesfully sent before
|
||||||
|
if (len > 0) {
|
||||||
|
if (IsSocketReady(metasocket, false, true) > 0) {
|
||||||
|
int ret = send(metasocket, (const char*)&packet, len, 0);
|
||||||
|
int sockerr = errno;
|
||||||
|
|
||||||
|
if (ret > 0 || (ret == SOCKET_ERROR && sockerr != EAGAIN && sockerr != EWOULDBLOCK)) {
|
||||||
|
// Prevent from sending again
|
||||||
|
req.opcode = 0;
|
||||||
|
if (ret == SOCKET_ERROR)
|
||||||
|
DEBUG_LOG(SCENET, "sceNetAdhocctl[%i]: Socket Error (%i)", uid, sockerr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we just need to wait for replies from adhoc server and the change of state
|
||||||
|
int waitVal = __KernelGetWaitValue(threadID, error);
|
||||||
if (adhocctlState != waitVal && error == 0) {
|
if (adhocctlState != waitVal && error == 0) {
|
||||||
// Detecting Adhocctl Initialization using waitVal < 0
|
// Detecting Adhocctl Initialization using waitVal < 0
|
||||||
if (waitVal >= 0 || (waitVal < 0 && (g_Config.bEnableWlan && !networkInited))) {
|
if (waitVal >= 0 || (waitVal < 0 && (g_Config.bEnableWlan && !networkInited))) {
|
||||||
|
@ -148,20 +190,32 @@ static void __AdhocctlNotify(u64 userdata, int cyclesLate) {
|
||||||
result = 0; // Faking successfully connected to adhoc server
|
result = 0; // Faking successfully connected to adhoc server
|
||||||
}
|
}
|
||||||
|
|
||||||
//HLEKernel::ResumeFromWait(threadID, WAITTYPE_NET, uid, result); // FIXME: This won't do anything if waitID == 0, not sure what kind of value returned from the HLE which i might want to change here.
|
__KernelResumeThreadFromWait(threadID, result);
|
||||||
__KernelResumeThreadFromWait(threadID, result); // FIXME: Forcing to change the result, will it cause an issue if waitID == 0?
|
|
||||||
DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %d) Result (%08x) of sceNetAdhocctl - State: %d", waitID, error, (int)result, adhocctlState);
|
DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %d) Result (%08x) of sceNetAdhocctl - State: %d", waitID, error, (int)result, adhocctlState);
|
||||||
|
|
||||||
|
// We are done with this request
|
||||||
|
adhocctlRequests.erase(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitAdhocctlState(int state, int usec, const char* reason) {
|
int WaitAdhocctlState(AdhocctlRequest request, int state, int usec, const char* reason) {
|
||||||
|
int uid = (state < 0) ? 1 : metasocket;
|
||||||
|
|
||||||
|
if (adhocctlRequests.find(uid) != adhocctlRequests.end()) {
|
||||||
|
WARN_LOG(SCENET, "sceNetAdhocctl - WaitID[%d] already existed, Socket is busy!", uid);
|
||||||
|
return ERROR_NET_ADHOCCTL_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
if (adhocctlNotifyEvent < 0)
|
if (adhocctlNotifyEvent < 0)
|
||||||
adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify);
|
adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify);
|
||||||
|
|
||||||
int uid = (state < 0)? 1: metasocket;
|
|
||||||
u64 param = ((u64)__KernelGetCurThread()) << 32 | uid;
|
u64 param = ((u64)__KernelGetCurThread()) << 32 | uid;
|
||||||
adhocctlStartTime = (u64)(real_time_now() * 1000.0);
|
adhocctlStartTime = (u64)(real_time_now() * 1000.0);
|
||||||
|
adhocctlRequests[uid] = request;
|
||||||
CoreTiming::ScheduleEvent(usToCycles(usec), adhocctlNotifyEvent, param);
|
CoreTiming::ScheduleEvent(usToCycles(usec), adhocctlNotifyEvent, param);
|
||||||
__KernelWaitCurThread(WAITTYPE_NET, uid, state, 0, false, reason);
|
__KernelWaitCurThread(WAITTYPE_NET, uid, state, 0, false, reason);
|
||||||
|
|
||||||
|
// faked success
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DoBlockingPdpRecv(int uid, AdhocSocketRequest& req, s64& result) {
|
int DoBlockingPdpRecv(int uid, AdhocSocketRequest& req, s64& result) {
|
||||||
|
@ -386,17 +440,10 @@ int DoBlockingPtpAccept(int uid, AdhocSocketRequest& req, s64& result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DoBlockingPtpConnect(int uid, AdhocSocketRequest& req, s64& result) {
|
int DoBlockingPtpConnect(int uid, AdhocSocketRequest& req, s64& result) {
|
||||||
fd_set readfds, writefds;
|
int sockerr;
|
||||||
timeval tval;
|
|
||||||
FD_ZERO(&readfds);
|
|
||||||
FD_SET(uid, &readfds);
|
|
||||||
writefds = readfds;
|
|
||||||
tval.tv_sec = 0;
|
|
||||||
tval.tv_usec = 0;
|
|
||||||
|
|
||||||
// Wait for Connection (assuming "connect" has been called before)
|
// Wait for Connection (assuming "connect" has been called before)
|
||||||
int ret = select(uid + 1, &readfds, &writefds, NULL, &tval);
|
int ret = IsSocketReady(uid, true, true, &sockerr);
|
||||||
int sockerr = errno;
|
|
||||||
|
|
||||||
// Connection is ready
|
// Connection is ready
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
|
@ -535,11 +582,11 @@ static void __AdhocSocketNotify(u64 userdata, int cyclesLate) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are done with this socket
|
|
||||||
adhocSocketRequests.erase(uid);
|
|
||||||
|
|
||||||
__KernelResumeThreadFromWait(threadID, result);
|
__KernelResumeThreadFromWait(threadID, result);
|
||||||
DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %d) Result (%08x) of sceNetAdhoc - SocketID: %d", waitID, error, (int)result, req.id);
|
DEBUG_LOG(SCENET, "Returning (WaitID: %d, error: %d) Result (%08x) of sceNetAdhoc - SocketID: %d", waitID, error, (int)result, req.id);
|
||||||
|
|
||||||
|
// We are done with this socket
|
||||||
|
adhocSocketRequests.erase(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WaitBlockingAdhocSocket(int socketId, int type, int pspSocketId, void* buffer, s32_le* len, u32 timeoutUS, SceNetEtherAddr* remoteMAC, u16_le* remotePort, const char* reason) {
|
int WaitBlockingAdhocSocket(int socketId, int type, int pspSocketId, void* buffer, s32_le* len, u32 timeoutUS, SceNetEtherAddr* remoteMAC, u16_le* remotePort, const char* reason) {
|
||||||
|
@ -551,8 +598,7 @@ int WaitBlockingAdhocSocket(int socketId, int type, int pspSocketId, void* buffe
|
||||||
if (adhocSocketNotifyEvent < 0)
|
if (adhocSocketNotifyEvent < 0)
|
||||||
adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify);
|
adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify);
|
||||||
|
|
||||||
if (getNonBlockingFlag(socketId) == 0)
|
//changeBlockingMode(socketId, 1);
|
||||||
changeBlockingMode(socketId, 1);
|
|
||||||
|
|
||||||
u32 tmout = timeoutUS;
|
u32 tmout = timeoutUS;
|
||||||
if (tmout > 0)
|
if (tmout > 0)
|
||||||
|
@ -646,6 +692,7 @@ void __NetAdhocDoState(PointerWrap &p) {
|
||||||
// Discard leftover events
|
// Discard leftover events
|
||||||
adhocctlEvents.clear();
|
adhocctlEvents.clear();
|
||||||
matchingEvents.clear();
|
matchingEvents.clear();
|
||||||
|
adhocctlRequests.clear();
|
||||||
adhocSocketRequests.clear();
|
adhocSocketRequests.clear();
|
||||||
sendTargetPeers.clear();
|
sendTargetPeers.clear();
|
||||||
|
|
||||||
|
@ -683,6 +730,7 @@ void __AdhocNotifInit() {
|
||||||
adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify);
|
adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify);
|
||||||
adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify);
|
adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify);
|
||||||
|
|
||||||
|
adhocctlRequests.clear();
|
||||||
adhocSocketRequests.clear();
|
adhocSocketRequests.clear();
|
||||||
sendTargetPeers.clear();
|
sendTargetPeers.clear();
|
||||||
}
|
}
|
||||||
|
@ -744,7 +792,8 @@ static u32 sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) {
|
||||||
// Need to make sure to be connected to adhoc server before returning to prevent GTA VCS failed to create/join a group and unable to see any game room
|
// Need to make sure to be connected to adhoc server before returning to prevent GTA VCS failed to create/join a group and unable to see any game room
|
||||||
int us = adhocExtraPollDelayMS * 1000;
|
int us = adhocExtraPollDelayMS * 1000;
|
||||||
if (g_Config.bEnableWlan && !networkInited) {
|
if (g_Config.bEnableWlan && !networkInited) {
|
||||||
WaitAdhocctlState(-1, us, "adhoc init");
|
AdhocctlRequest dummyreq = { OPCODE_LOGIN, {0} };
|
||||||
|
return WaitAdhocctlState(dummyreq, -1, us, "adhocctl init");
|
||||||
}
|
}
|
||||||
// Give a little time for friendFinder thread to be ready before the game use the next sceNet functions, should've checked for friendFinderRunning status instead of guessing the time?
|
// Give a little time for friendFinder thread to be ready before the game use the next sceNet functions, should've checked for friendFinderRunning status instead of guessing the time?
|
||||||
else
|
else
|
||||||
|
@ -871,6 +920,9 @@ static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 u
|
||||||
//sceNetPortOpen("UDP", port);
|
//sceNetPortOpen("UDP", port);
|
||||||
UPnP_Add(IP_PROTOCOL_UDP, isOriPort ? port : port + portOffset, port + portOffset); // g_PortManager.Add(IP_PROTOCOL_UDP, isOriPort ? port : port + portOffset, port + portOffset);
|
UPnP_Add(IP_PROTOCOL_UDP, isOriPort ? port : port + portOffset, port + portOffset); // g_PortManager.Add(IP_PROTOCOL_UDP, isOriPort ? port : port + portOffset, port + portOffset);
|
||||||
|
|
||||||
|
// Switch to non-blocking for futher usage
|
||||||
|
changeBlockingMode(usocket, 1);
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return i + 256;
|
return i + 256;
|
||||||
}
|
}
|
||||||
|
@ -1009,7 +1061,6 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int
|
||||||
//_acquireNetworkLock();
|
//_acquireNetworkLock();
|
||||||
|
|
||||||
// Send Data. UDP are guaranteed to be sent as a whole or nothing(failed if len > SO_MAX_MSG_SIZE), and never be partially sent/recv
|
// Send Data. UDP are guaranteed to be sent as a whole or nothing(failed if len > SO_MAX_MSG_SIZE), and never be partially sent/recv
|
||||||
changeBlockingMode(socket->id, 1);
|
|
||||||
int sent = sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target));
|
int sent = sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target));
|
||||||
int error = errno;
|
int error = errno;
|
||||||
|
|
||||||
|
@ -1087,8 +1138,6 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int
|
||||||
peerlock.unlock();
|
peerlock.unlock();
|
||||||
|
|
||||||
// Send Data
|
// Send Data
|
||||||
changeBlockingMode(socket->id, 1); // Do we need to switched to blocking-mode to make sure the data are fully sent?
|
|
||||||
|
|
||||||
// Simulate blocking behaviour with non-blocking socket
|
// Simulate blocking behaviour with non-blocking socket
|
||||||
if (!flag) {
|
if (!flag) {
|
||||||
if (sendTargetPeers.find(socket->id) != sendTargetPeers.end()) {
|
if (sendTargetPeers.find(socket->id) != sendTargetPeers.end()) {
|
||||||
|
@ -1232,11 +1281,9 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *
|
||||||
|
|
||||||
|
|
||||||
// Receive Data. PDP always sent in full size or nothing(failed), recvfrom will always receive in full size as requested (blocking) or failed (non-blocking). If available UDP data is larger than buffer, excess data is lost.
|
// Receive Data. PDP always sent in full size or nothing(failed), recvfrom will always receive in full size as requested (blocking) or failed (non-blocking). If available UDP data is larger than buffer, excess data is lost.
|
||||||
changeBlockingMode(socket->id, 1);
|
|
||||||
// Should peek first for the available data size if it's more than len return ERROR_NET_ADHOC_NOT_ENOUGH_SPACE along with required size in len to prevent losing excess data
|
// Should peek first for the available data size if it's more than len return ERROR_NET_ADHOC_NOT_ENOUGH_SPACE along with required size in len to prevent losing excess data
|
||||||
received = recvfrom(socket->id, (char*)buf, *len, MSG_PEEK, (sockaddr*)&sin, &sinlen);
|
received = recvfrom(socket->id, (char*)buf, *len, MSG_PEEK, (sockaddr*)&sin, &sinlen);
|
||||||
if (received != SOCKET_ERROR && *len < received) {
|
if (received != SOCKET_ERROR && *len < received) {
|
||||||
changeBlockingMode(socket->id, 0);
|
|
||||||
WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", id, getLocalPort(socket->id), received, *len, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
WARN_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Peeked %u/%u bytes from %s:%u\n", id, getLocalPort(socket->id), received, *len, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||||
*len = received;
|
*len = received;
|
||||||
|
|
||||||
|
@ -1272,7 +1319,6 @@ static int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *
|
||||||
|
|
||||||
VERBOSE_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpRecv[%i:%u] [size=%i]", error, id, socket->lport, *len);
|
VERBOSE_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpRecv[%i:%u] [size=%i]", error, id, socket->lport, *len);
|
||||||
}
|
}
|
||||||
changeBlockingMode(socket->id, 0);
|
|
||||||
|
|
||||||
// Should we set output length to 0 on Error?
|
// Should we set output length to 0 on Error?
|
||||||
*len = 0;
|
*len = 0;
|
||||||
|
@ -1571,6 +1617,7 @@ int sceNetAdhocctlScan() {
|
||||||
|
|
||||||
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED) {
|
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED) {
|
||||||
adhocctlState = ADHOCCTL_STATE_SCANNING;
|
adhocctlState = ADHOCCTL_STATE_SCANNING;
|
||||||
|
int us = adhocEventPollDelayMS * 1000;
|
||||||
|
|
||||||
// Reset Networks/Group list to prevent other threads from using these soon to be replaced networks
|
// Reset Networks/Group list to prevent other threads from using these soon to be replaced networks
|
||||||
peerlock.lock();
|
peerlock.lock();
|
||||||
|
@ -1582,17 +1629,23 @@ int sceNetAdhocctlScan() {
|
||||||
uint8_t opcode = OPCODE_SCAN;
|
uint8_t opcode = OPCODE_SCAN;
|
||||||
|
|
||||||
// Send Scan Request Packet, 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)
|
// Send Scan Request Packet, 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)
|
||||||
changeBlockingMode(metasocket, 0);
|
|
||||||
int iResult = send(metasocket, (char *)&opcode, 1, 0);
|
int iResult = send(metasocket, (char *)&opcode, 1, 0);
|
||||||
int error = errno;
|
int error = errno;
|
||||||
changeBlockingMode(metasocket, 1);
|
|
||||||
if (iResult == SOCKET_ERROR) {
|
if (iResult == SOCKET_ERROR) {
|
||||||
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
if (error != EAGAIN && error != EWOULDBLOCK) {
|
||||||
adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
|
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
||||||
//notifyAdhocctlHandlers(ADHOCCTL_EVENT_SCAN, 0);
|
adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
|
||||||
//if (error == ECONNABORTED || error == ECONNRESET || error == ENOTCONN) return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; // A case where it need to reconnect to AdhocServer
|
//if (error == ECONNABORTED || error == ECONNRESET || error == ENOTCONN) return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; // A case where it need to reconnect to AdhocServer
|
||||||
return ERROR_NET_ADHOCCTL_DISCONNECTED; // ERROR_NET_ADHOCCTL_BUSY
|
return ERROR_NET_ADHOCCTL_BUSY;
|
||||||
|
}
|
||||||
|
else if (friendFinderRunning) {
|
||||||
|
AdhocctlRequest req = { OPCODE_SCAN, {0} };
|
||||||
|
return WaitAdhocctlState(req, ADHOCCTL_STATE_DISCONNECTED, us, "adhocctl scan");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
hleDelayResult(0, "give a little time to be ready to receive the callback", us); // Not delaying here may cause Naruto Shippuden Ultimate Ninja Heroes 3 to get disconnected when the mission started
|
||||||
|
|
||||||
// Return Success
|
// Return Success
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1741,6 +1794,8 @@ static u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) {
|
||||||
u32 NetAdhocctl_Disconnect() {
|
u32 NetAdhocctl_Disconnect() {
|
||||||
// Library initialized
|
// Library initialized
|
||||||
if (netAdhocctlInited) {
|
if (netAdhocctlInited) {
|
||||||
|
int iResult, error;
|
||||||
|
int us = adhocEventPollDelayMS * 1000;
|
||||||
// Connected State (Adhoc Mode)
|
// Connected State (Adhoc Mode)
|
||||||
if (adhocctlState != ADHOCCTL_STATE_DISCONNECTED) { // (threadStatus == ADHOCCTL_STATE_CONNECTED)
|
if (adhocctlState != ADHOCCTL_STATE_DISCONNECTED) { // (threadStatus == ADHOCCTL_STATE_CONNECTED)
|
||||||
// Clear Network Name
|
// Clear Network Name
|
||||||
|
@ -1756,14 +1811,20 @@ u32 NetAdhocctl_Disconnect() {
|
||||||
//_acquireNetworkLock();
|
//_acquireNetworkLock();
|
||||||
|
|
||||||
// Send Disconnect Request Packet
|
// Send Disconnect Request Packet
|
||||||
changeBlockingMode(metasocket, 0);
|
iResult = send(metasocket, (const char*)&opcode, 1, 0);
|
||||||
int iResult = send(metasocket, (const char*)&opcode, 1, 0);
|
error = errno;
|
||||||
int error = errno;
|
|
||||||
changeBlockingMode(metasocket, 1);
|
// Sending may get socket error 10053 if the AdhocServer is already shutted down
|
||||||
if (iResult == SOCKET_ERROR) {
|
if (iResult == SOCKET_ERROR) {
|
||||||
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
if (error != EAGAIN && error != EWOULDBLOCK) {
|
||||||
// Set Disconnected State
|
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
||||||
adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
|
// Set Disconnected State
|
||||||
|
adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
|
||||||
|
}
|
||||||
|
else if (friendFinderRunning) {
|
||||||
|
AdhocctlRequest req = { OPCODE_DISCONNECT, {0} };
|
||||||
|
WaitAdhocctlState(req, ADHOCCTL_STATE_DISCONNECTED, us, "adhocctl disconnect");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free Network Lock
|
// Free Network Lock
|
||||||
|
@ -1793,12 +1854,8 @@ u32 NetAdhocctl_Disconnect() {
|
||||||
notifyAdhocctlHandlers(ADHOCCTL_EVENT_DISCONNECT, 0);
|
notifyAdhocctlHandlers(ADHOCCTL_EVENT_DISCONNECT, 0);
|
||||||
//hleCheckCurrentCallbacks();
|
//hleCheckCurrentCallbacks();
|
||||||
|
|
||||||
int us = adhocEventPollDelayMS * 1000;
|
|
||||||
if (adhocctlState != ADHOCCTL_STATE_DISCONNECTED && friendFinderRunning) {
|
|
||||||
WaitAdhocctlState(ADHOCCTL_STATE_DISCONNECTED, us, "adhoc disconnect");
|
|
||||||
}
|
|
||||||
// Return Success, some games might ignore returned value and always treat it as success, otherwise repeatedly calling this function
|
// Return Success, some games might ignore returned value and always treat it as success, otherwise repeatedly calling this function
|
||||||
else if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED)
|
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED || iResult != SOCKET_ERROR)
|
||||||
hleDelayResult(0, "give time to init/cleanup", us);
|
hleDelayResult(0, "give time to init/cleanup", us);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2038,10 +2095,9 @@ int NetAdhocctl_Create(const char* groupName) {
|
||||||
// Acquire Network Lock
|
// Acquire Network Lock
|
||||||
|
|
||||||
// Send Packet
|
// Send Packet
|
||||||
changeBlockingMode(metasocket, 0);
|
|
||||||
int iResult = send(metasocket, (const char*)&packet, sizeof(packet), 0);
|
int iResult = send(metasocket, (const char*)&packet, sizeof(packet), 0);
|
||||||
int error = errno;
|
int error = errno;
|
||||||
changeBlockingMode(metasocket, 1);
|
|
||||||
if (iResult == SOCKET_ERROR) {
|
if (iResult == SOCKET_ERROR) {
|
||||||
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
||||||
//return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; // ERROR_NET_ADHOCCTL_DISCONNECTED; // ERROR_NET_ADHOCCTL_BUSY;
|
//return ERROR_NET_ADHOCCTL_NOT_INITIALIZED; // ERROR_NET_ADHOCCTL_DISCONNECTED; // ERROR_NET_ADHOCCTL_BUSY;
|
||||||
|
@ -2059,11 +2115,13 @@ int NetAdhocctl_Create(const char* groupName) {
|
||||||
|
|
||||||
// Wait for Status to be connected to prevent Ford Street Racing from Failed to create game session
|
// Wait for Status to be connected to prevent Ford Street Racing from Failed to create game session
|
||||||
int us = adhocEventDelayMS * 1000;
|
int us = adhocEventDelayMS * 1000;
|
||||||
if (adhocctlState != ADHOCCTL_STATE_CONNECTED && friendFinderRunning) {
|
if (adhocctlState != ADHOCCTL_STATE_CONNECTED && iResult == SOCKET_ERROR && friendFinderRunning) {
|
||||||
WaitAdhocctlState(ADHOCCTL_STATE_CONNECTED, us, "adhoc connect");
|
AdhocctlRequest req = { OPCODE_CONNECT, {0} };
|
||||||
|
if (groupNameStruct != NULL) req.group = *groupNameStruct;
|
||||||
|
return WaitAdhocctlState(req, ADHOCCTL_STATE_CONNECTED, us, "adhocctl connect");
|
||||||
}
|
}
|
||||||
// Giving time for Naruto Shippuden Ninja Heroes 3 to close down the "Connecting..." dialog, otherwise the dialog will stuck there.
|
// Giving time for Naruto Shippuden Ninja Heroes 3 to close down the "Connecting..." dialog, otherwise the dialog will stuck there.
|
||||||
else if (adhocctlState == ADHOCCTL_STATE_CONNECTED)
|
else if (adhocctlState == ADHOCCTL_STATE_CONNECTED || iResult != SOCKET_ERROR)
|
||||||
hleDelayResult(0, "give time to init/cleanup", us);
|
hleDelayResult(0, "give time to init/cleanup", us);
|
||||||
|
|
||||||
// Return Success
|
// Return Success
|
||||||
|
@ -2497,6 +2555,9 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac,
|
||||||
if (!isClient)
|
if (!isClient)
|
||||||
UPnP_Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset); // g_PortManager.Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset);
|
UPnP_Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset); // g_PortManager.Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset);
|
||||||
|
|
||||||
|
// Switch to non-blocking for futher usage
|
||||||
|
changeBlockingMode(tcpsocket, 1);
|
||||||
|
|
||||||
// Return PTP Socket Pointer
|
// Return PTP Socket Pointer
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
@ -2665,15 +2726,6 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int
|
||||||
memset(&peeraddr, 0, sizeof(peeraddr));
|
memset(&peeraddr, 0, sizeof(peeraddr));
|
||||||
socklen_t peeraddrlen = sizeof(peeraddr);
|
socklen_t peeraddrlen = sizeof(peeraddr);
|
||||||
|
|
||||||
// Grab Nonblocking Flag
|
|
||||||
uint32_t nbio = getNonBlockingFlag(socket->id);
|
|
||||||
// Switch to Nonblocking Behaviour
|
|
||||||
if (nbio == 0) {
|
|
||||||
// Overwrite Socket Option
|
|
||||||
changeBlockingMode(socket->id, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Use a different thread (similar to sceIo) for recvfrom, recv & accept to prevent blocking-socket from blocking emulation
|
|
||||||
// Accept Connection
|
// Accept Connection
|
||||||
int newsocket = accept(socket->id, (sockaddr *)&peeraddr, &peeraddrlen);
|
int newsocket = accept(socket->id, (sockaddr *)&peeraddr, &peeraddrlen);
|
||||||
int error = errno;
|
int error = errno;
|
||||||
|
@ -2689,12 +2741,6 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore Blocking Behaviour
|
|
||||||
if (nbio == 0) {
|
|
||||||
// Restore Socket Option
|
|
||||||
changeBlockingMode(socket->id, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accepted New Connection
|
// Accepted New Connection
|
||||||
if (newsocket > 0) {
|
if (newsocket > 0) {
|
||||||
int newid = AcceptPtpSocket(id, newsocket, peeraddr, addr, port);
|
int newid = AcceptPtpSocket(id, newsocket, peeraddr, addr, port);
|
||||||
|
@ -2769,10 +2815,6 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) {
|
||||||
// Grab Nonblocking Flag
|
// Grab Nonblocking Flag
|
||||||
//uint32_t nbio = getNonBlockingFlag(socket->id);
|
//uint32_t nbio = getNonBlockingFlag(socket->id);
|
||||||
|
|
||||||
// Switch to Nonblocking Behaviour. Forcing blocking behaviour on the first connect may fix connection issue on GvG Next Plus, But i don't like using blocking socket with infinite timeout if the game it self were asking for non-blocking behaviour :(
|
|
||||||
// We are using non-blocking to simulate blocking
|
|
||||||
changeBlockingMode(socket->id, 1);
|
|
||||||
|
|
||||||
// Connect Socket to Peer
|
// Connect Socket to Peer
|
||||||
// NOTE: Based on what i read at stackoverflow, The First Non-blocking POSIX connect will always returns EAGAIN/EWOULDBLOCK because it returns without waiting for ACK/handshake, But GvG Next Plus is treating non-blocking PtpConnect just like blocking connect, May be on a real PSP the first non-blocking sceNetAdhocPtpConnect can be successfull?
|
// NOTE: Based on what i read at stackoverflow, The First Non-blocking POSIX connect will always returns EAGAIN/EWOULDBLOCK because it returns without waiting for ACK/handshake, But GvG Next Plus is treating non-blocking PtpConnect just like blocking connect, May be on a real PSP the first non-blocking sceNetAdhocPtpConnect can be successfull?
|
||||||
// TODO: Keep track number of Connect attempts so we can simulate blocking on first attempt (getNonBlockingFlag can't be used to get non-blocking flag on Windows thus can't be used to keep track)
|
// TODO: Keep track number of Connect attempts so we can simulate blocking on first attempt (getNonBlockingFlag can't be used to get non-blocking flag on Windows thus can't be used to keep track)
|
||||||
|
@ -2998,6 +3040,9 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int
|
||||||
//sceNetPortOpen("TCP", sport);
|
//sceNetPortOpen("TCP", sport);
|
||||||
UPnP_Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset); // g_PortManager.Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset);
|
UPnP_Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset); // g_PortManager.Add(IP_PROTOCOL_TCP, isOriPort ? sport : sport + portOffset, sport + portOffset);
|
||||||
|
|
||||||
|
// Switch to non-blocking for futher usage
|
||||||
|
changeBlockingMode(tcpsocket, 1);
|
||||||
|
|
||||||
// Return PTP Socket Pointer
|
// Return PTP Socket Pointer
|
||||||
return i + 1;
|
return i + 1;
|
||||||
}
|
}
|
||||||
|
@ -3082,7 +3127,6 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou
|
||||||
// _acquireNetworkLock();
|
// _acquireNetworkLock();
|
||||||
|
|
||||||
// Send Data
|
// Send Data
|
||||||
changeBlockingMode(socket->id, 1);
|
|
||||||
int sent = send(socket->id, data, *len, 0);
|
int sent = send(socket->id, data, *len, 0);
|
||||||
int error = errno;
|
int error = errno;
|
||||||
|
|
||||||
|
@ -3173,7 +3217,6 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
// Receive Data
|
// Receive Data
|
||||||
changeBlockingMode(socket->id, 1);
|
|
||||||
received = recv(socket->id, (char*)buf, *len, 0);
|
received = recv(socket->id, (char*)buf, *len, 0);
|
||||||
error = errno;
|
error = errno;
|
||||||
|
|
||||||
|
@ -3185,7 +3228,6 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou
|
||||||
|
|
||||||
VERBOSE_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPtpRecv[%i:%u] [size=%i]", error, id, socket->lport, *len);
|
VERBOSE_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPtpRecv[%i:%u] [size=%i]", error, id, socket->lport, *len);
|
||||||
}
|
}
|
||||||
changeBlockingMode(socket->id, 0);
|
|
||||||
|
|
||||||
// Free Network Lock
|
// Free Network Lock
|
||||||
// _freeNetworkLock();
|
// _freeNetworkLock();
|
||||||
|
|
|
@ -30,6 +30,11 @@ typedef struct MatchingArgs {
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct AdhocctlRequest {
|
||||||
|
u8 opcode;
|
||||||
|
SceNetAdhocctlGroupName group;
|
||||||
|
};
|
||||||
|
|
||||||
struct AdhocSendTarget {
|
struct AdhocSendTarget {
|
||||||
u32 ip;
|
u32 ip;
|
||||||
u16 port; // original port
|
u16 port; // original port
|
||||||
|
@ -48,7 +53,7 @@ struct AdhocSocketRequest {
|
||||||
s32_le* length;
|
s32_le* length;
|
||||||
u32 timeout;
|
u32 timeout;
|
||||||
u64 startTime;
|
u64 startTime;
|
||||||
struct SceNetEtherAddr* remoteMAC;
|
SceNetEtherAddr* remoteMAC;
|
||||||
u16_le* remotePort;
|
u16_le* remotePort;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue