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
26#include "AppenderDB.h"
27#include "AuthSocketMgr.h"
28#include "Banner.h"
29#include "Config.h"
30#include "DatabaseEnv.h"
31#include "DatabaseLoader.h"
32#include "DeadlineTimer.h"
33#include "IoContext.h"
34#include "IPLocation.h"
35#include "GitRevision.h"
36#include "Locales.h"
37#include "MySQLThreading.h"
38#include "OpenSSLCrypto.h"
39#include "ProcessPriority.h"
40#include "RealmList.h"
41#include "SecretMgr.h"
42#include "SharedDefines.h"
43#include "Util.h"
44#include <boost/asio/signal_set.hpp>
45#include <boost/dll/runtime_symbol_info.hpp>
46#include <boost/program_options.hpp>
47#include <boost/filesystem/operations.hpp>
48#include <openssl/crypto.h>
49#include <openssl/opensslv.h>
50#include <iostream>
51#include <csignal>
52
53using boost::asio::ip::tcp;
54using namespace boost::program_options;
55namespace fs = boost::filesystem;
56
57#ifndef _TRINITY_REALM_CONFIG
58# define _TRINITY_REALM_CONFIG "authserver.conf"
59#endif
60#ifndef _TRINITY_REALM_CONFIG_DIR
61 #define _TRINITY_REALM_CONFIG_DIR "authserver.conf.d"
62#endif
63
64#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
65#include "ServiceWin32.h"
66#include <tchar.h>
67TCHAR serviceName[] = _T("authserver");
68TCHAR serviceLongName[] = _T("TrinityCore auth service");
69TCHAR serviceDescription[] = _T("TrinityCore World of Warcraft emulator auth service");
70/*
71* -1 - not in service mode
72* 0 - stopped
73* 1 - running
74* 2 - paused
75*/
77
78void ServiceStatusWatcher(std::weak_ptr<Trinity::Asio::DeadlineTimer> serviceStatusWatchTimerRef, std::weak_ptr<Trinity::Asio::IoContext> ioContextRef, boost::system::error_code const& error);
79#endif
80
81bool StartDB();
82void StopDB();
83void SignalHandler(std::weak_ptr<Trinity::Asio::IoContext> ioContextRef, boost::system::error_code const& error, int signalNumber);
84void KeepDatabaseAliveHandler(std::weak_ptr<Trinity::Asio::DeadlineTimer> dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const& error);
85void BanExpiryHandler(std::weak_ptr<Trinity::Asio::DeadlineTimer> banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const& error);
86variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, std::string& winServiceAction);
87
88int main(int argc, char** argv)
89{
91 signal(SIGABRT, &Trinity::AbortHandler);
92
94
96
97 auto configFile = fs::absolute(_TRINITY_REALM_CONFIG);
98 auto configDir = fs::absolute(_TRINITY_REALM_CONFIG_DIR);
99 std::string winServiceAction;
100 auto vm = GetConsoleArguments(argc, argv, configFile, configDir, winServiceAction);
101 // exit if help or version is enabled
102 if (vm.count("help") || vm.count("version"))
103 return 0;
104
105#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
107 if (winServiceAction == "install")
109 if (winServiceAction == "uninstall")
111 if (winServiceAction == "run")
112 return Trinity::Service::Run();
113#endif
114
115 std::string configError;
116 if (!sConfigMgr->LoadInitial(configFile.generic_string(),
117 std::vector<std::string>(argv, argv + argc),
118 configError))
119 {
120 printf("Error in config file: %s\n", configError.c_str());
121 return 1;
122 }
123
124 std::vector<std::string> loadedConfigFiles;
125 std::vector<std::string> configDirErrors;
126 bool additionalConfigFileLoadSuccess = sConfigMgr->LoadAdditionalDir(configDir.generic_string(), true, loadedConfigFiles, configDirErrors);
127 for (std::string const& loadedConfigFile : loadedConfigFiles)
128 printf("Loaded additional config file %s\n", loadedConfigFile.c_str());
129
130 if (!additionalConfigFileLoadSuccess)
131 {
132 for (std::string const& configDirError : configDirErrors)
133 printf("Error in additional config files: %s\n", configDirError.c_str());
134
135 return 1;
136 }
137
138 std::vector<std::string> overriddenKeys = sConfigMgr->OverrideWithEnvVariablesIfAny();
139
140 sLog->RegisterAppender<AppenderDB>();
141 sLog->Initialize(nullptr);
142
143 Trinity::Banner::Show("authserver",
144 [](char const* text)
145 {
146 TC_LOG_INFO("server.authserver", "{}", text);
147 },
148 []()
149 {
150 TC_LOG_INFO("server.authserver", "Using configuration file {}.", sConfigMgr->GetFilename());
151 TC_LOG_INFO("server.authserver", "Using SSL version: {} (library: {})", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
152 TC_LOG_INFO("server.authserver", "Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
153 }
154 );
155
156 for (std::string const& key : overriddenKeys)
157 TC_LOG_INFO("server.authserver", "Configuration field '{}' was overridden with environment variable.", key);
158
159 OpenSSLCrypto::threadsSetup(boost::dll::program_location().remove_filename());
160
161 std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });
162
163 // authserver PID file creation
164 std::string pidFile = sConfigMgr->GetStringDefault("PidFile", "");
165 if (!pidFile.empty())
166 {
167 if (uint32 pid = CreatePIDFile(pidFile))
168 TC_LOG_INFO("server.authserver", "Daemon PID: {}\n", pid);
169 else
170 {
171 TC_LOG_ERROR("server.authserver", "Cannot create PID file {}.\n", pidFile);
172 return 1;
173 }
174 }
175
176 // Initialize the database connection
177 if (!StartDB())
178 return 1;
179
180 std::shared_ptr<void> dbHandle(nullptr, [](void*) { StopDB(); });
181
182 if (vm.count("update-databases-only"))
183 return 0;
184
185 sSecretMgr->Initialize();
186
187 // Load IP Location Database
188 sIPLocation->Load();
189
190 std::shared_ptr<Trinity::Asio::IoContext> ioContext = std::make_shared<Trinity::Asio::IoContext>();
191
192 // Get the list of realms for the server
193 sRealmList->Initialize(*ioContext, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
194
195 std::shared_ptr<void> sRealmListHandle(nullptr, [](void*) { sRealmList->Close(); });
196
197 // Start the listening port (acceptor) for auth connections
198 int32 port = sConfigMgr->GetIntDefault("RealmServerPort", 3724);
199 if (port < 0 || port > 0xFFFF)
200 {
201 TC_LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)");
202 return 1;
203 }
204
205 std::string bindIp = sConfigMgr->GetStringDefault("BindIP", "0.0.0.0");
206
207 if (!sAuthSocketMgr.StartNetwork(*ioContext, bindIp, port))
208 {
209 TC_LOG_ERROR("server.authserver", "Failed to initialize network");
210 return 1;
211 }
212
213 std::shared_ptr<void> sAuthSocketMgrHandle(nullptr, [](void*) { sAuthSocketMgr.StopNetwork(); });
214
215 // Set signal handlers
216 boost::asio::signal_set signals(*ioContext, SIGINT, SIGTERM);
217#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
218 signals.add(SIGBREAK);
219#endif
220 signals.async_wait(std::bind(&SignalHandler, std::weak_ptr<Trinity::Asio::IoContext>(ioContext), std::placeholders::_1, std::placeholders::_2));
221
222 // Set process priority according to configuration settings
223 SetProcessPriority("server.authserver", sConfigMgr->GetIntDefault(CONFIG_PROCESSOR_AFFINITY, 0), sConfigMgr->GetBoolDefault(CONFIG_HIGH_PRIORITY, false));
224
225 // Enabled a timed callback for handling the database keep alive ping
226 int32 dbPingInterval = sConfigMgr->GetIntDefault("MaxPingTime", 30);
227 std::shared_ptr<Trinity::Asio::DeadlineTimer> dbPingTimer = std::make_shared<Trinity::Asio::DeadlineTimer>(*ioContext);
228 dbPingTimer->expires_after(std::chrono::minutes(dbPingInterval));
229 dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, std::weak_ptr<Trinity::Asio::DeadlineTimer>(dbPingTimer), dbPingInterval, std::placeholders::_1));
230
231 int32 banExpiryCheckInterval = sConfigMgr->GetIntDefault("BanExpiryCheckInterval", 60);
232 std::shared_ptr<Trinity::Asio::DeadlineTimer> banExpiryCheckTimer = std::make_shared<Trinity::Asio::DeadlineTimer>(*ioContext);
233 banExpiryCheckTimer->expires_after(std::chrono::seconds(banExpiryCheckInterval));
234 banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, std::weak_ptr<Trinity::Asio::DeadlineTimer>(banExpiryCheckTimer), banExpiryCheckInterval, std::placeholders::_1));
235
236#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
237 std::shared_ptr<Trinity::Asio::DeadlineTimer> serviceStatusWatchTimer;
238 if (m_ServiceStatus != -1)
239 {
240 serviceStatusWatchTimer = std::make_shared<Trinity::Asio::DeadlineTimer>(*ioContext);
241 serviceStatusWatchTimer->expires_after(1s);
242 serviceStatusWatchTimer->async_wait(std::bind(&ServiceStatusWatcher,
243 std::weak_ptr<Trinity::Asio::DeadlineTimer>(serviceStatusWatchTimer),
244 std::weak_ptr<Trinity::Asio::IoContext>(ioContext),
245 std::placeholders::_1));
246 }
247#endif
248
249 // Start the io service worker loop
250 ioContext->run();
251
252 banExpiryCheckTimer->cancel();
253 dbPingTimer->cancel();
254
255 TC_LOG_INFO("server.authserver", "Halting process...");
256
257 signals.cancel();
258
259 return 0;
260}
261
264{
266
267 // Load databases
268 // NOTE: While authserver is singlethreaded you should keep synch_threads == 1.
269 // Increasing it is just silly since only 1 will be used ever.
270 DatabaseLoader loader("server.authserver", DatabaseLoader::DATABASE_NONE);
271 loader
272 .AddDatabase(LoginDatabase, "Login");
273
274 if (!loader.Load())
275 return false;
276
277 TC_LOG_INFO("server.authserver", "Started auth database connection pool.");
278 sLog->SetRealmId(0); // Enables DB appenders when realm is set.
279 return true;
280}
281
283void StopDB()
284{
285 LoginDatabase.Close();
287}
288
289void SignalHandler(std::weak_ptr<Trinity::Asio::IoContext> ioContextRef, boost::system::error_code const& error, int /*signalNumber*/)
290{
291 if (!error)
292 if (std::shared_ptr<Trinity::Asio::IoContext> ioContext = ioContextRef.lock())
293 ioContext->stop();
294}
295
296void KeepDatabaseAliveHandler(std::weak_ptr<Trinity::Asio::DeadlineTimer> dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const& error)
297{
298 if (!error)
299 {
300 if (std::shared_ptr<Trinity::Asio::DeadlineTimer> dbPingTimer = dbPingTimerRef.lock())
301 {
302 TC_LOG_DEBUG("sql.driver", "Ping MySQL to keep connection alive");
303 LoginDatabase.KeepAlive();
304
305 dbPingTimer->expires_after(std::chrono::minutes(dbPingInterval));
306 dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, dbPingTimerRef, dbPingInterval, std::placeholders::_1));
307 }
308 }
309}
310
311void BanExpiryHandler(std::weak_ptr<Trinity::Asio::DeadlineTimer> banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const& error)
312{
313 if (!error)
314 {
315 if (std::shared_ptr<Trinity::Asio::DeadlineTimer> banExpiryCheckTimer = banExpiryCheckTimerRef.lock())
316 {
317 LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
318 LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS));
319
320 banExpiryCheckTimer->expires_after(std::chrono::seconds(banExpiryCheckInterval));
321 banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, banExpiryCheckTimerRef, banExpiryCheckInterval, std::placeholders::_1));
322 }
323 }
324}
325
326#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
327void ServiceStatusWatcher(std::weak_ptr<Trinity::Asio::DeadlineTimer> serviceStatusWatchTimerRef, std::weak_ptr<Trinity::Asio::IoContext> ioContextRef, boost::system::error_code const& error)
328{
329 if (!error)
330 {
331 if (std::shared_ptr<Trinity::Asio::IoContext> ioContext = ioContextRef.lock())
332 {
333 if (m_ServiceStatus == 0)
334 ioContext->stop();
335 else if (std::shared_ptr<Trinity::Asio::DeadlineTimer> serviceStatusWatchTimer = serviceStatusWatchTimerRef.lock())
336 {
337 serviceStatusWatchTimer->expires_after(1s);
338 serviceStatusWatchTimer->async_wait(std::bind(&ServiceStatusWatcher, serviceStatusWatchTimerRef, ioContextRef, std::placeholders::_1));
339 }
340 }
341 }
342}
343#endif
344
345variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, fs::path& configDir, [[maybe_unused]] std::string& winServiceAction)
346{
347 options_description all("Allowed options");
348 all.add_options()
349 ("help,h", "print usage message")
350 ("version,v", "print version build info")
351 ("config,c", value<fs::path>(&configFile)->default_value(fs::absolute(_TRINITY_REALM_CONFIG)),
352 "use <arg> as configuration file")
353 ("config-dir,cd", value<fs::path>(&configDir)->default_value(fs::absolute(_TRINITY_REALM_CONFIG_DIR)),
354 "use <arg> as directory with additional config files")
355 ("update-databases-only,u", "updates databases only")
356 ;
357#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
358 options_description win("Windows platform specific options");
359 win.add_options()
360 ("service,s", value<std::string>(&winServiceAction)->default_value(""), "Windows service options: [install | uninstall]")
361 ;
362
363 all.add(win);
364#endif
365 variables_map variablesMap;
366 try
367 {
368 store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap);
369 notify(variablesMap);
370 }
371 catch (std::exception& e)
372 {
373 std::cerr << e.what() << "\n";
374 }
375
376 if (variablesMap.count("help"))
377 std::cout << all << "\n";
378 else if (variablesMap.count("version"))
379 std::cout << GitRevision::GetFullVersion() << "\n";
380
381 return variablesMap;
382}
383
384#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
386// must be at end of file because of init_seg pragma
388#endif
#define sAuthSocketMgr
#define sConfigMgr
Definition Config.h:60
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
#define sIPLocation
Definition IPLocation.h:48
#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
@ LOGIN_DEL_EXPIRED_IP_BANS
@ LOGIN_UPD_EXPIRED_ACCOUNT_BANS
void SetProcessPriority(std::string const &logChannel, uint32 affinity, bool highPriority)
#define CONFIG_HIGH_PRIORITY
#define CONFIG_PROCESSOR_AFFINITY
#define sRealmList
Definition RealmList.h:63
#define sSecretMgr
Definition SecretMgr.h:73
@ SERVER_PROCESS_AUTHSERVER
uint32 CreatePIDFile(std::string const &filename)
create PID file
Definition Util.cpp:324
bool StartDB()
Initialize connection to the database.
Definition Main.cpp:263
void ServiceStatusWatcher(std::weak_ptr< Trinity::Asio::DeadlineTimer > serviceStatusWatchTimerRef, std::weak_ptr< Trinity::Asio::IoContext > ioContextRef, boost::system::error_code const &error)
Definition Main.cpp:327
void BanExpiryHandler(std::weak_ptr< Trinity::Asio::DeadlineTimer > banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const &error)
Definition Main.cpp:311
#define _TRINITY_REALM_CONFIG_DIR
Definition Main.cpp:61
void SignalHandler(std::weak_ptr< Trinity::Asio::IoContext > ioContextRef, boost::system::error_code const &error, int signalNumber)
Definition Main.cpp:289
int main(int argc, char **argv)
Definition Main.cpp:88
#define _TRINITY_REALM_CONFIG
Definition Main.cpp:58
variables_map GetConsoleArguments(int argc, char **argv, fs::path &configFile, fs::path &configDir, std::string &winServiceAction)
Definition Main.cpp:345
void KeepDatabaseAliveHandler(std::weak_ptr< Trinity::Asio::DeadlineTimer > dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const &error)
Definition Main.cpp:296
void StopDB()
Close the connection to the database.
Definition Main.cpp:283
int m_ServiceStatus
Definition Main.cpp:76
TCHAR serviceLongName[]
Definition Main.cpp:68
TCHAR serviceName[]
Definition Main.cpp:67
TCHAR serviceDescription[]
Definition Main.cpp:69
INIT_CRASH_HANDLER()
DatabaseLoader & AddDatabase(DatabaseWorkerPool< T > &pool, std::string const &name)
TC_COMMON_API char const * GetFullVersion()
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
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