/** * 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 proNetAdhocPtpRecv(int id, void * buf, int * len, uint32_t timeout, int flag) { // Library is initialized if(_init) { // 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 sceNetInetSetsockopt(socket->id, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); // Acquire Network Lock _acquireNetworkLock(); // Receive Data int received = sceNetInetRecv(socket->id, buf, *len, ((flag) ? (INET_MSG_DONTWAIT) : (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 && sceNetInetGetErrno() == EAGAIN) { // Blocking Situation if(flag) return ADHOC_WOULD_BLOCK; // Timeout return ADHOC_TIMEOUT; } // Change Socket State socket->state = PTP_STATE_CLOSED; // Disconnected return ADHOC_DISCONNECTED; } // Invalid Arguments return ADHOC_INVALID_ARG; } // Invalid Socket return ADHOC_INVALID_SOCKET_ID; } // Library is uninitialized return ADHOC_NOT_INITIALIZED; }
/** * 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(SceSize args, void * argp) { // 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; // Finder Loop while(_init == 1) { // Acquire Network Lock _acquireNetworkLock(); // Ping Server if((sceKernelGetSystemTimeWide() - lastping) >= ADHOCCTL_PING_TIMEOUT) { // Update Ping Time lastping = sceKernelGetSystemTimeWide(); // Prepare Packet uint8_t opcode = OPCODE_PING; // Send Ping to Server sceNetInetSend(_metasocket, &opcode, 1, INET_MSG_DONTWAIT); } // Send Chat Messages while(popFromOutbox(chat.message)) { // Send Chat to Server sceNetInetSend(_metasocket, &chat, sizeof(chat), INET_MSG_DONTWAIT); } // Wait for Incoming Data int received = sceNetInetRecv(_metasocket, rx + rxpos, sizeof(rx) - rxpos, INET_MSG_DONTWAIT); // Free Network Lock _freeNetworkLock(); // Received Data if(received > 0) { // Fix Position rxpos += received; // Log Incoming Traffic #ifdef DEBUG printk("Received %d Bytes of Data from Server\n", received); #endif } // 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 _thread_status = ADHOCCTL_STATE_CONNECTED; // Notify Event Handlers int i = 0; for(; i < ADHOCCTL_MAX_HANDLER; i++) { // Active Handler if(_event_handler[i] != NULL) _event_handler[i](ADHOCCTL_EVENT_CONNECT, 0, _event_args[i]); } // 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 if(stricmp((char *)packet->name.data, "ME") == 0) strcpy((char *)packet->name.data, "NOT ME"); // Add Incoming Chat to HUD addChatLog((char *)packet->name.data, 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 #ifdef DEBUG printk("Incoming Peer Data...\n"); #endif // 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 #ifdef DEBUG printk("Incoming Peer Data Delete Request...\n"); #endif // 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 #ifdef DEBUG printk("Incoming Group Information...\n"); #endif // 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 #ifdef DEBUG printk("Incoming Scan complete response...\n"); #endif // Change State _thread_status = ADHOCCTL_STATE_DISCONNECTED; // Notify Event Handlers 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; } } // Reception Update required if((sceKernelGetSystemTimeWide() - lastreceptionupdate) > 5000000) { // Clone Time into Last Update Field lastreceptionupdate = sceKernelGetSystemTimeWide(); // Update Reception Level union SceNetApctlInfo info; if(sceNetApctlGetInfo(PSP_NET_APCTL_INFO_STRENGTH, &info) >= 0) setReceptionPercentage((int)info.strength); else setReceptionPercentage(0); } // Delay Thread (10ms) sceKernelDelayThread(10000); } // Set WLAN HUD Reception to 0% on Shutdown setReceptionPercentage(0); // Notify Caller of Shutdown _init = -1; // Log Shutdown printk("End of Friend Finder Thread\n"); // Reset Thread Status _thread_status = ADHOCCTL_STATE_DISCONNECTED; // Kill Thread sceKernelExitDeleteThread(0); // Return Success return 0; }
/** * 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 proNetAdhocPdpSend(int id, const SceNetEtherAddr * daddr, uint16_t dport, const void * data, int len, uint32_t timeout, int flag) { // Library is initialized if(_init) { // 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 #ifdef DEBUG printk("Attempting PDP Send to %02X:%02X:%02X:%02X:%02X:%02X on Port %u\n", daddr->data[0], daddr->data[1], daddr->data[2], daddr->data[3], daddr->data[4], daddr->data[5], dport); #endif // Schedule Timeout Removal if(flag) timeout = 0; // Apply Send Timeout Settings to Socket sceNetInetSetsockopt(socket->id, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); // Single Target if(!_isBroadcastMAC(daddr)) { // Fill in Target Structure SceNetInetSockaddrIn target; target.sin_family = AF_INET; target.sin_port = sceNetHtons(dport); // Get Peer IP if(_resolveMAC((SceNetEtherAddr *)daddr, &target.sin_addr) == 0) { // Acquire Network Lock _acquireNetworkLock(); // Send Data int sent = sceNetInetSendto(socket->id, data, len, ((flag != 0) ? (INET_MSG_DONTWAIT) : (0)), (SceNetInetSockaddr *)&target, sizeof(target)); // Free Network Lock _freeNetworkLock(); // Sent Data if(sent == len) { // Success return 0; } // Blocking Situation if(flag) return ADHOC_WOULD_BLOCK; // Timeout return 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 _acquirePeerLock(); // Iterate Peers SceNetAdhocctlPeerInfo * peer = _getInternalPeerList(); for(; peer != NULL; peer = peer->next) { // Fill in Target Structure SceNetInetSockaddrIn target; target.sin_family = AF_INET; target.sin_addr = peer->ip_addr; target.sin_port = sceNetHtons(dport); // Send Data sceNetInetSendto(socket->id, data, len, ((flag != 0) ? (INET_MSG_DONTWAIT) : (0)), (SceNetInetSockaddr *)&target, sizeof(target)); } // Free Peer Lock _freePeerLock(); // Free Network Lock _freeNetworkLock(); // Broadcast never fails! return 0; } } // Invalid Destination Address return ADHOC_INVALID_ADDR; } // Invalid Argument return ADHOC_INVALID_ARG; } // Invalid Socket ID return ADHOC_INVALID_SOCKET_ID; } // Invalid Data Length return ADHOC_INVALID_DATALEN; } // Invalid Destination Port return ADHOC_INVALID_PORT; } // Library is uninitialized return ADHOC_NOT_INITIALIZED; }
/** * 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(const SceNetAdhocctlAdhocId * adhoc_id, const char * server_ip) { // WLAN Switch Check if(sceWlanGetSwitchState() == 1) { // Initialize Access Point Control if(sceNetApctlInit(0x1800, 0x30) == 0) { // Attempt Counter int attemptmax = 10; // Attempt Number int attempt = 0; // Attempt Connection Setup for(; attempt < attemptmax; attempt++) { // Start Connection if(sceNetApctlConnect(_hotspot) == 0) { // Wait for Connection int statebefore = 0; int state = 0; while(state != 4) { // Query State int getstate = sceNetApctlGetState(&state); // Log State Change if(statebefore != state) printk("New Connection State: %d\n", state); // Query Success if(getstate == 0 && state != 4) { // Wait for Retry sceKernelDelayThread(1000000); } // Query Error else break; // Save Before State statebefore = state; } // Connected if(state == 4) { // Create Friend Finder Socket int socket = sceNetInetSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Created Socket if(socket > 0) { // Enable Port Re-use sceNetInetSetsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &_one, sizeof(_one)); sceNetInetSetsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &_one, sizeof(_one)); // Apply Receive Timeout Settings to Socket // uint32_t timeout = ADHOCCTL_RECV_TIMEOUT; // sceNetInetSetsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); // Server IP uint32_t ip = 0; // Initialize DNS Resolver if(sceNetResolverInit() == 0) { // Create DNS Resolver unsigned char rbuf[512]; int rid = 0; if(sceNetResolverCreate(&rid, rbuf, sizeof(rbuf)) == 0) { // Resolve Domain if(sceNetResolverStartNtoA(rid, server_ip, &ip, 500000, 2) != 0) { // Attempt IP Conversion sceNetInetInetAton(server_ip, &ip); } // Delete DNS Resolver sceNetResolverDelete(rid); } // Shutdown DNS Resolver sceNetResolverTerm(); } // Prepare Server Address SceNetInetSockaddrIn addr; addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_addr = ip; addr.sin_port = sceNetHtons(ADHOCCTL_METAPORT); // Connect to Server if(sceNetInetConnect(socket, (SceNetInetSockaddr *)&addr, sizeof(addr)) == 0) { // Save Meta Socket _metasocket = socket; // Save Product Code _product_code = *adhoc_id; // Clear Event Handler memset(_event_handler, 0, sizeof(_event_handler[0]) * ADHOCCTL_MAX_HANDLER); memset(_event_args, 0, sizeof(_event_args[0]) * ADHOCCTL_MAX_HANDLER); // Clear Internal Control Status memset(&_parameter, 0, sizeof(_parameter)); // Read PSP Player Name sceUtilityGetSystemParamString(PSP_SYSTEMPARAM_ID_STRING_NICKNAME, (char *)_parameter.nickname.data, ADHOCCTL_NICKNAME_LEN); // Read Adhoc Channel sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_ADHOC_CHANNEL, &_parameter.channel); // Fake Channel Number 1 on Automatic Channel if(_parameter.channel == 0) _parameter.channel = 1; // Read PSP MAC Address sceWlanGetEtherAddr((void *)&_parameter.bssid.mac_addr.data); // Prepare Login Packet SceNetAdhocctlLoginPacketC2S packet; // Set Packet Opcode packet.base.opcode = OPCODE_LOGIN; // Set MAC Address packet.mac = _parameter.bssid.mac_addr; // Set Nickname packet.name = _parameter.nickname; // Set Game Product ID memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN); // Acquire Network Layer Lock _acquireNetworkLock(); // Send Login Packet sceNetInetSend(_metasocket, &packet, sizeof(packet), INET_MSG_DONTWAIT); // Free Network Layer Lock _freeNetworkLock(); // Load UPNP Library _upnp_uid = sceKernelLoadModule("ms0:/kd/pspnet_miniupnc.prx", 0, NULL); // Start UPNP Library int status = 0; sceKernelStartModule(_upnp_uid, 0, NULL, &status, NULL); // Return Success return 0; } // Delete Socket sceNetInetClose(socket); } // Close Hotspot Connection sceNetApctlDisconnect(); } } } // Terminate Access Point Control sceNetApctlTerm(); } } // Generic Error return -1; }
/** * Adhoc Emulator PDP Socket Poller (Select Equivalent) * @param sds Poll Socket Descriptor Array * @param nsds Array Item Count * @param timeout Timeout in Microseconds * @param flags Nonblocking Flag * @return Number of affected Sockets on success or... ADHOC_NOT_INITIALIZED, ADHOC_INVALID_SOCKET_ID, ADHOC_INVALID_ARG, ADHOC_TIMEOUT, ADHOC_THREAD_ABORTED, ADHOC_EXCEPTION_EVENT, NET_NO_SPACE, NET_INTERNAL */ int proNetAdhocPollSocket(SceNetAdhocPollSd * sds, int nsds, uint32_t timeout, int flags) { // Library is initialized if(_init) { // Valid Arguments if(sds != NULL && nsds > 0) { // Socket Check int i = 0; for(; i < nsds; i++) { // Invalid Socket if(sds[i].id < 1 || sds[i].id > 255 || _pdp[sds[i].id - 1] == NULL) return ADHOC_INVALID_SOCKET_ID; } // Allocate Infrastructure Memory SceNetInetPollfd * isds = (SceNetInetPollfd *)malloc(sizeof(SceNetInetPollfd) * nsds); // Allocated Memory if(isds != NULL) { // Clear Memory memset(isds, 0, sizeof(SceNetInetPollfd) * nsds); // Translate Polling Flags to Infrastructure for(i = 0; i < nsds; i++) { // Fill in Infrastructure Socket ID isds[i].fd = _pdp[sds[i].id - 1]->id; // Send Event if(sds[i].events & ADHOC_EV_SEND) isds[i].events |= INET_POLLWRNORM; // Receive Event if(sds[i].events & ADHOC_EV_RECV) isds[i].events |= INET_POLLRDNORM; } // Nonblocking Mode if(flags) timeout = 0; // Timeout Translation (Micro to Milliseconds) else { // Convert Timeout timeout /= 1000; // Prevent Nonblocking Mode if(timeout == 0) timeout = 1; } // Acquire Network Lock _acquireNetworkLock(); // Poll Sockets int affectedsockets = sceNetInetPoll(isds, nsds, timeout); // Free Network Lock _freeNetworkLock(); // Sockets affected if(affectedsockets > 0) { // Translate Polling Results to Adhoc for(i = 0; i < nsds; i++) { // Send Event if(isds[i].revents & INET_POLLWRNORM) sds[i].revents |= ADHOC_EV_SEND; // Receive Event if(isds[i].revents & INET_POLLRDNORM) sds[i].revents |= ADHOC_EV_RECV; } } // Free Memory free(isds); // Blocking Mode (Nonblocking Mode returns 0, even on Success) if(!flags) { // Success if(affectedsockets > 0) return affectedsockets; // Timeout return ADHOC_TIMEOUT; } } // No Events generated return 0; } // Invalid Argument return ADHOC_INVALID_ARG; } // Library is uninitialized return ADHOC_NOT_INITIALIZED; }