* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
- * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
- * E-mail:
- * <brain@chatspike.net>
- * <Craig@chatspike.net>
- *
- * Written by Craig Edwards, Craig McLure, and others.
+ * InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
* This program is free but copyrighted software; see
- * the file COPYING for details.
+ * the file COPYING for details.
*
* ---------------------------------------------------
*/
#include "channels.h"
#include "socket.h"
#include "mode.h"
-
#include "socketengine.h"
#include "command_parse.h"
+#include "snomasks.h"
-/** Returned by some functions to indicate failure,
- * and the exit code of the program if it terminates.
+/** Returned by some functions to indicate failure.
*/
#define ERROR -1
-/** Crucial defines
+/** Support for librodent -
+ * see http://www.chatspike.net/index.php?z=64
*/
-#define ETIREDGERBILS EAGAIN
+#define ETIREDHAMSTERS EAGAIN
/** Debug levels for use with InspIRCd::Log()
*/
/** Delete a pointer, and NULL its value
*/
-#define DELETE(x) {if (x) { delete x; x = NULL; }}
+template<typename T> inline void DELETE(T* x)
+{
+ delete x;
+ x = NULL;
+}
/** Template function to convert any input type to std::string
*/
return tmp.str();
}
+template<typename T> inline long ConvToInt(const T &in)
+{
+ std::stringstream tmp;
+ if (!(tmp << in)) return 0;
+ return atoi(tmp.str().c_str());
+}
+
+/** Template function to convert integer to char, storing result in *res and
+ * also returning the pointer to res. Based on Stuart Lowe's C/C++ Pages.
+ */
+template<typename T, typename V, typename R> inline char* itoa(const T &in, V *res, R base)
+{
+ if (base < 2 || base > 16) { *res = 0; return res; }
+ char* out = res;
+ int quotient = in;
+ while (quotient) {
+ *out = "0123456789abcdef"[ std::abs( quotient % base ) ];
+ ++out;
+ quotient /= base;
+ }
+ if ( in < 0 && base == 10) *out++ = '-';
+ std::reverse( res, out );
+ *out = 0;
+ return res;
+}
+
/** This class contains various STATS counters
* It is used by the InspIRCd class, which internally
* has an instance of it.
*/
unsigned long BoundPortCount;
+ /** Cpu usage at last sample
+ */
+ timeval LastCPU;
+
+ /** Time last sample was read
+ */
+ timeval LastSampled;
+
/** The constructor initializes all the counts to zero
*/
serverstats()
}
};
+class InspIRCd;
+
+/** This class implements a nonblocking log-writer.
+ * Most people writing an ircd give little thought to their disk
+ * i/o. On a congested system, disk writes can block for long
+ * periods of time (e.g. if the system is busy and/or swapping
+ * a lot). If we just use a blocking fprintf() call, this could
+ * block for undesirable amounts of time (half of a second through
+ * to whole seconds). We DO NOT want this, so we make our logfile
+ * nonblocking and hook it into the SocketEngine.
+ * NB: If the operating system does not support nonblocking file
+ * I/O (linux seems to, as does freebsd) this will default to
+ * blocking behaviour.
+ */
+class FileLogger : public EventHandler
+{
+ protected:
+ /** The creator/owner of this object
+ */
+ InspIRCd* ServerInstance;
+ /** The log file (fd is inside this somewhere,
+ * we get it out with fileno())
+ */
+ FILE* log;
+ /** Buffer of pending log lines to be written
+ */
+ std::string buffer;
+ /** Number of write operations that have occured
+ */
+ int writeops;
+ public:
+ /** The constructor takes an already opened logfile.
+ */
+ FileLogger(InspIRCd* Instance, FILE* logfile);
+ /** This returns false, logfiles are writeable.
+ */
+ virtual bool Readable();
+ /** Handle pending write events.
+ * This will flush any waiting data to disk.
+ * If any data remains after the fprintf call,
+ * another write event is scheduled to write
+ * the rest of the data when possible.
+ */
+ virtual void HandleEvent(EventType et, int errornum = 0);
+ /** Write one or more preformatted log lines.
+ * If the data cannot be written immediately,
+ * this class will insert itself into the
+ * SocketEngine, and register a write event,
+ * and when the write event occurs it will
+ * attempt again to write the data.
+ */
+ void WriteLogLine(const std::string &line);
+ /** Close the log file and cancel any events.
+ */
+ virtual void Close();
+ /** Close the log file and cancel any events.
+ * (indirectly call Close()
+ */
+ virtual ~FileLogger();
+};
+
+/** A list of failed port bindings, used for informational purposes on startup */
+typedef std::vector<std::pair<std::string, long> > FailedPortList;
+
+/** A list of ip addresses cross referenced against clone counts */
+typedef std::map<irc::string, unsigned int> clonemap;
+
class XLineManager;
-/** The main singleton class of the irc server.
+/** The main class of the irc server.
* This class contains instances of all the other classes
* in this software, with the exception of the base class,
* classbase. Amongst other things, it contains a ModeParser,
/** Holds a string describing the last module error to occur
*/
char MODERR[MAXBUF];
-
- /** This is an internal flag used by the mainloop
- */
- bool expire_run;
-
- /** List of server names we've seen.
- */
- servernamelist servernames;
/** Remove a ModuleFactory pointer
* @param j Index number of the ModuleFactory to remove
void Start();
/** Set up the signal handlers
- * @param SEGVHandler create a handler for segfaults (deprecated)
*/
- void SetSignals(bool SEGVHandler);
+ void SetSignals();
/** Daemonize the ircd and close standard input/output streams
* @return True if the program daemonized succesfully
*/
bool DaemonSeed();
- /** Build the upper/lowercase comparison table
- */
- void MakeLowerMap();
-
/** Moves the given module to the last slot in the list
* @param modulename The module name to relocate
*/
*/
void MoveBefore(std::string modulename, std::string before);
- /** Process a user whos socket has been flagged as active
- * @param cu The user to process
- * @return There is no actual return value, however upon exit, the user 'cu' may have been deleted
- */
- void ProcessUser(userrec* cu);
-
/** Iterate the list of InspSocket objects, removing ones which have timed out
* @param TIME the current time
*/
*/
featurelist Features;
+ /** The interface names published by various modules
+ */
+ interfacelist Interfaces;
+
/** The current time, updated in the mainloop
*/
time_t TIME;
*/
socklen_t length;
- /** Used to count iterations around the mainloop
+ /** Nonblocking file writer
+ */
+ FileLogger* Logger;
+
+ /** Time offset in seconds
+ * This offset is added to all calls to Time(). Use SetTimeDelta() to update
*/
- int iterations;
+ int time_delta;
public:
+
+ /** Number of unregistered users online right now.
+ * (Unregistered means before USER/NICK/dns)
+ */
+ int unregistered_count;
+
+ /** List of server names we've seen.
+ */
+ servernamelist servernames;
+
/** Time this ircd was booted
*/
time_t startup_time;
*/
ServerConfig* Config;
- /** Module sockets list, holds the active set of InspSocket classes
+ /** Snomask manager - handles routing of snomask messages
+ * to opers.
*/
- std::vector<InspSocket*> module_sockets;
-
- /** Socket reference table, provides fast lookup of fd to InspSocket*
- */
- InspSocket* socket_ref[MAX_DESCRIPTORS];
-
- /** user reference table, provides fast lookup of fd to userrec*
- */
- userrec* fd_ref_table[MAX_DESCRIPTORS];
+ SnomaskManager* SNO;
/** Client list, a hash_map containing all clients, local and remote
*/
- user_hash clientlist;
+ user_hash* clientlist;
/** Channel list, a hash_map containing all channels
*/
- chan_hash chanlist;
+ chan_hash* chanlist;
/** Local client list, a vector containing only local clients
*/
*/
std::vector<userrec*> all_opers;
- /** Whowas container, contains a map of vectors of users tracked by WHOWAS
- */
- irc::whowas::whowas_users whowas;
+ clonemap local_clones;
+
+ clonemap global_clones;
/** DNS class, provides resolver facilities to the core and modules
*/
*/
FactoryList factory;
+ /** The time we next call our ping timeout and reg timeout checks
+ */
+ time_t next_call;
+
/** Get the current time
* Because this only calls time() once every time around the mainloop,
* it is much faster than calling time() directly.
+ * @param delta True to use the delta as an offset, false otherwise
* @return The current time as an epoch value (time_t)
*/
- time_t Time();
+ time_t Time(bool delta = false);
+
+ /** Set the time offset in seconds
+ * This offset is added to Time() to offset the system time by the specified
+ * number of seconds.
+ * @param delta The number of seconds to offset
+ * @return The old time delta
+ */
+ int SetTimeDelta(int delta);
+
+ void AddLocalClone(userrec* user);
+
+ void AddGlobalClone(userrec* user);
+
+ /** Number of users with a certain mode set on them
+ */
+ int ModeCount(const char mode);
+
+ /** Get the time offset in seconds
+ * @return The current time delta (in seconds)
+ */
+ int GetTimeDelta();
+
+ /** Process a user whos socket has been flagged as active
+ * @param cu The user to process
+ * @return There is no actual return value, however upon exit, the user 'cu' may have been deleted
+ */
+ void ProcessUser(userrec* cu);
/** Get the total number of currently loaded modules
* @return The number of loaded modules
/** Bind all ports specified in the configuration file.
* @param bail True if the function should bail back to the shell on failure
+ * @param found_ports The actual number of ports found in the config, as opposed to the number actually bound
* @return The number of ports actually bound without error
*/
- int BindPorts(bool bail);
+ int BindPorts(bool bail, int &found_ports, FailedPortList &failed_ports);
/** Returns true if this server has the given port bound to the given address
* @param port The port number
*/
void OpenLog(char** argv, int argc);
+ void CloseLog();
+
/** Convert a user to a pseudoclient, disconnecting the real user
* @param user The user to convert
* @param message The quit message to display when exiting the user
/** Causes the server to exit immediately
* @param The exit code to give to the operating system
+ * (See the ExitStatus enum for valid values)
*/
static void Exit(int status);
/** Send an error notice to all local users, opered and unopered
* @param s The error string to send
*/
- void SendError(const char *s);
+ void SendError(const std::string &s);
/** For use with Module::Prioritize().
* When the return value of this function is returned from
*/
bool PublishFeature(const std::string &FeatureName, Module* Mod);
+ /** Publish a module to an 'interface'.
+ * Modules which implement the same interface (the same way of communicating
+ * with other modules) can publish themselves to an interface, using this
+ * method. When they do so, they become part of a list of related or
+ * compatible modules, and a third module may then query for that list
+ * and know that all modules within that list offer the same API.
+ * A prime example of this is the hashing modules, which all accept the
+ * same types of Request class. Consider this to be similar to PublishFeature,
+ * except for that multiple modules may publish the same 'feature'.
+ * @param InterfaceName The case sensitive interface name to make available
+ * @param Mod a pointer to your module class
+ * @returns True on success, false on failure (there are currently no failure
+ * cases)
+ */
+ bool PublishInterface(const std::string &InterfaceName, Module* Mod);
+
+ /** Return a pair saying how many other modules are currently using the
+ * interfaces provided by module m.
+ * @param m The module to count usage for
+ * @return A pair, where the first value is the number of uses of the interface,
+ * and the second value is the interface name being used.
+ */
+ std::pair<int,std::string> GetInterfaceInstanceCount(Module* m);
+
+ /** Mark your module as using an interface.
+ * If you mark your module as using an interface, then that interface
+ * module may not unload until your module has unloaded first.
+ * This can be used to prevent crashes by ensuring code you depend on
+ * is always in memory while your module is active.
+ * @param InterfaceName The interface to use
+ */
+ void UseInterface(const std::string &InterfaceName);
+
+ /** Mark your module as finished with an interface.
+ * If you used UseInterface() above, you should use this method when
+ * your module is finished with the interface (usually in its destructor)
+ * to allow the modules which implement the given interface to be unloaded.
+ * @param InterfaceName The interface you are finished with using.
+ */
+ void DoneWithInterface(const std::string &InterfaceName);
+
/** Unpublish a 'feature'.
* When your module exits, it must call this method for every feature it
* is providing so that the feature table is cleaned up.
*/
bool UnpublishFeature(const std::string &FeatureName);
+ /** Unpublish your module from an interface
+ * When your module exits, it must call this method for every interface
+ * it is part of so that the interfaces table is cleaned up. Only when
+ * the last item is deleted from an interface does the interface get
+ * removed.
+ * @param InterfaceName the interface to be removed from
+ * @param Mod The module to remove from the interface list
+ */
+ bool UnpublishInterface(const std::string &InterfaceName, Module* Mod);
+
/** Find a 'feature'.
* There are two ways for a module to find another module it depends on.
* Either by name, using InspIRCd::FindModule, or by feature, using the
*/
Module* FindFeature(const std::string &FeatureName);
+ /** Find an 'interface'.
+ * An interface is a list of modules which all implement the same API.
+ * @param InterfaceName The Interface you wish to obtain the module
+ * list of.
+ * @return A pointer to a deque of Module*, or NULL if the interface
+ * does not exist.
+ */
+ modulelist* FindInterface(const std::string &InterfaceName);
+
/** Given a pointer to a Module, return its filename
* @param m The module pointer to identify
* @return The module name or an empty string
*/
bool IsValidMask(const std::string &mask);
- /** Add an InspSocket class to the active set
- * @param sock A socket to add to the active set
- */
- void AddSocket(InspSocket* sock);
-
- /** Remove an InspSocket class from the active set at next time around the loop
- * @param sock A socket to remove from the active set
- */
- void RemoveSocket(InspSocket* sock);
-
- /** Delete a socket immediately without waiting for the next iteration of the mainloop
- * @param sock A socket to delete from the active set
- */
- void DelSocket(InspSocket* sock);
-
/** Rehash the local server
*/
void RehashServer();
* against possible hashed equivalents in the input string.
* @param data The data from the config file
* @param input The data input by the oper
+ * @param tagnum the tag number of the oper's tag in the config file
* @return 0 if the strings match, 1 or -1 if they do not
*/
- int OperPassCompare(const char* data,const char* input);
+ int OperPassCompare(const char* data,const char* input, int tagnum);
/** Check if a given server is a uline.
* An empty string returns true, this is by design.
*/
void Log(int level, const std::string &text);
+ void SendWhoisLine(userrec* user, userrec* dest, int numeric, const std::string &text);
+
+ void SendWhoisLine(userrec* user, userrec* dest, int numeric, const char* format, ...);
+
+ /** Restart the server.
+ * This function will not return. If an error occurs,
+ * it will throw an instance of CoreException.
+ * @param reason The restart reason to show to all clients
+ * @throw CoreException An instance of CoreException indicating the error from execv().
+ */
+ void Restart(const std::string &reason);
+
+ /** Prepare the ircd for restart or shutdown.
+ * This function unloads all modules which can be unloaded,
+ * closes all open sockets, and closes the logfile.
+ */
+ void Cleanup();
+
+ /** This copies the user and channel hash_maps into new hash maps.
+ * This frees memory used by the hash_map allocator (which it neglects
+ * to free, most of the time, using tons of ram)
+ */
+ void RehashUsersAndChans();
+
/** Begin execution of the server.
* NOTE: this function NEVER returns. Internally,
* after performing some initialisation routines,