TrinityCore
Main.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
21
22#include "Common.h"
23#include "AppenderDB.h"
24#include "AsyncAcceptor.h"
26#include "Banner.h"
27#include "BattlegroundMgr.h"
28#include "BigNumber.h"
29#include "CliRunnable.h"
31#include "DatabaseEnv.h"
32#include "DatabaseLoader.h"
33#include "DeadlineTimer.h"
34#include "GitRevision.h"
35#include "InstanceLockMgr.h"
36#include "IoContext.h"
37#include "IpNetwork.h"
38#include "Locales.h"
39#include "MapManager.h"
40#include "Metric.h"
41#include "MySQLThreading.h"
42#include "OpenSSLCrypto.h"
44#include "ProcessPriority.h"
45#include "RASession.h"
46#include "RealmList.h"
47#include "ScriptLoader.h"
48#include "ScriptMgr.h"
49#include "ScriptReloadMgr.h"
50#include "SecretMgr.h"
51#include "TCSoap.h"
52#include "TerrainMgr.h"
53#include "ThreadPool.h"
54#include "World.h"
55#include "WorldSocket.h"
56#include "WorldSocketMgr.h"
57#include "Util.h"
58#include <openssl/opensslv.h>
59#include <openssl/crypto.h>
60#include <boost/asio/signal_set.hpp>
61#include <boost/dll/runtime_symbol_info.hpp>
62#include <boost/filesystem/operations.hpp>
63#include <boost/program_options.hpp>
64#include <google/protobuf/stubs/common.h>
65#include <iostream>
66#include <csignal>
67
69
70using namespace boost::program_options;
71namespace fs = boost::filesystem;
72
73#ifndef _TRINITY_CORE_CONFIG
74 #define _TRINITY_CORE_CONFIG "worldserver.conf"
75#endif
76
77#ifndef _TRINITY_CORE_CONFIG_DIR
78 #define _TRINITY_CORE_CONFIG_DIR "worldserver.conf.d"
79#endif
80
81#ifdef _WIN32
82#include "ServiceWin32.h"
83char serviceName[] = "worldserver";
84char serviceLongName[] = "TrinityCore world service";
85char serviceDescription[] = "TrinityCore World of Warcraft emulator world service";
86/*
87 * -1 - not in service mode
88 * 0 - stopped
89 * 1 - running
90 * 2 - paused
91 */
92int m_ServiceStatus = -1;
93
94#include <boost/dll/shared_library.hpp>
95#include <timeapi.h>
96#endif
97
99{
100public:
101 FreezeDetector(Trinity::Asio::IoContext& ioContext, uint32 maxCoreStuckTime)
102 : _timer(ioContext), _worldLoopCounter(0), _lastChangeMsTime(getMSTime()), _maxCoreStuckTimeInMs(maxCoreStuckTime) { }
103
104 static void Start(std::shared_ptr<FreezeDetector> const& freezeDetector)
105 {
106 freezeDetector->_timer.expires_from_now(boost::posix_time::seconds(5));
107 freezeDetector->_timer.async_wait([freezeDetectorRef = std::weak_ptr(freezeDetector)](boost::system::error_code const& error) mutable
108 {
109 Handler(std::move(freezeDetectorRef), error);
110 });
111 }
112
113 static void Handler(std::weak_ptr<FreezeDetector> freezeDetectorRef, boost::system::error_code const& error);
114
115private:
120};
121
122void SignalHandler(boost::system::error_code const& error, int signalNumber);
124bool StartDB();
125void StopDB();
126void WorldUpdateLoop();
128void ShutdownCLIThread(std::thread* cliThread);
129bool LoadRealmInfo();
130variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, std::string& winServiceAction);
131
133extern int main(int argc, char** argv)
134{
135 signal(SIGABRT, &Trinity::AbortHandler);
136
138
140
141 auto configFile = fs::absolute(_TRINITY_CORE_CONFIG);
142 auto configDir = fs::absolute(_TRINITY_CORE_CONFIG_DIR);
143 std::string winServiceAction;
144
145 auto vm = GetConsoleArguments(argc, argv, configFile, configDir, winServiceAction);
146 // exit if help or version is enabled
147 if (vm.count("help") || vm.count("version"))
148 return 0;
149
150 GOOGLE_PROTOBUF_VERIFY_VERSION;
151
152 std::shared_ptr<void> protobufHandle(nullptr, [](void*) { google::protobuf::ShutdownProtobufLibrary(); });
153
154#ifdef _WIN32
155 if (winServiceAction == "install")
156 return WinServiceInstall() ? 0 : 1;
157 if (winServiceAction == "uninstall")
158 return WinServiceUninstall() ? 0 : 1;
159 if (winServiceAction == "run")
160 return WinServiceRun() ? 0 : 1;
161
162 Optional<UINT> newTimerResolution;
163 boost::system::error_code dllError;
164 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)
165 {
166 try
167 {
168 if (newTimerResolution)
169 lib->get<decltype(timeEndPeriod)>("timeEndPeriod")(*newTimerResolution);
170 }
171 catch (std::exception const&)
172 {
173 // ignore
174 }
175
176 delete lib;
177 });
178
179 if (winmm->is_loaded())
180 {
181 try
182 {
183 auto timeGetDevCapsPtr = winmm->get<decltype(timeGetDevCaps)>("timeGetDevCaps");
184 // setup timer resolution
185 TIMECAPS timeResolutionLimits;
186 if (timeGetDevCapsPtr(&timeResolutionLimits, sizeof(TIMECAPS)) == TIMERR_NOERROR)
187 {
188 auto timeBeginPeriodPtr = winmm->get<decltype(timeBeginPeriod)>("timeBeginPeriod");
189 newTimerResolution = std::min(std::max(timeResolutionLimits.wPeriodMin, 1u), timeResolutionLimits.wPeriodMax);
190 timeBeginPeriodPtr(*newTimerResolution);
191 }
192 }
193 catch (std::exception const& e)
194 {
195 printf("Failed to initialize timer resolution: %s\n", e.what());
196 }
197 }
198
199#endif
200
201 std::string configError;
202 if (!sConfigMgr->LoadInitial(configFile.generic_string(),
203 std::vector<std::string>(argv, argv + argc),
204 configError))
205 {
206 printf("Error in config file: %s\n", configError.c_str());
207 return 1;
208 }
209
210 std::vector<std::string> loadedConfigFiles;
211 std::vector<std::string> configDirErrors;
212 bool additionalConfigFileLoadSuccess = sConfigMgr->LoadAdditionalDir(configDir.generic_string(), true, loadedConfigFiles, configDirErrors);
213 for (std::string const& loadedConfigFile : loadedConfigFiles)
214 printf("Loaded additional config file %s\n", loadedConfigFile.c_str());
215
216 if (!additionalConfigFileLoadSuccess)
217 {
218 for (std::string const& configDirError : configDirErrors)
219 printf("Error in additional config files: %s\n", configDirError.c_str());
220
221 return 1;
222 }
223
224 std::vector<std::string> overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny();
225
226 std::shared_ptr<Trinity::Asio::IoContext> ioContext = std::make_shared<Trinity::Asio::IoContext>();
227
228 sLog->RegisterAppender<AppenderDB>();
229 // If logs are supposed to be handled async then we need to pass the IoContext into the Log singleton
230 sLog->Initialize(sConfigMgr->GetBoolDefault("Log.Async.Enable", false) ? ioContext.get() : nullptr);
231
232 Trinity::Banner::Show("worldserver-daemon",
233 [](char const* text)
234 {
235 TC_LOG_INFO("server.worldserver", "{}", text);
236 },
237 []()
238 {
239 TC_LOG_INFO("server.worldserver", "Using configuration file {}.", sConfigMgr->GetFilename());
240 TC_LOG_INFO("server.worldserver", "Using SSL version: {} (library: {})", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
241 TC_LOG_INFO("server.worldserver", "Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
242 }
243 );
244
245 for (std::string const& key : overriddenKeys)
246 TC_LOG_INFO("server.worldserver", "Configuration field '{}' was overridden with environment variable.", key);
247
248 OpenSSLCrypto::threadsSetup(boost::dll::program_location().remove_filename());
249
250 std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });
251
252 // Seed the OpenSSL's PRNG here.
253 // That way it won't auto-seed when calling BigNumber::SetRand and slow down the first world login
254 BigNumber seed;
255 seed.SetRand(16 * 8);
256
258 std::string pidFile = sConfigMgr->GetStringDefault("PidFile", "");
259 if (!pidFile.empty())
260 {
261 if (uint32 pid = CreatePIDFile(pidFile))
262 TC_LOG_INFO("server.worldserver", "Daemon PID: {}\n", pid);
263 else
264 {
265 TC_LOG_ERROR("server.worldserver", "Cannot create PID file {}.\n", pidFile);
266 return 1;
267 }
268 }
269
270 // Set signal handlers (this must be done before starting IoContext threads, because otherwise they would unblock and exit)
271 boost::asio::signal_set signals(*ioContext, SIGINT, SIGTERM);
272#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
273 signals.add(SIGBREAK);
274#endif
275 signals.async_wait(SignalHandler);
276
277 // Start the Boost based thread pool
278 int numThreads = sConfigMgr->GetIntDefault("ThreadPool", 1);
279 if (numThreads < 1)
280 numThreads = 1;
281
282 std::shared_ptr<Trinity::ThreadPool> threadPool = std::make_shared<Trinity::ThreadPool>(numThreads);
283
284 for (int i = 0; i < numThreads; ++i)
285 threadPool->PostWork([ioContext]() { ioContext->run(); });
286
287 std::shared_ptr<void> ioContextStopHandle(nullptr, [ioContext](void*) { ioContext->stop(); });
288
289 // Set process priority according to configuration settings
290 SetProcessPriority("server.worldserver", sConfigMgr->GetIntDefault(CONFIG_PROCESSOR_AFFINITY, 0), sConfigMgr->GetBoolDefault(CONFIG_HIGH_PRIORITY, false));
291
292 // Start the databases
293 if (!StartDB())
294 return 1;
295
296 std::shared_ptr<void> dbHandle(nullptr, [](void*) { StopDB(); });
297
298 if (vm.count("update-databases-only"))
299 return 0;
300
302
303 // Set server offline (not connectable)
304 LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
305
306 sRealmList->Initialize(*ioContext, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 10));
307
308 std::shared_ptr<void> sRealmListHandle(nullptr, [](void*) { sRealmList->Close(); });
309
311
312 sMetric->Initialize(realm.Name, *ioContext, []()
313 {
314 TC_METRIC_VALUE("online_players", sWorld->GetPlayerCount());
315 TC_METRIC_VALUE("db_queue_login", uint64(LoginDatabase.QueueSize()));
316 TC_METRIC_VALUE("db_queue_character", uint64(CharacterDatabase.QueueSize()));
317 TC_METRIC_VALUE("db_queue_world", uint64(WorldDatabase.QueueSize()));
318 });
319
320 TC_METRIC_EVENT("events", "Worldserver started", "");
321
322 std::shared_ptr<void> sMetricHandle(nullptr, [](void*)
323 {
324 TC_METRIC_EVENT("events", "Worldserver shutdown", "");
325 sMetric->Unload();
326 });
327
328 sScriptMgr->SetScriptLoader(AddScripts);
329 std::shared_ptr<void> sScriptMgrHandle(nullptr, [](void*)
330 {
331 sScriptMgr->Unload();
332 sScriptReloadMgr->Unload();
333 });
334
335 // Initialize the World
337 sWorld->SetInitialWorldSettings();
338
339 std::shared_ptr<void> mapManagementHandle(nullptr, [](void*)
340 {
341 // unload battleground templates before different singletons destroyed
342 sBattlegroundMgr->DeleteAllBattlegrounds();
343
344 sOutdoorPvPMgr->Die(); // unload it before MapManager
345 sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
346 sTerrainMgr.UnloadAll();
347 sInstanceLockMgr.Unload();
348 });
349
350 // Start the Remote Access port (acceptor) if enabled
351 std::unique_ptr<AsyncAcceptor> raAcceptor;
352 if (sConfigMgr->GetBoolDefault("Ra.Enable", false))
353 raAcceptor.reset(StartRaSocketAcceptor(*ioContext));
354
355 // Start soap serving thread if enabled
356 std::shared_ptr<std::thread> soapThread;
357 if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false))
358 {
359 soapThread.reset(new std::thread(TCSoapThread, sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))),
360 [](std::thread* thr)
361 {
362 thr->join();
363 delete thr;
364 });
365 }
366
367 // Launch the worldserver listener socket
368 uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
369 uint16 instancePort = uint16(sWorld->getIntConfig(CONFIG_PORT_INSTANCE));
370 std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
371
372 int networkThreads = sConfigMgr->GetIntDefault("Network.Threads", 1);
373
374 if (networkThreads <= 0)
375 {
376 TC_LOG_ERROR("server.worldserver", "Network.Threads must be greater than 0");
378 return 1;
379 }
380
381 if (!sWorldSocketMgr.StartWorldNetwork(*ioContext, worldListener, worldPort, instancePort, networkThreads))
382 {
383 TC_LOG_ERROR("server.worldserver", "Failed to initialize network");
385 return 1;
386 }
387
388 std::shared_ptr<void> sWorldSocketMgrHandle(nullptr, [](void*)
389 {
390 sWorld->KickAll(); // save and kick all players
391 sWorld->UpdateSessions(1); // real players unload required UpdateSessions call
392
393 sWorldSocketMgr.StopNetwork();
394
397 });
398
399 // Set server online (allow connecting now)
400 LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~{}, population = 0 WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
401 realm.PopulationLevel = 0.0f;
403
404 // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec)
405 std::shared_ptr<FreezeDetector> freezeDetector;
406 if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 60))
407 {
408 freezeDetector = std::make_shared<FreezeDetector>(*ioContext, coreStuckTime * 1000);
409 FreezeDetector::Start(freezeDetector);
410 TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread ({} seconds max stuck time)...", coreStuckTime);
411 }
412
413 sScriptMgr->OnStartup();
414
415 TC_LOG_INFO("server.worldserver", "{} (worldserver-daemon) ready...", GitRevision::GetFullVersion());
416
417 // Launch CliRunnable thread
418 std::shared_ptr<std::thread> cliThread;
419#ifdef _WIN32
420 if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
421#else
422 if (sConfigMgr->GetBoolDefault("Console.Enable", true))
423#endif
424 {
425 cliThread.reset(new std::thread(CliThread), &ShutdownCLIThread);
426 }
427
429
430 // Shutdown starts here
433
434 ioContextStopHandle.reset();
435
436 threadPool.reset();
437
438 sLog->SetSynchronous();
439
440 sScriptMgr->OnShutdown();
441
442 // set server offline
443 LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
444
445 TC_LOG_INFO("server.worldserver", "Halting process...");
446
447 // 0 - normal shutdown
448 // 1 - shutdown at error
449 // 2 - restart command used, this code can be used by restarter for restart Trinityd
450
451 return World::GetExitCode();
452}
453
454void ShutdownCLIThread(std::thread* cliThread)
455{
456 if (cliThread != nullptr)
457 {
458#ifdef _WIN32
459 // First try to cancel any I/O in the CLI thread
460 if (!CancelSynchronousIo(cliThread->native_handle()))
461 {
462 // if CancelSynchronousIo() fails, print the error and try with old way
463 DWORD errorCode = GetLastError();
464
465 // if CancelSynchronousIo fails with ERROR_NOT_FOUND then there was nothing to cancel, proceed with shutdown
466 if (errorCode != ERROR_NOT_FOUND)
467 {
468 LPCSTR errorBuffer;
469 DWORD numCharsWritten = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
470 nullptr, errorCode, 0, (LPTSTR)&errorBuffer, 0, nullptr);
471 if (!numCharsWritten)
472 errorBuffer = "Unknown error";
473
474 TC_LOG_DEBUG("server.worldserver", "Error cancelling I/O of CliThread, error code {}, detail: {}", uint32(errorCode), errorBuffer);
475
476 if (numCharsWritten)
477 LocalFree((LPSTR)errorBuffer);
478
479 // send keyboard input to safely unblock the CLI thread
480 INPUT_RECORD b[4];
481 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
482 b[0].EventType = KEY_EVENT;
483 b[0].Event.KeyEvent.bKeyDown = TRUE;
484 b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
485 b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
486 b[0].Event.KeyEvent.wRepeatCount = 1;
487
488 b[1].EventType = KEY_EVENT;
489 b[1].Event.KeyEvent.bKeyDown = FALSE;
490 b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
491 b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
492 b[1].Event.KeyEvent.wRepeatCount = 1;
493
494 b[2].EventType = KEY_EVENT;
495 b[2].Event.KeyEvent.bKeyDown = TRUE;
496 b[2].Event.KeyEvent.dwControlKeyState = 0;
497 b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
498 b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
499 b[2].Event.KeyEvent.wRepeatCount = 1;
500 b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
501
502 b[3].EventType = KEY_EVENT;
503 b[3].Event.KeyEvent.bKeyDown = FALSE;
504 b[3].Event.KeyEvent.dwControlKeyState = 0;
505 b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
506 b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
507 b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
508 b[3].Event.KeyEvent.wRepeatCount = 1;
509 DWORD numb;
510 WriteConsoleInput(hStdIn, b, 4, &numb);
511 }
512 }
513#endif
514 cliThread->join();
515 delete cliThread;
516 }
517}
518
520{
521 uint32 minUpdateDiff = uint32(sConfigMgr->GetIntDefault("MinWorldUpdateTime", 1));
522 uint32 realCurrTime = 0;
523 uint32 realPrevTime = getMSTime();
524
525 uint32 maxCoreStuckTime = uint32(sConfigMgr->GetIntDefault("MaxCoreStuckTime", 60)) * 1000;
526 uint32 halfMaxCoreStuckTime = maxCoreStuckTime / 2;
527 if (!halfMaxCoreStuckTime)
528 halfMaxCoreStuckTime = std::numeric_limits<uint32>::max();
529
530 LoginDatabase.WarnAboutSyncQueries(true);
531 CharacterDatabase.WarnAboutSyncQueries(true);
532 WorldDatabase.WarnAboutSyncQueries(true);
533 HotfixDatabase.WarnAboutSyncQueries(true);
534
536 while (!World::IsStopped())
537 {
539 realCurrTime = getMSTime();
540
541 uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
542 if (diff < minUpdateDiff)
543 {
544 uint32 sleepTime = minUpdateDiff - diff;
545 if (sleepTime >= halfMaxCoreStuckTime)
546 TC_LOG_ERROR("server.worldserver", "WorldUpdateLoop() waiting for {} ms with MaxCoreStuckTime set to {} ms", sleepTime, maxCoreStuckTime);
547 // sleep until enough time passes that we can update all timers
548 std::this_thread::sleep_for(Milliseconds(sleepTime));
549 continue;
550 }
551
552 sWorld->Update(diff);
553 realPrevTime = realCurrTime;
554
555#ifdef _WIN32
556 if (m_ServiceStatus == 0)
558
559 while (m_ServiceStatus == 2)
560 Sleep(1000);
561#endif
562 }
563
564 LoginDatabase.WarnAboutSyncQueries(false);
565 CharacterDatabase.WarnAboutSyncQueries(false);
566 WorldDatabase.WarnAboutSyncQueries(false);
567 HotfixDatabase.WarnAboutSyncQueries(false);
568}
569
570void SignalHandler(boost::system::error_code const& error, int /*signalNumber*/)
571{
572 if (!error)
574}
575
576void FreezeDetector::Handler(std::weak_ptr<FreezeDetector> freezeDetectorRef, boost::system::error_code const& error)
577{
578 if (!error)
579 {
580 if (std::shared_ptr<FreezeDetector> freezeDetector = freezeDetectorRef.lock())
581 {
582 uint32 curtime = getMSTime();
583
584 uint32 worldLoopCounter = World::m_worldLoopCounter;
585 if (freezeDetector->_worldLoopCounter != worldLoopCounter)
586 {
587 freezeDetector->_lastChangeMsTime = curtime;
588 freezeDetector->_worldLoopCounter = worldLoopCounter;
589 }
590 // possible freeze
591 else
592 {
593 uint32 msTimeDiff = getMSTimeDiff(freezeDetector->_lastChangeMsTime, curtime);
594 if (msTimeDiff > freezeDetector->_maxCoreStuckTimeInMs)
595 {
596 TC_LOG_ERROR("server.worldserver", "World Thread hangs for {} ms, forcing a crash!", msTimeDiff);
597 ABORT_MSG("World Thread hangs for %u ms, forcing a crash!", msTimeDiff);
598 }
599 }
600
601 freezeDetector->_timer.expires_from_now(boost::posix_time::seconds(1));
602 freezeDetector->_timer.async_wait([freezeDetectorRef = std::move(freezeDetectorRef)](boost::system::error_code const& error) mutable
603 {
604 Handler(std::move(freezeDetectorRef), error);
605 });
606 }
607 }
608}
609
611{
612 uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443));
613 std::string raListener = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
614
615 AsyncAcceptor* acceptor = new AsyncAcceptor(ioContext, raListener, raPort);
616 if (!acceptor->Bind())
617 {
618 TC_LOG_ERROR("server.worldserver", "Failed to bind RA socket acceptor");
619 delete acceptor;
620 return nullptr;
621 }
622
623 acceptor->AsyncAccept<RASession>();
624 return acceptor;
625}
626
628{
629 if (Realm const* realmListRealm = sRealmList->GetRealm(realm.Id))
630 {
631 realm = *realmListRealm;
632 return true;
633 }
634
635 return false;
636}
637
640{
642
643 // Load databases
644 DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE);
645 loader
646 .AddDatabase(LoginDatabase, "Login")
647 .AddDatabase(CharacterDatabase, "Character")
648 .AddDatabase(WorldDatabase, "World")
649 .AddDatabase(HotfixDatabase, "Hotfix");
650
651 if (!loader.Load())
652 return false;
653
655 realm.Id.Realm = sConfigMgr->GetIntDefault("RealmID", 0);
656 if (!realm.Id.Realm)
657 {
658 TC_LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");
659 return false;
660 }
661
662 TC_LOG_INFO("server.worldserver", "Realm running as realm ID {}", realm.Id.Realm);
663
666
668 WorldDatabase.PExecute("UPDATE version SET core_version = '{}', core_revision = '{}'", GitRevision::GetFullVersion(), GitRevision::GetHash()); // One-time query
669
670 sWorld->LoadDBVersion();
671
672 TC_LOG_INFO("server.worldserver", "Using World DB: {}", sWorld->GetDBVersion());
673 return true;
674}
675
676void StopDB()
677{
678 HotfixDatabase.Close();
679 WorldDatabase.Close();
680 CharacterDatabase.Close();
681 LoginDatabase.Close();
682
684}
685
688{
689 // Reset online status for all accounts with characters on the current realm
690 LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = {})", realm.Id.Realm);
691
692 // Reset online status for all characters
693 CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
694
695 // Battleground instance ids reset at server restart
696 CharacterDatabase.DirectExecute("UPDATE character_battleground_data SET instanceId = 0");
697}
698
700
701variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, [[maybe_unused]] std::string& winServiceAction)
702{
703 options_description all("Allowed options");
704 all.add_options()
705 ("help,h", "print usage message")
706 ("version,v", "print version build info")
707 ("config,c", value<fs::path>(&configFile)->default_value(fs::absolute(_TRINITY_CORE_CONFIG)),
708 "use <arg> as configuration file")
709 ("config-dir,cd", value<fs::path>(&configDir)->default_value(fs::absolute(_TRINITY_CORE_CONFIG_DIR)),
710 "use <arg> as directory with additional config files")
711 ("update-databases-only,u", "updates databases only")
712 ;
713#ifdef _WIN32
714 options_description win("Windows platform specific options");
715 win.add_options()
716 ("service,s", value<std::string>(&winServiceAction)->default_value(""), "Windows service options: [install | uninstall]")
717 ;
718
719 all.add(win);
720#endif
721 variables_map vm;
722 try
723 {
724 store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), vm);
725 notify(vm);
726 }
727 catch (std::exception& e)
728 {
729 std::cerr << e.what() << "\n";
730 }
731
732 if (vm.count("help"))
733 {
734 std::cout << all << "\n";
735 }
736 else if (vm.count("version"))
737 {
738 std::cout << GitRevision::GetFullVersion() << "\n";
739 }
740
741 return vm;
742}
#define sBattlegroundMgr
#define sConfigMgr
Definition: Config.h:61
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
DatabaseWorkerPool< HotfixDatabaseConnection > HotfixDatabase
Accessor to the hotfix database.
Definition: DatabaseEnv.cpp:23
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#define ABORT_MSG
Definition: Errors.h:75
#define sInstanceLockMgr
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sLog
Definition: Log.h:130
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
#define sMapMgr
Definition: MapManager.h:184
#define sMetric
Definition: Metric.h:149
#define TC_METRIC_EVENT(category, title, description)
Definition: Metric.h:206
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
#define sOutdoorPvPMgr
void SetProcessPriority(std::string const &logChannel, uint32 affinity, bool highPriority)
#define CONFIG_HIGH_PRIORITY
#define CONFIG_PROCESSOR_AFFINITY
#define sRealmList
Definition: RealmList.h:96
RealmFlags
Definition: Realm.h:27
@ REALM_FLAG_OFFLINE
Definition: Realm.h:30
void AddScripts()
#define sScriptMgr
Definition: ScriptMgr.h:1418
#define sScriptReloadMgr
#define sSecretMgr
Definition: SecretMgr.h:83
@ SECRET_OWNER_WORLDSERVER
Definition: SecretMgr.h:40
void TCSoapThread(const std::string &host, uint16 port)
Definition: TCSoap.cpp:26
#define sTerrainMgr
Definition: TerrainMgr.h:165
uint32 getMSTime()
Definition: Timer.h:33
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition: Timer.h:40
uint32 CreatePIDFile(std::string const &filename)
create PID file
Definition: Util.cpp:324
char serviceDescription[]
Definition: Main.cpp:70
void SignalHandler(std::weak_ptr< Trinity::Asio::IoContext > ioContextRef, boost::system::error_code const &error, int signalNumber)
Definition: Main.cpp:323
char serviceLongName[]
Definition: Main.cpp:69
int main(int argc, char **argv)
Definition: Main.cpp:89
variables_map GetConsoleArguments(int argc, char **argv, fs::path &configFile, fs::path &configDir, std::string &winServiceAction)
Definition: Main.cpp:391
char serviceName[]
Definition: Main.cpp:68
int m_ServiceStatus
Definition: Main.cpp:77
bool StartDB()
Initialize connection to the database.
Definition: Main.cpp:299
void StopDB()
Close the connection to the database.
Definition: Main.cpp:317
void AsyncAccept()
void SetRand(int32 numbits)
Definition: BigNumber.cpp:70
DatabaseLoader & AddDatabase(DatabaseWorkerPool< T > &pool, std::string const &name)
uint32 _lastChangeMsTime
Definition: Main.cpp:118
uint32 _worldLoopCounter
Definition: Main.cpp:117
uint32 _maxCoreStuckTimeInMs
Definition: Main.cpp:119
static void Start(std::shared_ptr< FreezeDetector > const &freezeDetector)
Definition: Main.cpp:104
Trinity::Asio::DeadlineTimer _timer
Definition: Main.cpp:116
FreezeDetector(Trinity::Asio::IoContext &ioContext, uint32 maxCoreStuckTime)
Definition: Main.cpp:101
static uint8 GetExitCode()
Definition: World.h:669
static std::atomic< uint32 > m_worldLoopCounter
Definition: World.h:567
static void StopNow(uint8 exitcode)
Definition: World.h:670
static bool IsStopped()
Definition: World.h:671
void ClearOnlineAccounts()
Clear 'online' status for all accounts with characters in this realm.
Definition: Main.cpp:687
void CliThread()
Thread start
AsyncAcceptor * StartRaSocketAcceptor(Trinity::Asio::IoContext &ioContext)
Definition: Main.cpp:610
void WorldUpdateLoop()
Definition: Main.cpp:519
void ShutdownCLIThread(std::thread *cliThread)
Definition: Main.cpp:454
static void Handler(std::weak_ptr< FreezeDetector > freezeDetectorRef, boost::system::error_code const &error)
Definition: Main.cpp:576
#define _TRINITY_CORE_CONFIG
Definition: Main.cpp:74
#define _TRINITY_CORE_CONFIG_DIR
Definition: Main.cpp:78
bool LoadRealmInfo()
Definition: Main.cpp:627
#define sWorldSocketMgr
#define sWorld
Definition: World.h:931
Realm realm
Definition: World.cpp:3966
@ CONFIG_PORT_INSTANCE
Definition: World.h:240
@ CONFIG_PORT_WORLD
Definition: World.h:239
@ SHUTDOWN_EXIT_CODE
Definition: World.h:74
@ ERROR_EXIT_CODE
Definition: World.h:75
TC_COMMON_API char const * GetFullVersion()
Definition: GitRevision.cpp:96
TC_COMMON_API char const * GetHash()
Definition: GitRevision.cpp:21
TC_DATABASE_API void Library_Init()
TC_DATABASE_API void Library_End()
TC_COMMON_API void threadsSetup(boost::filesystem::path const &providerModulePath)
Needs to be called before threads using openssl are spawned.
TC_COMMON_API void threadsCleanup()
Needs to be called after threads using openssl are despawned.
TC_COMMON_API void Show(char const *applicationName, void(*log)(char const *text), void(*logExtraInfo)())
Definition: Banner.cpp:22
TC_COMMON_API void Init()
Definition: Locales.cpp:28
TC_COMMON_API void ScanLocalNetworks()
Definition: IpNetwork.cpp:149
TC_COMMON_API void VerifyOsVersion()
Definition: Util.cpp:34
void AbortHandler(int sigval)
Definition: Errors.cpp:146
Definition: Realm.h:81
RealmFlags Flags
Definition: Realm.h:89
float PopulationLevel
Definition: Realm.h:92
std::string Name
Definition: Realm.h:86
Battlenet::RealmHandle Id
Definition: Realm.h:82