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

Function Documentation

◆ AuctionListingRunnable()

void AuctionListingRunnable ( )

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

717{
718 LOG_INFO("server", "Starting up Auction House Listing thread...");
719
720 while (!World::IsStopped())
721 {
724
726 {
727 {
728 std::lock_guard<std::mutex> guard(AsyncAuctionListingMgr::GetTempLock());
729
730 for (auto const& delayEvent: AsyncAuctionListingMgr::GetTempList())
731 AsyncAuctionListingMgr::GetList().emplace_back(delayEvent);
732
734 }
735
736 for (auto& itr: AsyncAuctionListingMgr::GetList())
737 {
738 if (itr._pickupTimer <= diff)
739 {
740 itr._pickupTimer = Milliseconds::zero();
741 }
742 else
743 {
744 itr._pickupTimer -= diff;
745 }
746 }
747
748 for (auto itr = AsyncAuctionListingMgr::GetList().begin(); itr != AsyncAuctionListingMgr::GetList().end(); ++itr)
749 {
750 if ((*itr)._pickupTimer != Milliseconds::zero())
751 continue;
752
753 if ((*itr).Execute())
755
756 break;
757 }
758 }
759 std::this_thread::sleep_for(1ms);
760 }
761
762 LOG_INFO("server", "Auction House Listing thread exiting without problems.");
763}
#define LOG_INFO(filterType__,...)
Definition: Log.h:165
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:27
static std::mutex & GetTempLock()
Definition: AsyncAuctionListing.h:71
static void ResetDiff()
Definition: AsyncAuctionListing.h:68
static Milliseconds GetDiff()
Definition: AsyncAuctionListing.h:67
static std::list< AuctionListItemsDelayEvent > & GetTempList()
Definition: AsyncAuctionListing.h:70
static std::list< AuctionListItemsDelayEvent > & GetList()
Definition: AsyncAuctionListing.h:69
static bool IsStopped()
Definition: World.h:254

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

Referenced by main().

◆ ClearOnlineAccounts()

void ClearOnlineAccounts ( )

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

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

495{
496 // Reset online status for all accounts with characters on the current realm
497 // pussywizard: tc query would set online=0 even if logged in on another realm >_>
498 LoginDatabase.DirectExecute("UPDATE account SET online = 0 WHERE online = {}", realm.Id.Realm);
499
500 // Reset online status for all characters
501 CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
502}
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: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
109{
110#if AC_PLATFORM == AC_PLATFORM_WINDOWS
111 // print this here the first time
112 // later it will be printed after command queue updates
114#else
115 ::rl_attempted_completion_function = &Acore::Impl::Readline::cli_completion;
116 {
117 static char BLANK = '\0';
118 ::rl_completer_word_break_characters = &BLANK;
119 }
120 ::rl_event_hook = &Acore::Impl::Readline::cli_hook_func;
121#endif
122
123 if (sConfigMgr->GetOption<bool>("BeepAtStart", true))
124 printf("\a"); // \a = Alert
125
126#if AC_PLATFORM == AC_PLATFORM_WINDOWS
127 if (sConfigMgr->GetOption<bool>("FlashAtStart", true))
128 {
129 FLASHWINFO fInfo;
130 fInfo.cbSize = sizeof(FLASHWINFO);
131 fInfo.dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG;
132 fInfo.hwnd = GetConsoleWindow();
133 fInfo.uCount = 0;
134 fInfo.dwTimeout = 0;
135 FlashWindowEx(&fInfo);
136 }
137#endif
138
140 while (!World::IsStopped())
141 {
142 fflush(stdout);
143
144 std::string command;
145
146#if AC_PLATFORM == AC_PLATFORM_WINDOWS
147 wchar_t commandbuf[256];
148 if (fgetws(commandbuf, sizeof(commandbuf), stdin))
149 {
150 if (!WStrToUtf8(commandbuf, wcslen(commandbuf), command))
151 {
153 continue;
154 }
155 }
156#else
157 char* command_str = readline(CLI_PREFIX);
158 ::rl_bind_key('\t', ::rl_complete);
159 if (command_str != nullptr)
160 {
161 command = command_str;
162 free(command_str);
163 }
164#endif
165
166 if (!command.empty())
167 {
168 std::size_t nextLineIndex = command.find_first_of("\r\n");
169 if (nextLineIndex != std::string::npos)
170 {
171 if (nextLineIndex == 0)
172 {
173#if AC_PLATFORM == AC_PLATFORM_WINDOWS
175#endif
176 continue;
177 }
178
179 command.erase(nextLineIndex);
180 }
181
182 fflush(stdout);
183 sWorld->QueueCliCommand(new CliCommandHolder(nullptr, command.c_str(), &utf8print, &commandFinished));
184#if AC_PLATFORM != AC_PLATFORM_WINDOWS
185 add_history(command.c_str());
186#endif
187 }
188 else if (feof(stdin))
189 {
191 }
192 }
193}
bool WStrToUtf8(wchar_t const *wstr, std::size_t size, std::string &utf8str)
Definition: Util.cpp:333
#define sConfigMgr
Definition: Config.h:74
static void PrintCliPrefix()
Definition: CliRunnable.cpp:38
static constexpr char CLI_PREFIX[]
Definition: CliRunnable.cpp:36
void utf8print(void *, std::string_view str)
Definition: CliRunnable.cpp:74
void commandFinished(void *, bool)
Definition: CliRunnable.cpp:86
#define sWorld
Definition: World.h:443
@ SHUTDOWN_EXIT_CODE
Definition: World.h:53
Storage class for commands issued for delayed execution.
Definition: IWorld.h:34
static void StopNow(uint8 exitcode)
Definition: World.h:253

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   
)

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

87{
89 fflush(stdout);
90}

References PrintCliPrefix().

Referenced by CliThread().

◆ FreezeDetector()

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

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

766{
767 options_description all("Allowed options");
768 all.add_options()
769 ("help,h", "print usage message")
770 ("version,v", "print version build info")
771 ("dry-run,d", "Dry run")
772 ("config,c", value<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use <arg> as configuration file");
773
774#if AC_PLATFORM == AC_PLATFORM_WINDOWS
775 options_description win("Windows platform specific options");
776 win.add_options()
777 ("service,s", value<std::string>(&configService)->default_value(""), "Windows service options: [install | uninstall]");
778
779 all.add(win);
780#endif
781
782 variables_map vm;
783
784 try
785 {
786 store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), vm);
787 notify(vm);
788 }
789 catch (std::exception const& e)
790 {
791 std::cerr << e.what() << "\n";
792 }
793
794 if (vm.count("help"))
795 {
796 std::cout << all << "\n";
797 }
798 else if (vm.count("dry-run"))
799 {
800 sConfigMgr->setDryRun(true);
801 }
802
803 return vm;
804}
#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 <azerothcore-wotlk/src/server/apps/worldserver/Main.cpp>

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

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

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

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

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

◆ ShutdownCLIThread()

void ShutdownCLIThread ( std::thread *  cliThread)

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

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

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>

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 <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
432{
434
435 // Load databases
436 DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE, AC_MODULES_LIST);
437 loader
438 .AddDatabase(LoginDatabase, "Login")
439 .AddDatabase(CharacterDatabase, "Character")
440 .AddDatabase(WorldDatabase, "World");
441
442 if (!loader.Load())
443 return false;
444
446 realm.Id.Realm = sConfigMgr->GetOption<uint32>("RealmID", 0);
447 if (!realm.Id.Realm)
448 {
449 LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");
450 return false;
451 }
452 else if (realm.Id.Realm > 255)
453 {
454 /*
455 * Due to the client only being able to read a realm.Id.Realm
456 * with a size of uint8 we can "only" store up to 255 realms
457 * anything further the client will behave anormaly
458 */
459 LOG_ERROR("server.worldserver", "Realm ID must range from 1 to 255");
460 return false;
461 }
462
463 LOG_INFO("server.loading", "Loading World Information...");
464 LOG_INFO("server.loading", "> RealmID: {}", realm.Id.Realm);
465
468
472 stmt->SetData(1, GitRevision::GetHash());
473 WorldDatabase.Execute(stmt);
474
475 sWorld->LoadDBVersion();
476
477 LOG_INFO("server.loading", "> Version DB world: {}", sWorld->GetDBVersion());
478
479 sScriptMgr->OnAfterDatabasesLoaded(loader.GetUpdateFlags());
480
481 return true;
482}
@ WORLD_UPD_VERSION
Definition: WorldDatabase.h:103
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
AC_COMMON_API char const * GetHash()
Definition: GitRevision.cpp:21
AC_DATABASE_API void Library_Init()
Definition: MySQLThreading.cpp:21
Definition: PreparedStatement.h:157
Definition: DatabaseLoader.h:33
@ DATABASE_NONE
Definition: DatabaseLoader.h:46
Acore::Types::is_default< T > SetData(const uint8 index, T value)
Definition: PreparedStatement.h:77

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

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

References LOG_ERROR, and sConfigMgr.

Referenced by main().

◆ StopDB()

void StopDB ( )

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

485{
486 CharacterDatabase.Close();
487 WorldDatabase.Close();
488 LoginDatabase.Close();
489
491}
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 <azerothcore-wotlk/src/server/apps/worldserver/CommandLine/CliRunnable.cpp>

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

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

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"