/** * Handle Cancel Packet * @param context Matching Context Pointer * @param sendermac Packet Sender MAC * @param length Packet Length */ void _actOnCancelPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sendermac, uint32_t length) { // Find Peer SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, sendermac); // Get Parent SceNetAdhocMatchingMemberInternal * parent = _findParent(context); // Get Outgoing Join Request SceNetAdhocMatchingMemberInternal * request = _findOutgoingRequest(context); // Get P2P Partner SceNetAdhocMatchingMemberInternal * p2p = _findP2P(context); // Interest Condition fulfilled if(peer != NULL) { // Complete Packet Header available if(length >= 5) { // Extract Optional Data Length int optlen = 0; memcpy(&optlen, context->rxbuf + 1, sizeof(optlen)); // Complete Valid Packet available if(optlen >= 0 && length >= (5 + optlen)) { // Set Default Null Data void * opt = NULL; // Extract Optional Data Pointer if(optlen > 0) opt = context->rxbuf + 5; // Child Mode if(context->mode == ADHOC_MATCHING_MODE_CHILD) { // Join Request denied if(request == peer) { // Spawn Deny Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_DENY, sendermac, optlen, opt); // Delete Peer from List _deletePeer(context, peer); } // Kicked from Room else if(parent == peer) { // Iterate Peers SceNetAdhocMatchingMemberInternal * item = context->peerlist; for(; item != NULL; item = item->next) { // Established Peer if(item->state == ADHOC_MATCHING_PEER_CHILD || item->state == ADHOC_MATCHING_PEER_PARENT) { // Spawn Leave / Kick Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_LEAVE, &item->mac, optlen, opt); } } // Delete Peer from List _clearPeerList(context); } } // Parent Mode else if(context->mode == ADHOC_MATCHING_MODE_PARENT) { // Cancel Join Request if(peer->state == ADHOC_MATCHING_PEER_INCOMING_REQUEST) { // Spawn Request Cancel Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_CANCEL, sendermac, optlen, opt); // Delete Peer from List _deletePeer(context, peer); } // Leave Room else if(peer->state == ADHOC_MATCHING_PEER_CHILD) { // Spawn Leave / Kick Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_LEAVE, sendermac, optlen, opt); // Delete Peer from List _deletePeer(context, peer); } } // P2P Mode else { // Join Request denied if(request == peer) { // Spawn Deny Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_DENY, sendermac, optlen, opt); // Delete Peer from List _deletePeer(context, peer); } // Kicked from Room else if(p2p == peer) { // Spawn Leave / Kick Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_LEAVE, sendermac, optlen, opt); // Delete Peer from List _deletePeer(context, peer); } // Cancel Join Request else if(peer->state == ADHOC_MATCHING_PEER_INCOMING_REQUEST) { // Spawn Request Cancel Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_CANCEL, sendermac, optlen, opt); // Delete Peer from List _deletePeer(context, peer); } } } } } }
/** * Select / Accept Matching Target * @param id Matching Context ID * @param target Target MAC * @param optlen Length of Optional Data * @param opt Optional Data * @return 0 on success or... ADHOC_MATCHING_NOT_INITIALIZED, ADHOC_MATCHING_INVALID_ARG, ADHOC_MATCHING_INVALID_ID, ADHOC_MATCHING_NOT_RUNNING, ADHOC_MATCHING_UNKNOWN_TARGET, ADHOC_MATCHING_INVALID_OPTLEN, ADHOC_MATCHING_TARGET_NOT_READY, ADHOC_MATCHING_EXCEED_MAXNUM, ADHOC_MATCHING_NO_SPACE, ADHOC_MATCHING_REQUEST_IN_PROGRESS, ADHOC_MATCHING_ALREADY_ESTABLISHED */ int proNetAdhocMatchingSelectTarget(int id, const SceNetEtherAddr * target, int optlen, const void * opt) { // Initialized Library if(_init == 1) { // Valid Arguments if(target != NULL) { // Find Matching Context for ID SceNetAdhocMatchingContext * context = _findMatchingContext(id); // Found Matching Context if(context != NULL) { // Running Context if(context->running) { // Search Result SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, (SceNetEtherAddr *)target); // Found Peer in List if(peer != NULL) { // Valid Optional Data Length if((optlen == 0 && opt == NULL) || (optlen > 0 && opt != NULL)) { // Host Mode if(context->mode == ADHOC_MATCHING_MODE_PARENT) { // Already Connected if(peer->state == ADHOC_MATCHING_PEER_CHILD) return ADHOC_MATCHING_ALREADY_ESTABLISHED; // Not enough space if(_countChildren(context) == (context->maxpeers - 1)) return ADHOC_MATCHING_EXCEED_MAXNUM; // Requesting Peer if(peer->state == ADHOC_MATCHING_PEER_INCOMING_REQUEST) { // Accept Peer in Group peer->state = ADHOC_MATCHING_PEER_CHILD; // Send Accept Confirmation to Peer _sendAcceptMessage(context, peer, optlen, opt); // Tell Children about new Sibling _sendBirthMessage(context, peer); // Return Success return 0; } } // Client Mode else if(context->mode == ADHOC_MATCHING_MODE_CHILD) { // Already connected if(_findParent(context) != NULL) return ADHOC_MATCHING_ALREADY_ESTABLISHED; // Outgoing Request in Progress if(_findOutgoingRequest(context) != NULL) return ADHOC_MATCHING_REQUEST_IN_PROGRESS; // Valid Offer if(peer->state == ADHOC_MATCHING_PEER_OFFER) { // Switch into Join Request Mode peer->state = ADHOC_MATCHING_PEER_OUTGOING_REQUEST; // Send Join Request to Peer _sendJoinRequest(context, peer, optlen, opt); // Return Success return 0; } } // P2P Mode else { // Already connected if(_findP2P(context) != NULL) return ADHOC_MATCHING_ALREADY_ESTABLISHED; // Outgoing Request in Progress if(_findOutgoingRequest(context) != NULL) return ADHOC_MATCHING_REQUEST_IN_PROGRESS; // Join Request Mode if(peer->state == ADHOC_MATCHING_PEER_OFFER) { // Switch into Join Request Mode peer->state = ADHOC_MATCHING_PEER_OUTGOING_REQUEST; // Send Join Request to Peer _sendJoinRequest(context, peer, optlen, opt); // Return Success return 0; } // Requesting Peer else if(peer->state == ADHOC_MATCHING_PEER_INCOMING_REQUEST) { // Accept Peer in Group peer->state = ADHOC_MATCHING_PEER_P2P; // Send Accept Confirmation to Peer _sendAcceptMessage(context, peer, optlen, opt); // Return Success return 0; } } // How did this happen?! It shouldn't! return ADHOC_MATCHING_TARGET_NOT_READY; } // Invalid Optional Data Length return ADHOC_MATCHING_INVALID_OPTLEN; } // Peer not found return ADHOC_MATCHING_UNKNOWN_TARGET; } // Idle Context return ADHOC_MATCHING_NOT_RUNNING; } // Invalid Matching ID return ADHOC_MATCHING_INVALID_ID; } // Invalid Arguments return ADHOC_MATCHING_INVALID_ARG; } // Uninitialized Library return ADHOC_MATCHING_NOT_INITIALIZED; }
/** * Handle Accept Packet * @param context Matching Context Pointer * @param sendermac Packet Sender MAC * @param length Packet Length */ void _actOnAcceptPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sendermac, uint32_t length) { // Not a parent context if(context->mode != ADHOC_MATCHING_MODE_PARENT) { // Don't have a master yet if((context->mode == ADHOC_MATCHING_MODE_CHILD && _findParent(context) == NULL) || (context->mode == ADHOC_MATCHING_MODE_P2P && _findP2P(context) == NULL)) { // Complete Packet Header available if(length >= 9) { // Extract Optional Data Length int optlen = 0; memcpy(&optlen, context->rxbuf + 1, sizeof(optlen)); // Extract Sibling Count int siblingcount = 0; memcpy(&siblingcount, context->rxbuf + 5, sizeof(siblingcount)); // Complete Valid Packet available if(optlen >= 0 && length >= (9 + optlen + sizeof(SceNetEtherAddr) * siblingcount)) { // Set Default Null Data void * opt = NULL; // Extract Optional Data Pointer if(optlen > 0) opt = context->rxbuf + 9; // Sibling MAC Array Null Data SceNetEtherAddr * siblings = NULL; // Extract Optional Sibling MAC Array if(siblingcount > 0) siblings = (SceNetEtherAddr *)(context->rxbuf + 9 + optlen); // Find Outgoing Request SceNetAdhocMatchingMemberInternal * request = _findOutgoingRequest(context); // We are waiting for a answer to our request... if(request != NULL) { // Find Peer SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, sendermac); // It's the answer we wanted! if(request == peer) { // Change Peer State peer->state = (context->mode == ADHOC_MATCHING_MODE_CHILD) ? (ADHOC_MATCHING_PEER_PARENT) : (ADHOC_MATCHING_PEER_P2P); // Remove Unneeded Peer Information _postAcceptCleanPeerList(context); // Add Sibling Peers if(context->mode == ADHOC_MATCHING_MODE_CHILD) _postAcceptAddSiblings(context, siblingcount, siblings); // IMPORTANT! The Event Order here is ok! // Internally the Event Stack appends to the front, so the order will be switched around. // Spawn Established Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_ESTABLISHED, sendermac, 0, NULL); // Spawn Accept Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_ACCEPT, sendermac, optlen, opt); } } } } } } }
/** * Handle Join Packet * @param context Matching Context Pointer * @param sendermac Packet Sender MAC * @param length Packet Length */ void _actOnJoinPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sendermac, uint32_t length) { // Not a child mode context if(context->mode != ADHOC_MATCHING_MODE_CHILD) { // We still got a unoccupied slot in our room (Parent / P2P) if((context->mode == ADHOC_MATCHING_MODE_PARENT && _countChildren(context) < (context->maxpeers - 1)) || (context->mode == ADHOC_MATCHING_MODE_P2P && _findP2P(context) == NULL)) { // Complete Packet Header available if(length >= 5) { // Extract Optional Data Length int optlen = 0; memcpy(&optlen, context->rxbuf + 1, sizeof(optlen)); // Complete Valid Packet available if(optlen >= 0 && length >= (5 + optlen)) { // Set Default Null Data void * opt = NULL; // Extract Optional Data Pointer if(optlen > 0) opt = context->rxbuf + 5; // Find Peer SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, sendermac); // If we got the peer in the table already and are a parent, there is nothing left to be done. // This is because the only way a parent can know of a child is via a join request... // If we thus know of a possible child, then we already had a previous join request thus no need for double tapping. if(peer != NULL && context->mode == ADHOC_MATCHING_MODE_PARENT) return; // New Peer if(peer == NULL) { // Allocate Memory peer = (SceNetAdhocMatchingMemberInternal *)_malloc(sizeof(SceNetAdhocMatchingMemberInternal)); // Allocated Memory if(peer != NULL) { // Clear Memory memset(peer, 0, sizeof(SceNetAdhocMatchingMemberInternal)); // Copy Sender MAC peer->mac = *sendermac; // Set Peer State peer->state = ADHOC_MATCHING_PEER_INCOMING_REQUEST; // Initialize Ping Timer peer->lastping = sceKernelGetSystemTimeWide(); // Link Peer into List peer->next = context->peerlist; context->peerlist = peer; // Spawn Request Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_REQUEST, sendermac, optlen, opt); // Return Success return; } } // Existing Peer (this case is only reachable for P2P mode) else { // Set Peer State peer->state = ADHOC_MATCHING_PEER_INCOMING_REQUEST; // Spawn Request Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_REQUEST, sendermac, optlen, opt); // Return Success return; } } } } // Auto-Reject Player _sendCancelPacket(context, sendermac, 0, NULL); } }
/** * Handle Hello Packet * @param context Matching Context Pointer * @param sendermac Packet Sender MAC * @param length Packet Length */ void _actOnHelloPacket(SceNetAdhocMatchingContext * context, SceNetEtherAddr * sendermac, uint32_t length) { // Interested in Hello Data if((context->mode == ADHOC_MATCHING_MODE_CHILD && _findParent(context) == NULL) || (context->mode == ADHOC_MATCHING_MODE_P2P && _findP2P(context) == NULL)) { // Complete Packet Header available if(length >= 5) { // Extract Optional Data Length int optlen = 0; memcpy(&optlen, context->rxbuf + 1, sizeof(optlen)); // Complete Valid Packet available if(optlen >= 0 && length >= (5 + optlen)) { // Set Default Null Data void * opt = NULL; // Extract Optional Data Pointer if(optlen > 0) opt = context->rxbuf + 5; // Find Peer SceNetAdhocMatchingMemberInternal * peer = _findPeer(context, sendermac); // Peer not found if(peer == NULL) { // Allocate Memory peer = (SceNetAdhocMatchingMemberInternal *)_malloc(sizeof(SceNetAdhocMatchingMemberInternal)); // Allocated Memory if(peer != NULL) { // Clear Memory memset(peer, 0, sizeof(SceNetAdhocMatchingMemberInternal)); // Copy Sender MAC peer->mac = *sendermac; // Set Peer State peer->state = ADHOC_MATCHING_PEER_OFFER; // Initialize Ping Timer peer->lastping = sceKernelGetSystemTimeWide(); // Link Peer into List peer->next = context->peerlist; context->peerlist = peer; } } // Peer available now if(peer != NULL) { // Spawn Hello Event _spawnLocalEvent(context, ADHOC_MATCHING_EVENT_HELLO, sendermac, optlen, opt); } } } } }
/** * Matching IO Handler Thread * @param args sizeof(SceNetAdhocMatchingContext *) * @param argp SceNetAdhocMatchingContext * * @return Exit Point is never reached... */ int _matchingInputThread(uint32_t args, void * argp) { // Cast Context SceNetAdhocMatchingContext * context = *(SceNetAdhocMatchingContext **)argp; // Last Ping uint64_t lastping = 0; // Last Hello uint64_t lasthello = 0; // Run while needed... while(context->input_thid > 0) { // Hello Message Sending Context with unoccupied Slots if((context->mode == ADHOC_MATCHING_MODE_PARENT && _countChildren(context) < (context->maxpeers - 1)) || (context->mode == ADHOC_MATCHING_MODE_P2P && _findP2P(context) == NULL)) { // Hello Message Broadcast necessary because of Hello Interval if((sceKernelGetSystemTimeWide() - lasthello) >= context->hello_int) { // Broadcast Hello Message _broadcastHelloMessage(context); // Update Hello Timer lasthello = sceKernelGetSystemTimeWide(); } } // Ping Required if((sceKernelGetSystemTimeWide() - lastping) >= context->keepalive_int) { // Broadcast Ping Message _broadcastPingMessage(context); // Update Ping Timer lastping = sceKernelGetSystemTimeWide(); } // Messages on Stack ready for processing if(context->input_stack != NULL && context->input_stack_lock == 0) { // Claim Stack context->input_stack_lock = 1; // Iterate Message List ThreadMessage * msg = context->input_stack; for(; msg != NULL; msg = msg->next) { // Default Optional Data void * opt = NULL; // Grab Optional Data if(msg->optlen > 0) opt = ((void *)msg) + sizeof(ThreadMessage); // Send Accept Packet if(msg->opcode == ADHOC_MATCHING_PACKET_ACCEPT) _sendAcceptPacket(context, &msg->mac, msg->optlen, opt); // Send Join Packet else if(msg->opcode == ADHOC_MATCHING_PACKET_JOIN) _sendJoinPacket(context, &msg->mac, msg->optlen, opt); // Send Cancel Packet else if(msg->opcode == ADHOC_MATCHING_PACKET_CANCEL) _sendCancelPacket(context, &msg->mac, msg->optlen, opt); // Send Bulk Data Packet else if(msg->opcode == ADHOC_MATCHING_PACKET_BULK) _sendBulkDataPacket(context, &msg->mac, msg->optlen, opt); // Send Birth Packet else if(msg->opcode == ADHOC_MATCHING_PACKET_BIRTH) _sendBirthPacket(context, &msg->mac); // Cancel Bulk Data Transfer (does nothing as of now as we fire and forget anyway) // else if(msg->opcode == ADHOC_MATCHING_PACKET_BULK_ABORT) blabla; } // Clear IO Message Stack _clearStack(context, ADHOC_MATCHING_INPUT_STACK); // Free Stack context->input_stack_lock = 0; } // Receive PDP Datagram SceNetEtherAddr sendermac; uint16_t senderport; int rxbuflen = context->rxbuflen; int recvresult = sceNetAdhocPdpRecv(context->socket, &sendermac, &senderport, context->rxbuf, &rxbuflen, 0, ADHOC_F_NONBLOCK); // Received Data from a Sender that interests us if(recvresult == 0 && rxbuflen > 0 && context->port == senderport) { // Log Receive Success printk("Received %d Bytes (Opcode: %d)\n", rxbuflen, context->rxbuf[0]); // Ping Packet if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_PING) _actOnPingPacket(context, &sendermac); // Hello Packet else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_HELLO) _actOnHelloPacket(context, &sendermac, rxbuflen); // Join Packet else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_JOIN) _actOnJoinPacket(context, &sendermac, rxbuflen); // Accept Packet else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_ACCEPT) _actOnAcceptPacket(context, &sendermac, rxbuflen); // Cancel Packet else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_CANCEL) _actOnCancelPacket(context, &sendermac, rxbuflen); // Bulk Data Packet else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_BULK) _actOnBulkDataPacket(context, &sendermac, rxbuflen); // Birth Packet else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_BIRTH) _actOnBirthPacket(context, &sendermac, rxbuflen); // Death Packet else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_DEATH) _actOnDeathPacket(context, &sendermac, rxbuflen); // Bye Packet else if(context->rxbuf[0] == ADHOC_MATCHING_PACKET_BYE) _actOnByePacket(context, &sendermac); // Ignore Incoming Trash Data } // Handle Peer Timeouts _handleTimeout(context); // Share CPU Time sceKernelDelayThread(10000); } // Send Bye Messages _sendByePacket(context); // Free Peer List Buffer _clearPeerList(context); // Delete Pointer Reference (and notify caller about finished cleanup) context->input_thid = 0; // Terminate Thread sceKernelExitDeleteThread(0); // Return Zero to shut up Compiler (never reached anyway) return 0; }
/** * Get Member List * @return 0 on success or... ADHOC_MATCHING_NOT_INITIALIZED, ADHOC_MATCHING_INVALID_ARG, ADHOC_MATCHING_INVALID_ID, ADHOC_MATCHING_NOT_RUNNING */ int proNetAdhocMatchingGetMembers(int id, int * buflen, SceNetAdhocMatchingMember * buf) { // Initialized Library if(_init == 1) { // Find Matching Context SceNetAdhocMatchingContext * context = _findMatchingContext(id); // Found Context if(context != NULL) { // Running Context if(context->running) { // Length Buffer available if(buflen != NULL) { // Number of Connected Peers uint32_t peercount = _countConnectedPeers(context); // Calculate Connected Peer Bytesize int available = sizeof(SceNetAdhocMatchingMember) * peercount; // Length Returner Mode if(buf == NULL) { // Get Connected Peer Count *buflen = available; } // Normal Mode else { // Fix Negative Length if((*buflen) < 0) *buflen = 0; // Fix Oversize Request if((*buflen) > available) *buflen = available; // Clear Memory memset(buf, 0, *buflen); // Calculate Requested Peer Count int requestedpeers = (*buflen) / sizeof(SceNetAdhocMatchingMember); // Filled Request Counter int filledpeers = 0; // Add Self-Peer if(requestedpeers > 0) { // Add Local MAC buf[filledpeers++].addr = context->mac; // Room for more than local peer if(requestedpeers > 1) { // P2P Mode if(context->mode == ADHOC_MATCHING_MODE_P2P) { // Find P2P Brother SceNetAdhocMatchingMemberInternal * p2p = _findP2P(context); // P2P Brother found if(p2p != NULL) { // Add P2P Brother MAC buf[filledpeers++].addr = p2p->mac; } } // Parent or Child Mode else { // Iterate Peer List SceNetAdhocMatchingMemberInternal * peer = context->peerlist; for(; peer != NULL && filledpeers < requestedpeers; peer = peer->next) { // Parent Mode if(context->mode == ADHOC_MATCHING_MODE_PARENT) { // Interested in Children (Michael Jackson Style) if(peer->state == ADHOC_MATCHING_PEER_CHILD) { // Add Child MAC buf[filledpeers++].addr = peer->mac; } } // Children Mode else { // Interested in Parent & Siblings if(peer->state == ADHOC_MATCHING_PEER_CHILD || peer->state == ADHOC_MATCHING_PEER_PARENT) { // Add Peer MAC buf[filledpeers++].addr = peer->mac; } } } } // Link Result List int i = 0; for(; i < filledpeers - 1; i++) { // Link Next Element buf[i].next = &buf[i + 1]; } } } // Fix Buffer Size *buflen = sizeof(SceNetAdhocMatchingMember) * filledpeers; } // Return Success return 0; } // Invalid Arguments return ADHOC_MATCHING_INVALID_ARG; } // Context not running return ADHOC_MATCHING_NOT_RUNNING; } // Invalid Matching ID return ADHOC_MATCHING_INVALID_ID; } // Uninitialized Library return ADHOC_MATCHING_NOT_INITIALIZED; }