AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
Main.cpp File Reference
#include "AppenderDB.h"
#include "AuthSocketMgr.h"
#include "Banner.h"
#include "Config.h"
#include "DBUpdater.h"
#include "DatabaseEnv.h"
#include "DatabaseLoader.h"
#include "GitRevision.h"
#include "IPLocation.h"
#include "IoContext.h"
#include "Log.h"
#include "MySQLThreading.h"
#include "OpenSSLCrypto.h"
#include "ProcessPriority.h"
#include "RealmList.h"
#include "SecretMgr.h"
#include "SharedDefines.h"
#include "SteadyTimer.h"
#include "Util.h"
#include <boost/asio/signal_set.hpp>
#include <boost/program_options.hpp>
#include <boost/version.hpp>
#include <csignal>
#include <filesystem>
#include <iostream>
#include <openssl/crypto.h>
#include <openssl/opensslv.h>

Go to the source code of this file.

Macros

#define _ACORE_REALM_CONFIG   "authserver.conf"
 

Functions

bool StartDB ()
 Initialize connection to the database.
 
void StopDB ()
 Close the connection to the database.
 
void SignalHandler (std::weak_ptr< Acore::Asio::IoContext > ioContextRef, boost::system::error_code const &error, int signalNumber)
 
void KeepDatabaseAliveHandler (std::weak_ptr< boost::asio::steady_timer > dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const &error)
 
void BanExpiryHandler (std::weak_ptr< boost::asio::steady_timer > banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const &error)
 
variables_map GetConsoleArguments (int argc, char **argv, fs::path &configFile)
 
int main (int argc, char **argv)
 Launch the auth server.
 

Macro Definition Documentation

◆ _ACORE_REALM_CONFIG

#define _ACORE_REALM_CONFIG   "authserver.conf"

Function Documentation

◆ BanExpiryHandler()

void BanExpiryHandler ( std::weak_ptr< boost::asio::steady_timer >  banExpiryCheckTimerRef,
int32  banExpiryCheckInterval,
boost::system::error_code const &  error 
)
275{
276 if (!error)
277 {
278 if (std::shared_ptr<boost::asio::steady_timer> banExpiryCheckTimer = banExpiryCheckTimerRef.lock())
279 {
280 LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));
281 LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS));
282
283 banExpiryCheckTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(banExpiryCheckInterval));
284 banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, banExpiryCheckTimerRef, banExpiryCheckInterval, std::placeholders::_1));
285 }
286 }
287}
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition DatabaseEnv.cpp:22
@ LOGIN_DEL_EXPIRED_IP_BANS
Definition LoginDatabase.h:32
@ LOGIN_UPD_EXPIRED_ACCOUNT_BANS
Definition LoginDatabase.h:33
auto GetExpirationTime(int32 seconds)
Definition SteadyTimer.h:25
void BanExpiryHandler(std::weak_ptr< boost::asio::steady_timer > banExpiryCheckTimerRef, int32 banExpiryCheckInterval, boost::system::error_code const &error)
Definition Main.cpp:274

References BanExpiryHandler(), Acore::Asio::SteadyTimer::GetExpirationTime(), LOGIN_DEL_EXPIRED_IP_BANS, LOGIN_UPD_EXPIRED_ACCOUNT_BANS, and LoginDatabase.

Referenced by BanExpiryHandler(), and main().

◆ GetConsoleArguments()

variables_map GetConsoleArguments ( int  argc,
char **  argv,
fs::path &  configFile 
)
290{
291 options_description all("Allowed options");
292 all.add_options()
293 ("help,h", "print usage message")
294 ("version,v", "print version build info")
295 ("dry-run,d", "Dry run")
296 ("config,c", value<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_REALM_CONFIG))), "use <arg> as configuration file")
297 ("config-policy", value<std::string>()->value_name("policy"), "override config severity policy (e.g. default=skip,critical_option=fatal)");
298
299 variables_map variablesMap;
300
301 try
302 {
303 store(command_line_parser(argc, argv).options(all).allow_unregistered().run(), variablesMap);
304 notify(variablesMap);
305 }
306 catch (std::exception const& e)
307 {
308 std::cerr << e.what() << "\n";
309 }
310
311 if (variablesMap.count("help"))
312 std::cout << all << "\n";
313 else if (variablesMap.count("version"))
314 std::cout << GitRevision::GetFullVersion() << "\n";
315 else if (variablesMap.count("dry-run"))
316 sConfigMgr->setDryRun(true);
317
318 return variablesMap;
319}
#define sConfigMgr
Definition Config.h:93
AC_COMMON_API char const * GetFullVersion()
Definition GitRevision.cpp:82
#define _ACORE_REALM_CONFIG
Definition Main.cpp:55

References _ACORE_REALM_CONFIG, GitRevision::GetFullVersion(), and sConfigMgr.

Referenced by main().

◆ KeepDatabaseAliveHandler()

void KeepDatabaseAliveHandler ( std::weak_ptr< boost::asio::steady_timer >  dbPingTimerRef,
int32  dbPingInterval,
boost::system::error_code const &  error 
)
260{
261 if (!error)
262 {
263 if (std::shared_ptr<boost::asio::steady_timer> dbPingTimer = dbPingTimerRef.lock())
264 {
265 LOG_DEBUG("sql.driver", "Ping MySQL to keep connection alive");
266 LoginDatabase.KeepAlive();
267
268 dbPingTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(dbPingInterval));
269 dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, dbPingTimerRef, dbPingInterval, std::placeholders::_1));
270 }
271 }
272}
#define LOG_DEBUG(filterType__,...)
Definition Log.h:157
void KeepDatabaseAliveHandler(std::weak_ptr< boost::asio::steady_timer > dbPingTimerRef, int32 dbPingInterval, boost::system::error_code const &error)
Definition Main.cpp:259

References Acore::Asio::SteadyTimer::GetExpirationTime(), KeepDatabaseAliveHandler(), LOG_DEBUG, and LoginDatabase.

Referenced by KeepDatabaseAliveHandler(), and main().

◆ main()

int main ( int  argc,
char **  argv 
)

Launch the auth server.

71{
73 signal(SIGABRT, &Acore::AbortHandler);
74
75 // Command line parsing
76 auto configFile = fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_REALM_CONFIG));
77 auto vm = GetConsoleArguments(argc, argv, configFile);
78
79 // exit if help or version is enabled
80 if (vm.count("help") || vm.count("version"))
81 return 0;
82
83 // Add file and args in config
84 sConfigMgr->Configure(configFile.generic_string(), std::vector<std::string>(argv, argv + argc));
85
86 if (!sConfigMgr->LoadAppConfigs())
87 return 1;
88
89 // Init logging
90 sLog->RegisterAppender<AppenderDB>();
91 sLog->Initialize(nullptr);
92
93 Acore::Banner::Show("authserver",
94 [](std::string_view text)
95 {
96 LOG_INFO("server.authserver", text);
97 },
98 []()
99 {
100 LOG_INFO("server.authserver", "> Using configuration file {}", sConfigMgr->GetFilename());
101 LOG_INFO("server.authserver", "> Using SSL version: {} (library: {})", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
102 LOG_INFO("server.authserver", "> Using Boost version: {}.{}.{}", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
103 });
104
106
107 std::shared_ptr<void> opensslHandle(nullptr, [](void*) { OpenSSLCrypto::threadsCleanup(); });
108
109 // authserver PID file creation
110 std::string pidFile = sConfigMgr->GetOption<std::string>("PidFile", "");
111 if (!pidFile.empty())
112 {
113 if (uint32 pid = CreatePIDFile(pidFile))
114 LOG_INFO("server.authserver", "Daemon PID: {}\n", pid); // outError for red color in console
115 else
116 {
117 LOG_ERROR("server.authserver", "Cannot create PID file {} (possible error: permission)\n", pidFile);
118 return 1;
119 }
120 }
121
122 // Initialize the database connection
123 if (!StartDB())
124 return 1;
125
126 sSecretMgr->Initialize();
127
128 // Load IP Location Database
129 sIPLocation->Load();
130
131 std::shared_ptr<void> dbHandle(nullptr, [](void*) { StopDB(); });
132
133 // Mark every realm offline on startup; each worldserver clears this flag for its own realm once it is ready.
134 // This prevents realms from appearing online in the realm list when no worldserver is actually running.
135 LoginDatabase.DirectExecute("UPDATE realmlist SET flag = flag | {}", REALM_FLAG_OFFLINE);
136
137 std::shared_ptr<Acore::Asio::IoContext> ioContext = std::make_shared<Acore::Asio::IoContext>();
138
139 // Get the list of realms for the server
140 sRealmList->Initialize(*ioContext, sConfigMgr->GetOption<int32>("RealmsStateUpdateDelay", 20));
141
142 std::shared_ptr<void> sRealmListHandle(nullptr, [](void*) { sRealmList->Close(); });
143
144 if (sRealmList->GetRealms().empty())
145 {
146 LOG_ERROR("server.authserver", "No valid realms specified. Possible reasons:");
147 LOG_ERROR("server.authserver", "- the realmlist table of the auth database is empty");
148 LOG_ERROR("server.authserver", "- every realm has flag 3 (REALM_FLAG_VERSION_MISMATCH | REALM_FLAG_OFFLINE), which the realm list "
149 "query excludes. Reset it with: UPDATE realmlist SET flag = 0 WHERE id = <realm id>;");
150 LOG_ERROR("server.authserver", "- no realm address could be resolved, see the resolver errors logged above");
151 return 1;
152 }
153
154 // Stop auth server if dry run
155 if (sConfigMgr->isDryRun())
156 {
158 {
159 LOG_FATAL("server.authserver", "Dry run completed with {} failed database update(s), terminating.", failed);
160 return 1;
161 }
162
163 LOG_INFO("server.authserver", "Dry run completed, terminating.");
164 return 0;
165 }
166
167 // Start the listening port (acceptor) for auth connections
168 int32 port = sConfigMgr->GetOption<int32>("RealmServerPort", 3724);
169 if (port < 0 || port > 0xFFFF)
170 {
171 LOG_ERROR("server.authserver", "Specified port out of allowed range (1-65535)");
172 return 1;
173 }
174
175 std::string bindIp = sConfigMgr->GetOption<std::string>("BindIP", "0.0.0.0");
176
177 if (!sAuthSocketMgr.StartNetwork(*ioContext, bindIp, port))
178 {
179 LOG_ERROR("server.authserver", "Failed to initialize network");
180 return 1;
181 }
182
183 std::shared_ptr<void> sAuthSocketMgrHandle(nullptr, [](void*) { sAuthSocketMgr.StopNetwork(); });
184
185 // Set signal handlers
186 boost::asio::signal_set signals(*ioContext, SIGINT, SIGTERM);
187#if AC_PLATFORM == AC_PLATFORM_WINDOWS
188 signals.add(SIGBREAK);
189#endif
190 signals.async_wait(std::bind(&SignalHandler, std::weak_ptr<Acore::Asio::IoContext>(ioContext), std::placeholders::_1, std::placeholders::_2));
191
192 // Set process priority according to configuration settings
193 SetProcessPriority("server.authserver", sConfigMgr->GetOption<int32>(CONFIG_PROCESSOR_AFFINITY, 0), sConfigMgr->GetOption<bool>(CONFIG_HIGH_PRIORITY, false));
194
195 // Enabled a timed callback for handling the database keep alive ping
196 int32 dbPingInterval = sConfigMgr->GetOption<int32>("MaxPingTime", 30);
197 std::shared_ptr<boost::asio::steady_timer> dbPingTimer = std::make_shared<boost::asio::steady_timer>(*ioContext);
198
199 dbPingTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(dbPingInterval * MINUTE));
200 dbPingTimer->async_wait(std::bind(&KeepDatabaseAliveHandler, std::weak_ptr<boost::asio::steady_timer>(dbPingTimer), dbPingInterval, std::placeholders::_1));
201
202 int32 banExpiryCheckInterval = sConfigMgr->GetOption<int32>("BanExpiryCheckInterval", 60);
203 std::shared_ptr<boost::asio::steady_timer> banExpiryCheckTimer = std::make_shared<boost::asio::steady_timer>(*ioContext);
204
205 banExpiryCheckTimer->expires_at(Acore::Asio::SteadyTimer::GetExpirationTime(banExpiryCheckInterval));
206 banExpiryCheckTimer->async_wait(std::bind(&BanExpiryHandler, std::weak_ptr<boost::asio::steady_timer>(banExpiryCheckTimer), banExpiryCheckInterval, std::placeholders::_1));
207
208 // Start the io service worker loop
209 ioContext->run();
210
211 banExpiryCheckTimer->cancel();
212 dbPingTimer->cancel();
213
214 LOG_INFO("server.authserver", "Halting process...");
215
216 signals.cancel();
217
218 return 0;
219}
#define sAuthSocketMgr
Definition AuthSocketMgr.h:63
constexpr auto MINUTE
Definition Common.h:47
std::int32_t int32
Definition Define.h:103
std::uint32_t uint32
Definition Define.h:107
#define sIPLocation
Definition IPLocation.h:49
#define LOG_FATAL(filterType__,...)
Definition Log.h:141
#define LOG_INFO(filterType__,...)
Definition Log.h:153
#define LOG_ERROR(filterType__,...)
Definition Log.h:145
#define sLog
Definition Log.h:127
void SetProcessPriority(std::string const &logChannel, uint32 affinity, bool highPriority)
Definition ProcessPriority.cpp:29
#define CONFIG_HIGH_PRIORITY
Definition ProcessPriority.h:25
#define CONFIG_PROCESSOR_AFFINITY
Definition ProcessPriority.h:24
#define sRealmList
Definition RealmList.h:83
@ REALM_FLAG_OFFLINE
Definition Realm.h:29
#define sSecretMgr
Definition SecretMgr.h:72
@ SERVER_PROCESS_AUTHSERVER
Definition SharedDefines.h:3994
uint32 CreatePIDFile(std::string const &filename)
create PID file
Definition Util.cpp:218
Definition AppenderDB.h:25
static uint32 GetFailedUpdateCount()
Definition DBUpdater.cpp:78
AC_COMMON_API void Show(std::string_view applicationName, void(*log)(std::string_view text), void(*logExtraInfo)())
Definition Banner.cpp:22
AC_COMMON_API void AbortHandler(int sigval)
Definition Errors.cpp:148
AC_COMMON_API void threadsSetup()
Needs to be called before threads using openssl are spawned.
Definition OpenSSLCrypto.cpp:41
AC_COMMON_API void threadsCleanup()
Needs to be called after threads using openssl are despawned.
Definition OpenSSLCrypto.cpp:50
bool StartDB()
Initialize connection to the database.
Definition Main.cpp:222
variables_map GetConsoleArguments(int argc, char **argv, fs::path &configFile)
Definition Main.cpp:289
void StopDB()
Close the connection to the database.
Definition Main.cpp:242
void SignalHandler(std::weak_ptr< Acore::Asio::IoContext > ioContextRef, boost::system::error_code const &error, int signalNumber)
Definition Main.cpp:248
static ServerProcessTypes _type
Definition SharedDefines.h:4019

References _ACORE_REALM_CONFIG, Acore::Impl::CurrentServerProcessHolder::_type, Acore::AbortHandler(), BanExpiryHandler(), CONFIG_HIGH_PRIORITY, CONFIG_PROCESSOR_AFFINITY, CreatePIDFile(), GetConsoleArguments(), Acore::Asio::SteadyTimer::GetExpirationTime(), DBUpdaterUtil::GetFailedUpdateCount(), KeepDatabaseAliveHandler(), LOG_ERROR, LOG_FATAL, LOG_INFO, LoginDatabase, MINUTE, REALM_FLAG_OFFLINE, sAuthSocketMgr, sConfigMgr, SERVER_PROCESS_AUTHSERVER, SetProcessPriority(), Acore::Banner::Show(), SignalHandler(), sIPLocation, sLog, sRealmList, sSecretMgr, StartDB(), StopDB(), OpenSSLCrypto::threadsCleanup(), and OpenSSLCrypto::threadsSetup().

◆ SignalHandler()

void SignalHandler ( std::weak_ptr< Acore::Asio::IoContext ioContextRef,
boost::system::error_code const &  error,
int  signalNumber 
)
249{
250 if (!error)
251 {
252 if (std::shared_ptr<Acore::Asio::IoContext> ioContext = ioContextRef.lock())
253 {
254 ioContext->stop();
255 }
256 }
257}

Referenced by main().

◆ StartDB()

bool StartDB ( )

Initialize connection to the database.

223{
225
226 // Load databases
227 // NOTE: While authserver is singlethreaded you should keep synch_threads == 1.
228 // Increasing it is just silly since only 1 will be used ever.
229 DatabaseLoader loader("server.authserver");
230 loader
231 .AddDatabase(LoginDatabase, "Login");
232
233 if (!loader.Load())
234 return false;
235
236 LOG_INFO("server.authserver", "Started auth database connection pool.");
237 sLog->SetRealmId(0); // Enables DB appenders when realm is set.
238 return true;
239}
Definition DatabaseLoader.h:33
AC_DATABASE_API void Library_Init()
Definition MySQLThreading.cpp:21

References DatabaseLoader::AddDatabase(), MySQL::Library_Init(), DatabaseLoader::Load(), LOG_INFO, LoginDatabase, and sLog.

Referenced by main().

◆ StopDB()

void StopDB ( )

Close the connection to the database.

243{
244 LoginDatabase.Close();
246}
AC_DATABASE_API void Library_End()
Definition MySQLThreading.cpp:26

References MySQL::Library_End(), and LoginDatabase.

Referenced by main().