/* $Id: status.c 6372 2003-05-31 19:48:28Z rra $ ** ** Periodic status reporting. */ #include "config.h" #include "clibrary.h" #include "portable/socket.h" #include "inn/innconf.h" #include "innd.h" #include "innperl.h" #define MIN_REFRESH 60 /* 1 min */ #define HTML_STATUS #if defined(HTML_STATUS) #define STATUS_FILE "inn_status.html" /* will be in pathhttp */ #else #define STATUS_FILE "inn.status" /* will be in pathlog */ #endif typedef struct _STATUS { char name[SMBUF]; char ip_addr[64]; bool can_stream; unsigned short activeCxn; unsigned short sleepingCxns; time_t seconds; unsigned long accepted; unsigned long refused; unsigned long rejected; unsigned long Duplicate; unsigned long Unwanted_u; unsigned long Unwanted_d; unsigned long Unwanted_g; unsigned long Unwanted_s; unsigned long Unwanted_f; float Size; float DuplicateSize; unsigned long Check; unsigned long Check_send; unsigned long Check_deferred; unsigned long Check_got; unsigned long Check_cybercan; unsigned long Takethis; unsigned long Takethis_Ok; unsigned long Takethis_Err; unsigned long Ihave; unsigned long Ihave_Duplicate; unsigned long Ihave_Deferred; unsigned long Ihave_SendIt; unsigned long Ihave_Cybercan; struct _STATUS *next; } STATUS; static unsigned STATUSlast_time; char start_time[50]; static unsigned STATUSgettime(void) { static int init = 0; static struct timeval start_tv; struct timeval tv; if (!init) { gettimeofday(&start_tv, NULL); init++; } gettimeofday(&tv, NULL); return((tv.tv_sec - start_tv.tv_sec) * 1000 + (tv.tv_usec - start_tv.tv_usec) / 1000); } void STATUSinit(void) { time_t now; STATUSlast_time = STATUSgettime(); /* First invocation */ now = time (NULL) ; strlcpy(start_time, ctime(&now), sizeof(start_time)); } static char * PrettySize(float size, char *str) { if (size > 1073741824) /* 1024*1024*1024 */ sprintf (str, "%.1fGb", size / 1073741824.); else if (size > 1048576) /* 1024*1024 */ sprintf (str, "%.1fMb", size / 1048576.); else sprintf (str, "%.1fkb", size / 1024.); return (str); } static void STATUSsummary(void) { FILE *F; int i, j; CHANNEL *cp; int activeCxn = 0; int sleepingCxns = 0; time_t seconds = 0; unsigned long duplicate = 0; unsigned long offered; unsigned long accepted = 0; unsigned long refused = 0; unsigned long rejected = 0; float size = 0; float DuplicateSize = 0; int peers = 0; char TempString[SMBUF]; char *path; STATUS *head, *status, *tmp; char str[9]; time_t now; #if defined(HTML_STATUS) path = concatpath(innconf->pathhttp, STATUS_FILE); #else path = concatpath(innconf->pathlog, STATUS_FILE); #endif if ((F = Fopen(path, "w", TEMPORARYOPEN)) == NULL) return; #if defined(HTML_STATUS) /* HTML Header */ fprintf (F,"\n
\n\n", innconf->status < MIN_REFRESH ? MIN_REFRESH : innconf->status); fprintf (F, "\n") ;
#endif /* defined(HTML_STATUS) */
fprintf (F, "%s\n", inn_version_string);
fprintf (F, "pid %d started %s\n", (int) getpid(), start_time);
tmp = head = NULL;
for (i = 0; (cp = CHANiter(&i, CTnntp)) != NULL; ) {
j = 0;
strlcpy(TempString,
cp->Address.ss_family == 0 ? "localhost" : RChostname(cp),
sizeof(TempString));
for (status = head ; status != NULL ; status = status->next) {
if (strcmp(TempString, status->name) == 0)
break;
}
if (status == NULL) {
status = xmalloc(sizeof(STATUS));
peers++; /* a new peer */
strlcpy(status->name, TempString, sizeof(status->name));
strlcpy(status->ip_addr,
sprint_sockaddr((struct sockaddr *)&cp->Address),
sizeof(status->ip_addr));
status->can_stream = cp->Streaming;
status->seconds = status->Size = status->DuplicateSize = 0;
status->Ihave = status->Ihave_Duplicate =
status->Ihave_Deferred = status->Ihave_SendIt =
status->Ihave_Cybercan = 0;
status->Check = status->Check_send =
status->Check_deferred = status->Check_got =
status->Check_cybercan = 0;
status->Takethis = status->Takethis_Ok = status->Takethis_Err = 0;
status->activeCxn = status->sleepingCxns = 0;
status->accepted = 0;
status->refused = status->rejected = 0;
status->Duplicate = status->Unwanted_u = 0;
status->Unwanted_d = status->Unwanted_g = 0;
status->Unwanted_s = status->Unwanted_f = 0;
status->next = NULL;
if (head == NULL)
head = status;
else
tmp->next = status;
tmp = status;
}
if (Now.time - cp->Started > status->seconds)
status->seconds = Now.time - cp->Started;
if (Now.time - cp->Started > seconds)
seconds = Now.time - cp->Started;
status->accepted += cp->Received;
accepted += cp->Received;
status->refused += cp->Refused;
refused += cp->Refused;
status->rejected += cp->Rejected;
rejected += cp->Rejected;
status->Duplicate += cp->Duplicate;
duplicate += cp->Duplicate;
status->Unwanted_u += cp->Unwanted_u;
status->Unwanted_d += cp->Unwanted_d;
status->Unwanted_g += cp->Unwanted_g;
status->Unwanted_s += cp->Unwanted_s;
status->Unwanted_f += cp->Unwanted_f;
status->Ihave += cp->Ihave;
status->Ihave_Duplicate += cp->Ihave_Duplicate;
status->Ihave_Deferred += cp->Ihave_Deferred;
status->Ihave_SendIt += cp->Ihave_SendIt;
status->Ihave_Cybercan += cp->Ihave_Cybercan;
status->Check += cp->Check;
status->Check_send += cp->Check_send;
status->Check_deferred += cp->Check_deferred;
status->Check_got += cp->Check_got;
status->Check_cybercan += cp->Check_cybercan;
status->Takethis += cp->Takethis;
status->Takethis_Ok += cp->Takethis_Ok;
status->Takethis_Err += cp->Takethis_Err;
status->Size += cp->Size;
status->DuplicateSize += cp->DuplicateSize;
size += cp->Size;
DuplicateSize += cp->DuplicateSize;
if (CHANsleeping(cp)) {
sleepingCxns++;
status->sleepingCxns++;
} else {
activeCxn++;
status->activeCxn++;
}
}
/* Header */
now = time (NULL);
strlcpy (TempString, ctime (&now), sizeof(TempString));
fprintf (F, "Updated: %s", TempString);
fprintf (F, "(peers: %d, active-cxns: %d, sleeping-cxns: %d)\n\n",
peers, activeCxn, sleepingCxns);
fprintf (F, "Mode: %s", Mode == OMrunning ? "running" :
Mode == OMpaused ? "paused" :
Mode == OMthrottled ? "throttled" : "Unknown");
if ((Mode == OMpaused) || (Mode == OMthrottled))
fprintf (F, " (%s)", ModeReason);
/* Global configuration */
fprintf (F, "\n\nConfiguration file: %s\n\n", _PATH_CONFIG);
fprintf (F, "Global configuration parameters:\n");
fprintf (F, " Largest Article: %ld bytes\n", innconf->maxartsize);
fprintf (F, " Max Incoming connections: ");
if (innconf->maxconnections)
fprintf (F, "%ld\n", innconf->maxconnections);
else
fprintf (F, "unlimited\n");
fprintf (F, " Max Outgoing file feeds: %d\n", MaxOutgoing);
fprintf (F, " Cutoff: ");
if (innconf->artcutoff)
fprintf (F, "%ld days\n", innconf->artcutoff);
else
fprintf (F, "none\n");
fprintf (F, " Timeout period: %ld seconds\n",
(long)TimeOut.tv_sec);
if (innconf->remembertrash) {
fprintf (F, " Remember Trash: Yes\n");
} else {
fprintf (F, " Remember Trash: No\n");
}
#if defined(DO_TCL)
fprintf (F, " Tcl filtering: %s\n",
TCLFilterActive ? "enabled" : "disabled");
#endif /* defined(DO_TCL) */
#if defined(DO_PERL)
fprintf (F, " Perl filtering: %s\n",
PerlFilterActive ? "enabled" : "disabled");
#endif /* defined(DO_PERL) */
fputc ('\n', F) ;
/* Global values */
fprintf (F, "global (process)\n");
fprintf (F, " seconds: %ld\n", (long) seconds);
offered = accepted + refused + rejected;
fprintf (F, " offered: %-9ld\n", offered);
if (!offered) offered = 1; /* to avoid division by zero */
if (!size) size = 1; /* avoid divide by zero here too */
fprintf (F, " accepted: %-9ld %%accepted: %.1f%%\n",
accepted, (float) accepted / offered * 100);
fprintf (F, " refused: %-9ld %%refused: %.1f%%\n",
refused, (float) refused / offered * 100);
fprintf (F, " rejected: %-9ld %%rejected: %.1f%%\n",
rejected, (float) rejected / offered * 100);
fprintf (F, " duplicated: %-9ld %%duplicated: %.1f%%\n",
duplicate, (float) duplicate / offered * 100);
fprintf (F, " bytes: %-7s\n", PrettySize (size + DuplicateSize, str));
fprintf (F, " duplicated size: %-7s %%duplicated size: %.1f%%\n",
PrettySize(DuplicateSize, str), (float) DuplicateSize / size * 100);
fputc ('\n', F) ;
/* Incoming Feeds */
for (status = head ; status != NULL ;) {
fprintf (F, "%s\n", status->name);
fprintf (F, " seconds: %-7ld ", (long) status->seconds);
fprintf (F, " duplicates: %-7ld ", status->Duplicate);
fprintf (F, " ip address: %s\n", status->ip_addr);
fprintf (F, " offered: %-7ld ",
status->accepted + status->refused + status->rejected);
fprintf (F, " uw newsgroups: %-7ld ", status->Unwanted_g);
fprintf (F, " active cxns: %d\n", status->activeCxn);
fprintf (F, " accepted: %-7ld ", status->accepted);
fprintf (F, "uw distributions: %-7ld ", status->Unwanted_d);
fprintf (F, " sleeping cxns: %d\n", status->sleepingCxns);
fprintf (F, " refused: %-7ld ", status->refused);
fprintf (F, " unapproved: %-7ld ", status->Unwanted_u);
fprintf (F, "want streaming: %s\n",
status->can_stream ? "Yes" : "No");
fprintf (F, " rejected: %-7ld ", status->rejected);
fprintf (F, " filtered: %-7ld ", status->Unwanted_f);
fprintf (F, " is streaming: %s\n",
(status->Check || status->Takethis) ? "Yes" : "No");
fprintf (F, " size: %-8s ", PrettySize(status->Size, str));
fprintf (F, " bad sites: %-7ld ", status->Unwanted_s);
fprintf (F, "duplicate size: %s\n", PrettySize(status->DuplicateSize, str));
fprintf (F, " Protocol:\n");
fprintf (F, " Ihave: %-6ld SendIt[%d]: %-6ld Got[%d]: %-6ld Deferred[%d]: %ld\n",
status->Ihave, NNTP_SENDIT_VAL, status->Ihave_SendIt,
NNTP_HAVEIT_VAL, status->Ihave_Duplicate, NNTP_RESENDIT_VAL,
status->Ihave_Deferred);
fprintf (F, " Check: %-6ld SendIt[%d]: %-6ld Got[%d]: %-6ld Deferred[%d]: %ld\n",
status->Check, NNTP_OK_SENDID_VAL, status->Check_send,
NNTP_ERR_GOTID_VAL, status->Check_got, NNTP_RESENDID_VAL,
status->Check_deferred);
fprintf (F, " Takethis: %-6ld Ok[%d]: %-6ld Error[%d]: %-6ld\n",
status->Takethis, NNTP_OK_RECID_VAL, status->Takethis_Ok,
NNTP_ERR_FAILID_VAL, status->Takethis_Err);
if (innconf->refusecybercancels) {
fprintf (F, " Cancelrejects: Ihave[%d]: %-6ld Check[%d]: %-6ld\n",
NNTP_HAVEIT_VAL, status->Ihave_Cybercan,
NNTP_ERR_GOTID_VAL, status->Check_cybercan);
}
fputc ('\n', F) ;
tmp = status->next;
free(status);
status = tmp;
}
#if defined(HTML_STATUS)
/* HTML Footer */
fprintf (F,"\n\n\n");
#endif /* defined(HTML_STATUS) */
Fclose(F);
}
void
STATUSmainloophook(void)
{
unsigned now;
if (!innconf->status)
return;
now = STATUSgettime();
if (now - STATUSlast_time > (unsigned)(innconf->status * 1000)) {
STATUSsummary();
STATUSlast_time = now;
}
}