コード例 #1
0
ファイル: Master.cpp プロジェクト: SkyFire/sandshroud
bool Master::Run(int argc, char ** argv)
{
	m_stopEvent = false;
	char * config_file = (char*)default_config_file;
	char * options_config_file = (char*)default_options_config_file;
	int screen_log_level = DEF_VALUE_NOT_SET;
	int do_check_conf = 0;
	int do_version = 0;
	int do_cheater_check = 0;
	int do_database_clean = 0;
	time_t curTime;

	struct hearthstone_option longopts[] =
	{
		{ "checkconf",			hearthstone_no_argument,			&do_check_conf,			1		},
		{ "screenloglevel",		hearthstone_required_argument,		&screen_log_level,		1		},
		{ "version",			hearthstone_no_argument,			&do_version,			1		},
		{ "cheater",			hearthstone_no_argument,			&do_cheater_check,		1		},
		{ "cleandb",			hearthstone_no_argument,			&do_database_clean,		1		},
		{ "conf",				hearthstone_required_argument,		NULL,					'c'		},
		{ "realmconf",			hearthstone_required_argument,		NULL,					'r'		},
		{ 0, 0, 0, 0 }
	};

	char c;
	while ((c = hearthstone_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1)
	{
		switch (c)
		{
		case 'c':
			config_file = new char[strlen(hearthstone_optarg)];
			strcpy(config_file, hearthstone_optarg);
			break;

		case 'o':
			options_config_file = new char[strlen(hearthstone_optarg)];
			strcpy(options_config_file, hearthstone_optarg);
			break;

		case 0:
			break;
		default:
			sLog.m_screenLogLevel = 3;
			printf("Usage: %s [--checkconf] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]);
			return true;
		}
	}
	/* set new log levels if used as argument*/
	if( screen_log_level != (int)DEF_VALUE_NOT_SET )
		sLog.SetScreenLoggingLevel(screen_log_level);

	// Startup banner
	UNIXTIME = time(NULL);
	g_localTime = *localtime(&UNIXTIME);

	printf(BANNER, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH);
	printf("Built at %s on %s by %s@%s\n", BUILD_TIME, BUILD_DATE, BUILD_USER, BUILD_HOST);
	Log.Line();

	if( do_check_conf )
	{
		Log.Notice( "Config", "Checking config file: %s", config_file );
		if( Config.MainConfig.SetSource(config_file, true ) )
			Log.Success( "Config", "Passed without errors." );
		else
			Log.Warning( "Config", "Encountered one or more errors." );

		Log.Notice( "Config", "Checking config file: %s\n", options_config_file );
		if( Config.OptionalConfig.SetSource( options_config_file, true ) )
			Log.Success( "Config", "Passed without errors.\n" );
		else
			Log.Warning( "Config", "Encountered one or more errors.\n" );
		return true;
	}

	printf( "The key combination <Ctrl-C> will safely shut down the server at any time.\n" );
	Log.Line();

	//use these log_level until we are fully started up.
#ifdef _DEBUG
	sLog.Init(3);
#else
	sLog.Init(1);
#endif // _DEBUG

#ifndef WIN32
	if(geteuid() == 0 || getegid() == 0)
		Log.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running Hearthstone as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL);
#endif

	InitRandomNumberGenerators();
	Log.Success( "Rnd", "Initialized Random Number Generators." );

	ThreadPool.Startup();
	uint32 LoadingTime = getMSTime();

	Log.Notice( "Config", "Loading Config Files..." );
	if( Config.MainConfig.SetSource( config_file ) )
		Log.Success( "Config", ">> hearthstone-world.conf" );
	else
	{
		Log.Error( "Config", ">> hearthstone-world.conf" );
		return false;
	}

	if(Config.OptionalConfig.SetSource(options_config_file))
		Log.Success( "Config", ">> hearthstone-options.conf" );
	else
	{
		Log.Error( "Config", ">> hearthstone-options.conf" );
		return false;
	}

	if(!_StartDB())
	{
		Database::CleanupLibs();
		return false;
	}

	Log.Line();
	sLog.outString( "" );

	new EventMgr;
	new World;

	/* load the config file */
	sWorld.Rehash(true);

	// Because of our log DB system, these have to be initialized different then rehash.
	sWorld.LogCheaters = Config.MainConfig.GetBoolDefault("Log", "Cheaters", false);
	sWorld.LogCommands = Config.MainConfig.GetBoolDefault("Log", "GMCommands", false);
	sWorld.LogPlayers = Config.MainConfig.GetBoolDefault("Log", "Player", false);
	sWorld.LogChats = Config.MainConfig.GetBoolDefault("Log", "Chat", false);

	//Update sLog to obey config setting
	sLog.Init(Config.MainConfig.GetIntDefault("LogLevel", "Screen", 1));

	// Initialize Opcode Table
	WorldSession::InitPacketHandlerTable();

	new ScriptMgr;

	if( !sWorld.SetInitialWorldSettings() )
	{
		Log.Error( "Server", "SetInitialWorldSettings() failed. Something went wrong? Exiting." );
		return false;
	}

	sWorld.SetStartTime(uint32(UNIXTIME));

	WorldRunnable *wr = new WorldRunnable();
	ThreadPool.ExecuteTask(wr);

	_HookSignals();

	ConsoleThread* console = new ConsoleThread();
	ThreadPool.ExecuteTask(console);

	uint32 realCurrTime, realPrevTime;
	realCurrTime = realPrevTime = getMSTime();

	// Socket loop!
	uint32 start;
	uint32 diff;
	uint32 last_time = now();
	uint32 etime;

	// Start Network Subsystem
	DEBUG_LOG("Server","Starting network subsystem..." );
	CreateSocketEngine();
	sSocketEngine.SpawnThreads();

	if( StartConsoleListener() )
	{
#ifdef WIN32
		ThreadPool.ExecuteTask( GetConsoleListener() );
#endif
		Log.Success("RemoteConsole", "Started and listening on port %i",Config.MainConfig.GetIntDefault("RemoteConsole", "Port", 8092));
	}
	else
		DEBUG_LOG("RemoteConsole", "Not enabled or failed listen.");

	LoadingTime = getMSTime() - LoadingTime;
	Log.Success("Server","Ready for connections. Startup time: %ums\n", LoadingTime );

	/* write pid file */
	FILE * fPid = fopen( "hearthstone-world.pid", "w" );
	if( fPid )
	{
		uint32 pid;
#ifdef WIN32
		pid = GetCurrentProcessId();
#else
		pid = getpid();
#endif
		fprintf( fPid, "%u", uint(pid) );
		fclose( fPid );
	}
#ifdef WIN32
	HANDLE hThread = GetCurrentThread();
#endif

	uint32 loopcounter = 0;
	//ThreadPool.Gobble();

	new ClusterInterface;
	sClusterInterface.ConnectToRealmServer();
	while(!m_stopEvent)
	{
		start = now();
		diff = start - last_time;
		if(! ((++loopcounter) % 10000) )		// 5mins
		{
			ThreadPool.ShowStats();
			ThreadPool.IntegrityCheck();//Checks if THREAD_RESERVE is met
		}

		/* since time() is an expensive system call, we only update it once per server loop */
		curTime = time(NULL);
		if( UNIXTIME != curTime )
		{
			UNIXTIME = time(NULL);
			g_localTime = *localtime(&curTime);
		}

		sClusterInterface.Update();
		sSocketDeleter.Update();

		/* UPDATE */
		last_time = now();
		etime = last_time - start;
		if( 50 > etime )
		{
#ifdef WIN32
			WaitForSingleObject( hThread, 50 - etime );
#else
			Sleep( 50 - etime );
#endif
		}
	}
	// begin server shutdown
	Log.Notice( "Shutdown", "Initiated at %s", ConvertTimeStampToDataTime( (uint32)UNIXTIME).c_str() );
	bServerShutdown = true;

	wr->Terminate();

	/* Shut down console system */
	CloseConsoleListener();
	console->terminate();
	delete console;

	if( lootmgr.is_loading )
	{
		Log.Notice( "Shutdown", "Waiting for loot to finish loading..." );
		while( lootmgr.is_loading )
			Sleep( 100 );
	}

	Log.Notice( "CharacterLoaderThread", "Exiting..." );
	sCLT.Terminate();

	sWorld.LogoutPlayers(); //(Also saves players).
	CharacterDatabase.Execute("UPDATE characters SET online = 0");

	// send a query to wake it up if its inactive
	Log.Notice( "Database", "Clearing all pending queries..." );

	// kill the database thread first so we don't lose any queries/data
	CharacterDatabase.EndThreads();
	WorldDatabase.EndThreads();

	if(Config.MainConfig.GetBoolDefault("Log", "Cheaters", false) || Config.MainConfig.GetBoolDefault("Log", "GMCommands", false)
		|| Config.MainConfig.GetBoolDefault("Log", "Player", false) || Config.MainConfig.GetBoolDefault("Log", "Chat", false))
		LogDatabase.EndThreads();

	Log.Notice("Server", "Shutting down random generator.");
	CleanupRandomNumberGenerators();

	if(wintergrasp)
	{
		Log.Notice( "WintergraspInternal", "Exiting..." );
		sWintergraspI.terminate();
	}

	Log.Notice( "DayWatcherThread", "Exiting..." );
	sDayWatcher.terminate();

	Log.Notice( "Network", "Shutting down network subsystem." );
	sSocketEngine.Shutdown();

	sAddonMgr.SaveToDB();
	Log.Notice("AddonMgr", "~AddonMgr()");
	delete AddonMgr::getSingletonPtr();

	Log.Notice("LootMgr", "~LootMgr()");
	delete LootMgr::getSingletonPtr();

	Log.Notice("MailSystem", "~MailSystem()");
	delete MailSystem::getSingletonPtr();

	ThreadPool.Shutdown();

	Log.Notice("CharacterLoaderThread", "~CharacterLoaderThread()");
	delete CharacterLoaderThread::getSingletonPtr();

	if(wintergrasp)
	{
		Log.Notice("WintergraspInternal", "~WintergraspInternal()");
		delete WintergraspInternal::getSingletonPtr();
	}

	Log.Notice( "World", "~World()" );
	delete World::getSingletonPtr();

	Log.Notice( "ScriptMgr", "~ScriptMgr()" );
	sScriptMgr.UnloadScripts();
	delete ScriptMgr::getSingletonPtr();

	Log.Notice( "EventMgr", "~EventMgr()" );
	delete EventMgr::getSingletonPtr();

	Log.Notice( "Database", "Closing Connections..." );
	_StopDB();

	_UnhookSignals();

#ifdef WIN32
	WSACleanup();
#endif

	// remove pid
	remove( "hearthstone-world.pid" );

	Log.Notice( "Shutdown", "Shutdown complete." );
	Sleep(1000);
	return true;
}
コード例 #2
0
bool Master::Run(int argc, char ** argv)
{
	char * config_file = (char*)default_config_file;
	char * realm_config_file = (char*)default_realm_config_file;

	int file_log_level = DEF_VALUE_NOT_SET;
	int screen_log_level = DEF_VALUE_NOT_SET;
	int do_check_conf = 0;
	int do_version = 0;
	int do_cheater_check = 0;
	int do_database_clean = 0;
	time_t curTime;

	struct hearthstone_option longopts[] =
	{
		{ "checkconf",			hearthstone_no_argument,			&do_check_conf,			1		},
		{ "screenloglevel",		hearthstone_required_argument,		&screen_log_level,		1		},
		{ "fileloglevel",		hearthstone_required_argument,		&file_log_level,		-1		},
		{ "version",			hearthstone_no_argument,			&do_version,			1		},
		{ "conf",				hearthstone_required_argument,		NULL,					'c'		},
		{ "realmconf",			hearthstone_required_argument,		NULL,					'r'		},
		{ 0, 0, 0, 0 }
	};

	char c;
	while ((c = hearthstone_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1)
	{
		switch (c)
		{
		case 'c':
			config_file = new char[strlen(hearthstone_optarg)];
			strcpy(config_file, hearthstone_optarg);
			break;

		case 'r':
			realm_config_file = new char[strlen(hearthstone_optarg)];
			strcpy(realm_config_file, hearthstone_optarg);
			break;

		case 0:
			break;
		default:
			sLog.m_fileLogLevel = -1;
			sLog.m_screenLogLevel = 3;
			printf("Usage: %s [--checkconf] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]);
			return true;
		}
	}
	/* set new log levels if used as argument*/
	if( screen_log_level != (int)DEF_VALUE_NOT_SET )
		sLog.SetScreenLoggingLevel(screen_log_level);
	
	if( file_log_level != (int)DEF_VALUE_NOT_SET )
		sLog.SetFileLoggingLevel(file_log_level);

	// Startup banner
	UNIXTIME = time(NULL);
	g_localTime = *localtime(&UNIXTIME);

	printf(BANNER, BUILD_BRANCH, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH);
	printf("Built at %s on %s by %s@%s\n", BUILD_TIME, BUILD_DATE, BUILD_USER, BUILD_HOST);
	Log.Line();

	if( do_check_conf )
	{
		Log.Notice( "Config", "Checking config file: %s", config_file );
		if( Config.MainConfig.SetSource(config_file, true ) )
			Log.Success( "Config", "Passed without errors." );
		else
			Log.Warning( "Config", "Encountered one or more errors." );

		Log.Notice( "Config", "Checking config file: %s\n", realm_config_file );
		if( Config.RealmConfig.SetSource( realm_config_file, true ) )
			Log.Success( "Config", "Passed without errors.\n" );
		else
			Log.Warning( "Config", "Encountered one or more errors.\n" );

		/* test for die variables */
		string die;
		if( Config.MainConfig.GetString( "die", "msg", &die) || Config.MainConfig.GetString("die2", "msg", &die ) )
			Log.Warning( "Config", "Die directive received: %s", die.c_str() );

		return true;
	}

	printf( "The key combination <Ctrl-C> will safely shut down the server at any time.\n" );
	Log.Line();

	//use these log_level until we are fully started up.
	sLog.Init(-1, 3);

#ifndef WIN32
	if(geteuid() == 0 || getegid() == 0)
		Log.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running Ascent as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL);
#endif

	InitRandomNumberGenerators();
	Log.Success( "Rnd", "Initialized Random Number Generators." );

	ThreadPool.Startup();
	uint32 LoadingTime = getMSTime();

	Log.Notice( "Config", "Loading Config Files...\n" );
	if( Config.MainConfig.SetSource( config_file ) )
		Log.Success( "Config", ">> hearthstone-world.conf" );
	else
	{
		Log.Error( "Config", ">> hearthstone-world.conf" );
		return false;
	}

	string die;
	if( Config.MainConfig.GetString( "die", "msg", &die) || Config.MainConfig.GetString( "die2", "msg", &die ) )
	{
		Log.Warning( "Config", "Die directive received: %s", die.c_str() );
		return false;
	}	

	if(Config.RealmConfig.SetSource(realm_config_file))
		Log.Success( "Config", ">> hearthstone-realms.conf" );
	else
	{
		Log.Error( "Config", ">> hearthstone-realms.conf" );
		return false;
	}

	if( !_StartDB() )
	{
		Database::CleanupLibs();
		return false;
	}

	Log.Line();
	sLog.outString( "" );

	//ScriptSystem = new ScriptEngine;
	//ScriptSystem->Reload();

	new EventMgr;
	WorldPointer shWorld(new World); // Need this so we're not deleted.

	// open cheat log file
	Anticheat_Log = new SessionLogWriter(FormatOutputString( "logs", "cheaters", false).c_str(), false );
	GMCommand_Log = new SessionLogWriter(FormatOutputString( "logs", "gmcommand", false).c_str(), false );
	Player_Log = new SessionLogWriter(FormatOutputString( "logs", "players", false).c_str(), false );

	/* load the config file */
	sWorld.Rehash(false);

	// Initialize Opcode Table
	WorldSession::InitPacketHandlerTable();

	string host = Config.MainConfig.GetStringDefault( "Listen", "Host", DEFAULT_HOST );
	int wsport = Config.MainConfig.GetIntDefault( "Listen", "WorldServerPort", DEFAULT_WORLDSERVER_PORT );

	new ScriptMgr;

	if( !sWorld.SetInitialWorldSettings() )
	{
		Log.Error( "Server", "SetInitialWorldSettings() failed. Something went wrong? Exiting." );
		return false;
	}

	g_bufferPool.Init();
	sWorld.SetStartTime((uint32)UNIXTIME);
	
	WorldRunnable * wr = new WorldRunnable();
	ThreadPool.ExecuteTask(wr);

	_HookSignals();

	ConsoleThread * console = new ConsoleThread();
	ThreadPool.ExecuteTask(console);

	uint32 realCurrTime, realPrevTime;
	realCurrTime = realPrevTime = getMSTime();

	// Socket loop!
	uint32 start;
	uint32 diff;
	uint32 last_time = now();
	uint32 etime;

	// Start Network Subsystem
	DEBUG_LOG("Server","Starting network subsystem..." );
	new SocketMgr;
	new SocketGarbageCollector;
	sSocketMgr.SpawnWorkerThreads();

	if( StartConsoleListener() )
	{
#ifdef WIN32
		ThreadPool.ExecuteTask( GetConsoleListener() );
#endif
		Log.Success("RemoteConsole", "Started and listening on port %i",Config.MainConfig.GetIntDefault("RemoteConsole", "Port", 8092));
	}
	else
		DEBUG_LOG("RemoteConsole", "Not enabled or failed listen.");

	sLog.outString(""); 
	LoadingTime = getMSTime() - LoadingTime;
	Log.Success("Server","Ready for connections. Startup time: %ums\n", LoadingTime );
	sLog.outString(""); 

	//Update sLog to obey config setting
	sLog.Init(Config.MainConfig.GetIntDefault("LogLevel", "File", -1),Config.MainConfig.GetIntDefault("LogLevel", "Screen", 1));

	/* write pid file */
	FILE * fPid = fopen( "ascent.pid", "w" );
	if( fPid )
	{
		uint32 pid;
#ifdef WIN32
		pid = GetCurrentProcessId();
#else
		pid = getpid();
#endif
		fprintf( fPid, "%u", (unsigned int)pid );
		fclose( fPid );
	}
#ifdef WIN32
	HANDLE hThread = GetCurrentThread();
#endif

	uint32 loopcounter = 0;
	//ThreadPool.Gobble();

#ifndef CLUSTERING
	/* Connect to realmlist servers / logon servers */
	new LogonCommHandler();
	sLogonCommHandler.Startup();

	/* voicechat */
#ifdef VOICE_CHAT
	new VoiceChatHandler();
	sVoiceChatHandler.Startup();
#endif

	// Create listener
	ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(host.c_str(), wsport);
    bool listnersockcreate = ls->IsOpen();
#ifdef WIN32
	if( listnersockcreate )
		ThreadPool.ExecuteTask(ls);
#endif
	while( !m_stopEvent && listnersockcreate )
#else
	new ClusterInterface;
	sClusterInterface.ConnectToRealmServer();
	while(!m_stopEvent)
#endif
	{
		start = now();
		diff = start - last_time;
		if(! ((++loopcounter) % 10000) )		// 5mins
		{
			ThreadPool.ShowStats();
			ThreadPool.IntegrityCheck();//Checks if THREAD_RESERVE is met
			g_bufferPool.Optimize();
		}

		/* since time() is an expensive system call, we only update it once per server loop */
		curTime = time(NULL);
		if( UNIXTIME != curTime )
		{
			UNIXTIME = time(NULL);
			g_localTime = *localtime(&curTime);
		}

#ifndef CLUSTERING
#ifdef VOICE_CHAT
		sVoiceChatHandler.Update();
#endif
#else
		sClusterInterface.Update();
#endif
		sSocketGarbageCollector.Update();

		/* UPDATE */
		last_time = now();
		etime = last_time - start;
		if( 50 > etime )
		{
#ifdef WIN32
			WaitForSingleObject( hThread, 50 - etime );
#else
			Sleep( 50 - etime );
#endif
		}
	}
	_UnhookSignals();

    wr->Terminate();
	ThreadPool.ShowStats();
	/* Shut down console system */
	console->terminate();
	delete console;

	// begin server shutdown
	Log.Notice( "Shutdown", "Initiated at %s", ConvertTimeStampToDataTime( (uint32)UNIXTIME).c_str() );

	if( lootmgr.is_loading )
	{
		Log.Notice( "Shutdown", "Waiting for loot to finish loading..." );
		while( lootmgr.is_loading )
			Sleep( 100 );
	}


	Log.Notice( "CharacterLoaderThread", "Exiting..." );
	ctl->Terminate();
	ctl = NULL;


	sWorld.LogoutPlayers(); //(Also saves players).
	CharacterDatabase.Execute("UPDATE characters SET online = 0");

	// send a query to wake it up if its inactive
	Log.Notice( "Database", "Clearing all pending queries..." );

	// kill the database thread first so we don't lose any queries/data
	CharacterDatabase.EndThreads();
	WorldDatabase.EndThreads();

	Log.Notice("Server", "Shutting down random generator.");
	CleanupRandomNumberGenerators();

	Log.Notice( "DayWatcherThread", "Exiting..." );
	dw->terminate();
	dw = NULL;

#ifndef CLUSTERING
	ls->Close();
#endif

	CloseConsoleListener();
	delete ls;

	Log.Notice( "Network", "Shutting down network subsystem." );
#ifdef WIN32
	sSocketMgr.ShutdownThreads();
#endif
	sSocketMgr.CloseAll();

	Log.Notice("AddonMgr", "~AddonMgr()");
	sAddonMgr.SaveToDB();
	delete AddonMgr::getSingletonPtr();

	Log.Notice("AuctionMgr", "~AuctionMgr()");
	delete AuctionMgr::getSingletonPtr();
	Log.Notice("LootMgr", "~LootMgr()");
	delete LootMgr::getSingletonPtr();

	Log.Notice("MailSystem", "~MailSystem()");
	delete MailSystem::getSingletonPtr();

	bServerShutdown = true;
	ThreadPool.Shutdown();

	sLog.outString( "" );

	delete LogonCommHandler::getSingletonPtr();

	Log.Notice( "World", "~World()" );
	//delete World::getSingletonPtr();
	World::getSingletonPtr()->Destructor();


	sScriptMgr.UnloadScripts();
	delete ScriptMgr::getSingletonPtr();

	Log.Notice( "ChatHandler", "~ChatHandler()" );
	delete ChatHandler::getSingletonPtr();

	Log.Notice( "EventMgr", "~EventMgr()" );
	delete EventMgr::getSingletonPtr();

	Log.Notice( "Database", "Closing Connections..." );
	_StopDB();

	Log.Notice( "Network", "Deleting Network Subsystem..." );
	delete SocketMgr::getSingletonPtr();
	delete SocketGarbageCollector::getSingletonPtr();
#ifdef VOICE_CHAT
	Log.Notice( "VoiceChatHandler", "~VoiceChatHandler()" );
	delete VoiceChatHandler::getSingletonPtr();
#endif

#ifdef ENABLE_LUA_SCRIPTING
	sLog.outString("Deleting Script Engine...");
	LuaEngineMgr::getSingleton().Unload();
#endif
	//delete ScriptSystem;

	delete GMCommand_Log;
	delete Anticheat_Log;
	delete Player_Log;

	// remove pid
	remove( "ascent.pid" );
	g_bufferPool.Destroy();

	Log.Notice( "Shutdown", "Shutdown complete." );

#ifdef WIN32
	WSACleanup();

	// Terminate Entire Application
	//HANDLE pH = OpenProcess(PROCESS_TERMINATE, TRUE, GetCurrentProcessId());
	//TerminateProcess(pH, 0);
	//CloseHandle(pH);

#endif

	return true;
}
コード例 #3
0
ファイル: Main.cpp プロジェクト: SkyFire/sandshroud
void LogonServer::Run(int argc, char ** argv)
{
	UNIXTIME = time(NULL);
	g_localTime = *localtime(&UNIXTIME);
#ifdef WIN32
	char * config_file = "configs/hearthstone-logonserver.conf";
#else
	char * config_file = (char*)CONFDIR "/configs/hearthstone-logonserver.conf";
#endif
	int file_log_level = DEF_VALUE_NOT_SET;
	int screen_log_level = DEF_VALUE_NOT_SET;
	int do_check_conf = 0;
	int do_version = 0;

	struct hearthstone_option longopts[] =
	{
		{ "checkconf",			hearthstone_no_argument,				&do_check_conf,			1		},
		{ "screenloglevel",		hearthstone_required_argument,		&screen_log_level,		1		},
		{ "fileloglevel",		hearthstone_required_argument,		&file_log_level,		1		},
		{ "version",			hearthstone_no_argument,				&do_version,			1		},
		{ "conf",				hearthstone_required_argument,		NULL,					'c'		},
		{ 0, 0, 0, 0 }
	};

	char c;
	while ((c = hearthstone_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1)
	{
		switch (c)
		{
		case 'c':
			/* Log filename was set */
			config_file = new char[strlen(hearthstone_optarg)];
			strcpy(config_file,hearthstone_optarg);
			break;
		case 0:
			break;
		default:
			sLog.m_screenLogLevel = 3;
			printf("Usage: %s [--checkconf] [--screenloglevel <level>] [--fileloglevel <level>] [--conf <filename>] [--version]\n", argv[0]);
			return;
		}
	}

	// Startup banner
	if(!do_version && !do_check_conf)
	{
		sLog.Init(3);
	}
	else
	{
		sLog.m_screenLogLevel = 3;
	}

	sLog.outString("Hearthstone r%u/%s-%s(%s)::Logon Server\n", BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH);
	printf("Built at %s on %s by %s@%s\n", BUILD_TIME, BUILD_DATE, BUILD_USER, BUILD_HOST);

	sLog.outString("==============================================================================");
	sLog.outString("");
	if(do_version)
		return;

	if(do_check_conf)
	{
		printf("Checking config file: %s\n", config_file);
		if(Config.MainConfig.SetSource(config_file, true))
			printf("  Passed without errors.\n");
		else
			printf("  Encountered one or more errors.\n");
		/* test for die variables */
		string die;
		if(Config.MainConfig.GetString("die", "msg", &die) || Config.MainConfig.GetString("die2", "msg", &die))
			printf("Die directive received: %s", die.c_str());

		return;
	}
	
	sLog.outString("The key combination <Ctrl-C> will safely shut down the server at any time.");
	sLog.outString("");
	Log.Notice("System","Initializing Random Number Generators...");

	Log.Notice("Config", "Loading Config Files...");
	if(!Rehash())
		return;

	Log.Notice("ThreadMgr", "Starting...");

	ThreadPool.Startup(4);
	if(!startdb())
		return;

	Log.Notice("AccountMgr", "Starting...");
	new AccountMgr;
	new IPBanner;

	Log.Notice("InfoCore", "Starting...");
	new InformationCore;

	new PatchMgr;
	Log.Notice("AccountMgr", "Precaching accounts...");
	sAccountMgr.ReloadAccounts(true);
	Log.Notice("AccountMgr", "%u accounts are loaded and ready.", sAccountMgr.GetCount());

	Log.CNotice(TPURPLE, "AccountMgr", "Loading static realms");
	sInfoCore.LoadStaticRealms();
	Log.Line();

	// Spawn periodic function caller thread for account reload every 10mins
	int atime = Config.MainConfig.GetIntDefault("Rates", "AccountRefresh",600);
	atime *= 1000;
	PeriodicFunctionCaller<AccountMgr> * pfc = new PeriodicFunctionCaller<AccountMgr>(AccountMgr::getSingletonPtr(),&AccountMgr::ReloadAccountsCallback, atime);
	ThreadPool.ExecuteTask(pfc);

	// Load conf settings..
	uint32 cport = Config.MainConfig.GetIntDefault("Listen", "RealmListPort", 3724);
	uint32 sport = Config.MainConfig.GetIntDefault("Listen", "ServerPort", 8093);
	string host = Config.MainConfig.GetStringDefault("Listen", "Host", "0.0.0.0");
	string shost = Config.MainConfig.GetStringDefault("Listen", "ISHost", host.c_str());
	min_build = Config.MainConfig.GetIntDefault("Client", "MinBuild", 12340);
	max_build = Config.MainConfig.GetIntDefault("Client", "MaxBuild", 12340);
	string logon_pass = Config.MainConfig.GetStringDefault("LogonServer", "RemotePassword", "r3m0t3b4d");
	Sha1Hash hash;
	hash.UpdateData(logon_pass);
	hash.Finalize();
	memcpy(sql_hash, hash.GetDigest(), 20);
	
	ThreadPool.ExecuteTask(new LogonConsoleThread);

	new iocpEngine;
	new SocketEngineThread(&sSocketEngine);
	sSocketEngine.SpawnThreads();

	ListenSocket<AuthSocket> * cl = new ListenSocket<AuthSocket>();
	ListenSocket<LogonCommServerSocket> * sl = new ListenSocket<LogonCommServerSocket>();

	// Spawn auth listener
	// Spawn interserver listener
	bool authsockcreated = cl->Open(host.c_str(), cport);
	bool intersockcreated = sl->Open(shost.c_str(), sport);

	// hook signals
	Log.Notice("LogonServer","Hooking signals...");
	signal(SIGINT, _OnSignal);
	signal(SIGTERM, _OnSignal);
	signal(SIGABRT, _OnSignal);
#ifdef _WIN32
	signal(SIGBREAK, _OnSignal);
#else
	signal(SIGHUP, _OnSignal);
#endif

		/* write pid file */
	FILE * fPid = fopen("logonserver.pid", "w");
	if(fPid)
	{
		uint32 pid;
#ifdef WIN32
		pid = GetCurrentProcessId();
#else
		pid = getpid();
#endif
		fprintf(fPid, "%u", (unsigned int)pid);
		fclose(fPid);
	}
	uint32 loop_counter = 0;
	//ThreadPool.Gobble();
	Log.Notice("LogonServer","Success! Ready for connections");
	while(mrunning && authsockcreated && intersockcreated)
	{

		if(!(++loop_counter%10000))	// 2mins
		{
			ThreadPool.IntegrityCheck(2); //Logonserver don't need as many threads as world-server, 2 will do
		}

		if(!(loop_counter%100))  //100 loop ~ 1seconds
		{
			sInfoCore.TimeoutSockets();
			sSocketDeleter.Update();
			CheckForDeadSockets();				// Flood Protection
			UNIXTIME = time(NULL);
			g_localTime = *localtime(&UNIXTIME);
		}

		PatchMgr::getSingleton().UpdateJobs();
		Sleep(10);
	}

	Log.Notice("LogonServer","Shutting down...");

	signal(SIGINT, 0);
	signal(SIGTERM, 0);
	signal(SIGABRT, 0);
#ifdef _WIN32
	signal(SIGBREAK, 0);
#else
	signal(SIGHUP, 0);
#endif
	pfc->kill();

	cl->Disconnect();
	sl->Disconnect();

	sSocketEngine.Shutdown();
	sLogonConsole.Kill();
	delete LogonConsole::getSingletonPtr();

	// kill db
	sLog.outString("Waiting for database to close..");
	sLogonSQL->EndThreads();
	sLogonSQL->Shutdown();
	delete sLogonSQL;

	ThreadPool.Shutdown();

	// delete pid file
	remove("logonserver.pid");

	delete AccountMgr::getSingletonPtr();
	delete InformationCore::getSingletonPtr();
	delete IPBanner::getSingletonPtr();
	delete SocketEngine::getSingletonPtr();
	delete SocketDeleter::getSingletonPtr();
	delete pfc;
	delete cl;
	delete sl;
	Log.Notice("LogonServer","Shutdown complete.\n");
}
コード例 #4
0
bool Master::Run(int argc, char ** argv)
{
    sLog.InitializeUnderlayingLog();

    m_stopEvent = false;
    char * config_file = (char*)default_config_file;
    int screen_log_level = DEF_VALUE_NOT_SET;
    int do_check_conf = 0;
    int do_version = 0;
    int do_cheater_check = 0;
    int do_database_clean = 0;
    time_t curTime;

    struct hearthstone_option longopts[] =
    {
        { "checkconf",          hearthstone_no_argument,            &do_check_conf,         1       },
        { "screenloglevel",     hearthstone_required_argument,      &screen_log_level,      1       },
        { "version",            hearthstone_no_argument,            &do_version,            1       },
        { "cheater",            hearthstone_no_argument,            &do_cheater_check,      1       },
        { "cleandb",            hearthstone_no_argument,            &do_database_clean,     1       },
        { "conf",               hearthstone_required_argument,      NULL,                   'c'     },
        { "realmconf",          hearthstone_required_argument,      NULL,                   'r'     },
        { 0, 0, 0, 0 }
    };

    char c;
    while ((c = hearthstone_getopt_long_only(argc, argv, ":f:", longopts, NULL)) != -1)
    {
        switch (c)
        {
        case 'c':
            config_file = new char[strlen(hearthstone_optarg)];
            strcpy(config_file, hearthstone_optarg);
            break;
        case 0:
            break;
        default:
            sLog.SetLoggingLevel(3);
            printf("Usage: %s [--checkconf] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]);
            return true;
        }
    }

    /* set new log levels if used as argument*/
    if( screen_log_level != (int)DEF_VALUE_NOT_SET )
        sLog.SetLoggingLevel(screen_log_level);

    // Startup banner
    UNIXTIME = time(NULL);
    g_localTime = *localtime(&UNIXTIME);

    printf(BANNER, BUILD_TAG, BUILD_HASH_STR, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH);
    sLog.Line();

    printf( "The key combination <Ctrl-C> will safely shut down the server at any time.\n" );
    sLog.Line();

#ifndef WIN32
    if(geteuid() == 0 || getegid() == 0)
        sLog.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running Hearthstone as root.", "This is not needed, and may be a possible security risk.", "It is advised to hit CTRL+C now and", "start as a non-privileged user.", NULL);
#endif

    InitRandomNumberGenerators();
    sLog.Success( "Rnd", "Initialized Random Number Generators." );

    mainIni = new CIniFile(config_file);
    uint32 LoadingTime = getMSTime();
    sLog.Notice( "Config", "Loading Config Files..." );
    if( !mainIni->ParseError() )
        sLog.Success( "Config", ">> hearthstone-world.ini" );
    else
    {
        sLog.Error( "Config", ">> hearthstone-world.ini" );
        return false;
    }

    //use these log_level until we are fully started up.
    if(mainIni->ReadInteger("LogLevel", "Screen", 1) == -1)
    {
        sLog.Notice("Master", "Running silent mode...");
        sLog.Init(-1);
    }
    else
#ifdef _DEBUG
        sLog.Init(3);
#else
        sLog.Init(1);
#endif // _DEBUG

    sDBEngine.Init(false);

    if(!_StartDB())
    {
        DirectDatabase::CleanupLibs();
        return false;
    }

    sLog.Line();
    sLog.outString("");

    new EventMgr();
    EventableObjectHolder* m_Holder = new EventableObjectHolder(-1);

    new World();

    /* load the config file */
    sWorld.Rehash(true);

    // Because of our log DB system, these have to be initialized different then rehash.
    sWorld.LogCheaters = mainIni->ReadBoolean("Log", "Cheaters", false);
    sWorld.LogCommands = mainIni->ReadBoolean("Log", "GMCommands", false);
    sWorld.LogPlayers = mainIni->ReadBoolean("Log", "Player", false);
    sWorld.bLogChat = mainIni->ReadBoolean("Log", "Chat", false);

    //Update log to obey config setting
    sLog.Init(mainIni->ReadInteger("LogLevel", "Screen", 1));

    // Initialize Opcode Table
    WorldSession::InitPacketHandlerTable();

    string host = mainIni->ReadString( "Listen", "Host", DEFAULT_HOST );
    int wsport = mainIni->ReadInteger( "RealmData", "WorldServerPort", DEFAULT_WORLDSERVER_PORT );

    new ScriptMgr();

    if( !sWorld.SetInitialWorldSettings() )
    {
        sLog.Error( "Server", "SetInitialWorldSettings() failed. Something went wrong? Exiting." );
        return false;
    }

    sWorld.SetStartTime(uint32(UNIXTIME));

    WorldRunnable * wr = new WorldRunnable(m_Holder);
    ThreadPool.ExecuteTask("WorldRunnable", wr);

    _HookSignals();

    ConsoleThread* console = new ConsoleThread();
    ThreadPool.ExecuteTask("ConsoleThread", console);

    uint32 realCurrTime, realPrevTime;
    realCurrTime = realPrevTime = getMSTime();

    // Socket loop!
    uint32 start = 0, last_time = getMSTime(), etime = 0;

    // Start Network Subsystem
    sLog.Debug("Server","Starting network subsystem..." );
    CreateSocketEngine(8);
    sSocketEngine.SpawnThreads();

    if( StartConsoleListener() )
        sLog.Success("RemoteConsole", "Started and listening on port %i", mainIni->ReadInteger("RemoteConsole", "Port", 8092));
    else
        sLog.Debug("RemoteConsole", "Not enabled or failed listen.");

    LoadingTime = getMSTime() - LoadingTime;
    sLog.Success("Server","Ready for connections. Startup time: %ums\n", LoadingTime );

    /* write pid file */
    FILE * fPid = fopen( "hearthstone-world.pid", "w" );
    if( fPid )
    {
        uint32 pid;
#ifdef WIN32
        pid = GetCurrentProcessId();
#else
        pid = getpid();
#endif
        fprintf( fPid, "%u", uint(pid) );
        fclose( fPid );
    }
#ifdef WIN32
    HANDLE hThread = GetCurrentThread();
#endif

    uint32 loopcounter = 0, LastLogonUpdate = getMSTime();
    if(mainIni->ReadInteger("LogLevel", "Screen", 1) == -1)
    {
        sLog.Init(1);
        sLog.Notice("Master", "Leaving Silent Mode...");
    }

    /* Connect to realmlist servers / logon servers */
    new LogonCommHandler();
    sLogonCommHandler.Startup();

    ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>();
    bool listnersockcreate = ls->Open(host.c_str(), wsport);

    while( !m_stopEvent && listnersockcreate )
    {
        start = getMSTime();

        /* since time() is an expensive system call, we only update it once per server loop */
        curTime = time(NULL);
        if( UNIXTIME != curTime )
        {
            UNIXTIME = time(NULL);
            g_localTime = *localtime(&curTime);
            UpdateRandomNumberGenerators();
        }

        sLogonCommHandler.UpdateSockets(getMSTime()-LastLogonUpdate);
        LastLogonUpdate = getMSTime();
        sSocketDeleter.Update();

        /* UPDATE */
        last_time = getMSTime();
        etime = last_time - start;
        if( 25 > etime )
        {
#if PLATFORM == PLATFORM_WIN
            WaitForSingleObject( hThread, 25 - etime );
#else
            Sleep( 25 - etime );
#endif
        }
    }
    // begin server shutdown
    sLog.Notice( "Shutdown", "Initiated at %s", ConvertTimeStampToDataTime( (uint32)UNIXTIME).c_str() );
    bServerShutdown = true;

    if( lootmgr.is_loading )
    {
        sLog.Notice( "Shutdown", "Waiting for loot to finish loading..." );
        while( lootmgr.is_loading )
            Sleep( 100 );
    }

    sDBEngine.EndThreads();

    if(sWorld.LacrimiThread != NULL) // Shut this down first...
    {
        sWorld.LacrimiThread->SelfTerminate();

        sLog.Notice( "Shutdown", "Waiting for Lacrimi to finish shutting down..." );
        while(sWorld.LacrimiThread->GetThreadState() == THREADSTATE_SELF_TERMINATE)
            Sleep(100);
    }

    sLog.Notice( "Database", "Clearing all pending queries..." );

    // kill the database thread first so we don't lose any queries/data
    CharacterDatabase.EndThreads();
    WorldDatabase.EndThreads();

    if(Database_Log)
        LogDatabase.EndThreads();

    guildmgr.SaveAllGuilds();
    sWorld.LogoutPlayers(); //(Also saves players).
    CharacterDatabase.Execute("UPDATE characters SET online = 0");

    sLog.Notice("Server", "Shutting down random generator.");
    CleanupRandomNumberGenerators();

    ls->Disconnect();

    sLog.Notice( "Network", "Shutting down network subsystem." );
    sSocketEngine.Shutdown();

    sAddonMgr.SaveToDB();
    sLog.Notice("AddonMgr", "~AddonMgr()");
    delete AddonMgr::getSingletonPtr();

    sLog.Notice("LootMgr", "~LootMgr()");
    delete LootMgr::getSingletonPtr();

    sLog.Notice("MailSystem", "~MailSystem()");
    delete MailSystem::getSingletonPtr();

    /* Shut down console system */
    CloseConsoleListener();
    console->terminate();
    delete console;

    sLog.Notice("Thread", "Terminating thread pool...");
    ThreadPool.Shutdown();

    ls = NULL;

    sLog.Notice( "Network", "Deleting Network Subsystem..." );
    {
        /* delete the socket deleter */
        delete SocketDeleter::getSingletonPtr();

        /* delete the socket engine */
        delete SocketEngine::getSingletonPtr();

        /* WSA network cleanup */
        WSACleanup();
    }

    sLog.Notice("InsertQueueLoader", "~InsertQueueLoader()");
    delete InsertQueueLoader::getSingletonPtr();

    sLog.Notice("LogonComm", "~LogonCommHandler()");
    delete LogonCommHandler::getSingletonPtr();

    sLog.Notice( "World", "~World()" );
    sWorld.Destruct();
//  delete World::getSingletonPtr();

    sLog.Notice( "ScriptMgr", "~ScriptMgr()" );
    sScriptMgr.UnloadScripts();
    delete ScriptMgr::getSingletonPtr();

    sLog.Notice( "EventMgr", "~EventMgr()" );
    delete EventMgr::getSingletonPtr();

    sLog.Notice( "Database", "Closing Connections..." );
    _StopDB();

    _UnhookSignals();

    // remove pid
    remove( "hearthstone-world.pid" );

    sLog.Notice( "Shutdown", "Shutdown complete." );
    return true;
}