home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NNTP-1.000 / NNTP-1 / nntp.1.5.11t / server / serve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-31  |  10.0 KB  |  497 lines

  1. #ifndef lint
  2. static char    *sccsid = "@(#)$Header: serve.c,v 1.37 91/01/10 17:19:52 sob Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Main server routine
  7.  */
  8.  
  9. #include "common.h"
  10. #include <signal.h>
  11. #ifdef USG
  12. #include <sys/times.h>
  13. #else
  14. #include <sys/time.h>
  15. #endif
  16.  
  17. #ifdef LOG
  18. # ifndef USG
  19. #  include <sys/resource.h>
  20. # endif not USG
  21. #endif
  22.  
  23. #ifdef TIMERS_DONT_WORK
  24. #include "timer.h"
  25. #endif
  26.  
  27. extern    int    ahbs(), group(), help(), ihave();
  28. extern    int    list(), newgroups(), newnews(), nextlast(), post();
  29. extern    int    slave(), stat(), xhdr(), xthread();
  30.  
  31. extern int errno;
  32.  
  33. #ifdef AUTH
  34. extern    int    doauth();
  35. #endif AUTH
  36.  
  37. static struct cmdent {
  38.     char    *cmd_name;
  39.     int    authreq;    /* 0=none,1=userpass */
  40.     int    (*cmd_fctn)();
  41. } cmdtbl[] = {
  42. #ifdef AUTH
  43.     "authcap",    0,    doauth,
  44.     "authinfo",    0,    doauth,
  45.     "authsys",    0,    doauth,
  46. #endif AUTH
  47.     "article",    0,    ahbs,
  48.     "body",        0,    ahbs,
  49.     "group",    0,    group,
  50.     "head",        0,    ahbs,
  51.     "help",        0,    help,
  52.     "ihave",    1,    ihave,
  53.     "last",        0,    nextlast,
  54.     "list",        0,    list,
  55.     "newgroups",    0,    newgroups,
  56.     "newnews",    0,    newnews,
  57.     "next",        0,    nextlast,
  58.     "post",        1,    post,
  59.     "slave",    0,    slave,
  60.     "stat",        0,    ahbs,
  61. #ifdef XHDR
  62.     "xhdr",        0,    xhdr,
  63. #endif XHDR
  64. #ifdef XTHREAD
  65.     "xthread",    0,    xthread,
  66. #endif
  67. };
  68. #define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent))
  69.  
  70. #ifdef TIMEOUT
  71. static void timeout();
  72. #endif
  73. #ifdef LOGINCHECK
  74. static void logincheck();
  75. static int firstlogincheck;
  76. #endif
  77. #ifdef BATCHED_INPUT
  78. static void batchcheck();
  79. #endif
  80.  
  81. #ifdef TIMERS_DONT_WORK
  82. static struct timer timers[] = {
  83. #ifdef TIMEOUT
  84.     { timeout, 1, TIMEOUT, 0 },
  85. #endif
  86. #ifdef LOGINCHECK
  87.     { logincheck, 0, LOGINCHECK, 0 },
  88. #endif
  89. #ifdef BATCHCHECK
  90.     { batchcheck, 1, BATCHCHECK, 0 },
  91. #endif
  92. };
  93. #define NTIMERS_DONT_WORK (sizeof(timers) / sizeof(struct timer))
  94. #endif
  95.  
  96. static char *stats_init();
  97. #ifdef LOG
  98. static void stats_finish();
  99. #endif
  100.  
  101. #ifdef AUTH
  102. extern int    Needauth;
  103. extern char    User[];
  104. #endif AUTH
  105.  
  106. /*
  107.  * serve -- given a connection on stdin/stdout, serve
  108.  *    a client, executing commands until the client
  109.  *    says goodbye.
  110.  *
  111.  *    Parameters:    None.
  112.  *
  113.  *    Returns:    Exits.
  114.  *
  115.  *    Side effects:    Talks to client, does a lot of
  116.  *            stuff.
  117.  */
  118.  
  119. serve()
  120. {
  121.     char        line[NNTP_STRLEN];
  122.     char        host[MAXHOSTNAMELEN];
  123.     char        gdbuf[MAXBUFLEN];
  124.     char        **argp;
  125.     char        *timeptr, *cp;
  126.     int        argnum, i;
  127. #ifdef POSTER
  128.     struct passwd    *pp;
  129. #endif
  130. #ifdef LOG
  131.     grps_acsd = arts_acsd = 0;
  132. #endif
  133.  
  134.     /* Not all systems pass fd's 1 and 2 from inetd */
  135.  
  136.     (void) close(1);
  137.     (void) close(2);
  138.     (void) dup(0);
  139.     (void) dup(0);
  140.  
  141.     /* If we're ALONE, then we've already opened syslog */
  142.  
  143. #ifndef ALONE
  144. # ifdef SYSLOG
  145. #  ifdef BSD_42
  146.     openlog("nntpd", LOG_PID);
  147. #  else
  148.     openlog("nntpd", LOG_PID, SYSLOG);
  149. #  endif
  150. # endif
  151. #endif
  152.  
  153.     timeptr = stats_init();
  154.  
  155. #ifdef ALONE
  156. #ifndef USG
  157.     (void) signal(SIGCHLD, SIG_IGN);
  158. #endif not USG
  159. #endif
  160.  
  161.     /* Ignore SIGPIPE, since we'll see closed connections with read */
  162.  
  163.     (void) signal(SIGPIPE, SIG_IGN);
  164.  
  165.     /* Get permissions and see if we can talk to this client */
  166. #ifdef AUTH
  167.     Needauth = 1;
  168.     strcpy(User,"");
  169. #endif AUTH
  170.     host_access(&canread, &canpost, &canxfer, gdbuf);
  171.  
  172.     if (gethostname(host, sizeof(host)) < 0)
  173.         (void) strcpy(host, "Amnesiac");
  174.  
  175. #ifdef SETPROCTITLE
  176.     setproctitle("%s", hostname);
  177. #endif
  178.  
  179.     if (!canread && !canxfer) {
  180.         printf("%d %s NNTP server can't talk to you.  Goodbye.\r\n",
  181.             ERR_ACCESS, host);
  182.         (void) fflush(stdout);
  183.         (void) fclose(stdout);
  184. #ifdef SYSLOG
  185.         syslog(LOG_INFO, "%s refused connection", hostname);
  186. #endif
  187.         exit(1);
  188.     }
  189.  
  190. #ifdef LOGINCHECK
  191.     firstlogincheck = 1;
  192.     logincheck();
  193.     firstlogincheck = 0;
  194. #endif
  195.  
  196.     if ( !canpost && !canread && !space(MINFREE)) {
  197.         printf("%d %s NNTP server out of space. Try later.\r\n",
  198.             ERR_GOODBYE, host);
  199.         (void) fflush(stdout);
  200. #ifdef SYSLOG
  201.         syslog(LOG_INFO, "%s no space", hostname);
  202. #endif
  203.         exit(1);
  204.     }
  205.  
  206.     /* If we can talk, proceed with initialization */
  207.  
  208.     ngpermcount = get_nglist(&ngpermlist, gdbuf);
  209.  
  210. #ifdef POSTER
  211.     pp = getpwnam(POSTER);
  212.     if (pp != NULL) {
  213.         uid_poster = pp->pw_uid;
  214.         gid_poster = pp->pw_gid;
  215.         home_poster = pp->pw_dir;
  216.     } else
  217. #endif
  218.         uid_poster = gid_poster = 0;
  219.  
  220. #ifndef FASTFORK
  221.     num_groups = 0;
  222.     num_groups = read_groups();    /* Read in the active file */
  223. #else
  224.     signal(SIGALRM, SIG_IGN);    /* Children don't deal with */
  225.                     /* these things */
  226. #endif
  227.     /*
  228.      * num_groups may be zero if expire is running and the active
  229.      * file is locked. (Under System V with lockf, for example.)
  230.      * Or, something may be really screwed up....
  231.      */
  232.     if (num_groups == 0){ /* can't get a group list */
  233.         printf("%d %s NNTP server unavailable. Try later.\r\n",
  234.             ERR_FAULT, host);
  235.         (void) fflush(stdout);
  236. #ifdef SYSLOG
  237.         syslog(LOG_INFO, "%s no groups", hostname);
  238. #endif
  239.         exit(1);
  240.     }
  241.  
  242.     art_fp = NULL;
  243.     argp = (char **) NULL;        /* for first time */
  244.  
  245.     if ((cp = index(timeptr, '\n')) != NULL)
  246.         *cp = '\0';
  247.     else
  248.         timeptr = "Unknown date";
  249. #ifdef AUTH
  250.     printf("%d %s NNTP[auth] server version %s ready at %s (%s).\r\n",
  251. #else
  252.     printf("%d %s NNTP server version %s ready at %s (%s).\r\n",
  253. #endif
  254.         canpost ? OK_CANPOST : OK_NOPOST,
  255.         host, nntp_version,
  256.         timeptr,
  257.         canpost ? "posting ok" : "no posting");
  258.     (void) fflush(stdout);
  259.  
  260.     /*
  261.      * Now get commands one at a time and execute the
  262.      * appropriate routine to deal with them.
  263.      */
  264. #ifdef TIMERS_DONT_WORK
  265.     timer_init(timers, NTIMERS_DONT_WORK);
  266. #endif
  267.     for (;;) {
  268. #ifdef TIMERS_DONT_WORK
  269.         /* Don't try to read input unless there is some */
  270.         if (!timer_sleep(timers, NTIMERS_DONT_WORK))
  271.             continue;
  272. #endif
  273.         if (fgets(line, sizeof(line), stdin) == NULL)
  274.             break;
  275.         /* Strip trailing CR-LF */
  276.         cp = line + strlen(line) - 1;
  277.         while (cp >= line && (*cp == '\n' || *cp == '\r'))
  278.             *cp-- = '\0';
  279. #ifdef DEBUG
  280.         if (debug)
  281.             syslog(LOG_DEBUG, "<- \"%s\"", line);
  282. #endif
  283.  
  284.         /* Null command */
  285.         if ((argnum = parsit(line, &argp)) == 0)
  286.             continue;
  287.  
  288.         /* a motion to adjourn is always in order */
  289.         if (!strcasecmp(argp[0], "quit"))
  290.             break;
  291.  
  292.         for (i = 0; i < NUMCMDS; ++i)
  293.             if (!strcasecmp(cmdtbl[i].cmd_name, argp[0]))
  294.                 break;
  295.  
  296.         if (i < NUMCMDS) {
  297. #ifdef SETPROCTITLE
  298.             setproctitle("%s %s", hostname, argp[0]);
  299. #endif
  300. #ifdef AUTH
  301.             /* authentication required? */
  302.             if (cmdtbl[i].authreq == 1 && Needauth)
  303.                 {
  304. printf("%d Authentication required for command\r\n", ERR_NOAUTH);
  305.                 (void) fflush(stdout);
  306.                 continue;
  307.                 }
  308. #endif AUTH
  309.             (*cmdtbl[i].cmd_fctn)(argnum, argp);
  310.         } else {
  311. #ifdef SYSLOG
  312.             syslog(LOG_INFO, "%s unrecognized %s", hostname, line);
  313. #endif
  314.             printf("%d Command unrecognized.\r\n", ERR_COMMAND);
  315.             (void) fflush(stdout);
  316.         }
  317.     }
  318.  
  319.     printf("%d %s closing connection.  Goodbye.\r\n", OK_GOODBYE, host);
  320.  
  321.     (void) fflush(stdout);
  322.  
  323. #ifdef BATCHED_INPUT
  324.     batchcheck();
  325. #endif
  326.  
  327. #ifdef SYSLOG
  328.     if (ferror(stdout))
  329.         syslog(LOG_ERR, "%s disconnect: %m", hostname);
  330. #ifdef LOG
  331.     stats_finish();
  332. #endif
  333. #endif
  334.  
  335. #ifdef PROFILE
  336.     profile();
  337. #endif
  338.     exit(0);
  339. }
  340.  
  341. #ifdef TIMEOUT
  342. /*
  343.  * Called after TIMEOUT seconds of idle time to shut things down.
  344.  * XXX stats are not reported when this occurs
  345.  */
  346. static void
  347. timeout()
  348. {
  349.  
  350.     printf("%d Timeout after %d seconds, closing connection.\r\n",
  351.         ERR_FAULT, TIMEOUT);
  352. #ifdef SYSLOG
  353.     syslog(LOG_NOTICE, "%s timeout", hostname);
  354. #endif
  355.     (void) fflush(stdout);
  356. #ifdef BATCHED_INPUT
  357.     batchcheck();
  358. #endif
  359. #ifdef LOG
  360.     stats_finish();
  361. #endif
  362. #ifdef PROFILE
  363.     profile();
  364. #endif
  365.     exit(1);
  366. }
  367. #endif
  368.  
  369. #ifdef LOGINCHECK
  370. /*
  371.  * Called ever LOGINCHECK seconds to see if logins have been disabled.
  372.  * If so, shut down.
  373.  * XXX stats are not reported when this occurs
  374.  */
  375. static void
  376. logincheck()
  377. {
  378.     char host[MAXHOSTNAMELEN];
  379.  
  380.     if (access(NOLOGIN, F_OK) < 0)
  381.         return;
  382.     if (gethostname(host, sizeof(host)) < 0)
  383.         (void) strcpy(host, "Amnesiac");
  384.     printf("%d Logins are disabled on NNTP server %s. Try again later.\r\n",
  385.         ERR_ACCESS, host);
  386.     (void) fflush(stdout);
  387. #ifdef SYSLOG
  388.     syslog(LOG_INFO, "%s logins disabled%s",
  389.         hostname, firstlogincheck ? "" : " (kicked out)");
  390. #endif
  391. #ifdef BATCHED_INPUT
  392.     batchcheck();
  393. #endif
  394. #ifdef LOG
  395.     stats_finish();
  396. #endif
  397. #ifdef PROFILE
  398.     profile();
  399. #endif
  400.     exit(1);
  401. }
  402. #endif
  403.  
  404. #ifdef BATCHED_INPUT
  405. /*
  406.  * Called after BATCHCHECK seconds of idle time and at the end
  407.  * of a session to see if a batch needs to be launched.
  408.  */
  409. static void
  410. batchcheck()
  411. {
  412.     char errbuf[2 * NNTP_STRLEN];
  413.  
  414.     enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf);
  415. }
  416. #endif
  417.  
  418. /*
  419.  * Stats stuff
  420.  */
  421. static double        Tstart, Tfinish;
  422. static double        user, sys;
  423. #ifdef USG
  424. static time_t        start, finish;
  425. #else /* not USG */
  426. static struct timeval    start, finish;
  427. #endif /* not USG */
  428.  
  429. static char *
  430. stats_init()
  431. {
  432.     extern char    *ctime();
  433.  
  434. #ifdef USG
  435.     (void) time(&start);
  436.     Tstart = (double) start;
  437.     return(ctime(&start));
  438. #else /* not USG */
  439.     (void) gettimeofday(&start, (struct timezone *)NULL);
  440.     Tstart = (double) start.tv_sec + ((double)start.tv_usec)/1000000.0;
  441.     return(ctime(&start.tv_sec));
  442. #endif /* not USG */
  443. }
  444.  
  445. #ifdef LOG
  446. static void
  447. stats_finish()
  448. {
  449.     char        buf[NNTP_STRLEN];
  450. # ifdef USG
  451.     struct tms    cpu;
  452. # else /* not USG */
  453.     struct rusage    me, kids;
  454. # endif /* not USG */
  455.  
  456. #ifdef USG
  457.     (void) time(&finish);
  458.     Tfinish = (double) finish;
  459.  
  460. #ifndef HZ
  461. #define    HZ    60.0    /* typical system clock ticks - param.h */
  462. #endif /* not HZ */
  463.  
  464.     (void) times(&cpu);
  465.     user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
  466.     sys  = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
  467. #else /* not USG */
  468.     (void) gettimeofday(&finish, (struct timezone *)NULL);
  469.     Tfinish = (double) finish.tv_sec + ((double)finish.tv_usec)/1000000.0;
  470.  
  471.     (void) getrusage(RUSAGE_SELF, &me);
  472.     (void) getrusage(RUSAGE_CHILDREN, &kids);
  473.  
  474.     user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 +
  475.         kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0;
  476.     sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 +
  477.         kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0;
  478. #endif /* not USG */
  479.     if (grps_acsd)
  480.         syslog(LOG_INFO, "%s exit %d articles %d groups",
  481.             hostname, arts_acsd, grps_acsd);
  482.     if (nn_told)
  483.         syslog(LOG_INFO, "%s newnews_stats told %d took %d",
  484.             hostname, nn_told, nn_took);
  485.     if (ih_accepted || ih_rejected || ih_failed)
  486.         syslog(LOG_INFO,
  487.             "%s ihave_stats accepted %d rejected %d failed %d",
  488.             hostname,
  489.             ih_accepted,
  490.             ih_rejected,
  491.             ih_failed);
  492.     (void) sprintf(buf, "user %.3f system %.3f elapsed %.3f",
  493.         user, sys, Tfinish - Tstart);
  494.     syslog(LOG_INFO, "%s times %s", hostname, buf);
  495. }
  496. #endif LOG
  497.