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