Ejemplo n.º 1
0
void CStackWalker::OnOutput(LPCSTR szText)
{
	std::string s;
	if(m_sharedptrlog)
		s = FormatOutputString("logs", "SharedPtrLog", false);
	else
		s = FormatOutputString("logs", "CrashLog", false);
	FILE * m_file = fopen(s.c_str(), "a");
	if(!m_file) return;

	printf("   %s", szText);
	fprintf(m_file, "   %s", szText);
	fclose(m_file);
}
Ejemplo n.º 2
0
void CStackWalker::OnOutput(LPCSTR szText)
{
	std::string s = FormatOutputString("logs", "CrashLog", false);
	FILE* m_file = fopen(s.c_str(), "a");
	if(!m_file) return;

	sLog.outError("   %s", szText);
	fprintf(m_file, "   %s", szText);
	fclose(m_file);
}
Ejemplo n.º 3
0
void OutputCrashLogLine(const char * format, ...)
{
        std::string s = FormatOutputString("logs", "CrashLog", false);
        FILE * m_file = fopen(s.c_str(), "a");
        if(!m_file) return;

        va_list ap;
        va_start(ap, format);
        vfprintf(m_file, format, ap);
        fprintf(m_file, "\n");
        fclose(m_file);
        va_end(ap);
}
Ejemplo n.º 4
0
WorldLog::WorldLog()
{
	log = new TextLogger(FormatOutputString("logs", "WorldLog", true).c_str(), false);
	bEnabled = false;

	if (Config.MainConfig.GetBoolDefault("LogLevel", "World", false))
	{
		sLog.outString("  Enabling packetlog output to \"world.log\"");
		Enable();
	} else {
		Disable();
	}
}
Ejemplo n.º 5
0
bool ChatHandler::HandleGPSCommand(const char* args, WorldSession* m_session)
{
	Object* obj;

	uint64 guid = m_session->GetPlayer()->GetSelection();
	if(guid != 0)
	{
		if((obj = m_session->GetPlayer()->GetMapMgr()->GetUnit(guid)) == 0)
		{
			SystemMessage(m_session, "You should select a character or a creature.");
			return true;
		}
	}
	else
		obj = m_session->GetPlayer();

	char buf[328];
	AreaTable* at = dbcArea.LookupEntryForced(obj->GetMapMgr()->GetAreaID(obj->GetPositionX(), obj->GetPositionY()));
	if(!at)
	{
		snprintf((char*)buf, 328, "|cff00ff00Current Position: |cffffffffMap: |cff00ff00%d |cffffffffX: |cff00ff00%f |cffffffffY: |cff00ff00%f |cffffffffZ: |cff00ff00%f |cffffffffOrientation: |cff00ff00%f|r",
		         (unsigned int)obj->GetMapId(), obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation());
		SystemMessage(m_session, buf);
		return true;
	}

	snprintf((char*)buf, 328, "|cff00ff00Current Position: |cffffffffMap: |cff00ff00%d |cffffffffZone: |cff00ff00%u |cffffffffArea: |cff00ff00%u  |cffffffffX: |cff00ff00%f |cffffffffY: |cff00ff00%f |cffffffffZ: |cff00ff00%f |cffffffffOrientation: |cff00ff00%f |cffffffffArea Name: |cff00ff00%s |r",
	         (unsigned int)obj->GetMapId(), at->ZoneId, at->AreaId, obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), at->name);


	SystemMessage(m_session, buf);
// ".gps 1" will save gps info to file logs/gps.log - This probably isn't very multithread safe so don't have many gms spamming it!
	if(args != NULL && *args == '1')
	{
		FILE* gpslog = fopen(FormatOutputString("logs", "gps", false).c_str(), "at");
		if(gpslog)
		{
			fprintf(gpslog, "%d, %u, %u, %f, %f, %f, %f, \'%s\'",
			        (unsigned int)obj->GetMapId(), at->ZoneId, at->AreaId, obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientation(), at->name);
// ".gps 1 comment" will save comment after the gps data
			if(*(args + 1) == ' ')
				fprintf(gpslog, ",%s\n", args + 2);
			else
				fprintf(gpslog, "\n");
			fclose(gpslog);
		}
	}
	return true;
}
Ejemplo n.º 6
0
void oLog::Init(int32 fileLogLevel, int32 screenLogLevel)
{
	m_screenLogLevel = screenLogLevel;
	m_fileLogLevel = fileLogLevel;
	fileLogger = new TextLogger(FormatOutputString("logs", "ServerLog", true).c_str(), false);

	if(m_fileLogLevel >= 0)
		fileLogger->Open();

	// get error handle
#ifdef WIN32
	stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
	stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
}
Ejemplo n.º 7
0
void echo(const char * format, ...)
{
	va_list ap;
	va_start(ap, format);
	vprintf(format, ap);
	std::string s = FormatOutputString("logs", "CrashLog", false);
	FILE * m_file = fopen(s.c_str(), "a");
	if(!m_file)
	{
		va_end(ap);
		return;
	}

	vfprintf(m_file, format, ap);
	fclose(m_file);
	va_end(ap);
}
Ejemplo n.º 8
0
bool Master::Run(int argc, char ** argv)
{
	char * config_file = (char*)default_config_file;
	char * optional_config_file = (char*)default_optional_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 arcemu_option longopts[] =
	{
		{ "checkconf",			arcemu_no_argument,				&do_check_conf,			1		},
		{ "screenloglevel",		arcemu_required_argument,		&screen_log_level,		1		},
		{ "fileloglevel",		arcemu_required_argument,		&file_log_level,		1		},
		{ "version",			arcemu_no_argument,				&do_version,			1		},
		{ "conf",				arcemu_required_argument,		NULL,					'c'		},
		{ "realmconf",			arcemu_required_argument,		NULL,					'r'		},
		{ "databasecleanup",	arcemu_no_argument,				&do_database_clean,		1		},
		{ "cheatercheck",		arcemu_no_argument,				&do_cheater_check,		1		},
		{ 0, 0, 0, 0 }
	};

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

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

		case 0:
			break;
		default:
			sLog.m_fileLogLevel = -1;
			sLog.m_screenLogLevel = 3;
			printf("Usage: %s [--checkconf] [--screenloglevel <level>] [--fileloglevel <level>] [--conf <filename>] [--realmconf <filename>] [--version] [--databasecleanup] [--cheatercheck]\n", argv[0]);
			return true;
		}
	}

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

	if(!do_version && !do_check_conf)
	{
		sLog.Init(-1, 3);
	}
	else
	{
		sLog.m_fileLogLevel = -1;
		sLog.m_screenLogLevel = 1;
	}

	printf(BANNER, BUILD_TAG, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH);
#ifdef REPACK
	printf("\nRepack: %s | Author: %s | %s\n", REPACK, REPACK_AUTHOR, REPACK_WEBSITE);
#endif
	Log.Color(TBLUE);
	printf("\nCopyright (C) 2008 ArcEmu. http://www.arcemu.org/\n");
	printf("This program is free software: you can redistribute it and/or modify\n");
	printf("it under the terms of the GNU Affero General Public License as published by\n");
	printf("the Free Software Foundation, either version 3 of the License, or\n");
	printf("any later version.\n");
	printf("This program is distributed in the hope that it will be useful,\n");
	printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
	printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
	printf("GNU Affero General Public License for more details.\n");
	printf("                                                \n");
	printf("                     ``````                     \n");
	printf("    ArcEmu!        `/o/::-:/-                   \n"); 
	printf("                   oho/-.-:yN-                  \n"); 
	printf("                    os+/-.:::                   \n"); 
	printf("                    :ysyoo+:`                   \n"); 
	printf("					`ohdys/.                    \n"); 
	printf("                     oyho/-`   ``               \n"); 
	printf("                   `shyo+:./ssmdsyo:`           \n"); 
	printf("                    .shss+:yNMMNNMNmms.         \n"); 
	printf("                    :ysss+:mNMMMMNNmmds.        \n"); 
	printf("                `-//sssoo/:NMNMMMNMNNdy-        \n"); 
	printf("    -`/`       `omhyyhyyyshNMMNNNMMMNmy:        \n"); 
	printf("    :/::-`     `sdmdmmNMNMMMMMMNMNNNNms-        \n"); 
	printf("     /+++/-.....shdmmNMMNMMMMMMMMMNNNd+         \n");
	printf("     ./+oshyhhhddmhdmNMMMMMMMMMMMMNNds.         \n"); 
	printf("       `:/:.`````.:+ymmNMMNMMMNMMNNd/           \n"); 
	printf("                     -+shmNNMMMNmhy/            \n"); 
	printf("                          `..-ods:.             \n");
	printf("                               o:.`             \n");
	printf("                               :-.              \n");
	printf("                              `/-...            \n"); 
	printf("    Introducing the emu!     --``-/:`           \n"); 
	printf("                           .:/+:-.-::.          \n"); 
	printf("                          `.-///:-.`            \n");
	printf(" Website: http://www.ArcEmu.org	     			\n");
	printf(" Forums: http://www.ArcEmu.org/forums/          \n");
	printf(" Credits: http://www.ArcEmu.org/credits         \n");
	printf(" SVN: http://arcemu.info/svn/                   \n");
	printf(" Have fun!                                      \n");
	Log.Line();
#ifdef REPACK
	Log.Color(TRED);
	printf("Warning: Using repacks is potentially dangerous. You should always compile\n");
	printf("from the source yourself at www.arcemu.org.\n");
	printf("By using this repack, you agree to not visit the arcemu website and ask\nfor support.\n");
	printf("For all support, you should visit the repacker's website at %s\n", REPACK_WEBSITE);
	Log.Color(TNORMAL);
	Log.Line();
#endif
	Log.log_level = 3;

	if(do_version)
		return true;

	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" );

		Log.Notice( "Config", "Checking config file:: %s\n", optional_config_file);
		if(Config.OptionalConfig.SetSource(optional_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();
    
#ifndef WIN32
	if(geteuid() == 0 || getegid() == 0)
		Log.LargeErrorMessage( LARGERRORMESSAGE_WARNING, "You are running ArcEmu 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", ">> configs/arcemu-world.conf" );
	else
	{
		Log.Error( "Config", ">> configs/arcemu-world.conf" );
		return false;
	}

	if(Config.OptionalConfig.SetSource(optional_config_file))
		Log.Success( "Config", ">> configs/arcemu-optional.conf");
	else
	{
		Log.Error("Config", ">> configs/arcemu-optional.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", ">> configs/arcemu-realms.conf" );
	else
	{
		Log.Error( "Config", ">> configs/arcemu-realms.conf" );
		return false;
	}

#if !defined(WIN32) && defined(__DEBUG__)
	if (Config.MainConfig.GetIntDefault( "LogLevel", "DisableCrashdumpReport", 0) == 0)
	{
		char cmd[1024];
		char banner[1024];
		snprintf(banner, 1024, BANNER, BUILD_TAG, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH);
		snprintf(cmd, 1024, "./arcemu-crashreport -r %d -d \"%s\"", BUILD_REVISION, banner);
		system(cmd);
	}
	unlink("arcemu.uptime");
#endif

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

	if(do_database_clean)
	{
		printf( "\nEntering database maintenance mode.\n\n" );
		new DatabaseCleaner;
		DatabaseCleaner::getSingleton().Run();
		delete DatabaseCleaner::getSingletonPtr();
		Log.Color(TYELLOW);
		printf( "\nMaintenence finished. Take a moment to review the output, and hit space to continue startup." );
		Log.Color(TNORMAL);
		fflush(stdout);
	}

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

#ifdef GM_SCRIPT
	ScriptSystem = new ScriptEngine;
	ScriptSystem->Reload();
#endif

	new EventMgr;
	new World;
	//have to init this ones for singleton
	new tPPoolClass<Item>;
	new tPPoolClass<Aura>;
	new tPPoolClass<Spell>;

	// 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);

	/* set new log levels */
	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);

	// 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;
	}

	if( do_cheater_check )
		sWorld.CleanupCheaters();

	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;
	uint32 next_printout = getMSTime(), next_send = getMSTime();

	// Start Network Subsystem
	Log.Notice( "Network","Starting subsystem..." );
	new SocketMgr;
	new SocketGarbageCollector;
	sSocketMgr.SpawnWorkerThreads();

	sScriptMgr.LoadScripts();

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

	Log.Notice("RemoteConsole", "Starting...");
	if( StartConsoleListener() )
	{
#ifdef WIN32
		ThreadPool.ExecuteTask( GetConsoleListener() );
#endif
		Log.Notice("RemoteConsole", "Now open.");
	}
	else
	{
		Log.Warning("RemoteConsole", "Not enabled or failed listen.");
	}
	
 
	/* write pid file */
	FILE * fPid = fopen( "arcemu.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();
#if !defined(WIN32) && defined(__DEBUG__)
			FILE * f = fopen( "arcemu.uptime", "w" );
			if( f )
			{
				fprintf(f, "%u", sWorld.GetUptime());
				fclose(f);
			}
#endif
		}

		/* 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( m_ShutdownEvent )
		{
			if( getMSTime() >= next_printout )
			{
				if(m_ShutdownTimer > 60000.0f)
				{
					if( !( (int)(m_ShutdownTimer) % 60000 ) )
						Log.Notice( "Server", "Shutdown in %i minutes.", (int)(m_ShutdownTimer / 60000.0f ) );
				}
				else
					Log.Notice( "Server","Shutdown in %i seconds.", (int)(m_ShutdownTimer / 1000.0f ) );
					
				next_printout = getMSTime() + 500;
			}

			if( getMSTime() >= next_send )
			{
				int time = m_ShutdownTimer / 1000;
				if( ( time % 30 == 0 ) || time < 10 )
				{
					// broadcast packet.
					WorldPacket data( 20 );
					data.SetOpcode( SMSG_SERVER_MESSAGE );
					if(m_restartEvent)
						data << uint32( SERVER_MSG_RESTART_TIME );
					else
						data << uint32( SERVER_MSG_SHUTDOWN_TIME );
					
					if( time > 0 )
					{
						int mins = 0, secs = 0;
						if(time > 60)
							mins = time / 60;
						if(mins)
							time -= (mins * 60);
						secs = time;
						char str[20];
						snprintf( str, 20, "%02u:%02u", mins, secs );
						data << str;
						sWorld.SendGlobalMessage( &data, NULL );
					}
				}
				next_send = getMSTime() + 1000;
			}
			if( diff >= m_ShutdownTimer )
				break;
			else
				m_ShutdownTimer -= diff;
		}

		if( 50 > etime )
		{
#ifdef WIN32
			WaitForSingleObject( hThread, 50 - etime );
#else
			Sleep( 50 - etime );
#endif
		}
	}
	_UnhookSignals();

    wr->SetThreadState( THREADSTATE_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 );
	}

	// 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( "DayWatcherThread", "Exiting..." );
	dw->terminate();
	dw = NULL;

	Log.Notice( "CommonScheduleThread", "Exiting..." );
	cs->terminate();
	cs = NULL;

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

	CloseConsoleListener();
	sWorld.SaveAllPlayers();

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

	bServerShutdown = true;
	ThreadPool.Shutdown();

	delete ls;

	sWorld.LogoutPlayers();
	sLog.outString( "" );

	delete LogonCommHandler::getSingletonPtr();

	//should delete pools before other handlers !
	Log.Notice( "Item Pool", "Item Pool" );
	ItemPool.DestroyPool();

	Log.Notice( "Spell Pool", "Spell Pool" );
	SpellPool.DestroyPool();

	Log.Notice( "Aura Pool", "Aura Pool" );
	AuraPool.DestroyPool();

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

	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 GM_SCRIPT
	Log.Notice("GM-scripting:", "Closing ScriptEngine...");
	delete ScriptSystem;
#endif

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

	delete GMCommand_Log;
	delete Anticheat_Log;
	delete Player_Log;

	// remove pid
	remove( "arcemu.pid" );

	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;
}
Ejemplo n.º 9
0
bool Master::Run(int argc, char ** argv)
{
    char * config_file = (char*)default_config_file;
    char * optional_config_file = (char*)default_optional_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 arcemu_option longopts[] =
    {
        { "checkconf", arcemu_no_argument, &do_check_conf, 1 },
        { "screenloglevel", arcemu_required_argument, &screen_log_level, 1 },
        { "fileloglevel", arcemu_required_argument, &file_log_level, 1 },
        { "version", arcemu_no_argument, &do_version, 1 },
        { "conf", arcemu_required_argument, NULL, 'c' },
        { "realmconf", arcemu_required_argument, NULL, 'r' },
        { "databasecleanup", arcemu_no_argument, &do_database_clean, 1 },
        { "cheatercheck", arcemu_no_argument, &do_cheater_check, 1 },
        { 0, 0, 0, 0 }
    };

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

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

            case 0:
                break;
            default:
                sLog.m_fileLogLevel = -1;
                sLog.m_screenLogLevel = 3;
                printf("Usage: %s [--checkconf] [--screenloglevel <level>] [--fileloglevel <level>] [--conf <filename>] [--realmconf <filename>] [--version] [--databasecleanup] [--cheatercheck]\n", argv[0]);
                return true;
        }
    }

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

    if (!do_version && !do_check_conf)
    {
        sLog.Init(0, WORLD_LOG);
    }
    else
    {
        sLog.m_fileLogLevel = -1;
        sLog.m_screenLogLevel = 1;
    }

    sLog.outBasic(BANNER, BUILD_HASH_STR, CONFIG, PLATFORM_TEXT, ARCH);
    sLog.outBasic("========================================================");
    sLog.outErrorSilent(BANNER, BUILD_HASH_STR, CONFIG, PLATFORM_TEXT, ARCH); // Echo off.
    sLog.outErrorSilent("========================================================"); // Echo off.

    if (do_version)
        return true;

    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", realm_config_file);
        if (Config.RealmConfig.SetSource(realm_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", optional_config_file);
        if (Config.OptionalConfig.SetSource(optional_config_file, true))
            Log.Success("Config", "Passed without errors.");
        else
            Log.Warning("Config", "Encountered one or more errors.");

        return true;
    }

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

#ifndef WIN32
    if (geteuid() == 0 || getegid() == 0)
        Log.LargeErrorMessage("You are running ArcEmu 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.Success("Config", "Loading Config Files...");
    if (Config.MainConfig.SetSource(config_file))
        Log.Notice("Config", ">> " CONFDIR "/world.conf loaded");
    else
    {
        Log.Error("Config", ">> error occurred loading " CONFDIR "/world.conf");
        return false;
    }

    if (Config.OptionalConfig.SetSource(optional_config_file))
        Log.Notice("Config", ">> " CONFDIR "/optional.conf loaded");
    else
    {
        Log.Error("Config", ">> error occurred loading " CONFDIR "/optional.conf");
        return false;
    }


    if (Config.RealmConfig.SetSource(realm_config_file))
        Log.Notice("Config", ">> " CONFDIR "/realms.conf loaded");
    else
    {
        Log.Error("Config", ">> error occurred loading " CONFDIR "/realms.conf");
        return false;
    }

#if !defined(WIN32) && defined(__DEBUG__)
    if (Config.MainConfig.GetIntDefault("LogLevel", "DisableCrashdumpReport", 0) == 0)
    {
        char cmd[1024];
        char banner[1024];
        snprintf(banner, 1024, BANNER, BUILD_TAG, BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH);
        snprintf(cmd, 1024, "./crashreport -r %d -d \"%s\"", BUILD_REVISION, banner);
        system(cmd);
    }
    unlink("arcemu.uptime");
#endif

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

    // Checking the DB version. If it's wrong or can't be validated we exit.
    if (!CheckDBVersion())
    {
        sLog.Close();
        return false;
    }

    if (do_database_clean)
    {
        sLog.outDebug("Entering database maintenance mode.");
        new DatabaseCleaner;
        DatabaseCleaner::getSingleton().Run();
        delete DatabaseCleaner::getSingletonPtr();
        sLog.outDebug("Maintenance finished.");
    }

#ifdef GM_SCRIPT
    ScriptSystem = new ScriptEngine;
    ScriptSystem->Reload();
#endif

    new EventMgr;
    new World;
    //have to init this ones for singleton
    new tPPoolClass<Item>;
    new tPPoolClass<Aura>;
    new tPPoolClass<Spell>;

    // 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);

    /* set new log levels */
    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);

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

    std::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;
    }

    if (do_cheater_check)
        sWorld.CleanupCheaters();

    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;
    uint32 next_printout = getMSTime(), next_send = getMSTime();

    // Start Network Subsystem
    Log.Notice("Network", "Starting subsystem...");
    new SocketMgr;
    new SocketGarbageCollector;
    sSocketMgr.SpawnWorkerThreads();

    sScriptMgr.LoadScripts();

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

    Log.Notice("RemoteConsole", "Starting...");
    if (StartConsoleListener())
    {
#ifdef WIN32
        ThreadPool.ExecuteTask(GetConsoleListener());
#endif
        Log.Notice("RemoteConsole", "Now open.");
    }
    else
    {
        Log.Warning("RemoteConsole", "Not enabled or failed listen.");
    }


    /* write pid file */
    FILE * fPid = fopen("worldserver.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();
#if !defined(WIN32) && defined(__DEBUG__)
            FILE * f = fopen("arcemu.uptime", "w");
            if (f)
            {
                fprintf(f, "%u", sWorld.GetUptime());
                fclose(f);
            }
#endif
        }

        /* 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 (m_ShutdownEvent)
        {
            if (getMSTime() >= next_printout)
            {
                if (m_ShutdownTimer > 60000.0f)
                {
                    if (!((int)(m_ShutdownTimer) % 60000))
                        Log.Notice("Server", "Shutdown in %i minutes.", (int)(m_ShutdownTimer / 60000.0f));
                }
                else
                    Log.Notice("Server", "Shutdown in %i seconds.", (int)(m_ShutdownTimer / 1000.0f));

                next_printout = getMSTime() + 500;
            }

            if (getMSTime() >= next_send)
            {
                int time = m_ShutdownTimer / 1000;
                if ((time % 30 == 0) || time < 10)
                {
                    // broadcast packet.
                    WorldPacket data(20);
                    data.SetOpcode(SMSG_SERVER_MESSAGE);
                    if (m_restartEvent)
                        data << uint32(SERVER_MSG_RESTART_TIME);
                    else
                        data << uint32(SERVER_MSG_SHUTDOWN_TIME);

                    if (time > 0)
                    {
                        int mins = 0, secs = 0;
                        if (time > 60)
                            mins = time / 60;
                        if (mins)
                            time -= (mins * 60);
                        secs = time;
                        char str[20];
                        snprintf(str, 20, "%02u:%02u", mins, secs);
                        data << str;
                        sWorld.SendGlobalMessage(&data, NULL);
                    }
                }
                next_send = getMSTime() + 1000;
            }
            if (diff >= m_ShutdownTimer)
                break;
            else
                m_ShutdownTimer -= diff;
        }

        if (50 > etime)
        {
#ifdef WIN32
            WaitForSingleObject(hThread, 50 - etime);
#else
            Sleep(50 - etime);
#endif
        }
    }
    _UnhookSignals();

    wr->SetThreadState(THREADSTATE_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);
    }

    // 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("DayWatcherThread", "Exiting...");
    dw->terminate();
    dw = NULL;

    Log.Notice("CommonScheduleThread", "Exiting...");
    cs->terminate();
    cs = NULL;

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

    CloseConsoleListener();
    sWorld.SaveAllPlayers();

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

    bServerShutdown = true;
    ThreadPool.Shutdown();

    delete ls;

    sWorld.LogoutPlayers();
    sLog.outString("");

    delete LogonCommHandler::getSingletonPtr();

    //should delete pools before other handlers !
    Log.Notice("Item Pool", "Item Pool");
    ItemPool.DestroyPool();

    Log.Notice("Spell Pool", "Spell Pool");
    SpellPool.DestroyPool();

    Log.Notice("Aura Pool", "Aura Pool");
    AuraPool.DestroyPool();

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

    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 GM_SCRIPT
    Log.Notice("GM-scripting:", "Closing ScriptEngine...");
    delete ScriptSystem;
#endif

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

    delete GMCommand_Log;
    delete Anticheat_Log;
    delete Player_Log;

    // remove pid
    remove("worldserver.pid");

    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;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
bool Master::Run(int argc, char ** argv)
{
#ifdef WIN32
	char * config_file = "antrix.conf";
	char * realm_config_file = "realms.conf";
#else
	char * config_file = CONFDIR "/antrix.conf";
	char * realm_config_file = CONFDIR "/realms.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 antrix_option longopts[] =
	{
		{ "checkconf",			antrix_no_argument,				&do_check_conf,			1		},
		{ "screenloglevel",		antrix_required_argument,		&screen_log_level,		1		},
		{ "fileloglevel",		antrix_required_argument,		&file_log_level,		1		},
		{ "version",			antrix_no_argument,				&do_version,			1		},
		{ "conf",				antrix_required_argument,		NULL,					'c'		},
		{ "realmconf",			antrix_required_argument,		NULL,					'r'		},
		{ 0, 0, 0, 0 }
	};

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

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

		case 0:
			break;
		default:
			sLog.m_fileLogLevel = -1;
			sLog.m_screenLogLevel = 3;
			printf("Usage: %s [--checkconf] [--screenloglevel <level>] [--fileloglevel <level>] [--conf <filename>] [--realmconf <filename>] [--version]\n", argv[0]);
			return true;
		}
	}

	// Startup banner
	if(!do_version && !do_check_conf)
	{
		launch_thread(new TextLoggerThread);
		sLog.Init(-1, 3);
	}
	else
	{
		sLog.m_fileLogLevel = -1;
		sLog.m_screenLogLevel = 3;
	}

	sLog.outString("==============================================================================");
	sLog.outString(BANNER, g_getRevision());
	sLog.outString("");
	sLog.outString("Copyright (c) 2007 Antrix Team. This software is under the QPL license, for");
	sLog.outString("more information look under the COPYING file in this distribution.");
	sLog.outString("==============================================================================");
	sLog.outString("");
	if(do_version)
		return true;

	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");

		printf("\nChecking config file: %s\n", realm_config_file);
		if(Config.RealmConfig.SetSource(realm_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 true;
	}

	sLog.outString("The key combination <Ctrl-C> will safely shut down the server at any time.");
	sLog.outString("");
	sLog.outString("Initializing File Loggers...");
	Crash_Log = new TextLogger(FormatOutputString("logs", "CrashLog", true).c_str(), false);
    
	sLog.outString("Initializing Random Number Generators...");
	uint32 seed = time(NULL);
	new MTRand(seed);
	srand(seed);

	sLog.outString("Starting Thread Manager...\n");
	new ThreadMgr;
	uint32 LoadingTime = getMSTime();

	sLog.outColor(TNORMAL, "Loading Config Files...\n");
	sLog.outColor(TYELLOW, "  >> %s :: ", config_file);
	if(Config.MainConfig.SetSource(config_file))
	{
		sLog.outColor(TGREEN, "ok!");
		sLog.outColor(TNORMAL, "\n");
	}
	else
	{
		sLog.outColor(TRED, "fail.");
		sLog.outColor(TNORMAL, "\n");
		return false;
	}

	/* 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 false;
	}	


	sLog.outColor(TYELLOW, "  >> %s :: ", realm_config_file);
	if(Config.RealmConfig.SetSource(realm_config_file))
	{
		sLog.outColor(TGREEN, "ok!");
		sLog.outColor(TNORMAL, "\n\n");
	}
	else
	{
		sLog.outColor(TRED, "fail.");
		sLog.outColor(TNORMAL, "\n\n");
		return false;
	}

	if(!_StartDB())
	{
		return false;
	}

	sLog.outString("");

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

	new EventMgr;
	new World;

	// 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);

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

	/* set new log levels */
	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);

	// 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;

	sWorld.SetInitialWorldSettings();
	sWorld.SetStartTime((uint32)time(NULL));
	
	_HookSignals();

	launch_thread(new CConsoleThread);

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

	// initialize thread system
	sThreadMgr.Initialize();
	
	// Socket loop!
	uint32 start;
	uint32 diff;
	uint32 last_time = now();
	uint32 etime;
	uint32 next_printout = getMSTime(), next_send = getMSTime();

	// Start Network Subsystem
	sLog.outString("Starting network subsystem...");
	new SocketMgr;
	new SocketGarbageCollector;
	sSocketMgr.SpawnWorkerThreads();

	sScriptMgr.LoadScripts();


	sLog.outString("Threading system initialized, currently %u threads are active.", sThreadMgr.GetThreadCount());	

	LoadingTime = getMSTime() - LoadingTime;
	sLog.outString ("\nServer is ready for connections. Startup time: %ums\n", LoadingTime );
 
	/* write pid file */
	FILE * fPid = fopen("antrix.pid", "w");
	if(fPid)
	{
		uint32 pid;
#ifdef WIN32
		pid = GetCurrentProcessId();
#else
		pid = getpid();
#endif
		fprintf(fPid, "%u", (unsigned int)pid);
		fclose(fPid);
	}
#ifndef CLUSTERING
	/* Connect to realmlist servers / logon servers */
	new LogonCommHandler();
	sLogonCommHandler.Startup();

	// Create listener
	ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(host.c_str(), wsport);
    bool listnersockcreate = ls->IsOpen();
	while(!m_stopEvent && listnersockcreate)
#else
	new ClusterInterface;
	sClusterInterface.ConnectToRealmServer();
	while(!m_stopEvent)
#endif
	{
		start = now();
		diff = start - last_time;

#ifndef CLUSTERING
		sLogonCommHandler.UpdateSockets();
		ls->Update();
#else
		sClusterInterface.Update();
#endif
		sSocketGarbageCollector.Update();

		/* UPDATE */
		last_time = now();
		etime = last_time - start;
		if(m_ShutdownEvent)
		{
			if(getMSTime() >= next_printout)
			{
				if(m_ShutdownTimer > 60000.0f)
				{
					if(!((int)(m_ShutdownTimer)%60000))
						sLog.outString("Server shutdown in %i minutes.", (int)(m_ShutdownTimer / 60000.0f));
				}
				else
					sLog.outString("Server shutdown in %i seconds.", (int)(m_ShutdownTimer / 1000.0f));
					
				next_printout = getMSTime() + 500;
			}
			if(getMSTime() >= next_send)
			{
				// broadcast packet.
				WorldPacket data(20);
				data.SetOpcode(SMSG_SERVER_MESSAGE);
				data << uint32(SERVER_MSG_SHUTDOWN_TIME);
				int time = m_ShutdownTimer / 1000;
				if(time > 0)
				{
					int mins = 0, secs = 0;
					if(time > 60)
						mins = time / 60;
					if(mins)
						time -= (mins*60);
					secs = time;
					char str[20];
					snprintf(str, 20, "%02u:%02u", mins, secs);
					data << str;
					sWorld.SendGlobalMessage(&data, NULL);
				}
				next_send = getMSTime() + 1000;
			}
			if(diff >= m_ShutdownTimer)
				break;
			else
				m_ShutdownTimer -= diff;
		}
		
		Database_Character->CheckConnections();
		Database_World->CheckConnections();
		sWorld.UpdateQueuedSessions(diff);

		if(50 > etime)
			Sleep(50 - etime);

	}
	_UnhookSignals();

	CConsoleThread *thread = (CConsoleThread*)sThreadMgr.GetThreadByType(THREADTYPE_CONSOLEINTERFACE);
	ASSERT(thread);
	thread->SetThreadState(THREADSTATE_TERMINATE);
	// have to cleanup manually.
	sThreadMgr.RemoveThread(thread);

	sLog.outString("Killing all sockets and network subsystem.");
#ifndef CLUSTERING
	ls->Close();
	delete ls;
#endif
#ifdef WIN32
	sSocketMgr.ShutdownThreads();
#endif
	sSocketMgr.CloseAll();

	// begin server shutdown
	time_t st = time(NULL);
	sLog.outString("Server shutdown initiated at %s", ctime(&st));

	// send a query to wake it up if its inactive
	sLog.outString("Executing pending database queries and closing database thread...");
	// kill the database thread first so we don't lose any queries/data
	((MySQLDatabase*)Database_Character)->SetThreadState(THREADSTATE_TERMINATE);
	((MySQLDatabase*)Database_World)->SetThreadState(THREADSTATE_TERMINATE);

	CharacterDatabase.Execute("UPDATE characters SET online = 0");
	WorldDatabase.Execute("UPDATE characters SET online = 0");

	// wait for it to finish its work
	while(((MySQLDatabase*)Database_Character)->ThreadRunning || ((MySQLDatabase*)Database_World)->ThreadRunning)
	{
		Sleep(100);
	}
	sThreadMgr.RemoveThread(((MySQLDatabase*)Database_Character));
	sThreadMgr.RemoveThread(((MySQLDatabase*)Database_World));

	sLog.outString("All pending database operations cleared.\n");

	sWorld.SaveAllPlayers();
	sLog.outString("");

	delete LogonCommHandler::getSingletonPtr();

	sWorld.ShutdownClasses();
	sLog.outString("\nDeleting World...");
	delete World::getSingletonPtr();

	sLog.outString("Deleting Event Manager...");
	delete EventMgr::getSingletonPtr();

	sLog.outString("Terminating MySQL connections...\n");
	_StopDB();

	sLog.outString("Deleting Network Subsystem...");
	delete SocketMgr::getSingletonPtr();
	delete SocketGarbageCollector::getSingletonPtr();

	sLog.outString("Deleting Script Engine...");
	delete ScriptSystem;

	sLog.outString("\nServer shutdown completed successfully.\n");

	// close the logs
	TextLogger::Thread->Die();

#ifdef WIN32
	WSACleanup();

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

#endif

	return true;
}