This is serve.c in view mode; [Download] [Up]
#ifndef lint static char *sccsid = "@(#)$Header: serve.c,v 1.37 91/01/10 17:19:52 sob Exp $"; #endif /* * Main server routine */ #include "common.h" #include <signal.h> #ifdef USG #include <sys/times.h> #else #include <sys/time.h> #endif #ifdef LOG # ifndef USG # include <sys/resource.h> # endif not USG #endif #ifdef TIMERS #include "timer.h" #endif extern int ahbs(), group(), help(), ihave(); extern int list(), newgroups(), newnews(), nextlast(), post(); extern int slave(), stat(), xhdr(); extern int errno; #ifdef AUTH extern int doauth(); #endif AUTH static struct cmdent { char *cmd_name; int authreq; /* 0=none,1=userpass */ int (*cmd_fctn)(); } cmdtbl[] = { #ifdef AUTH "authcap", 0, doauth, "authinfo", 0, doauth, "authsys", 0, doauth, #endif AUTH "article", 0, ahbs, "body", 0, ahbs, "group", 0, group, "head", 0, ahbs, "help", 0, help, "ihave", 1, ihave, "last", 0, nextlast, "list", 0, list, "newgroups", 0, newgroups, "newnews", 0, newnews, "next", 0, nextlast, "post", 1, post, "slave", 0, slave, "stat", 0, ahbs, #ifdef XHDR "xhdr", 0, xhdr, #endif XHDR }; #define NUMCMDS (sizeof(cmdtbl) / sizeof(struct cmdent)) #ifdef TIMEOUT static void timeout(); #endif #ifdef LOGINCHECK static void logincheck(); static int firstlogincheck; #endif #ifdef BATCHED_INPUT static void batchcheck(); #endif #ifdef TIMERS static struct timer timers[] = { #ifdef TIMEOUT { timeout, 1, TIMEOUT, 0 }, #endif #ifdef LOGINCHECK { logincheck, 0, LOGINCHECK, 0 }, #endif #ifdef BATCHCHECK { batchcheck, 1, BATCHCHECK, 0 }, #endif }; #define NTIMERS (sizeof(timers) / sizeof(struct timer)) #endif static char *stats_init(); #ifdef LOG static void stats_finish(); #endif #ifdef AUTH extern int Needauth; extern char User[]; #endif AUTH /* * serve -- given a connection on stdin/stdout, serve * a client, executing commands until the client * says goodbye. * * Parameters: None. * * Returns: Exits. * * Side effects: Talks to client, does a lot of * stuff. */ serve() { char line[NNTP_STRLEN]; char host[MAXHOSTNAMELEN]; char gdbuf[MAXBUFLEN]; char **argp; char *timeptr, *cp; int argnum, i; #ifdef POSTER struct passwd *pp; #endif #ifdef LOG grps_acsd = arts_acsd = 0; #endif /* Not all systems pass fd's 1 and 2 from inetd */ (void) close(1); (void) close(2); (void) dup(0); (void) dup(0); /* If we're ALONE, then we've already opened syslog */ #ifndef ALONE # ifdef SYSLOG # ifdef BSD_42 openlog("nntpd", LOG_PID); # else openlog("nntpd", LOG_PID, SYSLOG); # endif # endif #endif timeptr = stats_init(); #ifdef ALONE #ifndef USG (void) signal(SIGCHLD, SIG_IGN); #endif not USG #endif /* Ignore SIGPIPE, since we'll see closed connections with read */ (void) signal(SIGPIPE, SIG_IGN); /* Get permissions and see if we can talk to this client */ #ifdef AUTH Needauth = 1; strcpy(User,""); #endif AUTH host_access(&canread, &canpost, &canxfer, gdbuf); if (gethostname(host, sizeof(host)) < 0) (void) strcpy(host, "Amnesiac"); #ifdef SETPROCTITLE setproctitle("%s", hostname); #endif if (!canread && !canxfer) { printf("%d %s NNTP server can't talk to you. Goodbye.\r\n", ERR_ACCESS, host); (void) fflush(stdout); (void) fclose(stdout); #ifdef SYSLOG syslog(LOG_INFO, "%s refused connection", hostname); #endif exit(1); } #ifdef LOGINCHECK firstlogincheck = 1; logincheck(); firstlogincheck = 0; #endif if ( !canpost && !canread && !space(MINFREE)) { printf("%d %s NNTP server out of space. Try later.\r\n", ERR_GOODBYE, host); (void) fflush(stdout); #ifdef SYSLOG syslog(LOG_INFO, "%s no space", hostname); #endif exit(1); } /* If we can talk, proceed with initialization */ ngpermcount = get_nglist(&ngpermlist, gdbuf); #ifdef POSTER pp = getpwnam(POSTER); if (pp != NULL) { uid_poster = pp->pw_uid; gid_poster = pp->pw_gid; home_poster = pp->pw_dir; } else #endif uid_poster = gid_poster = 0; #ifndef FASTFORK num_groups = 0; num_groups = read_groups(); /* Read in the active file */ #else signal(SIGALRM, SIG_IGN); /* Children don't deal with */ /* these things */ #endif /* * num_groups may be zero if expire is running and the active * file is locked. (Under System V with lockf, for example.) * Or, something may be really screwed up.... */ if (num_groups == 0){ /* can't get a group list */ printf("%d %s NNTP server unavailable. Try later.\r\n", ERR_FAULT, host); (void) fflush(stdout); #ifdef SYSLOG syslog(LOG_INFO, "%s no groups", hostname); #endif exit(1); } art_fp = NULL; argp = (char **) NULL; /* for first time */ if ((cp = index(timeptr, '\n')) != NULL) *cp = '\0'; else timeptr = "Unknown date"; #ifdef AUTH printf("%d %s NNTP[auth] server version %s ready at %s (%s).\r\n", #else printf("%d %s NNTP server version %s ready at %s (%s).\r\n", #endif canpost ? OK_CANPOST : OK_NOPOST, host, nntp_version, timeptr, canpost ? "posting ok" : "no posting"); (void) fflush(stdout); /* * Now get commands one at a time and execute the * appropriate routine to deal with them. */ #ifdef TIMERS timer_init(timers, NTIMERS); #endif for (;;) { #ifdef TIMERS /* Don't try to read input unless there is some */ if (!timer_sleep(timers, NTIMERS)) continue; #endif if (fgets(line, sizeof(line), stdin) == NULL) break; /* Strip trailing CR-LF */ cp = line + strlen(line) - 1; while (cp >= line && (*cp == '\n' || *cp == '\r')) *cp-- = '\0'; #ifdef DEBUG if (debug) syslog(LOG_DEBUG, "<- \"%s\"", line); #endif /* Null command */ if ((argnum = parsit(line, &argp)) == 0) continue; /* a motion to adjourn is always in order */ if (!strcasecmp(argp[0], "quit")) break; for (i = 0; i < NUMCMDS; ++i) if (!strcasecmp(cmdtbl[i].cmd_name, argp[0])) break; if (i < NUMCMDS) { #ifdef SETPROCTITLE setproctitle("%s %s", hostname, argp[0]); #endif #ifdef AUTH /* authentication required? */ if (cmdtbl[i].authreq == 1 && Needauth) { printf("%d Authentication required for command\r\n", ERR_NOAUTH); (void) fflush(stdout); continue; } #endif AUTH (*cmdtbl[i].cmd_fctn)(argnum, argp); } else { #ifdef SYSLOG syslog(LOG_INFO, "%s unrecognized %s", hostname, line); #endif printf("%d Command unrecognized.\r\n", ERR_COMMAND); (void) fflush(stdout); } } printf("%d %s closing connection. Goodbye.\r\n", OK_GOODBYE, host); (void) fflush(stdout); #ifdef BATCHED_INPUT batchcheck(); #endif #ifdef SYSLOG if (ferror(stdout)) syslog(LOG_ERR, "%s disconnect: %m", hostname); #ifdef LOG stats_finish(); #endif #endif #ifdef PROFILE profile(); #endif exit(0); } #ifdef TIMEOUT /* * Called after TIMEOUT seconds of idle time to shut things down. * XXX stats are not reported when this occurs */ static void timeout() { printf("%d Timeout after %d seconds, closing connection.\r\n", ERR_FAULT, TIMEOUT); #ifdef SYSLOG syslog(LOG_NOTICE, "%s timeout", hostname); #endif (void) fflush(stdout); #ifdef BATCHED_INPUT batchcheck(); #endif #ifdef LOG stats_finish(); #endif #ifdef PROFILE profile(); #endif exit(1); } #endif #ifdef LOGINCHECK /* * Called ever LOGINCHECK seconds to see if logins have been disabled. * If so, shut down. * XXX stats are not reported when this occurs */ static void logincheck() { char host[MAXHOSTNAMELEN]; if (access(NOLOGIN, F_OK) < 0) return; if (gethostname(host, sizeof(host)) < 0) (void) strcpy(host, "Amnesiac"); printf("%d Logins are disabled on NNTP server %s. Try again later.\r\n", ERR_ACCESS, host); (void) fflush(stdout); #ifdef SYSLOG syslog(LOG_INFO, "%s logins disabled%s", hostname, firstlogincheck ? "" : " (kicked out)"); #endif #ifdef BATCHED_INPUT batchcheck(); #endif #ifdef LOG stats_finish(); #endif #ifdef PROFILE profile(); #endif exit(1); } #endif #ifdef BATCHED_INPUT /* * Called after BATCHCHECK seconds of idle time and at the end * of a session to see if a batch needs to be launched. */ static void batchcheck() { char errbuf[2 * NNTP_STRLEN]; enqpartbatch(CONT_XFER, ERR_XFERFAIL, errbuf); } #endif /* * Stats stuff */ static double Tstart, Tfinish; static double user, sys; #ifdef USG static time_t start, finish; #else /* not USG */ static struct timeval start, finish; #endif /* not USG */ static char * stats_init() { extern char *ctime(); #ifdef USG (void) time(&start); Tstart = (double) start; return(ctime(&start)); #else /* not USG */ (void) gettimeofday(&start, (struct timezone *)NULL); Tstart = (double) start.tv_sec + ((double)start.tv_usec)/1000000.0; return(ctime(&start.tv_sec)); #endif /* not USG */ } #ifdef LOG static void stats_finish() { char buf[NNTP_STRLEN]; # ifdef USG struct tms cpu; # else /* not USG */ struct rusage me, kids; # endif /* not USG */ #ifdef USG (void) time(&finish); Tfinish = (double) finish; #ifndef HZ #define HZ 60.0 /* typical system clock ticks - param.h */ #endif /* not HZ */ (void) times(&cpu); user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ; sys = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ; #else /* not USG */ (void) gettimeofday(&finish, (struct timezone *)NULL); Tfinish = (double) finish.tv_sec + ((double)finish.tv_usec)/1000000.0; (void) getrusage(RUSAGE_SELF, &me); (void) getrusage(RUSAGE_CHILDREN, &kids); user = (double) me.ru_utime.tv_sec + me.ru_utime.tv_usec/1000000.0 + kids.ru_utime.tv_sec + kids.ru_utime.tv_usec/1000000.0; sys = (double) me.ru_stime.tv_sec + me.ru_stime.tv_usec/1000000.0 + kids.ru_stime.tv_sec + kids.ru_stime.tv_usec/1000000.0; #endif /* not USG */ if (grps_acsd) syslog(LOG_INFO, "%s exit %d articles %d groups", hostname, arts_acsd, grps_acsd); if (nn_told) syslog(LOG_INFO, "%s newnews_stats told %d took %d", hostname, nn_told, nn_took); if (ih_accepted || ih_rejected || ih_failed) syslog(LOG_INFO, "%s ihave_stats accepted %d rejected %d failed %d", hostname, ih_accepted, ih_rejected, ih_failed); (void) sprintf(buf, "user %.3f system %.3f elapsed %.3f", user, sys, Tfinish - Tstart); syslog(LOG_INFO, "%s times %s", hostname, buf); } #endif LOG
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.