diff --git a/CMakeLists.txt b/CMakeLists.txt
index 83b0952d27..a235e29e5c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -873,6 +873,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/sceNet.h
Core/HLE/sceNetAdhoc.cpp
Core/HLE/sceNetAdhoc.h
+ Core/HLE/proAdhoc.h
+ Core/HLE/proAdhoc.cpp
Core/HLE/sceOpenPSID.cpp
Core/HLE/sceOpenPSID.h
Core/HLE/sceP3da.cpp
diff --git a/Core/Config.cpp b/Core/Config.cpp
index fde6cc4412..6fe6f0d80e 100644
--- a/Core/Config.cpp
+++ b/Core/Config.cpp
@@ -297,6 +297,8 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
pspConfig->Get("NickName", &sNickName, "PPSSPP");
+ pspConfig->Get("proAdhocServer", &proAdhocServer, "localhost");
+ pspConfig->Get("MacAddress", &localMacAddress, "01:02:03:04:05:06");
pspConfig->Get("Language", &iLanguage, PSP_SYSTEMPARAM_LANGUAGE_ENGLISH);
pspConfig->Get("TimeFormat", &iTimeFormat, PSP_SYSTEMPARAM_TIME_FORMAT_24HR);
pspConfig->Get("DateFormat", &iDateFormat, PSP_SYSTEMPARAM_DATE_FORMAT_YYYYMMDD);
@@ -521,6 +523,8 @@ void Config::Save() {
IniFile::Section *pspConfig = iniFile.GetOrCreateSection("SystemParam");
pspConfig->Set("NickName", sNickName.c_str());
+ pspConfig->Set("proAdhocServer", proAdhocServer.c_str());
+ pspConfig->Set("MacAddress", localMacAddress.c_str());
pspConfig->Set("Language", iLanguage);
pspConfig->Set("TimeFormat", iTimeFormat);
pspConfig->Set("DateFormat", iDateFormat);
diff --git a/Core/Config.h b/Core/Config.h
index 1ede569d58..9a445c794b 100644
--- a/Core/Config.h
+++ b/Core/Config.h
@@ -203,6 +203,8 @@ public:
// SystemParam
std::string sNickName;
+ std::string proAdhocServer;
+ std::string localMacAddress;
int iLanguage;
int iTimeFormat;
int iDateFormat;
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index f2bc31111c..627f6dd9d3 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -195,6 +195,7 @@
+
@@ -451,6 +452,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 25d3cde361..a33b57641f 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -499,6 +499,9 @@
Debugger
+
+ HLE\Libraries
+
@@ -924,6 +927,9 @@
Debugger
+
+ HLE\Libraries
+
@@ -931,4 +937,4 @@
-
\ No newline at end of file
+
diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp
index d047c75cd1..31775cefa0 100644
--- a/Core/Dialog/PSPNetconfDialog.cpp
+++ b/Core/Dialog/PSPNetconfDialog.cpp
@@ -18,6 +18,11 @@
#include "PSPNetconfDialog.h"
#include "ChunkFile.h"
#include "../Core/MemMap.h"
+#include "../Core/HLE/sceNetAdhoc.h"
+
+#define NETCONF_CONNECT_ADHOC 2
+#define NETCONF_CREATE_ADHOC 4
+#define NETCONF_JOIN_ADHOC 5
PSPNetconfDialog::PSPNetconfDialog() {
}
@@ -40,6 +45,19 @@ int PSPNetconfDialog::Init(u32 paramAddr) {
}
int PSPNetconfDialog::Update(int animSpeed) {
+ if(request.netAction == NETCONF_CONNECT_ADHOC ||
+ request.netAction == NETCONF_CREATE_ADHOC ||
+ request.netAction == NETCONF_JOIN_ADHOC){
+ if(request.NetconfData != NULL){
+ Shutdown(true);
+ if(sceNetAdhocctlCreate(request.NetconfData->groupName) == 0)
+ {
+ status = SCE_UTILITY_STATUS_FINISHED;
+ return 0;
+ }
+ return -1;
+ }
+ }
return 0;
}
@@ -58,4 +76,4 @@ void PSPNetconfDialog::DoState(PointerWrap &p) {
return;
p.Do(request);
-}
\ No newline at end of file
+}
diff --git a/Core/Dialog/PSPNetconfDialog.h b/Core/Dialog/PSPNetconfDialog.h
index 421e41ac69..9774e74891 100644
--- a/Core/Dialog/PSPNetconfDialog.h
+++ b/Core/Dialog/PSPNetconfDialog.h
@@ -46,4 +46,4 @@ public:
private:
SceUtilityNetconfParam request;
-};
\ No newline at end of file
+};
diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h
index b80a51b139..bd5f672a30 100644
--- a/Core/HLE/FunctionWrappers.h
+++ b/Core/HLE/FunctionWrappers.h
@@ -806,3 +806,13 @@ template void WrapI_ICI() {
int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2));
RETURN(retval);
}
+
+template void WrapI_IVVVVUI(){
+ u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), Memory::GetPointer(PARAM(2)), Memory::GetPointer(PARAM(3)), Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) );
+ RETURN(retval);
+}
+
+template void WrapI_ICUVIII(){
+ u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6));
+ RETURN(retval);
+}
diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp
new file mode 100644
index 0000000000..fe446c68e8
--- /dev/null
+++ b/Core/HLE/proAdhoc.cpp
@@ -0,0 +1,708 @@
+#include "proAdhoc.h"
+
+uint32_t fakePoolSize = 0;
+SceNetAdhocMatchingContext * contexts = NULL;
+int one = 1;
+bool friendFinderRunning = false;
+SceNetAdhocctlPeerInfo * friends = NULL;
+SceNetAdhocctlScanInfo * networks = NULL;
+int eventHandlerUpdate = -1;
+int threadStatus = ADHOCCTL_STATE_DISCONNECTED;
+
+int metasocket;
+SceNetAdhocctlParameter parameter;
+std::thread friendFinderThread;
+recursive_mutex peerlock;
+SceNetAdhocPdpStat * pdp[255];
+SceNetAdhocPtpStat * ptp[255];
+
+int isLocalMAC(const SceNetEtherAddr * addr) {
+ SceNetEtherAddr saddr;
+ getLocalMac(&saddr);
+
+ // Compare MAC Addresses
+ int match = memcmp((const void *)addr, (const void *)&saddr, ETHER_ADDR_LEN);
+
+ // Return Result
+ return (match == 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;
+}
+
+int isPTPPortInUse(uint16_t port) {
+ // Iterate Sockets
+ int i = 0; for(; i < 255; i++) if(ptp[i] != NULL && ptp[i]->lport == port) return 1;
+
+ // Unused Port
+ return 0;
+}
+
+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();
+ }
+}
+
+void changeBlockingMode(int fd, int nonblocking) {
+ unsigned long on = 1;
+ unsigned long off = 0;
+#ifdef _MSC_VER
+ if(nonblocking){
+ // Change to Non-Blocking Mode
+ ioctlsocket(fd,FIONBIO,&on);
+ }else {
+ // Change to Blocking Mode
+ ioctlsocket(fd, FIONBIO, &off);
+ }
+#else
+ if(nonblocking == 1) 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
+}
+
+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;
+}
+
+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;
+ }
+ }
+}
+
+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;
+ }
+ }
+}
+
+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;
+ }
+}
+
+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;
+}
+
+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;
+}
+
+void freeFriendsRecursive(SceNetAdhocctlPeerInfo * node) {
+ // End of List
+ if(node == NULL) return;
+
+ // Increase Recursion Depth
+ freeFriendsRecursive(node->next);
+
+ // Free Memory
+ free(node);
+}
+
+int friendFinder(){
+ // Receive Buffer
+ int rxpos = 0;
+ uint8_t rx[1024];
+
+ // Chat Packet
+ SceNetAdhocctlChatPacketC2S chat;
+ chat.base.opcode = OPCODE_CHAT;
+
+ // Last Ping Time
+ uint64_t lastping = 0;
+
+ // Last Time Reception got updated
+ uint64_t lastreceptionupdate = 0;
+
+ uint64_t now;
+
+ // Finder Loop
+ while(friendFinderRunning) {
+ // Acquire Network Lock
+ //_acquireNetworkLock();
+
+ // Ping Server
+ now = real_time_now()*1000.0;
+ if(now - lastping >= 100) {
+ // Update Ping Time
+ lastping = 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 _MSC_VER
+ 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...");
+
+ // 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...");
+
+ // 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...");
+ // 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...");
+
+ // 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;
+ }
+ }
+ // Original value was 10 ms, I think 100 is just fine
+ sleep_ms(100);
+ }
+
+ // Log Shutdown
+ INFO_LOG(SCENET, "FriendFinder: End of Friend Finder Thread");
+
+ // Return Success
+ return 0;
+}
+
+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;
+}
+
+int getLocalIp(sockaddr_in * SocketAddress){
+#ifdef _MSC_VER
+ // 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
+ SocketAddress->sin_addr.s_addr = inet_addr("192.168.12.1");
+ return 0;
+#endif
+}
+
+void getLocalMac(SceNetEtherAddr * addr){
+ //MAC Adress from config
+ uint8_t mac[ETHER_ADDR_LEN];
+ sscanf(g_Config.localMacAddress.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+ memcpy(addr,mac,ETHER_ADDR_LEN);
+}
+
+int getPTPSocketCount(void) {
+ // Socket Counter
+ int counter = 0;
+
+ // Count Sockets
+ int i = 0; for(; i < 255; i++) if(ptp[i] != NULL) counter++;
+
+ // Return Socket Count
+ return counter;
+}
+
+int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
+ int iResult = 0;
+#ifdef _MSC_VER
+ WSADATA data;
+ iResult = WSAStartup(MAKEWORD(2,2),&data);
+ if(iResult != NOERROR){
+ ERROR_LOG(SCENET, "Wsa failed");
+ return iResult;
+ }
+#endif
+ metasocket = INVALID_SOCKET;
+ metasocket = socket(AF_INET,SOCK_STREAM, IPPROTO_TCP);
+ if(metasocket == INVALID_SOCKET){
+ ERROR_LOG(SCENET,"invalid socket");
+ return INVALID_SOCKET;
+ }
+ struct sockaddr_in server_addr;
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(27312); // Maybe read this from config too
+
+ // Resolve dns
+ addrinfo * resultAddr;
+ addrinfo * ptr;
+ in_addr serverIp;
+ iResult = getaddrinfo(g_Config.proAdhocServer.c_str(),0,NULL,&resultAddr);
+ if(iResult != 0){
+ ERROR_LOG(SCENET, "Dns error\n");
+ return iResult;
+ }
+ for(ptr = resultAddr; ptr != NULL; ptr = ptr->ai_next){
+ switch(ptr->ai_family){
+ case AF_INET:
+ serverIp = ((sockaddr_in *)ptr->ai_addr)->sin_addr;
+ }
+ }
+ server_addr.sin_addr = serverIp; iResult = connect(metasocket,(sockaddr *)&server_addr,sizeof(server_addr));
+ if(iResult == SOCKET_ERROR){
+ ERROR_LOG(SCENET,"Socket error");
+ return iResult;
+ }
+ memset(¶meter,0,sizeof(parameter));
+ strcpy((char *)¶meter.nickname.data, g_Config.sNickName.c_str());
+ parameter.channel = 1; // Fake Channel 1
+
+ // Prepare Login Packet
+ getLocalMac(¶meter.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);
+ changeBlockingMode(metasocket,1); // Change to non-blocking
+ if(sent > 0){
+ return 0;
+ }else{
+ return -1;
+ }
+}
+
+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;
+}
+
+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 -1;
+}
+
+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 -1;
+}
+
+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;
+}
+
+u64 join32(u32 num1, u32 num2){
+ return (u64)num2 << 32 | num1;
+}
+
+void split64(u64 num, int buff[]){
+ int num1 = (int)(num&firstMask);
+ int num2 = (int)((num&secondMask)>>32);
+ buff[0] = num1;
+ buff[1] = num2;
+}
diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h
new file mode 100644
index 0000000000..1723eb84ab
--- /dev/null
+++ b/Core/HLE/proAdhoc.h
@@ -0,0 +1,598 @@
+#pragma once
+
+#include "Common/ChunkFile.h"
+#include "../Config.h"
+#include "Core/HLE/HLE.h"
+#include "../CoreTiming.h"
+#include "Core/HLE/sceNetAdhoc.h"
+#include "native/base/timeutil.h"
+#include "native/base/mutex.h"
+#include "native/thread/thread.h"
+
+#include "sceKernel.h"
+#include "sceKernelThread.h"
+#include "sceKernelMutex.h"
+#include "sceUtility.h"
+#include "net/resolve.h"
+
+/*
+#ifdef _MSC_VER
+#include
+#else
+#include
+#endif
+*/
+
+// Net stuff
+#ifdef _MSC_VER
+#include
+#else
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+#ifdef _MSC_VER
+#define PACK
+#define errno WSAGetLastError()
+#define EAGAIN WSAEWOULDBLOCK
+#define EINPROGRESS WSAEWOULDBLOCK
+#define EISCONN WSAEISCONN
+#else
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define closesocket close
+#define PACK __attribute__((packed))
+#endif
+
+// 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
+
+// PTP Connection States
+#define PTP_STATE_CLOSED 0
+#define PTP_STATE_LISTEN 1
+#define PTP_STATE_ESTABLISHED 4
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif
+// Ethernet Address
+#define ETHER_ADDR_LEN 6
+typedef struct SceNetEtherAddr {
+ uint8_t data[ETHER_ADDR_LEN];
+} PACK SceNetEtherAddr;
+
+
+// Adhoc Virtual Network Name
+#define ADHOCCTL_GROUPNAME_LEN 8
+typedef struct SceNetAdhocctlGroupName {
+ uint8_t data[ADHOCCTL_GROUPNAME_LEN];
+} PACK SceNetAdhocctlGroupName;
+
+// Virtual Network Host Information
+typedef struct SceNetAdhocctlBSSId {
+ SceNetEtherAddr mac_addr;
+ uint8_t padding[2];
+} PACK SceNetAdhocctlBSSId;
+
+// Virtual Network Information
+typedef struct SceNetAdhocctlScanInfo {
+ struct SceNetAdhocctlScanInfo * next;
+ s32_le channel;
+ SceNetAdhocctlGroupName group_name;
+ SceNetAdhocctlBSSId bssid;
+ s32_le mode;
+} PACK SceNetAdhocctlScanInfo;
+
+// Player Nickname
+#define ADHOCCTL_NICKNAME_LEN 128
+typedef struct SceNetAdhocctlNickname {
+ uint8_t data[ADHOCCTL_NICKNAME_LEN];
+} PACK SceNetAdhocctlNickname;
+
+// Active Virtual Network Information
+typedef struct SceNetAdhocctlParameter {
+ s32_le channel;
+ SceNetAdhocctlGroupName group_name;
+ SceNetAdhocctlBSSId bssid;
+ SceNetAdhocctlNickname nickname;
+} PACK SceNetAdhocctlParameter;
+
+// Peer Information
+typedef struct SceNetAdhocctlPeerInfo {
+ SceNetAdhocctlPeerInfo * next;
+ SceNetAdhocctlNickname nickname;
+ SceNetEtherAddr mac_addr;
+ u32_le ip_addr;
+ uint8_t padding[2];
+ u64_le last_recv;
+} PACK SceNetAdhocctlPeerInfo;
+
+// Peer Information with u32 pointers
+typedef struct SceNetAdhocctlPeerInfoEmu {
+ u32_le next; // Changed the pointer to u32
+ SceNetAdhocctlNickname nickname;
+ SceNetEtherAddr mac_addr;
+ u32_le ip_addr;
+ u32 padding; // Changed the pointer to u32
+ u64_le last_recv;
+} SceNetAdhocctlPeerInfoEmu;
+
+// Game Mode Peer List
+#define ADHOCCTL_GAMEMODE_MAX_MEMBERS 16
+typedef struct SceNetAdhocctlGameModeInfo {
+ s32_le num;
+ SceNetEtherAddr member[ADHOCCTL_GAMEMODE_MAX_MEMBERS];
+} PACK SceNetAdhocctlGameModeInfo;
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
+// Adhoc ID (Game Product Key)
+#define ADHOCCTL_ADHOCID_LEN 9
+typedef struct SceNetAdhocctlAdhocId {
+ s32_le type;
+ uint8_t data[ADHOCCTL_ADHOCID_LEN];
+ uint8_t padding[3];
+} SceNetAdhocctlAdhocId;
+
+// Socket Polling Event Listener
+struct SceNetAdhocPollSd {
+ s32_le id;
+ s32_le events;
+ s32_le revents;
+};
+
+// PDP Socket Status
+struct SceNetAdhocPdpStat {
+ struct SceNetAdhocPdpStat * next;
+ s32_le id;
+ SceNetEtherAddr laddr;
+ u16_le lport;
+ u32_le rcv_sb_cc;
+};
+
+// PTP Socket Status
+struct SceNetAdhocPtpStat {
+ u32_le next; // Changed the pointer to u32
+ s32_le id;
+ SceNetEtherAddr laddr;
+ SceNetEtherAddr paddr;
+ u16_le lport;
+ u16_le pport;
+ u32_le snd_sb_cc;
+ u32_le rcv_sb_cc;
+ s32_le state;
+};
+
+// Gamemode Optional Peer Buffer Data
+struct SceNetAdhocGameModeOptData {
+ u32_le size;
+ u32_le flag;
+ u64_le last_recv;
+};
+
+// Gamemode Buffer Status
+struct SceNetAdhocGameModeBufferStat {
+ struct SceNetAdhocGameModeBufferStat * next;
+ s32_le id;
+ void * ptr;
+ u32_le size;
+ u32_le master;
+ SceNetAdhocGameModeOptData opt;
+};
+
+
+// Internal Matching Peer Information
+typedef struct SceNetAdhocMatchingMemberInternal {
+ // Next Peer
+ struct SceNetAdhocMatchingMemberInternal * next;
+
+ // MAC Address
+ SceNetEtherAddr mac;
+
+ // State Variable
+ s32_le state;
+
+ // Send in Progress
+ s32_le sending;
+
+ // Last Heartbeat
+ u64_le lastping;
+} SceNetAdhocMatchingMemberInternal;
+
+
+// Matching handler
+struct SceNetAdhocMatchingHandlerArgs {
+ s32_le id;
+ s32_le event;
+ SceNetEtherAddr * peer;
+ s32_le optlen;
+ void * opt;
+};
+
+struct SceNetAdhocMatchingHandler {
+ u32_le entryPoint;
+};
+
+// Thread Message Stack Item
+typedef struct ThreadMessage {
+ // Next Thread Message
+ struct ThreadMessage * next;
+
+ // Stack Event Opcode
+ u32_le opcode;
+
+ // Target MAC Address
+ SceNetEtherAddr mac;
+
+ // Optional Data Length
+ s32_le optlen;
+} ThreadMessage;
+
+// Established Peer
+
+// Context Information
+typedef struct SceNetAdhocMatchingContext {
+ // Next Context
+ struct SceNetAdhocMatchingContext * next;
+
+ // Externally Visible ID
+ s32_le id;
+
+ // Matching Mode (HOST, CLIENT, P2P)
+ s32_le mode;
+
+ // Running Flag (1 = running, 0 = created)
+ s32_le running;
+
+ // Maximum Number of Peers (for HOST, P2P)
+ s32_le maxpeers;
+
+ // Local MAC Address
+ SceNetEtherAddr mac;
+
+ // Peer List for Connectees
+ SceNetAdhocMatchingMemberInternal * peerlist;
+
+ // Local PDP Port
+ u16_le port;
+
+ // Local PDP Socket
+ s32_le socket;
+
+ // Receive Buffer Length
+ s32_le rxbuflen;
+
+ // Receive Buffer
+ uint8_t * rxbuf;
+
+ // Hello Broadcast Interval (Microseconds)
+ u32_le hello_int;
+
+ // Keep-Alive Broadcast Interval (Microseconds)
+ u32_le keepalive_int;
+
+ // Resend Interval (Microseconds)
+ u32_le resend_int;
+
+ // Resend-Counter
+ s32_le resendcounter;
+
+ // Keep-Alive Counter
+ s32_le keepalivecounter;
+
+ // Event Handler
+ SceNetAdhocMatchingHandler handler;
+
+ // Hello Data Length
+ u32_le hellolen;
+
+ // Hello Data
+ void * hello;
+
+ // Event Caller Thread
+ s32_le event_thid;
+
+ // IO Handler Thread
+ s32_le input_thid;
+
+ // Event Caller Thread Message Stack
+ s32_le event_stack_lock;
+ ThreadMessage * event_stack;
+
+ // IO Handler Thread Message Stack
+ s32_le 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
+
+#ifdef _MSC_VER
+#pragma pack(push,1)
+#endif
+
+typedef struct {
+ // Game Product Code (ex. ULUS12345)
+ char data[PRODUCT_CODE_LENGTH];
+} PACK SceNetAdhocctlProductCode;
+
+// Basic Packet
+typedef struct {
+ uint8_t opcode;
+} PACK SceNetAdhocctlPacketBase;
+
+// C2S Login Packet
+typedef struct {
+ SceNetAdhocctlPacketBase base;
+ SceNetEtherAddr mac;
+ SceNetAdhocctlNickname name;
+ SceNetAdhocctlProductCode game;
+} PACK SceNetAdhocctlLoginPacketC2S;
+
+// C2S Connect Packet
+typedef struct {
+ SceNetAdhocctlPacketBase base;
+ SceNetAdhocctlGroupName group;
+} PACK SceNetAdhocctlConnectPacketC2S;
+
+// C2S Chat Packet
+typedef struct {
+ SceNetAdhocctlPacketBase base;
+ char message[64];
+} PACK SceNetAdhocctlChatPacketC2S;
+
+// S2C Connect Packet
+typedef struct {
+ SceNetAdhocctlPacketBase base;
+ SceNetAdhocctlNickname name;
+ SceNetEtherAddr mac;
+ uint32_t ip;
+} PACK SceNetAdhocctlConnectPacketS2C;
+
+// S2C Disconnect Packet
+typedef struct {
+ SceNetAdhocctlPacketBase base;
+ uint32_t ip;
+} PACK SceNetAdhocctlDisconnectPacketS2C;
+
+// S2C Scan Packet
+typedef struct {
+ SceNetAdhocctlPacketBase base;
+ SceNetAdhocctlGroupName group;
+ SceNetEtherAddr mac;
+} PACK SceNetAdhocctlScanPacketS2C;
+
+// S2C Connect BSSID Packet
+typedef struct {
+ SceNetAdhocctlPacketBase base;
+ SceNetEtherAddr mac;
+} PACK SceNetAdhocctlConnectBSSIDPacketS2C;
+
+// S2C Chat Packet
+typedef struct {
+ SceNetAdhocctlChatPacketC2S base;
+ SceNetAdhocctlNickname name;
+} PACK SceNetAdhocctlChatPacketS2C;
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
+// Aux vars
+extern int metasocket;
+extern SceNetAdhocctlParameter parameter;
+extern std::thread friendFinderThread;
+extern recursive_mutex peerlock;
+extern SceNetAdhocPdpStat * pdp[255];
+extern SceNetAdhocPtpStat * ptp[255];
+
+extern uint32_t fakePoolSize;
+extern SceNetAdhocMatchingContext * contexts;
+extern int one;
+extern bool friendFinderRunning;
+extern SceNetAdhocctlPeerInfo * friends;
+extern SceNetAdhocctlScanInfo * networks;
+extern int eventHandlerUpdate;
+extern int threadStatus;
+// End of Aux vars
+
+/**
+ * Local MAC Check
+ * @param saddr To-be-checked MAC Address
+ * @return 1 if valid or... 0
+ */
+int isLocalMAC(const SceNetEtherAddr * addr);
+
+/**
+ * PDP Port Check
+ * @param port To-be-checked Port
+ * @return 1 if in use or... 0
+ */
+int isPDPPortInUse(uint16_t port);
+
+/**
+ * Check whether PTP Port is in use or not
+ * @param port To-be-checked Port Number
+ * @return 1 if in use or... 0
+ */
+int isPTPPortInUse(uint16_t port);
+
+/**
+ * Add Friend to Local List
+ * @param packet Friend Information
+ */
+void addFriend(SceNetAdhocctlConnectPacketS2C * packet);
+
+/**
+ * Changes the Blocking Mode of the socket
+ * @param fd File Descriptor of the socket
+ * @param nonblocking 1 to set to nonblock and 0 to set blocking
+ */
+void changeBlockingMode(int fd, int nonblocking);
+
+/**
+ * Count Virtual Networks by analyzing the Friend List
+ * @return Number of Virtual Networks
+ */
+int countAvailableNetworks();
+
+/**
+ * Closes & Deletes all PDP Sockets
+ */
+void deleteAllPDP(void);
+
+/**
+ * Closes & Deletes all PTP sockets
+ */
+void deleteAllPTP(void);
+
+/**
+ * Delete Friend from Local List
+ * @param ip Friend IP
+ */
+void deleteFriendByIP(uint32_t ip);
+
+/**
+ * Find Free Matching ID
+ * @return First unoccupied Matching ID
+ */
+int findFreeMatchingID(void);
+
+/**
+ * Find Internal Matching Context for Matching ID
+ * @param id Matching ID
+ * @return Matching Context Pointer or... NULL
+ */
+SceNetAdhocMatchingContext * findMatchingContext(int id);
+
+/**
+ * Recursive Memory Freeing-Helper for Friend-Structures
+ * @param node Current Node in List
+ */
+void freeFriendsRecursive(SceNetAdhocctlPeerInfo * node);
+
+/**
+ * Friend Finder Thread (Receives Peer Information)
+ * @param args Length of argp in Bytes (Unused)
+ * @param argp Argument (Unused)
+ * @return Unused Value - Return 0
+ */
+int friendFinder();
+
+/**
+ * Return Number of active Peers in the same Network as the Local Player
+ * @return Number of active Peers
+ */
+int getActivePeerCount(void);
+
+/**
+ * Returns the locall Ip of this machine, TODO: Implement the linux version
+ * @param SocketAddres OUT: local ip
+ */
+int getLocalIp(sockaddr_in * SocketAddress);
+
+/**
+ * Joins two 32 bits number into a 64 bit one
+ * @param num1: first number
+ * @param num2: second number
+ * @return Single 64 bit number
+ */
+#define firstMask 0x00000000FFFFFFFF
+#define secondMask 0xFFFFFFFF00000000
+u64 join32(u32 num1, u32 num2);
+
+/**
+ * Splits a 64 bit number into two 32 bit ones
+ * @param num: The number to be split
+ * @param buf OUT: Array containing the split numbers
+ */
+void split64(u64 num, int buff[]);
+
+/**
+ * Returns the local mac, TODO: Read from Config file
+ * @param addr OUT: Local Mac
+ */
+void getLocalMac(SceNetEtherAddr * addr);
+
+/**
+ * PTP Socket Counter
+ * @return Number of internal PTP Sockets
+ */
+int getPTPSocketCount(void);
+
+/**
+ * Initialize Networking Components for Adhocctl Emulator
+ * @param adhoc_id Game Product Code
+ * @param server_ip Server IP
+ * @return 0 on success or... -1
+ */
+int initNetwork(SceNetAdhocctlAdhocId *adhocid);
+
+/**
+ * Broadcast MAC Check
+ * @param addr To-be-checked MAC Address
+ * @return 1 if Broadcast MAC or... 0
+ */
+int isBroadcastMAC(const SceNetEtherAddr * addr);
+
+/**
+ * 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);
+
+/**
+ * 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);
+
+/**
+ * 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 * groupname);
diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp
index 80b963d169..8212f025eb 100644
--- a/Core/HLE/sceNet.cpp
+++ b/Core/HLE/sceNet.cpp
@@ -18,6 +18,7 @@
#include "Common/ChunkFile.h"
#include "HLE.h"
#include "../MIPS/MIPS.h"
+#include "../Config.h"
#include "sceKernel.h"
#include "sceKernelThread.h"
@@ -130,22 +131,28 @@ u32 sceNetTerm() {
}
u32 sceWlanGetEtherAddr(u32 addrAddr) {
- static const u8 fakeEtherAddr[6] = { 1, 2, 3, 4, 5, 6 };
+ //MAC Adress from config
+ uint8_t mac[6];
+ sscanf(g_Config.localMacAddress.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
DEBUG_LOG(SCENET, "sceWlanGetEtherAddr(%08x)", addrAddr);
for (int i = 0; i < 6; i++)
- Memory::Write_U8(fakeEtherAddr[i], addrAddr + i);
+ Memory::Write_U8(mac[i], addrAddr + i);
return 0;
}
+u32 sceNetGetLocalEtherAddr(u32 addrAddr) {
+ return sceWlanGetEtherAddr(addrAddr);
+}
+
u32 sceWlanDevIsPowerOn() {
DEBUG_LOG(SCENET, "UNTESTED 0=sceWlanDevIsPowerOn()");
- return 0;
+ return 1;
}
u32 sceWlanGetSwitchState() {
DEBUG_LOG(SCENET, "UNTESTED sceWlanGetSwitchState()");
- return 0;
+ return 1;
}
// Probably a void function, but often returns a useful value.
@@ -348,7 +355,7 @@ const HLEFunction sceNet[] = {
{0x281928A9, WrapU_V, "sceNetTerm"},
{0x89360950, WrapI_UU, "sceNetEtherNtostr"},
{0xd27961c9, WrapI_UU, "sceNetEtherStrton"},
- {0x0bf0a3ae, 0, "sceNetGetLocalEtherAddr"},
+ {0x0bf0a3ae, WrapU_U, "sceNetGetLocalEtherAddr"},
{0x50647530, 0, "sceNetFreeThreadinfo"},
{0xcc393e48, WrapI_U, "sceNetGetMallocStat"},
{0xad6844c6, 0, "sceNetThreadAbort"},
diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp
index 852b29b6d3..684b6283a6 100644
--- a/Core/HLE/sceNetAdhoc.cpp
+++ b/Core/HLE/sceNetAdhoc.cpp
@@ -18,56 +18,71 @@
// 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 "Core/HLE/HLE.h"
-#include "Core/HLE/sceNetAdhoc.h"
-
-#include "sceKernel.h"
-#include "sceKernelThread.h"
-#include "sceKernelMutex.h"
-#include "sceUtility.h"
-
-#include "net/resolve.h"
+// This is a direct port of colorbird code from http://code.google.com/p/aemu/
+// All credit goes to him!
+#include "proAdhoc.h"
enum {
- ERROR_NET_ADHOC_INVALID_SOCKET_ID = 0x80410701,
- ERROR_NET_ADHOC_INVALID_ADDR = 0x80410702,
- 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_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_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,
+ 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;
@@ -76,546 +91,2115 @@ static bool netAdhocInited;
static bool netAdhocctlInited;
static bool netAdhocMatchingInited;
-// These might come in handy in the future, if PPSSPP ever supports wifi/ad-hoc..
-struct SceNetAdhocctlParams {
- s32_le channel; //which ad-hoc channel to connect to
- char name[8]; //connection name
- u8 bssid[6]; //BSSID of the connection?
- char nickname[128]; //PSP's nickname?
-};
-
struct AdhocctlHandler {
- u32 entryPoint;
- u32 argument;
+ u32 entryPoint;
+ u32 argument;
};
static std::map adhocctlHandlers;
void __NetAdhocInit() {
- netAdhocInited = false;
- netAdhocctlInited = false;
- netAdhocMatchingInited = false;
- adhocctlHandlers.clear();
+ netAdhocInited = false;
+ netAdhocctlInited = false;
+ netAdhocMatchingInited = false;
+ adhocctlHandlers.clear();
}
-void __NetAdhocShutdown() {
+int sceNetAdhocTerm();
+int sceNetAdhocctlTerm();
+int sceNetAdhocMatchingTerm();
+
+void __NetAdhocShutdown() {
+ sceNetAdhocTerm();
+ sceNetAdhocctlTerm();
+ sceNetAdhocMatchingTerm();
}
void __NetAdhocDoState(PointerWrap &p) {
- auto s = p.Section("sceNetAdhoc", 1);
- if (!s)
- return;
+ auto s = p.Section("sceNetAdhoc", 1);
+ if (!s)
+ return;
- p.Do(netAdhocInited);
- p.Do(netAdhocctlInited);
- p.Do(netAdhocMatchingInited);
- p.Do(adhocctlHandlers);
+ 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;
+ u32 args[3] = { 0, 0, 0 };
+ args[0] = flag;
+ args[1] = error;
- for (std::map::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); ++it) {
- args[2] = it->second.argument;
+ for (std::map::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); ++it) {
+ args[2] = it->second.argument;
- __KernelDirectMipsCall(it->second.entryPoint, NULL, args, 3, true);
- }
+ __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() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocInit()");
- if (netAdhocInited)
- return ERROR_NET_ADHOC_ALREADY_INITIALIZED;
- netAdhocInited = true;
+ // Library uninitialized
+ INFO_LOG(SCENET, "sceNetAdhocInit()");
+ if(!netAdhocInited) {
+ // Clear Translator Memory
+ memset(&pdp, 0, sizeof(pdp));
+ memset(&ptp, 0, sizeof(ptp));
- return 0;
+ // 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;
- netAdhocctlInited = true;
-
- return 0;
+ INFO_LOG(SCENET, "sceNetAdhocctlInit(%i, %i, %08x)", stackSize, prio, productAddr);
+ if (netAdhocctlInited) {
+ return ERROR_NET_ADHOCCTL_ALREADY_INITIALIZED;
+ }else{
+ if(initNetwork((SceNetAdhocctlAdhocId *)Memory::GetPointer(productAddr)) == 0){
+ netAdhocctlInited = true;
+ eventHandlerUpdate = CoreTiming::RegisterEvent("HandlerUpdateEvent", __handlerUpdateCallback);
+ friendFinderRunning = true;
+ 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) {
- WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlGetState(%x)", ptrToStatus);
- if (Memory::IsValidAddress(ptrToStatus))
- Memory::Write_U32(0, ptrToStatus);
- else
- ERROR_LOG(SCENET, "UNTESTED sceNetAdhocctlGetState(%x): Tried to write invalid location", ptrToStatus);
-
- return 0;
+ // 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;
}
-// Always return -1 since we don't have any real networking...
+/**
+ * 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);
- return -1;
+ INFO_LOG(SCENET, "sceNetAdhocPdpCreate(%s, %d, %d, %d)", 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;
}
-// TODO: Should we really write the struct if we're disconnected?
+/**
+ * Get Adhoc Parameter
+ * @param parameter OUT: Adhoc Parameter
+ * @return 0 on success or... ADHOCCTL_NOT_INITIALIZED, ADHOCCTL_INVALID_ARG
+ */
int sceNetAdhocctlGetParameter(u32 paramAddr) {
- WARN_LOG(SCENET, "UNTESTED sceNetAdhocctlGetParameter(%x)", paramAddr);
- struct SceNetAdhocctlParams params;
- params.channel = 0;
- for (int i = 0; i < 6; i++)
- params.bssid[i] = i + 1;
- strcpy(params.name, "");
- strcpy(params.nickname, "");
+ INFO_LOG(SCENET, "sceNetAdhocctlGetParameter(%u)",paramAddr);
+ // Library initialized
+ if(netAdhocctlInited) {
+ // Valid Arguments
+ if(Memory::IsValidAddress(paramAddr)) {
+ // Copy Parameter
+ Memory::WriteStruct(paramAddr,¶meter);
+ // Return Success
+ return 0;
+ }
- if (Memory::IsValidAddress(paramAddr))
- Memory::WriteStruct(paramAddr, ¶ms);
+ // Invalid Arguments
+ return ERROR_NET_ADHOCCTL_INVALID_ARG;
+ }
- return ERROR_NET_ADHOCCTL_DISCONNECTED;
+ // Library uninitialized
+ return ERROR_NET_ADHOCCTL_NOT_INITIALIZED;
}
-int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, void *dataLength, u32 timeout, int nonBlock) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPdpSend(%d, %s, %d, %p, %p, %d, %d)", id, mac, port, data, dataLength, timeout, nonBlock);
- return -1;
+/**
+ * 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, (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;
+
}
-// Return -1 packets since we don't have networking yet..
-int sceNetAdhocPdpRecv(int id, const char *mac, u32 port, void *data, void *dataLength, u32 timeout, int nonBlock) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPdpRecv(%d, %s, %d, %p, %p, %d, %d)", id, mac, port, data, dataLength, timeout, nonBlock);
- return -1;
+/**
+ * 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
+ 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;
+ 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;
+ 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);
- return 0;
+ INFO_LOG(SCENET, "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;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetAdhocId(%x)", productStructAddr);
+ return 0;
}
int sceNetAdhocctlScan() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlScan()");
- __UpdateAdhocctlHandlers(0, ERROR_NET_ADHOCCTL_WLAN_SWITCH_OFF);
- return 0;
+ // 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() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetScanInfo()");
- return 0;
+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));
+ bool foundHandler = false;
+ u32 retval = 0;
+ struct AdhocctlHandler handler;
+ memset(&handler, 0, sizeof(handler));
- while (adhocctlHandlers.find(retval) != adhocctlHandlers.end())
- ++retval;
+ while (adhocctlHandlers.find(retval) != adhocctlHandlers.end())
+ ++retval;
- handler.entryPoint = handlerPtr;
- handler.argument = handlerArg;
+ handler.entryPoint = handlerPtr;
+ handler.argument = handlerArg;
- for (std::map::iterator it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); it++) {
- if (it->second.entryPoint == handlerPtr) {
- foundHandler = true;
- break;
- }
- }
+ for (std::map::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);
- }
+ 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;
+ // The id to return is the number of handlers currently registered
+ return retval;
}
-int sceNetAdhocctlConnect(u32 ptrToGroupName) {
- if (Memory::IsValidAddress(ptrToGroupName)) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlConnect(groupName=%s)", Memory::GetCharPointer(ptrToGroupName));
- } else {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlConnect(%x)", ptrToGroupName);
- }
- __UpdateAdhocctlHandlers(0, ERROR_NET_ADHOCCTL_WLAN_SWITCH_OFF);
-
- return 0;
-}
u32 sceNetAdhocctlDisconnect() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlDisconnect()");
- __UpdateAdhocctlHandlers(0, ERROR_NET_ADHOCCTL_WLAN_SWITCH_OFF);
+ // 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));
- return 0;
+ // 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;
+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()");
- netAdhocctlInited = false;
+ INFO_LOG(SCENET, "sceNetAdhocctlTerm()");
+ if(netAdhocctlInited){
+ netAdhocctlInited = false;
+ friendFinderRunning = false;
+ if(friendFinderThread.joinable()){
+ friendFinderThread.join();
+ }
+ // Free sttuf here
+ closesocket(metasocket);
+ metasocket = INVALID_SOCKET;
+#ifdef _MSC_VER
+ WSACleanup();
+#endif
+ }
- return 0;
+ return 0;
}
int sceNetAdhocctlGetNameByAddr(const char *mac, u32 nameAddr) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetNameByAddr(%s, %08x)", mac, nameAddr);
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetNameByAddr(%s, %08x)", mac, nameAddr);
+ return -1;
}
int sceNetAdhocctlJoin(u32 scanInfoAddr) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlJoin(%08x)", scanInfoAddr);
- return -1;
+ 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;
+ 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);
- return -1;
+ INFO_LOG(SCENET, "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(¶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)) {
+ INFO_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;
+ 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;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlJoinEnterGameMode(%s, %s, %i, %i)", groupName, macAddr, timeout, unknown2);
+ return -1;
}
int sceNetAdhocTerm() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocTerm()");
- // Seems to return this when called a second time after being terminated without another initialisation
- if(!netAdhocInited)
- return SCE_KERNEL_ERROR_LWMUTEX_NOT_FOUND;
- netAdhocInited = false;
+ INFO_LOG(SCENET, "sceNetAdhocTerm()");
+ // Library is initialized
+ if(netAdhocInited) {
+ // Delete PDP Sockets
+ deleteAllPDP();
- return 0;
+ // 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;
+ 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;
+
+/**
+ * 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) {
+ // INFO_LOG(SCENET,"sceNetAdhocGetPtpStat(%u,%u)",structSize,structAddr);
+ // Spams a lot
+ 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;
}
-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;
+
+/**
+ * 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) {
+ INFO_LOG(SCENET, "sceNetAdhocPtpOpen(%s,%d,%s,%d,%d,%d,%d,%d)", srcmac, sport,
+ dstmac,dport,bufsize, rexmt_int, rexmt_cnt, unknown);
+ 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 = 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) {
+ // 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;
}
-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;
+
+/**
+ * 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 = Memory::GetStruct(peerMacAddrPtr);
+ }
+ uint16_t * port = NULL;
+ if(Memory::IsValidAddress(peerPortPtr)){
+ port = (uint16_t *)Memory::GetPointer(peerPortPtr);
+ }
+ INFO_LOG(SCENET, "sceNetAdhocPtpAccept(%d,%s,%d,%u,%d)",id, addr->data,*port,timeout,
+ flag);
+ // 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));
+#ifdef _MSC_VER
+ int peeraddrlen = sizeof(peeraddr);
+#else
+ uint32_t peeraddrlen = sizeof(peeraddr);
+#endif
+ // Local Address Information
+ sockaddr_in local;
+ memset(&local, 0, sizeof(local));
+#ifdef _MSC_VER
+ int locallen = sizeof(local);
+#else
+ uint32_t locallen = sizeof(local);
+#endif
+
+ // 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) < 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;
}
-int sceNetAdhocPtpConnect(int id, int timeout, int nonblock) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpConnect(%i, %i, %i)", id, timeout, nonblock);
- return -1;
+
+/**
+ * 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) {
+ // 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 && errorcode == EINPROGRESS) {
+ // 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));
+#ifdef _MSC_VER
+ int peerlen = sizeof(peer);
+#else
+ uint32_t peerlen = sizeof(peer);
+#endif
+ // Wait for Connection
+ while((timeout == 0 || ( (uint32_t)(real_time_now()*1000.0) - starttime) < 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) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpClose(%i, %i)", id, unknown);
- return 0;
+ INFO_LOG(SCENET,"sceNetAdhocPtpClose(%d,%d)",id,unknown);
+ // 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;
}
-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;
+
+/**
+ * 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) {
+ INFO_LOG(SCENET, "sceNetAdhocPtpListen(%s,%d,%d,%d,%d,%d,%d)",
+ srcmac,sport,bufsize,rexmt_int,rexmt_cnt,backlog,unk);
+ // 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;
}
-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;
+/**
+ * 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) {
+ 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;
}
-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;
+
+/**
+ * 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 data, u32 dataSizeAddr, int timeout, int flag) {
+ void * buf = (void *)Memory::GetPointer(data);
+ 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) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocPtpFlush(%i, %i, %i)", id, timeout, nonblock);
- return 0;
+ INFO_LOG(SCENET,"sceNetAdhocPtpFlush(%d,%d,%d)", id, timeout, nonblock);
+ // 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;
+ 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;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeCreateReplica(%s, %08x, %i)", mac, data, size);
+ return -1;
}
int sceNetAdhocGameModeUpdateMaster() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeUpdateMaster()");
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeUpdateMaster()");
+ return -1;
}
int sceNetAdhocGameModeDeleteMaster() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeDeleteMaster()");
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeDeleteMaster()");
+ return -1;
}
int sceNetAdhocGameModeUpdateReplica(int id, u32 infoAddr) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeUpdateReplica(%i, %08x)", id, infoAddr);
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeUpdateReplica(%i, %08x)", id, infoAddr);
+ return -1;
}
int sceNetAdhocGameModeDeleteReplica(int id) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeDeleteReplica(%i)", id);
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGameModeDeleteReplica(%i)", id);
+ return -1;
}
int sceNetAdhocGetSocketAlert() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGetSocketAlert()");
- return 0;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocGetSocketAlert()");
+ return 0;
}
int sceNetAdhocMatchingInit(u32 memsize) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingInit(%08x)", memsize);
- if (netAdhocMatchingInited)
- return ERROR_NET_ADHOC_MATCHING_ALREADY_INITIALIZED;
- netAdhocMatchingInited = true;
+ // Uninitialized Library
+ if(!netAdhocMatchingInited) {
+ // Save Fake Pool Size
+ fakePoolSize = memsize;
- return 0;
+ // 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;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingTerm()");
+ netAdhocMatchingInited = false;
- return 0;
+ return 0;
}
// Presumably returns a "matchingId".
-int sceNetAdhocMatchingCreate(int mode, int maxPeers, int port, int bufSize, int helloDelay, int pingDelay, int initCount, int msgDelay, u32 callbackAddr) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingCreate(%i, %i, %i, %i, %i, %i, %i, %i, %08x)", mode, maxPeers, port, bufSize, helloDelay, pingDelay, initCount, msgDelay, callbackAddr);
- return -1;
+int sceNetAdhocMatchingCreate(int mode, int maxnum, int port, int rxbuflen, int hello_int, int keepalive_int, int init_count, int rexmt_int, u32 callbackAddr) {
+ INFO_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;
+ 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;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingStop(%i)", matchingId);
+ return -1;
}
int sceNetAdhocMatchingDelete(int matchingId) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingDelete(%i)", matchingId);
- return -1;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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;
+ 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;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingAbortSendData(%i, %s)", matchingId, mac);
+ return -1;
}
int sceNetAdhocMatchingGetPoolMaxAlloc() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetPoolMaxAlloc()");
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetPoolMaxAlloc()");
+ return -1;
}
int sceNetAdhocMatchingGetPoolStat() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetPoolStat()");
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocMatchingGetPoolStat()");
+ return -1;
}
const HLEFunction sceNetAdhoc[] = {
- {0xE1D621D7, WrapU_V, "sceNetAdhocInit"},
- {0xA62C6F57, WrapI_V, "sceNetAdhocTerm"},
- {0x0AD043ED, WrapI_U, "sceNetAdhocctlConnect"},
- {0x6f92741b, WrapI_CUIU, "sceNetAdhocPdpCreate"},
- {0xabed3790, WrapI_ICUVVUI, "sceNetAdhocPdpSend"},
- {0xdfe53e03, WrapI_ICUVVUI, "sceNetAdhocPdpRecv"},
- {0x7f27bb5e, WrapI_II, "sceNetAdhocPdpDelete"},
- {0xc7c1fc57, WrapI_IU, "sceNetAdhocGetPdpStat"},
- {0x157e6225, WrapI_II, "sceNetAdhocPtpClose"},
- {0x4da4c788, WrapI_IUUII, "sceNetAdhocPtpSend"},
- {0x877f6d66, WrapI_CICIIIII, "sceNetAdhocPtpOpen"},
- {0x8bea2b3e, WrapI_IUUII, "sceNetAdhocPtpRecv"},
- {0x9df81198, WrapI_IUUII, "sceNetAdhocPtpAccept"},
- {0xe08bdac1, WrapI_CIIIIII, "sceNetAdhocPtpListen"},
- {0xfc6fc07b, WrapI_III, "sceNetAdhocPtpConnect"},
- {0x9ac2eeac, WrapI_III, "sceNetAdhocPtpFlush"},
- {0xb9685118, WrapI_IU, "sceNetAdhocGetPtpStat"},
- {0x3278ab0c, WrapI_CUI, "sceNetAdhocGameModeCreateReplica"},
- {0x98c204c8, WrapI_V, "sceNetAdhocGameModeUpdateMaster"},
- {0xfa324b4e, WrapI_IU, "sceNetAdhocGameModeUpdateReplica"},
- {0xa0229362, WrapI_V, "sceNetAdhocGameModeDeleteMaster"},
- {0x0b2228e9, WrapI_I, "sceNetAdhocGameModeDeleteReplica"},
- {0x7F75C338, WrapI_UI, "sceNetAdhocGameModeCreateMaster"},
- {0x73bfd52d, WrapI_II, "sceNetAdhocSetSocketAlert"},
- {0x4d2ce199, WrapI_V, "sceNetAdhocGetSocketAlert"},
- {0x7a662d6b, WrapI_UIII, "sceNetAdhocPollSocket"},
+ {0xE1D621D7, WrapU_V, "sceNetAdhocInit"},
+ {0xA62C6F57, WrapI_V, "sceNetAdhocTerm"},
+ {0x0AD043ED, WrapI_U, "sceNetAdhocctlConnect"},
+ {0x6f92741b, WrapI_CUIU, "sceNetAdhocPdpCreate"},
+ {0xabed3790, WrapI_ICUVIII, "sceNetAdhocPdpSend"},
+ {0xdfe53e03, WrapI_IVVVVUI, "sceNetAdhocPdpRecv"},
+ {0x7f27bb5e, WrapI_II, "sceNetAdhocPdpDelete"},
+ {0xc7c1fc57, WrapI_IU, "sceNetAdhocGetPdpStat"},
+ {0x157e6225, WrapI_II, "sceNetAdhocPtpClose"},
+ {0x4da4c788, WrapI_IUUII, "sceNetAdhocPtpSend"},
+ {0x877f6d66, WrapI_CICIIIII, "sceNetAdhocPtpOpen"},
+ {0x8bea2b3e, WrapI_IUUII, "sceNetAdhocPtpRecv"},
+ {0x9df81198, WrapI_IUUII, "sceNetAdhocPtpAccept"},
+ {0xe08bdac1, WrapI_CIIIIII, "sceNetAdhocPtpListen"},
+ {0xfc6fc07b, WrapI_III, "sceNetAdhocPtpConnect"},
+ {0x9ac2eeac, WrapI_III, "sceNetAdhocPtpFlush"},
+ {0xb9685118, WrapI_UU, "sceNetAdhocGetPtpStat"},
+ {0x3278ab0c, WrapI_CUI, "sceNetAdhocGameModeCreateReplica"},
+ {0x98c204c8, WrapI_V, "sceNetAdhocGameModeUpdateMaster"},
+ {0xfa324b4e, WrapI_IU, "sceNetAdhocGameModeUpdateReplica"},
+ {0xa0229362, WrapI_V, "sceNetAdhocGameModeDeleteMaster"},
+ {0x0b2228e9, WrapI_I, "sceNetAdhocGameModeDeleteReplica"},
+ {0x7F75C338, WrapI_UI, "sceNetAdhocGameModeCreateMaster"},
+ {0x73bfd52d, WrapI_II, "sceNetAdhocSetSocketAlert"},
+ {0x4d2ce199, WrapI_V, "sceNetAdhocGetSocketAlert"},
+ {0x7a662d6b, WrapI_UIII, "sceNetAdhocPollSocket"},
};
const HLEFunction sceNetAdhocMatching[] = {
- {0x2a2a1e07, WrapI_U, "sceNetAdhocMatchingInit"},
- {0x7945ecda, WrapI_V, "sceNetAdhocMatchingTerm"},
- {0xca5eda6f, WrapI_IIIIIIIIU, "sceNetAdhocMatchingCreate"},
- {0x93ef3843, WrapI_IIIIIIU, "sceNetAdhocMatchingStart"},
- {0x32b156b3, WrapI_I, "sceNetAdhocMatchingStop"},
- {0xf16eaf4f, WrapI_I, "sceNetAdhocMatchingDelete"},
- {0x5e3d4b79, WrapI_ICIU, "sceNetAdhocMatchingSelectTarget"},
- {0xea3c6108, WrapI_IC, "sceNetAdhocMatchingCancelTarget"},
- {0x8f58bedf, WrapI_ICIU, "sceNetAdhocMatchingCancelTargetWithOpt"},
- {0xb5d96c2a, WrapI_IUU, "sceNetAdhocMatchingGetHelloOpt"},
- {0xb58e61b7, WrapI_IIU, "sceNetAdhocMatchingSetHelloOpt"},
- {0xc58bcd9e, WrapI_IUU, "sceNetAdhocMatchingGetMembers"},
- {0xf79472d7, WrapI_ICIU, "sceNetAdhocMatchingSendData"},
- {0xec19337d, WrapI_IC, "sceNetAdhocMatchingAbortSendData"},
- {0x40F8F435, WrapI_V, "sceNetAdhocMatchingGetPoolMaxAlloc"},
- {0x9c5cfb7d, WrapI_V, "sceNetAdhocMatchingGetPoolStat"},
+ {0x2a2a1e07, WrapI_U, "sceNetAdhocMatchingInit"},
+ {0x7945ecda, WrapI_V, "sceNetAdhocMatchingTerm"},
+ {0xca5eda6f, WrapI_IIIIIIIIU, "sceNetAdhocMatchingCreate"},
+ {0x93ef3843, WrapI_IIIIIIU, "sceNetAdhocMatchingStart"},
+ {0x32b156b3, WrapI_I, "sceNetAdhocMatchingStop"},
+ {0xf16eaf4f, WrapI_I, "sceNetAdhocMatchingDelete"},
+ {0x5e3d4b79, WrapI_ICIU, "sceNetAdhocMatchingSelectTarget"},
+ {0xea3c6108, WrapI_IC, "sceNetAdhocMatchingCancelTarget"},
+ {0x8f58bedf, WrapI_ICIU, "sceNetAdhocMatchingCancelTargetWithOpt"},
+ {0xb5d96c2a, WrapI_IUU, "sceNetAdhocMatchingGetHelloOpt"},
+ {0xb58e61b7, WrapI_IIU, "sceNetAdhocMatchingSetHelloOpt"},
+ {0xc58bcd9e, WrapI_IUU, "sceNetAdhocMatchingGetMembers"},
+ {0xf79472d7, WrapI_ICIU, "sceNetAdhocMatchingSendData"},
+ {0xec19337d, WrapI_IC, "sceNetAdhocMatchingAbortSendData"},
+ {0x40F8F435, WrapI_V, "sceNetAdhocMatchingGetPoolMaxAlloc"},
+ {0x9c5cfb7d, WrapI_V, "sceNetAdhocMatchingGetPoolStat"},
};
int sceNetAdhocctlExitGameMode() {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlExitGameMode()");
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlExitGameMode()");
+ return -1;
}
int sceNetAdhocctlGetGameModeInfo(u32 infoAddr) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetGameModeInfo(%08x)", infoAddr);
- return -1;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetGameModeInfo(%08x)", infoAddr);
+ return -1;
}
+
int sceNetAdhocctlGetPeerList(u32 sizeAddr, u32 bufAddr) {
- ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetPeerList(%08x, %08x)", sizeAddr, bufAddr);
- 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;
+ ERROR_LOG(SCENET, "UNIMPL sceNetAdhocctlGetPeerList(%s, %08x, %08x)", nickName, sizeAddr, bufAddr);
+ return -1;
}
const HLEFunction sceNetAdhocctl[] = {
- {0xE26F226E, WrapU_IIU, "sceNetAdhocctlInit"},
- {0x9D689E13, WrapI_V, "sceNetAdhocctlTerm"},
- {0x20B317A0, WrapU_UU, "sceNetAdhocctlAddHandler"},
- {0x6402490B, WrapU_U, "sceNetAdhocctlDelHandler"},
- {0x34401D65, WrapU_V, "sceNetAdhocctlDisconnect"},
- {0x0ad043ed, WrapI_U, "sceNetAdhocctlConnect"},
- {0x08fff7a0, WrapI_V, "sceNetAdhocctlScan"},
- {0x75ecd386, WrapI_U, "sceNetAdhocctlGetState"},
- {0x8916c003, WrapI_CU, "sceNetAdhocctlGetNameByAddr"},
- {0xded9d28e, WrapI_U, "sceNetAdhocctlGetParameter"},
- {0x81aee1be, WrapI_V, "sceNetAdhocctlGetScanInfo"},
- {0x5e7f79c9, WrapI_U, "sceNetAdhocctlJoin"},
- {0x8db83fdc, WrapI_CIU, "sceNetAdhocctlGetPeerInfo"},
- {0xec0635c1, WrapI_C, "sceNetAdhocctlCreate"},
- {0xa5c055ce, WrapI_CIIUII, "sceNetAdhocctlCreateEnterGameMode"},
- {0x1ff89745, WrapI_CCII, "sceNetAdhocctlJoinEnterGameMode"},
- {0xcf8e084d, WrapI_V, "sceNetAdhocctlExitGameMode"},
- {0xe162cb14, WrapI_UU, "sceNetAdhocctlGetPeerList"},
- {0x362cbe8f, WrapI_U, "sceNetAdhocctlGetAdhocId"},
- {0x5a014ce0, WrapI_U, "sceNetAdhocctlGetGameModeInfo"},
- {0x99560abe, WrapI_CUU, "sceNetAdhocctlGetAddrByName"},
- {0xb0b80e80, 0, "sceNetAdhocctlCreateEnterGameModeMin"}, // ??
+ {0xE26F226E, WrapU_IIU, "sceNetAdhocctlInit"},
+ {0x9D689E13, WrapI_V, "sceNetAdhocctlTerm"},
+ {0x20B317A0, WrapU_UU, "sceNetAdhocctlAddHandler"},
+ {0x6402490B, WrapU_U, "sceNetAdhocctlDelHandler"},
+ {0x34401D65, WrapU_V, "sceNetAdhocctlDisconnect"},
+ {0x0ad043ed, WrapI_U, "sceNetAdhocctlConnect"},
+ {0x08fff7a0, WrapI_V, "sceNetAdhocctlScan"},
+ {0x75ecd386, WrapI_U, "sceNetAdhocctlGetState"},
+ {0x8916c003, WrapI_CU, "sceNetAdhocctlGetNameByAddr"},
+ {0xded9d28e, WrapI_U, "sceNetAdhocctlGetParameter"},
+ {0x81aee1be, WrapI_UU, "sceNetAdhocctlGetScanInfo"},
+ {0x5e7f79c9, WrapI_U, "sceNetAdhocctlJoin"},
+ {0x8db83fdc, WrapI_CIU, "sceNetAdhocctlGetPeerInfo"},
+ {0xec0635c1, WrapI_C, "sceNetAdhocctlCreate"},
+ {0xa5c055ce, WrapI_CIIUII, "sceNetAdhocctlCreateEnterGameMode"},
+ {0x1ff89745, WrapI_CCII, "sceNetAdhocctlJoinEnterGameMode"},
+ {0xcf8e084d, WrapI_V, "sceNetAdhocctlExitGameMode"},
+ {0xe162cb14, WrapI_UU, "sceNetAdhocctlGetPeerList"},
+ {0x362cbe8f, WrapI_U, "sceNetAdhocctlGetAdhocId"},
+ {0x5a014ce0, WrapI_U, "sceNetAdhocctlGetGameModeInfo"},
+ {0x99560abe, WrapI_CUU, "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"},
+ {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);
+ RegisterModule("sceNetAdhoc", ARRAY_SIZE(sceNetAdhoc), sceNetAdhoc);
+ RegisterModule("sceNetAdhocMatching", ARRAY_SIZE(sceNetAdhocMatching), sceNetAdhocMatching);
+ RegisterModule("sceNetAdhocDiscover", ARRAY_SIZE(sceNetAdhocDiscover), sceNetAdhocDiscover);
+ RegisterModule("sceNetAdhocctl", ARRAY_SIZE(sceNetAdhocctl), sceNetAdhocctl);
}
diff --git a/Core/HLE/sceNetAdhoc.h b/Core/HLE/sceNetAdhoc.h
index 2c7c1ec89b..1529557593 100644
--- a/Core/HLE/sceNetAdhoc.h
+++ b/Core/HLE/sceNetAdhoc.h
@@ -24,3 +24,6 @@ void Register_sceNetAdhoc();
void __NetAdhocInit();
void __NetAdhocShutdown();
void __NetAdhocDoState(PointerWrap &p);
+
+// I have to call this from netdialog
+int sceNetAdhocctlCreate(const char * groupName);
diff --git a/README.md b/README.md
index b8b61e8815..1dfa7b2863 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,29 @@
+ADHOC SUPPORT
+=============
+This is based on coldbird code: http://code.google.com/p/aemu/ All Credit goes
+to him!
+
+Status
+------
+Code is a complete mess and it's not fully functional yet, I still need to implement
+some functions and add a upnp lib(really important for people with routers).
+
+I did test it with some games(emulator <-> real psp with the server running locally)
+and it's looking good:
+* Worms Open Warfare: Ran just fine, I was able to play a whole match without problems
+* Monster Hunter Freedom Unite: Runs fine too. Gathering Hall and embarking on quests Works
+* Dissidia Duodecim 012: Doesn't work. It requires some functions that I haven't implemented
+yet. Also, it uses a port < 1000 and thats reserved for admin apps on linux, running the emu
+as sudo "solves" it, but it's far from ideal.
+* Pacman World Rally: Works too.
+
+Update (Kyhel) :
+---------------
+* Now compiles on both Mac OSX and Windows. For more details on how to play and build
+go to see there http://forums.ppsspp.org/showthread.php?tid=3595&pid=59241#pid59241
+* Got it tested windows <-> mac osx <-> psp, it works
+* Monster Hunter 3rd HD works too, as well as God Eater Burst.
+
PPSSPP - a fast and portable PSP emulator
=========================================