]> jfr.im git - irc/rqf/shadowircd.git/blobdiff - src/ircd.c
New custom channel mode API allowing reloading such modules.
[irc/rqf/shadowircd.git] / src / ircd.c
index 40993b1baf4e546282a5ad22f96f27d172bc1a4f..a9f6cfbd1ef4cf2446d609b78f4d6051da981746 100644 (file)
@@ -1,10 +1,11 @@
 /*
- *  ircd-ratbox: A slightly useful ircd.
+ *  charybdis: A slightly useful ircd.
  *  ircd.c: Starts up and runs the ircd.
  *
  *  Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
  *  Copyright (C) 1996-2002 Hybrid Development Team
- *  Copyright (C) 2002-2005 ircd-ratbox development team
+ *  Copyright (C) 2002-2008 ircd-ratbox development team
+ *  Copyright (C) 2005-2008 charybdis development team
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
  *  USA
  *
- *  $Id: ircd.c 3380 2007-04-03 22:25:11Z jilles $
+ *  $Id$
  */
 
+#include "ratbox_lib.h"
 #include "stdinc.h"
 #include "setup.h"
 #include "config.h"
-
-#include "tools.h"
 #include "ircd.h"
 #include "channel.h"
 #include "class.h"
 #include "client.h"
 #include "common.h"
-#include "event.h"
 #include "hash.h"
-#include "irc_string.h"
+#include "match.h"
 #include "ircd_signal.h"
-#include "sprintf_irc.h"
-#include "s_gline.h"
 #include "msg.h"               /* msgtab */
 #include "hostmask.h"
 #include "numeric.h"
@@ -47,9 +44,8 @@
 #include "res.h"
 #include "restart.h"
 #include "s_auth.h"
-#include "commio.h"
 #include "s_conf.h"
-#include "s_log.h"
+#include "logger.h"
 #include "s_serv.h"            /* try_connections */
 #include "s_user.h"
 #include "s_stats.h"
 #include "supported.h"
 #include "whowas.h"
 #include "modules.h"
-#include "memory.h"
 #include "hook.h"
 #include "ircd_getopt.h"
-#include "balloc.h"
 #include "newconf.h"
-#include "patricia.h"
 #include "reject.h"
 #include "s_conf.h"
 #include "s_newconf.h"
 #include "cache.h"
 #include "monitor.h"
-#include "libcharybdis.h"
 #include "patchlevel.h"
 #include "serno.h"
+#include "sslproc.h"
+#include "chmode.h"
+#include "privilege.h"
+#include "bandbi.h"
+
+/* /quote set variables */
+struct SetOptions GlobalSetOptions;
+
+/* configuration set from ircd.conf */
+struct config_file_entry ConfigFileEntry;
+/* server info set from ircd.conf */
+struct server_info ServerInfo;
+/* admin info set from ircd.conf */
+struct admin_info AdminInfo;
+
+struct Counter Count;
+struct ServerStatistics ServerStats;
+
+int maxconnections;
+struct Client me;              /* That's me */
+struct LocalUser meLocalUser;  /* That's also part of me */
+
+rb_dlink_list global_client_list;
+
+/* unknown/client pointer lists */
+rb_dlink_list unknown_list;        /* unknown clients ON this server only */
+rb_dlink_list lclient_list;    /* local clients only ON this server */
+rb_dlink_list serv_list;           /* local servers to this server ONLY */
+rb_dlink_list global_serv_list;    /* global servers on the network */
+rb_dlink_list local_oper_list;     /* our opers, duplicated in lclient_list */
+rb_dlink_list oper_list;           /* network opers */
+
+const char *logFileName = LPATH;
+const char *pidFileName = PPATH;
+
+char **myargv;
+int dorehash = 0;
+int dorehashbans = 0;
+int doremotd = 0;
+int kline_queued = 0;
+int server_state_foreground = 0;
+int opers_see_all_users = 0;
+int ssl_ok = 0;
+int zlib_ok = 1;
+
+int testing_conf = 0;
+time_t startup_time;
+
+int default_server_capabs = CAP_MASK;
+
+int splitmode;
+int splitchecking;
+int split_users;
+int split_servers;
+int eob_count;
 
-/*
- * Try and find the correct name to use with getrlimit() for setting the max.
- * number of files allowed to be open by this process.
- */
-int _charybdis_data_version = CHARYBDIS_DV;
+void
+ircd_shutdown(const char *reason)
+{
+       struct Client *target_p;
+       rb_dlink_node *ptr;
+
+       RB_DLINK_FOREACH(ptr, lclient_list.head)
+       {
+               target_p = ptr->data;
+
+               sendto_one(target_p, ":%s NOTICE %s :Server Terminating. %s",
+                       me.name, target_p->name, reason);
+       }
+
+       RB_DLINK_FOREACH(ptr, serv_list.head)
+       {
+               target_p = ptr->data;
 
-extern int ServerRunning;
-extern struct LocalUser meLocalUser;
-extern char **myargv;
+               sendto_one(target_p, ":%s ERROR :Terminated by %s",
+                       me.name, reason);
+       }
+
+       ilog(L_MAIN, "Server Terminating. %s", reason);
+       close_logfiles();
+
+       unlink(pidFileName);
+       exit(0);
+}
 
 /*
  * print_startup - print startup information
@@ -105,36 +171,6 @@ print_startup(int pid)
        dup2(0, 2);
 }
 
-static void
-ircd_log_cb(const char *str)
-{
-       ilog(L_MAIN, "%s", str);
-}
-
-static void
-ircd_restart_cb(const char *str)
-{
-       ilog(L_MAIN, "%s", str);
-}
-
-/*
- * Why EXIT_FAILURE here?
- * Because if ircd_die_cb() is called it's because of a fatal
- * error inside libcharybdis, and we don't know how to handle the
- * exception, so it is logical to return a FAILURE exit code here.
- *    --nenolod
- */
-static void
-ircd_die_cb(const char *str)
-{
-       /* Try to get the message out to currently logged in operators. */
-       sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "Server panic! %s", str);
-       inotice("server panic: %s", str);
-
-       unlink(pidFileName);
-       exit(EXIT_FAILURE);
-}
-
 /*
  * init_sys
  *
@@ -150,14 +186,17 @@ init_sys(void)
 
        if(!getrlimit(RLIMIT_NOFILE, &limit))
        {
-               limit.rlim_cur = limit.rlim_max;        /* make soft limit the max */
-               if(setrlimit(RLIMIT_NOFILE, &limit) == -1)
+               maxconnections = limit.rlim_cur;
+               if(maxconnections <= MAX_BUFFER)
                {
-                       fprintf(stderr, "error setting max fd's to %ld\n", (long) limit.rlim_cur);
+                       fprintf(stderr, "ERROR: Shell FD limits are too low.\n");
+                       fprintf(stderr, "ERROR: charybdis reserves %d FDs, shell limits must be above this\n", MAX_BUFFER);
                        exit(EXIT_FAILURE);
                }
+               return;
        }
-#endif /* RLIMIT_NOFILE */
+#endif /* RLIMIT_FD_MAX */
+       maxconnections = MAXCONNECTIONS;
 }
 
 static int
@@ -204,16 +243,8 @@ make_daemon(void)
 static int printVersion = 0;
 
 struct lgetopt myopts[] = {
-       {"dlinefile", &ConfigFileEntry.dlinefile,
-        STRING, "File to use for dlines.conf"},
        {"configfile", &ConfigFileEntry.configfile,
         STRING, "File to use for ircd.conf"},
-       {"klinefile", &ConfigFileEntry.klinefile,
-        STRING, "File to use for kline.conf"},
-       {"xlinefile", &ConfigFileEntry.xlinefile,
-        STRING, "File to use for xline.conf"},
-       {"resvfile", &ConfigFileEntry.resvfile,
-        STRING, "File to use for resv.conf"},
        {"logfile", &logFileName,
         STRING, "File to use for ircd.log"},
        {"pidfile", &pidFileName,
@@ -228,32 +259,6 @@ struct lgetopt myopts[] = {
        {NULL, NULL, STRING, NULL},
 };
 
-void
-set_time(void)
-{
-       struct timeval newtime;
-       newtime.tv_sec = 0;
-       newtime.tv_usec = 0;
-#ifdef HAVE_GETTIMEOFDAY
-       if(gettimeofday(&newtime, NULL) == -1)
-       {
-               ilog(L_MAIN, "Clock Failure (%d)", errno);
-               sendto_realops_snomask(SNO_GENERAL, L_ALL,
-                                    "Clock Failure (%d), TS can be corrupted", errno);
-
-               restart("Clock Failure");
-       }
-#else
-       newtime.tv_sec = time(NULL);
-       
-#endif
-       if(newtime.tv_sec < CurrentTime)
-               set_back_events(CurrentTime - newtime.tv_sec);
-
-       SystemTime.tv_sec = newtime.tv_sec;
-       SystemTime.tv_usec = newtime.tv_usec;
-}
-
 static void
 check_rehash(void *unused)
 {
@@ -276,32 +281,11 @@ check_rehash(void *unused)
        {
                sendto_realops_snomask(SNO_GENERAL, L_ALL,
                                     "Got signal SIGUSR1, reloading ircd motd file");
-               free_cachefile(user_motd);
-               user_motd = cache_file(MPATH, "ircd.motd", 0);
+               cache_user_motd();
                doremotd = 0;
        }
 }
 
-void
-charybdis_io_loop(void)
-{
-       time_t delay;
-
-       while (ServerRunning)
-       {
-               /* Run pending events, then get the number of seconds to the next
-                * event
-                */
-
-               delay = eventNextTime();
-               if(delay <= CurrentTime)
-                       eventRun();
-
-
-               comm_select(250);
-       }
-}
-
 /*
  * initalialize_global_set_options
  *
@@ -315,7 +299,11 @@ initialize_global_set_options(void)
        memset(&GlobalSetOptions, 0, sizeof(GlobalSetOptions));
        /* memset( &ConfigFileEntry, 0, sizeof(ConfigFileEntry)); */
 
-       GlobalSetOptions.maxclients = ServerInfo.max_clients;
+       GlobalSetOptions.maxclients = ServerInfo.default_max_clients;
+
+       if(GlobalSetOptions.maxclients > (maxconnections - MAX_BUFFER) || (GlobalSetOptions.maxclients <= 0))
+               GlobalSetOptions.maxclients = maxconnections - MAX_BUFFER;
+
        GlobalSetOptions.autoconn = 1;
 
        GlobalSetOptions.spam_time = MIN_JOIN_LEAVE_TIME;
@@ -338,10 +326,10 @@ initialize_global_set_options(void)
 
        GlobalSetOptions.ident_timeout = IDENT_TIMEOUT;
 
-       strlcpy(GlobalSetOptions.operstring,
+       rb_strlcpy(GlobalSetOptions.operstring,
                ConfigFileEntry.default_operstring,
                sizeof(GlobalSetOptions.operstring));
-       strlcpy(GlobalSetOptions.adminstring,
+       rb_strlcpy(GlobalSetOptions.adminstring,
                ConfigFileEntry.default_adminstring,
                sizeof(GlobalSetOptions.adminstring));
 
@@ -380,7 +368,7 @@ write_pidfile(const char *filename)
        {
                unsigned int pid = (unsigned int) getpid();
 
-               ircsnprintf(buff, sizeof(buff), "%u\n", pid);
+               rb_snprintf(buff, sizeof(buff), "%u\n", pid);
                if((fputs(buff, fb) == -1))
                {
                        ilog(L_MAIN, "Error writing %u to pid file %s (%s)",
@@ -450,6 +438,85 @@ setup_corefile(void)
 #endif
 }
 
+static void
+ircd_log_cb(const char *str)
+{
+       ilog(L_MAIN, "libratbox reports: %s", str);
+}
+
+static void
+ircd_restart_cb(const char *str)
+{
+       inotice("libratbox has called the restart callback: %s", str);
+       restart(str);
+}
+
+/*
+ * Why EXIT_FAILURE here?
+ * Because if ircd_die_cb() is called it's because of a fatal
+ * error inside libcharybdis, and we don't know how to handle the
+ * exception, so it is logical to return a FAILURE exit code here.
+ *    --nenolod
+ */
+static void
+ircd_die_cb(const char *str)
+{
+       if(str != NULL)
+       {
+               /* Try to get the message out to currently logged in operators. */
+               sendto_realops_snomask(SNO_GENERAL, L_NETWIDE, "libratbox has called the die callback..aborting: %s", str);
+               inotice("libratbox has called the die callback..aborting: %s", str);
+       }
+       else
+               inotice("libratbox has called the die callback..aborting");
+
+       unlink(pidFileName);
+       exit(EXIT_FAILURE);
+}
+
+struct ev_entry *check_splitmode_ev = NULL;
+
+static int
+seed_with_urandom(void)
+{
+       unsigned int seed;
+       int fd;
+
+       fd = open("/dev/urandom", O_RDONLY);
+       if(fd >= 0)
+       {
+               if(read(fd, &seed, sizeof(seed)) == sizeof(seed))
+               {
+                       close(fd);
+                       srand(seed);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static void
+seed_with_clock(void)
+{
+       const struct timeval *tv;       
+       rb_set_time();
+       tv = rb_current_time_tv();
+       srand(tv->tv_sec ^ (tv->tv_usec | (getpid() << 20)));
+}
+
+static void
+seed_random(void *unused)
+{
+       unsigned int seed;
+       if(rb_get_random(&seed, sizeof(seed)) == -1)
+       {
+               if(!seed_with_urandom())
+                       seed_with_clock();
+               return;
+       }
+       srand(seed);
+}
+
 /*
  * main
  *
@@ -471,18 +538,30 @@ main(int argc, char *argv[])
                return -1;
        }
 
-       /*
-        * save server boot time right away, so getrusage works correctly
-        */
-       set_time();
+       init_sys();
+
+       ConfigFileEntry.dpath = DPATH;
+       ConfigFileEntry.configfile = CPATH;     /* Server configuration file */
+       ConfigFileEntry.connect_timeout = 30;   /* Default to 30 */
+       
+       umask(077);             /* better safe than sorry --SRB */
+
+       myargv = argv;
+       parseargs(&argc, &argv, myopts);
+
+       if(chdir(ConfigFileEntry.dpath))
+       {
+               fprintf(stderr, "Unable to chdir to %s: %s\n", ConfigFileEntry.dpath, strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+
+       rb_set_time();
+
        /*
         * Setup corefile size immediately after boot -kre
         */
        setup_corefile();
 
-       ServerRunning = 0;
-       /* It ain't random, but it ought to be a little harder to guess */
-       srand(SystemTime.tv_sec ^ (SystemTime.tv_usec | (getpid() << 20)));
        memset(&me, 0, sizeof(me));
        memset(&meLocalUser, 0, sizeof(meLocalUser));
        me.localClient = &meLocalUser;
@@ -495,44 +574,26 @@ main(int argc, char *argv[])
        memset(&local_oper_list, 0, sizeof(local_oper_list));
        memset(&oper_list, 0, sizeof(oper_list));
 
-       dlinkAddTail(&me, &me.node, &global_client_list);
+       rb_dlinkAddTail(&me, &me.node, &global_client_list);
 
-       memset((void *) &Count, 0, sizeof(Count));
-       memset((void *) &ServerInfo, 0, sizeof(ServerInfo));
-       memset((void *) &AdminInfo, 0, sizeof(AdminInfo));
+       memset(&Count, 0, sizeof(Count));
+       memset(&ServerInfo, 0, sizeof(ServerInfo));
+       memset(&AdminInfo, 0, sizeof(AdminInfo));
+       memset(&ServerStats, 0, sizeof(struct ServerStatistics));
 
        /* Initialise the channel capability usage counts... */
        init_chcap_usage_counts();
 
-       ConfigFileEntry.dpath = DPATH;
-       ConfigFileEntry.configfile = CPATH;     /* Server configuration file */
-       ConfigFileEntry.klinefile = KPATH;      /* Server kline file */
-       ConfigFileEntry.dlinefile = DLPATH;     /* dline file */
-       ConfigFileEntry.xlinefile = XPATH;
-       ConfigFileEntry.resvfile = RESVPATH;
-       ConfigFileEntry.connect_timeout = 30;   /* Default to 30 */
-       myargv = argv;
-       umask(077);             /* better safe than sorry --SRB */
-
-       parseargs(&argc, &argv, myopts);
-
        if(printVersion)
        {
-               printf("ircd: version %s\n", ircd_version);
+               printf("ircd: version %s(%s)\n", ircd_version, serno);
+               printf("ircd: %s\n", rb_lib_version());
                exit(EXIT_SUCCESS);
        }
 
-       if(chdir(ConfigFileEntry.dpath))
-       {
-               fprintf(stderr, "Unable to chdir to %s: %s\n", ConfigFileEntry.dpath, strerror(errno));
-               exit(EXIT_FAILURE);
-       }
 
-       setup_signals();
 
-#ifdef __CYGWIN__
-       server_state_foreground = 1;
-#endif
+       setup_signals();
 
        if (testing_conf)
                server_state_foreground = 1;
@@ -555,21 +616,22 @@ main(int argc, char *argv[])
                if(!server_state_foreground)
                        make_daemon();
                inotice("starting %s ...", ircd_version);
+               inotice("%s", rb_lib_version());
        }
 
        /* Init the event subsystem */
-       init_sys();
-       libcharybdis_init(ircd_log_cb, restart, ircd_die_cb);
-       rb_lib_init(ircd_log_cb, restart, ircd_die_cb);
+       rb_lib_init(ircd_log_cb, ircd_restart_cb, ircd_die_cb, !server_state_foreground, maxconnections, DNODE_HEAP_SIZE, FD_HEAP_SIZE);
+       rb_linebuf_init(LINEBUF_HEAP_SIZE);
 
-       fdlist_init();
-       if(!server_state_foreground)
+       if(ConfigFileEntry.use_egd && (ConfigFileEntry.egdpool_path != NULL))
        {
-               comm_close_all();
-       }
+               rb_init_prng(ConfigFileEntry.egdpool_path, RB_PRNG_EGD);
+       } else
+               rb_init_prng(NULL, RB_PRNG_DEFAULT);
+
+       seed_random(NULL);
 
        init_main_logfile();
-       init_patricia();
        newconf_init();
        init_s_conf();
        init_s_newconf();
@@ -578,33 +640,39 @@ main(int argc, char *argv[])
        init_host_hash();
        clear_hash_parse();
        init_client();
-       initUser();
        init_hook();
        init_channels();
        initclass();
        initwhowas();
-       init_stats();
        init_reject();
        init_cache();
        init_monitor();
        init_isupport();
+
+        construct_cflags_strings();
+
        load_all_modules(1);
 #ifndef STATIC_MODULES
        load_core_modules(1);
 #endif
        init_auth();            /* Initialise the auth code */
        init_resolver();        /* Needs to be setup before the io loop */
+       privilegeset_set_new("default", "", 0);
 
        if (testing_conf)
                fprintf(stderr, "\nBeginning config test\n");
        read_conf_files(YES);   /* cold start init conf files */
-       rehash_bans(0);
 #ifndef STATIC_MODULES
 
        mod_add_path(MODULE_DIR); 
        mod_add_path(MODULE_DIR "/autoload"); 
 #endif
 
+       init_bandb();
+       init_ssld();
+
+       rehash_bans(0);
+
        initialize_server_capabs();     /* Set up default_server_capabs */
        initialize_global_set_options();
 
@@ -613,7 +681,7 @@ main(int argc, char *argv[])
                ierror("no server name specified in serverinfo block.");
                return -1;
        }
-       strlcpy(me.name, ServerInfo.name, sizeof(me.name));
+       rb_strlcpy(me.name, ServerInfo.name, sizeof(me.name));
 
        if(ServerInfo.sid[0] == '\0')
        {
@@ -629,7 +697,19 @@ main(int argc, char *argv[])
                ierror("no server description specified in serverinfo block.");
                return -3;
        }
-       strlcpy(me.info, ServerInfo.description, sizeof(me.info));
+       rb_strlcpy(me.info, ServerInfo.description, sizeof(me.info));
+
+       if(ServerInfo.ssl_cert != NULL && ServerInfo.ssl_private_key != NULL)
+       {
+               /* just do the rb_setup_ssl_server to validate the config */
+               if(!rb_setup_ssl_server(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params))
+               {
+                       ilog(L_MAIN, "WARNING: Unable to setup SSL.");
+                       ssl_ok = 0;
+               }
+               else
+                       ssl_ok = 1;
+       }
 
        if (testing_conf)
        {
@@ -642,12 +722,12 @@ main(int argc, char *argv[])
        me.servptr = &me;
        SetMe(&me);
        make_server(&me);
-       startup_time = CurrentTime;
+       startup_time = rb_current_time();
        add_to_client_hash(me.name, &me);
        add_to_id_hash(me.id, &me);
        me.serv->nameinfo = scache_connect(me.name, me.info, 0);
 
-       dlinkAddAlloc(&me, &global_serv_list);
+       rb_dlinkAddAlloc(&me, &global_serv_list);
 
        construct_umodebuf();
 
@@ -658,31 +738,22 @@ main(int argc, char *argv[])
 
        ilog(L_MAIN, "Server Ready");
 
-       eventAddIsh("cleanup_glines", cleanup_glines, NULL, CLEANUP_GLINES_TIME);
-
        /* We want try_connections to be called as soon as possible now! -- adrian */
        /* No, 'cause after a restart it would cause all sorts of nick collides */
        /* um.  by waiting even longer, that just means we have even *more*
         * nick collisions.  what a stupid idea. set an event for the IO loop --fl
         */
-       eventAddIsh("try_connections", try_connections, NULL, STARTUP_CONNECTIONS_TIME);
-       eventAddOnce("try_connections_startup", try_connections, NULL, 0);
-
-       eventAddIsh("collect_zipstats", collect_zipstats, NULL, ZIPSTATS_TIME);
-
-       /* Setup the timeout check. I'll shift it later :)  -- adrian */
-       eventAddIsh("comm_checktimeouts", comm_checktimeouts, NULL, 1);
-
-       eventAdd("check_rehash", check_rehash, NULL, 1);
+       rb_event_addish("try_connections", try_connections, NULL, STARTUP_CONNECTIONS_TIME);
+       rb_event_addonce("try_connections_startup", try_connections, NULL, 2);
+       rb_event_add("check_rehash", check_rehash, NULL, 3);
+       rb_event_addish("reseed_srand", seed_random, NULL, 300); /* reseed every 10 minutes */
 
        if(splitmode)
-               eventAdd("check_splitmode", check_splitmode, NULL, 2);
-
-       ServerRunning = 1;
+               check_splitmode_ev = rb_event_add("check_splitmode", check_splitmode, NULL, 5);
 
        print_startup(getpid());
 
-       charybdis_io_loop();
+       rb_lib_loop(0);
 
        return 0;
 }