--- lib/newsfeed.c 1999/11/09 18:22:28 1.1 +++ lib/newsfeed.c 1999/11/10 04:46:45 1.2 @@ -21,6 +21,8 @@ Prototype int FeedQuerySpam(const char *hlabel, const char *hostInfo); Prototype int PathElmMatches(const char *hlabel, const char *p, int bytes, int *pidx); Prototype int CommonElmMatches(const char *common, const char *p, int bytes); +Prototype void FeedGetThrottle(const char *hlabel, int *delay, int *lines); +Prototype int FeedCanReadOnly(const char *hlabel); Prototype FILE *FeedFo; @@ -53,6 +55,9 @@ char nf_NoMisMatch; char nf_SpamFeedOpt; char nf_Resolved; + int nf_ThrottleDelay; + int nf_ThrottleLines; + char nf_AllowReadOnly; } NewsFeed; #define MAXRECURSION 16 @@ -589,6 +594,57 @@ } /* + * Write the throttling delay and line count into the appropriate + * memory locations. + */ + +void +FeedGetThrottle(const char *hlabel, int *delay, int *lines) +{ + NewsFeed *feed; + + if ((feed = NFCache) == NULL) { + for (feed = NFBase; feed; feed = feed->nf_Next) { + if (strcmp(hlabel, feed->nf_Label) == 0) + break; + } + NFCache = feed; + } + + if (feed) { + *delay = feed->nf_ThrottleDelay; + *lines = feed->nf_ThrottleLines; + } else { + *delay = 0; + *lines = 0; + } +} + +/* + * Return 1 if read-only-dhistory ``reader'' connections are allowed, + * 0 otherwise. + */ + +int +FeedCanReadOnly(const char *hlabel) +{ + NewsFeed *feed; + + if ((feed = NFCache) == NULL) { + for (feed = NFBase; feed; feed = feed->nf_Next) { + if (strcmp(hlabel, feed->nf_Label) == 0) + break; + } + NFCache = feed; + } + + if (feed) + return feed->nf_AllowReadOnly; + else + return 0; +} + +/* * filterQueryGroups() * * 0 if no filter commands matched @@ -1094,6 +1150,21 @@ } if (psNode && s2) err = 0; + } else if (strcmp(s1, "throttle_delay") == 0) { + if (nf && s2) { + nf->nf_ThrottleDelay = strtol(s2, NULL, 0); + err = 0; + } + } else if (strcmp(s1, "throttle_lines") == 0) { + if (nf && s2) { + nf->nf_ThrottleLines = strtol(s2, NULL, 0); + err = 0; + } + } else if (strcmp(s1, "allow_readonly") == 0) { + if (nf) { + nf->nf_AllowReadOnly = 1; + err = 0; + } } else if (strcmp(s1, "end") == 0) { if (nf) { *paNode = NULL; @@ -1357,6 +1428,13 @@ nf->nf_NoMisMatch = gl->nf_NoMisMatch; if (!nf->nf_SpamFeedOpt && gl->nf_SpamFeedOpt) nf->nf_SpamFeedOpt = gl->nf_SpamFeedOpt; + + if (!nf->nf_ThrottleDelay && gl->nf_ThrottleDelay) + nf->nf_ThrottleDelay = gl->nf_ThrottleDelay; + if (!nf->nf_ThrottleLines && gl->nf_ThrottleLines) + nf->nf_ThrottleLines = gl->nf_ThrottleLines; + if (!nf->nf_AllowReadOnly && gl->nf_AllowReadOnly) + nf->nf_AllowReadOnly = gl->nf_AllowReadOnly; } no = no->no_Next; } --- util/diablo.c 1999/11/09 18:20:17 1.1 +++ util/diablo.c 1999/11/10 05:44:37 1.3 @@ -97,6 +97,7 @@ char HLabel[256]; int MaxFds; int NumForks; +int ReadOnlyCount = 0; int PausedCount; fd_set RFds; Buffer *PipeAry[MAXFDS]; @@ -138,6 +139,8 @@ int RejectArtsWithNul; MemPool *ParProcMemPool; char *MySpoolHome; +int AllowReadOnly = 0; +int ReadOnlyMode = 0; #define REJ_ACCEPTED 0 /* not rejected, accepted */ #define REJ_CTLMSG 1 /* not rejected, accepted was control */ @@ -424,6 +427,48 @@ DebugOpt = 0; } +void +sigAlrm(int sigNo) +{ + if (AllowReadOnly) { + ReadOnlyMode = 1; + if (DidFork) { + struct sockaddr_un soun; + int ufd; + FILE *fo; + + memset(&soun, 0, sizeof(soun)); + if((ufd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + /* Can't make socket; hang ourselves */ + syslog(LOG_INFO, "Unable to create UNIX socket: %s\n", + strerror(errno)); + sigHup(SIGHUP); + } + + soun.sun_family = AF_UNIX; + sprintf(soun.sun_path, "%s", PatExpand(DiabloSocketPat)); + if (connect(ufd, (struct sockaddr *)&soun, offsetof(struct sockaddr_un, sun_path[strlen(soun.sun_path)+1])) < 0) { + /* Can't connect; hang ourselves */ + syslog(LOG_INFO, "Unable to connect to master %s: %s\n", + soun.sun_path, strerror(errno)); + sigHup(SIGHUP); + } + + fo = fdopen(ufd, "w"); + + fprintf(fo, "child-is-readonly\n"); + fprintf(fo, "quit\n"); + fflush(fo); + + fclose(fo); + + close(ufd); + } + } else { + sigHup(SIGHUP); + } +} + /* * DIABLOSERVER() - The master server process. It accept()s connections * and forks off children. @@ -485,6 +530,7 @@ rsignal(SIGINT, sigHup); rsignal(SIGUSR1, sigUsr1); rsignal(SIGUSR2, sigUsr2); + rsignal(SIGALRM, sigAlrm); /* * Call InitPreCommit() and InitSpamFilter() to setup any shared memory @@ -609,7 +655,7 @@ fcntl(ufd, F_SETFL, O_NONBLOCK); #endif - if (listen(ufd, 10) < 0) { + if (listen(ufd, 200) < 0) { perror("udom-listen"); exit(1); } @@ -640,7 +686,7 @@ struct timeval tv = { 5, 0 }; time_t t; - if (PausedCount && NumForks == 0) { + if ((ReadOnlyMode || PausedCount) && (NumForks == ReadOnlyCount)) { FinishRetain(RET_PAUSE); } @@ -1354,7 +1400,12 @@ fflush(fo); exit(0); } - + if (ReadOnlyMode) { + xfprintf(fo, "502 %s DIABLO is currently in read-only mode\r\n", + HostName); + fflush(fo); + exit(0); + } HistoryOpen(NULL, 0); LoadNewsFeed(0, 1, HLabel); /* free old memory and load only our label */ @@ -1384,6 +1435,7 @@ LoadExpireCtl(1); /* load entire expire.ctl */ ArticleFileInit(); /* initialize article file cache */ + AllowReadOnly = FeedCanReadOnly(HLabel); /* allow read-only mode? */ if (DiabloActiveEnabled && DiabloXRefSlave == 0) InitDActive(ServerDActivePat); /* initialize dactive.kp if enabled */ @@ -1408,6 +1460,10 @@ continue; if (strcasecmp(cmd, "ihave") == 0) { + if(ReadOnlyMode) { + xfprintf(fo, "436 Spool in read-only mode; try again later\r\n"); + } else { + const char *msgid = MsgId(strtok(NULL, "\r\n")); ++ArtsIHave; @@ -1490,7 +1546,12 @@ break; /* not reached */ } } + } /* ReadOnlyMode */ } else if (strcasecmp(cmd, "check") == 0) { + if(ReadOnlyMode) { + xfprintf(fo, "436 Spool in read-only mode; try again later\r\n"); + } else { + const char *msgid = MsgId(strtok(NULL, "\r\n")); ++ArtsCheck; @@ -1523,7 +1584,12 @@ } else { xfprintf(fo, "238 %s\r\n", msgid); } + } /* ReadOnlyMode */ } else if (strcasecmp(cmd, "takethis") == 0) { + if(ReadOnlyMode) { + xfprintf(fo, "436 Spool in read-only mode; try again later\r\n"); + } else { + const char *msgid = MsgId(strtok(NULL, "\r\n")); int r; int alreadyResponded = 0; @@ -1581,6 +1647,7 @@ break; /* not reached */ } } + } /* ReadOnlyMode */ } else if (strcasecmp(cmd, "head") == 0 || strcasecmp(cmd, "body") == 0 || strcasecmp(cmd, "article") == 0 @@ -1921,6 +1988,13 @@ char dist[80]; hash_t bh = { 0 }; + struct timespec delay; + int delay_counter = 0; + int delay_counter_max; + delay.tv_sec = 0; + + FeedGetThrottle(HLabel, (int *)&(delay.tv_nsec), &delay_counter_max); + nglist[0] = 0; npath[0] = 0; dateBuf[0] = 0; @@ -1933,6 +2007,16 @@ b = bopen(-1); while ((p = bgets(bi, &bytes)) != NULL && p != (char *)-1) { + + if(delay_counter_max) { + delay_counter++; + if(delay_counter == delay_counter_max) { + delay_counter = 0; + if(delay.tv_nsec) + nanosleep(&delay, NULL); + } + } + size += bytes; lastNl = thisNl; @@ -2474,8 +2558,9 @@ if (r == RCOK) { #if USE_SYSV_SIGNALS sighold(SIGHUP); + sighold(SIGALRM); #else - int smask = sigblock((1 << SIGHUP)); + int smask = sigblock((1 << SIGHUP) | (1 << SIGALRM)); #endif /* * Get the expiration. An expiration of zero @@ -2547,6 +2632,7 @@ } #if USE_SYSV_SIGNALS sigrelse(SIGHUP); + sigrelse(SIGALRM); #else sigsetmask(smask); #endif @@ -2731,7 +2817,9 @@ } else if (strcmp(s1, "pause") == 0) { retain = RET_PAUSE; ++PausedCount; - fprintf(fo, "200 Pause, count %d\n", PausedCount); + ReadOnlyMode = 0; + ReadOnlyCount = 0; + fprintf(fo, "200 Pause, count %d.\n", PausedCount); if (PausedCount == 1) { int i; @@ -2741,9 +2829,40 @@ } } } + } else if (strcmp(s1, "readonly") == 0) { + retain = RET_PAUSE; + ReadOnlyMode = 1; + ReadOnlyCount = 0; + fprintf(fo, "200 Read-only mode %d.\n", ReadOnlyMode); + { + int i; + + for (i = 0; i < MAXFDS; ++i) { + if (PidAry[i].tr_Pid) { + kill(PidAry[i].tr_Pid, SIGALRM); + } + } + } + } else if (strcmp(s1, "child-is-readonly") == 0) { + ReadOnlyCount++; } else if (strcmp(s1, "go") == 0) { + int i; + + if ((PausedCount == 1) && ReadOnlyMode) { + for (i = 0; i < MAXFDS; ++i) { + if (PidAry[i].tr_Pid) { + kill(PidAry[i].tr_Pid, SIGHUP); + } + } + ReadOnlyMode = 0; + } + if (PausedCount) --PausedCount; + + if (ReadOnlyMode && !PausedCount) + ReadOnlyMode = 0; + fprintf(fo, "200 Resume, count %d\n", PausedCount); } else if (strcmp(s1, "quit") == 0) { fprintf(fo, "200 Goodbye\n");