Merge pull request #6421 from ANR2ME/master

Fixed some bugs (ie. possible of memory leaks) on Adhoc, and implement a...
This commit is contained in:
Henrik Rydgård 2014-06-24 20:07:07 +02:00
commit a1d359f22c
5 changed files with 721 additions and 115 deletions

View File

@ -47,7 +47,87 @@ int isPTPPortInUse(uint16_t port) {
return 0;
}
SceNetAdhocMatchingMemberInternal* findMember(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac) {
if (context == NULL || mac == NULL) return NULL;
SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
while (peer != NULL) {
if (IsMatch(peer->mac, *mac))
return peer;
peer = peer->next;
}
return NULL;
}
void addMember(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac) {
if (context == NULL || mac == NULL) return;
SceNetAdhocMatchingMemberInternal * peer = findMember(context, mac);
// Member is not added yet
if (peer == NULL) {
peer = (SceNetAdhocMatchingMemberInternal *)malloc(sizeof(SceNetAdhocMatchingMemberInternal));
if (peer != NULL) {
memset(peer, 0, sizeof(SceNetAdhocMatchingMemberInternal));
peer->mac = *mac;
peer->next = context->peerlist;
context->peerlist = peer;
}
}
}
void deleteMember(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac) {
if (context == NULL || mac == NULL) return;
// Previous Peer Reference
SceNetAdhocMatchingMemberInternal * prev = NULL;
// Peer Pointer
SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
// Iterate Peers
for (; peer != NULL; peer = peer->next) {
// Found Peer
if (IsMatch(context->mac, *mac)) {
// Multithreading Lock
//context->peerlock.lock();
// Unlink Left (Beginning)
if (prev == NULL) context->peerlist = peer->next;
// Unlink Left (Other)
else prev->next = peer->next;
// Multithreading Unlock
//context->peerlock.unlock();
// Free Memory
free(peer);
// Stop Search
break;
}
// Set Previous Reference
prev = peer;
}
}
void deleteAllMembers(SceNetAdhocMatchingContext * context) {
if (context == NULL) return;
SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
while (peer != NULL) {
context->peerlist = peer->next;
free(peer);
peer = context->peerlist;
}
}
void addFriend(SceNetAdhocctlConnectPacketS2C * packet) {
if (packet == NULL) return;
// Allocate Structure
SceNetAdhocctlPeerInfo * peer = (SceNetAdhocctlPeerInfo *)malloc(sizeof(SceNetAdhocctlPeerInfo));
// Allocated Structure
@ -114,6 +194,32 @@ int countAvailableNetworks(void) {
return count;
}
SceNetAdhocctlScanInfo * findGroup(SceNetEtherAddr * MAC) {
if (MAC == NULL) return NULL;
// Group Reference
SceNetAdhocctlScanInfo * group = networks;
// Count Groups
for (; group != NULL; group = group->next) {
if (IsMatch(group->bssid.mac_addr, *MAC)) break;
}
// Return Network Count
return group;
}
void freeGroupsRecursive(SceNetAdhocctlScanInfo * node) {
// End of List
if (node == NULL) return;
// Increase Recursion Depth
freeGroupsRecursive(node->next);
// Free Memory
free(node);
}
void deleteAllPDP(void) {
// Iterate Element
int i = 0; for(; i < 255; i++) {
@ -244,6 +350,9 @@ int friendFinder(){
uint64_t now;
// Log Startup
INFO_LOG(SCENET, "FriendFinder: Begin of Friend Finder Thread");
// Finder Loop
while(friendFinderRunning) {
// Acquire Network Lock
@ -258,8 +367,12 @@ int friendFinder(){
// Prepare Packet
uint8_t opcode = OPCODE_PING;
// Send Ping to Server
send(metasocket, (const char *)&opcode, 1,0);
// 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);
//friendFinderRunning = false;
}*/
}
// Send Chat Messages
@ -289,6 +402,7 @@ int friendFinder(){
if(rxpos > 0) {
// BSSID Packet
if(rx[0] == OPCODE_CONNECT_BSSID) {
INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT_BSSID");
// Enough Data available
if(rxpos >= (int)sizeof(SceNetAdhocctlConnectBSSIDPacketS2C)) {
// Cast Packet
@ -310,6 +424,7 @@ int friendFinder(){
// Chat Packet
else if(rx[0] == OPCODE_CHAT) {
INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CHAT");
// Enough Data available
if(rxpos >= (int)sizeof(SceNetAdhocctlChatPacketS2C)) {
// Cast Packet
@ -320,6 +435,7 @@ int friendFinder(){
// Add Incoming Chat to HUD
//printf("Receive chat message %s", packet->base.message);
DEBUG_LOG(SCENET, "Received chat message %s", packet->base.message);
// Move RX Buffer
memmove(rx, rx + sizeof(SceNetAdhocctlChatPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlChatPacketS2C));
@ -331,6 +447,7 @@ int friendFinder(){
// Connect Packet
else if(rx[0] == OPCODE_CONNECT) {
DEBUG_LOG(SCENET, "FriendFinder: OPCODE_CONNECT");
// Enough Data available
if(rxpos >= (int)sizeof(SceNetAdhocctlConnectPacketS2C)) {
// Log Incoming Peer
@ -359,6 +476,7 @@ int friendFinder(){
// Disconnect Packet
else if(rx[0] == OPCODE_DISCONNECT) {
DEBUG_LOG(SCENET, "FriendFinder: OPCODE_DISCONNECT");
// Enough Data available
if(rxpos >= (int)sizeof(SceNetAdhocctlDisconnectPacketS2C)) {
// Log Incoming Peer Delete Request
@ -367,8 +485,8 @@ int friendFinder(){
// Cast Packet
SceNetAdhocctlDisconnectPacketS2C * packet = (SceNetAdhocctlDisconnectPacketS2C *)rx;
// Delete User by IP
deleteFriendByIP(packet->ip);
// Delete User by IP, should delete by MAC since IP can be shared (behind NAT) isn't?
deleteFriendByIP(packet->ip);
// Update HUD User Count
#ifdef LOCALHOST_AS_PEER
@ -387,6 +505,7 @@ int friendFinder(){
// Scan Packet
else if(rx[0] == OPCODE_SCAN) {
DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN");
// Enough Data available
if(rxpos >= (int)sizeof(SceNetAdhocctlScanPacketS2C)) {
// Log Incoming Network Information
@ -394,38 +513,59 @@ int friendFinder(){
// Cast Packet
SceNetAdhocctlScanPacketS2C * packet = (SceNetAdhocctlScanPacketS2C *)rx;
// Allocate Structure Data
SceNetAdhocctlScanInfo * group = (SceNetAdhocctlScanInfo *)malloc(sizeof(SceNetAdhocctlScanInfo));
// Multithreading Lock
peerlock.lock();
// Allocated Structure Data
if(group != NULL)
{
// Clear Memory
memset(group, 0, sizeof(SceNetAdhocctlScanInfo));
// It seems AdHoc Server always sent the full group list, so we should reset group list during Scan initialization
// Link to existing Groups
group->next = networks;
// Should only add non-existing group (or replace an existing group) to prevent Ford Street Racing from showing a strange game session list
/*SceNetAdhocctlScanInfo * group = findGroup(&packet->mac);
// Copy Group Name
group->group_name = packet->group;
if (group != NULL) {
// Copy Group Name
group->group_name = packet->group;
// Set Group Host
group->bssid.mac_addr = packet->mac;
// Set Group Host
group->bssid.mac_addr = packet->mac;
}
else*/ {
// Allocate Structure Data
SceNetAdhocctlScanInfo * group = (SceNetAdhocctlScanInfo *)malloc(sizeof(SceNetAdhocctlScanInfo));
// Link into Group List
networks = group;
}
// Allocated Structure Data
if (group != NULL)
{
// Clear Memory, should this be done only when allocating new group?
memset(group, 0, sizeof(SceNetAdhocctlScanInfo));
// Move RX Buffer
memmove(rx, rx + sizeof(SceNetAdhocctlScanPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlScanPacketS2C));
// Link to existing Groups
group->next = networks;
// Fix RX Buffer Length
rxpos -= sizeof(SceNetAdhocctlScanPacketS2C);
}
// Copy Group Name
group->group_name = packet->group;
// Set Group Host
group->bssid.mac_addr = packet->mac;
// Link into Group List
networks = group;
}
}
// Multithreading Unlock
peerlock.unlock();
// Move RX Buffer
memmove(rx, rx + sizeof(SceNetAdhocctlScanPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlScanPacketS2C));
// Fix RX Buffer Length
rxpos -= sizeof(SceNetAdhocctlScanPacketS2C);
}
}
// Scan Complete Packet
else if(rx[0] == OPCODE_SCAN_COMPLETE) {
DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN_COMPLETE");
// Log Scan Completion
INFO_LOG(SCENET,"FriendFinder: Incoming Scan complete response...");
@ -451,6 +591,11 @@ int friendFinder(){
sleep_ms(100);
}
// 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;
// Log Shutdown
INFO_LOG(SCENET, "FriendFinder: End of Friend Finder Thread");
@ -504,6 +649,14 @@ int getLocalIp(sockaddr_in * SocketAddress){
#endif
}
uint32_t getLocalIp(int sock) {
struct sockaddr_in localAddr;
localAddr.sin_addr.s_addr = INADDR_ANY;
socklen_t addrLen = sizeof(localAddr);
getsockname(sock, (struct sockaddr*)&localAddr, &addrLen);
return localAddr.sin_addr.s_addr;
}
void getLocalMac(SceNetEtherAddr * addr){
// Read MAC Address from config
uint8_t mac[ETHER_ADDR_LEN] = {0};
@ -513,6 +666,14 @@ void getLocalMac(SceNetEtherAddr * addr){
memcpy(addr, mac, ETHER_ADDR_LEN);
}
uint16_t getLocalPort(int sock) {
struct sockaddr_in localAddr;
localAddr.sin_port = 0;
socklen_t addrLen = sizeof(localAddr);
getsockname(sock, (struct sockaddr*)&localAddr, &addrLen);
return localAddr.sin_port;
}
int getPTPSocketCount(void) {
// Socket Counter
int counter = 0;
@ -531,16 +692,16 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
int iResult = 0;
#ifdef _MSC_VER
WSADATA data;
iResult = WSAStartup(MAKEWORD(2,2),&data);
iResult = WSAStartup(MAKEWORD(2,2),&data); // Might be better to call WSAStartup/WSACleanup from sceNetInit/sceNetTerm isn't? since it's the first/last network function being used
if(iResult != NOERROR){
ERROR_LOG(SCENET, "Wsa failed");
ERROR_LOG(SCENET, "WSA failed");
return iResult;
}
#endif
metasocket = (int)INVALID_SOCKET;
metasocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
if(metasocket == INVALID_SOCKET){
ERROR_LOG(SCENET,"invalid socket");
ERROR_LOG(SCENET,"Invalid socket");
return -1;
}
struct sockaddr_in server_addr;
@ -555,7 +716,7 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
iResult = getaddrinfo(g_Config.proAdhocServer.c_str(),0,NULL,&resultAddr);
if (iResult != 0) {
ERROR_LOG(SCENET, "Dns error\n");
ERROR_LOG(SCENET, "DNS error (%s)\n", g_Config.proAdhocServer.c_str());
return iResult;
}
for (ptr = resultAddr; ptr != NULL; ptr = ptr->ai_next) {
@ -568,7 +729,8 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
server_addr.sin_addr = serverIp;
iResult = connect(metasocket,(sockaddr *)&server_addr,sizeof(server_addr));
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET,"Socket error");
uint8_t * sip = (uint8_t *)&server_addr.sin_addr.s_addr;
ERROR_LOG(SCENET, "Socket error (%i) when connecting to %s/%u.%u.%u.%u:%u", errno, g_Config.proAdhocServer.c_str(), sip[0], sip[1], sip[2], sip[3], ntohs(server_addr.sin_port));
return iResult;
}
memset(&parameter,0,sizeof(parameter));

View File

@ -49,6 +49,8 @@ inline bool connectInProgress(int errcode){ return (errcode == WSAEWOULDBLOCK ||
inline bool connectInProgress(int errcode){ return (errcode == EINPROGRESS); }
#endif
#define IsMatch(buf1, buf2) (memcmp(&buf1, &buf2, sizeof(buf1)) == 0)
// psp strutcs and definitions
#define ADHOCCTL_MODE_ADHOC 0
#define ADHOCCTL_MODE_GAMEMODE 1
@ -112,6 +114,15 @@ typedef struct SceNetAdhocctlScanInfo {
s32_le mode;
} PACK SceNetAdhocctlScanInfo;
// Virtual Network Information with u32 pointers
typedef struct SceNetAdhocctlScanInfoEmu {
u32_le next;
s32_le channel;
SceNetAdhocctlGroupName group_name;
SceNetAdhocctlBSSId bssid;
s32_le mode;
} PACK SceNetAdhocctlScanInfoEmu;
// Player Nickname
#define ADHOCCTL_NICKNAME_LEN 128
typedef struct SceNetAdhocctlNickname {
@ -144,7 +155,21 @@ typedef struct SceNetAdhocctlPeerInfoEmu {
u32_le ip_addr;
u32 padding; // Changed the pointer to u32
u64_le last_recv;
} SceNetAdhocctlPeerInfoEmu;
} PACK SceNetAdhocctlPeerInfoEmu;
// Member Information
typedef struct SceNetAdhocMatchingMemberInfo {
SceNetAdhocMatchingMemberInfo * next;
SceNetEtherAddr mac_addr;
uint8_t padding[2];
} PACK SceNetAdhocctlMemberInfo;
// Member Information with u32 pointers
typedef struct SceNetAdhocMatchingMemberInfoEmu {
u32_le next; // Changed the pointer to u32
SceNetEtherAddr mac_addr;
uint8_t padding[2];
} PACK SceNetAdhocctlMemberInfoEmu;
// Game Mode Peer List
#define ADHOCCTL_GAMEMODE_MAX_MEMBERS 16
@ -281,7 +306,7 @@ typedef struct SceNetAdhocMatchingContext {
SceNetEtherAddr mac;
// Peer List for Connectees
SceNetAdhocMatchingMemberInternal * peerlist;
SceNetAdhocMatchingMemberInternal * peerlist; // SceNetAdhocMatchingMemberInfo[Emu]
// Local PDP Port
u16_le port;
@ -313,9 +338,15 @@ typedef struct SceNetAdhocMatchingContext {
// Event Handler
SceNetAdhocMatchingHandler handler;
// Socket Connectivity
//bool connected;
// Hello Data Length
u32_le hellolen;
// Hello Data Address
u32_le helloAddr;
// Hello Data
void * hello;
@ -457,6 +488,15 @@ int isPDPPortInUse(uint16_t port);
*/
int isPTPPortInUse(uint16_t port);
/*
* Matching Members
*/
SceNetAdhocMatchingMemberInternal* findMember(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac);
void addMember(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac);
void deleteMember(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac);
void deleteAllMembers(SceNetAdhocMatchingContext * context);
/**
* Add Friend to Local List
* @param packet Friend Information
@ -476,6 +516,16 @@ void changeBlockingMode(int fd, int nonblocking);
*/
int countAvailableNetworks();
/*
* Find an existing group in networks
*/
SceNetAdhocctlScanInfo * findGroup(SceNetEtherAddr * MAC);
/*
* Deletes all groups in networks
*/
void freeGroupsRecursive(SceNetAdhocctlScanInfo * node);
/**
* Closes & Deletes all PDP Sockets
*/
@ -530,6 +580,7 @@ int getActivePeerCount(void);
* @param SocketAddres OUT: local ip
*/
int getLocalIp(sockaddr_in * SocketAddress);
uint32_t getLocalIp(int sock);
/**
* Joins two 32 bits number into a 64 bit one
@ -554,6 +605,11 @@ void split64(u64 num, int buff[]);
*/
void getLocalMac(SceNetEtherAddr * addr);
/*
* Returns the local port used by the socket
*/
uint16_t getLocalPort(int sock);
/**
* PTP Socket Counter
* @return Number of internal PTP Sockets

View File

@ -30,6 +30,8 @@
#include "sceKernelMutex.h"
#include "sceUtility.h"
#include "Core/HLE/sceNetAdhoc.h"
static bool netInited;
static bool netInetInited;
static bool netApctlInited;
@ -119,9 +121,22 @@ void __NetDoState(PointerWrap &p) {
p.Do(netMallocStat);
}
u32 sceNetTerm() {
//May also need to Terminate netAdhocctl and netAdhoc since the game (ie. GTA:VCS, Wipeout Pulse, etc) might not called them before calling sceNetTerm and causing them to behave strangely on the next sceNetInit+sceNetAdhocInit
if (netAdhocctlInited) sceNetAdhocctlTerm();
if (netAdhocInited) sceNetAdhocTerm();
WARN_LOG(SCENET, "UNTESTED sceNetTerm()");
netInited = false;
return 0;
}
// TODO: should that struct actually be initialized here?
u32 sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netinitPri, u32 netinitStack) {
ERROR_LOG(SCENET,"UNIMPL sceNetInit(poolsize=%d, calloutpri=%i, calloutstack=%d, netintrpri=%i, netintrstack=%d)", poolSize, calloutPri, calloutStack, netinitPri, netinitStack);
// May need to Terminate old one first since the game (ie. GTA:VCS) might not called sceNetTerm before the next sceNetInit and behave strangely
if (netInited) sceNetTerm();
ERROR_LOG(SCENET, "UNIMPL sceNetInit(poolsize=%d, calloutpri=%i, calloutstack=%d, netintrpri=%i, netintrstack=%d) at %08x", poolSize, calloutPri, calloutStack, netinitPri, netinitStack, currentMIPS->pc);
netInited = true;
netMallocStat.maximum = poolSize;
netMallocStat.free = poolSize;
@ -130,13 +145,6 @@ u32 sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netinitPri, u
return 0;
}
u32 sceNetTerm() {
ERROR_LOG(SCENET,"UNIMPL sceNetTerm()");
netInited = false;
return 0;
}
u32 sceWlanGetEtherAddr(u32 addrAddr) {
// Read MAC Address from config
uint8_t mac[6] = {0};

View File

@ -136,8 +136,9 @@ enum {
const size_t MAX_ADHOCCTL_HANDLERS = 32;
static bool netAdhocInited;
static bool netAdhocctlInited;
// shared in sceNetAdhoc.h since it need to be used from sceNet.cpp also
/*static*/ bool netAdhocInited;
/*static*/ bool netAdhocctlInited;
static bool netAdhocMatchingInited;
struct AdhocctlHandler {
@ -160,6 +161,7 @@ void __NetAdhocInit() {
int sceNetAdhocTerm();
int sceNetAdhocctlTerm();
int sceNetAdhocMatchingTerm();
int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAddr);
void __NetAdhocShutdown() {
// Checks to avoid confusing logspam
@ -213,7 +215,7 @@ void __handlerUpdateCallback(u64 userdata, int cycleslate) {
u32 sceNetAdhocInit() {
// Library uninitialized
DEBUG_LOG(SCENET, "sceNetAdhocInit()");
INFO_LOG(SCENET, "sceNetAdhocInit() at %08x", currentMIPS->pc);
if (!netAdhocInited) {
// Clear Translator Memory
memset(&pdp, 0, sizeof(pdp));
@ -230,7 +232,7 @@ u32 sceNetAdhocInit() {
}
u32 sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) {
DEBUG_LOG(SCENET, "sceNetAdhocctlInit(%i, %i, %08x)", stackSize, prio, productAddr);
INFO_LOG(SCENET, "sceNetAdhocctlInit(%i, %i, %08x) at %08x", stackSize, prio, productAddr, currentMIPS->pc);
if (netAdhocctlInited) {
return ERROR_NET_ADHOCCTL_ALREADY_INITIALIZED;
} else if (!g_Config.bEnableWlan) {
@ -244,9 +246,12 @@ u32 sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) {
friendFinderRunning = true;
friendFinderThread = std::thread(friendFinder);
} else {
//WARN_LOG(SCENET, "sceNetAdhocctlInit: Failed to initialize");
//return -1; // ERROR_NET_ADHOCCTL_NOT_INITIALIZED; //returning success while initNetwork failed to connect to ProServer may cause some games (ie. GTA:VCS) to behave strangely/stuck, but if not success some games (ie. Ford Street Racing) will also stuck
WARN_LOG(SCENET, "sceNetAdhocctlInit: Faking success");
return 0; // Generic error, but just return success to make games conform.
//return 0; // Generic error, but just return success to make games conform.
}
netAdhocctlInited = true; //needed for cleanup during ctlTerm even when it failed to connect to Adhoc Server (since it's being faked as success)
return 0;
}
@ -277,12 +282,14 @@ int sceNetAdhocctlGetState(u32 ptrToStatus) {
* @param flag Bitflags (Unused)
* @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_SOCKET_ID_NOT_AVAIL, ADHOC_INVALID_ADDR, ADHOC_PORT_NOT_AVAIL, ADHOC_INVALID_PORT, ADHOC_PORT_IN_USE, NET_NO_SPACE
*/
// When choosing AdHoc menu in Wipeout Pulse sometimes it's saying that "WLAN is turned off" on game screen and getting "kUnityCommandCode_MediaDisconnected" error in the Log Console when calling sceNetAdhocPdpCreate, probably it needed to wait something from the thread before calling this (ie. need to receives 7 bytes from adhoc server 1st?)
int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 unknown) {
DEBUG_LOG(SCENET, "sceNetAdhocPdpCreate(%s, %d, %d, %d)", mac, port, bufferSize, unknown);
INFO_LOG(SCENET, "sceNetAdhocPdpCreate(%08x, %u, %u, %u) at %08x", mac, port, bufferSize, unknown, currentMIPS->pc);
if (!g_Config.bEnableWlan) {
return -1;
}
int retval = ERROR_NET_ADHOC_NOT_INITIALIZED;
// Library is initialized
SceNetEtherAddr * saddr = (SceNetEtherAddr *)mac;
if (netAdhocInited) {
@ -309,9 +316,16 @@ int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 unknown)
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port); // This not safe in any way...
// The port might be under 1024 (ie. GTA:VCS use port 1, Ford Street Racing use port 0 (UNUSED_PORT), etc) and already used by other application/host OS, should we add 1024 to the port whenever it tried to use an already used port?
// Bound Socket to local Port
if (bind(usocket, (sockaddr *)&addr, sizeof(addr)) == 0) {
int iResult = bind(usocket, (sockaddr *)&addr, sizeof(addr));
/*if (iResult == SOCKET_ERROR && errno == 10048) { //Forcing PdpCreate to be successfull using a different Port might not works and might affect other players sharing the same IP due to "deleteFriendByIP" (should delete by MAC instead of IP)
addr.sin_port = 0; //UNUSED_PORT
iResult = bind(usocket, (sockaddr *)&addr, sizeof(addr));
WARN_LOG(SCENET, "Port %u is already used, replaced with UNUSED_PORT(%u)", port, ntohs(addr.sin_port));
}*/
if (iResult == 0) {
// Allocate Memory for Internal Data
SceNetAdhocPdpStat * internal = (SceNetAdhocPdpStat *)malloc(sizeof(SceNetAdhocPdpStat));
@ -328,7 +342,7 @@ int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 unknown)
// Fill in Data
internal->id = usocket;
internal->laddr = *saddr;
internal->lport = port;
internal->lport = ntohs(getLocalPort(usocket)); // port; //should use the port given to the socket (in case it's UNUSED_PORT port) isn't?
internal->rcv_sb_cc = bufferSize;
// Link Socket to Translator ID
@ -337,17 +351,34 @@ int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 unknown)
// Forward Port on Router
//sceNetPortOpen("UDP", sport); // I need to figure out how to use this in windows/linux
// Wait for Status to be connected to prevent Wipeout Pulse from showing "WLAN is turned off"
if ((i == 0) && friendFinderRunning) {
int cnt = 0;
while ((threadStatus != ADHOCCTL_STATE_CONNECTED) && (cnt < 5000)) {
sleep_ms(1);
cnt++;
}
}
// Success
return i + 1;
}
}
// Free Memory for Internal Data
free(internal);
}
retval = ERROR_NET_NO_SPACE;
}
else {
retval = ERROR_NET_ADHOC_PORT_IN_USE;
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket error (%i) when binding port %u", errno, ntohs(addr.sin_port));
}
}
// Close Socket
closesocket(usocket);
return retval;
}
// Default to No-Space Error
@ -355,7 +386,7 @@ int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 unknown)
}
// Invalid MAC supplied
return ERROR_NET_ADHOC_INVALID_ADDR;
//return ERROR_NET_ADHOC_INVALID_ADDR;
}
// Invalid Arguments were supplied
@ -406,7 +437,7 @@ int sceNetAdhocctlGetParameter(u32 paramAddr) {
* @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT, ADHOC_INVALID_DATALEN, ADHOC_SOCKET_ALERTED, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_WOULD_BLOCK, NET_NO_SPACE, NET_INTERNAL
*/
int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, int timeout, int flag) {
DEBUG_LOG(SCENET, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i)", id, mac, port, data, len, timeout, flag);
DEBUG_LOG(SCENET, "sceNetAdhocPdpSend(%i, %08x, %i, %p, %i, %i, %i)", id, mac, port, data, len, timeout, flag);
if (!g_Config.bEnableWlan) {
return -1;
}
@ -420,7 +451,7 @@ int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, i
// Valid Port
if (dport != 0) {
// Valid Data Length
if (len > 0) {
if (len >= 0) { // should we allow 0 size packet (for ping) ?
// Valid Socket ID
if (id > 0 && id <= 255 && pdp[id - 1] != NULL) {
// Cast Socket
@ -452,22 +483,37 @@ int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, i
// Send Data
changeBlockingMode(socket->id, flag);
int sent = sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target));
if (sent == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend", errno);
}
changeBlockingMode(socket->id, 0);
// Free Network Lock
//_freeNetworkLock();
uint8_t * sip = (uint8_t *)&target.sin_addr.s_addr;
// Sent Data
if (sent == len) {
DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Sent %u bytes to %u.%u.%u.%u:%u", socket->id, ntohs(getLocalPort(socket->id)), sent, sip[0], sip[1], sip[2], sip[3], ntohs(target.sin_port));
// Return sent size
return sent;
// Success
return 0;
//return 0;
}
// Partially Sent Data (when non-blocking socket's send buffer is smaller than len)
else if (flag && (sent >= 0)) {
DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u]: Partial Sent %u bytes to %u.%u.%u.%u:%u", socket->id, ntohs(getLocalPort(socket->id)), sent, sip[0], sip[1], sip[2], sip[3], ntohs(target.sin_port));
// Return sent size
return sent;
}
// Blocking Situation
if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK;
// Timeout
return ERROR_NET_ADHOC_TIMEOUT;
return ERROR_NET_ADHOC_TIMEOUT; //-1;
}
}
@ -489,6 +535,7 @@ int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, i
// sceNetInetSendto(socket->id, data, len, ((flag != 0) ? (INET_MSG_DONTWAIT) : (0)), (SceNetInetSockaddr *)&target, sizeof(target));
//}
#endif
int maxsent = 0;
// Acquire Peer Lock
peerlock.lock();
@ -506,8 +553,16 @@ int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, i
// printf("Attempting PDP Send to %u.%u.%u.%u on Port %u\n", thing[0], thing[1], thing[2], thing[3], dport);
// Send Data
changeBlockingMode(socket->id, flag);
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));
if (sent > maxsent) maxsent = sent;
if (sent == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpSend[i%](Broadcast)", errno, socket->id);
}
changeBlockingMode(socket->id, 0);
if (sent >= 0) {
uint8_t * sip = (uint8_t *)&target.sin_addr.s_addr;
DEBUG_LOG(SCENET, "sceNetAdhocPdpSend[%i:%u](BC): Sent %u bytes to %u.%u.%u.%u:%u", socket->id, ntohs(getLocalPort(socket->id)), sent, sip[0], sip[1], sip[2], sip[3], ntohs(target.sin_port));
}
}
// Free Peer Lock
@ -517,7 +572,9 @@ int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, i
//_freeNetworkLock();
// Broadcast never fails!
return 0;
//return 0;
// Return sent size
return maxsent;
}
}
@ -558,13 +615,13 @@ int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int len, i
* @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_ENOUGH_SPACE, ADHOC_THREAD_ABORTED, NET_INTERNAL
*/
int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *dataLength, u32 timeout, int flag) {
DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i)", id, addr, port, buf, dataLength, timeout, flag);
DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i) at %08x", id, addr, port, buf, dataLength, timeout, flag, currentMIPS->pc);
if (!g_Config.bEnableWlan) {
return -1;
}
SceNetEtherAddr *saddr = (SceNetEtherAddr *)addr;
uint16_t * sport = (uint16_t *)port;
uint32_t * sport = (uint32_t *)port; // uint16_t * sport = (uint16_t *)port; //Looking at Quake3 sourcecode (net_adhoc.c) this should be 32bit isn't?
int * len = (int *)dataLength;
if (netAdhocInited) {
// Valid Socket ID
@ -573,7 +630,7 @@ int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *dataLen
SceNetAdhocPdpStat * socket = pdp[id - 1];
// Valid Arguments
if (saddr != NULL && port != NULL && buf != NULL && len != NULL && *len > 0) {
if (saddr != NULL && port != NULL && buf != NULL && len != NULL && *len >= 0) { // since it's possible to recv 0 size, should we allow 0 size also?
#ifndef PDP_DIRTY_MAGIC
// Schedule Timeout Removal
if (flag == 1) timeout = 0;
@ -612,10 +669,16 @@ int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *dataLen
// Receive Data
changeBlockingMode(socket->id,flag);
int received = recvfrom(socket->id, (char *)buf, *len,0,(sockaddr *)&sin, &sinlen);
changeBlockingMode(socket->id,0);
/*if (received == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket Error (%i) on sceNetAdhocPdpRecv", errno);
}*/
changeBlockingMode(socket->id, 0);
// Received Data
if (received > 0) {
if (received >= 0) { // (received > 0)
uint8_t * sip = (uint8_t *)&sin.sin_addr.s_addr;
DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv[%i:%u]: Received %u bytes from %u.%u.%u.%u:%u", socket->id, ntohs(getLocalPort(socket->id)), received, sip[0], sip[1], sip[2], sip[3], ntohs(sin.sin_port));
// Peer MAC
SceNetEtherAddr mac;
@ -623,7 +686,7 @@ int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *dataLen
if (resolveIP(sin.sin_addr.s_addr, &mac) == 0) {
// Provide Sender Information
*saddr = mac;
*sport = htons(sin.sin_port);
*sport = ntohs(sin.sin_port); //htons(sin.sin_port);
// Save Length
*len = received;
@ -632,8 +695,11 @@ int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *dataLen
//_freeNetworkLock();
// Return Success
return 0;
//return 0;
}
//Return Received len
return received;
}
// Free Network Lock
@ -645,8 +711,8 @@ int sceNetAdhocPdpRecv(int id, void *addr, void * port, void *buf, void *dataLen
#endif
// Nothing received
if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK;
return ERROR_NET_ADHOC_TIMEOUT;
if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK; //ERROR_NET_ADHOC_NO_DATA_AVAILABLE;
return ERROR_NET_ADHOC_TIMEOUT; //
}
// Invalid Argument
@ -679,10 +745,14 @@ int sceNetAdhocPollSocket(u32 socketStructAddr, int count, int timeout, int nonb
* @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID
*/
int sceNetAdhocPdpDelete(int id, int unknown) {
DEBUG_LOG(SCENET, "sceNetAdhocPdpDelete(%d, %d)", id, unknown);
// WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right?
INFO_LOG(SCENET, "sceNetAdhocPdpDelete(%d, %d) at %08x", id, unknown, currentMIPS->pc);
/*
if (!g_Config.bEnableWlan) {
return 0;
}
*/
// Library is initialized
if (netAdhocInited) {
// Valid Arguments
@ -726,7 +796,7 @@ int sceNetAdhocctlGetAdhocId(u32 productStructAddr) {
}
int sceNetAdhocctlScan() {
DEBUG_LOG(SCENET, "sceNetAdhocctlScan()");
INFO_LOG(SCENET, "sceNetAdhocctlScan() at %08x", currentMIPS->pc);
// Library initialized
if (netAdhocctlInited) {
@ -734,18 +804,42 @@ int sceNetAdhocctlScan() {
if (threadStatus == ADHOCCTL_STATE_DISCONNECTED) {
threadStatus = ADHOCCTL_STATE_SCANNING;
// Multithreading Lock
peerlock.lock();
// It seems AdHoc Server always sent the full group list, so we should reset current networks to prevent leaving host to be listed again
freeGroupsRecursive(networks);
networks = NULL;
// Multithreading Unlock
peerlock.unlock();
// Prepare Scan Request Packet
uint8_t opcode = OPCODE_SCAN;
// Send Scan Request Packet
send(metasocket, (char *)&opcode, 1, 0);
// 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)
int iResult = send(metasocket, (char *)&opcode, 1, 0);
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket error (%i) when sending", errno);
threadStatus = ADHOCCTL_STATE_DISCONNECTED;
return ERROR_NET_ADHOCCTL_DISCONNECTED; // ERROR_NET_ADHOCCTL_BUSY
}
// Wait for Status to be connected to prevent Ford Street Racing from Failed to find game session
if (friendFinderRunning) {
int cnt = 0;
while ((threadStatus == ADHOCCTL_STATE_SCANNING) && (cnt < 5000)) {
sleep_ms(1);
cnt++;
}
}
// Return Success
return 0;
}
// Library is busy
return ERROR_NET_ADHOCCTL_BUSY;
return ERROR_NET_ADHOCCTL_BUSY; // ERROR_NET_ADHOCCTL_BUSY may trigger the game (ie. Ford Street Racing) to call sceNetAdhocctlDisconnect
}
// Library uninitialized
@ -753,24 +847,27 @@ int sceNetAdhocctlScan() {
}
int sceNetAdhocctlGetScanInfo(u32 size, u32 bufAddr) {
DEBUG_LOG(SCENET, "sceNetAdhocctlGetScanInfo(%08x, %08x)", size, bufAddr);
INFO_LOG(SCENET, "sceNetAdhocctlGetScanInfo([%08x]=%i, %08x)", size, Memory::Read_U32(size), bufAddr);
if (!g_Config.bEnableWlan) {
return 0;
}
int * buflen = (int *)Memory::GetPointer(size);
SceNetAdhocctlScanInfo * buf = NULL;
SceNetAdhocctlScanInfoEmu * buf = NULL;
if (Memory::IsValidAddress(bufAddr)) {
buf = (SceNetAdhocctlScanInfo *)Memory::GetPointer(bufAddr);
buf = (SceNetAdhocctlScanInfoEmu *)Memory::GetPointer(bufAddr);
}
// Library initialized
if (netAdhocctlInited) {
if (!Memory::IsValidAddress(size)) return ERROR_NET_ADHOCCTL_INVALID_ARG;
// Minimum Argument Requirements
if (buflen != NULL) {
// Multithreading Lock
peerlock.lock();
// Length Returner Mode
if (buf == NULL) *buflen = countAvailableNetworks() * sizeof(SceNetAdhocctlScanInfo);
if (buf == NULL) *buflen = countAvailableNetworks() * sizeof(SceNetAdhocctlScanInfoEmu);
// Normal Information Mode
else {
@ -781,7 +878,7 @@ int sceNetAdhocctlGetScanInfo(u32 size, u32 bufAddr) {
int discovered = 0;
// Count requested Networks
int requestcount = *buflen / sizeof(SceNetAdhocctlScanInfo);
int requestcount = *buflen / sizeof(SceNetAdhocctlScanInfoEmu);
// Minimum Argument Requirements
if (requestcount > 0) {
@ -791,7 +888,10 @@ int sceNetAdhocctlGetScanInfo(u32 size, u32 bufAddr) {
// Iterate Group List
for (; group != NULL && discovered < requestcount; group = group->next) {
// Copy Group Information
buf[discovered] = *group;
//buf[discovered] = *group;
buf[discovered].group_name = group->group_name;
buf[discovered].bssid = group->bssid;
buf[discovered].mode = group->mode;
// Exchange Adhoc Channel
// sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL, &buf[discovered].channel);
@ -809,15 +909,15 @@ int sceNetAdhocctlGetScanInfo(u32 size, u32 bufAddr) {
// Link List
int i = 0; for (; i < discovered - 1; i++) {
// Link Network
buf[i].next = &buf[i + 1];
buf[i].next = bufAddr + (sizeof(SceNetAdhocctlScanInfoEmu)*i) + sizeof(SceNetAdhocctlScanInfoEmu); // buf[i].next = &buf[i + 1];
}
// Fix Last Element
if (discovered > 0) buf[discovered - 1].next = NULL;
if (discovered > 0) buf[discovered - 1].next = 0;
}
// Fix Size
*buflen = discovered * sizeof(SceNetAdhocctlScanInfo);
*buflen = discovered * sizeof(SceNetAdhocctlScanInfoEmu);
}
// Multithreading Unlock
@ -864,8 +964,12 @@ u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) {
}
adhocctlHandlers[retval] = handler;
WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): added handler %d", handlerPtr, handlerArg, retval);
} else {
} else if(foundHandler) {
ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Same handler already exists", handlerPtr, handlerArg);
retval = 0; //Faking success
} else {
ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Invalid handler", handlerPtr, handlerArg);
retval = ERROR_NET_ADHOCCTL_INVALID_ARG;
}
// The id to return is the number of handlers currently registered
@ -873,14 +977,18 @@ u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) {
}
u32 sceNetAdhocctlDisconnect() {
DEBUG_LOG(SCENET, "sceNetAdhocctlDisconnect()");
// WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right?
INFO_LOG(SCENET, "sceNetAdhocctlDisconnect() at %08x", currentMIPS->pc);
/*
if (!g_Config.bEnableWlan) {
return 0;
}
*/
// Library initialized
if (netAdhocctlInited) {
// Connected State (Adhoc Mode)
if (threadStatus == ADHOCCTL_STATE_CONNECTED) {
if (threadStatus != ADHOCCTL_STATE_DISCONNECTED) { // (threadStatus == ADHOCCTL_STATE_CONNECTED)
// Clear Network Name
memset(&parameter.group_name, 0, sizeof(parameter.group_name));
@ -897,7 +1005,10 @@ u32 sceNetAdhocctlDisconnect() {
//_acquireNetworkLock();
// Send Disconnect Request Packet
send(metasocket, (const char *)&opcode, 1, 0);
int iResult = send(metasocket, (const char *)&opcode, 1, 0);
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket error (%i) when sending", errno);
}
// Free Network Lock
//_freeNetworkLock();
@ -911,19 +1022,25 @@ u32 sceNetAdhocctlDisconnect() {
// Delete Peer Reference
friends = NULL;
// Clear Group List
freeGroupsRecursive(networks);
// Delete Group Reference
networks = NULL;
// Multithreading Unlock
peerlock.unlock();
}
// Notify Event Handlers (even if we weren't connected, not doing this will freeze games like God Eater, which expect this behaviour)
__UpdateAdhocctlHandlers(ADHOCCTL_EVENT_DISCONNECT,0);
// Return Success
// Return Success, some games might ignore returned value and always treat it as success, otherwise repeatedly calling this function
return 0;
}
// Library uninitialized
return ERROR_NET_ADHOC_NOT_INITIALIZED;
return 0; //ERROR_NET_ADHOC_NOT_INITIALIZED; // Wipeout Pulse will repeatedly calling this function if returned value is ERROR_NET_ADHOC_NOT_INITIALIZED
}
u32 sceNetAdhocctlDelHandler(u32 handlerID) {
@ -938,11 +1055,14 @@ u32 sceNetAdhocctlDelHandler(u32 handlerID) {
}
int sceNetAdhocctlTerm() {
DEBUG_LOG(SCENET, "sceNetAdhocctlTerm()");
// WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right?
INFO_LOG(SCENET, "sceNetAdhocctlTerm()");
/*
if (!g_Config.bEnableWlan) {
netAdhocctlInited = false;
return 0;
}
*/
if (netAdhocctlInited) {
netAdhocctlInited = false;
@ -950,11 +1070,13 @@ int sceNetAdhocctlTerm() {
if (friendFinderThread.joinable()) {
friendFinderThread.join();
}
//May also need to clear Handlers
adhocctlHandlers.clear();
// Free stuff here
closesocket(metasocket);
metasocket = (int)INVALID_SOCKET;
#ifdef _MSC_VER
WSACleanup();
WSACleanup(); // Might be better to call WSAStartup/WSACleanup from sceNetInit/sceNetTerm isn't? since it's the first/last network function being used
#endif
}
@ -967,8 +1089,66 @@ int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) {
}
int sceNetAdhocctlJoin(u32 scanInfoAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlJoin(%08x)", scanInfoAddr);
return -1;
WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlJoin(%08x) at %08x", scanInfoAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan) {
return -1;
}
// Library initialized
if (netAdhocctlInited) {
if (!Memory::IsValidAddress(scanInfoAddr)) return ERROR_NET_ADHOCCTL_INVALID_ARG;
// Disconnected State
if (threadStatus == ADHOCCTL_STATE_DISCONNECTED) {
SceNetAdhocctlScanInfo * sinfo = (SceNetAdhocctlScanInfo*)Memory::GetPointer(scanInfoAddr);
// Prepare Connect Packet
SceNetAdhocctlConnectPacketC2S packet;
// Clear Packet Memory
memset(&packet, 0, sizeof(packet));
// Set Packet Opcode
packet.base.opcode = OPCODE_CONNECT;
// Set Target Group
if (sinfo != NULL)
packet.group = sinfo->group_name;
// Acquire Network Lock
// Send Packet
int iResult = send(metasocket, (const char *)&packet, sizeof(packet), 0);
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket error (%i) when sending", errno);
return ERROR_NET_ADHOCCTL_DISCONNECTED; // ERROR_NET_ADHOCCTL_BUSY;
}
// Free Network Lock
// Set HUD Connection Status
//setConnectionStatus(1);
// Wait for Status to be connected to prevent Ford Street Racing from Failed to create game session
if (friendFinderRunning) {
int cnt = 0;
while ((threadStatus != ADHOCCTL_STATE_CONNECTED) && (cnt < 5000)) {
sleep_ms(1);
cnt++;
}
}
// Return Success
return 0;
}
// Connected State
return ERROR_NET_ADHOCCTL_BUSY; // ERROR_NET_ADHOCCTL_BUSY may trigger the game (ie. Ford Street Racing) to call sceNetAdhocctlDisconnect
}
return ERROR_NET_ADHOCCTL_NOT_INITIALIZED;
}
int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) {
@ -982,7 +1162,7 @@ int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) {
* @return 0 on success or... ADHOCCTL_NOT_INITIALIZED, ADHOCCTL_INVALID_ARG, ADHOCCTL_BUSY
*/
int sceNetAdhocctlCreate(const char *groupName) {
DEBUG_LOG(SCENET, "sceNetAdhocctlCreate(%s)", groupName);
INFO_LOG(SCENET, "sceNetAdhocctlCreate(%s) at %08x", groupName, currentMIPS->pc);
if (!g_Config.bEnableWlan) {
return -1;
}
@ -992,8 +1172,8 @@ int sceNetAdhocctlCreate(const char *groupName) {
if (netAdhocctlInited) {
// Valid Argument
if (validNetworkName(groupNameStruct)) {
// Disconnected State
if (threadStatus == ADHOCCTL_STATE_DISCONNECTED) {
// Disconnected State, may also need to check for Scanning state to prevent some games from failing to host a game session
if ((threadStatus == ADHOCCTL_STATE_DISCONNECTED) || (threadStatus == ADHOCCTL_STATE_SCANNING)) {
// Set Network Name
if (groupNameStruct != NULL) parameter.group_name = *groupNameStruct;
@ -1015,21 +1195,34 @@ int sceNetAdhocctlCreate(const char *groupName) {
// Acquire Network Lock
// Send Packet
send(metasocket, (const char *)&packet, sizeof(packet), 0);
int iResult = send(metasocket, (const char *)&packet, sizeof(packet), 0);
if (iResult == SOCKET_ERROR) {
ERROR_LOG(SCENET, "Socket error (%i) when sending", errno);
return ERROR_NET_ADHOCCTL_DISCONNECTED; // ERROR_NET_ADHOCCTL_BUSY;
}
// Free Network Lock
// Set HUD Connection Status
//setConnectionStatus(1);
// Wait for Status to be connected to prevent Ford Street Racing from Failed to create game session
if (friendFinderRunning) {
int cnt = 0;
while ((threadStatus != ADHOCCTL_STATE_CONNECTED) && (cnt < 5000)) {
sleep_ms(1);
cnt++;
}
}
// Return Success
return 0;
}
// Connected State
return ERROR_NET_ADHOCCTL_BUSY;
return ERROR_NET_ADHOCCTL_BUSY; // ERROR_NET_ADHOCCTL_BUSY may trigger the game (ie. Ford Street Racing) to call sceNetAdhocctlDisconnect
}
// Invalid Argument
return ERROR_NET_ADHOC_INVALID_ARG;
}
@ -1039,29 +1232,32 @@ int sceNetAdhocctlCreate(const char *groupName) {
int sceNetAdhocctlConnect(u32 ptrToGroupName) {
if (Memory::IsValidAddress(ptrToGroupName)) {
DEBUG_LOG(SCENET, "sceNetAdhocctlConnect(groupName=%s)", Memory::GetCharPointer(ptrToGroupName));
INFO_LOG(SCENET, "sceNetAdhocctlConnect(groupName=%s) at %08x", Memory::GetCharPointer(ptrToGroupName), currentMIPS->pc);
return sceNetAdhocctlCreate(Memory::GetCharPointer(ptrToGroupName));
} else {
return ERROR_NET_ADHOC_INVALID_ADDR;
return ERROR_NET_ADHOC_INVALID_ADDR; // shouldn't this be ERROR_NET_ADHOC_INVALID_ARG ?
}
}
int sceNetAdhocctlCreateEnterGameMode(const char *groupName, int unknown, int playerNum, u32 macsAddr, int timeout, int unknown2) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlCreateEnterGameMode(%s, %i, %i, %08x, %i, %i)", groupName, unknown, playerNum, macsAddr, timeout, unknown2);
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlCreateEnterGameMode(%s, %i, %i, %08x, %i, %i) at %08x", groupName, unknown, playerNum, macsAddr, timeout, unknown2, currentMIPS->pc);
return -1;
}
int sceNetAdhocctlJoinEnterGameMode(const char *groupName, const char *macAddr, int timeout, int unknown2) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlJoinEnterGameMode(%s, %s, %i, %i)", groupName, macAddr, timeout, unknown2);
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlJoinEnterGameMode(%s, %s, %i, %i) at %08x", groupName, macAddr, timeout, unknown2, currentMIPS->pc);
return -1;
}
int sceNetAdhocTerm() {
DEBUG_LOG(SCENET, "sceNetAdhocTerm()");
INFO_LOG(SCENET, "sceNetAdhocTerm()");
// WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup all the sockets right?
/*
if (!g_Config.bEnableWlan) {
netAdhocInited = false;
return 0;
}
*/
// Library is initialized
if (netAdhocInited) {
@ -1307,7 +1503,7 @@ int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int timeou
if (Memory::IsValidAddress(peerMacAddrPtr)) {
addr = PSPPointer<SceNetEtherAddr>::Create(peerMacAddrPtr);
}
uint16_t * port = NULL;
uint16_t * port = NULL; //
if (Memory::IsValidAddress(peerPortPtr)) {
port = (uint16_t *)Memory::GetPointer(peerPortPtr);
}
@ -1398,11 +1594,11 @@ int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int timeou
// Copy Local Address Data to Structure
getLocalMac(&internal->laddr);
internal->lport = htons(local.sin_port);
internal->lport = ntohs(local.sin_port); // htons(local.sin_port);
// Copy Peer Address Data to Structure
internal->paddr = mac;
internal->pport = htons(peeraddr.sin_port);
internal->pport = ntohs(peeraddr.sin_port); // htons(peeraddr.sin_port);
// Set Connected State
internal->state = PTP_STATE_ESTABLISHED;
@ -1930,12 +2126,12 @@ int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) {
}
int sceNetAdhocGameModeCreateMaster(u32 data, int size) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateMaster(%08x, %i)", data, size);
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateMaster(%08x, %i) at %08x", data, size, currentMIPS->pc);
return -1;
}
int sceNetAdhocGameModeCreateReplica(const char *mac, u32 data, int size) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateReplica(%s, %08x, %i)", mac, data, size);
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateReplica(%s, %08x, %i) at %08x", mac, data, size, currentMIPS->pc);
return -1;
}
@ -1965,6 +2161,7 @@ int sceNetAdhocGetSocketAlert() {
}
int sceNetAdhocMatchingInit(u32 memsize) {
INFO_LOG(SCENET, "sceNetAdhocMatchingInit(%d) at %08x", memsize, currentMIPS->pc);
// Uninitialized Library
if (!netAdhocMatchingInited) {
// Save Fake Pool Size
@ -1981,6 +2178,13 @@ int sceNetAdhocMatchingInit(u32 memsize) {
}
int sceNetAdhocMatchingTerm() {
// Should we cleanup all created matching contexts first? just in case there are games that doesn't delete them before calling this
/*
if (netAdhocMatchingInited) {
// Should we also delete all PDP? since creating a matching context will also create a PDP socket
}
*/
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingTerm()");
netAdhocMatchingInited = false;
@ -1991,7 +2195,7 @@ int sceNetAdhocMatchingTerm() {
// Presumably returns a "matchingId".
int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbuflen, int hello_int, int keepalive_int, int init_count, int rexmt_int, u32 callbackAddr) {
DEBUG_LOG(SCENET, "sceNetAdhocMatchingCreate");
INFO_LOG(SCENET, "sceNetAdhocMatchingCreate(mode=%i, maxnum=%i, port=%i, rxbuflen=%i, hello=%i, keepalive=%i, initcount=%i, rexmt=%i, callbackAddr=%08x) at %08x", mode, maxnum, port, rxbuflen, hello_int, keepalive_int, init_count, rexmt_int, callbackAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan) {
return -1;
}
@ -2054,23 +2258,30 @@ int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbuflen, int
// Fill in Selfpeer
context->mac = localmac;
// Multithreading Lock
peerlock.lock(); //contextlock.lock();
// Link Context
//context->connected = true;
context->next = contexts;
contexts = context;
// Multithreading UnLock
peerlock.unlock(); //contextlock.unlock();
// Return Matching ID
return context->id;
}
// Close PDP Socket
sceNetAdhocPdpDelete(socket, 0);
sceNetAdhocPdpDelete(socket, 0); // context->connected = (sceNetAdhocPdpDelete(socket, 0) < 0);
}
// Free Memory
free(context);
// Port in use
if (socket < 1) return ERROR_NET_ADHOC_MATCHING_PORT_IN_USE;
if (socket < 1) return ERROR_NET_ADHOC_MATCHING_PORT_IN_USE; // ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED; // -1; // ERROR_NET_ADHOC_MATCHING_NOT_ESTABLISHED;
}
// Out of Memory
@ -2092,10 +2303,36 @@ int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbuflen, int
return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED;
}
// TODO: Should we execute the callback used to create the Matching Id if it's a valid address?
int sceNetAdhocMatchingStart(int matchingId, int evthPri, int evthStack, int inthPri, int inthStack, int optLen, u32 optDataAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingStart(%i, %i, %i, %i, %i, %i, %08x)", matchingId, evthPri, evthStack, inthPri, inthStack, optLen, optDataAddr);
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingStart(%i, %i, %i, %i, %i, %i, %08x) at %08x", matchingId, evthPri, evthStack, inthPri, inthStack, optLen, optDataAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan)
return -1;
SceNetAdhocMatchingContext * item = findMatchingContext(matchingId);
if (item != NULL) {
sceNetAdhocMatchingSetHelloOpt(matchingId, optLen, optDataAddr);
if ((optLen > 0) && Memory::IsValidAddress(optDataAddr)) {
// Allocate the memory and copy the content
if (item->hello != NULL) free(item->hello);
item->hello = malloc(optLen);
if (item->hello != NULL)
Memory::Memcpy(item->hello, optDataAddr, optLen);
}
//else return ERROR_NET_ADHOC_MATCHING_INVALID_ARG; // ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN; // Returning Not Success will cause GTA:VC unable to host/join
//Add your own MAC as a member (ony if it's empty?)
addMember(item, &item->mac);
//TODO: Create a new thread
// Easier to implement if using an existing thread (friendFinder) instead of creating a new one ^_^
//sceKernelCreateThread
/*eventHandlerUpdate = CoreTiming::RegisterEvent("HandlerUpdateEvent", __handlerUpdateCallback);
memberFinderRunning = true;
memberFinderThread = std::thread(memberFinder);*/
}
return 0;
}
@ -2103,13 +2340,68 @@ int sceNetAdhocMatchingStop(int matchingId) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingStop(%i)", matchingId);
if (!g_Config.bEnableWlan)
return -1;
SceNetAdhocMatchingContext * item = findMatchingContext(matchingId);
if (item != NULL) {
/*memberFinderRunning = false;
if (memberFinderThread.joinable()) {
friendFinderThread.join();
}*/
// Remove your own MAC, or All memebers, don't remove at all?
//delAllMembers();
}
return 0;
}
int sceNetAdhocMatchingDelete(int matchingId) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingDelete(%i)", matchingId);
// WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right?
/*
if (!g_Config.bEnableWlan)
return -1;
*/
// Previous Context Reference
SceNetAdhocMatchingContext * prev = NULL;
// Context Pointer
SceNetAdhocMatchingContext * item = contexts;
// Iterate contexts
for (; item != NULL; item = item->next) {
// Found matching ID
if (item->id == matchingId) {
// Multithreading Lock
peerlock.lock(); //contextlock.lock();
// Unlink Left (Beginning)
if (prev == NULL) contexts = item->next;
// Unlink Left (Other)
else prev->next = item->next;
// Multithreading Unlock
peerlock.unlock(); //contextlock.unlock();
// Delete the socket
sceNetAdhocPdpDelete(item->socket, 0); // item->connected = (sceNetAdhocPdpDelete(item->socket, 0) < 0);
// Free allocated memories
free(item->hello);
free(item->rxbuf);
deleteAllMembers(item);
// Free item context memory
free(item);
// Stop Search
break;
}
// Set Previous Reference
prev = item;
}
WARN_LOG(SCENET, "UNTESTED sceNetAdhocMatchingDelete(%i) at %08x", matchingId, currentMIPS->pc);
return 0;
}
@ -2142,16 +2434,98 @@ int sceNetAdhocMatchingGetHelloOpt(int matchingId, u32 optLenAddr, u32 optDataAd
}
int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingSetHelloOpt(%i, %i, %08x)", matchingId, optLenAddr, optDataAddr);
DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocMatchingSetHelloOpt(%i, %i, %08x) at %08x", matchingId, optLenAddr, optDataAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan)
return -1;
//if (!Memory::IsValidAddress(optDataAddr)) return ERROR_NET_ADHOC_MATCHING_INVALID_ARG;
SceNetAdhocMatchingContext * item = findMatchingContext(matchingId);
if (item != NULL) {
// Set OptData
int oldLen = item->hellolen;
item->hellolen = optLenAddr; //optLenAddr doesn't seems to be an address to the actual len
item->helloAddr = optDataAddr;
if (optLenAddr <= 0 || !Memory::IsValidAddress(optDataAddr)) {
if (item->hello != NULL) {
free(item->hello);
item->hello = NULL;
}
}
else {
if (optLenAddr > oldLen) {
free(item->hello);
item->hello = malloc(optLenAddr);
}
Memory::Memcpy(item->hello, optDataAddr, optLenAddr);
}
}
//else return ERROR_NET_ADHOC_MATCHING_INVALID_ID;
//sceNetAdhocctlScan();
return 0;
}
int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetMembers(%i, %08x, %08x)", matchingId, sizeAddr, buf);
DEBUG_LOG(SCENET, "UNTESTED sceNetAdhocMatchingGetMembers(%i, [%08x]=%i, %08x) at %08x", matchingId, sizeAddr, Memory::Read_U32(sizeAddr), buf, currentMIPS->pc);
if (!g_Config.bEnableWlan)
return -1;
// Minimum Argument
if (!Memory::IsValidAddress(sizeAddr)) return ERROR_NET_ADHOC_MATCHING_INVALID_ARG;
SceNetAdhocMatchingContext * item = findMatchingContext(matchingId);
if (item != NULL) {
int * buflen = (int *)Memory::GetPointer(sizeAddr);
SceNetAdhocMatchingMemberInfoEmu * buf2 = NULL;
if (Memory::IsValidAddress(buf)) {
buf2 = (SceNetAdhocMatchingMemberInfoEmu *)Memory::GetPointer(buf);
}
// Multithreading Lock
peerlock.lock();
// Iterate Members
//SceNetAdhocMatchingMemberInternal * peer = item->peerlist;
//Using friend list instead, since it's easier to implement ^_^
SceNetAdhocctlPeerInfo * peer = friends;
int count = 0;
if (!Memory::IsValidAddress(buf)) { // Returning needed buf size instead
count++;
for (; peer != NULL; peer = peer->next) count++;
}
else {
buf2[count].mac_addr = item->mac; //add your own MAC
buf2[count].padding[0] = 0; // does padding need to be 0 ?
buf2[count++].padding[1] = 0;
for (; peer != NULL; peer = peer->next) {
buf2[count].mac_addr = peer->mac_addr;
buf2[count].padding[0] = 0;
buf2[count].padding[1] = 0;
count++;
}
// Link List
int i = 0;
for (; i < count - 1; i++) {
// Link Network
buf2[i].next = buf + (sizeof(SceNetAdhocMatchingMemberInfoEmu)*i) + sizeof(SceNetAdhocMatchingMemberInfoEmu);
}
// Fix Last Element
if (count > 0) buf2[count - 1].next = 0;
}
// Fix Size
*buflen = count * sizeof(SceNetAdhocMatchingMemberInfoEmu); //includes your own MAC
// Multithreading Unlock
peerlock.unlock();
}
//else return ERROR_NET_ADHOC_MATCHING_INVALID_ID;
return 0;
}
@ -2243,7 +2617,7 @@ int sceNetAdhocctlGetGameModeInfo(u32 infoAddr) {
int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) {
DEBUG_LOG(SCENET, "sceNetAdhocctlGetPeerList(%08x, %08x)", sizeAddr, bufAddr);
INFO_LOG(SCENET, "sceNetAdhocctlGetPeerList(%08x, %08x) at %08x", sizeAddr, bufAddr, currentMIPS->pc);
if (!g_Config.bEnableWlan) {
return -1;
}

View File

@ -27,3 +27,9 @@ void __NetAdhocDoState(PointerWrap &p);
// I have to call this from netdialog
int sceNetAdhocctlCreate(const char * groupName);
// May need to use these from sceNet.cpp
extern bool netAdhocInited;
extern bool netAdhocctlInited;
int sceNetAdhocctlTerm();
int sceNetAdhocTerm();