ppsspp/Core/HLE/sceNetAdhoc.cpp

2606 lines
75 KiB
C++

// Copyright (c) 2013- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// sceNetAdhoc
// These acronyms are seen in function names:
// * PDP: a proprietary Sony protocol similar to UDP.
// * PTP: a proprietary Sony protocol similar to TCP.
// We will need to wrap them into the similar UDP and TCP messages. If we want to
// play adhoc remotely online, I guess we'll need to wrap both into TCP/IP.
// We will need some server infrastructure to provide match making. We'll
// group players per game. Maybe allow players to join rooms and then start the game,
// instead of the other way around?
#include "../Config.h"
#include "Core/HLE/HLE.h"
#include "../CoreTiming.h"
#include "Core/HLE/sceNetAdhoc.h"
#include "sceKernel.h"
#include "sceKernelThread.h"
#include "sceKernelMutex.h"
#include "sceUtility.h"
#include "net/resolve.h"
// Temporary stuff
#include <thread>
#ifdef _WIN32
#include <WS2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define Sleep sleep
#define closesocket close
#endif
#include <mutex>
// End of extra includes
enum {
ERROR_NET_ADHOC_INVALID_SOCKET_ID = 0x80410701,
ERROR_NET_ADHOC_INVALID_ADDR = 0x80410702,
ERROR_NET_ADHOC_INVALID_ARG = 0x80410B04,
ERROR_NET_ADHOC_NO_DATA_AVAILABLE = 0x80410709,
ERROR_NET_ADHOC_PORT_IN_USE = 0x8041070a,
ERROR_NET_ADHOC_NOT_INITIALIZED = 0x80410712,
ERROR_NET_ADHOC_ALREADY_INITIALIZED = 0x80410713,
ERROR_NET_ADHOC_DISCONNECTED = 0x8041070c,
ERROR_NET_ADHOC_TIMEOUT = 0x80410715,
ERROR_NET_ADHOC_NO_ENTRY = 0x80410716,
ERROR_NET_ADHOC_CONNECTION_REFUSED = 0x80410718,
ERROR_NET_ADHOC_INVALID_MATCHING_ID = 0x80410807,
ERROR_NET_ADHOC_MATCHING_ALREADY_INITIALIZED = 0x80410812,
ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED = 0x80410813,
ERROR_NET_ADHOC_WOULD_BLOCK = 0x80410709,
ERROR_NET_ADHOC_INVALID_DATALEN = 0x80410705,
ERROR_NET_ADHOC_INVALID_PORT = 0x80410703,
ERROR_NET_ADHOCCTL_INVALID_ARG = 0x80410B04,
ERROR_NET_ADHOCCTL_WLAN_SWITCH_OFF = 0x80410b03,
ERROR_NET_ADHOCCTL_ALREADY_INITIALIZED = 0x80410b07,
ERROR_NET_ADHOCCTL_NOT_INITIALIZED = 0x80410b08,
ERROR_NET_ADHOCCTL_DISCONNECTED = 0x80410b09,
ERROR_NET_ADHOCCTL_BUSY = 0x80410b10,
ERROR_NET_ADHOCCTL_TOO_MANY_HANDLERS = 0x80410b12,
ERROR_NET_ADHOC_MATCHING_INVALID_MODE = 0x80410801,
ERROR_NET_ADHOC_MATCHING_INVALID_MAXNUM = 0x80410803,
ERROR_NET_ADHOC_MATCHING_RXBUF_TOO_SHORT = 0x80410804,
ERROR_NET_ADHOC_MATCHING_INVALID_OPTLEN = 0x80410805,
ERROR_NET_ADHOC_MATCHING_INVALID_ARG = 0x80410806,
ERROR_NET_ADHOC_MATCHING_INVALID_ID = 0x80410807,
ERROR_NET_ADHOC_MATCHING_ID_NOT_AVAIL = 0x80410808,
ERROR_NET_ADHOC_MATCHING_NO_SPACE = 0x80410809,
ERROR_NET_ADHOC_MATCHING_IS_RUNNING = 0x8041080A,
ERROR_NET_ADHOC_MATCHING_NOT_RUNNING = 0x8041080B,
ERROR_NET_ADHOC_MATCHING_UNKNOWN_TARGET = 0x8041080C,
ERROR_NET_ADHOC_MATCHING_TARGET_NOT_READY = 0x8041080D,
ERROR_NET_ADHOC_MATCHING_EXCEED_MAXNUM = 0x8041080E,
ERROR_NET_ADHOC_MATCHING_REQUEST_IN_PROGRESS = 0x8041080F,
ERROR_NET_ADHOC_MATCHING_ALREADY_ESTABLISHED = 0x80410810,
ERROR_NET_ADHOC_MATCHING_BUSY = 0x80410811,
ERROR_NET_ADHOC_MATCHING_PORT_IN_USE = 0x80410814,
ERROR_NET_ADHOC_MATCHING_STACKSIZE_TOO_SHORT = 0x80410815,
ERROR_NET_ADHOC_MATCHING_INVALID_DATALEN = 0x80410816,
ERROR_NET_ADHOC_MATCHING_NOT_ESTABLISHED = 0x80410817,
ERROR_NET_ADHOC_MATCHING_DATA_BUSY = 0x80410818,
ERROR_NET_NO_SPACE = 0x80410001
};
int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 unknown);
enum {
PSP_ADHOC_POLL_READY_TO_SEND = 1,
PSP_ADHOC_POLL_DATA_AVAILABLE = 2,
PSP_ADHOC_POLL_CAN_CONNECT = 4,
PSP_ADHOC_POLL_CAN_ACCEPT = 8,
};
const size_t MAX_ADHOCCTL_HANDLERS = 32;
static bool netAdhocInited;
static bool netAdhocctlInited;
static bool netAdhocMatchingInited;
// psp strutcs and definitions
#define ADHOCCTL_MODE_ADHOC 0
#define ADHOCCTL_MODE_GAMEMODE 1
// Event Types for Event Handler
#define ADHOCCTL_EVENT_CONNECT 1
#define ADHOCCTL_EVENT_DISCONNECT 2
#define ADHOCCTL_EVENT_SCAN 3
// Internal Thread States
#define ADHOCCTL_STATE_DISCONNECTED 0
#define ADHOCCTL_STATE_CONNECTED 1
#define ADHOCCTL_STATE_SCANNING 2
#define ADHOCCTL_STATE_GAMEMODE 3
// Kernel Utility Netconf Adhoc Types
#define UTILITY_NETCONF_TYPE_CONNECT_ADHOC 2
#define UTILITY_NETCONF_TYPE_CREATE_ADHOC 4
#define UTILITY_NETCONF_TYPE_JOIN_ADHOC 5
// Kernel Utility States
#define UTILITY_NETCONF_STATUS_NONE 0
#define UTILITY_NETCONF_STATUS_INITIALIZE 1
#define UTILITY_NETCONF_STATUS_RUNNING 2
#define UTILITY_NETCONF_STATUS_FINISHED 3
#define UTILITY_NETCONF_STATUS_SHUTDOWN 4
// Ethernet Address
#define ETHER_ADDR_LEN 6
typedef struct SceNetEtherAddr {
uint8_t data[ETHER_ADDR_LEN];
} __attribute__((packed)) SceNetEtherAddr;
// Adhoc ID (Game Product Key)
#define ADHOCCTL_ADHOCID_LEN 9
typedef struct SceNetAdhocctlAdhocId {
int type;
uint8_t data[ADHOCCTL_ADHOCID_LEN];
uint8_t padding[3];
} SceNetAdhocctlAdhocId;
// Adhoc Virtual Network Name
#define ADHOCCTL_GROUPNAME_LEN 8
typedef struct SceNetAdhocctlGroupName {
uint8_t data[ADHOCCTL_GROUPNAME_LEN];
} __attribute__((packed)) SceNetAdhocctlGroupName;
// Virtual Network Host Information
typedef struct SceNetAdhocctlBSSId {
SceNetEtherAddr mac_addr;
uint8_t padding[2];
} __attribute__((packed)) SceNetAdhocctlBSSId;
// Virtual Network Information
typedef struct SceNetAdhocctlScanInfo {
struct SceNetAdhocctlScanInfo * next;
int channel;
SceNetAdhocctlGroupName group_name;
SceNetAdhocctlBSSId bssid;
int mode;
} __attribute__((packed)) SceNetAdhocctlScanInfo;
// Player Nickname
#define ADHOCCTL_NICKNAME_LEN 128
typedef struct SceNetAdhocctlNickname {
uint8_t data[ADHOCCTL_NICKNAME_LEN];
} __attribute__((packed)) SceNetAdhocctlNickname;
// Active Virtual Network Information
typedef struct SceNetAdhocctlParameter {
int channel;
SceNetAdhocctlGroupName group_name;
SceNetAdhocctlBSSId bssid;
SceNetAdhocctlNickname nickname;
} __attribute__((packed)) SceNetAdhocctlParameter;
// Peer Information
typedef struct SceNetAdhocctlPeerInfo {
SceNetAdhocctlPeerInfo * next;
SceNetAdhocctlNickname nickname;
SceNetEtherAddr mac_addr;
uint32_t ip_addr;
uint8_t padding[2];
uint64_t last_recv;
} __attribute__((packed)) SceNetAdhocctlPeerInfo;
// Game Mode Peer List
#define ADHOCCTL_GAMEMODE_MAX_MEMBERS 16
typedef struct SceNetAdhocctlGameModeInfo {
int num;
SceNetEtherAddr member[ADHOCCTL_GAMEMODE_MAX_MEMBERS];
} __attribute__((packed)) SceNetAdhocctlGameModeInfo;
// Ethernet Address (MAC)
// Socket Polling Event Listener
typedef struct SceNetAdhocPollSd {
int id;
int events;
int revents;
};
// PDP Socket Status
typedef struct SceNetAdhocPdpStat {
struct SceNetAdhocPdpStat * next;
int id;
SceNetEtherAddr laddr;
uint16_t lport;
uint32_t rcv_sb_cc;
};
// PTP Socket Status
typedef struct SceNetAdhocPtpStat {
struct SceNetAdhocPtpStat * next;
int id;
SceNetEtherAddr laddr;
SceNetEtherAddr paddr;
uint16_t lport;
uint16_t pport;
uint32_t snd_sb_cc;
uint32_t rcv_sb_cc;
int state;
};
// Gamemode Optional Peer Buffer Data
typedef struct SceNetAdhocGameModeOptData {
uint32_t size;
uint32_t flag;
uint64_t last_recv;
};
// Gamemode Buffer Status
typedef struct SceNetAdhocGameModeBufferStat {
struct SceNetAdhocGameModeBufferStat * next;
int id;
void * ptr;
uint32_t size;
uint32_t master;
SceNetAdhocGameModeOptData opt;
};
// Matching Peer Information
typedef struct SceNetAdhocMatchingMember {
struct SceNetAdhocMatchingMember * next;
SceNetEtherAddr addr;
uint8_t padding[2];
} __attribute__((packed)) SceNetAdhocMatchingMember;
// Internal Matching Peer Information
typedef struct SceNetAdhocMatchingMemberInternal {
// Next Peer
struct SceNetAdhocMatchingMemberInternal * next;
// MAC Address
SceNetEtherAddr mac;
// State Variable
int state;
// Send in Progress
int sending;
// Last Heartbeat
uint64_t lastping;
} SceNetAdhocMatchingMemberInternal;
// Matching handler
struct SceNetAdhocMatchingHandlerArgs {
int id;
int event;
SceNetEtherAddr * peer;
int optlen;
void * opt;
};
struct SceNetAdhocMatchingHandler {
u32 entryPoint;
};
// Thread Message Stack Item
typedef struct ThreadMessage
{
// Next Thread Message
struct ThreadMessage * next;
// Stack Event Opcode
uint32_t opcode;
// Target MAC Address
SceNetEtherAddr mac;
// Optional Data Length
int optlen;
} ThreadMessage;
// Established Peer
// Context Information
typedef struct SceNetAdhocMatchingContext {
// Next Context
struct SceNetAdhocMatchingContext * next;
// Externally Visible ID
int id;
// Matching Mode (HOST, CLIENT, P2P)
int mode;
// Running Flag (1 = running, 0 = created)
int running;
// Maximum Number of Peers (for HOST, P2P)
int maxpeers;
// Local MAC Address
SceNetEtherAddr mac;
// Peer List for Connectees
SceNetAdhocMatchingMemberInternal * peerlist;
// Local PDP Port
uint16_t port;
// Local PDP Socket
int socket;
// Receive Buffer Length
int rxbuflen;
// Receive Buffer
uint8_t * rxbuf;
// Hello Broadcast Interval (Microseconds)
uint32_t hello_int;
// Keep-Alive Broadcast Interval (Microseconds)
uint32_t keepalive_int;
// Resend Interval (Microseconds)
uint32_t resend_int;
// Resend-Counter
int resendcounter;
// Keep-Alive Counter
int keepalivecounter;
// Event Handler
SceNetAdhocMatchingHandler handler;
// Hello Data Length
uint32_t hellolen;
// Hello Data
void * hello;
// Event Caller Thread
int event_thid;
// IO Handler Thread
int input_thid;
// Event Caller Thread Message Stack
int event_stack_lock;
ThreadMessage * event_stack;
// IO Handler Thread Message Stack
int input_stack_lock;
ThreadMessage * input_stack;
} SceNetAdhocMatchingContext;
// End of psp definitions
#define OPCODE_PING 0
#define OPCODE_LOGIN 1
#define OPCODE_CONNECT 2
#define OPCODE_DISCONNECT 3
#define OPCODE_SCAN 4
#define OPCODE_SCAN_COMPLETE 5
#define OPCODE_CONNECT_BSSID 6
#define OPCODE_CHAT 7
// PSP Product Code
#define PRODUCT_CODE_LENGTH 9
typedef struct
{
// Game Product Code (ex. ULUS12345)
char data[PRODUCT_CODE_LENGTH];
} __attribute__((packed)) SceNetAdhocctlProductCode;
// Basic Packet
typedef struct
{
uint8_t opcode;
} __attribute__((packed)) SceNetAdhocctlPacketBase;
// C2S Login Packet
typedef struct
{
SceNetAdhocctlPacketBase base;
SceNetEtherAddr mac;
SceNetAdhocctlNickname name;
SceNetAdhocctlProductCode game;
} __attribute__((packed)) SceNetAdhocctlLoginPacketC2S;
// C2S Connect Packet
typedef struct
{
SceNetAdhocctlPacketBase base;
SceNetAdhocctlGroupName group;
} __attribute__((packed)) SceNetAdhocctlConnectPacketC2S;
// C2S Chat Packet
typedef struct
{
SceNetAdhocctlPacketBase base;
char message[64];
} __attribute__((packed)) SceNetAdhocctlChatPacketC2S;
// S2C Connect Packet
typedef struct
{
SceNetAdhocctlPacketBase base;
SceNetAdhocctlNickname name;
SceNetEtherAddr mac;
uint32_t ip;
} __attribute__((packed)) SceNetAdhocctlConnectPacketS2C;
// S2C Disconnect Packet
typedef struct
{
SceNetAdhocctlPacketBase base;
uint32_t ip;
} __attribute__((packed)) SceNetAdhocctlDisconnectPacketS2C;
// S2C Scan Packet
typedef struct
{
SceNetAdhocctlPacketBase base;
SceNetAdhocctlGroupName group;
SceNetEtherAddr mac;
} __attribute__((packed)) SceNetAdhocctlScanPacketS2C;
// S2C Connect BSSID Packet
typedef struct
{
SceNetAdhocctlPacketBase base;
SceNetEtherAddr mac;
} __attribute__((packed)) SceNetAdhocctlConnectBSSIDPacketS2C;
// S2C Chat Packet
typedef struct
{
SceNetAdhocctlChatPacketC2S base;
SceNetAdhocctlNickname name;
} __attribute__((packed)) SceNetAdhocctlChatPacketS2C;
// Aux vars
static int metasocket;
static int eventHandlerUpdate = -1;
static int threadStatus = ADHOCCTL_STATE_DISCONNECTED;
static SceNetAdhocctlParameter parameter;
static std::thread friendFinderThread;
static SceNetAdhocctlPeerInfo * friends = NULL;
static SceNetAdhocctlScanInfo * networks = NULL;
static std::mutex peerlock;
static SceNetAdhocPdpStat * pdp[255];
static SceNetAdhocPtpStat * ptp[255];
static uint32_t fakePoolSize = 0;
static SceNetAdhocMatchingContext * contexts = NULL;
// End of Aux vars
struct AdhocctlHandler {
u32 entryPoint;
u32 argument;
};
static std::map<int, AdhocctlHandler> adhocctlHandlers;
void __NetAdhocInit() {
netAdhocInited = false;
netAdhocctlInited = false;
netAdhocMatchingInited = false;
adhocctlHandlers.clear();
}
void __NetAdhocShutdown() {
}
void __NetAdhocDoState(PointerWrap &p) {
auto s = p.Section("sceNetAdhoc", 1);
if (!s)
return;
p.Do(netAdhocInited);
p.Do(netAdhocctlInited);
p.Do(netAdhocMatchingInited);
p.Do(adhocctlHandlers);
}
void __UpdateAdhocctlHandlers(int flag, int error) {
u32 args[3] = { 0, 0, 0 };
args[0] = flag;
args[1] = error;
for (std::map<int, AdhocctlHandler>::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); ++it) {
args[2] = it->second.argument;
__KernelDirectMipsCall(it->second.entryPoint, NULL, args, 3, true);
}
}
#define firstMask 0x00000000FFFFFFFF
#define secondMask 0xFFFFFFFF00000000
void split64(u64 num, int buff[]){
int num1 = (int)(num&firstMask);
int num2 = (int)((num&secondMask)>>32);
buff[0] = num1;
buff[1] = num2;
}
u64 join32(u32 num1, u32 num2){
return (u64)num2 << 32 | num1;
}
// Gets the local mac TODO: Read from config
void __getLocalMac(SceNetEtherAddr * addr){
uint8_t mac[] = {1, 2, 3, 4, 5, 6};
memcpy(addr,mac,ETHER_ADDR_LEN);
}
// This only usefull if the server is running on the same machine as the client
int __getLocalIp(sockaddr_in * SocketAddress){
#ifdef _WIN32
// Get local host name
char szHostName[128] = "";
if(::gethostname(szHostName, sizeof(szHostName))) {
// Error handling
}
// Get local IP addresses
struct hostent *pHost = 0;
pHost = ::gethostbyname(szHostName);
if(pHost) {
memcpy(&SocketAddress->sin_addr, pHost->h_addr_list[0], pHost->h_length);
return 0;
}
return -1;
#else
char ip[] = "192.168.12.1";
SocketAddress->sin_addr.s_addr = inet_addr("192.168.12.1");
return 0;
#endif
}
// Returns current system time in miliseconds, windows only!
long long __milliseconds_now() {
#ifdef _WIN32
static LARGE_INTEGER s_frequency;
static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
if (s_use_qpc) {
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (1000LL * now.QuadPart) / s_frequency.QuadPart;
} else {
return GetTickCount();
}
#else
timeval val;
gettimeofday(&val,NULL);
return val.tv_usec * 1000;
#endif
}
/* chages to the blocking mode of the socket
1 to set noblocking
0 to set blocking
*/
void __change_blocking_mode(int fd, int nonblocking) {
unsigned long on = 1;
unsigned long off = 0;
#ifdef _WIN32
if(nonblocking){
// Change to Non-Blocking Mode
ioctlsocket(fd,FIONBIO,&on);
}else {
// Change to Blocking Mode
ioctlsocket(fd, FIONBIO, &off);
}
#else
if(nonblocking) fcntl(fd, F_SETFL, O_NONBLOCK);
else {
// Get Flags
int flags = fcntl(fd, F_GETFL);
// Remove Non-Blocking Flag
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
}
#endif
}
// Inits all basic net functionality and logins the user to the main server
int __init_network(SceNetAdhocctlAdhocId *adhoc_id){
int iResult = 0;
#ifdef _WIN32
WSADATA data;
iResult = WSAStartup(MAKEWORD(2,2),&data);
if(iResult != NOERROR){
printf("Wsa failed with error %d\n",iResult);
return iResult;
}
#endif
metasocket = INVALID_SOCKET;
metasocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
if(metasocket == INVALID_SOCKET){
printf("invalid socket");
return INVALID_SOCKET;
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(27312);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
iResult = connect(metasocket,(sockaddr *)&server_addr,sizeof(server_addr));
if(iResult == SOCKET_ERROR){
printf("Socket error %d", iResult);
return iResult;
}
memset(&parameter,0,sizeof(parameter));
strcpy((char *)&parameter.nickname.data, g_Config.sNickName.c_str());
parameter.channel = 1; // Fake Channel 1
__getLocalMac(&parameter.bssid.mac_addr);
SceNetAdhocctlLoginPacketC2S packet;
packet.base.opcode = OPCODE_LOGIN;
SceNetEtherAddr addres;
__getLocalMac(&addres);
packet.mac = addres;
strcpy((char *)packet.name.data, g_Config.sNickName.c_str());
memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
int sent = send(metasocket, (char*)&packet, sizeof(packet), 0);
__change_blocking_mode(metasocket,1); // Change to non-blocking
if(sent > 0){
return 0;
}else{
return -1;
}
}
/**
* Add Friend to Local List
* @param packet Friend Information
*/
void __addFriend(SceNetAdhocctlConnectPacketS2C * packet) {
// Allocate Structure
SceNetAdhocctlPeerInfo * peer = (SceNetAdhocctlPeerInfo *)malloc(sizeof(SceNetAdhocctlPeerInfo));
// Allocated Structure
if(peer != NULL)
{
// Clear Memory
memset(peer, 0, sizeof(SceNetAdhocctlPeerInfo));
// Link to existing Peers
peer->next = friends;
// Save Nickname
peer->nickname = packet->name;
// Save MAC Address
peer->mac_addr = packet->mac;
// Save IP Address
peer->ip_addr = packet->ip;
// Multithreading Lock
peerlock.lock();
// Link into Peerlist
friends = peer;
// Multithreading Unlock
peerlock.unlock();
}
}
/**
* Delete Friend from Local List
* @param ip Friend IP
*/
void __deleteFriendByIP(uint32_t ip) {
// Previous Peer Reference
SceNetAdhocctlPeerInfo * prev = NULL;
// Peer Pointer
SceNetAdhocctlPeerInfo * peer = friends;
// Iterate Peers
for(; peer != NULL; peer = peer->next)
{
// Found Peer
if(peer->ip_addr == ip)
{
// Multithreading Lock
peerlock.lock();
// Unlink Left (Beginning)
if(prev == NULL)friends = peer->next;
// Unlink Left (Other)
else prev->next = peer->next;
// Multithreading Unlock
peerlock.unlock();
// Free Memory
free(peer);
// Stop Search
break;
}
// Set Previous Reference
prev = peer;
}
}
/**
* Recursive Memory Freeing-Helper for Friend-Structures
* @param node Current Node in List
*/
void __freeFriendsRecursive(SceNetAdhocctlPeerInfo * node) {
// End of List
if(node == NULL) return;
// Increase Recursion Depth
__freeFriendsRecursive(node->next);
// Free Memory
free(node);
}
// Thread that listens to all relevant messages from the server
int __friendFinder(){
// Receive Buffer
int rxpos = 0;
uint8_t rx[1024];
// Chat Packet
SceNetAdhocctlChatPacketC2S chat;
chat.base.opcode = OPCODE_CHAT;
// Last Ping Time
long long lastping = 0;
// Last Time Reception got updated
uint64_t lastreceptionupdate = 0;
// Finder Loop
while(netAdhocctlInited) {
// Acquire Network Lock
//_acquireNetworkLock();
// Ping Server
if(__milliseconds_now() - lastping >= 100) {
// Update Ping Time
lastping = __milliseconds_now();
// Prepare Packet
uint8_t opcode = OPCODE_PING;
// Send Ping to Server
send(metasocket, (const char *)&opcode, 1,0);
}
// Send Chat Messages
//while(popFromOutbox(chat.message))
//{
// // Send Chat to Server
// sceNetInetSend(metasocket, (const char *)&chat, sizeof(chat), 0);
//}
// Wait for Incoming Data
int received = recv(metasocket, (char *)(rx + rxpos), sizeof(rx) - rxpos,0);
// 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
if(rxpos > 0) {
// BSSID Packet
if(rx[0] == OPCODE_CONNECT_BSSID) {
// Enough Data available
if(rxpos >= sizeof(SceNetAdhocctlConnectBSSIDPacketS2C)) {
// Cast Packet
SceNetAdhocctlConnectBSSIDPacketS2C * packet = (SceNetAdhocctlConnectBSSIDPacketS2C *)rx;
// Update BSSID
parameter.bssid.mac_addr = packet->mac;
// Change State
threadStatus = ADHOCCTL_STATE_CONNECTED;
// Notify Event Handlers
CoreTiming::ScheduleEvent_Threadsafe_Immediate(eventHandlerUpdate, join32(ADHOCCTL_EVENT_CONNECT, 0));
// Move RX Buffer
memmove(rx, rx + sizeof(SceNetAdhocctlConnectBSSIDPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectBSSIDPacketS2C));
// Fix RX Buffer Length
rxpos -= sizeof(SceNetAdhocctlConnectBSSIDPacketS2C);
}
}
// Chat Packet
else if(rx[0] == OPCODE_CHAT) {
// Enough Data available
if(rxpos >= sizeof(SceNetAdhocctlChatPacketS2C)) {
// Cast Packet
SceNetAdhocctlChatPacketS2C * packet = (SceNetAdhocctlChatPacketS2C *)rx;
// Fix for Idiots that try to troll the "ME" Nametag
#ifdef _WIN32
if(stricmp((char *)packet->name.data, "ME") == 0) strcpy((char *)packet->name.data, "NOT ME");
#else
if(strcasecmp((char *)packet->name.data, "ME") == 0) strcpy((char *)packet->name.data, "NOT ME");
#endif
// Add Incoming Chat to HUD
//printf("Receive chat message %s", packet->base.message);
// Move RX Buffer
memmove(rx, rx + sizeof(SceNetAdhocctlChatPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlChatPacketS2C));
// Fix RX Buffer Length
rxpos -= sizeof(SceNetAdhocctlChatPacketS2C);
}
}
// Connect Packet
else if(rx[0] == OPCODE_CONNECT) {
// Enough Data available
if(rxpos >= sizeof(SceNetAdhocctlConnectPacketS2C)) {
// Log Incoming Peer
INFO_LOG(SCENET,"Incoming Peer Data...\n");
// Cast Packet
SceNetAdhocctlConnectPacketS2C * packet = (SceNetAdhocctlConnectPacketS2C *)rx;
// Add User
__addFriend(packet);
// Update HUD User Count
#ifdef LOCALHOST_AS_PEER
setUserCount(_getActivePeerCount());
#else
//setUserCount(_getActivePeerCount()+1);
#endif
// Move RX Buffer
memmove(rx, rx + sizeof(SceNetAdhocctlConnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectPacketS2C));
// Fix RX Buffer Length
rxpos -= sizeof(SceNetAdhocctlConnectPacketS2C);
}
}
// Disconnect Packet
else if(rx[0] == OPCODE_DISCONNECT) {
// Enough Data available
if(rxpos >= sizeof(SceNetAdhocctlDisconnectPacketS2C)) {
// Log Incoming Peer Delete Request
INFO_LOG(SCENET,"FriendFinder: Incoming Peer Data Delete Request...\n");
// Cast Packet
SceNetAdhocctlDisconnectPacketS2C * packet = (SceNetAdhocctlDisconnectPacketS2C *)rx;
// Delete User by IP
__deleteFriendByIP(packet->ip);
// Update HUD User Count
#ifdef LOCALHOST_AS_PEER
setUserCount(_getActivePeerCount());
#else
//setUserCount(_getActivePeerCount()+1);
#endif
// Move RX Buffer
memmove(rx, rx + sizeof(SceNetAdhocctlDisconnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlDisconnectPacketS2C));
// Fix RX Buffer Length
rxpos -= sizeof(SceNetAdhocctlDisconnectPacketS2C);
}
}
// Scan Packet
else if(rx[0] == OPCODE_SCAN) {
// Enough Data available
if(rxpos >= sizeof(SceNetAdhocctlScanPacketS2C)) {
// Log Incoming Network Information
INFO_LOG(SCENET,"Incoming Group Information...\n");
// Cast Packet
SceNetAdhocctlScanPacketS2C * packet = (SceNetAdhocctlScanPacketS2C *)rx;
// Allocate Structure Data
SceNetAdhocctlScanInfo * group = (SceNetAdhocctlScanInfo *)malloc(sizeof(SceNetAdhocctlScanInfo));
// Allocated Structure Data
if(group != NULL)
{
// Clear Memory
memset(group, 0, sizeof(SceNetAdhocctlScanInfo));
// Link to existing Groups
group->next = networks;
// Copy Group Name
group->group_name = packet->group;
// Set Group Host
group->bssid.mac_addr = packet->mac;
// Link into Group List
networks = group;
}
// 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) {
// Log Scan Completion
INFO_LOG(SCENET,"FriendFinder: Incoming Scan complete response...\n");
// Change State
threadStatus = ADHOCCTL_STATE_DISCONNECTED;
// Notify Event Handlers
CoreTiming::ScheduleEvent_Threadsafe_Immediate(eventHandlerUpdate,join32(ADHOCCTL_EVENT_SCAN, 0));
//int i = 0; for(; i < ADHOCCTL_MAX_HANDLER; i++)
//{
// // Active Handler
// if(_event_handler[i] != NULL) _event_handler[i](ADHOCCTL_EVENT_SCAN, 0, _event_args[i]);
//}
// Move RX Buffer
memmove(rx, rx + 1, sizeof(rx) - 1);
// Fix RX Buffer Length
rxpos -= 1;
}
}
// Delay Thread (10ms)
#ifdef _WIN32
Sleep(10);
#else
sleep(10);
#endif
}
// Log Shutdown
INFO_LOG(SCENET, "FriendFinder: End of Friend Finder Thread\n");
// Return Success
return 0;
}
/**
* Check whether Network Name contains only valid symbols
* @param group_name To-be-checked Network Name
* @return 1 if valid or... 0
*/
int __validNetworkName(const SceNetAdhocctlGroupName * group_name) {
// Result
int valid = 1;
// Name given
if(group_name != NULL) {
// Iterate Name Characters
int i = 0; for(; i < ADHOCCTL_GROUPNAME_LEN && valid; i++) {
// End of Name
if(group_name->data[i] == 0) break;
// Not a digit
if(group_name->data[i] < '0' || group_name->data[i] > '9') {
// Not 'A' to 'Z'
if(group_name->data[i] < 'A' || group_name->data[i] > 'Z') {
// Not 'a' to 'z'
if(group_name->data[i] < 'a' || group_name->data[i] > 'z') {
// Invalid Name
valid = 0;
}
}
}
}
}
// Return Result
return valid;
}
/**
* Local MAC Check
* @param saddr To-be-checked MAC Address
* @return 1 if valid or... 0
*/
int _IsLocalMAC(const SceNetEtherAddr * addr) {
// Get Local MAC Address
SceNetEtherAddr saddr;
__getLocalMac(&saddr);
//sceNetGetLocalEtherAddr(&saddr);
// Compare MAC Addresses
int match = memcmp((const void *)addr, (const void *)&saddr, ETHER_ADDR_LEN);
// Return Result
return (match == 0);
}
/**
* Resolve IP to MAC
* @param ip Peer IP Address
* @param mac OUT: Peer MAC
* @return 0 on success or... ADHOC_NO_ENTRY
*/
int __resolveIP(uint32_t ip, SceNetEtherAddr * mac) {
sockaddr_in addr;
__getLocalIp(&addr);
uint32 localIp = addr.sin_addr.s_addr;
if(ip == localIp){
__getLocalMac(mac);
return 0;
}
// Multithreading Lock
peerlock.lock();
// Peer Reference
SceNetAdhocctlPeerInfo * peer = friends;
// Iterate Peers
for(; peer != NULL; peer = peer->next) {
// Found Matching Peer
if(peer->ip_addr == ip) {
// Copy Data
*mac = peer->mac_addr;
// Multithreading Unlock
peerlock.unlock();
// Return Success
return 0;
}
}
// Multithreading Unlock
peerlock.unlock();
// Peer not found
return ERROR_NET_ADHOC_NO_ENTRY;
}
/**
* Resolve MAC to IP
* @param mac Peer MAC Address
* @param ip OUT: Peer IP
* @return 0 on success or... ADHOC_NO_ENTRY
*/
int __resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) {
// Get Local MAC Address
SceNetEtherAddr localMac;
__getLocalMac(&localMac);
// Local MAC Requested
if(memcmp(&localMac, mac, sizeof(SceNetEtherAddr)) == 0) {
// Get Local IP Address
sockaddr_in sockAddr;
__getLocalIp(&sockAddr);
*ip = sockAddr.sin_addr.s_addr;
return 0; // return succes
}
// Multithreading Lock
peerlock.lock();
// Peer Reference
SceNetAdhocctlPeerInfo * peer = friends;
// Iterate Peers
for(; peer != NULL; peer = peer->next) {
// Found Matching Peer
if(memcmp(&peer->mac_addr, mac, sizeof(SceNetEtherAddr)) == 0) {
// Copy Data
*ip = peer->ip_addr;
// Multithreading Unlock
peerlock.unlock();
// Return Success
return 0;
}
}
// Multithreading Unlock
peerlock.unlock();
// Peer not found
return ERROR_NET_ADHOC_NO_ENTRY;
}
/**
* PDP Port Check
* @param port To-be-checked Port
* @return 1 if in use or... 0
*/
int _IsPDPPortInUse(uint16_t port) {
// Iterate Elements
int i = 0; for(; i < 255; i++) if(pdp[i] != NULL && pdp[i]->lport == port) return 1;
// Unused Port
return 0;
}
/**
* Broadcast MAC Check
* @param addr To-be-checked MAC Address
* @return 1 if Broadcast MAC or... 0
*/
int __isBroadcastMAC(const SceNetEtherAddr * addr) {
// Broadcast MAC
if(memcmp(addr->data, "\xFF\xFF\xFF\xFF\xFF\xFF", ETHER_ADDR_LEN) == 0) return 1;
// Normal MAC
return 0;
}
/**
* Closes & Deletes all PDP Sockets
*/
void __deleteAllPDP(void) {
// Iterate Element
int i = 0; for(; i < 255; i++) {
// Active Socket
if(pdp[i] != NULL) {
// Close Socket
closesocket(pdp[i]->id);
// Free Memory
free(pdp[i]);
// Delete Reference
pdp[i] = NULL;
}
}
}
/**
* Closes & Deletes all PTP Sockets
*/
void __deleteAllPTP(void) {
// Iterate Element
int i = 0; for(; i < 255; i++) {
// Active Socket
if(ptp[i] != NULL) {
// Close Socket
closesocket(ptp[i]->id);
// Free Memory
free(ptp[i]);
// Delete Reference
ptp[i] = NULL;
}
}
}
/**
* Count Virtual Networks by analyzing the Friend List
* @return Number of Virtual Networks
*/
int __countAvailableNetworks(void) {
// Network Count
int count = 0;
// Group Reference
SceNetAdhocctlScanInfo * group = networks;
// Count Groups
for(; group != NULL; group = group->next) count++;
// Return Network Count
return count;
}
/**
* Return Number of active Peers in the same Network as the Local Player
* @return Number of active Peers
*/
int __getActivePeerCount(void) {
// Counter
int count = 0;
// #ifdef LOCALHOST_AS_PEER
// // Increase for Localhost
// count++;
// #endif
// Peer Reference
SceNetAdhocctlPeerInfo * peer = friends;
// Iterate Peers
for(; peer != NULL; peer = peer->next) {
// Increase Counter
count++;
}
// Return Result
return count;
}
/**
* Find Internal Matching Context for Matching ID
* @param id Matching ID
* @return Matching Context Pointer or... NULL
*/
SceNetAdhocMatchingContext * __findMatchingContext(int id) {
// Iterate Matching Context List
SceNetAdhocMatchingContext * item = contexts; for(; item != NULL; item = item->next) {
// Found Matching ID
if(item->id == id) return item;
}
// Context not found
return NULL;
}
/**
* Find Free Matching ID
* @return First unoccupied Matching ID
*/
int __findFreeMatchingID(void) {
// Minimum Matching ID
int min = 1;
// Maximum Matching ID
int max = 0;
// Find highest Matching ID
SceNetAdhocMatchingContext * item = contexts; for(; item != NULL; item = item->next) {
// New Maximum
if(max < item->id) max = item->id;
}
// Find unoccupied ID
int i = min; for(; i < max; i++) {
// Found unoccupied ID
if(__findMatchingContext(i) == NULL) return i;
}
// Append at virtual end
return max + 1;
}
void __handlerUpdateCallback(u64 userdata, int cycleslate){
int buff[2];
split64(userdata,buff);
__UpdateAdhocctlHandlers(buff[0], buff[1]);
}
u32 sceNetAdhocInit() {
// Library uninitialized
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocInit()");
if(!netAdhocInited) {
// Clear Translator Memory
memset(&pdp, 0, sizeof(pdp));
memset(&ptp, 0, sizeof(ptp));
// Library initialized
netAdhocInited = true;
// Return Success
return 0;
}
// Already initialized
return ERROR_NET_ADHOC_ALREADY_INITIALIZED;
}
u32 sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlInit(%i, %i, %08x)", stackSize, prio, productAddr);
if (netAdhocctlInited) {
return ERROR_NET_ADHOCCTL_ALREADY_INITIALIZED;
}else{
if(__init_network((SceNetAdhocctlAdhocId *)Memory::GetPointer(productAddr)) == 0){
netAdhocctlInited = true;
eventHandlerUpdate = CoreTiming::RegisterEvent("HandlerUpdateEvent", __handlerUpdateCallback);
friendFinderThread = std::thread(__friendFinder);
}else{
return -1; // Generic error
}
}
return 0;
}
// Seems to always return 0, and write 0 to the pointer..
// TODO: Eventually research what possible states there are
int sceNetAdhocctlGetState(u32 ptrToStatus) {
// Library initialized
if(netAdhocctlInited) {
// Valid Arguments
if(Memory::IsValidAddress(ptrToStatus)) {
// Return Thread Status
Memory::Write_U32(threadStatus,ptrToStatus);
// Return Success
return 0;
}
// Invalid Arguments
return ERROR_NET_ADHOCCTL_INVALID_ARG;
}
// Library uninitialized
return ERROR_NET_ADHOCCTL_NOT_INITIALIZED;
}
/**
* Adhoc Emulator PDP Socket Creator
* @param saddr Local MAC (Unused)
* @param sport Local Binding Port
* @param bufsize Socket Buffer Size
* @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
*/
int sceNetAdhocPdpCreate(const char *mac, u32 port, int bufferSize, u32 unknown) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPdpCreate(%s, %x, %x, %x)", mac, port, bufferSize, unknown);
// Library is initialized
SceNetEtherAddr * saddr = (SceNetEtherAddr *)mac;
if(netAdhocInited) {
// Valid Arguments are supplied
if(mac != NULL && bufferSize > 0) {
// Valid MAC supplied
if(_IsLocalMAC(saddr)) {
//// Unused Port supplied
//if(!_IsPDPPortInUse(port)) {}
//
//// Port is in use by another PDP Socket
//return ERROR_NET_ADHOC_PORT_IN_USE;
// Create Internet UDP Socket
int usocket = INVALID_SOCKET;
usocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// Valid Socket produced
if(usocket != INVALID_SOCKET) {
// Enable Port Re-use
//setsockopt(usocket, SOL_SOCKET, SO_REUSEADDR, &_one, sizeof(_one)); NO idea if we need this
// Binding Information for local Port
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port); //This not safe in any way...
// Bound Socket to local Port
if(bind(usocket, (sockaddr *)&addr, sizeof(addr)) == 0) {
// Allocate Memory for Internal Data
SceNetAdhocPdpStat * internal = (SceNetAdhocPdpStat *)malloc(sizeof(SceNetAdhocPdpStat));
// Allocated Memory
if(internal != NULL) {
// Clear Memory
memset(internal, 0, sizeof(SceNetAdhocPdpStat));
// Find Free Translator Index
int i = 0; for(; i < 255; i++) if(pdp[i] == NULL) break;
// Found Free Translator Index
if(i < 255) {
// Fill in Data
internal->id = usocket;
internal->laddr = *saddr;
internal->lport = port;
internal->rcv_sb_cc = bufferSize;
// Link Socket to Translator ID
pdp[i] = internal;
// Forward Port on Router
//sceNetPortOpen("UDP", sport); // I need to figure out how to use this in windows/linux
// Success
return i + 1;
}
// Free Memory for Internal Data
free(internal);
}
}
// Close Socket
closesocket(usocket);
}
// Default to No-Space Error
return ERROR_NET_NO_SPACE;
}
// Invalid MAC supplied
return ERROR_NET_ADHOC_INVALID_ADDR;
}
// Invalid Arguments were supplied
return ERROR_NET_ADHOC_INVALID_ARG;
}
// Library is uninitialized
return ERROR_NET_ADHOC_NOT_INITIALIZED;
}
/**
* Get Adhoc Parameter
* @param parameter OUT: Adhoc Parameter
* @return 0 on success or... ADHOCCTL_NOT_INITIALIZED, ADHOCCTL_INVALID_ARG
*/
int sceNetAdhocctlGetParameter(u32 paramAddr) {
// Library initialized
if(netAdhocctlInited) {
// Valid Arguments
if(Memory::IsValidAddress(paramAddr)) {
// Copy Parameter
Memory::WriteStruct(paramAddr,&parameter);
// Return Success
return 0;
}
// Invalid Arguments
return ERROR_NET_ADHOCCTL_INVALID_ARG;
}
// Library uninitialized
return ERROR_NET_ADHOCCTL_NOT_INITIALIZED;
}
/**
* Adhoc Emulator PDP Send Call
* @param id Socket File Descriptor
* @param daddr Target MAC Address
* @param dport Target Port
* @param data Data Payload
* @param len Payload Length
* @param timeout Send Timeout
* @param flag Nonblocking Flag
* @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) {
SceNetEtherAddr * daddr = (SceNetEtherAddr *)mac;
uint16 dport = (uint16 )port;
// Library is initialized
if(netAdhocInited) {
// Valid Port
if(dport != 0) {
// Valid Data Length
if(len > 0) {
// Valid Socket ID
if(id > 0 && id <= 255 && pdp[id - 1] != NULL) {
// Cast Socket
SceNetAdhocPdpStat * socket = pdp[id - 1];
// Valid Data Buffer
if(data != NULL) {
// Valid Destination Address
if(daddr != NULL) {
// Log Destination
// Schedule Timeout Removal
if(flag) timeout = 0;
// Apply Send Timeout Settings to Socket
setsockopt(socket->id, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout));
// Single Target
if(!__isBroadcastMAC(daddr))
{
// Fill in Target Structure
sockaddr_in target;
target.sin_family = AF_INET;
target.sin_port = htons(dport);
// Get Peer IP
if(__resolveMAC((SceNetEtherAddr *)daddr, &target.sin_addr.s_addr) == 0) {
// Acquire Network Lock
//_acquireNetworkLock();
// Send Data
__change_blocking_mode(socket->id, flag);
int sent = sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target));
__change_blocking_mode(socket->id, 0);
// Free Network Lock
//_freeNetworkLock();
// Sent Data
if(sent == len) {
// Success
return 0;
}
// Blocking Situation
if(flag) return ERROR_NET_ADHOC_WOULD_BLOCK;
// Timeout
return ERROR_NET_ADHOC_TIMEOUT;
}
}
// Broadcast Target
else {
// Acquire Network Lock
//_acquireNetworkLock();
#ifdef BROADCAST_TO_LOCALHOST
//// Get Local IP Address
//union SceNetApctlInfo info; if(sceNetApctlGetInfo(PSP_NET_APCTL_INFO_IP, &info) == 0) {
// // Fill in Target Structure
// SceNetInetSockaddrIn target;
// target.sin_family = AF_INET;
// sceNetInetInetAton(info.ip, &target.sin_addr);
// target.sin_port = sceNetHtons(dport);
//
// // Send Data
// sceNetInetSendto(socket->id, data, len, ((flag != 0) ? (INET_MSG_DONTWAIT) : (0)), (SceNetInetSockaddr *)&target, sizeof(target));
//}
#endif
// Acquire Peer Lock
peerlock.lock();
// Iterate Peers
SceNetAdhocctlPeerInfo * peer = friends;
for(; peer != NULL; peer = peer->next) {
// Fill in Target Structure
sockaddr_in target;
target.sin_family = AF_INET;
target.sin_addr.s_addr = peer->ip_addr;
target.sin_port = htons(dport);
uint8_t * thing = (uint8_t *)&peer->ip_addr;
// printf("Attempting PDP Send to %u.%u.%u.%u on Port %u\n", thing[0], thing[1], thing[2], thing[3], dport);
// Send Data
__change_blocking_mode(socket->id, flag);
sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target));
__change_blocking_mode(socket->id, 0);
}
// Free Peer Lock
peerlock.unlock();
// Free Network Lock
//_freeNetworkLock();
// Broadcast never fails!
return 0;
}
}
// Invalid Destination Address
return ERROR_NET_ADHOC_INVALID_ADDR;
}
// Invalid Argument
return ERROR_NET_ADHOC_INVALID_ARG;
}
// Invalid Socket ID
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
}
// Invalid Data Length
return ERROR_NET_ADHOC_INVALID_DATALEN;
}
// Invalid Destination Port
return ERROR_NET_ADHOC_INVALID_PORT;
}
// Library is uninitialized
return ERROR_NET_ADHOC_NOT_INITIALIZED;
}
/**
* Adhoc Emulator PDP Receive Call
* @param id Socket File Descriptor
* @param saddr OUT: Source MAC Address
* @param sport OUT: Source Port
* @param buf OUT: Received Data
* @param len IN: Buffer Size OUT: Received Data Length
* @param timeout Receive Timeout
* @param flag Nonblocking Flag
* @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) {
SceNetEtherAddr *saddr = (SceNetEtherAddr *)addr;
uint16_t * sport = (uint16_t *)port;
int * len = (int *)dataLength;
if(netAdhocInited) {
// Valid Socket ID
if(id > 0 && id <= 255 && pdp[id - 1] != NULL) {
// Cast Socket
SceNetAdhocPdpStat * socket = pdp[id - 1];
// Valid Arguments
if(saddr != NULL && port != NULL && buf != NULL && len != NULL && *len > 0) {
#ifndef PDP_DIRTY_MAGIC
// Schedule Timeout Removal
if(flag == 1) timeout = 0;
#else
// Nonblocking Simulator
int wouldblock = 0;
// Minimum Timeout
uint32_t mintimeout = 250000;
// Nonblocking Call
if(flag == 1) {
// Erase Nonblocking Flag
flag = 0;
// Set Wouldblock Behaviour
wouldblock = 1;
// Set Minimum Timeout (250ms)
if(timeout < mintimeout) timeout = mintimeout;
}
#endif
// Apply Receive Timeout Settings to Socket
setsockopt(socket->id, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
// Sender Address
sockaddr_in sin;
// Set Address Length (so we get the sender ip)
socklen_t sinlen = sizeof(sin);
//sin.sin_len = (uint8_t)sinlen;
// Acquire Network Lock
//_acquireNetworkLock();
// Receive Data
__change_blocking_mode(socket->id,flag);
int received = recvfrom(socket->id, (char *)buf, *len,0,(sockaddr *)&sin, &sinlen);
__change_blocking_mode(socket->id,0);
// Received Data
if(received > 0) {
// Peer MAC
SceNetEtherAddr mac;
// Find Peer MAC
if(__resolveIP(sin.sin_addr.s_addr, &mac) == 0) {
// Provide Sender Information
*saddr = mac;
*sport = htons(sin.sin_port);
// Save Length
*len = received;
// Free Network Lock
//_freeNetworkLock();
// Return Success
return 0;
}
}
// Free Network Lock
//_freeNetworkLock();
#ifdef PDP_DIRTY_MAGIC
// Restore Nonblocking Flag for Return Value
if(wouldblock) flag = 1;
#endif
// Nothing received
if(flag) return ERROR_NET_ADHOC_WOULD_BLOCK;
return ERROR_NET_ADHOC_TIMEOUT;
}
// Invalid Argument
return ERROR_NET_ADHOC_INVALID_ARG;
}
// Invalid Socket ID
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
}
// Library is uninitialized
return ERROR_NET_ADHOC_NOT_INITIALIZED;
}
// Assuming < 0 for failure, homebrew SDK doesn't have much to say about this one..
int sceNetAdhocSetSocketAlert(int id, int flag) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocSetSocketAlert(%d, %d)", id, flag);
return -1;
}
int sceNetAdhocPollSocket(u32 socketStructAddr, int count, int timeout, int nonblock) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPollSocket(%08x, %i, %i, %i)", socketStructAddr, count, timeout, nonblock);
return -1;
}
/**
* Adhoc Emulator PDP Socket Delete
* @param id Socket File Descriptor
* @param flag Bitflags (Unused)
* @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID
*/
int sceNetAdhocPdpDelete(int id, int unknown) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPdpDelete(%d, %d)", id, unknown);
// Library is initialized
if(netAdhocInited) {
// Valid Arguments
if(id > 0 && id <= 255) {
// Cast Socket
SceNetAdhocPdpStat * sock = pdp[id - 1];
// Valid Socket
if(socket != NULL) {
// Close Connection
closesocket(sock->id);
// Remove Port Forward from Router
//sceNetPortClose("UDP", socket->lport);
// Free Memory
// free(socket);
// Free Translation Slot
pdp[id - 1] = NULL;
// Success
return 0;
}
// Invalid Socket ID
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
}
// Invalid Argument
return ERROR_NET_ADHOC_INVALID_ARG;
}
// Library is uninitialized
return ERROR_NET_ADHOC_NOT_INITIALIZED;
}
int sceNetAdhocctlGetAdhocId(u32 productStructAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetAdhocId(%x)", productStructAddr);
return 0;
}
int sceNetAdhocctlScan() {
// Library initialized
if(netAdhocctlInited) {
// Not connected
if(threadStatus == ADHOCCTL_STATE_DISCONNECTED) {
threadStatus = ADHOCCTL_STATE_SCANNING;
// Prepare Scan Request Packet
uint8_t opcode = OPCODE_SCAN;
// Send Scan Request Packet
send(metasocket, (char *)&opcode, 1, 0);
// Return Success
return 0;
}
// Library is busy
return ERROR_NET_ADHOCCTL_BUSY;
}
// Library uninitialized
return ERROR_NET_ADHOCCTL_NOT_INITIALIZED;
}
int sceNetAdhocctlGetScanInfo(u32 size, u32 bufAddr) {
int * buflen = (int *)Memory::GetPointer(size);
SceNetAdhocctlScanInfo * buf = NULL;
if(Memory::IsValidAddress(bufAddr)){
buf = (SceNetAdhocctlScanInfo *)Memory::GetPointer(bufAddr);
}
// Library initialized
if(netAdhocctlInited) {
// Minimum Argument Requirements
if(buflen != NULL) {
// Multithreading Lock
peerlock.lock();
// Length Returner Mode
if(buf == NULL) *buflen = __countAvailableNetworks() * sizeof(SceNetAdhocctlScanInfo);
// Normal Information Mode
else {
// Clear Memory
memset(buf, 0, *buflen);
// Network Discovery Counter
int discovered = 0;
// Count requested Networks
int requestcount = *buflen / sizeof(SceNetAdhocctlScanInfo);
// Minimum Argument Requirements
if(requestcount > 0) {
// Group List Element
SceNetAdhocctlScanInfo * group = networks;
// Iterate Group List
for(; group != NULL && discovered < requestcount; group = group->next) {
// Copy Group Information
buf[discovered] = *group;
// Exchange Adhoc Channel
// sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL, &buf[discovered].channel);
// Fake Channel Number 1 on Automatic Channel
// if(buf[discovered].channel == 0) buf[discovered].channel = 1;
//Always Fake Channel 1
buf[discovered].channel = 1;
// Increase Discovery Counter
discovered++;
}
// Link List
int i = 0; for(; i < discovered - 1; i++) {
// Link Network
buf[i].next = &buf[i + 1];
}
// Fix Last Element
if(discovered > 0) buf[discovered - 1].next = NULL;
}
// Fix Size
*buflen = discovered * sizeof(SceNetAdhocctlScanInfo);
}
// Multithreading Unlock
peerlock.unlock();
// Return Success
return 0;
}
// Generic Error
return -1;
}
// Library uninitialized
return ERROR_NET_ADHOCCTL_NOT_INITIALIZED;
}
// TODO: How many handlers can the PSP actually have for Adhocctl?
// TODO: Should we allow the same handler to be added more than once?
u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) {
bool foundHandler = false;
u32 retval = 0;
struct AdhocctlHandler handler;
memset(&handler, 0, sizeof(handler));
while (adhocctlHandlers.find(retval) != adhocctlHandlers.end())
++retval;
handler.entryPoint = handlerPtr;
handler.argument = handlerArg;
for (std::map<int, AdhocctlHandler>::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); it++) {
if (it->second.entryPoint == handlerPtr) {
foundHandler = true;
break;
}
}
if (!foundHandler && Memory::IsValidAddress(handlerPtr)) {
if (adhocctlHandlers.size() >= MAX_ADHOCCTL_HANDLERS) {
ERROR_LOG(SCENET, "UNTESTED UNTESTED sceNetAdhocctlAddHandler(%x, %x): Too many handlers", handlerPtr, handlerArg);
retval = ERROR_NET_ADHOCCTL_TOO_MANY_HANDLERS;
return retval;
}
adhocctlHandlers[retval] = handler;
WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): added handler %d", handlerPtr, handlerArg, retval);
} else {
ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Same handler already exists", handlerPtr, handlerArg);
}
// The id to return is the number of handlers currently registered
return retval;
}
u32 sceNetAdhocctlDisconnect() {
// Library initialized
if(netAdhocctlInited) {
// Connected State (Adhoc Mode)
if(threadStatus == ADHOCCTL_STATE_CONNECTED) {
// Clear Network Name
memset(&parameter.group_name, 0, sizeof(parameter.group_name));
// Set Disconnected State
threadStatus = ADHOCCTL_STATE_DISCONNECTED;
// Set HUD Connection Status
//setConnectionStatus(0);
// Prepare Packet
uint8_t opcode = OPCODE_DISCONNECT;
// Acquire Network Lock
//_acquireNetworkLock();
// Send Disconnect Request Packet
send(metasocket, (const char *)&opcode, 1, 0);
// Free Network Lock
//_freeNetworkLock();
// Multithreading Lock
peerlock.lock();
// Clear Peer List
__freeFriendsRecursive(friends);
// Delete Peer Reference
friends = 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 0;
}
// Library uninitialized
return ERROR_NET_ADHOC_NOT_INITIALIZED;
}
u32 sceNetAdhocctlDelHandler(u32 handlerID) {
if (adhocctlHandlers.find(handlerID) != adhocctlHandlers.end()) {
adhocctlHandlers.erase(handlerID);
WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlDelHandler(%d): deleted handler %d", handlerID, handlerID);
} else {
ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlDelHandler(%d): asked to delete invalid handler %d", handlerID, handlerID);
}
return 0;
}
int sceNetAdhocctlTerm() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlTerm()");
if(netAdhocInited){
netAdhocctlInited = false;
friendFinderThread.join();
// Free sttuf here
closesocket(metasocket);
metasocket = -1;
#ifdef _WIN32
WSACleanup(); // WINDOWS ONLY!
#endif
}
return 0;
}
int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetNameByAddr(%s, %08x)", mac, nameAddr);
return -1;
}
int sceNetAdhocctlJoin(u32 scanInfoAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlJoin(%08x)", scanInfoAddr);
return -1;
}
int sceNetAdhocctlGetPeerInfo(const char *mac, int size, u32 peerInfoAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetPeerInfo(%s, %i, %08x)", mac, size, peerInfoAddr);
return -1;
}
/**
* Create and / or Join a Virtual Network of the specified Name
* @param group_name Virtual Network Name
* @return 0 on success or... ADHOCCTL_NOT_INITIALIZED, ADHOCCTL_INVALID_ARG, ADHOCCTL_BUSY
*/
int sceNetAdhocctlCreate(const char *groupName) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlCreate(%s)", groupName);
const SceNetAdhocctlGroupName * groupNameStruct = (const SceNetAdhocctlGroupName *)groupName;
// Library initialized
if(netAdhocctlInited) {
// Valid Argument
if(__validNetworkName(groupNameStruct)) {
// Disconnected State
if(threadStatus == ADHOCCTL_STATE_DISCONNECTED) {
// Set Network Name
if(groupNameStruct != NULL) parameter.group_name = *groupNameStruct;
// Reset Network Name
else memset(&parameter.group_name, 0, sizeof(parameter.group_name));
// 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(groupNameStruct != NULL) packet.group = *groupNameStruct;
// Acquire Network Lock
// Send Packet
send(metasocket, (const char *)&packet, sizeof(packet), 0);
// Free Network Lock
// Set HUD Connection Status
//setConnectionStatus(1);
// Return Success
return 0;
}
// Connected State
return ERROR_NET_ADHOCCTL_BUSY;
}
// Invalid Argument
return ERROR_NET_ADHOC_INVALID_ARG;
}
// Library uninitialized
return ERROR_NET_ADHOCCTL_NOT_INITIALIZED;
}
int sceNetAdhocctlConnect(u32 ptrToGroupName) {
if (Memory::IsValidAddress(ptrToGroupName)) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlConnect(groupName=%s)", Memory::GetCharPointer(ptrToGroupName));
return sceNetAdhocctlCreate(Memory::GetCharPointer(ptrToGroupName));
} else {
return ERROR_NET_ADHOC_INVALID_ADDR;
}
}
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);
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);
return -1;
}
int sceNetAdhocTerm() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocTerm()");
// Library is initialized
if(netAdhocInited) {
// Delete PDP Sockets
__deleteAllPDP();
// Delete PTP Sockets
__deleteAllPTP();
// Delete Gamemode Buffer
//_deleteAllGMB();
// Terminate Internet Library
//sceNetInetTerm();
// Unload Internet Modules (Just keep it in memory... unloading crashes?!)
// if(_manage_modules != 0) sceUtilityUnloadModule(PSP_MODULE_NET_INET);
// Library shutdown
netAdhocInited = false;
return 0;
}else {
// Seems to return this when called a second time after being terminated without another initialisation
return SCE_KERNEL_ERROR_LWMUTEX_NOT_FOUND;
}
}
int sceNetAdhocGetPdpStat(int structSize, u32 structAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGetPdpStat(%i, %08x)", structSize, structAddr);
return 0;
}
int sceNetAdhocGetPtpStat(int structSize, u32 structAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGetPtpStat(%i, %08x)", structSize, structAddr);
return 0;
}
int sceNetAdhocPtpOpen(const char *srcmac, int srcport, const char *dstmac, int dstport, int bufsize, int retryDelay, int retryCount, int unknown) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpOpen(%s : %i, %s : %i, %i, %i, %i, %08x)", srcmac, srcport, dstmac, dstport, bufsize, retryDelay, retryCount, unknown);
return 0;
}
int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int timeout, int nonblock) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpAccept(%i, %08x, %08x, %i, %i)", id, peerMacAddrPtr, peerPortPtr, timeout, nonblock);
return 0;
}
int sceNetAdhocPtpConnect(int id, int timeout, int nonblock) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpConnect(%i, %i, %i)", id, timeout, nonblock);
return -1;
}
int sceNetAdhocPtpClose(int id, int unknown) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpClose(%i, %i)", id, unknown);
return 0;
}
int sceNetAdhocPtpListen(const char *srcmac, int srcport, int bufsize, int retryDelay, int retryCount, int queue, int unk) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpListen(%s : %i, %i, %i, %i, %i, %i)", srcmac, srcport, bufsize, retryDelay, retryCount, queue, unk);
return 0;
}
int sceNetAdhocPtpSend(int id, u32 data, u32 dataSizeAddr, int timeout, int nonblock) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpSend(%i, %08x, %08x, %i, %i)", id, data, dataSizeAddr, timeout, nonblock);
return 0;
}
int sceNetAdhocPtpRecv(int id, u32 data, u32 dataSizeAddr, int timeout, int nonblock) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpRecv(%i, %08x, %08x, %i, %i)", id, data, dataSizeAddr, timeout, nonblock);
return 0;
}
int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpFlush(%i, %i, %i)", id, timeout, nonblock);
return 0;
}
int sceNetAdhocGameModeCreateMaster(u32 data, int size) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateMaster(%08x, %i)", data, size);
return -1;
}
int sceNetAdhocGameModeCreateReplica(const char *mac, u32 data, int size) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateReplica(%s, %08x, %i)", mac, data, size);
return -1;
}
int sceNetAdhocGameModeUpdateMaster() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeUpdateMaster()");
return -1;
}
int sceNetAdhocGameModeDeleteMaster() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeDeleteMaster()");
return -1;
}
int sceNetAdhocGameModeUpdateReplica(int id, u32 infoAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeUpdateReplica(%i, %08x)", id, infoAddr);
return -1;
}
int sceNetAdhocGameModeDeleteReplica(int id) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeDeleteReplica(%i)", id);
return -1;
}
int sceNetAdhocGetSocketAlert() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGetSocketAlert()");
return 0;
}
int sceNetAdhocMatchingInit(u32 memsize) {
// Uninitialized Library
if(!netAdhocMatchingInited) {
// Save Fake Pool Size
fakePoolSize = memsize;
// Initialize Library
netAdhocMatchingInited = true;
// Return Success
return 0;
}else{
return ERROR_NET_ADHOC_MATCHING_ALREADY_INITIALIZED;
}
}
int sceNetAdhocMatchingTerm() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingTerm()");
netAdhocMatchingInited = false;
return 0;
}
// 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) {
ERROR_LOG(SCENET, "sceNetAdhocMatchingCreate");
SceNetAdhocMatchingHandler handler;
handler.entryPoint = callbackAddr;
// Library initialized
if(netAdhocMatchingInited) {
// Valid Member Limit
if(maxnum > 1 && maxnum <= 16) {
// Valid Receive Buffer size
if(rxbuflen >= 1024) {
// Valid Arguments
if(mode >= 1 && mode <= 3) {
// Iterate Matching Contexts
SceNetAdhocMatchingContext * item = contexts; for(; item != NULL; item = item->next) {
// Port Match found
if(item->port == port) return ERROR_NET_ADHOC_MATCHING_PORT_IN_USE;
}
// Allocate Context Memory
SceNetAdhocMatchingContext * context = (SceNetAdhocMatchingContext *)malloc(sizeof(SceNetAdhocMatchingContext));
// Allocated Memory
if(context != NULL) {
// Create PDP Socket
SceNetEtherAddr localmac; __getLocalMac(&localmac);
const char * mac = (const char *)&localmac.data;
int socket = sceNetAdhocPdpCreate(mac, (uint32_t)port, rxbuflen, 0);
// Created PDP Socket
if(socket > 0) {
// Clear Memory
memset(context, 0, sizeof(SceNetAdhocMatchingContext));
// Allocate Receive Buffer
context->rxbuf = (uint8_t *)malloc(rxbuflen);
// Allocated Memory
if(context->rxbuf != NULL) {
// Clear Memory
memset(context->rxbuf, 0, rxbuflen);
// Fill in Context Data
context->id = __findFreeMatchingID();
context->mode = mode;
context->maxpeers = maxnum;
context->port = port;
context->socket = socket;
context->rxbuflen = rxbuflen;
context->hello_int = hello_int;
context->keepalive_int = 500000;
//context->keepalive_int = keepalive_int;
context->resendcounter = init_count;
context->keepalivecounter = 100;
//context->keepalivecounter = init_count;
context->resend_int = rexmt_int;
context->handler = handler;
// Fill in Selfpeer
context->mac = localmac;
// Link Context
context->next = contexts;
contexts = context;
// Return Matching ID
return context->id;
}
// Close PDP Socket
sceNetAdhocPdpDelete(socket, 0);
}
// Free Memory
free(context);
// Port in use
if(socket < 1) return ERROR_NET_ADHOC_MATCHING_PORT_IN_USE;
}
// Out of Memory
return ERROR_NET_ADHOC_MATCHING_NO_SPACE;
}
// InvalidERROR_NET_Arguments
return ERROR_NET_ADHOC_MATCHING_INVALID_ARG;
}
// Invalid Receive Buffer Size
return ERROR_NET_ADHOC_MATCHING_RXBUF_TOO_SHORT;
}
// Invalid Member Limit
return ERROR_NET_ADHOC_MATCHING_INVALID_MAXNUM;
}
// Uninitialized Library
return ERROR_NET_ADHOC_MATCHING_NOT_INITIALIZED;
}
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);
return -1;
}
int sceNetAdhocMatchingStop(int matchingId) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingStop(%i)", matchingId);
return -1;
}
int sceNetAdhocMatchingDelete(int matchingId) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingDelete(%i)", matchingId);
return -1;
}
int sceNetAdhocMatchingSelectTarget(int matchingId, const char *macAddress, int optLen, u32 optDataPtr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingSelectTarget(%i, %s, %i, %08x)", matchingId, macAddress, optLen, optDataPtr);
return -1;
}
int sceNetAdhocMatchingCancelTargetWithOpt(int matchingId, const char *macAddress, int optLen, u32 optDataPtr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingCancelTargetWithOpt(%i, %s, %i, %08x)", matchingId, macAddress, optLen, optDataPtr);
return -1;
}
int sceNetAdhocMatchingCancelTarget(int matchingId, const char *macAddress) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingCancelTarget(%i, %s)", matchingId, macAddress);
return -1;
}
int sceNetAdhocMatchingGetHelloOpt(int matchingId, u32 optLenAddr, u32 optDataAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetHelloOpt(%i, %08x, %08x)", matchingId, optLenAddr, optDataAddr);
return -1;
}
int sceNetAdhocMatchingSetHelloOpt(int matchingId, int optLenAddr, u32 optDataAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingSetHelloOpt(%i, %i, %08x)", matchingId, optLenAddr, optDataAddr);
return -1;
}
int sceNetAdhocMatchingGetMembers(int matchingId, u32 sizeAddr, u32 buf) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetMembers(%i, %08x, %08x)", matchingId, sizeAddr, buf);
return -1;
}
int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u32 dataAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingSendData(%i, %s, %i, %08x)", matchingId, mac, dataLen, dataAddr);
return -1;
}
int sceNetAdhocMatchingAbortSendData(int matchingId, const char *mac) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingAbortSendData(%i, %s)", matchingId, mac);
return -1;
}
int sceNetAdhocMatchingGetPoolMaxAlloc() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetPoolMaxAlloc()");
return -1;
}
int sceNetAdhocMatchingGetPoolStat() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetPoolStat()");
return -1;
}
const HLEFunction sceNetAdhoc[] = {
{0xE1D621D7, WrapU_V<sceNetAdhocInit>, "sceNetAdhocInit"},
{0xA62C6F57, WrapI_V<sceNetAdhocTerm>, "sceNetAdhocTerm"},
{0x0AD043ED, WrapI_U<sceNetAdhocctlConnect>, "sceNetAdhocctlConnect"},
{0x6f92741b, WrapI_CUIU<sceNetAdhocPdpCreate>, "sceNetAdhocPdpCreate"},
{0xabed3790, WrapI_ICUVIII<sceNetAdhocPdpSend>, "sceNetAdhocPdpSend"},
{0xdfe53e03, WrapI_IVVVVUI<sceNetAdhocPdpRecv>, "sceNetAdhocPdpRecv"},
{0x7f27bb5e, WrapI_II<sceNetAdhocPdpDelete>, "sceNetAdhocPdpDelete"},
{0xc7c1fc57, WrapI_IU<sceNetAdhocGetPdpStat>, "sceNetAdhocGetPdpStat"},
{0x157e6225, WrapI_II<sceNetAdhocPtpClose>, "sceNetAdhocPtpClose"},
{0x4da4c788, WrapI_IUUII<sceNetAdhocPtpSend>, "sceNetAdhocPtpSend"},
{0x877f6d66, WrapI_CICIIIII<sceNetAdhocPtpOpen>, "sceNetAdhocPtpOpen"},
{0x8bea2b3e, WrapI_IUUII<sceNetAdhocPtpRecv>, "sceNetAdhocPtpRecv"},
{0x9df81198, WrapI_IUUII<sceNetAdhocPtpAccept>, "sceNetAdhocPtpAccept"},
{0xe08bdac1, WrapI_CIIIIII<sceNetAdhocPtpListen>, "sceNetAdhocPtpListen"},
{0xfc6fc07b, WrapI_III<sceNetAdhocPtpConnect>, "sceNetAdhocPtpConnect"},
{0x9ac2eeac, WrapI_III<sceNetAdhocPtpFlush>, "sceNetAdhocPtpFlush"},
{0xb9685118, WrapI_IU<sceNetAdhocGetPtpStat>, "sceNetAdhocGetPtpStat"},
{0x3278ab0c, WrapI_CUI<sceNetAdhocGameModeCreateReplica>, "sceNetAdhocGameModeCreateReplica"},
{0x98c204c8, WrapI_V<sceNetAdhocGameModeUpdateMaster>, "sceNetAdhocGameModeUpdateMaster"},
{0xfa324b4e, WrapI_IU<sceNetAdhocGameModeUpdateReplica>, "sceNetAdhocGameModeUpdateReplica"},
{0xa0229362, WrapI_V<sceNetAdhocGameModeDeleteMaster>, "sceNetAdhocGameModeDeleteMaster"},
{0x0b2228e9, WrapI_I<sceNetAdhocGameModeDeleteReplica>, "sceNetAdhocGameModeDeleteReplica"},
{0x7F75C338, WrapI_UI<sceNetAdhocGameModeCreateMaster>, "sceNetAdhocGameModeCreateMaster"},
{0x73bfd52d, WrapI_II<sceNetAdhocSetSocketAlert>, "sceNetAdhocSetSocketAlert"},
{0x4d2ce199, WrapI_V<sceNetAdhocGetSocketAlert>, "sceNetAdhocGetSocketAlert"},
{0x7a662d6b, WrapI_UIII<sceNetAdhocPollSocket>, "sceNetAdhocPollSocket"},
};
const HLEFunction sceNetAdhocMatching[] = {
{0x2a2a1e07, WrapI_U<sceNetAdhocMatchingInit>, "sceNetAdhocMatchingInit"},
{0x7945ecda, WrapI_V<sceNetAdhocMatchingTerm>, "sceNetAdhocMatchingTerm"},
{0xca5eda6f, WrapI_IIIIIIIIU<sceNetAdhocMatchingCreate>, "sceNetAdhocMatchingCreate"},
{0x93ef3843, WrapI_IIIIIIU<sceNetAdhocMatchingStart>, "sceNetAdhocMatchingStart"},
{0x32b156b3, WrapI_I<sceNetAdhocMatchingStop>, "sceNetAdhocMatchingStop"},
{0xf16eaf4f, WrapI_I<sceNetAdhocMatchingDelete>, "sceNetAdhocMatchingDelete"},
{0x5e3d4b79, WrapI_ICIU<sceNetAdhocMatchingSelectTarget>, "sceNetAdhocMatchingSelectTarget"},
{0xea3c6108, WrapI_IC<sceNetAdhocMatchingCancelTarget>, "sceNetAdhocMatchingCancelTarget"},
{0x8f58bedf, WrapI_ICIU<sceNetAdhocMatchingCancelTargetWithOpt>, "sceNetAdhocMatchingCancelTargetWithOpt"},
{0xb5d96c2a, WrapI_IUU<sceNetAdhocMatchingGetHelloOpt>, "sceNetAdhocMatchingGetHelloOpt"},
{0xb58e61b7, WrapI_IIU<sceNetAdhocMatchingSetHelloOpt>, "sceNetAdhocMatchingSetHelloOpt"},
{0xc58bcd9e, WrapI_IUU<sceNetAdhocMatchingGetMembers>, "sceNetAdhocMatchingGetMembers"},
{0xf79472d7, WrapI_ICIU<sceNetAdhocMatchingSendData>, "sceNetAdhocMatchingSendData"},
{0xec19337d, WrapI_IC<sceNetAdhocMatchingAbortSendData>, "sceNetAdhocMatchingAbortSendData"},
{0x40F8F435, WrapI_V<sceNetAdhocMatchingGetPoolMaxAlloc>, "sceNetAdhocMatchingGetPoolMaxAlloc"},
{0x9c5cfb7d, WrapI_V<sceNetAdhocMatchingGetPoolStat>, "sceNetAdhocMatchingGetPoolStat"},
};
int sceNetAdhocctlExitGameMode() {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlExitGameMode()");
return -1;
}
int sceNetAdhocctlGetGameModeInfo(u32 infoAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetGameModeInfo(%08x)", infoAddr);
return -1;
}
// Peer Information with u32 pointers
typedef struct SceNetAdhocctlPeerInfoEmu {
u32 next; // Changed the pointer to u32
SceNetAdhocctlNickname nickname;
SceNetEtherAddr mac_addr;
uint32_t ip_addr;
u32 padding; // Changed the pointer to u32
uint64_t last_recv;
} __attribute__((packed)) SceNetAdhocctlPeerInfoEmu;
int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) {
int * buflen = (int *)Memory::GetPointer(sizeAddr);
SceNetAdhocctlPeerInfoEmu * buf = NULL;
if(Memory::IsValidAddress(bufAddr)){
buf = (SceNetAdhocctlPeerInfoEmu *)Memory::GetPointer(bufAddr);
}
// Initialized Library
if(netAdhocctlInited) {
// Minimum Arguments
if(buflen != NULL) {
// Multithreading Lock
peerlock.lock();
// Length Calculation Mode
if(buf == NULL) *buflen = __getActivePeerCount() * sizeof(SceNetAdhocctlPeerInfoEmu);
// Normal Mode
else {
// Discovery Counter
int discovered = 0;
// Calculate Request Count
int requestcount = *buflen / sizeof(SceNetAdhocctlPeerInfoEmu);
// Clear Memory
memset(buf, 0, *buflen);
// Minimum Arguments
if(requestcount > 0) {
// Peer Reference
SceNetAdhocctlPeerInfo * peer = friends;
// Iterate Peers
for(; peer != NULL && discovered < requestcount; peer = peer->next) {
// Fake Receive Time
peer->last_recv = (uint64_t)time(NULL);
// Copy Peer Info
buf[discovered].nickname = peer->nickname;
buf[discovered].mac_addr = peer->mac_addr;
buf[discovered].ip_addr = peer->ip_addr;
buf[discovered].last_recv = peer->last_recv;
discovered++;
}
// Link List
int i = 0; for(; i < discovered - 1; i++) {
// Link Network
buf[i].next = bufAddr+(sizeof(SceNetAdhocctlPeerInfoEmu)*i)+
sizeof(SceNetAdhocctlPeerInfoEmu);
}
// Fix Last Element
if(discovered > 0) buf[discovered - 1].next = 0;
}
// Fix Size
*buflen = discovered * sizeof(SceNetAdhocctlPeerInfo);
}
// Multithreading Unlock
peerlock.unlock();
// Return Success
return 0;
}
// Invalid Arguments
return ERROR_NET_ADHOCCTL_INVALID_ARG;
}
// Uninitialized Library
return ERROR_NET_ADHOCCTL_NOT_INITIALIZED;
}
int sceNetAdhocctlGetAddrByName(const char *nickName, u32 sizeAddr, u32 bufAddr) {
ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetPeerList(%s, %08x, %08x)", nickName, sizeAddr, bufAddr);
return -1;
}
const HLEFunction sceNetAdhocctl[] = {
{0xE26F226E, WrapU_IIU<sceNetAdhocctlInit>, "sceNetAdhocctlInit"},
{0x9D689E13, WrapI_V<sceNetAdhocctlTerm>, "sceNetAdhocctlTerm"},
{0x20B317A0, WrapU_UU<sceNetAdhocctlAddHandler>, "sceNetAdhocctlAddHandler"},
{0x6402490B, WrapU_U<sceNetAdhocctlDelHandler>, "sceNetAdhocctlDelHandler"},
{0x34401D65, WrapU_V<sceNetAdhocctlDisconnect>, "sceNetAdhocctlDisconnect"},
{0x0ad043ed, WrapI_U<sceNetAdhocctlConnect>, "sceNetAdhocctlConnect"},
{0x08fff7a0, WrapI_V<sceNetAdhocctlScan>, "sceNetAdhocctlScan"},
{0x75ecd386, WrapI_U<sceNetAdhocctlGetState>, "sceNetAdhocctlGetState"},
{0x8916c003, WrapI_CU<sceNetAdhocctlGetNameByAddr>, "sceNetAdhocctlGetNameByAddr"},
{0xded9d28e, WrapI_U<sceNetAdhocctlGetParameter>, "sceNetAdhocctlGetParameter"},
{0x81aee1be, WrapI_UU<sceNetAdhocctlGetScanInfo>, "sceNetAdhocctlGetScanInfo"},
{0x5e7f79c9, WrapI_U<sceNetAdhocctlJoin>, "sceNetAdhocctlJoin"},
{0x8db83fdc, WrapI_CIU<sceNetAdhocctlGetPeerInfo>, "sceNetAdhocctlGetPeerInfo"},
{0xec0635c1, WrapI_C<sceNetAdhocctlCreate>, "sceNetAdhocctlCreate"},
{0xa5c055ce, WrapI_CIIUII<sceNetAdhocctlCreateEnterGameMode>, "sceNetAdhocctlCreateEnterGameMode"},
{0x1ff89745, WrapI_CCII<sceNetAdhocctlJoinEnterGameMode>, "sceNetAdhocctlJoinEnterGameMode"},
{0xcf8e084d, WrapI_V<sceNetAdhocctlExitGameMode>, "sceNetAdhocctlExitGameMode"},
{0xe162cb14, WrapI_UU<sceNetAdhocctlGetPeerList>, "sceNetAdhocctlGetPeerList"},
{0x362cbe8f, WrapI_U<sceNetAdhocctlGetAdhocId>, "sceNetAdhocctlGetAdhocId"},
{0x5a014ce0, WrapI_U<sceNetAdhocctlGetGameModeInfo>, "sceNetAdhocctlGetGameModeInfo"},
{0x99560abe, WrapI_CUU<sceNetAdhocctlGetAddrByName>, "sceNetAdhocctlGetAddrByName"},
{0xb0b80e80, 0, "sceNetAdhocctlCreateEnterGameModeMin"}, // ??
};
const HLEFunction sceNetAdhocDiscover[] = {
{0x941B3877, 0, "sceNetAdhocDiscoverInitStart"},
{0x52DE1B97, 0, "sceNetAdhocDiscoverUpdate"},
{0x944DDBC6, 0, "sceNetAdhocDiscoverGetStatus"},
{0xA2246614, 0, "sceNetAdhocDiscoverTerm"},
{0xF7D13214, 0, "sceNetAdhocDiscoverStop"},
{0xA423A21B, 0, "sceNetAdhocDiscoverRequestSuspend"},
};
void Register_sceNetAdhoc() {
RegisterModule("sceNetAdhoc", ARRAY_SIZE(sceNetAdhoc), sceNetAdhoc);
RegisterModule("sceNetAdhocMatching", ARRAY_SIZE(sceNetAdhocMatching), sceNetAdhocMatching);
RegisterModule("sceNetAdhocDiscover", ARRAY_SIZE(sceNetAdhocDiscover), sceNetAdhocDiscover);
RegisterModule("sceNetAdhocctl", ARRAY_SIZE(sceNetAdhocctl), sceNetAdhocctl);
}