/*
* PtokaX - hub server for Direct Connect peer to peer network.
* Copyright (C) 2002-2005 Ptaczek, Ptaczek at PtokaX dot org
* Copyright (C) 2004-2022 Petr Kozelka, PPK at PtokaX dot org
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3
* as published by the Free Software Foundation.
* 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 for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
#include "stdinc.h"
//---------------------------------------------------------------------------
#include "ServerManager.h"
//---------------------------------------------------------------------------
#include "colUsers.h"
#include "DcCommands.h"
#include "eventqueue.h"
#include "GlobalDataQueue.h"
#include "hashBanManager.h"
#include "hashUsrManager.h"
#include "hashRegManager.h"
#include "LanguageManager.h"
#include "LuaScriptManager.h"
#include "ProfileManager.h"
#include "serviceLoop.h"
#include "SettingManager.h"
#include "UdpDebug.h"
#include "utility.h"
#include "ZlibUtility.h"
//---------------------------------------------------------------------------
#ifdef _WIN32
#pragma hdrstop
#endif
//---------------------------------------------------------------------------
#include "HubCommands.h"
#include "IP2Country.h"
#include "LuaScript.h"
#include "RegThread.h"
#include "ResNickManager.h"
#include "ServerThread.h"
#include "TextConverter.h"
#include "TextFileManager.h"
//#include "TLSManager.h"
#include "UDPThread.h"
//---------------------------------------------------------------------------
#ifdef _BUILD_GUI
#include "../gui.win/MainWindow.h"
#include "../gui.win/MainWindowPageScripts.h"
#endif
//---------------------------------------------------------------------------
#ifdef _WITH_SQLITE
#include "DB-SQLite.h"
#elif _WITH_POSTGRES
#include "DB-PostgreSQL.h"
#elif _WITH_MYSQL
#include "DB-MySQL.h"
#endif
//---------------------------------------------------------------------------
static ServerThread * m_pServersE = nullptr;
#ifdef _BUILD_GUI
HWND ServerManager::m_hMainWindow;
#endif
//---------------------------------------------------------------------------
#ifdef _WIN32
#ifndef _WIN_IOT
UINT_PTR ServerManager::m_upSecTimer = 0;
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
UINT_PTR ServerManager::m_upRegTimer = 0;
#endif
#endif
HANDLE ServerManager::m_hConsole = nullptr;
string ServerManager::m_sLuaPath, ServerManager::m_sOS;
#endif
#ifdef __MACH__
clock_serv_t ServerManager::m_csMachClock;
#endif
string ServerManager::m_sPath, ServerManager::m_sScriptPath;
size_t ServerManager::m_szGlobalBufferSize = 0;
char * ServerManager::m_pGlobalBuffer = NULL;
bool ServerManager::m_bCmdAutoStart = false, ServerManager::m_bCmdNoAutoStart = false, ServerManager::m_bCmdNoTray = false, ServerManager::m_bUseIPv4 = true,
ServerManager::m_bUseIPv6 = true, ServerManager::m_bIPv6DualStack = false;
#ifdef FLYLINKDC_USE_CPU_STAT
double ServerManager::m_dCpuUsages[60];
double ServerManager::m_dCpuUsage = 0;
#endif
uint64_t ServerManager::m_ui64ActualTick = 0, ServerManager::m_ui64TotalShare = 0;
uint64_t ServerManager::m_ui64BytesRead = 0, ServerManager::m_ui64BytesSent = 0, ServerManager::m_ui64BytesSentSaved = 0;
uint64_t ServerManager::m_ui64LastBytesRead = 0, ServerManager::m_ui64LastBytesSent = 0;
uint64_t ServerManager::m_ui64Mins = 0, ServerManager::m_ui64Hours = 0, ServerManager::m_ui64Days = 0;
#ifndef _WIN32
uint32_t ServerManager::m_ui32CpuCount = 0;
#endif
uint32_t ServerManager::m_ui32UploadSpeed[60], ServerManager::m_ui32DownloadSpeed[60];
uint32_t ServerManager::m_ui32Joins = 0, ServerManager::m_ui32Parts = 0, ServerManager::m_ui32Logged = 0, ServerManager::m_ui32Peak = 0;
uint32_t ServerManager::m_ui32ActualBytesRead = 0, ServerManager::m_ui32ActualBytesSent = 0;
uint32_t ServerManager::m_ui32AverageBytesRead = 0, ServerManager::m_ui32AverageBytesSent = 0;
ServerThread * ServerManager::m_pServersS = NULL;
time_t ServerManager::m_tStartTime = 0;
bool ServerManager::m_bServerRunning = false, ServerManager::m_bServerTerminated = false, ServerManager::m_bIsRestart = false, ServerManager::m_bIsClose = false;
#ifdef _WIN32
#ifndef _BUILD_GUI
bool ServerManager::m_bService = false;
#else
HINSTANCE ServerManager::m_hInstance;
HWND ServerManager::m_hWndActiveDialog;
#endif
#else
bool ServerManager::m_bDaemon = false;
#endif
char ServerManager::m_sHubIP[16], ServerManager::m_sHubIP6[40];
uint8_t ServerManager::m_ui8SrCntr = 0, ServerManager::m_ui8MinTick = 0;
//---------------------------------------------------------------------------
void ServerManager::OnSecTimer()
{
#ifdef FLYLINKDC_USE_CPU_STAT
#ifdef _WIN32
FILETIME tmpa, tmpb, kernelTimeFT, userTimeFT;
GetProcessTimes(GetCurrentProcess(), &tmpa, &tmpb, &kernelTimeFT, &userTimeFT);
int64_t kernelTime = kernelTimeFT.dwLowDateTime | (((int64_t)kernelTimeFT.dwHighDateTime) << 32);
int64_t userTime = userTimeFT.dwLowDateTime | (((int64_t)userTimeFT.dwHighDateTime) << 32);
double dcpuSec = double(kernelTime + userTime) / double(10000000I64);
m_dCpuUsage = dcpuSec - m_dCpuUsages[m_ui8MinTick];
m_dCpuUsages[m_ui8MinTick] = dcpuSec;
#else
struct rusage rs;
getrusage(RUSAGE_SELF, &rs);
double dcpuSec = double(rs.ru_utime.tv_sec) + (double(rs.ru_utime.tv_usec) / 1000000) +
double(rs.ru_stime.tv_sec) + (double(rs.ru_stime.tv_usec) / 1000000);
m_dCpuUsage = dcpuSec - m_dCpuUsages[m_ui8MinTick];
m_dCpuUsages[m_ui8MinTick] = dcpuSec;
#endif
#endif
if (++m_ui8MinTick == 60)
{
m_ui8MinTick = 0;
}
#ifdef _WIN32
if (m_bServerRunning == false)
{
return;
}
#endif
m_ui64ActualTick++;
m_ui32ActualBytesRead = (uint32_t)(m_ui64BytesRead - m_ui64LastBytesRead);
m_ui32ActualBytesSent = (uint32_t)(m_ui64BytesSent - m_ui64LastBytesSent);
m_ui64LastBytesRead = m_ui64BytesRead;
m_ui64LastBytesSent = m_ui64BytesSent;
m_ui32AverageBytesSent -= m_ui32UploadSpeed[m_ui8MinTick];
m_ui32AverageBytesRead -= m_ui32DownloadSpeed[m_ui8MinTick];
m_ui32UploadSpeed[m_ui8MinTick] = m_ui32ActualBytesSent;
m_ui32DownloadSpeed[m_ui8MinTick] = m_ui32ActualBytesRead;
m_ui32AverageBytesSent += m_ui32UploadSpeed[m_ui8MinTick];
m_ui32AverageBytesRead += m_ui32DownloadSpeed[m_ui8MinTick];
#ifdef _BUILD_GUI
MainWindow::m_Ptr->UpdateStats();
MainWindowPageScripts::m_Ptr->UpdateMemUsage();
#endif
}
//---------------------------------------------------------------------------
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
void ServerManager::m_OnRegTimer()
{
if (SettingManager::m_Ptr->m_bBools[SETBOOL_AUTO_REG] == true && SettingManager::m_Ptr->m_sTexts[SETTXT_REGISTER_SERVERS] != NULL)
{
// First destroy old hublist reg thread if any
if (RegisterThread::m_Ptr != NULL)
{
RegisterThread::m_Ptr->Close();
RegisterThread::m_Ptr->WaitFor();
safe_delete(RegisterThread::m_Ptr);
}
// Create hublist reg thread
RegisterThread::m_Ptr = new (std::nothrow) RegisterThread();
if (RegisterThread::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate RegisterThread::m_Ptr in ServerOnRegTimer\n");
return;
}
// Setup hublist reg thread
RegisterThread::m_Ptr->Setup(SettingManager::m_Ptr->m_sTexts[SETTXT_REGISTER_SERVERS], SettingManager::m_Ptr->m_ui16TextsLens[SETTXT_REGISTER_SERVERS]);
// Start the hublist reg thread
RegisterThread::m_Ptr->Resume();
}
}
#endif // #ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
//---------------------------------------------------------------------------
void ServerManager::Initialize()
{
setlocale(LC_ALL, "");
time_t acctime;
time(&acctime);
#ifdef _WIN32
srand((uint32_t)acctime);
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
if (DirExist((ServerManager::m_sPath + "\\cfg").c_str()) == false)
{
CreateDirectory((ServerManager::m_sPath + "\\cfg").c_str(), NULL);
}
if (DirExist((ServerManager::m_sPath + "\\logs").c_str()) == false)
{
CreateDirectory((ServerManager::m_sPath + "\\logs").c_str(), NULL);
}
if (DirExist((ServerManager::m_sPath + "\\scripts").c_str()) == false)
{
CreateDirectory((ServerManager::m_sPath + "\\scripts").c_str(), NULL);
}
if (DirExist((ServerManager::m_sPath + "\\texts").c_str()) == false)
{
CreateDirectory((ServerManager::m_sPath + "\\texts").c_str(), NULL);
}
ServerManager::m_sScriptPath = ServerManager::m_sPath + "\\scripts\\";
ServerManager::m_sLuaPath = ServerManager::m_sPath + "/";
char * sTempLuaPath = (char *)ServerManager::m_sLuaPath.c_str();
for (size_t szi = 0; szi < ServerManager::m_sPath.size(); szi++)
{
if (sTempLuaPath[szi] == '\\')
{
sTempLuaPath[szi] = '/';
}
}
SetupOsVersion();
#else
srandom(acctime);
if (DirExist((ServerManager::m_sPath + "/logs").c_str()) == false)
{
if (mkdir((ServerManager::m_sPath + "/logs").c_str(), 0755) == -1)
{
if (m_bDaemon == true)
{
syslog(LOG_USER | LOG_ERR, "Creating of logs directory failed!\n");
}
else
{
printf("Creating of logs directory failed!");
}
}
}
if (DirExist((ServerManager::m_sPath + "/cfg").c_str()) == false)
{
if (mkdir((ServerManager::m_sPath + "/cfg").c_str(), 0755) == -1)
{
AppendLog("Creating of cfg directory failed!");
}
}
if (DirExist((ServerManager::m_sPath + "/scripts").c_str()) == false)
{
if (mkdir((ServerManager::m_sPath + "/scripts").c_str(), 0755) == -1)
{
AppendLog("Creating of scripts directory failed!");
}
}
if (DirExist((ServerManager::m_sPath + "/texts").c_str()) == false)
{
if (mkdir((ServerManager::m_sPath + "/texts").c_str(), 0755) == -1)
{
AppendLog("Creating of texts directory failed!");
}
}
ServerManager::m_sScriptPath = ServerManager::m_sPath + "/scripts/";
// get cpu count
FILE *fp = fopen("/proc/cpuinfo", "r");
if (fp != NULL)
{
char buf[1024];
while (fgets(buf, 1024, fp) != NULL)
{
if (strncasecmp(buf, "model name", 10) == 0 || strncmp(buf, "Processor", 9) == 0 || strncmp(buf, "cpu model", 9) == 0)
{
m_ui32CpuCount++;
}
}
fclose(fp);
}
if (m_ui32CpuCount == 0)
{
m_ui32CpuCount = 1;
}
#endif
CreateGlobalBuffer();
CheckForIPv6();
#ifdef __MACH__
mach_port_t mpMachHost = mach_host_self();
host_get_clock_service(mpMachHost, SYSTEM_CLOCK, &ServerManager::m_csMachClock);
mach_port_deallocate(mach_task_self(), mpMachHost);
#endif
ReservedNicksManager::m_Ptr = new (std::nothrow) ReservedNicksManager();
if (ReservedNicksManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate ReservedNicksManager::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
m_ui64ActualTick = m_ui64TotalShare = 0;
m_ui64BytesRead = m_ui64BytesSent = m_ui64BytesSentSaved = 0;
m_ui32ActualBytesRead = m_ui32ActualBytesSent = m_ui32AverageBytesRead = m_ui32AverageBytesSent = 0;
m_ui32Joins = m_ui32Parts = m_ui32Logged = m_ui32Peak = 0;
m_pServersS = NULL;
m_pServersE = NULL;
m_tStartTime = 0;
m_ui64Mins = m_ui64Hours = m_ui64Days = 0;
m_bServerRunning = m_bIsRestart = m_bIsClose = false;
m_sHubIP[0] = '\0';
m_sHubIP6[0] = '\0';
m_ui8SrCntr = 0;
ZlibUtility::m_Ptr = new (std::nothrow) ZlibUtility();
if (ZlibUtility::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate ZlibUtility::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
m_ui8MinTick = 0;
m_ui64LastBytesRead = m_ui64LastBytesSent = 0;
for (uint8_t ui8i = 0 ; ui8i < 60; ui8i++)
{
#ifdef FLYLINKDC_USE_CPU_STAT
m_dCpuUsages[ui8i] = 0;
#endif
m_ui32UploadSpeed[ui8i] = 0;
m_ui32DownloadSpeed[ui8i] = 0;
}
#ifdef FLYLINKDC_USE_CPU_STAT
m_dCpuUsage = 0.0;
#endif
SettingManager::m_Ptr = new (std::nothrow) SettingManager();
if (SettingManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate SettingManager::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
#ifdef FLYLINKDC_USE_DB
#if defined(_WITH_SQLITE)
TextConverter::m_Ptr = new (std::nothrow) TextConverter();
if (TextConverter::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate TextConverter::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
#endif
#endif
LanguageManager::m_Ptr = new (std::nothrow) LanguageManager();
if (LanguageManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate LanguageManager::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
LanguageManager::m_Ptr->Load();
ProfileManager::m_Ptr = new (std::nothrow) ProfileManager();
if (ProfileManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate ProfileManager::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
RegManager::m_Ptr = new (std::nothrow) RegManager();
if (RegManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate RegManager::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
// Load registered users
RegManager::m_Ptr->Load();
BanManager::m_Ptr = new (std::nothrow) BanManager();
if (BanManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate BanManager::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
// load banlist
BanManager::m_Ptr->Load();
TextFilesManager::m_Ptr = new (std::nothrow) TextFilesManager();
if (TextFilesManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate TextFilesManager::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
UdpDebug::m_Ptr = new (std::nothrow) UdpDebug();
if (UdpDebug::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate UdpDebug::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
ScriptManager::m_Ptr = new (std::nothrow) ScriptManager();
if (ScriptManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate ScriptManager::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
#ifdef _BUILD_GUI
MainWindow::m_Ptr = new (std::nothrow) MainWindow();
if (MainWindow::m_Ptr == NULL || MainWindow::m_Ptr->CreateEx() == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate MainWindow::m_Ptr in ServerInitialize\n");
exit(EXIT_FAILURE);
}
m_hMainWindow = MainWindow::m_Ptr->m_hWnd;
#endif
SettingManager::m_Ptr->UpdateAll();
#if defined(_WIN32) && !defined(_WIN_IOT)
m_upSecTimer = SetTimer(NULL, 0, 1000, NULL);
if (m_upSecTimer == 0)
{
AppendDebugLog("%s - [ERR] Cannot startsectimer in ServerInitialize\n");
exit(EXIT_FAILURE);
}
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
m_upRegTimer = 0;
#endif
#endif
}
//---------------------------------------------------------------------------
bool ServerManager::Start()
{
time(&m_tStartTime);
SettingManager::m_Ptr->UpdateAll();
TextFilesManager::m_Ptr->RefreshTextFiles();
#ifdef _BUILD_GUI
MainWindow::m_Ptr->EnableStartButton(FALSE);
#endif
m_ui64ActualTick = m_ui64TotalShare = 0;
m_ui64BytesRead = m_ui64BytesSent = m_ui64BytesSentSaved = 0;
m_ui32ActualBytesRead = m_ui32ActualBytesSent = m_ui32AverageBytesRead = m_ui32AverageBytesSent = 0;
m_ui32Joins = m_ui32Parts = m_ui32Logged = m_ui32Peak = 0;
m_ui64Mins = m_ui64Hours = m_ui64Days = 0;
m_ui8SrCntr = 0;
m_sHubIP[0] = '\0';
m_sHubIP6[0] = '\0';
#ifdef _BUILD_GUI
if (ResolveHubAddress() == false)
{
MainWindow::m_Ptr->EnableStartButton(TRUE);
return false;
}
#else
ResolveHubAddress();
#endif
for (uint8_t ui8i = 0; ui8i < 25; ui8i++)
{
if (SettingManager::m_Ptr->m_ui16PortNumbers[ui8i] == 0)
{
break;
}
if(m_bUseIPv6 == false)
{
CreateServerThread(AF_INET, SettingManager::m_Ptr->m_ui16PortNumbers[ui8i]);
continue;
}
CreateServerThread(AF_INET6, SettingManager::m_Ptr->m_ui16PortNumbers[ui8i]);
if(SettingManager::m_Ptr->m_bBools[SETBOOL_BIND_ONLY_SINGLE_IP] == true || m_bIPv6DualStack == false)
{
CreateServerThread(AF_INET, SettingManager::m_Ptr->m_ui16PortNumbers[ui8i]);
}
}
if (m_pServersS == NULL)
{
#ifdef _BUILD_GUI
::MessageBox(MainWindow::m_Ptr->m_hWnd, LanguageManager::m_Ptr->m_sTexts[LAN_NO_VALID_TCP_PORT_SPECIFIED], LanguageManager::m_Ptr->m_sTexts[LAN_ERROR], MB_OK | MB_ICONERROR);
MainWindow::m_Ptr->EnableStartButton(TRUE);
#else
AppendLog(LanguageManager::m_Ptr->m_sTexts[LAN_NO_VALID_TCP_PORT_SPECIFIED]);
#endif
return false;
}
AppendLog("Serving started");
// if(tlsenabled == true) {
/* TLSManager = new (std::nothrow) TLSMan();
if(TLSManager == NULL) {
AppendDebugLog("%s - [MEM] Cannot allocate TLSManager in ServerStart\n", 0);
exit(EXIT_FAILURE);
}*/
// }
#ifdef FLYLINKDC_USE_DB
#ifdef _WITH_SQLITE
DBSQLite::m_Ptr = new (std::nothrow) DBSQLite();
if (DBSQLite::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate DBSQLite::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
#elif _WITH_POSTGRES
DBPostgreSQL::m_Ptr = new (std::nothrow) DBPostgreSQL();
if (DBPostgreSQL::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate DBPostgreSQL::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
#elif _WITH_MYSQL
DBMySQL::m_Ptr = new (std::nothrow) DBMySQL();
if (DBMySQL::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate DBMySQL::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
#endif
#endif // FLYLINKDC_USE_DB
IpP2Country::m_Ptr = new (std::nothrow) IpP2Country();
if (IpP2Country::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate IpP2Country::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
EventQueue::m_Ptr = new (std::nothrow) EventQueue();
if (EventQueue::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate EventQueue::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
HashManager::m_Ptr = new (std::nothrow) HashManager();
if (HashManager::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate HashManager::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
Users::m_Ptr = new (std::nothrow) Users();
if (Users::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate Users::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
GlobalDataQueue::m_Ptr = new (std::nothrow) GlobalDataQueue();
if (GlobalDataQueue::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate GlobalDataQueue::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
DcCommands::m_Ptr = new (std::nothrow) DcCommands();
if (DcCommands::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate DcCommands::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
// add botname to reserved nicks
ReservedNicksManager::m_Ptr->AddReservedNick(SettingManager::m_Ptr->m_sTexts[SETTXT_BOT_NICK]);
SettingManager::m_Ptr->UpdateBot();
// add opchat botname to reserved nicks
ReservedNicksManager::m_Ptr->AddReservedNick(SettingManager::m_Ptr->m_sTexts[SETTXT_OP_CHAT_NICK]);
SettingManager::m_Ptr->UpdateOpChat();
ReservedNicksManager::m_Ptr->AddReservedNick(SettingManager::m_Ptr->m_sTexts[SETTXT_ADMIN_NICK]);
#ifdef FLYLINKDC_USE_UDP_THREAD
if ((uint16_t)atoi(SettingManager::m_Ptr->m_sTexts[SETTXT_UDP_PORT]) != 0)
{
if(m_bUseIPv6 == false)
{
UDPThread::m_PtrIPv6 = UDPThread::Create(AF_INET);
}
else
{
UDPThread::m_PtrIPv6 = UDPThread::Create(AF_INET6);
if(SettingManager::m_Ptr->m_bBools[SETBOOL_BIND_ONLY_SINGLE_IP] == true || m_bIPv6DualStack == false)
{
UDPThread::m_PtrIPv6 = UDPThread::Create(AF_INET);
}
}
}
#endif
if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_SCRIPTING] == true)
{
ScriptManager::m_Ptr->Start();
}
ServiceLoop::m_Ptr = new (std::nothrow) ServiceLoop();
if (ServiceLoop::m_Ptr == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate ServiceLoop::m_Ptr in ServerStart\n");
exit(EXIT_FAILURE);
}
// Start the server socket threads
ServerThread * cur = NULL,
* next = m_pServersS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
cur->Resume();
}
m_bServerRunning = true;
// Call lua_Main
ScriptManager::m_Ptr->OnStartup();
#ifdef _BUILD_GUI
MainWindow::m_Ptr->SetStatusValue((string(LanguageManager::m_Ptr->m_sTexts[LAN_RUNNING], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_RUNNING]) + "...").c_str());
MainWindow::m_Ptr->SetStartButtonText(LanguageManager::m_Ptr->m_sTexts[LAN_STOP_HUB]);
MainWindow::m_Ptr->EnableStartButton(TRUE);
MainWindow::m_Ptr->EnableGuiItems(TRUE);
#endif
#if defined(_WIN32) && !defined(_WIN_IOT)
//Start the HubRegistration timer
if (SettingManager::m_Ptr->m_bBools[SETBOOL_AUTO_REG] == true)
{
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
m_upRegTimer = SetTimer(NULL, 0, 901000, NULL);
if (m_upRegTimer == 0)
{
AppendDebugLog("%s - [ERR] Cannot start regtimer in ServerStart\n");
exit(EXIT_FAILURE);
}
#endif
}
if (::SetEvent(ServiceLoop::m_Ptr->m_hLoopEvents[0]) == 0)
{
AppendDebugLog("%s - [ERR] Cannot set m_hLoopEvent in ServerManager::Start\n");
exit(EXIT_FAILURE);
}
#endif
return true;
}
//---------------------------------------------------------------------------
void ServerManager::Stop()
{
#ifdef _BUILD_GUI
MainWindow::m_Ptr->EnableStartButton(FALSE);
#endif
int iRet = snprintf(m_pGlobalBuffer, m_szGlobalBufferSize, "Serving stopped (UL: %" PRIu64 " [%" PRIu64 "], DL: %" PRIu64 ")", m_ui64BytesSent, m_ui64BytesSentSaved, m_ui64BytesRead);
if (iRet > 0)
{
AppendLog(m_pGlobalBuffer);
}
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
#if defined(_WIN32) && !defined(_WIN_IOT)
//Stop the HubRegistration timer
if (SettingManager::m_Ptr->m_bBools[SETBOOL_AUTO_REG] == true)
{
if (KillTimer(NULL, m_upRegTimer) == 0)
{
AppendDebugLog("%s - [ERR] Cannot stop regtimer in ServerStop\n");
exit(EXIT_FAILURE);
}
}
#endif
#endif
ServerThread * cur = NULL,
* next = m_pServersS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
cur->Close();
cur->WaitFor();
delete cur;
}
m_pServersS = nullptr;
m_pServersE = nullptr;
// stop the main hub loop
if (ServiceLoop::m_Ptr != NULL)
{
m_bServerTerminated = true;
}
else
{
FinalStop(false);
}
}
//---------------------------------------------------------------------------
void ServerManager::FinalStop(const bool bDeleteServiceLoop)
{
if (bDeleteServiceLoop == true)
{
safe_delete(ServiceLoop::m_Ptr);
}
if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_SCRIPTING] == true)
{
ScriptManager::m_Ptr->Stop();
}
#ifdef FLYLINKDC_USE_UDP_THREAD
#ifdef FLYLINKDC_USE_UDP_THREAD_IP6
UDPThread::Destroy(UDPThread::m_PtrIPv6);
#endif
UDPThread::Destroy(UDPThread::m_PtrIPv4);
#endif
// delete userlist field
if (Users::m_Ptr != NULL)
{
Users::m_Ptr->DisconnectAll();
safe_delete(Users::m_Ptr);
}
safe_delete(DcCommands::m_Ptr);
// delete hashed userlist manager
safe_delete(HashManager::m_Ptr);
safe_delete(GlobalDataQueue::m_Ptr);
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
if (RegisterThread::m_Ptr != NULL)
{
RegisterThread::m_Ptr->Close();
RegisterThread::m_Ptr->WaitFor();
safe_delete(RegisterThread::m_Ptr);
}
#endif
safe_delete(EventQueue::m_Ptr);
safe_delete(IpP2Country::m_Ptr);
#ifdef FLYLINKDC_USE_DB
#ifdef _WITH_SQLITE
safe_delete(DBSQLite::m_Ptr);
#elif _WITH_POSTGRES
safe_delete(DBPostgreSQL::m_Ptr);
#elif _WITH_MYSQL
safe_delete(DBMySQL::m_Ptr);
#endif
#endif // FLYLINKDC_USE_DB
/* if(TLSManager != NULL) {
safe_delete(TLSManager);
}*/
//userstat // better here ;)
// sqldb->FinalizeAllVisits();
#ifdef _BUILD_GUI
MainWindow::m_Ptr->SetStatusValue((string(LanguageManager::m_Ptr->m_sTexts[LAN_STOPPED], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_STOPPED]) + ".").c_str());
MainWindow::m_Ptr->SetStartButtonText(LanguageManager::m_Ptr->m_sTexts[LAN_START_HUB]);
MainWindow::m_Ptr->EnableStartButton(TRUE);
MainWindow::m_Ptr->EnableGuiItems(FALSE);
#endif
m_ui8SrCntr = 0;
m_ui32Joins = m_ui32Parts = m_ui32Logged = 0;
UdpDebug::m_Ptr->Cleanup();
m_bServerRunning = false;
if (m_bIsRestart == true)
{
m_bIsRestart = false;
// start hub
#ifdef _BUILD_GUI
if (Start() == false)
{
MainWindow::m_Ptr->SetStatusValue((string(LanguageManager::m_Ptr->m_sTexts[LAN_READY], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_READY]) + ".").c_str());
}
#else
if (Start() == false)
{
AppendLog("[ERR] Server start failed in ServerFinalStop");
exit(EXIT_FAILURE);
}
#endif
}
else if (m_bIsClose == true)
{
FinalClose();
}
}
//---------------------------------------------------------------------------
void ServerManager::FinalClose()
{
#if defined(_WIN32) && !defined(_WIN_IOT)
KillTimer(NULL, m_upSecTimer);
#endif
BanManager::m_Ptr->Save(true);
ProfileManager::m_Ptr->SaveProfiles();
RegManager::m_Ptr->Save();
ScriptManager::m_Ptr->SaveScripts();
SettingManager::m_Ptr->Save();
safe_delete(ScriptManager::m_Ptr);
safe_delete(TextFilesManager::m_Ptr);
safe_delete(ProfileManager::m_Ptr);
safe_delete(UdpDebug::m_Ptr);
safe_delete(RegManager::m_Ptr);
safe_delete(BanManager::m_Ptr);
safe_delete(ZlibUtility::m_Ptr);
safe_delete(LanguageManager::m_Ptr);
#ifdef FLYLINKDC_USE_DB
#if defined(_WITH_SQLITE)
safe_delete(TextConverter::m_Ptr);
#endif
#endif
safe_delete(SettingManager::m_Ptr);
safe_delete(ReservedNicksManager::m_Ptr);
#ifdef _BUILD_GUI
MainWindow::m_Ptr->SaveGuiSettings();
#endif
#ifdef __MACH__
mach_port_deallocate(mach_task_self(), m_csMachClock);
#endif
DeleteGlobalBuffer();
#ifdef _WIN32
WSACleanup();
#ifndef _WIN_IOT
::PostQuitMessage(0);
#endif
#endif
}
//---------------------------------------------------------------------------
void ServerManager::UpdateServers()
{
bool bFound = false;
// Remove servers for ports we don't want use anymore
ServerThread * pCur = NULL,
* pNext = m_pServersS;
while (pNext != NULL)
{
pCur = pNext;
pNext = pCur->m_pNext;
bFound = false;
for (uint8_t ui8i = 0; ui8i < 25; ui8i++)
{
if (SettingManager::m_Ptr->m_ui16PortNumbers[ui8i] == 0)
{
break;
}
if (pCur->m_ui16Port == SettingManager::m_Ptr->m_ui16PortNumbers[ui8i])
{
bFound = true;
break;
}
}
if (bFound == false)
{
if (pCur->m_pPrev == NULL)
{
if (pCur->m_pNext == NULL)
{
m_pServersS = NULL;
m_pServersE = NULL;
}
else
{
pCur->m_pNext->m_pPrev = NULL;
m_pServersS = pCur->m_pNext;
}
}
else if (pCur->m_pNext == NULL)
{
pCur->m_pPrev->m_pNext = NULL;
m_pServersE = pCur->m_pPrev;
}
else
{
pCur->m_pPrev->m_pNext = pCur->m_pNext;
pCur->m_pNext->m_pPrev = pCur->m_pPrev;
}
pCur->Close();
pCur->WaitFor();
delete pCur;
}
}
// Add servers for ports that not running
for (uint8_t ui8i = 0; ui8i < 25; ui8i++)
{
if (SettingManager::m_Ptr->m_ui16PortNumbers[ui8i] == 0)
{
break;
}
bFound = false;
pCur = NULL,
pNext = m_pServersS;
while (pNext != NULL)
{
pCur = pNext;
pNext = pCur->m_pNext;
if (pCur->m_ui16Port == SettingManager::m_Ptr->m_ui16PortNumbers[ui8i])
{
bFound = true;
break;
}
}
if (bFound == false)
{
if (m_bUseIPv6 == false)
{
CreateServerThread(AF_INET, SettingManager::m_Ptr->m_ui16PortNumbers[ui8i]);
continue;
}
CreateServerThread(AF_INET6, SettingManager::m_Ptr->m_ui16PortNumbers[ui8i]);
if (SettingManager::m_Ptr->m_bBools[SETBOOL_BIND_ONLY_SINGLE_IP] == true || m_bIPv6DualStack == false)
{
CreateServerThread(AF_INET, SettingManager::m_Ptr->m_ui16PortNumbers[ui8i]);
}
}
}
}
//---------------------------------------------------------------------------
void ServerManager::ResumeAccepts()
{
if (m_bServerRunning == false)
{
return;
}
ServerThread * cur = NULL,
* next = m_pServersS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
cur->ResumeSck();
}
}
//---------------------------------------------------------------------------
void ServerManager::SuspendAccepts(const uint32_t ui32Time)
{
if (m_bServerRunning == false)
{
return;
}
if (ui32Time != 0)
{
UdpDebug::m_Ptr->BroadcastFormat("[SYS] Suspending listening threads to %u seconds.", ui32Time);
}
else
{
const char sSuspendMsg[] = "[SYS] Suspending listening threads.";
UdpDebug::m_Ptr->Broadcast(sSuspendMsg, sizeof(sSuspendMsg) - 1);
}
ServerThread * cur = NULL,
* next = m_pServersS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
cur->SuspendSck(ui32Time);
}
}
//---------------------------------------------------------------------------
#ifdef FLYLINKDC_REMOVE_REGISTER_THREAD
void ServerManager::UpdateAutoRegState()
{
if (m_bServerRunning == false)
{
return;
}
if (SettingManager::m_Ptr->m_bBools[SETBOOL_AUTO_REG] == true)
{
#if defined(_WIN32) && !defined(_WIN_IOT)
m_upRegTimer = SetTimer(NULL, 0, 901000, NULL);
if (m_upRegTimer == 0)
{
AppendDebugLog("%s - [ERR] Cannot start regtimer in ServerUpdateAutoRegState\n");
exit(EXIT_FAILURE);
}
#else
#ifdef __MACH__
mach_timespec_t mts;
clock_get_time(m_csMachClock, &mts);
ServiceLoop::m_Ptr->m_ui64LastRegToHublist = mts.tv_sec;
#elif _WIN32
ServiceLoop::m_Ptr->m_ui64LastRegToHublist = ::GetTickCount64() / 1000;
#else
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ServiceLoop::m_Ptr->m_ui64LastRegToHublist = ts.tv_sec;
#endif
#endif
#if defined(_WIN32) && !defined(_WIN_IOT)
}
else
{
if (KillTimer(NULL, m_upRegTimer) == 0)
{
AppendDebugLog("%s - [ERR] Cannot stop regtimer in ServerUpdateAutoRegState\n");
exit(EXIT_FAILURE);
}
#endif
}
}
#endif
//---------------------------------------------------------------------------
void ServerManager::CreateServerThread(const int iAddrFamily, const uint16_t ui16PortNumber, const bool bResume/* = false*/)
{
ServerThread * pServer = new (std::nothrow) ServerThread(iAddrFamily, ui16PortNumber);
if(pServer == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate pServer in ServerCreateServerThread\n");
exit(EXIT_FAILURE);
}
if(pServer->Listen() == true)
{
if(m_pServersE == NULL)
{
m_pServersS = pServer;
m_pServersE = pServer;
}
else
{
pServer->m_pPrev = m_pServersE;
m_pServersE->m_pNext = pServer;
m_pServersE = pServer;
}
if(bResume == true)
{
pServer->Resume();
}
}
else
{
delete pServer;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ServerManager::CommandLineSetup()
{
printf("%s built on %s %s\n\n", g_sPtokaXTitle, __DATE__, __TIME__);
printf("Welcome to PtokaX configuration setup.\nDirectory for PtokaX configuration is: %s\nWhen this directory is wrong, then exit this setup.\nTo specify correct configuration directory start PtokaX with -c configdir parameter.", m_sPath.c_str());
const char sMenu[] = "\n\nAvailable options:\n"
"1. Basic setup. Only few things required for PtokaX run.\n"
"2. Complete setup. Long setup, where you can change all PtokaX setings.\n"
"3. Add registered user.\n"
"4. Exit this setup.\n\n"
"Your choice: ";
printf("%s", sMenu);
while (true)
{
int iChar = getchar();
while (getchar() != '\n')
{
// boredom...
};
switch (iChar)
{
case '1':
SettingManager::m_Ptr->CmdLineBasicSetup();
printf("%s", sMenu);
continue;
case '2':
SettingManager::m_Ptr->CmdLineCompleteSetup();
printf("%s", sMenu);
continue;
case '3':
RegManager::m_Ptr->AddRegCmdLine();
printf("%s", sMenu);
continue;
case '4':
printf("%s ending...\n", g_sPtokaXTitle);
break;
default:
printf("Unknown option: %c\nYour choice: ", iChar);
continue;
}
break;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bool ServerManager::ResolveHubAddress(const bool bSilent/* = false*/)
{
if (SettingManager::m_Ptr->m_bBools[SETBOOL_RESOLVE_TO_IP] == true)
{
if (isIP(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS]) == false)
{
#ifdef _BUILD_GUI
MainWindow::m_Ptr->SetStatusValue((string(LanguageManager::m_Ptr->m_sTexts[LAN_RESOLVING_HUB_ADDRESS], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_RESOLVING_HUB_ADDRESS]) + "...").c_str());
#endif
struct addrinfo hints;
memset(&hints, 0, sizeof(addrinfo));
if (m_bUseIPv6 == true)
{
hints.ai_family = AF_UNSPEC;
}
else
{
hints.ai_family = AF_INET;
}
struct addrinfo *res;
if (::getaddrinfo(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS], NULL, &hints, &res) != 0 || (res->ai_family != AF_INET && res->ai_family != AF_INET6))
{
if (bSilent == false)
{
#ifdef _WIN32
int err = WSAGetLastError();
#ifdef _BUILD_GUI
::MessageBox(MainWindow::m_Ptr->m_hWnd, (std::to_string(LanguageManager::m_Ptr->m_sTexts[LAN_RESOLVING_OF_HOSTNAME], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_RESOLVING_OF_HOSTNAME]) + " '" + std::to_string(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS]) + "' " +
std::to_string(LanguageManager::m_Ptr->m_sTexts[LAN_HAS_FAILED], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_HAS_FAILED]) + ".\n" + std::to_string(LanguageManager::m_Ptr->m_sTexts[LAN_ERROR_CODE], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_ERROR_CODE]) + ": " + std::to_string(WSErrorStr(err)) + " (" + std::to_string(err) + ")\n\n" +
std::to_string(LanguageManager::m_Ptr->m_sTexts[LAN_CHECK_THE_ADDRESS_PLEASE], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_CHECK_THE_ADDRESS_PLEASE]) + ".").c_str(), LanguageManager::m_Ptr->m_sTexts[LAN_ERROR], MB_OK | MB_ICONERROR);
#else
AppendLog(std::to_string(LanguageManager::m_Ptr->m_sTexts[LAN_RESOLVING_OF_HOSTNAME], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_RESOLVING_OF_HOSTNAME]) +
" '" + std::to_string(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS]) + "' " + std::to_string(LanguageManager::m_Ptr->m_sTexts[LAN_HAS_FAILED], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_HAS_FAILED]) + ".\n" + std::to_string(LanguageManager::m_Ptr->m_sTexts[LAN_ERROR_CODE], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_ERROR_CODE]) +
": " + std::to_string(WSErrorStr(err)) + " (" + std::to_string(err) + ")\n\n" + std::to_string(LanguageManager::m_Ptr->m_sTexts[LAN_CHECK_THE_ADDRESS_PLEASE], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_CHECK_THE_ADDRESS_PLEASE]) + ".");
#endif
#else
AppendLog(string(LanguageManager::m_Ptr->m_sTexts[LAN_RESOLVING_OF_HOSTNAME], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_RESOLVING_OF_HOSTNAME]) +
" '" + string(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS]) + "' " + string(LanguageManager::m_Ptr->m_sTexts[LAN_HAS_FAILED], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_HAS_FAILED]) + ".\n" + string(LanguageManager::m_Ptr->m_sTexts[LAN_CHECK_THE_ADDRESS_PLEASE],
(size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_CHECK_THE_ADDRESS_PLEASE]) + ".");
#endif
}
return false;
}
else
{
Memo("*** " + string(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS], (size_t)SettingManager::m_Ptr->m_ui16TextsLens[SETTXT_HUB_ADDRESS]) + " " + string(LanguageManager::m_Ptr->m_sTexts[LAN_RESOLVED_SUCCESSFULLY], (size_t)LanguageManager::m_Ptr->m_ui16TextsLens[LAN_RESOLVED_SUCCESSFULLY]) + ".");
if (m_bUseIPv6 == true)
{
struct addrinfo *next = res;
while (next != NULL)
{
if (next->ai_family == AF_INET)
{
if (((sockaddr_in *)(next->ai_addr))->sin_addr.s_addr != INADDR_ANY)
{
strcpy(m_sHubIP, inet_ntoa(((sockaddr_in *)(next->ai_addr))->sin_addr));
}
}
else if (next->ai_family == AF_INET6)
{
#if defined(_WIN32) && !defined(_WIN64) && !defined(_WIN_IOT)
win_inet_ntop(&((struct sockaddr_in6 *)next->ai_addr)->sin6_addr, m_sHubIP6, 40);
#else
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)next->ai_addr)->sin6_addr, m_sHubIP6, 40);
#endif
}
next = next->ai_next;
}
}
else if (((sockaddr_in *)(res->ai_addr))->sin_addr.s_addr != INADDR_ANY)
{
strcpy(m_sHubIP, inet_ntoa(((sockaddr_in *)(res->ai_addr))->sin_addr));
}
if (m_sHubIP[0] != '\0')
{
string msg = "*** " + string(m_sHubIP);
if (IsPrivateIP(m_sHubIP) == true)
{
SettingManager::m_Ptr->SetBool(SETBOOL_AUTO_REG, false);
}
if (m_sHubIP6[0] != '\0')
{
msg += " / " + string(m_sHubIP6);
if (IsPrivateIP(m_sHubIP6) == true)
{
SettingManager::m_Ptr->SetBool(SETBOOL_AUTO_REG, false);
}
}
Memo(msg);
}
else if (m_sHubIP6[0] != '\0')
{
Memo("*** " + string(m_sHubIP6));
if (IsPrivateIP(m_sHubIP6) == true)
{
SettingManager::m_Ptr->SetBool(SETBOOL_AUTO_REG, false);
}
}
freeaddrinfo(res);
}
}
else
{
strcpy(m_sHubIP, SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS]);
if (IsPrivateIP(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS]) == true)
{
SettingManager::m_Ptr->SetBool(SETBOOL_AUTO_REG, false);
}
}
}
else
{
if (SettingManager::m_Ptr->m_sTexts[SETTXT_IPV4_ADDRESS] != NULL)
{
strcpy(m_sHubIP, SettingManager::m_Ptr->m_sTexts[SETTXT_IPV4_ADDRESS]);
}
else
{
m_sHubIP[0] = '\0';
}
if (SettingManager::m_Ptr->m_sTexts[SETTXT_IPV6_ADDRESS] != NULL)
{
strcpy(m_sHubIP6, SettingManager::m_Ptr->m_sTexts[SETTXT_IPV6_ADDRESS]);
}
else
{
m_sHubIP6[0] = '\0';
}
if (isIP(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS]) == true)
{
if (IsPrivateIP(SettingManager::m_Ptr->m_sTexts[SETTXT_HUB_ADDRESS]) == true)
{
SettingManager::m_Ptr->SetBool(SETBOOL_AUTO_REG, false);
}
}
}
return true;
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
↑ V1042 This file is marked with copyleft license, which requires you to open the derived source code.