chiark / gitweb /
some fixes; debug for missing
[inn-innduct.git] / innd / status.c
1 /*  $Id: status.c 7547 2006-08-26 06:18:14Z eagle $
2 **
3 **  Periodic status reporting.
4 */
5 #include "config.h"
6 #include "clibrary.h"
7 #include "portable/socket.h"
8
9 #include "inn/innconf.h"
10 #include "innd.h"
11 #include "innperl.h"
12
13 #define MIN_REFRESH   60  /* 1 min */
14 #define HTML_STATUS
15 #if defined(HTML_STATUS)
16 #define STATUS_FILE     "inn_status.html"       /* will be in pathhttp */
17 #else
18 #define STATUS_FILE     "inn.status"            /* will be in pathlog */
19 #endif
20
21 typedef struct _STATUS {
22     char                name[SMBUF];
23     char                ip_addr[64];
24     bool                can_stream;
25     unsigned short      activeCxn;
26     unsigned short      sleepingCxns;
27     time_t              seconds;
28     unsigned long       accepted;
29     unsigned long       refused;
30     unsigned long       rejected;
31     unsigned long       Duplicate;
32     unsigned long       Unwanted_u;
33     unsigned long       Unwanted_d;
34     unsigned long       Unwanted_g;
35     unsigned long       Unwanted_s;
36     unsigned long       Unwanted_f;
37     float               Size;
38     float               DuplicateSize;
39     unsigned long       Check;
40     unsigned long       Check_send;
41     unsigned long       Check_deferred;
42     unsigned long       Check_got;
43     unsigned long       Check_cybercan;
44     unsigned long       Takethis;
45     unsigned long       Takethis_Ok;
46     unsigned long       Takethis_Err;
47     unsigned long       Ihave;
48     unsigned long       Ihave_Duplicate;
49     unsigned long       Ihave_Deferred;
50     unsigned long       Ihave_SendIt;
51     unsigned long       Ihave_Cybercan;
52     struct _STATUS *next;
53 } STATUS;
54
55 static unsigned STATUSlast_time;
56 char            start_time[50];
57
58 static unsigned
59 STATUSgettime(void)
60 {
61   static int            init = 0;
62   static struct timeval start_tv;
63   struct timeval        tv;
64   
65   if (!init) {
66     gettimeofday(&start_tv, NULL);
67     init++;
68   }
69   gettimeofday(&tv, NULL);
70   return((tv.tv_sec - start_tv.tv_sec) * 1000 +
71          (tv.tv_usec - start_tv.tv_usec) / 1000);
72 }
73
74 void
75 STATUSinit(void)
76 {
77   time_t now;
78   
79   STATUSlast_time = STATUSgettime();    /* First invocation */
80   now = time (NULL) ;
81   strlcpy(start_time, ctime(&now), sizeof(start_time));
82 }
83
84 static char *
85 PrettySize(float size, char *str)
86 {
87   if (size > 1073741824) /* 1024*1024*1024 */
88     sprintf (str, "%.1fGb", size / 1073741824.);
89   else
90     if (size > 1048576) /* 1024*1024 */
91       sprintf (str, "%.1fMb", size / 1048576.);
92     else
93       sprintf (str, "%.1fkb", size / 1024.);
94   return (str);
95 }
96
97 static void
98 STATUSsummary(void)
99 {
100   FILE                  *F;
101   int                   i, j;
102   CHANNEL               *cp;
103   int                   activeCxn = 0;
104   int                   sleepingCxns = 0;
105   time_t                seconds = 0;
106   unsigned long         duplicate = 0;
107   unsigned long         offered;
108   unsigned long         accepted = 0;
109   unsigned long         refused = 0;
110   unsigned long         rejected = 0;
111   float                 size = 0;
112   float                 DuplicateSize = 0;
113   int                   peers = 0;
114   char                  TempString[SMBUF];
115   char                  *path;
116   STATUS                *head, *status, *tmp;
117   char                  str[9];
118   time_t                now;
119  
120 #if defined(HTML_STATUS)
121   path = concatpath(innconf->pathhttp, STATUS_FILE);
122 #else
123   path = concatpath(innconf->pathlog, STATUS_FILE);
124 #endif
125   if ((F = Fopen(path, "w", TEMPORARYOPEN)) == NULL) {
126     syslog(L_ERROR, "%s cannot open %s: %m", LogName, path);
127     return;
128   }
129
130 #if defined(HTML_STATUS)
131   /* HTML Header */
132
133   fprintf (F,"<HTML>\n<HEAD>\n<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%ld;\">\n",
134            innconf->status < MIN_REFRESH ? MIN_REFRESH : innconf->status);
135   fprintf (F, "<TITLE>%s: incoming feeds</TITLE>\n", innconf->pathhost);
136   fprintf (F, "</HEAD>\n<BODY>\n<PRE>\n") ;
137 #endif /* defined(HTML_STATUS) */
138
139   fprintf (F, "%s\n", inn_version_string);
140   fprintf (F, "pid %d started %s\n", (int) getpid(), start_time);
141
142   tmp = head = NULL;
143   for (i = 0; (cp = CHANiter(&i, CTnntp)) != NULL; ) {
144     j = 0;
145     strlcpy(TempString,
146             cp->Address.ss_family == 0 ? "localhost" : RChostname(cp),
147             sizeof(TempString));
148     for (status = head ; status != NULL ; status = status->next) {
149         if (strcmp(TempString, status->name) == 0)
150             break;
151     }
152     if (status == NULL) {
153       status = xmalloc(sizeof(STATUS));
154       peers++;                                              /* a new peer */
155       strlcpy(status->name, TempString, sizeof(status->name));
156       if (cp->Address.ss_family == 0) {
157         /* Connections from lc.c do not have an IP address. */
158         memset(&status->ip_addr, 0, sizeof(status->ip_addr));
159       } else {
160         strlcpy(status->ip_addr,
161           sprint_sockaddr((struct sockaddr *)&cp->Address),
162           sizeof(status->ip_addr));
163       }
164       status->can_stream = cp->Streaming;
165       status->seconds = status->Size = status->DuplicateSize = 0;
166       status->Ihave = status->Ihave_Duplicate =
167         status->Ihave_Deferred = status->Ihave_SendIt =
168         status->Ihave_Cybercan = 0;
169       status->Check = status->Check_send = 
170         status->Check_deferred = status->Check_got =
171         status->Check_cybercan = 0;
172       status->Takethis = status->Takethis_Ok = status->Takethis_Err = 0;
173       status->activeCxn = status->sleepingCxns = 0;
174       status->accepted = 0;
175       status->refused = status->rejected = 0;
176       status->Duplicate = status->Unwanted_u = 0;
177       status->Unwanted_d = status->Unwanted_g = 0;
178       status->Unwanted_s = status->Unwanted_f = 0;
179       status->next = NULL;
180       if (head == NULL)
181         head = status;
182       else
183         tmp->next = status;
184       tmp = status;
185     }
186     if (Now.time - cp->Started > status->seconds)
187       status->seconds = Now.time - cp->Started;
188     if (Now.time - cp->Started > seconds)
189       seconds = Now.time - cp->Started;
190     status->accepted += cp->Received;
191     accepted += cp->Received;
192     status->refused += cp->Refused;
193     refused += cp->Refused;
194     status->rejected += cp->Rejected;
195     rejected += cp->Rejected;
196     status->Duplicate += cp->Duplicate;
197     duplicate += cp->Duplicate;
198     status->Unwanted_u += cp->Unwanted_u;
199     status->Unwanted_d += cp->Unwanted_d;
200     status->Unwanted_g += cp->Unwanted_g;
201     status->Unwanted_s += cp->Unwanted_s;
202     status->Unwanted_f += cp->Unwanted_f;
203     status->Ihave += cp->Ihave;
204     status->Ihave_Duplicate += cp->Ihave_Duplicate;
205     status->Ihave_Deferred += cp->Ihave_Deferred;
206     status->Ihave_SendIt += cp->Ihave_SendIt;
207     status->Ihave_Cybercan += cp->Ihave_Cybercan;
208     status->Check += cp->Check;
209     status->Check_send += cp->Check_send;
210     status->Check_deferred += cp->Check_deferred;
211     status->Check_got += cp->Check_got;
212     status->Check_cybercan += cp->Check_cybercan;
213     status->Takethis += cp->Takethis;
214     status->Takethis_Ok += cp->Takethis_Ok;
215     status->Takethis_Err += cp->Takethis_Err;
216     status->Size += cp->Size;
217     status->DuplicateSize += cp->DuplicateSize;
218     size += cp->Size;
219     DuplicateSize += cp->DuplicateSize;
220     if (CHANsleeping(cp)) {
221       sleepingCxns++;
222       status->sleepingCxns++;
223     } else {
224       activeCxn++;
225       status->activeCxn++;
226     }
227   }
228
229   /* Header */
230   now = time (NULL);
231   strlcpy (TempString, ctime (&now), sizeof(TempString));
232   fprintf (F, "Updated: %s", TempString);
233   fprintf (F, "(peers: %d, active-cxns: %d, sleeping-cxns: %d)\n\n",
234            peers, activeCxn, sleepingCxns);
235
236   fprintf (F, "Mode: %s", Mode == OMrunning ? "running" :
237            Mode == OMpaused ? "paused" :
238            Mode == OMthrottled ? "throttled" : "Unknown");
239   if ((Mode == OMpaused) || (Mode == OMthrottled))
240     fprintf (F, " (%s)", ModeReason);
241   
242   /* Global configuration */
243   fprintf (F, "\n\nConfiguration file: %s\n\n", _PATH_CONFIG);
244
245   fprintf (F, "Global configuration parameters:\n");
246   fprintf (F, "              Largest Article: %ld bytes\n", innconf->maxartsize);
247   fprintf (F, "     Max Incoming connections: ");
248   if (innconf->maxconnections)
249     fprintf (F, "%ld\n", innconf->maxconnections);
250   else
251     fprintf (F, "unlimited\n");
252   fprintf (F, "      Max Outgoing file feeds: %d\n", MaxOutgoing);
253   fprintf (F, "                       Cutoff: ");
254   if (innconf->artcutoff)
255     fprintf (F, "%ld days\n", innconf->artcutoff);
256   else
257     fprintf (F, "none\n");
258   fprintf (F, "               Timeout period: %ld seconds\n",
259            (long)TimeOut.tv_sec);
260   if (innconf->remembertrash) {
261         fprintf (F, "               Remember Trash: Yes\n");
262   } else {
263         fprintf (F, "               Remember Trash: No\n");
264   }
265 #if defined(DO_TCL)
266   fprintf (F, "                Tcl filtering: %s\n", 
267            TCLFilterActive ? "enabled" : "disabled");
268 #endif /* defined(DO_TCL) */
269 #if defined(DO_PERL)
270   fprintf (F, "               Perl filtering: %s\n", 
271            PerlFilterActive ? "enabled" : "disabled");
272 #endif /* defined(DO_PERL) */
273
274   fputc ('\n', F) ;
275
276   /* Global values */
277   fprintf (F, "global (process)\n");
278   fprintf (F, "         seconds: %ld\n", (long) seconds);
279   offered = accepted + refused + rejected;
280   fprintf (F, "         offered: %-9ld\n", offered);
281   if (!offered) offered = 1; /* to avoid division by zero */
282   if (!size) size = 1; /* avoid divide by zero here too */
283   fprintf (F, "        accepted: %-9ld       %%accepted: %.1f%%\n",
284            accepted, (float) accepted / offered * 100);
285   fprintf (F, "         refused: %-9ld        %%refused: %.1f%%\n",
286            refused, (float) refused / offered * 100);
287   fprintf (F, "        rejected: %-9ld       %%rejected: %.1f%%\n",
288            rejected, (float) rejected / offered * 100);
289   fprintf (F, "      duplicated: %-9ld     %%duplicated: %.1f%%\n",
290            duplicate, (float) duplicate / offered * 100);
291   fprintf (F, "           bytes: %-7s\n", PrettySize (size + DuplicateSize, str));
292   fprintf (F, " duplicated size: %-7s  %%duplicated size: %.1f%%\n",
293            PrettySize(DuplicateSize, str), (float) DuplicateSize / size * 100);
294   fputc ('\n', F) ;
295   
296   /* Incoming Feeds */
297   for (status = head ; status != NULL ;) {
298     fprintf (F, "%s\n",                      status->name);
299     fprintf (F, "    seconds: %-7ld  ",      (long) status->seconds);
300     fprintf (F, "      duplicates: %-7ld ",  status->Duplicate);
301     fprintf (F, "    ip address: %s\n",      status->ip_addr);
302     fprintf (F, "    offered: %-7ld  ",
303              status->accepted + status->refused + status->rejected);
304     fprintf (F, "   uw newsgroups: %-7ld ",  status->Unwanted_g);
305     fprintf (F, "   active cxns: %d\n",      status->activeCxn);
306     fprintf (F, "   accepted: %-7ld  ",      status->accepted);
307     fprintf (F, "uw distributions: %-7ld ",  status->Unwanted_d);
308     fprintf (F, " sleeping cxns: %d\n",      status->sleepingCxns);
309     fprintf (F, "    refused: %-7ld  ",      status->refused);
310     fprintf (F, "      unapproved: %-7ld ",  status->Unwanted_u);
311     fprintf (F, "want streaming: %s\n",
312              status->can_stream ? "Yes" : "No");
313     fprintf (F, "   rejected: %-7ld  ",      status->rejected);
314     fprintf (F, "        filtered: %-7ld ",  status->Unwanted_f);
315     fprintf (F, "  is streaming: %s\n",
316              (status->Check || status->Takethis) ? "Yes" : "No");
317     fprintf (F, "       size: %-8s ",        PrettySize(status->Size, str));
318     fprintf (F, "       bad sites: %-7ld ", status->Unwanted_s);
319     fprintf (F, "duplicate size: %s\n", PrettySize(status->DuplicateSize, str));
320     fprintf (F, "  Protocol:\n");
321     fprintf (F, "      Ihave: %-6ld SendIt[%d]: %-6ld    Got[%d]: %-6ld Deferred[%d]: %ld\n",
322              status->Ihave, NNTP_SENDIT_VAL, status->Ihave_SendIt,
323              NNTP_HAVEIT_VAL, status->Ihave_Duplicate, NNTP_RESENDIT_VAL,
324              status->Ihave_Deferred);
325     fprintf (F, "      Check: %-6ld SendIt[%d]: %-6ld    Got[%d]: %-6ld Deferred[%d]: %ld\n",
326              status->Check, NNTP_OK_SENDID_VAL, status->Check_send,
327              NNTP_ERR_GOTID_VAL, status->Check_got, NNTP_RESENDID_VAL,
328              status->Check_deferred);
329     fprintf (F, "   Takethis: %-6ld     Ok[%d]: %-6ld  Error[%d]: %-6ld\n",
330              status->Takethis, NNTP_OK_RECID_VAL, status->Takethis_Ok,
331              NNTP_ERR_FAILID_VAL, status->Takethis_Err);
332     if (innconf->refusecybercancels) {
333         fprintf (F, "   Cancelrejects:    Ihave[%d]: %-6ld  Check[%d]: %-6ld\n",
334              NNTP_HAVEIT_VAL, status->Ihave_Cybercan,
335              NNTP_ERR_GOTID_VAL, status->Check_cybercan);
336     }
337     fputc ('\n', F) ;
338     tmp = status->next;
339     free(status);
340     status = tmp;
341   }
342
343 #if defined(HTML_STATUS)
344   /* HTML Footer */
345   fprintf (F,"</PRE>\n</BODY>\n</HTML>\n");
346 #endif /* defined(HTML_STATUS) */
347
348   Fclose(F);
349 }
350
351 void
352 STATUSmainloophook(void)
353 {
354   unsigned now;
355     
356   if (!innconf->status)
357     return;
358   now = STATUSgettime();
359   
360   if (now - STATUSlast_time > (unsigned)(innconf->status * 1000)) {
361     STATUSsummary();
362     STATUSlast_time = now;
363   }
364 }