int _cdecl main( int argc, char * argv[] ) #endif { #ifndef _WIN32 // Initialize nonblocking IO and disable readline on linux g_UnixTerminal.prepare(); #endif g_Serv.m_iExitFlag = Sphere_InitServer( argc, argv ); if ( ! g_Serv.m_iExitFlag ) { WritePidFile(); // Start the ping server, this can only be ran in a separate thread if ( IsSetEF( EF_UsePingServer ) ) g_PingServer.start(); #if !defined(_WIN32) || defined(_LIBEV) if ( g_Cfg.m_fUseAsyncNetwork != 0 ) g_NetworkEvent.start(); #endif #ifndef _MTNETWORK g_NetworkIn.onStart(); if (IsSetEF( EF_NetworkOutThread )) g_NetworkOut.start(); #else g_NetworkManager.start(); #endif bool shouldRunInThread = ( g_Cfg.m_iFreezeRestartTime > 0 ); if( shouldRunInThread ) { g_Main.start(); Sphere_MainMonitorLoop(); } else { while( !g_Serv.m_iExitFlag ) { g_Main.tick(); } } } #ifdef _WIN32 NTWindow_DeleteIcon(); #endif Sphere_ExitServer(); WritePidFile(true); return( g_Serv.m_iExitFlag ); }
int Daemon::Start(const char* pidFile) { int pid = ReadPidFile(pidFile); if (pid > 0 && 0 == kill(pid, 0)) {//有另一个已经存在的进程 GLOG(IM_ERROR, "another pid is running, pid=%d", pid); return -1; } //fork两次 for (int i = 0; i < 2; ++i) { switch (fork()) { case -1: //error GLOG(IM_ERROR, "call fork() error"); return -1; case 0://子进程 break; default://父进程退出 exit(0); } setsid(); } //写pid文件 if (WritePidFile(pidFile) != 0) { return -1; } int fd = open("/dev/null", O_RDWR); if (-1 == fd) { GLOG(IM_ERROR, "call open() failed"); return -1; } //0重定向到/dev/null if (dup2(fd, 0) == -1) {//stdin GLOG(IM_ERROR, "call dup2() failed"); return -1; } //1重定向到/dev/null if (dup2(fd, 1) == -1) {//stdout GLOG(IM_ERROR, "call dup2() failed"); return -1; } //关闭fd if (fd > 2) { if (close(fd) == -1) { GLOG(IM_ERROR, "call close(%d) error", fd); return -1; } } return 0; }
void SetupPidFile() { char *Tempstr=NULL; Tempstr=SessionSubstituteVars(Tempstr,Settings.PidFile,NULL); PidFile=WritePidFile(Tempstr); DestroyString(Tempstr); }
int Sphere_InitServer( int argc, char *argv[] ) { #ifdef EXCEPTIONS_DEBUG const char *m_sClassName = "Sphere"; #endif EXC_TRY("Init"); ASSERT(MAX_BUFFER >= sizeof(CEvent)); ASSERT(sizeof(int) == sizeof(DWORD)); // make this assumption often. ASSERT(sizeof(ITEMID_TYPE) == sizeof(DWORD)); ASSERT(sizeof(WORD) == 2 ); ASSERT(sizeof(DWORD) == 4 ); ASSERT(sizeof(NWORD) == 2 ); ASSERT(sizeof(NDWORD) == 4 ); ASSERT(sizeof(CUOItemTypeRec) == 37 ); // byte pack working ? ASSERT((std::numeric_limits<size_t>::min)() == 0); // ensure unsigned #ifdef _WIN32 if ( !QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&llTimeProfileFrequency)) ) llTimeProfileFrequency = 1000; #if !defined(_DEBUG) && !defined(__MINGW32__) EXC_SET("setting exception catcher"); SetExceptionTranslator(); #endif #endif EXC_SET("loading"); if ( !g_Serv.Load() ) return -3; if ( argc > 1 ) { EXC_SET("cmdline"); if ( !g_Serv.CommandLine(argc, argv) ) return -1; } WritePidFile(2); EXC_SET("load world"); if ( !g_World.LoadAll() ) return -8; EXC_SET("sockets init"); if ( !g_Serv.SocketsInit() ) return -9; // load auto-complete dictionary EXC_SET("auto-complete"); { CFileText dict; if ( dict.Open(SPHERE_FILE ".dic", OF_READ|OF_TEXT|OF_DEFAULTMODE) ) { TCHAR * pszTemp = Str_GetTemp(); size_t count = 0; while ( !dict.IsEOF() ) { dict.ReadString(pszTemp, SCRIPT_MAX_LINE_LEN-1); if ( *pszTemp ) { TCHAR *c = strchr(pszTemp, '\r'); if ( c != NULL ) *c = '\0'; c = strchr(pszTemp, '\n'); if ( c != NULL ) *c = '\0'; if ( *pszTemp != '\0' ) { count++; g_AutoComplete.AddTail(pszTemp); } } } g_Log.Event(LOGM_INIT, "Auto-complete dictionary loaded (contains %" FMTSIZE_T " words)\n", count); dict.Close(); } } EXC_SET("finalizing"); g_Serv.SetServerMode(SERVMODE_Run); g_Log.Event(LOGM_INIT, "Startup complete (Items=%lu, Chars=%lu, Accounts=%lu)\nPress '?' for console commands\n\n", g_Serv.StatGet(SERV_STAT_ITEMS), g_Serv.StatGet(SERV_STAT_CHARS), g_Serv.StatGet(SERV_STAT_ACCOUNTS)); if ( !g_Accounts.Account_GetCount() ) g_Log.Event(LOGL_WARN|LOGM_INIT, "The server has no accounts. To create admin account you must type:\n ACCOUNT ADD [login] [password]\n ACCOUNT [login] PLEVEL 7\n"); // Trigger server start g_Serv.r_Call("f_onserver_start", &g_Serv, NULL); return g_Serv.m_iExitFlag; EXC_CATCH; EXC_DEBUG_START; g_Log.EventDebug("cmdline argc=%d starting with %p (argv1='%s')\n", argc, static_cast<void *>(argv), ( argc > 2 ) ? argv[1] : ""); EXC_DEBUG_END; return -10; }
int Sphere_InitServer( int argc, char *argv[] ) { const char *m_sClassName = "Sphere"; EXC_TRY("Init"); ASSERT(MAX_BUFFER >= sizeof(CCommand)); ASSERT(MAX_BUFFER >= sizeof(CEvent)); ASSERT(sizeof(int) == sizeof(DWORD)); // make this assumption often. ASSERT(sizeof(ITEMID_TYPE) == sizeof(DWORD)); ASSERT(sizeof(WORD) == 2 ); ASSERT(sizeof(DWORD) == 4 ); ASSERT(sizeof(NWORD) == 2 ); ASSERT(sizeof(NDWORD) == 4 ); ASSERT(sizeof(CUOItemTypeRec) == 37 ); // byte pack working ? ASSERT((std::numeric_limits<size_t>::min)() == 0); // ensure unsigned #ifdef _WIN32 if ( !QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&llTimeProfileFrequency))) llTimeProfileFrequency = 1000; EXC_SET("setting exception catcher"); SetExceptionTranslator(); #endif // _WIN32 EXC_SET("loading"); if ( !g_Serv.Load() ) return -3; if ( argc > 1 ) { EXC_SET("cmdline"); if ( !g_Serv.CommandLine(argc, argv) ) return -1; } WritePidFile(2); EXC_SET("sockets init"); if ( !g_Serv.SocketsInit() ) return -9; EXC_SET("load world"); if ( !g_World.LoadAll() ) return -8; // load auto-complete dictionary EXC_SET("auto-complete"); { CFileText dict; if ( dict.Open(GRAY_FILE ".dic", OF_READ|OF_TEXT|OF_DEFAULTMODE) ) { TCHAR * pszTemp = Str_GetTemp(); size_t count = 0; while ( !dict.IsEOF() ) { dict.ReadString(pszTemp, SCRIPT_MAX_LINE_LEN-1); if ( *pszTemp ) { TCHAR *c = strchr(pszTemp, '\r'); if ( c != NULL ) *c = '\0'; c = strchr(pszTemp, '\n'); if ( c != NULL ) *c = '\0'; if ( *pszTemp != '\0' ) { count++; g_AutoComplete.AddTail(pszTemp); } } } g_Log.Event(LOGM_INIT, "Auto-complete dictionary loaded (contains %" FMTSIZE_T " words).\n", count); dict.Close(); } } g_Serv.SetServerMode(SERVMODE_Run); // ready to go. // Display EF/OF Flags g_Cfg.PrintEFOFFlags(); EXC_SET("finilizing"); g_Log.Event(LOGM_INIT, "%s", g_Serv.GetStatusString(0x24)); g_Log.Event(LOGM_INIT, "Startup complete. items=%lu, chars=%lu\n", g_Serv.StatGet(SERV_STAT_ITEMS), g_Serv.StatGet(SERV_STAT_CHARS)); #ifdef _WIN32 g_Log.Event(LOGM_INIT, "Press '?' for console commands\n"); #endif // Trigger server start g_Serv.r_Call("f_onserver_start", &g_Serv, NULL); return 0; EXC_CATCH; EXC_DEBUG_START; g_Log.EventDebug("cmdline argc=%d starting with %p (argv1='%s')\n", argc, static_cast<void *>(argv), ( argc > 2 ) ? argv[1] : ""); EXC_DEBUG_END; return -10; }
bool Initialize() { Logger::Init(); if ((bool)gRs.commandLine["arguments"]["--use-implicit-console-appender"]) { Variant dummy; dummy[CONF_LOG_APPENDER_NAME] = "implicit console appender"; dummy[CONF_LOG_APPENDER_TYPE] = CONF_LOG_APPENDER_TYPE_CONSOLE; dummy[CONF_LOG_APPENDER_COLORED] = (bool)true; dummy[CONF_LOG_APPENDER_LEVEL] = (uint32_t) 6; ConsoleLogLocation * pLogLocation = new ConsoleLogLocation(dummy); pLogLocation->SetLevel(_FINEST_); Logger::AddLogLocation(pLogLocation); } INFO("Reading configuration from %s", STR(gRs.commandLine["arguments"]["configFile"])); #ifdef COMPILE_STATIC gRs.pConfigFile = new ConfigFile(SpawnApplication, SpawnFactory); #else gRs.pConfigFile = new ConfigFile(NULL, NULL); #endif string configFilePath = gRs.commandLine["arguments"]["configFile"]; string fileName; string extension; splitFileName(configFilePath, fileName, extension); if (lowerCase(extension) == "xml") { if (!gRs.pConfigFile->LoadXmlFile(configFilePath, (bool)gRs.commandLine["arguments"]["--daemon"])) { FATAL("Unable to load file %s", STR(configFilePath)); return false; } } else if (lowerCase(extension) == "lua") { #ifdef HAS_LUA if (!gRs.pConfigFile->LoadLuaFile(configFilePath, (bool)gRs.commandLine["arguments"]["--daemon"])) { FATAL("Unable to load file %s", STR(configFilePath)); return false; } #else fprintf(stdout, "Lua is not supported by the current build of the server\n"); ASSERT("Lua is not supported by the current build of the server"); return false; #endif /* HAS_LUA */ } else { FATAL("Invalid file format: %s", STR(configFilePath)); return false; } #ifndef WIN32 if (gRs.pConfigFile->IsDaemon()) { if (!gRs.daemon) { INFO("Daemonize..."); pid_t pid = fork(); if (pid < 0) { FATAL("Unable to start as daemon. fork() failed"); return false; } if (pid > 0) { if (gRs.commandLine["arguments"].HasKey("--pid")) WritePidFile(pid); return false; } FINEST("Create a new SID for the daemon"); pid_t sid = setsid(); if (sid < 0) { FATAL("Unable to start as daemon. setsid() failed"); return false; } int fd = open("/dev/null", O_RDWR, 0); if (fd < 0) { FATAL("Unable to start as daemon. open(/dev/null) failed"); return false; } (void) dup2(fd, STDIN_FILENO); (void) dup2(fd, STDOUT_FILENO); (void) dup2(fd, STDERR_FILENO); if (fd > 2) { (void) close(fd); } gRs.daemon = true; Logger::SignalFork(); } } #endif /* WIN32 */ INFO("Configure logger"); if (!gRs.pConfigFile->ConfigLogAppenders()) { FATAL("Unable to configure log appenders"); return false; } INFO("%s", STR(Version::GetBanner())); INFO("Initialize I/O handlers manager: %s", NETWORK_REACTOR); IOHandlerManager::Initialize(); INFO("Configure modules"); if (!gRs.pConfigFile->ConfigModules()) { FATAL("Unable to configure modules"); return false; } INFO("Plug in the default protocol factory"); gRs.pProtocolFactory = new DefaultProtocolFactory(); if (!ProtocolFactoryManager::RegisterProtocolFactory(gRs.pProtocolFactory)) { FATAL("Unable to register default protocols factory"); return false; } INFO("Configure factories"); if (!gRs.pConfigFile->ConfigFactories()) { FATAL("Unable to configure factories"); return false; } INFO("Configure acceptors"); if (!gRs.pConfigFile->ConfigAcceptors()) { FATAL("Unable to configure acceptors"); return false; } INFO("Configure instances"); if (!gRs.pConfigFile->ConfigInstances()) { FATAL("Unable to configure instances"); return false; } INFO("Start I/O handlers manager: %s", NETWORK_REACTOR); IOHandlerManager::Start(); INFO("Configure applications"); if (!gRs.pConfigFile->ConfigApplications()) { FATAL("Unable to configure applications"); return false; } INFO("Install the quit signal"); installQuitSignal(QuitSignalHandler); return true; }
int main(int argc, char *argv[]) { int servSock; /* Socket descriptor for server */ unsigned short echoServPort; /* Server port */ pid_t processID; /* Process ID */ FILE *efp; FILE *afp; /* Error and access files */ FILE *seq_in; char *execname; char *pidpath; char *logpath; int summarise_coords = 0, d_flag = 0, c; while ((c = getopt (argc, argv, "m:hdc")) != -1) switch (c) { case 'h': usage(argv[0]); exit(0); break; case 'm': // i5 comptability - matrix option no longer needed. added to prevent warnings break; case 'c': summarise_coords = 1; // i5 output - list of start/end pairs break; case 'd': d_flag = 1; // daemon mode break; } if (! d_flag) { process_seq_stdin(summarise_coords); // run standalone - either printing a list of p values of the list of start/end for i5 exit(0); } else { // deamonise if (argc - optind != 3) // Test for correct number of arguments // optind is the number of real (excluding $0/-xxx) arguments, or the index into the first real argument { usage(argv[0]); exit(1); } } execname = "ncoilsd"; pidpath = argv[optind + 1]; logpath = argv[optind + 2]; /* Open the logs */ OpenLog(&efp, ERROR, logpath, execname); OpenLog(&afp, LOG, logpath, execname); echoServPort = atoi(argv[optind]); /* First arg: local port */ LogMessage(afp, "Trying to listening on port %d\n", echoServPort); servSock = CreateTCPServerSocket(echoServPort, efp); if(servSock == 0){ LogDie(efp, "Failed to open sockect connection on port %d\n", echoServPort); }else{ LogMessage(afp, "Successfully listening on port %d\n", echoServPort); } processID = fork(); if (processID < 0){ LogMessage(efp, "fork() failed.\n"); } else if (processID == 0) { /* If this is the child process */ LogMessage(afp, "Forked with processID %d\n", processID); WritePidFile(pidpath, execname ); ProcessMain(servSock, afp, efp); } LogMessage(afp, "Exiting parent process.\n"); exit(0); /* The child will carry on, while the parent exists out gracefully */ }
void SpawnApplyConfig(const char *Config, int Flags) { char *User=NULL, *Group=NULL, *Dir=NULL; char *Name=NULL, *Value=NULL; const char *ptr; struct rlimit limit; rlim_t val; int i; //set all signal handlers to default if (Flags & SPAWN_SIGDEF) { for (i =0; i < _NSIG; i++) signal(i,SIG_DFL); } //Set controlling tty to be stdin. This means that CTRL-C, SIGWINCH etc is handled for the //stdin file descriptor, not for any oher if (Flags & SPAWN_DAEMON) demonize(); else { if (Flags & SPAWN_SETSID) setsid(); if (Flags & SPAWN_CTRL_TTY) tcsetpgrp(0, getpgrp()); } User=CopyStr(User,""); Group=CopyStr(Group,""); ptr=GetNameValuePair(Config,"\\S","=",&Name,&Value); while (ptr) { if (strcasecmp(Name,"User")==0) User=CopyStr(User, Value); else if (strcasecmp(Name,"Group")==0) Group=CopyStr(Group, Value); else if (strcasecmp(Name,"Dir")==0) Dir=CopyStr(Dir, Value); else if (strcasecmp(Name,"PidFile")==0) WritePidFile(Value); else if (strcasecmp(Name,"prio")==0) setpriority(PRIO_PROCESS, 0, atoi(Value)); else if (strcasecmp(Name,"nice")==0) setpriority(PRIO_PROCESS, 0, atoi(Value)); else if (strcasecmp(Name,"priority")==0) setpriority(PRIO_PROCESS, 0, atoi(Value)); else if (strcasecmp(Name,"mem")==0) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_DATA, &limit); } else if (strcasecmp(Name,"fsize")==0) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_FSIZE, &limit); } else if (strcasecmp(Name,"files")==0) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_NOFILE, &limit); } else if (strcasecmp(Name,"coredumps")==0) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_CORE, &limit); } else if ( (strcasecmp(Name,"procs")==0) || (strcasecmp(Name,"nproc")==0) ) { val=(rlim_t) ParseHumanReadableDataQty(Value, 0); limit.rlim_cur=val; limit.rlim_max=val; setrlimit(RLIMIT_NPROC, &limit); } ptr=GetNameValuePair(ptr,"\\S","=",&Name,&Value); } // This allows us to chroot into a whole different unix directory tree, with its own // password file etc if (Flags & SPAWN_CHROOT) chroot("."); if (StrLen(Dir)) chdir(Dir); //Always do group first, otherwise we'll lose ability to switch user/group if (StrLen(Group)) SwitchGroup(Group); if (StrLen(User)) SwitchUser(User); //Must do this last! After parsing Config, and also after functions like //SwitchUser that will need access to /etc/passwd if (Flags & SPAWN_JAIL) chroot("."); DestroyString(Name); DestroyString(Value); DestroyString(User); DestroyString(Group); DestroyString(Dir); }
/** * Entry point */ int main(int argc, char** argv ) { // TODO ([email protected]) put init settings in ctor ApplicationConfig config; config.print_debug = false; config.is_logging = true; SetSignalHandlers(); #ifdef LOG logging_init(createTimestampedLogFilename(PANTHEIOS_FE_PROCESS_IDENTITY).c_str()); #endif if (capk::InitializeZMQPublisher(&g_zmq_context, &g_pub_socket) != 0) { #ifdef LOG pan::log_CRITICAL("Can't init ZMQ - exiting"); #endif return (-1); } // Must call this to use protobufs GOOGLE_PROTOBUF_VERIFY_VERSION; // First read command line if (ReadCommandLineParams(argc, argv, &config) != 0) { #ifdef LOG pan::log_CRITICAL("Aborting due to missing parameters."); #endif return (-1); } // Read the symbols to subscribe to from file std::vector<std::string> symbols = capk::readSymbolsFile(config.symbol_file_name); if (symbols.size() <= 0) { #ifdef LOG pan::log_CRITICAL("No symbols set in:", config.symbol_file_name.c_str()); #endif return (-1); } try { FIX::SessionSettings settings(config.config_file_name); std::set<FIX::SessionID> sessions = settings.getSessions(); assert(sessions.size() == 1); FIX::SessionID sessionId = *(sessions.begin()); const FIX::Dictionary& dict = settings.get(sessionId); // Get additional config settings from FIX config file if (ReadFIXConfig(&config, dict) != 0) { fprintf(stderr, "Can't read local config file - exiting\n"); return (-1); } if (config.venue_config_file_name == "") { // Get config settings from config server if (ReadRemoteConfig(&config) != 0) { fprintf(stderr, "Can't read remote configuration - exiting\n"); return (-1); } } else { // Get config settings from local ini file if (ReadLocalVenueConfig(config.venue_config_file_name, &config) != 0) { fprintf(stderr, "Can't read local venue configuration - exiting\n"); return (-1); } } PrintConfig(&config); // Create the FIX application instance Application application(config); g_papplication = &application; application.addSymbols(symbols); // Create the output directories for orderbooks, log, and store if needed. // Note that actual log directories are created in the location specified // with -o arg each time the program starts // @TODO ([email protected]) Maybe better to put // each log in the dated directory rather than have store and // log on same level as dated tick dirs if (config.root_output_dir.length() > 0) { fs::path argPath = fs::path(config.root_output_dir); if (!fs::exists(argPath)) { fs::create_directories(argPath); } fs::path fix_log_path = argPath / fs::path("log"); if (!fs::exists(fix_log_path)) { fs::create_directory(fix_log_path); } config.fix_log_output_dir = fix_log_path.string(); fs::path store_path = argPath / fs::path("store"); if (!fs::exists(store_path)) { fs::create_directory(store_path); } config.fix_store_output_dir = store_path.string(); } pid_t pid = getpid(); pid_t ppid = getppid(); #ifdef LOG pan::log_DEBUG("pid: ", pan::integer(pid), " ppid: ", pan::integer(ppid)); #endif if (WritePidFile(argv[0], config.mic_string.c_str(), pid, ppid) != 0) { #ifdef LOG pan::log_CRITICAL("Can't write pid file - exiting"); #endif return (-1); } // Set ZMQ parameters in Application if (config.is_publishing) { zmq_bind(g_pub_socket, config.publishing_addr.c_str()); application.setZMQContext(g_zmq_context); application.setZMQSocket(g_pub_socket); } if (config.is_logging) { std::cout << "Logging with FileStoreFactory" << std::endl; FIX::FileStoreFactory fileStoreFactory(config.fix_store_output_dir); FIX::FileLogFactory logFactory(config.fix_log_output_dir); g_pinitiator = new FIX::SocketInitiator(application, fileStoreFactory, settings, logFactory); assert(g_pinitiator); } else { std::cout << "Logging with NullStoreFactory" << std::endl; FIX::NullStoreFactory nullStoreFactory; g_pinitiator = new FIX::SocketInitiator(application, nullStoreFactory, settings); assert(g_pinitiator); } std::cout << "Starting initiator" << std::endl; g_pinitiator->start(); char x; std::cout << "Type 'q' to disconnect and exit" << std::endl; while (std::cin >> x) { if (x == 'q') { break; } } std::cout << "Cleaning up" << std::endl; g_pinitiator->stop(); return 0; } catch(FIX::Exception& e) { std::cerr << e.what(); return 1; } }
/** * CCore * * Creates a new shroudBNC application object. * * @param Config the main config object * @param argc argument counts * @param argv program arguments */ CCore::CCore(CConfig *Config, int argc, char **argv) { int i; m_Log = NULL; m_PidFile = NULL; WritePidFile(); m_Config = Config; m_SSLContext = NULL; m_SSLClientContext = NULL; m_Status = Status_Running; CacheInitialize(m_ConfigCache, Config, "system."); char *SourcePath = strdup(BuildPathLog("sbnc.log")); rename(SourcePath, BuildPathLog("sbnc.log.old")); free(SourcePath); m_PollFds.Preallocate(SFD_SETSIZE); m_Log = new CLog("sbnc.log", true); if (m_Log == NULL) { printf("Log system could not be initialized. Shutting down."); exit(EXIT_FAILURE); } m_Log->Clear(); Log("Log system initialized."); g_Bouncer = this; m_Config = Config; m_Args.SetList(argv, argc); m_Ident = new CIdentSupport(); m_Config = new CConfig("sbnc.conf", NULL); CacheInitialize(m_ConfigCache, m_Config, "system."); const char *Users; CUser *User; if ((Users = m_Config->ReadString("system.users")) == NULL) { if (!MakeConfig()) { Log("Configuration file could not be created."); Fatal(); } printf("Configuration has been successfully saved. Please restart shroudBNC now.\n"); exit(EXIT_SUCCESS); } const char *Args; int Count; Args = ArgTokenize(Users); if (AllocFailed(Args)) { Fatal(); } Count = ArgCount(Args); for (i = 0; i < Count; i++) { const char *Name = ArgGet(Args, i + 1); User = new CUser(Name); if (AllocFailed(User)) { Fatal(); } m_Users.Add(Name, User); } ArgFree(Args); m_Listener = NULL; m_ListenerV6 = NULL; m_SSLListener = NULL; m_SSLListenerV6 = NULL; time(&m_Startup); m_LoadingModules = false; m_LoadingListeners = false; InitializeSocket(); m_Capabilities = new CVector<const char *>(); m_Capabilities->Insert("multi-prefix"); m_Capabilities->Insert("znc.in/server-time-iso"); }
/** * StartMainLoop * * Executes shroudBNC's main loop. */ void CCore::StartMainLoop(bool ShouldDaemonize) { unsigned int i; time(&g_CurrentTime); int Port = CacheGetInteger(m_ConfigCache, port); #ifdef HAVE_LIBSSL int SSLPort = CacheGetInteger(m_ConfigCache, sslport); if (Port == 0 && SSLPort == 0) { #else if (Port == 0) { #endif Port = 9000; } const char *BindIp = CacheGetString(m_ConfigCache, ip); if (m_Listener == NULL) { if (Port != 0) { m_Listener = new CClientListener(Port, BindIp, AF_INET); } else { m_Listener = NULL; } } if (m_ListenerV6 == NULL) { if (Port != 0) { m_ListenerV6 = new CClientListener(Port, BindIp, AF_INET6); if (m_ListenerV6->IsValid() == false) { delete m_ListenerV6; m_ListenerV6 = NULL; } } else { m_ListenerV6 = NULL; } } #ifdef HAVE_LIBSSL if (m_SSLListener == NULL) { if (SSLPort != 0) { m_SSLListener = new CClientListener(SSLPort, BindIp, AF_INET, true); } else { m_SSLListener = NULL; } } if (m_SSLListenerV6 == NULL) { if (SSLPort != 0) { m_SSLListenerV6 = new CClientListener(SSLPort, BindIp, AF_INET6, true); if (m_SSLListenerV6->IsValid() == false) { delete m_SSLListenerV6; m_SSLListenerV6 = NULL; } } else { m_SSLListenerV6 = NULL; } } SSL_library_init(); SSL_load_error_strings(); SSL_METHOD *SSLMethod = (SSL_METHOD *)SSLv23_method(); m_SSLContext = SSL_CTX_new(SSLMethod); SSL_CTX_set_passwd_cb(m_SSLContext); m_SSLClientContext = SSL_CTX_new(SSLMethod); SSL_CTX_set_passwd_cb(m_SSLClientContext); SSL_CTX_set_mode(m_SSLContext, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_mode(m_SSLClientContext, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); g_SSLCustomIndex = SSL_get_ex_new_index(0, (void *)"CConnection*", NULL, NULL, NULL); if (!SSL_CTX_use_PrivateKey_file(m_SSLContext, BuildPathConfig("sbnc.key"), SSL_FILETYPE_PEM)) { if (SSLPort != 0) { Log("Could not load private key (sbnc.key)."); ERR_print_errors_fp(stdout); return; } else { SSL_CTX_free(m_SSLContext); m_SSLContext = NULL; } } else { SSL_CTX_set_verify(m_SSLContext, SSL_VERIFY_PEER, SSLVerifyCertificate); } if (!SSL_CTX_use_certificate_chain_file(m_SSLContext, BuildPathConfig("sbnc.crt"))) { if (SSLPort != 0) { Log("Could not load public key (sbnc.crt)."); ERR_print_errors_fp(stdout); return; } else { SSL_CTX_free(m_SSLContext); m_SSLContext = NULL; } } else { SSL_CTX_set_verify(m_SSLClientContext, SSL_VERIFY_PEER, SSLVerifyCertificate); } #endif if (Port != 0 && m_Listener != NULL && m_Listener->IsValid()) { Log("Created main listener."); } else if (Port != 0) { Log("Could not create listener port"); return; } #ifdef HAVE_LIBSSL if (SSLPort != 0 && m_SSLListener != NULL && m_SSLListener->IsValid()) { Log("Created ssl listener."); } else if (SSLPort != 0) { Log("Could not create ssl listener port"); return; } #endif InitializeAdditionalListeners(); Log("Starting main loop."); if (ShouldDaemonize) { #ifndef _WIN32 fprintf(stderr, "Daemonizing... "); UnlockPidFile(); if (Daemonize()) { fprintf(stderr, "DONE\n"); } else { fprintf(stderr, "FAILED\n"); } WritePidFile(); #endif } /* Note: We need to load the modules after using fork() as otherwise tcl cannot be cleanly unloaded */ m_LoadingModules = true; #ifdef _MSC_VER LoadModule("bnctcl.dll"); LoadModule("bncidentd.dll"); #else LoadModule("libbnctcl.la"); #endif char *Out; i = 0; while (true) { int rc = asprintf(&Out, "system.modules.mod%d", i++); if (RcFailed(rc)) { Fatal(); } const char *File = m_Config->ReadString(Out); free(Out); if (File == NULL) { break; } LoadModule(File); } m_LoadingModules = false; i = 0; while (hash_t<CUser *> *User = m_Users.Iterate(i++)) { User->Value->LoadEvent(); } int m_ShutdownLoop = 5; time_t Last = 0; while (GetStatus() == Status_Running || --m_ShutdownLoop) { time_t Now, Best = 0, SleepInterval = 0; #if defined(_WIN32) && defined(_DEBUG) DWORD TickCount = GetTickCount(); #endif time(&Now); i = 0; while (hash_t<CUser *> *UserHash = m_Users.Iterate(i++)) { CIRCConnection *IRC; if ((IRC = UserHash->Value->GetIRCConnection()) != NULL) { if (GetStatus() != Status_Running) { Log("Closing connection for user %s", UserHash->Name); IRC->Kill("Shutting down."); UserHash->Value->SetIRCConnection(NULL); } if (IRC->ShouldDestroy()) { IRC->Destroy(); } } } CUser::RescheduleReconnectTimer(); time(&Now); if (g_CurrentTime - 5 > Now) { Log("Time warp detected: %d seconds", Now - g_CurrentTime); } g_CurrentTime = Now; Best = CTimer::GetNextCall(); if (Best <= g_CurrentTime) { #ifdef _DEBUG if (g_CurrentTime - 1 > Best) { #else if (g_CurrentTime - 5 > Best) { #endif Log("Time warp detected: %d seconds", g_CurrentTime - Best); } CTimer::CallTimers(); Best = CTimer::GetNextCall(); } SleepInterval = Best - g_CurrentTime; DnsSocketCookie *DnsCookie = CDnsQuery::RegisterSockets(); for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) { if (SocketCursor->PollFd->fd == INVALID_SOCKET) { continue; } if (SocketCursor->Events->ShouldDestroy()) { SocketCursor->Events->Destroy(); } else { SocketCursor->PollFd->events = POLLIN | POLLERR; if (SocketCursor->Events->HasQueuedData()) { SocketCursor->PollFd->events |= POLLOUT; } } } bool ModulesBusy = false; for (int j = 0; j < m_Modules.GetLength(); j++) { if (m_Modules[j]->MainLoop()) { ModulesBusy = true; } } if (SleepInterval <= 0 || GetStatus() != Status_Running || ModulesBusy) { SleepInterval = 1; } if (GetStatus() != Status_Running && SleepInterval > 3) { SleepInterval = 3; } timeval interval = { (long)SleepInterval, 0 }; time(&Last); #ifdef _DEBUG //printf("poll: %d seconds\n", SleepInterval); #endif #if defined(_WIN32) && defined(_DEBUG) DWORD TimeDiff = GetTickCount(); #endif int ready = poll(m_PollFds.GetList(), m_PollFds.GetLength(), interval.tv_sec * 1000); #if defined(_WIN32) && defined(_DEBUG) TickCount += GetTickCount() - TimeDiff; #endif time(&g_CurrentTime); if (ready > 0) { for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) { pollfd *PollFd = SocketCursor->PollFd; CSocketEvents *Events = SocketCursor->Events; if (PollFd->fd != INVALID_SOCKET) { if (PollFd->revents & (POLLERR|POLLHUP|POLLNVAL)) { int ErrorCode; socklen_t ErrorCodeLength = sizeof(ErrorCode); ErrorCode = 0; if (getsockopt(PollFd->fd, SOL_SOCKET, SO_ERROR, (char *)&ErrorCode, &ErrorCodeLength) != -1) { if (ErrorCode != 0) { Events->Error(ErrorCode); } } if (ErrorCode == 0) { Events->Error(-1); } Events->Destroy(); continue; } if (PollFd->revents & (POLLIN|POLLPRI)) { int Code; if ((Code = Events->Read()) != 0) { Events->Error(Code); Events->Destroy(); continue; } } if (PollFd->revents & POLLOUT) { Events->Write(); } } } } else if (ready == -1) { #ifndef _WIN32 if (errno != EBADF && errno != 0) { #else if (errno != WSAENOTSOCK) { #endif continue; } m_OtherSockets.Lock(); for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) { if (SocketCursor->PollFd->fd == INVALID_SOCKET) { continue; } pollfd pfd; pfd.fd = SocketCursor->PollFd->fd; pfd.events = POLLIN | POLLOUT | POLLERR; int code = poll(&pfd, 1, 0); if (code == -1) { SocketCursor->Events->Error(-1); SocketCursor->Events->Destroy(); } } } CDnsQuery::ProcessTimeouts(); CDnsQuery::UnregisterSockets(DnsCookie); #if defined(_WIN32) && defined(_DEBUG) DWORD Ticks = GetTickCount() - TickCount; if (Ticks > 50) { printf("Spent %d msec in the main loop.\n", Ticks); } #endif } #ifdef HAVE_LIBSSL SSL_CTX_free(m_SSLContext); SSL_CTX_free(m_SSLClientContext); #endif } /** * GetUser * * Returns a user object for the specified username (or NULL * if there's no such user). * * @param Name the username */ CUser *CCore::GetUser(const char *Name) { if (Name == NULL) { return NULL; } else { return m_Users.Get(Name); } } /** * GlobalNotice * * Sends a message to all bouncer users who are currently * logged in. * * @param Text the text of the message */ void CCore::GlobalNotice(const char *Text) { int i = 0; char *GlobalText; int rc = asprintf(&GlobalText, "Global admin message: %s", Text); if (RcFailed(rc)) { return; } while (hash_t<CUser *> *User = m_Users.Iterate(i++)) { if (User->Value->GetClientConnectionMultiplexer() != NULL) { User->Value->GetClientConnectionMultiplexer()->Privmsg(GlobalText); } else { User->Value->Log("%s", GlobalText); } } free(GlobalText); } /** * GetUsers * * Returns a hashtable which contains all bouncer users. */ CHashtable<CUser *, false> *CCore::GetUsers(void) { return &m_Users; } /** * SetIdent * * Sets the ident which is returned for the next ident request. * * @param Ident the ident */ void CCore::SetIdent(const char *Ident) { if (m_Ident != NULL) { m_Ident->SetIdent(Ident); } } /** * GetIdent * * Returns the ident which is to be returned for the next ident * request. */ const char *CCore::GetIdent(void) const { if (m_Ident != NULL) { return m_Ident->GetIdent(); } else { return NULL; } } /** * GetModules * * Returns a list of currently loaded modules. */ const CVector<CModule *> *CCore::GetModules(void) const { return &m_Modules; } /** * LoadModule * * Attempts to load a bouncer module. * * @param Filename the module's filename */ RESULT<CModule *> CCore::LoadModule(const char *Filename) { RESULT<bool> Result; CModule *Module = new CModule(Filename); if (AllocFailed(Module)) { THROW(CModule *, Generic_OutOfMemory, "new operator failed."); } Result = Module->GetError(); if (!IsError(Result)) { Result = m_Modules.Insert(Module); if (IsError(Result)) { delete Module; Log("Insert() failed. Could not load module"); THROWRESULT(CModule *, Result); } Log("Loaded module: %s", Module->GetFilename()); Module->Init(this); if (!m_LoadingModules) { UpdateModuleConfig(); } RETURN(CModule *, Module); } else { static char *ErrorString = NULL; free(ErrorString); ErrorString = strdup(GETDESCRIPTION(Result)); if (AllocFailed(ErrorString)) { delete Module; THROW(CModule *, Generic_OutOfMemory, "strdup() failed."); } Log("Module %s could not be loaded: %s", Filename, ErrorString); delete Module; THROW(CModule *, Generic_Unknown, ErrorString); } THROW(CModule *, Generic_Unknown, NULL); } /** * UnloadModule * * Unloads a module. * * @param Module the module */ bool CCore::UnloadModule(CModule *Module) { if (m_Modules.Remove(Module)) { Log("Unloaded module: %s", Module->GetFilename()); delete Module; UpdateModuleConfig(); return true; } else { return false; } } /** * UpdateModuleConfig * * Updates the module list in the main config. */ void CCore::UpdateModuleConfig(void) { char *Out; int a = 0, rc; for (int i = 0; i < m_Modules.GetLength(); i++) { rc = asprintf(&Out, "system.modules.mod%d", a++); if (RcFailed(rc)) { Fatal(); } m_Config->WriteString(Out, m_Modules[i]->GetFilename()); free(Out); } rc = asprintf(&Out, "system.modules.mod%d", a); if (RcFailed(rc)) { Fatal(); } m_Config->WriteString(Out, NULL); free(Out); }
bool Master::Run(int /*argc*/, char** /*argv*/) { char* config_file = (char*)CONFDIR "/world.conf"; UNIXTIME = time(NULL); g_localTime = *localtime(&UNIXTIME); AscLog.InitalizeLogFiles("world"); PrintBanner(); LogDefault("The key combination <Ctrl-C> will safely shut down the server."); #ifndef WIN32 if (geteuid() == 0 || getegid() == 0) AscLog.ConsoleLogMajorError("You are running AscEmu 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."); #endif InitImplicitTargetFlags(); ThreadPool.Startup(); auto startTime = Util::TimeNow(); new EventMgr; new World; if (!LoadWorldConfiguration(config_file)) { return false; } sWorld.loadWorldConfigValues(); AscLog.SetFileLoggingLevel(worldConfig.log.worldFileLogLevel); AscLog.SetDebugFlags(worldConfig.log.worldDebugFlags); OpenCheatLogFiles(); if (!_StartDB()) { Database::CleanupLibs(); AscLog.~AscEmuLog(); return false; } if (!_CheckDBVersion()) { AscLog.~AscEmuLog(); return false; } // Initialize Opcode Table WorldSession::InitPacketHandlerTable(); new ScriptMgr; if (!sWorld.setInitialWorldSettings()) { LOG_ERROR("SetInitialWorldSettings() failed. Something went wrong? Exiting."); AscLog.~AscEmuLog(); return false; } sWorld.setWorldStartTime((uint32)UNIXTIME); worldRunnable = std::move(std::make_unique<WorldRunnable>()); _HookSignals(); ConsoleThread* console = new ConsoleThread(); ThreadPool.ExecuteTask(console); StartNetworkSubsystem(); sSocketMgr.SpawnWorkerThreads(); sScriptMgr.LoadScripts(); if (worldConfig.startup.enableSpellIdDump) { sScriptMgr.DumpUnimplementedSpells(); } LogDetail("Server : Ready for connections. Startup time: %u ms", Util::GetTimeDifferenceToNow(startTime)); ThreadPool.ExecuteTask(new GameEventMgr::GameEventMgrThread()); StartRemoteConsole(); WritePidFile(); if (!ChannelMgr::getSingletonPtr()) new ChannelMgr; channelmgr.seperatechannels = worldConfig.server.seperateChatChannels; if (!MailSystem::getSingletonPtr()) new MailSystem; uint32_t mailFlags = 0; if (worldConfig.mail.isCostsForGmDisabled) mailFlags |= MAIL_FLAG_NO_COST_FOR_GM; if (worldConfig.mail.isCostsForEveryoneDisabled) mailFlags |= MAIL_FLAG_DISABLE_POSTAGE_COSTS; if (worldConfig.mail.isDelayItemsDisabled) mailFlags |= MAIL_FLAG_DISABLE_HOUR_DELAY_FOR_ITEMS; if (worldConfig.mail.isMessageExpiryDisabled) mailFlags |= MAIL_FLAG_NO_EXPIRY; if (worldConfig.mail.isInterfactionMailEnabled) mailFlags |= MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION; if (worldConfig.mail.isInterfactionMailForGmEnabled) mailFlags |= MAIL_FLAG_CAN_SEND_TO_OPPOSITE_FACTION_GM; sMailSystem.config_flags = mailFlags; //ThreadPool.Gobble(); /* Connect to realmlist servers / logon servers */ new LogonCommHandler(); sLogonCommHandler.startLogonCommHandler(); // Create listener ListenSocket<WorldSocket> * ls = new ListenSocket<WorldSocket>(worldConfig.listen.listenHost.c_str(), worldConfig.listen.listenPort); bool listnersockcreate = ls->IsOpen(); #ifdef WIN32 if (listnersockcreate) ThreadPool.ExecuteTask(ls); #endif ShutdownThreadPools(listnersockcreate); _UnhookSignals(); worldRunnable->threadShutdown(); worldRunnable = nullptr; ThreadPool.ShowStats(); /* Shut down console system */ console->stopThread(); delete console; // begin server shutdown ShutdownLootSystem(); // send a query to wake it up if its inactive LogNotice("Database : Clearing all pending queries..."); // kill the database thread first so we don't lose any queries/data CharacterDatabase.EndThreads(); WorldDatabase.EndThreads(); ls->Close(); CloseConsoleListener(); sWorld.saveAllPlayersToDb(); LogNotice("Network : Shutting down network subsystem."); #ifdef WIN32 sSocketMgr.ShutdownThreads(); #endif sSocketMgr.CloseAll(); bServerShutdown = true; ThreadPool.Shutdown(); delete ls; sWorld.logoutAllPlayers(); delete LogonCommHandler::getSingletonPtr(); LogNotice("AddonMgr : ~AddonMgr()"); #if VERSION_STRING != Cata sAddonMgr.SaveToDB(); #endif delete AddonMgr::getSingletonPtr(); LogNotice("AuctionMgr : ~AuctionMgr()"); delete AuctionMgr::getSingletonPtr(); LogNotice("LootMgr : ~LootMgr()"); delete LootMgr::getSingletonPtr(); LogNotice("MailSystem : ~MailSystem()"); delete MailSystem::getSingletonPtr(); LogNotice("World : ~World()"); delete World::getSingletonPtr(); sScriptMgr.UnloadScripts(); delete ScriptMgr::getSingletonPtr(); LogNotice("ChatHandler : ~ChatHandler()"); delete ChatHandler::getSingletonPtr(); LogNotice("EventMgr : ~EventMgr()"); delete EventMgr::getSingletonPtr(); LogNotice("Database : Closing Connections..."); _StopDB(); LogNotice("Network : Deleting Network Subsystem..."); delete SocketMgr::getSingletonPtr(); delete SocketGarbageCollector::getSingletonPtr(); delete GMCommand_Log; delete Anticheat_Log; delete Player_Log; // remove pid if (remove("worldserver.pid") != 0) { LOG_ERROR("Error deleting file worldserver.pid"); } else { LOG_DEBUG("File worldserver.pid successfully deleted"); } LogDetail("Shutdown : Shutdown complete."); AscLog.~AscEmuLog(); #ifdef WIN32 WSACleanup(); #endif return true; }