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