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)
 
AsyncAcceptorStartRaSocketAcceptor (Acore::Asio::IoContext &ioContext)
 
void ShutdownCLIThread (std::thread *cliThread)
 
void AuctionListingRunnable ()
 
void ShutdownAuctionListingThread (std::thread *thread)
 
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
 
Acore::Asio::DeadlineTimer 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

◆ AuctionListingRunnable()

void AuctionListingRunnable ( )

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

715{
716 LOG_INFO("server", "Starting up Auction House Listing thread...");
717
718 while (!World::IsStopped())
719 {
721 {
724
726 {
727 std::lock_guard<std::mutex> guard(AsyncAuctionListingMgr::GetLock());
728
729 {
730 std::lock_guard<std::mutex> guard(AsyncAuctionListingMgr::GetTempLock());
731
732 for (auto const& delayEvent : AsyncAuctionListingMgr::GetTempList())
733 AsyncAuctionListingMgr::GetList().emplace_back(delayEvent);
734
736 }
737
738 for (auto& itr : AsyncAuctionListingMgr::GetList())
739 {
740 if (itr._msTimer <= diff)
741 itr._msTimer = 0;
742 else
743 itr._msTimer -= diff;
744 }
745
746 for (std::list<AuctionListItemsDelayEvent>::iterator itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr)
747 {
748 if ((*itr)._msTimer != 0)
749 continue;
750
751 if ((*itr).Execute())
753
754 break;
755 }
756 }
757 }
758 std::this_thread::sleep_for(1ms);
759 }
760
761 LOG_INFO("server", "Auction House Listing thread exiting without problems.");
762}
std::uint32_t uint32
Definition: Define.h:108
#define LOG_INFO(filterType__,...)
Definition: Log.h:167
static std::mutex & GetTempLock()
Definition: AsyncAuctionListing.h:79
static std::mutex & GetLock()
Definition: AsyncAuctionListing.h:78
static void ResetDiff()
Definition: AsyncAuctionListing.h:72
static uint32 GetDiff()
Definition: AsyncAuctionListing.h:71
static std::list< AuctionListItemsDelayEvent > & GetTempList()
Definition: AsyncAuctionListing.h:77
static bool IsAuctionListingAllowed()
Definition: AsyncAuctionListing.h:73
static std::list< AuctionListItemsDelayEvent > & GetList()
Definition: AsyncAuctionListing.h:76
static bool IsStopped()
Definition: World.h:260

References AsyncAuctionListingMgr::GetDiff(), AsyncAuctionListingMgr::GetList(), AsyncAuctionListingMgr::GetLock(), AsyncAuctionListingMgr::GetTempList(), AsyncAuctionListingMgr::GetTempLock(), AsyncAuctionListingMgr::IsAuctionListingAllowed(), World::IsStopped(), LOG_INFO, and AsyncAuctionListingMgr::ResetDiff().

Referenced by main().

◆ ClearOnlineAccounts()

void ClearOnlineAccounts ( )

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

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

493{
494 // Reset online status for all accounts with characters on the current realm
495 // pussywizard: tc query would set online=0 even if logged in on another realm >_>
496 LoginDatabase.DirectExecute("UPDATE account SET online = 0 WHERE online = {}", realm.Id.Realm);
497
498 // Reset online status for all characters
499 CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
500}
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:113
uint32 Realm
Definition: Realm.h:42
RealmHandle Id
Definition: Realm.h:68

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

Referenced by main(), and StartDB().

◆ CliThread()

void CliThread ( )

#include <D:/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
110{
111#if AC_PLATFORM == AC_PLATFORM_WINDOWS
112 // print this here the first time
113 // later it will be printed after command queue updates
115#else
116 ::rl_attempted_completion_function = &Acore::Impl::Readline::cli_completion;
117 {
118 static char BLANK = '\0';
119 ::rl_completer_word_break_characters = &BLANK;
120 }
121 ::rl_event_hook = &Acore::Impl::Readline::cli_hook_func;
122#endif
123
124 if (sConfigMgr->GetOption<bool>("BeepAtStart", true))
125 printf("\a"); // \a = Alert
126
127#if AC_PLATFORM == AC_PLATFORM_WINDOWS
128 if (sConfigMgr->GetOption<bool>("FlashAtStart", true))
129 {
130 FLASHWINFO fInfo;
131 fInfo.cbSize = sizeof(FLASHWINFO);
132 fInfo.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
133 fInfo.hwnd = GetConsoleWindow();
134 fInfo.uCount = 0;
135 fInfo.dwTimeout = 0;
136 FlashWindowEx(&fInfo);
137 }
138#endif
139
141 while (!World::IsStopped())
142 {
143 fflush(stdout);
144
145 std::string command;
146
147#if AC_PLATFORM == AC_PLATFORM_WINDOWS
148 wchar_t commandbuf[256];
149 if (fgetws(commandbuf, sizeof(commandbuf), stdin))
150 {
151 if (!WStrToUtf8(commandbuf, wcslen(commandbuf), command))
152 {
154 continue;
155 }
156 }
157#else
158 char* command_str = readline(CLI_PREFIX);
159 ::rl_bind_key('\t', ::rl_complete);
160 if (command_str != nullptr)
161 {
162 command = command_str;
163 free(command_str);
164 }
165#endif
166
167 if (!command.empty())
168 {
169 std::size_t nextLineIndex = command.find_first_of("\r\n");
170 if (nextLineIndex != std::string::npos)
171 {
172 if (nextLineIndex == 0)
173 {
174#if AC_PLATFORM == AC_PLATFORM_WINDOWS
176#endif
177 continue;
178 }
179
180 command.erase(nextLineIndex);
181 }
182
183 fflush(stdout);
184 sWorld->QueueCliCommand(new CliCommandHolder(nullptr, command.c_str(), &utf8print, &commandFinished));
185#if AC_PLATFORM != AC_PLATFORM_WINDOWS
186 add_history(command.c_str());
187#endif
188 }
189 else if (feof(stdin))
190 {
192 }
193 }
194}
#define sConfigMgr
Definition: Config.h:92
bool WStrToUtf8(wchar_t const *wstr, size_t size, std::string &utf8str)
Definition: Util.cpp:334
static void PrintCliPrefix()
Definition: CliRunnable.cpp:39
static constexpr char CLI_PREFIX[]
Definition: CliRunnable.cpp:37
void utf8print(void *, std::string_view str)
Definition: CliRunnable.cpp:75
void commandFinished(void *, bool)
Definition: CliRunnable.cpp:87
#define sWorld
Definition: World.h:449
@ SHUTDOWN_EXIT_CODE
Definition: World.h:54
Storage class for commands issued for delayed execution.
Definition: IWorld.h:39
static void StopNow(uint8 exitcode)
Definition: World.h:259

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

Referenced by main().

◆ commandFinished()

void commandFinished ( void *  ,
bool   
)

◆ FreezeDetector()

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

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

91 : _timer(ioContext), _worldLoopCounter(0), _lastChangeMsTime(getMSTime()), _maxCoreStuckTimeInMs(maxCoreStuckTime) { }
uint32 getMSTime()
Definition: Timer.h:103
uint32 _lastChangeMsTime
Definition: Main.cpp:104
uint32 _worldLoopCounter
Definition: Main.cpp:103
Acore::Asio::DeadlineTimer _timer
Definition: Main.cpp:102
uint32 _maxCoreStuckTimeInMs
Definition: Main.cpp:105

◆ GetConsoleArguments()

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

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

774{
775 options_description all("Allowed options");
776 all.add_options()
777 ("help,h", "print usage message")
778 ("version,v", "print version build info")
779 ("dry-run,d", "Dry run")
780 ("config,c", value<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use <arg> as configuration file");
781
782#if AC_PLATFORM == WARHEAD_PLATFORM_WINDOWS
783 options_description win("Windows platform specific options");
784 win.add_options()
785 ("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]");
786
787 all.add(win);
788#endif
789
790 variables_map vm;
791
792 try
793 {
794 store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), vm);
795 notify(vm);
796 }
797 catch (std::exception const& e)
798 {
799 std::cerr << e.what() << "\n";
800 }
801
802 if (vm.count("help"))
803 {
804 std::cout << all << "\n";
805 }
806 else if (vm.count("dry-run"))
807 {
808 sConfigMgr->setDryRun(true);
809 }
810
811 return vm;
812}
#define _ACORE_CORE_CONFIG
Definition: Main.cpp:81

References _ACORE_CORE_CONFIG, and sConfigMgr.

Referenced by main().

◆ Handler()

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

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

619{
620 if (!error)
621 {
622 if (std::shared_ptr<FreezeDetector> freezeDetector = freezeDetectorRef.lock())
623 {
624 uint32 curtime = getMSTime();
625
626 uint32 worldLoopCounter = World::m_worldLoopCounter;
627 if (freezeDetector->_worldLoopCounter != worldLoopCounter)
628 {
629 freezeDetector->_lastChangeMsTime = curtime;
630 freezeDetector->_worldLoopCounter = worldLoopCounter;
631 }
632 // possible freeze
633 else
634 {
635 uint32 msTimeDiff = getMSTimeDiff(freezeDetector->_lastChangeMsTime, curtime);
636 if (msTimeDiff > freezeDetector->_maxCoreStuckTimeInMs)
637 {
638 LOG_ERROR("server.worldserver", "World Thread hangs for {} ms, forcing a crash!", msTimeDiff);
639 ABORT("World Thread hangs for {} ms, forcing a crash!", msTimeDiff);
640 }
641 }
642
643 freezeDetector->_timer.expires_from_now(boost::posix_time::seconds(1));
644 freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, freezeDetectorRef, std::placeholders::_1));
645 }
646 }
647}
#define ABORT
Definition: Errors.h:76
#define LOG_ERROR(filterType__,...)
Definition: Log.h:159
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition: Timer.h:110
static void Handler(std::weak_ptr< FreezeDetector > freezeDetectorRef, boost::system::error_code const &error)
Definition: Main.cpp:618
static uint32 m_worldLoopCounter
Definition: World.h:158

References ABORT, 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 <D:/azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

667{
668 QueryResult result = LoginDatabase.Query("SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE id = {}", realm.Id.Realm);
669 if (!result)
670 return false;
671
672 Acore::Asio::Resolver resolver(ioContext);
673
674 Field* fields = result->Fetch();
675 realm.Name = fields[1].Get<std::string>();
676
677 Optional<boost::asio::ip::tcp::endpoint> externalAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[2].Get<std::string>(), "");
678 if (!externalAddress)
679 {
680 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[2].Get<std::string>());
681 return false;
682 }
683
684 realm.ExternalAddress = std::make_unique<boost::asio::ip::address>(externalAddress->address());
685
686 Optional<boost::asio::ip::tcp::endpoint> localAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[3].Get<std::string>(), "");
687 if (!localAddress)
688 {
689 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[3].Get<std::string>());
690 return false;
691 }
692
693 realm.LocalAddress = std::make_unique<boost::asio::ip::address>(localAddress->address());
694
695 Optional<boost::asio::ip::tcp::endpoint> localSubmask = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[4].Get<std::string>(), "");
696 if (!localSubmask)
697 {
698 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[4].Get<std::string>());
699 return false;
700 }
701
702 realm.LocalSubnetMask = std::make_unique<boost::asio::ip::address>(localSubmask->address());
703
704 realm.Port = fields[5].Get<uint16>();
705 realm.Type = fields[6].Get<uint8>();
706 realm.Flags = RealmFlags(fields[7].Get<uint8>());
707 realm.Timezone = fields[8].Get<uint8>();
708 realm.AllowedSecurityLevel = AccountTypes(fields[9].Get<uint8>());
709 realm.PopulationLevel = fields[10].Get<float>();
710 realm.Build = fields[11].Get<uint32>();
711 return true;
712}
AccountTypes
Definition: Common.h:65
std::uint8_t uint8
Definition: Define.h:110
std::uint16_t uint16
Definition: Define.h:109
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:24
std::shared_ptr< ResultSet > QueryResult
Definition: DatabaseEnvFwd.h:28
RealmFlags
Definition: Realm.h:25
Definition: Resolver.h:32
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:73
RealmFlags Flags
Definition: Realm.h:76
AccountTypes AllowedSecurityLevel
Definition: Realm.h:78
uint8 Timezone
Definition: Realm.h:77
std::unique_ptr< boost::asio::ip::address > LocalSubnetMask
Definition: Realm.h:72
std::unique_ptr< boost::asio::ip::address > LocalAddress
Definition: Realm.h:71
float PopulationLevel
Definition: Realm.h:79
uint32 Build
Definition: Realm.h:69
std::unique_ptr< boost::asio::ip::address > ExternalAddress
Definition: Realm.h:70
std::string Name
Definition: Realm.h:74
uint8 Type
Definition: Realm.h:75

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 <D:/azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

Launch the Azeroth server.

worldserver PID file creation

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

References _ACORE_CORE_CONFIG, Acore::Impl::CurrentServerProcessHolder::_type, Acore::AbortHandler(), ACSoapThread(), AddScripts(), AuctionListingRunnable(), 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(), StopDB(), World::StopNow(), sWorld, sWorldSocketMgr, OpenSSLCrypto::threadsCleanup(), OpenSSLCrypto::threadsSetup(), and WorldUpdateLoop().

◆ PrintCliPrefix()

static void PrintCliPrefix ( )
inlinestatic

◆ ShutdownAuctionListingThread()

void ShutdownAuctionListingThread ( std::thread *  thread)

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

765{
766 if (thread)
767 {
768 thread->join();
769 delete thread;
770 }
771}

◆ ShutdownCLIThread()

void ShutdownCLIThread ( std::thread *  cliThread)

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

503{
504 if (cliThread)
505 {
506#ifdef _WIN32
507 // First try to cancel any I/O in the CLI thread
508 if (!CancelSynchronousIo(cliThread->native_handle()))
509 {
510 // if CancelSynchronousIo() fails, print the error and try with old way
511 DWORD errorCode = GetLastError();
512 LPCSTR errorBuffer;
513
514 DWORD formatReturnCode = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
515 nullptr, errorCode, 0, (LPTSTR)&errorBuffer, 0, nullptr);
516 if (!formatReturnCode)
517 errorBuffer = "Unknown error";
518
519 LOG_DEBUG("server.worldserver", "Error cancelling I/O of CliThread, error code {}, detail: {}", uint32(errorCode), errorBuffer);
520
521 if (!formatReturnCode)
522 LocalFree((LPSTR)errorBuffer);
523
524 // send keyboard input to safely unblock the CLI thread
525 INPUT_RECORD b[4];
526 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
527 b[0].EventType = KEY_EVENT;
528 b[0].Event.KeyEvent.bKeyDown = TRUE;
529 b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
530 b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
531 b[0].Event.KeyEvent.wRepeatCount = 1;
532
533 b[1].EventType = KEY_EVENT;
534 b[1].Event.KeyEvent.bKeyDown = FALSE;
535 b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
536 b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
537 b[1].Event.KeyEvent.wRepeatCount = 1;
538
539 b[2].EventType = KEY_EVENT;
540 b[2].Event.KeyEvent.bKeyDown = TRUE;
541 b[2].Event.KeyEvent.dwControlKeyState = 0;
542 b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
543 b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
544 b[2].Event.KeyEvent.wRepeatCount = 1;
545 b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
546
547 b[3].EventType = KEY_EVENT;
548 b[3].Event.KeyEvent.bKeyDown = FALSE;
549 b[3].Event.KeyEvent.dwControlKeyState = 0;
550 b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
551 b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
552 b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
553 b[3].Event.KeyEvent.wRepeatCount = 1;
554 DWORD numb;
555 WriteConsoleInput(hStdIn, b, 4, &numb);
556 }
557#endif
558 cliThread->join();
559 delete cliThread;
560 }
561}
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:171

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 <D:/azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

94 {
95 freezeDetector->_timer.expires_from_now(boost::posix_time::seconds(5));
96 freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, std::weak_ptr<FreezeDetector>(freezeDetector), std::placeholders::_1));
97 }

References FreezeDetector::Handler().

Referenced by main().

◆ StartDB()

bool StartDB ( )

#include <D:/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
  • Insert version info into DB
433{
435
436 // Load databases
437 DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE, AC_MODULES_LIST);
438 loader
439 .AddDatabase(LoginDatabase, "Login")
440 .AddDatabase(CharacterDatabase, "Character")
441 .AddDatabase(WorldDatabase, "World");
442
443 if (!loader.Load())
444 return false;
445
447 realm.Id.Realm = sConfigMgr->GetOption<uint32>("RealmID", 0);
448 if (!realm.Id.Realm)
449 {
450 LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");
451 return false;
452 }
453 else if (realm.Id.Realm > 255)
454 {
455 /*
456 * Due to the client only being able to read a realm.Id.Realm
457 * with a size of uint8 we can "only" store up to 255 realms
458 * anything further the client will behave anormaly
459 */
460 LOG_ERROR("server.worldserver", "Realm ID must range from 1 to 255");
461 return false;
462 }
463
464 LOG_INFO("server.loading", "Loading World Information...");
465 LOG_INFO("server.loading", "> RealmID: {}", realm.Id.Realm);
466
469
471 WorldDatabase.Execute("UPDATE version SET core_version = '{}', core_revision = '{}'", GitRevision::GetFullVersion(), GitRevision::GetHash()); // One-time query
472
473 sWorld->LoadDBVersion();
474
475 LOG_INFO("server.loading", "> Version DB world: {}", sWorld->GetDBVersion());
476
477 sScriptMgr->OnAfterDatabasesLoaded(loader.GetUpdateFlags());
478
479 return true;
480}
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
AC_COMMON_API char const * GetHash()
Definition: GitRevision.cpp:9
AC_DATABASE_API void Library_Init()
Definition: MySQLThreading.cpp:21
Definition: DatabaseLoader.h:33
@ DATABASE_NONE
Definition: DatabaseLoader.h:46

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

Referenced by main().

◆ StartRaSocketAcceptor()

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

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

650{
651 uint16 raPort = uint16(sConfigMgr->GetOption<int32>("Ra.Port", 3443));
652 std::string raListener = sConfigMgr->GetOption<std::string>("Ra.IP", "0.0.0.0");
653
654 AsyncAcceptor* acceptor = new AsyncAcceptor(ioContext, raListener, raPort);
655 if (!acceptor->Bind())
656 {
657 LOG_ERROR("server.worldserver", "Failed to bind RA socket acceptor");
658 delete acceptor;
659 return nullptr;
660 }
661
662 acceptor->AsyncAccept<RASession>();
663 return acceptor;
664}
Definition: RASession.h:32
Definition: AsyncAcceptor.h:37

References LOG_ERROR, and sConfigMgr.

Referenced by main().

◆ StopDB()

void StopDB ( )

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

483{
484 CharacterDatabase.Close();
485 WorldDatabase.Close();
486 LoginDatabase.Close();
487
489}
AC_DATABASE_API void Library_End()
Definition: MySQLThreading.cpp:26

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

Referenced by main().

◆ utf8print()

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

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

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

Referenced by CliThread().

◆ WorldUpdateLoop()

void WorldUpdateLoop ( )

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

  • While we have not World::m_stopEvent, update the world
564{
565 uint32 minUpdateDiff = uint32(sConfigMgr->GetOption<int32>("MinWorldUpdateTime", 1));
566 uint32 realCurrTime = 0;
567 uint32 realPrevTime = getMSTime();
568
569 uint32 maxCoreStuckTime = uint32(sConfigMgr->GetOption<int32>("MaxCoreStuckTime", 60)) * 1000;
570 uint32 halfMaxCoreStuckTime = maxCoreStuckTime / 2;
571 if (!halfMaxCoreStuckTime)
572 halfMaxCoreStuckTime = std::numeric_limits<uint32>::max();
573
574 LoginDatabase.WarnAboutSyncQueries(true);
575 CharacterDatabase.WarnAboutSyncQueries(true);
576 WorldDatabase.WarnAboutSyncQueries(true);
577
579 while (!World::IsStopped())
580 {
582 realCurrTime = getMSTime();
583
584 uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
585 if (diff < minUpdateDiff)
586 {
587 uint32 sleepTime = minUpdateDiff - diff;
588 if (sleepTime >= halfMaxCoreStuckTime)
589 LOG_ERROR("server.worldserver", "WorldUpdateLoop() waiting for {} ms with MaxCoreStuckTime set to {} ms", sleepTime, maxCoreStuckTime);
590 // sleep until enough time passes that we can update all timers
591 std::this_thread::sleep_for(Milliseconds(sleepTime));
592 continue;
593 }
594
595 sWorld->Update(diff);
596 realPrevTime = realCurrTime;
597
598#ifdef _WIN32
599 if (m_ServiceStatus == 0)
601
602 while (m_ServiceStatus == 2)
603 Sleep(1000);
604#endif
605 }
606
607 LoginDatabase.WarnAboutSyncQueries(false);
608 CharacterDatabase.WarnAboutSyncQueries(false);
609 WorldDatabase.WarnAboutSyncQueries(false);
610}
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, World::StopNow(), sWorld, and WorldDatabase.

Referenced by main().

Variable Documentation

◆ _lastChangeMsTime

uint32 FreezeDetector::_lastChangeMsTime
private

◆ _maxCoreStuckTimeInMs

uint32 FreezeDetector::_maxCoreStuckTimeInMs
private

◆ _timer

Acore::Asio::DeadlineTimer 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"