1 #include <unistd.h>
2 #include <setjmp.h>
3 #include <signal.h>
4 #include <string.h>
5 #include <netdb.h>
6 #include <netinet/in.h>
7
8 #include <sys/types.h>
9 #include <sys/socket.h>
10
11 #include <time.h>
12 #include "bandwidthd.h"
13
14 #ifdef HAVE_ARPA_NAMESER_H
15 #include <arpa/nameser.h>
16 #endif
17 #ifdef HAVE_RESOLV_H
18 #include <resolv.h>
19 #endif
20
21 extern unsigned int SubnetCount;
22 extern struct config config;
23
24 jmp_buf dnsjump;
25
26 static void rdnslngjmp(int signal);
27
rdns(char * Buffer,unsigned long IP)28 void rdns(char *Buffer, unsigned long IP) // This takes over sigalarm!
29 {
30 #ifdef HAVE_RESOLV_H
31 char DNSError[] = "DNS Timeout: Correct to speed up graphing";
32 char None[] = "Configure DNS to reverse this IP";
33 char TooManyDNSTimeouts[] = "Too many dns timeouts, reverse lookups suspended";
34 struct hostent *hostent;
35 char chrIP[50];
36 static int Init = TRUE;
37 static int DNSTimeouts = 0; // This is reset for each run because we're forked
38 unsigned long addr = htonl(IP);
39
40 _res.retrans = 1;
41 _res.retry = 2;
42
43 if (Init)
44 {
45 signal(SIGALRM, rdnslngjmp);
46 Init = FALSE;
47 }
48
49 if (DNSTimeouts > 100)
50 {
51 syslog(LOG_ERR, "Too many dns timeouts, reverse lookups suspended");
52 strncpy(Buffer, TooManyDNSTimeouts, 253);
53 Buffer[254] = '\0';
54 return;
55 }
56
57 if (setjmp(dnsjump) == 0)
58 {
59 alarm(10); // Don't let gethostbyaddr hold us up too long
60 hostent = gethostbyaddr((char *) &addr, 4, AF_INET); // (char *)&Data->IP
61 alarm(0);
62
63 if (hostent)
64 sprintf(Buffer, "%s", hostent->h_name);
65 else
66 {
67 strncpy(Buffer, None, 253);
68 Buffer[254] = '\0';
69 }
70 }
71 else // Our alarm timed out
72 {
73 HostIp2CharIp(IP, chrIP);
74 syslog(LOG_ERR, "DNS timeout for %s: This problem reduces graphing performance", chrIP);
75 DNSTimeouts++;
76 strncpy(Buffer, DNSError, 253);
77 Buffer[254] = '\0';
78 }
79 #else
80 Buffer[0] = '\0';
81 #endif
82 }
83
rdnslngjmp(int signal)84 static void rdnslngjmp(int signal)
85 {
86 longjmp(dnsjump, 1);
87 }
88
swap(struct SummaryData ** a,struct SummaryData ** b)89 void swap(struct SummaryData **a, struct SummaryData **b) {
90 struct SummaryData *temp;
91 temp = *a; *a = *b; *b = temp;
92 }
QuickSortSummaryData(struct SummaryData * SummaryData[],int left,int right)93 void QuickSortSummaryData(struct SummaryData *SummaryData[], int left, int right) {
94 int i,j,center;
95 unsigned long long pivot;
96 if (left==right) return;
97 if (left+1==right) {
98 if (SummaryData[left]->Total < SummaryData[right]->Total)
99 swap(&SummaryData[left],&SummaryData[right]);
100 return;
101 }
102 /* use the median-of-three method for picking pivot */
103 center = (left+right)/2;
104 if (SummaryData[left]->Total < SummaryData[center]->Total)
105 swap(&SummaryData[left],&SummaryData[center]);
106 if (SummaryData[left]->Total < SummaryData[right]->Total)
107 swap(&SummaryData[left],&SummaryData[right]);
108 if (SummaryData[center]->Total < SummaryData[right]->Total)
109 swap(&SummaryData[center],&SummaryData[right]);
110 pivot = SummaryData[center]->Total;
111 swap(&SummaryData[center],&SummaryData[right-1]); /* hide the pivot */
112 i = left; j = right - 1;
113 do {
114 do { ++i; } while (SummaryData[i]->Total > pivot);
115 do { --j; } while (SummaryData[j]->Total < pivot);
116 swap(&SummaryData[i],&SummaryData[j]);
117 } while (j > i);
118 swap(&SummaryData[i],&SummaryData[j]); /* undo last swap */
119 swap(&SummaryData[i],&SummaryData[right-1]); /* restore pivot */
120 QuickSortSummaryData(SummaryData,left,i-1);
121 QuickSortSummaryData(SummaryData,i+1,right);
122 }
123
124 #define NumFactor 1024
FormatNum(unsigned long long n,char * buf,int len)125 static void FormatNum(unsigned long long n, char *buf, int len) {
126 double f;
127 if (n<NumFactor) { snprintf(buf,len,"<td align=\"right\"><tt>%i </tt></td>",(int)n); return; }
128 f = n;
129 f /= NumFactor; if (f<NumFactor) { snprintf(buf,len,"<td align=\"right\"><tt>%.1fK</tt></td>",f); return; }
130 f /= NumFactor; if (f<NumFactor) { snprintf(buf,len,"<td align=\"right\"><tt>%.1fM</tt></td>",f); return; }
131 f /= NumFactor; if (f<NumFactor) { snprintf(buf,len,"<td align=\"right\"><tt>%.1fG</tt></td>",f); return; }
132 f /= NumFactor; snprintf(buf,len,"<td align=\"right\"><tt>%.1fT</tt></td>\n",f);
133 }
134
PrintTableLine(FILE * stream,struct SummaryData * Data,int Counter)135 void PrintTableLine(FILE *stream, struct SummaryData *Data, int Counter)
136 {
137 char Buffer1[50];
138 char Buffer2[50];
139 char Buffer3[50];
140 char Buffer4[50];
141 char Buffer4b[50];
142 char Buffer5[50];
143 char Buffer5b[50];
144 char Buffer6[50];
145 char Buffer7[50];
146 char Buffer8[50];
147
148 // First convert the info to nice, human readable stuff
149 if (Data->IP == 0)
150 strcpy(Buffer1, "Total");
151 else
152 HostIp2CharIp(Data->IP, Buffer1);
153
154 FormatNum(Data->Total, Buffer2, 50);
155 FormatNum(Data->TotalSent, Buffer3, 50);
156 FormatNum(Data->TotalReceived, Buffer4, 50);
157 FormatNum(Data->FTP, Buffer4b, 50);
158 FormatNum(Data->HTTP, Buffer5, 50);
159 FormatNum(Data->P2P, Buffer5b, 50);
160 FormatNum(Data->TCP, Buffer6, 50);
161 FormatNum(Data->UDP, Buffer7, 50);
162 FormatNum(Data->ICMP, Buffer8, 50);
163
164 if (Counter%4 == 0 || (Counter-1)%4 == 0)
165 fprintf(stream, "<TR>");
166 else
167 fprintf(stream, "<TR bgcolor=lightblue>");
168
169 if (Data->Graph)
170 fprintf(stream, "<TD><a href=\"#%s-%c\">%s</a></TD>%s%s%s%s%s%s%s%s%s</TR>\n",
171 Buffer1, // Ip
172 config.tag,
173 Buffer1, // Ip
174 Buffer2, // Total
175 Buffer3, // TotalSent
176 Buffer4, // TotalReceived
177 Buffer4b, // FTP
178 Buffer5, // HTTP
179 Buffer5b, // P2P
180 Buffer6, // TCP
181 Buffer7, // UDP
182 Buffer8); // ICMP
183 else
184 fprintf(stream, "<TD>%s</TD>%s%s%s%s%s%s%s%s%s</TR>\n",
185 Buffer1, // Ip
186 Buffer2, // Total
187 Buffer3, // TotalSent
188 Buffer4, // TotalReceived
189 Buffer4b, // FTP
190 Buffer5, // HTTP
191 Buffer5b, // P2P
192 Buffer6, // TCP
193 Buffer7, // UDP
194 Buffer8); // ICMP
195 }
196
MakeIndexPages(int NumIps,struct SummaryData * SummaryData[])197 void MakeIndexPages(int NumIps, struct SummaryData *SummaryData[])
198 {
199 int SubnetCounter;
200 int Counter, tCounter;
201 time_t WriteTime;
202 char filename[] = "./htdocs/index2.html";
203 char *PeriodDesc;
204
205 FILE *file;
206
207 char Buffer1[50];
208 char Buffer2[50];
209 char HostName[255];
210
211 WriteTime = time(NULL);
212
213 QuickSortSummaryData(SummaryData, 0, NumIps-1);
214
215 ////////////////////////////////////////////////
216 // Print main index page
217
218 if (config.tag == '1')
219 {
220 if ((file = fopen("./htdocs/index.html", "wt")) == NULL)
221 {
222 syslog(LOG_ERR, "Failed to open ./htdocs/index.html");
223 exit(1);
224 }
225 }
226 else
227 {
228 filename[14] = config.tag;
229 if ((file = fopen(filename, "wt")) == NULL)
230 {
231 syslog(LOG_ERR, "Failed to open %s", filename);
232 exit(1);
233 }
234 }
235
236 switch (config.tag)
237 {
238 case '1': PeriodDesc = "Daily"; break;
239 case '2': PeriodDesc = "Weekly"; break;
240 case '3': PeriodDesc = "Monthly"; break;
241 case '4': PeriodDesc = "Yearly"; break;
242 default: PeriodDesc = ""; break;
243 }
244
245 fprintf(file, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
246 fprintf(file, "<HTML>\n<HEAD>\n<TITLE>Bandwidthd</TITLE>\n");
247
248 if (config.meta_refresh)
249 fprintf(file, "<META HTTP-EQUIV=\"REFRESH\" content=\"%u\">\n",
250 config.meta_refresh);
251 fprintf(file, "<META HTTP-EQUIV=\"EXPIRES\" content=\"-1\">\n");
252 fprintf(file, "<META HTTP-EQUIV=\"PRAGMA\" content=\"no-cache\">\n");
253 fprintf(file, "</HEAD>\n<BODY vlink=blue>\n%s<br>\n<center><img src=\"logo.gif\" ALT=\"Logo\"><BR>\n", ctime(&WriteTime));
254 fprintf(file, "Programmed by David Hinkle, Commissioned by <a href=\"http://www.derbytech.com\">DerbyTech</a> wireless networking.<BR>");
255 fprintf(file, "<BR>\n - <a href=\"index.html\">Daily</a> -- <a href=\"index2.html\">Weekly</a> -- ");
256 fprintf(file, "<a href=\"index3.html\">Monthly</a> -- <a href=\"index4.html\">Yearly</a> - <BR>\n");
257
258 fprintf(file, "<BR>\nPick a Subnet:<BR>\n");
259 if (config.tag == '1')
260 fprintf(file, "- <a href=\"index.html\">Top20</a> -");
261 else
262 fprintf(file, "- <a href=\"index%c.html\">Top20</a> -", config.tag);
263
264 for (Counter = 0; Counter < SubnetCount; Counter++)
265 {
266 HostIp2CharIp(SubnetTable[Counter].ip, Buffer1);
267 fprintf(file, "- <a href=\"Subnet-%c-%s.html\">%s</a> -", config.tag, Buffer1, Buffer1);
268 }
269
270 ///// TOP 20
271
272 fprintf(file, "<H1>Top 20 IPs by Traffic - %s</H1></center>", PeriodDesc);
273 fprintf(file, "<center>\n<table width=\"100%%\" border=1 cellspacing=0>\n");
274
275 // PASS 1: Write out the table
276
277 fprintf(file, "<TR bgcolor=lightblue><TD>Ip and Name<TD align=center>Total<TD align=center>Total Sent<TD align=center>Total Received<TD align=center>FTP<TD align=center>HTTP<TD align=center>P2P<TD align=center>TCP<TD align=center>UDP<TD align=center>ICMP\n");
278 for (Counter=0; Counter < 21 && Counter < NumIps; Counter++)
279 PrintTableLine(file, SummaryData[Counter], Counter);
280
281 fprintf(file, "</table></center>\n");
282
283 // PASS 2: The graphs
284 for (Counter=0; Counter < 21 && Counter < NumIps; Counter++)
285 if (SummaryData[Counter]->Graph)
286 {
287 if (SummaryData[Counter]->IP == 0)
288 {
289 strcpy(Buffer1, "Total");
290 strcpy(HostName, "Total of all subnets");
291 }
292 else
293 {
294 HostIp2CharIp(SummaryData[Counter]->IP, Buffer1);
295 rdns(HostName, SummaryData[Counter]->IP);
296 }
297 fprintf(file, "<a name=\"%s-%c\"></a><H1><a href=\"#top\">(Top)</a> %s - %s</H1><BR>\nSend:<br>\n<img src=%s-%c-S.png ALT=\"Sent traffic for %s\"><BR>\n<img src=legend.gif ALT=\"Legend\"><br>\nReceived:<br>\n<img src=%s-%c-R.png ALT=\"Sent traffic for %s\"><BR>\n<img src=legend.gif ALT=\"Legend\"><br>\n<BR>\n", Buffer1, config.tag, Buffer1, HostName, Buffer1, config.tag, Buffer1, Buffer1, config.tag, Buffer1);
298 }
299
300 fprintf(file, "</BODY></HTML>\n");
301
302 fclose(file);
303
304 ////////////////////////////////////////////////
305 // Print each subnet page
306
307 for (SubnetCounter = 0; SubnetCounter < SubnetCount; SubnetCounter++)
308 {
309 HostIp2CharIp(SubnetTable[SubnetCounter].ip, Buffer1);
310 sprintf(Buffer2, "./htdocs/Subnet-%c-%s.html", config.tag, Buffer1);
311 file = fopen(Buffer2, "wt");
312 fprintf(file, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
313 fprintf(file, "<HTML>\n<HEAD><TITLE>Bandwidthd - Subnet %s</TITLE>\n", Buffer1);
314
315 if (config.meta_refresh)
316 fprintf(file, "<META HTTP-EQUIV=\"REFRESH\" content=\"%u\">\n",
317 config.meta_refresh);
318 fprintf(file, "<META HTTP-EQUIV=\"EXPIRES\" content=\"-1\">\n");
319 fprintf(file, "<META HTTP-EQUIV=\"PRAGMA\" content=\"no-cache\">\n");
320 fprintf(file, "</HEAD>\n<BODY vlink=blue>\n%s<br>\n<CENTER><a name=\"Top\"></a>", ctime(&WriteTime));
321 fprintf(file, "<img src=\"logo.gif\" ALT=\"Logo\"><BR>");
322 fprintf(file, "Programmed by David Hinkle, Commissioned by <a href=\"http://www.derbytech.com\">DerbyTech</a> wireless networking.<BR>\n");
323
324 fprintf(file, "<BR>\n - <a href=\"index.html\">Daily</a> -- <a href=\"index2.html\">Weekly</a> -- ");
325 fprintf(file, "<a href=\"index3.html\">Monthly</a> -- <a href=\"index4.html\">Yearly</a> - <BR>\n");
326
327 fprintf(file, "<BR>\nPick a Subnet:<BR>\n");
328 if (config.tag == '1')
329 fprintf(file, "- <a href=\"index.html\">Top20</a> -");
330 else
331 fprintf(file, "- <a href=\"index%c.html\">Top20</a> -", config.tag);
332
333 for (Counter = 0; Counter < SubnetCount; Counter++)
334 {
335 HostIp2CharIp(SubnetTable[Counter].ip, Buffer2);
336 fprintf(file, "- <a href=\"Subnet-%c-%s.html\">%s</a> -", config.tag, Buffer2, Buffer2);
337 }
338
339 fprintf(file, "<H1>%s - %s</H1></center>", Buffer1, PeriodDesc);
340 fprintf(file, "<table width=\"100%%\" border=1 cellspacing=0>\n");
341
342 // PASS 1: Write out the table
343
344 fprintf(file, "<TR bgcolor=lightblue><TD>Ip and Name<TD align=center>Total<TD align=center>Total Sent<TD align=center>Total Received<TD align=center>FTP<TD align=center>HTTP<TD align=center>P2P<TD align=center>TCP<TD align=center>UDP<TD align=center>ICMP\n");
345 for (tCounter=0, Counter=0; Counter < NumIps; Counter++)
346 {
347 if (SubnetTable[SubnetCounter].ip == (SummaryData[Counter]->IP & SubnetTable[SubnetCounter].mask))
348 { // The ip belongs to this subnet
349 PrintTableLine(file, SummaryData[Counter], tCounter++);
350 }
351 }
352
353 fprintf(file, "</table>\n");
354
355 // PASS 2: The graphs
356 for (Counter=0; Counter < NumIps; Counter++)
357 {
358 if (SubnetTable[SubnetCounter].ip == (SummaryData[Counter]->IP & SubnetTable[SubnetCounter].mask))
359 { // The ip belongs to this subnet
360 if (SummaryData[Counter]->Graph)
361 {
362 HostIp2CharIp(SummaryData[Counter]->IP, Buffer1);
363 rdns(HostName, SummaryData[Counter]->IP);
364 fprintf(file, "<a name=\"%s-%c\"></a><H1><a href=\"#top\">(Top)</a> %s - %s</H1><BR>\nSend:<br>\n<img src=%s-%c-S.png ALT=\"Sent traffic graph for %s\"><BR>\n<img src=legend.gif ALT=\"Legend\"><br>\nReceived:<br>\n<img src=%s-%c-R.png ALT=\"Received traffic for %s\"><BR>\n<img src=legend.gif ALT=\"Legend\"><br>\n<BR>\n", Buffer1, config.tag, Buffer1, HostName, Buffer1, config.tag, Buffer1, Buffer1, config.tag, Buffer1);
365 }
366 }
367 }
368
369 fprintf(file, "</BODY></HTML>\n");
370 fclose(file);
371 }
372
373 free(SummaryData);
374 }
375
GraphIp(struct IPDataStore * DataStore,struct SummaryData * SummaryData,time_t timestamp)376 void GraphIp(struct IPDataStore *DataStore, struct SummaryData *SummaryData, time_t timestamp)
377 {
378 FILE *OutputFile;
379 char outputfilename[50];
380 gdImagePtr im, im2;
381 int white;
382 unsigned long long int YMax;
383 char CharIp[20];
384
385 time_t GraphBeginTime;
386
387 // TODO: First determine if graph will be printed before creating image and drawing backround, etc
388
389 if (DataStore->ip == 0)
390 strcpy(CharIp, "Total");
391 else
392 HostIp2CharIp(DataStore->ip, CharIp);
393
394 GraphBeginTime = timestamp - config.range;
395
396 im = gdImageCreate(XWIDTH, YHEIGHT);
397 white = gdImageColorAllocate(im, 255, 255, 255);
398 //gdImageFill(im, 10, 10, white);
399
400 im2 = gdImageCreate(XWIDTH, YHEIGHT);
401 white = gdImageColorAllocate(im2, 255, 255, 255);
402 //gdImageFill(im2, 10, 10, white);
403
404 YMax = GraphData(im, im2, DataStore, GraphBeginTime, SummaryData);
405 if (YMax != 0)
406 {
407 // Finish the graph
408 PrepareXAxis(im, timestamp);
409 PrepareYAxis(im, YMax);
410
411 PrepareXAxis(im2, timestamp);
412 PrepareYAxis(im2, YMax);
413
414 sprintf(outputfilename, "./htdocs/%s-%c-S.png", CharIp, config.tag);
415 OutputFile = fopen(outputfilename, "wb");
416 gdImagePng(im, OutputFile);
417 fclose(OutputFile);
418
419 sprintf(outputfilename, "./htdocs/%s-%c-R.png", CharIp, config.tag);
420 OutputFile = fopen(outputfilename, "wb");
421 gdImagePng(im2, OutputFile);
422 fclose(OutputFile);
423 }
424 else
425 {
426 // The graph isn't worth clutering up the web pages with
427 sprintf(outputfilename, "./htdocs/%s-%c-R.png", CharIp, config.tag);
428 unlink(outputfilename);
429 sprintf(outputfilename, "./htdocs/%s-%c-S.png", CharIp, config.tag);
430 unlink(outputfilename);
431 }
432
433 gdImageDestroy(im);
434 gdImageDestroy(im2);
435 }
436
437 // Returns YMax
GraphData(gdImagePtr im,gdImagePtr im2,struct IPDataStore * DataStore,time_t timestamp,struct SummaryData * SummaryData)438 unsigned long long int GraphData(gdImagePtr im, gdImagePtr im2, struct IPDataStore *DataStore, time_t timestamp, struct SummaryData *SummaryData)
439 {
440 unsigned long long int YMax=0;
441
442 struct DataStoreBlock *CurrentBlock;
443 struct IPData *Data;
444
445 // TODO: These should be a structure!!!!
446 // TODO: This is an awfull lot of data to be allocated on the stack
447
448 unsigned long long total[XWIDTH];
449 unsigned long long icmp[XWIDTH];
450 unsigned long long udp[XWIDTH];
451 unsigned long long tcp[XWIDTH];
452 unsigned long long ftp[XWIDTH];
453 unsigned long long http[XWIDTH];
454 unsigned long long p2p[XWIDTH];
455 int Count[XWIDTH];
456
457 unsigned long long total2[XWIDTH];
458 unsigned long long icmp2[XWIDTH];
459 unsigned long long udp2[XWIDTH];
460 unsigned long long tcp2[XWIDTH];
461 unsigned long long ftp2[XWIDTH];
462 unsigned long long http2[XWIDTH];
463 unsigned long long p2p2[XWIDTH];
464
465 size_t DataPoints;
466 double x;
467 int xint;
468 int Counter;
469 char Buffer[30];
470 char Buffer2[50];
471
472 int blue, lblue, red, yellow, purple, green, brown, black;
473 int blue2, lblue2, red2, yellow2, purple2, green2, brown2, black2;
474
475 unsigned long long int SentPeak = 0;
476 unsigned long long int ReceivedPeak = 0;
477
478 yellow = gdImageColorAllocate(im, 255, 255, 0);
479 purple = gdImageColorAllocate(im, 255, 0, 255);
480 green = gdImageColorAllocate(im, 0, 255, 0);
481 blue = gdImageColorAllocate(im, 0, 0, 255);
482 lblue = gdImageColorAllocate(im, 128, 128, 255);
483 brown = gdImageColorAllocate(im, 128, 0, 0);
484 red = gdImageColorAllocate(im, 255, 0, 0);
485 black = gdImageColorAllocate(im, 0, 0, 0);
486
487 yellow2 = gdImageColorAllocate(im2, 255, 255, 0);
488 purple2 = gdImageColorAllocate(im2, 255, 0, 255);
489 green2 = gdImageColorAllocate(im2, 0, 255, 0);
490 blue2 = gdImageColorAllocate(im2, 0, 0, 255);
491 lblue2 = gdImageColorAllocate(im2, 128, 128, 255);
492 brown2 = gdImageColorAllocate(im2, 128, 0, 0);
493 red2 = gdImageColorAllocate(im2, 255, 0, 0);
494 black2 = gdImageColorAllocate(im2, 0, 0, 0);
495
496 CurrentBlock = DataStore->FirstBlock;
497 Data = CurrentBlock->Data;
498 DataPoints = CurrentBlock->NumEntries;
499
500 memset(SummaryData, 0, sizeof(struct SummaryData));
501 SummaryData->IP = Data[0].ip;
502
503 memset(Count, 0, sizeof(Count[0])*XWIDTH);
504
505 memset(total, 0, sizeof(total[0])*XWIDTH);
506 memset(icmp, 0, sizeof(total[0])*XWIDTH);
507 memset(udp, 0, sizeof(total[0])*XWIDTH);
508 memset(tcp, 0, sizeof(total[0])*XWIDTH);
509 memset(ftp, 0, sizeof(total[0])*XWIDTH);
510 memset(http, 0, sizeof(total[0])*XWIDTH);
511 memset(p2p, 0, sizeof(total[0])*XWIDTH);
512
513 memset(total2, 0, sizeof(total[0])*XWIDTH);
514 memset(icmp2, 0, sizeof(total[0])*XWIDTH);
515 memset(udp2, 0, sizeof(total[0])*XWIDTH);
516 memset(tcp2, 0, sizeof(total[0])*XWIDTH);
517 memset(ftp2, 0, sizeof(total[0])*XWIDTH);
518 memset(http2, 0, sizeof(total[0])*XWIDTH);
519 memset(p2p2, 0, sizeof(total[0])*XWIDTH);
520
521 // Change this to just run through all the datapoints we have stored in ram
522
523 // Sum up the bytes/second
524 while(DataPoints > 0) // We have data to graph
525 {
526 for (Counter = 0; Counter < DataPoints; Counter++) // Graph it all
527 {
528 x = (Data[Counter].timestamp-timestamp)*((XWIDTH-XOFFSET)/config.range)+XOFFSET;
529 xint = x;
530
531 if (xint >= 0 && xint < XWIDTH)
532 {
533 Count[xint]++;
534
535 if (Data[Counter].Send.total > SentPeak)
536 SentPeak = Data[Counter].Send.total;
537 total[xint] += Data[Counter].Send.total;
538 icmp[xint] += Data[Counter].Send.icmp;
539 udp[xint] += Data[Counter].Send.udp;
540 tcp[xint] += Data[Counter].Send.tcp;
541 ftp[xint] += Data[Counter].Send.ftp;
542 http[xint] += Data[Counter].Send.http;
543 p2p[xint] += Data[Counter].Send.p2p;
544
545 if (Data[Counter].Receive.total > ReceivedPeak)
546 ReceivedPeak = Data[Counter].Receive.total;
547 total2[xint] += Data[Counter].Receive.total;
548 icmp2[xint] += Data[Counter].Receive.icmp;
549 udp2[xint] += Data[Counter].Receive.udp;
550 tcp2[xint] += Data[Counter].Receive.tcp;
551 ftp2[xint] += Data[Counter].Receive.ftp;
552 http2[xint] += Data[Counter].Receive.http;
553 p2p2[xint] += Data[Counter].Receive.p2p;
554 }
555 }
556
557 CurrentBlock = CurrentBlock->Next;
558
559 if (CurrentBlock)
560 {
561 Data = CurrentBlock->Data;
562 DataPoints = CurrentBlock->NumEntries;
563 }
564 else
565 DataPoints = 0;
566 }
567
568 // Convert SentPeak and ReceivedPeak from bytes to bytes/second
569 SentPeak /= config.interval; ReceivedPeak /= config.interval;
570
571 // Preform the Average
572 for(Counter=XOFFSET+1; Counter < XWIDTH; Counter++)
573 {
574 if (Count[Counter] > 0)
575 {
576 SummaryData->Total += total[Counter] + total2[Counter];
577 SummaryData->TotalSent += total[Counter];
578 SummaryData->TotalReceived += total2[Counter];
579 SummaryData->TCP += tcp[Counter] + tcp2[Counter];
580 SummaryData->FTP += ftp[Counter] + ftp2[Counter];
581 SummaryData->HTTP += http[Counter] + http2[Counter];
582 SummaryData->P2P += p2p[Counter] + p2p2[Counter];
583 SummaryData->UDP += udp[Counter] + udp2[Counter];
584 SummaryData->ICMP += icmp[Counter] + icmp2[Counter];
585
586 // Preform the average
587 total[Counter] /= (Count[Counter]*config.interval);
588 tcp[Counter] /= (Count[Counter]*config.interval);
589 ftp[Counter] /= (Count[Counter]*config.interval);
590 http[Counter] /= (Count[Counter]*config.interval);
591 p2p[Counter] /= (Count[Counter]*config.interval);
592 udp[Counter] /= (Count[Counter]*config.interval);
593 icmp[Counter] /= (Count[Counter]*config.interval);
594
595 total2[Counter] /= (Count[Counter]*config.interval);
596 tcp2[Counter] /= (Count[Counter]*config.interval);
597 ftp2[Counter] /= (Count[Counter]*config.interval);
598 http2[Counter] /= (Count[Counter]*config.interval);
599 p2p2[Counter] /= (Count[Counter]*config.interval);
600 udp2[Counter] /= (Count[Counter]*config.interval);
601 icmp2[Counter] /= (Count[Counter]*config.interval);
602
603
604 if (total[Counter] > YMax)
605 YMax = total[Counter];
606
607 if (total2[Counter] > YMax)
608 YMax = total2[Counter];
609 }
610 }
611
612 YMax += YMax*0.05; // Add an extra 5%
613
614 if ((SummaryData->IP != 0 && SummaryData->Total < config.graph_cutoff))
615 {
616 SummaryData->Graph = FALSE;
617 return(0);
618 }
619 else
620 SummaryData->Graph = TRUE;
621
622 // Plot the points
623 for(Counter=XOFFSET+1; Counter < XWIDTH; Counter++)
624 {
625 if (Count[Counter] > 0)
626 {
627 // Convert the bytes/sec to y coords
628 total[Counter] = (total[Counter]*(YHEIGHT-YOFFSET))/YMax;
629 tcp[Counter] = (tcp[Counter]*(YHEIGHT-YOFFSET))/YMax;
630 ftp[Counter] = (ftp[Counter]*(YHEIGHT-YOFFSET))/YMax;
631 http[Counter] = (http[Counter]*(YHEIGHT-YOFFSET))/YMax;
632 p2p[Counter] = (p2p[Counter]*(YHEIGHT-YOFFSET))/YMax;
633 udp[Counter] = (udp[Counter]*(YHEIGHT-YOFFSET))/YMax;
634 icmp[Counter] = (icmp[Counter]*(YHEIGHT-YOFFSET))/YMax;
635
636 total2[Counter] = (total2[Counter]*(YHEIGHT-YOFFSET))/YMax;
637 tcp2[Counter] = (tcp2[Counter]*(YHEIGHT-YOFFSET))/YMax;
638 ftp2[Counter] = (ftp2[Counter]*(YHEIGHT-YOFFSET))/YMax;
639 http2[Counter] = (http2[Counter]*(YHEIGHT-YOFFSET))/YMax;
640 p2p2[Counter] = (p2p2[Counter]*(YHEIGHT-YOFFSET))/YMax;
641 udp2[Counter] = (udp2[Counter]*(YHEIGHT-YOFFSET))/YMax;
642 icmp2[Counter] = (icmp2[Counter]*(YHEIGHT-YOFFSET))/YMax;
643
644 // Stack 'em up!
645 // Total is stacked from the bottom
646 // Icmp is on the bottom too
647 // Udp is stacked on top of icmp
648 udp[Counter] += icmp[Counter];
649 udp2[Counter] += icmp2[Counter];
650 // TCP and p2p are stacked on top of Udp
651 tcp[Counter] += udp[Counter];
652 tcp2[Counter] += udp2[Counter];
653 p2p[Counter] += udp[Counter];
654 p2p2[Counter] += udp2[Counter];
655 // Http is stacked on top of p2p
656 http[Counter] += p2p[Counter];
657 http2[Counter] += p2p2[Counter];
658 // Ftp is stacked on top of http
659 ftp[Counter] += http[Counter];
660 ftp2[Counter] += http2[Counter];
661
662 // Plot them!
663 // Sent
664 gdImageLine(im, Counter, (YHEIGHT-YOFFSET) - total[Counter], Counter, YHEIGHT-YOFFSET-1, yellow);
665 gdImageLine(im, Counter, (YHEIGHT-YOFFSET) - icmp[Counter], Counter, YHEIGHT-YOFFSET-1, red);
666 gdImageLine(im, Counter, (YHEIGHT-YOFFSET) - udp[Counter], Counter, (YHEIGHT-YOFFSET) - icmp[Counter] - 1, brown);
667 gdImageLine(im, Counter, (YHEIGHT-YOFFSET) - tcp[Counter], Counter, (YHEIGHT-YOFFSET) - udp[Counter] - 1, green);
668 gdImageLine(im, Counter, (YHEIGHT-YOFFSET) - p2p[Counter], Counter, (YHEIGHT-YOFFSET) - udp[Counter] - 1, purple);
669 gdImageLine(im, Counter, (YHEIGHT-YOFFSET) - http[Counter], Counter, (YHEIGHT-YOFFSET) - p2p[Counter] - 1, blue);
670 gdImageLine(im, Counter, (YHEIGHT-YOFFSET) - ftp[Counter], Counter, (YHEIGHT-YOFFSET) - http[Counter] - 1, lblue);
671
672 // Receive
673 gdImageLine(im2, Counter, (YHEIGHT-YOFFSET) - total2[Counter], Counter, YHEIGHT-YOFFSET-1, yellow2);
674 gdImageLine(im2, Counter, (YHEIGHT-YOFFSET) - icmp2[Counter], Counter, YHEIGHT-YOFFSET-1, red2);
675 gdImageLine(im2, Counter, (YHEIGHT-YOFFSET) - udp2[Counter], Counter, (YHEIGHT-YOFFSET) - icmp2[Counter] - 1, brown2);
676 gdImageLine(im2, Counter, (YHEIGHT-YOFFSET) - tcp2[Counter], Counter, (YHEIGHT-YOFFSET) - udp2[Counter] - 1, green2);
677 gdImageLine(im2, Counter, (YHEIGHT-YOFFSET) - p2p2[Counter], Counter, (YHEIGHT-YOFFSET) - udp2[Counter] - 1, purple2);
678 gdImageLine(im2, Counter, (YHEIGHT-YOFFSET) - http2[Counter], Counter, (YHEIGHT-YOFFSET) - p2p2[Counter] - 1, blue2);
679 gdImageLine(im2, Counter, (YHEIGHT-YOFFSET) - ftp2[Counter], Counter, (YHEIGHT-YOFFSET) - http2[Counter] - 1, lblue2);
680
681
682 }
683 }
684
685 if (SentPeak < 1024/8)
686 snprintf(Buffer2, 50, "Peak Send Rate: %.1f Bits/sec", (double)SentPeak*8);
687 else if (SentPeak < (1024*1024)/8)
688 snprintf(Buffer2, 50, "Peak Send Rate: %.1f KBits/sec", ((double)SentPeak*8.0)/1024.0);
689 else snprintf(Buffer2, 50, "Peak Send Rate: %.1f MBits/sec", ((double)SentPeak*8.0)/(1024.0*1024.0));
690
691 if (SummaryData->TotalSent < 1024)
692 snprintf(Buffer, 30, "Sent %.1f Bytes", (double)SummaryData->TotalSent);
693 else if (SummaryData->TotalSent < 1024*1024)
694 snprintf(Buffer, 30, "Sent %.1f KBytes", (double)SummaryData->TotalSent/1024.0);
695 else snprintf(Buffer, 30, "Sent %.1f MBytes", (double)SummaryData->TotalSent/(1024.0*1024.0));
696
697 gdImageString(im, gdFontSmall, XOFFSET+5, YHEIGHT-20, Buffer, black);
698 gdImageString(im, gdFontSmall, XWIDTH/2+XOFFSET/2, YHEIGHT-20, Buffer2, black);
699
700 if (ReceivedPeak < 1024/8)
701 snprintf(Buffer2, 50, "Peak Receive Rate: %.1f Bits/sec", (double)ReceivedPeak*8);
702 else if (ReceivedPeak < (1024*1024)/8)
703 snprintf(Buffer2, 50, "Peak Receive Rate: %.1f KBits/sec", ((double)ReceivedPeak*8.0)/1024.0);
704 else snprintf(Buffer2, 50, "Peak Receive Rate: %.1f MBits/sec", ((double)ReceivedPeak*8.0)/(1024.0*1024.0));
705
706 if (SummaryData->TotalReceived < 1024)
707 snprintf(Buffer, 30, "Received %.1f Bytes", (double)SummaryData->TotalReceived);
708 else if (SummaryData->TotalReceived < 1024*1024)
709 snprintf(Buffer, 30, "Received %.1f KBytes", (double)SummaryData->TotalReceived/1024.0);
710 else snprintf(Buffer, 30, "Received %.1f MBytes", (double)SummaryData->TotalReceived/(1024.0*1024.0));
711
712 gdImageString(im2, gdFontSmall, XOFFSET+5, YHEIGHT-20, Buffer, black2);
713 gdImageString(im2, gdFontSmall, XWIDTH/2+XOFFSET/2, YHEIGHT-20, Buffer2, black2);
714
715 return(YMax);
716 }
717
PrepareYAxis(gdImagePtr im,unsigned long long int YMax)718 void PrepareYAxis(gdImagePtr im, unsigned long long int YMax)
719 {
720 char buffer[20];
721
722 char YLegend;
723 long long int Divisor;
724
725 int black;
726 float YTic = 0;
727 double y;
728 long int YStep;
729
730 black = gdImageColorAllocate(im, 0, 0, 0);
731 gdImageLine(im, XOFFSET, 0, XOFFSET, YHEIGHT, black);
732
733 YLegend = ' ';
734 Divisor = 1;
735 if (YMax*8 > 1024*2)
736 {
737 Divisor = 1024; // Display in K
738 YLegend = 'k';
739 }
740 if (YMax*8 > 1024*1024*2)
741 {
742 Divisor = 1024*1024; // Display in M
743 YLegend = 'm';
744 }
745 if (YMax*8 > (long long)1024*1024*1024*2)
746 {
747 Divisor = 1024*1024*1024; // Display in G
748 YLegend = 'g';
749 }
750
751 YStep = YMax/10;
752 if (YStep < 1)
753 YStep=1;
754 YTic=YStep;
755
756 while (YTic < (YMax - YMax/10))
757 {
758 y = (YHEIGHT-YOFFSET)-((YTic*(YHEIGHT-YOFFSET))/YMax);
759
760 gdImageLine(im, XOFFSET, y, XWIDTH, y, black);
761 snprintf(buffer, 20, "%4.1f %cbits/s", (float)(8.0*YTic)/Divisor, YLegend);
762 gdImageString(im, gdFontSmall, 3, y-7, buffer, black);
763
764 YTic += YStep;
765 }
766 }
767
PrepareXAxis(gdImagePtr im,time_t timestamp)768 void PrepareXAxis(gdImagePtr im, time_t timestamp)
769 {
770 char buffer[100];
771 int black, red;
772 time_t sample_begin, sample_end;
773 struct tm *timestruct;
774 long int MarkTime;
775 long int MarkTimeStep;
776 double x;
777
778 sample_begin=timestamp-config.range;
779 sample_end=sample_begin+config.interval;
780
781 black = gdImageColorAllocate(im, 0, 0, 0);
782 red = gdImageColorAllocate(im, 255, 0, 0);
783
784 gdImageLine(im, 0, YHEIGHT-YOFFSET, XWIDTH, YHEIGHT-YOFFSET, black);
785
786 // ********************************************************************
787 // **** Write the red day/month seperator bars
788 // ********************************************************************
789
790 if ((24*60*60*(XWIDTH-XOFFSET))/config.range > (XWIDTH-XOFFSET)/10)
791 {
792 // Day bars
793 timestruct = localtime((time_t *)&sample_begin);
794 timestruct->tm_sec = 0;
795 timestruct->tm_min = 0;
796 timestruct->tm_hour = 0;
797 MarkTime = mktime(timestruct);
798
799 x = (MarkTime-sample_begin)*( ((double)(XWIDTH-XOFFSET)) / config.range) + XOFFSET;
800 while (x < XOFFSET)
801 {
802 MarkTime += (24*60*60);
803 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
804 }
805
806 while (x < (XWIDTH-10))
807 {
808 // Day Lines
809 gdImageLine(im, x, 0, x, YHEIGHT-YOFFSET, red);
810 gdImageLine(im, x+1, 0, x+1, YHEIGHT-YOFFSET, red);
811
812 timestruct = localtime((time_t *)&MarkTime);
813 strftime(buffer, 100, "%a, %b %d", timestruct);
814 gdImageString(im, gdFontSmall, x-30, YHEIGHT-YOFFSET+10, buffer, black);
815
816 // Calculate Next x
817 MarkTime += (24*60*60);
818 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
819 }
820 }
821 else
822 {
823 // Month Bars
824 timestruct = localtime((time_t *)&sample_begin);
825 timestruct->tm_sec = 0;
826 timestruct->tm_min = 0;
827 timestruct->tm_hour = 0;
828 timestruct->tm_mday = 1;
829 timestruct->tm_mon--; // Start the month before the sample
830 MarkTime = mktime(timestruct);
831
832 x = (MarkTime-sample_begin)*( ((double)(XWIDTH-XOFFSET)) / config.range) + XOFFSET;
833 while (x < XOFFSET)
834 {
835 timestruct->tm_mon++;
836 MarkTime = mktime(timestruct);
837 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
838 }
839
840 while (x < (XWIDTH-10))
841 {
842 // Month Lines
843 gdImageLine(im, x, 0, x, YHEIGHT-YOFFSET, red);
844 gdImageLine(im, x+1, 0, x+1, YHEIGHT-YOFFSET, red);
845
846 timestruct = localtime((time_t *)&MarkTime);
847 strftime(buffer, 100, "%b", timestruct);
848 gdImageString(im, gdFontSmall, x-6, YHEIGHT-YOFFSET+10, buffer, black);
849
850 // Calculate Next x
851 timestruct->tm_mon++;
852 MarkTime = mktime(timestruct);
853 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
854 }
855 }
856
857 // ********************************************************************
858 // **** Write the tic marks
859 // ********************************************************************
860
861 timestruct = localtime((time_t *)&sample_begin);
862 timestruct->tm_sec = 0;
863 timestruct->tm_min = 0;
864 timestruct->tm_hour = 0;
865 MarkTime = mktime(timestruct);
866
867 if ((6*60*60*(XWIDTH-XOFFSET))/config.range > 10) // pixels per 6 hours is more than 2
868 MarkTimeStep = 6*60*60; // Major ticks are 6 hours
869 else if ((24*60*60*(XWIDTH-XOFFSET))/config.range > 10)
870 MarkTimeStep = 24*60*60; // Major ticks are 24 hours;
871 else
872 return; // Done
873
874 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
875 while (x < XOFFSET)
876 {
877 MarkTime += MarkTimeStep;
878 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
879 }
880
881 while (x < (XWIDTH-10))
882 {
883 if (x > XOFFSET) {
884 gdImageLine(im, x, YHEIGHT-YOFFSET-5, x, YHEIGHT-YOFFSET+5, black);
885 gdImageLine(im, x+1, YHEIGHT-YOFFSET-5, x+1, YHEIGHT-YOFFSET+5, black);
886 }
887 MarkTime += MarkTimeStep;
888 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
889 }
890
891 timestruct = localtime((time_t *)&sample_begin);
892 timestruct->tm_sec = 0;
893 timestruct->tm_min = 0;
894 timestruct->tm_hour = 0;
895 MarkTime = mktime(timestruct);
896
897 if ((60*60*(XWIDTH-XOFFSET))/config.range > 2) // pixels per hour is more than 2
898 MarkTimeStep = 60*60; // Minor ticks are 1 hour
899 else if ((6*60*60*(XWIDTH-XOFFSET))/config.range > 2)
900 MarkTimeStep = 6*60*60; // Minor ticks are 6 hours
901 else if ((24*60*60*(XWIDTH-XOFFSET))/config.range > 2)
902 MarkTimeStep = 24*60*60;
903 else
904 return; // Done
905
906 // Draw Minor Tic Marks
907 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
908
909 while (x < XOFFSET)
910 {
911 MarkTime += MarkTimeStep;
912 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
913 }
914
915 while (x < (XWIDTH-10))
916 {
917 if (x > XOFFSET) {
918 gdImageLine(im, x, YHEIGHT-YOFFSET, x, YHEIGHT-YOFFSET+5, black);
919 gdImageLine(im, x+1, YHEIGHT-YOFFSET, x+1, YHEIGHT-YOFFSET+5, black);
920 }
921 MarkTime+=MarkTimeStep;
922 x = (MarkTime-sample_begin)*((XWIDTH-XOFFSET)/config.range) + XOFFSET;
923 }
924 }
925
926
927