bool Master::_StartDB() { sLog.SetLogDB(false); std::string dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", ""); if (dbstring.empty()) { sLog.outError("World database not specified in configuration file"); return false; } if (!WorldDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to world database %s",dbstring.c_str()); return false; } dbstring = sConfig.GetStringDefault("CharacterDatabaseInfo", ""); if (dbstring.empty()) { sLog.outError("Character database not specified in configuration file"); return false; } if (!CharacterDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to Character database %s",dbstring.c_str()); return false; } dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", ""); if (dbstring.empty()) { sLog.outError("Login database not specified in configuration file"); return false; } if (!LoginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to login database %s",dbstring.c_str()); return false; } realmID = sConfig.GetIntDefault("RealmID", 0); if (!realmID) { sLog.outError("Realm ID not defined in configuration file"); return false; } sLog.outString("Realm running as realm ID %d", realmID); sLog.SetLogDBLater(sConfig.GetBoolDefault("EnableLogDB", false)); sLog.SetLogDB(false); sLog.SetRealmID(realmID); clearOnlineAccounts(); WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _REVISION); sWorld.LoadDBVersion(); sLog.outString("Using World DB: %s", sWorld.GetDBVersion()); return true; }
// Initialize connection to the databases void Master::_StartDB() { sConsole.SetLoadingLabel("Connecting to databases..."); // Get world database info from configuration file std::string dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", ""); if (dbstring.empty()) sLog.outFatal("World database not specified in configuration file"); // Initialise the world database if (!WorldDatabase.Initialize(dbstring.c_str())) sLog.outFatal("Cannot connect to world database %s", dbstring.c_str()); // Get character database info from configuration file dbstring = sConfig.GetStringDefault("CharacterDatabaseInfo", ""); if (dbstring.empty()) sLog.outFatal("Character database not specified in configuration file"); // Initialise the Character database if (!CharacterDatabase.Initialize(dbstring.c_str())) sLog.outFatal("Cannot connect to Character database %s", dbstring.c_str()); // Get login database info from configuration file dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", ""); if (dbstring.empty()) sLog.outFatal("Login database not specified in configuration file"); // Initialise the login database if (!LoginDatabase.Initialize(dbstring.c_str())) sLog.outFatal("Cannot connect to login database %s", dbstring.c_str()); // Get the realm Id from the configuration file realmID = sConfig.GetIntDefault("RealmID", 0); if (!realmID) sLog.outFatal("Realm ID not defined in configuration file"); sLog.outString("Realm running as realm ID %d", realmID); // Clean the database before starting clearOnlineAccounts(); // Insert version info into DB WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _REVISION); sWorld.LoadDBVersion(); sLog.outString("Using World DB: %s", sWorld.GetDBVersion()); }
bool Master::_StartDB() { std::string dbstring; if(!sConfig.GetString("WorldDatabaseInfo", &dbstring)) { sLog.outError("Database not specified"); exit(1); } sLog.outString("World Database: %s", dbstring.c_str() ); if(!sDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to world database"); exit(1); } if(!sConfig.GetString("LoginDatabaseInfo", &dbstring)) { sLog.outError("Login database not specified"); exit(1); } sLog.outString("Login Database: %s", dbstring.c_str() ); if(!loginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to login database"); exit(1); } realmID = sConfig.GetIntDefault("RealmID", 0); if(!realmID) { sLog.outError("Realm ID not defined"); exit(1); } else { sLog.outString("Realm running as realm ID %d", realmID); } sDatabase.PExecute("UPDATE `character` SET `online` = 0"); clearOnlineAccounts(); return true; }
/// Initialize connection to the databases bool Master::_StartDB() { MySQL::Library_Init(); sLog->SetLogDB(false); std::string dbstring; uint8 async_threads, synch_threads; dbstring = ConfigMgr::GetStringDefault("WorldDatabaseInfo", ""); if (dbstring.empty()) { sLog->outError("World database not specified in configuration file"); return false; } async_threads = ConfigMgr::GetIntDefault("WorldDatabase.WorkerThreads", 1); if (async_threads < 1 || async_threads > 32) { sLog->outError("World database: invalid number of worker threads specified. " "Please pick a value between 1 and 32."); return false; } synch_threads = ConfigMgr::GetIntDefault("WorldDatabase.SynchThreads", 1); ///- Initialise the world database if (!WorldDatabase.Open(dbstring, async_threads, synch_threads)) { sLog->outError("Cannot connect to world database %s", dbstring.c_str()); return false; } ///- Get character database info from configuration file dbstring = ConfigMgr::GetStringDefault("CharacterDatabaseInfo", ""); if (dbstring.empty()) { sLog->outError("Character database not specified in configuration file"); return false; } async_threads = ConfigMgr::GetIntDefault("CharacterDatabase.WorkerThreads", 1); if (async_threads < 1 || async_threads > 32) { sLog->outError("Character database: invalid number of worker threads specified. " "Please pick a value between 1 and 32."); return false; } synch_threads = ConfigMgr::GetIntDefault("CharacterDatabase.SynchThreads", 2); ///- Initialise the Character database if (!CharacterDatabase.Open(dbstring, async_threads, synch_threads)) { sLog->outError("Cannot connect to Character database %s", dbstring.c_str()); return false; } ///- Get login database info from configuration file dbstring = ConfigMgr::GetStringDefault("LoginDatabaseInfo", ""); if (dbstring.empty()) { sLog->outError("Login database not specified in configuration file"); return false; } async_threads = ConfigMgr::GetIntDefault("LoginDatabase.WorkerThreads", 1); if (async_threads < 1 || async_threads > 32) { sLog->outError("Login database: invalid number of worker threads specified. " "Please pick a value between 1 and 32."); return false; } synch_threads = ConfigMgr::GetIntDefault("LoginDatabase.SynchThreads", 1); ///- Initialise the login database if (!LoginDatabase.Open(dbstring, async_threads, synch_threads)) { sLog->outError("Cannot connect to login database %s", dbstring.c_str()); return false; } ///- Get the realm Id from the configuration file realmID = ConfigMgr::GetIntDefault("RealmID", 0); if (!realmID) { sLog->outError("Realm ID not defined in configuration file"); return false; } sLog->outString("Realm running as realm ID %d", realmID); ///- Initialize the DB logging system sLog->SetLogDBLater(ConfigMgr::GetBoolDefault("EnableLogDB", false)); // set var to enable DB logging once startup finished. sLog->SetLogDB(false); sLog->SetRealmID(realmID); ///- Clean the database before starting clearOnlineAccounts(); ///- Insert version info into DB WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _HASH); // One-time query sWorld->LoadDBVersion(); sLog->outString("Using World DB: %s", sWorld->GetDBVersion()); return true; }
/// Main function int Master::Run() { BigNumber seed1; seed1.SetRand(16 * 8); sLog->outString("%s (worldserver-daemon)", _FULLVERSION); sLog->outString("<Ctrl-C> to stop.\n"); sLog->outString(" ______ __ __ __ __ ______ __ ______ ______ "); sLog->outString(" /\\ ___\\/\\ \\/ / /\\ \\_\\ \\/\\ ___/\\ \\/\\ == \\/\\ ___\\ "); sLog->outString(" \\ \\___ \\ \\ _'-\\ \\____ \\ \\ __\\ \\ \\ \\ __<\\ \\ __\\ "); sLog->outString(" \\/\\_____\\ \\_\\ \\_\\/\\_____\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_____\\ "); sLog->outString(" \\/_____/\\/_/\\/_/\\/_____/\\/_/ \\/_/\\/_/ /_/\\/_____/ "); sLog->outString(" Project SkyFireEmu 2012(c) Open-sourced Game Emulation "); sLog->outString(" <http://www.projectskyfire.org/> \n"); /// worldserver PID file creation std::string pidfile = ConfigMgr::GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog->outError("Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog->outString("Daemon PID: %u\n", pid); } ///- Start the databases if (!_StartDB()) return 1; // set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET color = (color & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmID); ///- Initialize the World sWorld->SetInitialWorldSettings(); // Initialize the signal handlers WorldServerSignalHandler SignalINT, SignalTERM; #ifdef _WIN32 WorldServerSignalHandler SignalBREAK; #endif /* _WIN32 */ // Register worldserver's signal handlers ACE_Sig_Handler Handler; Handler.register_handler(SIGINT, &SignalINT); Handler.register_handler(SIGTERM, &SignalTERM); #ifdef _WIN32 Handler.register_handler(SIGBREAK, &SignalBREAK); #endif /* _WIN32 */ ///- Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (ConfigMgr::GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (ConfigMgr::GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); ///- Handle affinity for multiple processors and process priority on Windows #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = ConfigMgr::GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if (!curAff) { sLog->outError("Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", Aff, appAff); } else { if (SetProcessAffinityMask(hProcess, curAff)) sLog->outString("Using processors (bitmask, hex): %x", curAff); else sLog->outError("Can't set used processors (hex): %x", curAff); } } sLog->outString(""); } bool Prio = ConfigMgr::GetBoolDefault("ProcessPriority", false); //if (Prio && (m_ServiceStatus == -1) /* need set to default process priority class in service mode*/) if (Prio) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog->outString("worldserver process priority class set to HIGH"); else sLog->outError("Can't set worldserver process priority class."); sLog->outString(""); } } #endif //Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (ConfigMgr::GetBoolDefault("SOAP.Enabled", false)) { TCSoapRunnable* runnable = new TCSoapRunnable(); runnable->setListenArguments(ConfigMgr::GetStringDefault("SOAP.IP", "127.0.0.1"), ConfigMgr::GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread if (uint32 freeze_delay = ConfigMgr::GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay * 1000); ACE_Based::Thread freeze_thread(fdr); freeze_thread.setPriority(ACE_Based::Highest); } ///- Launch the world listener socket uint16 wsport = sWorld->getIntConfig(CONFIG_PORT_WORLD); std::string bind_ip = ConfigMgr::GetStringDefault("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork(wsport, bind_ip.c_str ()) == -1) { sLog->outError("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } // set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET color = color & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmID); sLog->outString("%s (worldserver-daemon) ready...", _FULLVERSION); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); rar_thread.wait(); if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // set server offline LoginDatabase.DirectPExecute("UPDATE realmlist SET color = color | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); ///- Clean database before leaving clearOnlineAccounts(); _StopDB(); sLog->outString("Halting process..."); if (cliThread) { #ifdef _WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module //UnloadScriptingModule(); // Exit the process with specified return value return World::GetExitCode(); }
/// Initialize connection to the databases bool Master::_StartDB() { ///- Get world database info from configuration file std::string dbstring; if(!sConfig.GetString("WorldDatabaseInfo", &dbstring)) { sLog.outError("Database not specified in configuration file"); return false; } sLog.outString("World Database: %s", dbstring.c_str()); ///- Initialise the world database if(!WorldDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to world database %s",dbstring.c_str()); return false; } if(!WorldDatabase.CheckRequiredField("db_version",REVISION_DB_MANGOS)) return false; if(!sConfig.GetString("CharacterDatabaseInfo", &dbstring)) { sLog.outError("Character Database not specified in configuration file"); return false; } sLog.outString("Character Database: %s", dbstring.c_str()); ///- Initialise the Character database if(!CharacterDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to Character database %s",dbstring.c_str()); return false; } if(!CharacterDatabase.CheckRequiredField("character_db_version",REVISION_DB_CHARACTERS)) return false; ///- Get login database info from configuration file if(!sConfig.GetString("LoginDatabaseInfo", &dbstring)) { sLog.outError("Login database not specified in configuration file"); return false; } ///- Initialise the login database sLog.outString("Login Database: %s", dbstring.c_str() ); if(!loginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to login database %s",dbstring.c_str()); return false; } if(!loginDatabase.CheckRequiredField("realmd_db_version",REVISION_DB_REALMD)) return false; ///- Get the realm Id from the configuration file realmID = sConfig.GetIntDefault("RealmID", 0); if(!realmID) { sLog.outError("Realm ID not defined in configuration file"); return false; } sLog.outString("Realm running as realm ID %d", realmID); ///- Clean the database before starting clearOnlineAccounts(); sWorld.LoadDBVersion(); sLog.outString("Using World DB: %s", sWorld.GetDBVersion()); sLog.outString("Using creature EventAI: %s", sWorld.GetCreatureEventAIVersion()); return true; }
/// Main function int Master::Run() { /// worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if( !pid ) { sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() ); return 1; } sLog.outString( "Daemon PID: %u\n", pid ); } ///- Start the databases if (!_StartDB()) return 1; ///- Initialize the World sWorld.SetInitialWorldSettings(); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set server online loginDatabase.PExecute("UPDATE realmlist SET color = 0, population = 0 WHERE id = '%d'",realmID); ACE_Based::Thread* cliThread = NULL; #ifdef WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); ///- Handle affinity for multiple processors and process priority on Windows #ifdef WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if(Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if(GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if(!curAff ) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for mangosd. Accessible processors bitmask (hex): %x",Aff,appAff); } else { if(SetProcessAffinityMask(hProcess,curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x",curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); // if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/) if(Prio) { if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("mangosd process priority class set to HIGH"); else sLog.outError("ERROR: Can't set mangosd process priority class."); sLog.outString(); } } #endif uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); ///- Start up freeze catcher thread if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); ACE_Based::Thread freeze_thread(fdr); freeze_thread.setPriority(ACE_Based::Highest); } ///- Launch the world listener socket port_t wsport = sWorld.getConfig (CONFIG_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1) { sLog.outError ("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait (); // set server offline loginDatabase.PExecute("UPDATE realmlist SET color = 2 WHERE id = '%d'",realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); rar_thread.wait (); ///- Clean database before leaving clearOnlineAccounts(); ///- Wait for delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); loginDatabase.HaltDelayThread(); sLog.outString( "Halting process..." ); if (cliThread) { #ifdef WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module UnloadScriptingModule(); // Exit the process with specified return value return World::GetExitCode(); }
/// Initialize connection to the databases bool Master::_StartDB() { sLog.SetLogDB(false); std::string dbstring; ///- Get world database info from configuration file dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", ""); if(dbstring.empty()) { sLog.outError("Database not specified in configuration file"); return false; } ///- Initialise the world database if(!WorldDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to world database %s",dbstring.c_str()); return false; } ///- Get character database info from configuration file dbstring = sConfig.GetStringDefault("CharacterDatabaseInfo", ""); if(dbstring.empty()) { sLog.outError("Character Database not specified in configuration file"); return false; } ///- Initialise the Character database if(!CharacterDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to Character database %s",dbstring.c_str()); return false; } ///- Get login database info from configuration file dbstring = sConfig.GetStringDefault("loginDatabaseInfo", ""); if(dbstring.empty()) { sLog.outError("Login database not specified in configuration file"); return false; } ///- Initialise the login database if(!loginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to login database %s",dbstring.c_str()); return false; } ///- Get the realm Id from the configuration file realmID = sConfig.GetIntDefault("RealmID", 0); if(!realmID) { sLog.outError("Realm ID not defined in configuration file"); return false; } sLog.outString("Realm running as realm ID %d", realmID); ///- Initialize the DB logging system if(sConfig.GetBoolDefault("EnableLogDB", false)) { // everything successful - set var to enable DB logging once startup finished. sLog.SetLogDBLater(true); sLog.SetLogDB(false); sLog.SetRealmID(realmID); } else { sLog.SetLogDBLater(false); sLog.SetLogDB(false); sLog.SetRealmID(realmID); } ///- Clean the database before starting clearOnlineAccounts(); ///- Insert version info into DB WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _REVISION); sWorld.LoadDBVersion(); sLog.outString("Using World DB: %s", sWorld.GetDBVersion()); sLog.outString("Using creature EventAI: %s", sWorld.GetCreatureEventAIVersion()); return true; }
void Master::_StopDB() { clearOnlineAccounts(); }
// Initialize connection to the databases bool Master::_StartDB() { sLog.SetLogDB(false); // Get world database info from configuration file std::string dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", ""); if (dbstring.empty()) { sLog.outError("World database not specified in configuration file"); sleep(10); return false; } // Initialise the world database if (!WorldDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to world database %s",dbstring.c_str()); sleep(10); return false; } // Get character database info from configuration file dbstring = sConfig.GetStringDefault("CharacterDatabaseInfo", ""); if (dbstring.empty()) { sLog.outError("Character database not specified in configuration file"); sleep(10); return false; } // Initialise the Character database if (!CharacterDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to Character database %s",dbstring.c_str()); sleep(10); return false; } // Get login database info from configuration file dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", ""); if (dbstring.empty()) { sLog.outError("Login database not specified in configuration file"); sleep(10); return false; } // Initialise the login database if (!LoginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to login database %s",dbstring.c_str()); sleep(10); return false; } // Get the realm Id from the configuration file realmID = sConfig.GetIntDefault("RealmID", 0); if (!realmID) { sLog.outError("Realm ID not defined in configuration file"); sleep(10); return false; } sLog.outString("Realm running as realm ID %d", realmID); // Initialize the DB logging system sLog.SetLogDBLater(sConfig.GetBoolDefault("EnableLogDB", false)); // set var to enable DB logging once startup finished. sLog.SetLogDB(false); sLog.SetRealmID(realmID); // Clean the database before starting clearOnlineAccounts(); // Insert version info into DB WorldDatabase.PExecute("UPDATE version SET core_version = '%s', core_revision = '%s'", _FULLVERSION, _REVISION); // Check DB version sWorld.LoadDBVersion(); const char* db_version = sWorld.GetDBVersion(); if (strcmp(db_version, _REQ_BDB_VERSION) != 0) { sLog.outError(" WARNING:"); sLog.outError(" Your World DB version: %s is wrong.", db_version); sLog.outError(" Required World DB version: %s", _REQ_BDB_VERSION); sleep(10); return false; } sLog.outString("Using World DB: %s", db_version); return true; }
// Main function int Master::Run() { sLog.outString("%s [core-daemon]", _FULLVERSION); sLog.outString("<Ctrl-C> to stop."); sLog.outString(" "); sLog.outString(" BBBBBB BBB "); sLog.outString(" BBBB:..:::BB BBBBBBBBB "); sLog.outString(" B:::::BBB:::B BB:....:::B "); sLog.outString(" BB:::B BB::B B:::BBBB:::B "); sLog.outString(" B:::B BB:.B B:::B BB.:B "); sLog.outString(" B:::BBB::BBB BB::B BB.B "); sLog.outString(" B.:..BBB....BBB.:.B "); sLog.outString(" B...BB BB..:BB...B "); sLog.outString(" B...B B..:BB...B "); sLog.outString(" B...B B..BBB...B "); sLog.outString(" B...B BB.BBBB...B "); sLog.outString(" B...B BB:.BB B...BB "); sLog.outString(" B: . B. :BB B . B BBB "); sLog.outString(" B: ..:BBBB B: .B BB .B "); sLog.outString(" BBBBB B. :B B.: B "); sLog.outString(" B. :BB BB:BB"); sLog.outString(" BlizzLikeCore 2012(c) BB BBBBBBB B "); sLog.outString(" <blizzlike.servegame.com> BBB. .BB "); sLog.outString(" BBBBBBBB "); sLog.outString(" "); // worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog.outError("Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog.outString("Daemon PID: %u\n", pid); } // Start the databases if (!_StartDB()) return 1; // Initialize the World sWorld.SetInitialWorldSettings(); // Catch termination signals _HookSignals(); // Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set realmbuilds depend on BlizzLikeCore expected builds, and set server online std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%d'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { // Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); // Handle affinity for multiple processors and process priority on Windows #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if (!curAff) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for BlizzLikeCore. Accessible processors bitmask (hex): %x",Aff,appAff); } else { if (SetProcessAffinityMask(hProcess,curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x",curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); if (Prio) { if (SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("BlizzLikeCore process priority class set to HIGH"); else sLog.outError("ERROR: Can't set BlizzLikeCore process priority class."); sLog.outString(); } } #endif // Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) { BCSoapRunnable *runnable = new BCSoapRunnable(); runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } uint32 realCurrTime, realPrevTime; realCurrTime = realPrevTime = getMSTime(); uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); // Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } // Launch the world listener socket uint16 wsport = sWorld.getConfig(CONFIG_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1) { sLog.outError("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait(); // Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } // Stop soap thread if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } // Set server offline in realmlist LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); // Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); rar_thread.wait (); // Clean account database before leaving clearOnlineAccounts(); // Wait for delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString("Halting process..."); if (cliThread) { #ifdef _WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module //UnloadScriptingModule(); // Exit the process with specified return value return World::GetExitCode(); }
/// Initialize connection to the databases bool Master::_StartDB() { ///- Get world database info from configuration file std::string dbstring; if(!sConfig.GetString("WorldDatabaseInfo", &dbstring)) { sLog.outError("Database not specified in configuration file"); return false; } sLog.outString("World Database: %s", dbstring.c_str()); ///- Initialise the world database if(!WorldDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to world database %s",dbstring.c_str()); return false; } if(!sConfig.GetString("CharacterDatabaseInfo", &dbstring)) { sLog.outError("Character Database not specified in configuration file"); return false; } sLog.outString("Character Database: %s", dbstring.c_str()); ///- Initialise the Character database if(!CharacterDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to Character database %s",dbstring.c_str()); return false; } ///- Get login database info from configuration file if(!sConfig.GetString("LoginDatabaseInfo", &dbstring)) { sLog.outError("Login database not specified in configuration file"); return false; } ///- Initialise the login database sLog.outString("Login Database: %s", dbstring.c_str() ); if(!loginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to login database %s",dbstring.c_str()); return false; } ///- Get the realm Id from the configuration file realmID = sConfig.GetIntDefault("RealmID", 0); if(!realmID) { sLog.outError("Realm ID not defined in configuration file"); return false; } sLog.outString("Realm running as realm ID %d", realmID); ///- Clean the database before starting clearOnlineAccounts(); sWorld.LoadDBVersion(); sLog.outString("Using %s", sWorld.GetDBVersion()); return true; }
/// Main function int Master::Run() { /// worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile"); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog.outError("Cannot create PID file %s.\n", pidfile.c_str()); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString("Daemon PID: %u\n", pid); } ///- Start the databases if (!_StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Initialize the World sWorld.SetInitialWorldSettings(); #ifndef _WIN32 detachDaemon(); #endif // server loaded successfully => enable async DB requests // this is done to forbid any async transactions during server startup! CharacterDatabase.AllowAsyncTransactions(); WorldDatabase.AllowAsyncTransactions(); LoginDatabase.AllowAsyncTransactions(); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread MaNGOS::Thread world_thread(new WorldRunnable); world_thread.setPriority(MaNGOS::Priority_Highest); // set realmbuilds depend on mangosd expected builds, and set server online { std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%u'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); } MaNGOS::Thread* cliThread = nullptr; #ifdef _WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new MaNGOS::Thread(new CliRunnable); } ///- Handle affinity for multiple processors and process priority on Windows #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if (!curAff) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for mangosd. Accessible processors bitmask (hex): %x", Aff, appAff); } else { if (SetProcessAffinityMask(hProcess, curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x", curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); // if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/) if (Prio) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog.outString("mangosd process priority class set to HIGH"); else sLog.outError("Can't set mangosd process priority class."); sLog.outString(); } } #endif ///- Start up freeze catcher thread MaNGOS::Thread* freeze_thread = nullptr; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay * 1000); freeze_thread = new MaNGOS::Thread(fdr); freeze_thread->setPriority(MaNGOS::Priority_Highest); } { int32 networkThreadWorker = sConfig.GetIntDefault("Network.Threads", 1); if (networkThreadWorker <= 0) { sLog.outError("Invalid network tread workers setting in mangosd.conf. (%d) should be > 0", networkThreadWorker); networkThreadWorker = 1; } MaNGOS::Listener<WorldSocket> listener(sConfig.GetStringDefault("BindIP", "0.0.0.0"), int32(sWorld.getConfig(CONFIG_UINT32_PORT_WORLD)), networkThreadWorker); std::unique_ptr<MaNGOS::Listener<RASocket>> raListener; if (sConfig.GetBoolDefault("Ra.Enable", false)) raListener.reset(new MaNGOS::Listener<RASocket>(sConfig.GetStringDefault("Ra.IP", "0.0.0.0"), sConfig.GetIntDefault("Ra.Port", 3443), 1)); std::unique_ptr<SOAPThread> soapThread; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) soapThread.reset(new SOAPThread(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878))); // wait for shut down and then let things go out of scope to close them down while (!World::IsStopped()) std::this_thread::sleep_for(std::chrono::seconds(1)); } ///- Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } ///- Set server offline in realmlist LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); ///- Clean account database before leaving clearOnlineAccounts(); // send all still queued mass mails (before DB connections shutdown) sMassMailMgr.Update(true); ///- Wait for DB delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString("Halting process..."); if (cliThread) { #ifdef _WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } // mark this can be killable m_canBeKilled = true; ///- Exit the process with specified return value return World::GetExitCode(); }
int Master::Run() { sLog.outString(" ___ _ _ ___ "); sLog.outString(" / _ \\ | |_ ___ _ __ (_) __ / __| ___ _ _ ___ "); sLog.outString(" / /_\\ \\ | _| / _ \\ | ' \\ | | / _| | (__ / _ \\ | '_| / -_)"); sLog.outString("/_/ \\_\\ \\__| \\___/ |_|_|_| |_| \\__| \\___| \\___/ |_| \\___|"); sLog.outString(""); std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog.outError("Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog.outString("Daemon PID: %u\n", pid); } if (!_StartDB()) return 1; sWorld.SetInitialWorldSettings(); _HookSignals(); ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.PExecute("UPDATE realmlist SET flag = flag & ~(%u), population = 0, gamebuild = '%s' WHERE id = '%d'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { ULONG_PTR curAff = Aff & appAff; if (!curAff) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for OregonCore. Accessible processors bitmask (hex): %x",Aff,appAff); } else { if (SetProcessAffinityMask(hProcess,curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x",curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); if (Prio) { if (SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("OregonCore process priority class set to HIGH"); else sLog.outError("ERROR: Can't set OregonCore process priority class."); sLog.outString(); } } #endif ACE_Based::Thread* soap_thread = NULL; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) { OCSoapRunnable* soapconnectector = new OCSoapRunnable(); soapconnectector->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfig.GetIntDefault("SOAP.Port", 7878))); soap_thread = new ACE_Based::Thread(soapconnectector); } ACE_Based::Thread* freeze_thread = NULL; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } uint16 wsport = sWorld.getConfig(CONFIG_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1) { sLog.outError("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); } sWorldSocketMgr->Wait(); if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } if (soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } LoginDatabase.PExecute("UPDATE realmlist SET flag = flag | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); _UnhookSignals(); world_thread.wait(); rar_thread.wait (); clearOnlineAccounts(); CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString("Halting process..."); if (cliThread) { #ifdef _WIN32 INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } return World::GetExitCode(); }
/// Initialize connection to the databases bool Master::_StartDB() { ///- Get world database info from configuration file std::string dbstring; if(!sConfig.GetString("WorldDatabaseInfo", &dbstring)) { sLog.outError("Database not specified in configuration file"); return false; } sLog.outString("World Database: %s", dbstring.c_str()); ///- Initialise the world database if(!WorldDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to world database %s",dbstring.c_str()); return false; } if(!sConfig.GetString("CharacterDatabaseInfo", &dbstring)) { sLog.outError("Character Database not specified in configuration file"); return false; } sLog.outString("Character Database: %s", dbstring.c_str()); ///- Initialise the Character database if(!CharacterDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to Character database %s",dbstring.c_str()); return false; } ///- Get login database info from configuration file if(!sConfig.GetString("LoginDatabaseInfo", &dbstring)) { sLog.outError("Login database not specified in configuration file"); return false; } ///- Initialise the login database sLog.outString("Login Database: %s", dbstring.c_str() ); if(!loginDatabase.Initialize(dbstring.c_str())) { sLog.outError("Cannot connect to login database %s",dbstring.c_str()); return false; } ///- Get the realm Id from the configuration file realmID = sConfig.GetIntDefault("RealmID", 0); if(!realmID) { sLog.outError("Realm ID not defined in configuration file"); return false; } sLog.outString("Realm running as realm ID %d", realmID); ///- Clean the database before starting clearOnlineAccounts(); QueryResult* result = WorldDatabase.Query("SELECT version FROM db_version LIMIT 1"); if(result) { Field* fields = result->Fetch(); sLog.outString("Using %s", fields[0].GetString()); delete result; } else sLog.outString("Using unknown world database."); return true; }
/// Main function int Master::Run() { /// worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if( !pid ) { sLog.outError( "Cannot create PID file %s.\n", pidfile.c_str() ); Log::WaitBeforeContinueIfNeed(); return 1; } sLog.outString( "Daemon PID: %u\n", pid ); } ///- Start the databases if (!_StartDB()) { Log::WaitBeforeContinueIfNeed(); return 1; } ///- Initialize the World sWorld.SetInitialWorldSettings(); #ifndef WIN32 detachDaemon(); #endif //server loaded successfully => enable async DB requests //this is done to forbid any async transactions during server startup! CharacterDatabase.AllowAsyncTransactions(); WorldDatabase.AllowAsyncTransactions(); LoginDatabase.AllowAsyncTransactions(); ///- Catch termination signals _HookSignals(); ///- Launch WorldRunnable thread ACE_Based::Thread world_thread(new WorldRunnable); world_thread.setPriority(ACE_Based::Highest); // set realmbuilds depend on mangosd expected builds, and set server online { std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%u'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); } ACE_Based::Thread* cliThread = NULL; #ifdef WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { ///- Launch CliRunnable thread cliThread = new ACE_Based::Thread(new CliRunnable); } ACE_Based::Thread* rar_thread = NULL; if(sConfig.GetBoolDefault ("Ra.Enable", false)) { rar_thread = new ACE_Based::Thread(new RARunnable); } ///- Handle affinity for multiple processors and process priority on Windows #ifdef WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if(Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if(GetProcessAffinityMask(hProcess,&appAff,&sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if(!curAff ) { sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for mangosd. Accessible processors bitmask (hex): %x",Aff,appAff); } else { if(SetProcessAffinityMask(hProcess,curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x",curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); // if(Prio && (m_ServiceStatus == -1)/* need set to default process priority class in service mode*/) if(Prio) { if(SetPriorityClass(hProcess,HIGH_PRIORITY_CLASS)) sLog.outString("mangosd process priority class set to HIGH"); else sLog.outError("Can't set mangosd process priority class."); sLog.outString(); } } #endif ///- Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if(sConfig.GetBoolDefault("SOAP.Enabled", false)) { MaNGOSsoapRunnable *runnable = new MaNGOSsoapRunnable(); runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } ///- Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if(uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable *fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay*1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } ///- Launch the world listener socket uint16 wsport = sWorld.getConfig (CONFIG_UINT32_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip) == -1) { sLog.outError ("Failed to start network"); Log::WaitBeforeContinueIfNeed(); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server } sWorldSocketMgr->Wait (); ///- Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->destroy(); delete freeze_thread; } ///- Stop soap thread if(soap_thread) { soap_thread->wait(); soap_thread->destroy(); delete soap_thread; } ///- Set server offline in realmlist LoginDatabase.DirectPExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%u'", REALM_FLAG_OFFLINE, realmID); ///- Remove signal handling before leaving _UnhookSignals(); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master world_thread.wait(); if(rar_thread) { rar_thread->wait(); rar_thread->destroy(); delete rar_thread; } ///- Clean account database before leaving clearOnlineAccounts(); // send all still queued mass mails (before DB connections shutdown) sMassMailMgr.Update(true); ///- Wait for DB delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString( "Halting process..." ); if (cliThread) { #ifdef WIN32 // this only way to terminate CLI thread exist at Win32 (alt. way exist only in Windows Vista API) //_exit(1); // send keyboard input to safely unblock the CLI thread INPUT_RECORD b[5]; HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); b[0].EventType = KEY_EVENT; b[0].Event.KeyEvent.bKeyDown = TRUE; b[0].Event.KeyEvent.uChar.AsciiChar = 'X'; b[0].Event.KeyEvent.wVirtualKeyCode = 'X'; b[0].Event.KeyEvent.wRepeatCount = 1; b[1].EventType = KEY_EVENT; b[1].Event.KeyEvent.bKeyDown = FALSE; b[1].Event.KeyEvent.uChar.AsciiChar = 'X'; b[1].Event.KeyEvent.wVirtualKeyCode = 'X'; b[1].Event.KeyEvent.wRepeatCount = 1; b[2].EventType = KEY_EVENT; b[2].Event.KeyEvent.bKeyDown = TRUE; b[2].Event.KeyEvent.dwControlKeyState = 0; b[2].Event.KeyEvent.uChar.AsciiChar = '\r'; b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[2].Event.KeyEvent.wRepeatCount = 1; b[2].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].EventType = KEY_EVENT; b[3].Event.KeyEvent.bKeyDown = FALSE; b[3].Event.KeyEvent.dwControlKeyState = 0; b[3].Event.KeyEvent.uChar.AsciiChar = '\r'; b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN; b[3].Event.KeyEvent.wVirtualScanCode = 0x1c; b[3].Event.KeyEvent.wRepeatCount = 1; DWORD numb; BOOL ret = WriteConsoleInput(hStdIn, b, 4, &numb); cliThread->wait(); #else cliThread->destroy(); #endif delete cliThread; } ///- Exit the process with specified return value uint8 worldExitCode = World::GetExitCode(); FILE* exitFile = fopen("mangos-exit.log","w"); fprintf(exitFile,"%d\n",worldExitCode); sLog.outString( "\nWorld exit code = %d\n",worldExitCode ); //fprintf(exitFile,"%d",worldExitCode); fflush(exitFile); fclose(exitFile); return worldExitCode; }
/// Initialize connection to the databases bool Master::_StartDB() { ///- Get world database info from configuration file std::string dbstring = sConfig.GetStringDefault("WorldDatabaseInfo", ""); int nConnections = sConfig.GetIntDefault("WorldDatabaseConnections", 1); if(dbstring.empty()) { sLog.outError("Database not specified in configuration file"); return false; } sLog.outString("World Database total connections: %i", nConnections + 1); ///- Initialise the world database if(!WorldDatabase.Initialize(dbstring.c_str(), nConnections)) { sLog.outError("Cannot connect to world database %s",dbstring.c_str()); return false; } if(!WorldDatabase.CheckRequiredField("db_version",REVISION_DB_MANGOS)) { ///- Wait for already started DB delay threads to end WorldDatabase.HaltDelayThread(); return false; } dbstring = sConfig.GetStringDefault("CharacterDatabaseInfo", ""); nConnections = sConfig.GetIntDefault("CharacterDatabaseConnections", 1); if(dbstring.empty()) { sLog.outError("Character Database not specified in configuration file"); ///- Wait for already started DB delay threads to end WorldDatabase.HaltDelayThread(); return false; } sLog.outString("Character Database total connections: %i", nConnections + 1); ///- Initialise the Character database if(!CharacterDatabase.Initialize(dbstring.c_str(), nConnections)) { sLog.outError("Cannot connect to Character database %s",dbstring.c_str()); ///- Wait for already started DB delay threads to end WorldDatabase.HaltDelayThread(); return false; } if(!CharacterDatabase.CheckRequiredField("character_db_version",REVISION_DB_CHARACTERS)) { ///- Wait for already started DB delay threads to end WorldDatabase.HaltDelayThread(); CharacterDatabase.HaltDelayThread(); return false; } ///- Get login database info from configuration file dbstring = sConfig.GetStringDefault("LoginDatabaseInfo", ""); nConnections = sConfig.GetIntDefault("LoginDatabaseConnections", 1); if(dbstring.empty()) { sLog.outError("Login database not specified in configuration file"); ///- Wait for already started DB delay threads to end WorldDatabase.HaltDelayThread(); CharacterDatabase.HaltDelayThread(); return false; } ///- Initialise the login database sLog.outString("Login Database total connections: %i", nConnections + 1); if(!LoginDatabase.Initialize(dbstring.c_str(), nConnections)) { sLog.outError("Cannot connect to login database %s",dbstring.c_str()); ///- Wait for already started DB delay threads to end WorldDatabase.HaltDelayThread(); CharacterDatabase.HaltDelayThread(); return false; } if(!LoginDatabase.CheckRequiredField("realmd_db_version",REVISION_DB_REALMD)) { ///- Wait for already started DB delay threads to end WorldDatabase.HaltDelayThread(); CharacterDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); return false; } ///- Get the realm Id from the configuration file realmID = sConfig.GetIntDefault("RealmID", 0); if(!realmID) { sLog.outError("Realm ID not defined in configuration file"); ///- Wait for already started DB delay threads to end WorldDatabase.HaltDelayThread(); CharacterDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); return false; } sLog.outString("Realm running as realm ID %d", realmID); ///- Clean the database before starting clearOnlineAccounts(); sWorld.LoadDBVersion(); sLog.outString("Using World DB: %s", sWorld.GetDBVersion()); sLog.outString("Using creature EventAI: %s", sWorld.GetCreatureEventAIVersion()); return true; }
// Main function int Master::Run() { int defaultStderr = dup(2); if (sConfig.GetBoolDefault("Console.Enable", true)) sConsole.Initialize(); sConsole.SetLoading(true); sConsole.DrawLogo(); // worldd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if (!pidfile.empty()) { uint32 pid = CreatePIDFile(pidfile); if (!pid) { sLog.outError("Cannot create PID file %s.\n", pidfile.c_str()); return 1; } sLog.outString("Daemon PID: %u\n", pid); } // Start the databases _StartDB(); // Initialize the World sWorld.SetInitialWorldSettings(); // set realmbuilds depend on OregonCore expected builds, and set server online std::string builds = AcceptableClientBuildsListStr(); LoginDatabase.escape_string(builds); LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags & ~(%u), population = 0, realmbuilds = '%s' WHERE id = '%d'", REALM_FLAG_OFFLINE, builds.c_str(), realmID); sConsole.SetLoading(false); // Catch termination signals _HookSignals(); ACE_Based::Thread* cliThread = NULL; #ifdef _WIN32 if (sConfig.GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/) #else if (sConfig.GetBoolDefault("Console.Enable", true)) #endif { // Launch CliRunnable thread cliThread = new ACE_Based::Thread(new Console::CliRunnable); } ACE_Based::Thread rar_thread(new RARunnable); // Handle affinity for multiple processors and process priority on Windows #ifdef _WIN32 { HANDLE hProcess = GetCurrentProcess(); uint32 Aff = sConfig.GetIntDefault("UseProcessors", 0); if (Aff > 0) { ULONG_PTR appAff; ULONG_PTR sysAff; if (GetProcessAffinityMask(hProcess, &appAff, &sysAff)) { ULONG_PTR curAff = Aff & appAff; // remove non accessible processors if (!curAff) sLog.outError("Processors marked in UseProcessors bitmask (hex) %x not accessible for OregonCore. Accessible processors bitmask (hex): %x", Aff, appAff); else { if (SetProcessAffinityMask(hProcess, curAff)) sLog.outString("Using processors (bitmask, hex): %x", curAff); else sLog.outError("Can't set used processors (hex): %x", curAff); } } sLog.outString(); } bool Prio = sConfig.GetBoolDefault("ProcessPriority", false); if (Prio) { if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS)) sLog.outString("OregonCore process priority class set to HIGH"); else sLog.outError("ERROR: Can't set OregonCore process priority class."); sLog.outString(); } } #endif // Start soap serving thread ACE_Based::Thread* soap_thread = NULL; if (sConfig.GetBoolDefault("SOAP.Enabled", false)) { OCSoapRunnable* runnable = new OCSoapRunnable(); runnable->setListenArguments(sConfig.GetStringDefault("SOAP.IP", "127.0.0.1"), sConfig.GetIntDefault("SOAP.Port", 7878)); soap_thread = new ACE_Based::Thread(runnable); } //uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); // Start up freeze catcher thread ACE_Based::Thread* freeze_thread = NULL; if (uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0)) { FreezeDetectorRunnable* fdr = new FreezeDetectorRunnable(); fdr->SetDelayTime(freeze_delay * 1000); freeze_thread = new ACE_Based::Thread(fdr); freeze_thread->setPriority(ACE_Based::Highest); } // Launch the world listener socket uint16 wsport = sWorld.getConfig(CONFIG_PORT_WORLD); std::string bind_ip = sConfig.GetStringDefault ("BindIP", "0.0.0.0"); if (sWorldSocketMgr->StartNetwork (wsport, bind_ip.c_str ()) == -1) { sLog.outError("Failed to start network"); World::StopNow(ERROR_EXIT_CODE); // go down and shutdown the server // give other threads a chance to start-up so we can shutdown them safely ACE_Based::Thread::Sleep(1500); } /* Run our World, we use main thread for this, because it we need the highest priority possible */ WorldRunnable().run(); // Stop freeze protection before shutdown tasks if (freeze_thread) { freeze_thread->kill(-1); // destroy freeze_thread->wait(); delete freeze_thread; } sWorldSocketMgr->Wait(); // Stop soap thread if (soap_thread) { soap_thread->wait(); delete soap_thread; } // Set server offline in realmlist LoginDatabase.PExecute("UPDATE realmlist SET realmflags = realmflags | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, realmID); // when the main thread closes the singletons get unloaded // since worldrunnable uses them, it will crash if unloaded after master rar_thread.wait (); // Clean account database before leaving clearOnlineAccounts(); // Wait for delay threads to end CharacterDatabase.HaltDelayThread(); WorldDatabase.HaltDelayThread(); LoginDatabase.HaltDelayThread(); sLog.outString("Halting process..."); if (cliThread) { cliThread->kill(SIGINT); cliThread->wait(); delete cliThread; } // we've been messing up with stderr (if Console.Enable was set), // so we need to restore it back, to prevent SIGPIPEs after restart dup2(defaultStderr, 2); close(defaultStderr); // Remove signal handling before leaving _UnhookSignals(); // for some unknown reason, unloading scripts here and not in worldrunnable // fixes a memory leak related to detaching threads from the module //UnloadScriptingModule(); // Exit the process with specified return value return World::GetExitCode(); }