2010-10-07 15:35:36 +02:00
/*
2014-01-01 00:07:53 +01:00
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2008-10-02 16:23:55 -05:00
*/
2013-07-28 18:58:12 +01:00
2012-10-02 23:20:03 +02:00
/**
* @file main.cpp
* @brief Authentication Server main program
*
* This file contains the main program for the
* authentication server
*/
2013-07-28 16:59:07 +01:00
2010-12-27 09:02:02 -08:00
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
2014-05-17 20:27:39 +02:00
#include <iostream>
#include <cstdlib>
#include <boost/date_time/posix_time/posix_time.hpp>
2009-10-17 15:51:44 -07:00
2009-06-04 21:41:07 +02:00
#include "Common.h"
#include "Database/DatabaseEnv.h"
2010-07-29 01:22:45 +02:00
#include "Configuration/Config.h"
2009-06-04 21:41:07 +02:00
#include "Log.h"
2010-08-16 09:51:37 +02:00
#include "SystemConfig.h"
2008-10-02 16:23:55 -05:00
#include "Util.h"
2010-03-09 19:01:45 +03:00
#include "RealmList.h"
2014-07-02 18:05:30 +02:00
#include "AsyncAcceptor.h"
#include "AuthSession.h"
2014-05-17 20:27:39 +02:00
2010-03-09 18:01:42 +03:00
2013-07-28 18:58:12 +01:00
#ifdef __linux__
#include <sched.h>
#include <sys/resource.h>
#define PROCESS_HIGH_PRIORITY -15 // [-20, 19], default is 0
#endif
2008-10-02 16:23:55 -05:00
#ifndef _TRINITY_REALM_CONFIG
2010-06-10 16:39:51 +02:00
# define _TRINITY_REALM_CONFIG "authserver.conf"
2008-10-02 16:23:55 -05:00
#endif
2009-10-17 15:51:44 -07:00
2009-03-20 22:17:39 +01:00
bool StartDB ();
2011-01-13 21:30:37 +01:00
void StopDB ();
2014-05-17 20:27:39 +02:00
void SetProcessPriority ();
2009-10-17 15:51:44 -07:00
2014-05-17 20:27:39 +02:00
boost :: asio :: io_service _ioService ;
boost :: asio :: deadline_timer _dbPingTimer ( _ioService );
uint32 _dbPingInterval ;
2009-10-17 15:51:44 -07:00
2013-07-28 18:58:12 +01:00
LoginDatabaseWorkerPool LoginDatabase ; // Accessor to the authserver database
2009-10-17 15:51:44 -07:00
2014-05-17 20:27:39 +02:00
using boost :: asio :: ip :: tcp ;
void SignalHandler ( const boost :: system :: error_code & error , int signalNumber )
{
2014-05-30 15:46:17 +02:00
if ( ! error )
{
switch ( signalNumber )
{
case SIGINT :
case SIGTERM :
_ioService . stop ();
break ;
}
}
2014-05-17 20:27:39 +02:00
}
void KeepDatabaseAliveHandler ( const boost :: system :: error_code & error )
{
2014-05-30 15:46:17 +02:00
if ( ! error )
{
TC_LOG_INFO ( "server.authserver" , "Ping MySQL to keep connection alive" );
LoginDatabase . KeepAlive ();
2014-05-17 20:27:39 +02:00
2014-05-30 15:46:17 +02:00
_dbPingTimer . expires_from_now ( boost :: posix_time :: minutes ( _dbPingInterval ));
}
2014-05-13 22:41:59 +02:00
}
2010-05-19 21:16:59 +02:00
2008-10-02 16:23:55 -05:00
/// Print out the usage string for this program on the console.
2013-07-28 16:59:07 +01:00
void usage ( const char * prog )
2008-10-02 16:23:55 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.authserver" , "Usage: \n %s [<options>] \n "
2010-12-27 09:02:02 -08:00
" -c config_file use config_file as configuration file \n\r " ,
prog );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2012-10-02 23:20:03 +02:00
/// Launch the auth server
2014-05-17 20:27:39 +02:00
int main ( int argc , char ** argv )
2008-10-02 16:23:55 -05:00
{
2010-12-27 09:02:02 -08:00
// Command line parsing to get the configuration file name
2013-07-28 16:59:07 +01:00
char const * configFile = _TRINITY_REALM_CONFIG ;
int count = 1 ;
while ( count < argc )
2008-10-02 16:23:55 -05:00
{
2013-07-28 16:59:07 +01:00
if ( strcmp ( argv [ count ], "-c" ) == 0 )
2008-10-02 16:23:55 -05:00
{
2013-07-28 16:59:07 +01:00
if ( ++ count >= argc )
2008-10-02 16:23:55 -05:00
{
2012-10-22 10:37:39 +02:00
printf ( "Runtime-Error: -c option requires an input argument \n " );
2008-10-02 16:23:55 -05:00
usage ( argv [ 0 ]);
return 1 ;
}
else
2013-07-28 16:59:07 +01:00
configFile = argv [ count ];
2008-10-02 16:23:55 -05:00
}
2013-07-28 16:59:07 +01:00
++ count ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2013-07-28 16:59:07 +01:00
if ( ! sConfigMgr -> LoadInitial ( configFile ))
2008-10-02 16:23:55 -05:00
{
2013-07-28 16:59:07 +01:00
printf ( "Invalid or missing configuration file : %s \n " , configFile );
2012-10-22 10:37:39 +02:00
printf ( "Verify that the file exists and has \' [authserver] \' written in the top of the file! \n " );
2008-10-02 16:23:55 -05:00
return 1 ;
}
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.authserver" , "%s (authserver)" , _FULLVERSION );
TC_LOG_INFO ( "server.authserver" , "<Ctrl-C> to stop. \n " );
TC_LOG_INFO ( "server.authserver" , "Using configuration file %s." , configFile );
2009-10-17 15:51:44 -07:00
2014-06-28 17:55:40 +02:00
TC_LOG_INFO ( "server.authserver" , "%s (Library: %s)" , OPENSSL_VERSION_TEXT , SSLeay_version ( SSLEAY_VERSION ));
2009-10-17 15:51:44 -07:00
2011-04-12 14:30:18 -04:00
// authserver PID file creation
2013-07-28 16:59:07 +01:00
std :: string pidFile = sConfigMgr -> GetStringDefault ( "PidFile" , "" );
if ( ! pidFile . empty ())
2008-10-02 16:23:55 -05:00
{
2013-07-28 16:59:07 +01:00
if ( uint32 pid = CreatePIDFile ( pidFile ))
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.authserver" , "Daemon PID: %u \n " , pid );
2013-07-28 16:59:07 +01:00
else
2008-10-02 16:23:55 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "server.authserver" , "Cannot create PID file %s. \n " , pidFile . c_str ());
2008-10-02 16:23:55 -05:00
return 1 ;
}
}
2009-10-17 15:51:44 -07:00
2010-12-27 09:02:02 -08:00
// Initialize the database connection
2009-09-19 00:51:47 -04:00
if ( ! StartDB ())
2008-10-02 16:23:55 -05:00
return 1 ;
2009-10-17 15:51:44 -07:00
2010-12-27 09:02:02 -08:00
// Get the list of realms for the server
2014-05-31 15:58:59 +02:00
sRealmList . Initialize ( sConfigMgr -> GetIntDefault ( "RealmsStateUpdateDelay" , 20 ));
if ( sRealmList . size () == 0 )
2008-10-02 16:23:55 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "server.authserver" , "No valid realms specified." );
2008-10-02 16:23:55 -05:00
return 1 ;
}
2009-10-17 15:51:44 -07:00
2010-12-27 09:02:02 -08:00
// Launch the listening network socket
2010-05-13 00:15:21 +02:00
2014-05-17 20:27:39 +02:00
int32 port = sConfigMgr -> GetIntDefault ( "RealmServerPort" , 3724 );
if ( port < 0 || port > 0xFFFF )
2012-08-21 18:20:42 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "server.authserver" , "Specified port out of allowed range (1-65535)" );
2012-08-21 18:20:42 +02:00
return 1 ;
}
2014-05-17 20:27:39 +02:00
std :: string bindIp = sConfigMgr -> GetStringDefault ( "BindIP" , "0.0.0.0" );
2010-04-07 18:09:10 +02:00
2014-07-02 18:05:30 +02:00
AsyncAcceptor < AuthSession > authServer ( _ioService , bindIp , port );
2014-05-13 22:41:59 +02:00
2014-05-30 15:46:17 +02:00
// Set signal handlers
boost :: asio :: signal_set signals ( _ioService , SIGINT , SIGTERM );
signals . async_wait ( SignalHandler );
2009-10-17 15:51:44 -07:00
2014-05-30 15:46:17 +02:00
SetProcessPriority ();
2009-10-17 15:51:44 -07:00
2014-05-30 15:46:17 +02:00
_dbPingInterval = sConfigMgr -> GetIntDefault ( "MaxPingTime" , 30 );
2009-10-17 15:51:44 -07:00
2014-05-30 15:46:17 +02:00
_dbPingTimer . expires_from_now ( boost :: posix_time :: seconds ( _dbPingInterval ));
_dbPingTimer . async_wait ( KeepDatabaseAliveHandler );
2014-05-13 22:41:59 +02:00
2014-05-30 15:46:17 +02:00
// Start the io service
_ioService . run ();
2009-10-17 15:51:44 -07:00
2011-01-13 21:30:37 +01:00
// Close the Database Pool and library
StopDB ();
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.authserver" , "Halting process..." );
2008-10-02 16:23:55 -05:00
return 0 ;
}
2009-10-17 15:51:44 -07:00
2014-05-17 20:27:39 +02:00
2012-10-02 23:20:03 +02:00
/// Initialize connection to the database
2009-03-20 22:17:39 +01:00
bool StartDB ()
2008-10-02 16:23:55 -05:00
{
2012-03-26 13:33:47 +02:00
MySQL :: Library_Init ();
2013-07-15 17:31:44 +02:00
std :: string dbstring = sConfigMgr -> GetStringDefault ( "LoginDatabaseInfo" , "" );
2009-09-19 00:51:47 -04:00
if ( dbstring . empty ())
2008-10-02 16:23:55 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "server.authserver" , "Database not specified" );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2013-07-15 17:31:44 +02:00
int32 worker_threads = sConfigMgr -> GetIntDefault ( "LoginDatabase.WorkerThreads" , 1 );
2010-09-27 00:20:56 +02:00
if ( worker_threads < 1 || worker_threads > 32 )
2010-08-18 02:25:52 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "server.authserver" , "Improper value specified for LoginDatabase.WorkerThreads, defaulting to 1." );
2010-09-27 00:20:56 +02:00
worker_threads = 1 ;
2010-08-18 02:25:52 +02:00
}
2013-07-15 17:31:44 +02:00
int32 synch_threads = sConfigMgr -> GetIntDefault ( "LoginDatabase.SynchThreads" , 1 );
2010-12-13 09:18:49 +01:00
if ( synch_threads < 1 || synch_threads > 32 )
2010-09-27 00:20:56 +02:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "server.authserver" , "Improper value specified for LoginDatabase.SynchThreads, defaulting to 1." );
2010-12-13 09:18:49 +01:00
synch_threads = 1 ;
2010-09-27 00:20:56 +02:00
}
2010-12-27 09:02:02 -08:00
// NOTE: While authserver is singlethreaded you should keep synch_threads == 1. Increasing it is just silly since only 1 will be used ever.
2013-09-01 22:45:40 +03:00
if ( ! LoginDatabase . Open ( dbstring , uint8 ( worker_threads ), uint8 ( synch_threads )))
2008-10-02 16:23:55 -05:00
{
2013-11-08 10:50:51 +01:00
TC_LOG_ERROR ( "server.authserver" , "Cannot connect to database" );
2008-10-02 16:23:55 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2013-11-08 10:50:51 +01:00
TC_LOG_INFO ( "server.authserver" , "Started auth database connection pool." );
2013-01-16 08:59:56 +01:00
sLog -> SetRealmId ( 0 ); // Enables DB appenders when realm is set.
2008-10-02 16:23:55 -05:00
return true ;
}
2011-01-13 21:30:37 +01:00
2012-10-02 23:20:03 +02:00
/// Close the connection to the database
2011-01-13 21:30:37 +01:00
void StopDB ()
{
LoginDatabase . Close ();
MySQL :: Library_End ();
2011-04-12 14:30:18 -04:00
}
2014-05-17 20:27:39 +02:00
void SetProcessPriority ()
{
#if defined(_WIN32) || defined(__linux__)
2014-05-30 15:46:17 +02:00
///- Handle affinity for multiple processors and process priority
uint32 affinity = sConfigMgr -> GetIntDefault ( "UseProcessors" , 0 );
bool highPriority = sConfigMgr -> GetBoolDefault ( "ProcessPriority" , false );
2014-05-17 20:27:39 +02:00
#ifdef _WIN32 // Windows
2014-05-30 15:46:17 +02:00
HANDLE hProcess = GetCurrentProcess ();
if ( affinity > 0 )
{
ULONG_PTR appAff ;
ULONG_PTR sysAff ;
if ( GetProcessAffinityMask ( hProcess , & appAff , & sysAff ))
{
// remove non accessible processors
ULONG_PTR currentAffinity = affinity & appAff ;
if ( ! currentAffinity )
TC_LOG_ERROR ( "server.authserver" , "Processors marked in UseProcessors bitmask (hex) %x are not accessible for the authserver. Accessible processors bitmask (hex): %x" , affinity , appAff );
else if ( SetProcessAffinityMask ( hProcess , currentAffinity ))
TC_LOG_INFO ( "server.authserver" , "Using processors (bitmask, hex): %x" , currentAffinity );
else
TC_LOG_ERROR ( "server.authserver" , "Can't set used processors (hex): %x" , currentAffinity );
}
}
if ( highPriority )
{
if ( SetPriorityClass ( hProcess , HIGH_PRIORITY_CLASS ))
TC_LOG_INFO ( "server.authserver" , "authserver process priority class set to HIGH" );
else
TC_LOG_ERROR ( "server.authserver" , "Can't set authserver process priority class." );
}
2014-05-17 20:27:39 +02:00
#else // Linux
2014-05-30 15:46:17 +02:00
if ( affinity > 0 )
{
cpu_set_t mask ;
CPU_ZERO ( & mask );
for ( unsigned int i = 0 ; i < sizeof ( affinity ) * 8 ; ++ i )
if ( affinity & ( 1 << i ))
CPU_SET ( i , & mask );
if ( sched_setaffinity ( 0 , sizeof ( mask ), & mask ))
TC_LOG_ERROR ( "server.authserver" , "Can't set used processors (hex): %x, error: %s" , affinity , strerror ( errno ));
else
{
CPU_ZERO ( & mask );
sched_getaffinity ( 0 , sizeof ( mask ), & mask );
TC_LOG_INFO ( "server.authserver" , "Using processors (bitmask, hex): %lx" , * ( __cpu_mask * )( & mask ));
}
}
if ( highPriority )
{
if ( setpriority ( PRIO_PROCESS , 0 , PROCESS_HIGH_PRIORITY ))
TC_LOG_ERROR ( "server.authserver" , "Can't set authserver process priority class, error: %s" , strerror ( errno ));
else
TC_LOG_INFO ( "server.authserver" , "authserver process priority class set to %i" , getpriority ( PRIO_PROCESS , 0 ));
}
2014-05-17 20:27:39 +02:00
#endif
#endif
2014-05-30 15:46:17 +02:00
}