CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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