* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
- * InspIRCd: (C) 2002-2008 InspIRCd Development Team
- * See: http://www.inspircd.org/wiki/index.php/Credits
+ * InspIRCd: (C) 2002-2009 InspIRCd Development Team
+ * See: http://wiki.inspircd.org/Credits
*
* This program is free but copyrighted software; see
* the file COPYING for details.
* ---------------------------------------------------
*/
-/* w00t was here. ;p */
-
/* $Install: src/inspircd $(BINPATH) */
#include "inspircd.h"
#include <signal.h>
#define RUSAGE_SELF 0
#endif
- /* CRT memory debugging */
- #ifdef DEBUG
- #define _CRTDBG_MAP_ALLOC
- #include <stdlib.h>
- #include <crtdbg.h>
- #endif
+ #include <pwd.h> // setuid
+ #include <grp.h> // setgid
#endif
#include <fstream>
InspIRCd* SI = NULL;
int* mysig = NULL;
+/** Seperate from the other casemap tables so that code *can* still exclusively rely on RFC casemapping
+ * if it must.
+ *
+ * This is provided as a pointer so that modules can change it to their custom mapping tables,
+ * e.g. for national character support.
+ */
+unsigned const char *national_case_insensitive_map = rfc_case_insensitive_map;
+
/* Moved from exitcodes.h -- due to duplicate symbols -- Burlex
* XXX this is a bit ugly. -- w00t
"CreateEvent failed" /* 19 */
};
+template<typename T> static void DeleteZero(T* n)
+{
+ if (n != NULL)
+ {
+ delete n;
+ n = NULL;
+ }
+}
+
void InspIRCd::Cleanup()
{
if (Config)
for(servernamelist::iterator itr = servernames.begin(); itr != servernames.end(); ++itr)
delete (*itr);
- /* 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 (this->Users)
- {
- delete this->Users;
- this->Users = 0;
- }
-
- if (this->Modes)
- {
- delete this->Modes;
- this->Modes = 0;
- }
-
- if (this->XLines)
- {
- delete this->XLines;
- this->XLines = 0;
- }
-
- if (this->Parser)
- {
- delete this->Parser;
- this->Parser = 0;
-
- if (this->stats)
- {
- delete this->stats;
- this->stats = 0;
- }
-
- if (this->Modules)
- {
- delete this->Modules;
- this->Modules = 0;
- }
-
- if (this->BanCache)
- delete this->BanCache;
- this->BanCache = 0;
- }
-
- if (this->SNO)
- {
- delete this->SNO;
- this->SNO = 0;
- }
-
- if (this->Config)
- {
- delete this->Config;
- this->Config = 0;
- }
-
- if (this->Res)
- {
- delete this->Res;
- this->Res = 0;
- }
-
- if (this->chanlist)
- {
- delete chanlist;
- chanlist = 0;
- }
-
- if (this->PI)
- {
- delete this->PI;
- this->PI = 0;
- }
-
- if (this->Threads)
- {
- delete this->Threads;
- this->Threads = 0;
- }
-
- /* Needs to be deleted after Res, DNS has a timer */
- if (this->Timers)
- {
- delete this->Timers;
- this->Timers = 0;
- }
-
+ /* 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 */
+ 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->Res);
+ DeleteZero(this->chanlist);
+ DeleteZero(this->PI);
+ DeleteZero(this->Threads);
+ DeleteZero(this->Timers);
/* Close logging */
this->Logs->CloseLogs();
-
- if (this->Logs)
- {
- delete this->Logs;
- this->Logs = 0;
- }
+ DeleteZero(this->Logs);
}
void InspIRCd::Restart(const std::string &reason)
signal(SIGHUP, InspIRCd::SetSignal);
signal(SIGPIPE, SIG_IGN);
signal(SIGCHLD, SIG_IGN);
+ /* We want E2BIG not a signal! */
+ signal(SIGXFSZ, SIG_IGN);
#endif
signal(SIGTERM, InspIRCd::SetSignal);
}
InspIRCd::InspIRCd(int argc, char** argv)
: GlobalCulls(this),
- /* Functor initialisation. Note that the ordering here is very important.
+ /* Functor initialisation. Note that the ordering here is very important.
*
* THIS MUST MATCH ORDER OF DECLARATION OF THE HandleWhateverFunc classes
* within class InspIRCd.
#ifdef WIN32
// Strict, frequent checking of memory on debug builds
_CrtSetDbgFlag ( _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
-
+
// Avoid erroneous frees on early exit
WindowsIPC = 0;
#endif
this->Modes = 0;
this->Res = 0;
+ // Initialise TIME
+ this->TIME = time(NULL);
memset(&server, 0, sizeof(server));
memset(&client, 0, sizeof(client));
SE = SEF->Create(this);
delete SEF;
- ThreadEngineFactory* tef = new ThreadEngineFactory();
- this->Threads = tef->Create(this);
- delete tef;
- this->Mutexes = new MutexFactory(this);
+ this->Threads = new ThreadEngine(this);
/* Default implementation does nothing */
this->PI = new ProtocolInterface(this);
this->s_signal = 0;
-
+
// Create base manager classes early, so nothing breaks
this->Users = new UserManager(this);
-
+
this->Users->unregistered_count = 0;
this->Users->clientlist = new user_hash();
if (!ServerConfig::FileExists(this->ConfigFileName))
{
- printf("ERROR: Cannot open config file: %s\nExiting...\n", this->ConfigFileName);
- this->Logs->Log("STARTUP",DEFAULT,"Unable to open config file %s", this->ConfigFileName);
- Exit(EXIT_STATUS_CONFIG);
+#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()))
+ {
+ strlcat(this->ConfigFileName, ".txt", MAXBUF);
+ }
+ else
+#endif
+ {
+ printf("ERROR: Cannot open config file: %s\nExiting...\n", this->ConfigFileName);
+ this->Logs->Log("STARTUP",DEFAULT,"Unable to open config file %s", this->ConfigFileName);
+ Exit(EXIT_STATUS_CONFIG);
+ }
}
printf_c("\033[1;32mInspire Internet Relay Chat Server, compiled %s at %s\n",__DATE__,__TIME__);
printf_c("(C) InspIRCd Development Team.\033[0m\n\n");
printf_c("Developers:\n");
printf_c("\t\033[1;32mBrain, FrostyCoolSlug, w00t, Om, Special\n");
- printf_c("\t\033[1;32mpippijn, peavey, aquanight, fez\033[0m\n\n");
+ printf_c("\t\033[1;32mpeavey, aquanight, psychon, dz, danieldg\033[0m\n\n");
printf_c("Others:\t\t\t\033[1;32mSee /INFO Output\033[0m\n");
Config->ClearStack();
/* During startup we don't actually initialize this
* in the thread engine.
*/
- this->ConfigThread = new ConfigReaderThread(this, true, NULL);
+ this->ConfigThread = new ConfigReaderThread(this, true, "");
ConfigThread->Run();
delete ConfigThread;
this->ConfigThread = NULL;
+ /* Switch over logfiles */
+ Logs->OpenFileLogs();
+
+ /** Note: This is safe, the method checks for user == NULL */
+ this->Parser->SetupCommandTable();
this->Res = new DNS(this);
printf("\n");
this->Modules->LoadAll();
-
+
/* Just in case no modules were loaded - fix for bug #101 */
this->BuildISupport();
InitializeDisabledCommands(Config->DisabledCommands, this);
}
printf("\nInspIRCd is now running as '%s'[%s] with %d max open sockets\n", Config->ServerName,Config->GetSID().c_str(), SE->GetMaxFds());
-
+
#ifndef WINDOWS
if (!Config->nofork)
{
Logs->Log("STARTUP", DEFAULT, "Startup complete as '%s'[%s], %d max open sockets", Config->ServerName,Config->GetSID().c_str(), SE->GetMaxFds());
+#ifndef WIN32
+ if (*(this->Config->SetGroup))
+ {
+ int ret;
+
+ // setgroups
+ ret = setgroups(0, NULL);
+
+ if (ret == -1)
+ {
+ this->Logs->Log("SETGROUPS", DEFAULT, "setgroups() failed (wtf?): %s", strerror(errno));
+ this->QuickExit(0);
+ }
+
+ // setgid
+ struct group *g;
+
+ errno = 0;
+ g = getgrnam(this->Config->SetGroup);
+
+ if (!g)
+ {
+ this->Logs->Log("SETGUID", DEFAULT, "getgrnam() failed (bad user?): %s", strerror(errno));
+ this->QuickExit(0);
+ }
+
+ ret = setgid(g->gr_gid);
+
+ if (ret == -1)
+ {
+ this->Logs->Log("SETGUID", DEFAULT, "setgid() failed (bad user?): %s", strerror(errno));
+ this->QuickExit(0);
+ }
+ }
+
+ if (*(this->Config->SetUser))
+ {
+ // setuid
+ struct passwd *u;
+
+ errno = 0;
+ u = getpwnam(this->Config->SetUser);
+
+ if (!u)
+ {
+ this->Logs->Log("SETGUID", DEFAULT, "getpwnam() failed (bad user?): %s", strerror(errno));
+ this->QuickExit(0);
+ }
+
+ int ret = setuid(u->pw_uid);
+
+ if (ret == -1)
+ {
+ this->Logs->Log("SETGUID", DEFAULT, "setuid() failed (bad user?): %s", strerror(errno));
+ this->QuickExit(0);
+ }
+ }
+#endif
+
this->WritePID(Config->PID);
}
#endif
/* Check if there is a config thread which has finished executing but has not yet been freed */
- if (this->ConfigThread && this->ConfigThread->GetExitFlag())
+ if (this->ConfigThread && this->ConfigThread->IsDone())
{
/* Rehash has completed */
- this->Logs->Log("CONFIG",DEBUG,"Detected ConfigThread exiting, tidying up...");
- /* IMPORTANT: This delete may hang if you fuck up your thread syncronization.
- * It will hang waiting for the ConfigThread to 'join' to avoid race conditons,
- * until the other thread is completed.
- */
- delete ConfigThread;
- ConfigThread = NULL;
+ /* Switch over logfiles */
+ Logs->CloseLogs();
+ Logs->OpenFileLogs();
+
+ this->Logs->Log("CONFIG",DEBUG,"Detected ConfigThread exiting, tidying up...");
/* These are currently not known to be threadsafe, so they are executed outside
* of the thread. It would be pretty simple to move them to the thread Run method
- * once they are known threadsafe with all the correct mutexes in place.
+ * once they are known threadsafe with all the correct mutexes in place. This might
+ * not be worth the effort however as these functions execute relatively quickly
+ * and would not benefit from being within the config read thread.
*
* XXX: The order of these is IMPORTANT, do not reorder them without testing
* thoroughly!!!
User* user = !Config->RehashUserUID.empty() ? FindNick(Config->RehashUserUID) : NULL;
FOREACH_MOD_I(this, I_OnRehash, OnRehash(user, Config->RehashParameter));
this->BuildISupport();
+
+ /* IMPORTANT: This delete may hang if you fuck up your thread syncronization.
+ * It will hang waiting for the ConfigThread to 'join' to avoid race conditons,
+ * until the other thread is completed.
+ */
+ delete ConfigThread;
+ ConfigThread = NULL;
}
/* time() seems to be a pretty expensive syscall, so avoid calling it too much.
this->stats->LastCPU = ru.ru_utime;
}
#else
- WindowsIPC->Check();
+ WindowsIPC->Check();
#endif
}