Example #1
0
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;
		}
	}

	printf("Sandshroud Hearthstone r%u/%s-%s(%s)::Logon Server\n", BUILD_REVISION, CONFIG, PLATFORM_TEXT, ARCH);
	printf("==============================================================================\n");
	Log.Line();
	if(do_version)
		return;

	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.");
		return;
	}

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

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

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

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

	sDBEngine.Init(false);
	if(!startdb())
	{
		Database::CleanupLibs();
		return;
	}

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

	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.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("PeriodicFunctionCaller", 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("ConsoleThread", new LogonConsoleThread());

	DEBUG_LOG("Server","Starting network subsystem..." );
	CreateSocketEngine(2);
	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%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...");
	sDBEngine.EndThreads();
	sLogonSQL->EndThreads();

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

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

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

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

	// kill db
	sLog.outString("Waiting for database to close..");
	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;
	Log.Notice("LogonServer","Shutdown complete.\n");
}
Example #2
0
InspIRCd::InspIRCd(int argc, char** argv) :
    ConfigFileName(CONFIG_PATH "/inspircd.conf"),

    /* Functor pointer initialisation.
     *
     * THIS MUST MATCH THE ORDER OF DECLARATION OF THE FUNCTORS, e.g. the methods
     * themselves within the class.
     */
    NICKForced("NICKForced", NULL),
    OperQuit("OperQuit", NULL),
    GenRandom(&HandleGenRandom),
    IsChannel(&HandleIsChannel),
    Rehash(&HandleRehash),
    IsNick(&HandleIsNick),
    IsIdent(&HandleIsIdent),
    OnCheckExemption(&HandleOnCheckExemption)
{
    ServerInstance = this;

    Extensions.Register(&NICKForced);
    Extensions.Register(&OperQuit);

    FailedPortList pl;
    int do_version = 0, do_nofork = 0, do_debug = 0,
        do_nolog = 0, do_root = 0, do_testsuite = 0;    /* flag variables */
    int c = 0;

    // Initialize so that if we exit before proper initialization they're not deleted
    this->Logs = 0;
    this->Threads = 0;
    this->PI = 0;
    this->Users = 0;
    this->chanlist = 0;
    this->Config = 0;
    this->SNO = 0;
    this->BanCache = 0;
    this->Modules = 0;
    this->stats = 0;
    this->Timers = 0;
    this->Parser = 0;
    this->XLines = 0;
    this->Modes = 0;
    this->ConfigThread = NULL;
    this->FakeClient = NULL;

    UpdateTime();
    this->startup_time = TIME.tv_sec;

    // This must be created first, so other parts of Insp can use it while starting up
    this->Logs = new LogManager;

    SE = CreateSocketEngine();

    this->Threads = new ThreadEngine;

    /* Default implementation does nothing */
    this->PI = new ProtocolInterface;

    // Create base manager classes early, so nothing breaks
    this->Users = new UserManager;

    this->Users->unregistered_count = 0;

    this->Users->clientlist = new user_hash();
    this->Users->uuidlist = new user_hash();
    this->chanlist = new chan_hash();

    this->Config = new ServerConfig;
    this->SNO = new SnomaskManager;
    this->BanCache = new BanCacheManager;
    this->Modules = new ModuleManager();
    dynamic_reference_base::reset_all();
    this->stats = new serverstats();
    this->Timers = new TimerManager;
    this->Parser = new CommandParser;
    this->XLines = new XLineManager;

    this->Config->cmdline.argv = argv;
    this->Config->cmdline.argc = argc;

#ifdef _WIN32
    srand(TIME.tv_nsec ^ TIME.tv_sec);

    // Initialize the console values
    g_hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO bufinf;
    if(GetConsoleScreenBufferInfo(g_hStdout, &bufinf))
    {
        g_wOriginalColors = bufinf.wAttributes & 0x00FF;
        g_wBackgroundColor = bufinf.wAttributes & 0x00F0;
    }
    else
    {
        g_wOriginalColors = FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN;
        g_wBackgroundColor = 0;
    }
#else
    srandom(TIME.tv_nsec ^ TIME.tv_sec);
#endif

    struct option longopts[] =
    {
        { "nofork",	no_argument,		&do_nofork,	1	},
        { "logfile",	required_argument,	NULL,		'f'	},
        { "config",	required_argument,	NULL,		'c'	},
        { "debug",	no_argument,		&do_debug,	1	},
        { "nolog",	no_argument,		&do_nolog,	1	},
        { "runasroot",	no_argument,		&do_root,	1	},
        { "version",	no_argument,		&do_version,	1	},
        { "testsuite",	no_argument,		&do_testsuite,	1	},
        { 0, 0, 0, 0 }
    };

    int index;
    while ((c = getopt_long(argc, argv, ":c:f:", longopts, &index)) != -1)
    {
        switch (c)
        {
        case 'f':
            /* Log filename was set */
            Config->cmdline.startup_log = optarg;
            break;
        case 'c':
            /* Config filename was set */
            ConfigFileName = optarg;
            break;
        case 0:
            /* getopt_long_only() set an int variable, just keep going */
            break;
        case '?':
        /* Unknown parameter */
        default:
            /* Fall through to handle other weird values too */
            std::cout << "Unknown parameter '" << argv[optind-1] << "'" << std::endl;
            std::cout << "Usage: " << argv[0] << " [--nofork] [--nolog] [--debug] [--logfile <filename>] " << std::endl <<
                      std::string(static_cast<int>(8+strlen(argv[0])), ' ') << "[--runasroot] [--version] [--config <config>] [--testsuite]" << std::endl;
            Exit(EXIT_STATUS_ARGV);
            break;
        }
    }

    if (do_testsuite)
        do_nofork = do_debug = true;

    if (do_version)
    {
        std::cout << std::endl << VERSION << " r" << REVISION << std::endl;
        Exit(EXIT_STATUS_NOERROR);
    }

#ifdef _WIN32
    // Set up winsock
    WSADATA wsadata;
    WSAStartup(MAKEWORD(2,2), &wsadata);
#endif

    /* Set the finished argument values */
    Config->cmdline.nofork = (do_nofork != 0);
    Config->cmdline.forcedebug = (do_debug != 0);
    Config->cmdline.writelog = (!do_nolog != 0);
    Config->cmdline.TestSuite = (do_testsuite != 0);

    if (do_debug)
    {
        FileWriter* fw = new FileWriter(stdout);
        FileLogStream* fls = new FileLogStream(LOG_RAWIO, fw);
        Logs->AddLogTypes("*", fls, true);
    }
    else if (!this->OpenLog(argv, argc))
    {
        std::cout << "ERROR: Could not open initial logfile " << Config->cmdline.startup_log << ": " << strerror(errno) << std::endl << std::endl;
        Exit(EXIT_STATUS_LOG);
    }

    if (!ServerConfig::FileExists(ConfigFileName.c_str()))
    {
#ifdef _WIN32
        /* Windows can (and defaults to) hide file extensions, so let's play a bit nice for windows users. */
        std::string txtconf = this->ConfigFileName;
        txtconf.append(".txt");

        if (ServerConfig::FileExists(txtconf.c_str()))
        {
            ConfigFileName = txtconf;
        }
        else
#endif
        {
            std::cout << "ERROR: Cannot open config file: " << ConfigFileName << std::endl << "Exiting..." << std::endl;
            this->Logs->Log("STARTUP",LOG_DEFAULT,"Unable to open config file %s", ConfigFileName.c_str());
            Exit(EXIT_STATUS_CONFIG);
        }
    }

    std::cout << con_green << "Inspire Internet Relay Chat Server" << con_reset << ", compiled on " __DATE__ " at " __TIME__ << std::endl;
    std::cout << con_green << "(C) InspIRCd Development Team." << con_reset << std::endl << std::endl;
    std::cout << "Developers:" << std::endl;
    std::cout << con_green << "\tBrain, FrostyCoolSlug, w00t, Om, Special, peavey" << std::endl;
    std::cout << "\taquanight, psychon, dz, danieldg, jackmcbarn" << con_reset << std::endl << std::endl;
    std::cout << "Others:\t\t\t" << con_green << "See /INFO Output" << con_reset << std::endl;

    this->Modes = new ModeParser;

#ifndef _WIN32
    if (!do_root)
        this->CheckRoot();
    else
    {
        std::cout << "* WARNING * WARNING * WARNING * WARNING * WARNING *" << std::endl
                  << "YOU ARE RUNNING INSPIRCD AS ROOT. THIS IS UNSUPPORTED" << std::endl
                  << "AND IF YOU ARE HACKED, CRACKED, SPINDLED OR MUTILATED" << std::endl
                  << "OR ANYTHING ELSE UNEXPECTED HAPPENS TO YOU OR YOUR" << std::endl
                  << "SERVER, THEN IT IS YOUR OWN FAULT. IF YOU DID NOT MEAN" << std::endl
                  << "TO START INSPIRCD AS ROOT, HIT CTRL+C NOW AND RESTART" << std::endl
                  << "THE PROGRAM AS A NORMAL USER. YOU HAVE BEEN WARNED!" << std::endl << std::endl
                  << "InspIRCd starting in 20 seconds, ctrl+c to abort..." << std::endl;
        sleep(20);
    }
#endif

    this->SetSignals();

    if (!Config->cmdline.nofork)
    {
        if (!this->DaemonSeed())
        {
            std::cout << "ERROR: could not go into daemon mode. Shutting down." << std::endl;
            Logs->Log("STARTUP", LOG_DEFAULT, "ERROR: could not go into daemon mode. Shutting down.");
            Exit(EXIT_STATUS_FORK);
        }
    }

    SE->RecoverFromFork();

    /* During startup we don't actually initialize this
     * in the thread engine.
     */
    this->Config->Read();
    this->Config->Apply(NULL, "");
    Logs->OpenFileLogs();
    ModeParser::InitBuiltinModes();

    // If we don't have a SID, generate one based on the server name and the server description
    if (Config->sid.empty())
        Config->sid = UIDGenerator::GenerateSID(Config->ServerName, Config->ServerDesc);

    // Initialize the UID generator with our sid
    this->UIDGen.init(Config->sid);

    /* set up fake client again this time with the correct uid */
    this->FakeClient = new FakeUser(Config->sid, Config->ServerName);

    // Get XLine to do it's thing.
    this->XLines->CheckELines();
    this->XLines->ApplyLines();

    int bounditems = BindPorts(pl);

    std::cout << std::endl;

    this->Modules->LoadAll();

    /* Just in case no modules were loaded - fix for bug #101 */
    this->ISupport.Build();
    Config->ApplyDisabledCommands(Config->DisabledCommands);

    if (!pl.empty())
    {
        std::cout << std::endl << "WARNING: Not all your client ports could be bound -- " << std::endl << "starting anyway with " << bounditems
                  << " of " << bounditems + (int)pl.size() << " client ports bound." << std::endl << std::endl;
        std::cout << "The following port(s) failed to bind:" << std::endl << std::endl;
        int j = 1;
        for (FailedPortList::iterator i = pl.begin(); i != pl.end(); i++, j++)
        {
            std::cout << j << ".\tAddress: " << (i->first.empty() ? "<all>" : i->first) << " \tReason: " << i->second << std::endl;
        }

        std::cout << std::endl << "Hint: Try using a public IP instead of blank or *" << std::endl;
    }

    std::cout << "InspIRCd is now running as '" << Config->ServerName << "'[" << Config->GetSID() << "] with " << SE->GetMaxFds() << " max open sockets" << std::endl;

#ifndef _WIN32
    if (!Config->cmdline.nofork)
    {
        if (kill(getppid(), SIGTERM) == -1)
        {
            std::cout << "Error killing parent process: " << strerror(errno) << std::endl;
            Logs->Log("STARTUP", LOG_DEFAULT, "Error killing parent process: %s",strerror(errno));
        }
    }

    /* Explicitly shut down stdio's stdin/stdout/stderr.
     *
     * The previous logic here was to only do this if stdio was connected to a controlling
     * terminal.  However, we must do this always to avoid information leaks and other
     * problems related to stdio.
     *
     * The only exception is if we are in debug mode.
     *
     *    -- nenolod
     */
    if ((!do_nofork) && (!do_testsuite) && (!Config->cmdline.forcedebug))
    {
        int fd = open("/dev/null", O_RDWR);

        fclose(stdin);
        fclose(stderr);
        fclose(stdout);

        if (dup2(fd, STDIN_FILENO) < 0)
            Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdin.");
        if (dup2(fd, STDOUT_FILENO) < 0)
            Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stdout.");
        if (dup2(fd, STDERR_FILENO) < 0)
            Logs->Log("STARTUP", LOG_DEFAULT, "Failed to dup /dev/null to stderr.");
        close(fd);
    }
    else
    {
        Logs->Log("STARTUP", LOG_DEFAULT,"Keeping pseudo-tty open as we are running in the foreground.");
    }
#else
    /* Set win32 service as running, if we are running as a service */
    SetServiceRunning();

    // Handle forking
    if(!do_nofork)
    {
        FreeConsole();
    }

    QueryPerformanceFrequency(&stats->QPFrequency);
#endif

    Logs->Log("STARTUP", LOG_DEFAULT, "Startup complete as '%s'[%s], %d max open sockets", Config->ServerName.c_str(),Config->GetSID().c_str(), SE->GetMaxFds());

#ifndef _WIN32
    std::string SetUser = Config->ConfValue("security")->getString("runasuser");
    std::string SetGroup = Config->ConfValue("security")->getString("runasgroup");
    if (!SetGroup.empty())
    {
        int ret;

        // setgroups
        ret = setgroups(0, NULL);

        if (ret == -1)
        {
            this->Logs->Log("SETGROUPS", LOG_DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno));
            this->QuickExit(0);
        }

        // setgid
        struct group *g;

        errno = 0;
        g = getgrnam(SetGroup.c_str());

        if (!g)
        {
            this->Logs->Log("SETGUID", LOG_DEFAULT, "getgrnam() failed (bad user?): %s", strerror(errno));
            this->QuickExit(0);
        }

        ret = setgid(g->gr_gid);

        if (ret == -1)
        {
            this->Logs->Log("SETGUID", LOG_DEFAULT, "setgid() failed (bad user?): %s", strerror(errno));
            this->QuickExit(0);
        }
    }

    if (!SetUser.empty())
    {
        // setuid
        struct passwd *u;

        errno = 0;
        u = getpwnam(SetUser.c_str());

        if (!u)
        {
            this->Logs->Log("SETGUID", LOG_DEFAULT, "getpwnam() failed (bad user?): %s", strerror(errno));
            this->QuickExit(0);
        }

        int ret = setuid(u->pw_uid);

        if (ret == -1)
        {
            this->Logs->Log("SETGUID", LOG_DEFAULT, "setuid() failed (bad user?): %s", strerror(errno));
            this->QuickExit(0);
        }
    }

    this->WritePID(Config->PID);
#endif
}
Example #3
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;
}