Add new feature FEAT_HIS_WHOIS_LOCALCHAN.
[ircu2.10.12-pk.git] / ircd / ircd.c
index ea3a538f1e74868eb7452cb2ca6e02f715be12b7..7cb126ec83d18f9a9a6ce8569369887de57e4fe6 100644 (file)
@@ -26,6 +26,7 @@
 #include "class.h"
 #include "client.h"
 #include "crule.h"
+#include "destruct_event.h"
 #include "hash.h"
 #include "ircd_alloc.h"
 #include "ircd_events.h"
@@ -34,6 +35,7 @@
 #include "ircd_reply.h"
 #include "ircd_signal.h"
 #include "ircd_string.h"
+#include "ircd_crypt.h"
 #include "jupe.h"
 #include "list.h"
 #include "match.h"
@@ -41,6 +43,7 @@
 #include "msg.h"
 #include "numeric.h"
 #include "numnicks.h"
+#include "opercmds.h"
 #include "parse.h"
 #include "res.h"
 #include "s_auth.h"
@@ -48,6 +51,7 @@
 #include "s_conf.h"
 #include "s_debug.h"
 #include "s_misc.h"
+#include "s_stats.h"
 #include "send.h"
 #include "sys.h"
 #include "uping.h"
  * External stuff
  *--------------------------------------------------------------------------*/
 extern void init_counters(void);
+extern void mem_dbg_initialise(void);
 
 /*----------------------------------------------------------------------------
  * Constants / Enums
  *--------------------------------------------------------------------------*/
 enum {
   BOOT_DEBUG = 1,
-  BOOT_TTY   = 2
+  BOOT_TTY   = 2,
+  BOOT_CHKCONF = 4
 };
 
 
@@ -103,6 +109,7 @@ static char   *dpath             = DPATH;
 
 static struct Timer connect_timer; /* timer structure for try_connections() */
 static struct Timer ping_timer; /* timer structure for check_pings() */
+static struct Timer destruct_event_timer; /* timer structure for exec_expired_destruct_events() */
 
 static struct Daemon thisServer  = { 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0 };
 
@@ -112,7 +119,8 @@ int running = 1;
 /*----------------------------------------------------------------------------
  * API: server_die
  *--------------------------------------------------------------------------*/
-void server_die(const char* message) {
+void server_die(const char *message)
+{
   /* log_write will send out message to both log file and as server notice */
   log_write(LS_SYSTEM, L_CRIT, 0, "Server terminating: %s", message);
   flush_connections(0);
@@ -120,11 +128,24 @@ void server_die(const char* message) {
   running = 0;
 }
 
+/*----------------------------------------------------------------------------
+ * API: server_panic
+ *--------------------------------------------------------------------------*/
+void server_panic(const char *message)
+{
+  /* inhibit sending server notice--we may be panicing due to low memory */
+  log_write(LS_SYSTEM, L_CRIT, LOG_NOSNOTICE, "Server panic: %s", message);
+  flush_connections(0);
+  log_close();
+  close_connections(1);
+  exit(1);
+}
 
 /*----------------------------------------------------------------------------
  * API: server_restart
  *--------------------------------------------------------------------------*/
-void server_restart(const char* message) {
+void server_restart(const char *message)
+{
   static int restarting = 0;
 
   /* inhibit sending any server notices; we may be in a loop */
@@ -139,7 +160,7 @@ void server_restart(const char* message) {
 
   log_close();
 
-  close_connections(!(thisServer.bootopt & (BOOT_TTY | BOOT_DEBUG)));
+  close_connections(!(thisServer.bootopt & (BOOT_TTY | BOOT_DEBUG | BOOT_CHKCONF)));
 
   execv(SPATH, thisServer.argv);
 
@@ -227,7 +248,7 @@ static void try_connections(struct Event* ev) {
   struct ConnectionClass* cltmp;
   struct ConfItem*  con_conf    = 0;
   struct Jupe*      ajupe;
-  unsigned int      con_class   = 0;
+  const char*       con_class   = NULL;
 
   assert(ET_EXPIRE == ev_type(ev));
   assert(0 != ev_timer(ev));
@@ -236,7 +257,7 @@ static void try_connections(struct Event* ev) {
   Debug((DEBUG_NOTICE, "Connection check at   : %s", myctime(CurrentTime)));
   for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
     /* Also when already connecting! (update holdtimes) --SRB */
-    if (!(aconf->status & CONF_SERVER) || aconf->port == 0)
+    if (!(aconf->status & CONF_SERVER) || aconf->address.port == 0 || aconf->hold == 0)
       continue;
 
     /* Also skip juped servers */
@@ -255,7 +276,10 @@ static void try_connections(struct Event* ev) {
 
     cltmp = aconf->conn_class;
     confrq = get_con_freq(cltmp);
-    aconf->hold = CurrentTime + confrq;
+    if(confrq == 0)
+      aconf->hold = next = 0;
+    else
+      aconf->hold = CurrentTime + confrq;
 
     /* Found a CONNECT config with port specified, scan clients and see if
      * this server is already connected?
@@ -263,7 +287,7 @@ static void try_connections(struct Event* ev) {
     cptr = FindServer(aconf->name);
 
     if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) &&
-        (!connecting || (ConClass(cltmp) > con_class))) {
+        (!connecting /*|| (ConClass(cltmp) > con_class)*/)) {
       /*
        * Check connect rules to see if we're allowed to try
        */
@@ -286,7 +310,7 @@ static void try_connections(struct Event* ev) {
       (*pconf = con_conf)->next = 0;
     }
 
-    if (connect_server(con_conf, 0, 0))
+    if (connect_server(con_conf, 0))
       sendto_opmask_butone(0, SNO_OLDSNO, "Connection to %s activated.",
                           con_conf->name);
   }
@@ -339,64 +363,86 @@ static void check_pings(struct Event* ev) {
    
     Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d",
           cli_name(cptr),
-          (cli_flags(cptr) & FLAGS_PINGSENT) ? "[Ping Sent]" : "[]", 
+          IsPingSent(cptr) ? "[Ping Sent]" : "[]", 
           max_ping, (int)(CurrentTime - cli_lasttime(cptr))));
-          
 
     /* Ok, the thing that will happen most frequently, is that someone will
      * have sent something recently.  Cover this first for speed.
+     * -- 
+     * If it's an unregisterd client and hasn't managed to register within
+     * max_ping then it's obviously having problems (broken client) or it's
+     * just up to no good, so we won't skip it, even if its been sending
+     * data to us. 
+     * -- hikari
      */
-    if (CurrentTime-cli_lasttime(cptr) < max_ping) {
+    if ((CurrentTime-cli_lasttime(cptr) < max_ping) && IsRegistered(cptr)) {
       expire = cli_lasttime(cptr) + max_ping;
       if (expire < next_check) 
        next_check = expire;
       continue;
     }
 
-    /* Quit the client after max_ping*2 - they should have answered by now */
-    if (CurrentTime-cli_lasttime(cptr) >= (max_ping*2) ) {
-      /* If it was a server, then tell ops about it. */
-      if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
-       sendto_opmask_butone(0, SNO_OLDSNO,
-                            "No response from %s, closing link",
-                            cli_name(cptr));
-      exit_client_msg(cptr, cptr, &me, "Ping timeout");
-      continue;
-    }
-    
     /* Unregistered clients pingout after max_ping seconds, they don't
      * get given a second chance - if they were then people could not quite
      * finish registration and hold resources without being subject to k/g
      * lines
      */
     if (!IsRegistered(cptr)) {
-      /* Display message if they have sent a NICK and a USER but no
-       * nospoof PONG.
-       */
-      if (*(cli_name(cptr)) && cli_user(cptr) && *(cli_user(cptr))->username) {
-       send_reply(cptr, SND_EXPLICIT | ERR_BADPING,
-                  ":Your client may not be compatible with this server.");
-       send_reply(cptr, SND_EXPLICIT | ERR_BADPING,
-                  ":Compatible clients are available at "
-                  URL_CLIENTS);
-      }    
-      exit_client_msg(cptr,cptr,&me, "Ping Timeout");
+      assert(!IsServer(cptr));
+      if ((CurrentTime-cli_firsttime(cptr) >= max_ping)) {
+       /* Display message if they have sent a NICK and a USER but no
+        * nospoof PONG.
+        */
+       if (*(cli_name(cptr)) && cli_user(cptr) && *(cli_user(cptr))->username) {
+         send_reply(cptr, SND_EXPLICIT | ERR_BADPING,
+           ":Your client may not be compatible with this server.");
+         send_reply(cptr, SND_EXPLICIT | ERR_BADPING,
+           ":Compatible clients are available at %s",
+         feature_str(FEAT_URL_CLIENTS));
+       }
+       exit_client_msg(cptr,cptr,&me, "Registration Timeout");
+       continue;
+      } else {
+        /* OK, they still have enough time left, so we'll just skip to the
+         * next client.  Set the next check to be when their time is up, if
+         * that's before the currently scheduled next check -- hikari */
+        expire = cli_firsttime(cptr) + max_ping;
+        if (expire < next_check)
+          next_check = expire;
+        continue;
+      }
+    }
+
+    /* Quit the client after max_ping*2 - they should have answered by now */
+    if (CurrentTime-cli_lasttime(cptr) >= (max_ping*2) )
+    {
+      /* If it was a server, then tell ops about it. */
+      if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
+        sendto_opmask_butone(0, SNO_OLDSNO,
+                             "No response from %s, closing link",
+                             cli_name(cptr));
+      exit_client_msg(cptr, cptr, &me, "Ping timeout");
       continue;
     }
     
-    if (!(cli_flags(cptr) & FLAGS_PINGSENT)) {
+    if (!IsPingSent(cptr))
+    {
       /* If we havent PINGed the connection and we havent heard from it in a
        * while, PING it to make sure it is still alive.
        */
-      cli_flags(cptr) |= FLAGS_PINGSENT;
+      SetPingSent(cptr);
 
       /* If we're late in noticing don't hold it against them :) */
       cli_lasttime(cptr) = CurrentTime - max_ping;
       
       if (IsUser(cptr))
-       sendrawto_one(cptr, MSG_PING " :%s", cli_name(&me));
+        sendrawto_one(cptr, MSG_PING " :%s", cli_name(&me));
       else
-       sendcmdto_one(&me, CMD_PING, cptr, ":%s", cli_name(&me));
+      {
+        char *asll_ts = militime_float(NULL);
+        sendcmdto_one(&me, CMD_PING, cptr, "!%s %s %s", asll_ts,
+                      cli_name(cptr), asll_ts);
+      }
     }
     
     expire = cli_lasttime(cptr) + max_ping * 2;
@@ -419,7 +465,7 @@ static void check_pings(struct Event* ev) {
  * debugmode
  *--------------------------------------------------------------------------*/
 static void parse_command_line(int argc, char** argv) {
-  const char *options = "d:f:h:ntvx:";
+  const char *options = "d:f:h:nktvx:";
   int opt;
 
   if (thisServer.euid != thisServer.uid)
@@ -430,12 +476,31 @@ static void parse_command_line(int argc, char** argv) {
    */
   while ((opt = getopt(argc, argv, options)) != EOF)
     switch (opt) {
+    case 'k':  thisServer.bootopt |= BOOT_CHKCONF;     break;
     case 'n':
     case 't':  thisServer.bootopt |= BOOT_TTY;         break;
     case 'd':  dpath      = optarg;                    break;
     case 'f':  configfile = optarg;                    break;
     case 'h':  ircd_strncpy(cli_name(&me), optarg, HOSTLEN); break;
-    case 'v':  printf("ircd %s\n", version);           exit(0);
+    case 'v':
+      printf("ircd %s\n", version);
+      printf("Event engines: ");
+#ifdef USE_KQUEUE
+      printf("kqueue() ");
+#endif
+#ifdef USE_DEVPOLL
+      printf("/dev/poll ");
+#endif
+#ifdef USE_POLL
+      printf("poll()");
+#else
+      printf("select()");
+#endif
+      printf("\nCompiled for a maximum of %d connections.\n", MAXCONNECTIONS);
+
+
+      exit(0);
+      break;
       
     case 'x':
       debuglevel = atoi(optarg);
@@ -446,8 +511,8 @@ static void parse_command_line(int argc, char** argv) {
       break;
       
     default:
-      printf("Usage: ircd [-f config] [-h servername] [-x loglevel] [-ntv]\n");
-      printf("\n -n -t\t Don't detach\n -v\t display version\n\n");
+      printf("Usage: ircd [-f config] [-h servername] [-x loglevel] [-ntvk]\n");
+      printf("\n -n -t\t Don't detach\n -v\t display version\n -k\t exit after checking config\n\n");
       printf("Server not started.\n");
       exit(1);
     }
@@ -458,11 +523,6 @@ static void parse_command_line(int argc, char** argv) {
  * daemon_init
  *--------------------------------------------------------------------------*/
 static void daemon_init(int no_fork) {
-  if (!init_connection_limits())
-    exit(9);
-
-  close_connections(!(thisServer.bootopt & (BOOT_DEBUG | BOOT_TTY)));
-
   if (no_fork)
     return;
 
@@ -492,9 +552,9 @@ static char check_file_access(const char *path, char which, int mode) {
 
   fprintf(stderr, 
          "Check on %cPATH (%s) failed: %s\n"
-         "Please create file and/or rerun `make config' and "
-         "recompile to correct this.\n",
-         which, path, strerror(errno));
+         "Please create this file and/or rerun `configure' "
+         "using --with-%cpath and recompile to correct this.\n",
+         which, path, strerror(errno), which);
 
   return 0;
 }
@@ -549,6 +609,10 @@ int main(int argc, char **argv) {
   thisServer.uid  = getuid();
   thisServer.euid = geteuid();
 
+#ifdef MDEBUG
+  mem_dbg_initialise();
+#endif
+
 #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE)
   set_core_limit();
 #endif
@@ -574,19 +638,18 @@ int main(int argc, char **argv) {
       !check_file_access(configfile, 'C', R_OK))
     return 4;
 
-  debug_init(thisServer.bootopt & BOOT_TTY);
-  daemon_init(thisServer.bootopt & BOOT_TTY);
+  if (!init_connection_limits())
+    return 9;
+
+  close_connections(!(thisServer.bootopt & (BOOT_DEBUG | BOOT_TTY | BOOT_CHKCONF)));
+
   event_init(MAXCONNECTIONS);
 
   setup_signals();
   feature_init(); /* initialize features... */
   log_init(*argv);
-  if (check_pid()) {
-    Debug((DEBUG_FATAL, "Failed to acquire PID file lock after fork"));
-    exit(2);
-  }
   set_nomem_handler(outofmemory);
-  
+
   if (!init_string()) {
     log_write(LS_SYSTEM, L_CRIT, 0, "Failed to initialize string module");
     return 6;
@@ -602,6 +665,10 @@ int main(int argc, char **argv) {
 
   init_resolver();
 
+  /* we need this for now, when we're modular this 
+     should be removed -- hikari */
+  ircd_crypt_init();
+
   motd_init();
 
   if (!init_conf()) {
@@ -610,13 +677,28 @@ int main(int argc, char **argv) {
     return 7;
   }
 
+  if(thisServer.bootopt & BOOT_CHKCONF) {
+    fprintf(stderr, "Configuration file checked okay.\n");
+    return 0;
+  }
+
+  debug_init(thisServer.bootopt & BOOT_TTY);
+  daemon_init(thisServer.bootopt & BOOT_TTY);
+  if (check_pid()) {
+    Debug((DEBUG_FATAL, "Failed to acquire PID file lock after fork"));
+    exit(2);
+  }
+
   init_server_identity();
 
   uping_init();
 
+  stats_init();
+
   IPcheck_init();
   timer_add(timer_init(&connect_timer), try_connections, 0, TT_RELATIVE, 1);
   timer_add(timer_init(&ping_timer), check_pings, 0, TT_RELATIVE, 1);
+  timer_add(timer_init(&destruct_event_timer), exec_expired_destruct_events, 0, TT_PERIODIC, 60);
 
   CurrentTime = time(NULL);