home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / other / irc / ircd / ircd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-14  |  20.2 KB  |  830 lines

  1. /************************************************************************
  2.  *   IRC - Internet Relay Chat, ircd/ircd.c
  3.  *   Copyright (C) 1990 Jarkko Oikarinen and
  4.  *                      University of Oulu, Computing Center
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 1, or (at your option)
  9.  *   any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #ifndef lint
  22. static    char sccsid[] = "@(#)ircd.c    2.48 3/9/94 (C) 1988 University of Oulu, \
  23. Computing Center and Jarkko Oikarinen";
  24. #endif
  25.  
  26. #include "struct.h"
  27. #include "common.h"
  28. #include "sys.h"
  29. #include "numeric.h"
  30. #include <sys/file.h>
  31. #include <sys/stat.h>
  32. #include <pwd.h>
  33. #include <signal.h>
  34. #include <fcntl.h>
  35. #include "h.h"
  36.  
  37. aClient me;            /* That's me */
  38. aClient *client = &me;        /* Pointer to beginning of Client list */
  39.  
  40. void    server_reboot();
  41. void    restart PROTO((char *));
  42. static    void    open_debugfile(), setup_signals();
  43.  
  44. char    **myargv;
  45. int    portnum = -1;            /* Server port number, listening this */
  46. char    *configfile = CONFIGFILE;    /* Server configuration file */
  47. int    debuglevel = -1;        /* Server debug level */
  48. int    bootopt = 0;            /* Server boot option flags */
  49. char    *debugmode = "";        /*  -"-    -"-   -"-  */
  50. char    *sbrk0;                /* initial sbrk(0) */
  51. static    int    dorehash = 0;
  52. static    char    *dpath = DPATH;
  53.  
  54. time_t    nextconnect = 1;    /* time for next try_connections call */
  55. time_t    nextping = 1;        /* same as above for check_pings() */
  56. time_t    nextdnscheck = 0;    /* next time to poll dns to force timeouts */
  57. time_t    nextexpire = 1;    /* next expire run on the dns cache */
  58.  
  59. #ifdef    PROFIL
  60. extern    etext();
  61.  
  62. VOIDSIG    s_monitor()
  63. {
  64.     static    int    mon = 0;
  65. #ifdef    POSIX_SIGNALS
  66.     struct    sigaction act;
  67. #endif
  68.  
  69.     (void)moncontrol(mon);
  70.     mon = 1 - mon;
  71. #ifdef    POSIX_SIGNALS
  72.     act.sa_handler = s_rehash;
  73.     act.sa_flags = 0;
  74.     (void)sigemptyset(&act.sa_mask);
  75.     (void)sigaddset(&act.sa_mask, SIGUSR1);
  76.     (void)sigaction(SIGUSR1, &act, NULL);
  77. #else
  78.     (void)signal(SIGUSR1, s_monitor);
  79. #endif
  80. }
  81. #endif
  82.  
  83. VOIDSIG s_die()
  84. {
  85. #ifdef    USE_SYSLOG
  86.     (void)syslog(LOG_CRIT, "Server Killed By SIGTERM");
  87. #endif
  88.     flush_connections(me.fd);
  89.     exit(-1);
  90. }
  91.  
  92. static VOIDSIG s_rehash()
  93. {
  94. #ifdef    POSIX_SIGNALS
  95.     struct    sigaction act;
  96. #endif
  97.     dorehash = 1;
  98. #ifdef    POSIX_SIGNALS
  99.     act.sa_handler = s_rehash;
  100.     act.sa_flags = 0;
  101.     (void)sigemptyset(&act.sa_mask);
  102.     (void)sigaddset(&act.sa_mask, SIGHUP);
  103.     (void)sigaction(SIGHUP, &act, NULL);
  104. #else
  105.     (void)signal(SIGHUP, s_rehash);    /* sysV -argv */
  106. #endif
  107. }
  108.  
  109. void    restart(mesg)
  110. char    *mesg;
  111. {
  112. #ifdef    USE_SYSLOG
  113.     (void)syslog(LOG_WARNING, "Restarting Server because: %s",mesg);
  114. #endif
  115.     server_reboot();
  116. }
  117.  
  118. VOIDSIG s_restart()
  119. {
  120.     static int restarting = 0;
  121.  
  122. #ifdef    USE_SYSLOG
  123.     (void)syslog(LOG_WARNING, "Server Restarting on SIGINT");
  124. #endif
  125.     if (restarting == 0)
  126.         {
  127.         /* Send (or attempt to) a dying scream to oper if present */
  128.  
  129.         restarting = 1;
  130.         server_reboot();
  131.         }
  132. }
  133.  
  134. void    server_reboot()
  135. {
  136.     Reg1    int    i;
  137.  
  138.     sendto_ops("Aieeeee!!!  Restarting server...");
  139.     Debug((DEBUG_NOTICE,"Restarting server..."));
  140.     flush_connections(me.fd);
  141.     /*
  142.     ** fd 0 must be 'preserved' if either the -d or -i options have
  143.     ** been passed to us before restarting.
  144.     */
  145. #ifdef USE_SYSLOG
  146.     (void)closelog();
  147. #endif
  148.     for (i = 3; i < MAXCONNECTIONS; i++)
  149.         (void)close(i);
  150.     if (!(bootopt & (BOOT_TTY|BOOT_DEBUG)))
  151.         (void)close(2);
  152.     (void)close(1);
  153.     if ((bootopt & BOOT_CONSOLE) || isatty(0))
  154.         (void)close(0);
  155.     if (!(bootopt & (BOOT_INETD|BOOT_OPER)))
  156.         (void)execv(MYNAME, myargv);
  157. #ifdef USE_SYSLOG
  158.     /* Have to reopen since it has been closed above */
  159.  
  160.     openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
  161.     syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", MYNAME, myargv[0]);
  162.     closelog();
  163. #endif
  164.     Debug((DEBUG_FATAL,"Couldn't restart server: %s", strerror(errno)));
  165.     exit(-1);
  166. }
  167.  
  168.  
  169. /*
  170. ** try_connections
  171. **
  172. **    Scan through configuration and try new connections.
  173. **    Returns the calendar time when the next call to this
  174. **    function should be made latest. (No harm done if this
  175. **    is called earlier or later...)
  176. */
  177. static    time_t    try_connections(currenttime)
  178. time_t    currenttime;
  179. {
  180.     Reg1    aConfItem *aconf;
  181.     Reg2    aClient *cptr;
  182.     aConfItem **pconf;
  183.     int    connecting, confrq;
  184.     time_t    next = 0;
  185.     aClass    *cltmp;
  186.     aConfItem *con_conf;
  187.     int    con_class = 0;
  188.  
  189.     connecting = FALSE;
  190.     Debug((DEBUG_NOTICE,"Connection check at   : %s",
  191.         myctime(currenttime)));
  192.     for (aconf = conf; aconf; aconf = aconf->next )
  193.         {
  194.         /* Also when already connecting! (update holdtimes) --SRB */
  195.         if (!(aconf->status & CONF_CONNECT_SERVER) || aconf->port <= 0)
  196.             continue;
  197.         cltmp = Class(aconf);
  198.         /*
  199.         ** Skip this entry if the use of it is still on hold until
  200.         ** future. Otherwise handle this entry (and set it on hold
  201.         ** until next time). Will reset only hold times, if already
  202.         ** made one successfull connection... [this algorithm is
  203.         ** a bit fuzzy... -- msa >;) ]
  204.         */
  205.  
  206.         if ((aconf->hold > currenttime))
  207.             {
  208.             if ((next > aconf->hold) || (next == 0))
  209.                 next = aconf->hold;
  210.             continue;
  211.             }
  212.  
  213.         confrq = get_con_freq(cltmp);
  214.         aconf->hold = currenttime + confrq;
  215.         /*
  216.         ** Found a CONNECT config with port specified, scan clients
  217.         ** and see if this server is already connected?
  218.         */
  219.         cptr = find_name(aconf->name, (aClient *)NULL);
  220.  
  221.         if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) &&
  222.             (!connecting || (Class(cltmp) > con_class)))
  223.             {
  224.             con_class = Class(cltmp);
  225.             con_conf = aconf;
  226.             /* We connect only one at time... */
  227.             connecting = TRUE;
  228.             }
  229.         if ((next > aconf->hold) || (next == 0))
  230.             next = aconf->hold;
  231.         }
  232.     if (connecting)
  233.         {
  234.         if (con_conf->next)  /* are we already last? */
  235.             {
  236.             for (pconf = &conf; (aconf = *pconf);
  237.                  pconf = &(aconf->next))
  238.                 /* put the current one at the end and
  239.                  * make sure we try all connections
  240.                  */
  241.                 if (aconf == con_conf)
  242.                     *pconf = aconf->next;
  243.             (*pconf = con_conf)->next = 0;
  244.             }
  245.         if (connect_server(con_conf, (aClient *)NULL,
  246.                    (struct hostent *)NULL) == 0)
  247.             sendto_ops("Connection to %s[%s] activated.",
  248.                    con_conf->name, con_conf->host);
  249.         }
  250.     Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next)));
  251.     return (next);
  252. }
  253.  
  254. static    time_t    check_pings(currenttime)
  255. time_t    currenttime;
  256. {
  257.     Reg1    aClient    *cptr;
  258.     Reg2    int    killflag;
  259.     int    ping = 0, i, rflag = 0;
  260.     time_t    oldest = 0, timeout;
  261.  
  262.     for (i = 0; i <= highest_fd; i++)
  263.         {
  264.         if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr))
  265.             continue;
  266.  
  267.         /*
  268.         ** Note: No need to notify opers here. It's
  269.         ** already done when "FLAGS_DEADSOCKET" is set.
  270.         */
  271.         if (cptr->flags & FLAGS_DEADSOCKET)
  272.             {
  273.             (void)exit_client(cptr, cptr, &me, "Dead socket");
  274.             continue;
  275.             }
  276.  
  277.         killflag = IsPerson(cptr) ? find_kill(cptr) : 0;
  278. #ifdef R_LINES_OFTEN
  279.         rflag = IsPerson(cptr) ? find_restrict(cptr) : 0;
  280. #endif
  281.         ping = IsRegistered(cptr) ? get_client_ping(cptr) :
  282.                         CONNECTTIMEOUT;
  283.         Debug((DEBUG_DEBUG, "c(%s)=%d p %d k %d r %d a %d",
  284.             cptr->name, cptr->status, ping, killflag, rflag,
  285.             currenttime - cptr->lasttime));
  286.         /*
  287.          * Ok, so goto's are ugly and can be avoided here but this code
  288.          * is already indented enough so I think its justified. -avalon
  289.          */
  290.         if (!killflag && !rflag && IsRegistered(cptr) &&
  291.             (ping >= currenttime - cptr->lasttime))
  292.             goto ping_timeout;
  293.         /*
  294.          * If the server hasnt talked to us in 2*ping seconds
  295.          * and it has a ping time, then close its connection.
  296.          * If the client is a user and a KILL line was found
  297.          * to be active, close this connection too.
  298.          */
  299.         if (killflag || rflag ||
  300.             ((currenttime - cptr->lasttime) >= (2 * ping) &&
  301.              (cptr->flags & FLAGS_PINGSENT)) ||
  302.             (!IsRegistered(cptr) &&
  303.              (currenttime - cptr->firsttime) >= ping))
  304.             {
  305.             if (!IsRegistered(cptr) &&
  306.                 (DoingDNS(cptr) || DoingAuth(cptr)))
  307.                 {
  308.                 if (cptr->authfd >= 0)
  309.                     {
  310.                     (void)close(cptr->authfd);
  311.                     cptr->authfd = -1;
  312.                     cptr->count = 0;
  313.                     *cptr->buffer = '\0';
  314.                     }
  315.                 Debug((DEBUG_NOTICE,
  316.                     "DNS/AUTH timeout %s",
  317.                     get_client_name(cptr,TRUE)));
  318.                 del_queries((char *)cptr);
  319.                 ClearAuth(cptr);
  320.                 ClearDNS(cptr);
  321.                 SetAccess(cptr);
  322.                 cptr->firsttime = currenttime;
  323.                 cptr->lasttime = currenttime;
  324.                 continue;
  325.                 }
  326.             if (IsServer(cptr) || IsConnecting(cptr) ||
  327.                 IsHandshake(cptr))
  328.                 sendto_ops("No response from %s, closing link",
  329.                        get_client_name(cptr, FALSE));
  330.             /*
  331.              * this is used for KILL lines with time restrictions
  332.              * on them - send a messgae to the user being killed
  333.              * first.
  334.              */
  335.             if (killflag && IsPerson(cptr))
  336.                 sendto_ops("Kill line active for %s",
  337.                        get_client_name(cptr, FALSE));
  338.  
  339. #if defined(R_LINES) && defined(R_LINES_OFTEN)
  340.             if (IsPerson(cptr) && rflag)
  341.                 sendto_ops("Restricting %s, closing link.",
  342.                        get_client_name(cptr,FALSE));
  343. #endif
  344.             (void)exit_client(cptr, cptr, &me, "Ping timeout");
  345.             continue;
  346.             }
  347.         else if (IsRegistered(cptr) &&
  348.              (cptr->flags & FLAGS_PINGSENT) == 0)
  349.             {
  350.             /*
  351.              * if we havent PINGed the connection and we havent
  352.              * heard from it in a while, PING it to make sure
  353.              * it is still alive.
  354.              */
  355.             cptr->flags |= FLAGS_PINGSENT;
  356.             /* not nice but does the job */
  357.             cptr->lasttime = currenttime - ping;
  358.             sendto_one(cptr, "PING :%s", me.name);
  359.             }
  360. ping_timeout:
  361.         timeout = cptr->lasttime + ping;
  362.         while (timeout <= currenttime)
  363.             timeout += ping;
  364.         if (timeout < oldest || !oldest)
  365.             oldest = timeout;
  366.         }
  367.     if (!oldest || oldest < currenttime)
  368.         oldest = currenttime + PINGFREQUENCY;
  369.     Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
  370.         myctime(oldest), ping, oldest, currenttime));
  371.  
  372.     return (oldest);
  373. }
  374.  
  375. /*
  376. ** bad_command
  377. **    This is called when the commandline is not acceptable.
  378. **    Give error message and exit without starting anything.
  379. */
  380. static    int    bad_command()
  381. {
  382.   (void)printf(
  383.      "Usage: ircd %s[-h servername] [-p portnumber] [-x loglevel] [-t]\n",
  384. #ifdef CMDLINE_CONFIG
  385.      "[-f config] "
  386. #else
  387.      ""
  388. #endif
  389.      );
  390.   (void)printf("Server not started\n\n");
  391.   return (-1);
  392. }
  393.  
  394. int    main(argc, argv)
  395. int    argc;
  396. char    *argv[];
  397. {
  398.     int    portarg = 0;
  399.     uid_t    uid, euid;
  400.     time_t    delay = 0, now;
  401.  
  402.     sbrk0 = (char *)sbrk((size_t)0);
  403.     uid = getuid();
  404.     euid = geteuid();
  405. #ifdef    PROFIL
  406.     (void)monstartup(0, etext);
  407.     (void)moncontrol(1);
  408.     (void)signal(SIGUSR1, s_monitor);
  409. #endif
  410.  
  411. #ifdef    CHROOTDIR
  412.     if (chdir(dpath))
  413.         {
  414.         perror("chdir");
  415.         exit(-1);
  416.         }
  417.     res_init();
  418.     if (chroot(DPATH))
  419.       {
  420.         (void)fprintf(stderr,"ERROR:  Cannot chdir/chroot\n");
  421.         exit(5);
  422.       }
  423. #endif /*CHROOTDIR*/
  424.  
  425.     myargv = argv;
  426.     (void)umask(077);                /* better safe than sorry --SRB */
  427.     bzero((char *)&me, sizeof(me));
  428.  
  429.     setup_signals();
  430.  
  431.     /*
  432.     ** All command line parameters have the syntax "-fstring"
  433.     ** or "-f string" (e.g. the space is optional). String may
  434.     ** be empty. Flag characters cannot be concatenated (like
  435.     ** "-fxyz"), it would conflict with the form "-fstring".
  436.     */
  437.     while (--argc > 0 && (*++argv)[0] == '-')
  438.         {
  439.         char    *p = argv[0]+1;
  440.         int    flag = *p++;
  441.  
  442.         if (flag == '\0' || *p == '\0')
  443.             if (argc > 1 && argv[1][0] != '-')
  444.                 {
  445.                 p = *++argv;
  446.                 argc -= 1;
  447.                 }
  448.             else
  449.                 p = "";
  450.  
  451.         switch (flag)
  452.             {
  453.                     case 'a':
  454.             bootopt |= BOOT_AUTODIE;
  455.             break;
  456.             case 'c':
  457.             bootopt |= BOOT_CONSOLE;
  458.             break;
  459.             case 'q':
  460.             bootopt |= BOOT_QUICK;
  461.             break;
  462.             case 'd' :
  463.                         (void)setuid((uid_t)uid);
  464.             dpath = p;
  465.             break;
  466.             case 'o': /* Per user local daemon... */
  467.                         (void)setuid((uid_t)uid);
  468.             bootopt |= BOOT_OPER;
  469.                 break;
  470. #ifdef CMDLINE_CONFIG
  471.             case 'f':
  472.                         (void)setuid((uid_t)uid);
  473.             configfile = p;
  474.             break;
  475. #endif
  476.             case 'h':
  477.             strncpyzt(me.name, p, sizeof(me.name));
  478.             break;
  479.             case 'i':
  480.             bootopt |= BOOT_INETD|BOOT_AUTODIE;
  481.                 break;
  482.             case 'p':
  483.             if ((portarg = atoi(p)) > 0 )
  484.                 portnum = portarg;
  485.             break;
  486.             case 't':
  487.                         (void)setuid((uid_t)uid);
  488.             bootopt |= BOOT_TTY;
  489.             break;
  490.             case 'v':
  491.             (void)printf("ircd %s\n", version);
  492.             exit(0);
  493.             case 'x':
  494. #ifdef    DEBUGMODE
  495.                         (void)setuid((uid_t)uid);
  496.             debuglevel = atoi(p);
  497.             debugmode = *p ? p : "0";
  498.             bootopt |= BOOT_DEBUG;
  499.             break;
  500. #else
  501.             (void)fprintf(stderr,
  502.                 "%s: DEBUGMODE must be defined for -x y\n",
  503.                 myargv[0]);
  504.             exit(0);
  505. #endif
  506.             default:
  507.             bad_command();
  508.             break;
  509.             }
  510.         }
  511.  
  512. #ifndef    CHROOT
  513.     if (chdir(dpath))
  514.         {
  515.         perror("chdir");
  516.         exit(-1);
  517.         }
  518. #endif
  519.  
  520. #ifndef IRC_UID
  521.     if ((uid != euid) && !euid)
  522.         {
  523.         (void)fprintf(stderr,
  524.             "ERROR: do not run ircd setuid root. Make it setuid a\
  525.  normal user.\n");
  526.         exit(-1);
  527.         }
  528. #endif
  529.  
  530. #if !defined(CHROOTDIR) || (defined(IRC_UID) && defined(IRC_GID))
  531. # ifndef    AIX
  532.     (void)setuid((uid_t)euid);
  533. # endif
  534.  
  535.     if ((int)getuid() == 0)
  536.         {
  537. # if defined(IRC_UID) && defined(IRC_GID)
  538.  
  539.         /* run as a specified user */
  540.         (void)fprintf(stderr,"WARNING: running ircd with uid = %d\n",
  541.             IRC_UID);
  542.         (void)fprintf(stderr,"         changing to gid %d.\n",IRC_GID);
  543.         (void)setuid(IRC_UID);
  544.         (void)setgid(IRC_GID);
  545. #else
  546.         /* check for setuid root as usual */
  547.         (void)fprintf(stderr,
  548.             "ERROR: do not run ircd setuid root. Make it setuid a\
  549.  normal user.\n");
  550.         exit(-1);
  551. # endif    
  552.         } 
  553. #endif /*CHROOTDIR/UID/GID*/
  554.  
  555.     /* didn't set debuglevel */
  556.     /* but asked for debugging output to tty */
  557.     if ((debuglevel < 0) &&  (bootopt & BOOT_TTY))
  558.         {
  559.         (void)fprintf(stderr,
  560.             "you specified -t without -x. use -x <n>\n");
  561.         exit(-1);
  562.         }
  563.  
  564.     if (argc > 0)
  565.         return bad_command(); /* This should exit out */
  566.  
  567.     clear_client_hash_table();
  568.     clear_channel_hash_table();
  569.     initlists();
  570.     initclass();
  571.     initwhowas();
  572.     initstats();
  573.     open_debugfile();
  574.     if (portnum < 0)
  575.         portnum = PORTNUM;
  576.     me.port = portnum;
  577.     (void)init_sys();
  578.     me.flags = FLAGS_LISTEN;
  579.     if (bootopt & BOOT_INETD)
  580.         {
  581.         me.fd = 0;
  582.         local[0] = &me;
  583.         me.flags = FLAGS_LISTEN;
  584.         }
  585.     else
  586.         me.fd = -1;
  587.  
  588. #ifdef USE_SYSLOG
  589.     openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
  590. #endif
  591.     if (initconf(bootopt) == -1)
  592.         {
  593.         Debug((DEBUG_FATAL, "Failed in reading configuration file %s",
  594.             configfile));
  595.         (void)printf("Couldn't open configuration file %s\n",
  596.             configfile);
  597.         exit(-1);
  598.         }
  599.     if (!(bootopt & BOOT_INETD))
  600.         {
  601.         static    char    star[] = "*";
  602.         aConfItem    *aconf;
  603.  
  604.         if ((aconf = find_me()) && portarg <= 0 && aconf->port > 0)
  605.             portnum = aconf->port;
  606.         Debug((DEBUG_ERROR, "Port = %d", portnum));
  607.         if (inetport(&me, star, portnum))
  608.             exit(1);
  609.         }
  610.     else if (inetport(&me, "*", 0))
  611.         exit(1);
  612.  
  613.     (void)setup_ping();
  614.     (void)get_my_name(&me, me.sockhost, sizeof(me.sockhost)-1);
  615.     if (me.name[0] == '\0')
  616.         strncpyzt(me.name, me.sockhost, sizeof(me.name));
  617.     me.hopcount = 0;
  618.     me.authfd = -1;
  619.     me.confs = NULL;
  620.     me.next = NULL;
  621.     me.user = NULL;
  622.     me.from = &me;
  623.     SetMe(&me);
  624.     make_server(&me);
  625.     (void)strcpy(me.serv->up, me.name);
  626.  
  627.     me.lasttime = me.since = me.firsttime = time(NULL);
  628.     (void)add_to_client_hash_table(me.name, &me);
  629.  
  630.     check_class();
  631.     if (bootopt & BOOT_OPER)
  632.         {
  633.         aClient *tmp = add_connection(&me, 0);
  634.  
  635.         if (!tmp)
  636.             exit(1);
  637.         SetMaster(tmp);
  638.         }
  639.     else
  640.         write_pidfile();
  641.  
  642.     Debug((DEBUG_NOTICE,"Server ready..."));
  643. #ifdef USE_SYSLOG
  644.     syslog(LOG_NOTICE, "Server Ready");
  645. #endif
  646.  
  647.     for (;;)
  648.         {
  649.         now = time(NULL);
  650.         /*
  651.         ** We only want to connect if a connection is due,
  652.         ** not every time through.  Note, if there are no
  653.         ** active C lines, this call to Tryconnections is
  654.         ** made once only; it will return 0. - avalon
  655.         */
  656.         if (nextconnect && now >= nextconnect)
  657.             nextconnect = try_connections(now);
  658.         /*
  659.         ** DNS checks. One to timeout queries, one for cache expiries.
  660.         */
  661.         if (now >= nextdnscheck)
  662.             nextdnscheck = timeout_query_list(now);
  663.         if (now >= nextexpire)
  664.             nextexpire = expire_cache(now);
  665.         /*
  666.         ** take the smaller of the two 'timed' event times as
  667.         ** the time of next event (stops us being late :) - avalon
  668.         ** WARNING - nextconnect can return 0!
  669.         */
  670.         if (nextconnect)
  671.             delay = MIN(nextping, nextconnect);
  672.         else
  673.             delay = nextping;
  674.         delay = MIN(nextdnscheck, delay);
  675.         delay = MIN(nextexpire, delay);
  676.         delay -= now;
  677.         /*
  678.         ** Adjust delay to something reasonable [ad hoc values]
  679.         ** (one might think something more clever here... --msa)
  680.         ** We don't really need to check that often and as long
  681.         ** as we don't delay too long, everything should be ok.
  682.         ** waiting too long can cause things to timeout...
  683.         ** i.e. PINGS -> a disconnection :(
  684.         ** - avalon
  685.         */
  686.         if (delay < 1)
  687.             delay = 1;
  688.         else
  689.             delay = MIN(delay, TIMESEC);
  690.         (void)read_message(delay);
  691.         
  692.         Debug((DEBUG_DEBUG ,"Got message(s)"));
  693.         
  694.         now = time(NULL);
  695.         /*
  696.         ** ...perhaps should not do these loops every time,
  697.         ** but only if there is some chance of something
  698.         ** happening (but, note that conf->hold times may
  699.         ** be changed elsewhere--so precomputed next event
  700.         ** time might be too far away... (similarly with
  701.         ** ping times) --msa
  702.         */
  703.         if (now >= nextping)
  704.             nextping = check_pings(now);
  705.  
  706.         if (dorehash)
  707.             {
  708.             (void)rehash(&me, &me, 1);
  709.             dorehash = 0;
  710.             }
  711.         /*
  712.         ** Flush output buffers on all connections now if they
  713.         ** have data in them (or at least try to flush)
  714.         ** -avalon
  715.         */
  716.         flush_connections(me.fd);
  717.         }
  718.     }
  719.  
  720. /*
  721.  * open_debugfile
  722.  *
  723.  * If the -t option is not given on the command line when the server is
  724.  * started, all debugging output is sent to the file set by LPATH in config.h
  725.  * Here we just open that file and make sure it is opened to fd 2 so that
  726.  * any fprintf's to stderr also goto the logfile.  If the debuglevel is not
  727.  * set from the command line by -x, use /dev/null as the dummy logfile as long
  728.  * as DEBUGMODE has been defined, else dont waste the fd.
  729.  */
  730. static    void    open_debugfile()
  731. {
  732. #ifdef    DEBUGMODE
  733.     int    fd;
  734.     aClient    *cptr;
  735.  
  736.     if (debuglevel >= 0)
  737.         {
  738.         cptr = make_client(NULL);
  739.         cptr->fd = 2;
  740.         SetLog(cptr);
  741.         cptr->port = debuglevel;
  742.         cptr->flags = 0;
  743.         cptr->acpt = cptr;
  744.         local[2] = cptr;
  745.         (void)strcpy(cptr->sockhost, me.sockhost);
  746.  
  747.         (void)printf("isatty = %d ttyname = %#x\n",
  748.             isatty(2), (u_int)ttyname(2));
  749.         if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd 2 */
  750.             {
  751.             (void)truncate(LOGFILE, 0);
  752.             if ((fd = open(LOGFILE, O_WRONLY | O_CREAT, 0600)) < 0) 
  753.                 if ((fd = open("/dev/null", O_WRONLY)) < 0)
  754.                     exit(-1);
  755.             if (fd != 2)
  756.                 {
  757.                 (void)dup2(fd, 2);
  758.                 (void)close(fd); 
  759.                 }
  760.             strncpyzt(cptr->name, LOGFILE, sizeof(cptr->name));
  761.             }
  762.         else if (isatty(2) && ttyname(2))
  763.             strncpyzt(cptr->name, ttyname(2), sizeof(cptr->name));
  764.         else
  765.             (void)strcpy(cptr->name, "FD2-Pipe");
  766.         Debug((DEBUG_FATAL, "Debug: File <%s> Level: %d at %s",
  767.             cptr->name, cptr->port, myctime(time(NULL))));
  768.         }
  769.     else
  770.         local[2] = NULL;
  771. #endif
  772.     return;
  773. }
  774.  
  775. static    void    setup_signals()
  776. {
  777. #ifdef    POSIX_SIGNALS
  778.     struct    sigaction act;
  779.  
  780.     act.sa_handler = SIG_IGN;
  781.     act.sa_flags = 0;
  782.     (void)sigemptyset(&act.sa_mask);
  783.     (void)sigaddset(&act.sa_mask, SIGPIPE);
  784.     (void)sigaddset(&act.sa_mask, SIGALRM);
  785. # ifdef    SIGWINCH
  786.     (void)sigaddset(&act.sa_mask, SIGWINCH);
  787.     (void)sigaction(SIGWINCH, &act, NULL);
  788. # endif
  789.     (void)sigaction(SIGPIPE, &act, NULL);
  790.     act.sa_handler = dummy;
  791.     (void)sigaction(SIGALRM, &act, NULL);
  792.     act.sa_handler = s_rehash;
  793.     (void)sigemptyset(&act.sa_mask);
  794.     (void)sigaddset(&act.sa_mask, SIGHUP);
  795.     (void)sigaction(SIGHUP, &act, NULL);
  796.     act.sa_handler = s_restart;
  797.     (void)sigaddset(&act.sa_mask, SIGINT);
  798.     (void)sigaction(SIGINT, &act, NULL);
  799.     act.sa_handler = s_die;
  800.     (void)sigaddset(&act.sa_mask, SIGTERM);
  801.     (void)sigaction(SIGTERM, &act, NULL);
  802.  
  803. #else
  804. # ifndef    HAVE_RELIABLE_SIGNALS
  805.     (void)signal(SIGPIPE, dummy);
  806. #  ifdef    SIGWINCH
  807.     (void)signal(SIGWINCH, dummy);
  808. #  endif
  809. # else
  810. #  ifdef    SIGWINCH
  811.     (void)signal(SIGWINCH, SIG_IGN);
  812. #  endif
  813.     (void)signal(SIGPIPE, SIG_IGN);
  814. # endif
  815.     (void)signal(SIGALRM, dummy);   
  816.     (void)signal(SIGHUP, s_rehash);
  817.     (void)signal(SIGTERM, s_die); 
  818.     (void)signal(SIGINT, s_restart);
  819. #endif
  820.  
  821. #ifdef RESTARTING_SYSTEMCALLS
  822.     /*
  823.     ** At least on Apollo sr10.1 it seems continuing system calls
  824.     ** after signal is the default. The following 'siginterrupt'
  825.     ** should change that default to interrupting calls.
  826.     */
  827.     (void)siginterrupt(SIGALRM, 1);
  828. #endif
  829. }
  830.