Project

General

Profile

Download (14.6 KB) Statistics
| Branch: | Tag: | Revision:
1 5b237745 Scott Ullrich
<?php
2
/*
3
	graph.php
4 6afa3a82 Scott Ullrich
	part of m0n0wall (http://m0n0.ch/wall)
5
	
6 985a897f Scott Ullrich
	Copyright (C) 2004-2006 T. Lechat <dev@lechat.org>, Manuel Kasper <mk@neon1.net>
7 6afa3a82 Scott Ullrich
	and Jonathan Watt <jwatt@jwatt.org>.
8 5b237745 Scott Ullrich
	All rights reserved.
9 6afa3a82 Scott Ullrich
	
10 5b237745 Scott Ullrich
	Redistribution and use in source and binary forms, with or without
11
	modification, are permitted provided that the following conditions are met:
12 6afa3a82 Scott Ullrich
	
13 5b237745 Scott Ullrich
	1. Redistributions of source code must retain the above copyright notice,
14
	   this list of conditions and the following disclaimer.
15 6afa3a82 Scott Ullrich
	
16 5b237745 Scott Ullrich
	2. Redistributions in binary form must reproduce the above copyright
17
	   notice, this list of conditions and the following disclaimer in the
18
	   documentation and/or other materials provided with the distribution.
19 6afa3a82 Scott Ullrich
	
20 5b237745 Scott Ullrich
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
	POSSIBILITY OF SUCH DAMAGE.
30
*/
31 7ac5a4cb Scott Ullrich
/*
32
	pfSense_MODULE:	graph
33
*/
34 5b237745 Scott Ullrich
35 6b07c15a Matthew Grooms
##|+PRIV
36
##|*IDENT=page-diagnostics-interfacetraffic
37
##|*NAME=Diagnostics: Interface Traffic page
38
##|*DESCR=Allow access to the 'Diagnostics: Interface Traffic' page.
39
##|*MATCH=graph.php*
40
##|-PRIV
41
42 12e437a2 Scott Ullrich
require("globals.inc");
43 8b379e47 Scott Ullrich
require("guiconfig.inc");
44 beb54c8f Scott Ullrich
45 45581172 Ermal Luçi
header("Last-Modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" );
46
header("Expires: " . gmdate( "D, j M Y H:i:s", time() ) . " GMT" );
47
header("Cache-Control: no-store, no-cache, must-revalidate" ); // HTTP/1.1
48
header("Cache-Control: post-check=0, pre-check=0", FALSE );
49
header("Pragma: no-cache"); // HTTP/1.0
50 6afa3a82 Scott Ullrich
header("Content-type: image/svg+xml");
51 5b237745 Scott Ullrich
52
/********** HTTP GET Based Conf ***********/
53 6afa3a82 Scott Ullrich
$ifnum=@$_GET["ifnum"];  // BSD / SNMP interface name / number
54
$ifname=@$_GET["ifname"]?$_GET["ifname"]:"Interface $ifnum";  //Interface name that will be showed on top right of graph
55 5b237745 Scott Ullrich
56
/********* Other conf *******/
57 6afa3a82 Scott Ullrich
$scale_type="up";               //Autoscale default setup : "up" = only increase scale; "follow" = increase and decrease scale according to current graphed datas
58
$nb_plot=120;                   //NB plot in graph
59 358cb12c Scott Dale
if ($_GET["timeint"])
60
	$time_interval = $_GET["timeint"];		//Refresh time Interval
61
else
62 920e60b5 Scott Ullrich
	$time_interval = 3;
63 0543e1e9 Scott Ullrich
64 6afa3a82 Scott Ullrich
//SVG attributes
65
$attribs['axis']='fill="black" stroke="black"';
66 a85f75c2 Scott Ullrich
$attribs['in']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
67
$attribs['out']='fill="#000000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
68
$attribs['graph_in']='fill="none" stroke="#FF0000" stroke-opacity="0.8"';
69
$attribs['graph_out']='fill="none" stroke="#000000" stroke-opacity="0.8"';
70 6afa3a82 Scott Ullrich
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
71 a85f75c2 Scott Ullrich
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
72 6afa3a82 Scott Ullrich
$attribs['grid_txt']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="6"';
73
$attribs['grid']='stroke="gray" stroke-opacity="0.5"';
74 a85f75c2 Scott Ullrich
$attribs['switch_unit']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
75
$attribs['switch_scale']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
76 6afa3a82 Scott Ullrich
$attribs['error']='fill="blue" font-family="Arial" font-size="4"';
77
$attribs['collect_initial']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
78 5b237745 Scott Ullrich
79
//Error text if we cannot fetch data : depends on which method is used
80
$error_text = "Cannot get data about interface $ifnum";
81
82 6afa3a82 Scott Ullrich
$height=100;            //SVG internal height : do not modify
83
$width=200;             //SVG internal width : do not modify
84 5b237745 Scott Ullrich
85 72d1b575 Scott Ullrich
$fetch_link = "ifstats.php?if={$ifnum}";
86
87
/* check for custom theme colors */
88
if(file_exists("/usr/local/www/themes/{$g['theme']}/graph.php")) {
89
	$themetxt = file_get_contents("/usr/local/www/themes/{$g['theme']}/graph.php");
90
	eval($themetxt);
91
} 
92
93 5b237745 Scott Ullrich
/********* Graph DATA **************/
94 6afa3a82 Scott Ullrich
print('<?xml version="1.0" encoding="iso-8859-1"?>' . "\n");?>
95
<svg width="100%" height="100%" viewBox="0 0 <?=$width?> <?=$height?>" preserveAspectRatio="none" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="init(evt)">
96
  <g id="graph">
97
    <rect id="bg" x1="0" y1="0" width="100%" height="100%" fill="white"/>
98
    <line id="axis_x" x1="0" y1="0" x2="0" y2="100%" <?=$attribs['axis']?>/>
99
    <line id="axis_y" x1="0" y1="100%" x2="100%" y2="100%" <?=$attribs['axis']?>/>
100
    <path id="graph_out" d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_out']?>/>
101
    <path id="graph_in"  d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_in']?>/>
102
    <path id="grid"  d="M0 <?=$height/4*1?> L <?=$width?> <?=$height/4*1?> M0 <?=$height/4*2?> L <?=$width?> <?=$height/4*2?> M0 <?=$height/4*3?> L <?=$width?> <?=$height/4*3?>" <?=$attribs['grid']?>/>
103
    <text id="grid_txt1" x="<?=$width?>" y="<?=$height/4*1?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
104
    <text id="grid_txt2" x="<?=$width?>" y="<?=$height/4*2?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
105
    <text id="grid_txt3" x="<?=$width?>" y="<?=$height/4*3?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
106 8454080a Carlos Eduardo Ramos
    <text id="graph_in_lbl" x="5" y="8" <?=$attribs['in']?>><?=gettext("In"); ?></text>
107
    <text id="graph_out_lbl" x="5" y="16" <?=$attribs['out']?>><?=gettext("Out"); ?></text>
108 6afa3a82 Scott Ullrich
    <text id="graph_in_txt" x="20" y="8" <?=$attribs['in']?>> </text>
109
    <text id="graph_out_txt" x="20" y="16" <?=$attribs['out']?>> </text>
110
    <text id="ifname" x="<?=$width?>" y="8" <?=$attribs['graphname']?> text-anchor="end"><?=$ifname?></text>
111 8454080a Carlos Eduardo Ramos
    <text id="switch_unit" x="<?=$width*0.55?>" y="5" <?=$attribs['switch_unit']?>><?=gettext("Switch to bytes/s"); ?></text>
112
    <text id="switch_scale" x="<?=$width*0.55?>" y="11" <?=$attribs['switch_scale']?>><?=gettext("AutoScale"); ?> (<?=$scale_type?>)</text>
113 6afa3a82 Scott Ullrich
    <text id="datetime" x="<?=$width*0.33?>" y="5" <?=$attribs['legend']?>> </text>
114 8454080a Carlos Eduardo Ramos
    <text id="graphlast" x="<?=$width*0.55?>" y="17" <?=$attribs['legend']?>><?=gettext("Graph shows last"); ?> <?=$time_interval*$nb_plot?> <?=gettext("seconds"); ?></text>
115 6afa3a82 Scott Ullrich
    <polygon id="axis_arrow_x" <?=$attribs['axis']?> points="<?=($width) . "," . ($height)?> <?=($width-2) . "," . ($height-2)?> <?=($width-2) . "," . $height?>"/>
116
    <text id="error" x="<?=$width*0.5?>" y="<?=$height*0.5?>"  visibility="hidden" <?=$attribs['error']?> text-anchor="middle"><?=$error_text?></text>
117 8454080a Carlos Eduardo Ramos
    <text id="collect_initial" x="<?=$width*0.5?>" y="<?=$height*0.5?>"  visibility="hidden" <?=$attribs['collect_initial']?> text-anchor="middle"><?=gettext("Collecting initial data, please wait"); ?>...</text>
118 6afa3a82 Scott Ullrich
  </g>
119
  <script type="text/ecmascript">
120
    <![CDATA[
121
122
/**
123
 * getURL is a proprietary Adobe function, but it's simplicity has made it very
124
 * popular. If getURL is undefined we spin our own by wrapping XMLHttpRequest.
125
 */
126
if (typeof getURL == 'undefined') {
127
  getURL = function(url, callback) {
128
    if (!url)
129 8454080a Carlos Eduardo Ramos
      throw '<?=gettext("No URL for getURL"); ?>';
130 6afa3a82 Scott Ullrich
131
    try {
132
      if (typeof callback.operationComplete == 'function')
133
        callback = callback.operationComplete;
134
    } catch (e) {}
135
    if (typeof callback != 'function')
136 8454080a Carlos Eduardo Ramos
      throw '<?=gettext("No callback function for getURL"); ?>';
137 6afa3a82 Scott Ullrich
138
    var http_request = null;
139
    if (typeof XMLHttpRequest != 'undefined') {
140
      http_request = new XMLHttpRequest();
141
    }
142
    else if (typeof ActiveXObject != 'undefined') {
143
      try {
144
        http_request = new ActiveXObject('Msxml2.XMLHTTP');
145
      } catch (e) {
146
        try {
147
          http_request = new ActiveXObject('Microsoft.XMLHTTP');
148
        } catch (e) {}
149
      }
150
    }
151
    if (!http_request)
152 8454080a Carlos Eduardo Ramos
      throw '<?=gettext("Both getURL and XMLHttpRequest are undefined"); ?>';
153 6afa3a82 Scott Ullrich
154
    http_request.onreadystatechange = function() {
155
      if (http_request.readyState == 4) {
156
        callback( { success : true,
157
                    content : http_request.responseText,
158
                    contentType : http_request.getResponseHeader("Content-Type") } );
159
      }
160
    }
161
    http_request.open('GET', url, true);
162
    http_request.send(null);
163
  }
164
}
165
166
var SVGDoc = null;
167
var last_ifin = 0;
168
var last_ifout = 0;
169
var last_ugmt = 0;
170 5b237745 Scott Ullrich
var max = 0;
171 6afa3a82 Scott Ullrich
var plot_in = new Array();
172
var plot_out = new Array();
173 5b237745 Scott Ullrich
174 6afa3a82 Scott Ullrich
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
175
var step = <?=$width?> / max_num_points ;
176 5b237745 Scott Ullrich
var unit = 'bits';
177
var scale_type = '<?=$scale_type?>';
178
179
function init(evt) {
180 6afa3a82 Scott Ullrich
  SVGDoc = evt.target.ownerDocument;
181
  SVGDoc.getElementById("switch_unit").addEventListener("mousedown", switch_unit, false);
182
  SVGDoc.getElementById("switch_scale").addEventListener("mousedown", switch_scale, false);
183 5b237745 Scott Ullrich
184 6afa3a82 Scott Ullrich
  fetch_data();
185 5b237745 Scott Ullrich
}
186
187
function switch_unit(event)
188
{
189 8454080a Carlos Eduardo Ramos
  SVGDoc.getElementById('switch_unit').firstChild.data = '<?=gettext("Switch to"); ?> ' + unit + '/s';
190 6afa3a82 Scott Ullrich
  unit = (unit == 'bits') ? 'bytes' : 'bits';
191 5b237745 Scott Ullrich
}
192
193
function switch_scale(event)
194
{
195 8454080a Carlos Eduardo Ramos
  scale_type = (scale_type == 'up') ? '<?=gettext("follow"); ?>' : '<?=gettext("up"); ?>';
196 6afa3a82 Scott Ullrich
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
197 5b237745 Scott Ullrich
}
198
199 6afa3a82 Scott Ullrich
function fetch_data() {
200
  getURL('<?=$fetch_link?>', plot_data);
201 5b237745 Scott Ullrich
}
202
203 6afa3a82 Scott Ullrich
function plot_data(obj) {
204
  // Show datetimelegend
205
  var now = new Date();
206
  var datetime = (now.getMonth()+1) + "/" + now.getDate() + "/" + now.getFullYear() + ' ' + 
207
    LZ(now.getHours()) + ":" + LZ(now.getMinutes()) + ":" + LZ(now.getSeconds());
208
  SVGDoc.getElementById('datetime').firstChild.data = datetime;
209
210
  if (!obj.success)
211
    return handle_error();  // getURL failed to get data
212
213
  var t = obj.content.split("|");
214
  var ugmt = parseFloat(t[0]);  // ugmt is an unixtimestamp style
215
  var ifin = parseInt(t[1]);    // number of bytes received by the interface
216
  var ifout = parseInt(t[2]);   // number of bytes sent by the interface
217
  var scale;
218
219
  if (!isNumber(ifin) || !isNumber(ifout))
220
    return handle_error();
221
222
  var diff_ugmt  = ugmt - last_ugmt;
223 67c04e80 Seth Mos
  var diff_ifin  = ifin - last_ifin;
224
  var diff_ifout = ifout - last_ifout;
225
226 6afa3a82 Scott Ullrich
  if (diff_ugmt == 0)
227
    diff_ugmt = 1;  /* avoid division by zero */
228
229
  last_ugmt = ugmt;
230
  last_ifin = ifin;
231
  last_ifout = ifout;
232
  
233
  switch (plot_in.length) {
234
  	case 0:
235
  		SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'visible');
236
		plot_in[0] = diff_ifin / diff_ugmt;
237
		plot_out[0] = diff_ifout / diff_ugmt;
238
		setTimeout('fetch_data()',<?=1000*$time_interval?>);
239
		return;
240
	case 1:
241
    	SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'hidden');
242
    	break;
243
    case max_num_points:
244
		// shift plot to left if the maximum number of plot points has been reached
245
		var i = 0;
246
		while (i < max_num_points) {
247
		  plot_in[i] = plot_in[i+1];
248
		  plot_out[i] = plot_out[++i];
249 5b237745 Scott Ullrich
		}
250 6afa3a82 Scott Ullrich
		plot_in.length--;
251
		plot_out.length--;
252
  }
253
254
  plot_in[plot_in.length] = diff_ifin / diff_ugmt;
255
  plot_out[plot_out.length]= diff_ifout / diff_ugmt;
256
  var index_plot = plot_in.length - 1;
257
258
  SVGDoc.getElementById('graph_in_txt').firstChild.data = formatSpeed(plot_in[index_plot], unit);
259
  SVGDoc.getElementById('graph_out_txt').firstChild.data = formatSpeed(plot_out[index_plot], unit);
260
261
  /* determine peak for sensible scaling */
262
  if (scale_type == 'up') {
263
    if (plot_in[index_plot] > max)
264
      max = plot_in[index_plot];
265
    if (plot_out[index_plot] > max)
266
      max = plot_out[index_plot];
267
  }
268
  else if (scale_type == 'follow') {
269
    i = 0;
270
    max = 0;
271
    while (i < plot_in.length) {
272
      if (plot_in[i] > max)
273
        max = plot_in[i];
274
      if (plot_out[i] > max)
275
        max = plot_out[i];
276
      i++;
277
    }
278
  }
279
280
  var rmax;  // max, rounded up
281
282
  if (unit == 'bits') {
283
    /* round up max, such that
284
         100 kbps -> 200 kbps -> 400 kbps -> 800 kbps -> 1 Mbps -> 2 Mbps -> ... */
285
    rmax = 12500;
286
    i = 0;
287
    while (max > rmax) {
288
      i++;
289
      if (i && (i % 4 == 0))
290
        rmax *= 1.25;
291
      else
292
        rmax *= 2;
293
    }
294
  } else {
295
    /* round up max, such that
296
         10 KB/s -> 20 KB/s -> 40 KB/s -> 80 KB/s -> 100 KB/s -> 200 KB/s -> 400 KB/s -> 800 KB/s -> 1 MB/s ... */
297
    rmax = 10240;
298
    i = 0;
299
    while (max > rmax) {
300
      i++;
301
      if (i && (i % 4 == 0))
302
        rmax *= 1.25;
303
      else
304
        rmax *= 2;
305
      
306
      if (i == 8)
307
        rmax *= 1.024;
308
    }
309
  }
310
311
  scale = <?=$height?> / rmax;
312
313
  /* change labels accordingly */
314
  SVGDoc.getElementById('grid_txt1').firstChild.data = formatSpeed(3*rmax/4,unit);
315
  SVGDoc.getElementById('grid_txt2').firstChild.data = formatSpeed(2*rmax/4,unit);
316
  SVGDoc.getElementById('grid_txt3').firstChild.data = formatSpeed(rmax/4,unit);
317
318
  var path_in = "M 0 " + (<?=$height?> - (plot_in[0] * scale));
319
  var path_out = "M 0 " + (<?=$height?> - (plot_out[0] * scale));
320
  for (i = 1; i < plot_in.length; i++)
321
  {
322
    var x = step * i;
323
    var y_in = <?=$height?> - (plot_in[i] * scale);
324
    var y_out = <?=$height?> - (plot_out[i] * scale);
325
    path_in += " L" + x + " " + y_in;
326
    path_out += " L" + x + " " + y_out;
327
  }
328
329
  SVGDoc.getElementById('error').setAttributeNS(null, 'visibility', 'hidden');
330
  SVGDoc.getElementById('graph_in').setAttributeNS(null, 'd', path_in);
331
  SVGDoc.getElementById('graph_out').setAttributeNS(null, 'd', path_out);
332
333
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
334 5b237745 Scott Ullrich
}
335
336 6afa3a82 Scott Ullrich
function handle_error() {
337
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
338
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
339 5b237745 Scott Ullrich
}
340
341
function isNumber(a) {
342 6afa3a82 Scott Ullrich
  return typeof a == 'number' && isFinite(a);
343 5b237745 Scott Ullrich
}
344
345 6afa3a82 Scott Ullrich
function formatSpeed(speed, unit) {
346
  if (unit == 'bits')
347
    return formatSpeedBits(speed);
348
  if (unit == 'bytes')
349
    return formatSpeedBytes(speed);
350 5b237745 Scott Ullrich
}
351
352
function formatSpeedBits(speed) {
353 6afa3a82 Scott Ullrich
  // format speed in bits/sec, input: bytes/sec
354
  if (speed < 125000)
355 8454080a Carlos Eduardo Ramos
    return Math.round(speed / 125) + " " + <?=gettext("Kbps"); ?>;
356 6afa3a82 Scott Ullrich
  if (speed < 125000000)
357 8454080a Carlos Eduardo Ramos
    return Math.round(speed / 1250)/100 + " " + <?=gettext("Mbps"); ?>;
358 6afa3a82 Scott Ullrich
  // else
359 8454080a Carlos Eduardo Ramos
  return Math.round(speed / 1250000)/100 + " " + <?=gettext("Gbps"); ?>;  /* wow! */
360 5b237745 Scott Ullrich
}
361 6afa3a82 Scott Ullrich
362 5b237745 Scott Ullrich
function formatSpeedBytes(speed) {
363 6afa3a82 Scott Ullrich
  // format speed in bytes/sec, input:  bytes/sec
364
  if (speed < 1048576)
365 8454080a Carlos Eduardo Ramos
    return Math.round(speed / 10.24)/100 + " " + <?=gettext("KB/s"); ?>;
366 6afa3a82 Scott Ullrich
  if (speed < 1073741824)
367 8454080a Carlos Eduardo Ramos
    return Math.round(speed / 10485.76)/100 + " " + <?=gettext("MB/s"); ?>;
368 6afa3a82 Scott Ullrich
  // else
369 8454080a Carlos Eduardo Ramos
  return Math.round(speed / 10737418.24)/100 + " " + <?=gettext("GB/s"); ?>;  /* wow! */
370 5b237745 Scott Ullrich
}
371 6afa3a82 Scott Ullrich
372 5b237745 Scott Ullrich
function LZ(x) {
373 6afa3a82 Scott Ullrich
  return (x < 0 || x > 9 ? "" : "0") + x;
374 5b237745 Scott Ullrich
}
375 6afa3a82 Scott Ullrich
376
    ]]>
377
  </script>
378 985a897f Scott Ullrich
</svg>