diff options
Diffstat (limited to 'src/trinitycore/Master.cpp')
-rw-r--r-- | src/trinitycore/Master.cpp | 536 |
1 files changed, 0 insertions, 536 deletions
diff --git a/src/trinitycore/Master.cpp b/src/trinitycore/Master.cpp deleted file mode 100644 index 8b34b512f57..00000000000 --- a/src/trinitycore/Master.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** \file - \ingroup Trinityd -*/ - -#include <ace/Sig_Handler.h> - -#include "Common.h" -#include "SystemConfig.h" -#include "SignalHandler.h" -#include "World.h" -#include "WorldRunnable.h" -#include "WorldSocket.h" -#include "WorldSocketMgr.h" -#include "Config/ConfigEnv.h" -#include "Database/DatabaseEnv.h" -#include "Policies/SingletonImp.h" - -#include "CliRunnable.h" -#include "Log.h" -#include "Master.h" -#include "RASocket.h" -#include "Timer.h" -#include "Util.h" - -#include "sockets/TcpSocket.h" -#include "sockets/Utility.h" -#include "sockets/Parse.h" -#include "sockets/Socket.h" -#include "sockets/SocketHandler.h" -#include "sockets/ListenSocket.h" -#include "Auth/BigNumber.h" - -#ifdef WIN32 -#include "ServiceWin32.h" -extern int m_ServiceStatus; -#endif - -/// \todo Warning disabling not useful under VC++2005. Can somebody say on which compiler it is useful? -#pragma warning(disable:4305) - -INSTANTIATE_SINGLETON_1( Master ); - -volatile uint32 Master::m_masterLoopCounter = 0; - -/// Handle cored's termination signals -class CoredSignalHandler : public Trinity::SignalHandler -{ - public: - virtual void HandleSignal(int SigNum) - { - switch (SigNum) - { - case SIGINT: - World::StopNow(RESTART_EXIT_CODE); - break; - case SIGTERM: - #ifdef _WIN32 - case SIGBREAK: - if (m_ServiceStatus != 1) - #endif /* _WIN32 */ - World::StopNow(SHUTDOWN_EXIT_CODE); - break; - } - } -}; - -class FreezeDetectorRunnable : public ACE_Based::Runnable -{ -public: - FreezeDetectorRunnable() { _delaytime = 0; } - uint32 m_loops, m_lastchange; - uint32 w_loops, w_lastchange; - uint32 _delaytime; - void SetDelayTime(uint32 t) { _delaytime = t; } - void run(void) - { - if(!_delaytime) - return; - sLog.outString("Starting up anti-freeze thread (%u seconds max stuck time)...",_delaytime/1000); - m_loops = 0; - w_loops = 0; - m_lastchange = 0; - w_lastchange = 0; - while(!World::IsStopped()) - { - ACE_Based::Thread::Sleep(1000); - uint32 curtime = getMSTime(); - //DEBUG_LOG("anti-freeze: time=%u, counters=[%u; %u]",curtime,Master::m_masterLoopCounter,World::m_worldLoopCounter); - - // There is no Master anymore - // TODO: clear the rest of the code -// // normal work -// if(m_loops != Master::m_masterLoopCounter) -// { -// m_lastchange = curtime; -// m_loops = Master::m_masterLoopCounter; -// } -// // possible freeze -// else if(getMSTimeDiff(m_lastchange,curtime) > _delaytime) -// { -// sLog.outError("Main/Sockets Thread hangs, kicking out server!"); -// *((uint32 volatile*)NULL) = 0; // bang crash -// } - - // normal work - if(w_loops != World::m_worldLoopCounter) - { - w_lastchange = curtime; - w_loops = World::m_worldLoopCounter; - } - // possible freeze - else if(getMSTimeDiff(w_lastchange,curtime) > _delaytime) - { - sLog.outError("World Thread hangs, kicking out server!"); - *((uint32 volatile*)NULL) = 0; // bang crash - } - } - sLog.outString("Anti-freeze thread exiting without problems."); - } -}; - -class RARunnable : public ACE_Based::Runnable -{ -public: - uint32 numLoops, loopCounter; - - RARunnable () - { - uint32 socketSelecttime = sWorld.getConfig (CONFIG_SOCKET_SELECTTIME); - numLoops = (sConfig.GetIntDefault ("MaxPingTime", 30) * (MINUTE * 1000000 / socketSelecttime)); - loopCounter = 0; - } - - void checkping () - { - // ping if need - if ((++loopCounter) == numLoops) - { - loopCounter = 0; - sLog.outDetail ("Ping MySQL to keep connection alive"); - WorldDatabase.Query ("SELECT 1 FROM command LIMIT 1"); - LoginDatabase.Query ("SELECT 1 FROM realmlist LIMIT 1"); - CharacterDatabase.Query ("SELECT 1 FROM bugreport LIMIT 1"); - } - } - - void run () - { - SocketHandler h; - - // Launch the RA listener socket - ListenSocket<RASocket> RAListenSocket (h); - bool usera = sConfig.GetBoolDefault ("Ra.Enable", false); - - if (usera) - { - port_t raport = sConfig.GetIntDefault ("Ra.Port", 3443); - std::string stringip = sConfig.GetStringDefault ("Ra.IP", "0.0.0.0"); - ipaddr_t raip; - if (!Utility::u2ip (stringip, raip)) - sLog.outError ("Trinity RA can not bind to ip %s", stringip.c_str ()); - else if (RAListenSocket.Bind (raip, raport)) - sLog.outError ("Trinity RA can not bind to port %d on %s", raport, stringip.c_str ()); - else - { - h.Add (&RAListenSocket); - - sLog.outString ("Starting Remote access listner on port %d on %s", raport, stringip.c_str ()); - } - } - - // Socket Selet time is in microseconds , not miliseconds!! - uint32 socketSelecttime = sWorld.getConfig (CONFIG_SOCKET_SELECTTIME); - - // if use ra spend time waiting for io, if not use ra ,just sleep - if (usera) - { - while (!World::IsStopped()) - { - h.Select (0, socketSelecttime); - checkping (); - } - } - else - { - while (!World::IsStopped()) - { - ACE_Based::Thread::Sleep(static_cast<unsigned long> (socketSelecttime / 1000)); - checkping (); - } - } - } -}; - -Master::Master() -{ -} - -Master::~Master() -{ -} - -/// Main function -int Master::Run() -{ - BigNumber seed1; - seed1.SetRand(16 * 8); - - sLog.outString( "%s (core-daemon)", _FULLVERSION ); - sLog.outString( "<Ctrl-C> to stop.\n" ); - - sLog.outString( " ______ __"); - sLog.outString( "/\\__ _\\ __ __/\\ \\__"); - sLog.outString( "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\ ,_\\ __ __"); - sLog.outString( " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\"); - sLog.outString( " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\"); - sLog.outString( " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\"); - sLog.outString( " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\"); - sLog.outString( " C O R E /\\___/"); - sLog.outString( "http://TrinityCore.org \\/__/\n"); - - /// worldd PID file creation - std::string pidfile = sConfig.GetStringDefault("PidFile", ""); - if(!pidfile.empty()) - { - uint32 pid = CreatePIDFile(pidfile); - if( !pid ) - { - sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() ); - return 1; - } - - sLog.outString( "Daemon PID: %u\n", pid ); - } - - ///- Start the databases - if (!_StartDB()) - return 1; - - ///- Initialize the World - sWorld.SetInitialWorldSettings(); - - - // Initialise the signal handlers - CoredSignalHandler SignalINT, SignalTERM; - #ifdef _WIN32 - CoredSignalHandler SignalBREAK; - #endif /* _WIN32 */ - - // Register realmd's signal handlers - ACE_Sig_Handler Handler; - Handler.register_handler(SIGINT, &SignalINT); - Handler.register_handler(SIGTERM, &SignalTERM); - #ifdef _WIN32 - Handler.register_handler(SIGBREAK, &SignalBREAK); - #endif /* _WIN32 */ - - - ///- Launch WorldRunnable thread - ACE_Based::Thread world_thread(new WorldRunnable); - world_thread.setPriority(ACE_Based::Highest); - - // set server online - LoginDatabase.PExecute("UPDATE realmlist SET color = 0, population = 0 WHERE id = '%d'",realmID); - - ACE_Based::Thread* cliThread = NULL; - -#ifdef WIN32 - if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) -#else - if (sConfig.GetBoolDefault("Console.Enable", true)) -#endif - { - ///- Launch CliRunnable thread - cliThread = new ACE_Based::Thread(new CliRunnable); - } - - ACE_Based::Thread rar_thread(new RARunnable); - - ///- Handle affinity for multiple processors and process priority on Windows - #ifdef WIN32 - { - HANDLE hProcess = GetCurrentProcess(); - - uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); - if(Aff > 0) - { - ULONG_PTR appAff; - ULONG_PTR sysAff; - - if(GetProcessAffinityMask(hProcess,&appAff,&sysAff)) - { - ULONG_PTR curAff = Aff & appAff; // remove non accessible processors - - if(!curAff ) - { - sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for Trinityd. Accessible processors bitmask (hex): %x",Aff,appAff); - } - else - { - if(SetProcessAffinityMask(hProcess,curAff)) - sLog.outString("Using processors (bitmask, hex): %x", curAff); - else - sLog.outError("Can't set used processors (hex): %x",curAff); - } - } - sLog.outString(""); - } - - bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); - -// if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/) - if(Prio) - { - if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) - sLog.outString("TrinityCore process priority class set to HIGH"); - else - sLog.outError("ERROR: Can't set Trinityd process priority class."); - sLog.outString(""); - } - } - #endif - - uint32 realCurrTime, realPrevTime; - realCurrTime = realPrevTime = getMSTime(); - - ///- Start up freeze catcher thread - if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) - { - FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); - fdr->SetDelayTime(freeze_delay*1000); - ACE_Based::Thread freeze_thread(fdr); - freeze_thread.setPriority(ACE_Based::Highest); - } - - ///- Launch the world listener socket - port_t wsport = sWorld.getConfig (CONFIG_PORT_WORLD); - std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); - - if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1) - { - sLog.outError ("Failed to start network"); - World::StopNow(ERROR_EXIT_CODE); - // go down and shutdown the server - } - - sWorldSocketMgr->Wait (); - - // set server offline - LoginDatabase.PExecute("UPDATE realmlist SET color = 2 WHERE id = '%d'",realmID); - - // when the main thread closes the singletons get unloaded - // since worldrunnable uses them, it will crash if unloaded after master - world_thread.wait(); - rar_thread.wait (); - - ///- Clean database before leaving - clearOnlineAccounts(); - - ///- Wait for delay threads to end - CharacterDatabase.HaltDelayThread(); - WorldDatabase.HaltDelayThread(); - LoginDatabase.HaltDelayThread(); - - sLog.outString( "Halting process..." ); - - if (cliThread) - { - #ifdef WIN32 - - // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) - //_exit(1); - // send keyboard input to safely unblock the CLI thread - INPUT_RECORD b[5]; - HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); - b[0].EventType = KEY_EVENT; - b[0].Event.KeyEvent.bKeyDown = TRUE; - b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; - b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; - b[0].Event.KeyEvent.wRepeatCount = 1; - - b[1].EventType = KEY_EVENT; - b[1].Event.KeyEvent.bKeyDown = FALSE; - b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; - b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; - b[1].Event.KeyEvent.wRepeatCount = 1; - - b[2].EventType = KEY_EVENT; - b[2].Event.KeyEvent.bKeyDown = TRUE; - b[2].Event.KeyEvent.dwControlKeyState = 0; - b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; - b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; - b[2].Event.KeyEvent.wRepeatCount = 1; - b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; - - b[3].EventType = KEY_EVENT; - b[3].Event.KeyEvent.bKeyDown = FALSE; - b[3].Event.KeyEvent.dwControlKeyState = 0; - b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; - b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; - b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; - b[3].Event.KeyEvent.wRepeatCount = 1; - DWORD numb; - WriteConsoleInput(hStdIn, b, 4, &numb); - - cliThread->wait(); - - #else - - cliThread->destroy(); - - #endif - - delete cliThread; - } - - // for some unknown reason, unloading scripts here and not in worldrunnable - // fixes a memory leak related to detaching threads from the module - //UnloadScriptingModule(); - - // Exit the process with specified return value - return World::GetExitCode(); -} - -/// Initialize connection to the databases -bool Master::_StartDB() -{ - sLog.SetLogDB(false); - std::string dbstring; - - ///- Get world database info from configuration file - dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", ""); - if(dbstring.empty()) - { - sLog.outError("Database not specified in configuration file"); - return false; - } - - ///- Initialise the world database - if(!WorldDatabase.Initialize(dbstring.c_str())) - { - sLog.outError("Cannot connect to world database %s",dbstring.c_str()); - return false; - } - - ///- Get character database info from configuration file - dbstring = sConfig.GetStringDefault("CharacterDatabaseInfo", ""); - if(dbstring.empty()) - { - sLog.outError("Character Database not specified in configuration file"); - return false; - } - - ///- Initialise the Character database - if(!CharacterDatabase.Initialize(dbstring.c_str())) - { - sLog.outError("Cannot connect to Character database %s",dbstring.c_str()); - return false; - } - - ///- Get login database info from configuration file - dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", ""); - if(dbstring.empty()) - { - sLog.outError("Login database not specified in configuration file"); - return false; - } - - ///- Initialise the login database - if(!LoginDatabase.Initialize(dbstring.c_str())) - { - sLog.outError("Cannot connect to login database %s",dbstring.c_str()); - return false; - } - - ///- Get the realm Id from the configuration file - realmID = sConfig.GetIntDefault("RealmID", 0); - if(!realmID) - { - sLog.outError("Realm ID not defined in configuration file"); - return false; - } - sLog.outString("Realm running as realm ID %d", realmID); - - ///- Initialize the DB logging system - sLog.SetLogDBLater(sConfig.GetBoolDefault("EnableLogDB", false)); // set var to enable DB logging once startup finished. - sLog.SetLogDB(false); - sLog.SetRealmID(realmID); - - ///- Clean the database before starting - clearOnlineAccounts(); - - ///- Insert version info into DB - WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _REVISION); - - sWorld.LoadDBVersion(); - - sLog.outString("Using World DB: %s", sWorld.GetDBVersion()); - sLog.outString("Using creature EventAI: %s", sWorld.GetCreatureEventAIVersion()); - return true; -} - -/// Clear 'online' status for all accounts with characters in this realm -void Master::clearOnlineAccounts() -{ - // Cleanup online status for characters hosted at current realm - /// \todo Only accounts with characters logged on *this* realm should have online status reset. Move the online column from 'account' to 'realmcharacters'? - LoginDatabase.PExecute( - "UPDATE account SET online = 0 WHERE online > 0 " - "AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = '%d')",realmID); - - CharacterDatabase.Execute("UPDATE characters SET online = 0 WHERE online<>0"); - - // Battleground instance ids reset at server restart - CharacterDatabase.Execute("UPDATE character_battleground_data SET instance_id = 0"); -} |