2014-08-01 01:55:42 +07:00
// Copyright (c) 2014- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// proAdhocServer
// This is a direct port of Coldbird's code from http://code.google.com/p/aemu/
// All credit goes to him!
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <signal.h>
# if !defined(__APPLE__)
2014-08-19 22:29:03 +08:00
# include <stdlib.h>
2014-08-01 01:55:42 +07:00
# endif
# include <sys/types.h>
// Net stuff
2017-08-29 22:41:50 +02:00
# if defined(_WIN32)
2014-08-01 01:55:42 +07:00
# include <WS2tcpip.h>
# else
# include <sys/socket.h>
# include <netinet/in.h>
2020-01-18 02:32:09 +07:00
# include <netinet/tcp.h>
2014-08-01 01:55:42 +07:00
# endif
# include <fcntl.h>
# include <errno.h>
//#include <sqlite3.h>
2020-08-15 20:53:08 +02:00
2020-09-07 02:38:45 +07:00
# ifndef MSG_NOSIGNAL
// Default value to 0x00 (do nothing) in systems where it's not supported.
# define MSG_NOSIGNAL 0x00
# endif
2020-08-15 20:53:08 +02:00
# include "i18n/i18n.h"
2020-10-01 09:27:25 +02:00
# include "Common/Thread/ThreadUtil.h"
2020-08-15 20:53:08 +02:00
2016-01-17 15:59:20 +01:00
# include "Common/FileUtil.h"
2020-08-15 20:53:08 +02:00
# include "Common/TimeUtil.h"
2020-01-18 02:32:09 +07:00
# include "Core/Util/PortManager.h"
2014-08-01 01:55:42 +07:00
# include "Core/Core.h"
2019-12-24 00:04:03 +07:00
# include "Core/Host.h"
2014-08-01 01:55:42 +07:00
# include "Core/HLE/proAdhocServer.h"
// User Count
uint32_t _db_user_count = 0 ;
// User Database
SceNetAdhocctlUserNode * _db_user = NULL ;
// Game Database
SceNetAdhocctlGameNode * _db_game = NULL ;
// Server Status
//int _status = 0;
bool adhocServerRunning = false ;
std : : thread adhocServerThread ;
2016-12-27 12:13:51 +01:00
// Crosslink database for cross region Adhoc play
2014-08-05 20:05:08 +08:00
std : : vector < db_crosslink > crosslinks ;
2016-12-27 13:14:45 +01:00
static const db_crosslink default_crosslinks [ ] = {
2016-12-24 05:46:50 +08:00
// Ace Combat X2 - Joint Assault
2016-12-27 12:13:51 +01:00
{ " ULES01408 " , " ULUS10511 " } ,
{ " NPJH50263 " , " ULUS10511 " } ,
2016-12-24 05:46:50 +08:00
// Armored Core 3 Portable
2016-12-27 12:13:51 +01:00
{ " ULJM05492 " , " NPUH10023 " } ,
2016-12-24 05:46:50 +08:00
// BlazBlue - Continuum Shift 2
2016-12-27 12:13:51 +01:00
{ " NPJH50401 " , " ULUS10579 " } ,
2016-12-24 05:46:50 +08:00
// Blood Bowl
2016-12-27 12:13:51 +01:00
{ " ULES01230 " , " ULUS10516 " } ,
2016-12-24 05:46:50 +08:00
// Bomberman
2016-12-27 12:13:51 +01:00
{ " ULJM05034 " , " ULUS10121 " } ,
{ " ULES00469 " , " ULUS10121 " } ,
{ " ULJM05316 " , " ULUS10121 " } ,
2016-12-24 05:46:50 +08:00
// Bomberman Land
2016-12-27 12:13:51 +01:00
{ " ULJM05181 " , " ULUS10319 " } ,
{ " ULJM05319 " , " ULUS10319 " } ,
{ " ULES00959 " , " ULUS10319 " } ,
2016-12-24 05:46:50 +08:00
// Call of Duty - Roads to Victory
2016-12-27 12:13:51 +01:00
{ " ULES00643 " , " ULUS10218 " } ,
2016-12-24 05:46:50 +08:00
// Dissidia 012 Duodecim Final Fantasy
2016-12-27 12:13:51 +01:00
{ " ULES01505 " , " ULUS10566 " } ,
{ " NPJH50377 " , " ULUS10566 " } ,
2016-12-24 05:46:50 +08:00
// Dissidia Final Fantasy
2016-12-27 12:13:51 +01:00
{ " ULES01270 " , " ULUS10437 " } ,
{ " ULJM05262 " , " ULUS10437 " } ,
2016-12-24 05:46:50 +08:00
// Dragon Ball Z - Shin Budokai
2016-12-27 12:13:51 +01:00
{ " ULJS00049 " , " ULUS10081 " } ,
{ " ULKS46085 " , " ULUS10081 " } ,
{ " ULES00309 " , " ULUS10081 " } ,
2016-12-24 05:46:50 +08:00
// Dragon Ball Z - Shin Budokai 2
2016-12-27 12:13:51 +01:00
{ " ULJS00107 " , " ULUS10234 " } ,
{ " ULES00789 " , " ULUS10234 " } ,
2016-12-24 05:46:50 +08:00
// Dragon Ball Z - Tenkaichi Tag Team
2016-12-27 12:13:51 +01:00
{ " ULES01456 " , " ULUS10537 " } ,
2016-12-24 05:46:50 +08:00
// Dungeon Siege - Throne of Agony
2016-12-27 12:13:51 +01:00
{ " ULES00569 " , " ULUS10177 " } ,
2016-12-24 05:46:50 +08:00
// Everybody's Tennis
2016-12-27 12:13:51 +01:00
{ " UCJS10101 " , " UCUS98701 " } ,
{ " UCES01420 " , " UCUS98701 " } ,
2016-12-24 05:46:50 +08:00
// Fat Princess - Fistful of Cake
2016-12-27 12:13:51 +01:00
{ " UCES01312 " , " UCUS98740 " } ,
{ " NPHG00025 " , " UCUS98740 " } ,
2016-12-24 05:46:50 +08:00
// God Eater Burst
2016-12-27 12:13:51 +01:00
{ " ULES01519 " , " ULUS10563 " } ,
{ " NPJH50352 " , " ULUS10563 " } ,
2016-12-24 05:46:50 +08:00
// Gran Turismo
2016-12-27 12:13:51 +01:00
{ " UCES01245 " , " UCUS98632 " } ,
{ " UCES00543 " , " UCUS98645 " } ,
2016-12-24 05:46:50 +08:00
// Gundam VS Gundam - Next Plus
2016-12-27 12:13:51 +01:00
{ " ULJS00250 " , " NPJH50107 " } ,
{ " ULJS19048 " , " NPJH50107 " } ,
2016-12-24 05:46:50 +08:00
// Hatsune Miku - Project Diva Extend
2016-12-27 12:13:51 +01:00
{ " NPJH50465 " , " ULJM05933 " } ,
2016-12-24 05:46:50 +08:00
// Hot Pixel
2016-12-27 12:13:51 +01:00
{ " ULES00642 " , " ULUS10298 " } ,
2016-12-24 05:46:50 +08:00
// Lord of Arcana
2016-12-27 12:13:51 +01:00
{ " ULJM05767 " , " ULES01507 " } ,
{ " ULUS10479 " , " ULES01507 " } ,
2016-12-24 05:46:50 +08:00
// M.A.C.H. - Modified Air Combat Heroes
2016-12-27 12:13:51 +01:00
{ " ULES00565 " , " ULUS10180 " } ,
{ " ULES00566 " , " ULUS10180 " } ,
{ " ULJM05202 " , " ULUS10180 " } ,
2016-12-24 05:46:50 +08:00
// Metal Gear Solid - Peace Walker
2016-12-27 12:13:51 +01:00
{ " ULES01372 " , " NPJH50045 " } ,
{ " ULUS10509 " , " NPJH50045 " } ,
2016-12-24 05:46:50 +08:00
// Metal Gear Solid - Portable Ops
2016-12-27 12:13:51 +01:00
{ " ULES00645 " , " ULUS10202 " } ,
{ " ULJM05193 " , " ULUS10202 " } ,
2016-12-24 05:46:50 +08:00
// Metal Gear Solid - Portable Ops +
2016-12-27 12:13:51 +01:00
{ " ULES01003 " , " ULUS10290 " } ,
{ " ULJM05261 " , " ULUS10290 " } ,
2016-12-24 05:46:50 +08:00
// Midnight Club - LA Remix
2016-12-27 12:13:51 +01:00
{ " ULES01144 " , " ULUS10383 " } ,
{ " ULJS00180 " , " ULUS10383 " } ,
2016-12-24 05:46:50 +08:00
// Mod Nation Racers
2016-12-27 12:13:51 +01:00
{ " UCES01327 " , " UCUS98741 " } ,
{ " UCJS10112 " , " UCUS98741 " } ,
{ " UCAS40306 " , " UCUS98741 " } ,
2016-12-24 05:46:50 +08:00
// Monster Hunter Freedom
2016-12-27 12:13:51 +01:00
{ " ULJM05066 " , " ULUS10084 " } ,
{ " ULES00318 " , " ULUS10084 " } ,
2016-12-24 05:46:50 +08:00
// Monster Hunter Freedom 2
2016-12-27 12:13:51 +01:00
{ " ULJM05156 " , " ULUS10266 " } ,
{ " ULES00851 " , " ULUS10266 " } ,
2016-12-24 05:46:50 +08:00
// Monster Hunter Freedom Unite
2016-12-27 12:13:51 +01:00
{ " ULES01213 " , " ULUS10391 " } ,
{ " ULJM05500 " , " ULUS10391 " } ,
2016-12-24 05:46:50 +08:00
// N+
2016-12-27 12:13:51 +01:00
{ " ULES01026 " , " ULUS10340 " } ,
2016-12-24 05:46:50 +08:00
// Need for Speed - Undercover
2016-12-27 12:13:51 +01:00
{ " ULJM05403 " , " ULUS10376 " } ,
{ " ULJM05612 " , " ULUS10376 " } ,
{ " ULES01145 " , " ULUS10376 " } ,
2016-12-24 05:46:50 +08:00
// Outrun 2006 - Coast 2 Coast
2016-12-27 12:13:51 +01:00
{ " ULES00262 " , " ULUS10064 " } ,
2016-12-24 05:46:50 +08:00
// Pangya! - Fantasy Golf
2016-12-27 12:13:51 +01:00
{ " ULJM05440 " , " ULUS10438 " } ,
{ " ULKS46164 " , " ULUS10438 " } ,
2016-12-24 05:46:50 +08:00
// PRO Evolution Soccer 2012
2016-12-27 12:13:51 +01:00
{ " ULES01540 " , " ULUS10586 " } ,
{ " ULES01541 " , " ULUS10586 " } ,
{ " ULES01542 " , " ULUS10586 " } ,
{ " ULAS42289 " , " ULUS10586 " } ,
2016-12-24 05:46:50 +08:00
// Patapon 2
2016-12-27 12:13:51 +01:00
{ " UCJS10089 " , " UCUS98732 " } ,
{ " PSPJ30000 " , " UCUS98732 " } ,
{ " UCES01177 " , " UCUS98732 " } ,
{ " UCJS18036 " , " UCUS98732 " } ,
2016-12-24 05:46:50 +08:00
// Patapon 3
2016-12-27 12:13:51 +01:00
{ " UCES01421 " , " UCUS98751 " } ,
{ " NPJG00122 " , " UCUS98751 " } ,
2016-12-24 05:46:50 +08:00
// Phantasy Star Portable
2016-12-27 12:13:51 +01:00
{ " ULJM05309 " , " ULUS10410 " } ,
{ " ULES01218 " , " ULUS10410 " } ,
{ " ULJM08023 " , " ULUS10410 " } ,
2016-12-24 05:46:50 +08:00
// Phantasy Star Portable 2
2016-12-27 12:13:51 +01:00
{ " ULJM05493 " , " ULUS10529 " } ,
{ " ULJM08030 " , " ULUS10529 " } ,
{ " ULES01439 " , " ULUS10529 " } ,
2016-12-24 05:46:50 +08:00
// Resistance - Retribution
2016-12-27 12:13:51 +01:00
{ " UCES01184 " , " UCJS10090 " } ,
{ " UCUS98668 " , " UCJS10090 " } ,
2016-12-24 05:46:50 +08:00
// Rocky Balboa
2016-12-27 12:13:51 +01:00
{ " ULUS10233 " , " ULES00670 " } ,
2016-12-24 05:46:50 +08:00
// SOCOM - Fireteam Bravo
2016-12-27 12:13:51 +01:00
{ " UCES00038 " , " UCUS98615 " } ,
{ " UCJS10102 " , " UCUS98615 " } ,
2016-12-24 05:46:50 +08:00
// SOCOM - Fireteam Bravo 3
2016-12-27 12:13:51 +01:00
{ " UCES01242 " , " UCUS98716 " } ,
{ " NPJG00035 " , " UCUS98716 " } ,
2016-12-24 05:46:50 +08:00
// Shrek - Smash and Crash Racing
2016-12-27 12:13:51 +01:00
{ " ULES00618 " , " ULUS10194 " } ,
2016-12-24 05:46:50 +08:00
// Smash Court Tennis 3
2016-12-27 12:13:51 +01:00
{ " ULJS00098 " , " UCES00758 " } ,
{ " ULUS10269 " , " UCES00758 " } ,
2016-12-24 05:46:50 +08:00
// Soul Calibur - Broken Destiny
2016-12-27 12:13:51 +01:00
{ " ULES01298 " , " ULUS10457 " } ,
{ " ULJS00202 " , " ULUS10457 " } ,
2016-12-24 05:46:50 +08:00
// Split Second - Velocity
2016-12-27 12:13:51 +01:00
{ " ULES01402 " , " ULUS10513 " } ,
{ " ULJM05812 " , " ULUS10513 " } ,
2016-12-24 05:46:50 +08:00
// Street Fighter Alpha 3 MAX
2016-12-27 12:13:51 +01:00
{ " ULJM05082 " , " ULUS10062 " } ,
{ " ULES00235 " , " ULUS10062 " } ,
{ " ULJM05225 " , " ULUS10062 " } ,
2016-12-24 05:46:50 +08:00
// Taiko no Tatsujin Portable DX"
2016-12-27 12:13:51 +01:00
{ " ULJS00383 " , " NPJH50426 " } ,
2016-12-24 05:46:50 +08:00
// Tekken 6
2016-12-27 12:13:51 +01:00
{ " ULES01376 " , " ULUS10466 " } ,
{ " NPJH50184 " , " ULUS10466 " } ,
{ " ULJS00224 " , " ULUS10466 " } ,
2016-12-24 05:46:50 +08:00
// TRON - Evolution
2016-12-27 12:13:51 +01:00
{ " ULES01495 " , " ULUS10548 " } ,
2016-12-24 05:46:50 +08:00
// Untold Legends - Brotherhood of the Blade
2016-12-27 12:13:51 +01:00
{ " ULES00046 " , " ULUS10003 " } ,
{ " ULJM05087 " , " ULUS10003 " } ,
{ " ULKS46015 " , " ULUS10003 " } ,
2016-12-24 05:46:50 +08:00
// Untold Legends - The Warrior's Code
2016-12-27 12:13:51 +01:00
{ " ULES00301 " , " ULUS10086 " } ,
{ " ULJM05179 " , " ULUS10086 " } ,
{ " ULKS46069 " , " ULUS10086 " } ,
2016-12-24 05:46:50 +08:00
// Virtua Tennis 3
2016-12-27 12:13:51 +01:00
{ " ULES00763 " , " ULUS10246 " } ,
2016-12-24 05:46:50 +08:00
// World Series of Poker 2008 - Battle for the Bracelets
2016-12-27 12:13:51 +01:00
{ " ULES00991 " , " ULUS10321 " } ,
2016-12-24 05:46:50 +08:00
// Worms Battle Islands
2016-12-27 12:13:51 +01:00
{ " NPEH00019 " , " NPUH10045 " } ,
2016-12-24 05:46:50 +08:00
// Worms Open Warfare
2016-12-27 12:13:51 +01:00
{ " ULES00268 " , " ULUS10065 " } ,
2016-12-24 05:46:50 +08:00
// Worms Open Warfare 2
2016-12-27 12:13:51 +01:00
{ " ULES00819 " , " ULUS10260 " } ,
2016-12-24 05:46:50 +08:00
// Yu-Gi-Oh! 5D's Tag Force 5
2016-12-27 12:13:51 +01:00
{ " ULUS10555 " , " ULJM05734 " } ,
{ " ULES01474 " , " ULJM05734 " } ,
} ;
2016-12-24 05:46:50 +08:00
2016-12-27 12:13:51 +01:00
std : : vector < db_productid > productids ;
2016-12-27 13:14:45 +01:00
static const db_productid default_productids [ ] = {
2016-12-27 12:13:51 +01:00
{ " ULUS10511 " , " Ace Combat X2 - Joint Assault " } ,
{ " ULUS10245 " , " Alien Syndrome " } ,
{ " NPUH10023 " , " Armored Core 3 Portable " } ,
{ " ULES00719 " , " Asphalt - Urban GT 2 " } ,
{ " ULUS10579 " , " BlazBlue - Continuum Shift 2 " } ,
{ " ULUS10519 " , " BlazBlue Calamity Trigger " } ,
{ " UCJS10110 " , " Bleach Heat The Soul 7 " } ,
{ " ULUS10516 " , " Blood Bowl " } ,
{ " ULUS10121 " , " Bomberman " } ,
{ " ULUS10319 " , " Bomberman Land " } ,
{ " ULES00703 " , " Burnout Dominator " } ,
{ " ULES00125 " , " Burnout Legends " } ,
{ " ULJM05538 " , " Busou Shinki - Battle Masters " } ,
{ " ULUS10057 " , " Bust A Move Deluxe " } ,
{ " ULUS10218 " , " Call of Duty - Roads to Victory " } ,
{ " ULUS10351 " , " Code Lyoko - Quest for Infinity " } ,
{ " NPJH50583 " , " Conception - Please have my children! " } ,
{ " ULUS10044 " , " Crash Tag Team Racing " } ,
{ " ULUS10100 " , " Def Jam Fight For NY - The Takeover " } ,
{ " NPJH50588 " , " Digimon World Re:Digitize " } ,
{ " ULUS10566 " , " Dissidia 012 Duodecim Final Fantasy " } ,
{ " ULUS10437 " , " Dissidia Final Fantasy " } ,
{ " ULUS10081 " , " Dragon Ball Z - Shin Budokai " } ,
{ " ULUS10234 " , " Dragon Ball Z - Shin Budokai 2 " } ,
{ " ULUS10537 " , " Dragon Ball Z - Tenkaichi Tag Team " } ,
2016-12-24 05:46:50 +08:00
//maybe we can crosslinks this 2 region to ULUS10537 not having the game to test
2016-12-27 12:13:51 +01:00
{ " ULJS00311 " , " Dragon Ball Z - Tenkaichi Tag Team " } ,
{ " NPJH90135 " , " Dragon Ball Z - Tenkaichi Tag Team " } ,
{ " ULJM05127 " , " Dragon Quest & Final Fantasy in Itadaki Street Special " } ,
{ " ULES00847 " , " Dungeon Explorer - Warriors of Ancient Arts " } ,
{ " ULUS10177 " , " Dungeon Siege - Throne of Agony " } ,
{ " ULUS10170 " , " Dynasty Warrior 2 " } ,
2016-12-24 05:46:50 +08:00
//looks like can be crosslinked too
2016-12-27 12:13:51 +01:00
{ " ULES01221 " , " Dynasty Warriors - Strike Force " } ,
{ " ULUS10416 " , " Dynasty Warriors - Strike Force " } ,
{ " UCUS98701 " , " Everybody's Tennis " } ,
{ " UCUS98740 " , " Fat Princess - Fistful of Cake " } ,
{ " ULJM05360 " , " Fate Tiger Colosseum Upper " } ,
{ " ULUS10297 " , " Final Fantasy Tactics - The War of the Lions " } ,
{ " ULES00850 " , " Final Fantasy Tactics - War of the Lions " } ,
{ " NPJH50443 " , " Final Fantasy Type 0 " } ,
{ " NPJH50468 " , " Frontier Gate " } ,
{ " NPJH50721 " , " Frontier Gate Boost+ " } ,
{ " ULES01432 " , " Full Metal Alchemist - Brotherhood " } ,
{ " ULUS10490 " , " GTA Chinatown Wars " } ,
{ " ULUS10160 " , " GTA Vice City Stories " } ,
{ " ULUS10210 " , " Ghost Rider " } ,
{ " ULJS00237 " , " God Eater " } ,
{ " NPJH50832 " , " God Eater 2 " } ,
{ " ULUS10563 " , " God Eater Burst " } ,
{ " UCUS98632 " , " Gran Turismo " } ,
{ " NPJH50107 " , " Gundam VS Gundam - Next Plus " } ,
{ " ULJM05933 " , " Hatsune Miku - Project Diva Extend " } ,
{ " ULUS10298 " , " Hot Pixel " } ,
{ " ULJM05709 " , " K-ON! Houkago Live " } ,
{ " NPJH50221 " , " Kateikyoushi Hitman Reborn! Kizuna no Tag Battle " } ,
{ " ULJS00165 " , " Kidou Senshi Gundam - Gundam vs. Gundam " } ,
{ " UCUS98646 " , " Killzone Liberation " } ,
{ " ULJM05775 " , " Kingdom Hearts - Birth by Sleep Final Mix " } ,
{ " ULUS10487 " , " LEGO Indiana Jones 2 " } ,
{ " NPJH50503 " , " Lord of Apocalypse " } ,
{ " ULES01507 " , " Lord of Arcana " } ,
{ " ULUS10180 " , " M.A.C.H. - Modified Air Combat Heroes " } ,
{ " UCUS98758 " , " MLB11 - The Show " } ,
{ " ULUS10581 " , " Madden NFL 12 " } ,
{ " ULJS00385 " , " Mahou Shoujo Nanoha A's Portable - The Gears of Destiny " } ,
{ " ULUS10408 " , " Mana Khemia Student Alliance " } ,
{ " ULUS10141 " , " Medal Of Honor Heroes " } ,
{ " NPJH50045 " , " Metal Gear Solid - Peace Walker " } ,
{ " ULUS10202 " , " Metal Gear Solid - Portable Ops " } ,
{ " ULUS10290 " , " Metal Gear Solid - Portable Ops + " } ,
{ " ULUS10154 " , " Metal Slug Anthology " } ,
{ " ULUS10495 " , " Metal Slug XX " } ,
{ " ULES01429 " , " Metal Slug XX " } ,
{ " ULES00368 " , " Micro Machines V4 " } ,
{ " ULUS10383 " , " Midnight Club - LA Remix " } ,
{ " UCUS98741 " , " Mod Nation Racers " } ,
{ " ULUS10084 " , " Monster Hunter Freedom " } ,
{ " ULUS10266 " , " Monster Hunter Freedom 2 " } ,
{ " ULUS10391 " , " Monster Hunter Freedom Unite " } ,
{ " ULJM05800 " , " Monster Hunter Portable 3rd " } ,
{ " ULJM06097 " , " Musou Orochi 2 Special " } ,
{ " ULUS10340 " , " N+ " } ,
{ " ULES01578 " , " NBA 2K13 " } ,
{ " ULUS10598 " , " NBA 2K13 " } ,
{ " ULUS10349 " , " Naruto - Ultimate Ninja Heroes 2 " } ,
{ " ULUS10518 " , " Naruto - Ultimate Ninja Heroes 3 " } ,
{ " ULJS00236 " , " Naruto - Accel 3 " } ,
{ " ULUS10582 " , " Naruto Shippuden - Ultimate Ninja Impact " } ,
{ " ULES01537 " , " Naruto Shippuden - Ultimate Ninja Impact " } ,
{ " ULUS10571 " , " Naruto Shippuden - Kizuna Drive " } ,
{ " ULES00196 " , " Need For Speed - Most Wanted " } ,
{ " ULUS10036 " , " Need For Speed - Most Wanted " } ,
{ " ULUS10376 " , " Need for Speed - Undercover " } ,
{ " ULKS46004 " , " Need for Speed - Underground Rivals " } ,
{ " ULES01340 " , " Obscure - The Aftermath " } ,
{ " ULUS10064 " , " Outrun 2006 - Coast 2 Coast " } ,
{ " ULUS10586 " , " PRO Evolution Soccer 2012 " } ,
{ " ULUS10149 " , " Pac Man - World Rally " } ,
{ " ULUS10438 " , " Pangya! - Fantasy Golf " } ,
{ " UCUS98732 " , " Patapon 2 " } ,
{ " UCUS98751 " , " Patapon 3 " } ,
{ " ULUS10410 " , " Phantasy Star Portable " } ,
{ " ULUS10529 " , " Phantasy Star Portable 2 " } ,
2016-12-24 05:46:50 +08:00
//looks like this japan version can crosslink to ULUS10529
2016-12-27 12:13:51 +01:00
{ " NPJH50332 " , " Phantasy Star Portable 2 " } ,
{ " ULJM05732 " , " Phantasy Star Portable 2 - Infinity " } ,
{ " ULES01596 " , " Pro Evolution Soccer 2014 " } ,
{ " ULES01595 " , " Pro Evolution Soccer 2015 " } ,
{ " NPJH50520 " , " Pro Yakyuu Spirits 2012 " } ,
{ " NPJH50838 " , " Pro Yakyuu Spirits 2014 " } ,
{ " NPJH50492 " , " Puyo Puyo!! 20th Anniversary " } ,
{ " ULUS10292 " , " Renegrade Squadron " } ,
{ " UCJS10090 " , " Resistance - Retribution " } ,
{ " ULES00670 " , " Rocky Balboa " } ,
{ " ULJS00360 " , " Rurouni Kenshin - Meiji Kenkaku Romantan Saisen " } ,
{ " UCUS98615 " , " SOCOM - Fireteam Bravo " } ,
{ " UCUS98645 " , " SOCOM - Fireteam Bravo 2 " } ,
{ " UCUS98716 " , " SOCOM - Fireteam Bravo 3 " } ,
{ " NPJH50460 " , " Sengoku Basara - Chronicles Heroes " } ,
{ " ULJM05436 " , " Sengoku Basara - Battle Heroes " } ,
{ " ULJM05637 " , " Shin Sangoku Musou - Multi Raid 2 " } ,
{ " ULJM05035 " , " Shinobido - Tales of the Ninja " } ,
{ " ULUS10194 " , " Shrek - Smash and Crash Racing " } ,
{ " UCES00758 " , " Smash Court Tennis 3 " } ,
{ " ULUS10195 " , " Sonic Rivals " } ,
{ " ULUS10457 " , " Soul Calibur - Broken Destiny " } ,
{ " ULUS10513 " , " Split Second - Velocity " } ,
{ " ULES00183 " , " Star Wars Battle Front 2 " } ,
{ " ULUS10062 " , " Street Fighter Alpha 3 MAX " } ,
{ " NPUH10020 " , " Strikers 1945 Plus Portable " } ,
{ " ULUS10548 " , " TRON - Evolution " } ,
{ " NPJH50426 " , " Taiko no Tatsujin Portable DX " } ,
{ " ULUS10466 " , " Tekken 6 " } ,
{ " NPJH50691 " , " Tokusatsu University " } ,
2016-12-24 05:46:50 +08:00
//looks like can be crosslinked
2016-12-27 12:13:51 +01:00
{ " ULUS10445 " , " Tom Clancy's Ghost Recon - Predator " } ,
{ " ULES01350 " , " Tom Clancy's Ghost Recon - Predator " } ,
{ " NPJH50789 " , " Toukiden " } ,
{ " NPJH50878 " , " Toukiden - Kiwami " } ,
{ " UCUS98601 " , " Twisted Metal - Head On " } ,
{ " ULUS10508 " , " UFC Undisputed 2010 " } ,
{ " ULJS00069 " , " Ultraman Fighting Evo Zero " } ,
{ " ULUS10003 " , " Untold Legends - Brotherhood of the Blade " } ,
{ " ULUS10086 " , " Untold Legends - The Warrior's Code " } ,
{ " ULUS10515 " , " Valkryia Chronicles 2 " } ,
{ " ULUS10087 " , " Viewtiful Joe " } ,
{ " ULUS10246 " , " Virtua Tennis 3 " } ,
{ " ULUS82741 " , " WWE 2K14 " } ,
{ " ULUS10543 " , " WWE Smackdown vs. Raw 2011 " } ,
{ " ULUS10423 " , " Warriors Orochi 2 " } ,
{ " ULJM05553 " , " Warship Gunner 2 Portable " } ,
{ " ULJS00155 " , " Way Of The Samurai " } ,
{ " UCES00465 " , " Wipeout Pulse " } ,
{ " ULUS10321 " , " World Series of Poker 2008 - Battle for the Bracelets " } ,
{ " NPUH10045 " , " Worms Battle Islands " } ,
{ " ULUS10065 " , " Worms Open Warfare " } ,
{ " ULUS10260 " , " Worms Open Warfare 2 " } ,
{ " ULJM05734 " , " Yu-Gi-Oh! 5D's Tag Force 5 " } ,
{ " ULJM05940 " , " Yu-Gi-Oh! 5D's Tag Force 6 " } ,
{ " NPJH00142 " , " Yu-Gi-Oh! Arc-V Tag Force " } ,
{ " ULJM05151 " , " Yu-Gi-Oh! GX Tag Force " } ,
{ " ULJM05373 " , " Yu-Gi-Oh! GX Tag Force 3 " } ,
{ " NPUG80086 " , " flOw " } ,
} ;
// Function Prototypes
const char * strcpyxml ( char * out , const char * in , uint32_t size ) ;
// Function Prototypes
void interrupt ( int sig ) ;
void enable_address_reuse ( int fd ) ;
2020-01-18 02:32:09 +07:00
void enable_keepalive ( int fd ) ;
void change_nodelay_mode ( int fd , int flag ) ;
2016-12-27 12:13:51 +01:00
void change_blocking_mode ( int fd , int nonblocking ) ;
int create_listen_socket ( uint16_t port ) ;
int server_loop ( int server ) ;
2016-12-24 05:46:50 +08:00
2016-12-27 12:13:51 +01:00
void __AdhocServerInit ( ) {
// Database Product name will update if new game region played on my server to list possible crosslinks
2016-12-27 13:14:45 +01:00
productids = std : : vector < db_productid > ( default_productids , default_productids + ARRAY_SIZE ( default_productids ) ) ;
crosslinks = std : : vector < db_crosslink > ( default_crosslinks , default_crosslinks + ARRAY_SIZE ( default_crosslinks ) ) ;
2014-08-05 20:05:08 +08:00
}
2014-08-01 01:55:42 +07:00
/**
* Login User into Database ( Stream )
* @ param fd Socket
* @ param ip IP Address ( Network Order )
*/
void login_user_stream ( int fd , uint32_t ip )
{
// Enough Space available
if ( _db_user_count < SERVER_USER_MAXIMUM )
{
// Check IP Duplication
SceNetAdhocctlUserNode * u = _db_user ;
while ( u ! = NULL & & u - > resolver . ip ! = ip ) u = u - > next ;
if ( u ! = NULL ) { // IP Already existed
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: Already Existing IP: %s \n " , inet_ntoa ( * ( in_addr * ) & u - > resolver . ip ) ) ;
2014-08-01 01:55:42 +07:00
}
// Unique IP Address
else //if(u == NULL)
{
// Allocate User Node Memory
SceNetAdhocctlUserNode * user = ( SceNetAdhocctlUserNode * ) malloc ( sizeof ( SceNetAdhocctlUserNode ) ) ;
// Allocated User Node Memory
if ( user ! = NULL )
{
// Clear Memory
memset ( user , 0 , sizeof ( SceNetAdhocctlUserNode ) ) ;
// Save Socket
user - > stream = fd ;
// Save IP
user - > resolver . ip = ip ;
// Link into User List
user - > next = _db_user ;
if ( _db_user ! = NULL ) _db_user - > prev = user ;
_db_user = user ;
// Initialize Death Clock
user - > last_recv = time ( NULL ) ;
// Notify User
2019-12-24 00:04:03 +07:00
INFO_LOG ( SCENET , " AdhocServer: New Connection from %s " , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) ) ;
2014-08-01 01:55:42 +07:00
// Fix User Counter
_db_user_count + + ;
// Update Status Log
update_status ( ) ;
// Exit Function
return ;
}
}
}
// Duplicate IP, Allocation Error or not enough space - Close Stream
closesocket ( fd ) ;
}
/**
* Login User into Database ( Login Data )
* @ param user User Node
* @ param data Login Packet
*/
void login_user_data ( SceNetAdhocctlUserNode * user , SceNetAdhocctlLoginPacketC2S * data )
{
// Product Code Check
int valid_product_code = 1 ;
// Iterate Characters
int i = 0 ; for ( ; i < PRODUCT_CODE_LENGTH & & valid_product_code = = 1 ; i + + )
{
// Valid Characters
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 ;
}
// Valid Packet Data
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 )
{
2019-11-10 06:23:19 +07:00
// Check for duplicated MAC as most games identify Players by MAC
SceNetAdhocctlUserNode * u = _db_user ;
while ( u ! = NULL & & ! IsMatch ( u - > resolver . mac , data - > mac ) ) u = u - > next ;
if ( u ! = NULL ) { // MAC Already existed
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: Already Existing MAC: %02x:%02x:%02x:%02x:%02x:%02x [%s] \n " , data - > mac . data [ 0 ] , data - > mac . data [ 1 ] , data - > mac . data [ 2 ] , data - > mac . data [ 3 ] , data - > mac . data [ 4 ] , data - > mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & u - > resolver . ip ) ) ;
2019-11-10 06:23:19 +07:00
}
2014-08-01 01:55:42 +07:00
// Game Product Override
game_product_override ( & data - > game ) ;
// Find existing Game
SceNetAdhocctlGameNode * game = _db_game ;
while ( game ! = NULL & & strncmp ( game - > game . data , data - > game . data , PRODUCT_CODE_LENGTH ) ! = 0 ) game = game - > next ;
// Game not found
if ( game = = NULL )
{
// Allocate Game Node Memory
game = ( SceNetAdhocctlGameNode * ) malloc ( sizeof ( SceNetAdhocctlGameNode ) ) ;
// Allocated Game Node Memory
if ( game ! = NULL )
{
// Clear Memory
memset ( game , 0 , sizeof ( SceNetAdhocctlGameNode ) ) ;
// Save Game Product ID
game - > game = data - > game ;
// Link into Game List
game - > next = _db_game ;
if ( _db_game ! = NULL ) _db_game - > prev = game ;
_db_game = game ;
}
}
// Game now available
if ( game ! = NULL )
{
// Save MAC
user - > resolver . mac = data - > mac ;
// Save Nickname
user - > resolver . name = data - > name ;
// Increase Player Count in Game Node
game - > playercount + + ;
// Link Game to Player
user - > game = game ;
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , game - > game . data , PRODUCT_CODE_LENGTH ) ;
2019-12-24 00:04:03 +07:00
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) started playing %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr ) ;
2014-08-01 01:55:42 +07:00
// Update Status Log
update_status ( ) ;
// Leave Function
return ;
}
}
// Invalid Packet Data
else
{
// Notify User
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: Invalid Login Packet Contents from %s " , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) ) ;
2014-08-01 01:55:42 +07:00
}
// Logout User - Out of Memory or Invalid Arguments
logout_user ( user ) ;
}
/**
* Logout User from Database
* @ param user User Node
*/
void logout_user ( SceNetAdhocctlUserNode * user )
{
// Disconnect from Group
if ( user - > group ! = NULL ) disconnect_user ( user ) ;
// Unlink Leftside (Beginning)
if ( user - > prev = = NULL ) _db_user = user - > next ;
// Unlink Leftside (Other)
else user - > prev - > next = user - > next ;
// Unlink Rightside
if ( user - > next ! = NULL ) user - > next - > prev = user - > prev ;
// Close Stream
closesocket ( user - > stream ) ;
// Playing User
if ( user - > game ! = NULL )
{
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
2019-12-24 00:04:03 +07:00
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) stopped playing %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr ) ;
2014-08-01 01:55:42 +07:00
// Fix Game Player Count
user - > game - > playercount - - ;
// Empty Game Node
if ( user - > game - > playercount = = 0 )
{
// Unlink Leftside (Beginning)
if ( user - > game - > prev = = NULL ) _db_game = user - > game - > next ;
// Unlink Leftside (Other)
else user - > game - > prev - > next = user - > game - > next ;
// Unlink Rightside
if ( user - > game - > next ! = NULL ) user - > game - > next - > prev = user - > game - > prev ;
// Free Game Node Memory
free ( user - > game ) ;
}
}
// Unidentified User
else
{
// Notify User
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: Dropped Connection to %s " , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) ) ;
2014-08-01 01:55:42 +07:00
}
// Free Memory
free ( user ) ;
// Fix User Counter
_db_user_count - - ;
// Update Status Log
update_status ( ) ;
}
/**
* Free Database Memory
*/
2019-12-24 00:04:03 +07:00
void free_database ( )
2014-08-01 01:55:42 +07:00
{
// There are users playing
if ( _db_user_count > 0 )
{
// Send Shutdown Notice
spread_message ( NULL , SERVER_SHUTDOWN_MESSAGE ) ;
}
// Iterate Users for Deletion
SceNetAdhocctlUserNode * user = _db_user ;
while ( user ! = NULL )
{
// Next User (for safe delete)
SceNetAdhocctlUserNode * next = user - > next ;
// Logout User
logout_user ( user ) ;
// Move Pointer
user = next ;
}
}
/**
* Connect User to Game Group
* @ param user User Node
* @ param group Group Name
*/
void connect_user ( SceNetAdhocctlUserNode * user , SceNetAdhocctlGroupName * group )
{
// Group Name Check
int valid_group_name = 1 ;
{
// Iterate Characters
int i = 0 ; for ( ; i < ADHOCCTL_GROUPNAME_LEN & & valid_group_name = = 1 ; i + + )
{
// End of Name
if ( group - > data [ i ] = = 0 ) break ;
// A - Z
if ( group - > data [ i ] > = ' A ' & & group - > data [ i ] < = ' Z ' ) continue ;
// a - z
if ( group - > data [ i ] > = ' a ' & & group - > data [ i ] < = ' z ' ) continue ;
// 0 - 9
if ( group - > data [ i ] > = ' 0 ' & & group - > data [ i ] < = ' 9 ' ) continue ;
// Invalid Symbol
valid_group_name = 0 ;
}
}
// Valid Group Name
if ( valid_group_name = = 1 )
{
// User is disconnected
if ( user - > group = = NULL )
{
// Find Group in Game Node
SceNetAdhocctlGroupNode * g = user - > game - > group ;
while ( g ! = NULL & & strncmp ( ( char * ) g - > group . data , ( char * ) group - > data , ADHOCCTL_GROUPNAME_LEN ) ! = 0 ) g = g - > next ;
// BSSID Packet
SceNetAdhocctlConnectBSSIDPacketS2C bssid ;
// Set BSSID Opcode
bssid . base . opcode = OPCODE_CONNECT_BSSID ;
// Set Default BSSID
bssid . mac = user - > resolver . mac ;
// No Group found
if ( g = = NULL )
{
// Allocate Group Memory
g = ( SceNetAdhocctlGroupNode * ) malloc ( sizeof ( SceNetAdhocctlGroupNode ) ) ;
// Allocated Group Memory
if ( g ! = NULL )
{
// Clear Memory
memset ( g , 0 , sizeof ( SceNetAdhocctlGroupNode ) ) ;
// Link Game Node
g - > game = user - > game ;
// Link Group Node
g - > next = g - > game - > group ;
if ( g - > game - > group ! = NULL ) g - > game - > group - > prev = g ;
g - > game - > group = g ;
// Copy Group Name
g - > group = * group ;
// Increase Group Counter for Game
g - > game - > groupcount + + ;
}
}
// Group now available
if ( g ! = NULL )
{
// Iterate remaining Group Players
SceNetAdhocctlUserNode * peer = g - > player ;
while ( peer ! = NULL )
{
// Connect Packet
SceNetAdhocctlConnectPacketS2C packet ;
// Clear Memory
// memset(&packet, 0, sizeof(packet));
// Set Connect Opcode
packet . base . opcode = OPCODE_CONNECT ;
// Set Player Name
packet . name = user - > resolver . name ;
// Set Player MAC
packet . mac = user - > resolver . mac ;
// Set Player IP
packet . ip = user - > resolver . ip ;
// Send Data
2020-09-07 02:38:45 +07:00
int iResult = send ( peer - > stream , ( const char * ) & packet , sizeof ( packet ) , MSG_NOSIGNAL ) ;
2014-08-11 23:06:09 +07:00
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: connect_user[send peer] (Socket error %d) " , errno ) ;
2014-08-01 01:55:42 +07:00
// Set Player Name
packet . name = peer - > resolver . name ;
// Set Player MAC
packet . mac = peer - > resolver . mac ;
// Set Player IP
packet . ip = peer - > resolver . ip ;
// Send Data
2020-09-07 02:38:45 +07:00
iResult = send ( user - > stream , ( const char * ) & packet , sizeof ( packet ) , MSG_NOSIGNAL ) ;
2014-08-11 23:06:09 +07:00
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: connect_user[send user] (Socket error %d) " , errno ) ;
2014-08-01 01:55:42 +07:00
// Set BSSID
if ( peer - > group_next = = NULL ) bssid . mac = peer - > resolver . mac ;
// Move Pointer
peer = peer - > group_next ;
}
// Link User to Group
user - > group_next = g - > player ;
if ( g - > player ! = NULL ) g - > player - > group_prev = user ;
g - > player = user ;
// Link Group to User
user - > group = g ;
// Increase Player Count
g - > playercount + + ;
// Send Network BSSID to User
2020-09-07 02:38:45 +07:00
int iResult = send ( user - > stream , ( const char * ) & bssid , sizeof ( bssid ) , MSG_NOSIGNAL ) ;
2014-08-11 23:06:09 +07:00
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: connect_user[send user bssid] (Socket error %d) " , errno ) ;
2014-08-01 01:55:42 +07:00
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
2019-12-24 00:04:03 +07:00
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) joined %s group %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr , safegroupstr ) ;
2014-08-01 01:55:42 +07:00
// Update Status Log
update_status ( ) ;
// Exit Function
return ;
}
}
// Already connected to another group
else
{
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) group - > data , ADHOCCTL_GROUPNAME_LEN ) ;
char safegroupstr2 [ 9 ] ;
memset ( safegroupstr2 , 0 , sizeof ( safegroupstr2 ) ) ;
strncpy ( safegroupstr2 , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to join %s group %s without disconnecting from %s first " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr , safegroupstr , safegroupstr2 ) ;
2014-08-01 01:55:42 +07:00
}
}
// Invalid Group Name
else
{
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) group - > data , ADHOCCTL_GROUPNAME_LEN ) ;
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to join invalid %s group %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr , safegroupstr ) ;
2014-08-01 01:55:42 +07:00
}
// Invalid State, Out of Memory or Invalid Group Name
logout_user ( user ) ;
}
/**
* Disconnect User from Game Group
* @ param user User Node
*/
void disconnect_user ( SceNetAdhocctlUserNode * user )
{
// User is connected
if ( user - > group ! = NULL )
{
// Unlink Leftside (Beginning)
if ( user - > group_prev = = NULL ) user - > group - > player = user - > group_next ;
// Unlink Leftside (Other)
else user - > group_prev - > group_next = user - > group_next ;
// Unlink Rightside
if ( user - > group_next ! = NULL ) user - > group_next - > group_prev = user - > group_prev ;
// Fix Player Count
user - > group - > playercount - - ;
// Iterate remaining Group Players
SceNetAdhocctlUserNode * peer = user - > group - > player ;
while ( peer ! = NULL )
{
// Disconnect Packet
SceNetAdhocctlDisconnectPacketS2C packet ;
// Clear Memory
// memset(&packet, 0, sizeof(packet));
// Set Disconnect Opcode
packet . base . opcode = OPCODE_DISCONNECT ;
// Set User IP
packet . ip = user - > resolver . ip ;
// Send Data
2020-09-07 02:38:45 +07:00
int iResult = send ( peer - > stream , ( const char * ) & packet , sizeof ( packet ) , MSG_NOSIGNAL ) ;
2014-08-11 23:06:09 +07:00
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: disconnect_user[send peer] (Socket error %d) " , errno ) ;
2014-08-01 01:55:42 +07:00
// Move Pointer
peer = peer - > group_next ;
}
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
2019-12-24 00:04:03 +07:00
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) left %s group %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr , safegroupstr ) ;
2014-08-01 01:55:42 +07:00
// Empty Group
if ( user - > group - > playercount = = 0 )
{
// Unlink Leftside (Beginning)
if ( user - > group - > prev = = NULL ) user - > group - > game - > group = user - > group - > next ;
// Unlink Leftside (Other)
else user - > group - > prev - > next = user - > group - > next ;
// Unlink Rightside
if ( user - > group - > next ! = NULL ) user - > group - > next - > prev = user - > group - > prev ;
// Free Group Memory
free ( user - > group ) ;
// Decrease Group Counter in Game Node
user - > game - > groupcount - - ;
}
// Unlink from Group
user - > group = NULL ;
user - > group_next = NULL ;
user - > group_prev = NULL ;
// Update Status Log
update_status ( ) ;
// Exit Function
return ;
}
// Not in a game group
else
{
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to leave %s group without joining one first " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr ) ;
2014-08-01 01:55:42 +07:00
}
// Delete User
logout_user ( user ) ;
}
/**
* Send Game Group List
* @ param user User Node
*/
void send_scan_results ( SceNetAdhocctlUserNode * user )
{
// User is disconnected
if ( user - > group = = NULL )
{
// Iterate Groups
SceNetAdhocctlGroupNode * group = user - > game - > group ;
for ( ; group ! = NULL ; group = group - > next )
{
// Scan Result Packet
SceNetAdhocctlScanPacketS2C packet ;
// Clear Memory
// memset(&packet, 0, sizeof(packet));
// Set Opcode
packet . base . opcode = OPCODE_SCAN ;
// Set Group Name
packet . group = group - > group ;
// Iterate Players in Network Group
SceNetAdhocctlUserNode * peer = group - > player ;
for ( ; peer ! = NULL ; peer = peer - > group_next )
{
// Found Network Founder
if ( peer - > group_next = = NULL )
{
// Set Group Host MAC
packet . mac = peer - > resolver . mac ;
}
}
// Send Group Packet
2020-09-07 02:38:45 +07:00
int iResult = send ( user - > stream , ( const char * ) & packet , sizeof ( packet ) , MSG_NOSIGNAL ) ;
2014-08-11 23:06:09 +07:00
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: send_scan_result[send user] (Socket error %d) " , errno ) ;
2014-08-01 01:55:42 +07:00
}
// Notify Player of End of Scan
uint8_t opcode = OPCODE_SCAN_COMPLETE ;
2020-09-07 02:38:45 +07:00
int iResult = send ( user - > stream , ( const char * ) & opcode , 1 , MSG_NOSIGNAL ) ;
2014-08-11 23:06:09 +07:00
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: send_scan_result[send peer complete] (Socket error %d) " , errno ) ;
2014-08-01 01:55:42 +07:00
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
2019-12-24 00:04:03 +07:00
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) requested information on %d %s groups " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , user - > game - > groupcount , safegamestr ) ;
2014-08-01 01:55:42 +07:00
// Exit Function
return ;
}
// User in a game group
else
{
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to scan for %s groups without disconnecting from %s first " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr , safegroupstr ) ;
2014-08-01 01:55:42 +07:00
}
// Delete User
logout_user ( user ) ;
}
/**
* Spread Chat Message in P2P Network
* @ param user Sender User Node
* @ param message Chat Message
*/
2015-01-11 14:23:03 -08:00
void spread_message ( SceNetAdhocctlUserNode * user , const char * message )
2014-08-01 01:55:42 +07:00
{
// Global Notice
if ( user = = NULL )
{
// Iterate Players
for ( user = _db_user ; user ! = NULL ; user = user - > next )
{
// Player has access to chat
if ( user - > group ! = NULL )
{
// Chat Packet
SceNetAdhocctlChatPacketS2C packet ;
// Clear Memory
memset ( & packet , 0 , sizeof ( packet ) ) ;
// Set Chat Opcode
packet . base . base . opcode = OPCODE_CHAT ;
// Set Chat Message
strcpy ( packet . base . message , message ) ;
// Send Data
2020-09-07 02:38:45 +07:00
int iResult = send ( user - > stream , ( const char * ) & packet , sizeof ( packet ) , MSG_NOSIGNAL ) ;
2014-08-11 23:06:09 +07:00
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: spread_message[send user chat] (Socket error %d) " , errno ) ;
2014-08-01 01:55:42 +07:00
}
}
// Prevent NULL Error
return ;
}
// User is connected
else if ( user - > group ! = NULL )
{
// Broadcast Range Counter
uint32_t counter = 0 ;
// Iterate Group Players
SceNetAdhocctlUserNode * peer = user - > group - > player ;
while ( peer ! = NULL )
{
// Skip Self
if ( peer = = user )
{
// Move Pointer
peer = peer - > group_next ;
// Continue Loop
continue ;
}
// Chat Packet
SceNetAdhocctlChatPacketS2C packet ;
// Set Chat Opcode
packet . base . base . opcode = OPCODE_CHAT ;
// Set Chat Message
strcpy ( packet . base . message , message ) ;
// Set Sender Nickname
packet . name = user - > resolver . name ;
// Send Data
2020-09-07 02:38:45 +07:00
int iResult = send ( peer - > stream , ( const char * ) & packet , sizeof ( packet ) , MSG_NOSIGNAL ) ;
2014-08-11 23:06:09 +07:00
if ( iResult < 0 ) ERROR_LOG ( SCENET , " AdhocServer: spread_message[send peer chat] (Socket error %d) " , errno ) ;
2014-08-01 01:55:42 +07:00
// Move Pointer
peer = peer - > group_next ;
// Increase Broadcast Range Counter
counter + + ;
}
// Message Sent
if ( counter > 0 )
{
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
char safegroupstr [ 9 ] ;
memset ( safegroupstr , 0 , sizeof ( safegroupstr ) ) ;
strncpy ( safegroupstr , ( char * ) user - > group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
2019-12-24 00:04:03 +07:00
INFO_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) sent \" %s \" to %d players in %s group %s " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , message , counter , safegamestr , safegroupstr ) ;
2014-08-01 01:55:42 +07:00
}
// Exit Function
return ;
}
// User not in a game group
else
{
// Notify User
char safegamestr [ 10 ] ;
memset ( safegamestr , 0 , sizeof ( safegamestr ) ) ;
strncpy ( safegamestr , user - > game - > game . data , PRODUCT_CODE_LENGTH ) ;
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) attempted to send a text message without joining a %s group first " , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) , safegamestr ) ;
2014-08-01 01:55:42 +07:00
}
// Delete User
logout_user ( user ) ;
}
/**
* Get User State
* @ param user User Node
*/
int get_user_state ( SceNetAdhocctlUserNode * user )
{
// Timeout Status
if ( ( time ( NULL ) - user - > last_recv ) > = SERVER_USER_TIMEOUT ) return USER_STATE_TIMED_OUT ;
// Waiting Status
if ( user - > game = = NULL ) return USER_STATE_WAITING ;
// Logged-In Status
return USER_STATE_LOGGED_IN ;
}
/**
* Clear RX Buffer
* @ param user User Node
* @ param clear Number of Bytes to clear ( - 1 for all )
*/
void clear_user_rxbuf ( SceNetAdhocctlUserNode * user , int clear )
{
// Fix Clear Length
if ( clear = = - 1 | | clear > ( int ) user - > rxpos ) clear = user - > rxpos ;
// Move Buffer
memmove ( user - > rx , user - > rx + clear , sizeof ( user - > rx ) - clear ) ;
// Fix RX Buffer Pointer
user - > rxpos - = clear ;
}
/**
* Patch Game Product Code
* @ param product To - be - patched Product Code
* @ param from If the Product Code matches this . . .
* @ param to . . . then change it to this one .
*/
void game_product_relink ( SceNetAdhocctlProductCode * product , char * from , char * to )
{
// Relink Region Code
if ( strncmp ( product - > data , from , PRODUCT_CODE_LENGTH ) = = 0 ) strncpy ( product - > data , to , PRODUCT_CODE_LENGTH ) ;
}
/**
* Game Product Override ( used for mixing multi - region games )
* @ param product IN : Source Product OUT : Override Product
*/
void game_product_override ( SceNetAdhocctlProductCode * product )
{
// Safe Product Code
char productid [ PRODUCT_CODE_LENGTH + 1 ] ;
// Prepare Safe Product Code
strncpy ( productid , product - > data , PRODUCT_CODE_LENGTH ) ;
productid [ PRODUCT_CODE_LENGTH ] = 0 ;
// Database Handle
//sqlite3 * db = NULL;
// Open Database
//if(sqlite3_open(SERVER_DATABASE, &db) == SQLITE_OK)
{
// Crosslinked Flag
int crosslinked = 0 ;
// Exists Flag
int exists = 0 ;
// SQL Statements
/*const char * sql = "SELECT id_to FROM crosslinks WHERE id_from=?;";
const char * sql2 = " SELECT * FROM productids WHERE id=?; " ;
const char * sql3 = " INSERT INTO productids(id, name) VALUES(?, ?); " ;
// Prepared SQL Statement
sqlite3_stmt * statement = NULL ;
// Prepare SQL Statement
if ( sqlite3_prepare_v2 ( db , sql , strlen ( sql ) + 1 , & statement , NULL ) = = SQLITE_OK )
{
// Bind SQL Statement Data
if ( sqlite3_bind_text ( statement , 1 , productid , strlen ( productid ) , SQLITE_STATIC ) = = SQLITE_OK )
{
// Found Matching Row
if ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
// Grab Crosslink ID
const char * crosslink = ( const char * ) sqlite3_column_text ( statement , 0 ) ;
// Crosslink Product Code
strncpy ( product - > data , crosslink , PRODUCT_CODE_LENGTH ) ;
// Log Crosslink
INFO_LOG ( SCENET , " Crosslinked %s to %s " , productid , crosslink ) ;
// Set Crosslinked Flag
crosslinked = 1 ;
}
}
// Destroy Prepared SQL Statement
sqlite3_finalize ( statement ) ;
} */
for ( std : : vector < db_crosslink > : : iterator it = crosslinks . begin ( ) ; it ! = crosslinks . end ( ) ; it + + ) {
if ( IsMatch ( it - > id_from , productid ) ) {
// Grab Crosslink ID
char crosslink [ PRODUCT_CODE_LENGTH + 1 ] ;
strncpy ( crosslink , it - > id_to , PRODUCT_CODE_LENGTH ) ;
crosslink [ PRODUCT_CODE_LENGTH ] = 0 ; // null terminated
// Crosslink Product Code
strncpy ( product - > data , it - > id_to , PRODUCT_CODE_LENGTH ) ;
// Log Crosslink
INFO_LOG ( SCENET , " AdhocServer: Crosslinked %s to %s " , productid , crosslink ) ;
// Set Crosslinked Flag
crosslinked = 1 ;
break ;
}
}
// Not Crosslinked
if ( ! crosslinked )
{
// Prepare SQL Statement
/*if(sqlite3_prepare_v2(db, sql2, strlen(sql2) + 1, &statement, NULL) == SQLITE_OK)
{
// Bind SQL Statement Data
if ( sqlite3_bind_text ( statement , 1 , productid , strlen ( productid ) , SQLITE_STATIC ) = = SQLITE_OK )
{
// Found Matching Row
if ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
// Set Exists Flag
exists = 1 ;
}
}
// Destroy Prepare SQL Statement
sqlite3_finalize ( statement ) ;
} */
for ( std : : vector < db_productid > : : iterator it = productids . begin ( ) ; it ! = productids . end ( ) ; it + + ) {
if ( IsMatch ( it - > id , productid ) ) {
// Set Exists Flag
exists = 1 ;
break ;
}
}
// Game doesn't exist in Database
if ( ! exists )
{
// Prepare SQL Statement
/*if(sqlite3_prepare_v2(db, sql3, strlen(sql3) + 1, &statement, NULL) == SQLITE_OK)
{
// Bind SQL Statement Data
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 )
{
// Save Product ID to Database
if ( sqlite3_step ( statement ) = = SQLITE_DONE )
{
// Log Addition
INFO_LOG ( SCENET , " Added Unknown Product ID %s to Database " , productid ) ;
}
}
// Destroy Prepare SQL Statement
sqlite3_finalize ( statement ) ;
} */
db_productid unkproduct ;
strncpy ( unkproduct . id , productid , sizeof ( unkproduct . id ) ) ;
strncpy ( unkproduct . name , productid , sizeof ( productid ) ) ;
productids . push_back ( unkproduct ) ; //productids[productids.size()] = unkproduct;
// Log Addition
INFO_LOG ( SCENET , " AdhocServer: Added Unknown Product ID %s to Database " , productid ) ;
}
}
// Close Database
//sqlite3_close(db);
}
}
/**
* Update Status Logfile
*/
2019-12-24 00:04:03 +07:00
void update_status ( )
2014-08-01 01:55:42 +07:00
{
// Open Logfile
2016-01-17 15:59:20 +01:00
FILE * log = File : : OpenCFile ( SERVER_STATUS_XMLOUT , " w " ) ;
2014-08-01 01:55:42 +07:00
// Opened Logfile
if ( log ! = NULL )
{
// Write XML Header
fprintf ( log , " <?xml version= \" 1.0 \" encoding= \" UTF-8 \" ?> \n " ) ;
// Write XSL Processor Information
fprintf ( log , " <?xml-stylesheet type= \" text/xsl \" href= \" status.xsl \" ?> \n " ) ;
// Output Root Tag + User Count
fprintf ( log , " <prometheus usercount= \" %u \" > \n " , _db_user_count ) ;
// Database Handle
//sqlite3 * db = NULL;
// Open Database
//if(sqlite3_open(SERVER_DATABASE, &db) == SQLITE_OK)
{
// Iterate Games
SceNetAdhocctlGameNode * game = _db_game ; for ( ; game ! = NULL ; game = game - > next )
{
// Safe Product ID
char productid [ PRODUCT_CODE_LENGTH + 1 ] ;
strncpy ( productid , game - > game . data , PRODUCT_CODE_LENGTH ) ;
productid [ PRODUCT_CODE_LENGTH ] = 0 ;
// Display Name
char displayname [ 128 ] ;
memset ( displayname , 0 , sizeof ( displayname ) ) ;
// SQL Statement
//const char * sql = "SELECT name FROM productids WHERE id=?;";
// Prepared SQL Statement
//sqlite3_stmt * statement = NULL;
// Prepare SQL Statement
/*if(sqlite3_prepare_v2(db, sql, strlen(sql) + 1, &statement, NULL) == SQLITE_OK)
{
// Bind SQL Statement Data
if ( sqlite3_bind_text ( statement , 1 , productid , strlen ( productid ) , SQLITE_STATIC ) = = SQLITE_OK )
{
// Found Matching Row
if ( sqlite3_step ( statement ) = = SQLITE_ROW )
{
// Fetch Game Name from Database
const char * gamename = ( const char * ) sqlite3_column_text ( statement , 0 ) ;
// Copy Game Name
strcpyxml ( displayname , gamename , sizeof ( displayname ) ) ;
}
// Game not in Database
else
{
// Use Product Code as Name
strcpyxml ( displayname , productid , sizeof ( displayname ) ) ;
}
}
// Destroy Prepared SQL Statement
sqlite3_finalize ( statement ) ;
} */
//db_productid *foundid = NULL;
bool found = false ;
for ( std : : vector < db_productid > : : iterator it = productids . begin ( ) ; it ! = productids . end ( ) ; it + + ) {
if ( IsMatch ( it - > id , productid ) ) {
// Copy Game Name
strcpyxml ( displayname , it - > name , sizeof ( displayname ) ) ;
found = true ;
break ;
}
}
if ( ! found ) {
// Use Product Code as Name
strcpyxml ( displayname , productid , sizeof ( displayname ) ) ;
}
// Output Game Tag + Game Name
fprintf ( log , " \t <game name= \" %s \" usercount= \" %u \" > \n " , displayname , game - > playercount ) ;
// Activate User Count
uint32_t activecount = 0 ;
// Iterate Game Groups
SceNetAdhocctlGroupNode * group = game - > group ; for ( ; group ! = NULL ; group = group - > next )
{
// Safe Group Name
char groupname [ ADHOCCTL_GROUPNAME_LEN + 1 ] ;
strncpy ( groupname , ( const char * ) group - > group . data , ADHOCCTL_GROUPNAME_LEN ) ;
groupname [ ADHOCCTL_GROUPNAME_LEN ] = 0 ;
// Output Group Tag + Group Name + User Count
fprintf ( log , " \t \t <group name= \" %s \" usercount= \" %u \" > \n " , strcpyxml ( displayname , groupname , sizeof ( displayname ) ) , group - > playercount ) ;
// Iterate Users
SceNetAdhocctlUserNode * user = group - > player ; for ( ; user ! = NULL ; user = user - > group_next )
{
// Output User Tag + Username
fprintf ( log , " \t \t \t <user>%s</user> \n " , strcpyxml ( displayname , ( const char * ) user - > resolver . name . data , sizeof ( displayname ) ) ) ;
}
// Output Closing Group Tag
fprintf ( log , " \t \t </group> \n " ) ;
// Increase Active Game User Count
activecount + = group - > playercount ;
}
// Output Idle Game Group
if ( game - > playercount > activecount )
{
// Output Group Tag + Group Name + Idle User Count
fprintf ( log , " \t \t <group name= \" Groupless \" usercount= \" %u \" /> \n " , game - > playercount - activecount ) ;
}
// Output Closing Game Tag
fprintf ( log , " \t </game> \n " ) ;
}
// Close Database
//sqlite3_close(db);
}
// Output Closing Root Tag
fprintf ( log , " </prometheus> " ) ;
// Close Logfile
fclose ( log ) ;
}
}
/**
* Escape XML Sequences to avoid malformed XML files .
* @ param out Out Buffer
* @ param in In Buffer
* @ param size Size of Out Buffer
* @ return Reference to Out Buffer
*/
const char * strcpyxml ( char * out , const char * in , uint32_t size )
{
// Valid Arguments
if ( out ! = NULL & & in ! = NULL & & size > 0 )
{
// Clear Memory
memset ( out , 0 , size ) ;
// Written Size Pointer
uint32_t written = 0 ;
// Iterate In-Buffer Symbols
uint32_t i = 0 ; for ( ; i < strlen ( in ) ; i + + )
{
// " Symbol
if ( in [ i ] = = ' " ' )
{
// Enough Space in Out-Buffer (6B for ")
if ( ( size - written ) > 6 )
{
// Write Escaped Sequence
strcpy ( out + written , " " " ) ;
// Move Pointer
written + = 6 ;
}
// Truncate required
else break ;
}
// < Symbol
else if ( in [ i ] = = ' < ' )
{
// Enough Space in Out-Buffer (4B for <)
if ( ( size - written ) > 4 )
{
// Write Escaped Sequence
strcpy ( out + written , " < " ) ;
// Move Pointer
written + = 4 ;
}
// Truncate required
else break ;
}
// > Symbol
else if ( in [ i ] = = ' > ' )
{
// Enough Space in Out-Buffer (4B for >)
if ( ( size - written ) > 4 )
{
// Write Escaped Sequence
strcpy ( out + written , " > " ) ;
// Move Pointer
written + = 4 ;
}
// Truncate required
else break ;
}
// & Symbol
else if ( in [ i ] = = ' & ' )
{
// Enough Space in Out-Buffer (5B for &)
if ( ( size - written ) > 5 )
{
// Write Escaped Sequence
strcpy ( out + written , " & " ) ;
// Move Pointer
written + = 5 ;
}
// Truncate required
else break ;
}
// Normal Character
else
{
// Enough Space in Out-Buffer (1B)
if ( ( size - written ) > 1 )
{
// Write Character
out [ written + + ] = in [ i ] ;
}
}
}
// Return Reference
return out ;
}
// Invalid Arguments
return NULL ;
}
/**
* Server Entry Point
* @ param argc Number of Arguments
* @ param argv Arguments
* @ return OS Error Code
*/
int proAdhocServerThread ( int port ) // (int argc, char * argv[])
{
2019-12-24 00:04:03 +07:00
setCurrentThreadName ( " AdhocServer " ) ;
2014-08-01 01:55:42 +07:00
// Result
int result = 0 ;
INFO_LOG ( SCENET , " AdhocServer: Begin of AdhocServer Thread " ) ;
// Create Signal Receiver for CTRL + C
//signal(SIGINT, interrupt);
// Create Signal Receiver for kill / killall
//signal(SIGTERM, interrupt);
// Create Listening Socket
int server = create_listen_socket ( port ) ; //SERVER_PORT
// Created Listening Socket
2020-01-18 02:32:09 +07:00
if ( server ! = SOCKET_ERROR )
2014-08-01 01:55:42 +07:00
{
// Notify User
INFO_LOG ( SCENET , " AdhocServer: Listening for Connections on TCP Port %u " , port ) ; //SERVER_PORT
2020-01-18 02:32:09 +07:00
// Port forward
2020-07-18 08:19:43 +07:00
UPnP_Add ( IP_PROTOCOL_TCP , port ) ; // g_PortManager.Add(IP_PROTOCOL_TCP, port);
2020-01-18 02:32:09 +07:00
2014-08-01 01:55:42 +07:00
// Enter Server Loop
result = server_loop ( server ) ;
2020-01-18 02:32:09 +07:00
// Remove Port mapping
2020-07-18 08:19:43 +07:00
UPnP_Remove ( IP_PROTOCOL_TCP , port ) ; // g_PortManager.Remove(IP_PROTOCOL_TCP, port);
2020-01-18 02:32:09 +07:00
2014-08-01 01:55:42 +07:00
// Notify User
INFO_LOG ( SCENET , " AdhocServer: Shutdown complete " ) ;
}
//_status = 0;
adhocServerRunning = false ;
INFO_LOG ( SCENET , " AdhocServer: End of AdhocServer Thread " ) ;
// Return Result
return result ;
}
/**
* Server Shutdown Request Handler
* @ param sig Captured Signal
*/
void interrupt ( int sig )
{
// Notify User
INFO_LOG ( SCENET , " AdhocServer: Shutting down... please wait " ) ;
// Trigger Shutdown
//_status = 0;
adhocServerRunning = false ;
}
/**
* Enable Address Reuse on Socket
* @ param fd Socket
*/
void enable_address_reuse ( int fd )
{
// Enable Port Reuse
2020-09-12 09:08:50 +07:00
setSockReuseAddrPort ( fd ) ;
2014-08-01 01:55:42 +07:00
}
2020-01-04 07:41:54 +07:00
/**
* Enable KeepAlive on Socket
* @ param fd Socket
*/
void enable_keepalive ( int fd )
{
// Enable Value
int on = 1 ;
// Enable Port Reuse
setsockopt ( fd , SOL_SOCKET , SO_KEEPALIVE , ( const char * ) & on , sizeof ( on ) ) ;
}
2020-01-18 02:32:09 +07:00
/**
* Change TCP Socket TCP_NODELAY ( Nagle Algo ) mode
* @ param fd Socket
* @ param nonblocking 1 for Nonblocking , 0 for Blocking
*/
void change_nodelay_mode ( int fd , int flag )
{
int opt = flag ;
setsockopt ( fd , IPPROTO_TCP , TCP_NODELAY , ( char * ) & opt , sizeof ( opt ) ) ;
}
2014-08-01 01:55:42 +07:00
/**
* Change Socket Blocking Mode
* @ param fd Socket
* @ param nonblocking 1 for Nonblocking , 0 for Blocking
*/
void change_blocking_mode ( int fd , int nonblocking )
{
unsigned long on = 1 ;
unsigned long off = 0 ;
2017-08-29 22:41:50 +02:00
# ifdef _WIN32
2014-08-01 01:55:42 +07:00
if ( nonblocking ) {
// Change to Non-Blocking Mode
ioctlsocket ( fd , FIONBIO , & on ) ;
}
else {
// Change to Blocking Mode
ioctlsocket ( fd , FIONBIO , & off ) ;
}
# else
// Change to Non-Blocking Mode
if ( nonblocking ) fcntl ( fd , F_SETFL , O_NONBLOCK ) ;
// Change to Blocking Mode
else
{
// Get Flags
int flags = fcntl ( fd , F_GETFL ) ;
// Remove Non-Blocking Flag
fcntl ( fd , F_SETFL , flags & ~ O_NONBLOCK ) ;
}
# endif
}
/**
* Create Port - Bound Listening Socket
* @ param port TCP Port
* @ return Socket Descriptor
*/
int create_listen_socket ( uint16_t port )
{
// Create Socket
int fd = ( int ) socket ( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
// Created Socket
if ( fd ! = - 1 )
{
2020-01-04 07:41:54 +07:00
// Enable KeepAlive
enable_keepalive ( fd ) ;
2014-08-01 01:55:42 +07:00
// Enable Address Reuse
enable_address_reuse ( fd ) ; // Shouldn't Reuse the port for built-in AdhocServer to prevent conflict with Dedicated AdhocServer
// Make Socket Nonblocking
change_blocking_mode ( fd , 1 ) ;
2020-01-18 02:32:09 +07:00
// Make TCP Socket send immediately
change_nodelay_mode ( fd , 1 ) ;
2014-08-01 01:55:42 +07:00
// Prepare Local Address Information
struct sockaddr_in local ;
memset ( & local , 0 , sizeof ( local ) ) ;
local . sin_family = AF_INET ;
local . sin_addr . s_addr = INADDR_ANY ;
local . sin_port = htons ( port ) ;
2019-11-10 06:23:19 +07:00
//Should only bind to specific IP for the 2nd or more instance of PPSSPP to prevent communication interference issue when sharing the same port. Doesn't work well when PPSSPP_ID reseted everytime emulation restarted.
/*
if ( PPSSPP_ID > 1 ) {
2020-08-17 23:08:35 -07:00
local . sin_addr = g_localhostIP . in . sin_addr ;
2019-11-10 06:23:19 +07:00
}
*/
2014-08-01 01:55:42 +07:00
// Bind Local Address to Socket
int bindresult = bind ( fd , ( struct sockaddr * ) & local , sizeof ( local ) ) ;
// Bound Local Address to Socket
2019-12-24 00:04:03 +07:00
if ( bindresult ! = SOCKET_ERROR )
2014-08-01 01:55:42 +07:00
{
// Switch Socket into Listening Mode
listen ( fd , SERVER_LISTEN_BACKLOG ) ;
// Return Socket
return fd ;
}
// Notify User
2019-12-24 00:04:03 +07:00
else {
ERROR_LOG ( SCENET , " AdhocServer: Bind returned %i (Socket error %d) " , bindresult , errno ) ;
2020-02-10 13:35:11 +07:00
auto n = GetI18NCategory ( " Networking " ) ;
2019-12-24 00:04:03 +07:00
host - > NotifyUserMessage ( std : : string ( n - > T ( " AdhocServer Failed to Bind Port " ) ) + " " + std : : to_string ( port ) , 3.0 , 0x0000ff ) ;
}
2014-08-01 01:55:42 +07:00
// Close Socket
closesocket ( fd ) ;
}
// Notify User
2014-08-11 23:06:09 +07:00
else ERROR_LOG ( SCENET , " AdhocServer: Socket returned %i (Socket error %d) " , fd, errno) ;
2014-08-01 01:55:42 +07:00
// Return Error
return - 1 ;
}
/**
* Server Main Loop
* @ param server Server Listening Socket
* @ return OS Error Code
*/
int server_loop ( int server )
{
// Set Running Status
//_status = 1;
adhocServerRunning = true ;
// Create Empty Status Logfile
update_status ( ) ;
// Handling Loop
while ( adhocServerRunning ) //(_status == 1)
{
// Login Block
{
// Login Result
int loginresult = 0 ;
// Login Processing Loop
do
{
// Prepare Address Structure
struct sockaddr_in addr ;
socklen_t addrlen = sizeof ( addr ) ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
// Accept Login Requests
// loginresult = accept4(server, (struct sockaddr *)&addr, &addrlen, SOCK_NONBLOCK);
// Alternative Accept Approach (some Linux Kernel don't support the accept4 Syscall... wtf?)
loginresult = accept ( server , ( struct sockaddr * ) & addr , & addrlen ) ;
if ( loginresult ! = - 1 )
{
// Switch Socket into Non-Blocking Mode
change_blocking_mode ( loginresult , 1 ) ;
}
// Login User (Stream)
if ( loginresult ! = - 1 ) {
u32_le sip = addr . sin_addr . s_addr ;
2019-11-10 06:23:19 +07:00
/* // Replacing 127.0.0.x with Ethernet IP will cause issue with multiple-instance of localhost (127.0.0.x)
2014-08-01 01:55:42 +07:00
if ( sip = = 0x0100007f ) { //127.0.0.1 should be replaced with LAN/WAN IP whenever available
char str [ 100 ] ;
gethostname ( str , 100 ) ;
u8 * pip = ( u8 * ) & sip ;
if ( gethostbyname ( str ) - > h_addrtype = = AF_INET & & gethostbyname ( str ) - > h_addr_list [ 0 ] ! = NULL ) pip = ( u8 * ) gethostbyname ( str ) - > h_addr_list [ 0 ] ;
sip = * ( u32_le * ) pip ;
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: Replacing IP %s with %s " , inet_ntoa ( addr . sin_addr ) , inet_ntoa ( * ( in_addr * ) & pip ) ) ;
2014-08-01 01:55:42 +07:00
}
2019-11-10 06:23:19 +07:00
*/
2014-08-01 01:55:42 +07:00
login_user_stream ( loginresult , sip ) ;
}
} while ( loginresult ! = - 1 ) ;
}
// Receive Data from Users
SceNetAdhocctlUserNode * user = _db_user ;
while ( user ! = NULL )
{
// Next User (for safe delete)
SceNetAdhocctlUserNode * next = user - > next ;
// Receive Data from User
2020-09-07 02:38:45 +07:00
int recvresult = recv ( user - > stream , ( char * ) user - > rx + user - > rxpos , sizeof ( user - > rx ) - user - > rxpos , MSG_NOSIGNAL ) ;
2014-08-01 01:55:42 +07:00
// Connection Closed or Timed Out
if ( recvresult = = 0 | | ( recvresult = = - 1 & & errno ! = EAGAIN & & errno ! = EWOULDBLOCK ) | | get_user_state ( user ) = = USER_STATE_TIMED_OUT )
{
// Logout User
logout_user ( user ) ;
}
// Received Data (or leftovers in RX-Buffer)
else if ( recvresult > 0 | | user - > rxpos > 0 )
{
// New Incoming Data
if ( recvresult > 0 )
{
// Move RX Pointer
user - > rxpos + = recvresult ;
// Update Death Clock
user - > last_recv = time ( NULL ) ;
}
// Waiting for Login Packet
if ( get_user_state ( user ) = = USER_STATE_WAITING )
{
// Valid Opcode
if ( user - > rx [ 0 ] = = OPCODE_LOGIN )
{
// Enough Data available
if ( user - > rxpos > = sizeof ( SceNetAdhocctlLoginPacketC2S ) )
{
// Clone Packet
SceNetAdhocctlLoginPacketC2S packet = * ( SceNetAdhocctlLoginPacketC2S * ) user - > rx ;
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , sizeof ( SceNetAdhocctlLoginPacketC2S ) ) ;
// Login User (Data)
login_user_data ( user , & packet ) ;
}
}
// Invalid Opcode
else
{
// Notify User
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: Invalid Opcode 0x%02X in Waiting State from %s " , user - > rx [ 0 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) ) ;
2014-08-01 01:55:42 +07:00
// Logout User
logout_user ( user ) ;
}
}
// Logged-In User
else if ( get_user_state ( user ) = = USER_STATE_LOGGED_IN )
{
// Ping Packet
if ( user - > rx [ 0 ] = = OPCODE_PING )
{
// Delete Packet from RX Buffer
clear_user_rxbuf ( user , 1 ) ;
}
// Group Connect Packet
else if ( user - > rx [ 0 ] = = OPCODE_CONNECT )
{
// Enough Data available
if ( user - > rxpos > = sizeof ( SceNetAdhocctlConnectPacketC2S ) )
{
// Cast Packet
SceNetAdhocctlConnectPacketC2S * packet = ( SceNetAdhocctlConnectPacketC2S * ) user - > rx ;
// Clone Group Name
SceNetAdhocctlGroupName group = packet - > group ;
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , sizeof ( SceNetAdhocctlConnectPacketC2S ) ) ;
// Change Game Group
connect_user ( user , & group ) ;
}
}
// Group Disconnect Packet
else if ( user - > rx [ 0 ] = = OPCODE_DISCONNECT )
{
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , 1 ) ;
// Leave Game Group
disconnect_user ( user ) ;
}
// Network Scan Packet
else if ( user - > rx [ 0 ] = = OPCODE_SCAN )
{
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , 1 ) ;
// Send Network List
send_scan_results ( user ) ;
}
// Chat Text Packet
else if ( user - > rx [ 0 ] = = OPCODE_CHAT )
{
// Enough Data available
if ( user - > rxpos > = sizeof ( SceNetAdhocctlChatPacketC2S ) )
{
// Cast Packet
SceNetAdhocctlChatPacketC2S * packet = ( SceNetAdhocctlChatPacketC2S * ) user - > rx ;
// Clone Buffer for Message
char message [ 64 ] ;
memset ( message , 0 , sizeof ( message ) ) ;
strncpy ( message , packet - > message , sizeof ( message ) - 1 ) ;
// Remove Packet from RX Buffer
clear_user_rxbuf ( user , sizeof ( SceNetAdhocctlChatPacketC2S ) ) ;
// Spread Chat Message
spread_message ( user , message ) ;
}
}
// Invalid Opcode
else
{
// Notify User
2019-12-24 00:04:03 +07:00
WARN_LOG ( SCENET , " AdhocServer: Invalid Opcode 0x%02X in Logged-In State from %s (MAC: %02x:%02x:%02x:%02x:%02x:%02x - IP: %s) " , user - > rx [ 0 ] , ( char * ) user - > resolver . name . data , user - > resolver . mac . data [ 0 ] , user - > resolver . mac . data [ 1 ] , user - > resolver . mac . data [ 2 ] , user - > resolver . mac . data [ 3 ] , user - > resolver . mac . data [ 4 ] , user - > resolver . mac . data [ 5 ] , inet_ntoa ( * ( in_addr * ) & user - > resolver . ip ) ) ;
2014-08-01 01:55:42 +07:00
// Logout User
logout_user ( user ) ;
}
}
}
// Move Pointer
user = next ;
}
// Prevent needless CPU Overload (1ms Sleep)
2020-09-11 13:24:45 +07:00
sleep_ms ( 10 ) ;
2014-08-01 01:55:42 +07:00
// Don't do anything if it's paused, otherwise the log will be flooded
2020-09-11 13:24:45 +07:00
while ( adhocServerRunning & & Core_IsStepping ( ) & & coreState ! = CORE_POWERDOWN ) sleep_ms ( 10 ) ;
2014-08-01 01:55:42 +07:00
}
// Free User Database Memory
free_database ( ) ;
// Close Server Socket
closesocket ( server ) ;
// Return Success
return 0 ;
}