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/sceKernelThread.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/HLE/sceNetAdhoc.h"
|
||||
#include "Core/Instance.h"
|
||||
#include "proAdhoc.h"
|
||||
|
||||
|
@ -212,13 +213,26 @@ SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC) {
|
|||
return peer;
|
||||
}
|
||||
|
||||
int getNonBlockingFlag(int fd) {
|
||||
#ifdef _WIN32
|
||||
return 0;
|
||||
#else
|
||||
int sockflag = fcntl(fd, F_GETFL, O_NONBLOCK);
|
||||
return sockflag & O_NONBLOCK;
|
||||
#endif
|
||||
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) {
|
||||
|
@ -1186,14 +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
|
||||
changeBlockingMode(metasocket, 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1242,49 +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)
|
||||
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);
|
||||
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
|
||||
|
@ -1297,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);
|
||||
|
@ -1307,8 +1341,6 @@ 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);
|
||||
// Change State
|
||||
|
@ -1576,9 +1608,7 @@ int getLocalIp(sockaddr_in* SocketAddress) {
|
|||
struct sockaddr_in localAddr;
|
||||
localAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
socklen_t addrLen = sizeof(localAddr);
|
||||
changeBlockingMode(metasocket, 0);
|
||||
int ret = getsockname(metasocket, (struct sockaddr*)&localAddr, &addrLen);
|
||||
changeBlockingMode(metasocket, 1);
|
||||
if (SOCKET_ERROR != ret) {
|
||||
if (isLocalServer) {
|
||||
localAddr.sin_addr = g_localhostIP.in.sin_addr;
|
||||
|
@ -1858,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;
|
||||
|
@ -1914,17 +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++;
|
||||
}
|
||||
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);
|
||||
|
@ -1941,9 +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);
|
||||
changeBlockingMode(metasocket, 0);
|
||||
|
||||
IsSocketReady(metasocket, false, true, nullptr, adhocDefaultTimeout * 1000);
|
||||
int sent = send(metasocket, (char*)&packet, sizeof(packet), 0);
|
||||
changeBlockingMode(metasocket, 1);
|
||||
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"
|
||||
|
@ -928,11 +927,12 @@ extern int newChat;
|
|||
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
|
||||
* @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
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/HLE/sceKernelModule.h"
|
||||
#include "Core/HLE/sceKernelInterrupt.h"
|
||||
#include "Core/HLE/proAdhoc.h"
|
||||
#include "Core/HLE/sceNetAdhoc.h"
|
||||
#include "Core/HLE/sceNet.h"
|
||||
#include "Core/HLE/proAdhocServer.h"
|
||||
|
@ -63,7 +62,7 @@ static bool netAdhocMatchingInited;
|
|||
int netAdhocMatchingStarted = 0;
|
||||
int adhocDefaultTimeout = 2000; //5000 ms
|
||||
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 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 adhocSocketNotifyEvent = -1;
|
||||
std::map<int, AdhocctlRequest> adhocctlRequests;
|
||||
std::map<int, AdhocSocketRequest> adhocSocketRequests;
|
||||
std::map<int, AdhocSendTargets> sendTargetPeers;
|
||||
|
||||
|
@ -129,9 +129,51 @@ static void __AdhocctlNotify(u64 userdata, int cyclesLate) {
|
|||
|
||||
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_NET, error);
|
||||
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) {
|
||||
// Detecting Adhocctl Initialization using waitVal < 0
|
||||
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
|
||||
}
|
||||
|
||||
//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); // FIXME: Forcing to change the result, will it cause an issue if waitID == 0?
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
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)
|
||||
adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify);
|
||||
|
||||
int uid = (state < 0)? 1: metasocket;
|
||||
u64 param = ((u64)__KernelGetCurThread()) << 32 | uid;
|
||||
adhocctlStartTime = (u64)(real_time_now() * 1000.0);
|
||||
adhocctlRequests[uid] = request;
|
||||
CoreTiming::ScheduleEvent(usToCycles(usec), adhocctlNotifyEvent, param);
|
||||
__KernelWaitCurThread(WAITTYPE_NET, uid, state, 0, false, reason);
|
||||
|
||||
// faked success
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
fd_set readfds, writefds;
|
||||
timeval tval;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(uid, &readfds);
|
||||
writefds = readfds;
|
||||
tval.tv_sec = 0;
|
||||
tval.tv_usec = 0;
|
||||
int sockerr;
|
||||
|
||||
// Wait for Connection (assuming "connect" has been called before)
|
||||
int ret = select(uid + 1, &readfds, &writefds, NULL, &tval);
|
||||
int sockerr = errno;
|
||||
int ret = IsSocketReady(uid, true, true, &sockerr);
|
||||
|
||||
// Connection is ready
|
||||
if (ret > 0) {
|
||||
|
@ -535,11 +582,11 @@ static void __AdhocSocketNotify(u64 userdata, int cyclesLate) {
|
|||
break;
|
||||
}
|
||||
|
||||
// We are done with this socket
|
||||
adhocSocketRequests.erase(uid);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, result);
|
||||
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) {
|
||||
|
@ -551,8 +598,7 @@ int WaitBlockingAdhocSocket(int socketId, int type, int pspSocketId, void* buffe
|
|||
if (adhocSocketNotifyEvent < 0)
|
||||
adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify);
|
||||
|
||||
if (getNonBlockingFlag(socketId) == 0)
|
||||
changeBlockingMode(socketId, 1);
|
||||
//changeBlockingMode(socketId, 1);
|
||||
|
||||
u32 tmout = timeoutUS;
|
||||
if (tmout > 0)
|
||||
|
@ -646,6 +692,7 @@ void __NetAdhocDoState(PointerWrap &p) {
|
|||
// Discard leftover events
|
||||
adhocctlEvents.clear();
|
||||
matchingEvents.clear();
|
||||
adhocctlRequests.clear();
|
||||
adhocSocketRequests.clear();
|
||||
sendTargetPeers.clear();
|
||||
|
||||
|
@ -683,6 +730,7 @@ void __AdhocNotifInit() {
|
|||
adhocctlNotifyEvent = CoreTiming::RegisterEvent("__AdhocctlNotify", __AdhocctlNotify);
|
||||
adhocSocketNotifyEvent = CoreTiming::RegisterEvent("__AdhocSocketNotify", __AdhocSocketNotify);
|
||||
|
||||
adhocctlRequests.clear();
|
||||
adhocSocketRequests.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
|
||||
int us = adhocExtraPollDelayMS * 1000;
|
||||
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?
|
||||
else
|
||||
|
@ -871,6 +920,9 @@ static int sceNetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 u
|
|||
//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);
|
||||
|
||||
// Switch to non-blocking for futher usage
|
||||
changeBlockingMode(usocket, 1);
|
||||
|
||||
// Success
|
||||
return i + 256;
|
||||
}
|
||||
|
@ -1009,7 +1061,6 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int
|
|||
//_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
|
||||
changeBlockingMode(socket->id, 1);
|
||||
int sent = sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target));
|
||||
int error = errno;
|
||||
|
||||
|
@ -1087,8 +1138,6 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int
|
|||
peerlock.unlock();
|
||||
|
||||
// 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
|
||||
if (!flag) {
|
||||
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.
|
||||
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
|
||||
received = recvfrom(socket->id, (char*)buf, *len, MSG_PEEK, (sockaddr*)&sin, &sinlen);
|
||||
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));
|
||||
*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);
|
||||
}
|
||||
changeBlockingMode(socket->id, 0);
|
||||
|
||||
// Should we set output length to 0 on Error?
|
||||
*len = 0;
|
||||
|
@ -1571,6 +1617,7 @@ int sceNetAdhocctlScan() {
|
|||
|
||||
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED) {
|
||||
adhocctlState = ADHOCCTL_STATE_SCANNING;
|
||||
int us = adhocEventPollDelayMS * 1000;
|
||||
|
||||
// Reset Networks/Group list to prevent other threads from using these soon to be replaced networks
|
||||
peerlock.lock();
|
||||
|
@ -1582,17 +1629,23 @@ int sceNetAdhocctlScan() {
|
|||
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)
|
||||
changeBlockingMode(metasocket, 0);
|
||||
int iResult = send(metasocket, (char *)&opcode, 1, 0);
|
||||
int error = errno;
|
||||
changeBlockingMode(metasocket, 1);
|
||||
|
||||
if (iResult == SOCKET_ERROR) {
|
||||
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
||||
adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
|
||||
//notifyAdhocctlHandlers(ADHOCCTL_EVENT_SCAN, 0);
|
||||
//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
|
||||
if (error != EAGAIN && error != EWOULDBLOCK) {
|
||||
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
||||
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
|
||||
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 0;
|
||||
|
@ -1741,6 +1794,8 @@ static u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) {
|
|||
u32 NetAdhocctl_Disconnect() {
|
||||
// Library initialized
|
||||
if (netAdhocctlInited) {
|
||||
int iResult, error;
|
||||
int us = adhocEventPollDelayMS * 1000;
|
||||
// Connected State (Adhoc Mode)
|
||||
if (adhocctlState != ADHOCCTL_STATE_DISCONNECTED) { // (threadStatus == ADHOCCTL_STATE_CONNECTED)
|
||||
// Clear Network Name
|
||||
|
@ -1756,14 +1811,20 @@ u32 NetAdhocctl_Disconnect() {
|
|||
//_acquireNetworkLock();
|
||||
|
||||
// Send Disconnect Request Packet
|
||||
changeBlockingMode(metasocket, 0);
|
||||
int iResult = send(metasocket, (const char*)&opcode, 1, 0);
|
||||
int error = errno;
|
||||
changeBlockingMode(metasocket, 1);
|
||||
iResult = send(metasocket, (const char*)&opcode, 1, 0);
|
||||
error = errno;
|
||||
|
||||
// Sending may get socket error 10053 if the AdhocServer is already shutted down
|
||||
if (iResult == SOCKET_ERROR) {
|
||||
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
||||
// Set Disconnected State
|
||||
adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
|
||||
if (error != EAGAIN && error != EWOULDBLOCK) {
|
||||
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
||||
// 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
|
||||
|
@ -1793,12 +1854,8 @@ u32 NetAdhocctl_Disconnect() {
|
|||
notifyAdhocctlHandlers(ADHOCCTL_EVENT_DISCONNECT, 0);
|
||||
//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
|
||||
else if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED)
|
||||
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED || iResult != SOCKET_ERROR)
|
||||
hleDelayResult(0, "give time to init/cleanup", us);
|
||||
|
||||
return 0;
|
||||
|
@ -2038,10 +2095,9 @@ int NetAdhocctl_Create(const char* groupName) {
|
|||
// Acquire Network Lock
|
||||
|
||||
// Send Packet
|
||||
changeBlockingMode(metasocket, 0);
|
||||
int iResult = send(metasocket, (const char*)&packet, sizeof(packet), 0);
|
||||
int error = errno;
|
||||
changeBlockingMode(metasocket, 1);
|
||||
|
||||
if (iResult == SOCKET_ERROR) {
|
||||
ERROR_LOG(SCENET, "Socket error (%i) when sending", error);
|
||||
//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
|
||||
int us = adhocEventDelayMS * 1000;
|
||||
if (adhocctlState != ADHOCCTL_STATE_CONNECTED && friendFinderRunning) {
|
||||
WaitAdhocctlState(ADHOCCTL_STATE_CONNECTED, us, "adhoc connect");
|
||||
if (adhocctlState != ADHOCCTL_STATE_CONNECTED && iResult == SOCKET_ERROR && friendFinderRunning) {
|
||||
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.
|
||||
else if (adhocctlState == ADHOCCTL_STATE_CONNECTED)
|
||||
else if (adhocctlState == ADHOCCTL_STATE_CONNECTED || iResult != SOCKET_ERROR)
|
||||
hleDelayResult(0, "give time to init/cleanup", us);
|
||||
|
||||
// Return Success
|
||||
|
@ -2497,6 +2555,9 @@ static int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac,
|
|||
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);
|
||||
|
||||
// Switch to non-blocking for futher usage
|
||||
changeBlockingMode(tcpsocket, 1);
|
||||
|
||||
// Return PTP Socket Pointer
|
||||
return i + 1;
|
||||
}
|
||||
|
@ -2665,15 +2726,6 @@ static int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int
|
|||
memset(&peeraddr, 0, 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
|
||||
int newsocket = accept(socket->id, (sockaddr *)&peeraddr, &peeraddrlen);
|
||||
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
|
||||
if (newsocket > 0) {
|
||||
int newid = AcceptPtpSocket(id, newsocket, peeraddr, addr, port);
|
||||
|
@ -2769,10 +2815,6 @@ static int sceNetAdhocPtpConnect(int id, int timeout, int flag) {
|
|||
// Grab Nonblocking Flag
|
||||
//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
|
||||
// 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)
|
||||
|
@ -2998,6 +3040,9 @@ static int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int
|
|||
//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);
|
||||
|
||||
// Switch to non-blocking for futher usage
|
||||
changeBlockingMode(tcpsocket, 1);
|
||||
|
||||
// Return PTP Socket Pointer
|
||||
return i + 1;
|
||||
}
|
||||
|
@ -3082,7 +3127,6 @@ static int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeou
|
|||
// _acquireNetworkLock();
|
||||
|
||||
// Send Data
|
||||
changeBlockingMode(socket->id, 1);
|
||||
int sent = send(socket->id, data, *len, 0);
|
||||
int error = errno;
|
||||
|
||||
|
@ -3173,7 +3217,6 @@ static int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeou
|
|||
int error = 0;
|
||||
|
||||
// Receive Data
|
||||
changeBlockingMode(socket->id, 1);
|
||||
received = recv(socket->id, (char*)buf, *len, 0);
|
||||
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);
|
||||
}
|
||||
changeBlockingMode(socket->id, 0);
|
||||
|
||||
// Free Network Lock
|
||||
// _freeNetworkLock();
|
||||
|
|
|
@ -30,6 +30,11 @@ typedef struct MatchingArgs {
|
|||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
struct AdhocctlRequest {
|
||||
u8 opcode;
|
||||
SceNetAdhocctlGroupName group;
|
||||
};
|
||||
|
||||
struct AdhocSendTarget {
|
||||
u32 ip;
|
||||
u16 port; // original port
|
||||
|
@ -48,7 +53,7 @@ struct AdhocSocketRequest {
|
|||
s32_le* length;
|
||||
u32 timeout;
|
||||
u64 startTime;
|
||||
struct SceNetEtherAddr* remoteMAC;
|
||||
SceNetEtherAddr* remoteMAC;
|
||||
u16_le* remotePort;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue