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 wowice_option longopts[] = { { "checkconf", wowice_no_argument, &do_check_conf, 1 }, { "screenloglevel", wowice_required_argument, &screen_log_level, 1 }, { "fileloglevel", wowice_required_argument, &file_log_level, 1 }, { "version", wowice_no_argument, &do_version, 1 }, { "conf", wowice_required_argument, NULL, 'c' }, { "realmconf", wowice_required_argument, NULL, 'r' }, { "databasecleanup", wowice_no_argument, &do_database_clean, 1 }, { "cheatercheck", wowice_no_argument, &do_cheater_check, 1 }, { 0, 0, 0, 0 } }; char c; while ((c = static_cast<char>( wowice_getopt_long_only(argc, argv, ":f:", longopts, NULL) ) ) != -1) { switch (c) { case 'c': config_file = new char[strlen(wowice_optarg)]; strcpy(config_file, wowice_optarg); break; case 'r': realm_config_file = new char[strlen(wowice_optarg)]; strcpy(realm_config_file, wowice_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) 2009 WoWICE. http://code.google.com/p/wowice/\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(" Website: http://code.google.com/p/wowice/ \n"); printf(" SVN: https//wowice.googlecode.com/svn/trunk/ \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 http://code.google.com/p/wowice/ .\n"); printf("By using this repack, you agree to not visit the wowice 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"); 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 WoWICE 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 InitImplicitTargetFlags(); 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/world.conf" ); else { sLog.outError( "Config", ">> configs/world.conf" ); return false; } if(Config.OptionalConfig.SetSource(optional_config_file)) Log.Success( "Config", ">> configs/optional.conf"); else { sLog.outError("Config", ">> configs/optional.conf"); return false; } if(Config.RealmConfig.SetSource(realm_config_file)) Log.Success( "Config", ">> configs/realms.conf" ); else { Log.Error( "Config", ">> configs/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, "./wowice-crashreport -r %d -d \'%s\'", BUILD_REVISION, banner); system(cmd); } unlink("wowice.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( "\nMaintenance finished. Take a moment to review the output.\n" ); Log.Color(TNORMAL); fflush(stdout); system("PAUSE"); } Log.Line(); sLog.outString( "" ); new EventMgr; new World; // optional time stamp in logs bool useTimeStamp = Config.MainConfig.GetBoolDefault("log", "TimeStamp", false); // open cheat log file Anticheat_Log = new SessionLogWriter(FormatOutputString( "logs", "cheaters", useTimeStamp).c_str(), false ); GMCommand_Log = new SessionLogWriter(FormatOutputString( "logs", "gmcommand", useTimeStamp).c_str(), false ); Player_Log = new SessionLogWriter(FormatOutputString( "logs", "players", useTimeStamp).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, "file.log"); // 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( "wowice.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(); /* 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(); #ifdef WIN32 if( listnersockcreate ) ThreadPool.ExecuteTask(ls); #endif while( !m_stopEvent && listnersockcreate ) { start = now(); diff = start - last_time; if(! ((++loopcounter) % 10000) ) // 5mins { ThreadPool.ShowStats(); ThreadPool.IntegrityCheck(); #if !defined(WIN32) && defined(__DEBUG__) FILE * f = fopen( "wowice.uptime", "w" ); if( f ) { fprintf(f, "%u %u %u %u", sWorld.GetUptime(), sWorld.GetSessionCount(), sWorld.PeakSessionCount, sWorld.mAcceptedConnections); 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); } 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; ls->Close(); 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(); 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 ENABLE_LUA_SCRIPTING sLog.outString("Deleting Script Engine..."); LuaEngineMgr::getSingleton().Unload(); #endif delete GMCommand_Log; delete Anticheat_Log; delete Player_Log; // remove pid remove( "wowice.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; }
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 = static_cast<char>(arcemu_getopt_long_only(argc, argv, ":f:", longopts, NULL))) != -1) { switch (c) { case 'c': config_file = new char[strlen(arcemu_optarg) + 1]; strcpy(config_file, arcemu_optarg); break; case 'r': realm_config_file = new char[strlen(arcemu_optarg) + 1]; strcpy(realm_config_file, arcemu_optarg); break; case 0: break; default: sLog.Init(0, WORLD_LOG); printf("Usage: %s [--checkconf] [--fileloglevel <level>] [--conf <filename>] [--realmconf <filename>] [--version] [--databasecleanup] [--cheatercheck]\n", argv[0]); sLog.Close(); return true; } } // Startup banner UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); sLog.Init(0, WORLD_LOG); 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) { sLog.Close(); 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.Error("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.Error("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.Error("Config", "Encountered one or more errors."); sLog.Close(); return true; } sLog.outBasic("The key combination <Ctrl-C> will safely shut down the server."); #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 InitImplicitTargetFlags(); InitRandomNumberGenerators(); Log.Notice("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 { sLog.Error("Config", ">> error occurred loading " CONFDIR "/world.conf"); sLog.Close(); return false; } if (Config.OptionalConfig.SetSource(optional_config_file)) Log.Notice("Config", ">> " CONFDIR "/optional.conf loaded"); else { sLog.Error("Config", ">> error occurred loading " CONFDIR "/optional.conf"); sLog.Close(); return false; } if (Config.RealmConfig.SetSource(realm_config_file)) Log.Notice("Config", ">> " CONFDIR "/realms.conf loaded"); else { sLog.Error("Config", ">> error occurred loading " CONFDIR "/realms.conf"); sLog.Close(); 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("worldserver.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."); } new EventMgr; new World; // optional time stamp in logs bool useTimeStamp = Config.MainConfig.GetBoolDefault("log", "TimeStamp", false); // open cheat log file Anticheat_Log = new SessionLogWriter(FormatOutputString("logs", "cheaters", useTimeStamp).c_str(), false); GMCommand_Log = new SessionLogWriter(FormatOutputString("logs", "gmcommand", useTimeStamp).c_str(), false); Player_Log = new SessionLogWriter(FormatOutputString("logs", "players", useTimeStamp).c_str(), false); /* load the config file */ sWorld.Rehash(false); /* set new log levels */ 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."); sLog.Close(); delete[] realm_config_file; 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.Success("Network", "Starting subsystem..."); new SocketMgr; new SocketGarbageCollector; sSocketMgr.SpawnWorkerThreads(); sScriptMgr.LoadScripts(); if (Config.MainConfig.GetBoolDefault("Startup", "EnableSpellIDDump", false)) sScriptMgr.DumpUnimplementedSpells(); LoadingTime = getMSTime() - LoadingTime; Log.Success("Server", "Ready for connections. Startup time: %ums", LoadingTime); ThreadPool.ExecuteTask(new GameEventMgr::GameEventMgrThread()); 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); } uint32 loopcounter = 0; //ThreadPool.Gobble(); /* 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(); #ifdef WIN32 if (listnersockcreate) ThreadPool.ExecuteTask(ls); #endif while (!m_stopEvent && listnersockcreate) { start = now(); diff = start - last_time; if (!((++loopcounter) % 10000)) // 5mins { ThreadPool.ShowStats(); ThreadPool.IntegrityCheck(); #if !defined(WIN32) && defined(__DEBUG__) FILE* f = fopen("worldserver.uptime", "w"); if (f) { fprintf(f, "%u %u %u %u", sWorld.GetUptime(), sWorld.GetSessionCount(), sWorld.PeakSessionCount, sWorld.mAcceptedConnections); 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); } 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) { Arcemu::Sleep(50 - etime); } } _UnhookSignals(); wr->SetThreadState(THREADSTATE_TERMINATE); ThreadPool.ShowStats(); /* Shut down console system */ console->terminate(); delete console; // begin server shutdown Log.Success("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) Arcemu::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; ls->Close(); 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(); delete LogonCommHandler::getSingletonPtr(); 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(); delete GMCommand_Log; delete Anticheat_Log; delete Player_Log; // remove pid remove("worldserver.pid"); Log.Success("Shutdown", "Shutdown complete."); Log.Close(); #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; }