Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / ircd.c
index 27f6c8e5d10909ac94ff0f0209db608026355ca1..cfee4af807282c030b1719c438956a87ff32bdc7 100644 (file)
@@ -19,6 +19,8 @@
  *
  * $Id$
  */
+#include "config.h"
+
 #include "ircd.h"
 #include "IPcheck.h"
 #include "class.h"
@@ -26,6 +28,7 @@
 #include "crule.h"
 #include "hash.h"
 #include "ircd_alloc.h"
+#include "ircd_events.h"
 #include "ircd_features.h"
 #include "ircd_log.h"
 #include "ircd_reply.h"
@@ -62,6 +65,7 @@
 #include <string.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 
@@ -83,24 +87,26 @@ enum {
 /*----------------------------------------------------------------------------
  * Global data (YUCK!)
  *--------------------------------------------------------------------------*/
-struct Client  me;                      // That's me
-struct Connection me_con;              // That's me too
-struct Client *GlobalClientList  = &me; // Pointer to beginning of Client list
-time_t         TSoffset          = 0;   // Offset of timestamps to system clock
-int            GlobalRehashFlag  = 0;   // do a rehash if set
-int            GlobalRestartFlag = 0;   // do a restart if set
-time_t         CurrentTime;             // Updated every time we leave select()
-
-char          *configfile        = CPATH; // Server configuration file
-int            debuglevel        = -1;    // Server debug level 
-char          *debugmode         = "";    // Server debug level
+struct Client  me;                      /* That's me */
+struct Connection me_con;              /* That's me too */
+struct Client *GlobalClientList  = &me; /* Pointer to beginning of
+                                          Client list */
+time_t         TSoffset          = 0;/* Offset of timestamps to system clock */
+int            GlobalRehashFlag  = 0;   /* do a rehash if set */
+int            GlobalRestartFlag = 0;   /* do a restart if set */
+time_t         CurrentTime;          /* Updated every time we leave select() */
+
+char          *configfile        = CPATH; /* Server configuration file */
+int            debuglevel        = -1;    /* Server debug level  */
+char          *debugmode         = "";    /* Server debug level */
 static char   *dpath             = DPATH;
 
-time_t         nextconnect       = 1; // time for next try_connections call
-time_t         nextping          = 1; // same as above for check_pings()
+static struct Timer connect_timer; /* timer structure for try_connections() */
+static struct Timer ping_timer; /* timer structure for check_pings() */
 
-static struct Daemon thisServer  = { 0 };     // server process info 
+static struct Daemon thisServer  = { 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0 };
 
+int running = 1;
 
 
 /*----------------------------------------------------------------------------
@@ -111,7 +117,7 @@ void server_die(const char* message) {
   log_write(LS_SYSTEM, L_CRIT, 0, "Server terminating: %s", message);
   flush_connections(0);
   close_connections(1);
-  thisServer.running = 0;
+  running = 0;
 }
 
 
@@ -162,22 +168,45 @@ static void outofmemory(void) {
  * write_pidfile
  *--------------------------------------------------------------------------*/
 static void write_pidfile(void) {
-  FILE *pidf;
-
-  if (!(pidf = fopen(feature_str(FEAT_PPATH), "w+"))) {
-    Debug((DEBUG_NOTICE, 
-          "Error opening pid file \"%s\": %s", feature_str(FEAT_PPATH),
-          strerror(errno)));
+  char buff[20];
+
+  if (thisServer.pid_fd >= 0) {
+    memset(buff, 0, sizeof(buff));
+    sprintf(buff, "%5d\n", (int)getpid());
+    if (write(thisServer.pid_fd, buff, strlen(buff)) == -1)
+      Debug((DEBUG_NOTICE, "Error writing to pid file %s: %m",
+            feature_str(FEAT_PPATH)));
     return;
   }
-    
-  if (fprintf(pidf, "%5d\n", getpid()) < 5)
-    Debug((DEBUG_NOTICE, "Error writing to pid file %s",
-          feature_str(FEAT_PPATH)));
-
-  fclose(pidf);
+  Debug((DEBUG_NOTICE, "Error opening pid file %s: %m",
+        feature_str(FEAT_PPATH)));
 }
 
+/* check_pid
+ * 
+ * inputs: 
+ *   none
+ * returns:
+ *   true - if the pid file exists (and is readable), and the pid refered
+ *          to in the file is still running.
+ *   false - otherwise.
+ */
+static int check_pid(void)
+{
+  struct flock lock;
+
+  lock.l_type = F_WRLCK;
+  lock.l_start = 0;
+  lock.l_whence = SEEK_SET;
+  lock.l_len = 0;
+
+  if ((thisServer.pid_fd = open(feature_str(FEAT_PPATH), O_CREAT | O_RDWR,
+                               0600)) >= 0)
+    return fcntl(thisServer.pid_fd, F_SETLK, &lock);
+
+  return 0;
+}
+  
 
 /*----------------------------------------------------------------------------
  * try_connections
@@ -188,7 +217,7 @@ static void write_pidfile(void) {
  * function should be made latest. (No harm done if this
  * is called earlier or later...)
  *--------------------------------------------------------------------------*/
-static time_t try_connections(void) {
+static void try_connections(struct Event* ev) {
   struct ConfItem*  aconf;
   struct Client*    cptr;
   struct ConfItem** pconf;
@@ -200,6 +229,9 @@ static time_t try_connections(void) {
   struct Jupe*      ajupe;
   unsigned int      con_class   = 0;
 
+  assert(ET_EXPIRE == ev_type(ev));
+  assert(0 != ev_timer(ev));
+
   connecting = FALSE;
   Debug((DEBUG_NOTICE, "Connection check at   : %s", myctime(CurrentTime)));
   for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
@@ -259,8 +291,12 @@ static time_t try_connections(void) {
                           con_conf->name);
   }
 
+  if (next == 0)
+    next = CurrentTime + feature_int(FEAT_CONNECTFREQUENCY);
+
   Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next)));
-  return(next);
+
+  timer_add(&connect_timer, try_connections, 0, TT_ABSOLUTE, next);
 }
 
 
@@ -271,12 +307,15 @@ static time_t try_connections(void) {
  *       get right down to it.  Can't really be done until the server is more
  *       modular, however...
  *--------------------------------------------------------------------------*/
-static time_t check_pings(void) {
-  int expire     = 0; 
+static void check_pings(struct Event* ev) {
+  int expire     = 0;
   int next_check = CurrentTime;
   int max_ping   = 0;
   int i;
 
+  assert(ET_EXPIRE == ev_type(ev));
+  assert(0 != ev_timer(ev));
+
   next_check += feature_int(FEAT_PINGFREQUENCY);
   
   /* Scan through the client table */
@@ -299,7 +338,8 @@ static time_t check_pings(void) {
       feature_int(FEAT_CONNECTTIMEOUT);
    
     Debug((DEBUG_DEBUG, "check_pings(%s)=status:%s limit: %d current: %d",
-          cli_name(cptr), (cli_flags(cptr) & FLAGS_PINGSENT) ? "[Ping Sent]" : "[]", 
+          cli_name(cptr),
+          (cli_flags(cptr) & FLAGS_PINGSENT) ? "[Ping Sent]" : "[]", 
           max_ping, (int)(CurrentTime - cli_lasttime(cptr))));
           
 
@@ -318,7 +358,8 @@ static time_t check_pings(void) {
       /* 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));
+                            "No response from %s, closing link",
+                            cli_name(cptr));
       exit_client_msg(cptr, cptr, &me, "Ping timeout");
       continue;
     }
@@ -368,7 +409,7 @@ static time_t check_pings(void) {
   Debug((DEBUG_DEBUG, "[%i] check_pings() again in %is",
         CurrentTime, next_check-CurrentTime));
   
-  return next_check;
+  timer_add(&ping_timer, check_pings, 0, TT_ABSOLUTE, next_check);
 }
 
 
@@ -441,71 +482,6 @@ static void daemon_init(int no_fork) {
   setsid();
 }
 
-
-/*----------------------------------------------------------------------------
- * event_loop
- *--------------------------------------------------------------------------*/
-static void event_loop(void) {
-  time_t nextdnscheck = 0;
-  time_t delay        = 0;
-
-  thisServer.running = 1;
-  while (thisServer.running) {
-    /* We only want to connect if a connection is due, not every time through.
-     * Note, if there are no active C lines, this call to Tryconnections is
-     * made once only; it will return 0. - avalon
-     */
-    if (nextconnect && CurrentTime >= nextconnect)
-      nextconnect = try_connections();
-
-    /* DNS checks. One to timeout queries, one for cache expiries. */
-    nextdnscheck = timeout_resolver(CurrentTime);
-
-    /* Take the smaller of the two 'timed' event times as the time of next
-     * event (stops us being late :) - avalon
-     * WARNING - nextconnect can return 0!
-     */
-    if (nextconnect)
-      delay = IRCD_MIN(nextping, nextconnect);
-    else
-      delay = nextping;
-
-    delay = IRCD_MIN(nextdnscheck, delay) - CurrentTime;
-
-    /* Adjust delay to something reasonable [ad hoc values] (one might think
-     * something more clever here... --msa) We don't really need to check that
-     * often and as long as we don't delay too long, everything should be ok.
-     * waiting too long can cause things to timeout...  i.e. PINGS -> a
-     * disconnection :( - avalon
-     */
-    if (delay < 1)
-      read_message(1);
-    else
-      read_message(IRCD_MIN(delay, feature_int(FEAT_TIMESEC)));
-
-    /* ...perhaps should not do these loops every time, but only if there is
-     * some chance of something happening (but, note that conf->hold times may
-     * be changed elsewhere--so precomputed next event time might be too far
-     * away... (similarly with ping times) --msa
-     */
-    if (CurrentTime >= nextping)
-      nextping = check_pings();
-    
-    /* timeout pending queries that haven't been responded to */
-    timeout_auth_queries(CurrentTime);
-
-    IPcheck_expire();
-
-    if (GlobalRehashFlag) {
-      rehash(&me, 1);
-      GlobalRehashFlag = 0;
-    }
-
-    if (GlobalRestartFlag)
-      server_restart("caught signal: SIGINT");
-  }
-}
-
 /*----------------------------------------------------------------------------
  * check_file_access:  random helper function to make sure that a file is
  *                     accessible in a certain way, and complain if not.
@@ -645,11 +621,15 @@ int main(int argc, char **argv) {
 
   debug_init(thisServer.bootopt & BOOT_TTY);
   daemon_init(thisServer.bootopt & BOOT_TTY);
+  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()) {
@@ -679,9 +659,14 @@ int main(int argc, char **argv) {
 
   uping_init();
 
+  IPcheck_init();
+  timer_add(&connect_timer, try_connections, 0, TT_RELATIVE, 1);
+  timer_add(&ping_timer, check_pings, 0, TT_RELATIVE, 1);
+
   CurrentTime = time(NULL);
 
   SetMe(&me);
+  cli_magic(&me) = CLIENT_MAGIC;
   cli_from(&me) = &me;
   make_server(&me);