mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
According to http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625%28v=vs.85%29.aspx "[...] it is not recommended that applications use multiple calls to connect to detect connection completion. If they do, they must be prepared to handle WSAEINVAL and WSAEWOULDBLOCK error values the same way that they handle WSAEALREADY, to assure robust operation." Ideally socket->state should be set to a different state and select() used to poll sockets until state can be switched to closed or established. Changes to socket->state are visible to games as so probably should not be done without testing.
2298 lines
69 KiB
C++
2298 lines
69 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
|
|
|
|
// This is a direct port of Coldbird's code from http://code.google.com/p/aemu/
|
|
// All credit goes to him!
|
|
#include "Common/ChunkFile.h"
|
|
#include "Core/HLE/FunctionWrappers.h"
|
|
#include "Core/HLE/sceKernelThread.h"
|
|
#include "Core/HLE/proAdhoc.h"
|
|
#include "Core/MemMap.h"
|
|
|
|
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_ADHOC_NOT_LISTENED = 0x8040070E,
|
|
ERROR_NET_ADHOC_NOT_OPENED = 0x8040070D,
|
|
ERROR_NET_ADHOC_SOCKET_ID_NOT_AVAIL = 0x8041070F,
|
|
ERROR_NET_ADHOC_NOT_CONNECTED = 0x8041070B,
|
|
|
|
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
|
|
};
|
|
|
|
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;
|
|
|
|
struct AdhocctlHandler {
|
|
u32 entryPoint;
|
|
u32 argument;
|
|
};
|
|
|
|
static std::map<int, AdhocctlHandler> adhocctlHandlers;
|
|
|
|
void __NetAdhocInit() {
|
|
friendFinderRunning = false;
|
|
eventHandlerUpdate = -1;
|
|
netAdhocInited = false;
|
|
netAdhocctlInited = false;
|
|
netAdhocMatchingInited = false;
|
|
adhocctlHandlers.clear();
|
|
}
|
|
|
|
|
|
int sceNetAdhocTerm();
|
|
int sceNetAdhocctlTerm();
|
|
int sceNetAdhocMatchingTerm();
|
|
|
|
void __NetAdhocShutdown() {
|
|
// Checks to avoid confusing logspam
|
|
if (netAdhocInited) {
|
|
sceNetAdhocTerm();
|
|
}
|
|
if (netAdhocctlInited) {
|
|
sceNetAdhocctlTerm();
|
|
}
|
|
if (netAdhocMatchingInited) {
|
|
sceNetAdhocMatchingTerm();
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
int getBlockingFlag(int id) {
|
|
#ifdef _MSC_VER
|
|
return 0;
|
|
#else
|
|
int sockflag = fcntl(id, F_GETFL, O_NONBLOCK);
|
|
return sockflag & O_NONBLOCK;
|
|
#endif
|
|
}
|
|
|
|
void __handlerUpdateCallback(u64 userdata, int cycleslate) {
|
|
int buff[2];
|
|
split64(userdata,buff);
|
|
__UpdateAdhocctlHandlers(buff[0], buff[1]);
|
|
}
|
|
|
|
u32 sceNetAdhocInit() {
|
|
// Library uninitialized
|
|
DEBUG_LOG(SCENET, "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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocctlInit(%i, %i, %08x)", stackSize, prio, productAddr);
|
|
if (netAdhocctlInited) {
|
|
return ERROR_NET_ADHOCCTL_ALREADY_INITIALIZED;
|
|
} else if (!g_Config.bEnableWlan) {
|
|
// Pretend success but don't actually start the friendfinder thread and stuff.
|
|
// Dunno if this is the way to go...
|
|
netAdhocctlInited = true;
|
|
return 0;
|
|
} else if (initNetwork((SceNetAdhocctlAdhocId *)Memory::GetPointer(productAddr)) == 0) {
|
|
netAdhocctlInited = true;
|
|
eventHandlerUpdate = CoreTiming::RegisterEvent("HandlerUpdateEvent", __handlerUpdateCallback);
|
|
friendFinderRunning = true;
|
|
friendFinderThread = std::thread(friendFinder);
|
|
} else {
|
|
WARN_LOG(SCENET, "sceNetAdhocctlInit: Faking success");
|
|
return 0; // Generic error, but just return success to make games conform.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPdpCreate(%s, %d, %d, %d)", mac, port, bufferSize, unknown);
|
|
if (!g_Config.bEnableWlan) {
|
|
return -1;
|
|
}
|
|
|
|
// 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 = (int)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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocctlGetParameter(%u)",paramAddr);
|
|
if (!g_Config.bEnableWlan) {
|
|
return ERROR_NET_ADHOCCTL_DISCONNECTED;
|
|
}
|
|
|
|
// Library initialized
|
|
if (netAdhocctlInited) {
|
|
// Valid Arguments
|
|
if (Memory::IsValidAddress(paramAddr)) {
|
|
// Copy Parameter
|
|
Memory::WriteStruct(paramAddr,¶meter);
|
|
// 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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPdpSend(%i, %s, %i, %p, %i, %i, %i)", id, mac, port, data, len, timeout, flag);
|
|
if (!g_Config.bEnableWlan) {
|
|
return -1;
|
|
}
|
|
SceNetEtherAddr * daddr = (SceNetEtherAddr *)mac;
|
|
uint16 dport = (uint16)port;
|
|
|
|
// Really should flatten this with early outs, all this indentation is making me dizzy.
|
|
|
|
// 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, (uint32_t *)&target.sin_addr.s_addr) == 0) {
|
|
// Acquire Network Lock
|
|
//_acquireNetworkLock();
|
|
|
|
// Send Data
|
|
changeBlockingMode(socket->id, flag);
|
|
int sent = sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target));
|
|
changeBlockingMode(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
|
|
changeBlockingMode(socket->id, flag);
|
|
sendto(socket->id, (const char *)data, len, 0, (sockaddr *)&target, sizeof(target));
|
|
changeBlockingMode(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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPdpRecv(%i, %p, %p, %p, %p, %i, %i)", id, addr, port, buf, dataLength, timeout, flag);
|
|
if (!g_Config.bEnableWlan) {
|
|
return -1;
|
|
}
|
|
|
|
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
|
|
changeBlockingMode(socket->id,flag);
|
|
int received = recvfrom(socket->id, (char *)buf, *len,0,(sockaddr *)&sin, &sinlen);
|
|
changeBlockingMode(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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPdpDelete(%d, %d)", id, unknown);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
// Library is initialized
|
|
if (netAdhocInited) {
|
|
// Valid Arguments
|
|
if (id > 0 && id <= 255) {
|
|
// Cast Socket
|
|
SceNetAdhocPdpStat * sock = pdp[id - 1];
|
|
|
|
// Valid Socket
|
|
if (sock != NULL) {
|
|
// Close Connection
|
|
closesocket(sock->id);
|
|
|
|
// Remove Port Forward from Router
|
|
//sceNetPortClose("UDP", sock->lport);
|
|
|
|
// Free Memory
|
|
// free(sock);
|
|
|
|
// 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() {
|
|
DEBUG_LOG(SCENET, "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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocctlGetScanInfo(%08x, %08x)", size, bufAddr);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
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 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() {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocctlDisconnect()");
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
// Library initialized
|
|
if (netAdhocctlInited) {
|
|
// Connected State (Adhoc Mode)
|
|
if (threadStatus == ADHOCCTL_STATE_CONNECTED) {
|
|
// Clear Network Name
|
|
memset(¶meter.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() {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocctlTerm()");
|
|
if (!g_Config.bEnableWlan) {
|
|
netAdhocctlInited = false;
|
|
return 0;
|
|
}
|
|
|
|
if (netAdhocctlInited) {
|
|
netAdhocctlInited = false;
|
|
friendFinderRunning = false;
|
|
if (friendFinderThread.joinable()) {
|
|
friendFinderThread.join();
|
|
}
|
|
// Free stuff here
|
|
closesocket(metasocket);
|
|
metasocket = (int)INVALID_SOCKET;
|
|
#ifdef _MSC_VER
|
|
WSACleanup();
|
|
#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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocctlCreate(%s)", groupName);
|
|
if (!g_Config.bEnableWlan) {
|
|
return -1;
|
|
}
|
|
|
|
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(¶meter.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)) {
|
|
DEBUG_LOG(SCENET, "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() {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocTerm()");
|
|
if (!g_Config.bEnableWlan) {
|
|
netAdhocInited = false;
|
|
return 0;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Socket List Getter
|
|
* @param buflen IN: Length of Buffer in Bytes OUT: Required Length of Buffer in Bytes
|
|
* @param buf PTP Socket List Buffer (can be NULL if you wish to receive Required Length)
|
|
* @return 0 on success or... ADHOC_INVALID_ARG, ADHOC_NOT_INITIALIZED
|
|
*/
|
|
int sceNetAdhocGetPtpStat(u32 structSize, u32 structAddr) {
|
|
// Spams a lot
|
|
VERBOSE_LOG(SCENET,"sceNetAdhocGetPtpStat(%u,%u)",structSize,structAddr);
|
|
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
|
|
int * buflen = (int *)Memory::GetPointer(structSize);
|
|
// Library is initialized
|
|
if (netAdhocInited) {
|
|
// Length Returner Mode
|
|
if (buflen != NULL && !Memory::IsValidAddress(structAddr)) {
|
|
// Return Required Size
|
|
*buflen = sizeof(SceNetAdhocPtpStat) * getPTPSocketCount();
|
|
|
|
// Success
|
|
return 0;
|
|
}
|
|
|
|
// Status Returner Mode
|
|
else if (buflen != NULL && Memory::IsValidAddress(structAddr)) {
|
|
// Socket Count
|
|
int socketcount = getPTPSocketCount();
|
|
SceNetAdhocPtpStat * buf = (SceNetAdhocPtpStat *)Memory::GetPointer(structAddr);
|
|
|
|
// Figure out how many Sockets we will return
|
|
int count = *buflen / sizeof(SceNetAdhocPtpStat);
|
|
if (count > socketcount) count = socketcount;
|
|
|
|
// Copy Counter
|
|
int i = 0;
|
|
|
|
// Iterate Sockets
|
|
int j = 0; for (; j < 255 && i < count; j++) {
|
|
// Active Socket
|
|
if (ptp[j] != NULL) {
|
|
// Copy Socket Data from internal Memory
|
|
buf[i] = *ptp[j];
|
|
|
|
// Fix Client View Socket ID
|
|
buf[i].id = j + 1;
|
|
|
|
// Write End of List Reference
|
|
buf[i].next = 0;
|
|
|
|
// Link previous Element to this one
|
|
if (i > 0)
|
|
buf[i-1].next = structAddr + (i*sizeof(SceNetAdhocPtpStat)) + sizeof(SceNetAdhocPtpStat);
|
|
|
|
// Increment Counter
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// Update Buffer Length
|
|
*buflen = i * sizeof(SceNetAdhocPtpStat);
|
|
|
|
// Success
|
|
return 0;
|
|
}
|
|
|
|
// Invalid Arguments
|
|
return ERROR_NET_ADHOC_INVALID_ARG;
|
|
}
|
|
|
|
// Library is uninitialized
|
|
return ERROR_NET_ADHOC_NOT_INITIALIZED;
|
|
}
|
|
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Active Socket Creator
|
|
* @param saddr Local MAC (Unused)
|
|
* @param sport Local Binding Port
|
|
* @param daddr Target MAC
|
|
* @param dport Target Port
|
|
* @param bufsize Socket Buffer Size
|
|
* @param rexmt_int Retransmit Interval (in Microseconds)
|
|
* @param rexmt_cnt Retransmit Count
|
|
* @param flag Bitflags (Unused)
|
|
* @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT
|
|
*/
|
|
int sceNetAdhocPtpOpen(const char *srcmac, int sport, const char *dstmac, int dport, int bufsize, int rexmt_int, int rexmt_cnt, int unknown) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPtpOpen(%s,%d,%s,%d,%d,%d,%d,%d)", srcmac, sport, dstmac,dport,bufsize, rexmt_int, rexmt_cnt, unknown);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
SceNetEtherAddr * saddr = (SceNetEtherAddr *)srcmac;
|
|
SceNetEtherAddr * daddr = (SceNetEtherAddr *)dstmac;
|
|
// Library is initialized
|
|
if (netAdhocInited) {
|
|
// Valid Addresses
|
|
if (saddr != NULL && isLocalMAC(saddr) && daddr != NULL && !isBroadcastMAC(daddr)) {
|
|
// Random Port required
|
|
if (sport == 0) {
|
|
// Find unused Port
|
|
// while (sport == 0 || _IsPTPPortInUse(sport)) {
|
|
// // Generate Port Number
|
|
// sport = (uint16_t)_getRandomNumber(65535);
|
|
// }
|
|
}
|
|
|
|
// Valid Ports
|
|
if (!isPTPPortInUse(sport) && dport != 0) {
|
|
// Valid Arguments
|
|
if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0) {
|
|
// Create Infrastructure Socket
|
|
int tcpsocket = (int)INVALID_SOCKET;
|
|
tcpsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
// Valid Socket produced
|
|
if (tcpsocket > 0) {
|
|
// Enable Port Re-use
|
|
setsockopt(tcpsocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one));
|
|
|
|
// Binding Information for local Port
|
|
sockaddr_in addr;
|
|
// addr.sin_len = sizeof(addr);
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
addr.sin_port = htons(sport);
|
|
|
|
// Bound Socket to local Port
|
|
if (bind(tcpsocket, (sockaddr *)&addr, sizeof(addr)) == 0) {
|
|
// Update sport with the port assigned by bind
|
|
socklen_t len = sizeof(addr);
|
|
if (getsockname(tcpsocket, (sockaddr *)&addr, &len) == 0) {
|
|
sport = ntohs(addr.sin_port);
|
|
}
|
|
|
|
// Allocate Memory
|
|
SceNetAdhocPtpStat * internal = (SceNetAdhocPtpStat *)malloc(sizeof(SceNetAdhocPtpStat));
|
|
|
|
// Allocated Memory
|
|
if (internal != NULL) {
|
|
// Find Free Translator ID
|
|
int i = 0; for (; i < 255; i++) if (ptp[i] == NULL) break;
|
|
|
|
// Found Free Translator ID
|
|
if (i < 255) {
|
|
// Clear Memory
|
|
memset(internal, 0, sizeof(SceNetAdhocPtpStat));
|
|
|
|
// Copy Infrastructure Socket ID
|
|
internal->id = tcpsocket;
|
|
|
|
// Copy Address Information
|
|
internal->laddr = *saddr;
|
|
internal->paddr = *daddr;
|
|
internal->lport = sport;
|
|
internal->pport = dport;
|
|
|
|
// Set Buffer Size
|
|
internal->rcv_sb_cc = bufsize;
|
|
|
|
// Link PTP Socket
|
|
ptp[i] = internal;
|
|
|
|
// Add Port Forward to Router
|
|
// sceNetPortOpen("TCP", sport);
|
|
|
|
// Return PTP Socket Pointer
|
|
return i + 1;
|
|
}
|
|
|
|
// Free Memory
|
|
free(internal);
|
|
}
|
|
}
|
|
|
|
// Close Socket
|
|
closesocket(tcpsocket);
|
|
}
|
|
}
|
|
|
|
// Invalid Arguments
|
|
return ERROR_NET_ADHOC_INVALID_ARG;
|
|
}
|
|
|
|
// Invalid Ports
|
|
return ERROR_NET_ADHOC_INVALID_PORT;
|
|
}
|
|
|
|
// Invalid Addresses
|
|
return ERROR_NET_ADHOC_INVALID_ADDR;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Connection Acceptor
|
|
* @param id Socket File Descriptor
|
|
* @param addr OUT: Peer MAC Address
|
|
* @param port OUT: Peer Port
|
|
* @param timeout Accept Timeout (in Microseconds)
|
|
* @param flag Nonblocking Flag
|
|
* @return Socket ID >= 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_SOCKET_ID_NOT_AVAIL, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_LISTENED, ADHOC_THREAD_ABORTED, NET_INTERNAL
|
|
*/
|
|
int sceNetAdhocPtpAccept(int id, u32 peerMacAddrPtr, u32 peerPortPtr, int timeout, int flag) {
|
|
|
|
SceNetEtherAddr * addr = NULL;
|
|
if (Memory::IsValidAddress(peerMacAddrPtr)) {
|
|
addr = PSPPointer<SceNetEtherAddr>::Create(peerMacAddrPtr);
|
|
}
|
|
uint16_t * port = NULL;
|
|
if (Memory::IsValidAddress(peerPortPtr)) {
|
|
port = (uint16_t *)Memory::GetPointer(peerPortPtr);
|
|
}
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPtpAccept(%d,%s,%d,%u,%d)",id, addr->data,*port,timeout, flag);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
|
|
// Library is initialized
|
|
if (netAdhocInited) {
|
|
// Valid Socket
|
|
if (id > 0 && id <= 255 && ptp[id - 1] != NULL) {
|
|
// Cast Socket
|
|
SceNetAdhocPtpStat * socket = ptp[id - 1];
|
|
|
|
// Listener Socket
|
|
if (socket->state == PTP_STATE_LISTEN) {
|
|
// Valid Arguments
|
|
if (addr != NULL && port != NULL) {
|
|
// Address Information
|
|
sockaddr_in peeraddr;
|
|
memset(&peeraddr, 0, sizeof(peeraddr));
|
|
socklen_t peeraddrlen = sizeof(peeraddr);
|
|
// Local Address Information
|
|
sockaddr_in local;
|
|
memset(&local, 0, sizeof(local));
|
|
socklen_t locallen = sizeof(local);
|
|
|
|
// Grab Nonblocking Flag
|
|
uint32_t nbio = getBlockingFlag(socket->id);
|
|
// Switch to Nonblocking Behaviour
|
|
if (nbio == 0) {
|
|
// Overwrite Socket Option
|
|
changeBlockingMode(socket->id,1);
|
|
}
|
|
|
|
// Accept Connection
|
|
int newsocket = accept(socket->id, (sockaddr *)&peeraddr, &peeraddrlen);
|
|
|
|
// Blocking Behaviour
|
|
if (!flag && newsocket == -1) {
|
|
// Get Start Time
|
|
uint32_t starttime = (uint32_t)(real_time_now()*1000.0);
|
|
|
|
// Retry until Timeout hits
|
|
while ((timeout == 0 ||((uint32_t)(real_time_now()*1000.0) - starttime) < (uint32_t)timeout) && newsocket == -1) {
|
|
// Accept Connection
|
|
newsocket = accept(socket->id, (sockaddr *)&peeraddr, &peeraddrlen);
|
|
|
|
// Wait a bit...
|
|
sleep_ms(1);
|
|
}
|
|
}
|
|
|
|
// Restore Blocking Behaviour
|
|
if (nbio == 0) {
|
|
// Restore Socket Option
|
|
changeBlockingMode(socket->id,0);
|
|
}
|
|
|
|
// Accepted New Connection
|
|
if (newsocket > 0) {
|
|
// Enable Port Re-use
|
|
setsockopt(newsocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one));
|
|
|
|
// Grab Local Address
|
|
if (getsockname(newsocket, (sockaddr *)&local, &locallen) == 0) {
|
|
// Peer MAC
|
|
SceNetEtherAddr mac;
|
|
|
|
// Find Peer MAC
|
|
if (resolveIP(peeraddr.sin_addr.s_addr, &mac) == 0) {
|
|
// Allocate Memory
|
|
SceNetAdhocPtpStat * internal = (SceNetAdhocPtpStat *)malloc(sizeof(SceNetAdhocPtpStat));
|
|
|
|
// Allocated Memory
|
|
if (internal != NULL) {
|
|
// Find Free Translator ID
|
|
int i = 0; for (; i < 255; i++) if (ptp[i] == NULL) break;
|
|
|
|
// Found Free Translator ID
|
|
if (i < 255) {
|
|
// Clear Memory
|
|
memset(internal, 0, sizeof(SceNetAdhocPtpStat));
|
|
|
|
// Copy Socket Descriptor to Structure
|
|
internal->id = newsocket;
|
|
|
|
// Copy Local Address Data to Structure
|
|
getLocalMac(&internal->laddr);
|
|
internal->lport = htons(local.sin_port);
|
|
|
|
// Copy Peer Address Data to Structure
|
|
internal->paddr = mac;
|
|
internal->pport = htons(peeraddr.sin_port);
|
|
|
|
// Set Connected State
|
|
internal->state = PTP_STATE_ESTABLISHED;
|
|
|
|
// Return Peer Address Information
|
|
*addr = internal->paddr;
|
|
*port = internal->pport;
|
|
|
|
// Link PTP Socket
|
|
ptp[i] = internal;
|
|
|
|
// Add Port Forward to Router
|
|
// sceNetPortOpen("TCP", internal->lport);
|
|
|
|
// Return Socket
|
|
return i + 1;
|
|
}
|
|
|
|
// Free Memory
|
|
free(internal);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close Socket
|
|
closesocket(newsocket);
|
|
}
|
|
|
|
// Action would block
|
|
if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK;
|
|
|
|
// Timeout
|
|
return ERROR_NET_ADHOC_TIMEOUT;
|
|
}
|
|
|
|
// Invalid Arguments
|
|
return ERROR_NET_ADHOC_INVALID_ARG;
|
|
}
|
|
|
|
// Client Socket
|
|
return ERROR_NET_ADHOC_NOT_LISTENED;
|
|
}
|
|
|
|
// Invalid Socket
|
|
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
|
|
}
|
|
|
|
// Library is uninitialized
|
|
return ERROR_NET_ADHOC_NOT_INITIALIZED;
|
|
}
|
|
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Connection Opener
|
|
* @param id Socket File Descriptor
|
|
* @param timeout Connect Timeout (in Microseconds)
|
|
* @param flag Nonblocking Flag
|
|
* @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_CONNECTION_REFUSED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_OPENED, ADHOC_THREAD_ABORTED, NET_INTERNAL
|
|
*/
|
|
int sceNetAdhocPtpConnect(int id, int timeout, int flag) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPtpConnect(%i, %i, %08x)", id, timeout, flag);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
|
|
// Library is initialized
|
|
if (netAdhocInited)
|
|
{
|
|
// Valid Socket
|
|
if (id > 0 && id <= 255 && ptp[id - 1] != NULL) {
|
|
// Cast Socket
|
|
SceNetAdhocPtpStat * socket = ptp[id - 1];
|
|
|
|
// Valid Client Socket
|
|
if (socket->state == 0) {
|
|
// Target Address
|
|
sockaddr_in sin;
|
|
memset(&sin, 0, sizeof(sin));
|
|
|
|
// Setup Target Address
|
|
// sin.sin_len = sizeof(sin);
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(socket->pport);
|
|
|
|
// Grab Peer IP
|
|
if (resolveMAC(&socket->paddr, (uint32_t *)&sin.sin_addr.s_addr) == 0) {
|
|
// Grab Nonblocking Flag
|
|
uint32_t nbio = getBlockingFlag(socket->id);
|
|
// Switch to Nonblocking Behaviour
|
|
if (nbio == 0) {
|
|
// Overwrite Socket Option
|
|
changeBlockingMode(socket->id, 1);
|
|
}
|
|
|
|
// Connect Socket to Peer (Nonblocking)
|
|
int connectresult = connect(socket->id, (sockaddr *)&sin, sizeof(sin));
|
|
|
|
// Grab Error Code
|
|
int errorcode = errno;
|
|
|
|
// Restore Blocking Behaviour
|
|
if (nbio == 0) {
|
|
// Restore Socket Option
|
|
changeBlockingMode(socket->id,0);
|
|
}
|
|
|
|
// Instant Connection (Lucky!)
|
|
if (connectresult == 0 || (connectresult == -1 && errorcode == EISCONN)) {
|
|
// Set Connected State
|
|
socket->state = PTP_STATE_ESTABLISHED;
|
|
|
|
// Success
|
|
return 0;
|
|
}
|
|
|
|
// Connection in Progress
|
|
else if (connectresult == -1 && connectInProgress(errorcode)) {
|
|
// Nonblocking Mode
|
|
if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK;
|
|
|
|
// Blocking Mode
|
|
else {
|
|
// Grab Connection Start Time
|
|
uint32_t starttime = (uint32_t)(real_time_now()*1000.0);
|
|
|
|
// Peer Information (for Connection-Polling)
|
|
sockaddr_in peer;
|
|
memset(&peer, 0, sizeof(peer));
|
|
socklen_t peerlen = sizeof(peer);
|
|
// Wait for Connection
|
|
while ((timeout == 0 || ( (uint32_t)(real_time_now()*1000.0) - starttime) < (uint32_t)timeout) && getpeername(socket->id, (sockaddr *)&peer, &peerlen) != 0) {
|
|
// Wait 1ms
|
|
sleep_ms(1);
|
|
}
|
|
|
|
// Connected in Time
|
|
if (sin.sin_addr.s_addr == peer.sin_addr.s_addr/* && sin.sin_port == peer.sin_port*/) {
|
|
// Set Connected State
|
|
socket->state = PTP_STATE_ESTABLISHED;
|
|
|
|
// Success
|
|
return 0;
|
|
}
|
|
|
|
// Timeout occured
|
|
return ERROR_NET_ADHOC_TIMEOUT;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Peer not found
|
|
return ERROR_NET_ADHOC_CONNECTION_REFUSED;
|
|
}
|
|
|
|
// Not a valid Client Socket
|
|
return ERROR_NET_ADHOC_NOT_OPENED;
|
|
}
|
|
|
|
// Invalid Socket
|
|
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
|
|
}
|
|
|
|
// Library is uninitialized
|
|
return ERROR_NET_ADHOC_NOT_INITIALIZED;
|
|
}
|
|
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Socket Closer
|
|
* @param id Socket File Descriptor
|
|
* @param flag Bitflags (Unused)
|
|
* @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED
|
|
*/
|
|
int sceNetAdhocPtpClose(int id, int unknown) {
|
|
DEBUG_LOG(SCENET,"sceNetAdhocPtpClose(%d,%d)",id,unknown);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
// Library is initialized
|
|
if (netAdhocInited) {
|
|
// Valid Arguments & Atleast one Socket
|
|
if (id > 0 && id <= 255 && ptp[id - 1] != NULL) {
|
|
// Cast Socket
|
|
SceNetAdhocPtpStat * socket = ptp[id - 1];
|
|
|
|
// Close Connection
|
|
closesocket(socket->id);
|
|
|
|
// Remove Port Forward from Router
|
|
// sceNetPortClose("TCP", socket->lport);
|
|
|
|
// Free Memory
|
|
free(socket);
|
|
|
|
// Free Reference
|
|
ptp[id - 1] = NULL;
|
|
|
|
// Success
|
|
return 0;
|
|
}
|
|
|
|
// Invalid Argument
|
|
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
|
|
}
|
|
|
|
// Library is uninitialized
|
|
return ERROR_NET_ADHOC_NOT_INITIALIZED;
|
|
}
|
|
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Passive Socket Creator
|
|
* @param saddr Local MAC (Unused)
|
|
* @param sport Local Binding Port
|
|
* @param bufsize Socket Buffer Size
|
|
* @param rexmt_int Retransmit Interval (in Microseconds)
|
|
* @param rexmt_cnt Retransmit Count
|
|
* @param backlog Size of Connection Queue
|
|
* @param flag Bitflags (Unused)
|
|
* @return Socket ID > 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_ADDR, ADHOC_INVALID_PORT, ADHOC_SOCKET_ID_NOT_AVAIL, ADHOC_PORT_NOT_AVAIL, ADHOC_PORT_IN_USE, NET_NO_SPACE
|
|
*/
|
|
int sceNetAdhocPtpListen(const char *srcmac, int sport, int bufsize, int rexmt_int, int rexmt_cnt, int backlog, int unk) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPtpListen(%s,%d,%d,%d,%d,%d,%d)",srcmac,sport,bufsize,rexmt_int,rexmt_cnt,backlog,unk);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
// Library is initialized
|
|
SceNetEtherAddr * saddr = (SceNetEtherAddr *)srcmac;
|
|
if (netAdhocInited) {
|
|
// Valid Address
|
|
if (saddr != NULL && isLocalMAC(saddr))
|
|
{
|
|
// Random Port required
|
|
if (sport == 0) {
|
|
// Find unused Port
|
|
// while (sport == 0 || __IsPTPPortInUse(sport))
|
|
// {
|
|
// // Generate Port Number
|
|
// sport = (uint16_t)_getRandomNumber(65535);
|
|
// }
|
|
}
|
|
|
|
// Valid Ports
|
|
if (!isPTPPortInUse(sport)) {
|
|
// Valid Arguments
|
|
if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0 && backlog > 0)
|
|
{
|
|
// Create Infrastructure Socket
|
|
int tcpsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
// Valid Socket produced
|
|
if (tcpsocket > 0) {
|
|
// Enable Port Re-use
|
|
setsockopt(tcpsocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one));
|
|
|
|
// Binding Information for local Port
|
|
sockaddr_in addr;
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
addr.sin_port = htons(sport);
|
|
|
|
// Bound Socket to local Port
|
|
if (bind(tcpsocket, (sockaddr *)&addr, sizeof(addr)) == 0) {
|
|
// Switch into Listening Mode
|
|
if (listen(tcpsocket, backlog) == 0) {
|
|
// Allocate Memory
|
|
SceNetAdhocPtpStat * internal = (SceNetAdhocPtpStat *)malloc(sizeof(SceNetAdhocPtpStat));
|
|
|
|
// Allocated Memory
|
|
if (internal != NULL) {
|
|
// Find Free Translator ID
|
|
int i = 0; for (; i < 255; i++) if (ptp[i] == NULL) break;
|
|
|
|
// Found Free Translator ID
|
|
if (i < 255) {
|
|
// Clear Memory
|
|
memset(internal, 0, sizeof(SceNetAdhocPtpStat));
|
|
|
|
// Copy Infrastructure Socket ID
|
|
internal->id = tcpsocket;
|
|
|
|
// Copy Address Information
|
|
internal->laddr = *saddr;
|
|
internal->lport = sport;
|
|
|
|
// Flag Socket as Listener
|
|
internal->state = PTP_STATE_LISTEN;
|
|
|
|
// Set Buffer Size
|
|
internal->rcv_sb_cc = bufsize;
|
|
|
|
// Link PTP Socket
|
|
ptp[i] = internal;
|
|
|
|
// Add Port Forward to Router
|
|
// sceNetPortOpen("TCP", sport);
|
|
|
|
// Return PTP Socket Pointer
|
|
return i + 1;
|
|
}
|
|
|
|
// Free Memory
|
|
free(internal);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close Socket
|
|
closesocket(tcpsocket);
|
|
}
|
|
|
|
// Socket not available
|
|
return ERROR_NET_ADHOC_SOCKET_ID_NOT_AVAIL;
|
|
}
|
|
|
|
// Invalid Arguments
|
|
return ERROR_NET_ADHOC_INVALID_ARG;
|
|
}
|
|
|
|
// Invalid Ports
|
|
return ERROR_NET_ADHOC_PORT_IN_USE;
|
|
}
|
|
|
|
// Invalid Addresses
|
|
return ERROR_NET_ADHOC_INVALID_ADDR;
|
|
}
|
|
|
|
// Library is uninitialized
|
|
return ERROR_NET_ADHOC_NOT_INITIALIZED;
|
|
}
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Sender
|
|
* @param id Socket File Descriptor
|
|
* @param data Data Payload
|
|
* @param len IN: Length of Payload OUT: Sent Data (in Bytes)
|
|
* @param timeout Send Timeout (in Microseconds)
|
|
* @param flag Nonblocking Flag
|
|
* @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_NOT_CONNECTED, ADHOC_THREAD_ABORTED, ADHOC_INVALID_DATALEN, ADHOC_DISCONNECTED, NET_INTERNAL, NET_NO_SPACE
|
|
*/
|
|
int sceNetAdhocPtpSend(int id, u32 dataAddr, u32 dataSizeAddr, int timeout, int flag) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPtpSend(%d,%08x,%08x,%d,%d)", id, dataAddr, dataSizeAddr, timeout, flag);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
int * len = (int *)Memory::GetPointer(dataSizeAddr);
|
|
const char * data = Memory::GetCharPointer(dataAddr);
|
|
// Library is initialized
|
|
if (netAdhocInited) {
|
|
// Valid Socket
|
|
if (id > 0 && id <= 255 && ptp[id - 1] != NULL) {
|
|
// Cast Socket
|
|
SceNetAdhocPtpStat * socket = ptp[id - 1];
|
|
|
|
// Connected Socket
|
|
if (socket->state == PTP_STATE_ESTABLISHED) {
|
|
// Valid Arguments
|
|
if (data != NULL && len != NULL && *len > 0) {
|
|
// 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));
|
|
|
|
// Acquire Network Lock
|
|
// _acquireNetworkLock();
|
|
|
|
// Send Data
|
|
changeBlockingMode(socket->id, flag);
|
|
int sent = send(socket->id, data, *len, 0);
|
|
int error = errno;
|
|
changeBlockingMode(socket->id, 0);
|
|
|
|
// Free Network Lock
|
|
// _freeNetworkLock();
|
|
|
|
// Success
|
|
if (sent > 0) {
|
|
// Save Length
|
|
*len = sent;
|
|
|
|
// Return Success
|
|
return 0;
|
|
}
|
|
|
|
// Non-Critical Error
|
|
else if (sent == -1 && error == EAGAIN) {
|
|
// Blocking Situation
|
|
if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK;
|
|
|
|
// Timeout
|
|
return ERROR_NET_ADHOC_TIMEOUT;
|
|
}
|
|
|
|
// Change Socket State
|
|
socket->state = PTP_STATE_CLOSED;
|
|
|
|
// Disconnected
|
|
return ERROR_NET_ADHOC_DISCONNECTED;
|
|
}
|
|
|
|
// Invalid Arguments
|
|
return ERROR_NET_ADHOC_INVALID_ARG;
|
|
}
|
|
|
|
// Not connected
|
|
return ERROR_NET_ADHOC_NOT_CONNECTED;
|
|
}
|
|
|
|
// Invalid Socket
|
|
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
|
|
}
|
|
|
|
// Library is uninitialized
|
|
return ERROR_NET_ADHOC_NOT_INITIALIZED;
|
|
}
|
|
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Receiver
|
|
* @param id Socket File Descriptor
|
|
* @param buf Data Buffer
|
|
* @param len IN: Buffersize OUT: Received Data (in Bytes)
|
|
* @param timeout Receive Timeout (in Microseconds)
|
|
* @param flag Nonblocking Flag
|
|
* @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_DISCONNECTED, NET_INTERNAL
|
|
*/
|
|
int sceNetAdhocPtpRecv(int id, u32 dataAddr, u32 dataSizeAddr, int timeout, int flag) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocPtpRecv(%d,%08x,%08x,%d,%d)", id, dataAddr, dataSizeAddr, timeout, flag);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
void * buf = (void *)Memory::GetPointer(dataAddr);
|
|
int * len = (int *)Memory::GetPointer(dataSizeAddr);
|
|
// Library is initialized
|
|
if (netAdhocInited) {
|
|
// Valid Socket
|
|
if (id > 0 && id <= 255 && ptp[id - 1] != NULL && ptp[id - 1]->state == PTP_STATE_ESTABLISHED) {
|
|
// Cast Socket
|
|
SceNetAdhocPtpStat * socket = ptp[id - 1];
|
|
|
|
// Valid Arguments
|
|
if (buf != NULL && len != NULL && *len > 0) {
|
|
// Schedule Timeout Removal
|
|
if (flag) timeout = 0;
|
|
|
|
// Apply Send Timeout Settings to Socket
|
|
setsockopt(socket->id, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
|
|
|
|
// Acquire Network Lock
|
|
// _acquireNetworkLock();
|
|
|
|
// Receive Data
|
|
changeBlockingMode(socket->id, flag);
|
|
int received = recv(socket->id, (char *)buf, *len, 0);
|
|
int error = errno;
|
|
changeBlockingMode(socket->id, 0);
|
|
|
|
// Free Network Lock
|
|
// _freeNetworkLock();
|
|
|
|
// Received Data
|
|
if (received > 0) {
|
|
// Save Length
|
|
*len = received;
|
|
|
|
// Return Success
|
|
return 0;
|
|
}
|
|
|
|
// Non-Critical Error
|
|
else if (received == -1 && error == EAGAIN) {
|
|
// Blocking Situation
|
|
if (flag) return ERROR_NET_ADHOC_WOULD_BLOCK;
|
|
|
|
// Timeout
|
|
return ERROR_NET_ADHOC_TIMEOUT;
|
|
}
|
|
|
|
// Change Socket State
|
|
socket->state = PTP_STATE_CLOSED;
|
|
|
|
// Disconnected
|
|
return ERROR_NET_ADHOC_DISCONNECTED;
|
|
}
|
|
|
|
// Invalid Arguments
|
|
return ERROR_NET_ADHOC_INVALID_ARG;
|
|
}
|
|
|
|
// Invalid Socket
|
|
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
|
|
}
|
|
|
|
// Library is uninitialized
|
|
return ERROR_NET_ADHOC_NOT_INITIALIZED;
|
|
}
|
|
|
|
/**
|
|
* Adhoc Emulator PTP Flusher
|
|
* @param id Socket File Descriptor
|
|
* @param timeout Flush Timeout (in Microseconds)
|
|
* @param flag Nonblocking Flag
|
|
* @return 0 on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_ARG, ADHOC_INVALID_SOCKET_ID, ADHOC_SOCKET_DELETED, ADHOC_SOCKET_ALERTED, ADHOC_WOULD_BLOCK, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_DISCONNECTED, ADHOC_NOT_CONNECTED, NET_INTERNAL
|
|
*/
|
|
int sceNetAdhocPtpFlush(int id, int timeout, int nonblock) {
|
|
DEBUG_LOG(SCENET,"sceNetAdhocPtpFlush(%d,%d,%d)", id, timeout, nonblock);
|
|
if (!g_Config.bEnableWlan) {
|
|
return 0;
|
|
}
|
|
|
|
// Library initialized
|
|
if (netAdhocInited) {
|
|
// Valid Socket
|
|
if (id > 0 && id <= 255 && ptp[id - 1] != NULL) {
|
|
// Dummy Result
|
|
return 0;
|
|
}
|
|
|
|
// Invalid Socket
|
|
return ERROR_NET_ADHOC_INVALID_SOCKET_ID;
|
|
}
|
|
// Library uninitialized
|
|
return ERROR_NET_ADHOC_NOT_INITIALIZED;
|
|
}
|
|
|
|
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) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocMatchingCreate");
|
|
if (!g_Config.bEnableWlan) {
|
|
return -1;
|
|
}
|
|
|
|
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_UU<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;
|
|
}
|
|
|
|
|
|
int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) {
|
|
DEBUG_LOG(SCENET, "sceNetAdhocctlGetPeerList(%08x, %08x)", sizeAddr, bufAddr);
|
|
if (!g_Config.bEnableWlan) {
|
|
return -1;
|
|
}
|
|
|
|
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);
|
|
}
|