2020-06-16 19:40:32 +02:00
# include <dlfcn.h>
2019-07-17 19:37:18 +02:00
# include <client/linux/handler/exception_handler.h>
# include <iostream>
2019-09-14 12:06:48 +02:00
# include <misc/strobf.h>
2019-07-17 19:37:18 +02:00
# include <CXXTerminal/QuickTerminal.h>
# include <event2/thread.h>
# include <log/LogUtils.h>
# include <ThreadPool/Timer.h>
# include "src/Configuration.h"
2020-01-26 18:04:38 +01:00
# include "src/VirtualServer.h"
2019-07-17 19:37:18 +02:00
# include "src/InstanceHandler.h"
# include "src/server/QueryServer.h"
# include "src/terminal/CommandHandler.h"
# include "src/client/InternalClient.h"
# include "src/SignalHandler.h"
# include "src/build.h"
using namespace std ;
using namespace std : : chrono ;
# define BUILD_CREATE_TABLE(tblName, types) "CREATE TABLE IF NOT EXISTS `" tblName "` (" types ")"
# define CREATE_TABLE(table, types) \
result = sql : : command ( sqlData , BUILD_CREATE_TABLE ( table , types ) ) . execute ( ) ; \
if ( ! result ) { \
logger : : logger ( 0 ) - > critical ( " Could not setup sql tables. Command '{}' returns {} " , BUILD_CREATE_TABLE ( table , types ) , result . fmtStr ( ) ) ; \
goto stopApp ; \
}
bool mainThreadActive = true ;
bool mainThreadDone = false ;
ts : : server : : InstanceHandler * serverInstance = nullptr ;
extern void testTomMath ( ) ;
# ifndef FUCK_CLION
# define DB_NAME_BEG "TeaData"
# define DB_NAME_END ".sqlite"
# define DB_NAME DB_NAME_BEG DB_NAME_END
# else
# define DB_NAME "TeaData.sqlite"
# endif
# include <codecvt>
# include "src/client/music/internal_provider/channel_replay/ChannelProvider.h"
2020-05-09 16:55:15 +02:00
class CLIParser {
2019-07-17 19:37:18 +02:00
public :
CLIParser ( int & argc , char * * argv ) {
for ( int i = 1 ; i < argc ; i + + )
this - > tokens . emplace_back ( argv [ i ] ) ;
}
2020-01-24 02:57:58 +01:00
std : : deque < std : : string > getCmdOptions ( const std : : string & option ) const {
std : : deque < std : : string > result ;
auto itr = this - > tokens . begin ( ) ;
while ( true ) {
itr = std : : find ( itr , this - > tokens . end ( ) , option ) ;
if ( itr ! = this - > tokens . end ( ) & & + + itr ! = this - > tokens . end ( ) ) {
result . push_back ( * itr ) ;
itr + + ;
} else break ;
}
return result ;
}
std : : deque < std : : string > getCmdOptionsBegins ( const std : : string & option ) const {
std : : deque < std : : string > result ;
for ( const auto & token : this - > tokens )
if ( token . find ( option ) = = 0 )
result . push_back ( token ) ;
return result ;
}
2019-07-17 19:37:18 +02:00
const std : : string & get_option ( const std : : string & option ) const {
auto itr = std : : find ( this - > tokens . begin ( ) , this - > tokens . end ( ) , option ) ;
if ( itr ! = this - > tokens . end ( ) & & + + itr ! = this - > tokens . end ( ) ) {
return * itr ;
}
static const std : : string empty_string ;
return empty_string ;
}
bool cmdOptionExists ( const std : : string & option ) const {
return std : : find ( this - > tokens . begin ( ) , this - > tokens . end ( ) , option ) ! = this - > tokens . end ( ) ;
}
private :
std : : vector < std : : string > tokens ;
} ;
/* addr is where the exception identifier is stored
id is the exception identifier . */
void __raise_exception ( void * * addr , void * id ) ;
# define T(address) \
std : : cout < < " Testing: " < < address < < " => " ; \
{ \
2020-01-24 02:57:58 +01:00
sockaddr_storage storage ; \
net : : resolve_address ( address , storage ) ; \
std : : cout < < manager . contains ( storage ) < < std : : endl ; \
2019-07-17 19:37:18 +02:00
}
# define CONFIG_NAME "config.yml"
const char * malloc_conf = " " ; //retain:false"; //,dirty_decay_ms:0";
int main ( int argc , char * * argv ) {
# ifdef HAVE_JEMALLOC
2020-01-24 02:57:58 +01:00
( void * ) malloc_conf ;
2019-07-17 19:37:18 +02:00
# endif
CLIParser arguments ( argc , argv ) ;
SSL_load_error_strings ( ) ;
OpenSSL_add_ssl_algorithms ( ) ;
2020-01-24 02:57:58 +01:00
ts : : permission : : setup_permission_resolve ( ) ;
{
auto evthread_use_pthreads_result = evthread_use_pthreads ( ) ;
assert ( evthread_use_pthreads_result = = 0 ) ;
( void ) evthread_use_pthreads_result ;
}
2020-02-28 11:24:07 +01:00
if ( ! arguments . cmdOptionExists ( " --no-terminal " ) ) {
terminal : : install ( ) ;
if ( ! terminal : : active ( ) ) { cerr < < " could not setup terminal! " < < endl ; return - 1 ; }
}
2019-07-17 19:37:18 +02:00
if ( arguments . cmdOptionExists ( " --help " ) | | arguments . cmdOptionExists ( " -h " ) ) {
# define HELP_FMT " {} {} | {}"
logMessageFmt ( true , LOG_GENERAL , " Available command line parameters: " ) ;
logMessageFmt ( true , LOG_GENERAL , HELP_FMT , " -h " , " --help " , " Shows this page " ) ;
logMessageFmt ( true , LOG_GENERAL , HELP_FMT , " -q " , " --set_query_password " , " Changed the server admin query password " ) ;
2020-01-24 02:57:58 +01:00
logMessageFmt ( true , LOG_GENERAL , HELP_FMT , " -P<property>=<value> " , " --property:<property>=<value> " , " Override a config value manual " ) ;
logMessageFmt ( true , LOG_GENERAL , HELP_FMT , " -l " , " --property-list " , " List all available properties " ) ;
2019-07-17 19:37:18 +02:00
terminal : : uninstall ( ) ;
return 0 ;
}
2020-01-24 02:57:58 +01:00
if ( arguments . cmdOptionExists ( " --property-list " ) | | arguments . cmdOptionExists ( " -l " ) ) {
logMessageFmt ( true , LOG_GENERAL , " Available properties: " ) ;
auto properties = ts : : config : : create_bindings ( ) ;
for ( const auto & property : properties ) {
logMessageFmt ( true , LOG_GENERAL , " " + property - > key ) ;
for ( const auto & entry : property - > description ) {
if ( entry . first . empty ( ) ) {
for ( const auto & line : entry . second )
logMessageFmt ( true , LOG_GENERAL , " " + line ) ;
} else {
logMessageFmt ( true , LOG_GENERAL , " " + entry . first + " : " ) ;
for ( const auto & line : entry . second )
logMessageFmt ( true , LOG_GENERAL , " " + line ) ;
}
}
logMessageFmt ( true , LOG_GENERAL , " " + property - > value_description ( ) ) ;
}
return 0 ;
}
if ( ! arguments . cmdOptionExists ( " --valgrind " ) ) {
ts : : syssignal : : setup ( ) ;
}
ts : : syssignal : : setup_threads ( ) ;
map < string , string > override_settings ;
{
auto short_override = arguments . getCmdOptionsBegins ( " -P " ) ;
for ( const auto & entry : short_override ) {
if ( entry . length ( ) < 2 ) continue ;
auto ei = entry . find ( ' = ' ) ;
if ( ei = = string : : npos | | ei = = 2 ) {
logErrorFmt ( true , LOG_GENERAL , " Invalid command line parameter. ( \" " + entry + " \" ) " ) ;
return 1 ;
}
auto key = entry . substr ( 2 , ei - 2 ) ;
auto value = entry . substr ( ei + 1 ) ;
override_settings [ key ] = value ;
}
}
{
auto short_override = arguments . getCmdOptionsBegins ( " --property: " ) ;
for ( const auto & entry : short_override ) {
if ( entry . length ( ) < 11 ) continue ;
auto ei = entry . find ( ' = ' ) ;
if ( ei = = string : : npos | | ei = = 11 ) {
logErrorFmt ( true , LOG_GENERAL , " Invalid command line parameter. ( \" " + entry + " \" ) " ) ;
return 1 ;
}
auto key = entry . substr ( 11 , ei - 11 ) ;
auto value = entry . substr ( ei + 1 ) ;
override_settings [ key ] = value ;
}
}
{
auto bindings = ts : : config : : create_bindings ( ) ;
for ( const auto & setting : bindings ) {
for ( auto it = override_settings . begin ( ) ; it ! = override_settings . end ( ) ; it + + ) {
if ( it - > first = = setting - > key ) {
try {
setting - > read_argument ( it - > second ) ;
} catch ( const std : : exception & ex ) {
logErrorFmt ( true , LOG_GENERAL , " Failed to apply value for given property ' " + it - > first + " ': " + ex . what ( ) ) ;
}
override_settings . erase ( it ) ;
break ;
}
}
}
for ( const auto & entry : override_settings ) {
logMessageFmt ( true , LOG_GENERAL , " Missing property " + entry . first + " . Value unused! " ) ;
}
}
2019-07-17 19:37:18 +02:00
/*
std : : string error ;
if ( ! interaction : : waitForAttach ( error ) ) {
cerr < < " Rsult: " < < error < < endl ;
}
while ( interaction : : memoryInfo ( ) ) {
usleep ( 1 * 1000 * 1000 ) ;
logMessage ( " Current instances: " + to_string ( interaction : : memoryInfo ( ) - > instanceCount ) + " / " + to_string ( interaction : : memoryInfo ( ) - > maxInstances ) ) ;
}
interaction : : removeMemoryHook ( ) ;
if ( true ) return 0 ;
*/
//debugMessage(LOG_GENERAL, "Sizeof ViewEntry {} Sizeof LinkedTreeEntry {} Sizeof shared_ptr<ViewEntry> {} Sizeof ClientChannelView {}", sizeof(ts::ViewEntry), sizeof(ts::TreeView::LinkedTreeEntry), sizeof(shared_ptr<ts::ViewEntry>), sizeof(ts::ClientChannelView));
{
//http://git.mcgalaxy.de/WolverinDEV/tomcrypt/blob/develop/src/misc/crypt/crypt_inits.c#L40-86
std : : string descriptors = " LTGE " ;
bool crypt_init = false ;
for ( const auto & c : descriptors )
2019-09-14 12:06:48 +02:00
if ( ( crypt_init | = crypt_mp_init ( & c ) ) )
2019-07-17 19:37:18 +02:00
break ;
if ( ! crypt_init ) {
logCritical ( LOG_GENERAL , " Could not initialise libtomcrypt mp descriptors! " ) ;
return 1 ;
}
if ( register_prng ( & sprng_desc ) = = - 1 ) {
2020-01-24 02:57:58 +01:00
logCritical ( LOG_GENERAL , " could not setup prng " ) ;
2019-07-17 19:37:18 +02:00
return EXIT_FAILURE ;
}
if ( register_cipher ( & rijndael_desc ) = = - 1 ) {
2020-01-24 02:57:58 +01:00
logCritical ( LOG_GENERAL , " could not setup rijndael " ) ;
2019-07-17 19:37:18 +02:00
return EXIT_FAILURE ;
}
testTomMath ( ) ;
}
2020-01-24 02:57:58 +01:00
ts : : server : : SqlDataManager * sql = nullptr ;
std : : string errorMessage ;
2019-07-17 19:37:18 +02:00
shared_ptr < logger : : LoggerConfig > logConfig = nullptr ;
2020-01-24 02:57:58 +01:00
std : : string line ;
2019-07-17 19:37:18 +02:00
2019-09-14 12:06:48 +02:00
logMessageFmt ( true , LOG_GENERAL , " Loading configuration " ) ;
2019-07-17 19:37:18 +02:00
auto cfgErrors = ts : : config : : parseConfig ( CONFIG_NAME ) ;
if ( ! cfgErrors . empty ( ) ) {
2019-09-14 12:06:48 +02:00
logErrorFmt ( true , LOG_GENERAL , " Could not load configuration. Errors: ( " + to_string ( cfgErrors . size ( ) ) + " ) " ) ;
2019-07-17 19:37:18 +02:00
for ( const auto & entry : cfgErrors )
2020-04-19 18:40:40 +02:00
logErrorFmt ( true , LOG_GENERAL , " - {} " , entry ) ;
2019-09-14 12:06:48 +02:00
logErrorFmt ( true , LOG_GENERAL , " Stopping server... " ) ;
2019-07-17 19:37:18 +02:00
goto stopApp ;
}
2019-09-14 12:06:48 +02:00
logMessage ( LOG_GENERAL , " Setting up logging " ) ;
2019-07-17 19:37:18 +02:00
logConfig = make_shared < logger : : LoggerConfig > ( ) ;
logConfig - > logfileLevel = ( spdlog : : level : : level_enum ) ts : : config : : log : : logfileLevel ;
logConfig - > terminalLevel = ( spdlog : : level : : level_enum ) ts : : config : : log : : terminalLevel ;
logConfig - > file_colored = ts : : config : : log : : logfileColored ;
logConfig - > logPath = ts : : config : : log : : path ;
logConfig - > vs_group_size = ts : : config : : log : : vs_size ;
2020-02-28 11:24:07 +01:00
logConfig - > sync = ! terminal : : instance ( ) ;
2019-07-17 19:37:18 +02:00
logger : : setup ( logConfig ) ;
2020-01-24 02:57:58 +01:00
threads : : timer : : function_log = [ ] ( const std : : string & message , bool debug ) {
2020-02-15 14:03:46 +01:00
auto msg = message . find ( ' \n ' ) = = std : : string : : npos ? message : message . substr ( 0 , message . find ( ' \n ' ) ) ;
2020-01-24 02:57:58 +01:00
if ( debug )
2020-02-15 14:03:46 +01:00
debugMessage ( LOG_GENERAL , msg ) ;
2020-01-24 02:57:58 +01:00
else
2020-02-15 14:03:46 +01:00
logWarning ( LOG_GENERAL , msg ) ;
2020-01-24 02:57:58 +01:00
} ;
2019-07-17 19:37:18 +02:00
logger : : updateLogLevels ( ) ;
2020-01-24 02:57:58 +01:00
if ( ts : : config : : license_original & & ts : : config : : license_original - > data . type ! = license : : LicenseType : : DEMO ) {
logMessageFmt ( true , LOG_GENERAL , strobf ( " []---------------------------------------------------------[] " ) . string ( ) ) ;
logMessageFmt ( true , LOG_GENERAL , strobf ( " §aThank you for buying the TeaSpeak-§lPremium-§aSoftware! " ) . string ( ) ) ;
logMessageFmt ( true , LOG_GENERAL , strobf ( " §aLicense information: " ) . string ( ) ) ;
logMessageFmt ( true , LOG_GENERAL , strobf ( " §aLicense owner : §e " ) . string ( ) + ts : : config : : license_original - > owner ( ) ) ;
logMessageFmt ( true , LOG_GENERAL , strobf ( " §aLicense type : §e " ) . string ( ) + license : : LicenseTypeNames [ ts : : config : : license_original - > data . type ] ) ;
if ( ts : : config : : license_original - > end ( ) . time_since_epoch ( ) . count ( ) = = 0 ) {
logMessageFmt ( true , LOG_GENERAL , strobf ( " §aLicense expires: §enever " ) . string ( ) ) ;
} else {
char timeBuffer [ 32 ] ;
time_t t = duration_cast < seconds > ( ts : : config : : license_original - > end ( ) . time_since_epoch ( ) ) . count ( ) ;
tm * stime = localtime ( & t ) ;
strftime ( timeBuffer , 32 , " %c " , stime ) ;
logMessageFmt ( true , LOG_GENERAL , strobf ( " §aLicense expires: §e " ) . string ( ) + string ( timeBuffer ) ) ;
}
logMessageFmt ( true , LOG_GENERAL , string ( ) + strobf ( " §aLicense valid : " ) . string ( ) + ( ts : : config : : license_original - > isValid ( ) ? strobf ( " §ayes " ) . string ( ) : strobf ( " §cno " ) . string ( ) ) ) ;
logMessageFmt ( true , LOG_GENERAL , strobf ( " []---------------------------------------------------------[] " ) . string ( ) ) ;
}
2019-07-17 19:37:18 +02:00
2020-03-25 20:36:44 +01:00
{
rlimit rlimit { 0 , 0 } ;
//forum.teaspeak.de/index.php?threads/2570/
constexpr auto seek_help_message = " Fore more help visit the forum and read this thread (https://forum.teaspeak.de/index.php?threads/2570/). " ;
if ( getrlimit ( RLIMIT_NOFILE , & rlimit ) ! = 0 ) {
//prlimit -n4096 -p pid_of_process
logWarningFmt ( true , LOG_INSTANCE , " Failed to get open file rlimit ({}). Please ensure its over 16384. " , strerror ( errno ) ) ;
logWarningFmt ( true , LOG_INSTANCE , seek_help_message ) ;
} else {
const auto original = rlimit . rlim_cur ;
rlimit . rlim_cur = std : : max ( rlimit . rlim_cur , std : : min ( rlimit . rlim_max , ( rlim_t ) 16384 ) ) ;
if ( original ! = rlimit . rlim_cur ) {
if ( setrlimit ( RLIMIT_NOFILE , & rlimit ) ! = 0 ) {
logErrorFmt ( true , LOG_INSTANCE , " Failed to set open file rlimit to {} ({}). Please ensure its over 16384. " , rlimit . rlim_cur , strerror ( errno ) ) ;
logWarningFmt ( true , LOG_INSTANCE , seek_help_message ) ;
goto rlimit_updates ;
}
}
if ( rlimit . rlim_cur < 16384 ) {
logWarningFmt ( true , LOG_INSTANCE , " Open file rlimit is bellow 16384 ({}). Please increase the system file descriptor limits. " , rlimit . rlim_cur ) ;
logWarningFmt ( true , LOG_INSTANCE , seek_help_message ) ;
}
}
rlimit_updates : ;
}
2019-07-17 19:37:18 +02:00
logMessage ( LOG_GENERAL , " Starting TeaSpeak-Server v{} " , build : : version ( ) - > string ( true ) ) ;
2020-01-24 02:57:58 +01:00
logMessage ( LOG_GENERAL , " Starting music providers " ) ;
2019-07-17 19:37:18 +02:00
2020-02-28 11:24:07 +01:00
if ( terminal : : instance ( ) ) terminal : : instance ( ) - > setPrompt ( " §aStarting server. §7[§aloading music§7] " ) ;
2020-01-24 02:57:58 +01:00
if ( ts : : config : : music : : enabled & & ! arguments . cmdOptionExists ( " --no-providers " ) ) {
: : music : : manager : : loadProviders ( " providers " ) ;
: : music : : manager : : register_provider ( : : music : : provider : : ChannelProvider : : create_provider ( ) ) ;
}
2019-07-17 19:37:18 +02:00
2020-02-28 11:24:07 +01:00
if ( terminal : : instance ( ) ) terminal : : instance ( ) - > setPrompt ( " §aStarting server. §7[§aloading geoloc§7] " ) ;
2019-07-17 19:37:18 +02:00
if ( ! ts : : config : : geo : : staticFlag ) {
if ( ts : : config : : geo : : type = = geoloc : : PROVIDER_SOFTWARE77 )
geoloc : : provider = new geoloc : : Software77Provider ( ts : : config : : geo : : mappingFile ) ;
else if ( ts : : config : : geo : : type = = geoloc : : PROVIDER_IP2LOCATION )
geoloc : : provider = new geoloc : : IP2LocationProvider ( ts : : config : : geo : : mappingFile ) ;
else {
2019-11-23 21:16:55 +01:00
logCritical ( LOG_GENERAL , " Invalid geo resolver type! " ) ;
2019-07-17 19:37:18 +02:00
}
if ( geoloc : : provider & & ! geoloc : : provider - > load ( errorMessage ) ) {
2019-11-23 21:16:55 +01:00
logCritical ( LOG_GENERAL , " Could not setup geoloc! Fallback to default flag! " ) ;
logCritical ( LOG_GENERAL , " Message: {} " , errorMessage ) ;
2019-07-17 19:37:18 +02:00
geoloc : : provider = nullptr ;
2020-01-24 02:57:58 +01:00
errorMessage = " " ;
2019-07-17 19:37:18 +02:00
}
}
if ( ts : : config : : geo : : vpn_block ) {
geoloc : : provider_vpn = new geoloc : : IPCatBlocker ( ts : : config : : geo : : vpn_file ) ;
if ( geoloc : : provider_vpn & & ! geoloc : : provider_vpn - > load ( errorMessage ) ) {
2019-11-23 21:16:55 +01:00
logCritical ( LOG_GENERAL , " Could not setup vpn detector! " ) ;
2020-01-24 02:57:58 +01:00
logCritical ( LOG_GENERAL , " Message: {} " , errorMessage ) ;
2019-07-17 19:37:18 +02:00
geoloc : : provider_vpn = nullptr ;
errorMessage = " " ;
}
}
2020-02-28 11:24:07 +01:00
if ( terminal : : instance ( ) ) terminal : : instance ( ) - > setPrompt ( " §aStarting server. §7[§aloading sql§7] " ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
sql = new ts : : server : : SqlDataManager ( ) ;
if ( ! sql - > initialize ( errorMessage ) ) {
logCriticalFmt ( true , LOG_GENERAL , " Could not initialize SQL! " ) ;
if ( errorMessage . find ( " database is locked " ) ! = string : : npos ) {
logCriticalFmt ( true , LOG_GENERAL , " ----------------------------[ ATTENTION ]---------------------------- " ) ;
2019-07-17 19:37:18 +02:00
logCriticalFmt ( true , LOG_GENERAL , " {:^69} " , " You're database is already in use! " ) ;
2020-01-24 02:57:58 +01:00
logCriticalFmt ( true , LOG_GENERAL , " {:^69} " , " Stop the other instance first! " ) ;
logCriticalFmt ( true , LOG_GENERAL , " ----------------------------[ ATTENTION ]---------------------------- " ) ;
} else {
2019-07-17 19:37:18 +02:00
logCriticalFmt ( true , LOG_GENERAL , errorMessage ) ;
2020-01-24 02:57:58 +01:00
}
goto stopApp ;
}
2019-07-17 19:37:18 +02:00
2020-02-28 11:24:07 +01:00
if ( terminal : : instance ( ) ) terminal : : instance ( ) - > setPrompt ( " §aStarting server. §7[§astarting instance§7] " ) ;
2019-07-17 19:37:18 +02:00
serverInstance = new ts : : server : : InstanceHandler ( sql ) ; //if error than mainThreadActive = false
if ( ! mainThreadActive | | ! serverInstance - > startInstance ( ) )
goto stopApp ;
if ( arguments . cmdOptionExists ( " -q " ) | | arguments . cmdOptionExists ( " --set_query_password " ) ) {
2020-01-24 02:57:58 +01:00
auto password = arguments . cmdOptionExists ( " -q " ) ? arguments . get_option ( " -q " ) : arguments . get_option ( " --set_query_password " ) ;
if ( ! password . empty ( ) ) {
logMessageFmt ( true , LOG_GENERAL , " Updating server admin query password to \" {} \" " , password ) ;
2020-03-11 10:33:39 +01:00
auto account = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( " serveradmin " ) ;
if ( ! account ) {
logErrorFmt ( true , LOG_GENERAL , " Failed to update server admin query password! Login does not exists! " ) ;
} else {
2020-01-24 02:57:58 +01:00
if ( ! serverInstance - > getQueryServer ( ) - > change_query_password ( account , password ) ) {
logErrorFmt ( true , LOG_GENERAL , " Failed to update server admin query password! (Internal error) " ) ;
}
}
}
2019-07-17 19:37:18 +02:00
}
2020-02-28 11:24:07 +01:00
if ( terminal : : instance ( ) ) terminal : : instance ( ) - > setPrompt ( " §7> §f " ) ;
2019-07-17 19:37:18 +02:00
while ( mainThreadActive ) {
usleep ( 5 * 1000 ) ;
2020-02-28 11:24:07 +01:00
if ( terminal : : instance ( ) ) {
if ( terminal : : instance ( ) - > linesAvailable ( ) > 0 ) {
while ( ! ( line = terminal : : instance ( ) - > readLine ( " §7> §f " ) ) . empty ( ) )
threads : : Thread ( THREAD_DETACHED , [ line ] ( ) { terminal : : chandler : : handleCommand ( line ) ; } ) ;
}
2019-07-17 19:37:18 +02:00
}
}
stopApp :
2019-09-14 12:06:48 +02:00
logMessageFmt ( true , LOG_GENERAL , " Stopping application " ) ;
2020-01-24 02:57:58 +01:00
: : music : : manager : : finalizeProviders ( ) ;
2019-11-22 20:51:00 +01:00
2019-07-17 19:37:18 +02:00
if ( serverInstance )
serverInstance - > stopInstance ( ) ;
delete serverInstance ;
2020-01-24 02:57:58 +01:00
serverInstance = nullptr ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
ts : : music : : MusicBotManager : : shutdown ( ) ;
2019-07-17 19:37:18 +02:00
if ( sql )
2020-01-24 02:57:58 +01:00
sql - > finalize ( ) ;
delete sql ;
logMessageFmt ( true , LOG_GENERAL , " Application suspend successful! " ) ;
2019-07-17 19:37:18 +02:00
logger : : uninstall ( ) ;
2020-02-28 11:24:07 +01:00
if ( terminal : : active ( ) )
terminal : : uninstall ( ) ;
2020-01-24 02:57:58 +01:00
mainThreadDone = true ;
2019-07-17 19:37:18 +02:00
return 0 ;
2020-06-16 19:40:32 +02:00
}
/* Fix for Virtuzzo 7 where sometimes the pthread create fails! */
typedef int ( * pthread_create_t ) ( pthread_t * thread , const pthread_attr_t * attr , void * ( * start_routine ) ( void * ) , void * arg ) ;
pthread_create_t original_pthread_create { nullptr } ;
int pthread_create ( pthread_t * thread , const pthread_attr_t * attr , void * ( * start_routine ) ( void * ) , void * arg ) {
if ( ! original_pthread_create ) {
original_pthread_create = ( pthread_create_t ) dlsym ( RTLD_NEXT , " pthread_create " ) ;
if ( ! original_pthread_create ) {
std : : cerr < < " [CRITICAL] Missing original pthread_create function. Aborting execution! " < < std : : endl ;
std : : abort ( ) ;
}
}
2020-06-16 19:51:06 +02:00
int result , attempt { 0 } , sleep { 5 } ;
2020-06-16 19:40:32 +02:00
while ( ( result = original_pthread_create ( thread , attr , start_routine , arg ) ) ! = 0 & & errno = = EAGAIN ) {
2020-06-16 19:51:06 +02:00
if ( attempt > 50 ) {
std : : cerr < < " [CRITICAL] pthread_create(...) cause EAGAIN for the last 50 attempts! Aborting application execution! " < < std : : endl ;
2020-06-16 19:40:32 +02:00
std : : abort ( ) ;
} else if ( attempt > 5 ) {
/* let some other threads do work */
pthread_yield ( ) ;
}
2020-06-16 19:51:06 +02:00
std : : string message { " [CRITICAL] pthread_create(...) cause EAGAIN! Trying again in " + std : : to_string ( sleep ) + " usec (Attempt: " + std : : to_string ( attempt ) + " ) " } ;
std : : cerr < < message < < std : : endl ;
usleep ( sleep ) ;
2020-06-16 19:40:32 +02:00
attempt + + ;
2020-06-16 19:51:06 +02:00
sleep = ( int ) ( sleep * 1.25 ) ;
2020-06-16 19:40:32 +02:00
}
return result ;
2019-11-22 20:51:00 +01:00
}