// Initialize connection to the database bool StartDB() { MySQL::Library_Init(); std::string dbstring = ConfigMgr::GetStringDefault("LoginDatabaseInfo", ""); if (dbstring.empty()) { sLog->outError("Database not specified"); return false; } uint8 worker_threads = ConfigMgr::GetIntDefault("LoginDatabase.WorkerThreads", 1); if (worker_threads < 1 || worker_threads > 32) { sLog->outError("Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1."); worker_threads = 1; } uint8 synch_threads = ConfigMgr::GetIntDefault("LoginDatabase.SynchThreads", 1); if (synch_threads < 1 || synch_threads > 32) { sLog->outError("Improper value specified for LoginDatabase.SynchThreads, defaulting to 1."); synch_threads = 1; } // NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever. if (!LoginDatabase.Open(dbstring.c_str(), worker_threads, synch_threads)) { sLog->outError("Cannot connect to database"); return false; } dbstring = ConfigMgr::GetStringDefault("WotLKLoginDatabaseInfo", ""); if (dbstring.empty()) { sLog->outError("WotLK Database not specified"); return false; } worker_threads = ConfigMgr::GetIntDefault("WotLKLoginDatabase.WorkerThreads", 1); if (worker_threads < 1 || worker_threads > 32) { sLog->outError("Improper value specified for WotLKLoginDatabase.WorkerThreads, defaulting to 1."); worker_threads = 1; } synch_threads = ConfigMgr::GetIntDefault("WotLKLoginDatabase.SynchThreads", 1); if (synch_threads < 1 || synch_threads > 32) { sLog->outError("Improper value specified for WotLKLoginDatabase.SynchThreads, defaulting to 1."); synch_threads = 1; } // NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever. if (!WotLKLoginDatabase.Open(dbstring.c_str(), worker_threads, synch_threads)) { sLog->outError("Cannot connect to WotLK database"); return false; } return true; }
void StopDB() { LoginDatabase.Close(); WotLKLoginDatabase.Close(); MySQL::Library_End(); }
/// Launch the Trinity server extern int main(int argc, char** argv) { std::string configFile = _TRINITY_CORE_CONFIG; std::string configService; auto vm = GetConsoleArguments(argc, argv, configFile, configService); // exit if help or version is enabled if (vm.count("help") || vm.count("version")) return 0; #ifdef _WIN32 if (configService.compare("install") == 0) return WinServiceInstall() == true ? 0 : 1; else if (configService.compare("uninstall") == 0) return WinServiceUninstall() == true ? 0 : 1; else if (configService.compare("run") == 0) WinServiceRun(); #endif std::string configError; if (!sConfigMgr->LoadInitial(configFile, configError)) { printf("Error in config file: %s\n", configError.c_str()); return 1; } sLog->RegisterAppender<AppenderDB>(); // If logs are supposed to be handled async then we need to pass the io_service into the Log singleton sLog->Initialize(sConfigMgr->GetBoolDefault("Log.Async.Enable", false) ? &_ioService : nullptr); TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", GitRevision::GetFullVersion()); TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n"); 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", " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\"); TC_LOG_INFO("server.worldserver", " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\"); TC_LOG_INFO("server.worldserver", " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\"); TC_LOG_INFO("server.worldserver", " Rudi C O R E /\\___/"); TC_LOG_INFO("server.worldserver", "http://TrinityCore.org \\/__/\n"); TC_LOG_INFO("server.worldserver", "Using configuration file %s.", configFile.c_str()); TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); OpenSSLCrypto::threadsSetup(); // Seed the OpenSSL's PRNG here. // That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login BigNumber seed; seed.SetRand(16 * 8); /// 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; } } // Set signal handlers (this must be done before starting io_service threads, because otherwise they would unblock and exit) boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); #if PLATFORM == PLATFORM_WINDOWS signals.add(SIGBREAK); #endif signals.async_wait(SignalHandler); // Start the Boost based thread pool int numThreads = sConfigMgr->GetIntDefault("ThreadPool", 1); std::vector<std::thread> threadPool; if (numThreads < 1) numThreads = 1; for (int i = 0; i < numThreads; ++i) threadPool.push_back(std::thread(boost::bind(&boost::asio::io_service::run, &_ioService))); // Set process priority according to configuration settings SetProcessPriority("server.worldserver"); // Start the databases if (!StartDB()) { ShutdownThreadPool(threadPool); 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(); // Launch CliRunnable thread std::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 { cliThread = new std::thread(CliThread); } // Start the Remote Access port (acceptor) if enabled AsyncAcceptor* raAcceptor = nullptr; if (sConfigMgr->GetBoolDefault("Ra.Enable", false)) raAcceptor = StartRaSocketAcceptor(_ioService); // Start soap serving thread if enabled std::thread* soapThread = nullptr; if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false)) { soapThread = new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))); } // Launch the worldserver listener socket uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); sWorldSocketMgr.StartNetwork(_ioService, worldListener, worldPort); // Set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec) if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) { _maxCoreStuckTimeInMs = coreStuckTime * 1000; _freezeCheckTimer.expires_from_now(boost::posix_time::seconds(5)); _freezeCheckTimer.async_wait(FreezeDetectorHandler); TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", coreStuckTime); } TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", GitRevision::GetFullVersion()); sScriptMgr->OnStartup(); WorldUpdateLoop(); // Shutdown starts here ShutdownThreadPool(threadPool); sScriptMgr->OnShutdown(); sWorld->KickAll(); // save and kick all players sWorld->UpdateSessions(1); // real players unload required UpdateSessions call // unload battleground templates before different singletons destroyed sBattlegroundMgr->DeleteAllBattlegrounds(); sWorldSocketMgr.StopNetwork(); sInstanceSaveMgr->Unload(); sOutdoorPvPMgr->Die(); sMapMgr->UnloadAll(); // unload all grids (including locked in memory) sScriptMgr->Unload(); // set server offline LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); // Clean up threads if any if (soapThread != nullptr) { soapThread->join(); delete soapThread; } delete raAcceptor; ///- Clean database before leaving ClearOnlineAccounts(); StopDB(); TC_LOG_INFO("server.worldserver", "Halting process..."); ShutdownCLIThread(cliThread); OpenSSLCrypto::threadsCleanup(); // 0 - normal shutdown // 1 - shutdown at error // 2 - restart command used, this code can be used by restarter for restart Trinityd return World::GetExitCode(); }
// Launch the auth server extern int main(int argc, char **argv) { sLog->SetLogDB(false); // Command line parsing to get the configuration file name char const *cfg_file = _AUTHSERVER_CONFIG; int c = 1; while(c < argc) { if (strcmp(argv[c], "-c") == 0) { if (++c >= argc) { sLog->outError("Runtime-Error: -c option requires an input argument"); usage(argv[0]); return 1; } else cfg_file = argv[c]; } ++c; } if (!sConfig->SetSource(cfg_file)) { sLog->outError( "Invalid or missing configuration file : %s", cfg_file); sLog->outError( "Verify that the file exists and has \'[authserver]\' written in the top of the file!"); return 1; } sLog->Initialize(); sLog->outString( "%s (authserver)", _FULLVERSION); sLog->outString( "<Ctrl-C> to stop.\n"); sLog->outString( "Using configuration file %s.", cfg_file); sLog->outString(" "); sLog->outString(" ______ __ __ __ __ ______ __ ______ ______ "); sLog->outString(" /\\ ___\\/\\ \\/ / /\\ \\_\\ \\/\\ ___/\\ \\/\\ == \\/\\ ___\\ "); sLog->outString(" \\ \\___ \\ \\ _'-\\ \\____ \\ \\ __\\ \\ \\ \\ __<\\ \\ __\\ "); sLog->outString(" \\/\\_____\\ \\_\\ \\_\\/\\_____\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_____\\ "); sLog->outString(" \\/_____/\\/_/\\/_/\\/_____/\\/_/ \\/_/\\/_/ /_/\\/_____/ "); sLog->outString(" Project SkyFireEmu 2011(c) Open-sourced Game Emulation "); sLog->outString(" <http://www.projectskyfire.org/> "); sLog->outString("<Ctrl-C> to stop.\n"); sLog->outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); #else ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); #endif sLog->outBasic("Max allowed open files is %d", ACE::max_handles()); // authserver 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); } // Initialize the database connection if (!StartDB()) return 1; // Initialize the log database sLog->SetLogDBLater(sConfig->GetBoolDefault("EnableLogDB", false)); // set var to enable DB logging once startup finished. sLog->SetLogDB(false); sLog->SetRealmID(0); // Get the list of realms for the server sRealmList->Initialize(sConfig->GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList->size() == 0) { sLog->outError( "No valid realms specified."); return 1; } // Launch the listening network socket RealmAcceptor acceptor; uint16 rmport = sConfig->GetIntDefault("RealmServerPort", 3724); std::string bind_ip = sConfig->GetStringDefault("BindIP", "0.0.0.0"); ACE_INET_Addr bind_addr(rmport, bind_ip.c_str()); if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) { sLog->outError("Auth server can not bind to %s:%d", bind_ip.c_str(), rmport); return 1; } // Initialize the signal handlers AuthServerSignalHandler SignalINT, SignalTERM; // Register authservers's signal handlers ACE_Sig_Handler Handler; Handler.register_handler(SIGINT, &SignalINT); Handler.register_handler(SIGTERM, &SignalTERM); ///- 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 authserver. 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("auth process priority class set to HIGH"); else sLog->outError("Can't set auth process priority class."); sLog->outString(); } } #endif sLog->outString("%s (authserver-daemon) ready...", _FULLVERSION); // maximum counter for next ping uint32 numLoops = (sConfig->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; // possibly enable db logging; avoid massive startup spam by doing it here. if (sLog->GetLogDBLater()) { sLog->outString("Enabling database logging..."); sLog->SetLogDBLater(false); // login db needs thread for logging sLog->SetLogDB(true); } else sLog->SetLogDB(false); // Wait for termination signal while (!stopEvent) { // don't move this outside the loop, the reactor will modify it ACE_Time_Value interval(0, 100000); if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) break; if ((++loopCounter) == numLoops) { loopCounter = 0; sLog->outDetail("Ping MySQL to keep connection alive"); LoginDatabase.KeepAlive(); } } // Close the Database Pool and library StopDB(); sLog->outString( "Halting process..."); return 0; }
/// Launch the auth server extern int main(int argc, char** argv) { // Command line parsing to get the configuration file name char const* configFile = _TRINITY_REALM_CONFIG; int count = 1; while (count < argc) { if (strcmp(argv[count], "-c") == 0) { if (++count >= argc) { printf("Runtime-Error: -c option requires an input argument\n"); usage(argv[0]); return 1; } else configFile = argv[count]; } ++count; } if (!sConfigMgr->LoadInitial(configFile)) { printf("Invalid or missing configuration file : %s\n", configFile); printf("Verify that the file exists and has \'[authserver]\' written in the top of the file!\n"); return 1; } TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "%s (authserver)", _FULLVERSION); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " "); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " A World of Warcraft: Cataclysm Core Emulator "); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " _/_/ _/ _/_/_/ _/_/ _/_/_/ _/_/_/_/ "); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " _/ _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ "); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " _/_/_/_/ _/_/ _/_/ _/ _/ _/ _/_/_/ _/_/_/ "); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ "); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " _/ _/ _/ _/ _/ _/_/_/ _/_/ _/ _/ _/_/_/_/ "); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " Arkania Community (c) 2013"); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " <http://arkania.net/>"); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, " "); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "<Ctrl-C> to stop.\n"); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "Using configuration file %s.", configFile); TC_LOG_WARN(LOG_FILTER_AUTHSERVER, "%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); #else ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); #endif TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "Max allowed open files is %d", ACE::max_handles()); // authserver PID file creation std::string pidFile = sConfigMgr->GetStringDefault("PidFile", ""); if (!pidFile.empty()) { if (uint32 pid = CreatePIDFile(pidFile)) TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "Daemon PID: %u\n", pid); else { TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "Cannot create PID file %s.\n", pidFile.c_str()); return 1; } } // Initialize the database connection if (!StartDB()) return 1; // Get the list of realms for the server sRealmList->Initialize(sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList->size() == 0) { TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "No valid realms specified."); return 1; } // Launch the listening network socket RealmAcceptor acceptor; int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724); if (rmport < 0 || rmport > 0xFFFF) { TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "Specified port out of allowed range (1-65535)"); return 1; } std::string bind_ip = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); ACE_INET_Addr bind_addr(uint16(rmport), bind_ip.c_str()); if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) { TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "Auth server can not bind to %s:%d", bind_ip.c_str(), rmport); return 1; } // Initialize the signal handlers AuthServerSignalHandler SignalINT, SignalTERM; // Register authservers's signal handlers ACE_Sig_Handler Handler; Handler.register_handler(SIGINT, &SignalINT); Handler.register_handler(SIGTERM, &SignalTERM); ///- 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(LOG_FILTER_AUTHSERVER, "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the authserver. Accessible processors bitmask (hex): %x", affinity, appAff); else if (SetProcessAffinityMask(hProcess, currentAffinity)) TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "Using processors (bitmask, hex): %x", currentAffinity); else TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "Can't set used processors (hex): %x", currentAffinity); } } if (highPriority) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "authserver process priority class set to HIGH"); else TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "Can't set authserver process priority class."); } } #elif __linux__ // 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(LOG_FILTER_AUTHSERVER, "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(LOG_FILTER_AUTHSERVER, "Using processors (bitmask, hex): %x", *(uint32*)(&mask)); } } if (highPriority) { if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "Can't set authserver process priority class, error: %s", strerror(errno)); else TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); } #endif // maximum counter for next ping uint32 numLoops = (sConfigMgr->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; // Wait for termination signal while (!stopEvent) { // dont move this outside the loop, the reactor will modify it ACE_Time_Value interval(0, 100000); if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) break; if ((++loopCounter) == numLoops) { loopCounter = 0; TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "Ping MySQL to keep connection alive"); LoginDatabase.KeepAlive(); } } // Close the Database Pool and library StopDB(); TC_LOG_INFO(LOG_FILTER_AUTHSERVER, "Halting process..."); return 0; }
/// Initialize connection to the databases bool StartDB() { MySQL::Library_Init(); std::string dbString; uint8 asyncThreads, synchThreads; dbString = sConfigMgr->GetStringDefault("WorldDatabaseInfo", ""); if (dbString.empty()) { TC_LOG_ERROR("server.worldserver", "World database not specified in configuration file"); return false; } asyncThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.WorkerThreads", 1)); if (asyncThreads < 1 || asyncThreads > 32) { TC_LOG_ERROR("server.worldserver", "World database: invalid number of worker threads specified. " "Please pick a value between 1 and 32."); return false; } synchThreads = uint8(sConfigMgr->GetIntDefault("WorldDatabase.SynchThreads", 1)); ///- Initialize the world database if (!WorldDatabase.Open(dbString, asyncThreads, synchThreads)) { TC_LOG_ERROR("server.worldserver", "Cannot connect to world database %s", dbString.c_str()); return false; } ///- Get character database info from configuration file dbString = sConfigMgr->GetStringDefault("CharacterDatabaseInfo", ""); if (dbString.empty()) { TC_LOG_ERROR("server.worldserver", "Character database not specified in configuration file"); return false; } asyncThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.WorkerThreads", 1)); if (asyncThreads < 1 || asyncThreads > 32) { TC_LOG_ERROR("server.worldserver", "Character database: invalid number of worker threads specified. " "Please pick a value between 1 and 32."); return false; } synchThreads = uint8(sConfigMgr->GetIntDefault("CharacterDatabase.SynchThreads", 2)); ///- Initialize the Character database if (!CharacterDatabase.Open(dbString, asyncThreads, synchThreads)) { TC_LOG_ERROR("server.worldserver", "Cannot connect to Character database %s", dbString.c_str()); return false; } ///- Get login database info from configuration file dbString = sConfigMgr->GetStringDefault("LoginDatabaseInfo", ""); if (dbString.empty()) { TC_LOG_ERROR("server.worldserver", "Login database not specified in configuration file"); return false; } asyncThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.WorkerThreads", 1)); if (asyncThreads < 1 || asyncThreads > 32) { TC_LOG_ERROR("server.worldserver", "Login database: invalid number of worker threads specified. " "Please pick a value between 1 and 32."); return false; } synchThreads = uint8(sConfigMgr->GetIntDefault("LoginDatabase.SynchThreads", 1)); ///- Initialise the login database if (!LoginDatabase.Open(dbString, asyncThreads, synchThreads)) { TC_LOG_ERROR("server.worldserver", "Cannot connect to login database %s", dbString.c_str()); return false; } ///- Get the realm Id from the configuration file realmID = sConfigMgr->GetIntDefault("RealmID", 0); if (!realmID) { TC_LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file"); return false; } TC_LOG_INFO("server.worldserver", "Realm running as realm ID %d", realmID); ///- Clean the database before starting ClearOnlineAccounts(); ///- Insert version info into DB WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _HASH); // One-time query sWorld->LoadDBVersion(); TC_LOG_INFO("server.worldserver", "Using World DB: %s", sWorld->GetDBVersion()); return true; }
/// Launch the Trinity server extern int main(int argc, char** argv) { std::string configFile = _TRINITY_CORE_CONFIG; std::string configService; auto vm = GetConsoleArguments(argc, argv, configFile, configService); // exit if help is enabled if (vm.count("help")) return 0; #ifdef _WIN32 if (configService.compare("install") == 0) return WinServiceInstall() == true ? 0 : 1; else if (configService.compare("uninstall") == 0) return WinServiceUninstall() == true ? 0 : 1; else if (configService.compare("run") == 0) WinServiceRun(); #endif if (!sConfigMgr->LoadInitial(configFile)) { printf("Invalid or missing configuration file : %s\n", configFile.c_str()); printf("Verify that the file exists and has \'[worldserver]' written in the top of the file!\n"); return 1; } if (sConfigMgr->GetBoolDefault("Log.Async.Enable", false)) { // If logs are supposed to be handled async then we need to pass the io_service into the Log singleton Log::instance(&_ioService); } TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon)", _FULLVERSION); TC_LOG_INFO("server.worldserver", "<Ctrl-C> to stop.\n"); 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", " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\"); TC_LOG_INFO("server.worldserver", " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\"); TC_LOG_INFO("server.worldserver", " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\"); TC_LOG_INFO("server.worldserver", " C O R E /\\___/"); TC_LOG_INFO("server.worldserver", "http://TrinityCore.org \\/__/\n"); TC_LOG_INFO("server.worldserver", "Using configuration file %s.", configFile.c_str()); TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); OpenSSLCrypto::threadsSetup(); // Seed the OpenSSL's PRNG here. // That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login BigNumber seed; seed.SetRand(16 * 8); /// 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; } } // Set signal handlers (this must be done before starting io_service threads, because otherwise they would unblock and exit) boost::asio::signal_set signals(_ioService, SIGINT, SIGTERM); #if PLATFORM == PLATFORM_WINDOWS signals.add(SIGBREAK); #endif signals.async_wait(SignalHandler); // Start the Boost based thread pool int numThreads = sConfigMgr->GetIntDefault("ThreadPool", 1); std::vector<std::thread> threadPool; if (numThreads < 1) numThreads = 1; for (int i = 0; i < numThreads; ++i) threadPool.push_back(std::thread(boost::bind(&boost::asio::io_service::run, &_ioService))); // Set process priority according to configuration settings SetProcessPriority("server.worldserver"); // 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(); // Launch CliRunnable thread std::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 { cliThread = new std::thread(CliThread); } // Start the Remote Access port (acceptor) if enabled AsyncAcceptor<RASession>* raAcceptor = nullptr; if (sConfigMgr->GetBoolDefault("Ra.Enable", false)) raAcceptor = StartRaSocketAcceptor(_ioService); // Start soap serving thread if enabled std::thread* soapThread = nullptr; if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false)) { soapThread = new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))); } // Launch the worldserver listener socket uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD)); std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0"); bool tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true); AsyncAcceptor<WorldSocket> worldAcceptor(_ioService, worldListener, worldPort, tcpNoDelay); sScriptMgr->OnStartup(); // Set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec) if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) { _maxCoreStuckTimeInMs = coreStuckTime * 1000; _freezeCheckTimer.expires_from_now(boost::posix_time::seconds(5)); _freezeCheckTimer.async_wait(FreezeDetectorHandler); TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread (%u seconds max stuck time)...", coreStuckTime); } TC_LOG_INFO("server.worldserver", "%s (worldserver-daemon) ready...", _FULLVERSION); WorldUpdateLoop(); // Shutdown starts here _ioService.stop(); for (auto& thread : threadPool) { thread.join(); } sScriptMgr->OnShutdown(); sWorld->KickAll(); // save and kick all players sWorld->UpdateSessions(1); // real players unload required UpdateSessions call // unload battleground templates before different singletons destroyed sBattlegroundMgr->DeleteAllBattlegrounds(); sMapMgr->UnloadAll(); // unload all grids (including locked in memory) sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world sScriptMgr->Unload(); sOutdoorPvPMgr->Die(); // set server offline LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); // Clean up threads if any if (soapThread != nullptr) { soapThread->join(); delete soapThread; } if (raAcceptor != nullptr) delete raAcceptor; ///- Clean database before leaving ClearOnlineAccounts(); StopDB(); TC_LOG_INFO("server.worldserver", "Halting process..."); if (cliThread != nullptr) { #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); #endif cliThread->join(); delete cliThread; } OpenSSLCrypto::threadsCleanup(); // 0 - normal shutdown // 1 - shutdown at error // 2 - restart command used, this code can be used by restarter for restart Trinityd return World::GetExitCode(); }
// Launch the auth server extern int main(int argc, char **argv) { // Command line parsing to get the configuration file name char const* cfg_file = _TRINITY_REALM_CONFIG; int c = 1; while (c < argc) { if (strcmp(argv[c], "-c") == 0) { if (++c >= argc) { printf("Runtime-Error: -c option requires an input argument"); usage(argv[0]); return 1; } else cfg_file = argv[c]; } ++c; } if (!ConfigMgr::Load(cfg_file)) { printf("Invalid or missing configuration file : %s", cfg_file); printf("Verify that the file exists and has \'[authserver]\' written in the top of the file!"); return 1; } sLog->outInfo(LOG_FILTER_AUTHSERVER, "%s (authserver)", _FULLVERSION); sLog->outInfo(LOG_FILTER_AUTHSERVER, "<Ctrl-C> to stop.\n"); sLog->outInfo(LOG_FILTER_AUTHSERVER, "Using configuration file %s.", cfg_file); sLog->outWarn(LOG_FILTER_AUTHSERVER, "%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); #else ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); #endif sLog->outDebug(LOG_FILTER_AUTHSERVER, "Max allowed open files is %d", ACE::max_handles()); // authserver PID file creation std::string pidfile = ConfigMgr::GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog->outError(LOG_FILTER_AUTHSERVER, "Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog->outInfo(LOG_FILTER_AUTHSERVER, "Daemon PID: %u\n", pid); } // Initialize the database connection if (!StartDB()) return 1; sLog->SetRealmID(0); // ensure we've set realm to 0 (authserver realmid) // Get the list of realms for the server sRealmList->Initialize(ConfigMgr::GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList->size() == 0) { sLog->outError(LOG_FILTER_AUTHSERVER, "No valid realms specified."); return 1; } // Launch the listening network socket RealmAcceptor acceptor; int32 rmport = ConfigMgr::GetIntDefault("RealmServerPort", 3724); if (rmport < 0 || rmport > 0xFFFF) { sLog->outError(LOG_FILTER_AUTHSERVER, "Specified port out of allowed range (1-65535)"); return 1; } std::string bind_ip = ConfigMgr::GetStringDefault("BindIP", "0.0.0.0"); ACE_INET_Addr bind_addr(uint16(rmport), bind_ip.c_str()); if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) { sLog->outError(LOG_FILTER_AUTHSERVER, "Auth server can not bind to %s:%d", bind_ip.c_str(), rmport); return 1; } // Initialise the signal handlers AuthServerSignalHandler SignalINT, SignalTERM; // Register authservers's signal handlers ACE_Sig_Handler Handler; Handler.register_handler(SIGINT, &SignalINT); Handler.register_handler(SIGTERM, &SignalTERM); ///- 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(LOG_FILTER_AUTHSERVER, "Processors marked in UseProcessors bitmask (hex) %x not accessible for authserver. Accessible processors bitmask (hex): %x", Aff, appAff); else if (SetProcessAffinityMask(hProcess, curAff)) sLog->outInfo(LOG_FILTER_AUTHSERVER, "Using processors (bitmask, hex): %x", curAff); else sLog->outError(LOG_FILTER_AUTHSERVER, "Can't set used processors (hex): %x", curAff); } } bool Prio = ConfigMgr::GetBoolDefault("ProcessPriority", false); if (Prio) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog->outInfo(LOG_FILTER_AUTHSERVER, "The auth server process priority class has been set to HIGH"); else sLog->outError(LOG_FILTER_AUTHSERVER, "Can't set auth server process priority class."); } } #endif // maximum counter for next ping uint32 numLoops = (ConfigMgr::GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; // Wait for termination signal while (!stopEvent) { // dont move this outside the loop, the reactor will modify it ACE_Time_Value interval(0, 100000); if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) break; if ((++loopCounter) == numLoops) { loopCounter = 0; sLog->outInfo(LOG_FILTER_AUTHSERVER, "Ping MySQL to keep connection alive"); LoginDatabase.KeepAlive(); } } // Close the Database Pool and library StopDB(); sLog->outInfo(LOG_FILTER_AUTHSERVER, "Halting process..."); return 0; }
/// Launch the realm server extern int main(int argc, char **argv) { sLog->SetLogDB(false); ///- Command line parsing to get the configuration file name char const* cfg_file = _TRINITY_REALM_CONFIG; int c = 1; while(c < argc) { if (strcmp(argv[c], "-c") == 0) { if (++c >= argc) { sLog->outError("Runtime-Error: -c option requires an input argument"); usage(argv[0]); return 1; } else cfg_file = argv[c]; } #ifdef _WIN32 //////////// //Services// //////////// if (strcmp(argv[c], "-s") == 0) { if (++c >= argc) { sLog->outError("Runtime-Error: -s option requires an input argument"); usage(argv[0]); return 1; } if (strcmp(argv[c], "install") == 0) { if (WinServiceInstall()) sLog->outString("Installiere Service"); return 1; } else if (strcmp(argv[c], "uninstall") == 0) { if (WinServiceUninstall()) sLog->outString("Deinstalliere Service"); return 1; } else { sLog->outError("Runtime-Error: unsupported option %s", argv[c]); usage(argv[0]); return 1; } } if (strcmp(argv[c], "--service") == 0) WinServiceRun(); #endif ++c; } if (!sConfig->SetSource(cfg_file)) { sLog->outError("Invalid or missing configuration file : %s", cfg_file); sLog->outError("Verify that the file exists and has \'[authserver]\' written in the top of the file!"); return 1; } sLog->Initialize(); sLog->outString(" "); sLog->outString(" ##### ##### "); sLog->outString(" # # ##### ## ##### # # ## ##### ###### "); sLog->outString(" # # # # # # # # # # # "); sLog->outString(" ##### # # # # # # #### # # # ##### "); sLog->outString(" # # ###### ##### # # ###### # # "); sLog->outString(" # # # # # # # # # # # # # "); sLog->outString(" ##### # # # # # ##### # # # ######" ); sLog->outString(" "); sLog->outString(" Project StarGateEmu 2011 (c) "); sLog->outString(" "); sLog->outString(" %s ", _FULLVERSION); sLog->outString(" "); sLog->outString(" "); sLog->outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); #else ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); #endif sLog->outBasic("Max. zulässige offene Dateien %d", ACE::max_handles()); /// realmd 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); } ///- Initialize the database connection if (!StartDB()) return 1; ///- Initialize the log database sLog->SetLogDBLater(sConfig->GetBoolDefault("EnableLogDB", false)); // set var to enable DB logging once startup finished. sLog->SetLogDB(false); sLog->SetRealmID(0); // ensure we've set realm to 0 (realmd realmid) ///- Get the list of realms for the server sRealmList->Initialize(sConfig->GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList->size() == 0) { sLog->outError("Keine gültige Bereiche angegeben."); return 1; } ///- Launch the listening network socket RealmAcceptor acceptor; uint16 rmport = sConfig->GetIntDefault("RealmServerPort", 3724); std::string bind_ip = sConfig->GetStringDefault("BindIP", "0.0.0.0"); ACE_INET_Addr bind_addr(rmport, bind_ip.c_str()); if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) { sLog->outError("StarGateAuth nicht zu binden %s:%d", bind_ip.c_str(), rmport); return 1; } // Initialise the signal handlers RealmdSignalHandler SignalINT, SignalTERM; #ifdef _WIN32 RealmdSignalHandler 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 */ ///- 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("Prozessoren in UseProcessors Bitmaske markiert (hex) %x nicht zugänglich realmd. Accessible Prozessor Bitmaske (hex): %x", Aff, appAff); else if (SetProcessAffinityMask(hProcess, curAff)) sLog->outString("Mit Prozessoren (bitmask, hex): %x", curAff); else sLog->outError("Kann verwendeter Prozessor nicht festgelegen!.(hex): %x", curAff); } } bool Prio = sConfig->GetBoolDefault("ProcessPriority", false); if (Prio) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog->outString("[StarGate-Auth] Prozess-Priorität festgelegt auf HOCH"); else sLog->outError("Realmd Prozess-Priorität Fehler!."); } } #endif // maximum counter for next ping uint32 numLoops = (sConfig->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; // possibly enable db logging; avoid massive startup spam by doing it here. if (sLog->GetLogDBLater()) { sLog->outString("Aktiviere Datenbankprotokollierung..."); sLog->SetLogDBLater(false); // login db needs thread for logging sLog->SetLogDB(true); } else sLog->SetLogDB(false); ///- Wait for termination signal while (!stopEvent) { // dont move this outside the loop, the reactor will modify it ACE_Time_Value interval(0, 100000); if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) break; if ((++loopCounter) == numLoops) { loopCounter = 0; sLog->outDetail("Ping MySQL: Verbindung aufrecht zu erhalten"); LoginDatabase.KeepAlive(); } #ifdef _WIN32 if (m_ServiceStatus == 0) stopEvent = true; else { while (m_ServiceStatus == 2) Sleep(1000); } #endif } ///- Close the Database Pool LoginDatabase.Close(); sLog->outString("Halte Prozess..."); return 0; }