-/* +------------------------------------+
- * | Inspire Internet Relay Chat Daemon |
- * +------------------------------------+
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
*
- * InspIRCd: (C) 2002-2010 InspIRCd Development Team
- * See: http://wiki.inspircd.org/Credits
+ * Copyright (C) 2012 William Pitcock <nenolod@dereferenced.org>
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2003-2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2008 Uli Schlachter <psychon@znc.in>
+ * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com>
+ * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2007 Burlex <???@???>
+ * Copyright (C) 2003 Craig McLure <craig@chatspike.net>
+ * Copyright (C) 2003 randomdan <???@???>
*
- * This program is free but copyrighted software; see
- * the file COPYING for details.
+ * This file is part of InspIRCd. InspIRCd is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
*
- * ---------------------------------------------------
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
/* $Core */
#include "inspircd.h"
#include "inspircd_version.h"
i->second->ResetMaxBans();
}
-/** Because hash_map doesnt free its buckets when we delete items (this is a 'feature')
- * we must occasionally rehash the hash (yes really).
+/** Because hash_map doesn't free its buckets when we delete items, we occasionally
+ * recreate the hash to free them up.
* We do this by copying the entries from the old hash to a new hash, causing all
- * empty buckets to be weeded out of the hash. We dont do this on a timer, as its
- * very expensive, so instead we do it when the user types /REHASH and expects a
- * short delay anyway.
+ * empty buckets to be weeded out of the hash.
+ * Since this is quite expensive, it's not done very often.
*/
void InspIRCd::RehashUsersAndChans()
{
- user_hash* old_users = this->Users->clientlist;
- user_hash* old_uuid = this->Users->uuidlist;
- chan_hash* old_chans = this->chanlist;
+ user_hash* old_users = Users->clientlist;
+ user_hash* old_uuid = Users->uuidlist;
+ chan_hash* old_chans = chanlist;
- this->Users->clientlist = new user_hash();
- this->Users->uuidlist = new user_hash();
- this->chanlist = new chan_hash();
+ Users->clientlist = new user_hash();
+ Users->uuidlist = new user_hash();
+ chanlist = new chan_hash();
for (user_hash::const_iterator n = old_users->begin(); n != old_users->end(); n++)
- this->Users->clientlist->insert(*n);
-
- delete old_users;
+ Users->clientlist->insert(*n);
for (user_hash::const_iterator n = old_uuid->begin(); n != old_uuid->end(); n++)
- this->Users->uuidlist->insert(*n);
-
- delete old_uuid;
+ Users->uuidlist->insert(*n);
for (chan_hash::const_iterator n = old_chans->begin(); n != old_chans->end(); n++)
- this->chanlist->insert(*n);
+ chanlist->insert(*n);
+ delete old_users;
+ delete old_uuid;
delete old_chans;
+
+ // Reset the already_sent IDs so we don't wrap it around and drop a message
+ LocalUser::already_sent_id = 0;
+ for (std::vector<LocalUser*>::const_iterator i = Users->local_users.begin(); i != Users->local_users.end(); i++)
+ {
+ (**i).already_sent = 0;
+ (**i).RemoveExpiredInvites();
+ }
}
void InspIRCd::SetSignals()
exit(0);
}
setsid ();
- umask (007);
printf("InspIRCd Process ID: \033[1;32m%lu\033[0m\n",(unsigned long)getpid());
signal(SIGTERM, InspIRCd::SetSignal);
*/
NICKForced("NICKForced", NULL),
OperQuit("OperQuit", NULL),
+ GenRandom(&HandleGenRandom),
IsChannel(&HandleIsChannel),
IsSID(&HandleIsSID),
Rehash(&HandleRehash),
IsNick(&HandleIsNick),
IsIdent(&HandleIsIdent),
- FloodQuitUser(&HandleFloodQuitUser)
+ FloodQuitUser(&HandleFloodQuitUser),
+ OnCheckExemption(&HandleOnCheckExemption)
{
#ifdef WIN32
// Strict, frequent checking of memory on debug builds
this->Res = 0;
this->ConfigThread = NULL;
- // Initialise TIME
- this->TIME = this->OLDTIME = this->startup_time = time(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;
this->Config->cmdline.argv = argv;
this->Config->cmdline.argc = argc;
- srand(this->TIME);
+ srandom(TIME.tv_nsec ^ TIME.tv_sec);
struct option longopts[] =
{
};
int index;
- while ((c = getopt_long_only(argc, argv, ":f:", longopts, &index)) != -1)
+ while ((c = getopt_long(argc, argv, ":f:", longopts, &index)) != -1)
{
switch (c)
{
if (do_debug)
{
FileWriter* fw = new FileWriter(stdout);
- FileLogStream* fls = new FileLogStream(DEBUG, fw);
+ FileLogStream* fls = new FileLogStream(RAWIO, fw);
Logs->AddLogTypes("*", fls, true);
}
else if (!this->OpenLog(argv, argc))
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;32mpeavey, aquanight, psychon, dz, danieldg\033[0m\n\n");
+ printf_c("\t\033[1;32mBrain, FrostyCoolSlug, w00t, Om, Special, peavey\n");
+ printf_c("\t\033[1;32maquanight, psychon, dz, danieldg, jackmcbarn\033[0m\n\n");
printf_c("Others:\t\t\t\033[1;32mSee /INFO Output\033[0m\n");
this->Modes = new ModeParser;
}
}
- if (isatty(0) && isatty(1) && isatty(2))
+ /* 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))
{
- /* We didn't start from a TTY, we must have started from a background process -
- * e.g. we are restarting, or being launched by cron. Dont kill parent, and dont
- * close stdin/stdout
- */
- if ((!do_nofork) && (!do_testsuite))
- {
- fclose(stdin);
- fclose(stderr);
- if (!Config->cmdline.forcedebug)
- fclose(stdout);
- }
- else
- {
- Logs->Log("STARTUP", DEFAULT,"Keeping pseudo-tty open as we are running in the foreground.");
- }
+ int fd;
+
+ fclose(stdin);
+ fclose(stderr);
+ fclose(stdout);
+
+ fd = open("/dev/null", O_RDWR);
+ if (dup2(fd, 0) < 0)
+ Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stdin.");
+ if (dup2(fd, 1) < 0)
+ Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stdout.");
+ if (dup2(fd, 2) < 0)
+ Logs->Log("STARTUP", DEFAULT, "Failed to dup /dev/null to stderr.");
+ close(fd);
+ }
+ else
+ {
+ Logs->Log("STARTUP", DEFAULT,"Keeping pseudo-tty open as we are running in the foreground.");
}
#else
WindowsIPC = new IPC;
- if(!Config->nofork)
+ if(!Config->cmdline.nofork)
{
WindowsForkKillOwner();
FreeConsole();
this->WritePID(Config->PID);
}
+void InspIRCd::UpdateTime()
+{
+#ifdef HAS_CLOCK_GETTIME
+ clock_gettime(CLOCK_REALTIME, &TIME);
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ TIME.tv_sec = tv.tv_sec;
+ TIME.tv_nsec = tv.tv_usec * 1000;
+#endif
+}
+
int InspIRCd::Run()
{
/* See if we're supposed to be running the test suite rather than entering the mainloop */
Exit(0);
}
+ UpdateTime();
+ time_t OLDTIME = TIME.tv_sec;
+
while (true)
{
#ifndef WIN32
ConfigThread = NULL;
}
- /* time() seems to be a pretty expensive syscall, so avoid calling it too much.
- * Once per loop iteration is pleanty.
- */
- OLDTIME = TIME;
- TIME = time(NULL);
+ UpdateTime();
/* Run background module timers every few seconds
* (the docs say modules shouldnt rely on accurate
* timing using this event, so we dont have to
* time this exactly).
*/
- if (TIME != OLDTIME)
+ if (TIME.tv_sec != OLDTIME)
{
+ OLDTIME = TIME.tv_sec;
+#ifndef WIN32
+ getrusage(RUSAGE_SELF, &ru);
+ stats->LastSampled = TIME;
+ stats->LastCPU = ru.ru_utime;
+#else
+ WindowsIPC->Check();
+#endif
+
/* Allow a buffer of two seconds drift on this so that ntpdate etc dont harass admins */
- if (TIME < OLDTIME - 2)
+ 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);
+ 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 > OLDTIME + 2)
+ else if (TIME.tv_sec > OLDTIME + 2)
{
- SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is jumping FORWARDS! Clock skipped %lu secs.", (unsigned long)TIME - OLDTIME);
+ SNO->WriteToSnoMask('d', "\002EH?!\002 -- Time is jumping FORWARDS! Clock skipped %lu secs.", (unsigned long)TIME.tv_sec - OLDTIME);
}
- if ((TIME % 3600) == 0)
+ if ((TIME.tv_sec % 3600) == 0)
{
this->RehashUsersAndChans();
FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect());
}
- Timers->TickTimers(TIME);
+ Timers->TickTimers(TIME.tv_sec);
this->DoBackgroundUserStuff();
- if ((TIME % 5) == 0)
+ if ((TIME.tv_sec % 5) == 0)
{
- FOREACH_MOD(I_OnBackgroundTimer,OnBackgroundTimer(TIME));
+ FOREACH_MOD(I_OnBackgroundTimer,OnBackgroundTimer(TIME.tv_sec));
SNO->FlushSnotices();
}
-#ifndef WIN32
- /* Same change as in cmd_stats.cpp, use RUSAGE_SELF rather than '0' -- Om */
- if (!getrusage(RUSAGE_SELF, &ru))
- {
- gettimeofday(&this->stats->LastSampled, NULL);
- this->stats->LastCPU = ru.ru_utime;
- }
-#else
- WindowsIPC->Check();
-#endif
}
/* Call the socket engine to wait on the active
return (res == MOD_RES_PASSTHRU);
}
-time_t InspIRCd::Time()
-{
- return TIME;
-}
-
void InspIRCd::SetSignal(int signal)
{
*mysig = signal;