X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Finspircd.cpp;h=5b9ee670ac7edd27f666edfc03814011190ad342;hb=ff3b706b2506d7614bce5e54bc88657bd62ebd4d;hp=fe33045692ede0004cedd1c8fcdb33cb94f2c6ab;hpb=b36ce84c7da93f680fc397bcb4c877abe063eaaa;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/inspircd.cpp b/src/inspircd.cpp index fe3304569..5b9ee670a 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -26,7 +26,6 @@ */ -/* $Core */ #include "inspircd.h" #include @@ -53,12 +52,7 @@ #include #include #include "xline.h" -#include "bancache.h" -#include "socketengine.h" -#include "socket.h" -#include "command_parse.h" #include "exitcodes.h" -#include "caller.h" #include "testsuite.h" InspIRCd* ServerInstance = NULL; @@ -77,28 +71,26 @@ unsigned const char *national_case_insensitive_map = rfc_case_insensitive_map; */ const char* ExitCodes[] = { - "No error", /* 0 */ - "DIE command", /* 1 */ - "execv() failed", /* 2 */ - "Internal error", /* 3 */ - "Config file error", /* 4 */ - "Logfile error", /* 5 */ - "POSIX fork failed", /* 6 */ - "Bad commandline parameters", /* 7 */ - "No ports could be bound", /* 8 */ - "Can't write PID file", /* 9 */ - "SocketEngine could not initialize", /* 10 */ - "Refusing to start up as root", /* 11 */ - "Found a tag!", /* 12 */ - "Couldn't load module on startup", /* 13 */ - "Could not create windows forked process", /* 14 */ - "Received SIGTERM", /* 15 */ - "Bad command handler loaded", /* 16 */ - "RegisterServiceCtrlHandler failed", /* 17 */ - "UpdateSCMStatus failed", /* 18 */ - "CreateEvent failed" /* 19 */ + "No error", // 0 + "DIE command", // 1 + "Config file error", // 2 + "Logfile error", // 3 + "POSIX fork failed", // 4 + "Bad commandline parameters", // 5 + "Can't write PID file", // 6 + "SocketEngine could not initialize", // 7 + "Refusing to start up as root", // 8 + "Couldn't load module on startup", // 9 + "Received SIGTERM" // 10 }; +#ifdef INSPIRCD_ENABLE_TESTSUITE +/** True if we have been told to run the testsuite from the commandline, + * rather than entering the mainloop. + */ +static int do_testsuite = 0; +#endif + template static void DeleteZero(T*&n) { T* t = n; @@ -108,76 +100,29 @@ template static void DeleteZero(T*&n) void InspIRCd::Cleanup() { + // Close all listening sockets for (unsigned int i = 0; i < ports.size(); i++) { - /* This calls the constructor and closes the listening socket */ ports[i]->cull(); delete ports[i]; } ports.clear(); - /* Close all client sockets, or the new process inherits them */ - LocalUserList::reverse_iterator i = Users->local_users.rbegin(); - while (i != this->Users->local_users.rend()) - { - User* u = *i++; - Users->QuitUser(u, "Server shutdown"); - } - GlobalCulls.Apply(); Modules->UnloadAll(); /* Delete objects dynamically allocated in constructor (destructor would be more appropriate, but we're likely exiting) */ /* Must be deleted before modes as it decrements modelines */ if (FakeClient) + { + delete FakeClient->server; FakeClient->cull(); + } DeleteZero(this->FakeClient); - DeleteZero(this->Users); - DeleteZero(this->Modes); DeleteZero(this->XLines); - DeleteZero(this->Parser); - DeleteZero(this->stats); - DeleteZero(this->Modules); - DeleteZero(this->BanCache); - DeleteZero(this->SNO); DeleteZero(this->Config); - DeleteZero(this->chanlist); - DeleteZero(this->PI); - DeleteZero(this->Threads); - DeleteZero(this->Timers); - DeleteZero(this->SE); - /* Close logging */ - this->Logs->CloseLogs(); - DeleteZero(this->Logs); -} - -void InspIRCd::Restart(const std::string &reason) -{ - /* SendError flushes each client's queue, - * regardless of writeability state - */ - this->SendError(reason); - - /* Figure out our filename (if theyve renamed it, we're boned) */ - std::string me; - - char** argv = Config->cmdline.argv; - -#ifdef _WIN32 - char module[MAX_PATH]; - if (GetModuleFileNameA(NULL, module, MAX_PATH)) - me = module; -#else - me = argv[0]; -#endif - - this->Cleanup(); - - if (execv(me.c_str(), argv) == -1) - { - /* Will raise a SIGABRT if not trapped */ - throw CoreException(std::string("Failed to execv()! error: ") + strerror(errno)); - } + SocketEngine::Deinit(); + Logs->CloseLogs(); } void InspIRCd::SetSignals() @@ -194,6 +139,12 @@ void InspIRCd::SetSignals() } void InspIRCd::QuickExit(int status) +{ + exit(status); +} + +// Required for returning the proper value of EXIT_SUCCESS for the parent process +static void VoidSignalHandler(int signalreceived) { exit(0); } @@ -204,10 +155,11 @@ bool InspIRCd::DaemonSeed() std::cout << "InspIRCd Process ID: " << con_green << GetCurrentProcessId() << con_reset << std::endl; return true; #else - signal(SIGTERM, InspIRCd::QuickExit); + // Do not use QuickExit here: It will exit with status SIGTERM which would break e.g. daemon scripts + signal(SIGTERM, VoidSignalHandler); - int childpid; - if ((childpid = fork ()) < 0) + int childpid = fork(); + if (childpid < 0) return false; else if (childpid > 0) { @@ -242,12 +194,12 @@ bool InspIRCd::DaemonSeed() #endif } -void InspIRCd::WritePID(const std::string &filename) +void InspIRCd::WritePID(const std::string& filename, bool exitonfail) { #ifndef _WIN32 std::string fname(filename); if (fname.empty()) - fname = DATA_PATH "/inspircd.pid"; + fname = ServerInstance->Config->Paths.PrependData("inspircd.pid"); std::ofstream outfile(fname.c_str()); if (outfile.is_open()) { @@ -256,86 +208,52 @@ void InspIRCd::WritePID(const std::string &filename) } else { - std::cout << "Failed to write PID-file '" << fname << "', exiting." << std::endl; - this->Logs->Log("STARTUP", LOG_DEFAULT, "Failed to write PID-file '%s', exiting.",fname.c_str()); - Exit(EXIT_STATUS_PID); + if (exitonfail) + std::cout << "Failed to write PID-file '" << fname << "', exiting." << std::endl; + this->Logs->Log("STARTUP", LOG_DEFAULT, "Failed to write PID-file '%s'%s", fname.c_str(), (exitonfail ? ", exiting." : "")); + if (exitonfail) + Exit(EXIT_STATUS_PID); } #endif } InspIRCd::InspIRCd(int argc, char** argv) : - ConfigFileName(CONFIG_PATH "/inspircd.conf"), + ConfigFileName(INSPIRCD_CONFIG_PATH "/inspircd.conf"), + PI(&DefaultProtocolInterface), /* Functor pointer initialisation. * * THIS MUST MATCH THE ORDER OF DECLARATION OF THE FUNCTORS, e.g. the methods * themselves within the class. */ - OperQuit("OperQuit", NULL), + OperQuit("operquit", ExtensionItem::EXT_USER, NULL), GenRandom(&HandleGenRandom), IsChannel(&HandleIsChannel), - Rehash(&HandleRehash), IsNick(&HandleIsNick), - IsIdent(&HandleIsIdent), - OnCheckExemption(&HandleOnCheckExemption) + IsIdent(&HandleIsIdent) { ServerInstance = this; Extensions.Register(&OperQuit); FailedPortList pl; + // Flag variables passed to getopt_long() later int do_version = 0, do_nofork = 0, do_debug = 0, - do_nolog = 0, do_root = 0, do_testsuite = 0; /* flag variables */ - int c = 0; + do_nolog = 0, do_root = 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(); + SocketEngine::Init(); 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; @@ -369,10 +287,13 @@ InspIRCd::InspIRCd(int argc, char** argv) : { "nolog", no_argument, &do_nolog, 1 }, { "runasroot", no_argument, &do_root, 1 }, { "version", no_argument, &do_version, 1 }, +#ifdef INSPIRCD_ENABLE_TESTSUITE { "testsuite", no_argument, &do_testsuite, 1 }, +#endif { 0, 0, 0, 0 } }; + int c; int index; while ((c = getopt_long(argc, argv, ":c:", longopts, &index)) != -1) { @@ -380,7 +301,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : { case 'c': /* Config filename was set */ - ConfigFileName = optarg; + ConfigFileName = ServerInstance->Config->Paths.PrependConfig(optarg); break; case 0: /* getopt_long_only() set an int variable, just keep going */ @@ -391,18 +312,20 @@ InspIRCd::InspIRCd(int argc, char** argv) : /* 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] [--config ]" << std::endl << - std::string(static_cast(8+strlen(argv[0])), ' ') << "[--runasroot] [--version] [--testsuite]" << std::endl; + std::string(static_cast(8+strlen(argv[0])), ' ') << "[--runasroot] [--version]" << std::endl; Exit(EXIT_STATUS_ARGV); break; } } +#ifdef INSPIRCD_ENABLE_TESTSUITE if (do_testsuite) do_nofork = do_debug = true; +#endif if (do_version) { - std::cout << std::endl << VERSION << " r" << REVISION << std::endl; + std::cout << std::endl << INSPIRCD_VERSION << std::endl; Exit(EXIT_STATUS_NOERROR); } @@ -415,24 +338,23 @@ InspIRCd::InspIRCd(int argc, char** argv) : /* 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); + Config->cmdline.writelog = !do_nolog; if (do_debug) { - FileWriter* fw = new FileWriter(stdout); + FileWriter* fw = new FileWriter(stdout, 1); FileLogStream* fls = new FileLogStream(LOG_RAWIO, fw); Logs->AddLogTypes("*", fls, true); } - if (!ServerConfig::FileExists(ConfigFileName.c_str())) + if (!FileSystem::FileExists(ConfigFileName)) { #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())) + if (FileSystem::FileExists(txtconf)) { ConfigFileName = txtconf; } @@ -445,14 +367,8 @@ InspIRCd::InspIRCd(int argc, char** argv) : } } - 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; + std::cout << con_green << "InspIRCd - Internet Relay Chat Daemon" << con_reset << ", compiled on " __DATE__ " at " __TIME__ << std::endl; + std::cout << "For contributors & authors: " << con_green << "See /INFO Output" << con_reset << std::endl; #ifndef _WIN32 if (!do_root) @@ -483,10 +399,10 @@ InspIRCd::InspIRCd(int argc, char** argv) : } } - SE->RecoverFromFork(); + SocketEngine::RecoverFromFork(); - /* During startup we don't actually initialize this - * in the thread engine. + /* During startup we read the configuration now, not in + * a seperate thread */ this->Config->Read(); this->Config->Apply(NULL, ""); @@ -500,11 +416,10 @@ InspIRCd::InspIRCd(int argc, char** argv) : // 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); + // Create the server user for this server + this->FakeClient = new FakeUser(Config->sid, Config->ServerName, Config->ServerDesc); - // Get XLine to do it's thing. - this->XLines->CheckELines(); + // This is needed as all new XLines are marked pending until ApplyLines() is called this->XLines->ApplyLines(); int bounditems = BindPorts(pl); @@ -513,7 +428,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : this->Modules->LoadAll(); - /* Just in case no modules were loaded - fix for bug #101 */ + // Build ISupport as ModuleManager::LoadAll() does not do it this->ISupport.Build(); Config->ApplyDisabledCommands(Config->DisabledCommands); @@ -531,7 +446,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : 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; + std::cout << "InspIRCd is now running as '" << Config->ServerName << "'[" << Config->GetSID() << "] with " << SocketEngine::GetMaxFds() << " max open sockets" << std::endl; #ifndef _WIN32 if (!Config->cmdline.nofork) @@ -553,7 +468,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : * * -- nenolod */ - if ((!do_nofork) && (!do_testsuite) && (!Config->cmdline.forcedebug)) + if ((!do_nofork) && (!Config->cmdline.forcedebug)) { int fd = open("/dev/null", O_RDWR); @@ -583,10 +498,10 @@ InspIRCd::InspIRCd(int argc, char** argv) : FreeConsole(); } - QueryPerformanceFrequency(&stats->QPFrequency); + 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()); + Logs->Log("STARTUP", LOG_DEFAULT, "Startup complete as '%s'[%s], %d max open sockets", Config->ServerName.c_str(),Config->GetSID().c_str(), SocketEngine::GetMaxFds()); #ifndef _WIN32 std::string SetUser = Config->ConfValue("security")->getString("runasuser"); @@ -600,7 +515,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (ret == -1) { - this->Logs->Log("SETGROUPS", LOG_DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno)); this->QuickExit(0); } @@ -612,7 +527,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (!g) { - this->Logs->Log("SETGUID", LOG_DEFAULT, "getgrnam() failed (bad user?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "getgrnam(%s) failed (wrong group?): %s", SetGroup.c_str(), strerror(errno)); this->QuickExit(0); } @@ -620,7 +535,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (ret == -1) { - this->Logs->Log("SETGUID", LOG_DEFAULT, "setgid() failed (bad user?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "setgid() failed (wrong group?): %s", strerror(errno)); this->QuickExit(0); } } @@ -635,7 +550,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (!u) { - this->Logs->Log("SETGUID", LOG_DEFAULT, "getpwnam() failed (bad user?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "getpwnam(%s) failed (wrong user?): %s", SetUser.c_str(), strerror(errno)); this->QuickExit(0); } @@ -643,7 +558,7 @@ InspIRCd::InspIRCd(int argc, char** argv) : if (ret == -1) { - this->Logs->Log("SETGUID", LOG_DEFAULT, "setuid() failed (bad user?): %s", strerror(errno)); + this->Logs->Log("STARTUP", LOG_DEFAULT, "setuid() failed (wrong user?): %s", strerror(errno)); this->QuickExit(0); } } @@ -672,15 +587,17 @@ void InspIRCd::UpdateTime() #endif } -int InspIRCd::Run() +void InspIRCd::Run() { +#ifdef INSPIRCD_ENABLE_TESTSUITE /* See if we're supposed to be running the test suite rather than entering the mainloop */ - if (Config->cmdline.TestSuite) + if (do_testsuite) { TestSuite* ts = new TestSuite; delete ts; - Exit(0); + return; } +#endif UpdateTime(); time_t OLDTIME = TIME.tv_sec; @@ -715,45 +632,42 @@ int InspIRCd::Run() { #ifndef _WIN32 getrusage(RUSAGE_SELF, &ru); - stats->LastSampled = TIME; - stats->LastCPU = ru.ru_utime; + stats.LastSampled = TIME; + stats.LastCPU = ru.ru_utime; #else - if(QueryPerformanceCounter(&stats->LastSampled)) + if(QueryPerformanceCounter(&stats.LastSampled)) { FILETIME CreationTime; FILETIME ExitTime; FILETIME KernelTime; FILETIME UserTime; GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, &KernelTime, &UserTime); - stats->LastCPU.dwHighDateTime = KernelTime.dwHighDateTime + UserTime.dwHighDateTime; - stats->LastCPU.dwLowDateTime = KernelTime.dwLowDateTime + UserTime.dwLowDateTime; + stats.LastCPU.dwHighDateTime = KernelTime.dwHighDateTime + UserTime.dwHighDateTime; + stats.LastCPU.dwLowDateTime = KernelTime.dwLowDateTime + UserTime.dwLowDateTime; } #endif /* Allow a buffer of two seconds drift on this so that ntpdate etc dont harass admins */ if (TIME.tv_sec < OLDTIME - 2) { - SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is flowing BACKWARDS in this dimension! Clock drifted backwards %lu secs.", (unsigned long)OLDTIME-TIME.tv_sec); + SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is flowing BACKWARDS in this dimension! Clock drifted backwards %lu secs.", (unsigned long)(OLDTIME-TIME.tv_sec)); } else if (TIME.tv_sec > OLDTIME + 2) { - SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is jumping FORWARDS! Clock skipped %lu secs.", (unsigned long)TIME.tv_sec - OLDTIME); + SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is jumping FORWARDS! Clock skipped %lu secs.", (unsigned long)(TIME.tv_sec - OLDTIME)); } OLDTIME = TIME.tv_sec; if ((TIME.tv_sec % 3600) == 0) - { - Users->GarbageCollect(); - FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect()); - } + FOREACH_MOD(OnGarbageCollect, ()); - Timers->TickTimers(TIME.tv_sec); - this->DoBackgroundUserStuff(); + Timers.TickTimers(TIME.tv_sec); + Users->DoBackgroundUserStuff(); if ((TIME.tv_sec % 5) == 0) { - FOREACH_MOD(I_OnBackgroundTimer,OnBackgroundTimer(TIME.tv_sec)); + FOREACH_MOD(OnBackgroundTimer, (TIME.tv_sec)); SNO->FlushSnotices(); } } @@ -765,8 +679,8 @@ int InspIRCd::Run() * This will cause any read or write events to be * dispatched to their handlers. */ - this->SE->DispatchTrialWrites(); - this->SE->DispatchEvents(); + SocketEngine::DispatchTrialWrites(); + SocketEngine::DispatchEvents(); /* if any users were quit, take them out */ GlobalCulls.Apply(); @@ -778,21 +692,6 @@ int InspIRCd::Run() s_signal = 0; } } - - return 0; -} - -/**********************************************************************************/ - -/* this returns true when all modules are satisfied that the user should be allowed onto the irc server - * (until this returns true, a user will block in the waiting state, waiting to connect up to the - * registration timeout maximum seconds) - */ -bool InspIRCd::AllModulesReportReady(LocalUser* user) -{ - ModResult res; - FIRST_MOD_RESULT(OnCheckReady, res, (user)); - return (res == MOD_RES_PASSTHRU); } sig_atomic_t InspIRCd::s_signal = 0;