/// Launch the realm server extern int main(int argc, char** argv) { ///- Command line parsing char const* cfg_file = _REALMD_CONFIG; char const* options = ":c:s:"; ACE_Get_Opt cmd_opts(argc, argv, options); cmd_opts.long_option("version", 'v'); char serviceDaemonMode = '\0'; int option; while ((option = cmd_opts()) != EOF) { switch (option) { case 'c': cfg_file = cmd_opts.opt_arg(); break; case 'v': printf("%s\n", _FULLVERSION(REVISION_DATE, REVISION_TIME, REVISION_NR, REVISION_ID)); return 0; case 's': { const char* mode = cmd_opts.opt_arg(); if (!strcmp(mode, "run")) serviceDaemonMode = 'r'; #ifdef WIN32 else if (!strcmp(mode, "install")) serviceDaemonMode = 'i'; else if (!strcmp(mode, "uninstall")) serviceDaemonMode = 'u'; #else else if (!strcmp(mode, "stop")) serviceDaemonMode = 's'; #endif else { sLog.outError("Runtime-Error: -%c unsupported argument %s", cmd_opts.opt_opt(), mode); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; } break; } case ':': sLog.outError("Runtime-Error: -%c option requires an input argument", cmd_opts.opt_opt()); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; default: sLog.outError("Runtime-Error: bad format of commandline arguments"); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; } } #ifdef WIN32 // windows service command need execute before config read switch (serviceDaemonMode) { case 'i': if (WinServiceInstall()) sLog.outString("Installing service"); return 1; case 'u': if (WinServiceUninstall()) sLog.outString("Uninstalling service"); return 1; case 'r': WinServiceRun(); break; } #endif if (!sConfig.SetSource(cfg_file)) { sLog.outError("Could not find configuration file %s.", cfg_file); Log::WaitBeforeContinueIfNeed(); return 1; } #ifndef WIN32 // posix daemon commands need apply after config read switch (serviceDaemonMode) { case 'r': startDaemon(); break; case 's': stopDaemon(); break; } #endif sLog.Initialize(); sLog.outString("%s [realm-daemon]", _FULLVERSION(REVISION_DATE, REVISION_TIME, REVISION_NR, REVISION_ID)); sLog.outString("<Ctrl-C> to stop.\n"); sLog.outString("Using configuration file %s.", cfg_file); ///- Check the version of the configuration file uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); if (confVersion < _REALMDCONFVERSION) { sLog.outError("*****************************************************************************"); sLog.outError(" WARNING: Your realmd.conf version indicates your conf file is out of date!"); sLog.outError(" Please check for updates, as your current default values may cause"); sLog.outError(" strange behavior."); sLog.outError("*****************************************************************************"); Log::WaitBeforeContinueIfNeed(); } DETAIL_LOG("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); if (SSLeay() < 0x009080bfL) { DETAIL_LOG("WARNING: Outdated version of OpenSSL lib. Logins to server may not work!"); DETAIL_LOG("WARNING: Minimal required version [OpenSSL 0.9.8k]"); } DETAIL_LOG("Using ACE: %s", ACE_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()); /// 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()); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString("Daemon PID: %u\n", pid); } ///- Initialize the database connection if (!StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Get the list of realms for the server sRealmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList.size() == 0) { sLog.outError("No valid realms specified."); Log::WaitBeforeContinueIfNeed(); return 1; } // cleanup query // set expired bans to inactive LoginDatabase.BeginTransaction(); LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.CommitTransaction(); ///- Launch the listening network socket ACE_Acceptor<AuthSocket, ACE_SOCK_Acceptor> acceptor; uint16 rmport = sConfig.GetIntDefault("RealmServerPort", DEFAULT_REALMSERVER_PORT); 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("MaNGOS realmd can not bind to %s:%d", bind_ip.c_str(), rmport); Log::WaitBeforeContinueIfNeed(); return 1; } ///- Catch termination signals HookSignals(); ///- 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 realmd. 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("realmd process priority class set to HIGH"); else sLog.outError("Can't set realmd process priority class."); sLog.outString(); } } #endif // server has started up successfully => enable async DB requests LoginDatabase.AllowAsyncTransactions(); // maximum counter for next ping uint32 numLoops = (sConfig.GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; #ifndef WIN32 detachDaemon(); #endif ///- 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; DETAIL_LOG("Ping MySQL to keep connection alive"); LoginDatabase.Ping(); } #ifdef WIN32 if (m_ServiceStatus == 0) stopEvent = true; while (m_ServiceStatus == 2) Sleep(1000); #endif } ///- Wait for the delay thread to exit LoginDatabase.HaltDelayThread(); ///- Remove signal handling before leaving UnhookSignals(); sLog.outString("Halting process..."); return 0; }
// 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(); }
/// 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", "<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"); /// 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 = NULL; #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 = NULL; 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); // 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(); }
/// Launch the realm server extern int main(int argc, char **argv) { ///- Command line parsing to get the configuration file name char const* cfg_file = _REALMD_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]; } if( strcmp(argv[c],"--version") == 0) { printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); return 0; } #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("Installing service"); return 1; } else if( strcmp(argv[c],"uninstall") == 0) { if(WinServiceUninstall()) sLog.outString("Uninstalling 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("Could not find configuration file %s.", cfg_file); return 1; } sLog.Initialize(); sLog.outString( "%s [realm-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) ); sLog.outString( "<Ctrl-C> to stop.\n" ); sLog.outString("Using configuration file %s.", cfg_file); ///- Check the version of the configuration file uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); if (confVersion < _REALMDCONFVERSION) { sLog.outError("*****************************************************************************"); sLog.outError(" WARNING: Your realmd.conf version indicates your conf file is out of date!"); sLog.outError(" Please check for updates, as your current default values may cause"); sLog.outError(" strange behavior."); sLog.outError("*****************************************************************************"); clock_t pause = 3000 + clock(); while (pause > clock()) {} } sLog.outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); if (SSLeay() < 0x009080bfL ) { sLog.outDetail("WARNING: Outdated version of OpenSSL lib. Logins to server impossible!"); sLog.outDetail("WARNING: Minimal required version [OpenSSL 0.9.8k]"); } /// 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 std::string dbstring; if(!StartDB(dbstring)) return 1; ///- Get the list of realms for the server m_realmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20)); if (m_realmList.size() == 0) { sLog.outError("No valid realms specified."); return 1; } ///- Launch the listening network socket port_t rmport = sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT ); std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0"); SocketHandler h; ListenSocket<AuthSocket> authListenSocket(h); if ( authListenSocket.Bind(bind_ip.c_str(),rmport)) { sLog.outError( "MaNGOS realmd can not bind to %s:%d",bind_ip.c_str(), rmport ); return 1; } h.Add(&authListenSocket); ///- Catch termination signals HookSignals(); ///- 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 realmd. 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("realmd process priority class set to HIGH"); else sLog.outError("ERROR: Can't set realmd process priority class."); sLog.outString(); } } #endif // maximum counter for next ping uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; ///- Wait for termination signal while (!stopEvent) { h.Select(0, 100000); if( (++loopCounter) == numLoops ) { loopCounter = 0; sLog.outDetail("Ping MySQL to keep connection alive"); delete loginDatabase.Query("SELECT 1 FROM realmlist LIMIT 1"); } #ifdef WIN32 if (m_ServiceStatus == 0) stopEvent = true; while (m_ServiceStatus == 2) Sleep(1000); #endif } ///- Wait for the delay thread to exit loginDatabase.HaltDelayThread(); ///- Remove signal handling before leaving UnhookSignals(); 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* 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\n"); usage(argv[0]); return 1; } else cfg_file = argv[c]; } ++c; } if (!ConfigMgr::Load(cfg_file)) { printf("Invalid or missing configuration file : %s\n", cfg_file); printf("Verify that the file exists and has \'[authserver]\' written in the top of the file!\n"); return 1; } sLog->outInfo(LOG_FILTER_AUTHSERVER, "%s (authserver)", _FULLVERSION); 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; }
/// 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(); }
/// Main function int Master::Run() { BigNumber seed1; seed1.SetRand(16 * 8); sLog->outInfo(LOG_FILTER_WORLDSERVER, "%s (worldserver-daemon)", _FULLVERSION); sLog->outInfo(LOG_FILTER_WORLDSERVER, "<Ctrl-C> to stop.\n"); sLog->outInfo(LOG_FILTER_WORLDSERVER, " _ _ _ _ _____ "); sLog->outInfo(LOG_FILTER_WORLDSERVER, "| | | | | | | / ___| "); sLog->outInfo(LOG_FILTER_WORLDSERVER, "| | | | ___ | | | \\ `--. ___ _ _ _ __ ___ ___ "); sLog->outInfo(LOG_FILTER_WORLDSERVER, "| |/\\| |/ _ \\| |/\\| |`--. \\/ _ \\| | | | '__/ __/ _ \\"); sLog->outInfo(LOG_FILTER_WORLDSERVER, "\\ /\\ / (_) \\ /\\ /\\__/ / (_) | |_| | | | (_| __/"); sLog->outInfo(LOG_FILTER_WORLDSERVER, " \\/ \\/ \\___/ \\/ \\/\\____/ \\___/ \\__,_|_| \\___\\___|"); sLog->outInfo(LOG_FILTER_WORLDSERVER, "TrinityCore 2012-2015"); sLog->outInfo(LOG_FILTER_WORLDSERVER, "Visit our forum www.TrinityCore.info"); sLog->outInfo(LOG_FILTER_WORLDSERVER, "TrinityCore V3 Mop 5.4.8"); /// worldserver PID file creation std::string pidfile = ConfigMgr::GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog->outError(LOG_FILTER_WORLDSERVER, "Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog->outInfo(LOG_FILTER_WORLDSERVER, "Daemon PID: %u\n", pid); } ///- Start the databases if (!_StartDB()) return 1; ///- 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 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(LOG_FILTER_WORLDSERVER, "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->outInfo(LOG_FILTER_WORLDSERVER, "Using processors (bitmask, hex): %x", curAff); else sLog->outError(LOG_FILTER_WORLDSERVER, "Can't set used processors (hex): %x", curAff); } } } 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->outInfo(LOG_FILTER_WORLDSERVER, "worldserver process priority class set to HIGH"); else sLog->outError(LOG_FILTER_WORLDSERVER, "Can't set worldserver process priority class."); } } #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"), uint16(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(LOG_FILTER_WORLDSERVER, "Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sLog->outInfo(LOG_FILTER_WORLDSERVER, "%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; } ///- Clean database before leaving ClearOnlineAccounts(); _StopDB(); sLog->outInfo(LOG_FILTER_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[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(); }
/// 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 = _ARKCORE_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("Installing service"); return 1; } else if (strcmp(argv[c], "uninstall") == 0) { if (WinServiceUninstall()) sLog->outString("Uninstalling 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("%s (realm-daemon)", _CLIENT_BUILD_REVISION); sLog->outString(" "); sLog->outString("World of Warcraft: Mists of Pandaria"); sLog->outString(" Server emulator"); sLog->outString("This core is based on ArkCORE source."); sLog->outString(" "); 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()); /// 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("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("ArkCORE Auth can not bind to %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("Processors marked in UseProcessors bitmask (hex) %x not accessible for realmd. 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("ArkCORE Auth process priority class set to HIGH"); else sLog->outError("Can't set realmd process priority class."); sLog->outString(); } } #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("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) { // 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 to keep connection alive"); 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("Halting process..."); return 0; }
/// Launch the realm server int main(int argc, char *argv[]) { std::string configFile, serviceParameter; boost::program_options::options_description desc("Allowed options"); desc.add_options() ("config,c", boost::program_options::value<std::string>(&configFile)->default_value(_REALMD_CONFIG), "configuration file") ("version,v", "print version and exit") #ifdef _WIN32 ("s", boost::program_options::value<std::string>(&serviceParameter), "<run, install, uninstall> service"); #else ("s", boost::program_options::value<std::string>(&serviceParameter), "<run, stop> service"); #endif boost::program_options::variables_map vm; try { boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); boost::program_options::notify(vm); } catch (boost::program_options::error const &e) { std::cerr << "ERROR: " << e.what() << std::endl << std::endl; std::cerr << desc << std::endl; return 1; } #ifdef _WIN32 // windows service command need execute before config read if (vm.count("s")) { switch (::tolower(serviceParameter[0])) { case 'i': if (WinServiceInstall()) sLog.outString("Installing service"); return 1; case 'u': if (WinServiceUninstall()) sLog.outString("Uninstalling service"); return 1; case 'r': WinServiceRun(); break; } } #endif if (!sConfig.SetSource(configFile)) { sLog.outError("Could not find configuration file %s.", configFile.c_str()); Log::WaitBeforeContinueIfNeed(); return 1; } #ifndef _WIN32 // posix daemon commands need apply after config read if (vm.count("s")) { switch (::tolower(serviceParameter[0])) { case 'r': startDaemon(); break; case 's': stopDaemon(); break; } } #endif sLog.Initialize(); sLog.outString("%s [realm-daemon]", _FULLVERSION(REVISION_DATE, REVISION_TIME, REVISION_ID)); sLog.outString("<Ctrl-C> to stop.\n"); sLog.outString("Using configuration file %s.", configFile.c_str()); ///- Check the version of the configuration file uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); if (confVersion < _REALMDCONFVERSION) { sLog.outError("*****************************************************************************"); sLog.outError(" WARNING: Your realmd.conf version indicates your conf file is out of date!"); sLog.outError(" Please check for updates, as your current default values may cause"); sLog.outError(" strange behavior."); sLog.outError("*****************************************************************************"); Log::WaitBeforeContinueIfNeed(); } DETAIL_LOG("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); if (SSLeay() < 0x009080bfL) { DETAIL_LOG("WARNING: Outdated version of OpenSSL lib. Logins to server may not work!"); DETAIL_LOG("WARNING: Minimal required version [OpenSSL 0.9.8k]"); } /// 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()); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString("Daemon PID: %u\n", pid); } ///- Initialize the database connection if (!StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Get the list of realms for the server sRealmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList.size() == 0) { sLog.outError("No valid realms specified."); Log::WaitBeforeContinueIfNeed(); return 1; } // cleanup query // set expired bans to inactive LoginDatabase.BeginTransaction(); LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.CommitTransaction(); auto rmport = sConfig.GetIntDefault("RealmServerPort", DEFAULT_REALMSERVER_PORT); std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0"); // FIXME - more intelligent selection of thread count is needed here. config option? MaNGOS::Listener<AuthSocket> listener(rmport, 1); ///- Catch termination signals HookSignals(); ///- 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 realmd. 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("realmd process priority class set to HIGH"); else sLog.outError("Can't set realmd process priority class."); sLog.outString(); } } #endif // server has started up successfully => enable async DB requests LoginDatabase.AllowAsyncTransactions(); // maximum counter for next ping auto const numLoops = sConfig.GetIntDefault("MaxPingTime", 30) * MINUTE * 10; uint32 loopCounter = 0; #ifndef _WIN32 detachDaemon(); #endif ///- Wait for termination signal while (!stopEvent) { if ((++loopCounter) == numLoops) { loopCounter = 0; DETAIL_LOG("Ping MySQL to keep connection alive"); LoginDatabase.Ping(); } std::this_thread::sleep_for(std::chrono::milliseconds(100)); #ifdef _WIN32 if (m_ServiceStatus == 0) stopEvent = true; while (m_ServiceStatus == 2) Sleep(1000); #endif } ///- Wait for the delay thread to exit LoginDatabase.HaltDelayThread(); ///- Remove signal handling before leaving UnhookSignals(); sLog.outString("Halting process..."); return 0; }
/// 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(); }
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(); }
/// Launch the realm server extern int main(int argc, char** argv) { ///- Command line parsing std::string cfg_file; std::string serviceDaemonMode; boost::program_options::options_description description("Allowed options"); description.add_options() ("version,v", "print version and exit") ("help,h", "print commandline help and exit") ("config,c", boost::program_options::value<std::string>(&cfg_file)->default_value(_REALMD_CONFIG), "use as configuration file") #ifdef WIN32 ("service,s", boost::program_options::value<std::string>(&serviceDaemonMode), "running as service, arg functions: run, install, uninstall") #else ("service,s", boost::program_options::value<std::string>(&serviceDaemonMode), "running as daemon, arg functions: run, stop") #endif ; // parse option boost::program_options::variables_map vm; try { boost::program_options::store(boost::program_options::command_line_parser(argc, argv). options(description).run(), vm); boost::program_options::notify(vm); } catch(boost::program_options::unknown_option const& ex) { sLog.outError("Runtime-Error: unknown option %s", ex.get_option_name().c_str()); usage(description, argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; } catch(boost::program_options::invalid_command_line_syntax const& ex) { sLog.outError("Runtime-Error: invalid syntax for option %s", ex.get_option_name().c_str()); usage(description, argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; } if (vm.count("version")) { printf("%s\n", _FULLVERSION(REVISION_DATE, REVISION_TIME, REVISION_NR, REVISION_ID)); return 0; } if (vm.count("help")) { usage(description, argv[0]); return 0; } if (!serviceDaemonMode.empty()) { #ifdef WIN32 char const* const serviceModes[] = { "run", "install", "uninstall", NULL }; #else char const* const serviceModes[] = { "run", "stop", NULL }; #endif char const* const* mode_ptr = &serviceModes[0]; for(; *mode_ptr != NULL; ++mode_ptr) if (*mode_ptr == serviceDaemonMode) break; if (!*mode_ptr) { sLog.outError("Runtime-Error: -s unsupported argument %s", serviceDaemonMode.c_str()); usage(description, argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; } } #ifdef WIN32 // windows service command need execute before config read switch (serviceDaemonMode[0]) { case 'i': if (WinServiceInstall()) sLog.outString("Installing service"); return 1; case 'u': if (WinServiceUninstall()) sLog.outString("Uninstalling service"); return 1; case 'r': WinServiceRun(); break; } #endif if (!sConfig.SetSource(cfg_file, "RealmdConf")) { sLog.outError("Could not find configuration file %s.", cfg_file); Log::WaitBeforeContinueIfNeed(); return 1; } #ifndef WIN32 // posix daemon commands need apply after config read switch (serviceDaemonMode) { case 'r': startDaemon(); break; case 's': stopDaemon(); break; } #endif sLog.Initialize(); sLog.outString("%s [realm-daemon]", _FULLVERSION(REVISION_DATE, REVISION_TIME, REVISION_NR, REVISION_ID)); sLog.outString("<Ctrl-C> to stop.\n"); sLog.outString("Using configuration file %s.", cfg_file); ///- Check the version of the configuration file uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); if (confVersion < _REALMDCONFVERSION) { sLog.outError("*****************************************************************************"); sLog.outError(" WARNING: Your realmd.conf version indicates your conf file is out of date!"); sLog.outError(" Please check for updates, as your current default values may cause"); sLog.outError(" strange behavior."); sLog.outError("*****************************************************************************"); Log::WaitBeforeContinueIfNeed(); } DETAIL_LOG("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); if (SSLeay() < 0x009080bfL) { DETAIL_LOG("WARNING: Outdated version of OpenSSL lib. Logins to server may not work!"); DETAIL_LOG("WARNING: Minimal required version [OpenSSL 0.9.8k]"); } DETAIL_LOG("Using ACE: %s", ACE_VERSION); DETAIL_LOG("Using BOOST: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100); sLog.outBasic("Max allowed open files is %d", boost::asio::socket_base::max_connections); /// 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()); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString("Daemon PID: %u\n", pid); } ///- Initialize the database connection if (!StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Get the list of realms for the server sRealmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList.size() == 0) { sLog.outError("No valid realms specified."); Log::WaitBeforeContinueIfNeed(); return 1; } // cleanup query // set expired bans to inactive LoginDatabase.BeginTransaction(); LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.CommitTransaction(); ///- Launch the listening network socket uint16 rmport = sConfig.GetIntDefault("RealmServerPort", DEFAULT_REALMSERVER_PORT); std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0"); std::auto_ptr< SessionManager > manager( new SessionManager() ); if ( !manager->StartNetwork( rmport, bind_ip )) { sLog.outError("MaNGOS realmd can not bind to %s:%d", bind_ip.c_str(), rmport); Log::WaitBeforeContinueIfNeed(); return 1; } ///- Catch termination signals HookSignals(); ///- 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 realmd. 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("realmd process priority class set to HIGH"); else sLog.outError("Can't set realmd process priority class."); sLog.outString(); } } #endif // server has started up successfully => enable async DB requests LoginDatabase.AllowAsyncTransactions(); // maximum counter for next ping uint32 numLoops = (sConfig.GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; #ifndef WIN32 detachDaemon(); #endif ///- Wait for termination signal while (!stopEvent) { // dont move this outside the loop, the reactor will modify it boost::this_thread::sleep(boost::posix_time::milliseconds(10)); if ((++loopCounter) == numLoops) { loopCounter = 0; DETAIL_LOG("Ping MySQL to keep connection alive"); LoginDatabase.Ping(); } #ifdef WIN32 if (m_ServiceStatus == 0) stopEvent = true; while (m_ServiceStatus == 2) Sleep(1000); #endif } manager->StopNetwork(); manager.reset(); ///- Wait for the delay thread to exit LoginDatabase.HaltDelayThread(); ///- Remove signal handling before leaving UnhookSignals(); sLog.outString("Halting process..."); return 0; }
// Launch the warden server extern int main(int argc, char **argv) { // Command line parsing to get the configuration file name char const* cfg_file = _wardenserver_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 \'[wardenserver]\' written in the top of the file!"); return 1; } sLog->Initialize(); sLog->outString("%s (warden-daemon)", _FULLVERSION); sLog->outString("<Ctrl-C> to stop.\n"); sLog->outString("Using configuration file %s.", cfg_file); sLog->outDetail("Using ACE: %s", ACE_VERSION); ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); sLog->outBasic("Max allowed open files is %d", ACE::max_handles()); // wardenserver 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); } // Launch the listening network socket ACE_Acceptor<WardenSocket, ACE_SOCK_Acceptor> acceptor; uint16 rmport = sConfig->GetIntDefault("WardenServerPort", 4321); 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("wardenserver can not bind to %s:%d", bind_ip.c_str(), rmport); return 1; } // 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 Warden. 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("warden process priority class is set to HIGH"); else sLog->outError("Can't set warden process priority class."); sLog->outString(); } } #endif sWarden->Initialize(); // 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; } sLog->outString("Halting process..."); return 0; }
/// 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("Can not 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; } ///- Set Realm to Offline, if crash happens. Only used once. LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID); ///- 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 #ifdef ENABLE_SOAP ///- 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); } #else /* ENABLE_SOAP */ if (sConfig.GetBoolDefault("SOAP.Enabled", false)) { sLog.outError("SOAP is enabled but wasn't included during compilation, not activating it."); } #endif /* ENABLE_SOAP */ ///- 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; } #ifdef ENABLE_SOAP ///- Stop soap thread if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } #endif ///- 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 return World::GetExitCode(); }
// Launch the realm server extern int main(int argc, char **argv) { // Command line parsing char const* cfg_file = _OREGON_REALM_CONFIG; #ifdef _WIN32 char const *options = ":c:s:"; #else char const *options = ":c:"; #endif ACE_Get_Opt cmd_opts(argc, argv, options); cmd_opts.long_option("version", 'v'); int option; while ((option = cmd_opts()) != EOF) { switch (option) { case 'c': cfg_file = cmd_opts.opt_arg(); break; case 'v': printf("%s\n", _FULLVERSION); return 0; #ifdef _WIN32 case 's': { const char *mode = cmd_opts.opt_arg(); if (!strcmp(mode, "install")) { if (WinServiceInstall()) sLog.outString("Installing service"); return 1; } else if (!strcmp(mode, "uninstall")) { if (WinServiceUninstall()) sLog.outString("Uninstalling service"); return 1; } else if (!strcmp(mode, "run")) WinServiceRun(); else { sLog.outError("Runtime-Error: -%c unsupported argument %s", cmd_opts.opt_opt(), mode); usage(argv[0]); return 1; } break; } #endif case ':': sLog.outError("Runtime-Error: -%c option requires an input argument", cmd_opts.opt_opt()); usage(argv[0]); return 1; default: sLog.outError("Runtime-Error: bad format of commandline arguments"); usage(argv[0]); return 1; } } 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 [realm-daemon]", _FULLVERSION); sLog.outString( "<Ctrl-C> to stop.\n" ); sLog.outString("Using configuration file %s.", cfg_file); // Check the version of the configuration file uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); if (confVersion < _REALMDCONFVERSION) { sLog.outError("*****************************************************************************"); sLog.outError(" WARNING: Your oregonrealm.conf version indicates your conf file is out of date!"); sLog.outError(" Please check for updates, as your current default values may cause"); sLog.outError(" strange behavior."); sLog.outError("*****************************************************************************"); clock_t pause = 3000 + clock(); while (pause > clock()) {} } sLog.outDetail("Using ACE: %s", ACE_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()); // 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; // 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; } // cleanup query // set expired bans to inactive LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); // Launch the listening network socket ACE_Acceptor<AuthSocket, ACE_SOCK_Acceptor> acceptor; uint16 rmport = sConfig.GetIntDefault("RealmServerPort", DEFAULT_REALMSERVER_PORT); 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("realmd can not bind to %s:%d", bind_ip.c_str(), rmport); return 1; } // Catch termination signals HookSignals(); // 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 realmd. 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("realmd process priority class set to HIGH"); else sLog.outError("ERROR: Can't set realmd process priority class."); sLog.outString(); } } #endif // maximum counter for next ping uint32 numLoops = (sConfig.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.outDetail("Ping MySQL to keep connection alive"); LoginDatabase.Query("SELECT 1 FROM realmlist LIMIT 1"); } #ifdef _WIN32 if (m_ServiceStatus == 0) stopEvent = true; while (m_ServiceStatus == 2) Sleep(1000); #endif } // Wait for the delay thread to exit LoginDatabase.HaltDelayThread(); // Remove signal handling before leaving UnhookSignals(); sLog.outString( "Halting process..." ); return 0; }
/// 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(); ///- 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(); }
/// 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("server.authserver", "%s (authserver)", _FULLVERSION); TC_LOG_INFO("server.authserver", " "); TC_LOG_INFO("server.authserver", " A World of Warcraft Cataclsym 4.3.4 Emulator "); TC_LOG_INFO("server.authserver", " _/_/ _/ _/_/_/ _/_/ _/_/_/ _/_/_/_/ "); TC_LOG_INFO("server.authserver", " _/ _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ "); TC_LOG_INFO("server.authserver", " _/_/_/_/ _/_/ _/_/ _/ _/ _/ _/_/_/ _/_/_/ "); TC_LOG_INFO("server.authserver", " _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ "); TC_LOG_INFO("server.authserver", " _/ _/ _/ _/ _/ _/_/_/ _/_/ _/ _/ _/_/_/_/ "); TC_LOG_INFO("server.authserver", " Arkania Community (c) 2014!"); TC_LOG_INFO("server.authserver", " <http://arkania.net/>"); TC_LOG_INFO("server.authserver", " "); TC_LOG_INFO("server.authserver", "<Ctrl-C> to stop.\n"); TC_LOG_INFO("server.authserver", "Using configuration file %s.", configFile); TC_LOG_INFO("server.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("server.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("server.authserver", "Daemon PID: %u\n", pid); else { TC_LOG_ERROR("server.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("server.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("server.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("server.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); #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)) { // remove non accessible processors ULONG_PTR currentAffinity = affinity & appAff; if (!currentAffinity) TC_LOG_ERROR("server.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("server.authserver", "Using processors (bitmask, hex): %x", currentAffinity); else TC_LOG_ERROR("server.authserver", "Can't set used processors (hex): %x", currentAffinity); } } if (highPriority) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) TC_LOG_INFO("server.authserver", "authserver process priority class set to HIGH"); else TC_LOG_ERROR("server.authserver", "Can't set authserver 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.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("server.authserver", "Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask)); } } if (highPriority) { if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY)) TC_LOG_ERROR("server.authserver", "Can't set authserver process priority class, error: %s", strerror(errno)); else TC_LOG_INFO("server.authserver", "authserver process priority class set to %i", getpriority(PRIO_PROCESS, 0)); } #endif #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("server.authserver", "Ping MySQL to keep connection alive"); LoginDatabase.KeepAlive(); } } // Close the Database Pool and library StopDB(); TC_LOG_INFO("server.authserver", "Halting process..."); return 0; }
/// Main function int Master::Run() { BigNumber seed1; seed1.SetRand(16 * 8); sLog->outString("%s (worldserver-daemon)", _CLIENT_BUILD_REVISION); sLog->outString(" "); sLog->outString(" A World of Warcraft: Cataclysm Core Emulator "); sLog->outString(" _/_/ _/ _/_/_/ _/_/ _/_/_/ _/_/_/_/ "); sLog->outString(" _/ _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/ "); sLog->outString(" _/_/_/_/ _/_/ _/_/ _/ _/ _/ _/_/_/ _/_/_/ "); sLog->outString(" _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ "); sLog->outString(" _/ _/ _/ _/ _/ _/_/_/ _/_/ _/ _/ _/_/_/_/ "); sLog->outString(" Arkania Community (c) 2011"); sLog->outString(" <http://arkania.net/>"); sLog->outString(" "); sLog->outString("<Ctrl-C> to stop.\n"); #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 /// worldserver 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(); ///- Initialize 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 (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 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 = 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("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 (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); } ///- 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); sLog->outString("%s (worldserver-daemon) ready...", _FULLVERSION); sWorldSocketMgr->Wait(); if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // set server offline LoginDatabase.DirectPExecute( "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(); _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(); }
// 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 (!ConfigMgr::Load(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 2012(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 = 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); } // Initialize the database connection if (!StartDB()) return 1; // Initialize the log database sLog->SetLogDBLater(ConfigMgr::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 (authserver realmid) // Get the list of realms for the server sRealmList->Initialize(ConfigMgr::GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList->size() == 0) { sLog->outError("No valid realms specified."); return 1; } // Launch the listening network socket RealmAcceptor acceptor; uint16 rmport = ConfigMgr::GetIntDefault("RealmServerPort", 3724); std::string bind_ip = ConfigMgr::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 = 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 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 = ConfigMgr::GetBoolDefault("ProcessPriority", false); if (Prio) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog->outString("The auth server process priority class has been set to HIGH"); else sLog->outError("Can't set auth server process priority class."); sLog->outString(); } } #endif // maximum counter for next ping uint32 numLoops = (ConfigMgr::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.Query("SELECT 1 FROM realmlist LIMIT 1"); } } // Close the Database Pool and library //StopDB(); sLog->outString("Halting process..."); return 0; }
/// Launch the realm server extern int main(int argc, char **argv) { ///- Command line parsing char const* cfg_file = _REALMD_CONFIG; #ifdef WIN32 char const *options = ":c:s:"; #else char const *options = ":c:"; #endif ACE_Get_Opt cmd_opts(argc, argv, options); cmd_opts.long_option("version", 'v'); int option; while ((option = cmd_opts()) != EOF) { switch (option) { case 'c': cfg_file = cmd_opts.opt_arg(); break; case 'v': printf("%s\n", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID)); return 0; #ifdef WIN32 case 's': { const char *mode = cmd_opts.opt_arg(); if (!strcmp(mode, "install")) { if (WinServiceInstall()) sLog.outString("Installing service"); return 1; } else if (!strcmp(mode, "uninstall")) { if (WinServiceUninstall()) sLog.outString("Uninstalling service"); return 1; } else if (!strcmp(mode, "run")) WinServiceRun(); else { sLog.outError("Runtime-Error: -%c unsupported argument %s", cmd_opts.opt_opt(), mode); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; } break; } #endif case ':': sLog.outError("Runtime-Error: -%c option requires an input argument", cmd_opts.opt_opt()); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; default: sLog.outError("Runtime-Error: bad format of commandline arguments"); usage(argv[0]); Log::WaitBeforeContinueIfNeed(); return 1; } } if (!sConfig.SetSource(cfg_file)) { sLog.outError("Could not find configuration file %s.", cfg_file); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.Initialize(); sLog.outString( "%s [realm-daemon]", _FULLVERSION(REVISION_DATE,REVISION_TIME,REVISION_NR,REVISION_ID) ); sLog.outString( "<Ctrl-C> to stop.\n" ); sLog.outString("Using configuration file %s.", cfg_file); ///- Check the version of the configuration file uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); if (confVersion < _REALMDCONFVERSION) { sLog.outError("*****************************************************************************"); sLog.outError(" WARNING: Your realmd.conf version indicates your conf file is out of date!"); sLog.outError(" Please check for updates, as your current default values may cause"); sLog.outError(" strange behavior."); sLog.outError("*****************************************************************************"); Log::WaitBeforeContinueIfNeed(); } DETAIL_LOG("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); if (SSLeay() < 0x009080bfL ) { DETAIL_LOG("WARNING: Outdated version of OpenSSL lib. Logins to server may not work!"); DETAIL_LOG("WARNING: Minimal required version [OpenSSL 0.9.8k]"); } DETAIL_LOG("Using ACE: %s", ACE_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()); /// 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() ); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString( "Daemon PID: %u\n", pid ); } ///- Initialize the database connection if(!StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Get the list of realms for the server sRealmList.Initialize(sConfig.GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList.size() == 0) { sLog.outError("No valid realms specified."); Log::WaitBeforeContinueIfNeed(); return 1; } // cleanup query // set expired bans to inactive LoginDatabase.BeginTransaction(); LoginDatabase.Execute("UPDATE account_banned SET active = 0 WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); LoginDatabase.CommitTransaction(); ///- Launch the listening network socket ACE_Acceptor<AuthSocket, ACE_SOCK_Acceptor> acceptor; uint16 rmport = sConfig.GetIntDefault("RealmServerPort", DEFAULT_REALMSERVER_PORT); 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("MaNGOS realmd can not bind to %s:%d", bind_ip.c_str(), rmport); Log::WaitBeforeContinueIfNeed(); return 1; } // FG: "bad points" system related uint32 badPointsDropInterval = sConfig.GetIntDefault("BadPoints.DropInterval", HOUR); uint32 badPointsDropAmount = sConfig.GetIntDefault("BadPoints.DropAmount", 1); uint32 badPointsDropWaitTime = sConfig.GetIntDefault("BadPoints.WaitTime", WEEK); IntervalTimer badPointsTimer; badPointsTimer.SetInterval(badPointsDropInterval * IN_MILLISECONDS); ///- Catch termination signals HookSignals(); ///- 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 realmd. 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("realmd process priority class set to HIGH"); else sLog.outError("Can't set realmd process priority class."); sLog.outString(); } } #endif //server has started up successfully => enable async DB requests LoginDatabase.AllowAsyncTransactions(); // maximum counter for next ping uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; uint32 last_ping_time = 0; uint32 now = WorldTimer::getMSTime(); uint32 diff; uint32 lasttime = now; uint32 last_ipprops_cleanup = 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; now = WorldTimer::getMSTime(); diff = WorldTimer::getMSTimeDiff(lasttime, now); lasttime = now; badPointsTimer.Update(diff); if( (++loopCounter) == numLoops ) { // FG: protect against network system overloading // if that happens, force realmd close (autorestarter ftw!) if(WorldTimer::getMSTimeDiff(last_ping_time, now) < 10000) { sLog.outError("NETWORK SYSTEM OVERLOAD"); raise(SIGSEGV); // force close abort(); } last_ping_time = now; loopCounter = 0; DETAIL_LOG("Ping MySQL to keep connection alive"); LoginDatabase.Ping(); } // FG: clear flood protect buffer periodically if(WorldTimer::getMSTimeDiff(last_ipprops_cleanup, now) > 30000) // flush stored IPs every 30 secs { last_ipprops_cleanup = now; uint32 flushed = 0, blocked = 0, stored = 0; CleanupIPPropmap(flushed, blocked, stored); sLog.outDetail("IPProp: Flushed %u total, %u of them blocked, now %u stored", flushed, blocked, stored); } // FG: handle "bad points" drop if(badPointsTimer.Passed()) { badPointsTimer.Reset(); if(badPointsDropAmount) { uint64 goodtime = uint64(time(NULL)) - badPointsDropWaitTime; LoginDatabase.Execute("UPDATE account_badpoints SET maxpts = curpts WHERE maxpts < curpts"); LoginDatabase.PExecute("UPDATE account_badpoints SET curpts = 0 WHERE curpts <= %u AND lasttime < "UI64FMTD, badPointsDropAmount, goodtime); LoginDatabase.PExecute("UPDATE account_badpoints SET curpts = curpts - %u WHERE curpts > %u AND lasttime < "UI64FMTD, badPointsDropAmount, badPointsDropAmount, goodtime); } } #ifdef WIN32 if (m_ServiceStatus == 0) stopEvent = true; while (m_ServiceStatus == 2) Sleep(1000); #endif } ///- Wait for the delay thread to exit LoginDatabase.HaltDelayThread(); ///- Remove signal handling before leaving UnhookSignals(); sLog.outString( "Halting process..." ); 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(); }