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&nbsp;</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