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"
22#include "Banner.h"
23#include "BattlegroundMgr.h"
24#include "BigNumber.h"
25#include "CliRunnable.h"
27#include "DatabaseEnv.h"
28#include "DatabaseLoader.h"
29#include "DeadlineTimer.h"
30#include "GitRevision.h"
31#include "InstanceLockMgr.h"
32#include "IoContext.h"
33#include "IpNetwork.h"
34#include "Locales.h"
35#include "MapManager.h"
36#include "Memory.h"
37#include "Metric.h"
38#include "MySQLThreading.h"
39#include "OpenSSLCrypto.h"
41#include "ProcessPriority.h"
42#include "RASession.h"
43#include "RealmList.h"
44#include "ScriptLoader.h"
45#include "ScriptMgr.h"
46#include "ScriptReloadMgr.h"
47#include "SecretMgr.h"
48#include "TCSoap.h"
49#include "TerrainMgr.h"
50#include "ThreadPool.h"
51#include "World.h"
52#include "WorldSocketMgr.h"
53#include "Util.h"
54#include <openssl/opensslv.h>
55#include <openssl/crypto.h>
56#include <boost/asio/signal_set.hpp>
57#include <boost/dll/runtime_symbol_info.hpp>
58#include <boost/filesystem/operations.hpp>
59#include <boost/program_options.hpp>
60#include <google/protobuf/stubs/common.h>
61#include <iostream>
62#include <csignal>
63
65
66using namespace boost::program_options;
67namespace fs = boost::filesystem;
68
69#ifndef _TRINITY_CORE_CONFIG
70 #define _TRINITY_CORE_CONFIG "worldserver.conf"
71#endif
72
73#ifndef _TRINITY_CORE_CONFIG_DIR
74 #define _TRINITY_CORE_CONFIG_DIR "worldserver.conf.d"
75#endif
76
77#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
78#include "ServiceWin32.h"
79#include <tchar.h>
80TCHAR serviceName[] = _T("worldserver");
81TCHAR serviceLongName[] = _T("TrinityCore world service");
82TCHAR serviceDescription[] = _T("TrinityCore World of Warcraft emulator world service");
83/*
84 * -1 - not in service mode
85 * 0 - stopped
86 * 1 - running
87 * 2 - paused
88 */
90
91#include <boost/dll/shared_library.hpp>
92#include <timeapi.h>
93#endif
94
96{
97public:
98 FreezeDetector(Trinity::Asio::IoContext& ioContext, uint32 maxCoreStuckTime)
99 : _timer(ioContext), _worldLoopCounter(0), _lastChangeMsTime(getMSTime()), _maxCoreStuckTimeInMs(maxCoreStuckTime) { }
100
101 static void Start(std::shared_ptr<FreezeDetector> const& freezeDetector)
102 {
103 freezeDetector->_timer.expires_after(5s);
104 freezeDetector->_timer.async_wait([freezeDetectorRef = std::weak_ptr(freezeDetector)](boost::system::error_code const& error) mutable
105 {
106 Handler(std::move(freezeDetectorRef), error);
107 });
108 }
109
110 static void Handler(std::weak_ptr<FreezeDetector> freezeDetectorRef, boost::system::error_code const& error);
111
112private:
117};
118
119void SignalHandler(boost::system::error_code const& error, int signalNumber);
120std::unique_ptr<Trinity::Net::AsyncAcceptor> StartRaSocketAcceptor(Trinity::Asio::IoContext& ioContext);
121bool StartDB();
122void StopDB();
123void WorldUpdateLoop();
124void ClearOnlineAccounts(uint32 realmId);
125struct ShutdownTCSoapThread { void operator()(std::thread* thread) const; };
126struct ShutdownCLIThread { void operator()(std::thread* cliThread) const; };
127variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, std::string& winServiceAction);
128
130int main(int argc, char** argv)
131{
132 signal(SIGABRT, &Trinity::AbortHandler);
133
135
137
138 auto configFile = fs::absolute(_TRINITY_CORE_CONFIG);
139 auto configDir = fs::absolute(_TRINITY_CORE_CONFIG_DIR);
140 std::string winServiceAction;
141
142 auto vm = GetConsoleArguments(argc, argv, configFile, configDir, winServiceAction);
143 // exit if help or version is enabled
144 if (vm.count("help") || vm.count("version"))
145 return 0;
146
147 uint32 dummy = 0;
148
149 GOOGLE_PROTOBUF_VERIFY_VERSION;
150
151 auto protobufHandle = Trinity::make_unique_ptr_with_deleter<[](void*) { google::protobuf::ShutdownProtobufLibrary(); }>(&dummy);
152
153#ifdef _WIN32
155 if (winServiceAction == "install")
157 if (winServiceAction == "uninstall")
159 if (winServiceAction == "run")
160 return Trinity::Service::Run();
161
162 Optional<UINT> newTimerResolution;
163 boost::system::error_code dllError;
164 auto winmm = Trinity::make_unique_ptr_with_deleter(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 auto opensslHandle = Trinity::make_unique_ptr_with_deleter<[](void*) { OpenSSLCrypto::threadsCleanup(); }>(&dummy);
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::basic_signal_set<Trinity::Asio::IoContext::Executor> 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::unique_ptr<Trinity::ThreadPool> threadPool = std::make_unique<Trinity::ThreadPool>(numThreads);
283
284 for (int i = 0; i < numThreads; ++i)
285 threadPool->PostWork([ioContext]() { ioContext->run(); });
286
287 auto signalsCancelHandle = Trinity::make_unique_ptr_with_deleter<[](auto* s) { boost::system::error_code ec; s->cancel(ec); }>(&signals);
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 auto dbHandle = Trinity::make_unique_ptr_with_deleter<[](void*) { StopDB(); }>(&dummy);
297
298 if (vm.count("update-databases-only"))
299 return 0;
300
302
303 sRealmList->Initialize(*ioContext, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 10));
304
305 auto sRealmListHandle = Trinity::make_unique_ptr_with_deleter<&RealmList::Close>(sRealmList);
306
308 uint32 realmId = sConfigMgr->GetIntDefault("RealmID", 0);
309 if (!realmId)
310 {
311 TC_LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file");
312 return 1;
313 }
314
315 sRealmList->SetCurrentRealmId(realmId);
316
317 TC_LOG_INFO("server.worldserver", "Realm running as realm ID {}", realmId);
318
320 ClearOnlineAccounts(realmId);
321
322 std::shared_ptr<Realm const> realm = sRealmList->GetCurrentRealm();
323 if (!realm)
324 return 1;
325
326 // Set server offline (not connectable)
327 LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", Trinity::Legacy::REALM_FLAG_OFFLINE, realmId);
328
329 sMetric->Initialize(realm->Name, *ioContext, []()
330 {
331 TC_METRIC_VALUE("online_players", sWorld->GetPlayerCount());
332 TC_METRIC_VALUE("db_queue_login", uint64(LoginDatabase.QueueSize()));
333 TC_METRIC_VALUE("db_queue_character", uint64(CharacterDatabase.QueueSize()));
334 TC_METRIC_VALUE("db_queue_world", uint64(WorldDatabase.QueueSize()));
335 });
336
337 realm = nullptr;
338
339 TC_METRIC_EVENT("events", "Worldserver started", "");
340
341 auto sMetricHandle = Trinity::make_unique_ptr_with_deleter(sMetric, [](Metric* metric)
342 {
343 TC_METRIC_EVENT("events", "Worldserver shutdown", "");
344 metric->Unload();
345 });
346
347 auto scriptReloadMgrHandle = Trinity::make_unique_ptr_with_deleter<&ScriptReloadMgr::Unload>(sScriptReloadMgr);
348
349 sScriptMgr->SetScriptLoader(AddScripts);
350 auto sScriptMgrHandle = Trinity::make_unique_ptr_with_deleter<&ScriptMgr::Unload>(sScriptMgr);
351
352 // Initialize the World
354 if (!sWorld->SetInitialWorldSettings())
355 return 1;
356
357 auto instanceLockMgrHandle = Trinity::make_unique_ptr_with_deleter<&InstanceLockMgr::Unload>(&sInstanceLockMgr);
358
359 auto terrainMgrHandle = Trinity::make_unique_ptr_with_deleter<&TerrainMgr::UnloadAll>(&sTerrainMgr);
360
361 auto outdoorPvpMgrHandle = Trinity::make_unique_ptr_with_deleter<&OutdoorPvPMgr::Die>(sOutdoorPvPMgr);
362
363 // unload all grids (including locked in memory)
364 auto mapManagementHandle = Trinity::make_unique_ptr_with_deleter<&MapManager::UnloadAll>(sMapMgr);
365
366 // unload battleground templates before different singletons destroyed
367 auto battlegroundMgrHandle = Trinity::make_unique_ptr_with_deleter<&BattlegroundMgr::DeleteAllBattlegrounds>(sBattlegroundMgr);
368
369 // Start the Remote Access port (acceptor) if enabled
370 std::unique_ptr<Trinity::Net::AsyncAcceptor> raAcceptor;
371 if (sConfigMgr->GetBoolDefault("Ra.Enable", false))
372 raAcceptor = StartRaSocketAcceptor(*ioContext);
373
374 // Start soap serving thread if enabled
375 std::unique_ptr<std::thread, ShutdownTCSoapThread> soapThread;
376 if (sConfigMgr->GetBoolDefault("SOAP.Enabled", false))
377 {
378 if (std::thread* soap = CreateSoapThread(sConfigMgr->GetStringDefault("SOAP.IP", "127.0.0.1"), uint16(sConfigMgr->GetIntDefault("SOAP.Port", 7878))))
379 soapThread.reset(soap);
380 else
381 return -1;
382 }
383
384 // Launch the worldserver listener socket
385 uint16 worldPort = uint16(sWorld->getIntConfig(CONFIG_PORT_WORLD));
386 std::string worldListener = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
387
388 int networkThreads = sConfigMgr->GetIntDefault("Network.Threads", 1);
389
390 if (networkThreads <= 0)
391 {
392 TC_LOG_ERROR("server.worldserver", "Network.Threads must be greater than 0");
394 return 1;
395 }
396
397 if (!sWorldSocketMgr.StartNetwork(*ioContext, worldListener, worldPort, networkThreads))
398 {
399 TC_LOG_ERROR("server.worldserver", "Failed to initialize network");
401 return 1;
402 }
403
404 auto sWorldSocketMgrHandle = Trinity::make_unique_ptr_with_deleter(&sWorldSocketMgr, [realmId](WorldSocketMgr* mgr)
405 {
406 sWorld->KickAll(); // save and kick all players
407 sWorld->UpdateSessions(1); // real players unload required UpdateSessions call
408
409 mgr->StopNetwork();
410
412 ClearOnlineAccounts(realmId);
413 });
414
415 // Set server online (allow connecting now)
416 LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~{}, population = 0 WHERE id = '{}'", Trinity::Legacy::REALM_FLAG_OFFLINE, realmId);
417
418 // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec)
419 std::shared_ptr<FreezeDetector> freezeDetector;
420 if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 60))
421 {
422 freezeDetector = std::make_shared<FreezeDetector>(*ioContext, coreStuckTime * 1000);
423 FreezeDetector::Start(freezeDetector);
424 TC_LOG_INFO("server.worldserver", "Starting up anti-freeze thread ({} seconds max stuck time)...", coreStuckTime);
425 }
426
427 sScriptMgr->OnStartup();
428
429 TC_LOG_INFO("server.worldserver", "{} (worldserver-daemon) ready...", GitRevision::GetFullVersion());
430
431 // Launch CliRunnable thread
432 std::unique_ptr<std::thread, ShutdownCLIThread> cliThread;
433#ifdef _WIN32
434 if (sConfigMgr->GetBoolDefault("Console.Enable", true) && (m_ServiceStatus == -1)/* need disable console in service mode*/)
435#else
436 if (sConfigMgr->GetBoolDefault("Console.Enable", true))
437#endif
438 {
439 cliThread.reset(new std::thread(CliThread));
440 }
441
443
444 // Shutdown starts here
447
448 sLog->SetSynchronous();
449
450 sScriptMgr->OnShutdown();
451
452 // set server offline
453 LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", Trinity::Legacy::REALM_FLAG_OFFLINE, realmId);
454
455 TC_LOG_INFO("server.worldserver", "Halting process...");
456
457 // 0 - normal shutdown
458 // 1 - shutdown at error
459 // 2 - restart command used, this code can be used by restarter for restart Trinityd
460
461 return World::GetExitCode();
462}
463
464void ShutdownTCSoapThread::operator()(std::thread* thread) const
465{
466 thread->join();
467 delete thread;
468}
469
470void ShutdownCLIThread::operator()(std::thread* cliThread) const
471{
472 if (cliThread != nullptr)
473 {
474#ifdef _WIN32
475 // First try to cancel any I/O in the CLI thread
476 if (!CancelSynchronousIo(cliThread->native_handle()))
477 {
478 // if CancelSynchronousIo() fails, print the error and try with old way
479 DWORD errorCode = GetLastError();
480
481 // if CancelSynchronousIo fails with ERROR_NOT_FOUND then there was nothing to cancel, proceed with shutdown
482 if (errorCode != ERROR_NOT_FOUND)
483 {
484 LPCSTR errorBuffer;
485 DWORD numCharsWritten = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
486 nullptr, errorCode, 0, (LPTSTR)&errorBuffer, 0, nullptr);
487 if (!numCharsWritten)
488 errorBuffer = "Unknown error";
489
490 TC_LOG_DEBUG("server.worldserver", "Error cancelling I/O of CliThread, error code {}, detail: {}", uint32(errorCode), errorBuffer);
491
492 if (numCharsWritten)
493 LocalFree((LPSTR)errorBuffer);
494
495 // send keyboard input to safely unblock the CLI thread
496 INPUT_RECORD b[4];
497 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
498 b[0].EventType = KEY_EVENT;
499 b[0].Event.KeyEvent.bKeyDown = TRUE;
500 b[0].Event.KeyEvent.uChar.AsciiChar = 'X';
501 b[0].Event.KeyEvent.wVirtualKeyCode = 'X';
502 b[0].Event.KeyEvent.wRepeatCount = 1;
503
504 b[1].EventType = KEY_EVENT;
505 b[1].Event.KeyEvent.bKeyDown = FALSE;
506 b[1].Event.KeyEvent.uChar.AsciiChar = 'X';
507 b[1].Event.KeyEvent.wVirtualKeyCode = 'X';
508 b[1].Event.KeyEvent.wRepeatCount = 1;
509
510 b[2].EventType = KEY_EVENT;
511 b[2].Event.KeyEvent.bKeyDown = TRUE;
512 b[2].Event.KeyEvent.dwControlKeyState = 0;
513 b[2].Event.KeyEvent.uChar.AsciiChar = '\r';
514 b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
515 b[2].Event.KeyEvent.wRepeatCount = 1;
516 b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
517
518 b[3].EventType = KEY_EVENT;
519 b[3].Event.KeyEvent.bKeyDown = FALSE;
520 b[3].Event.KeyEvent.dwControlKeyState = 0;
521 b[3].Event.KeyEvent.uChar.AsciiChar = '\r';
522 b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
523 b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
524 b[3].Event.KeyEvent.wRepeatCount = 1;
525 DWORD numb;
526 WriteConsoleInput(hStdIn, b, 4, &numb);
527 }
528 }
529#endif
530 cliThread->join();
531 delete cliThread;
532 }
533}
534
536{
537 uint32 minUpdateDiff = uint32(sConfigMgr->GetIntDefault("MinWorldUpdateTime", 1));
538 uint32 realCurrTime = 0;
539 uint32 realPrevTime = getMSTime();
540
541 uint32 maxCoreStuckTime = uint32(sConfigMgr->GetIntDefault("MaxCoreStuckTime", 60)) * 1000;
542 uint32 halfMaxCoreStuckTime = maxCoreStuckTime / 2;
543 if (!halfMaxCoreStuckTime)
544 halfMaxCoreStuckTime = std::numeric_limits<uint32>::max();
545
546 LoginDatabase.WarnAboutSyncQueries(true);
547 CharacterDatabase.WarnAboutSyncQueries(true);
548 WorldDatabase.WarnAboutSyncQueries(true);
549 HotfixDatabase.WarnAboutSyncQueries(true);
550
552 while (!World::IsStopped())
553 {
555 realCurrTime = getMSTime();
556
557 uint32 diff = getMSTimeDiff(realPrevTime, realCurrTime);
558 if (diff < minUpdateDiff)
559 {
560 uint32 sleepTime = minUpdateDiff - diff;
561 if (sleepTime >= halfMaxCoreStuckTime)
562 TC_LOG_ERROR("server.worldserver", "WorldUpdateLoop() waiting for {} ms with MaxCoreStuckTime set to {} ms", sleepTime, maxCoreStuckTime);
563 // sleep until enough time passes that we can update all timers
564 std::this_thread::sleep_for(Milliseconds(sleepTime));
565 continue;
566 }
567
568 sWorld->Update(diff);
569 realPrevTime = realCurrTime;
570
571#ifdef _WIN32
572 if (m_ServiceStatus == 0)
574
575 while (m_ServiceStatus == 2)
576 Sleep(1000);
577#endif
578 }
579
580 LoginDatabase.WarnAboutSyncQueries(false);
581 CharacterDatabase.WarnAboutSyncQueries(false);
582 WorldDatabase.WarnAboutSyncQueries(false);
583 HotfixDatabase.WarnAboutSyncQueries(false);
584}
585
586void SignalHandler(boost::system::error_code const& error, int /*signalNumber*/)
587{
588 if (!error)
590}
591
592void FreezeDetector::Handler(std::weak_ptr<FreezeDetector> freezeDetectorRef, boost::system::error_code const& error)
593{
594 if (!error)
595 {
596 if (std::shared_ptr<FreezeDetector> freezeDetector = freezeDetectorRef.lock())
597 {
598 uint32 curtime = getMSTime();
599
600 uint32 worldLoopCounter = World::m_worldLoopCounter;
601 if (freezeDetector->_worldLoopCounter != worldLoopCounter)
602 {
603 freezeDetector->_lastChangeMsTime = curtime;
604 freezeDetector->_worldLoopCounter = worldLoopCounter;
605 }
606 // possible freeze
607 else
608 {
609 uint32 msTimeDiff = getMSTimeDiff(freezeDetector->_lastChangeMsTime, curtime);
610 if (msTimeDiff > freezeDetector->_maxCoreStuckTimeInMs)
611 {
612 TC_LOG_ERROR("server.worldserver", "World Thread hangs for {} ms, forcing a crash!", msTimeDiff);
613 ABORT_MSG("World Thread hangs for %u ms, forcing a crash!", msTimeDiff);
614 }
615 }
616
617 freezeDetector->_timer.expires_after(1s);
618 freezeDetector->_timer.async_wait([freezeDetectorRef = std::move(freezeDetectorRef)](boost::system::error_code const& error) mutable
619 {
620 Handler(std::move(freezeDetectorRef), error);
621 });
622 }
623 }
624}
625
626std::unique_ptr<Trinity::Net::AsyncAcceptor> StartRaSocketAcceptor(Trinity::Asio::IoContext& ioContext)
627{
628 uint16 raPort = uint16(sConfigMgr->GetIntDefault("Ra.Port", 3443));
629 std::string raListener = sConfigMgr->GetStringDefault("Ra.IP", "0.0.0.0");
630
631 std::unique_ptr<Trinity::Net::AsyncAcceptor> acceptor = std::make_unique<Trinity::Net::AsyncAcceptor>(ioContext, raListener, raPort);
632 if (!acceptor->Bind())
633 {
634 TC_LOG_ERROR("server.worldserver", "Failed to bind RA socket acceptor");
635 acceptor = nullptr;
636 return acceptor;
637 }
638
639 acceptor->AsyncAccept(
640 [&] { return &ioContext; },
641 [](Trinity::Net::IoContextTcpSocket&& sock) { std::make_shared<RASession>(std::move(sock))->Start(); });
642
643 return acceptor;
644}
645
648{
650
651 // Load databases
652 DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE);
653 loader
654 .AddDatabase(LoginDatabase, "Login")
655 .AddDatabase(CharacterDatabase, "Character")
656 .AddDatabase(WorldDatabase, "World")
657 .AddDatabase(HotfixDatabase, "Hotfix");
658
659 if (!loader.Load())
660 return false;
661
663 WorldDatabase.PExecute("UPDATE version SET core_version = '{}', core_revision = '{}'", GitRevision::GetFullVersion(), GitRevision::GetHash()); // One-time query
664
665 sWorld->LoadDBVersion();
666
667 TC_LOG_INFO("server.worldserver", "Using World DB: {}", sWorld->GetDBVersion());
668 return true;
669}
670
671void StopDB()
672{
673 HotfixDatabase.Close();
674 WorldDatabase.Close();
675 CharacterDatabase.Close();
676 LoginDatabase.Close();
677
679}
680
683{
684 // Reset online status for all accounts with characters on the current realm
685 LoginDatabase.DirectPExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = {})", realmId);
686
687 // Reset online status for all characters
688 CharacterDatabase.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");
689
690 // Battleground instance ids reset at server restart
691 CharacterDatabase.DirectExecute("UPDATE character_battleground_data SET instanceId = 0");
692}
693
694variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, [[maybe_unused]] std::string& winServiceAction)
695{
696 options_description all("Allowed options");
697 all.add_options()
698 ("help,h", "print usage message")
699 ("version,v", "print version build info")
700 ("config,c", value<fs::path>(&configFile)->default_value(fs::absolute(_TRINITY_CORE_CONFIG)),
701 "use <arg> as configuration file")
702 ("config-dir,cd", value<fs::path>(&configDir)->default_value(fs::absolute(_TRINITY_CORE_CONFIG_DIR)),
703 "use <arg> as directory with additional config files")
704 ("update-databases-only,u", "updates databases only")
705 ;
706#ifdef _WIN32
707 options_description win("Windows platform specific options");
708 win.add_options()
709 ("service,s", value<std::string>(&winServiceAction)->default_value(""), "Windows service options: [install | uninstall]")
710 ;
711
712 all.add(win);
713#endif
714 variables_map vm;
715 try
716 {
717 store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), vm);
718 notify(vm);
719 }
720 catch (std::exception& e)
721 {
722 std::cerr << e.what() << "\n";
723 }
724
725 if (vm.count("help"))
726 {
727 std::cout << all << "\n";
728 }
729 else if (vm.count("version"))
730 {
731 std::cout << GitRevision::GetFullVersion() << "\n";
732 }
733
734 return vm;
735}
736
737#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
739// must be at end of file because of init_seg pragma
741#endif
#define sBattlegroundMgr
#define sConfigMgr
Definition Config.h:64
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
DatabaseWorkerPool< HotfixDatabaseConnection > HotfixDatabase
Accessor to the hotfix database.
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define ABORT_MSG
Definition Errors.h:88
#define sInstanceLockMgr
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
#define sLog
Definition Log.h:156
#define sMapMgr
Definition MapManager.h:186
#define sMetric
Definition Metric.h:160
#define TC_METRIC_EVENT(category, title, description)
Definition Metric.h:201
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:93
void AddScripts()
#define sScriptMgr
Definition ScriptMgr.h:1449
#define sScriptReloadMgr
#define sSecretMgr
Definition SecretMgr.h:87
@ SECRET_OWNER_WORLDSERVER
Definition SecretMgr.h:40
std::thread * CreateSoapThread(const std::string &host, uint16 port)
Definition TCSoap.cpp:28
#define sTerrainMgr
Definition TerrainMgr.h:167
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:277
#define sWorldSocketMgr
void SetRand(int32 numbits)
Definition BigNumber.cpp:76
DatabaseLoader & AddDatabase(DatabaseWorkerPool< T > &pool, std::string const &name)
uint32 _lastChangeMsTime
Definition Main.cpp:115
uint32 _worldLoopCounter
Definition Main.cpp:114
uint32 _maxCoreStuckTimeInMs
Definition Main.cpp:116
static void Start(std::shared_ptr< FreezeDetector > const &freezeDetector)
Definition Main.cpp:101
static void Handler(std::weak_ptr< FreezeDetector > freezeDetectorRef, boost::system::error_code const &error)
Definition Main.cpp:592
Trinity::Asio::DeadlineTimer _timer
Definition Main.cpp:113
FreezeDetector(Trinity::Asio::IoContext &ioContext, uint32 maxCoreStuckTime)
Definition Main.cpp:98
void Unload()
Definition Metric.cpp:247
Manages all sockets connected to peers and network threads.
void StopNetwork() override
Stops all network threads, It will wait for all running threads .
static uint8 GetExitCode()
Definition World.h:666
static std::atomic< uint32 > m_worldLoopCounter
Definition World.h:564
static void StopNow(uint8 exitcode)
Definition World.h:667
static bool IsStopped()
Definition World.h:668
void CliThread()
Thread start
#define sWorld
Definition World.h:916
@ CONFIG_PORT_WORLD
Definition World.h:243
@ SHUTDOWN_EXIT_CODE
Definition World.h:75
@ ERROR_EXIT_CODE
Definition World.h:76
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
@ REALM_FLAG_OFFLINE
Definition Realm.h:60
TC_COMMON_API void Init()
Definition Locales.cpp:28
boost::asio::basic_stream_socket< boost::asio::ip::tcp, boost::asio::io_context::executor_type > IoContextTcpSocket
Definition Socket.h:40
TC_NETWORK_API void ScanLocalNetworks()
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:35
std::unique_ptr< T, Impl::stateful_unique_ptr_deleter< Ptr, Del > > make_unique_ptr_with_deleter(Ptr ptr, Del deleter)
Definition Memory.h:133
void AbortHandler(int sigval) noexcept
Definition Errors.cpp:160
void operator()(std::thread *cliThread) const
Definition Main.cpp:470
void operator()(std::thread *thread) const
Definition Main.cpp:464
bool StartDB()
Initialize connection to the databases.
Definition Main.cpp:647
int main(int argc, char **argv)
Launch the Trinity server.
Definition Main.cpp:130
variables_map GetConsoleArguments(int argc, char **argv, fs::path &configFile, fs::path &configDir, std::string &winServiceAction)
Definition Main.cpp:694
std::unique_ptr< Trinity::Net::AsyncAcceptor > StartRaSocketAcceptor(Trinity::Asio::IoContext &ioContext)
Definition Main.cpp:626
void WorldUpdateLoop()
Definition Main.cpp:535
void StopDB()
Definition Main.cpp:671
void ClearOnlineAccounts(uint32 realmId)
Clear 'online' status for all accounts with characters in this realm.
Definition Main.cpp:682
int m_ServiceStatus
Definition Main.cpp:89
TCHAR serviceLongName[]
Definition Main.cpp:81
void SignalHandler(boost::system::error_code const &error, int signalNumber)
Definition Main.cpp:586
#define _TRINITY_CORE_CONFIG
Definition Main.cpp:70
TCHAR serviceName[]
Definition Main.cpp:80
TCHAR serviceDescription[]
Definition Main.cpp:82
#define _TRINITY_CORE_CONFIG_DIR
Definition Main.cpp:74
INIT_CRASH_HANDLER()