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