1 // Copyright (c) 2013- PPSSPP Project.
2
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
11
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
19 // proAdhoc
20
21 // This is a direct port of Coldbird's code from http://code.google.com/p/aemu/
22 // All credit goes to him!
23
24 #include "ppsspp_config.h"
25
26 #if defined(_WIN32)
27 #include <WinSock2.h>
28 #include "Common/CommonWindows.h"
29 #endif
30
31 #if !defined(_WIN32)
32 #include <unistd.h>
33 #include <netinet/tcp.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/types.h>
37 #if !PPSSPP_PLATFORM(SWITCH)
38 #include <ifaddrs.h>
39 #endif // !PPSSPP_PLATFORM(SWITCH)
40 #endif
41
42 #ifndef MSG_NOSIGNAL
43 // Default value to 0x00 (do nothing) in systems where it's not supported.
44 #define MSG_NOSIGNAL 0x00
45 #endif
46
47 #if defined(HAVE_LIBNX) || PPSSPP_PLATFORM(SWITCH)
48 #undef __BSD_VISIBLE
49 #define __BSD_VISIBLE 1
50 #include <switch.h>
51 #define TCP_MAXSEG 2
52 #endif // defined(HAVE_LIBNX) || PPSSPP_PLATFORM(SWITCH)
53
54 #include <mutex>
55 #include <cstring>
56
57 #include "Common/Data/Text/I18n.h"
58 #include "Common/Thread/ThreadUtil.h"
59 #include "Common/Data/Text/Parsers.h"
60
61 #include "Common/Serialize/SerializeFuncs.h"
62 #include "Common/TimeUtil.h"
63 #include "Core/Core.h"
64 #include "Core/Host.h"
65 #include "Core/HLE/sceKernelInterrupt.h"
66 #include "Core/HLE/sceKernelThread.h"
67 #include "Core/HLE/sceKernelMemory.h"
68 #include "Core/HLE/sceNetAdhoc.h"
69 #include "Core/Instance.h"
70 #include "proAdhoc.h"
71
72 #if PPSSPP_PLATFORM(SWITCH) && !defined(INADDR_NONE)
73 // Missing toolchain define
74 #define INADDR_NONE 0xFFFFFFFF
75 #endif
76
77 uint16_t portOffset;
78 uint32_t minSocketTimeoutUS;
79 uint32_t fakePoolSize = 0;
80 SceNetAdhocMatchingContext * contexts = NULL;
81 char* dummyPeekBuf64k = NULL;
82 int dummyPeekBuf64kSize = 65536;
83 int one = 1;
84 std::atomic<bool> friendFinderRunning(false);
85 SceNetAdhocctlPeerInfo * friends = NULL;
86 SceNetAdhocctlScanInfo * networks = NULL;
87 SceNetAdhocctlScanInfo * newnetworks = NULL;
88 u64 adhocctlStartTime = 0;
89 bool isAdhocctlNeedLogin = false;
90 bool isAdhocctlBusy = false;
91 int adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
92 int adhocctlCurrentMode = ADHOCCTL_MODE_NONE;
93 int adhocConnectionType = ADHOC_CONNECT;
94
95 int gameModeSocket = (int)INVALID_SOCKET; // UDP/PDP socket? on Master only?
96 int gameModeBuffSize = 0;
97 u8* gameModeBuffer = nullptr;
98 GameModeArea masterGameModeArea;
99 std::vector<GameModeArea> replicaGameModeAreas;
100 std::vector<SceNetEtherAddr> requiredGameModeMacs;
101 std::vector<SceNetEtherAddr> gameModeMacs;
102 std::map<SceNetEtherAddr, u16_le> gameModePeerPorts;
103
104 int actionAfterAdhocMipsCall;
105 int actionAfterMatchingMipsCall;
106
107 // Broadcast MAC
108 uint8_t broadcastMAC[ETHER_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
109
110 std::atomic<int> metasocket((int)INVALID_SOCKET);
111 SceNetAdhocctlParameter parameter;
112 SceNetAdhocctlAdhocId product_code;
113 std::thread friendFinderThread;
114 std::recursive_mutex peerlock;
115 AdhocSocket* adhocSockets[MAX_SOCKET];
116 bool isOriPort = false;
117 bool isLocalServer = false;
118 SockAddrIN4 g_adhocServerIP;
119 SockAddrIN4 g_localhostIP;
120 sockaddr LocalIP;
121 int defaultWlanChannel = PSP_SYSTEMPARAM_ADHOC_CHANNEL_11; // Don't put 0(Auto) here, it needed to be a valid/actual channel number
122
123 static std::mutex chatLogLock;
124 static std::vector<std::string> chatLog;
125 static int chatMessageGeneration = 0;
126 static int chatMessageCount = 0;
127
isMacMatch(const SceNetEtherAddr * addr1,const SceNetEtherAddr * addr2)128 bool isMacMatch(const SceNetEtherAddr* addr1, const SceNetEtherAddr* addr2) {
129 // Ignoring the 1st byte since there are games (ie. Gran Turismo) who tamper with the 1st byte of OUI to change the unicast/multicast bit
130 return (memcmp(((const char*)addr1)+1, ((const char*)addr2)+1, ETHER_ADDR_LEN-1) == 0);
131 }
132
isLocalMAC(const SceNetEtherAddr * addr)133 bool isLocalMAC(const SceNetEtherAddr * addr) {
134 SceNetEtherAddr saddr;
135 getLocalMac(&saddr);
136
137 return isMacMatch(addr, &saddr);
138 }
139
isPDPPortInUse(uint16_t port)140 bool isPDPPortInUse(uint16_t port) {
141 // Iterate Elements
142 for (int i = 0; i < MAX_SOCKET; i++) {
143 auto sock = adhocSockets[i];
144 if (sock != NULL && sock->type == SOCK_PDP)
145 if (sock->data.pdp.lport == port)
146 return true;
147 }
148 // Unused Port
149 return false;
150 }
151
isPTPPortInUse(uint16_t port,bool forListen,SceNetEtherAddr * dstmac,uint16_t dstport)152 bool isPTPPortInUse(uint16_t port, bool forListen, SceNetEtherAddr* dstmac, uint16_t dstport) {
153 // Iterate Sockets
154 for (int i = 0; i < MAX_SOCKET; i++) {
155 auto sock = adhocSockets[i];
156 if (sock != NULL && sock->type == SOCK_PTP)
157 // It's allowed to Listen and Open the same PTP port, But it's not allowed to Listen or Open the same PTP port twice (unless destination mac or port are different).
158 if (sock->data.ptp.lport == port &&
159 ((forListen && sock->data.ptp.state == ADHOC_PTP_STATE_LISTEN) ||
160 (!forListen && sock->data.ptp.state != ADHOC_PTP_STATE_LISTEN &&
161 sock->data.ptp.pport == dstport && dstmac != nullptr && isMacMatch(&sock->data.ptp.paddr, dstmac))))
162 {
163 return true;
164 }
165 }
166 // Unused Port
167 return false;
168 }
169
170 // Replacement for inet_ntoa since it's getting deprecated
ip2str(in_addr in)171 std::string ip2str(in_addr in) {
172 char str[INET_ADDRSTRLEN] = "...";
173 u8* ipptr = (u8*)∈
174 snprintf(str, sizeof(str), "%u.%u.%u.%u", ipptr[0], ipptr[1], ipptr[2], ipptr[3]);
175 return std::string(str);
176 }
177
mac2str(SceNetEtherAddr * mac)178 std::string mac2str(SceNetEtherAddr* mac) {
179 char str[18] = ":::::";
180
181 if (mac != NULL) {
182 snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", mac->data[0], mac->data[1], mac->data[2], mac->data[3], mac->data[4], mac->data[5]);
183 }
184
185 return std::string(str);
186 }
187
addMember(SceNetAdhocMatchingContext * context,SceNetEtherAddr * mac)188 SceNetAdhocMatchingMemberInternal* addMember(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac) {
189 if (context == NULL || mac == NULL) return NULL;
190
191 SceNetAdhocMatchingMemberInternal * peer = findPeer(context, mac);
192 // Already existed
193 if (peer != NULL) {
194 WARN_LOG(SCENET, "Member Peer Already Existed! Updating [%s]", mac2str(mac).c_str());
195 peer->state = 0;
196 peer->sending = 0;
197 peer->lastping = CoreTiming::GetGlobalTimeUsScaled();
198 }
199 // Member is not added yet
200 else {
201 peer = (SceNetAdhocMatchingMemberInternal *)malloc(sizeof(SceNetAdhocMatchingMemberInternal));
202 if (peer != NULL) {
203 memset(peer, 0, sizeof(SceNetAdhocMatchingMemberInternal));
204 peer->mac = *mac;
205 peer->lastping = CoreTiming::GetGlobalTimeUsScaled();
206 peerlock.lock();
207 peer->next = context->peerlist;
208 context->peerlist = peer;
209 peerlock.unlock();
210 }
211 }
212 return peer;
213 }
214
addFriend(SceNetAdhocctlConnectPacketS2C * packet)215 void addFriend(SceNetAdhocctlConnectPacketS2C * packet) {
216 if (packet == NULL) return;
217
218 // Multithreading Lock
219 std::lock_guard<std::recursive_mutex> guard(peerlock);
220
221 SceNetAdhocctlPeerInfo * peer = findFriend(&packet->mac);
222 // Already existed
223 if (peer != NULL) {
224 u32 tmpip = packet->ip;
225 WARN_LOG(SCENET, "Friend Peer Already Existed! Updating [%s][%s][%s]", mac2str(&packet->mac).c_str(), ip2str(*(struct in_addr*)&tmpip).c_str(), packet->name.data); //inet_ntoa(*(in_addr*)&packet->ip)
226 peer->nickname = packet->name;
227 peer->mac_addr = packet->mac;
228 peer->ip_addr = packet->ip;
229 // Update TimeStamp
230 peer->last_recv = CoreTiming::GetGlobalTimeUsScaled();
231 }
232 else {
233 // Allocate Structure
234 peer = (SceNetAdhocctlPeerInfo *)malloc(sizeof(SceNetAdhocctlPeerInfo));
235 // Allocated Structure
236 if (peer != NULL) {
237 // Clear Memory
238 memset(peer, 0, sizeof(SceNetAdhocctlPeerInfo));
239
240 // Save Nickname
241 peer->nickname = packet->name;
242
243 // Save MAC Address
244 peer->mac_addr = packet->mac;
245
246 // Save IP Address
247 peer->ip_addr = packet->ip;
248
249 // TimeStamp
250 peer->last_recv = CoreTiming::GetGlobalTimeUsScaled();
251
252 // Link to existing Peers
253 peer->next = friends;
254
255 // Link into Peerlist
256 friends = peer;
257 }
258 }
259 }
260
findFriend(SceNetEtherAddr * MAC)261 SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC) {
262 if (MAC == NULL) return NULL;
263
264 // Friends Reference
265 SceNetAdhocctlPeerInfo * peer = friends;
266
267 // Iterate Friends
268 for (; peer != NULL; peer = peer->next) {
269 if (isMacMatch(&peer->mac_addr, MAC)) break;
270 }
271
272 // Return found friend
273 return peer;
274 }
275
findFriendByIP(uint32_t ip)276 SceNetAdhocctlPeerInfo* findFriendByIP(uint32_t ip) {
277 // Friends Reference
278 SceNetAdhocctlPeerInfo* peer = friends;
279
280 // Iterate Friends
281 for (; peer != NULL; peer = peer->next) {
282 if (peer->ip_addr == ip) break;
283 }
284
285 // Return found friend
286 return peer;
287 }
288
IsSocketReady(int fd,bool readfd,bool writefd,int * errorcode,int timeoutUS)289 int IsSocketReady(int fd, bool readfd, bool writefd, int* errorcode, int timeoutUS) {
290 fd_set readfds, writefds;
291 timeval tval;
292
293 // Avoid getting Fatal signal 6 (SIGABRT) on linux/android
294 if (fd < 0)
295 return SOCKET_ERROR;
296
297 FD_ZERO(&readfds);
298 writefds = readfds;
299 if (readfd) {
300 FD_SET(fd, &readfds);
301 }
302 if (writefd) {
303 FD_SET(fd, &writefds);
304 }
305 tval.tv_sec = timeoutUS / 1000000;
306 tval.tv_usec = timeoutUS % 1000000;
307
308 int ret = select(fd + 1, readfd? &readfds: nullptr, writefd? &writefds: nullptr, nullptr, &tval);
309 if (errorcode != nullptr)
310 *errorcode = errno;
311
312 return ret;
313 }
314
changeBlockingMode(int fd,int nonblocking)315 void changeBlockingMode(int fd, int nonblocking) {
316 unsigned long on = 1;
317 unsigned long off = 0;
318 #if defined(_WIN32)
319 if (nonblocking) {
320 // Change to Non-Blocking Mode
321 ioctlsocket(fd, FIONBIO, &on);
322 }
323 else {
324 // Change to Blocking Mode
325 ioctlsocket(fd, FIONBIO, &off);
326 }
327 // If they have O_NONBLOCK, use the POSIX way to do it. On POSIX sockets Error code would be EINPROGRESS instead of EAGAIN
328 //#elif defined(O_NONBLOCK)
329 #else
330 int flags = fcntl(fd, F_GETFL, 0);
331 // Fixme: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5.
332 if (flags == -1)
333 flags = 0;
334 if (nonblocking) {
335 // Set Non-Blocking Flag
336 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
337 }
338 else {
339 // Remove Non-Blocking Flag
340 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
341 }
342 // Otherwise, use the old way of doing it (UNIX way). On UNIX sockets Error code would be EAGAIN instead of EINPROGRESS
343 /*#else
344 if (nonblocking) {
345 // Change to Non - Blocking Mode
346 ioctl(fd, FIONBIO, (char*)&on);
347 }
348 else {
349 // Change to Blocking Mode
350 ioctl(fd, FIONBIO, (char*)&off);
351 }*/
352 #endif
353 }
354
countAvailableNetworks(const bool excludeSelf)355 int countAvailableNetworks(const bool excludeSelf) {
356 // Network Count
357 int count = 0;
358
359 // Group Reference
360 SceNetAdhocctlScanInfo * group = networks;
361
362 // Count Groups
363 for (; group != NULL && (!excludeSelf || !isLocalMAC(&group->bssid.mac_addr)); group = group->next) count++;
364
365 // Return Network Count
366 return count;
367 }
368
findGroup(SceNetEtherAddr * MAC)369 SceNetAdhocctlScanInfo * findGroup(SceNetEtherAddr * MAC) {
370 if (MAC == NULL) return NULL;
371
372 // Groups Reference
373 SceNetAdhocctlScanInfo * group = networks;
374
375 // Iterate Groups
376 for (; group != NULL; group = group->next) {
377 if (isMacMatch(&group->bssid.mac_addr, MAC)) break;
378 }
379
380 // Return found group
381 return group;
382 }
383
freeGroupsRecursive(SceNetAdhocctlScanInfo * node)384 void freeGroupsRecursive(SceNetAdhocctlScanInfo * node) {
385 // End of List
386 if (node == NULL) return;
387
388 // Increase Recursion Depth
389 freeGroupsRecursive(node->next);
390
391 // Free Memory
392 free(node);
393 node = NULL;
394 }
395
deleteAllAdhocSockets()396 void deleteAllAdhocSockets() {
397 // Iterate Element
398 for (int i = 0; i < MAX_SOCKET; i++) {
399 // Active Socket
400 if (adhocSockets[i] != NULL) {
401 auto sock = adhocSockets[i];
402 int fd = -1;
403
404 if (sock->type == SOCK_PTP)
405 fd = sock->data.ptp.id;
406 else if (sock->type == SOCK_PDP)
407 fd = sock->data.pdp.id;
408
409 if (fd > 0) {
410 // Close Socket
411 shutdown(fd, SD_BOTH);
412 closesocket(fd);
413 }
414 // Free Memory
415 free(adhocSockets[i]);
416
417 // Delete Reference
418 adhocSockets[i] = NULL;
419 }
420 }
421 }
422
deleteAllGMB()423 void deleteAllGMB() {
424 if (gameModeBuffer) {
425 free(gameModeBuffer);
426 gameModeBuffer = nullptr;
427 gameModeBuffSize = 0;
428 }
429 if (masterGameModeArea.data) {
430 free(masterGameModeArea.data);
431 masterGameModeArea = { 0 };
432 }
433 for (auto& it : replicaGameModeAreas) {
434 if (it.data) {
435 free(it.data);
436 it.data = nullptr;
437 }
438 }
439 replicaGameModeAreas.clear();
440 gameModeMacs.clear();
441 requiredGameModeMacs.clear();
442 }
443
deleteFriendByIP(uint32_t ip)444 void deleteFriendByIP(uint32_t ip) {
445 // Previous Peer Reference
446 SceNetAdhocctlPeerInfo * prev = NULL;
447
448 // Peer Pointer
449 SceNetAdhocctlPeerInfo * peer = friends;
450
451 // Iterate Peers
452 for (; peer != NULL; peer = peer->next) {
453 // Found Peer
454 if (peer->ip_addr == ip) {
455
456 // Multithreading Lock
457 peerlock.lock();
458
459 // Unlink Left (Beginning)
460 /*if (prev == NULL) friends = peer->next;
461
462 // Unlink Left (Other)
463 else prev->next = peer->next;
464 */
465
466 u32 tmpip = peer->ip_addr;
467 INFO_LOG(SCENET, "Removing Friend Peer %s [%s]", mac2str(&peer->mac_addr).c_str(), ip2str(*(struct in_addr *)&tmpip).c_str()); //inet_ntoa(*(in_addr*)&peer->ip_addr)
468
469 // Free Memory
470 //free(peer);
471 //peer = NULL;
472 // Instead of removing it from the list we'll make it timed out since most Matching games are moving group and may still need the peer data thus not recognizing it as Unknown peer
473 peer->last_recv = 0; //CoreTiming::GetGlobalTimeUsScaled();
474
475 // Multithreading Unlock
476 peerlock.unlock();
477
478 // Stop Search
479 break;
480 }
481
482 // Set Previous Reference
483 prev = peer;
484 }
485 }
486
findFreeMatchingID()487 int findFreeMatchingID() {
488 // Minimum Matching ID
489 int min = 1;
490
491 // Maximum Matching ID
492 int max = 0;
493
494 // Find highest Matching ID
495 SceNetAdhocMatchingContext * item = contexts;
496 for (; item != NULL; item = item->next) {
497 // New Maximum
498 if (max < item->id) max = item->id;
499 }
500
501 // Find unoccupied ID
502 int i = min;
503 for (; i < max; i++) {
504 // Found unoccupied ID
505 if (findMatchingContext(i) == NULL) return i;
506 }
507
508 // Append at virtual end
509 return max + 1;
510 }
511
findMatchingContext(int id)512 SceNetAdhocMatchingContext * findMatchingContext(int id) {
513 // Iterate Matching Context List
514 SceNetAdhocMatchingContext * item = contexts;
515 for (; item != NULL; item = item->next) { // Found Matching ID
516 if (item->id == id) return item;
517 }
518
519 // Context not found
520 return NULL;
521 }
522
523 /**
524 * Find Outgoing Request Target Peer
525 * @param context Matching Context Pointer
526 * @return Internal Peer Reference or... NULL
527 */
findOutgoingRequest(SceNetAdhocMatchingContext * context)528 SceNetAdhocMatchingMemberInternal * findOutgoingRequest(SceNetAdhocMatchingContext * context)
529 {
530 // Iterate Peer List for Matching Target
531 SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
532 for (; peer != NULL; peer = peer->next)
533 {
534 // Found Peer in List
535 if (peer->state == PSP_ADHOC_MATCHING_PEER_OUTGOING_REQUEST) return peer;
536 }
537
538 // Peer not found
539 return NULL;
540 }
541
542 /**
543 * Remove unneeded Peer Data after being accepted to a match
544 * @param context Matching Context Pointer
545 */
postAcceptCleanPeerList(SceNetAdhocMatchingContext * context)546 void postAcceptCleanPeerList(SceNetAdhocMatchingContext * context)
547 {
548 int delcount = 0;
549 int peercount = 0;
550 // Acquire Peer Lock
551 peerlock.lock();
552
553 // Iterate Peer List
554 SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
555 while (peer != NULL)
556 {
557 // Save next Peer just in case we have to delete this one
558 SceNetAdhocMatchingMemberInternal * next = peer->next;
559
560 // Unneeded Peer
561 if (peer->state != PSP_ADHOC_MATCHING_PEER_CHILD && peer->state != PSP_ADHOC_MATCHING_PEER_P2P && peer->state != PSP_ADHOC_MATCHING_PEER_PARENT && peer->state != 0) {
562 deletePeer(context, peer);
563 delcount++;
564 }
565
566 // Move to Next Peer
567 peer = next;
568 peercount++;
569 }
570
571 // Free Peer Lock
572 peerlock.unlock();
573
574 INFO_LOG(SCENET, "Removing Unneeded Peers (%i/%i)", delcount, peercount);
575 }
576
577 /**
578 * Add Sibling-Data that was sent with Accept-Datagram
579 * @param context Matching Context Pointer
580 * @param siblingcount Number of Siblings
581 * @param siblings Sibling MAC Array
582 */
postAcceptAddSiblings(SceNetAdhocMatchingContext * context,int siblingcount,SceNetEtherAddr * siblings)583 void postAcceptAddSiblings(SceNetAdhocMatchingContext * context, int siblingcount, SceNetEtherAddr * siblings)
584 {
585 // Cast Sibling MAC Array to uint8_t
586 // PSP CPU has a problem with non-4-byte aligned Pointer Access.
587 // As the buffer of "siblings" isn't properly aligned I don't want to risk a crash.
588 uint8_t * siblings_u8 = (uint8_t *)siblings;
589
590 peerlock.lock();
591 // Iterate Siblings. Reversed so these siblings are added into peerlist in the same order with the peerlist on host/parent side
592 for (int i = siblingcount - 1; i >= 0 ; i--)
593 {
594 SceNetEtherAddr* mac = (SceNetEtherAddr*)(siblings_u8 + sizeof(SceNetEtherAddr) * i);
595
596 auto peer = findPeer(context, mac);
597 // Already exist
598 if (peer != NULL) {
599 // Set Peer State
600 peer->state = PSP_ADHOC_MATCHING_PEER_CHILD;
601 peer->sending = 0;
602 peer->lastping = CoreTiming::GetGlobalTimeUsScaled();
603 WARN_LOG(SCENET, "Updating Sibling Peer %s", mac2str(mac).c_str());
604 }
605 else {
606 // Allocate Memory
607 SceNetAdhocMatchingMemberInternal* sibling = (SceNetAdhocMatchingMemberInternal*)malloc(sizeof(SceNetAdhocMatchingMemberInternal));
608
609 // Allocated Memory
610 if (sibling != NULL)
611 {
612 // Clear Memory
613 memset(sibling, 0, sizeof(SceNetAdhocMatchingMemberInternal));
614
615 // Save MAC Address
616 memcpy(&sibling->mac, mac, sizeof(SceNetEtherAddr));
617
618 // Set Peer State
619 sibling->state = PSP_ADHOC_MATCHING_PEER_CHILD;
620
621 // Initialize Ping Timer
622 sibling->lastping = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0;
623
624 // Link Peer
625 sibling->next = context->peerlist;
626 context->peerlist = sibling;
627
628 // Spawn Established Event. FIXME: ESTABLISHED event should only be triggered for Parent/P2P peer?
629 //spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_ESTABLISHED, &sibling->mac, 0, NULL);
630
631 INFO_LOG(SCENET, "Accepting Sibling Peer %s", mac2str(&sibling->mac).c_str());
632 }
633 }
634 }
635 peerlock.unlock();
636 }
637
638 /**
639 * Count Children Peers (for Parent)
640 * @param context Matching Context Pointer
641 * @return Number of Children
642 */
countChildren(SceNetAdhocMatchingContext * context,const bool excludeTimedout)643 s32_le countChildren(SceNetAdhocMatchingContext * context, const bool excludeTimedout)
644 {
645 // Children Counter
646 s32_le count = 0;
647
648 // Iterate Peer List for Matching Target
649 SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
650 for (; peer != NULL; peer = peer->next)
651 {
652 // Exclude timedout members?
653 if (!excludeTimedout || peer->lastping != 0)
654 // Increase Children Counter
655 if (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) count++;
656 }
657
658 // Return Children Count
659 return count;
660 }
661
662 /**
663 * Find Peer in Context by MAC
664 * @param context Matching Context Pointer
665 * @param mac Peer MAC Address
666 * @return Internal Peer Reference or... NULL
667 */
findPeer(SceNetAdhocMatchingContext * context,SceNetEtherAddr * mac)668 SceNetAdhocMatchingMemberInternal * findPeer(SceNetAdhocMatchingContext * context, SceNetEtherAddr * mac)
669 {
670 if (mac == NULL)
671 return NULL;
672
673 // Iterate Peer List for Matching Target
674 SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
675 for (; peer != NULL; peer = peer->next)
676 {
677 // Found Peer in List
678 if (isMacMatch(&peer->mac, mac))
679 {
680 // Return Peer Pointer
681 return peer;
682 }
683 }
684
685 // Peer not found
686 return NULL;
687 }
688
689 /**
690 * Find Parent Peer
691 * @param context Matching Context Pointer
692 * @return Internal Peer Reference or... NULL
693 */
findParent(SceNetAdhocMatchingContext * context)694 SceNetAdhocMatchingMemberInternal * findParent(SceNetAdhocMatchingContext * context)
695 {
696 // Iterate Peer List for Matching Target
697 SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
698 for (; peer != NULL; peer = peer->next)
699 {
700 // Found Peer in List
701 if (peer->state == PSP_ADHOC_MATCHING_PEER_PARENT) return peer;
702 }
703
704 // Peer not found
705 return NULL;
706 }
707
708 /**
709 * Find P2P Buddy Peer
710 * @param context Matching Context Pointer
711 * @return Internal Peer Reference or... NULL
712 */
findP2P(SceNetAdhocMatchingContext * context,const bool excludeTimedout)713 SceNetAdhocMatchingMemberInternal * findP2P(SceNetAdhocMatchingContext * context, const bool excludeTimedout)
714 {
715 // Iterate Peer List for Matching Target
716 SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
717 for (; peer != NULL; peer = peer->next)
718 {
719 // Exclude timedout members?
720 if (!excludeTimedout || peer->lastping != 0)
721 // Found Peer in List
722 if (peer->state == PSP_ADHOC_MATCHING_PEER_P2P) return peer;
723 }
724
725 // Peer not found
726 return NULL;
727 }
728
729 /**
730 * Delete Peer from List
731 * @param context Matching Context Pointer
732 * @param peer Internal Peer Reference
733 */
deletePeer(SceNetAdhocMatchingContext * context,SceNetAdhocMatchingMemberInternal * & peer)734 void deletePeer(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal *& peer)
735 {
736 // Valid Arguments
737 if (context != NULL && peer != NULL)
738 {
739 peerlock.lock();
740
741 // Previous Peer Reference
742 SceNetAdhocMatchingMemberInternal * previous = NULL;
743
744 // Iterate Peer List
745 SceNetAdhocMatchingMemberInternal * item = context->peerlist;
746 for (; item != NULL; item = item->next)
747 {
748 // Found Peer Match
749 if (item == peer) break;
750
751 // Set Previous Peer
752 previous = item;
753 }
754
755 if (item != NULL) {
756 // Middle Item
757 if (previous != NULL) previous->next = item->next;
758
759 // Beginning Item
760 else context->peerlist = item->next;
761
762 INFO_LOG(SCENET, "Removing Member Peer %s", mac2str(&peer->mac).c_str());
763 }
764
765 // Free Peer Memory
766 free(peer);
767 peer = NULL;
768
769 peerlock.unlock();
770 }
771 }
772
773 /**
774 * Safely Link Thread Message to Event Thread Stack
775 * @param context Matching Context Pointer
776 * @param message Thread Message Pointer
777 */
linkEVMessage(SceNetAdhocMatchingContext * context,ThreadMessage * message)778 void linkEVMessage(SceNetAdhocMatchingContext * context, ThreadMessage * message)
779 {
780 // Lock Access
781 context->eventlock->lock();
782
783 // Link Message
784 message->next = context->event_stack;
785 context->event_stack = message;
786
787 // Unlock Access
788 context->eventlock->unlock();
789 }
790
791 /**
792 * Safely Link Thread Message to IO Thread Stack
793 * @param context Matching Context Pointer
794 * @param message Thread Message Pointer
795 */
linkIOMessage(SceNetAdhocMatchingContext * context,ThreadMessage * message)796 void linkIOMessage(SceNetAdhocMatchingContext * context, ThreadMessage * message)
797 {
798 // Lock Access
799 context->inputlock->lock();
800
801 // Link Message
802 message->next = context->input_stack;
803 context->input_stack = message;
804
805 // Unlock Access
806 context->inputlock->unlock();
807 }
808
809 /**
810 * Send Generic Thread Message
811 * @param context Matching Context Pointer
812 * @param stack ADHOC_MATCHING_EVENT_STACK or ADHOC_MATCHING_INPUT_STACK
813 * @param mac Target MAC
814 * @param opcode Message Opcode
815 * @param optlen Optional Data Length
816 * @param opt Optional Data
817 */
sendGenericMessage(SceNetAdhocMatchingContext * context,int stack,SceNetEtherAddr * mac,int opcode,int optlen,const void * opt)818 void sendGenericMessage(SceNetAdhocMatchingContext * context, int stack, SceNetEtherAddr * mac, int opcode, int optlen, const void * opt)
819 {
820 // Calculate Required Memory Size
821 uint32_t size = sizeof(ThreadMessage) + optlen;
822
823 // Allocate Memory
824 uint8_t * memory = (uint8_t *)malloc(size);
825
826 // Allocated Memory
827 if (memory != NULL)
828 {
829 // Clear Memory
830 memset(memory, 0, size);
831
832 // Cast Header
833 ThreadMessage * header = (ThreadMessage *)memory;
834
835 // Set Message Opcode
836 header->opcode = opcode;
837
838 // Set Peer MAC Address
839 header->mac = *mac;
840
841 // Set Optional Data Length
842 header->optlen = optlen;
843
844 // Set Optional Data
845 memcpy(memory + sizeof(ThreadMessage), opt, optlen);
846
847 // Link Thread Message
848 if (stack == PSP_ADHOC_MATCHING_EVENT_STACK) linkEVMessage(context, header);
849
850 // Link Thread Message to Input Stack
851 else linkIOMessage(context, header);
852
853 // Exit Function
854 return;
855 }
856
857 peerlock.lock();
858 // Out of Memory Emergency Delete
859 auto peer = findPeer(context, mac);
860 deletePeer(context, peer);
861 peerlock.unlock();
862 }
863
864 /**
865 * Send Accept Message from P2P -> P2P or Parent -> Children
866 * @param context Matching Context Pointer
867 * @param peer Target Peer
868 * @param optlen Optional Data Length
869 * @param opt Optional Data
870 */
sendAcceptMessage(SceNetAdhocMatchingContext * context,SceNetAdhocMatchingMemberInternal * peer,int optlen,const void * opt)871 void sendAcceptMessage(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer, int optlen, const void * opt)
872 {
873 // Send Accept Message
874 sendGenericMessage(context, PSP_ADHOC_MATCHING_INPUT_STACK, &peer->mac, PSP_ADHOC_MATCHING_PACKET_ACCEPT, optlen, opt);
875 }
876
877 /**
878 * Send Join Request from P2P -> P2P or Children -> Parent
879 * @param context Matching Context Pointer
880 * @param peer Target Peer
881 * @param optlen Optional Data Length
882 * @param opt Optional Data
883 */
sendJoinRequest(SceNetAdhocMatchingContext * context,SceNetAdhocMatchingMemberInternal * peer,int optlen,const void * opt)884 void sendJoinRequest(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer, int optlen, const void * opt)
885 {
886 // Send Join Message
887 sendGenericMessage(context, PSP_ADHOC_MATCHING_INPUT_STACK, &peer->mac, PSP_ADHOC_MATCHING_PACKET_JOIN, optlen, opt);
888 }
889
890 /**
891 * Send Cancel Message to Peer (has various effects)
892 * @param context Matching Context Pointer
893 * @param peer Target Peer
894 * @param optlen Optional Data Length
895 * @param opt Optional Data
896 */
sendCancelMessage(SceNetAdhocMatchingContext * context,SceNetAdhocMatchingMemberInternal * peer,int optlen,const void * opt)897 void sendCancelMessage(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer, int optlen, const void * opt)
898 {
899 // Send Cancel Message
900 sendGenericMessage(context, PSP_ADHOC_MATCHING_INPUT_STACK, &peer->mac, PSP_ADHOC_MATCHING_PACKET_CANCEL, optlen, opt);
901 }
902
903 /**
904 * Send Bulk Data to Peer
905 * @param context Matching Context Pointer
906 * @param peer Target Peer
907 * @param datalen Data Length
908 * @param data Data
909 */
sendBulkData(SceNetAdhocMatchingContext * context,SceNetAdhocMatchingMemberInternal * peer,int datalen,const void * data)910 void sendBulkData(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer, int datalen, const void * data)
911 {
912 // Send Bulk Data Message
913 sendGenericMessage(context, PSP_ADHOC_MATCHING_INPUT_STACK, &peer->mac, PSP_ADHOC_MATCHING_PACKET_BULK, datalen, data);
914 }
915
916 /**
917 * Abort Bulk Data Transfer (if in progress)
918 * @param context Matching Context Pointer
919 * @param peer Target Peer
920 */
abortBulkTransfer(SceNetAdhocMatchingContext * context,SceNetAdhocMatchingMemberInternal * peer)921 void abortBulkTransfer(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer)
922 {
923 // Send Bulk Data Abort Message
924 sendGenericMessage(context, PSP_ADHOC_MATCHING_INPUT_STACK, &peer->mac, PSP_ADHOC_MATCHING_PACKET_BULK_ABORT, 0, NULL);
925 }
926
927 /**
928 * Notify all established Peers about new Kid in the Neighborhood
929 * @param context Matching Context Pointer
930 * @param peer New Kid
931 */
sendBirthMessage(SceNetAdhocMatchingContext * context,SceNetAdhocMatchingMemberInternal * peer)932 void sendBirthMessage(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer)
933 {
934 // Send Birth Message
935 sendGenericMessage(context, PSP_ADHOC_MATCHING_INPUT_STACK, &peer->mac, PSP_ADHOC_MATCHING_PACKET_BIRTH, 0, NULL);
936 }
937
938 /**
939 * Notify all established Peers about abandoned Child
940 * @param context Matching Context Pointer
941 * @param peer Abandoned Child
942 */
sendDeathMessage(SceNetAdhocMatchingContext * context,SceNetAdhocMatchingMemberInternal * peer)943 void sendDeathMessage(SceNetAdhocMatchingContext * context, SceNetAdhocMatchingMemberInternal * peer)
944 {
945 // Send Death Message
946 sendGenericMessage(context, PSP_ADHOC_MATCHING_INPUT_STACK, &peer->mac, PSP_ADHOC_MATCHING_PACKET_DEATH, 0, NULL);
947 }
948
949 /**
950 * Return Number of Connected Peers
951 * @param context Matching Context Pointer
952 * @return Number of Connected Peers
953 */
countConnectedPeers(SceNetAdhocMatchingContext * context,const bool excludeTimedout)954 uint32_t countConnectedPeers(SceNetAdhocMatchingContext * context, const bool excludeTimedout)
955 {
956 // Peer Count
957 uint32_t count = 0;
958
959 // Parent Mode
960 if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT)
961 {
962 // Number of Children + 1 Parent (Self)
963 count = countChildren(context, excludeTimedout) + 1;
964 }
965
966 // Child Mode
967 else if (context->mode == PSP_ADHOC_MATCHING_MODE_CHILD)
968 {
969 // Default to 1 Child (Self)
970 count = 1;
971
972 // Connected to Parent
973 if (findParent(context) != NULL)
974 {
975 // Add Number of Siblings + 1 Parent
976 count += countChildren(context, excludeTimedout) + 1; // Since count is already started from 1, Do we need to +1 here? Ys vs. Sora no Kiseki seems to show wrong number of players without +1 here
977 }
978 }
979
980 // P2P Mode
981 else
982 {
983 // Default to 1 P2P Client (Self)
984 count = 1;
985
986 // Connected to another P2P Client
987 if (findP2P(context, excludeTimedout) != NULL)
988 {
989 // Add P2P Brother
990 count++;
991 }
992 }
993
994 // Return Peer Count
995 return count;
996 }
997
998 /**
999 * Spawn Local Event for Event Thread
1000 * @param context Matching Context Pointer
1001 * @param event Event ID
1002 * @param mac Event Source MAC
1003 * @param optlen Optional Data Length
1004 * @param opt Optional Data
1005 */
spawnLocalEvent(SceNetAdhocMatchingContext * context,int event,SceNetEtherAddr * mac,int optlen,void * opt)1006 void spawnLocalEvent(SceNetAdhocMatchingContext * context, int event, SceNetEtherAddr * mac, int optlen, void * opt)
1007 {
1008 // Spawn Local Event
1009 sendGenericMessage(context, PSP_ADHOC_MATCHING_EVENT_STACK, mac, event, optlen, opt);
1010 }
1011
1012 /**
1013 * Handle Timeouts in Matching Context
1014 * @param context Matching Context Pointer
1015 */
handleTimeout(SceNetAdhocMatchingContext * context)1016 void handleTimeout(SceNetAdhocMatchingContext * context)
1017 {
1018 peerlock.lock();
1019 // Iterate Peer List
1020 SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
1021 while (peer != NULL && contexts != NULL && coreState != CORE_POWERDOWN)
1022 {
1023 // Get Next Pointer (to avoid crash on memory freeing)
1024 SceNetAdhocMatchingMemberInternal * next = peer->next;
1025
1026 u64_le now = CoreTiming::GetGlobalTimeUsScaled(); //time_now_d()*1000000.0
1027 // Timeout! Apparently the latest GetGlobalTimeUsScaled (ie. now) have a possibility to be smaller than previous GetGlobalTimeUsScaled (ie. lastping) thus resulting a negative number when subtracted :(
1028 if (peer->state != 0 && static_cast<s64>(now - peer->lastping) > static_cast<s64>(context->timeout))
1029 {
1030 // Spawn Timeout Event
1031 if ((context->mode == PSP_ADHOC_MATCHING_MODE_CHILD && peer->state == PSP_ADHOC_MATCHING_PEER_PARENT) ||
1032 (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT && peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) ||
1033 (context->mode == PSP_ADHOC_MATCHING_MODE_P2P && peer->state == PSP_ADHOC_MATCHING_PEER_P2P)) {
1034 // FIXME: TIMEOUT event should only be triggered on Parent/P2P mode and for Parent/P2P peer?
1035 spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_TIMEOUT, &peer->mac, 0, NULL);
1036
1037 INFO_LOG(SCENET, "TimedOut Member Peer %s (%lld - %lld = %lld > %lld us)", mac2str(&peer->mac).c_str(), now, peer->lastping, (now - peer->lastping), context->timeout);
1038
1039 if (context->mode == PSP_ADHOC_MATCHING_MODE_PARENT)
1040 sendDeathMessage(context, peer);
1041 else
1042 sendCancelMessage(context, peer, 0, NULL);
1043 }
1044 }
1045
1046 // Move Pointer
1047 peer = next;
1048 }
1049 peerlock.unlock();
1050 }
1051
1052 /**
1053 * Recursive Stack Cleaner
1054 * @param node Current Thread Message Node
1055 */
clearStackRecursive(ThreadMessage * & node)1056 void clearStackRecursive(ThreadMessage *& node)
1057 {
1058 // Not End of List
1059 if (node != NULL) clearStackRecursive(node->next);
1060
1061 // Free Last Existing Node of List (NULL is handled in _free)
1062 free(node);
1063 node = NULL;
1064 }
1065
1066 /**
1067 * Clear Thread Stack
1068 * @param context Matching Context Pointer
1069 * @param stack ADHOC_MATCHING_EVENT_STACK or ADHOC_MATCHING_INPUT_STACK
1070 */
clearStack(SceNetAdhocMatchingContext * context,int stack)1071 void clearStack(SceNetAdhocMatchingContext * context, int stack)
1072 {
1073 if (context == NULL) return;
1074
1075 // Clear Event Stack
1076 if (stack == PSP_ADHOC_MATCHING_EVENT_STACK)
1077 {
1078 context->eventlock->lock();
1079 // Free Memory Recursively
1080 clearStackRecursive(context->event_stack);
1081
1082 // Destroy Reference
1083 context->event_stack = NULL;
1084
1085 context->eventlock->unlock();
1086 }
1087
1088 // Clear IO Stack
1089 else
1090 {
1091 context->inputlock->lock();
1092 // Free Memory Recursively
1093 clearStackRecursive(context->input_stack);
1094
1095 // Destroy Reference
1096 context->input_stack = NULL;
1097
1098 context->inputlock->unlock();
1099 }
1100 }
1101
1102 /**
1103 * Clear Peer List
1104 * @param context Matching Context Pointer
1105 */
clearPeerList(SceNetAdhocMatchingContext * context)1106 void clearPeerList(SceNetAdhocMatchingContext * context)
1107 {
1108 // Acquire Peer Lock
1109 peerlock.lock();
1110
1111 // Iterate Peer List
1112 SceNetAdhocMatchingMemberInternal * peer = context->peerlist;
1113 while (peer != NULL)
1114 {
1115 // Grab Next Pointer
1116 context->peerlist = peer->next; //SceNetAdhocMatchingMemberInternal * next = peer->next;
1117
1118 // Delete Peer
1119 free(peer); //deletePeer(context, peer);
1120 // Instead of removing peer immediately, We should give a little time before removing the peer and let it timed out? just in case the game is in the middle of communicating with the peer on another thread so it won't recognize it as Unknown peer
1121 //peer->lastping = CoreTiming::GetGlobalTimeUsScaled();
1122
1123 // Move Pointer
1124 peer = context->peerlist; //peer = next;
1125 }
1126
1127 // Free Peer Lock
1128 peerlock.unlock();
1129 }
1130
DoState(PointerWrap & p)1131 void AfterMatchingMipsCall::DoState(PointerWrap & p) {
1132 auto s = p.Section("AfterMatchingMipsCall", 1, 4);
1133 if (!s)
1134 return;
1135 if (s >= 1) {
1136 Do(p, EventID);
1137 } else {
1138 EventID = -1;
1139 }
1140 if (s >= 4) {
1141 Do(p, contextID);
1142 Do(p, bufAddr);
1143 } else {
1144 contextID = -1;
1145 bufAddr = 0;
1146 }
1147 }
1148
1149 // It seems After Actions being called in reverse order of Mipscall order (ie. MipsCall order of ACCEPT(6)->ESTABLISH(7) getting AfterAction order of ESTABLISH(7)->ACCEPT(6)
run(MipsCall & call)1150 void AfterMatchingMipsCall::run(MipsCall &call) {
1151 if (context == NULL) {
1152 peerlock.lock();
1153 context = findMatchingContext(contextID);
1154 peerlock.unlock();
1155 }
1156 u32 v0 = currentMIPS->r[MIPS_REG_V0];
1157 if (__IsInInterrupt()) ERROR_LOG(SCENET, "AfterMatchingMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", contextID, EventID);
1158 //SetMatchingInCallback(context, false);
1159 DEBUG_LOG(SCENET, "AfterMatchingMipsCall::run [ID=%i][Event=%d][%s] [cbId: %u][retV0: %08x]", contextID, EventID, mac2str((SceNetEtherAddr*)Memory::GetPointer(bufAddr)).c_str(), call.cbId, v0);
1160 if (Memory::IsValidAddress(bufAddr)) userMemory.Free(bufAddr);
1161 //call.setReturnValue(v0);
1162 }
1163
SetData(int ContextID,int eventId,u32_le BufAddr)1164 void AfterMatchingMipsCall::SetData(int ContextID, int eventId, u32_le BufAddr) {
1165 contextID = ContextID;
1166 EventID = eventId;
1167 bufAddr = BufAddr;
1168 peerlock.lock();
1169 context = findMatchingContext(ContextID);
1170 peerlock.unlock();
1171 }
1172
SetMatchingInCallback(SceNetAdhocMatchingContext * context,bool IsInCB)1173 bool SetMatchingInCallback(SceNetAdhocMatchingContext* context, bool IsInCB) {
1174 if (context == NULL) return false;
1175 peerlock.lock();
1176 context->IsMatchingInCB = IsInCB;
1177 peerlock.unlock();
1178 return IsInCB;
1179 }
1180
IsMatchingInCallback(SceNetAdhocMatchingContext * context)1181 bool IsMatchingInCallback(SceNetAdhocMatchingContext* context) {
1182 bool inCB = false;
1183 if (context == NULL) return inCB;
1184 peerlock.lock();
1185 inCB = (context->IsMatchingInCB);
1186 peerlock.unlock();
1187 return inCB;
1188 }
1189
DoState(PointerWrap & p)1190 void AfterAdhocMipsCall::DoState(PointerWrap & p) {
1191 auto s = p.Section("AfterAdhocMipsCall", 1, 4);
1192 if (!s)
1193 return;
1194 if (s >= 3) {
1195 Do(p, HandlerID);
1196 Do(p, EventID);
1197 Do(p, argsAddr);
1198 } else {
1199 HandlerID = -1;
1200 EventID = -1;
1201 argsAddr = 0;
1202 }
1203 }
1204
run(MipsCall & call)1205 void AfterAdhocMipsCall::run(MipsCall& call) {
1206 u32 v0 = currentMIPS->r[MIPS_REG_V0];
1207 if (__IsInInterrupt()) ERROR_LOG(SCENET, "AfterAdhocMipsCall::run [ID=%i][Event=%d] is Returning Inside an Interrupt!", HandlerID, EventID);
1208 SetAdhocctlInCallback(false);
1209 isAdhocctlBusy = false;
1210 DEBUG_LOG(SCENET, "AfterAdhocMipsCall::run [ID=%i][Event=%d] [cbId: %u][retV0: %08x]", HandlerID, EventID, call.cbId, v0);
1211 //call.setReturnValue(v0);
1212 }
1213
SetData(int handlerID,int eventId,u32_le ArgsAddr)1214 void AfterAdhocMipsCall::SetData(int handlerID, int eventId, u32_le ArgsAddr) {
1215 HandlerID = handlerID;
1216 EventID = eventId;
1217 argsAddr = ArgsAddr;
1218 }
1219
SetAdhocctlInCallback(bool IsInCB)1220 int SetAdhocctlInCallback(bool IsInCB) {
1221 std::lock_guard<std::recursive_mutex> adhocGuard(adhocEvtMtx);
1222 IsAdhocctlInCB += (IsInCB?1:-1);
1223 return IsAdhocctlInCB;
1224 }
1225
IsAdhocctlInCallback()1226 int IsAdhocctlInCallback() {
1227 std::lock_guard<std::recursive_mutex> adhocGuard(adhocEvtMtx);
1228 int inCB = IsAdhocctlInCB;
1229 return inCB;
1230 }
1231
1232 // Make sure MIPS calls have been fully executed before the next notifyAdhocctlHandlers
notifyAdhocctlHandlers(u32 flag,u32 error)1233 void notifyAdhocctlHandlers(u32 flag, u32 error) {
1234 __UpdateAdhocctlHandlers(flag, error);
1235 }
1236
1237 // Matching callback is void function: typedef void(*SceNetAdhocMatchingHandler)(int id, int event, SceNetEtherAddr * peer, int optlen, void * opt);
1238 // Important! The MIPS call need to be fully executed before the next MIPS call invoked, as the game (ie. DBZ Tag Team) may need to prepare something for the next callback event to use
1239 // Note: Must not lock peerlock within this function to prevent race-condition with other thread whos owning peerlock and trying to lock context->eventlock owned by this thread
notifyMatchingHandler(SceNetAdhocMatchingContext * context,ThreadMessage * msg,void * opt,u32_le & bufAddr,u32_le & bufLen,u32_le * args)1240 void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * msg, void * opt, u32_le &bufAddr, u32_le &bufLen, u32_le * args) {
1241 // Don't share buffer address space with other mipscall in the queue since mipscalls aren't immediately executed
1242 MatchingArgs argsNew = { 0 };
1243 u32_le dataBufLen = msg->optlen + 8; //max(bufLen, msg->optlen + 8);
1244 u32_le dataBufAddr = userMemory.Alloc(dataBufLen); // We will free this memory after returning from mipscall
1245 uint8_t * dataPtr = Memory::GetPointer(dataBufAddr);
1246 if (dataPtr) {
1247 memcpy(dataPtr, &msg->mac, sizeof(msg->mac));
1248 if (msg->optlen > 0)
1249 memcpy(dataPtr + 8, opt, msg->optlen);
1250
1251 argsNew.data[1] = msg->opcode;
1252 argsNew.data[2] = dataBufAddr;
1253 argsNew.data[3] = msg->optlen;
1254 argsNew.data[4] = dataBufAddr + 8; // OptData Addr
1255 }
1256 else {
1257 argsNew.data[1] = PSP_ADHOC_MATCHING_EVENT_ERROR; // not sure where to put the error code for EVENT_ERROR tho
1258 }
1259 argsNew.data[0] = context->id;
1260 argsNew.data[5] = context->handler.entryPoint; //not part of callback argument, just borrowing a space to store callback address so i don't need to search the context first later
1261
1262 // ScheduleEvent_Threadsafe_Immediate seems to get mixed up with interrupt (returning from mipscall inside an interrupt) and getting invalid address before returning from interrupt
1263 __UpdateMatchingHandler(argsNew);
1264 }
1265
freeFriendsRecursive(SceNetAdhocctlPeerInfo * node,int32_t * count)1266 void freeFriendsRecursive(SceNetAdhocctlPeerInfo * node, int32_t* count) {
1267 // End of List
1268 if (node == NULL) return;
1269
1270 // Increase Recursion Depth
1271 freeFriendsRecursive(node->next, count);
1272
1273 // Free Memory
1274 free(node);
1275 node = NULL;
1276 if (count != NULL) (*count)++;
1277 }
1278
timeoutFriendsRecursive(SceNetAdhocctlPeerInfo * node,int32_t * count)1279 void timeoutFriendsRecursive(SceNetAdhocctlPeerInfo * node, int32_t* count) {
1280 // End of List
1281 if (node == NULL) return;
1282
1283 // Increase Recursion Depth
1284 timeoutFriendsRecursive(node->next, count);
1285
1286 // Set last timestamp
1287 node->last_recv = 0;
1288 if (count != NULL) (*count)++;
1289 }
1290
sendChat(std::string chatString)1291 void sendChat(std::string chatString) {
1292 SceNetAdhocctlChatPacketC2S chat;
1293 auto n = GetI18NCategory("Networking");
1294 chat.base.opcode = OPCODE_CHAT;
1295 //TODO check network inited, check send success or not, chatlog.pushback error on failed send, pushback error on not connected
1296 if (friendFinderRunning) {
1297 // Send Chat to Server
1298 if (!chatString.empty()) {
1299 //maximum char allowed is 64 character for compability with original server (pro.coldbird.net)
1300 std::string message = chatString.substr(0, 60); // 64 return chat variable corrupted is it out of memory?
1301 strcpy(chat.message, message.c_str());
1302 //Send Chat Messages
1303 if (IsSocketReady((int)metasocket, false, true) > 0) {
1304 int chatResult = send((int)metasocket, (const char*)&chat, sizeof(chat), MSG_NOSIGNAL);
1305 NOTICE_LOG(SCENET, "Send Chat %s to Adhoc Server", chat.message);
1306 std::string name = g_Config.sNickName.c_str();
1307
1308 std::lock_guard<std::mutex> guard(chatLogLock);
1309 chatLog.push_back(name.substr(0, 8) + ": " + chat.message);
1310 chatMessageGeneration++;
1311 }
1312 }
1313 } else {
1314 std::lock_guard<std::mutex> guard(chatLogLock);
1315 chatLog.push_back(n->T("You're in Offline Mode, go to lobby or online hall"));
1316 chatMessageGeneration++;
1317 }
1318 }
1319
getChatLog()1320 std::vector<std::string> getChatLog() {
1321 std::lock_guard<std::mutex> guard(chatLogLock);
1322 // If the log gets large, trim it down.
1323 if (chatLog.size() > 50) {
1324 chatLog.erase(chatLog.begin(), chatLog.begin() + (chatLog.size() - 50));
1325 }
1326 return chatLog;
1327 }
1328
GetChatChangeID()1329 int GetChatChangeID() {
1330 return chatMessageGeneration;
1331 }
1332
GetChatMessageCount()1333 int GetChatMessageCount() {
1334 return chatMessageCount;
1335 }
1336
1337 // TODO: We should probably change this thread into PSPThread (or merging it into the existing AdhocThread PSPThread) as there are too many global vars being used here which also being used within some HLEs
friendFinder()1338 int friendFinder(){
1339 SetCurrentThreadName("FriendFinder");
1340 auto n = GetI18NCategory("Networking");
1341 // Receive Buffer
1342 int rxpos = 0;
1343 uint8_t rx[1024];
1344
1345 // Chat Packet
1346 SceNetAdhocctlChatPacketC2S chat;
1347 chat.base.opcode = OPCODE_CHAT;
1348
1349 // Last Ping Time
1350 uint64_t lastping = 0;
1351
1352 // Last Time Reception got updated
1353 uint64_t lastreceptionupdate = 0;
1354
1355 uint64_t now;
1356
1357 // Log Startup
1358 INFO_LOG(SCENET, "FriendFinder: Begin of Friend Finder Thread");
1359
1360 // Resolve and cache AdhocServer DNS
1361 addrinfo* resolved = nullptr;
1362 std::string err;
1363 g_adhocServerIP.in.sin_addr.s_addr = INADDR_NONE;
1364 if (g_Config.bEnableWlan && !net::DNSResolve(g_Config.proAdhocServer, "", &resolved, err)) {
1365 ERROR_LOG(SCENET, "DNS Error Resolving %s\n", g_Config.proAdhocServer.c_str());
1366 host->NotifyUserMessage(n->T("DNS Error Resolving ") + g_Config.proAdhocServer, 2.0f, 0x0000ff);
1367 }
1368 if (resolved) {
1369 for (auto ptr = resolved; ptr != NULL; ptr = ptr->ai_next) {
1370 switch (ptr->ai_family) {
1371 case AF_INET:
1372 g_adhocServerIP.in = *(sockaddr_in*)ptr->ai_addr;
1373 break;
1374 }
1375 }
1376 net::DNSResolveFree(resolved);
1377 }
1378 g_adhocServerIP.in.sin_port = htons(SERVER_PORT);
1379
1380 // Finder Loop
1381 friendFinderRunning = true;
1382 while (friendFinderRunning) {
1383 // Acquire Network Lock
1384 //_acquireNetworkLock();
1385
1386 // Reconnect when disconnected while Adhocctl is still inited
1387 if (metasocket == (int)INVALID_SOCKET && netAdhocctlInited && isAdhocctlNeedLogin) {
1388 if (g_Config.bEnableWlan) {
1389 if (initNetwork(&product_code) == 0) {
1390 networkInited = true;
1391 INFO_LOG(SCENET, "FriendFinder: Network [RE]Initialized");
1392 // At this point we are most-likely not in a Group within the Adhoc Server, so we should probably reset AdhocctlState
1393 adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
1394 netAdhocGameModeEntered = false;
1395 isAdhocctlBusy = false;
1396 }
1397 else {
1398 networkInited = false;
1399 shutdown((int)metasocket, SD_BOTH);
1400 closesocket((int)metasocket);
1401 metasocket = (int)INVALID_SOCKET;
1402 }
1403 }
1404 }
1405 // Prevent retrying to Login again unless it was on demand
1406 isAdhocctlNeedLogin = false;
1407
1408 if (networkInited) {
1409 // Ping Server
1410 now = time_now_d() * 1000000.0; // Use time_now_d()*1000000.0 instead of CoreTiming::GetGlobalTimeUsScaled() if the game gets disconnected from AdhocServer too soon when FPS wasn't stable
1411 // original code : ((sceKernelGetSystemTimeWide() - lastping) >= ADHOCCTL_PING_TIMEOUT)
1412 if (static_cast<s64>(now - lastping) >= PSP_ADHOCCTL_PING_TIMEOUT) { // We may need to use lower interval to prevent getting timeout at Pro Adhoc Server through internet
1413 // Prepare Packet
1414 uint8_t opcode = OPCODE_PING;
1415
1416 // Send Ping to Server, may failed with socket error 10054/10053 if someone else with the same IP already connected to AdHoc Server (the server might need to be modified to differentiate MAC instead of IP)
1417 if (IsSocketReady((int)metasocket, false, true) > 0) {
1418 int iResult = send((int)metasocket, (const char*)&opcode, 1, MSG_NOSIGNAL);
1419 int error = errno;
1420 // KHBBS seems to be getting error 10053 often
1421 if (iResult == SOCKET_ERROR) {
1422 ERROR_LOG(SCENET, "FriendFinder: Socket Error (%i) when sending OPCODE_PING", error);
1423 if (error != EAGAIN && error != EWOULDBLOCK) {
1424 networkInited = false;
1425 shutdown((int)metasocket, SD_BOTH);
1426 closesocket((int)metasocket);
1427 metasocket = (int)INVALID_SOCKET;
1428 host->NotifyUserMessage(std::string(n->T("Disconnected from AdhocServer")) + " (" + std::string(n->T("Error")) + ": " + std::to_string(error) + ")", 2.0, 0x0000ff);
1429 // Mark all friends as timedout since we won't be able to detects disconnected friends anymore without being connected to Adhoc Server
1430 peerlock.lock();
1431 timeoutFriendsRecursive(friends);
1432 peerlock.unlock();
1433 }
1434 }
1435 else {
1436 // Update Ping Time
1437 lastping = now;
1438 VERBOSE_LOG(SCENET, "FriendFinder: Sending OPCODE_PING (%llu)", static_cast<unsigned long long>(now));
1439 }
1440 }
1441 }
1442
1443 // Check for Incoming Data
1444 if (IsSocketReady((int)metasocket, true, false) > 0) {
1445 int received = recv((int)metasocket, (char*)(rx + rxpos), sizeof(rx) - rxpos, MSG_NOSIGNAL);
1446
1447 // Free Network Lock
1448 //_freeNetworkLock();
1449
1450 // Received Data
1451 if (received > 0) {
1452 // Fix Position
1453 rxpos += received;
1454
1455 // Log Incoming Traffic
1456 //printf("Received %d Bytes of Data from Server\n", received);
1457 INFO_LOG(SCENET, "Received %d Bytes of Data from Adhoc Server", received);
1458 }
1459 }
1460
1461 // Calculate EnterGameMode Timeout to prevent waiting forever for disconnected players
1462 if (isAdhocctlBusy && adhocctlState == ADHOCCTL_STATE_DISCONNECTED && adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE && netAdhocGameModeEntered && static_cast<s64>(now - adhocctlStartTime) > netAdhocEnterGameModeTimeout) {
1463 netAdhocGameModeEntered = false;
1464 notifyAdhocctlHandlers(ADHOCCTL_EVENT_ERROR, ERROR_NET_ADHOC_TIMEOUT);
1465 }
1466
1467 // Handle Packets
1468 if (rxpos > 0) {
1469 // BSSID Packet
1470 if (rx[0] == OPCODE_CONNECT_BSSID) {
1471 // Enough Data available
1472 if (rxpos >= (int)sizeof(SceNetAdhocctlConnectBSSIDPacketS2C)) {
1473 // Cast Packet
1474 SceNetAdhocctlConnectBSSIDPacketS2C* packet = (SceNetAdhocctlConnectBSSIDPacketS2C*)rx;
1475
1476 INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT_BSSID [%s]", mac2str(&packet->mac).c_str());
1477 // Update User BSSID
1478 parameter.bssid.mac_addr = packet->mac; // This packet seems to contains Adhoc Group Creator's BSSID (similar to AP's BSSID) so it shouldn't get mixed up with local MAC address
1479
1480 // From JPCSP: Some games have problems when the PSP_ADHOCCTL_EVENT_CONNECTED is sent too quickly after connecting to a network. The connection will be set CONNECTED with a small delay (200ms or 200us?)
1481 // Notify Event Handlers
1482 if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) {
1483 SceNetEtherAddr localMac;
1484 getLocalMac(&localMac);
1485 if (std::find_if(gameModeMacs.begin(), gameModeMacs.end(),
1486 [localMac](SceNetEtherAddr const& e) {
1487 return isMacMatch(&e, &localMac);
1488 }) == gameModeMacs.end()) {
1489 // Arrange the order to be consistent on all players (Host on top), Starting from our self the rest of new players will be added to the back
1490 gameModeMacs.push_back(localMac);
1491
1492 // FIXME: OPCODE_CONNECT_BSSID only triggered once, but the timing of ADHOCCTL_EVENT_GAME notification could be too soon, since there could be more players that need to join before the event should be notified
1493 if (netAdhocGameModeEntered && gameModeMacs.size() >= requiredGameModeMacs.size()) {
1494 notifyAdhocctlHandlers(ADHOCCTL_EVENT_GAME, 0);
1495 }
1496 }
1497 else
1498 WARN_LOG(SCENET, "GameMode SelfMember [%s] Already Existed!", mac2str(&localMac).c_str());
1499 }
1500 else {
1501 //adhocctlState = ADHOCCTL_STATE_CONNECTED;
1502 notifyAdhocctlHandlers(ADHOCCTL_EVENT_CONNECT, 0);
1503 }
1504
1505 // Give time a little time
1506 //sceKernelDelayThread(adhocEventDelayMS * 1000);
1507 //sleep_ms(adhocEventDelayMS);
1508
1509 // Move RX Buffer
1510 memmove(rx, rx + sizeof(SceNetAdhocctlConnectBSSIDPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectBSSIDPacketS2C));
1511
1512 // Fix RX Buffer Length
1513 rxpos -= sizeof(SceNetAdhocctlConnectBSSIDPacketS2C);
1514 }
1515 }
1516
1517 // Chat Packet
1518 else if (rx[0] == OPCODE_CHAT) {
1519 // Enough Data available
1520 if (rxpos >= (int)sizeof(SceNetAdhocctlChatPacketS2C)) {
1521 // Cast Packet
1522 SceNetAdhocctlChatPacketS2C* packet = (SceNetAdhocctlChatPacketS2C*)rx;
1523 INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CHAT");
1524
1525 // Fix strings with null-terminated
1526 packet->name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0;
1527 packet->base.message[ADHOCCTL_MESSAGE_LEN - 1] = 0;
1528
1529 // Add Incoming Chat to HUD
1530 NOTICE_LOG(SCENET, "Received chat message %s", packet->base.message);
1531 std::string incoming = "";
1532 std::string name = (char*)packet->name.data;
1533 incoming.append(name.substr(0, 8));
1534 incoming.append(": ");
1535 incoming.append((char*)packet->base.message);
1536
1537 std::lock_guard<std::mutex> guard(chatLogLock);
1538 chatLog.push_back(incoming);
1539 chatMessageGeneration++;
1540 chatMessageCount++;
1541
1542 // Move RX Buffer
1543 memmove(rx, rx + sizeof(SceNetAdhocctlChatPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlChatPacketS2C));
1544
1545 // Fix RX Buffer Length
1546 rxpos -= sizeof(SceNetAdhocctlChatPacketS2C);
1547 }
1548 }
1549
1550 // Connect Packet
1551 else if (rx[0] == OPCODE_CONNECT) {
1552 // Enough Data available
1553 if (rxpos >= (int)sizeof(SceNetAdhocctlConnectPacketS2C)) {
1554 // Cast Packet
1555 SceNetAdhocctlConnectPacketS2C* packet = (SceNetAdhocctlConnectPacketS2C*)rx;
1556
1557 // Fix strings with null-terminated
1558 packet->name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0;
1559
1560 // Log Incoming Peer
1561 u32_le ipaddr = packet->ip;
1562 INFO_LOG(SCENET, "FriendFinder: Incoming OPCODE_CONNECT [%s][%s][%s]", mac2str(&packet->mac).c_str(), ip2str(*(in_addr*)&ipaddr).c_str(), packet->name.data);
1563
1564 // Add User
1565 addFriend(packet);
1566
1567 // Make sure GameMode participants are all joined (including self MAC)
1568 if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) {
1569 if (std::find_if(gameModeMacs.begin(), gameModeMacs.end(),
1570 [packet](SceNetEtherAddr const& e) {
1571 return isMacMatch(&e, &packet->mac);
1572 }) == gameModeMacs.end()) {
1573 // Arrange the order to be consistent on all players (Host on top), Existing players are sent in reverse by AdhocServer
1574 SceNetEtherAddr localMac;
1575 getLocalMac(&localMac);
1576 auto it = std::find_if(gameModeMacs.begin(), gameModeMacs.end(),
1577 [localMac](SceNetEtherAddr const& e) {
1578 return isMacMatch(&e, &localMac);
1579 });
1580 // Starting from our self the rest of new players will be added to the back
1581 if (it != gameModeMacs.end()) {
1582 gameModeMacs.push_back(packet->mac);
1583 }
1584 else {
1585 it = gameModeMacs.begin() + 1;
1586 gameModeMacs.insert(it, packet->mac);
1587 }
1588
1589 // From JPCSP: Join complete when all the required MACs have joined
1590 if (netAdhocGameModeEntered && requiredGameModeMacs.size() > 0 && gameModeMacs.size() == requiredGameModeMacs.size()) {
1591 // TODO: Should we replace gameModeMacs contents with requiredGameModeMacs contents to make sure they are in the same order with macs from sceNetAdhocctlCreateEnterGameMode? But may not be consistent with the list on client side!
1592 //gameModeMacs = requiredGameModeMacs;
1593 notifyAdhocctlHandlers(ADHOCCTL_EVENT_GAME, 0);
1594 }
1595 }
1596 else
1597 WARN_LOG(SCENET, "GameMode Member [%s] Already Existed!", mac2str(&packet->mac).c_str());
1598 }
1599
1600 // Update HUD User Count
1601 std::string name = (char*)packet->name.data;
1602 std::string incoming = "";
1603 incoming.append(name.substr(0, 8));
1604 incoming.append(" Joined ");
1605 //do we need ip?
1606 //joined.append((char *)packet->ip);
1607
1608 std::lock_guard<std::mutex> guard(chatLogLock);
1609 chatLog.push_back(incoming);
1610 chatMessageGeneration++;
1611
1612 #ifdef LOCALHOST_AS_PEER
1613 setUserCount(getActivePeerCount());
1614 #else
1615 // setUserCount(getActivePeerCount()+1);
1616 #endif
1617
1618 // Move RX Buffer
1619 memmove(rx, rx + sizeof(SceNetAdhocctlConnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlConnectPacketS2C));
1620
1621 // Fix RX Buffer Length
1622 rxpos -= sizeof(SceNetAdhocctlConnectPacketS2C);
1623 }
1624 }
1625
1626 // Disconnect Packet
1627 else if (rx[0] == OPCODE_DISCONNECT) {
1628 // Enough Data available
1629 if (rxpos >= (int)sizeof(SceNetAdhocctlDisconnectPacketS2C)) {
1630 // Cast Packet
1631 SceNetAdhocctlDisconnectPacketS2C* packet = (SceNetAdhocctlDisconnectPacketS2C*)rx;
1632
1633 DEBUG_LOG(SCENET, "FriendFinder: OPCODE_DISCONNECT");
1634
1635 // Log Incoming Peer Delete Request
1636 INFO_LOG(SCENET, "FriendFinder: Incoming Peer Data Delete Request...");
1637
1638 if (adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE) {
1639 auto peer = findFriendByIP(packet->ip);
1640 for (auto& gma : replicaGameModeAreas)
1641 if (isMacMatch(&gma.mac, &peer->mac_addr)) {
1642 gma.updateTimestamp = 0;
1643 break;
1644 }
1645 }
1646
1647 // Delete User by IP, should delete by MAC since IP can be shared (behind NAT) isn't?
1648 deleteFriendByIP(packet->ip);
1649
1650 // Update HUD User Count
1651 #ifdef LOCALHOST_AS_PEER
1652 setUserCount(_getActivePeerCount());
1653 #else
1654 //setUserCount(_getActivePeerCount()+1);
1655 #endif
1656
1657 // Move RX Buffer
1658 memmove(rx, rx + sizeof(SceNetAdhocctlDisconnectPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlDisconnectPacketS2C));
1659
1660 // Fix RX Buffer Length
1661 rxpos -= sizeof(SceNetAdhocctlDisconnectPacketS2C);
1662 }
1663 }
1664
1665 // Scan Packet
1666 else if (rx[0] == OPCODE_SCAN) {
1667 // Enough Data available
1668 if (rxpos >= (int)sizeof(SceNetAdhocctlScanPacketS2C)) {
1669 // Cast Packet
1670 SceNetAdhocctlScanPacketS2C* packet = (SceNetAdhocctlScanPacketS2C*)rx;
1671
1672 DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN");
1673
1674 // Log Incoming Network Information
1675 INFO_LOG(SCENET, "Incoming Group Information...");
1676
1677 // Multithreading Lock
1678 peerlock.lock();
1679
1680 // Allocate Structure Data
1681 SceNetAdhocctlScanInfo* group = (SceNetAdhocctlScanInfo*)malloc(sizeof(SceNetAdhocctlScanInfo));
1682
1683 // Allocated Structure Data
1684 if (group != NULL) {
1685 // Clear Memory, should this be done only when allocating new group?
1686 memset(group, 0, sizeof(SceNetAdhocctlScanInfo));
1687
1688 // Link to existing Groups
1689 group->next = newnetworks;
1690
1691 // Copy Group Name
1692 group->group_name = packet->group;
1693
1694 // Set Group Host
1695 group->bssid.mac_addr = packet->mac;
1696
1697 // Set group parameters
1698 // Since 0 is not a valid active channel we fake the channel for Automatic Channel (JPCSP use 11 as default). Ridge Racer 2 will ignore any groups with channel 0 or that doesn't matched with channel value returned from sceUtilityGetSystemParamInt (which mean sceUtilityGetSystemParamInt must not return channel 0 when connected to a network?)
1699 group->channel = parameter.channel; //(parameter.channel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) ? defaultWlanChannel : parameter.channel;
1700 // This Mode should be a valid mode (>=0), probably should be sent by AdhocServer since there are 2 possibilities (Normal and GameMode). Air Conflicts - Aces Of World War 2 (which use GameMode) seems to relies on this Mode value.
1701 group->mode = std::max(ADHOCCTL_MODE_NORMAL, adhocctlCurrentMode); // default to ADHOCCTL_MODE_NORMAL
1702
1703 // Link into Group List
1704 newnetworks = group;
1705 }
1706
1707 // Multithreading Unlock
1708 peerlock.unlock();
1709
1710 // Move RX Buffer
1711 memmove(rx, rx + sizeof(SceNetAdhocctlScanPacketS2C), sizeof(rx) - sizeof(SceNetAdhocctlScanPacketS2C));
1712
1713 // Fix RX Buffer Length
1714 rxpos -= sizeof(SceNetAdhocctlScanPacketS2C);
1715 }
1716 }
1717
1718 // Scan Complete Packet
1719 else if (rx[0] == OPCODE_SCAN_COMPLETE) {
1720 DEBUG_LOG(SCENET, "FriendFinder: OPCODE_SCAN_COMPLETE");
1721 // Log Scan Completion
1722 INFO_LOG(SCENET, "FriendFinder: Incoming Scan complete response...");
1723
1724 // Reset current networks to prevent disbanded host to be listed again
1725 peerlock.lock();
1726 if (networks != newnetworks) {
1727 freeGroupsRecursive(networks);
1728 networks = newnetworks;
1729 }
1730 newnetworks = NULL;
1731 peerlock.unlock();
1732
1733 // Notify Event Handlers
1734 notifyAdhocctlHandlers(ADHOCCTL_EVENT_SCAN, 0);
1735
1736 // Move RX Buffer
1737 memmove(rx, rx + 1, sizeof(rx) - 1);
1738
1739 // Fix RX Buffer Length
1740 rxpos -= 1;
1741 }
1742 }
1743 }
1744 // This delay time should be 100ms when there is an event otherwise 500ms ?
1745 sleep_ms(10); // Using 1ms for faster response just like AdhocServer?
1746
1747 // Don't do anything if it's paused, otherwise the log will be flooded
1748 while (Core_IsStepping() && coreState != CORE_POWERDOWN && friendFinderRunning) sleep_ms(10);
1749 }
1750
1751 // Groups/Networks should be deallocated isn't?
1752
1753 // Prevent the games from having trouble to reInitiate Adhoc (the next NetInit -> PdpCreate after NetTerm)
1754 adhocctlState = ADHOCCTL_STATE_DISCONNECTED;
1755 friendFinderRunning = false;
1756
1757 // Log Shutdown
1758 INFO_LOG(SCENET, "FriendFinder: End of Friend Finder Thread");
1759
1760 // Return Success
1761 return 0;
1762 }
1763
getActivePeerCount(const bool excludeTimedout)1764 int getActivePeerCount(const bool excludeTimedout) {
1765 // Counter
1766 int count = 0;
1767
1768 // #ifdef LOCALHOST_AS_PEER
1769 // // Increase for Localhost
1770 // count++;
1771 // #endif
1772
1773 // Peer Reference
1774 SceNetAdhocctlPeerInfo * peer = friends;
1775
1776 // Iterate Peers
1777 for (; peer != NULL; peer = peer->next) {
1778 // Increase Counter, Should we exclude peers pending for timed out?
1779 if (!excludeTimedout || peer->last_recv != 0)
1780 count++;
1781 }
1782
1783 // Return Result
1784 return count;
1785 }
1786
getLocalIp(sockaddr_in * SocketAddress)1787 int getLocalIp(sockaddr_in* SocketAddress) {
1788 if (isLocalServer) {
1789 SocketAddress->sin_addr = g_localhostIP.in.sin_addr;
1790 return 0;
1791 }
1792
1793 #if !PPSSPP_PLATFORM(SWITCH)
1794 if (metasocket != (int)INVALID_SOCKET) {
1795 struct sockaddr_in localAddr;
1796 localAddr.sin_addr.s_addr = INADDR_ANY;
1797 socklen_t addrLen = sizeof(localAddr);
1798 int ret = getsockname((int)metasocket, (struct sockaddr*)&localAddr, &addrLen);
1799 if (SOCKET_ERROR != ret) {
1800 SocketAddress->sin_addr = localAddr.sin_addr;
1801 return 0;
1802 }
1803 }
1804 #endif // !PPSSPP_PLATFORM(SWITCH)
1805
1806 // Fallback if not connected to AdhocServer
1807 #if defined(_WIN32)
1808 // Get local host name
1809 char szHostName[256] = "";
1810
1811 if (::gethostname(szHostName, sizeof(szHostName))) {
1812 // Error handling
1813 }
1814 // Get local network IP addresses (LAN/VPN/loopback)
1815 struct addrinfo hints, * res = 0;
1816 memset(&hints, 0, sizeof(hints));
1817 hints.ai_family = AF_INET; // AF_UNSPEC;
1818 hints.ai_socktype = SOCK_DGRAM;
1819 hints.ai_flags = AI_ADDRCONFIG; // getaddrinfo with AI_ADDRCONFIG will fail when there is no local network connected? https://github.com/stephane/libmodbus/issues/575
1820 // Note: getaddrinfo could cause freezes on Android if there is no network https://github.com/hrydgard/ppsspp/issues/13300
1821 if (getaddrinfo(szHostName, NULL, &hints, &res) == 0 && res != NULL) {
1822 memcpy(&SocketAddress->sin_addr, &((struct sockaddr_in*)res->ai_addr)->sin_addr, sizeof(SocketAddress->sin_addr));
1823 freeaddrinfo(res);
1824 return 0;
1825 }
1826
1827 #elif defined(getifaddrs) // On Android: Requires __ANDROID_API__ >= 24
1828 struct ifaddrs* ifAddrStruct = NULL;
1829 struct ifaddrs* ifa = NULL;
1830
1831 getifaddrs(&ifAddrStruct);
1832 if (ifAddrStruct != NULL) {
1833 for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
1834 if (!ifa->ifa_addr) {
1835 continue;
1836 }
1837 if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
1838 // is a valid IP4 Address
1839 SocketAddress->sin_addr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr;
1840 break;
1841 }
1842 }
1843 freeifaddrs(ifAddrStruct);
1844 return 0;
1845 }
1846
1847 #else // Alternative way
1848 int sock = socket(AF_INET, SOCK_DGRAM, 0);
1849 if (sock != SOCKET_ERROR) {
1850 const char* kGoogleDnsIp = "8.8.8.8"; // Needs to be an IP string so it can be resolved as fast as possible to IP, doesn't need to be reachable
1851 uint16_t kDnsPort = 53;
1852 struct sockaddr_in serv;
1853 memset(&serv, 0, sizeof(serv));
1854 serv.sin_family = AF_INET;
1855 serv.sin_addr.s_addr = inet_addr(kGoogleDnsIp);
1856 serv.sin_port = htons(kDnsPort);
1857
1858 int err = connect(sock, (struct sockaddr*)&serv, sizeof(serv));
1859 if (err != SOCKET_ERROR) {
1860 struct sockaddr_in name;
1861 socklen_t namelen = sizeof(name);
1862 err = getsockname(sock, (struct sockaddr*)&name, &namelen);
1863 if (err != SOCKET_ERROR) {
1864 SocketAddress->sin_addr = name.sin_addr; // May be we should cache this so it doesn't need to use connect all the time, or even better cache it when connecting to adhoc server to get an accurate IP
1865 closesocket(sock);
1866 return 0;
1867 }
1868 }
1869 closesocket(sock);
1870 }
1871 #endif
1872 return -1;
1873 }
1874
getLocalIp(int sock)1875 uint32_t getLocalIp(int sock) {
1876 struct sockaddr_in localAddr;
1877 localAddr.sin_addr.s_addr = INADDR_ANY;
1878 socklen_t addrLen = sizeof(localAddr);
1879 getsockname(sock, (struct sockaddr*)&localAddr, &addrLen);
1880 if (isLocalServer) {
1881 localAddr.sin_addr = g_localhostIP.in.sin_addr;
1882 }
1883 return localAddr.sin_addr.s_addr;
1884 }
1885
InitPrivateIPRanges()1886 static std::vector<std::pair<uint32_t, uint32_t>> InitPrivateIPRanges() {
1887 struct sockaddr_in saNet, saMask;
1888 std::vector<std::pair<uint32_t, uint32_t>> ip_ranges;
1889
1890 if (1 == inet_pton(AF_INET, "192.168.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.255.0.0", &(saMask.sin_addr)))
1891 ip_ranges.push_back({saNet.sin_addr.s_addr, saMask.sin_addr.s_addr});
1892 if (1 == inet_pton(AF_INET, "172.16.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.240.0.0", &(saMask.sin_addr)))
1893 ip_ranges.push_back({ saNet.sin_addr.s_addr, saMask.sin_addr.s_addr });
1894 if (1 == inet_pton(AF_INET, "10.0.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.0.0.0", &(saMask.sin_addr)))
1895 ip_ranges.push_back({ saNet.sin_addr.s_addr, saMask.sin_addr.s_addr });
1896 if (1 == inet_pton(AF_INET, "127.0.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.0.0.0", &(saMask.sin_addr)))
1897 ip_ranges.push_back({ saNet.sin_addr.s_addr, saMask.sin_addr.s_addr });
1898 if (1 == inet_pton(AF_INET, "169.254.0.0", &(saNet.sin_addr)) && 1 == inet_pton(AF_INET, "255.255.0.0", &(saMask.sin_addr)))
1899 ip_ranges.push_back({ saNet.sin_addr.s_addr, saMask.sin_addr.s_addr });
1900
1901 return ip_ranges;
1902 }
1903
isPrivateIP(uint32_t ip)1904 bool isPrivateIP(uint32_t ip) {
1905 static const std::vector<std::pair<uint32_t, uint32_t>> ip_ranges = InitPrivateIPRanges();
1906 for (auto ipRange : ip_ranges) {
1907 if ((ip & ipRange.second) == (ipRange.first & ipRange.second)) // We can just use ipRange.first directly if it's already correctly formatted
1908 return true;
1909 }
1910 return false;
1911 }
1912
isLoopbackIP(uint32_t ip)1913 bool isLoopbackIP(uint32_t ip) {
1914 return ((uint8_t*)&ip)[0] == 0x7f;
1915 }
1916
getLocalMac(SceNetEtherAddr * addr)1917 void getLocalMac(SceNetEtherAddr * addr){
1918 // Read MAC Address from config
1919 uint8_t mac[ETHER_ADDR_LEN] = {0};
1920 if (PPSSPP_ID > 1) {
1921 memset(&mac, PPSSPP_ID, sizeof(mac));
1922 // Making sure the 1st 2-bits on the 1st byte of OUI are zero to prevent issue with some games (ie. Gran Turismo)
1923 mac[0] &= 0xfc;
1924 }
1925 else
1926 if (!ParseMacAddress(g_Config.sMACAddress.c_str(), mac)) {
1927 ERROR_LOG(SCENET, "Error parsing mac address %s", g_Config.sMACAddress.c_str());
1928 memset(&mac, 0, sizeof(mac));
1929 }
1930 memcpy(addr, mac, ETHER_ADDR_LEN);
1931 }
1932
getLocalPort(int sock)1933 uint16_t getLocalPort(int sock) {
1934 struct sockaddr_in localAddr;
1935 localAddr.sin_port = 0;
1936 socklen_t addrLen = sizeof(localAddr);
1937 getsockname(sock, (struct sockaddr*)&localAddr, &addrLen);
1938 return ntohs(localAddr.sin_port);
1939 }
1940
getAvailToRecv(int sock,int udpBufferSize)1941 u_long getAvailToRecv(int sock, int udpBufferSize) {
1942 u_long n = 0; // Typical MTU size is 1500
1943 int err = -1;
1944 #if defined(_WIN32) // May not be available on all platform
1945 err = ioctlsocket(sock, FIONREAD, &n);
1946 #else
1947 err = ioctl(sock, FIONREAD, &n);
1948 #endif
1949 if (err < 0)
1950 return 0;
1951
1952 if (udpBufferSize > 0 && n > 0) {
1953 // TODO: Cap number of bytes of full DGRAM message(s) up to buffer size, but may cause Warriors Orochi 2 to get FPS drops
1954 }
1955 return n;
1956 }
1957
getSockMaxSize(int udpsock)1958 int getSockMaxSize(int udpsock) {
1959 int n = PSP_ADHOC_PDP_MTU; // Typical MTU size is 1500
1960 #if defined(SO_MAX_MSG_SIZE) // May not be available on all platform
1961 socklen_t m = sizeof(n);
1962 getsockopt(udpsock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char*)&n, &m);
1963 #endif
1964 return n;
1965 }
1966
getSockBufferSize(int sock,int opt)1967 int getSockBufferSize(int sock, int opt) { // opt = SO_RCVBUF/SO_SNDBUF
1968 int n = PSP_ADHOC_PDP_MFS; // 16384;
1969 socklen_t m = sizeof(n);
1970 getsockopt(sock, SOL_SOCKET, opt, (char *)&n, &m); // in linux the value is twice of the value being set using setsockopt
1971 return (n/2);
1972 }
1973
setSockBufferSize(int sock,int opt,int size)1974 int setSockBufferSize(int sock, int opt, int size) { // opt = SO_RCVBUF/SO_SNDBUF
1975 int n = size; // 8192; //16384
1976 return setsockopt(sock, SOL_SOCKET, opt, (char *)&n, sizeof(n));
1977 }
1978
setSockMSS(int sock,int size)1979 int setSockMSS(int sock, int size) {
1980 int mss = size; // 1460;
1981 return setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, (char*)&mss, sizeof(mss));
1982 }
1983
setSockTimeout(int sock,int opt,unsigned long timeout_usec)1984 int setSockTimeout(int sock, int opt, unsigned long timeout_usec) { // opt = SO_SNDTIMEO/SO_RCVTIMEO
1985 if (timeout_usec > 0 && timeout_usec < minSocketTimeoutUS) timeout_usec = minSocketTimeoutUS; // Override timeout for high latency multiplayer
1986 #if defined(_WIN32)
1987 unsigned long optval = timeout_usec / 1000UL;
1988 if (timeout_usec > 0 && optval == 0) optval = 1; // Since there are games that use 100 usec timeout, we should set it to minimum value on Windows (1 msec) instead of using 0 (0 = indefinitely timeout)
1989 #elif defined(__APPLE__)
1990 struct timeval optval;
1991 optval.tv_sec = static_cast<long>(timeout_usec) / 1000000L;
1992 optval.tv_usec = static_cast<long>(timeout_usec) % 1000000L;
1993 #else
1994 struct timeval optval = { static_cast<long>(timeout_usec) / 1000000L, static_cast<long>(timeout_usec) % 1000000L };
1995 #endif
1996 return setsockopt(sock, SOL_SOCKET, opt, (char*)&optval, sizeof(optval));
1997 }
1998
getSockNoDelay(int tcpsock)1999 int getSockNoDelay(int tcpsock) {
2000 int opt = 0;
2001 socklen_t optlen = sizeof(opt);
2002 getsockopt(tcpsock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, &optlen);
2003 return opt;
2004 }
2005
2006 //#define TCP_QUICKACK 0x0c
setSockNoDelay(int tcpsock,int flag)2007 int setSockNoDelay(int tcpsock, int flag) {
2008 int opt = flag;
2009 // Disable ACK Delay when supported
2010 #if defined(TCP_QUICKACK)
2011 setsockopt(tcpsock, IPPROTO_TCP, TCP_QUICKACK, (char*)&opt, sizeof(opt));
2012 #elif defined(_WIN32)
2013 #if !defined(SIO_TCP_SET_ACK_FREQUENCY)
2014 #define SIO_TCP_SET_ACK_FREQUENCY _WSAIOW(IOC_VENDOR,23)
2015 #endif
2016 int freq = flag? 1:2; // can be 1..255, default is 2 (delayed 200ms)
2017 DWORD retbytes = 0;
2018 WSAIoctl(tcpsock, SIO_TCP_SET_ACK_FREQUENCY, &freq, sizeof(freq), NULL, 0, &retbytes, NULL, NULL);
2019 #endif
2020 // Disable Nagle Algo
2021 return setsockopt(tcpsock, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt));
2022 }
2023
setSockNoSIGPIPE(int sock,int flag)2024 int setSockNoSIGPIPE(int sock, int flag) {
2025 // Set SIGPIPE when supported (ie. BSD/MacOS X)
2026 int opt = flag;
2027 #if defined(SO_NOSIGPIPE)
2028 return setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt));
2029 #endif
2030 return -1;
2031 }
2032
setSockReuseAddrPort(int sock)2033 int setSockReuseAddrPort(int sock) {
2034 int opt = 1;
2035 // Should we set SO_BROADCAST too for SO_REUSEADDR to works like SO_REUSEPORT ?
2036 // Set SO_REUSEPORT also when supported (ie. Android)
2037 #if defined(SO_REUSEPORT)
2038 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&opt, sizeof(opt));
2039 #endif
2040 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
2041 }
2042
setUDPConnReset(int udpsock,bool enabled)2043 int setUDPConnReset(int udpsock, bool enabled) {
2044 // On Windows: Connection Reset error on UDP could cause a strange behavior https://stackoverflow.com/questions/34242622/windows-udp-sockets-recvfrom-fails-with-error-10054
2045 #if defined(_WIN32)
2046 #if !defined(SIO_UDP_CONNRESET)
2047 #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
2048 #endif
2049 BOOL bNewBehavior = enabled;
2050 DWORD dwBytesReturned = 0;
2051 return WSAIoctl(udpsock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);
2052 #endif
2053 return -1;
2054 }
2055
2056 #if !defined(TCP_KEEPIDLE) && !PPSSPP_PLATFORM(SWITCH)
2057 #define TCP_KEEPIDLE TCP_KEEPALIVE //TCP_KEEPIDLE on Linux is equivalent to TCP_KEEPALIVE on macOS
2058 #endif
2059 // VS 2017 compatibility
2060 #if _MSC_VER
2061 #ifndef TCP_KEEPCNT
2062 #define TCP_KEEPCNT 16
2063 #endif
2064 #ifndef TCP_KEEPINTVL
2065 #define TCP_KEEPINTVL 17
2066 #endif
2067 #endif
setSockKeepAlive(int sock,bool keepalive,const int keepinvl,const int keepcnt,const int keepidle)2068 int setSockKeepAlive(int sock, bool keepalive, const int keepinvl, const int keepcnt, const int keepidle) {
2069 int optval = keepalive ? 1 : 0;
2070 int optlen = sizeof(optval);
2071 int result = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, optlen);
2072 #if !PPSSPP_PLATFORM(SWITCH)
2073 if (result == 0 && keepalive) {
2074 if (getsockopt(sock, SOL_SOCKET, SO_TYPE, (char*)&optval, (socklen_t*)&optlen) == 0 && optval == SOCK_STREAM) {
2075 optlen = sizeof(optval);
2076 optval = keepidle; //180 sec
2077 setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&optval, optlen);
2078 optval = keepinvl; //60 sec
2079 setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&optval, optlen);
2080 optval = keepcnt; //20
2081 setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, (char*)&optval, optlen);
2082 }
2083 }
2084 #endif // !PPSSPP_PLATFORM(SWITCH)
2085 return result;
2086 }
2087
2088 /**
2089 * Return the Number of Players with the chosen Nickname in the Local Users current Network
2090 * @param nickname To-be-searched Nickname
2091 * @return Number of matching Players
2092 */
getNicknameCount(const char * nickname)2093 int getNicknameCount(const char * nickname)
2094 {
2095 // Counter
2096 int count = 0;
2097
2098 // Local Nickname Matches
2099 if (strncmp((char *)¶meter.nickname.data, nickname, ADHOCCTL_NICKNAME_LEN) == 0) count++;
2100
2101 // Peer Reference
2102 SceNetAdhocctlPeerInfo * peer = friends;
2103
2104 // Iterate Peers
2105 for (; peer != NULL; peer = peer->next)
2106 {
2107 // Match found
2108 if (peer->last_recv != 0 && strncmp((char *)&peer->nickname.data, nickname, ADHOCCTL_NICKNAME_LEN) == 0) count++;
2109 }
2110
2111 // Return Result
2112 return count;
2113 }
2114
2115 /**
2116 * PDP Socket Counter
2117 * @return Number of internal PDP Sockets
2118 */
getPDPSocketCount()2119 int getPDPSocketCount()
2120 {
2121 // Socket Counter
2122 int counter = 0;
2123
2124 // Count Sockets
2125 for (int i = 0; i < MAX_SOCKET; i++)
2126 if (adhocSockets[i] != NULL && adhocSockets[i]->type == SOCK_PDP)
2127 counter++;
2128
2129 // Return Socket Count
2130 return counter;
2131 }
2132
getPTPSocketCount()2133 int getPTPSocketCount() {
2134 // Socket Counter
2135 int counter = 0;
2136
2137 // Count Sockets
2138 for (int i = 0; i < MAX_SOCKET; i++)
2139 if (adhocSockets[i] != NULL && adhocSockets[i]->type == SOCK_PTP)
2140 counter++;
2141
2142 // Return Socket Count
2143 return counter;
2144 }
2145
initNetwork(SceNetAdhocctlAdhocId * adhoc_id)2146 int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
2147 auto n = GetI18NCategory("Networking");
2148 int iResult = 0;
2149 metasocket = (int)INVALID_SOCKET;
2150 metasocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
2151 if (metasocket == INVALID_SOCKET){
2152 ERROR_LOG(SCENET, "Invalid socket");
2153 return SOCKET_ERROR;
2154 }
2155 setSockKeepAlive((int)metasocket, true);
2156 // Disable Nagle Algo to prevent delaying small packets
2157 setSockNoDelay((int)metasocket, 1);
2158 // Switch to Nonblocking Behaviour
2159 changeBlockingMode((int)metasocket, 1);
2160
2161 // If Server is at localhost Try to Bind socket to specific adapter before connecting to prevent 2nd instance being recognized as already existing 127.0.0.1 by AdhocServer
2162 // (may not works in WinXP/2003 for IPv4 due to "Weak End System" model)
2163 if (isLoopbackIP(g_adhocServerIP.in.sin_addr.s_addr)) {
2164 int on = 1;
2165 // Not sure what is this SO_DONTROUTE supposed to fix, but i do remembered there were issue related to multiple-instances without SO_DONTROUTE, but forgot how to reproduce it :(
2166 setsockopt((int)metasocket, SOL_SOCKET, SO_DONTROUTE, (const char*)&on, sizeof(on));
2167 setSockReuseAddrPort((int)metasocket);
2168
2169 g_localhostIP.in.sin_port = 0;
2170 // Bind Local Address to Socket
2171 iResult = bind((int)metasocket, &g_localhostIP.addr, sizeof(g_localhostIP.addr));
2172 if (iResult == SOCKET_ERROR) {
2173 ERROR_LOG(SCENET, "Bind to alternate localhost[%s] failed(%i).", ip2str(g_localhostIP.in.sin_addr).c_str(), iResult);
2174 host->NotifyUserMessage(std::string(n->T("Failed to Bind Localhost IP")) + " " + ip2str(g_localhostIP.in.sin_addr).c_str(), 2.0, 0x0000ff);
2175 }
2176 }
2177
2178 // Default/Initial Network Parameters
2179 memset(¶meter, 0, sizeof(parameter));
2180 strncpy((char *)¶meter.nickname.data, g_Config.sNickName.c_str(), ADHOCCTL_NICKNAME_LEN);
2181 parameter.nickname.data[ADHOCCTL_NICKNAME_LEN - 1] = 0;
2182 parameter.channel = g_Config.iWlanAdhocChannel;
2183 // Assign a Valid Channel when connected to AP/Adhoc if it's Auto. JPCSP use 11 as default for Auto (Commonly for Auto: 1, 6, 11)
2184 if (parameter.channel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) parameter.channel = defaultWlanChannel; // Faked Active channel to default channel
2185 //getLocalMac(¶meter.bssid.mac_addr);
2186
2187 // Default ProductId
2188 product_code.type = adhoc_id->type;
2189 memcpy(product_code.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
2190
2191 // Don't need to connect if AdhocServer DNS was not resolved
2192 if (g_adhocServerIP.in.sin_addr.s_addr == INADDR_NONE)
2193 return -1;
2194
2195 // Don't need to connect if AdhocServer IP is the same with this instance localhost IP and having AdhocServer disabled
2196 if (g_adhocServerIP.in.sin_addr.s_addr == g_localhostIP.in.sin_addr.s_addr && !g_Config.bEnableAdhocServer)
2197 return -1;
2198
2199 // Connect to Adhoc Server
2200 int errorcode = 0;
2201 int cnt = 0;
2202 iResult = connect((int)metasocket, &g_adhocServerIP.addr, sizeof(g_adhocServerIP));
2203 errorcode = errno;
2204
2205 if (iResult == SOCKET_ERROR && errorcode != EISCONN) {
2206 u64 startTime = (u64)(time_now_d() * 1000000.0);
2207 while (IsSocketReady((int)metasocket, false, true) <= 0) {
2208 u64 now = (u64)(time_now_d() * 1000000.0);
2209 if (coreState == CORE_POWERDOWN) return iResult;
2210 if (now - startTime > adhocDefaultTimeout) break;
2211 sleep_ms(10);
2212 }
2213 if (IsSocketReady((int)metasocket, false, true) <= 0) {
2214 ERROR_LOG(SCENET, "Socket error (%i) when connecting to AdhocServer [%s/%s:%u]", errorcode, g_Config.proAdhocServer.c_str(), ip2str(g_adhocServerIP.in.sin_addr).c_str(), ntohs(g_adhocServerIP.in.sin_port));
2215 host->NotifyUserMessage(std::string(n->T("Failed to connect to Adhoc Server")) + " (" + std::string(n->T("Error")) + ": " + std::to_string(errorcode) + ")", 1.0f, 0x0000ff);
2216 return iResult;
2217 }
2218 }
2219
2220 // Prepare Login Packet
2221 SceNetAdhocctlLoginPacketC2S packet;
2222 packet.base.opcode = OPCODE_LOGIN;
2223 SceNetEtherAddr addres;
2224 getLocalMac(&addres);
2225 packet.mac = addres;
2226 strncpy((char *)&packet.name.data, g_Config.sNickName.c_str(), ADHOCCTL_NICKNAME_LEN);
2227 packet.name.data[ADHOCCTL_NICKNAME_LEN - 1] = 0;
2228 memcpy(packet.game.data, adhoc_id->data, ADHOCCTL_ADHOCID_LEN);
2229
2230 IsSocketReady((int)metasocket, false, true, nullptr, adhocDefaultTimeout);
2231 int sent = send((int)metasocket, (char*)&packet, sizeof(packet), MSG_NOSIGNAL);
2232 if (sent > 0) {
2233 socklen_t addrLen = sizeof(LocalIP);
2234 memset(&LocalIP, 0, addrLen);
2235 getsockname((int)metasocket, &LocalIP, &addrLen);
2236 host->NotifyUserMessage(n->T("Network Initialized"), 1.0);
2237 return 0;
2238 }
2239 else{
2240 return SOCKET_ERROR;
2241 }
2242 }
2243
isZeroMAC(const SceNetEtherAddr * addr)2244 bool isZeroMAC(const SceNetEtherAddr* addr) {
2245 return (memcmp(addr->data, "\x00\x00\x00\x00\x00\x00", ETHER_ADDR_LEN) == 0);
2246 }
2247
isBroadcastMAC(const SceNetEtherAddr * addr)2248 bool isBroadcastMAC(const SceNetEtherAddr * addr) {
2249 return (memcmp(addr->data, "\xFF\xFF\xFF\xFF\xFF\xFF", ETHER_ADDR_LEN) == 0);
2250 }
2251
resolveIP(uint32_t ip,SceNetEtherAddr * mac)2252 bool resolveIP(uint32_t ip, SceNetEtherAddr * mac) {
2253 sockaddr_in addr;
2254 getLocalIp(&addr);
2255 uint32_t localIp = addr.sin_addr.s_addr;
2256
2257 if (ip == localIp || ip == g_localhostIP.in.sin_addr.s_addr) {
2258 getLocalMac(mac);
2259 return true;
2260 }
2261
2262 // Multithreading Lock
2263 std::lock_guard<std::recursive_mutex> peer_guard(peerlock);
2264
2265 // Peer Reference
2266 SceNetAdhocctlPeerInfo * peer = friends;
2267
2268 // Iterate Peers
2269 for (; peer != NULL; peer = peer->next) {
2270 // Found Matching Peer
2271 if (peer->ip_addr == ip) {
2272 // Copy Data
2273 *mac = peer->mac_addr;
2274
2275 // Return Success
2276 return true;
2277 }
2278 }
2279
2280 // Peer not found
2281 return false;
2282 }
2283
resolveMAC(SceNetEtherAddr * mac,uint32_t * ip)2284 bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) {
2285 // Get Local MAC Address
2286 SceNetEtherAddr localMac;
2287 getLocalMac(&localMac);
2288 // Local MAC Requested
2289 if (isMacMatch(&localMac, mac)) {
2290 // Get Local IP Address
2291 sockaddr_in sockAddr;
2292 getLocalIp(&sockAddr);
2293 *ip = sockAddr.sin_addr.s_addr;
2294 return true; // return succes
2295 }
2296
2297 // Multithreading Lock
2298 std::lock_guard<std::recursive_mutex> peer_guard(peerlock);
2299
2300 // Peer Reference
2301 SceNetAdhocctlPeerInfo * peer = friends;
2302
2303 // Iterate Peers
2304 for (; peer != NULL; peer = peer->next) {
2305 // Found Matching Peer
2306 if (isMacMatch(&peer->mac_addr, mac)) {
2307 // Copy Data
2308 *ip = peer->ip_addr;
2309
2310 // Return Success
2311 return true;
2312 }
2313 }
2314
2315 // Peer not found
2316 return false;
2317 }
2318
validNetworkName(const SceNetAdhocctlGroupName * group_name)2319 bool validNetworkName(const SceNetAdhocctlGroupName * group_name) {
2320 // Result
2321 bool valid = true;
2322
2323 // Name given
2324 if (group_name != NULL) {
2325 // Iterate Name Characters
2326 for (int i = 0; i < ADHOCCTL_GROUPNAME_LEN && valid; i++) {
2327 // End of Name
2328 if (group_name->data[i] == 0) break;
2329
2330 // Not a digit
2331 if (group_name->data[i] < '0' || group_name->data[i] > '9') {
2332 // Not 'A' to 'Z'
2333 if (group_name->data[i] < 'A' || group_name->data[i] > 'Z') {
2334 // Not 'a' to 'z'
2335 if (group_name->data[i] < 'a' || group_name->data[i] > 'z') {
2336 // Invalid Name
2337 valid = false;
2338 }
2339 }
2340 }
2341 }
2342 }
2343 // Return Result
2344 return valid;
2345 }
2346
join32(u32 num1,u32 num2)2347 u64 join32(u32 num1, u32 num2){
2348 return (u64)num2 << 32 | num1;
2349 }
2350
split64(u64 num,int buff[])2351 void split64(u64 num, int buff[]){
2352 int num1 = (int)(num&firstMask);
2353 int num2 = (int)((num&secondMask) >> 32);
2354 buff[0] = num1;
2355 buff[1] = num2;
2356 }
2357
getMatchingEventStr(int code)2358 const char* getMatchingEventStr(int code) {
2359 const char *buf = NULL;
2360 switch (code) {
2361 case PSP_ADHOC_MATCHING_EVENT_HELLO:
2362 buf = "HELLO"; break;
2363 case PSP_ADHOC_MATCHING_EVENT_REQUEST:
2364 buf = "JOIN"; break;
2365 case PSP_ADHOC_MATCHING_EVENT_LEAVE:
2366 buf = "LEAVE"; break;
2367 case PSP_ADHOC_MATCHING_EVENT_DENY:
2368 buf = "REJECT"; break;
2369 case PSP_ADHOC_MATCHING_EVENT_CANCEL:
2370 buf = "CANCEL"; break;
2371 case PSP_ADHOC_MATCHING_EVENT_ACCEPT:
2372 buf = "ACCEPT"; break;
2373 case PSP_ADHOC_MATCHING_EVENT_ESTABLISHED:
2374 buf = "ESTABLISHED"; break;
2375 case PSP_ADHOC_MATCHING_EVENT_TIMEOUT:
2376 buf = "TIMEOUT"; break;
2377 case PSP_ADHOC_MATCHING_EVENT_ERROR:
2378 buf = "ERROR"; break;
2379 case PSP_ADHOC_MATCHING_EVENT_BYE:
2380 buf = "DISCONNECT"; break;
2381 case PSP_ADHOC_MATCHING_EVENT_DATA:
2382 buf = "DATA"; break;
2383 case PSP_ADHOC_MATCHING_EVENT_DATA_ACK:
2384 buf = "DATA_ACK"; break;
2385 case PSP_ADHOC_MATCHING_EVENT_DATA_TIMEOUT:
2386 buf = "DATA_TIMEOUT"; break;
2387 case PSP_ADHOC_MATCHING_EVENT_INTERNAL_PING:
2388 buf = "INTERNAL_PING"; break;
2389 default:
2390 buf = "UNKNOWN";
2391 }
2392 return buf;
2393 }
2394
getMatchingOpcodeStr(int code)2395 const char* getMatchingOpcodeStr(int code) {
2396 const char *buf = NULL;
2397 switch (code) {
2398 case PSP_ADHOC_MATCHING_PACKET_PING:
2399 buf = "PING"; break;
2400 case PSP_ADHOC_MATCHING_PACKET_HELLO:
2401 buf = "HELLO"; break;
2402 case PSP_ADHOC_MATCHING_PACKET_JOIN:
2403 buf = "JOIN"; break;
2404 case PSP_ADHOC_MATCHING_PACKET_ACCEPT:
2405 buf = "ACCEPT"; break;
2406 case PSP_ADHOC_MATCHING_PACKET_CANCEL:
2407 buf = "CANCEL"; break;
2408 case PSP_ADHOC_MATCHING_PACKET_BULK:
2409 buf = "BULK"; break;
2410 case PSP_ADHOC_MATCHING_PACKET_BULK_ABORT:
2411 buf = "BULK_ABORT"; break;
2412 case PSP_ADHOC_MATCHING_PACKET_BIRTH:
2413 buf = "BIRTH"; break;
2414 case PSP_ADHOC_MATCHING_PACKET_DEATH:
2415 buf = "DEATH"; break;
2416 case PSP_ADHOC_MATCHING_PACKET_BYE:
2417 buf = "BYE"; break;
2418 default:
2419 buf = "UNKNOWN";
2420 }
2421 return buf;
2422 }
2423
2424