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 =========================================