AzeorthCore 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"
 
#define WORLD_SLEEP_CONST   10
 

Functions

static void PrintCliPrefix ()
 
void utf8print (void *, std::string_view str)
 
void commandFinished (void *, bool)
 
void CliThread ()
 Thread start More...
 
 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. More...
 
bool StartDB ()
 Initialize connection to the databases. More...
 
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. More...
 

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"

◆ WORLD_SLEEP_CONST

#define WORLD_SLEEP_CONST   10

Function Documentation

◆ AuctionListingRunnable()

void AuctionListingRunnable ( )

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

664{
665 LOG_INFO("server", "Starting up Auction House Listing thread...");
666
667 while (!World::IsStopped())
668 {
670 {
673
675 {
676 std::lock_guard<std::mutex> guard(AsyncAuctionListingMgr::GetLock());
677
678 {
679 std::lock_guard<std::mutex> guard(AsyncAuctionListingMgr::GetTempLock());
680
681 for (auto const& delayEvent : AsyncAuctionListingMgr::GetTempList())
682 AsyncAuctionListingMgr::GetList().emplace_back(delayEvent);
683
685 }
686
687 for (auto& itr : AsyncAuctionListingMgr::GetList())
688 {
689 if (itr._msTimer <= diff)
690 itr._msTimer = 0;
691 else
692 itr._msTimer -= diff;
693 }
694
695 for (std::list<AuctionListItemsDelayEvent>::iterator itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr)
696 {
697 if ((*itr)._msTimer != 0)
698 continue;
699
700 if ((*itr).Execute())
702
703 break;
704 }
705 }
706 }
707 std::this_thread::sleep_for(1ms);
708 }
709
710 LOG_INFO("server", "Auction House Listing thread exiting without problems.");
711}
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:263

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.

453{
454 // Reset online status for all accounts with characters on the current realm
455 // pussywizard: tc query would set online=0 even if logged in on another realm >_>
456 LoginDatabase.DirectExecute("UPDATE account SET online = 0 WHERE online = {}", realm.Id.Realm);
457
458 // Reset online status for all characters
459 CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
460}
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:112
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.

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:458
@ 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:262

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>

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

◆ 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>

723{
724 options_description all("Allowed options");
725 all.add_options()
726 ("help,h", "print usage message")
727 ("version,v", "print version build info")
728 ("dry-run,d", "Dry run")
729 ("config,c", value<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use <arg> as configuration file");
730
731#if AC_PLATFORM == WARHEAD_PLATFORM_WINDOWS
732 options_description win("Windows platform specific options");
733 win.add_options()
734 ("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]");
735
736 all.add(win);
737#endif
738
739 variables_map vm;
740
741 try
742 {
743 store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), vm);
744 notify(vm);
745 }
746 catch (std::exception const& e)
747 {
748 std::cerr << e.what() << "\n";
749 }
750
751 if (vm.count("help"))
752 {
753 std::cout << all << "\n";
754 }
755 else if (vm.count("dry-run"))
756 {
757 sConfigMgr->setDryRun(true);
758 }
759
760 return vm;
761}
#define _ACORE_CORE_CONFIG
Definition: Main.cpp:78

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>

572{
573 if (!error)
574 {
575 if (std::shared_ptr<FreezeDetector> freezeDetector = freezeDetectorRef.lock())
576 {
577 uint32 curtime = getMSTime();
578
579 uint32 worldLoopCounter = World::m_worldLoopCounter;
580 if (freezeDetector->_worldLoopCounter != worldLoopCounter)
581 {
582 freezeDetector->_lastChangeMsTime = curtime;
583 freezeDetector->_worldLoopCounter = worldLoopCounter;
584 }
585 // possible freeze
586 else if (getMSTimeDiff(freezeDetector->_lastChangeMsTime, curtime) > freezeDetector->_maxCoreStuckTimeInMs)
587 {
588 LOG_ERROR("server.worldserver", "World Thread hangs, kicking out server!");
589 ABORT();
590 }
591
592 freezeDetector->_timer.expires_from_now(boost::posix_time::seconds(1));
593 freezeDetector->_timer.async_wait(std::bind(&FreezeDetector::Handler, freezeDetectorRef, std::placeholders::_1));
594 }
595 }
596}
#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:571
static uint32 m_worldLoopCounter
Definition: World.h:160

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>

616{
617 QueryResult result = LoginDatabase.Query("SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild FROM realmlist WHERE id = {}", realm.Id.Realm);
618 if (!result)
619 return false;
620
621 Acore::Asio::Resolver resolver(ioContext);
622
623 Field* fields = result->Fetch();
624 realm.Name = fields[1].Get<std::string>();
625
626 Optional<boost::asio::ip::tcp::endpoint> externalAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[2].Get<std::string>(), "");
627 if (!externalAddress)
628 {
629 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[2].Get<std::string>());
630 return false;
631 }
632
633 realm.ExternalAddress = std::make_unique<boost::asio::ip::address>(externalAddress->address());
634
635 Optional<boost::asio::ip::tcp::endpoint> localAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[3].Get<std::string>(), "");
636 if (!localAddress)
637 {
638 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[3].Get<std::string>());
639 return false;
640 }
641
642 realm.LocalAddress = std::make_unique<boost::asio::ip::address>(localAddress->address());
643
644 Optional<boost::asio::ip::tcp::endpoint> localSubmask = resolver.Resolve(boost::asio::ip::tcp::v4(), fields[4].Get<std::string>(), "");
645 if (!localSubmask)
646 {
647 LOG_ERROR("server.worldserver", "Could not resolve address {}", fields[4].Get<std::string>());
648 return false;
649 }
650
651 realm.LocalSubnetMask = std::make_unique<boost::asio::ip::address>(localSubmask->address());
652
653 realm.Port = fields[5].Get<uint16>();
654 realm.Type = fields[6].Get<uint8>();
655 realm.Flags = RealmFlags(fields[7].Get<uint8>());
656 realm.Timezone = fields[8].Get<uint8>();
657 realm.AllowedSecurityLevel = AccountTypes(fields[9].Get<uint8>());
658 realm.PopulationLevel = fields[10].Get<float>();
659 realm.Build = fields[11].Get<uint32>();
660 return true;
661}
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
120{
122 signal(SIGABRT, &Acore::AbortHandler);
123
124 // Command line parsing
125 auto configFile = fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG));
126 std::string configService;
127 auto vm = GetConsoleArguments(argc, argv, configFile, configService);
128
129 // exit if help or version is enabled
130 if (vm.count("help"))
131 return 0;
132
133#if AC_PLATFORM == AC_PLATFORM_WINDOWS
134 if (configService.compare("install") == 0)
135 return WinServiceInstall() == true ? 0 : 1;
136 else if (configService.compare("uninstall") == 0)
137 return WinServiceUninstall() == true ? 0 : 1;
138 else if (configService.compare("run") == 0)
139 WinServiceRun();
140#endif
141
142 // Add file and args in config
143 sConfigMgr->Configure(configFile.generic_string(), {argv, argv + argc}, CONFIG_FILE_LIST);
144
145 if (!sConfigMgr->LoadAppConfigs())
146 return 1;
147
148 std::shared_ptr<Acore::Asio::IoContext> ioContext = std::make_shared<Acore::Asio::IoContext>();
149
150 // Init all logs
151 sLog->RegisterAppender<AppenderDB>();
152 // If logs are supposed to be handled async then we need to pass the IoContext into the Log singleton
153 sLog->Initialize(sConfigMgr->GetOption<bool>("Log.Async.Enable", false) ? ioContext.get() : nullptr);
154
155 Acore::Banner::Show("worldserver-daemon",
156 [](std::string_view text)
157 {
158 LOG_INFO("server.worldserver", text);
159 },
160 []()
161 {
162 LOG_INFO("server.worldserver", "> Using configuration file {}", sConfigMgr->GetFilename());
163 LOG_INFO("server.worldserver", "> Using SSL version: {} (library: {})", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
164 LOG_INFO("server.worldserver", "> Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
165 });
166
168
169 std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });
170
171 // Seed the OpenSSL's PRNG here.
172 // That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login
173 BigNumber seed;
174 seed.SetRand(16 * 8);
175
177 std::string pidFile = sConfigMgr->GetOption<std::string>("PidFile", "");
178 if (!pidFile.empty())
179 {
180 if (uint32 pid = CreatePIDFile(pidFile))
181 LOG_ERROR("server", "Daemon PID: {}\n", pid); // outError for red color in console
182 else
183 {
184 LOG_ERROR("server", "Cannot create PID file {} (possible error: permission)\n", pidFile);
185 return 1;
186 }
187 }
188
189 // Set signal handlers (this must be done before starting IoContext threads, because otherwise they would unblock and exit)
190 boost::asio::signal_set signals(*ioContext, SIGINT, SIGTERM);
191#if AC_PLATFORM == AC_PLATFORM_WINDOWS
192 signals.add(SIGBREAK);
193#endif
194 signals.async_wait(SignalHandler);
195
196 // Start the Boost based thread pool
197 int numThreads = sConfigMgr->GetOption<int32>("ThreadPool", 1);
198 std::shared_ptr<std::vector<std::thread>> threadPool(new std::vector<std::thread>(), [ioContext](std::vector<std::thread>* del)
199 {
200 ioContext->stop();
201 for (std::thread& thr : *del)
202 thr.join();
203
204 delete del;
205 });
206
207 if (numThreads < 1)
208 {
209 numThreads = 1;
210 }
211
212 for (int i = 0; i < numThreads; ++i)
213 {
214 threadPool->push_back(std::thread([ioContext]()
215 {
216 ioContext->run();
217 }));
218 }
219
220 // Set process priority according to configuration settings
221 SetProcessPriority("server.worldserver", sConfigMgr->GetOption<int32>(CONFIG_PROCESSOR_AFFINITY, 0), sConfigMgr->GetOption<bool>(CONFIG_HIGH_PRIORITY, false));
222
223 // Loading modules configs before scripts
224 sConfigMgr->LoadModulesConfigs();
225
226 sScriptMgr->SetScriptLoader(AddScripts);
227 sScriptMgr->SetModulesLoader(AddModulesScripts);
228
229 std::shared_ptr<void> sScriptMgrHandle(nullptr, [](void*)
230 {
231 sScriptMgr->Unload();
232 //sScriptReloadMgr->Unload();
233 });
234
235 LOG_INFO("server.loading", "Initializing Scripts...");
236 sScriptMgr->Initialize();
237
238 // Start the databases
239 if (!StartDB())
240 return 1;
241
242 std::shared_ptr<void> dbHandle(nullptr, [](void*) { StopDB(); });
243
244 // set server offline (not connectable)
245 LoginDatabase.DirectExecute("UPDATE realmlist SET flag = (flag & ~{}) | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, REALM_FLAG_VERSION_MISMATCH, realm.Id.Realm);
246
247 LoadRealmInfo(*ioContext);
248
249 sMetric->Initialize(realm.Name, *ioContext, []()
250 {
251 METRIC_VALUE("online_players", sWorld->GetPlayerCount());
252 METRIC_VALUE("db_queue_login", uint64(LoginDatabase.QueueSize()));
253 METRIC_VALUE("db_queue_character", uint64(CharacterDatabase.QueueSize()));
254 METRIC_VALUE("db_queue_world", uint64(WorldDatabase.QueueSize()));
255 });
256
257 METRIC_EVENT("events", "Worldserver started", "");
258
259 std::shared_ptr<void> sMetricHandle(nullptr, [](void*)
260 {
261 METRIC_EVENT("events", "Worldserver shutdown", "");
262 sMetric->Unload();
263 });
264
266
268 sSecretMgr->Initialize();
269 sWorld->SetInitialWorldSettings();
270
271 std::shared_ptr<void> mapManagementHandle(nullptr, [](void*)
272 {
273 // unload battleground templates before different singletons destroyed
274 sBattlegroundMgr->DeleteAllBattlegrounds();
275
276 sOutdoorPvPMgr->Die(); // unload it before MapMgr
277 sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
278
279 sScriptMgr->OnAfterUnloadAllMaps();
280 });
281
282 // Start the Remote Access port (acceptor) if enabled
283 std::unique_ptr<AsyncAcceptor> raAcceptor;
284 if (sConfigMgr->GetOption<bool>("Ra.Enable", false))
285 {
286 raAcceptor.reset(StartRaSocketAcceptor(*ioContext));
287 }
288
289 // Start soap serving thread if enabled
290 std::shared_ptr<std::thread> soapThread;
291 if (sConfigMgr->GetOption<bool>("SOAP.Enabled", false))
292 {
293 soapThread.reset(new std::thread(ACSoapThread, sConfigMgr->GetOption<std::string>("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetOption<int32>("SOAP.Port", 7878))),
294 [](std::thread* thr)
295 {
296 thr->join();
297 delete thr;
298 });
299 }
300
301 // Launch the worldserver listener socket
302 uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
303 std::string worldListener = sConfigMgr->GetOption<std::string>("BindIP", "0.0.0.0");
304
305 int networkThreads = sConfigMgr->GetOption<int32>("Network.Threads", 1);
306
307 if (networkThreads <= 0)
308 {
309 LOG_ERROR("server.worldserver", "Network.Threads must be greater than 0");
311 return 1;
312 }
313
314 if (!sWorldSocketMgr.StartWorldNetwork(*ioContext, worldListener, worldPort, networkThreads))
315 {
316 LOG_ERROR("server.worldserver", "Failed to initialize network");
318 return 1;
319 }
320
321 std::shared_ptr<void> sWorldSocketMgrHandle(nullptr, [](void*)
322 {
323 sWorld->KickAll(); // save and kick all players
324 sWorld->UpdateSessions(1); // real players unload required UpdateSessions call
325
326 sWorldSocketMgr.StopNetwork();
327
330 });
331
332 // Set server online (allow connecting now)
333 LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag & ~{}, population = 0 WHERE id = '{}'", REALM_FLAG_VERSION_MISMATCH, realm.Id.Realm);
334 realm.PopulationLevel = 0.0f;
336
337 // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec)
338 std::shared_ptr<FreezeDetector> freezeDetector;
339 if (int32 coreStuckTime = sConfigMgr->GetOption<int32>("MaxCoreStuckTime", 60))
340 {
341 freezeDetector = std::make_shared<FreezeDetector>(*ioContext, coreStuckTime * 1000);
342 FreezeDetector::Start(freezeDetector);
343 LOG_INFO("server.worldserver", "Starting up anti-freeze thread ({} seconds max stuck time)...", coreStuckTime);
344 }
345
346 LOG_INFO("server.worldserver", "{} (worldserver-daemon) ready...", GitRevision::GetFullVersion());
347
348 sScriptMgr->OnStartup();
349
350 // Launch CliRunnable thread
351 std::shared_ptr<std::thread> cliThread;
352#if AC_PLATFORM == AC_PLATFORM_WINDOWS
353 if (sConfigMgr->GetOption<bool>("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
354#else
355 if (sConfigMgr->GetOption<bool>("Console.Enable", true))
356#endif
357 {
358 cliThread.reset(new std::thread(CliThread), &ShutdownCLIThread);
359 }
360
361 // Launch CliRunnable thread
362 std::shared_ptr<std::thread> auctionLisingThread;
363 auctionLisingThread.reset(new std::thread(AuctionListingRunnable),
364 [](std::thread* thr)
365 {
366 thr->join();
367 delete thr;
368 });
369
371
372 // Shutdown starts here
373 threadPool.reset();
374
375 sLog->SetSynchronous();
376
377 sScriptMgr->OnShutdown();
378
379 // set server offline
380 LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
381
382 LOG_INFO("server.worldserver", "Halting process...");
383
384 // 0 - normal shutdown
385 // 1 - shutdown at error
386 // 2 - restart command used, this code can be used by restarter for restart Warheadd
387
388 return World::GetExitCode();
389}
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:212
#define sOutdoorPvPMgr
Definition: OutdoorPvPMgr.h:106
#define sScriptMgr
Definition: ScriptMgr.h:2690
@ CONFIG_PORT_WORLD
Definition: IWorld.h:220
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:598
bool StartDB()
Initialize connection to the databases.
Definition: Main.cpp:392
void ClearOnlineAccounts()
Clear 'online' status for all accounts with characters in this realm.
Definition: Main.cpp:452
void CliThread()
Thread start
Definition: CliRunnable.cpp:109
void WorldUpdateLoop()
Definition: Main.cpp:523
static void Start(std::shared_ptr< FreezeDetector > const &freezeDetector)
Definition: Main.cpp:91
bool LoadRealmInfo(Acore::Asio::IoContext &ioContext)
Definition: Main.cpp:615
void StopDB()
Definition: Main.cpp:442
void ShutdownCLIThread(std::thread *cliThread)
Definition: Main.cpp:462
variables_map GetConsoleArguments(int argc, char **argv, fs::path &configFile, std::string &cfg_service)
Definition: Main.cpp:722
int m_ServiceStatus
Definition: Main.cpp:74
void SignalHandler(boost::system::error_code const &error, int signalNumber)
Definition: Main.cpp:565
void AuctionListingRunnable()
Definition: Main.cpp:663
#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:27
void threadsSetup()
Definition: OpenSSLCrypto.h:37
void threadsCleanup()
Definition: OpenSSLCrypto.h:38
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:18
void SetRand(int32 numbits)
Definition: BigNumber.cpp:76
Definition: AppenderDB.h:24
static uint8 GetExitCode()
Definition: World.h:261
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>

714{
715 if (thread)
716 {
717 thread->join();
718 delete thread;
719 }
720}

◆ ShutdownCLIThread()

void ShutdownCLIThread ( std::thread *  cliThread)

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

463{
464 if (cliThread)
465 {
466#ifdef _WIN32
467 // First try to cancel any I/O in the CLI thread
468 if (!CancelSynchronousIo(cliThread->native_handle()))
469 {
470 // if CancelSynchronousIo() fails, print the error and try with old way
471 DWORD errorCode = GetLastError();
472 LPCSTR errorBuffer;
473
474 DWORD formatReturnCode = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
475 nullptr, errorCode, 0, (LPTSTR)&errorBuffer, 0, nullptr);
476 if (!formatReturnCode)
477 errorBuffer = "Unknown error";
478
479 LOG_DEBUG("server.worldserver", "Error cancelling I/O of CliThread, error code {}, detail: {}", uint32(errorCode), errorBuffer);
480
481 if (!formatReturnCode)
482 LocalFree((LPSTR)errorBuffer);
483
484 // send keyboard input to safely unblock the CLI thread
485 INPUT_RECORD b[4];
486 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
487 b[0].EventType = KEY_EVENT;
488 b[0].Event.KeyEvent.bKeyDown = TRUE;
489 b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
490 b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
491 b[0].Event.KeyEvent.wRepeatCount = 1;
492
493 b[1].EventType = KEY_EVENT;
494 b[1].Event.KeyEvent.bKeyDown = FALSE;
495 b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
496 b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
497 b[1].Event.KeyEvent.wRepeatCount = 1;
498
499 b[2].EventType = KEY_EVENT;
500 b[2].Event.KeyEvent.bKeyDown = TRUE;
501 b[2].Event.KeyEvent.dwControlKeyState = 0;
502 b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
503 b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
504 b[2].Event.KeyEvent.wRepeatCount = 1;
505 b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
506
507 b[3].EventType = KEY_EVENT;
508 b[3].Event.KeyEvent.bKeyDown = FALSE;
509 b[3].Event.KeyEvent.dwControlKeyState = 0;
510 b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
511 b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
512 b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
513 b[3].Event.KeyEvent.wRepeatCount = 1;
514 DWORD numb;
515 WriteConsoleInput(hStdIn, b, 4, &numb);
516 }
517#endif
518 cliThread->join();
519 delete cliThread;
520 }
521}
#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>

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

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
393{
395
396 // Load databases
397 DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE, AC_MODULES_LIST);
398 loader
399 .AddDatabase(LoginDatabase, "Login")
400 .AddDatabase(CharacterDatabase, "Character")
401 .AddDatabase(WorldDatabase, "World");
402
403 if (!loader.Load())
404 return false;
405
407 realm.Id.Realm = sConfigMgr->GetOption<uint32>("RealmID", 0);
408 if (!realm.Id.Realm)
409 {
410 LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");
411 return false;
412 }
413 else if (realm.Id.Realm > 255)
414 {
415 /*
416 * Due to the client only being able to read a realm.Id.Realm
417 * with a size of uint8 we can "only" store up to 255 realms
418 * anything further the client will behave anormaly
419 */
420 LOG_ERROR("server.worldserver", "Realm ID must range from 1 to 255");
421 return false;
422 }
423
424 LOG_INFO("server.loading", "Loading World Information...");
425 LOG_INFO("server.loading", "> RealmID: {}", realm.Id.Realm);
426
429
431 WorldDatabase.Execute("UPDATE version SET core_version = '{}', core_revision = '{}'", GitRevision::GetFullVersion(), GitRevision::GetHash()); // One-time query
432
433 sWorld->LoadDBVersion();
434
435 LOG_INFO("server.loading", "> Version DB world: {}", sWorld->GetDBVersion());
436
437 sScriptMgr->OnAfterDatabasesLoaded(loader.GetUpdateFlags());
438
439 return true;
440}
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>

599{
600 uint16 raPort = uint16(sConfigMgr->GetOption<int32>("Ra.Port", 3443));
601 std::string raListener = sConfigMgr->GetOption<std::string>("Ra.IP", "0.0.0.0");
602
603 AsyncAcceptor* acceptor = new AsyncAcceptor(ioContext, raListener, raPort);
604 if (!acceptor->Bind())
605 {
606 LOG_ERROR("server.worldserver", "Failed to bind RA socket acceptor");
607 delete acceptor;
608 return nullptr;
609 }
610
611 acceptor->AsyncAccept<RASession>();
612 return acceptor;
613}
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>

443{
444 CharacterDatabase.Close();
445 WorldDatabase.Close();
446 LoginDatabase.Close();
447
449}
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>

524{
525 uint32 realCurrTime = 0;
526 uint32 realPrevTime = getMSTime();
527
528 LoginDatabase.WarnAboutSyncQueries(true);
529 CharacterDatabase.WarnAboutSyncQueries(true);
530 WorldDatabase.WarnAboutSyncQueries(true);
531
533 while (!World::IsStopped())
534 {
536 realCurrTime = getMSTime();
537
538 uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
539
540 sWorld->Update(diff);
541 realPrevTime = realCurrTime;
542
543 uint32 executionTimeDiff = getMSTimeDiff(realCurrTime, getMSTime());
544
545 // we know exactly how long it took to update the world, if the update took less than WORLD_SLEEP_CONST, sleep for WORLD_SLEEP_CONST - world update time
546 if (executionTimeDiff < WORLD_SLEEP_CONST)
547 {
548 std::this_thread::sleep_for(Milliseconds(WORLD_SLEEP_CONST - executionTimeDiff));
549 }
550
551#ifdef _WIN32
552 if (m_ServiceStatus == 0)
554
555 while (m_ServiceStatus == 2)
556 Sleep(1000);
557#endif
558 }
559
560 LoginDatabase.WarnAboutSyncQueries(false);
561 CharacterDatabase.WarnAboutSyncQueries(false);
562 WorldDatabase.WarnAboutSyncQueries(false);
563}
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:27
#define WORLD_SLEEP_CONST
Definition: Main.cpp:81

References CharacterDatabase, getMSTime(), getMSTimeDiff(), World::IsStopped(), LoginDatabase, m_ServiceStatus, World::m_worldLoopCounter, SHUTDOWN_EXIT_CODE, World::StopNow(), sWorld, WORLD_SLEEP_CONST, 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"