AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
Acore Daemon

Files

file  CliRunnable.cpp
 
file  CliRunnable.h
 
file  Main.cpp
 

Classes

class  FreezeDetector
 

Macros

#define _ACORE_CORE_CONFIG   "worldserver.conf"
 

Functions

static void PrintCliPrefix ()
 
void utf8print (void *, std::string_view str)
 
void commandFinished (void *, bool)
 
void CliThread ()
 Thread start
 
 FreezeDetector::FreezeDetector (Acore::Asio::IoContext &ioContext, uint32 maxCoreStuckTime)
 
static void FreezeDetector::Start (std::shared_ptr< FreezeDetector > const &freezeDetector)
 
static void FreezeDetector::Handler (std::weak_ptr< FreezeDetector > freezeDetectorRef, boost::system::error_code const &error)
 
void SignalHandler (boost::system::error_code const &error, int signalNumber)
 
void ClearOnlineAccounts ()
 Clear 'online' status for all accounts with characters in this realm.
 
bool StartDB ()
 Initialize connection to the databases.
 
void StopDB ()
 
bool LoadRealmInfo (Acore::Asio::IoContext &ioContext)
 
AsyncAcceptor * StartRaSocketAcceptor (Acore::Asio::IoContext &ioContext)
 
void ShutdownCLIThread (std::thread *cliThread)
 
void WorldUpdateLoop ()
 
variables_map GetConsoleArguments (int argc, char **argv, fs::path &configFile, std::string &cfg_service)
 
int main (int argc, char **argv)
 Launch the Azeroth server.
 

Variables

static constexpr char CLI_PREFIX [] = "AC> "
 
char serviceName [] = "worldserver"
 
char serviceLongName [] = "AzerothCore world service"
 
char serviceDescription [] = "AzerothCore World of Warcraft emulator world service"
 
int m_ServiceStatus = -1
 
boost::asio::steady_timer FreezeDetector::_timer
 
uint32 FreezeDetector::_worldLoopCounter
 
uint32 FreezeDetector::_lastChangeMsTime
 
uint32 FreezeDetector::_maxCoreStuckTimeInMs
 

Detailed Description

Macro Definition Documentation

◆ _ACORE_CORE_CONFIG

#define _ACORE_CORE_CONFIG   "worldserver.conf"

Function Documentation

◆ ClearOnlineAccounts()

void ClearOnlineAccounts ( )

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

Clear 'online' status for all accounts with characters in this realm.

515{
516 // Reset online status for all accounts with characters on the current realm
517 // pussywizard: tc query would set online=0 even if logged in on another realm >_>
518 LoginDatabase.DirectExecute("UPDATE account SET online = 0 WHERE online = {}", realm.Id.Realm);
519
520 // Reset online status for all characters
521 CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
522}
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition DatabaseEnv.cpp:22
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition DatabaseEnv.cpp:21
Realm realm
Definition World.cpp:117
uint32 Realm
Definition Realm.h:43
RealmHandle Id
Definition Realm.h:69

References CharacterDatabase, Realm::Id, LoginDatabase, realm, and RealmHandle::Realm.

Referenced by main(), and StartDB().

◆ CliThread()

void CliThread ( )

#include <azerothcore-wotlk/src/server/apps/worldserver/CommandLine/CliRunnable.cpp>

Thread start

Command Line Interface handling thread.

  • As long as the World is running (no World::m_stopEvent), get the command line and handle it
112{
113#if AC_PLATFORM == AC_PLATFORM_WINDOWS
114 // Set console code pages to UTF-8
115 SetConsoleCP(CP_UTF8);
116 SetConsoleOutputCP(CP_UTF8);
117
118 // print this here the first time
119 // later it will be printed after command queue updates
121#else
122 ::rl_attempted_completion_function = &Acore::Impl::Readline::cli_completion;
123 {
124 static char BLANK = '\0';
125 ::rl_completer_word_break_characters = &BLANK;
126 }
127 ::rl_event_hook = &Acore::Impl::Readline::cli_hook_func;
128#endif
129
130 if (sConfigMgr->GetOption<bool>("BeepAtStart", true))
131 printf("\a"); // \a = Alert
132
133#if AC_PLATFORM == AC_PLATFORM_WINDOWS
134 if (sConfigMgr->GetOption<bool>("FlashAtStart", true))
135 {
136 FLASHWINFO fInfo;
137 fInfo.cbSize = sizeof(FLASHWINFO);
138 fInfo.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
139 fInfo.hwnd = GetConsoleWindow();
140 fInfo.uCount = 0;
141 fInfo.dwTimeout = 0;
142 FlashWindowEx(&fInfo);
143 }
144
145 // Get console input handle once for reading commands
146 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
147 if (hStdIn == INVALID_HANDLE_VALUE)
148 {
149 LOG_ERROR("server.worldserver", "Failed to get console input handle");
150 return;
151 }
152#endif
153
155 while (!World::IsStopped())
156 {
157 fflush(stdout);
158
159 std::string command;
160
161#if AC_PLATFORM == AC_PLATFORM_WINDOWS
162
163 static bool checkedConsole = false;
164 static bool isRealConsole = false;
165
166 if (!checkedConsole)
167 {
168 DWORD mode = 0;
169 isRealConsole = GetConsoleMode(hStdIn, &mode);
170 checkedConsole = true;
171 }
172
173 if (isRealConsole)
174 {
175 // ===== Real Windows Console =====
176 wchar_t commandbuf[256];
177 DWORD charsRead = 0;
178
179 if (ReadConsoleW(hStdIn, commandbuf,
180 sizeof(commandbuf) / sizeof(wchar_t) - 1,
181 &charsRead, nullptr))
182 {
183 if (charsRead > 0)
184 {
185 commandbuf[charsRead] = L'\0';
186 if (!WStrToUtf8(commandbuf, charsRead, command))
187 {
189 continue;
190 }
191 }
192 }
193 }
194 else
195 {
196 // ===== Redirected input (pipe) =====
197 if (!std::getline(std::cin, command))
198 {
200 break;
201 }
202 }
203
204#else
205 char* command_str = readline(CLI_PREFIX);
206 ::rl_bind_key('\t', ::rl_complete);
207 if (command_str != nullptr)
208 {
209 command = command_str;
210 free(command_str);
211 }
212#endif
213
214 if (!command.empty())
215 {
216 std::size_t nextLineIndex = command.find_first_of("\r\n");
217 if (nextLineIndex != std::string::npos)
218 {
219 if (nextLineIndex == 0)
220 {
221#if AC_PLATFORM == AC_PLATFORM_WINDOWS
223#endif
224 continue;
225 }
226
227 command.erase(nextLineIndex);
228 }
229
230 fflush(stdout);
231 sWorld->QueueCliCommand(new CliCommandHolder(nullptr, command.c_str(), &utf8print, &commandFinished));
232#if AC_PLATFORM != AC_PLATFORM_WINDOWS
233 add_history(command.c_str());
234#endif
235 }
236 else if (feof(stdin))
237 {
239 }
240 }
241}
#define LOG_ERROR(filterType__,...)
Definition Log.h:145
bool WStrToUtf8(wchar_t const *wstr, std::size_t size, std::string &utf8str)
Definition Util.cpp:333
static void StopNow(uint8 exitcode)
Definition World.h:195
static bool IsStopped()
Definition World.h:196
#define sConfigMgr
Definition Config.h:93
static void PrintCliPrefix()
Definition CliRunnable.cpp:41
static constexpr char CLI_PREFIX[]
Definition CliRunnable.cpp:39
void utf8print(void *, std::string_view str)
Definition CliRunnable.cpp:77
void commandFinished(void *, bool)
Definition CliRunnable.cpp:89
#define sWorld
Definition World.h:337
@ SHUTDOWN_EXIT_CODE
Definition World.h:53
Storage class for commands issued for delayed execution.
Definition IWorld.h:36

References CLI_PREFIX, commandFinished(), World::IsStopped(), LOG_ERROR, PrintCliPrefix(), sConfigMgr, SHUTDOWN_EXIT_CODE, World::StopNow(), sWorld, utf8print(), and WStrToUtf8().

Referenced by main().

◆ commandFinished()

void commandFinished ( void *  ,
bool   
)

#include <azerothcore-wotlk/src/server/apps/worldserver/CommandLine/CliRunnable.cpp>

90{
92 fflush(stdout);
93}

References PrintCliPrefix().

Referenced by CliThread().

◆ FreezeDetector()

FreezeDetector::FreezeDetector ( Acore::Asio::IoContext &  ioContext,
uint32  maxCoreStuckTime 
)
inline

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

94 : _timer(ioContext), _worldLoopCounter(0), _lastChangeMsTime(getMSTime()), _maxCoreStuckTimeInMs(maxCoreStuckTime) { }
uint32 getMSTime()
Definition Timer.h:103
uint32 _lastChangeMsTime
Definition Main.cpp:107
uint32 _worldLoopCounter
Definition Main.cpp:106
boost::asio::steady_timer _timer
Definition Main.cpp:105
uint32 _maxCoreStuckTimeInMs
Definition Main.cpp:108

◆ GetConsoleArguments()

variables_map GetConsoleArguments ( int  argc,
char **  argv,
fs::path &  configFile,
std::string &  cfg_service 
)

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

741{
742 options_description all("Allowed options");
743 all.add_options()
744 ("help,h", "print usage message")
745 ("version,v", "print version build info")
746 ("dry-run,d", "Dry run")
747 ("config,c", value<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use <arg> as configuration file")
748 ("config-policy", value<std::string>()->value_name("policy"), "override config severity policy (e.g. default=skip,critical_option=fatal)");
749
750#if AC_PLATFORM == AC_PLATFORM_WINDOWS
751 options_description win("Windows platform specific options");
752 win.add_options()
753 ("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]");
754
755 all.add(win);
756#endif
757
758 variables_map vm;
759
760 try
761 {
762 store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), vm);
763 notify(vm);
764 }
765 catch (std::exception const& e)
766 {
767 std::cerr << e.what() << "\n";
768 }
769
770 if (vm.count("help"))
771 std::cout << all << "\n";
772 else if (vm.count("version"))
773 std::cout << GitRevision::GetFullVersion() << "\n";
774 else if (vm.count("dry-run"))
775 sConfigMgr->setDryRun(true);
776
777 return vm;
778}
#define _ACORE_CORE_CONFIG
Definition Main.cpp:84
AC_COMMON_API char const * GetFullVersion()
Definition GitRevision.cpp:82

References _ACORE_CORE_CONFIG, GitRevision::GetFullVersion(), and sConfigMgr.

Referenced by main().

◆ Handler()

void FreezeDetector::Handler ( std::weak_ptr< FreezeDetector >  freezeDetectorRef,
boost::system::error_code const &  error 
)
static

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

645{
646 if (!error)
647 {
648 if (std::shared_ptr<FreezeDetector> freezeDetector = freezeDetectorRef.lock())
649 {
650 uint32 curtime = getMSTime();
651
652 uint32 worldLoopCounter = World::m_worldLoopCounter;
653 if (freezeDetector->_worldLoopCounter != worldLoopCounter)
654 {
655 freezeDetector->_lastChangeMsTime = curtime;
656 freezeDetector->_worldLoopCounter = worldLoopCounter;
657 }
658 // possible freeze
659 else
660 {
661 uint32 msTimeDiff = getMSTimeDiff(freezeDetector->_lastChangeMsTime, curtime);
662 if (msTimeDiff > freezeDetector->_maxCoreStuckTimeInMs)
663 {
664 LOG_ERROR("server.worldserver", "World Thread hangs for {} ms, forcing a crash!", msTimeDiff);
665 ABORT("World Thread hangs for {} ms, forcing a crash!", msTimeDiff);
666 }
667 }
668
669 freezeDetector->_timer.expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(1));
670 freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, freezeDetectorRef, std::placeholders::_1));
671 }
672 }
673}
std::uint32_t uint32
Definition Define.h:107
#define ABORT
Definition Errors.h:76
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition Timer.h:110
static uint32 m_worldLoopCounter
Definition World.h:149
static void Handler(std::weak_ptr< FreezeDetector > freezeDetectorRef, boost::system::error_code const &error)
Definition Main.cpp:644
auto GetExpirationTime(int32 seconds)
Definition SteadyTimer.h:25

References ABORT, Acore::Asio::SteadyTimer::GetExpirationTime(), getMSTime(), getMSTimeDiff(), FreezeDetector::Handler(), LOG_ERROR, and World::m_worldLoopCounter.

Referenced by FreezeDetector::Handler(), and FreezeDetector::Start().

◆ LoadRealmInfo()

bool LoadRealmInfo ( Acore::Asio::IoContext &  ioContext)

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

693{
694 QueryResult result = LoginDatabase.Query("SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE id = {}", realm.Id.Realm);
695 if (!result)
696 return false;
697
698 Acore::Asio::Resolver resolver(ioContext);
699
700 Field* fields = result->Fetch();
701 realm.Name = fields[1].Get<std::string>();
702
703 Optional<boost::asio::ip::tcp::endpoint> externalAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[2].Get<std::string>(), "");
704 if (!externalAddress)
705 {
706 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[2].Get<std::string>());
707 return false;
708 }
709
710 realm.ExternalAddress = std::make_unique<boost::asio::ip::address>(externalAddress->address());
711
712 Optional<boost::asio::ip::tcp::endpoint> localAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[3].Get<std::string>(), "");
713 if (!localAddress)
714 {
715 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[3].Get<std::string>());
716 return false;
717 }
718
719 realm.LocalAddress = std::make_unique<boost::asio::ip::address>(localAddress->address());
720
721 Optional<boost::asio::ip::tcp::endpoint> localSubmask = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[4].Get<std::string>(), "");
722 if (!localSubmask)
723 {
724 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[4].Get<std::string>());
725 return false;
726 }
727
728 realm.LocalSubnetMask = std::make_unique<boost::asio::ip::address>(localSubmask->address());
729
730 realm.Port = fields[5].Get<uint16>();
731 realm.Type = fields[6].Get<uint8>();
732 realm.Flags = RealmFlags(fields[7].Get<uint8>());
733 realm.Timezone = fields[8].Get<uint8>();
734 realm.AllowedSecurityLevel = AccountTypes(fields[9].Get<uint8>());
735 realm.PopulationLevel = fields[10].Get<float>();
736 realm.Build = fields[11].Get<uint32>();
737 return true;
738}
AccountTypes
Definition Common.h:56
std::shared_ptr< ResultSet > QueryResult
Definition DatabaseEnvFwd.h:27
std::uint8_t uint8
Definition Define.h:109
std::uint16_t uint16
Definition Define.h:108
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:24
RealmFlags
Definition Realm.h:26
Definition Resolver.h:31
Class used to access individual fields of database query result.
Definition Field.h:99
std::enable_if_t< std::is_arithmetic_v< T >, T > Get() const
Definition Field.h:113
uint16 Port
Definition Realm.h:74
RealmFlags Flags
Definition Realm.h:77
AccountTypes AllowedSecurityLevel
Definition Realm.h:79
uint8 Timezone
Definition Realm.h:78
std::unique_ptr< boost::asio::ip::address > LocalSubnetMask
Definition Realm.h:73
std::unique_ptr< boost::asio::ip::address > LocalAddress
Definition Realm.h:72
float PopulationLevel
Definition Realm.h:80
uint32 Build
Definition Realm.h:70
std::unique_ptr< boost::asio::ip::address > ExternalAddress
Definition Realm.h:71
std::string Name
Definition Realm.h:75
uint8 Type
Definition Realm.h:76

References Realm::AllowedSecurityLevel, Realm::Build, Realm::ExternalAddress, Realm::Flags, Field::Get(), Realm::Id, Realm::LocalAddress, Realm::LocalSubnetMask, LOG_ERROR, LoginDatabase, Realm::Name, Realm::PopulationLevel, Realm::Port, realm, RealmHandle::Realm, Acore::Asio::Resolver::Resolve(), Realm::Timezone, and Realm::Type.

Referenced by main().

◆ main()

int main ( int  argc,
char **  argv 
)

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

Launch the Azeroth server.

worldserver PID file creation

  • Clean database before leaving
123{
125 signal(SIGABRT, &Acore::AbortHandler);
126
127 // Command line parsing
128 auto configFile = fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG));
129 std::string configService;
130 auto vm = GetConsoleArguments(argc, argv, configFile, configService);
131
132 // exit if help or version is enabled
133 if (vm.count("help") || vm.count("version"))
134 return 0;
135
136#if AC_PLATFORM == AC_PLATFORM_WINDOWS
137 if (configService.compare("install") == 0)
138 return WinServiceInstall() == true ? 0 : 1;
139 else if (configService.compare("uninstall") == 0)
140 return WinServiceUninstall() == true ? 0 : 1;
141 else if (configService.compare("run") == 0)
142 WinServiceRun();
143
144 Optional<UINT> newTimerResolution;
145 boost::system::error_code dllError;
146 std::shared_ptr<boost::dll::shared_library> winmm(new boost::dll::shared_library("winmm.dll", dllError, boost::dll::load_mode::search_system_folders), [&](boost::dll::shared_library* lib)
147 {
148 try
149 {
150 if (newTimerResolution)
151 lib->get<decltype(timeEndPeriod)>("timeEndPeriod")(*newTimerResolution);
152 }
153 catch (std::exception const&)
154 {
155 // ignore
156 }
157
158 delete lib;
159 });
160
161 if (winmm->is_loaded())
162 {
163 try
164 {
165 auto timeGetDevCapsPtr = winmm->get<decltype(timeGetDevCaps)>("timeGetDevCaps");
166 // setup timer resolution
167 TIMECAPS timeResolutionLimits;
168 if (timeGetDevCapsPtr(&timeResolutionLimits, sizeof(TIMECAPS)) == TIMERR_NOERROR)
169 {
170 auto timeBeginPeriodPtr = winmm->get<decltype(timeBeginPeriod)>("timeBeginPeriod");
171 newTimerResolution = std::min(std::max(timeResolutionLimits.wPeriodMin, 1u), timeResolutionLimits.wPeriodMax);
172 timeBeginPeriodPtr(*newTimerResolution);
173 }
174 }
175 catch (std::exception const& e)
176 {
177 printf("Failed to initialize timer resolution: %s\n", e.what());
178 }
179 }
180
181#endif
182
183 // Add file and args in config
184 sConfigMgr->Configure(configFile.generic_string(), {argv, argv + argc}, CONFIG_FILE_LIST);
185
186 if (!sConfigMgr->LoadAppConfigs())
187 return 1;
188
189 std::shared_ptr<Acore::Asio::IoContext> ioContext = std::make_shared<Acore::Asio::IoContext>();
190
191 // Init all logs
192 sLog->RegisterAppender<AppenderDB>();
193 // If logs are supposed to be handled async then we need to pass the IoContext into the Log singleton
194 sLog->Initialize(sConfigMgr->GetOption<bool>("Log.Async.Enable", false) ? ioContext.get() : nullptr);
195
196 Acore::Banner::Show("worldserver-daemon",
197 [](std::string_view text)
198 {
199 LOG_INFO("server.worldserver", text);
200 },
201 []()
202 {
203 LOG_INFO("server.worldserver", "> Using configuration file {}", sConfigMgr->GetFilename());
204 LOG_INFO("server.worldserver", "> Using SSL version: {} (library: {})", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
205 LOG_INFO("server.worldserver", "> Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
206 });
207
208 // Cluster.Enabled is known from config here. Fail before DB/network if the
209 // loaded libsidecar is the stub or does not match the headers we built with.
210 if (!sToCloud9Sidecar->CheckLibsidecarAbi())
211 return 1;
212
214
215 std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });
216
217 // Seed the OpenSSL's PRNG here.
218 // That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login
219 BigNumber seed;
220 seed.SetRand(16 * 8);
221
223 std::string pidFile = sConfigMgr->GetOption<std::string>("PidFile", "");
224 if (!pidFile.empty())
225 {
226 if (uint32 pid = CreatePIDFile(pidFile))
227 LOG_ERROR("server", "Daemon PID: {}\n", pid); // outError for red color in console
228 else
229 {
230 LOG_ERROR("server", "Cannot create PID file {} (possible error: permission)\n", pidFile);
231 return 1;
232 }
233 }
234
235 // Set signal handlers (this must be done before starting IoContext threads, because otherwise they would unblock and exit)
236 boost::asio::signal_set signals(*ioContext, SIGINT, SIGTERM);
237#if AC_PLATFORM == AC_PLATFORM_WINDOWS
238 signals.add(SIGBREAK);
239#endif
240 signals.async_wait(SignalHandler);
241
242 // Start the Boost based thread pool
243 int numThreads = sConfigMgr->GetOption<int32>("ThreadPool", 2);
244 std::shared_ptr<std::vector<std::thread>> threadPool(new std::vector<std::thread>(), [ioContext](std::vector<std::thread>* del)
245 {
246 ioContext->stop();
247 for (std::thread& thr : *del)
248 thr.join();
249
250 delete del;
251 });
252
253 if (numThreads <= 0)
254 {
255 LOG_ERROR("server.worldserver", "The number of threads is 0 or less.");
256 return 1;
257 }
258
259 for (int i = 0; i < numThreads; ++i)
260 {
261 threadPool->push_back(std::thread([ioContext]()
262 {
263 ioContext->run();
264 }));
265 }
266
267 // Set process priority according to configuration settings
268 SetProcessPriority("server.worldserver", sConfigMgr->GetOption<int32>(CONFIG_PROCESSOR_AFFINITY, 0), sConfigMgr->GetOption<bool>(CONFIG_HIGH_PRIORITY, true));
269
270 // Loading modules configs before scripts
271 sConfigMgr->LoadModulesConfigs();
272
273 sScriptMgr->SetScriptLoader(AddScripts);
274 sScriptMgr->SetModulesLoader(AddModulesScripts);
275
276 std::shared_ptr<void> sScriptMgrHandle(nullptr, [](void*)
277 {
278 sScriptMgr->Unload();
279 //sScriptReloadMgr->Unload();
280 });
281
282 LOG_INFO("server.loading", "Initializing Scripts...");
283 sScriptMgr->Initialize();
284
285 // Start the databases
286 if (!StartDB())
287 return 1;
288
289 std::shared_ptr<void> dbHandle(nullptr, [](void*) { StopDB(); });
290
291 // Declared right after dbHandle so it runs after every other shutdown step; a crash before this leaves EndTime NULL
292 std::shared_ptr<void> sessionEndHandle(nullptr, [](void*) { sWorld->SaveSessionEnd(true); });
293
294 // set server offline (not connectable)
295 LoginDatabase.DirectExecute("UPDATE realmlist SET flag = (flag & ~{}) | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, REALM_FLAG_VERSION_MISMATCH, realm.Id.Realm);
296
297 LoadRealmInfo(*ioContext);
298
299 sMetric->Initialize(realm.Name, *ioContext, []()
300 {
301 METRIC_VALUE("online_players", sWorldSessionMgr->GetPlayerCount());
302 METRIC_VALUE("db_queue_login", uint64(LoginDatabase.QueueSize()));
303 METRIC_VALUE("db_queue_character", uint64(CharacterDatabase.QueueSize()));
304 METRIC_VALUE("db_queue_world", uint64(WorldDatabase.QueueSize()));
305 });
306
307 METRIC_EVENT("events", "Worldserver started", "");
308
309 std::shared_ptr<void> sMetricHandle(nullptr, [](void*)
310 {
311 METRIC_EVENT("events", "Worldserver shutdown", "");
312 sMetric->Unload();
313 });
314
316
318 sSecretMgr->Initialize();
319 sWorld->SetInitialWorldSettings();
320
321 std::shared_ptr<void> mapManagementHandle(nullptr, [](void*)
322 {
323 // unload battleground templates before different singletons destroyed
324 sBattlegroundMgr->DeleteAllBattlegrounds();
325
326 sOutdoorPvPMgr->Die(); // unload it before MapMgr
327 sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
328
329 sScriptMgr->OnAfterUnloadAllMaps();
330 });
331
332 // Start the Remote Access port (acceptor) if enabled
333 std::unique_ptr<AsyncAcceptor> raAcceptor;
334 if (sConfigMgr->GetOption<bool>("Ra.Enable", false))
335 {
336 raAcceptor.reset(StartRaSocketAcceptor(*ioContext));
337 }
338
339 // Start soap serving thread if enabled
340 std::shared_ptr<std::thread> soapThread;
341 if (sConfigMgr->GetOption<bool>("SOAP.Enabled", false))
342 {
343 soapThread.reset(new std::thread(ACSoapThread, sConfigMgr->GetOption<std::string>("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetOption<int32>("SOAP.Port", 7878))),
344 [](std::thread* thr)
345 {
346 thr->join();
347 delete thr;
348 });
349 }
350
351 // Launch the worldserver listener socket
352 uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
353 std::string worldListener = sConfigMgr->GetOption<std::string>("BindIP", "0.0.0.0");
354
355 int networkThreads = sConfigMgr->GetOption<int32>("Network.Threads", 1);
356
357 if (networkThreads <= 0)
358 {
359 LOG_ERROR("server.worldserver", "Network.Threads must be greater than 0");
361 return 1;
362 }
363
364 if (!sWorldSocketMgr.StartWorldNetwork(*ioContext, worldListener, worldPort, networkThreads))
365 {
366 LOG_ERROR("server.worldserver", "Failed to initialize network");
368 return 1;
369 }
370
371 std::shared_ptr<void> sWorldSocketMgrHandle(nullptr, [](void*)
372 {
373 sWorldSessionMgr->KickAll(); // save and kick all players
374 sWorldSessionMgr->UpdateSessions(1); // real players unload required UpdateSessions call
375
376 sWorldSocketMgr.StopNetwork();
377
379 if (!sToCloud9Sidecar->ClusterModeEnabled())
381 });
382
383 // Set server online (allow connecting now)
384 LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag & ~{}, population = 0 WHERE id = '{}'", REALM_FLAG_VERSION_MISMATCH, realm.Id.Realm);
385 realm.PopulationLevel = 0.0f;
387
388 // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec)
389 std::shared_ptr<FreezeDetector> freezeDetector;
390 if (int32 coreStuckTime = sConfigMgr->GetOption<int32>("MaxCoreStuckTime", 60))
391 {
392 freezeDetector = std::make_shared<FreezeDetector>(*ioContext, coreStuckTime * 1000);
393 FreezeDetector::Start(freezeDetector);
394 LOG_INFO("server.worldserver", "Starting up anti-freeze thread ({} seconds max stuck time)...", coreStuckTime);
395 }
396
397 LOG_INFO("server.worldserver", "{} (worldserver-daemon) ready...", GitRevision::GetFullVersion());
398
399 sScriptMgr->OnStartup();
400
401 // Launch CliRunnable thread
402 std::shared_ptr<std::thread> cliThread;
403#if AC_PLATFORM == AC_PLATFORM_WINDOWS
404 if (sConfigMgr->GetOption<bool>("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
405#else
406 if (sConfigMgr->GetOption<bool>("Console.Enable", true))
407#endif
408 {
409 cliThread.reset(new std::thread(CliThread), &ShutdownCLIThread);
410 }
411
412 sToCloud9Sidecar->Init(worldPort, realm.Id.Realm);
413
415
416 // Shutdown starts here
417 threadPool.reset();
418
419 // Record the shutdown details now so a crash while saving players still reports them.
420 // After threadPool.reset() no signal handler can run StopNow and change the exit code.
421 sWorld->SaveSessionEnd(false);
422
423 sToCloud9Sidecar->Deinit();
424
425 sLog->SetSynchronous();
426
427 sScriptMgr->OnShutdown();
428
429 // set server offline
430 if (!sConfigMgr->GetOption<bool>("Network.UseSocketActivation", false))
431 LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
432
433 LOG_INFO("server.worldserver", "Halting process...");
434
435 // 0 - normal shutdown
436 // 1 - shutdown at error
437 // 2 - restart command used, this code can be used by restarter for restart AzerothCore
438
439 return World::GetExitCode();
440}
void ACSoapThread(std::string const &host, uint16 port)
Definition ACSoap.cpp:26
#define sBattlegroundMgr
Definition BattlegroundMgr.h:190
std::int32_t int32
Definition Define.h:103
#define LOG_INFO(filterType__,...)
Definition Log.h:153
#define sLog
Definition Log.h:127
#define sMapMgr
Definition MapMgr.h:220
#define sMetric
Definition Metric.h:134
#define METRIC_EVENT(category, title, description)
Definition Metric.h:189
#define sOutdoorPvPMgr
Definition OutdoorPvPMgr.h:102
void SetProcessPriority(std::string const &logChannel, uint32 affinity, bool highPriority)
Definition ProcessPriority.cpp:29
#define CONFIG_HIGH_PRIORITY
Definition ProcessPriority.h:25
#define CONFIG_PROCESSOR_AFFINITY
Definition ProcessPriority.h:24
@ REALM_FLAG_OFFLINE
Definition Realm.h:29
@ REALM_FLAG_VERSION_MISMATCH
Definition Realm.h:28
void AddScripts()
Definition WorldMock.h:29
#define sScriptMgr
Definition ScriptMgr.h:769
#define sSecretMgr
Definition SecretMgr.h:72
@ SERVER_PROCESS_WORLDSERVER
Definition SharedDefines.h:3995
#define sToCloud9Sidecar
Definition TC9Sidecar.h:81
uint32 CreatePIDFile(std::string const &filename)
create PID file
Definition Util.cpp:218
@ CONFIG_PORT_WORLD
Definition WorldConfig.h:175
#define sWorldSessionMgr
Definition WorldSessionMgr.h:118
Definition AppenderDB.h:25
Definition BigNumber.h:29
void SetRand(int32 numbits)
Definition BigNumber.cpp:71
static uint8 GetExitCode()
Definition World.h:194
AsyncAcceptor * StartRaSocketAcceptor(Acore::Asio::IoContext &ioContext)
Definition Main.cpp:675
bool StartDB()
Initialize connection to the databases.
Definition Main.cpp:443
void ClearOnlineAccounts()
Clear 'online' status for all accounts with characters in this realm.
Definition Main.cpp:514
void CliThread()
Thread start
Definition CliRunnable.cpp:111
void WorldUpdateLoop()
Definition Main.cpp:585
static void Start(std::shared_ptr< FreezeDetector > const &freezeDetector)
Definition Main.cpp:96
bool LoadRealmInfo(Acore::Asio::IoContext &ioContext)
Definition Main.cpp:692
void StopDB()
Definition Main.cpp:502
void ShutdownCLIThread(std::thread *cliThread)
Definition Main.cpp:524
variables_map GetConsoleArguments(int argc, char **argv, fs::path &configFile, std::string &cfg_service)
Definition Main.cpp:740
int m_ServiceStatus
Definition Main.cpp:77
void SignalHandler(boost::system::error_code const &error, int signalNumber)
Definition Main.cpp:638
#define sWorldSocketMgr
Definition WorldSocketMgr.h:64
@ ERROR_EXIT_CODE
Definition World.h:54
AC_COMMON_API void Show(std::string_view applicationName, void(*log)(std::string_view text), void(*logExtraInfo)())
Definition Banner.cpp:22
AC_COMMON_API void SetEnableModulesList(std::string_view modulesList)
Definition ModuleMgr.cpp:26
AC_COMMON_API void AbortHandler(int sigval)
Definition Errors.cpp:148
AC_COMMON_API void threadsSetup()
Needs to be called before threads using openssl are spawned.
Definition OpenSSLCrypto.cpp:41
AC_COMMON_API void threadsCleanup()
Needs to be called after threads using openssl are despawned.
Definition OpenSSLCrypto.cpp:50
static ServerProcessTypes _type
Definition SharedDefines.h:4019

References _ACORE_CORE_CONFIG, Acore::Impl::CurrentServerProcessHolder::_type, Acore::AbortHandler(), ACSoapThread(), AddScripts(), ClearOnlineAccounts(), CliThread(), CONFIG_HIGH_PRIORITY, CONFIG_PORT_WORLD, CONFIG_PROCESSOR_AFFINITY, CreatePIDFile(), ERROR_EXIT_CODE, Realm::Flags, GetConsoleArguments(), World::GetExitCode(), GitRevision::GetFullVersion(), Realm::Id, LoadRealmInfo(), LOG_ERROR, LOG_INFO, LoginDatabase, m_ServiceStatus, METRIC_EVENT, Realm::Name, Realm::PopulationLevel, realm, RealmHandle::Realm, REALM_FLAG_OFFLINE, REALM_FLAG_VERSION_MISMATCH, sBattlegroundMgr, sConfigMgr, SERVER_PROCESS_WORLDSERVER, Acore::Module::SetEnableModulesList(), SetProcessPriority(), BigNumber::SetRand(), Acore::Banner::Show(), ShutdownCLIThread(), SignalHandler(), sLog, sMapMgr, sMetric, sOutdoorPvPMgr, sScriptMgr, sSecretMgr, FreezeDetector::Start(), StartDB(), StartRaSocketAcceptor(), sToCloud9Sidecar, StopDB(), World::StopNow(), sWorld, sWorldSessionMgr, sWorldSocketMgr, OpenSSLCrypto::threadsCleanup(), OpenSSLCrypto::threadsSetup(), and WorldUpdateLoop().

◆ PrintCliPrefix()

static void PrintCliPrefix ( )
inlinestatic

◆ ShutdownCLIThread()

void ShutdownCLIThread ( std::thread *  cliThread)

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

525{
526 if (cliThread)
527 {
528#ifdef _WIN32
529 // First try to cancel any I/O in the CLI thread
530 if (!CancelSynchronousIo(cliThread->native_handle()))
531 {
532 // if CancelSynchronousIo() fails, print the error and try with old way
533 DWORD errorCode = GetLastError();
534 LPCSTR errorBuffer;
535
536 DWORD formatReturnCode = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
537 nullptr, errorCode, 0, (LPTSTR)&errorBuffer, 0, nullptr);
538 if (!formatReturnCode)
539 errorBuffer = "Unknown error";
540
541 LOG_DEBUG("server.worldserver", "Error cancelling I/O of CliThread, error code {}, detail: {}", uint32(errorCode), errorBuffer);
542
543 if (!formatReturnCode)
544 LocalFree((LPSTR)errorBuffer);
545
546 // send keyboard input to safely unblock the CLI thread
547 INPUT_RECORD b[4];
548 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
549 b[0].EventType = KEY_EVENT;
550 b[0].Event.KeyEvent.bKeyDown = TRUE;
551 b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
552 b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
553 b[0].Event.KeyEvent.wRepeatCount = 1;
554
555 b[1].EventType = KEY_EVENT;
556 b[1].Event.KeyEvent.bKeyDown = FALSE;
557 b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
558 b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
559 b[1].Event.KeyEvent.wRepeatCount = 1;
560
561 b[2].EventType = KEY_EVENT;
562 b[2].Event.KeyEvent.bKeyDown = TRUE;
563 b[2].Event.KeyEvent.dwControlKeyState = 0;
564 b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
565 b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
566 b[2].Event.KeyEvent.wRepeatCount = 1;
567 b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
568
569 b[3].EventType = KEY_EVENT;
570 b[3].Event.KeyEvent.bKeyDown = FALSE;
571 b[3].Event.KeyEvent.dwControlKeyState = 0;
572 b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
573 b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
574 b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
575 b[3].Event.KeyEvent.wRepeatCount = 1;
576 DWORD numb;
577 WriteConsoleInput(hStdIn, b, 4, &numb);
578 }
579#endif
580 cliThread->join();
581 delete cliThread;
582 }
583}
#define LOG_DEBUG(filterType__,...)
Definition Log.h:157

References LOG_DEBUG.

Referenced by main().

◆ SignalHandler()

void SignalHandler ( boost::system::error_code const &  error,
int  signalNumber 
)

◆ Start()

static void FreezeDetector::Start ( std::shared_ptr< FreezeDetector > const &  freezeDetector)
inlinestatic

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

97 {
98 freezeDetector->_timer.expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(5));
99 freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, std::weak_ptr<FreezeDetector>(freezeDetector), std::placeholders::_1));
100 }

References Acore::Asio::SteadyTimer::GetExpirationTime(), and FreezeDetector::Handler().

Referenced by main().

◆ StartDB()

bool StartDB ( )

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

Initialize connection to the databases.

  • Get the realm Id from the configuration file
  • Clean the database before starting. Cluster.Enabled is read from config here because sToCloud9Sidecar->Init() has not run yet; ClusterModeEnabled() would still be the default false.
  • Insert version info into DB
444{
446
447 // Load databases
448 DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_MASK_ALL, AC_MODULES_LIST);
449 loader
450 .AddDatabase(LoginDatabase, "Login")
451 .AddDatabase(CharacterDatabase, "Character")
452 .AddDatabase(WorldDatabase, "World");
453
454 if (!loader.Load())
455 return false;
456
457 if (!sScriptMgr->OnModuleDatabasesLoading())
458 return false;
459
461 realm.Id.Realm = sConfigMgr->GetOption<uint32>("RealmID", 1);
462 if (!realm.Id.Realm)
463 {
464 LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");
465 return false;
466 }
467 else if (realm.Id.Realm > 255)
468 {
469 /*
470 * Due to the client only being able to read a realm.Id.Realm
471 * with a size of uint8 we can "only" store up to 255 realms
472 * anything further the client will behave anormaly
473 */
474 LOG_ERROR("server.worldserver", "Realm ID must range from 1 to 255");
475 return false;
476 }
477
478 LOG_INFO("server.loading", "Loading World Information...");
479 LOG_INFO("server.loading", "> RealmID: {}", realm.Id.Realm);
480
484 if (!sConfigMgr->GetOption<bool>("Cluster.Enabled", false))
486
490 stmt->SetData(1, GitRevision::GetHash());
491 WorldDatabase.Execute(stmt);
492
493 sWorld->LoadDBVersion();
494
495 LOG_INFO("server.loading", "> Version DB world: {}", sWorld->GetDBVersion());
496
497 sScriptMgr->OnAfterDatabasesLoaded(loader.GetUpdateFlags());
498
499 return true;
500}
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition DatabaseEnv.cpp:20
@ WORLD_UPD_VERSION
Definition WorldDatabase.h:120
Definition DatabaseLoader.h:33
@ DATABASE_MASK_ALL
Definition DatabaseLoader.h:52
Acore::Types::is_default< T > SetData(const uint8 index, T value)
Definition PreparedStatement.h:77
Definition PreparedStatement.h:157
AC_COMMON_API char const * GetHash()
Definition GitRevision.cpp:21
AC_DATABASE_API void Library_Init()
Definition MySQLThreading.cpp:21

References DatabaseLoader::AddDatabase(), CharacterDatabase, ClearOnlineAccounts(), DatabaseLoader::DATABASE_MASK_ALL, GitRevision::GetFullVersion(), GitRevision::GetHash(), DatabaseLoader::GetUpdateFlags(), Realm::Id, MySQL::Library_Init(), DatabaseLoader::Load(), LOG_ERROR, LOG_INFO, LoginDatabase, realm, RealmHandle::Realm, sConfigMgr, PreparedStatementBase::SetData(), sScriptMgr, sWorld, WORLD_UPD_VERSION, and WorldDatabase.

Referenced by main().

◆ StartRaSocketAcceptor()

AsyncAcceptor * StartRaSocketAcceptor ( Acore::Asio::IoContext &  ioContext)

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

676{
677 uint16 raPort = uint16(sConfigMgr->GetOption<int32>("Ra.Port", 3443));
678 std::string raListener = sConfigMgr->GetOption<std::string>("Ra.IP", "0.0.0.0");
679
680 AsyncAcceptor* acceptor = new AsyncAcceptor(ioContext, raListener, raPort);
681 if (!acceptor->Bind())
682 {
683 LOG_ERROR("server.worldserver", "Failed to bind RA socket acceptor");
684 delete acceptor;
685 return nullptr;
686 }
687
688 acceptor->AsyncAccept<RASession>();
689 return acceptor;
690}
Definition AsyncAcceptor.h:34
Definition RASession.h:28

References LOG_ERROR, and sConfigMgr.

Referenced by main().

◆ StopDB()

void StopDB ( )

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

503{
504 CharacterDatabase.Close();
505 WorldDatabase.Close();
506 LoginDatabase.Close();
507
508 sScriptMgr->OnModuleDatabasesClosing();
509
511}
AC_DATABASE_API void Library_End()
Definition MySQLThreading.cpp:26

References CharacterDatabase, MySQL::Library_End(), LoginDatabase, sScriptMgr, and WorldDatabase.

Referenced by main().

◆ utf8print()

void utf8print ( void *  ,
std::string_view  str 
)

#include <azerothcore-wotlk/src/server/apps/worldserver/CommandLine/CliRunnable.cpp>

78{
79#if AC_PLATFORM == AC_PLATFORM_WINDOWS
80 fmt::print("{}", str);
81#else
82{
83 fmt::print("{}", str);
84 fflush(stdout);
85}
86#endif
87}

Referenced by CliThread().

◆ WorldUpdateLoop()

void WorldUpdateLoop ( )

#include <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

  • While we have not World::m_stopEvent, update the world
586{
587 uint32 minUpdateDiff = uint32(sConfigMgr->GetOption<int32>("MinWorldUpdateTime", 1));
588 uint32 realCurrTime = 0;
589 uint32 realPrevTime = getMSTime();
590
591 uint32 maxCoreStuckTime = uint32(sConfigMgr->GetOption<int32>("MaxCoreStuckTime", 60)) * 1000;
592 uint32 halfMaxCoreStuckTime = maxCoreStuckTime / 2;
593 if (!halfMaxCoreStuckTime)
594 halfMaxCoreStuckTime = std::numeric_limits<uint32>::max();
595
596 LoginDatabase.WarnAboutSyncQueries(true);
597 CharacterDatabase.WarnAboutSyncQueries(true);
598 WorldDatabase.WarnAboutSyncQueries(true);
599
600 sScriptMgr->OnDatabaseWarnAboutSyncQueries(true);
601
603 while (!World::IsStopped())
604 {
606 realCurrTime = getMSTime();
607
608 uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
609 if (diff < minUpdateDiff)
610 {
611 uint32 sleepTime = minUpdateDiff - diff;
612 if (sleepTime >= halfMaxCoreStuckTime)
613 LOG_ERROR("server.worldserver", "WorldUpdateLoop() waiting for {} ms with MaxCoreStuckTime set to {} ms", sleepTime, maxCoreStuckTime);
614 // sleep until enough time passes that we can update all timers
615 std::this_thread::sleep_for(Milliseconds(sleepTime));
616 continue;
617 }
618
619 sWorld->Update(diff);
620 realPrevTime = realCurrTime;
621
622#ifdef _WIN32
623 if (m_ServiceStatus == 0)
625
626 while (m_ServiceStatus == 2)
627 Sleep(1000);
628#endif
629 }
630
631 sScriptMgr->OnDatabaseWarnAboutSyncQueries(false);
632
633 LoginDatabase.WarnAboutSyncQueries(false);
634 CharacterDatabase.WarnAboutSyncQueries(false);
635 WorldDatabase.WarnAboutSyncQueries(false);
636}
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:27

References CharacterDatabase, getMSTime(), getMSTimeDiff(), World::IsStopped(), LOG_ERROR, LoginDatabase, m_ServiceStatus, World::m_worldLoopCounter, sConfigMgr, SHUTDOWN_EXIT_CODE, sScriptMgr, World::StopNow(), sWorld, and WorldDatabase.

Referenced by main().

Variable Documentation

◆ _lastChangeMsTime

uint32 FreezeDetector::_lastChangeMsTime
private

◆ _maxCoreStuckTimeInMs

uint32 FreezeDetector::_maxCoreStuckTimeInMs
private

◆ _timer

boost::asio::steady_timer FreezeDetector::_timer
private

◆ _worldLoopCounter

uint32 FreezeDetector::_worldLoopCounter
private

◆ CLI_PREFIX

constexpr char CLI_PREFIX[] = "AC> "
staticconstexpr

◆ m_ServiceStatus

int m_ServiceStatus = -1

◆ serviceDescription

char serviceDescription[] = "AzerothCore World of Warcraft emulator world service"

◆ serviceLongName

char serviceLongName[] = "AzerothCore world service"

◆ serviceName

char serviceName[] = "worldserver"