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