bool Master::Run() { if (!sConfig.SetSource(REALITY_CONFIG)) { CRITICAL_LOG(format("Could not find configuration file %1%.") % REALITY_CONFIG); exit(0); } INFO_LOG(format("Reality v0.01 Alpha %1% bit version started") % (sizeof(int*) * 8)); if( !_StartDB() ) { CRITICAL_LOG("Error starting database!"); Database::CleanupLibs(); return false; } DEBUG_LOG("Initializing random number generators..."); uint32 seed = uint32(time(NULL)); new MTRand(seed); srand(seed); _HookSignals(); //init thread manager ThreadPool.Startup(); //start server threads AuthRunnable *authRun = new AuthRunnable(); ThreadPool.ExecuteTask(authRun); MarginRunnable *marginRun = new MarginRunnable(); ThreadPool.ExecuteTask(marginRun); GameRunnable *gameRun = new GameRunnable(); ThreadPool.ExecuteTask(gameRun); //spawn console thread ConsoleThread *consoleRun = new ConsoleThread(); ThreadPool.ExecuteTask(consoleRun); while (!Master::m_stopEvent) { Sleep(100); } authRun->Terminate(); marginRun->Terminate(); gameRun->Terminate(); consoleRun->Terminate(); DEBUG_LOG("Exiting..."); ThreadPool.ShowStats(); _UnhookSignals(); _StopDB(); return 0; }
// Use sMgr for Script Mgr. void Lacrimi::SetupScripts() { sLog.Success("Lacrimi", "Lacrimi Engine Started"); sLog.Success("","############################################################"); sLog.Success("","# ## # ####### ####### ## # # ## #"); sLog.Success("","# ## ### ## ## ## ## ### ### ## #"); sLog.Success("","# ## ## ## ## ## ## ## ### ### ## #"); sLog.Success("","# ## ####### ## ####### ## ## #### ## ## #"); sLog.Success("","# ## ## ## ## ##### ## ## #### ## ## #"); sLog.Success("","# ## ## ## ## ## ## ## ## ## ## ## #"); sLog.Success("","# ####### ## ## ####### ## ## ## ## ## ## ## #"); sLog.Success("","# :::::::.::.........::.:::::::.::...::.::.::...::...::.:: #"); sLog.Success("","############################################################"); // Load our configs lacrimiIni = new CIniFile("./lacrimi.ini"); if(lacrimiIni->ParseError()) config = false; // Load our DBs if(_StartDB()) database = true; dumpstats = GetConfigBool("StatDumper", "DumpStats", false); if(dumpstats) { sLog.Success("Lacrimi", "Stat Dumper Initialized"); strcpy(Filename, GetConfigString("StatDumper", "Filename", "stats.xml").c_str()); } sLog.Notice("Lacrimi", "C++ Loading scripts..."); SetupCityScripts(); SetupSpellScripts(); SetupCustomScripts(); SetupZoneScripts(); SetupInstanceScripts(); }
bool Master::Run(int argc, char ** argv) { char * config_file = (char*)default_config_file; char * realm_config_file = (char*)default_realm_config_file; int file_log_level = DEF_VALUE_NOT_SET; int screen_log_level = DEF_VALUE_NOT_SET; int do_check_conf = 0; int do_version = 0; int do_cheater_check = 0; int do_database_clean = 0; time_t curTime; struct ascent_option longopts[] = { { "checkconf", ascent_no_argument, &do_check_conf, 1 }, { "screenloglevel", ascent_required_argument, &screen_log_level, 1 }, { "fileloglevel", ascent_required_argument, &file_log_level, -1 }, { "version", ascent_no_argument, &do_version, 1 }, { "conf", ascent_required_argument, NULL, 'c' }, { "realmconf", ascent_required_argument, NULL, 'r' }, { 0, 0, 0, 0 } }; char c; while ((c = ascent_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'c': config_file = new char[strlen(ascent_optarg)]; strcpy(config_file, ascent_optarg); break; case 'r': realm_config_file = new char[strlen(ascent_optarg)]; strcpy(realm_config_file, ascent_optarg); break; case 0: break; default: sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 3; printf("Usage: %s [--checkconf] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]); return true; } } /* set new log levels if used as argument*/ if( screen_log_level != (int)DEF_VALUE_NOT_SET ) sLog.SetScreenLoggingLevel(screen_log_level); if( file_log_level != (int)DEF_VALUE_NOT_SET ) sLog.SetFileLoggingLevel(file_log_level); // Startup banner UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); /* Print Banner */ Log.Notice("Server", "=============================================================="); Log.Notice("Server", "| Ascent Cluster System - Realm Server |"); Log.Notice("Server", "| Version 1.0, Revision %04u |", BUILD_REVISION); Log.Notice("Server", "=============================================================="); Log.Line(); if( do_check_conf ) { Log.Notice( "Config", "Checking config file: %s", config_file ); if( Config.ClusterConfig.SetSource(config_file, true ) ) Log.Success( "Config", "Passed without errors." ); else Log.Warning( "Config", "Encountered one or more errors." ); Log.Notice( "Config", "Checking config file: %s\n", realm_config_file ); if( Config.RealmConfig.SetSource( realm_config_file, true ) ) Log.Success( "Config", "Passed without errors.\n" ); else Log.Warning( "Config", "Encountered one or more errors.\n" ); /* test for die variables */ string die; if( Config.ClusterConfig.GetString( "die", "msg", &die) || Config.ClusterConfig.GetString("die2", "msg", &die ) ) Log.Warning( "Config", "Die directive received: %s", die.c_str() ); return true; } printf( "The key combination <Ctrl-C> will safely shut down the server at any time.\n" ); Log.Line(); //use these log_level until we are fully started up. sLog.Init(-1, 3); #ifndef WIN32 if(geteuid() == 0 || getegid() == 0) Log.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running Ascent as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL); #endif ThreadPool.Startup(); uint32 LoadingTime = getMSTime(); _HookSignals(); Log.Line(); Log.Notice( "Config", "Loading Config Files..." ); if( Config.ClusterConfig.SetSource( config_file ) ) Log.Success( "Config", ">> %s", config_file ); else { Log.Error( "Config", ">> %s", config_file ); return false; } string die; if( Config.ClusterConfig.GetString( "die", "msg", &die) || Config.ClusterConfig.GetString( "die2", "msg", &die ) ) { Log.Warning( "Config", "Die directive received: %s", die.c_str() ); return false; } if(Config.RealmConfig.SetSource(realm_config_file)) Log.Success( "Config", ">> %s", realm_config_file ); else { Log.Error( "Config", ">> %s", realm_config_file ); return false; } Rehash(true); if( !_StartDB() ) { Database::CleanupLibs(); ThreadPool.Shutdown(); _UnhookSignals(); return false; } Log.Success("Database", "Connections established..."); new ClusterMgr; new ClientMgr; Log.Line(); ThreadPool.ShowStats(); Log.Line(); if( !LoadRSDBCs() ) { Log.LargeErrorMessage(LARGERRORMESSAGE_ERROR, "One or more of the DBC files are missing.", "These are absolutely necessary for the server to function.", "The server will not start without them.", NULL); return false; } Log.Success("Storage", "DBC Files Loaded..."); Storage_Load(); Log.Line(); new SocketMgr; new SocketGarbageCollector; sSocketMgr.SpawnWorkerThreads(); /* connect to LS */ new LogonCommHandler; sLogonCommHandler.Startup(); Log.Success("Network", "Network Subsystem Started."); Log.Notice("Network", "Opening Client Port..."); ListenSocket<WorldSocket> * wsl = new ListenSocket<WorldSocket>("0.0.0.0", 8129); bool lsc = wsl->IsOpen(); Log.Notice("Network", "Opening Server Port..."); ListenSocket<WSSocket> * isl = new ListenSocket<WSSocket>("0.0.0.0", 11010); bool ssc = isl->IsOpen(); if(!lsc || !ssc) { Log.Error("Network", "Could not open one of the sockets."); return 1; } ThreadPool.ExecuteTask( isl ); ThreadPool.ExecuteTask( wsl ); ConsoleThread * console = new ConsoleThread(); ThreadPool.ExecuteTask(console); uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); sSocketMgr.SpawnWorkerThreads(); LoadingTime = getMSTime() - LoadingTime; Log.Success("Server","Ready for connections. Startup time: %ums\n", LoadingTime ); m_startTime = uint32(UNIXTIME); //Update sLog to obey config setting sLog.Init(Config.ClusterConfig.GetIntDefault("LogLevel", "File", -1),Config.ClusterConfig.GetIntDefault("LogLevel", "Screen", 1)); /* write pid file */ FILE * fPid = fopen( "ascent-realmserver.pid", "w" ); if( fPid ) { uint32 pid; #ifdef WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif fprintf( fPid, "%u", (unsigned int)pid ); fclose( fPid ); } #ifdef WIN32 HANDLE hThread = GetCurrentThread(); #endif uint32 loopcounter = 0; uint32 start = 0; uint32 diff = 0; uint32 last_time = 0; uint32 etime = 0; //ThreadPool.Gobble(); /* voicechat */ #ifdef VOICE_CHAT new VoiceChatHandler(); sVoiceChatHandler.Startup(); #endif while(!m_stopEvent) { start = now(); diff = start - last_time; if(! ((++loopcounter) % 10000) ) // 5mins { ThreadPool.ShowStats(); ThreadPool.IntegrityCheck();//Checks if THREAD_RESERVE is met } /* since time() is an expensive system call, we only update it once per server loop */ curTime = time(NULL); if( UNIXTIME != curTime ) { UNIXTIME = time(NULL); g_localTime = *localtime(&curTime); } #ifdef VOICE_CHAT sVoiceChatHandler.Update(); #endif sLogonCommHandler.UpdateSockets(); //wsl->Update(); //isl->Update(); sClientMgr.Update(); sClusterMgr.Update(); sSocketGarbageCollector.Update(); /* UPDATE */ last_time = now(); etime = last_time - start; if( 50 > etime ) { #ifdef WIN32 WaitForSingleObject( hThread, 50 - etime ); #else Sleep( 50 - etime ); #endif } } // begin server shutdown Log.Notice( "Shutdown", "Initiated at %s", ConvertTimeStampToDataTime( (uint32)UNIXTIME).c_str() ); bServerShutdown = true; _UnhookSignals(); Log.Notice("ChannelMgr", "~ChannelMgr()"); delete ChannelMgr::getSingletonPtr(); delete LogonCommHandler::getSingletonPtr(); Log.Success("~LogonComm", "LogonCommHandler shut down"); sSocketMgr.CloseAll(); #ifdef WIN32 sSocketMgr.ShutdownThreads(); #endif Log.Success("~Network", "Network Subsystem shut down."); Log.Notice( "~Network", "Deleting network subsystem..." ); delete SocketGarbageCollector::getSingletonPtr(); delete SocketMgr::getSingletonPtr(); Log.Notice("~Network", "Closing Client Port..."); delete wsl; Log.Notice("~Network", "Closing Server Port..."); delete isl; Storage_Cleanup(); Log.Success("~Storage", "DBC Files Unloaded..."); delete ClusterMgr::getSingletonPtr(); delete ClientMgr::getSingletonPtr(); CharacterDatabase.EndThreads(); WorldDatabase.EndThreads(); Database::CleanupLibs(); Log.Notice( "Database", "Closing Connections..." ); _StopDB(); Log.Success("~Database", "Shut down."); Log.Notice("~ThreadPool", "Ending %u active threads...", ThreadPool.GetActiveThreadCount()); ThreadPool.Shutdown(); /* Shut down console system */ console->terminate(); delete console; // remove pid remove( "ascent-realmserver.pid" ); Log.Notice( "Shutdown", "Shutdown complete." ); #ifdef WIN32 WSACleanup(); #endif return true; }
// Main function int Master::Run() { sLog.outString("%s [core-daemon]", _FULLVERSION); sLog.outString("<Ctrl-C> to stop."); sLog.outString(" "); sLog.outString(" BBBBBB BBB "); sLog.outString(" BBBB:..:::BB BBBBBBBBB "); sLog.outString(" B:::::BBB:::B BB:....:::B "); sLog.outString(" BB:::B BB::B B:::BBBB:::B "); sLog.outString(" B:::B BB:.B B:::B BB.:B "); sLog.outString(" B:::BBB::BBB BB::B BB.B "); sLog.outString(" B.:..BBB....BBB.:.B "); sLog.outString(" B...BB BB..:BB...B "); sLog.outString(" B...B B..:BB...B "); sLog.outString(" B...B B..BBB...B "); sLog.outString(" B...B BB.BBBB...B "); sLog.outString(" B...B BB:.BB B...BB "); sLog.outString(" B: . B. :BB B . B BBB "); sLog.outString(" B: ..:BBBB B: .B BB .B "); sLog.outString(" BBBBB B. :B B.: B "); sLog.outString(" B. :BB BB:BB"); sLog.outString(" BlizzLikeCore 2012(c) BB BBBBBBB B "); sLog.outString(" <blizzlike.servegame.com> BBB. .BB "); sLog.outString(" BBBBBBBB "); sLog.outString(" "); // 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(); // Catch termination signals _HookSignals(); // Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set realmbuilds depend on BlizzLikeCore expected builds, and set server online std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%d'", REALM_FLAG_OFFLINE, builds.c_str(), 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 BlizzLikeCore. 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) { if (SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("BlizzLikeCore process priority class set to HIGH"); else sLog.outError("ERROR: Can't set BlizzLikeCore process priority class."); sLog.outString(); } } #endif // Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) { BCSoapRunnable *runnable = new BCSoapRunnable(); runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); // Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } // Launch the world listener socket uint16 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(); // Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } // Stop soap thread if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // Set server offline in realmlist LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); // Remove signal handling before leaving _UnhookSignals(); // 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 account 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(); }
bool Master::Run() { sLog.outString( "MaNGOS daemon %s", _FULLVERSION ); sLog.outString( "<Ctrl-C> to stop.\n\n" ); sLog.outTitle( "MM MM MM MM MMMMM MMMM MMMMM"); sLog.outTitle( "MM MM MM MM MMM MMM MM MM MMM MMM"); sLog.outTitle( "MMM MMM MMM MM MMM MMM MM MM MMM"); sLog.outTitle( "MM M MM MMMM MM MMM MM MM MMM"); sLog.outTitle( "MM M MM MMMMM MM MMMM MMM MM MM MMM"); sLog.outTitle( "MM M MM M MMM MM MMM MMMMMMM MM MM MMM"); sLog.outTitle( "MM MM MMM MM MM MM MMM MM MM MMM"); sLog.outTitle( "MM MM MMMMMMM MM MM MMM MMM MM MM MMM MMM"); sLog.outTitle( "MM MM MM MMM MM MM MMMMMM MMMM MMMMM"); sLog.outTitle( " MM MMM http://www.mangosproject.org"); sLog.outTitle( " MMMMMM\n\n"); _StartDB(); //loglevel = (uint8)sConfig.GetIntDefault("LogLevel", DEFAULT_LOG_LEVEL); sWorld.SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT) ); sWorld.SetMotd( sConfig.GetStringDefault("Motd", "Welcome to the Massive Network Game Object Server." ).c_str() ); sWorld.SetInitialWorldSettings(); port_t wsport, rmport; rmport = sWorld.getConfig(CONFIG_PORT_REALM); //sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT ); wsport = sWorld.getConfig(CONFIG_PORT_WORLD); //sConfig.GetIntDefault( "WorldServerPort", DEFAULT_WORLDSERVER_PORT ); uint32 socketSelecttime; //sConfig.GetIntDefault( "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME ); socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); //uint32 grid_clean_up_delay = sConfig.GetIntDefault("GridCleanUpDelay", 300); //sLog.outDebug("Setting Grid clean up delay to %d seconds.", grid_clean_up_delay); //grid_clean_up_delay *= 1000; //MapManager::Instance().SetGridCleanUpDelay(grid_clean_up_delay); //uint32 map_update_interval = sConfig.GetIntDefault("MapUpdateInterval", 100); //sLog.outDebug("Setting map update interval to %d milli-seconds.", map_update_interval); //MapManager::Instance().SetMapUpdateInterval(map_update_interval); // sRealmList.setServerPort(wsport); // sRealmList.GetAndAddRealms (); SocketHandler h; ListenSocket<WorldSocket> worldListenSocket(h); // ListenSocket<AuthSocket> authListenSocket(h); if (worldListenSocket.Bind(wsport)) { _StopDB(); sLog.outString( "MaNGOS can not bind to that port" ); exit(1); } h.Add(&worldListenSocket); // h.Add(&authListenSocket); _HookSignals(); ZThread::Thread t(new WorldRunnable); //#ifndef WIN32 t.setPriority ((ZThread::Priority )2); //#endif #ifdef ENABLE_CLI ZThread::Thread td1(new CliRunnable); #endif #ifdef ENABLE_RA ListenSocket<RASocket> RAListenSocket(h); if (RAListenSocket.Bind(sConfig.GetIntDefault( "RA.Port", 3443 ))) { sLog.outString( "MaNGOS can not bind to that port" ); // exit(1); go on with no RA } h.Add(&RAListenSocket); #endif #ifdef WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if(Aff > 0) { uint32 appAff; uint32 sysAff; if(GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { uint32 curAff = Aff & appAff; // remove non accassable processors if(!curAff ) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessable for mangosd. Accessable 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(""); } uint32 Prio = sConfig.GetIntDefault("ProcessPriority", 0); if(Prio) { if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("mangosd process priority class set to HIGH"); else sLog.outError("ERROR: Can't set mangosd process priority class."); sLog.outString(""); } } #endif uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); while (!World::m_stopEvent) { if (realPrevTime > realCurrTime) realPrevTime = 0; realCurrTime = getMSTime(); sWorldSocketMgr.Update( realCurrTime - realPrevTime ); realPrevTime = realCurrTime; //h.Select(0, 100000); h.Select(0, socketSelecttime); } sLog.outString( "WORLD: Saving Addons" ); sAddOnHandler._SaveToDB(); _UnhookSignals(); t.wait(); _StopDB(); sLog.outString( "Halting process..." ); return 0; }
/// Main function int Master::Run() { BigNumber seed1; seed1.SetRand(16 * 8); sLog->outString("%s (worldserver-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"); /// worldserver PID file creation std::string pidfile = ConfigMgr::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; // set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); ///- Initialize the World sWorld->SetInitialWorldSettings(); // Initialise the signal handlers WorldServerSignalHandler SignalINT, SignalTERM; #ifdef _WIN32 WorldServerSignalHandler SignalBREAK; #endif /* _WIN32 */ // Register worldserver'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); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (ConfigMgr::GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (ConfigMgr::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 = ConfigMgr::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 are not accessible for the worldserver. 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 = ConfigMgr::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("worldserver process priority class set to HIGH"); else sLog->outError("Can't set worldserver process priority class."); sLog->outString(""); } } #endif //Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (ConfigMgr::GetBoolDefault("SOAP.Enabled", false)) { TCSoapRunnable* runnable = new TCSoapRunnable(); runnable->setListenArguments(ConfigMgr::GetStringDefault("SOAP.IP", "127.0.0.1"), ConfigMgr::GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread if (uint32 freeze_delay = ConfigMgr::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 uint16 wsport = sWorld->getIntConfig(CONFIG_PORT_WORLD); std::string bind_ip = ConfigMgr::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 } // set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); sLog->outString("%s (worldserver-daemon) ready...", _FULLVERSION); // 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(); if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // set server offline LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); ///- Clean database before leaving ClearOnlineAccounts(); _StopDB(); 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(); }
/// Main function int Cluster::Run(int argc, char** argv) { ///- Start the databases if (!_StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Initialize the World sClusterBasic.SetInitialSettings(); sCORBAThread.setArgNb(argc); sCORBAThread.setArgTab(argv); ///- Launch CORBA thread ACE_Based::Thread corba_thread(new CORBAThread); corba_thread.setPriority(ACE_Based::Highest); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread ACE_Based::Thread cluster_thread(new ClusterBasic); cluster_thread.setPriority(ACE_Based::Highest); ///- 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 LootClusterFX. 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("LootClusterFX process priority class set to HIGH"); else sLog.outError("ERROR: Can't set LootClusterFX process priority class."); sLog.outString(); } } #endif uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); ///- Start up freeze catcher thread /*ACE_Based::Thread* freeze_thread = NULL; if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); }*/ ///- Launch the world listener socket /*uint16 wsport = sWorld.getConfig (CONFIG_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip) == -1) { sLog.outError ("Failed to start network"); Log::WaitBeforeContinueIfNeed(); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait ();*/ ///- Stop freeze protection before shutdown tasks /*if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; }*/ sClusterBasic.Wait(); // Stop CORBA Thread CORBAThread::StopNOW(); corba_thread.wait(); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master cluster_thread.wait(); ///- Wait for DB delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); loginDatabase.HaltDelayThread(); sLog.outString( "Halting process..." ); ///- Exit the process with specified return value return 0; }
// Main function int Master::Run() { int defaultStderr = dup(2); if (sConfig.GetBoolDefault("Console.Enable", true)) sConsole.Initialize(); sConsole.SetLoading(true); sConsole.DrawLogo(); // 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 _StartDB(); // Initialize the World sWorld.SetInitialWorldSettings(); // set realmbuilds depend on OregonCore expected builds, and set server online std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%d'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); sConsole.SetLoading(false); // Catch termination signals _HookSignals(); 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 Console::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 OregonCore. 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) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog.outString("OregonCore process priority class set to HIGH"); else sLog.outError("ERROR: Can't set OregonCore process priority class."); sLog.outString(); } } #endif // Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) { OCSoapRunnable* runnable = new OCSoapRunnable(); runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } //uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); // Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay * 1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } // Launch the world listener socket uint16 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 // give other threads a chance to start-up so we can shutdown them safely ACE_Based::Thread::Sleep(1500); } /* Run our World, we use main thread for this, because it we need the highest priority possible */ WorldRunnable().run(); // Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->kill(-1); // destroy freeze_thread->wait(); delete freeze_thread; } sWorldSocketMgr->Wait(); // Stop soap thread if (soap_thread) { soap_thread->wait(); delete soap_thread; } // Set server offline in realmlist LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master rar_thread.wait (); // Clean account database before leaving clearOnlineAccounts(); // Wait for delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString("Halting process..."); if (cliThread) { cliThread->kill(SIGINT); cliThread->wait(); delete cliThread; } // we've been messing up with stderr (if Console.Enable was set), // so we need to restore it back, to prevent SIGPIPEs after restart dup2(defaultStderr, 2); close(defaultStderr); // Remove signal handling before leaving _UnhookSignals(); // 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(); }
bool Master::Run(int argc, char ** argv) { sLog.InitializeUnderlayingLog(); m_stopEvent = false; char * config_file = (char*)default_config_file; int screen_log_level = DEF_VALUE_NOT_SET; int do_check_conf = 0; int do_version = 0; int do_cheater_check = 0; int do_database_clean = 0; time_t curTime; struct hearthstone_option longopts[] = { { "checkconf", hearthstone_no_argument, &do_check_conf, 1 }, { "screenloglevel", hearthstone_required_argument, &screen_log_level, 1 }, { "version", hearthstone_no_argument, &do_version, 1 }, { "cheater", hearthstone_no_argument, &do_cheater_check, 1 }, { "cleandb", hearthstone_no_argument, &do_database_clean, 1 }, { "conf", hearthstone_required_argument, NULL, 'c' }, { "realmconf", hearthstone_required_argument, NULL, 'r' }, { 0, 0, 0, 0 } }; char c; while ((c = hearthstone_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'c': config_file = new char[strlen(hearthstone_optarg)]; strcpy(config_file, hearthstone_optarg); break; case 0: break; default: sLog.SetLoggingLevel(3); printf("Usage: %s [--checkconf] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]); return true; } } /* set new log levels if used as argument*/ if( screen_log_level != (int)DEF_VALUE_NOT_SET ) sLog.SetLoggingLevel(screen_log_level); // Startup banner UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); printf(BANNER, BUILD_TAG, BUILD_HASH_STR, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH); sLog.Line(); printf( "The key combination <Ctrl-C> will safely shut down the server at any time.\n" ); sLog.Line(); #ifndef WIN32 if(geteuid() == 0 || getegid() == 0) sLog.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running Hearthstone as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL); #endif InitRandomNumberGenerators(); sLog.Success( "Rnd", "Initialized Random Number Generators." ); mainIni = new CIniFile(config_file); uint32 LoadingTime = getMSTime(); sLog.Notice( "Config", "Loading Config Files..." ); if( !mainIni->ParseError() ) sLog.Success( "Config", ">> hearthstone-world.ini" ); else { sLog.Error( "Config", ">> hearthstone-world.ini" ); return false; } //use these log_level until we are fully started up. if(mainIni->ReadInteger("LogLevel", "Screen", 1) == -1) { sLog.Notice("Master", "Running silent mode..."); sLog.Init(-1); } else #ifdef _DEBUG sLog.Init(3); #else sLog.Init(1); #endif // _DEBUG sDBEngine.Init(false); if(!_StartDB()) { DirectDatabase::CleanupLibs(); return false; } sLog.Line(); sLog.outString(""); new EventMgr(); EventableObjectHolder* m_Holder = new EventableObjectHolder(-1); new World(); /* load the config file */ sWorld.Rehash(true); // Because of our log DB system, these have to be initialized different then rehash. sWorld.LogCheaters = mainIni->ReadBoolean("Log", "Cheaters", false); sWorld.LogCommands = mainIni->ReadBoolean("Log", "GMCommands", false); sWorld.LogPlayers = mainIni->ReadBoolean("Log", "Player", false); sWorld.bLogChat = mainIni->ReadBoolean("Log", "Chat", false); //Update log to obey config setting sLog.Init(mainIni->ReadInteger("LogLevel", "Screen", 1)); // Initialize Opcode Table WorldSession::InitPacketHandlerTable(); string host = mainIni->ReadString( "Listen", "Host", DEFAULT_HOST ); int wsport = mainIni->ReadInteger( "RealmData", "WorldServerPort", DEFAULT_WORLDSERVER_PORT ); new ScriptMgr(); if( !sWorld.SetInitialWorldSettings() ) { sLog.Error( "Server", "SetInitialWorldSettings() failed. Something went wrong? Exiting." ); return false; } sWorld.SetStartTime(uint32(UNIXTIME)); WorldRunnable * wr = new WorldRunnable(m_Holder); ThreadPool.ExecuteTask("WorldRunnable", wr); _HookSignals(); ConsoleThread* console = new ConsoleThread(); ThreadPool.ExecuteTask("ConsoleThread", console); uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); // Socket loop! uint32 start = 0, last_time = getMSTime(), etime = 0; // Start Network Subsystem sLog.Debug("Server","Starting network subsystem..." ); CreateSocketEngine(8); sSocketEngine.SpawnThreads(); if( StartConsoleListener() ) sLog.Success("RemoteConsole", "Started and listening on port %i", mainIni->ReadInteger("RemoteConsole", "Port", 8092)); else sLog.Debug("RemoteConsole", "Not enabled or failed listen."); LoadingTime = getMSTime() - LoadingTime; sLog.Success("Server","Ready for connections. Startup time: %ums\n", LoadingTime ); /* write pid file */ FILE * fPid = fopen( "hearthstone-world.pid", "w" ); if( fPid ) { uint32 pid; #ifdef WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif fprintf( fPid, "%u", uint(pid) ); fclose( fPid ); } #ifdef WIN32 HANDLE hThread = GetCurrentThread(); #endif uint32 loopcounter = 0, LastLogonUpdate = getMSTime(); if(mainIni->ReadInteger("LogLevel", "Screen", 1) == -1) { sLog.Init(1); sLog.Notice("Master", "Leaving Silent Mode..."); } /* Connect to realmlist servers / logon servers */ new LogonCommHandler(); sLogonCommHandler.Startup(); ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(); bool listnersockcreate = ls->Open(host.c_str(), wsport); while( !m_stopEvent && listnersockcreate ) { start = getMSTime(); /* since time() is an expensive system call, we only update it once per server loop */ curTime = time(NULL); if( UNIXTIME != curTime ) { UNIXTIME = time(NULL); g_localTime = *localtime(&curTime); UpdateRandomNumberGenerators(); } sLogonCommHandler.UpdateSockets(getMSTime()-LastLogonUpdate); LastLogonUpdate = getMSTime(); sSocketDeleter.Update(); /* UPDATE */ last_time = getMSTime(); etime = last_time - start; if( 25 > etime ) { #if PLATFORM == PLATFORM_WIN WaitForSingleObject( hThread, 25 - etime ); #else Sleep( 25 - etime ); #endif } } // begin server shutdown sLog.Notice( "Shutdown", "Initiated at %s", ConvertTimeStampToDataTime( (uint32)UNIXTIME).c_str() ); bServerShutdown = true; if( lootmgr.is_loading ) { sLog.Notice( "Shutdown", "Waiting for loot to finish loading..." ); while( lootmgr.is_loading ) Sleep( 100 ); } sDBEngine.EndThreads(); if(sWorld.LacrimiThread != NULL) // Shut this down first... { sWorld.LacrimiThread->SelfTerminate(); sLog.Notice( "Shutdown", "Waiting for Lacrimi to finish shutting down..." ); while(sWorld.LacrimiThread->GetThreadState() == THREADSTATE_SELF_TERMINATE) Sleep(100); } sLog.Notice( "Database", "Clearing all pending queries..." ); // kill the database thread first so we don't lose any queries/data CharacterDatabase.EndThreads(); WorldDatabase.EndThreads(); if(Database_Log) LogDatabase.EndThreads(); guildmgr.SaveAllGuilds(); sWorld.LogoutPlayers(); //(Also saves players). CharacterDatabase.Execute("UPDATE characters SET online = 0"); sLog.Notice("Server", "Shutting down random generator."); CleanupRandomNumberGenerators(); ls->Disconnect(); sLog.Notice( "Network", "Shutting down network subsystem." ); sSocketEngine.Shutdown(); sAddonMgr.SaveToDB(); sLog.Notice("AddonMgr", "~AddonMgr()"); delete AddonMgr::getSingletonPtr(); sLog.Notice("LootMgr", "~LootMgr()"); delete LootMgr::getSingletonPtr(); sLog.Notice("MailSystem", "~MailSystem()"); delete MailSystem::getSingletonPtr(); /* Shut down console system */ CloseConsoleListener(); console->terminate(); delete console; sLog.Notice("Thread", "Terminating thread pool..."); ThreadPool.Shutdown(); ls = NULL; sLog.Notice( "Network", "Deleting Network Subsystem..." ); { /* delete the socket deleter */ delete SocketDeleter::getSingletonPtr(); /* delete the socket engine */ delete SocketEngine::getSingletonPtr(); /* WSA network cleanup */ WSACleanup(); } sLog.Notice("InsertQueueLoader", "~InsertQueueLoader()"); delete InsertQueueLoader::getSingletonPtr(); sLog.Notice("LogonComm", "~LogonCommHandler()"); delete LogonCommHandler::getSingletonPtr(); sLog.Notice( "World", "~World()" ); sWorld.Destruct(); // delete World::getSingletonPtr(); sLog.Notice( "ScriptMgr", "~ScriptMgr()" ); sScriptMgr.UnloadScripts(); delete ScriptMgr::getSingletonPtr(); sLog.Notice( "EventMgr", "~EventMgr()" ); delete EventMgr::getSingletonPtr(); sLog.Notice( "Database", "Closing Connections..." ); _StopDB(); _UnhookSignals(); // remove pid remove( "hearthstone-world.pid" ); sLog.Notice( "Shutdown", "Shutdown complete." ); return true; }
int Master::Run() { sLog.outString(" ___ _ _ ___ "); sLog.outString(" / _ \\ | |_ ___ _ __ (_) __ / __| ___ _ _ ___ "); sLog.outString(" / /_\\ \\ | _| / _ \\ | ' \\ | | / _| | (__ / _ \\ | '_| / -_)"); sLog.outString("/_/ \\_\\ \\__| \\___/ |_|_|_| |_| \\__| \\___| \\___/ |_| \\___|"); sLog.outString(""); 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); } if (!_StartDB()) return 1; sWorld.SetInitialWorldSettings(); _HookSignals(); ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.PExecute("UPDATE realmlist SET flag = flag & ~(%u), population = 0, gamebuild = '%s' WHERE id = '%d'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); #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; if (!curAff) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for OregonCore. 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) { if (SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("OregonCore process priority class set to HIGH"); else sLog.outError("ERROR: Can't set OregonCore process priority class."); sLog.outString(); } } #endif ACE_Based::Thread* soap_thread = NULL; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) { OCSoapRunnable* soapconnectector = new OCSoapRunnable(); soapconnectector->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfig.GetIntDefault("SOAP.Port", 7878))); soap_thread = new ACE_Based::Thread(soapconnectector); } ACE_Based::Thread* freeze_thread = NULL; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } uint16 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); } sWorldSocketMgr->Wait(); if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } LoginDatabase.PExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); _UnhookSignals(); world_thread.wait(); rar_thread.wait (); clearOnlineAccounts(); CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString("Halting process..."); if (cliThread) { #ifdef _WIN32 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; } return World::GetExitCode(); }
bool Master::Run(int argc, char ** argv) { #ifdef WIN32 char * config_file = "antrix.conf"; char * realm_config_file = "realms.conf"; #else char * config_file = CONFDIR "/antrix.conf"; char * realm_config_file = CONFDIR "/realms.conf"; #endif int file_log_level = DEF_VALUE_NOT_SET; int screen_log_level = DEF_VALUE_NOT_SET; int do_check_conf = 0; int do_version = 0; struct antrix_option longopts[] = { { "checkconf", antrix_no_argument, &do_check_conf, 1 }, { "screenloglevel", antrix_required_argument, &screen_log_level, 1 }, { "fileloglevel", antrix_required_argument, &file_log_level, 1 }, { "version", antrix_no_argument, &do_version, 1 }, { "conf", antrix_required_argument, NULL, 'c' }, { "realmconf", antrix_required_argument, NULL, 'r' }, { 0, 0, 0, 0 } }; char c; while ((c = antrix_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'c': config_file = new char[strlen(antrix_optarg)]; strcpy(config_file, antrix_optarg); break; case 'r': realm_config_file = new char[strlen(antrix_optarg)]; strcpy(realm_config_file, antrix_optarg); break; case 0: break; default: sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 3; printf("Usage: %s [--checkconf] [--screenloglevel <level>] [--fileloglevel <level>] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]); return true; } } // Startup banner if(!do_version && !do_check_conf) { launch_thread(new TextLoggerThread); sLog.Init(-1, 3); } else { sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 3; } sLog.outString("=============================================================================="); sLog.outString(BANNER, g_getRevision()); sLog.outString(""); sLog.outString("Copyright (c) 2007 Antrix Team. This software is under the QPL license, for"); sLog.outString("more information look under the COPYING file in this distribution."); sLog.outString("=============================================================================="); sLog.outString(""); if(do_version) return true; if(do_check_conf) { printf("Checking config file: %s\n", config_file); if(Config.MainConfig.SetSource(config_file, true)) printf(" Passed without errors.\n"); else printf(" Encountered one or more errors.\n"); printf("\nChecking config file: %s\n", realm_config_file); if(Config.RealmConfig.SetSource(realm_config_file, true)) printf(" Passed without errors.\n"); else printf(" Encountered one or more errors.\n"); /* test for die variables */ string die; if(Config.MainConfig.GetString("die", "msg", &die) || Config.MainConfig.GetString("die2", "msg", &die)) printf("Die directive received: %s", die.c_str()); return true; } sLog.outString("The key combination <Ctrl-C> will safely shut down the server at any time."); sLog.outString(""); sLog.outString("Initializing File Loggers..."); Crash_Log = new TextLogger(FormatOutputString("logs", "CrashLog", true).c_str(), false); sLog.outString("Initializing Random Number Generators..."); uint32 seed = time(NULL); new MTRand(seed); srand(seed); sLog.outString("Starting Thread Manager...\n"); new ThreadMgr; uint32 LoadingTime = getMSTime(); sLog.outColor(TNORMAL, "Loading Config Files...\n"); sLog.outColor(TYELLOW, " >> %s :: ", config_file); if(Config.MainConfig.SetSource(config_file)) { sLog.outColor(TGREEN, "ok!"); sLog.outColor(TNORMAL, "\n"); } else { sLog.outColor(TRED, "fail."); sLog.outColor(TNORMAL, "\n"); return false; } /* test for die variables */ string die; if(Config.MainConfig.GetString("die", "msg", &die) || Config.MainConfig.GetString("die2", "msg", &die)) { printf("Die directive received: %s", die.c_str()); return false; } sLog.outColor(TYELLOW, " >> %s :: ", realm_config_file); if(Config.RealmConfig.SetSource(realm_config_file)) { sLog.outColor(TGREEN, "ok!"); sLog.outColor(TNORMAL, "\n\n"); } else { sLog.outColor(TRED, "fail."); sLog.outColor(TNORMAL, "\n\n"); return false; } if(!_StartDB()) { return false; } sLog.outString(""); ScriptSystem = new ScriptEngine; ScriptSystem->Reload(); new EventMgr; new World; // open cheat log file Anticheat_Log = new SessionLogWriter(FormatOutputString("logs", "cheaters", false).c_str(), false); GMCommand_Log = new SessionLogWriter(FormatOutputString("logs", "gmcommand", false).c_str(), false); /* load the config file */ sWorld.Rehash(false); /* set new log levels */ if(screen_log_level != (int)DEF_VALUE_NOT_SET) sLog.SetScreenLoggingLevel(screen_log_level); if(file_log_level != (int)DEF_VALUE_NOT_SET) sLog.SetFileLoggingLevel(file_log_level); // Initialize Opcode Table WorldSession::InitPacketHandlerTable(); string host = Config.MainConfig.GetStringDefault("Listen", "Host", DEFAULT_HOST); int wsport = Config.MainConfig.GetIntDefault("Listen", "WorldServerPort", DEFAULT_WORLDSERVER_PORT); new ScriptMgr; sWorld.SetInitialWorldSettings(); sWorld.SetStartTime((uint32)time(NULL)); _HookSignals(); launch_thread(new CConsoleThread); uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); // initialize thread system sThreadMgr.Initialize(); // Socket loop! uint32 start; uint32 diff; uint32 last_time = now(); uint32 etime; uint32 next_printout = getMSTime(), next_send = getMSTime(); // Start Network Subsystem sLog.outString("Starting network subsystem..."); new SocketMgr; new SocketGarbageCollector; sSocketMgr.SpawnWorkerThreads(); sScriptMgr.LoadScripts(); sLog.outString("Threading system initialized, currently %u threads are active.", sThreadMgr.GetThreadCount()); LoadingTime = getMSTime() - LoadingTime; sLog.outString ("\nServer is ready for connections. Startup time: %ums\n", LoadingTime ); /* write pid file */ FILE * fPid = fopen("antrix.pid", "w"); if(fPid) { uint32 pid; #ifdef WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif fprintf(fPid, "%u", (unsigned int)pid); fclose(fPid); } #ifndef CLUSTERING /* Connect to realmlist servers / logon servers */ new LogonCommHandler(); sLogonCommHandler.Startup(); // Create listener ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(host.c_str(), wsport); bool listnersockcreate = ls->IsOpen(); while(!m_stopEvent && listnersockcreate) #else new ClusterInterface; sClusterInterface.ConnectToRealmServer(); while(!m_stopEvent) #endif { start = now(); diff = start - last_time; #ifndef CLUSTERING sLogonCommHandler.UpdateSockets(); ls->Update(); #else sClusterInterface.Update(); #endif sSocketGarbageCollector.Update(); /* UPDATE */ last_time = now(); etime = last_time - start; if(m_ShutdownEvent) { if(getMSTime() >= next_printout) { if(m_ShutdownTimer > 60000.0f) { if(!((int)(m_ShutdownTimer)%60000)) sLog.outString("Server shutdown in %i minutes.", (int)(m_ShutdownTimer / 60000.0f)); } else sLog.outString("Server shutdown in %i seconds.", (int)(m_ShutdownTimer / 1000.0f)); next_printout = getMSTime() + 500; } if(getMSTime() >= next_send) { // broadcast packet. WorldPacket data(20); data.SetOpcode(SMSG_SERVER_MESSAGE); data << uint32(SERVER_MSG_SHUTDOWN_TIME); int time = m_ShutdownTimer / 1000; if(time > 0) { int mins = 0, secs = 0; if(time > 60) mins = time / 60; if(mins) time -= (mins*60); secs = time; char str[20]; snprintf(str, 20, "%02u:%02u", mins, secs); data << str; sWorld.SendGlobalMessage(&data, NULL); } next_send = getMSTime() + 1000; } if(diff >= m_ShutdownTimer) break; else m_ShutdownTimer -= diff; } Database_Character->CheckConnections(); Database_World->CheckConnections(); sWorld.UpdateQueuedSessions(diff); if(50 > etime) Sleep(50 - etime); } _UnhookSignals(); CConsoleThread *thread = (CConsoleThread*)sThreadMgr.GetThreadByType(THREADTYPE_CONSOLEINTERFACE); ASSERT(thread); thread->SetThreadState(THREADSTATE_TERMINATE); // have to cleanup manually. sThreadMgr.RemoveThread(thread); sLog.outString("Killing all sockets and network subsystem."); #ifndef CLUSTERING ls->Close(); delete ls; #endif #ifdef WIN32 sSocketMgr.ShutdownThreads(); #endif sSocketMgr.CloseAll(); // begin server shutdown time_t st = time(NULL); sLog.outString("Server shutdown initiated at %s", ctime(&st)); // send a query to wake it up if its inactive sLog.outString("Executing pending database queries and closing database thread..."); // kill the database thread first so we don't lose any queries/data ((MySQLDatabase*)Database_Character)->SetThreadState(THREADSTATE_TERMINATE); ((MySQLDatabase*)Database_World)->SetThreadState(THREADSTATE_TERMINATE); CharacterDatabase.Execute("UPDATE characters SET online = 0"); WorldDatabase.Execute("UPDATE characters SET online = 0"); // wait for it to finish its work while(((MySQLDatabase*)Database_Character)->ThreadRunning || ((MySQLDatabase*)Database_World)->ThreadRunning) { Sleep(100); } sThreadMgr.RemoveThread(((MySQLDatabase*)Database_Character)); sThreadMgr.RemoveThread(((MySQLDatabase*)Database_World)); sLog.outString("All pending database operations cleared.\n"); sWorld.SaveAllPlayers(); sLog.outString(""); delete LogonCommHandler::getSingletonPtr(); sWorld.ShutdownClasses(); sLog.outString("\nDeleting World..."); delete World::getSingletonPtr(); sLog.outString("Deleting Event Manager..."); delete EventMgr::getSingletonPtr(); sLog.outString("Terminating MySQL connections...\n"); _StopDB(); sLog.outString("Deleting Network Subsystem..."); delete SocketMgr::getSingletonPtr(); delete SocketGarbageCollector::getSingletonPtr(); sLog.outString("Deleting Script Engine..."); delete ScriptSystem; sLog.outString("\nServer shutdown completed successfully.\n"); // close the logs TextLogger::Thread->Die(); #ifdef WIN32 WSACleanup(); // Terminate Entire Application //HANDLE pH = OpenProcess(PROCESS_TERMINATE, TRUE, GetCurrentProcessId()); //TerminateProcess(pH, 0); //CloseHandle(pH); #endif return true; }
bool Master::Run(int /*argc*/, char** /*argv*/) { char* config_file = (char*)CONFDIR "/world.conf"; UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); AscLog.InitalizeLogFiles("world"); PrintBanner(); LogDefault("The key combination <Ctrl-C> will safely shut down the server."); #ifndef WIN32 if (geteuid() == 0 || getegid() == 0) AscLog.ConsoleLogMajorError("You are running AscEmu as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user."); #endif InitImplicitTargetFlags(); ThreadPool.Startup(); auto startTime = Util::TimeNow(); new EventMgr; new World; if (!LoadWorldConfiguration(config_file)) { return false; } sWorld.loadWorldConfigValues(); AscLog.SetFileLoggingLevel(worldConfig.log.worldFileLogLevel); AscLog.SetDebugFlags(worldConfig.log.worldDebugFlags); OpenCheatLogFiles(); if (!_StartDB()) { Database::CleanupLibs(); AscLog.~AscEmuLog(); return false; } if (!_CheckDBVersion()) { AscLog.~AscEmuLog(); return false; } // Initialize Opcode Table WorldSession::InitPacketHandlerTable(); new ScriptMgr; if (!sWorld.setInitialWorldSettings()) { LOG_ERROR("SetInitialWorldSettings() failed. Something went wrong? Exiting."); AscLog.~AscEmuLog(); return false; } sWorld.setWorldStartTime((uint32)UNIXTIME); worldRunnable = std::move(std::make_unique<WorldRunnable>()); _HookSignals(); ConsoleThread* console = new ConsoleThread(); ThreadPool.ExecuteTask(console); StartNetworkSubsystem(); sSocketMgr.SpawnWorkerThreads(); sScriptMgr.LoadScripts(); if (worldConfig.startup.enableSpellIdDump) { sScriptMgr.DumpUnimplementedSpells(); } LogDetail("Server : Ready for connections. Startup time: %u ms", Util::GetTimeDifferenceToNow(startTime)); ThreadPool.ExecuteTask(new GameEventMgr::GameEventMgrThread()); StartRemoteConsole(); WritePidFile(); if (!ChannelMgr::getSingletonPtr()) new ChannelMgr; channelmgr.seperatechannels = worldConfig.server.seperateChatChannels; if (!MailSystem::getSingletonPtr()) new MailSystem; uint32_t mailFlags = 0; if (worldConfig.mail.isCostsForGmDisabled) mailFlags |= MAIL_FLAG_NO_COST_FOR_GM; if (worldConfig.mail.isCostsForEveryoneDisabled) mailFlags |= MAIL_FLAG_DISABLE_POSTAGE_COSTS; if (worldConfig.mail.isDelayItemsDisabled) mailFlags |= MAIL_FLAG_DISABLE_HOUR_DELAY_FOR_ITEMS; if (worldConfig.mail.isMessageExpiryDisabled) mailFlags |= MAIL_FLAG_NO_EXPIRY; if (worldConfig.mail.isInterfactionMailEnabled) mailFlags |= MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION; if (worldConfig.mail.isInterfactionMailForGmEnabled) mailFlags |= MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION_GM; sMailSystem.config_flags = mailFlags; //ThreadPool.Gobble(); /* Connect to realmlist servers / logon servers */ new LogonCommHandler(); sLogonCommHandler.startLogonCommHandler(); // Create listener ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(worldConfig.listen.listenHost.c_str(), worldConfig.listen.listenPort); bool listnersockcreate = ls->IsOpen(); #ifdef WIN32 if (listnersockcreate) ThreadPool.ExecuteTask(ls); #endif ShutdownThreadPools(listnersockcreate); _UnhookSignals(); worldRunnable->threadShutdown(); worldRunnable = nullptr; ThreadPool.ShowStats(); /* Shut down console system */ console->stopThread(); delete console; // begin server shutdown ShutdownLootSystem(); // send a query to wake it up if its inactive LogNotice("Database : Clearing all pending queries..."); // kill the database thread first so we don't lose any queries/data CharacterDatabase.EndThreads(); WorldDatabase.EndThreads(); ls->Close(); CloseConsoleListener(); sWorld.saveAllPlayersToDb(); LogNotice("Network : Shutting down network subsystem."); #ifdef WIN32 sSocketMgr.ShutdownThreads(); #endif sSocketMgr.CloseAll(); bServerShutdown = true; ThreadPool.Shutdown(); delete ls; sWorld.logoutAllPlayers(); delete LogonCommHandler::getSingletonPtr(); LogNotice("AddonMgr : ~AddonMgr()"); #if VERSION_STRING != Cata sAddonMgr.SaveToDB(); #endif delete AddonMgr::getSingletonPtr(); LogNotice("AuctionMgr : ~AuctionMgr()"); delete AuctionMgr::getSingletonPtr(); LogNotice("LootMgr : ~LootMgr()"); delete LootMgr::getSingletonPtr(); LogNotice("MailSystem : ~MailSystem()"); delete MailSystem::getSingletonPtr(); LogNotice("World : ~World()"); delete World::getSingletonPtr(); sScriptMgr.UnloadScripts(); delete ScriptMgr::getSingletonPtr(); LogNotice("ChatHandler : ~ChatHandler()"); delete ChatHandler::getSingletonPtr(); LogNotice("EventMgr : ~EventMgr()"); delete EventMgr::getSingletonPtr(); LogNotice("Database : Closing Connections..."); _StopDB(); LogNotice("Network : Deleting Network Subsystem..."); delete SocketMgr::getSingletonPtr(); delete SocketGarbageCollector::getSingletonPtr(); delete GMCommand_Log; delete Anticheat_Log; delete Player_Log; // remove pid if (remove("worldserver.pid") != 0) { LOG_ERROR("Error deleting file worldserver.pid"); } else { LOG_DEBUG("File worldserver.pid successfully deleted"); } LogDetail("Shutdown : Shutdown complete."); AscLog.~AscEmuLog(); #ifdef WIN32 WSACleanup(); #endif return true; }
bool Master::Run() { sLog.outString( "MaNGOS daemon %s", _FULLVERSION ); sLog.outString( "<Ctrl-C> to stop.\n" ); _StartDB(); loglevel = (uint8)sConfig.GetIntDefault("LogLevel", DEFAULT_LOG_LEVEL); std::string host; host = sConfig.GetStringDefault( "Host", DEFAULT_HOST ); sLog.outString( "Server: %s\n", host.c_str() ); new World; sWorld.SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT) ); sWorld.SetMotd( sConfig.GetStringDefault("Motd", "Welcome to the Massive Network Game Object Server." ).c_str() ); sWorld.SetInitialWorldSettings(); port_t wsport, rmport; rmport = sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT ); wsport = sConfig.GetIntDefault( "WorldServerPort", DEFAULT_WORLDSERVER_PORT ); // load regeneration rates. sWorld.setRate(RATE_HEALTH,sConfig.GetFloatDefault("Rate.Health",DEFAULT_REGEN_RATE)); sWorld.setRate(RATE_POWER1,sConfig.GetFloatDefault("Rate.Power1",DEFAULT_REGEN_RATE)); sWorld.setRate(RATE_POWER2,sConfig.GetFloatDefault("Rate.Power2",DEFAULT_REGEN_RATE)); sWorld.setRate(RATE_POWER3,sConfig.GetFloatDefault("Rate.Power4",DEFAULT_REGEN_RATE)); sWorld.setRate(RATE_DROP,sConfig.GetFloatDefault("Rate.Drop",DEFAULT_DROP_RATE)); sWorld.setRate(RATE_XP,sConfig.GetFloatDefault("Rate.XP",DEFAULT_XP_RATE)); sRealmList.setServerPort(wsport); sRealmList.GetAndAddRealms (); SocketHandler h; ListenSocket<WorldSocket> worldListenSocket(h); ListenSocket<AuthSocket> authListenSocket(h); if (worldListenSocket.Bind(wsport) || authListenSocket.Bind(rmport)) { delete World::getSingletonPtr(); _StopDB(); return 0; } h.Add(&worldListenSocket); h.Add(&authListenSocket); _HookSignals(); ZThread::Thread t(new WorldRunnable); uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); while (!Master::m_stopEvent) { // uint32 exceeded if (realPrevTime > realCurrTime) realPrevTime = 0; realCurrTime = getMSTime(); sWorldSocketMgr.Update( realCurrTime - realPrevTime ); realPrevTime = realCurrTime; h.Select(0, 100000); // 100 ms } _UnhookSignals(); t.wait(); delete World::getSingletonPtr(); _StopDB(); sLog.outString( "Halting process..." ); return 0; }
bool Master::Run(int argc, char ** argv) { m_stopEvent = false; char * config_file = (char*)default_config_file; char * options_config_file = (char*)default_options_config_file; int screen_log_level = DEF_VALUE_NOT_SET; int do_check_conf = 0; int do_version = 0; int do_cheater_check = 0; int do_database_clean = 0; time_t curTime; struct hearthstone_option longopts[] = { { "checkconf", hearthstone_no_argument, &do_check_conf, 1 }, { "screenloglevel", hearthstone_required_argument, &screen_log_level, 1 }, { "version", hearthstone_no_argument, &do_version, 1 }, { "cheater", hearthstone_no_argument, &do_cheater_check, 1 }, { "cleandb", hearthstone_no_argument, &do_database_clean, 1 }, { "conf", hearthstone_required_argument, NULL, 'c' }, { "realmconf", hearthstone_required_argument, NULL, 'r' }, { 0, 0, 0, 0 } }; char c; while ((c = hearthstone_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'c': config_file = new char[strlen(hearthstone_optarg)]; strcpy(config_file, hearthstone_optarg); break; case 'o': options_config_file = new char[strlen(hearthstone_optarg)]; strcpy(options_config_file, hearthstone_optarg); break; case 0: break; default: sLog.m_screenLogLevel = 3; printf("Usage: %s [--checkconf] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]); return true; } } /* set new log levels if used as argument*/ if( screen_log_level != (int)DEF_VALUE_NOT_SET ) sLog.SetScreenLoggingLevel(screen_log_level); // Startup banner UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); printf(BANNER, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH); printf("Built at %s on %s by %s@%s\n", BUILD_TIME, BUILD_DATE, BUILD_USER, BUILD_HOST); Log.Line(); if( do_check_conf ) { Log.Notice( "Config", "Checking config file: %s", config_file ); if( Config.MainConfig.SetSource(config_file, true ) ) Log.Success( "Config", "Passed without errors." ); else Log.Warning( "Config", "Encountered one or more errors." ); Log.Notice( "Config", "Checking config file: %s\n", options_config_file ); if( Config.OptionalConfig.SetSource( options_config_file, true ) ) Log.Success( "Config", "Passed without errors.\n" ); else Log.Warning( "Config", "Encountered one or more errors.\n" ); return true; } printf( "The key combination <Ctrl-C> will safely shut down the server at any time.\n" ); Log.Line(); //use these log_level until we are fully started up. #ifdef _DEBUG sLog.Init(3); #else sLog.Init(1); #endif // _DEBUG #ifndef WIN32 if(geteuid() == 0 || getegid() == 0) Log.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running Hearthstone as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL); #endif InitRandomNumberGenerators(); Log.Success( "Rnd", "Initialized Random Number Generators." ); ThreadPool.Startup(); uint32 LoadingTime = getMSTime(); Log.Notice( "Config", "Loading Config Files..." ); if( Config.MainConfig.SetSource( config_file ) ) Log.Success( "Config", ">> hearthstone-world.conf" ); else { Log.Error( "Config", ">> hearthstone-world.conf" ); return false; } if(Config.OptionalConfig.SetSource(options_config_file)) Log.Success( "Config", ">> hearthstone-options.conf" ); else { Log.Error( "Config", ">> hearthstone-options.conf" ); return false; } if(!_StartDB()) { Database::CleanupLibs(); return false; } Log.Line(); sLog.outString( "" ); new EventMgr; new World; /* load the config file */ sWorld.Rehash(true); // Because of our log DB system, these have to be initialized different then rehash. sWorld.LogCheaters = Config.MainConfig.GetBoolDefault("Log", "Cheaters", false); sWorld.LogCommands = Config.MainConfig.GetBoolDefault("Log", "GMCommands", false); sWorld.LogPlayers = Config.MainConfig.GetBoolDefault("Log", "Player", false); sWorld.LogChats = Config.MainConfig.GetBoolDefault("Log", "Chat", false); //Update sLog to obey config setting sLog.Init(Config.MainConfig.GetIntDefault("LogLevel", "Screen", 1)); // Initialize Opcode Table WorldSession::InitPacketHandlerTable(); new ScriptMgr; if( !sWorld.SetInitialWorldSettings() ) { Log.Error( "Server", "SetInitialWorldSettings() failed. Something went wrong? Exiting." ); return false; } sWorld.SetStartTime(uint32(UNIXTIME)); WorldRunnable *wr = new WorldRunnable(); ThreadPool.ExecuteTask(wr); _HookSignals(); ConsoleThread* console = new ConsoleThread(); ThreadPool.ExecuteTask(console); uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); // Socket loop! uint32 start; uint32 diff; uint32 last_time = now(); uint32 etime; // Start Network Subsystem DEBUG_LOG("Server","Starting network subsystem..." ); CreateSocketEngine(); sSocketEngine.SpawnThreads(); if( StartConsoleListener() ) { #ifdef WIN32 ThreadPool.ExecuteTask( GetConsoleListener() ); #endif Log.Success("RemoteConsole", "Started and listening on port %i",Config.MainConfig.GetIntDefault("RemoteConsole", "Port", 8092)); } else DEBUG_LOG("RemoteConsole", "Not enabled or failed listen."); LoadingTime = getMSTime() - LoadingTime; Log.Success("Server","Ready for connections. Startup time: %ums\n", LoadingTime ); /* write pid file */ FILE * fPid = fopen( "hearthstone-world.pid", "w" ); if( fPid ) { uint32 pid; #ifdef WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif fprintf( fPid, "%u", uint(pid) ); fclose( fPid ); } #ifdef WIN32 HANDLE hThread = GetCurrentThread(); #endif uint32 loopcounter = 0; //ThreadPool.Gobble(); new ClusterInterface; sClusterInterface.ConnectToRealmServer(); while(!m_stopEvent) { start = now(); diff = start - last_time; if(! ((++loopcounter) % 10000) ) // 5mins { ThreadPool.ShowStats(); ThreadPool.IntegrityCheck();//Checks if THREAD_RESERVE is met } /* since time() is an expensive system call, we only update it once per server loop */ curTime = time(NULL); if( UNIXTIME != curTime ) { UNIXTIME = time(NULL); g_localTime = *localtime(&curTime); } sClusterInterface.Update(); sSocketDeleter.Update(); /* UPDATE */ last_time = now(); etime = last_time - start; if( 50 > etime ) { #ifdef WIN32 WaitForSingleObject( hThread, 50 - etime ); #else Sleep( 50 - etime ); #endif } } // begin server shutdown Log.Notice( "Shutdown", "Initiated at %s", ConvertTimeStampToDataTime( (uint32)UNIXTIME).c_str() ); bServerShutdown = true; wr->Terminate(); /* Shut down console system */ CloseConsoleListener(); console->terminate(); delete console; if( lootmgr.is_loading ) { Log.Notice( "Shutdown", "Waiting for loot to finish loading..." ); while( lootmgr.is_loading ) Sleep( 100 ); } Log.Notice( "CharacterLoaderThread", "Exiting..." ); sCLT.Terminate(); sWorld.LogoutPlayers(); //(Also saves players). CharacterDatabase.Execute("UPDATE characters SET online = 0"); // send a query to wake it up if its inactive Log.Notice( "Database", "Clearing all pending queries..." ); // kill the database thread first so we don't lose any queries/data CharacterDatabase.EndThreads(); WorldDatabase.EndThreads(); if(Config.MainConfig.GetBoolDefault("Log", "Cheaters", false) || Config.MainConfig.GetBoolDefault("Log", "GMCommands", false) || Config.MainConfig.GetBoolDefault("Log", "Player", false) || Config.MainConfig.GetBoolDefault("Log", "Chat", false)) LogDatabase.EndThreads(); Log.Notice("Server", "Shutting down random generator."); CleanupRandomNumberGenerators(); if(wintergrasp) { Log.Notice( "WintergraspInternal", "Exiting..." ); sWintergraspI.terminate(); } Log.Notice( "DayWatcherThread", "Exiting..." ); sDayWatcher.terminate(); Log.Notice( "Network", "Shutting down network subsystem." ); sSocketEngine.Shutdown(); sAddonMgr.SaveToDB(); Log.Notice("AddonMgr", "~AddonMgr()"); delete AddonMgr::getSingletonPtr(); Log.Notice("LootMgr", "~LootMgr()"); delete LootMgr::getSingletonPtr(); Log.Notice("MailSystem", "~MailSystem()"); delete MailSystem::getSingletonPtr(); ThreadPool.Shutdown(); Log.Notice("CharacterLoaderThread", "~CharacterLoaderThread()"); delete CharacterLoaderThread::getSingletonPtr(); if(wintergrasp) { Log.Notice("WintergraspInternal", "~WintergraspInternal()"); delete WintergraspInternal::getSingletonPtr(); } Log.Notice( "World", "~World()" ); delete World::getSingletonPtr(); Log.Notice( "ScriptMgr", "~ScriptMgr()" ); sScriptMgr.UnloadScripts(); delete ScriptMgr::getSingletonPtr(); Log.Notice( "EventMgr", "~EventMgr()" ); delete EventMgr::getSingletonPtr(); Log.Notice( "Database", "Closing Connections..." ); _StopDB(); _UnhookSignals(); #ifdef WIN32 WSACleanup(); #endif // remove pid remove( "hearthstone-world.pid" ); Log.Notice( "Shutdown", "Shutdown complete." ); Sleep(1000); return true; }
bool Master::Run(int argc, char ** argv) { char * config_file = (char*)default_config_file; char * realm_config_file = (char*)default_realm_config_file; int file_log_level = DEF_VALUE_NOT_SET; int screen_log_level = DEF_VALUE_NOT_SET; int do_check_conf = 0; int do_version = 0; int do_cheater_check = 0; int do_database_clean = 0; time_t curTime; struct hearthstone_option longopts[] = { { "checkconf", hearthstone_no_argument, &do_check_conf, 1 }, { "screenloglevel", hearthstone_required_argument, &screen_log_level, 1 }, { "fileloglevel", hearthstone_required_argument, &file_log_level, -1 }, { "version", hearthstone_no_argument, &do_version, 1 }, { "conf", hearthstone_required_argument, NULL, 'c' }, { "realmconf", hearthstone_required_argument, NULL, 'r' }, { 0, 0, 0, 0 } }; char c; while ((c = hearthstone_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'c': config_file = new char[strlen(hearthstone_optarg)]; strcpy(config_file, hearthstone_optarg); break; case 'r': realm_config_file = new char[strlen(hearthstone_optarg)]; strcpy(realm_config_file, hearthstone_optarg); break; case 0: break; default: sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 3; printf("Usage: %s [--checkconf] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]); return true; } } /* set new log levels if used as argument*/ if( screen_log_level != (int)DEF_VALUE_NOT_SET ) sLog.SetScreenLoggingLevel(screen_log_level); if( file_log_level != (int)DEF_VALUE_NOT_SET ) sLog.SetFileLoggingLevel(file_log_level); // Startup banner UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); printf(BANNER, BUILD_BRANCH, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH); printf("Built at %s on %s by %s@%s\n", BUILD_TIME, BUILD_DATE, BUILD_USER, BUILD_HOST); Log.Line(); if( do_check_conf ) { Log.Notice( "Config", "Checking config file: %s", config_file ); if( Config.MainConfig.SetSource(config_file, true ) ) Log.Success( "Config", "Passed without errors." ); else Log.Warning( "Config", "Encountered one or more errors." ); Log.Notice( "Config", "Checking config file: %s\n", realm_config_file ); if( Config.RealmConfig.SetSource( realm_config_file, true ) ) Log.Success( "Config", "Passed without errors.\n" ); else Log.Warning( "Config", "Encountered one or more errors.\n" ); /* test for die variables */ string die; if( Config.MainConfig.GetString( "die", "msg", &die) || Config.MainConfig.GetString("die2", "msg", &die ) ) Log.Warning( "Config", "Die directive received: %s", die.c_str() ); return true; } printf( "The key combination <Ctrl-C> will safely shut down the server at any time.\n" ); Log.Line(); //use these log_level until we are fully started up. sLog.Init(-1, 3); #ifndef WIN32 if(geteuid() == 0 || getegid() == 0) Log.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running Ascent as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL); #endif InitRandomNumberGenerators(); Log.Success( "Rnd", "Initialized Random Number Generators." ); ThreadPool.Startup(); uint32 LoadingTime = getMSTime(); Log.Notice( "Config", "Loading Config Files...\n" ); if( Config.MainConfig.SetSource( config_file ) ) Log.Success( "Config", ">> hearthstone-world.conf" ); else { Log.Error( "Config", ">> hearthstone-world.conf" ); return false; } string die; if( Config.MainConfig.GetString( "die", "msg", &die) || Config.MainConfig.GetString( "die2", "msg", &die ) ) { Log.Warning( "Config", "Die directive received: %s", die.c_str() ); return false; } if(Config.RealmConfig.SetSource(realm_config_file)) Log.Success( "Config", ">> hearthstone-realms.conf" ); else { Log.Error( "Config", ">> hearthstone-realms.conf" ); return false; } if( !_StartDB() ) { Database::CleanupLibs(); return false; } Log.Line(); sLog.outString( "" ); //ScriptSystem = new ScriptEngine; //ScriptSystem->Reload(); new EventMgr; WorldPointer shWorld(new World); // Need this so we're not deleted. // open cheat log file Anticheat_Log = new SessionLogWriter(FormatOutputString( "logs", "cheaters", false).c_str(), false ); GMCommand_Log = new SessionLogWriter(FormatOutputString( "logs", "gmcommand", false).c_str(), false ); Player_Log = new SessionLogWriter(FormatOutputString( "logs", "players", false).c_str(), false ); /* load the config file */ sWorld.Rehash(false); // Initialize Opcode Table WorldSession::InitPacketHandlerTable(); string host = Config.MainConfig.GetStringDefault( "Listen", "Host", DEFAULT_HOST ); int wsport = Config.MainConfig.GetIntDefault( "Listen", "WorldServerPort", DEFAULT_WORLDSERVER_PORT ); new ScriptMgr; if( !sWorld.SetInitialWorldSettings() ) { Log.Error( "Server", "SetInitialWorldSettings() failed. Something went wrong? Exiting." ); return false; } g_bufferPool.Init(); sWorld.SetStartTime((uint32)UNIXTIME); WorldRunnable * wr = new WorldRunnable(); ThreadPool.ExecuteTask(wr); _HookSignals(); ConsoleThread * console = new ConsoleThread(); ThreadPool.ExecuteTask(console); uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); // Socket loop! uint32 start; uint32 diff; uint32 last_time = now(); uint32 etime; // Start Network Subsystem DEBUG_LOG("Server","Starting network subsystem..." ); new SocketMgr; new SocketGarbageCollector; sSocketMgr.SpawnWorkerThreads(); if( StartConsoleListener() ) { #ifdef WIN32 ThreadPool.ExecuteTask( GetConsoleListener() ); #endif Log.Success("RemoteConsole", "Started and listening on port %i",Config.MainConfig.GetIntDefault("RemoteConsole", "Port", 8092)); } else DEBUG_LOG("RemoteConsole", "Not enabled or failed listen."); sLog.outString(""); LoadingTime = getMSTime() - LoadingTime; Log.Success("Server","Ready for connections. Startup time: %ums\n", LoadingTime ); sLog.outString(""); //Update sLog to obey config setting sLog.Init(Config.MainConfig.GetIntDefault("LogLevel", "File", -1),Config.MainConfig.GetIntDefault("LogLevel", "Screen", 1)); /* write pid file */ FILE * fPid = fopen( "ascent.pid", "w" ); if( fPid ) { uint32 pid; #ifdef WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif fprintf( fPid, "%u", (unsigned int)pid ); fclose( fPid ); } #ifdef WIN32 HANDLE hThread = GetCurrentThread(); #endif uint32 loopcounter = 0; //ThreadPool.Gobble(); #ifndef CLUSTERING /* Connect to realmlist servers / logon servers */ new LogonCommHandler(); sLogonCommHandler.Startup(); /* voicechat */ #ifdef VOICE_CHAT new VoiceChatHandler(); sVoiceChatHandler.Startup(); #endif // Create listener ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(host.c_str(), wsport); bool listnersockcreate = ls->IsOpen(); #ifdef WIN32 if( listnersockcreate ) ThreadPool.ExecuteTask(ls); #endif while( !m_stopEvent && listnersockcreate ) #else new ClusterInterface; sClusterInterface.ConnectToRealmServer(); while(!m_stopEvent) #endif { start = now(); diff = start - last_time; if(! ((++loopcounter) % 10000) ) // 5mins { ThreadPool.ShowStats(); ThreadPool.IntegrityCheck();//Checks if THREAD_RESERVE is met g_bufferPool.Optimize(); } /* since time() is an expensive system call, we only update it once per server loop */ curTime = time(NULL); if( UNIXTIME != curTime ) { UNIXTIME = time(NULL); g_localTime = *localtime(&curTime); } #ifndef CLUSTERING #ifdef VOICE_CHAT sVoiceChatHandler.Update(); #endif #else sClusterInterface.Update(); #endif sSocketGarbageCollector.Update(); /* UPDATE */ last_time = now(); etime = last_time - start; if( 50 > etime ) { #ifdef WIN32 WaitForSingleObject( hThread, 50 - etime ); #else Sleep( 50 - etime ); #endif } } _UnhookSignals(); wr->Terminate(); ThreadPool.ShowStats(); /* Shut down console system */ console->terminate(); delete console; // begin server shutdown Log.Notice( "Shutdown", "Initiated at %s", ConvertTimeStampToDataTime( (uint32)UNIXTIME).c_str() ); if( lootmgr.is_loading ) { Log.Notice( "Shutdown", "Waiting for loot to finish loading..." ); while( lootmgr.is_loading ) Sleep( 100 ); } Log.Notice( "CharacterLoaderThread", "Exiting..." ); ctl->Terminate(); ctl = NULL; sWorld.LogoutPlayers(); //(Also saves players). CharacterDatabase.Execute("UPDATE characters SET online = 0"); // send a query to wake it up if its inactive Log.Notice( "Database", "Clearing all pending queries..." ); // kill the database thread first so we don't lose any queries/data CharacterDatabase.EndThreads(); WorldDatabase.EndThreads(); Log.Notice("Server", "Shutting down random generator."); CleanupRandomNumberGenerators(); Log.Notice( "DayWatcherThread", "Exiting..." ); dw->terminate(); dw = NULL; #ifndef CLUSTERING ls->Close(); #endif CloseConsoleListener(); delete ls; Log.Notice( "Network", "Shutting down network subsystem." ); #ifdef WIN32 sSocketMgr.ShutdownThreads(); #endif sSocketMgr.CloseAll(); Log.Notice("AddonMgr", "~AddonMgr()"); sAddonMgr.SaveToDB(); delete AddonMgr::getSingletonPtr(); Log.Notice("AuctionMgr", "~AuctionMgr()"); delete AuctionMgr::getSingletonPtr(); Log.Notice("LootMgr", "~LootMgr()"); delete LootMgr::getSingletonPtr(); Log.Notice("MailSystem", "~MailSystem()"); delete MailSystem::getSingletonPtr(); bServerShutdown = true; ThreadPool.Shutdown(); sLog.outString( "" ); delete LogonCommHandler::getSingletonPtr(); Log.Notice( "World", "~World()" ); //delete World::getSingletonPtr(); World::getSingletonPtr()->Destructor(); sScriptMgr.UnloadScripts(); delete ScriptMgr::getSingletonPtr(); Log.Notice( "ChatHandler", "~ChatHandler()" ); delete ChatHandler::getSingletonPtr(); Log.Notice( "EventMgr", "~EventMgr()" ); delete EventMgr::getSingletonPtr(); Log.Notice( "Database", "Closing Connections..." ); _StopDB(); Log.Notice( "Network", "Deleting Network Subsystem..." ); delete SocketMgr::getSingletonPtr(); delete SocketGarbageCollector::getSingletonPtr(); #ifdef VOICE_CHAT Log.Notice( "VoiceChatHandler", "~VoiceChatHandler()" ); delete VoiceChatHandler::getSingletonPtr(); #endif #ifdef ENABLE_LUA_SCRIPTING sLog.outString("Deleting Script Engine..."); LuaEngineMgr::getSingleton().Unload(); #endif //delete ScriptSystem; delete GMCommand_Log; delete Anticheat_Log; delete Player_Log; // remove pid remove( "ascent.pid" ); g_bufferPool.Destroy(); Log.Notice( "Shutdown", "Shutdown complete." ); #ifdef WIN32 WSACleanup(); // Terminate Entire Application //HANDLE pH = OpenProcess(PROCESS_TERMINATE, TRUE, GetCurrentProcessId()); //TerminateProcess(pH, 0); //CloseHandle(pH); #endif return true; }
/// Main function int Master::Run() { OpenSSLCrypto::threadsSetup(); BigNumber seed1; seed1.SetRand(16 * 8); TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", _FULLVERSION); TC_LOG_INFO("server.worldserver", " "); TC_LOG_INFO("server.worldserver", " A World of Warcraft Cataclsym 4.3.4 Emulator "); TC_LOG_INFO("server.worldserver", " _/_/ _/ _/_/_/ _/_/ _/_/_/ _/_/_/_/ "); TC_LOG_INFO("server.worldserver", " _/ _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ "); TC_LOG_INFO("server.worldserver", " _/_/_/_/ _/_/ _/_/ _/ _/ _/ _/_/_/ _/_/_/ "); TC_LOG_INFO("server.worldserver", " _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ "); TC_LOG_INFO("server.worldserver", " _/ _/ _/ _/ _/ _/_/_/ _/_/ _/ _/ _/_/_/_/ NG "); TC_LOG_INFO("server.worldserver", " Arkania Community (c) 2017! <http://arkania.net/> "); TC_LOG_INFO("server.worldserver", " "); TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n"); /// worldserver PID file creation std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); if (!pidFile.empty()) { if (uint32 pid = CreatePIDFile(pidFile)) TC_LOG_INFO("server.worldserver", "Daemon PID: %u\n", pid); else { TC_LOG_ERROR("server.worldserver", "Cannot create PID file %s.\n", pidFile.c_str()); return 1; } } ///- Start the databases if (!_StartDB()) return 1; // set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); ///- Initialize the World sWorld->SetInitialWorldSettings(); ///- Initialize the signal handlers WorldServerSignalHandler signalINT, signalTERM; #ifdef _WIN32 WorldServerSignalHandler signalBREAK; #endif /* _WIN32 */ ///- Register worldserver's signal handlers ACE_Sig_Handler handle; handle.register_handler(SIGINT, &signalINT); handle.register_handler(SIGTERM, &signalTERM); #ifdef _WIN32 handle.register_handler(SIGBREAK, &signalBREAK); #endif ///- Launch WorldRunnable thread ACE_Based::Thread worldThread(new WorldRunnable); worldThread.setPriority(ACE_Based::Highest); ACE_Based::Thread* cliThread = nullptr; #ifdef _WIN32 if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfigMgr->GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rarThread(new RARunnable); #if defined(_WIN32) || defined(__linux__) ///- Handle affinity for multiple processors and process priority uint32 affinity = sConfigMgr->GetIntDefault("UseProcessors", 0); bool highPriority = sConfigMgr->GetBoolDefault("ProcessPriority", false); #ifdef _WIN32 // Windows HANDLE hProcess = GetCurrentProcess(); if (affinity > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) { ULONG_PTR currentAffinity = affinity & appAff; // remove non accessible processors if (!currentAffinity) TC_LOG_ERROR("server.worldserver", "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", affinity, appAff); else if (SetProcessAffinityMask(hProcess, currentAffinity)) TC_LOG_INFO("server.worldserver", "Using processors (bitmask, hex): %x", currentAffinity); else TC_LOG_ERROR("server.worldserver", "Can't set used processors (hex): %x", currentAffinity); } } if (highPriority) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) TC_LOG_INFO("server.worldserver", "worldserver process priority class set to HIGH"); else TC_LOG_ERROR("server.worldserver", "Can't set worldserver process priority class."); } #else // Linux if (affinity > 0) { cpu_set_t mask; CPU_ZERO(&mask); for (unsigned int i = 0; i < sizeof(affinity) * 8; ++i) if (affinity & (1 << i)) CPU_SET(i, &mask); if (sched_setaffinity(0, sizeof(mask), &mask)) TC_LOG_ERROR("server.worldserver", "Can't set used processors (hex): %x, error: %s", affinity, strerror(errno)); else { CPU_ZERO(&mask); sched_getaffinity(0, sizeof(mask), &mask); TC_LOG_INFO("server.worldserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask)); } } if (highPriority) { if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) TC_LOG_ERROR("server.worldserver", "Can't set worldserver process priority class, error: %s", strerror(errno)); else TC_LOG_INFO("server.worldserver", "worldserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); } #endif #endif //Start soap serving thread ACE_Based::Thread* soapThread = nullptr; if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false)) { TCSoapRunnable* runnable = new TCSoapRunnable(); runnable->SetListenArguments(sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))); soapThread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread if (uint32 freezeDelay = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freezeDelay * 1000); ACE_Based::Thread freezeThread(fdr); freezeThread.setPriority(ACE_Based::Highest); } ///- Launch the world listener socket uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork(worldPort, bindIp.c_str()) == -1) { TC_LOG_ERROR("server.worldserver", "Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } // set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION); #ifdef _DEBUG ASSERT(false); // my debugging stop #endif // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master worldThread.wait(); rarThread.wait(); if (soapThread) { soapThread->wait(); soapThread->destroy(); delete soapThread; } // set server offline LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); ///- Clean database before leaving ClearOnlineAccounts(); _StopDB(); TC_LOG_INFO("server.worldserver", "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[4]; 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(); OpenSSLCrypto::threadsCleanup(); // Exit the process with specified return value return World::GetExitCode(); }
/// Main function int Master::Run() { /// 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()); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString("Daemon PID: %u\n", pid); } ///- Start the databases if (!_StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Initialize the World sWorld.SetInitialWorldSettings(); #ifndef _WIN32 detachDaemon(); #endif // server loaded successfully => enable async DB requests // this is done to forbid any async transactions during server startup! CharacterDatabase.AllowAsyncTransactions(); WorldDatabase.AllowAsyncTransactions(); LoginDatabase.AllowAsyncTransactions(); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread MaNGOS::Thread world_thread(new WorldRunnable); world_thread.setPriority(MaNGOS::Priority_Highest); // set realmbuilds depend on mangosd expected builds, and set server online { std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%u'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); } MaNGOS::Thread* cliThread = nullptr; #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 MaNGOS::Thread(new CliRunnable); } ///- 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 mangosd. 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("mangosd process priority class set to HIGH"); else sLog.outError("Can't set mangosd process priority class."); sLog.outString(); } } #endif ///- Start up freeze catcher thread MaNGOS::Thread* freeze_thread = nullptr; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay * 1000); freeze_thread = new MaNGOS::Thread(fdr); freeze_thread->setPriority(MaNGOS::Priority_Highest); } { int32 networkThreadWorker = sConfig.GetIntDefault("Network.Threads", 1); if (networkThreadWorker <= 0) { sLog.outError("Invalid network tread workers setting in mangosd.conf. (%d) should be > 0", networkThreadWorker); networkThreadWorker = 1; } MaNGOS::Listener<WorldSocket> listener(sConfig.GetStringDefault("BindIP", "0.0.0.0"), int32(sWorld.getConfig(CONFIG_UINT32_PORT_WORLD)), networkThreadWorker); std::unique_ptr<MaNGOS::Listener<RASocket>> raListener; if (sConfig.GetBoolDefault("Ra.Enable", false)) raListener.reset(new MaNGOS::Listener<RASocket>(sConfig.GetStringDefault("Ra.IP", "0.0.0.0"), sConfig.GetIntDefault("Ra.Port", 3443), 1)); std::unique_ptr<SOAPThread> soapThread; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) soapThread.reset(new SOAPThread(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878))); // wait for shut down and then let things go out of scope to close them down while (!World::IsStopped()) std::this_thread::sleep_for(std::chrono::seconds(1)); } ///- Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } ///- Set server offline in realmlist LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); ///- Clean account database before leaving clearOnlineAccounts(); // send all still queued mass mails (before DB connections shutdown) sMassMailMgr.Update(true); ///- Wait for DB 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; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // mark this can be killable m_canBeKilled = true; ///- Exit the process with specified return value return World::GetExitCode(); }
bool Master::Run(int argc, char ** argv) { char * config_file = (char*)default_config_file; char * optional_config_file = (char*)default_optional_config_file; char * realm_config_file = (char*)default_realm_config_file; int file_log_level = DEF_VALUE_NOT_SET; int screen_log_level = DEF_VALUE_NOT_SET; int do_check_conf = 0; int do_version = 0; int do_cheater_check = 0; int do_database_clean = 0; time_t curTime; struct arcemu_option longopts[] = { { "checkconf", arcemu_no_argument, &do_check_conf, 1 }, { "screenloglevel", arcemu_required_argument, &screen_log_level, 1 }, { "fileloglevel", arcemu_required_argument, &file_log_level, 1 }, { "version", arcemu_no_argument, &do_version, 1 }, { "conf", arcemu_required_argument, NULL, 'c' }, { "realmconf", arcemu_required_argument, NULL, 'r' }, { "databasecleanup", arcemu_no_argument, &do_database_clean, 1 }, { "cheatercheck", arcemu_no_argument, &do_cheater_check, 1 }, { 0, 0, 0, 0 } }; char c; while ((c = arcemu_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'c': config_file = new char[strlen(arcemu_optarg)]; strcpy(config_file, arcemu_optarg); break; case 'r': realm_config_file = new char[strlen(arcemu_optarg)]; strcpy(realm_config_file, arcemu_optarg); break; case 0: break; default: sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 3; printf("Usage: %s [--checkconf] [--screenloglevel <level>] [--fileloglevel <level>] [--conf <filename>] [--realmconf <filename>] [--version] [--databasecleanup] [--cheatercheck]\n", argv[0]); return true; } } // Startup banner UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); if(!do_version && !do_check_conf) { sLog.Init(-1, 3); } else { sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 1; } printf(BANNER, BUILD_TAG, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH); #ifdef REPACK printf("\nRepack: %s | Author: %s | %s\n", REPACK, REPACK_AUTHOR, REPACK_WEBSITE); #endif Log.Color(TBLUE); printf("\nCopyright (C) 2008 ArcEmu. http://www.arcemu.org/\n"); printf("This program is free software: you can redistribute it and/or modify\n"); printf("it under the terms of the GNU Affero General Public License as published by\n"); printf("the Free Software Foundation, either version 3 of the License, or\n"); printf("any later version.\n"); printf("This program is distributed in the hope that it will be useful,\n"); printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); printf("GNU Affero General Public License for more details.\n"); printf(" \n"); printf(" `````` \n"); printf(" ArcEmu! `/o/::-:/- \n"); printf(" oho/-.-:yN- \n"); printf(" os+/-.::: \n"); printf(" :ysyoo+:` \n"); printf(" `ohdys/. \n"); printf(" oyho/-` `` \n"); printf(" `shyo+:./ssmdsyo:` \n"); printf(" .shss+:yNMMNNMNmms. \n"); printf(" :ysss+:mNMMMMNNmmds. \n"); printf(" `-//sssoo/:NMNMMMNMNNdy- \n"); printf(" -`/` `omhyyhyyyshNMMNNNMMMNmy: \n"); printf(" :/::-` `sdmdmmNMNMMMMMMNMNNNNms- \n"); printf(" /+++/-.....shdmmNMMNMMMMMMMMMNNNd+ \n"); printf(" ./+oshyhhhddmhdmNMMMMMMMMMMMMNNds. \n"); printf(" `:/:.`````.:+ymmNMMNMMMNMMNNd/ \n"); printf(" -+shmNNMMMNmhy/ \n"); printf(" `..-ods:. \n"); printf(" o:.` \n"); printf(" :-. \n"); printf(" `/-... \n"); printf(" Introducing the emu! --``-/:` \n"); printf(" .:/+:-.-::. \n"); printf(" `.-///:-.` \n"); printf(" Website: http://www.ArcEmu.org \n"); printf(" Forums: http://www.ArcEmu.org/forums/ \n"); printf(" Credits: http://www.ArcEmu.org/credits \n"); printf(" SVN: http://arcemu.info/svn/ \n"); printf(" Have fun! \n"); Log.Line(); #ifdef REPACK Log.Color(TRED); printf("Warning: Using repacks is potentially dangerous. You should always compile\n"); printf("from the source yourself at www.arcemu.org.\n"); printf("By using this repack, you agree to not visit the arcemu website and ask\nfor support.\n"); printf("For all support, you should visit the repacker's website at %s\n", REPACK_WEBSITE); Log.Color(TNORMAL); Log.Line(); #endif Log.log_level = 3; if(do_version) return true; if( do_check_conf ) { Log.Notice( "Config", "Checking config file: %s", config_file ); if( Config.MainConfig.SetSource(config_file, true ) ) Log.Success( "Config", "Passed without errors." ); else Log.Warning( "Config", "Encountered one or more errors." ); Log.Notice( "Config", "Checking config file: %s\n", realm_config_file ); if( Config.RealmConfig.SetSource( realm_config_file, true ) ) Log.Success( "Config", "Passed without errors.\n" ); else Log.Warning( "Config", "Encountered one or more errors.\n" ); Log.Notice( "Config", "Checking config file:: %s\n", optional_config_file); if(Config.OptionalConfig.SetSource(optional_config_file, true) ) Log.Success( "Config", "Passed without errors.\n"); else Log.Warning( "Config", "Encountered one or more errors.\n"); /* test for die variables */ string die; if( Config.MainConfig.GetString( "die", "msg", &die) || Config.MainConfig.GetString("die2", "msg", &die ) ) Log.Warning( "Config", "Die directive received: %s", die.c_str() ); return true; } printf( "The key combination <Ctrl-C> will safely shut down the server at any time.\n" ); Log.Line(); #ifndef WIN32 if(geteuid() == 0 || getegid() == 0) Log.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running ArcEmu as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL); #endif InitRandomNumberGenerators(); Log.Success( "Rnd", "Initialized Random Number Generators." ); ThreadPool.Startup(); uint32 LoadingTime = getMSTime(); Log.Notice( "Config", "Loading Config Files...\n" ); if( Config.MainConfig.SetSource( config_file ) ) Log.Success( "Config", ">> configs/arcemu-world.conf" ); else { Log.Error( "Config", ">> configs/arcemu-world.conf" ); return false; } if(Config.OptionalConfig.SetSource(optional_config_file)) Log.Success( "Config", ">> configs/arcemu-optional.conf"); else { Log.Error("Config", ">> configs/arcemu-optional.conf"); return false; } string die; if( Config.MainConfig.GetString( "die", "msg", &die) || Config.MainConfig.GetString( "die2", "msg", &die ) ) { Log.Warning( "Config", "Die directive received: %s", die.c_str() ); return false; } if(Config.RealmConfig.SetSource(realm_config_file)) Log.Success( "Config", ">> configs/arcemu-realms.conf" ); else { Log.Error( "Config", ">> configs/arcemu-realms.conf" ); return false; } #if !defined(WIN32) && defined(__DEBUG__) if (Config.MainConfig.GetIntDefault( "LogLevel", "DisableCrashdumpReport", 0) == 0) { char cmd[1024]; char banner[1024]; snprintf(banner, 1024, BANNER, BUILD_TAG, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH); snprintf(cmd, 1024, "./arcemu-crashreport -r %d -d \"%s\"", BUILD_REVISION, banner); system(cmd); } unlink("arcemu.uptime"); #endif if( !_StartDB() ) { Database::CleanupLibs(); return false; } if(do_database_clean) { printf( "\nEntering database maintenance mode.\n\n" ); new DatabaseCleaner; DatabaseCleaner::getSingleton().Run(); delete DatabaseCleaner::getSingletonPtr(); Log.Color(TYELLOW); printf( "\nMaintenence finished. Take a moment to review the output, and hit space to continue startup." ); Log.Color(TNORMAL); fflush(stdout); } Log.Line(); sLog.outString( "" ); #ifdef GM_SCRIPT ScriptSystem = new ScriptEngine; ScriptSystem->Reload(); #endif new EventMgr; new World; //have to init this ones for singleton new tPPoolClass<Item>; new tPPoolClass<Aura>; new tPPoolClass<Spell>; // open cheat log file Anticheat_Log = new SessionLogWriter(FormatOutputString( "logs", "cheaters", false).c_str(), false ); GMCommand_Log = new SessionLogWriter(FormatOutputString( "logs", "gmcommand", false).c_str(), false ); Player_Log = new SessionLogWriter(FormatOutputString( "logs", "players", false).c_str(), false ); /* load the config file */ sWorld.Rehash(false); /* set new log levels */ if( screen_log_level != (int)DEF_VALUE_NOT_SET ) sLog.SetScreenLoggingLevel(screen_log_level); if( file_log_level != (int)DEF_VALUE_NOT_SET ) sLog.SetFileLoggingLevel(file_log_level); // Initialize Opcode Table WorldSession::InitPacketHandlerTable(); string host = Config.MainConfig.GetStringDefault( "Listen", "Host", DEFAULT_HOST ); int wsport = Config.MainConfig.GetIntDefault( "Listen", "WorldServerPort", DEFAULT_WORLDSERVER_PORT ); new ScriptMgr; if( !sWorld.SetInitialWorldSettings() ) { Log.Error( "Server", "SetInitialWorldSettings() failed. Something went wrong? Exiting." ); return false; } if( do_cheater_check ) sWorld.CleanupCheaters(); sWorld.SetStartTime((uint32)UNIXTIME); WorldRunnable * wr = new WorldRunnable(); ThreadPool.ExecuteTask(wr); _HookSignals(); ConsoleThread * console = new ConsoleThread(); ThreadPool.ExecuteTask(console); uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); // Socket loop! uint32 start; uint32 diff; uint32 last_time = now(); uint32 etime; uint32 next_printout = getMSTime(), next_send = getMSTime(); // Start Network Subsystem Log.Notice( "Network","Starting subsystem..." ); new SocketMgr; new SocketGarbageCollector; sSocketMgr.SpawnWorkerThreads(); sScriptMgr.LoadScripts(); LoadingTime = getMSTime() - LoadingTime; Log.Notice( "Server","Ready for connections. Startup time: %ums\n", LoadingTime ); Log.Notice("RemoteConsole", "Starting..."); if( StartConsoleListener() ) { #ifdef WIN32 ThreadPool.ExecuteTask( GetConsoleListener() ); #endif Log.Notice("RemoteConsole", "Now open."); } else { Log.Warning("RemoteConsole", "Not enabled or failed listen."); } /* write pid file */ FILE * fPid = fopen( "arcemu.pid", "w" ); if( fPid ) { uint32 pid; #ifdef WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif fprintf( fPid, "%u", (unsigned int)pid ); fclose( fPid ); } #ifdef WIN32 HANDLE hThread = GetCurrentThread(); #endif uint32 loopcounter = 0; //ThreadPool.Gobble(); #ifndef CLUSTERING /* Connect to realmlist servers / logon servers */ new LogonCommHandler(); sLogonCommHandler.Startup(); /* voicechat */ #ifdef VOICE_CHAT new VoiceChatHandler(); sVoiceChatHandler.Startup(); #endif // Create listener ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(host.c_str(), wsport); bool listnersockcreate = ls->IsOpen(); #ifdef WIN32 if( listnersockcreate ) ThreadPool.ExecuteTask(ls); #endif while( !m_stopEvent && listnersockcreate ) #else new ClusterInterface; sClusterInterface.ConnectToRealmServer(); while(!m_stopEvent) #endif { start = now(); diff = start - last_time; if(! ((++loopcounter) % 10000) ) // 5mins { ThreadPool.ShowStats(); ThreadPool.IntegrityCheck(); #if !defined(WIN32) && defined(__DEBUG__) FILE * f = fopen( "arcemu.uptime", "w" ); if( f ) { fprintf(f, "%u", sWorld.GetUptime()); fclose(f); } #endif } /* since time() is an expensive system call, we only update it once per server loop */ curTime = time(NULL); if( UNIXTIME != curTime ) { UNIXTIME = time(NULL); g_localTime = *localtime(&curTime); } #ifndef CLUSTERING #ifdef VOICE_CHAT sVoiceChatHandler.Update(); #endif #else sClusterInterface.Update(); #endif sSocketGarbageCollector.Update(); /* UPDATE */ last_time = now(); etime = last_time - start; if( m_ShutdownEvent ) { if( getMSTime() >= next_printout ) { if(m_ShutdownTimer > 60000.0f) { if( !( (int)(m_ShutdownTimer) % 60000 ) ) Log.Notice( "Server", "Shutdown in %i minutes.", (int)(m_ShutdownTimer / 60000.0f ) ); } else Log.Notice( "Server","Shutdown in %i seconds.", (int)(m_ShutdownTimer / 1000.0f ) ); next_printout = getMSTime() + 500; } if( getMSTime() >= next_send ) { int time = m_ShutdownTimer / 1000; if( ( time % 30 == 0 ) || time < 10 ) { // broadcast packet. WorldPacket data( 20 ); data.SetOpcode( SMSG_SERVER_MESSAGE ); if(m_restartEvent) data << uint32( SERVER_MSG_RESTART_TIME ); else data << uint32( SERVER_MSG_SHUTDOWN_TIME ); if( time > 0 ) { int mins = 0, secs = 0; if(time > 60) mins = time / 60; if(mins) time -= (mins * 60); secs = time; char str[20]; snprintf( str, 20, "%02u:%02u", mins, secs ); data << str; sWorld.SendGlobalMessage( &data, NULL ); } } next_send = getMSTime() + 1000; } if( diff >= m_ShutdownTimer ) break; else m_ShutdownTimer -= diff; } if( 50 > etime ) { #ifdef WIN32 WaitForSingleObject( hThread, 50 - etime ); #else Sleep( 50 - etime ); #endif } } _UnhookSignals(); wr->SetThreadState( THREADSTATE_TERMINATE ); ThreadPool.ShowStats(); /* Shut down console system */ console->terminate(); delete console; // begin server shutdown Log.Notice( "Shutdown", "Initiated at %s", ConvertTimeStampToDataTime( (uint32)UNIXTIME).c_str() ); if( lootmgr.is_loading ) { Log.Notice( "Shutdown", "Waiting for loot to finish loading..." ); while( lootmgr.is_loading ) Sleep( 100 ); } // send a query to wake it up if its inactive Log.Notice( "Database", "Clearing all pending queries..." ); // kill the database thread first so we don't lose any queries/data CharacterDatabase.EndThreads(); WorldDatabase.EndThreads(); Log.Notice( "DayWatcherThread", "Exiting..." ); dw->terminate(); dw = NULL; Log.Notice( "CommonScheduleThread", "Exiting..." ); cs->terminate(); cs = NULL; #ifndef CLUSTERING ls->Close(); #endif CloseConsoleListener(); sWorld.SaveAllPlayers(); Log.Notice( "Network", "Shutting down network subsystem." ); #ifdef WIN32 sSocketMgr.ShutdownThreads(); #endif sSocketMgr.CloseAll(); bServerShutdown = true; ThreadPool.Shutdown(); delete ls; sWorld.LogoutPlayers(); sLog.outString( "" ); delete LogonCommHandler::getSingletonPtr(); //should delete pools before other handlers ! Log.Notice( "Item Pool", "Item Pool" ); ItemPool.DestroyPool(); Log.Notice( "Spell Pool", "Spell Pool" ); SpellPool.DestroyPool(); Log.Notice( "Aura Pool", "Aura Pool" ); AuraPool.DestroyPool(); sWorld.ShutdownClasses(); Log.Notice( "World", "~World()" ); delete World::getSingletonPtr(); sScriptMgr.UnloadScripts(); delete ScriptMgr::getSingletonPtr(); Log.Notice( "ChatHandler", "~ChatHandler()" ); delete ChatHandler::getSingletonPtr(); Log.Notice( "EventMgr", "~EventMgr()" ); delete EventMgr::getSingletonPtr(); Log.Notice( "Database", "Closing Connections..." ); _StopDB(); Log.Notice( "Network", "Deleting Network Subsystem..." ); delete SocketMgr::getSingletonPtr(); delete SocketGarbageCollector::getSingletonPtr(); #ifdef VOICE_CHAT Log.Notice( "VoiceChatHandler", "~VoiceChatHandler()" ); delete VoiceChatHandler::getSingletonPtr(); #endif #ifdef GM_SCRIPT Log.Notice("GM-scripting:", "Closing ScriptEngine..."); delete ScriptSystem; #endif #ifdef ENABLE_LUA_SCRIPTING sLog.outString("Deleting Script Engine..."); LuaEngineMgr::getSingleton().Unload(); #endif delete GMCommand_Log; delete Anticheat_Log; delete Player_Log; // remove pid remove( "arcemu.pid" ); Log.Notice( "Shutdown", "Shutdown complete." ); #ifdef WIN32 WSACleanup(); // Terminate Entire Application //HANDLE pH = OpenProcess(PROCESS_TERMINATE, TRUE, GetCurrentProcessId()); //TerminateProcess(pH, 0); //CloseHandle(pH); #endif return true; }
/// Main function int Master::Run() { BigNumber seed1; seed1.SetRand(16 * 8); sLog->outString("%s (core-daemon)", _FULLVERSION); sLog->outString("<Ctrl-C> to stop.\n"); /* Beginning Of PDS-4TC Badge*/ /* Added by Pryd inspired by Lorac */ sLog->outString(" . . . "); sLog->outString(" . . "); sLog->outString(" ____ . \\ / . "); sLog->outString(" /\\ / \\ . - ^ - "); sLog->outString(" \\ \\_ / . / | \\ . . "); sLog->outString(" \\ \\\\ _ . "); sLog->outString(" \\ \\\\ \\// _ _ /\\ __ "); sLog->outString(" \\ \\\\ \\\\ \\\\ // /`'\\ \\__ \\ / "); sLog->outString(" \\//__\\\\ \\\\// /____\\ \\__ \\/ "); sLog->outString(" _____// ```````` "); sLog->outString(" /\\ ___\\ PDS-CC-2010 "); sLog->outString(" \\ \\ \\__/ ______ _ __ _____ "); sLog->outString(" \\ \\ \\ /\\ __ \\/\\`'__\\/\\ __\\ "); sLog->outString(" ,, \\ \\ \\___\\ \\ \\_\\ \\ \\ \\_/\\ \\ \\//_ "); sLog->outString("_/\\_|_____\\ \\_____\\ \\_____\\ \\_\\ \\ \\____\\ "); sLog->outString(" ` ` ` ` ` \\______/\\/_____/\\/_/ \\/____/ "); sLog->outString(" "); sLog->outString( "PDS-CC Core based on TrinityCore"); sLog->outString( "PDS Project Resource Locations"); sLog->outString( "Main: Http://prydevserver.com"); sLog->outString( "Repo: Http://sf.net/projects/prydevserver"); sLog->outString( "Forum: Http://prydevserver.com/ultracore/forum "); sLog->outString( "PryDevServer.com Development for the Community"); /* End Of PDS-4TC Badge*/ /* Added by Pryd inspired by Lorac */ #ifdef USE_SFMT_FOR_RNG sLog->outString("\n"); sLog->outString("SFMT has been enabled as the random number generator, if worldserver"); sLog->outString("freezes or crashes randomly, first, try disabling SFMT in CMAKE configuration"); sLog->outString("\n"); #endif //USE_SFMT_FOR_RNG /// 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; // set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET color = (color & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); ///- 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); 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("Can't set Trinityd process priority class."); sLog->outString(""); } } #endif //Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (sConfig->GetBoolDefault("SOAP.Enabled", false)) { TCSoapRunnable *runnable = new TCSoapRunnable(); runnable->setListenArguments(sConfig->GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig->GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } 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 uint16 wsport = sWorld->getIntConfig(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 } // set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET color = color & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); sWorldSocketMgr->Wait(); if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // set server offline LoginDatabase.PExecute("UPDATE realmlist SET color = color | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, 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.Close(); WorldDatabase.Close(); LoginDatabase.Close(); 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(); }
/// Main function int Master::Run() { /// 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(); ///- Catch termination signals _HookSignals(); ///- 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 mangosd. 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("mangosd process priority class set to HIGH"); else sLog.outError("ERROR: Can't set mangosd process priority class."); sLog.outString(); } } #endif uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); ///- 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); ///- Remove signal handling before leaving _UnhookSignals(); // 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; BOOL ret = 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(); }
bool Master::Run(int argc, char ** argv) { char * config_file = (char*)default_config_file; char * optional_config_file = (char*)default_optional_config_file; char * realm_config_file = (char*)default_realm_config_file; int file_log_level = DEF_VALUE_NOT_SET; int screen_log_level = DEF_VALUE_NOT_SET; int do_check_conf = 0; int do_version = 0; int do_cheater_check = 0; int do_database_clean = 0; time_t curTime; struct arcemu_option longopts[] = { { "checkconf", arcemu_no_argument, &do_check_conf, 1 }, { "screenloglevel", arcemu_required_argument, &screen_log_level, 1 }, { "fileloglevel", arcemu_required_argument, &file_log_level, 1 }, { "version", arcemu_no_argument, &do_version, 1 }, { "conf", arcemu_required_argument, NULL, 'c' }, { "realmconf", arcemu_required_argument, NULL, 'r' }, { "databasecleanup", arcemu_no_argument, &do_database_clean, 1 }, { "cheatercheck", arcemu_no_argument, &do_cheater_check, 1 }, { 0, 0, 0, 0 } }; char c; while ((c = arcemu_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1) { switch (c) { case 'c': config_file = new char[strlen(arcemu_optarg)]; strcpy(config_file, arcemu_optarg); break; case 'r': realm_config_file = new char[strlen(arcemu_optarg)]; strcpy(realm_config_file, arcemu_optarg); break; case 0: break; default: sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 3; printf("Usage: %s [--checkconf] [--screenloglevel <level>] [--fileloglevel <level>] [--conf <filename>] [--realmconf <filename>] [--version] [--databasecleanup] [--cheatercheck]\n", argv[0]); return true; } } // Startup banner UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); if (!do_version && !do_check_conf) { sLog.Init(0, WORLD_LOG); } else { sLog.m_fileLogLevel = -1; sLog.m_screenLogLevel = 1; } sLog.outBasic(BANNER, BUILD_HASH_STR, CONFIG, PLATFORM_TEXT, ARCH); sLog.outBasic("========================================================"); sLog.outErrorSilent(BANNER, BUILD_HASH_STR, CONFIG, PLATFORM_TEXT, ARCH); // Echo off. sLog.outErrorSilent("========================================================"); // Echo off. if (do_version) return true; if (do_check_conf) { Log.Notice("Config", "Checking config file: %s", config_file); if (Config.MainConfig.SetSource(config_file, true)) Log.Success("Config", "Passed without errors."); else Log.Warning("Config", "Encountered one or more errors."); Log.Notice("Config", "Checking config file: %s", realm_config_file); if (Config.RealmConfig.SetSource(realm_config_file, true)) Log.Success("Config", "Passed without errors."); else Log.Warning("Config", "Encountered one or more errors."); Log.Notice("Config", "Checking config file:: %s", optional_config_file); if (Config.OptionalConfig.SetSource(optional_config_file, true)) Log.Success("Config", "Passed without errors."); else Log.Warning("Config", "Encountered one or more errors."); return true; } sLog.outBasic("The key combination <Ctrl-C> will safely shut down the server at any time."); #ifndef WIN32 if (geteuid() == 0 || getegid() == 0) Log.LargeErrorMessage("You are running ArcEmu as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL); #endif InitRandomNumberGenerators(); Log.Success("Rnd", "Initialized Random Number Generators."); ThreadPool.Startup(); uint32 LoadingTime = getMSTime(); Log.Success("Config", "Loading Config Files..."); if (Config.MainConfig.SetSource(config_file)) Log.Notice("Config", ">> " CONFDIR "/world.conf loaded"); else { Log.Error("Config", ">> error occurred loading " CONFDIR "/world.conf"); return false; } if (Config.OptionalConfig.SetSource(optional_config_file)) Log.Notice("Config", ">> " CONFDIR "/optional.conf loaded"); else { Log.Error("Config", ">> error occurred loading " CONFDIR "/optional.conf"); return false; } if (Config.RealmConfig.SetSource(realm_config_file)) Log.Notice("Config", ">> " CONFDIR "/realms.conf loaded"); else { Log.Error("Config", ">> error occurred loading " CONFDIR "/realms.conf"); return false; } #if !defined(WIN32) && defined(__DEBUG__) if (Config.MainConfig.GetIntDefault("LogLevel", "DisableCrashdumpReport", 0) == 0) { char cmd[1024]; char banner[1024]; snprintf(banner, 1024, BANNER, BUILD_TAG, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH); snprintf(cmd, 1024, "./crashreport -r %d -d \"%s\"", BUILD_REVISION, banner); system(cmd); } unlink("arcemu.uptime"); #endif if (!_StartDB()) { Database::CleanupLibs(); sLog.Close(); return false; } // Checking the DB version. If it's wrong or can't be validated we exit. if (!CheckDBVersion()) { sLog.Close(); return false; } if (do_database_clean) { sLog.outDebug("Entering database maintenance mode."); new DatabaseCleaner; DatabaseCleaner::getSingleton().Run(); delete DatabaseCleaner::getSingletonPtr(); sLog.outDebug("Maintenance finished."); } #ifdef GM_SCRIPT ScriptSystem = new ScriptEngine; ScriptSystem->Reload(); #endif new EventMgr; new World; //have to init this ones for singleton new tPPoolClass<Item>; new tPPoolClass<Aura>; new tPPoolClass<Spell>; // open cheat log file Anticheat_Log = new SessionLogWriter(FormatOutputString("logs", "cheaters", false).c_str(), false); GMCommand_Log = new SessionLogWriter(FormatOutputString("logs", "gmcommand", false).c_str(), false); Player_Log = new SessionLogWriter(FormatOutputString("logs", "players", false).c_str(), false); /* load the config file */ sWorld.Rehash(false); /* set new log levels */ if (screen_log_level != (int)DEF_VALUE_NOT_SET) sLog.SetScreenLoggingLevel(screen_log_level); if (file_log_level != (int)DEF_VALUE_NOT_SET) sLog.SetFileLoggingLevel(file_log_level); // Initialize Opcode Table WorldSession::InitPacketHandlerTable(); std::string host = Config.MainConfig.GetStringDefault("Listen", "Host", DEFAULT_HOST); int wsport = Config.MainConfig.GetIntDefault("Listen", "WorldServerPort", DEFAULT_WORLDSERVER_PORT); new ScriptMgr; if (!sWorld.SetInitialWorldSettings()) { Log.Error("Server", "SetInitialWorldSettings() failed. Something went wrong? Exiting."); return false; } if (do_cheater_check) sWorld.CleanupCheaters(); sWorld.SetStartTime((uint32)UNIXTIME); WorldRunnable * wr = new WorldRunnable(); ThreadPool.ExecuteTask(wr); _HookSignals(); ConsoleThread * console = new ConsoleThread(); ThreadPool.ExecuteTask(console); uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); // Socket loop! uint32 start; uint32 diff; uint32 last_time = now(); uint32 etime; uint32 next_printout = getMSTime(), next_send = getMSTime(); // Start Network Subsystem Log.Notice("Network", "Starting subsystem..."); new SocketMgr; new SocketGarbageCollector; sSocketMgr.SpawnWorkerThreads(); sScriptMgr.LoadScripts(); LoadingTime = getMSTime() - LoadingTime; Log.Notice("Server", "Ready for connections. Startup time: %ums\n", LoadingTime); Log.Notice("RemoteConsole", "Starting..."); if (StartConsoleListener()) { #ifdef WIN32 ThreadPool.ExecuteTask(GetConsoleListener()); #endif Log.Notice("RemoteConsole", "Now open."); } else { Log.Warning("RemoteConsole", "Not enabled or failed listen."); } /* write pid file */ FILE * fPid = fopen("worldserver.pid", "w"); if (fPid) { uint32 pid; #ifdef WIN32 pid = GetCurrentProcessId(); #else pid = getpid(); #endif fprintf(fPid, "%u", (unsigned int)pid); fclose(fPid); } #ifdef WIN32 HANDLE hThread = GetCurrentThread(); #endif uint32 loopcounter = 0; //ThreadPool.Gobble(); #ifndef CLUSTERING /* Connect to realmlist servers / logon servers */ new LogonCommHandler(); sLogonCommHandler.Startup(); /* voicechat */ #ifdef VOICE_CHAT new VoiceChatHandler(); sVoiceChatHandler.Startup(); #endif // Create listener ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(host.c_str(), wsport); bool listnersockcreate = ls->IsOpen(); #ifdef WIN32 if (listnersockcreate) ThreadPool.ExecuteTask(ls); #endif while (!m_stopEvent && listnersockcreate) #else new ClusterInterface; sClusterInterface.ConnectToRealmServer(); while (!m_stopEvent) #endif { start = now(); diff = start - last_time; if (!((++loopcounter) % 10000)) // 5mins { ThreadPool.ShowStats(); ThreadPool.IntegrityCheck(); #if !defined(WIN32) && defined(__DEBUG__) FILE * f = fopen("arcemu.uptime", "w"); if (f) { fprintf(f, "%u", sWorld.GetUptime()); fclose(f); } #endif } /* since time() is an expensive system call, we only update it once per server loop */ curTime = time(NULL); if (UNIXTIME != curTime) { UNIXTIME = time(NULL); g_localTime = *localtime(&curTime); } #ifndef CLUSTERING #ifdef VOICE_CHAT sVoiceChatHandler.Update(); #endif #else sClusterInterface.Update(); #endif sSocketGarbageCollector.Update(); /* UPDATE */ last_time = now(); etime = last_time - start; if (m_ShutdownEvent) { if (getMSTime() >= next_printout) { if (m_ShutdownTimer > 60000.0f) { if (!((int)(m_ShutdownTimer) % 60000)) Log.Notice("Server", "Shutdown in %i minutes.", (int)(m_ShutdownTimer / 60000.0f)); } else Log.Notice("Server", "Shutdown in %i seconds.", (int)(m_ShutdownTimer / 1000.0f)); next_printout = getMSTime() + 500; } if (getMSTime() >= next_send) { int time = m_ShutdownTimer / 1000; if ((time % 30 == 0) || time < 10) { // broadcast packet. WorldPacket data(20); data.SetOpcode(SMSG_SERVER_MESSAGE); if (m_restartEvent) data << uint32(SERVER_MSG_RESTART_TIME); else data << uint32(SERVER_MSG_SHUTDOWN_TIME); if (time > 0) { int mins = 0, secs = 0; if (time > 60) mins = time / 60; if (mins) time -= (mins * 60); secs = time; char str[20]; snprintf(str, 20, "%02u:%02u", mins, secs); data << str; sWorld.SendGlobalMessage(&data, NULL); } } next_send = getMSTime() + 1000; } if (diff >= m_ShutdownTimer) break; else m_ShutdownTimer -= diff; } if (50 > etime) { #ifdef WIN32 WaitForSingleObject(hThread, 50 - etime); #else Sleep(50 - etime); #endif } } _UnhookSignals(); wr->SetThreadState(THREADSTATE_TERMINATE); ThreadPool.ShowStats(); /* Shut down console system */ console->terminate(); delete console; // begin server shutdown Log.Notice("Shutdown", "Initiated at %s", ConvertTimeStampToDataTime((uint32)UNIXTIME).c_str()); if (lootmgr.is_loading) { Log.Notice("Shutdown", "Waiting for loot to finish loading..."); while (lootmgr.is_loading) Sleep(100); } // send a query to wake it up if its inactive Log.Notice("Database", "Clearing all pending queries..."); // kill the database thread first so we don't lose any queries/data CharacterDatabase.EndThreads(); WorldDatabase.EndThreads(); Log.Notice("DayWatcherThread", "Exiting..."); dw->terminate(); dw = NULL; Log.Notice("CommonScheduleThread", "Exiting..."); cs->terminate(); cs = NULL; #ifndef CLUSTERING ls->Close(); #endif CloseConsoleListener(); sWorld.SaveAllPlayers(); Log.Notice("Network", "Shutting down network subsystem."); #ifdef WIN32 sSocketMgr.ShutdownThreads(); #endif sSocketMgr.CloseAll(); bServerShutdown = true; ThreadPool.Shutdown(); delete ls; sWorld.LogoutPlayers(); sLog.outString(""); delete LogonCommHandler::getSingletonPtr(); //should delete pools before other handlers ! Log.Notice("Item Pool", "Item Pool"); ItemPool.DestroyPool(); Log.Notice("Spell Pool", "Spell Pool"); SpellPool.DestroyPool(); Log.Notice("Aura Pool", "Aura Pool"); AuraPool.DestroyPool(); sWorld.ShutdownClasses(); Log.Notice("World", "~World()"); delete World::getSingletonPtr(); sScriptMgr.UnloadScripts(); delete ScriptMgr::getSingletonPtr(); Log.Notice("ChatHandler", "~ChatHandler()"); delete ChatHandler::getSingletonPtr(); Log.Notice("EventMgr", "~EventMgr()"); delete EventMgr::getSingletonPtr(); Log.Notice("Database", "Closing Connections..."); _StopDB(); Log.Notice("Network", "Deleting Network Subsystem..."); delete SocketMgr::getSingletonPtr(); delete SocketGarbageCollector::getSingletonPtr(); #ifdef VOICE_CHAT Log.Notice("VoiceChatHandler", "~VoiceChatHandler()"); delete VoiceChatHandler::getSingletonPtr(); #endif #ifdef GM_SCRIPT Log.Notice("GM-scripting:", "Closing ScriptEngine..."); delete ScriptSystem; #endif #ifdef ENABLE_LUA_SCRIPTING sLog.outString("Deleting Script Engine..."); LuaEngineMgr::getSingleton().Unload(); #endif delete GMCommand_Log; delete Anticheat_Log; delete Player_Log; // remove pid remove("worldserver.pid"); Log.Notice("Shutdown", "Shutdown complete."); #ifdef WIN32 WSACleanup(); // Terminate Entire Application //HANDLE pH = OpenProcess(PROCESS_TERMINATE, TRUE, GetCurrentProcessId()); //TerminateProcess(pH, 0); //CloseHandle(pH); #endif return true; }
/// Main function int Master::Run() { /// 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() ); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString( "Daemon PID: %u\n", pid ); } ///- Start the databases if (!_StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Initialize the World sWorld.SetInitialWorldSettings(); #ifndef WIN32 detachDaemon(); #endif //server loaded successfully => enable async DB requests //this is done to forbid any async transactions during server startup! CharacterDatabase.AllowAsyncTransactions(); WorldDatabase.AllowAsyncTransactions(); LoginDatabase.AllowAsyncTransactions(); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set realmbuilds depend on mangosd expected builds, and set server online { std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%u'", REALM_FLAG_OFFLINE, builds.c_str(), 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 = NULL; if(sConfig.GetBoolDefault ("Ra.Enable", false)) { rar_thread = new ACE_Based::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 mangosd. 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("mangosd process priority class set to HIGH"); else sLog.outError("Can't set mangosd process priority class."); sLog.outString(); } } #endif ///- Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if(sConfig.GetBoolDefault("SOAP.Enabled", false)) { MaNGOSsoapRunnable *runnable = new MaNGOSsoapRunnable(); runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } ///- Launch the world listener socket uint16 wsport = sWorld.getConfig (CONFIG_UINT32_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip) == -1) { sLog.outError ("Failed to start network"); Log::WaitBeforeContinueIfNeed(); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait (); ///- Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } ///- Stop soap thread if(soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } ///- Set server offline in realmlist LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); if(rar_thread) { rar_thread->wait(); rar_thread->destroy(); delete rar_thread; } ///- Clean account database before leaving clearOnlineAccounts(); // send all still queued mass mails (before DB connections shutdown) sMassMailMgr.Update(true); ///- Wait for DB 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; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } ///- Exit the process with specified return value uint8 worldExitCode = World::GetExitCode(); FILE* exitFile = fopen("mangos-exit.log","w"); fprintf(exitFile,"%d\n",worldExitCode); sLog.outString( "\nWorld exit code = %d\n",worldExitCode ); //fprintf(exitFile,"%d",worldExitCode); fflush(exitFile); fclose(exitFile); return worldExitCode; }
/// Main function int Master::Run() { BigNumber seed1; seed1.SetRand(16 * 8); sLog->outString("%s (worldserver-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"); sLog->outString(" "); sLog->outString(" ### ###"); sLog->outString(" #OFFM## Eye of Beholder ##FFO8#"); sLog->outString(" #F###K#### http://e0b.eu #######MM#"); sLog->outString(" #FFM#FFMM# #MFF##FF##"); sLog->outString(" #F###K### ######### ###M###F#"); sLog->outString(" #M#MX#XXM# #FMMMMM#F#MKMK# ##EX##M#MM#"); sLog->outString(" #MM#XX#VIM# ##KMM##MMFK##M#8## #FVO8XO#MM#"); sLog->outString(" #FM##MF#OO8### #MKAAOF##OL1 `o8## ###FOOKMF###F#"); sLog->outString(" #FM##K###XX#FOFMF3O#######D1` <AMFOFMXO###M##KM#"); sLog->outString(" ##M######KX####gw#######Dyuu1 `1####AX######MM#"); sLog->outString(" #MO##VAVVA#XX#u<8###########L< `<1KFX#8VIXVX#FF#"); sLog->outString(" #FF#8IVVIV8#MK<<A###########w` `<<3M##VVIAIV#MFM"); sLog->outString(" #KM#8hIAIIAK#J`<o8#########4<``<<1wM8AVhVVhV#MK#"); sLog->outString(" ####8hIAVIVK#g`<<bF#######O1``<<11wMMAIVAIhV####"); sLog->outString(" ####8hVIVAI#M81<<<<<1ooo1<```<11ub3M#AVAIVIV####"); sLog->outString("#####AhAIhVMM##J111<<``````<<11ubgLK#MKAII8II#####"); sLog->outString("#####8hAVhIK#VF8bo11<<<<<<<<11ubgJD#V##IhI8IV#####"); sLog->outString("##MM#VhVVIA#M#FAKJbbuuu11oubbgJL488F#M#MIIAhh##M##"); sLog->outString("#M#M#VhVII###VVM#KLggbbbbbg7JL349##VV8##AIAhh##K##"); sLog->outString("#M#M##A8###KM8AIhHM#K8D4DD990KKK8hIA8KK####A8#####"); sLog->outString("###M#####VK8AAIMVD##MMMM#KM#M#M#8IKVV8A#98####M###"); sLog->outString("###A##8##I8VAKVh8# ##### ###### #KIh9AVKhV#88#A###"); sLog->outString("###8A#AK#AV#VII0I# #HI0IIM8V8#AAMA###"); sLog->outString("###AV8hA#Vh8#ho0# #KhhKKhI##hAAA8##"); sLog->outString("##AV88hV#8hI#9h# #JI#AhI##hAAAV##"); sLog->outString("##hhA8oI##ho9M# #MKho9#AoAMIh8#"); sLog->outString("##ohM8oV##A9# #KA###oV#IoA#"); sLog->outString("##hhM####### ########VoA#"); sLog->outString("##h9K8A8IA8# #AVA#VMKhA#"); sLog->outString("##h8K#8FVV9# #IAAMAMKVA#"); sLog->outString("###A#M8#A88# #AVK8A#A8##"); sLog->outString("###V#MA#AAM# #KIK8A#V8##"); sLog->outString("#M8V#FAA8AF# #FV#AA#V88#"); sLog->outString("#88A8K88AA## #9V88A#A88#"); sLog->outString("##8V8AAAAV## #UVV8I#V88#"); sLog->outString("#8VhVVVAIV## #AhV8h8hVA#"); sLog->outString("#AVIVVVAhV## #UhV8h8hAV#"); sLog->outString("#8VhVIVVIV# #9IIAh8hVA#"); sLog->outString("#8IhVIVI8M# #M8IVh8hIA#"); sLog->outString("#AIhVVVIK# #FIVh8hhA#"); sLog->outString("##hoVUII# #UVhMhhA#"); sLog->outString("#8hhV9I9# #KVV#hhA#"); sLog->outString("##hhIKF# #K88hhA#"); sLog->outString("##hh8## #Mhh8#"); sLog->outString("#KhJ## #8hA#"); sLog->outString("#### ####"); /// worldserver PID file creation std::string pidfile = ConfigMgr::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; // set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); ///- Initialize the World sWorld->SetInitialWorldSettings(); // Initialise the signal handlers WorldServerSignalHandler SignalINT, SignalTERM; #ifdef _WIN32 WorldServerSignalHandler SignalBREAK; #endif /* _WIN32 */ // Register worldserver'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); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (ConfigMgr::GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (ConfigMgr::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 = ConfigMgr::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 are not accessible for the worldserver. 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 = ConfigMgr::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("worldserver process priority class set to HIGH"); else sLog->outError("Can't set worldserver process priority class."); sLog->outString(""); } } #endif //Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (ConfigMgr::GetBoolDefault("SOAP.Enabled", false)) { TCSoapRunnable* runnable = new TCSoapRunnable(); runnable->setListenArguments(ConfigMgr::GetStringDefault("SOAP.IP", "127.0.0.1"), ConfigMgr::GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread if (uint32 freeze_delay = ConfigMgr::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 uint16 wsport = sWorld->getIntConfig(CONFIG_PORT_WORLD); std::string bind_ip = ConfigMgr::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 } // set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); sLog->outString("%s (worldserver-daemon) ready...", _FULLVERSION); // 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(); if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // set server offline LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); ///- Clean database before leaving ClearOnlineAccounts(); _StopDB(); 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(); }