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 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(" Project SkyFireEmu 2012(c) Open-sourced Game Emulation "); sLog->outString(" <http://www.projectskyfire.org/> \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) { // 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(); } } // Close the Database Pool and library StopDB(); sLog->outString("Halting process..."); return 0; }
/// Launch the realm server extern int main(int argc, char **argv) { sLog->SetLogDB(false); ///- Command line parsing to get the configuration file name char const* cfg_file = _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(" "); sLog->outString(" Authserver"); sLog->outString(" "); sLog->outString(" A World of Warcraft: Cataclysm Core Emulator "); sLog->outString(" "); sLog->outString(" Deepshjir Cataclysm Repack ",_FULLVERSION); sLog->outString(" by Naios (2012) "); sLog->outString(" Supports Game version: 4.06a - 13623"); sLog->outString(" "); sLog->outString(" based on:"); sLog->outString(" ArkCore - by Arkania Community (c) 2012"); sLog->outString(" <http://arkania.net/>"); sLog->outString(" "); sLog->outString(" <Ctrl-C> to stop.\n"); #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; }
/// Main function int Master::Run() { /// worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog.outError("Cannot create PID file %s.\n", pidfile.c_str()); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString("Daemon PID: %u\n", pid); } ///- Start the databases if (!_StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Initialize the World sWorld.SetInitialWorldSettings(); #ifndef WIN32 detachDaemon(); #endif // server loaded successfully => enable async DB requests // this is done to forbid any async transactions during server startup! CharacterDatabase.AllowAsyncTransactions(); WorldDatabase.AllowAsyncTransactions(); LoginDatabase.AllowAsyncTransactions(); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set realmbuilds depend on worldserver 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 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)) { 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); } ///- Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay * 1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } ///- Launch the world listener socket uint16 wsport = sWorld.getConfig(CONFIG_UINT32_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork(wsport, bind_ip) == -1) { sLog.outError("Failed to start network"); Log::WaitBeforeContinueIfNeed(); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait(); ///- Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } ///- Stop soap thread if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } ///- Set server offline in realmlist LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); if (rar_thread) { rar_thread->wait(); rar_thread->destroy(); delete rar_thread; } ///- Clean account database before leaving clearOnlineAccounts(); // send all still queued mass mails (before DB connections shutdown) sMassMailMgr.Update(true); ///- Wait for DB delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString("Halting process..."); if (cliThread) { #ifdef WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } ///- Exit the process with specified return value return World::GetExitCode(); }
/// Main function int Master::Run() { sLog.outString( "%s (core-daemon)", _FULLVERSION ); sLog.outString( "<Ctrl-C> to stop.\n" ); sLog.outString( " ______ __"); sLog.outString( "/\\__ _\\ __ __/\\ \\__"); sLog.outString( "\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\ ,_\\ __ __"); sLog.outString( " \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\"); sLog.outString( " \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\"); sLog.outString( " \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\"); sLog.outString( " \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\"); sLog.outString( " C O R E /\\___/"); sLog.outString( "http://TrinityCore.org \\/__/\n"); /// worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if( !pid ) { sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() ); return 1; } sLog.outString( "Daemon PID: %u\n", pid ); } ///- Start the databases if (!_StartDB()) return 1; ///- Initialize the World sWorld.SetInitialWorldSettings(); ///- 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 Trinityd. Accessible processors bitmask (hex): %x",Aff,appAff); } else { if(SetProcessAffinityMask(hProcess,curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x",curAff); } } sLog.outString(""); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); // if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/) if(Prio) { if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("TrinityCore process priority class set to HIGH"); else sLog.outError("ERROR: Can't set Trinityd process priority class."); sLog.outString(""); } } #endif uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); ///- Start up freeze catcher thread if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); ACE_Based::Thread freeze_thread(fdr); freeze_thread.setPriority(ACE_Based::Highest); } ///- Launch the world listener socket port_t wsport = sWorld.getConfig (CONFIG_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1) { sLog.outError ("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait (); // set server offline LoginDatabase.PExecute("UPDATE realmlist SET color = 2 WHERE id = '%d'",realmID); ///- 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; 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 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; }
RakNetTimeUS RakNet::GetTimeNS( void ) { #if defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3) uint64_t curTime; if ( initialized == false) { ticksPerSecond = _PS3_GetTicksPerSecond(); // Use the function to get elapsed ticks, this is a macro. _PS3_GetElapsedTicks(curTime); uint64_t quotient, remainder; quotient=(curTime / ticksPerSecond); remainder=(curTime % ticksPerSecond); initialTime = (RakNetTimeUS) quotient*(RakNetTimeUS)1000000 + (remainder*(RakNetTimeUS)1000000 / ticksPerSecond); initialized = true; } #elif defined(_WIN32) // Win32 if ( initialized == false) { initialized = true; #if !defined(_WIN32_WCE) && !defined(_XBOX) && !defined(X360) // Save the current process HANDLE mProc = GetCurrentProcess(); // Get the current Affinity #if _MSC_VER >= 1400 && defined (_M_X64) GetProcessAffinityMask(mProc, (PDWORD_PTR)&mProcMask, (PDWORD_PTR)&mSysMask); #else GetProcessAffinityMask(mProc, &mProcMask, &mSysMask); #endif mThread = GetCurrentThread(); #endif // !defined(_WIN32_WCE) QueryPerformanceFrequency( &yo ); } // 01/12/08 - According to the docs "The frequency cannot change while the system is running." so this shouldn't be necessary /* if (++queryCount==200) { // Set affinity to the first core SetThreadAffinityMask(mThread, 1); QueryPerformanceFrequency( &yo ); // Reset affinity SetThreadAffinityMask(mThread, mProcMask); queryCount=0; } */ #elif (defined(__GNUC__) || defined(__GCCXML__)) if ( initialized == false) { gettimeofday( &tp, 0 ); initialized=true; // I do this because otherwise RakNetTime in milliseconds won't work as it will underflow when dividing by 1000 to do the conversion initialTime = ( tp.tv_sec ) * (RakNetTimeUS) 1000000 + ( tp.tv_usec ); } #endif #if defined(_PS3) || defined(__PS3__) || defined(SN_TARGET_PS3) // Use the function to get elapsed ticks, this is a macro. _PS3_GetElapsedTicks(curTime); uint64_t quotient, remainder; quotient=(curTime / ticksPerSecond); remainder=(curTime % ticksPerSecond); curTime = (RakNetTimeUS) quotient*(RakNetTimeUS)1000000 + (remainder*(RakNetTimeUS)1000000 / ticksPerSecond); // Subtract from initialTime so the millisecond conversion does not underflow return curTime - initialTime; #elif defined(_WIN32) RakNetTimeUS curTime; static RakNetTimeUS lastQueryVal=(RakNetTimeUS)0; // static unsigned long lastTickCountVal = GetTickCount(); LARGE_INTEGER PerfVal; #if !defined(_WIN32_WCE) && !defined(_XBOX) && !defined(X360) // Set affinity to the first core SetThreadAffinityMask(mThread, 1); #endif // !defined(_WIN32_WCE) // Docs: On a multiprocessor computer, it should not matter which processor is called. // However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL). To specify processor affinity for a thread, use the SetThreadAffinityMask function. // Query the timer QueryPerformanceCounter( &PerfVal ); #if !defined(_WIN32_WCE) && !defined(_XBOX) && !defined(X360) // Reset affinity SetThreadAffinityMask(mThread, mProcMask); #endif // !defined(_WIN32_WCE) __int64 quotient, remainder; quotient=((PerfVal.QuadPart) / yo.QuadPart); remainder=((PerfVal.QuadPart) % yo.QuadPart); curTime = (RakNetTimeUS) quotient*(RakNetTimeUS)1000000 + (remainder*(RakNetTimeUS)1000000 / yo.QuadPart); // 08/26/08 - With the below workaround, the time seems to jump forward regardless. // Just make sure the time doesn't go backwards if (curTime < lastQueryVal) return lastQueryVal; lastQueryVal=curTime; /* #if !defined(_WIN32_WCE) if (lastQueryVal==0) { // First call lastQueryVal=curTime; return curTime; } // To workaround http://support.microsoft.com/kb/274323 where the timer can sometimes jump forward by hours or days unsigned long curTickCount = GetTickCount(); unsigned long elapsedTickCount = curTickCount - lastTickCountVal; RakNetTimeUS elapsedQueryVal = curTime - lastQueryVal; if (elapsedQueryVal/1000 > elapsedTickCount+100) { curTime=(RakNetTimeUS)lastQueryVal+(RakNetTimeUS)elapsedTickCount*(RakNetTimeUS)1000; } lastTickCountVal=curTickCount; lastQueryVal=curTime; #endif */ return curTime; #elif (defined(__GNUC__) || defined(__GCCXML__)) // GCC RakNetTimeUS curTime; gettimeofday( &tp, 0 ); curTime = ( tp.tv_sec ) * (RakNetTimeUS) 1000000 + ( tp.tv_usec ); // Subtract from initialTime so the millisecond conversion does not underflow return curTime - initialTime; #endif }
static bool windows_init_clock(struct libusb_context *ctx) { DWORD_PTR affinity, dummy; HANDLE event = NULL; LARGE_INTEGER li_frequency; int i; if (QueryPerformanceFrequency(&li_frequency)) { // Load DLL imports if (windows_init_dlls() != LIBUSB_SUCCESS) { usbi_err(ctx, "could not resolve DLL functions"); return false; } // The hires frequency can go as high as 4 GHz, so we'll use a conversion // to picoseconds to compute the tv_nsecs part in clock_gettime hires_frequency = li_frequency.QuadPart; hires_ticks_to_ps = UINT64_C(1000000000000) / hires_frequency; usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency); // Because QueryPerformanceCounter might report different values when // running on different cores, we create a separate thread for the timer // calls, which we glue to the first available core always to prevent timing discrepancies. if (!GetProcessAffinityMask(GetCurrentProcess(), &affinity, &dummy) || (affinity == 0)) { usbi_err(ctx, "could not get process affinity: %s", windows_error_str(0)); return false; } // The process affinity mask is a bitmask where each set bit represents a core on // which this process is allowed to run, so we find the first set bit for (i = 0; !(affinity & (DWORD_PTR)(1 << i)); i++); affinity = (DWORD_PTR)(1 << i); usbi_dbg("timer thread will run on core #%d", i); event = CreateEvent(NULL, FALSE, FALSE, NULL); if (event == NULL) { usbi_err(ctx, "could not create event: %s", windows_error_str(0)); return false; } timer_thread = (HANDLE)_beginthreadex(NULL, 0, windows_clock_gettime_threaded, (void *)event, 0, (unsigned int *)&timer_thread_id); if (timer_thread == NULL) { usbi_err(ctx, "unable to create timer thread - aborting"); CloseHandle(event); return false; } if (!SetThreadAffinityMask(timer_thread, affinity)) usbi_warn(ctx, "unable to set timer thread affinity, timer discrepancies may arise"); // Wait for timer thread to init before continuing. if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) { usbi_err(ctx, "failed to wait for timer thread to become ready - aborting"); CloseHandle(event); return false; } CloseHandle(event); } else { usbi_dbg("no hires timer available on this platform"); hires_frequency = 0; hires_ticks_to_ps = UINT64_C(0); } return true; }
/// 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; }
int WindowProfiler::run ( const std::string& title, int argc, const char** argv, int width, int height, int Major, int Minor ) { s_project = this; sysVisibleConsole(); #if _WIN32 if (m_singleThreaded) { HANDLE proc = GetCurrentProcess(); size_t procmask; size_t sysmask; // pin to one physical cpu for smoother timings, disable hyperthreading GetProcessAffinityMask(proc,(PDWORD_PTR)&procmask,(PDWORD_PTR)&sysmask); if (sysmask & 8){ // quadcore, use last core procmask = 8; } else if (sysmask & 2){ // dualcore, use last core procmask = 2; } SetProcessAffinityMask(proc,(DWORD_PTR)procmask); } #endif bool vsyncstate = true; unsigned int intervalSeconds = 2; unsigned int frameLimit = 0; unsigned int timerLimit = 0; const char* dumpatexit = NULL; for (int i = 0; i < argc; i++){ if (strcmp(argv[i],"-winsize") == 0 && i + 2 < argc){ width = atoi(argv[i+1]); height = atoi(argv[i+2]); i+=2; } if (strcmp(argv[i],"-vsync") == 0 && i + 1 < argc){ vsyncstate = atoi(argv[i+1]) ? true : false; i+=1; } if (strcmp(argv[i],"-frames")==0 && i+1<argc){ frameLimit = atoi(argv[i+1]); i++; } if (strcmp(argv[i],"-timerprints")==0 && i+1<argc){ timerLimit = atoi(argv[i+1]); i++; } if (strcmp(argv[i],"-timerinterval")==0 && i+1<argc){ intervalSeconds = atoi(argv[i+1]); i++; } if (strcmp(argv[i],"-bmpatexit")==0 && i+1<argc){ dumpatexit = argv[i+1]; i++; } } ContextFlags flags; flags.major = Major; flags.minor = Minor; flags.robust = 0; flags.core = 0; #ifdef NDEBUG flags.debug = 0; #else flags.debug = 1; #endif flags.share = NULL; if (!activate(width,height,title.c_str(), &flags)){ printf("Could not create GL context: %d.%d\n",flags.major,flags.minor); return EXIT_FAILURE; } vsync( vsyncstate ); m_window.m_viewsize[0] = width; m_window.m_viewsize[1] = height; m_profiler.init(); m_gltimers.init(m_profiler.getRequiredTimers()); m_profiler.setDefaultGPUInterface(&m_gltimers); bool Run = begin(); m_active = true; double timeStart = sysGetTime(); double timeBegin = sysGetTime(); double frames = 0; bool lastVsync = m_vsync; if(Run) { while(true) { if (!NVPWindow::sysPollEvents(false)){ break; } while ( !isOpen() ){ NVPWindow::sysWaitEvents(); } if (m_window.onPress(KEY_V)){ vsync(!m_vsync); } std::string stats; { nv_helpers::Profiler::FrameHelper helper(m_profiler,sysGetTime(), float(intervalSeconds), stats); { NV_PROFILE_SECTION("Frame"); think(sysGetTime() - timeStart); } memset(m_window.m_keyToggled, 0, sizeof(m_window.m_keyToggled)); if( m_doSwap ) { swapBuffers(); } } if (m_profilerPrint && !stats.empty()){ if (!timerLimit || timerLimit == 1){ fprintf(stdout,"%s\n",stats.c_str()); } if (timerLimit == 1){ frameLimit = 1; } if (timerLimit){ timerLimit--; } } frames++; double timeCurrent = sysGetTime(); double timeDelta = timeCurrent - timeBegin; if (timeDelta > double(intervalSeconds) || lastVsync != m_vsync || frameLimit==1){ std::ostringstream combined; if (lastVsync != m_vsync){ timeDelta = 0; } if (m_timeInTitle) { combined << title << ": " << (timeDelta*1000.0/(frames)) << " [ms]" << (m_vsync ? " (vsync on - V for toggle)" : ""); setTitle(combined.str().c_str()); } if (frameLimit==1){ fprintf(stdout,"frametime: %f ms\n", (timeDelta*1000.0/(frames))); } frames = 0; timeBegin = timeCurrent; lastVsync = m_vsync; } if(m_window.m_keyPressed[KEY_ESCAPE] || frameLimit==1) break; if (frameLimit) frameLimit--; } } if (dumpatexit){ dumpScreenshot(dumpatexit,m_window.m_viewsize[0],m_window.m_viewsize[1]); } end(); m_active = false; m_profiler.deinit(); m_gltimers.deinit(); return Run ? EXIT_SUCCESS : EXIT_FAILURE; }
void main(int argc, char *argv[]) { clock_t startCPU; time_t startTime; double elapsedTime, cpuTime; uint64_t clock_reg; int pf0 = getPagefault(); #ifdef SMARTHEAP MemRegisterTask(); #endif setbuf(stdout, NULL); /* turn off buffering for output */ if (argc > 1) fin = fopen(argv[1], "r"); else fin = stdin; if (argc > 2) fout = fopen(argv[2], "w"); else fout = stdout; if(fin == NULL || fout == NULL) { fprintf(stderr, "Could not open file(s): "); int i=1; for(i=1; i<argc;i++) { fprintf(stderr, "%s ", argv[i]); } fprintf(stderr, "\n"); exit(-1); } ulCallCount = promptAndRead("call count", ulCallCount, 'u'); uMinBlockSize = (unsigned)promptAndRead("min block size",uMinBlockSize,'u'); uMaxBlockSize = (unsigned)promptAndRead("max block size",uMaxBlockSize,'u'); #ifdef HEAPALLOC_WRAPPER LoadLibrary("shsmpsys.dll"); #endif #ifdef SYS_MULTI_THREAD { unsigned i; void *threadArg = NULL; ThreadID *tids; #ifdef WIN32 //unsigned uCPUs = promptAndRead("CPUs (0 for all)", 0, 'u'); if (uCPUs) { DWORD m1, m2; if (GetProcessAffinityMask(GetCurrentProcess(), &m1, &m2)) { i = 0; m1 = 1; /* * iterate through process affinity mask m2, counting CPUs up to * the limit specified in uCPUs */ do if (m2 & m1) i++; while ((m1 <<= 1) && i < uCPUs); /* clear any extra CPUs in affinity mask */ do if (m2 & m1) m2 &= ~m1; while (m1 <<= 1); if (SetProcessAffinityMask(GetCurrentProcess(), m2)) fprintf(fout, "\nThreads in benchmark will run on max of %u CPUs", i); } } #endif /* WIN32 */ uThreadCount = uCPUs;//(int)promptAndRead("threads", GetNumProcessors(), 'u'); if (uThreadCount < 1) uThreadCount = 1; ulCallCount /= uThreadCount; if ((tids = malloc(sizeof(ThreadID) * uThreadCount)) != NULL) { startCPU = clock(); startTime = time(NULL); clock_reg = rdtsc(); UPDATENETMEM(mallinfo().uordblks + ulCallCount * sizeof(void *)); for (i = 0; i < uThreadCount; i++) { if (THREAD_EQ(tids[i] = RunThread(doBench, threadArg),THREAD_NULL)) { fprintf(fout, "\nfailed to start thread #%d", i); break; } } WaitForThreads(tids, uThreadCount); free(tids); } if (threadArg) free(threadArg); } #else UPDATENETMEM(mallinfo().uordblks + ulCallCount * sizeof(void *)); startCPU = clock(); startTime = time(NULL); clock_reg = rdtsc(); doBench(NULL); #endif uint64_t cpuTime_reg = (rdtsc() - clock_reg); elapsedTime = difftime(time(NULL), startTime); cpuTime = (double)(clock()-startCPU) / (double)CLK_TCK; // cpuTime = (double)(clock()-startCPU); // uint64_t cpuTime_reg = (rdtsc() - clock_reg) / 2246796049; fprintf_silent(fout, "\n"); #ifdef PRINTTHROUGHPUT fprintf(fout, "throughput %ld", (long) (cpuTime_reg)); #endif fprintf(fout, "\nTotal elapsed time" #ifdef SYS_MULTI_THREAD " for %d threads" #endif ": %.2f (%.4f CPU) (%ld clock ticks read from register)\n", #ifdef SYS_MULTI_THREAD uThreadCount, #endif elapsedTime, cpuTime, cpuTime_reg); if (fin != stdin) fclose(fin); if (fout != stdout) fclose(fout); printf("Occurred page faults: %d\n", getPagefault() - pf0); }
// // Performs special Extended Configuration Space access. // // It takes advantage of AMD-specific IO CF8h/CFCh extension that enables // accesses to PCI Extended Configuration Space. Access is realized by // enabling ECS access via IOCF8/IOCFC using EnableCf8ExtCfg from NB_CFG // MSR (MSRC001_001F) and performing CF8h/CFCh access per specifciation. // State of NB_CFG and IOCF8 is saved before the operation and gets // restored afterwards. Calling process is also bound to first CPU // in the system for the duration of the operation to accommodate // environments with multiple northbridges. // // EnableCf8ExtCfg is supported by all currently supported CPU families, // that is, 10h, 11h, 12h, 14h, 15h and 16h. // // IO CF8h/CFCh method, while racy, is the only feasible method to access // PCI ECS on Windows XP/2003 (accessing memory mapped configuration space // is off the table due to lack of physical memory access support // in WinRing0). // // Best effort is put to detect simultaneous users of CF8h/CFCh. // bool SpecialEcsAccess(bool write, DWORD devfunc, DWORD reg, DWORD *res) { DWORD_PTR mask_save; DWORD_PTR dummy; DWORD eax_save; DWORD edx_save; DWORD edx; DWORD addr; DWORD addr_save; DWORD addr_check; DWORD data; bool result = false; if (!GetProcessAffinityMask((HANDLE)-1, &mask_save, &dummy)) { fprintf(stderr, "ERROR getting affinity mask\n"); goto out; } if (!SetProcessAffinityMask((HANDLE)-1, 1)) { fprintf(stderr, "ERROR setting affinity mask\n"); goto out; } if (!RdmsrPx(0xC001001F, &eax_save, &edx_save, 1)) { fprintf(stderr, "ERROR reading NB_CFG\n"); goto out_affinity; } edx = edx_save; edx |= 0x4000; if (!WrmsrPx(0xC001001F, eax_save, edx, (DWORD_PTR)1)) { fprintf(stderr, "ERROR writing NB_CFG\n"); goto out_affinity; } addr_save = ReadIoPortDword(0xcf8); addr = 1; addr <<= 7; addr |= (reg >> 8) & 0x0F; addr <<= 16; addr |= devfunc & 0xFFFF; addr <<= 8; addr |= reg & 0xFF; WriteIoPortDword(0xcf8, addr); if (write == false) { data = ReadIoPortDword(0xcfc); } else { WriteIoPortDword(0xcfc, *res); } addr_check = ReadIoPortDword(0xcf8); if (addr_check != addr) { fprintf(stderr, "ERROR: IO CF8h hijacked!\n"); goto out_nbcfg; } WriteIoPortDword(0xcf8, addr_save); if (write == false) { *res = data; } result = true; out_nbcfg: WrmsrPx(0xC001001F, eax_save, edx_save, (DWORD_PTR)1); out_affinity: SetProcessAffinityMask((HANDLE)-1, mask_save); out: return result; }
/// Launch the realm server extern int main(int argc, char **argv) { sLog->SetLogDB(false); ///- Command line parsing to get the configuration file name char const* cfg_file = _TRINITY_REALM_CONFIG; int c = 1; while(c < argc) { if (strcmp(argv[c], "-c") == 0) { if (++c >= argc) { sLog->outError("Runtime-Error: -c option requires an input argument"); usage(argv[0]); return 1; } else cfg_file = argv[c]; } #ifdef _WIN32 //////////// //Services// //////////// if (strcmp(argv[c], "-s") == 0) { if (++c >= argc) { sLog->outError("Runtime-Error: -s option requires an input argument"); usage(argv[0]); return 1; } if (strcmp(argv[c], "install") == 0) { if (WinServiceInstall()) sLog->outString("Installiere Service"); return 1; } else if (strcmp(argv[c], "uninstall") == 0) { if (WinServiceUninstall()) sLog->outString("Deinstalliere Service"); return 1; } else { sLog->outError("Runtime-Error: unsupported option %s", argv[c]); usage(argv[0]); return 1; } } if (strcmp(argv[c], "--service") == 0) WinServiceRun(); #endif ++c; } if (!sConfig->SetSource(cfg_file)) { sLog->outError("Invalid or missing configuration file : %s", cfg_file); sLog->outError("Verify that the file exists and has \'[authserver]\' written in the top of the file!"); return 1; } sLog->Initialize(); sLog->outString(" "); sLog->outString(" ##### ##### "); sLog->outString(" # # ##### ## ##### # # ## ##### ###### "); sLog->outString(" # # # # # # # # # # # "); sLog->outString(" ##### # # # # # # #### # # # ##### "); sLog->outString(" # # ###### ##### # # ###### # # "); sLog->outString(" # # # # # # # # # # # # # "); sLog->outString(" ##### # # # # # ##### # # # ######" ); sLog->outString(" "); sLog->outString(" Project StarGateEmu 2011 (c) "); sLog->outString(" "); sLog->outString(" %s ", _FULLVERSION); sLog->outString(" "); sLog->outString(" "); sLog->outDetail("%s (Library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); #else ACE_Reactor::instance(new ACE_Reactor(new ACE_TP_Reactor(), true), true); #endif sLog->outBasic("Max. zulässige offene Dateien %d", ACE::max_handles()); /// realmd PID file creation std::string pidfile = sConfig->GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog->outError("Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog->outString("Daemon PID: %u\n", pid); } ///- Initialize the database connection if (!StartDB()) return 1; ///- Initialize the log database sLog->SetLogDBLater(sConfig->GetBoolDefault("EnableLogDB", false)); // set var to enable DB logging once startup finished. sLog->SetLogDB(false); sLog->SetRealmID(0); // ensure we've set realm to 0 (realmd realmid) ///- Get the list of realms for the server sRealmList->Initialize(sConfig->GetIntDefault("RealmsStateUpdateDelay", 20)); if (sRealmList->size() == 0) { sLog->outError("Keine gültige Bereiche angegeben."); return 1; } ///- Launch the listening network socket RealmAcceptor acceptor; uint16 rmport = sConfig->GetIntDefault("RealmServerPort", 3724); std::string bind_ip = sConfig->GetStringDefault("BindIP", "0.0.0.0"); ACE_INET_Addr bind_addr(rmport, bind_ip.c_str()); if (acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) { sLog->outError("StarGateAuth nicht zu binden %s:%d", bind_ip.c_str(), rmport); return 1; } // Initialise the signal handlers RealmdSignalHandler SignalINT, SignalTERM; #ifdef _WIN32 RealmdSignalHandler SignalBREAK; #endif /* _WIN32 */ // Register realmd's signal handlers ACE_Sig_Handler Handler; Handler.register_handler(SIGINT, &SignalINT); Handler.register_handler(SIGTERM, &SignalTERM); #ifdef _WIN32 Handler.register_handler(SIGBREAK, &SignalBREAK); #endif /* _WIN32 */ ///- Handle affinity for multiple processors and process priority on Windows #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig->GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if (!curAff) sLog->outError("Prozessoren in UseProcessors Bitmaske markiert (hex) %x nicht zugänglich realmd. Accessible Prozessor Bitmaske (hex): %x", Aff, appAff); else if (SetProcessAffinityMask(hProcess, curAff)) sLog->outString("Mit Prozessoren (bitmask, hex): %x", curAff); else sLog->outError("Kann verwendeter Prozessor nicht festgelegen!.(hex): %x", curAff); } } bool Prio = sConfig->GetBoolDefault("ProcessPriority", false); if (Prio) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog->outString("[StarGate-Auth] Prozess-Priorität festgelegt auf HOCH"); else sLog->outError("Realmd Prozess-Priorität Fehler!."); } } #endif // maximum counter for next ping uint32 numLoops = (sConfig->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000)); uint32 loopCounter = 0; // possibly enable db logging; avoid massive startup spam by doing it here. if (sLog->GetLogDBLater()) { sLog->outString("Aktiviere Datenbankprotokollierung..."); sLog->SetLogDBLater(false); // login db needs thread for logging sLog->SetLogDB(true); } else sLog->SetLogDB(false); ///- Wait for termination signal while (!stopEvent) { // dont move this outside the loop, the reactor will modify it ACE_Time_Value interval(0, 100000); if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) break; if ((++loopCounter) == numLoops) { loopCounter = 0; sLog->outDetail("Ping MySQL: Verbindung aufrecht zu erhalten"); LoginDatabase.KeepAlive(); } #ifdef _WIN32 if (m_ServiceStatus == 0) stopEvent = true; else { while (m_ServiceStatus == 2) Sleep(1000); } #endif } ///- Close the Database Pool LoginDatabase.Close(); sLog->outString("Halte Prozess..."); return 0; }
bool StartProcess(Settings& settings, HANDLE hCmdPipe) { //Launching as one of: //1. System Account //2. Specified account (or limited account) //3. As current process DWORD gle = 0; BOOL bLoadedProfile = FALSE; PROFILEINFO profile = {0}; profile.dwSize = sizeof(profile); profile.lpUserName = (LPWSTR)(LPCWSTR)settings.user; profile.dwFlags = PI_NOUI; if(false == GetUserHandle(settings, bLoadedProfile, profile, hCmdPipe)) return false; PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {0}; si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW; if(!BAD_HANDLE(settings.hStdErr)) { si.hStdError = settings.hStdErr; si.hStdInput = settings.hStdIn; si.hStdOutput = settings.hStdOut; si.dwFlags |= STARTF_USESTDHANDLES; #ifdef _DEBUG Log(L"DEBUG: Using redirected handles", false); #endif } #ifdef _DEBUG else Log(L"DEBUG: Not using redirected IO", false); #endif CString path = StrFormat(L"\"%s\"", settings.app); if(FALSE == settings.appArgs.IsEmpty()) { path += L" "; path += settings.appArgs; } LPCWSTR startingDir = NULL; if(FALSE == settings.workingDir.IsEmpty()) startingDir = settings.workingDir; DWORD launchGLE = 0; CleanupInteractive ci = {0}; if(settings.bInteractive || settings.bShowUIOnWinLogon) { BOOL b = PrepForInteractiveProcess(settings, &ci, settings.sessionToInteractWith); if(FALSE == b) Log(L"Failed to PrepForInteractiveProcess", true); if(NULL == si.lpDesktop) si.lpDesktop = L"WinSta0\\Default"; if(settings.bShowUIOnWinLogon) si.lpDesktop = L"winsta0\\Winlogon"; //Log(StrFormat(L"Using desktop: %s", si.lpDesktop), false); //http://blogs.msdn.com/b/winsdk/archive/2009/07/14/launching-an-interactive-process-from-windows-service-in-windows-vista-and-later.aspx //indicates desktop names are case sensitive } #ifdef _DEBUG Log(StrFormat(L"DEBUG: PAExec using desktop %s", si.lpDesktop == NULL ? L"{default}" : si.lpDesktop), false); #endif DWORD dwFlags = CREATE_SUSPENDED | CREATE_NEW_CONSOLE; LPVOID pEnvironment = NULL; VERIFY(CreateEnvironmentBlock(&pEnvironment, settings.hUser, TRUE)); if(NULL != pEnvironment) dwFlags |= CREATE_UNICODE_ENVIRONMENT; #ifdef _DEBUG gle = GetLastError(); Log(L"DEBUG: CreateEnvironmentBlock", gle); #endif if(settings.bDisableFileRedirection) DisableFileRedirection(); if(settings.bRunLimited) if(false == LimitRights(settings.hUser)) return false; if(settings.bRunElevated) if(false == ElevateUserToken(settings.hUser)) return false; CString user, domain; GetUserDomain(settings.user, user, domain); #ifdef _DEBUG Log(StrFormat(L"DEBUG: U:%s D:%s P:%s bP:%d Env:%s WD:%s", user, domain, settings.password, settings.bDontLoadProfile, pEnvironment ? L"true" : L"null", startingDir ? startingDir : L"null"), false); #endif BOOL bLaunched = FALSE; if(settings.bUseSystemAccount) { Log(StrFormat(L"PAExec starting process [%s] as Local System", path), false); if(BAD_HANDLE(settings.hUser)) Log(L"Have bad user handle", true); EnablePrivilege(SE_IMPERSONATE_NAME); BOOL bImpersonated = ImpersonateLoggedOnUser(settings.hUser); if(FALSE == bImpersonated) { Log(L"Failed to impersonate", GetLastError()); _ASSERT(bImpersonated); } EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); EnablePrivilege(SE_INCREASE_QUOTA_NAME); bLaunched = CreateProcessAsUser(settings.hUser, NULL, path.LockBuffer(), NULL, NULL, TRUE, dwFlags, pEnvironment, startingDir, &si, &pi); launchGLE = GetLastError(); path.UnlockBuffer(); #ifdef _DEBUG if(0 != launchGLE) Log(StrFormat(L"Launch (launchGLE=%u) params: user=[x%X] path=[%s] flags=[x%X], pEnv=[%s], dir=[%s], stdin=[x%X], stdout=[x%X], stderr=[x%X]", launchGLE, (DWORD)settings.hUser, path, dwFlags, pEnvironment ? L"{env}" : L"{null}", startingDir ? startingDir : L"{null}", (DWORD)si.hStdInput, (DWORD)si.hStdOutput, (DWORD)si.hStdError), false); #endif RevertToSelf(); } else { if(FALSE == settings.user.IsEmpty()) //launching as a specific user { Log(StrFormat(L"PAExec starting process [%s] as %s", path, settings.user), false); if(false == settings.bRunLimited) { bLaunched = CreateProcessWithLogonW(user, domain.IsEmpty() ? NULL : domain, settings.password, settings.bDontLoadProfile ? 0 : LOGON_WITH_PROFILE, NULL, path.LockBuffer(), dwFlags, pEnvironment, startingDir, &si, &pi); launchGLE = GetLastError(); path.UnlockBuffer(); #ifdef _DEBUG if(0 != launchGLE) Log(StrFormat(L"Launch (launchGLE=%u) params: user=[%s] domain=[%s] prof=[x%X] path=[%s] flags=[x%X], pEnv=[%s], dir=[%s], stdin=[x%X], stdout=[x%X], stderr=[x%X]", launchGLE, user, domain, settings.bDontLoadProfile ? 0 : LOGON_WITH_PROFILE, path, dwFlags, pEnvironment ? L"{env}" : L"{null}", startingDir ? startingDir : L"{null}", (DWORD)si.hStdInput, (DWORD)si.hStdOutput, (DWORD)si.hStdError), false); #endif } else bLaunched = FALSE; //force to run with CreateProcessAsUser so rights can be limited //CreateProcessWithLogonW can't be called from LocalSystem on Win2003 and earlier, so LogonUser/CreateProcessAsUser must be used. Might as well try for everyone if((FALSE == bLaunched) && !BAD_HANDLE(settings.hUser)) { #ifdef _DEBUG Log(L"DEBUG: Failed CreateProcessWithLogonW - trying CreateProcessAsUser", GetLastError()); #endif EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); EnablePrivilege(SE_INCREASE_QUOTA_NAME); EnablePrivilege(SE_IMPERSONATE_NAME); BOOL bImpersonated = ImpersonateLoggedOnUser(settings.hUser); if(FALSE == bImpersonated) { Log(L"Failed to impersonate", GetLastError()); _ASSERT(bImpersonated); } bLaunched = CreateProcessAsUser(settings.hUser, NULL, path.LockBuffer(), NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE, pEnvironment, startingDir, &si, &pi); if(0 == GetLastError()) launchGLE = 0; //mark as successful, otherwise return our original error path.UnlockBuffer(); #ifdef _DEBUG if(0 != launchGLE) Log(StrFormat(L"Launch (launchGLE=%u) params: user=[x%X] path=[%s] pEnv=[%s], dir=[%s], stdin=[x%X], stdout=[x%X], stderr=[x%X]", launchGLE, (DWORD)settings.hUser, path, pEnvironment ? L"{env}" : L"{null}", startingDir ? startingDir : L"{null}", (DWORD)si.hStdInput, (DWORD)si.hStdOutput, (DWORD)si.hStdError), false); #endif RevertToSelf(); } } else { Log(StrFormat(L"PAExec starting process [%s] as current user", path), false); EnablePrivilege(SE_ASSIGNPRIMARYTOKEN_NAME); EnablePrivilege(SE_INCREASE_QUOTA_NAME); EnablePrivilege(SE_IMPERSONATE_NAME); if(NULL != settings.hUser) bLaunched = CreateProcessAsUser(settings.hUser, NULL, path.LockBuffer(), NULL, NULL, TRUE, dwFlags, pEnvironment, startingDir, &si, &pi); if(FALSE == bLaunched) bLaunched = CreateProcess(NULL, path.LockBuffer(), NULL, NULL, TRUE, dwFlags, pEnvironment, startingDir, &si, &pi); launchGLE = GetLastError(); //#ifdef _DEBUG if(0 != launchGLE) Log(StrFormat(L"Launch (launchGLE=%u) params: path=[%s] user=[%s], pEnv=[%s], dir=[%s], stdin=[x%X], stdout=[x%X], stderr=[x%X]", launchGLE, path, settings.hUser ? L"{non-null}" : L"{null}", pEnvironment ? L"{env}" : L"{null}", startingDir ? startingDir : L"{null}", (DWORD)si.hStdInput, (DWORD)si.hStdOutput, (DWORD)si.hStdError), false); //#endif path.UnlockBuffer(); } } if(bLaunched) { if(gbInService) Log(L"Successfully launched", false); settings.hProcess = pi.hProcess; settings.processID = pi.dwProcessId; if(false == settings.allowedProcessors.empty()) { DWORD sysMask = 0, procMask = 0; VERIFY(GetProcessAffinityMask(pi.hProcess, &procMask, &sysMask)); procMask = 0; for(std::vector<WORD>::iterator itr = settings.allowedProcessors.begin(); settings.allowedProcessors.end() != itr; itr++) { DWORD bit = 1; bit = bit << (*itr - 1); procMask |= bit & sysMask; } VERIFY(SetProcessAffinityMask(pi.hProcess, procMask)); } VERIFY(SetPriorityClass(pi.hProcess, settings.priority)); ResumeThread(pi.hThread); VERIFY(CloseHandle(pi.hThread)); } else { Log(StrFormat(L"Failed to start %s.", path), launchGLE); if((ERROR_ELEVATION_REQUIRED == launchGLE) && (false == gbInService)) Log(L"HINT: PAExec probably needs to be \"Run As Administrator\"", false); } if(ci.bPreped) CleanUpInteractiveProcess(&ci); if(settings.bDisableFileRedirection) RevertFileRedirection(); if(NULL != pEnvironment) DestroyEnvironmentBlock(pEnvironment); pEnvironment = NULL; if(bLoadedProfile) UnloadUserProfile(settings.hUser, profile.hProfile); if(!BAD_HANDLE(settings.hUser)) { CloseHandle(settings.hUser); settings.hUser = NULL; } return bLaunched ? true : false; }
/* Thread safe - doesn't care about the lock */ static int AffinityPriorityFix(DWORD EnableAffinityFix, DWORD EnablePriorityFix) { HWND hFShwnd; DWORD nPriority; DWORD nProcAffinity; DWORD nSysAffinity; DWORD nProcId; HANDLE hFS; if(EnableAffinityFix || EnablePriorityFix) { /* Start by finding the window */ switch(FSUIPC_FS_Version) { case SIM_FSX: hFShwnd = FindWindow(NULL,"Microsoft Flight Simulator X"); break; case SIM_FS2K4: hFShwnd = FindWindow(NULL,"Microsoft Flight Simulator 2004 - A Century of Flight"); break; case SIM_FS2K2: hFShwnd = FindWindow(NULL,"Microsoft Flight Simulator 2002"); break; case SIM_FS2K: hFShwnd = FindWindow(NULL,"Microsoft Flight Simulator 2000"); break; case SIM_FS98: hFShwnd = FindWindow(NULL,"Microsoft Flight Simulator 98"); break; default: /* Couldn't find the window name, giving up on affinity or priority fix */ debuglog(DEBUG_WARNING,"Unknown FS, don't know what window to search\n"); return 0; } if(hFShwnd == NULL) { debuglog(DEBUG_WARNING,"Failed finding the window for the connected FS\n"); return 0; } GetWindowThreadProcessId(hFShwnd,&nProcId); if(!nProcId) { debuglog(DEBUG_WARNING,"Failed getting FS process ID\n"); return 0; } hFS = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION,FALSE,nProcId); if(hFS == NULL) { debuglog(DEBUG_WARNING,"Failed opening FS process!\n"); return 0; } /* Get FS priority class and copy it to our process */ if(EnablePriorityFix) { if(!(nPriority = GetPriorityClass(hFS))) { debuglog(DEBUG_WARNING,"Failed getting FS priority class!\n"); } else { if(!SetPriorityClass(GetCurrentProcess(),nPriority)) debuglog(DEBUG_WARNING,"Failed setting priority class!\n"); } } /* Get FS affinity mask and copy it to our process */ if(EnableAffinityFix) { if(!GetProcessAffinityMask(hFS,&nProcAffinity,&nSysAffinity)) { debuglog(DEBUG_WARNING,"Failed getting FS affinity mask!\n"); } else { if(!SetProcessAffinityMask(GetCurrentProcess(),nProcAffinity)) debuglog(DEBUG_WARNING,"Failed setting affinity mask!\n"); } } /* Finished with the FS process, let's close it */ CloseHandle(hFS); } return 1; }
// Main function int Master::Run() { BigNumber seed1; seed1.SetRand(16 * 8); sLog->outString("%s (core-daemon)", _FULLVERSION); sLog->outString("<Ctrl-C> to stop.\n"); sLog->outString(" ______ __"); sLog->outString("/\\__ _\\ __ __/\\ \\__"); sLog->outString("\\/_/\\ \\/ _ __ /\\_\\ ___ /\\_\\ \\ ,_\\ __ __"); sLog->outString(" \\ \\ \\/\\`'__\\/\\ \\ /' _ `\\/\\ \\ \\ \\/ /\\ \\/\\ \\"); sLog->outString(" \\ \\ \\ \\ \\/ \\ \\ \\/\\ \\/\\ \\ \\ \\ \\ \\_\\ \\ \\_\\ \\"); sLog->outString(" \\ \\_\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_\\ \\__\\\\/`____ \\"); sLog->outString(" \\/_/\\/_/ \\/_/\\/_/\\/_/\\/_/\\/__/ `/___/> \\"); sLog->outString(" C O R E /\\___/"); sLog->outString("http://www.trinitycore.ru \\/__/\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 // worldd PID file creation std::string pidfile = sConfig->GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog->outError("Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog->outString("Daemon PID: %u\n", pid); } // Start the databases if (!_StartDB()) return 1; // set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET color = (color & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); // Initialize the World sWorld->SetInitialWorldSettings(); // Initialise the signal handlers CoredSignalHandler SignalINT, SignalTERM; #ifdef _WIN32 CoredSignalHandler SignalBREAK; #endif /* _WIN32 */ // Register core's signal handlers ACE_Sig_Handler Handler; Handler.register_handler(SIGINT, &SignalINT); Handler.register_handler(SIGTERM, &SignalTERM); #ifdef _WIN32 Handler.register_handler(SIGBREAK, &SignalBREAK); #endif /* _WIN32 */ // Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (sConfig->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig->GetBoolDefault("Console.Enable", true)) #endif { // Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); // Handle affinity for multiple processors and process priority on Windows #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig->GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if (!curAff) { sLog->outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for 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("TrinityCore 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); } uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); // Start up freeze catcher thread if (uint32 freeze_delay = sConfig->GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); ACE_Based::Thread freeze_thread(fdr); freeze_thread.setPriority(ACE_Based::Highest); } // Launch the world listener socket uint16 wsport = sWorld->getIntConfig(CONFIG_PORT_WORLD); std::string bind_ip = sConfig->GetStringDefault("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork(wsport, bind_ip.c_str ()) == -1) { sLog->outError ("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } // set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET color = color & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); sWorldSocketMgr->Wait(); if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // set server offline LoginDatabase.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(); }
int uv_spawn(uv_loop_t* loop, uv_process_t* process, const uv_process_options_t* options) { int i; int err = 0; WCHAR* path = NULL, *alloc_path = NULL; BOOL result; WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; DWORD process_flags; uv_process_init(loop, process); process->exit_cb = options->exit_cb; if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { return UV_ENOTSUP; } if (options->file == NULL || options->args == NULL) { return UV_EINVAL; } if (options->cpumask != NULL) { if (options->cpumask_size < (size_t)uv_cpumask_size()) { return UV_EINVAL; } } assert(options->file != NULL); assert(!(options->flags & ~(UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID | UV_PROCESS_WINDOWS_HIDE | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); err = uv_utf8_to_utf16_alloc(options->file, &application); if (err) goto done; err = make_program_args( options->args, options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, &arguments); if (err) goto done; if (options->env) { err = make_program_env(options->env, &env); if (err) goto done; } if (options->cwd) { /* Explicit cwd */ err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); if (err) goto done; } else { /* Inherit cwd */ DWORD cwd_len, r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { err = GetLastError(); goto done; } cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR)); if (cwd == NULL) { err = ERROR_OUTOFMEMORY; goto done; } r = GetCurrentDirectoryW(cwd_len, cwd); if (r == 0 || r >= cwd_len) { err = GetLastError(); goto done; } } /* Get PATH environment variable. */ path = find_path(env); if (path == NULL) { DWORD path_len, r; path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); if (path_len == 0) { err = GetLastError(); goto done; } alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR)); if (alloc_path == NULL) { err = ERROR_OUTOFMEMORY; goto done; } path = alloc_path; r = GetEnvironmentVariableW(L"PATH", path, path_len); if (r == 0 || r >= path_len) { err = GetLastError(); goto done; } } err = uv__stdio_create(loop, options, &process->child_stdio_buffer); if (err) goto done; application_path = search_path(application, cwd, path); if (application_path == NULL) { /* Not found. */ err = ERROR_FILE_NOT_FOUND; goto done; } startup.cb = sizeof(startup); startup.lpReserved = NULL; startup.lpDesktop = NULL; startup.lpTitle = NULL; startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); process_flags = CREATE_UNICODE_ENVIRONMENT; if (options->flags & UV_PROCESS_WINDOWS_HIDE) { /* Avoid creating console window if stdio is not inherited. */ for (i = 0; i < options->stdio_count; i++) { if (options->stdio[i].flags & UV_INHERIT_FD) break; if (i == options->stdio_count - 1) process_flags |= CREATE_NO_WINDOW; } /* Use SW_HIDE to avoid any potential process window. */ startup.wShowWindow = SW_HIDE; } else { startup.wShowWindow = SW_SHOWDEFAULT; } if (options->flags & UV_PROCESS_DETACHED) { /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That * means that libuv might not let you create a fully daemonized process * when run under job control. However the type of job control that libuv * itself creates doesn't trickle down to subprocesses so they can still * daemonize. * * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the * CreateProcess call fail if we're under job control that doesn't allow * breakaway. */ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } if (options->cpumask != NULL) { /* Create the child in a suspended state so we have a chance to set its process affinity before it runs. */ process_flags |= CREATE_SUSPENDED; } if (!CreateProcessW(application_path, arguments, NULL, NULL, 1, process_flags, env, cwd, &startup, &info)) { /* CreateProcessW failed. */ err = GetLastError(); goto done; } if (options->cpumask != NULL) { /* The child is currently suspended. Set its process affinity or terminate it if we can't. */ int i; int cpumasksize; DWORD_PTR sysmask; DWORD_PTR oldmask; DWORD_PTR newmask; cpumasksize = uv_cpumask_size(); if (!GetProcessAffinityMask(info.hProcess, &oldmask, &sysmask)) { err = GetLastError(); TerminateProcess(info.hProcess, 1); goto done; } newmask = 0; for (i = 0; i < cpumasksize; i++) { if (options->cpumask[i]) { if (oldmask & (((DWORD_PTR)1) << i)) { newmask |= ((DWORD_PTR)1) << i; } else { err = UV_EINVAL; TerminateProcess(info.hProcess, 1); goto done; } } } if (!SetProcessAffinityMask(info.hProcess, newmask)) { err = GetLastError(); TerminateProcess(info.hProcess, 1); goto done; } /* The process affinity of the child is set. Let it run. */ if (ResumeThread(info.hThread) == ((DWORD)-1)) { err = GetLastError(); TerminateProcess(info.hProcess, 1); goto done; } } /* Spawn succeeded */ /* Beyond this point, failure is reported asynchronously. */ process->process_handle = info.hProcess; process->pid = info.dwProcessId; /* If the process isn't spawned as detached, assign to the global job */ /* object so windows will kill it when the parent process dies. */ if (!(options->flags & UV_PROCESS_DETACHED)) { uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) { /* AssignProcessToJobObject might fail if this process is under job * control and the job doesn't have the * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version * that doesn't support nested jobs. * * When that happens we just swallow the error and continue without * establishing a kill-child-on-parent-exit relationship, otherwise * there would be no way for libuv applications run under job control * to spawn processes at all. */ DWORD err = GetLastError(); if (err != ERROR_ACCESS_DENIED) uv_fatal_error(err, "AssignProcessToJobObject"); } } /* Set IPC pid to all IPC pipes. */ for (i = 0; i < options->stdio_count; i++) { const uv_stdio_container_t* fdopt = &options->stdio[i]; if (fdopt->flags & UV_CREATE_PIPE && fdopt->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) fdopt->data.stream)->ipc) { ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId; } } /* Setup notifications for when the child process exits. */ result = RegisterWaitForSingleObject(&process->wait_handle, process->process_handle, exit_wait_callback, (void*)process, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); if (!result) { uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); } CloseHandle(info.hThread); assert(!err); /* Make the handle active. It will remain active until the exit callback */ /* is made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* Cleanup, whether we succeeded or failed. */ done: uv__free(application); uv__free(application_path); uv__free(arguments); uv__free(cwd); uv__free(env); uv__free(alloc_path); if (process->child_stdio_buffer != NULL) { /* Clean up child stdio handles. */ uv__stdio_destroy(process->child_stdio_buffer); process->child_stdio_buffer = NULL; } return uv_translate_sys_error(err); }
/// 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 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; }
int CPUCount( int &logicalNum, int &physicalNum ) { int statusFlag; SYSTEM_INFO info; physicalNum = 1; logicalNum = 1; statusFlag = HT_NOT_CAPABLE; info.dwNumberOfProcessors = 0; GetSystemInfo (&info); // Number of physical processors in a non-Intel system // or in a 32-bit Intel system with Hyper-Threading technology disabled physicalNum = info.dwNumberOfProcessors; unsigned char HT_Enabled = 0; logicalNum = LogicalProcPerPhysicalProc(); if ( logicalNum >= 1 ) { // > 1 doesn't mean HT is enabled in the BIOS HANDLE hCurrentProcessHandle; DWORD dwProcessAffinity; DWORD dwSystemAffinity; DWORD dwAffinityMask; // Calculate the appropriate shifts and mask based on the // number of logical processors. unsigned char i = 1, PHY_ID_MASK = 0xFF, PHY_ID_SHIFT = 0; while( i < logicalNum ) { i *= 2; PHY_ID_MASK <<= 1; PHY_ID_SHIFT++; } hCurrentProcessHandle = GetCurrentProcess(); GetProcessAffinityMask( hCurrentProcessHandle, &dwProcessAffinity, &dwSystemAffinity ); // Check if available process affinity mask is equal to the // available system affinity mask if ( dwProcessAffinity != dwSystemAffinity ) { statusFlag = HT_CANNOT_DETECT; physicalNum = -1; return statusFlag; } dwAffinityMask = 1; while ( dwAffinityMask != 0 && dwAffinityMask <= dwProcessAffinity ) { // Check if this CPU is available if ( dwAffinityMask & dwProcessAffinity ) { if ( SetProcessAffinityMask( hCurrentProcessHandle, dwAffinityMask ) ) { unsigned char APIC_ID, LOG_ID, PHY_ID; Sleep( 0 ); // Give OS time to switch CPU APIC_ID = GetAPIC_ID(); LOG_ID = APIC_ID & ~PHY_ID_MASK; PHY_ID = APIC_ID >> PHY_ID_SHIFT; if ( LOG_ID != 0 ) { HT_Enabled = 1; } } } dwAffinityMask = dwAffinityMask << 1; } // Reset the processor affinity SetProcessAffinityMask( hCurrentProcessHandle, dwProcessAffinity ); if ( logicalNum == 1 ) { // Normal P4 : HT is disabled in hardware statusFlag = HT_DISABLED; } else { if ( HT_Enabled ) { // Total physical processors in a Hyper-Threading enabled system. physicalNum /= logicalNum; statusFlag = HT_ENABLED; } else { statusFlag = HT_SUPPORTED_NOT_ENABLED; } } }
void getnumthreads() { #ifdef _WIN32 DWORD_PTR dwProcessAffinity, dwSystemAffinity; #elif __linux__ cpu_set_t dwProcessAffinity; #else int dwProcessAffinity = 0; int32_t core_count = 0; #endif size_t len = sizeof(dwProcessAffinity); if (numthreads > 0) return; #ifdef _WIN32 GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); #elif __linux__ sched_getaffinity(0, len, &dwProcessAffinity); #else if (sysctlbyname("hw.logicalcpu", &core_count, &len, 0, 0) == 0) numthreads = core_count; #endif for (unsigned int i = 0; i < len * 8; i++) #if defined(_WIN32) if (dwProcessAffinity & (1i64 << i)) { #elif defined __linux__ if (CPU_ISSET(i, &dwProcessAffinity)) { #else if (dwProcessAffinity & (1 << i)) { #endif numthreads++; printf("Detected core on: %u\n", i); } printf("Number of threads: %i\n", (int)numthreads); } extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) { successval = 0; max_val = target; getnumthreads(); initialHash = (unsigned char *)starthash; # ifdef _WIN32 HANDLE* threads = (HANDLE*)calloc(sizeof(HANDLE), numthreads); # else pthread_t* threads = (pthread_t*)calloc(sizeof(pthread_t), numthreads); struct sched_param schparam; schparam.sched_priority = 0; # endif unsigned int *threaddata = (unsigned int *)calloc(sizeof(unsigned int), numthreads); for (unsigned int i = 0; i < numthreads; i++) { threaddata[i] = i; # ifdef _WIN32 threads[i] = CreateThread(NULL, 0, threadfunc, (LPVOID)&threaddata[i], 0, NULL); SetThreadPriority(threads[i], THREAD_PRIORITY_IDLE); # else pthread_create(&threads[i], NULL, threadfunc, (void*)&threaddata[i]); # ifdef __linux__ pthread_setschedparam(threads[i], SCHED_IDLE, &schparam); # else pthread_setschedparam(threads[i], SCHED_RR, &schparam); # endif # endif } # ifdef _WIN32 WaitForMultipleObjects(numthreads, threads, TRUE, INFINITE); # else for (unsigned int i = 0; i < numthreads; i++) { pthread_join(threads[i], NULL); } # endif free(threads); free(threaddata); return successval; }
pthread_t pthread_self (void) /* * ------------------------------------------------------ * DOCPUBLIC * This function returns a reference to the current running * thread. * * PARAMETERS * N/A * * * DESCRIPTION * This function returns a reference to the current running * thread. * * RESULTS * pthread_t reference to the current thread * * ------------------------------------------------------ */ { pthread_t self; pthread_t nil = {NULL, 0}; ptw32_thread_t * sp; #if defined(_UWIN) if (!ptw32_selfThreadKey) return nil; #endif sp = (ptw32_thread_t *) pthread_getspecific (ptw32_selfThreadKey); if (sp != NULL) { self = sp->ptHandle; } else { int fail = PTW32_FALSE; /* * Need to create an implicit 'self' for the currently * executing thread. */ self = ptw32_new (); sp = (ptw32_thread_t *) self.p; if (sp != NULL) { /* * This is a non-POSIX thread which has chosen to call * a POSIX threads function for some reason. We assume that * it isn't joinable, but we do assume that it's * (deferred) cancelable. */ sp->implicit = 1; sp->detachState = PTHREAD_CREATE_DETACHED; sp->thread = GetCurrentThreadId (); #if defined(NEED_DUPLICATEHANDLE) /* * DuplicateHandle does not exist on WinCE. * * NOTE: * GetCurrentThread only returns a pseudo-handle * which is only valid in the current thread context. * Therefore, you should not pass the handle to * other threads for whatever purpose. */ sp->threadH = GetCurrentThread (); #else if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (), GetCurrentProcess (), &sp->threadH, 0, FALSE, DUPLICATE_SAME_ACCESS)) { fail = PTW32_TRUE; } #endif if (!fail) { #if defined(HAVE_CPU_AFFINITY) /* * Get this threads CPU affinity by temporarily setting the threads * affinity to that of the process to get the old thread affinity, * then reset to the old affinity. */ DWORD_PTR vThreadMask, vProcessMask, vSystemMask; if (GetProcessAffinityMask(GetCurrentProcess(), &vProcessMask, &vSystemMask)) { vThreadMask = SetThreadAffinityMask(sp->threadH, vProcessMask); if (vThreadMask) { if (SetThreadAffinityMask(sp->threadH, vThreadMask)) { sp->cpuset = (size_t) vThreadMask; } else fail = PTW32_TRUE; } else fail = PTW32_TRUE; } else fail = PTW32_TRUE; #endif /* * No need to explicitly serialise access to sched_priority * because the new handle is not yet public. */ sp->sched_priority = GetThreadPriority (sp->threadH); pthread_setspecific (ptw32_selfThreadKey, (void *) sp); } } if (fail) { /* * Thread structs are never freed but are reused so if this * continues to fail at least we don't leak memory. */ ptw32_threadReusePush (self); /* * As this is a win32 thread calling us and we have failed, * return a value that makes sense to win32. */ return nil; } } return (self); }
/// Launch the realm server 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]; } else { sLog.outError("Runtime-Error: unsupported option %s",argv[c]); usage(argv[0]); return 1; } ++c; } if (!sConfig.SetSource(cfg_file)) { sLog.outError("Could not find configuration file %s.", cfg_file); return 1; } 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.outString( "MaNGOS realm daemon %s", _FULLVERSION ); sLog.outString( "<Ctrl-C> to stop.\n" ); ///- Initialise the database connection std::string dbstring; if(!StartDB(dbstring)) return 1; ///- Get the list of realms for the server m_realmList.GetAndAddRealms(dbstring); 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 ); SocketHandler h; ListenSocket<AuthSocket> authListenSocket(h); if ( authListenSocket.Bind(rmport)) { sLog.outError( "MaNGOS realmd can not bind to port %d", 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) { uint32 appAff; uint32 sysAff; if(GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { uint32 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(""); } uint32 Prio = sConfig.GetIntDefault("ProcessPriority", 0); 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 SQL to keep connection alive"); delete dbRealmServer.Query("SELECT 1 FROM `realmlist` LIMIT 1"); } } ///- 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(); }
/// 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; }
/* Return the number of processors available to the current process, based on a modern system call that returns the "affinity" between the current process and each CPU. Return 0 if unknown or if such a system call does not exist. */ static unsigned long num_processors_via_affinity_mask (void) { /* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np, but with different APIs. Also it requires linking with -lpthread. Therefore this code is not enabled. glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has sched_getaffinity_np. */ #if HAVE_PTHREAD_GETAFFINITY_NP && defined __GLIBC__ && 0 { cpu_set_t set; if (pthread_getaffinity_np (pthread_self (), sizeof (set), &set) == 0) { unsigned long count; # ifdef CPU_COUNT /* glibc >= 2.6 has the CPU_COUNT macro. */ count = CPU_COUNT (&set); # else size_t i; count = 0; for (i = 0; i < CPU_SETSIZE; i++) if (CPU_ISSET (i, &set)) count++; # endif if (count > 0) return count; } } #elif HAVE_PTHREAD_GETAFFINITY_NP && defined __NetBSD__ && 0 { cpuset_t *set; set = cpuset_create (); if (set != NULL) { unsigned long count = 0; if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set) == 0) { cpuid_t i; for (i = 0;; i++) { int ret = cpuset_isset (i, set); if (ret < 0) break; if (ret > 0) count++; } } cpuset_destroy (set); if (count > 0) return count; } } #elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */ { cpu_set_t set; if (sched_getaffinity (0, sizeof (set), &set) == 0) { unsigned long count; # ifdef CPU_COUNT /* glibc >= 2.6 has the CPU_COUNT macro. */ count = CPU_COUNT (&set); # else size_t i; count = 0; for (i = 0; i < CPU_SETSIZE; i++) if (CPU_ISSET (i, &set)) count++; # endif if (count > 0) return count; } } #elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */ { cpuset_t *set; set = cpuset_create (); if (set != NULL) { unsigned long count = 0; if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0) { cpuid_t i; for (i = 0;; i++) { int ret = cpuset_isset (i, set); if (ret < 0) break; if (ret > 0) count++; } } cpuset_destroy (set); if (count > 0) return count; } } #endif #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ { /* This works on native Windows platforms. */ DWORD_PTR process_mask; DWORD_PTR system_mask; if (GetProcessAffinityMask (GetCurrentProcess (), &process_mask, &system_mask)) { DWORD_PTR mask = process_mask; unsigned long count = 0; for (; mask != 0; mask = mask >> 1) if (mask & 1) count++; if (count > 0) return count; } }
/// 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, " "); sLog->outInfo(LOG_FILTER_AUTHSERVER, " "); sLog->outInfo(LOG_FILTER_AUTHSERVER, "<Ctrl-C> to stop.\n"); sLog->outInfo(LOG_FILTER_AUTHSERVER, "██████╗ ███████╗ █████╗ ████████╗██╗ ██╗"); sLog->outInfo(LOG_FILTER_AUTHSERVER, "██╔══██╗██╔════╝██╔══██╗╚══██╔══╝██║ ██║"); sLog->outInfo(LOG_FILTER_AUTHSERVER, "██║ ██║█████╗ ███████║ ██║ ███████║"); sLog->outInfo(LOG_FILTER_AUTHSERVER, "██║ ██║██╔══╝ ██╔══██║ ██║ ██╔══██║"); sLog->outInfo(LOG_FILTER_AUTHSERVER, "██████╔╝███████╗██║ ██║ ██║ ██║ ██║"); sLog->outInfo(LOG_FILTER_AUTHSERVER, "╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝"); sLog->outInfo(LOG_FILTER_AUTHSERVER, " ██████╗ ██████╗ ██████╗ ███████╗"); sLog->outInfo(LOG_FILTER_AUTHSERVER, " ██╔════╝██╔═══██╗██╔══██╗██╔════╝"); sLog->outInfo(LOG_FILTER_AUTHSERVER, " ██║ ██║ ██║██████╔╝█████╗"); sLog->outInfo(LOG_FILTER_AUTHSERVER, " ██║ ██║ ██║██╔══██╗██╔══╝"); sLog->outInfo(LOG_FILTER_AUTHSERVER, " ╚██████╗╚██████╔╝██║ ██║███████╗"); sLog->outInfo(LOG_FILTER_AUTHSERVER, " ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝"); sLog->outInfo(LOG_FILTER_AUTHSERVER, " Noffearr Death ProjecT 2015(c) Open-Sourced Game Emulation "); sLog->outInfo(LOG_FILTER_AUTHSERVER, " http://www.noffearrdeathproject.net \n"); 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; // 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->outInfo(LOG_FILTER_WORLDSERVER, "%s (worldserver-daemon)", _FULLVERSION); sLog->outInfo(LOG_FILTER_WORLDSERVER, "<Ctrl-C> to stop.\n"); sLog->outInfo(LOG_FILTER_WORLDSERVER, "TrinityCore 2012-2015"); sLog->outInfo(LOG_FILTER_WORLDSERVER, "MoPCore 2015"); /// 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) { ///- 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; }