CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

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

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HLE/proAdhocServer.cpp
Views: 1401
1
// Copyright (c) 2014- 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
// proAdhocServer
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 <cstdlib>
27
#include <cstdio>
28
#include <cstring>
29
#include <signal.h>
30
31
#if defined(HAVE_LIBNX) || PPSSPP_PLATFORM(SWITCH)
32
#include <netdb.h>
33
#include <switch.h>
34
// Missing include, *shrugs*
35
extern "C" struct hostent *gethostbyname(const char *name);
36
#endif // defined(HAVE_LIBNX) || PPSSPP_PLATFORM(SWITCH)
37
38
#include <sys/types.h>
39
// Net stuff
40
#if defined(_WIN32)
41
#include <WinSock2.h>
42
#include <WS2tcpip.h>
43
#else
44
#include <sys/socket.h>
45
#include <netinet/in.h>
46
#include <netinet/tcp.h>
47
#endif
48
49
#include <fcntl.h>
50
#include <errno.h>
51
//#include <sqlite3.h>
52
53
#ifndef MSG_NOSIGNAL
54
// Default value to 0x00 (do nothing) in systems where it's not supported.
55
#define MSG_NOSIGNAL 0x00
56
#endif
57
58
#include "Common/Data/Text/I18n.h"
59
#include "Common/Thread/ThreadUtil.h"
60
#include "Common/System/OSD.h"
61
62
#include "Common/File/FileUtil.h"
63
#include "Common/TimeUtil.h"
64
#include "Core/Util/PortManager.h"
65
#include "Core/Instance.h"
66
#include "Core/Core.h"
67
#include "Core/HLE/proAdhocServer.h"
68
69
// User Count
70
uint32_t _db_user_count = 0;
71
72
// User Database
73
SceNetAdhocctlUserNode * _db_user = NULL;
74
75
// Game Database
76
SceNetAdhocctlGameNode * _db_game = NULL;
77
78
// Server Status
79
std::atomic<bool> adhocServerRunning(false);
80
std::thread adhocServerThread;
81
82
// Crosslink database for cross region Adhoc play
83
std::vector<db_crosslink> crosslinks;
84
static const db_crosslink default_crosslinks[] = {
85
// Ace Combat X2 - Joint Assault
86
{ "ULES01408", "ULUS10511" },
87
{ "NPJH50263", "ULUS10511" },
88
89
// Armored Core 3 Portable
90
{ "ULJM05492", "NPUH10023" },
91
92
// BlazBlue - Continuum Shift 2
93
{ "NPJH50401", "ULUS10579" },
94
95
// Blood Bowl
96
{ "ULES01230", "ULUS10516" },
97
98
// Bomberman
99
{ "ULJM05034", "ULUS10121" },
100
{ "ULES00469", "ULUS10121" },
101
{ "ULJM05316", "ULUS10121" },
102
103
// Bomberman Land
104
{ "ULJM05181", "ULUS10319" },
105
{ "ULJM05319", "ULUS10319" },
106
{ "ULES00959", "ULUS10319" },
107
108
// Call of Duty - Roads to Victory
109
{ "ULES00643", "ULUS10218" },
110
111
// Dissidia 012 Duodecim Final Fantasy
112
{ "ULES01505", "ULUS10566" },
113
{ "NPJH50377", "ULUS10566" },
114
115
// Dissidia Final Fantasy
116
{ "ULES01270", "ULUS10437" },
117
{ "ULJM05262", "ULUS10437" },
118
119
// Dragon Ball Z - Shin Budokai
120
{ "ULJS00049", "ULUS10081" },
121
{ "ULKS46085", "ULUS10081" },
122
{ "ULES00309", "ULUS10081" },
123
124
// Dragon Ball Z - Shin Budokai 2
125
{ "ULJS00107", "ULUS10234" },
126
{ "ULES00789", "ULUS10234" },
127
128
// Dragon Ball Z - Tenkaichi Tag Team
129
{ "ULES01456", "ULUS10537" },
130
131
// Dungeon Siege - Throne of Agony
132
{ "ULES00569", "ULUS10177" },
133
134
// Everybody's Tennis
135
{ "UCJS10101", "UCUS98701" },
136
{ "UCES01420", "UCUS98701" },
137
138
// Fat Princess - Fistful of Cake
139
{ "UCES01312", "UCUS98740" },
140
{ "NPHG00025", "UCUS98740" },
141
142
// God Eater Burst
143
{ "ULES01519", "ULUS10563" },
144
{ "NPJH50352", "ULUS10563" },
145
146
// Gran Turismo
147
{ "UCES01245", "UCUS98632" },
148
{ "UCES00543", "UCUS98645" },
149
150
// Gundam VS Gundam - Next Plus
151
{ "ULJS00250", "NPJH50107" },
152
{ "ULJS19048", "NPJH50107" },
153
154
// Hatsune Miku - Project Diva Extend
155
{ "NPJH50465", "ULJM05933" },
156
157
// Hot Pixel
158
{ "ULES00642", "ULUS10298" },
159
160
// Lord of Arcana
161
{ "ULJM05767", "ULES01507" },
162
{ "ULUS10479", "ULES01507" },
163
164
// M.A.C.H. - Modified Air Combat Heroes
165
{ "ULES00565", "ULUS10180" },
166
{ "ULES00566", "ULUS10180" },
167
{ "ULJM05202", "ULUS10180" },
168
169
// Metal Gear Solid - Peace Walker
170
{ "ULES01372", "NPJH50045" },
171
{ "ULUS10509", "NPJH50045" },
172
173
// Metal Gear Solid - Portable Ops
174
{ "ULES00645", "ULUS10202" },
175
{ "ULJM05193", "ULUS10202" },
176
177
// Metal Gear Solid - Portable Ops +
178
{ "ULES01003", "ULUS10290" },
179
{ "ULJM05261", "ULUS10290" },
180
181
// Midnight Club - LA Remix
182
{ "ULES01144", "ULUS10383" },
183
{ "ULJS00180", "ULUS10383" },
184
185
// Mod Nation Racers
186
{ "UCES01327", "UCUS98741" },
187
{ "UCJS10112", "UCUS98741" },
188
{ "UCAS40306", "UCUS98741" },
189
190
// Monster Hunter Freedom
191
{ "ULJM05066", "ULUS10084" },
192
{ "ULES00318", "ULUS10084" },
193
194
// Monster Hunter Freedom 2
195
{ "ULJM05156", "ULUS10266" },
196
{ "ULES00851", "ULUS10266" },
197
198
// Monster Hunter Freedom Unite
199
{ "ULES01213", "ULUS10391" },
200
{ "ULJM05500", "ULUS10391" },
201
202
// N+
203
{ "ULES01026", "ULUS10340" },
204
205
// Need for Speed - Undercover
206
{ "ULJM05403", "ULUS10376" },
207
{ "ULJM05612", "ULUS10376" },
208
{ "ULES01145", "ULUS10376" },
209
210
// Outrun 2006 - Coast 2 Coast
211
{ "ULES00262", "ULUS10064" },
212
213
// Pangya! - Fantasy Golf
214
{ "ULJM05440", "ULUS10438" },
215
{ "ULKS46164", "ULUS10438" },
216
217
// PRO Evolution Soccer 2012
218
{ "ULES01540", "ULUS10586" },
219
{ "ULES01541", "ULUS10586" },
220
{ "ULES01542", "ULUS10586" },
221
{ "ULAS42289", "ULUS10586" },
222
223
// Patapon 2
224
{ "UCJS10089", "UCUS98732" },
225
{ "PSPJ30000", "UCUS98732" },
226
{ "UCES01177", "UCUS98732" },
227
{ "UCJS18036", "UCUS98732" },
228
229
// Patapon 3
230
{ "UCES01421", "UCUS98751" },
231
{ "NPJG00122", "UCUS98751" },
232
233
// Phantasy Star Portable
234
{ "ULJM05309", "ULUS10410" },
235
{ "ULES01218", "ULUS10410" },
236
{ "ULJM08023", "ULUS10410" },
237
238
// Phantasy Star Portable 2
239
{ "ULJM05493", "ULUS10529" },
240
{ "ULJM08030", "ULUS10529" },
241
{ "ULES01439", "ULUS10529" },
242
243
// Resistance - Retribution
244
{ "UCES01184", "UCJS10090" },
245
{ "UCUS98668", "UCJS10090" },
246
247
// Rocky Balboa
248
{ "ULUS10233", "ULES00670" },
249
250
// SOCOM - Fireteam Bravo
251
{ "UCES00038", "UCUS98615" },
252
{ "UCJS10102", "UCUS98615" },
253
254
// SOCOM - Fireteam Bravo 3
255
{ "UCES01242", "UCUS98716" },
256
{ "NPJG00035", "UCUS98716" },
257
258
// Shrek - Smash and Crash Racing
259
{ "ULES00618", "ULUS10194" },
260
261
// Smash Court Tennis 3
262
{ "ULJS00098", "UCES00758" },
263
{ "ULUS10269", "UCES00758" },
264
265
// Soul Calibur - Broken Destiny
266
{ "ULES01298", "ULUS10457" },
267
{ "ULJS00202", "ULUS10457" },
268
269
// Split Second - Velocity
270
{ "ULES01402", "ULUS10513" },
271
{ "ULJM05812", "ULUS10513" },
272
273
// Street Fighter Alpha 3 MAX
274
{ "ULJM05082", "ULUS10062" },
275
{ "ULES00235", "ULUS10062" },
276
{ "ULJM05225", "ULUS10062" },
277
278
// Taiko no Tatsujin Portable DX"
279
{ "ULJS00383", "NPJH50426" },
280
281
// Tekken 6
282
{ "ULES01376", "ULUS10466" },
283
{ "NPJH50184", "ULUS10466" },
284
{ "ULJS00224", "ULUS10466" },
285
286
// TRON - Evolution
287
{ "ULES01495", "ULUS10548" },
288
289
// Untold Legends - Brotherhood of the Blade
290
{ "ULES00046", "ULUS10003" },
291
{ "ULJM05087", "ULUS10003" },
292
{ "ULKS46015", "ULUS10003" },
293
294
// Untold Legends - The Warrior's Code
295
{ "ULES00301", "ULUS10086" },
296
{ "ULJM05179", "ULUS10086" },
297
{ "ULKS46069", "ULUS10086" },
298
299
// Virtua Tennis 3
300
{ "ULES00763", "ULUS10246" },
301
302
// World Series of Poker 2008 - Battle for the Bracelets
303
{ "ULES00991", "ULUS10321" },
304
305
// Worms Battle Islands
306
{ "NPEH00019", "NPUH10045" },
307
308
// Worms Open Warfare
309
{ "ULES00268", "ULUS10065" },
310
311
// Worms Open Warfare 2
312
{ "ULES00819", "ULUS10260" },
313
314
// Yu-Gi-Oh! 5D's Tag Force 5
315
{ "ULUS10555", "ULJM05734" },
316
{ "ULES01474", "ULJM05734" },
317
};
318
319
std::vector<db_productid> productids;
320
static const db_productid default_productids[] = {
321
{ "ULUS10511", "Ace Combat X2 - Joint Assault" },
322
{ "ULUS10245", "Alien Syndrome" },
323
{ "NPUH10023", "Armored Core 3 Portable" },
324
{ "ULES00719", "Asphalt - Urban GT 2" },
325
{ "ULUS10579", "BlazBlue - Continuum Shift 2" },
326
{ "ULUS10519", "BlazBlue Calamity Trigger" },
327
{ "UCJS10110", "Bleach Heat The Soul 7" },
328
{ "ULUS10516", "Blood Bowl" },
329
{ "ULUS10121", "Bomberman" },
330
{ "ULUS10319", "Bomberman Land" },
331
{ "ULES00703", "Burnout Dominator" },
332
{ "ULES00125", "Burnout Legends" },
333
{ "ULJM05538", "Busou Shinki - Battle Masters" },
334
{ "ULUS10057", "Bust A Move Deluxe" },
335
{ "ULUS10218", "Call of Duty - Roads to Victory" },
336
{ "ULUS10351", "Code Lyoko - Quest for Infinity" },
337
{ "NPJH50583", "Conception - Please have my children!" },
338
{ "ULUS10044", "Crash Tag Team Racing" },
339
{ "ULUS10100", "Def Jam Fight For NY - The Takeover" },
340
{ "NPJH50588", "Digimon World Re:Digitize" },
341
{ "ULUS10566", "Dissidia 012 Duodecim Final Fantasy" },
342
{ "ULUS10437", "Dissidia Final Fantasy" },
343
{ "ULUS10081", "Dragon Ball Z - Shin Budokai" },
344
{ "ULUS10234", "Dragon Ball Z - Shin Budokai 2" },
345
{ "ULUS10537", "Dragon Ball Z - Tenkaichi Tag Team" },
346
//maybe we can crosslinks this 2 region to ULUS10537 not having the game to test
347
{ "ULJS00311", "Dragon Ball Z - Tenkaichi Tag Team" },
348
{ "NPJH90135", "Dragon Ball Z - Tenkaichi Tag Team" },
349
{ "ULJM05127", "Dragon Quest & Final Fantasy in Itadaki Street Special" },
350
{ "ULES00847", "Dungeon Explorer - Warriors of Ancient Arts" },
351
{ "ULUS10177", "Dungeon Siege - Throne of Agony" },
352
{ "ULUS10170", "Dynasty Warrior 2" },
353
//looks like can be crosslinked too
354
{ "ULES01221", "Dynasty Warriors - Strike Force" },
355
{ "ULUS10416", "Dynasty Warriors - Strike Force" },
356
{ "UCUS98701", "Everybody's Tennis" },
357
{ "UCUS98740", "Fat Princess - Fistful of Cake" },
358
{ "ULJM05360", "Fate Tiger Colosseum Upper" },
359
{ "ULUS10297", "Final Fantasy Tactics - The War of the Lions" },
360
{ "ULES00850", "Final Fantasy Tactics - War of the Lions" },
361
{ "NPJH50443", "Final Fantasy Type 0" },
362
{ "NPJH50468", "Frontier Gate" },
363
{ "NPJH50721", "Frontier Gate Boost+" },
364
{ "ULES01432", "Full Metal Alchemist - Brotherhood" },
365
{ "ULUS10490", "GTA Chinatown Wars" },
366
{ "ULUS10160", "GTA Vice City Stories" },
367
{ "ULUS10210", "Ghost Rider" },
368
{ "ULJS00237", "God Eater" },
369
{ "NPJH50832", "God Eater 2" },
370
{ "ULUS10563", "God Eater Burst" },
371
{ "UCUS98632", "Gran Turismo" },
372
{ "NPJH50107", "Gundam VS Gundam - Next Plus" },
373
{ "ULJM05933", "Hatsune Miku - Project Diva Extend" },
374
{ "ULUS10298", "Hot Pixel" },
375
{ "ULJM05709", "K-ON! Houkago Live" },
376
{ "NPJH50221", "Kateikyoushi Hitman Reborn! Kizuna no Tag Battle" },
377
{ "ULJS00165", "Kidou Senshi Gundam - Gundam vs. Gundam" },
378
{ "UCUS98646", "Killzone Liberation" },
379
{ "ULJM05775", "Kingdom Hearts - Birth by Sleep Final Mix" },
380
{ "ULUS10487", "LEGO Indiana Jones 2" },
381
{ "NPJH50503", "Lord of Apocalypse" },
382
{ "ULES01507", "Lord of Arcana" },
383
{ "ULUS10180", "M.A.C.H. - Modified Air Combat Heroes" },
384
{ "UCUS98758", "MLB11 - The Show" },
385
{ "ULUS10581", "Madden NFL 12" },
386
{ "ULJS00385", "Mahou Shoujo Nanoha A's Portable - The Gears of Destiny" },
387
{ "ULUS10408", "Mana Khemia Student Alliance" },
388
{ "ULUS10141", "Medal Of Honor Heroes" },
389
{ "NPJH50045", "Metal Gear Solid - Peace Walker" },
390
{ "ULUS10202", "Metal Gear Solid - Portable Ops" },
391
{ "ULUS10290", "Metal Gear Solid - Portable Ops +" },
392
{ "ULUS10154", "Metal Slug Anthology" },
393
{ "ULUS10495", "Metal Slug XX" },
394
{ "ULES01429", "Metal Slug XX" },
395
{ "ULES00368", "Micro Machines V4" },
396
{ "ULUS10383", "Midnight Club - LA Remix" },
397
{ "UCUS98741", "Mod Nation Racers" },
398
{ "ULUS10084", "Monster Hunter Freedom" },
399
{ "ULUS10266", "Monster Hunter Freedom 2" },
400
{ "ULUS10391", "Monster Hunter Freedom Unite" },
401
{ "ULJM05800", "Monster Hunter Portable 3rd" },
402
{ "ULJM06097", "Musou Orochi 2 Special" },
403
{ "ULUS10340", "N+" },
404
{ "ULES01578", "NBA 2K13" },
405
{ "ULUS10598", "NBA 2K13" },
406
{ "ULUS10349", "Naruto - Ultimate Ninja Heroes 2" },
407
{ "ULUS10518", "Naruto - Ultimate Ninja Heroes 3" },
408
{ "ULJS00236", "Naruto - Accel 3" },
409
{ "ULUS10582", "Naruto Shippuden - Ultimate Ninja Impact" },
410
{ "ULES01537", "Naruto Shippuden - Ultimate Ninja Impact" },
411
{ "ULUS10571", "Naruto Shippuden - Kizuna Drive" },
412
{ "ULES00196", "Need For Speed - Most Wanted" },
413
{ "ULUS10036", "Need For Speed - Most Wanted" },
414
{ "ULUS10376", "Need for Speed - Undercover" },
415
{ "ULKS46004", "Need for Speed - Underground Rivals" },
416
{ "ULES01340", "Obscure - The Aftermath" },
417
{ "ULUS10064", "Outrun 2006 - Coast 2 Coast" },
418
{ "ULUS10586", "PRO Evolution Soccer 2012" },
419
{ "ULUS10149", "Pac Man - World Rally" },
420
{ "ULUS10438", "Pangya! - Fantasy Golf" },
421
{ "UCUS98732", "Patapon 2" },
422
{ "UCUS98751", "Patapon 3" },
423
{ "ULUS10410", "Phantasy Star Portable" },
424
{ "ULUS10529", "Phantasy Star Portable 2" },
425
//looks like this japan version can crosslink to ULUS10529
426
{ "NPJH50332", "Phantasy Star Portable 2" },
427
{ "ULJM05732", "Phantasy Star Portable 2 - Infinity" },
428
{ "ULES01596", "Pro Evolution Soccer 2014" },
429
{ "ULES01595", "Pro Evolution Soccer 2015" },
430
{ "NPJH50520", "Pro Yakyuu Spirits 2012" },
431
{ "NPJH50838", "Pro Yakyuu Spirits 2014" },
432
{ "NPJH50492", "Puyo Puyo!! 20th Anniversary" },
433
{ "ULUS10292", "Renegrade Squadron" },
434
{ "UCJS10090", "Resistance - Retribution" },
435
{ "ULES00670", "Rocky Balboa" },
436
{ "ULJS00360", "Rurouni Kenshin - Meiji Kenkaku Romantan Saisen" },
437
{ "UCUS98615", "SOCOM - Fireteam Bravo" },
438
{ "UCUS98645", "SOCOM - Fireteam Bravo 2" },
439
{ "UCUS98716", "SOCOM - Fireteam Bravo 3" },
440
{ "NPJH50460", "Sengoku Basara - Chronicles Heroes" },
441
{ "ULJM05436", "Sengoku Basara - Battle Heroes" },
442
{ "ULJM05637", "Shin Sangoku Musou - Multi Raid 2" },
443
{ "ULJM05035", "Shinobido - Tales of the Ninja" },
444
{ "ULUS10194", "Shrek - Smash and Crash Racing" },
445
{ "UCES00758", "Smash Court Tennis 3" },
446
{ "ULUS10195", "Sonic Rivals" },
447
{ "ULUS10457", "Soul Calibur - Broken Destiny" },
448
{ "ULUS10513", "Split Second - Velocity" },
449
{ "ULES00183", "Star Wars Battle Front 2" },
450
{ "ULUS10062", "Street Fighter Alpha 3 MAX" },
451
{ "NPUH10020", "Strikers 1945 Plus Portable" },
452
{ "ULUS10548", "TRON - Evolution" },
453
{ "NPJH50426", "Taiko no Tatsujin Portable DX" },
454
{ "ULUS10466", "Tekken 6" },
455
{ "NPJH50691", "Tokusatsu University" },
456
//looks like can be crosslinked
457
{ "ULUS10445", "Tom Clancy's Ghost Recon - Predator" },
458
{ "ULES01350", "Tom Clancy's Ghost Recon - Predator" },
459
{ "NPJH50789", "Toukiden" },
460
{ "NPJH50878", "Toukiden - Kiwami" },
461
{ "UCUS98601", "Twisted Metal - Head On" },
462
{ "ULUS10508", "UFC Undisputed 2010" },
463
{ "ULJS00069", "Ultraman Fighting Evo Zero" },
464
{ "ULUS10003", "Untold Legends - Brotherhood of the Blade" },
465
{ "ULUS10086", "Untold Legends - The Warrior's Code" },
466
{ "ULUS10515", "Valkryia Chronicles 2" },
467
{ "ULUS10087", "Viewtiful Joe" },
468
{ "ULUS10246", "Virtua Tennis 3" },
469
{ "ULUS82741", "WWE 2K14" },
470
{ "ULUS10543", "WWE Smackdown vs. Raw 2011" },
471
{ "ULUS10423", "Warriors Orochi 2" },
472
{ "ULJM05553", "Warship Gunner 2 Portable" },
473
{ "ULJS00155", "Way Of The Samurai" },
474
{ "UCES00465", "Wipeout Pulse" },
475
{ "ULUS10321", "World Series of Poker 2008 - Battle for the Bracelets" },
476
{ "NPUH10045", "Worms Battle Islands" },
477
{ "ULUS10065", "Worms Open Warfare" },
478
{ "ULUS10260", "Worms Open Warfare 2" },
479
{ "ULJM05734", "Yu-Gi-Oh! 5D's Tag Force 5" },
480
{ "ULJM05940", "Yu-Gi-Oh! 5D's Tag Force 6" },
481
{ "NPJH00142", "Yu-Gi-Oh! Arc-V Tag Force" },
482
{ "ULJM05151", "Yu-Gi-Oh! GX Tag Force" },
483
{ "ULJM05373", "Yu-Gi-Oh! GX Tag Force 3" },
484
{ "NPUG80086", "flOw" },
485
};
486
487
// Function Prototypes
488
const char * strcpyxml(char * out, const char * in, uint32_t size);
489
490
// Function Prototypes
491
void interrupt(int sig);
492
void enable_address_reuse(int fd);
493
void enable_keepalive(int fd);
494
void change_nodelay_mode(int fd, int flag);
495
void change_blocking_mode(int fd, int nonblocking);
496
int create_listen_socket(uint16_t port);
497
int server_loop(int server);
498
499
void __AdhocServerInit() {
500
// Database Product name will update if new game region played on my server to list possible crosslinks
501
productids = std::vector<db_productid>(default_productids, default_productids + ARRAY_SIZE(default_productids));
502
crosslinks = std::vector<db_crosslink>(default_crosslinks, default_crosslinks + ARRAY_SIZE(default_crosslinks));
503
}
504
505
/**
506
* Login User into Database (Stream)
507
* @param fd Socket
508
* @param ip IP Address (Network Order)
509
*/
510
void login_user_stream(int fd, uint32_t ip)
511
{
512
// Enough Space available
513
if(_db_user_count < SERVER_USER_MAXIMUM)
514
{
515
// Check IP Duplication
516
SceNetAdhocctlUserNode * u = _db_user;
517
while(u != NULL && u->resolver.ip != ip) u = u->next;
518
519
if (u != NULL) { // IP Already existed
520
WARN_LOG(Log::sceNet, "AdhocServer: Already Existing IP: %s\n", ip2str(*(in_addr*)&u->resolver.ip).c_str());
521
}
522
523
// Unique IP Address
524
else //if(u == NULL)
525
{
526
// Allocate User Node Memory
527
SceNetAdhocctlUserNode * user = (SceNetAdhocctlUserNode *)malloc(sizeof(SceNetAdhocctlUserNode));
528
529
// Allocated User Node Memory
530
if(user != NULL)
531
{
532
// Clear Memory
533
memset(user, 0, sizeof(SceNetAdhocctlUserNode));
534
535
// Save Socket
536
user->stream = fd;
537
538
// Save IP
539
user->resolver.ip = ip;
540
541
// Link into User List
542
user->next = _db_user;
543
if(_db_user != NULL) _db_user->prev = user;
544
_db_user = user;
545
546
// Initialize Death Clock
547
user->last_recv = time(NULL);
548
549
// Notify User
550
INFO_LOG(Log::sceNet, "AdhocServer: New Connection from %s", ip2str(*(in_addr*)&user->resolver.ip).c_str());
551
552
// Fix User Counter
553
_db_user_count++;
554
555
// Update Status Log
556
update_status();
557
558
// Exit Function
559
return;
560
}
561
}
562
}
563
564
// Duplicate IP, Allocation Error or not enough space - Close Stream
565
closesocket(fd);
566
}
567
568
/**
569
* Login User into Database (Login Data)
570
* @param user User Node
571
* @param data Login Packet
572
*/
573
void login_user_data(SceNetAdhocctlUserNode * user, SceNetAdhocctlLoginPacketC2S * data)
574
{
575
// Product Code Check
576
int valid_product_code = 1;
577
578
// Iterate Characters
579
int i = 0; for(; i < PRODUCT_CODE_LENGTH && valid_product_code == 1; i++)
580
{
581
// Valid Characters
582
if(!((data->game.data[i] >= 'A' && data->game.data[i] <= 'Z') || (data->game.data[i] >= '0' && data->game.data[i] <= '9'))) valid_product_code = 0;
583
}
584
585
// Valid Packet Data
586
if(valid_product_code == 1 && memcmp(&data->mac, "\xFF\xFF\xFF\xFF\xFF\xFF", sizeof(data->mac)) != 0 && memcmp(&data->mac, "\x00\x00\x00\x00\x00\x00", sizeof(data->mac)) != 0 && data->name.data[0] != 0)
587
{
588
// Check for duplicated MAC as most games identify Players by MAC
589
SceNetAdhocctlUserNode* u = _db_user;
590
while (u != NULL && !IsMatch(u->resolver.mac, data->mac)) u = u->next;
591
592
if (u != NULL) { // MAC Already existed
593
WARN_LOG(Log::sceNet, "AdhocServer: Already Existing MAC: %s [%s]\n", mac2str(&data->mac).c_str(), ip2str(*(in_addr*)&u->resolver.ip).c_str());
594
}
595
596
// Game Product Override
597
game_product_override(&data->game);
598
599
// Find existing Game
600
SceNetAdhocctlGameNode * game = _db_game;
601
while(game != NULL && strncmp(game->game.data, data->game.data, PRODUCT_CODE_LENGTH) != 0) game = game->next;
602
603
// Game not found
604
if(game == NULL)
605
{
606
// Allocate Game Node Memory
607
game = (SceNetAdhocctlGameNode *)malloc(sizeof(SceNetAdhocctlGameNode));
608
609
// Allocated Game Node Memory
610
if(game != NULL)
611
{
612
// Clear Memory
613
memset(game, 0, sizeof(SceNetAdhocctlGameNode));
614
615
// Save Game Product ID
616
game->game = data->game;
617
618
// Link into Game List
619
game->next = _db_game;
620
if(_db_game != NULL) _db_game->prev = game;
621
_db_game = game;
622
}
623
}
624
625
// Game now available
626
if(game != NULL)
627
{
628
// Save MAC
629
user->resolver.mac = data->mac;
630
631
// Save Nickname
632
user->resolver.name = data->name;
633
634
// Increase Player Count in Game Node
635
game->playercount++;
636
637
// Link Game to Player
638
user->game = game;
639
640
// Notify User
641
char safegamestr[10];
642
memset(safegamestr, 0, sizeof(safegamestr));
643
strncpy(safegamestr, game->game.data, PRODUCT_CODE_LENGTH);
644
INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) started playing %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr);
645
646
// Update Status Log
647
update_status();
648
649
// Leave Function
650
return;
651
}
652
}
653
654
// Invalid Packet Data
655
else
656
{
657
// Notify User
658
WARN_LOG(Log::sceNet, "AdhocServer: Invalid Login Packet Contents from %s", ip2str(*(in_addr*)&user->resolver.ip).c_str());
659
}
660
661
// Logout User - Out of Memory or Invalid Arguments
662
logout_user(user);
663
}
664
665
/**
666
* Logout User from Database
667
* @param user User Node
668
*/
669
void logout_user(SceNetAdhocctlUserNode * user)
670
{
671
// Disconnect from Group
672
if(user->group != NULL) disconnect_user(user);
673
674
// Unlink Leftside (Beginning)
675
if(user->prev == NULL) _db_user = user->next;
676
677
// Unlink Leftside (Other)
678
else user->prev->next = user->next;
679
680
// Unlink Rightside
681
if(user->next != NULL) user->next->prev = user->prev;
682
683
// Close Stream
684
closesocket(user->stream);
685
686
// Playing User
687
if(user->game != NULL)
688
{
689
// Notify User
690
char safegamestr[10];
691
memset(safegamestr, 0, sizeof(safegamestr));
692
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
693
INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) stopped playing %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr);
694
695
// Fix Game Player Count
696
user->game->playercount--;
697
698
// Empty Game Node
699
if(user->game->playercount == 0)
700
{
701
// Unlink Leftside (Beginning)
702
if(user->game->prev == NULL) _db_game = user->game->next;
703
704
// Unlink Leftside (Other)
705
else user->game->prev->next = user->game->next;
706
707
// Unlink Rightside
708
if(user->game->next != NULL) user->game->next->prev = user->game->prev;
709
710
// Free Game Node Memory
711
free(user->game);
712
}
713
}
714
715
// Unidentified User
716
else
717
{
718
// Notify User
719
WARN_LOG(Log::sceNet, "AdhocServer: Dropped Connection to %s", ip2str(*(in_addr*)&user->resolver.ip).c_str());
720
}
721
722
// Free Memory
723
free(user);
724
725
// Fix User Counter
726
_db_user_count--;
727
728
// Update Status Log
729
update_status();
730
}
731
732
/**
733
* Free Database Memory
734
*/
735
void free_database()
736
{
737
// There are users playing
738
if(_db_user_count > 0)
739
{
740
// Send Shutdown Notice
741
spread_message(NULL, SERVER_SHUTDOWN_MESSAGE);
742
}
743
744
// Iterate Users for Deletion
745
SceNetAdhocctlUserNode * user = _db_user;
746
while(user != NULL)
747
{
748
// Next User (for safe delete)
749
SceNetAdhocctlUserNode * next = user->next;
750
751
// Logout User
752
logout_user(user);
753
754
// Move Pointer
755
user = next;
756
}
757
}
758
759
/**
760
* Connect User to Game Group
761
* @param user User Node
762
* @param group Group Name
763
*/
764
void connect_user(SceNetAdhocctlUserNode * user, SceNetAdhocctlGroupName * group)
765
{
766
// Group Name Check
767
int valid_group_name = 1;
768
{
769
// Iterate Characters
770
int i = 0; for(; i < ADHOCCTL_GROUPNAME_LEN && valid_group_name == 1; i++)
771
{
772
// End of Name
773
if(group->data[i] == 0) break;
774
775
// A - Z
776
if(group->data[i] >= 'A' && group->data[i] <= 'Z') continue;
777
778
// a - z
779
if(group->data[i] >= 'a' && group->data[i] <= 'z') continue;
780
781
// 0 - 9
782
if(group->data[i] >= '0' && group->data[i] <= '9') continue;
783
784
// Invalid Symbol
785
valid_group_name = 0;
786
}
787
}
788
789
// Valid Group Name
790
if(valid_group_name == 1)
791
{
792
// User is disconnected
793
if(user->group == NULL)
794
{
795
// Find Group in Game Node
796
SceNetAdhocctlGroupNode * g = user->game->group;
797
while(g != NULL && strncmp((char *)g->group.data, (char *)group->data, ADHOCCTL_GROUPNAME_LEN) != 0) g = g->next;
798
799
// BSSID Packet
800
SceNetAdhocctlConnectBSSIDPacketS2C bssid;
801
802
// Set BSSID Opcode
803
bssid.base.opcode = OPCODE_CONNECT_BSSID;
804
805
// Set Default BSSID
806
bssid.mac = user->resolver.mac;
807
808
// No Group found
809
if(g == NULL)
810
{
811
// Allocate Group Memory
812
g = (SceNetAdhocctlGroupNode *)malloc(sizeof(SceNetAdhocctlGroupNode));
813
814
// Allocated Group Memory
815
if(g != NULL)
816
{
817
// Clear Memory
818
memset(g, 0, sizeof(SceNetAdhocctlGroupNode));
819
820
// Link Game Node
821
g->game = user->game;
822
823
// Link Group Node
824
g->next = g->game->group;
825
if(g->game->group != NULL) g->game->group->prev = g;
826
g->game->group = g;
827
828
// Copy Group Name
829
g->group = *group;
830
831
// Increase Group Counter for Game
832
g->game->groupcount++;
833
}
834
}
835
836
// Group now available
837
if(g != NULL)
838
{
839
// Iterate remaining Group Players
840
SceNetAdhocctlUserNode * peer = g->player;
841
while(peer != NULL)
842
{
843
// Connect Packet
844
SceNetAdhocctlConnectPacketS2C packet;
845
846
// Clear Memory
847
// memset(&packet, 0, sizeof(packet));
848
849
// Set Connect Opcode
850
packet.base.opcode = OPCODE_CONNECT;
851
852
// Set Player Name
853
packet.name = user->resolver.name;
854
855
// Set Player MAC
856
packet.mac = user->resolver.mac;
857
858
// Set Player IP
859
packet.ip = user->resolver.ip;
860
861
// Send Data
862
int iResult = (int)send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL);
863
if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: connect_user[send peer] (Socket error %d)", errno);
864
865
// Set Player Name
866
packet.name = peer->resolver.name;
867
868
// Set Player MAC
869
packet.mac = peer->resolver.mac;
870
871
// Set Player IP
872
packet.ip = peer->resolver.ip;
873
874
// Send Data
875
iResult = (int)send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL);
876
if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: connect_user[send user] (Socket error %d)", errno);
877
878
// Set BSSID
879
if(peer->group_next == NULL) bssid.mac = peer->resolver.mac;
880
881
// Move Pointer
882
peer = peer->group_next;
883
}
884
885
// Link User to Group
886
user->group_next = g->player;
887
if(g->player != NULL) g->player->group_prev = user;
888
g->player = user;
889
890
// Link Group to User
891
user->group = g;
892
893
// Increase Player Count
894
g->playercount++;
895
896
// Send Network BSSID to User
897
int iResult = (int)send(user->stream, (const char*)&bssid, sizeof(bssid), MSG_NOSIGNAL);
898
if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: connect_user[send user bssid] (Socket error %d)", errno);
899
900
// Notify User
901
char safegamestr[10];
902
memset(safegamestr, 0, sizeof(safegamestr));
903
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
904
char safegroupstr[9];
905
memset(safegroupstr, 0, sizeof(safegroupstr));
906
strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN);
907
INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) joined %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr);
908
909
// Update Status Log
910
update_status();
911
912
// Exit Function
913
return;
914
}
915
}
916
917
// Already connected to another group
918
else
919
{
920
// Notify User
921
char safegamestr[10];
922
memset(safegamestr, 0, sizeof(safegamestr));
923
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
924
char safegroupstr[9];
925
memset(safegroupstr, 0, sizeof(safegroupstr));
926
strncpy(safegroupstr, (char *)group->data, ADHOCCTL_GROUPNAME_LEN);
927
char safegroupstr2[9];
928
memset(safegroupstr2, 0, sizeof(safegroupstr2));
929
strncpy(safegroupstr2, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN);
930
WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to join %s group %s without disconnecting from %s first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr, safegroupstr2);
931
}
932
}
933
934
// Invalid Group Name
935
else
936
{
937
// Notify User
938
char safegamestr[10];
939
memset(safegamestr, 0, sizeof(safegamestr));
940
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
941
char safegroupstr[9];
942
memset(safegroupstr, 0, sizeof(safegroupstr));
943
strncpy(safegroupstr, (char *)group->data, ADHOCCTL_GROUPNAME_LEN);
944
WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to join invalid %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr);
945
}
946
947
// Invalid State, Out of Memory or Invalid Group Name
948
logout_user(user);
949
}
950
951
/**
952
* Disconnect User from Game Group
953
* @param user User Node
954
*/
955
void disconnect_user(SceNetAdhocctlUserNode * user)
956
{
957
// User is connected
958
if(user->group != NULL)
959
{
960
// Unlink Leftside (Beginning)
961
if(user->group_prev == NULL) user->group->player = user->group_next;
962
963
// Unlink Leftside (Other)
964
else user->group_prev->group_next = user->group_next;
965
966
// Unlink Rightside
967
if(user->group_next != NULL) user->group_next->group_prev = user->group_prev;
968
969
// Fix Player Count
970
user->group->playercount--;
971
972
// Iterate remaining Group Players
973
SceNetAdhocctlUserNode * peer = user->group->player;
974
while(peer != NULL)
975
{
976
// Disconnect Packet
977
SceNetAdhocctlDisconnectPacketS2C packet;
978
979
// Clear Memory
980
// memset(&packet, 0, sizeof(packet));
981
982
// Set Disconnect Opcode
983
packet.base.opcode = OPCODE_DISCONNECT;
984
985
// Set User IP
986
packet.ip = user->resolver.ip;
987
988
// Send Data
989
int iResult = (int)send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL);
990
if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: disconnect_user[send peer] (Socket error %d)", errno);
991
992
// Move Pointer
993
peer = peer->group_next;
994
}
995
996
// Notify User
997
char safegamestr[10];
998
memset(safegamestr, 0, sizeof(safegamestr));
999
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
1000
char safegroupstr[9];
1001
memset(safegroupstr, 0, sizeof(safegroupstr));
1002
strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN);
1003
INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) left %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr);
1004
1005
// Empty Group
1006
if(user->group->playercount == 0)
1007
{
1008
// Unlink Leftside (Beginning)
1009
if(user->group->prev == NULL) user->group->game->group = user->group->next;
1010
1011
// Unlink Leftside (Other)
1012
else user->group->prev->next = user->group->next;
1013
1014
// Unlink Rightside
1015
if(user->group->next != NULL) user->group->next->prev = user->group->prev;
1016
1017
// Free Group Memory
1018
free(user->group);
1019
1020
// Decrease Group Counter in Game Node
1021
user->game->groupcount--;
1022
}
1023
1024
// Unlink from Group
1025
user->group = NULL;
1026
user->group_next = NULL;
1027
user->group_prev = NULL;
1028
1029
// Update Status Log
1030
update_status();
1031
1032
// Exit Function
1033
return;
1034
}
1035
1036
// Not in a game group
1037
else
1038
{
1039
// Notify User
1040
char safegamestr[10];
1041
memset(safegamestr, 0, sizeof(safegamestr));
1042
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
1043
WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to leave %s group without joining one first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr);
1044
}
1045
1046
// Delete User
1047
logout_user(user);
1048
}
1049
1050
/**
1051
* Send Game Group List
1052
* @param user User Node
1053
*/
1054
void send_scan_results(SceNetAdhocctlUserNode * user)
1055
{
1056
// User is disconnected
1057
if(user->group == NULL)
1058
{
1059
// Iterate Groups
1060
SceNetAdhocctlGroupNode * group = user->game->group;
1061
for(; group != NULL; group = group->next)
1062
{
1063
// Scan Result Packet
1064
SceNetAdhocctlScanPacketS2C packet;
1065
1066
// Clear Memory
1067
// memset(&packet, 0, sizeof(packet));
1068
1069
// Set Opcode
1070
packet.base.opcode = OPCODE_SCAN;
1071
1072
// Set Group Name
1073
packet.group = group->group;
1074
1075
// Iterate Players in Network Group
1076
SceNetAdhocctlUserNode * peer = group->player;
1077
for(; peer != NULL; peer = peer->group_next)
1078
{
1079
// Found Network Founder
1080
if(peer->group_next == NULL)
1081
{
1082
// Set Group Host MAC
1083
packet.mac = peer->resolver.mac;
1084
}
1085
}
1086
1087
// Send Group Packet
1088
int iResult = (int)send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL);
1089
if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: send_scan_result[send user] (Socket error %d)", errno);
1090
}
1091
1092
// Notify Player of End of Scan
1093
uint8_t opcode = OPCODE_SCAN_COMPLETE;
1094
int iResult = (int)send(user->stream, (const char*)&opcode, 1, MSG_NOSIGNAL);
1095
if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: send_scan_result[send peer complete] (Socket error %d)", errno);
1096
1097
// Notify User
1098
char safegamestr[10];
1099
memset(safegamestr, 0, sizeof(safegamestr));
1100
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
1101
INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) requested information on %d %s groups", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), user->game->groupcount, safegamestr);
1102
1103
// Exit Function
1104
return;
1105
}
1106
1107
// User in a game group
1108
else
1109
{
1110
// Notify User
1111
char safegamestr[10];
1112
memset(safegamestr, 0, sizeof(safegamestr));
1113
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
1114
char safegroupstr[9];
1115
memset(safegroupstr, 0, sizeof(safegroupstr));
1116
strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN);
1117
WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to scan for %s groups without disconnecting from %s first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr, safegroupstr);
1118
}
1119
1120
// Delete User
1121
logout_user(user);
1122
}
1123
1124
/**
1125
* Spread Chat Message in P2P Network
1126
* @param user Sender User Node
1127
* @param message Chat Message
1128
*/
1129
void spread_message(SceNetAdhocctlUserNode *user, const char *message)
1130
{
1131
// Global Notice
1132
if(user == NULL)
1133
{
1134
// Iterate Players
1135
for(user = _db_user; user != NULL; user = user->next)
1136
{
1137
// Player has access to chat
1138
if(user->group != NULL)
1139
{
1140
// Chat Packet
1141
SceNetAdhocctlChatPacketS2C packet;
1142
1143
// Clear Memory
1144
memset(&packet, 0, sizeof(packet));
1145
1146
// Set Chat Opcode
1147
packet.base.base.opcode = OPCODE_CHAT;
1148
1149
// Set Chat Message
1150
strcpy(packet.base.message, message);
1151
1152
// Send Data
1153
int iResult = (int)send(user->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL);
1154
if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: spread_message[send user chat] (Socket error %d)", errno);
1155
}
1156
}
1157
1158
// Prevent NULL Error
1159
return;
1160
}
1161
1162
// User is connected
1163
else if(user->group != NULL)
1164
{
1165
// Broadcast Range Counter
1166
uint32_t counter = 0;
1167
1168
// Iterate Group Players
1169
SceNetAdhocctlUserNode * peer = user->group->player;
1170
while(peer != NULL)
1171
{
1172
// Skip Self
1173
if(peer == user)
1174
{
1175
// Move Pointer
1176
peer = peer->group_next;
1177
1178
// Continue Loop
1179
continue;
1180
}
1181
1182
// Chat Packet
1183
SceNetAdhocctlChatPacketS2C packet;
1184
1185
// Set Chat Opcode
1186
packet.base.base.opcode = OPCODE_CHAT;
1187
1188
// Set Chat Message
1189
strcpy(packet.base.message, message);
1190
1191
// Set Sender Nickname
1192
packet.name = user->resolver.name;
1193
1194
// Send Data
1195
int iResult = (int)send(peer->stream, (const char*)&packet, sizeof(packet), MSG_NOSIGNAL);
1196
if (iResult < 0) ERROR_LOG(Log::sceNet, "AdhocServer: spread_message[send peer chat] (Socket error %d)", errno);
1197
1198
// Move Pointer
1199
peer = peer->group_next;
1200
1201
// Increase Broadcast Range Counter
1202
counter++;
1203
}
1204
1205
// Message Sent
1206
if(counter > 0)
1207
{
1208
// Notify User
1209
char safegamestr[10];
1210
memset(safegamestr, 0, sizeof(safegamestr));
1211
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
1212
char safegroupstr[9];
1213
memset(safegroupstr, 0, sizeof(safegroupstr));
1214
strncpy(safegroupstr, (char *)user->group->group.data, ADHOCCTL_GROUPNAME_LEN);
1215
INFO_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) sent \"%s\" to %d players in %s group %s", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), message, counter, safegamestr, safegroupstr);
1216
}
1217
1218
// Exit Function
1219
return;
1220
}
1221
1222
// User not in a game group
1223
else
1224
{
1225
// Notify User
1226
char safegamestr[10];
1227
memset(safegamestr, 0, sizeof(safegamestr));
1228
strncpy(safegamestr, user->game->game.data, PRODUCT_CODE_LENGTH);
1229
WARN_LOG(Log::sceNet, "AdhocServer: %s (MAC: %s - IP: %s) attempted to send a text message without joining a %s group first", (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str(), safegamestr);
1230
}
1231
1232
// Delete User
1233
logout_user(user);
1234
}
1235
1236
/**
1237
* Get User State
1238
* @param user User Node
1239
*/
1240
int get_user_state(SceNetAdhocctlUserNode * user)
1241
{
1242
// Timeout Status
1243
if((time(NULL) - user->last_recv) >= SERVER_USER_TIMEOUT) return USER_STATE_TIMED_OUT;
1244
1245
// Waiting Status
1246
if(user->game == NULL) return USER_STATE_WAITING;
1247
1248
// Logged-In Status
1249
return USER_STATE_LOGGED_IN;
1250
}
1251
1252
/**
1253
* Clear RX Buffer
1254
* @param user User Node
1255
* @param clear Number of Bytes to clear (-1 for all)
1256
*/
1257
void clear_user_rxbuf(SceNetAdhocctlUserNode * user, int clear)
1258
{
1259
// Fix Clear Length
1260
if(clear == -1 || clear > (int)user->rxpos) clear = user->rxpos;
1261
1262
// Move Buffer
1263
memmove(user->rx, user->rx + clear, sizeof(user->rx) - clear);
1264
1265
// Fix RX Buffer Pointer
1266
user->rxpos -= clear;
1267
}
1268
1269
/**
1270
* Patch Game Product Code
1271
* @param product To-be-patched Product Code
1272
* @param from If the Product Code matches this...
1273
* @param to ... then change it to this one.
1274
*/
1275
void game_product_relink(SceNetAdhocctlProductCode * product, char * from, char * to)
1276
{
1277
// Relink Region Code
1278
if(strncmp(product->data, from, PRODUCT_CODE_LENGTH) == 0) strncpy(product->data, to, PRODUCT_CODE_LENGTH);
1279
}
1280
1281
/**
1282
* Game Product Override (used for mixing multi-region games)
1283
* @param product IN: Source Product OUT: Override Product
1284
*/
1285
void game_product_override(SceNetAdhocctlProductCode * product)
1286
{
1287
// Safe Product Code
1288
char productid[PRODUCT_CODE_LENGTH + 1];
1289
1290
// Prepare Safe Product Code
1291
strncpy(productid, product->data, PRODUCT_CODE_LENGTH);
1292
productid[PRODUCT_CODE_LENGTH] = 0;
1293
1294
// Database Handle
1295
//sqlite3 * db = NULL;
1296
1297
// Open Database
1298
//if(sqlite3_open(SERVER_DATABASE, &db) == SQLITE_OK)
1299
{
1300
// Crosslinked Flag
1301
int crosslinked = 0;
1302
1303
// Exists Flag
1304
int exists = 0;
1305
1306
// SQL Statements
1307
/*const char * sql = "SELECT id_to FROM crosslinks WHERE id_from=?;";
1308
const char * sql2 = "SELECT * FROM productids WHERE id=?;";
1309
const char * sql3 = "INSERT INTO productids(id, name) VALUES(?, ?);";
1310
1311
// Prepared SQL Statement
1312
sqlite3_stmt * statement = NULL;
1313
1314
// Prepare SQL Statement
1315
if(sqlite3_prepare_v2(db, sql, strlen(sql) + 1, &statement, NULL) == SQLITE_OK)
1316
{
1317
// Bind SQL Statement Data
1318
if(sqlite3_bind_text(statement, 1, productid, strlen(productid), SQLITE_STATIC) == SQLITE_OK)
1319
{
1320
// Found Matching Row
1321
if(sqlite3_step(statement) == SQLITE_ROW)
1322
{
1323
// Grab Crosslink ID
1324
const char * crosslink = (const char *)sqlite3_column_text(statement, 0);
1325
1326
// Crosslink Product Code
1327
strncpy(product->data, crosslink, PRODUCT_CODE_LENGTH);
1328
1329
// Log Crosslink
1330
INFO_LOG(Log::sceNet, "Crosslinked %s to %s", productid, crosslink);
1331
1332
// Set Crosslinked Flag
1333
crosslinked = 1;
1334
}
1335
}
1336
1337
// Destroy Prepared SQL Statement
1338
sqlite3_finalize(statement);
1339
}*/
1340
for (const auto &link : crosslinks) {
1341
if (IsMatch(link.id_from, productid)) {
1342
// Grab Crosslink ID
1343
char crosslink[PRODUCT_CODE_LENGTH + 1];
1344
strncpy(crosslink, link.id_to, PRODUCT_CODE_LENGTH);
1345
crosslink[PRODUCT_CODE_LENGTH] = 0; // null terminated
1346
1347
// Crosslink Product Code
1348
strncpy(product->data, link.id_to, PRODUCT_CODE_LENGTH);
1349
1350
// Log Crosslink
1351
INFO_LOG(Log::sceNet, "AdhocServer: Crosslinked %s to %s", productid, crosslink);
1352
1353
// Set Crosslinked Flag
1354
crosslinked = 1;
1355
break;
1356
}
1357
}
1358
1359
// Not Crosslinked
1360
if(!crosslinked)
1361
{
1362
// Prepare SQL Statement
1363
/*if(sqlite3_prepare_v2(db, sql2, strlen(sql2) + 1, &statement, NULL) == SQLITE_OK)
1364
{
1365
// Bind SQL Statement Data
1366
if(sqlite3_bind_text(statement, 1, productid, strlen(productid), SQLITE_STATIC) == SQLITE_OK)
1367
{
1368
// Found Matching Row
1369
if(sqlite3_step(statement) == SQLITE_ROW)
1370
{
1371
// Set Exists Flag
1372
exists = 1;
1373
}
1374
}
1375
1376
// Destroy Prepare SQL Statement
1377
sqlite3_finalize(statement);
1378
}*/
1379
for (const auto &product : productids) {
1380
if (IsMatch(product.id, productid)) {
1381
// Set Exists Flag
1382
exists = 1;
1383
break;
1384
}
1385
}
1386
1387
// Game doesn't exist in Database
1388
if(!exists)
1389
{
1390
// Prepare SQL Statement
1391
/*if(sqlite3_prepare_v2(db, sql3, strlen(sql3) + 1, &statement, NULL) == SQLITE_OK)
1392
{
1393
// Bind SQL Statement Data
1394
if(sqlite3_bind_text(statement, 1, productid, strlen(productid), SQLITE_STATIC) == SQLITE_OK && sqlite3_bind_text(statement, 2, productid, strlen(productid), SQLITE_STATIC) == SQLITE_OK)
1395
{
1396
// Save Product ID to Database
1397
if(sqlite3_step(statement) == SQLITE_DONE)
1398
{
1399
// Log Addition
1400
INFO_LOG(Log::sceNet, "Added Unknown Product ID %s to Database", productid);
1401
}
1402
}
1403
1404
// Destroy Prepare SQL Statement
1405
sqlite3_finalize(statement);
1406
}*/
1407
db_productid unkproduct;
1408
strncpy(unkproduct.id, productid, sizeof(unkproduct.id));
1409
strncpy(unkproduct.name, productid, sizeof(productid));
1410
productids.push_back(unkproduct); //productids[productids.size()] = unkproduct;
1411
// Log Addition
1412
INFO_LOG(Log::sceNet, "AdhocServer: Added Unknown Product ID %s to Database", productid);
1413
}
1414
}
1415
1416
// Close Database
1417
//sqlite3_close(db);
1418
}
1419
}
1420
1421
/**
1422
* Update Status Logfile
1423
*/
1424
void update_status()
1425
{
1426
// Open Logfile
1427
FILE * log = File::OpenCFile(Path(SERVER_STATUS_XMLOUT), "w");
1428
1429
// Opened Logfile
1430
if(log != NULL)
1431
{
1432
// Write XML Header
1433
fprintf(log, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1434
1435
// Write XSL Processor Information
1436
fprintf(log, "<?xml-stylesheet type=\"text/xsl\" href=\"status.xsl\"?>\n");
1437
1438
// Output Root Tag + User Count
1439
fprintf(log, "<prometheus usercount=\"%u\">\n", _db_user_count);
1440
1441
// Database Handle
1442
//sqlite3 * db = NULL;
1443
1444
// Open Database
1445
//if(sqlite3_open(SERVER_DATABASE, &db) == SQLITE_OK)
1446
{
1447
// Iterate Games
1448
SceNetAdhocctlGameNode * game = _db_game; for(; game != NULL; game = game->next)
1449
{
1450
// Safe Product ID
1451
char productid[PRODUCT_CODE_LENGTH + 1];
1452
strncpy(productid, game->game.data, PRODUCT_CODE_LENGTH);
1453
productid[PRODUCT_CODE_LENGTH] = 0;
1454
1455
// Display Name
1456
char displayname[128];
1457
memset(displayname, 0, sizeof(displayname));
1458
1459
// SQL Statement
1460
//const char * sql = "SELECT name FROM productids WHERE id=?;";
1461
1462
// Prepared SQL Statement
1463
//sqlite3_stmt * statement = NULL;
1464
1465
// Prepare SQL Statement
1466
/*if(sqlite3_prepare_v2(db, sql, strlen(sql) + 1, &statement, NULL) == SQLITE_OK)
1467
{
1468
// Bind SQL Statement Data
1469
if(sqlite3_bind_text(statement, 1, productid, strlen(productid), SQLITE_STATIC) == SQLITE_OK)
1470
{
1471
// Found Matching Row
1472
if(sqlite3_step(statement) == SQLITE_ROW)
1473
{
1474
// Fetch Game Name from Database
1475
const char * gamename = (const char *)sqlite3_column_text(statement, 0);
1476
1477
// Copy Game Name
1478
strcpyxml(displayname, gamename, sizeof(displayname));
1479
}
1480
1481
// Game not in Database
1482
else
1483
{
1484
// Use Product Code as Name
1485
strcpyxml(displayname, productid, sizeof(displayname));
1486
}
1487
}
1488
1489
// Destroy Prepared SQL Statement
1490
sqlite3_finalize(statement);
1491
}*/
1492
//db_productid *foundid = NULL;
1493
bool found = false;
1494
for (const auto &product : productids) {
1495
if (IsMatch(product.id, productid)) {
1496
// Copy Game Name
1497
strcpyxml(displayname, product.name, sizeof(displayname));
1498
found = true;
1499
break;
1500
}
1501
}
1502
1503
if (!found) {
1504
// Use Product Code as Name
1505
strcpyxml(displayname, productid, sizeof(displayname));
1506
}
1507
1508
// Output Game Tag + Game Name
1509
fprintf(log, "\t<game name=\"%s\" usercount=\"%u\">\n", displayname, game->playercount);
1510
1511
// Activate User Count
1512
uint32_t activecount = 0;
1513
1514
// Iterate Game Groups
1515
SceNetAdhocctlGroupNode * group = game->group; for(; group != NULL; group = group->next)
1516
{
1517
// Safe Group Name
1518
char groupname[ADHOCCTL_GROUPNAME_LEN + 1];
1519
strncpy(groupname, (const char *)group->group.data, ADHOCCTL_GROUPNAME_LEN);
1520
groupname[ADHOCCTL_GROUPNAME_LEN] = 0;
1521
1522
// Output Group Tag + Group Name + User Count
1523
fprintf(log, "\t\t<group name=\"%s\" usercount=\"%u\">\n", strcpyxml(displayname, groupname, sizeof(displayname)), group->playercount);
1524
1525
// Iterate Users
1526
SceNetAdhocctlUserNode * user = group->player; for(; user != NULL; user = user->group_next)
1527
{
1528
// Output User Tag + Username
1529
fprintf(log, "\t\t\t<user>%s</user>\n", strcpyxml(displayname, (const char *)user->resolver.name.data, sizeof(displayname)));
1530
}
1531
1532
// Output Closing Group Tag
1533
fprintf(log, "\t\t</group>\n");
1534
1535
// Increase Active Game User Count
1536
activecount += group->playercount;
1537
}
1538
1539
// Output Idle Game Group
1540
if(game->playercount > activecount)
1541
{
1542
// Output Group Tag + Group Name + Idle User Count
1543
fprintf(log, "\t\t<group name=\"Groupless\" usercount=\"%u\" />\n", game->playercount - activecount);
1544
}
1545
1546
// Output Closing Game Tag
1547
fprintf(log, "\t</game>\n");
1548
}
1549
1550
// Close Database
1551
//sqlite3_close(db);
1552
}
1553
1554
// Output Closing Root Tag
1555
fprintf(log, "</prometheus>");
1556
1557
// Close Logfile
1558
fclose(log);
1559
}
1560
}
1561
1562
/**
1563
* Escape XML Sequences to avoid malformed XML files.
1564
* @param out Out Buffer
1565
* @param in In Buffer
1566
* @param size Size of Out Buffer
1567
* @return Reference to Out Buffer
1568
*/
1569
const char * strcpyxml(char * out, const char * in, uint32_t size)
1570
{
1571
// Valid Arguments
1572
if(out != NULL && in != NULL && size > 0)
1573
{
1574
// Clear Memory
1575
memset(out, 0, size);
1576
1577
// Written Size Pointer
1578
uint32_t written = 0;
1579
1580
// Iterate In-Buffer Symbols
1581
uint32_t i = 0; for(; i < strlen(in); i++)
1582
{
1583
// " Symbol
1584
if(in[i] == '"')
1585
{
1586
// Enough Space in Out-Buffer (6B for &quot;)
1587
if((size - written) > 6)
1588
{
1589
// Write Escaped Sequence
1590
strcpy(out + written, "&quot;");
1591
1592
// Move Pointer
1593
written += 6;
1594
}
1595
1596
// Truncate required
1597
else break;
1598
}
1599
1600
// < Symbol
1601
else if(in[i] == '<')
1602
{
1603
// Enough Space in Out-Buffer (4B for &lt;)
1604
if((size - written) > 4)
1605
{
1606
// Write Escaped Sequence
1607
strcpy(out + written, "&lt;");
1608
1609
// Move Pointer
1610
written += 4;
1611
}
1612
1613
// Truncate required
1614
else break;
1615
}
1616
1617
// > Symbol
1618
else if(in[i] == '>')
1619
{
1620
// Enough Space in Out-Buffer (4B for &gt;)
1621
if((size - written) > 4)
1622
{
1623
// Write Escaped Sequence
1624
strcpy(out + written, "&gt;");
1625
1626
// Move Pointer
1627
written += 4;
1628
}
1629
1630
// Truncate required
1631
else break;
1632
}
1633
1634
// & Symbol
1635
else if(in[i] == '&')
1636
{
1637
// Enough Space in Out-Buffer (5B for &amp;)
1638
if((size - written) > 5)
1639
{
1640
// Write Escaped Sequence
1641
strcpy(out + written, "&amp;");
1642
1643
// Move Pointer
1644
written += 5;
1645
}
1646
1647
// Truncate required
1648
else break;
1649
}
1650
1651
// Normal Character
1652
else
1653
{
1654
// Enough Space in Out-Buffer (1B)
1655
if((size - written) > 1)
1656
{
1657
// Write Character
1658
out[written++] = in[i];
1659
}
1660
}
1661
}
1662
1663
// Return Reference
1664
return out;
1665
}
1666
1667
// Invalid Arguments
1668
return NULL;
1669
}
1670
1671
/**
1672
* Server Entry Point
1673
* @param argc Number of Arguments
1674
* @param argv Arguments
1675
* @return OS Error Code
1676
*/
1677
int proAdhocServerThread(int port) // (int argc, char * argv[])
1678
{
1679
SetCurrentThreadName("AdhocServer");
1680
// Result
1681
int result = 0;
1682
1683
INFO_LOG(Log::sceNet, "AdhocServer: Begin of AdhocServer Thread");
1684
1685
// Create Signal Receiver for CTRL + C
1686
//signal(SIGINT, interrupt);
1687
1688
// Create Signal Receiver for kill / killall
1689
//signal(SIGTERM, interrupt);
1690
1691
// Create Listening Socket
1692
int server = create_listen_socket(port); //SERVER_PORT
1693
1694
// Created Listening Socket
1695
if(server != SOCKET_ERROR)
1696
{
1697
// Notify User
1698
INFO_LOG(Log::sceNet, "AdhocServer: Listening for Connections on TCP Port %u", port); //SERVER_PORT
1699
1700
// Port forward
1701
UPnP_Add(IP_PROTOCOL_TCP, port); // g_PortManager.Add(IP_PROTOCOL_TCP, port);
1702
1703
// Enter Server Loop
1704
result = server_loop(server);
1705
1706
// Remove Port mapping
1707
UPnP_Remove(IP_PROTOCOL_TCP, port); // g_PortManager.Remove(IP_PROTOCOL_TCP, port);
1708
1709
// Notify User
1710
INFO_LOG(Log::sceNet, "AdhocServer: Shutdown complete");
1711
}
1712
1713
//_status = 0;
1714
adhocServerRunning = false;
1715
1716
INFO_LOG(Log::sceNet, "AdhocServer: End of AdhocServer Thread");
1717
1718
// Return Result
1719
return result;
1720
}
1721
1722
/**
1723
* Server Shutdown Request Handler
1724
* @param sig Captured Signal
1725
*/
1726
void interrupt(int sig)
1727
{
1728
// Notify User
1729
INFO_LOG(Log::sceNet, "AdhocServer: Shutting down... please wait");
1730
1731
// Trigger Shutdown
1732
//_status = 0;
1733
adhocServerRunning = false;
1734
}
1735
1736
/**
1737
* Enable Address Reuse on Socket
1738
* @param fd Socket
1739
*/
1740
void enable_address_reuse(int fd)
1741
{
1742
// Enable Port Reuse
1743
setSockReuseAddrPort(fd);
1744
}
1745
1746
/**
1747
* Enable KeepAlive on Socket
1748
* @param fd Socket
1749
*/
1750
void enable_keepalive(int fd)
1751
{
1752
// Enable Value
1753
int on = 1;
1754
1755
// Enable Port Reuse
1756
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(on));
1757
}
1758
1759
/**
1760
* Change TCP Socket TCP_NODELAY (Nagle Algo) mode
1761
* @param fd Socket
1762
* @param nonblocking 1 for Nonblocking, 0 for Blocking
1763
*/
1764
void change_nodelay_mode(int fd, int flag)
1765
{
1766
int opt = flag;
1767
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&opt, sizeof(opt));
1768
}
1769
1770
/**
1771
* Change Socket Blocking Mode
1772
* @param fd Socket
1773
* @param nonblocking 1 for Nonblocking, 0 for Blocking
1774
*/
1775
void change_blocking_mode(int fd, int nonblocking)
1776
{
1777
unsigned long on = 1;
1778
unsigned long off = 0;
1779
#ifdef _WIN32
1780
if (nonblocking){
1781
// Change to Non-Blocking Mode
1782
ioctlsocket(fd, FIONBIO, &on);
1783
}
1784
else {
1785
// Change to Blocking Mode
1786
ioctlsocket(fd, FIONBIO, &off);
1787
}
1788
#else
1789
// Change to Non-Blocking Mode
1790
if(nonblocking) fcntl(fd, F_SETFL, O_NONBLOCK);
1791
1792
// Change to Blocking Mode
1793
else
1794
{
1795
// Get Flags
1796
int flags = fcntl(fd, F_GETFL);
1797
1798
// Remove Non-Blocking Flag
1799
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
1800
}
1801
#endif
1802
}
1803
1804
/**
1805
* Create Port-Bound Listening Socket
1806
* @param port TCP Port
1807
* @return Socket Descriptor
1808
*/
1809
int create_listen_socket(uint16_t port)
1810
{
1811
// Create Socket
1812
int fd = (int)socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1813
1814
// Created Socket
1815
if(fd != -1)
1816
{
1817
// Ignore SIGPIPE when supported (ie. BSD/MacOS)
1818
setSockNoSIGPIPE(fd, 1);
1819
1820
// Enable KeepAlive
1821
enable_keepalive(fd);
1822
1823
// Enable Address Reuse
1824
enable_address_reuse(fd); // Shouldn't Reuse the port for built-in AdhocServer to prevent conflict with Dedicated AdhocServer
1825
1826
// Make Socket Nonblocking
1827
change_blocking_mode(fd, 1);
1828
1829
// Make TCP Socket send immediately
1830
change_nodelay_mode(fd, 1);
1831
1832
// Prepare Local Address Information
1833
struct sockaddr_in local;
1834
memset(&local, 0, sizeof(local));
1835
local.sin_family = AF_INET;
1836
local.sin_addr.s_addr = INADDR_ANY;
1837
local.sin_port = htons(port);
1838
1839
// Should only bind to specific IP for the 2nd or more instance of PPSSPP to prevent communication interference issue when sharing the same port. (ie. Capcom Classics Collection Remixed)
1840
if (PPSSPP_ID > 1) {
1841
local.sin_addr = g_localhostIP.in.sin_addr;
1842
}
1843
1844
// Bind Local Address to Socket
1845
int bindresult = bind(fd, (struct sockaddr *)&local, sizeof(local));
1846
1847
// Bound Local Address to Socket
1848
if(bindresult != SOCKET_ERROR)
1849
{
1850
// Switch Socket into Listening Mode
1851
listen(fd, SERVER_LISTEN_BACKLOG);
1852
1853
// Return Socket
1854
return fd;
1855
}
1856
1857
// Notify User
1858
else {
1859
ERROR_LOG(Log::sceNet, "AdhocServer: Bind returned %i (Socket error %d)", bindresult, errno);
1860
auto n = GetI18NCategory(I18NCat::NETWORKING);
1861
g_OSD.Show(OSDType::MESSAGE_ERROR, std::string(n->T("AdhocServer Failed to Bind Port")) + " " + std::to_string(port));
1862
}
1863
1864
// Close Socket
1865
closesocket(fd);
1866
}
1867
1868
// Notify User
1869
else ERROR_LOG(Log::sceNet, "AdhocServer: Socket returned %i (Socket error %d)", fd, errno);
1870
1871
// Return Error
1872
return -1;
1873
}
1874
1875
/**
1876
* Server Main Loop
1877
* @param server Server Listening Socket
1878
* @return OS Error Code
1879
*/
1880
int server_loop(int server)
1881
{
1882
// Set Running Status
1883
//_status = 1;
1884
adhocServerRunning = true;
1885
1886
// Create Empty Status Logfile
1887
update_status();
1888
1889
// Handling Loop
1890
while (adhocServerRunning) //(_status == 1)
1891
{
1892
// Login Block
1893
{
1894
// Login Result
1895
int loginresult = 0;
1896
1897
// Login Processing Loop
1898
do
1899
{
1900
// Prepare Address Structure
1901
struct sockaddr_in addr;
1902
socklen_t addrlen = sizeof(addr);
1903
memset(&addr, 0, sizeof(addr));
1904
1905
// Accept Login Requests
1906
// loginresult = accept4(server, (struct sockaddr *)&addr, &addrlen, SOCK_NONBLOCK);
1907
1908
// Alternative Accept Approach (some Linux Kernel don't support the accept4 Syscall... wtf?)
1909
loginresult = accept(server, (struct sockaddr *)&addr, &addrlen);
1910
if(loginresult != -1)
1911
{
1912
// Switch Socket into Non-Blocking Mode
1913
change_blocking_mode(loginresult, 1);
1914
}
1915
1916
// Login User (Stream)
1917
if (loginresult != -1) {
1918
u32_le sip = addr.sin_addr.s_addr;
1919
/* // Replacing 127.0.0.x with Ethernet IP will cause issue with multiple-instance of localhost (127.0.0.x)
1920
if (sip == 0x0100007f) { //127.0.0.1 should be replaced with LAN/WAN IP whenever available
1921
char str[100];
1922
gethostname(str, 100);
1923
u8 *pip = (u8*)&sip;
1924
if (gethostbyname(str)->h_addrtype == AF_INET && gethostbyname(str)->h_addr_list[0] != NULL) pip = (u8*)gethostbyname(str)->h_addr_list[0];
1925
sip = *(u32_le*)pip;
1926
WARN_LOG(Log::sceNet, "AdhocServer: Replacing IP %s with %s", inet_ntoa(addr.sin_addr), inet_ntoa(*(in_addr*)&pip));
1927
}
1928
*/
1929
login_user_stream(loginresult, sip);
1930
}
1931
} while(loginresult != -1);
1932
}
1933
1934
// Receive Data from Users
1935
SceNetAdhocctlUserNode * user = _db_user;
1936
while(user != NULL)
1937
{
1938
// Next User (for safe delete)
1939
SceNetAdhocctlUserNode * next = user->next;
1940
1941
// Receive Data from User
1942
int recvresult = (int)recv(user->stream, (char*)user->rx + user->rxpos, sizeof(user->rx) - user->rxpos, MSG_NOSIGNAL);
1943
1944
// Connection Closed or Timed Out
1945
if(recvresult == 0 || (recvresult == -1 && errno != EAGAIN && errno != EWOULDBLOCK) || get_user_state(user) == USER_STATE_TIMED_OUT)
1946
{
1947
// Logout User
1948
logout_user(user);
1949
}
1950
1951
// Received Data (or leftovers in RX-Buffer)
1952
else if(recvresult > 0 || user->rxpos > 0)
1953
{
1954
// New Incoming Data
1955
if(recvresult > 0)
1956
{
1957
// Move RX Pointer
1958
user->rxpos += recvresult;
1959
1960
// Update Death Clock
1961
user->last_recv = time(NULL);
1962
}
1963
1964
// Waiting for Login Packet
1965
if(get_user_state(user) == USER_STATE_WAITING)
1966
{
1967
// Valid Opcode
1968
if(user->rx[0] == OPCODE_LOGIN)
1969
{
1970
// Enough Data available
1971
if(user->rxpos >= sizeof(SceNetAdhocctlLoginPacketC2S))
1972
{
1973
// Clone Packet
1974
SceNetAdhocctlLoginPacketC2S packet = *(SceNetAdhocctlLoginPacketC2S *)user->rx;
1975
1976
// Remove Packet from RX Buffer
1977
clear_user_rxbuf(user, sizeof(SceNetAdhocctlLoginPacketC2S));
1978
1979
// Login User (Data)
1980
login_user_data(user, &packet);
1981
}
1982
}
1983
1984
// Invalid Opcode
1985
else
1986
{
1987
// Notify User
1988
WARN_LOG(Log::sceNet, "AdhocServer: Invalid Opcode 0x%02X in Waiting State from %s", user->rx[0], ip2str(*(in_addr*)&user->resolver.ip).c_str());
1989
1990
// Logout User
1991
logout_user(user);
1992
}
1993
}
1994
1995
// Logged-In User
1996
else if(get_user_state(user) == USER_STATE_LOGGED_IN)
1997
{
1998
// Ping Packet
1999
if(user->rx[0] == OPCODE_PING)
2000
{
2001
// Delete Packet from RX Buffer
2002
clear_user_rxbuf(user, 1);
2003
}
2004
2005
// Group Connect Packet
2006
else if(user->rx[0] == OPCODE_CONNECT)
2007
{
2008
// Enough Data available
2009
if(user->rxpos >= sizeof(SceNetAdhocctlConnectPacketC2S))
2010
{
2011
// Cast Packet
2012
SceNetAdhocctlConnectPacketC2S * packet = (SceNetAdhocctlConnectPacketC2S *)user->rx;
2013
2014
// Clone Group Name
2015
SceNetAdhocctlGroupName group = packet->group;
2016
2017
// Remove Packet from RX Buffer
2018
clear_user_rxbuf(user, sizeof(SceNetAdhocctlConnectPacketC2S));
2019
2020
// Change Game Group
2021
connect_user(user, &group);
2022
}
2023
}
2024
2025
// Group Disconnect Packet
2026
else if(user->rx[0] == OPCODE_DISCONNECT)
2027
{
2028
// Remove Packet from RX Buffer
2029
clear_user_rxbuf(user, 1);
2030
2031
// Leave Game Group
2032
disconnect_user(user);
2033
}
2034
2035
// Network Scan Packet
2036
else if(user->rx[0] == OPCODE_SCAN)
2037
{
2038
// Remove Packet from RX Buffer
2039
clear_user_rxbuf(user, 1);
2040
2041
// Send Network List
2042
send_scan_results(user);
2043
}
2044
2045
// Chat Text Packet
2046
else if(user->rx[0] == OPCODE_CHAT)
2047
{
2048
// Enough Data available
2049
if(user->rxpos >= sizeof(SceNetAdhocctlChatPacketC2S))
2050
{
2051
// Cast Packet
2052
SceNetAdhocctlChatPacketC2S * packet = (SceNetAdhocctlChatPacketC2S *)user->rx;
2053
2054
// Clone Buffer for Message
2055
char message[64];
2056
memset(message, 0, sizeof(message));
2057
strncpy(message, packet->message, sizeof(message) - 1);
2058
2059
// Remove Packet from RX Buffer
2060
clear_user_rxbuf(user, sizeof(SceNetAdhocctlChatPacketC2S));
2061
2062
// Spread Chat Message
2063
spread_message(user, message);
2064
}
2065
}
2066
2067
// Invalid Opcode
2068
else
2069
{
2070
// Notify User
2071
WARN_LOG(Log::sceNet, "AdhocServer: Invalid Opcode 0x%02X in Logged-In State from %s (MAC: %s - IP: %s)", user->rx[0], (char *)user->resolver.name.data, mac2str(&user->resolver.mac).c_str(), ip2str(*(in_addr*)&user->resolver.ip).c_str());
2072
2073
// Logout User
2074
logout_user(user);
2075
}
2076
}
2077
}
2078
2079
// Move Pointer
2080
user = next;
2081
}
2082
2083
// Prevent needless CPU Overload (1ms Sleep)
2084
sleep_ms(10);
2085
2086
// Don't do anything if it's paused, otherwise the log will be flooded
2087
while (adhocServerRunning && Core_IsStepping() && coreState != CORE_POWERDOWN) sleep_ms(10);
2088
}
2089
2090
// Free User Database Memory
2091
free_database();
2092
2093
// Close Server Socket
2094
closesocket(server);
2095
2096
// Return Success
2097
return 0;
2098
}
2099
2100