Project

General

Profile

Download (14.8 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 9228de6c jim-p
if ($_GET["initdelay"])
65
	$init_delay = $_GET["initdelay"];		//Initial Delay
66
else
67
	$init_delay = 3;
68
69 6afa3a82 Scott Ullrich
//SVG attributes
70
$attribs['axis']='fill="black" stroke="black"';
71 a85f75c2 Scott Ullrich
$attribs['in']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
72
$attribs['out']='fill="#000000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
73
$attribs['graph_in']='fill="none" stroke="#FF0000" stroke-opacity="0.8"';
74
$attribs['graph_out']='fill="none" stroke="#000000" stroke-opacity="0.8"';
75 6afa3a82 Scott Ullrich
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
76 a85f75c2 Scott Ullrich
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
77 6afa3a82 Scott Ullrich
$attribs['grid_txt']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="6"';
78
$attribs['grid']='stroke="gray" stroke-opacity="0.5"';
79 a85f75c2 Scott Ullrich
$attribs['switch_unit']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
80
$attribs['switch_scale']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
81 6afa3a82 Scott Ullrich
$attribs['error']='fill="blue" font-family="Arial" font-size="4"';
82
$attribs['collect_initial']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
83 5b237745 Scott Ullrich
84
//Error text if we cannot fetch data : depends on which method is used
85
$error_text = "Cannot get data about interface $ifnum";
86
87 6afa3a82 Scott Ullrich
$height=100;            //SVG internal height : do not modify
88
$width=200;             //SVG internal width : do not modify
89 5b237745 Scott Ullrich
90 72d1b575 Scott Ullrich
$fetch_link = "ifstats.php?if={$ifnum}";
91
92
/* check for custom theme colors */
93
if(file_exists("/usr/local/www/themes/{$g['theme']}/graph.php")) {
94
	$themetxt = file_get_contents("/usr/local/www/themes/{$g['theme']}/graph.php");
95
	eval($themetxt);
96
} 
97
98 5b237745 Scott Ullrich
/********* Graph DATA **************/
99 6afa3a82 Scott Ullrich
print('<?xml version="1.0" encoding="iso-8859-1"?>' . "\n");?>
100
<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)">
101
  <g id="graph">
102
    <rect id="bg" x1="0" y1="0" width="100%" height="100%" fill="white"/>
103
    <line id="axis_x" x1="0" y1="0" x2="0" y2="100%" <?=$attribs['axis']?>/>
104
    <line id="axis_y" x1="0" y1="100%" x2="100%" y2="100%" <?=$attribs['axis']?>/>
105
    <path id="graph_out" d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_out']?>/>
106
    <path id="graph_in"  d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_in']?>/>
107
    <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']?>/>
108
    <text id="grid_txt1" x="<?=$width?>" y="<?=$height/4*1?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
109
    <text id="grid_txt2" x="<?=$width?>" y="<?=$height/4*2?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
110
    <text id="grid_txt3" x="<?=$width?>" y="<?=$height/4*3?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
111 8454080a Carlos Eduardo Ramos
    <text id="graph_in_lbl" x="5" y="8" <?=$attribs['in']?>><?=gettext("In"); ?></text>
112
    <text id="graph_out_lbl" x="5" y="16" <?=$attribs['out']?>><?=gettext("Out"); ?></text>
113 6afa3a82 Scott Ullrich
    <text id="graph_in_txt" x="20" y="8" <?=$attribs['in']?>> </text>
114
    <text id="graph_out_txt" x="20" y="16" <?=$attribs['out']?>> </text>
115
    <text id="ifname" x="<?=$width?>" y="8" <?=$attribs['graphname']?> text-anchor="end"><?=$ifname?></text>
116 8454080a Carlos Eduardo Ramos
    <text id="switch_unit" x="<?=$width*0.55?>" y="5" <?=$attribs['switch_unit']?>><?=gettext("Switch to bytes/s"); ?></text>
117
    <text id="switch_scale" x="<?=$width*0.55?>" y="11" <?=$attribs['switch_scale']?>><?=gettext("AutoScale"); ?> (<?=$scale_type?>)</text>
118 6afa3a82 Scott Ullrich
    <text id="datetime" x="<?=$width*0.33?>" y="5" <?=$attribs['legend']?>> </text>
119 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>
120 6afa3a82 Scott Ullrich
    <polygon id="axis_arrow_x" <?=$attribs['axis']?> points="<?=($width) . "," . ($height)?> <?=($width-2) . "," . ($height-2)?> <?=($width-2) . "," . $height?>"/>
121
    <text id="error" x="<?=$width*0.5?>" y="<?=$height*0.5?>"  visibility="hidden" <?=$attribs['error']?> text-anchor="middle"><?=$error_text?></text>
122 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>
123 6afa3a82 Scott Ullrich
  </g>
124
  <script type="text/ecmascript">
125
    <![CDATA[
126
127
/**
128
 * getURL is a proprietary Adobe function, but it's simplicity has made it very
129
 * popular. If getURL is undefined we spin our own by wrapping XMLHttpRequest.
130
 */
131
if (typeof getURL == 'undefined') {
132
  getURL = function(url, callback) {
133
    if (!url)
134 8454080a Carlos Eduardo Ramos
      throw '<?=gettext("No URL for getURL"); ?>';
135 6afa3a82 Scott Ullrich
136
    try {
137
      if (typeof callback.operationComplete == 'function')
138
        callback = callback.operationComplete;
139
    } catch (e) {}
140
    if (typeof callback != 'function')
141 8454080a Carlos Eduardo Ramos
      throw '<?=gettext("No callback function for getURL"); ?>';
142 6afa3a82 Scott Ullrich
143
    var http_request = null;
144
    if (typeof XMLHttpRequest != 'undefined') {
145
      http_request = new XMLHttpRequest();
146
    }
147
    else if (typeof ActiveXObject != 'undefined') {
148
      try {
149
        http_request = new ActiveXObject('Msxml2.XMLHTTP');
150
      } catch (e) {
151
        try {
152
          http_request = new ActiveXObject('Microsoft.XMLHTTP');
153
        } catch (e) {}
154
      }
155
    }
156
    if (!http_request)
157 8454080a Carlos Eduardo Ramos
      throw '<?=gettext("Both getURL and XMLHttpRequest are undefined"); ?>';
158 6afa3a82 Scott Ullrich
159
    http_request.onreadystatechange = function() {
160
      if (http_request.readyState == 4) {
161
        callback( { success : true,
162
                    content : http_request.responseText,
163
                    contentType : http_request.getResponseHeader("Content-Type") } );
164
      }
165
    }
166
    http_request.open('GET', url, true);
167
    http_request.send(null);
168
  }
169
}
170
171
var SVGDoc = null;
172
var last_ifin = 0;
173
var last_ifout = 0;
174
var last_ugmt = 0;
175 5b237745 Scott Ullrich
var max = 0;
176 6afa3a82 Scott Ullrich
var plot_in = new Array();
177
var plot_out = new Array();
178 5b237745 Scott Ullrich
179 6afa3a82 Scott Ullrich
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
180
var step = <?=$width?> / max_num_points ;
181 5b237745 Scott Ullrich
var unit = 'bits';
182
var scale_type = '<?=$scale_type?>';
183
184
function init(evt) {
185 6afa3a82 Scott Ullrich
  SVGDoc = evt.target.ownerDocument;
186
  SVGDoc.getElementById("switch_unit").addEventListener("mousedown", switch_unit, false);
187
  SVGDoc.getElementById("switch_scale").addEventListener("mousedown", switch_scale, false);
188 5b237745 Scott Ullrich
189 6afa3a82 Scott Ullrich
  fetch_data();
190 5b237745 Scott Ullrich
}
191
192
function switch_unit(event)
193
{
194 8454080a Carlos Eduardo Ramos
  SVGDoc.getElementById('switch_unit').firstChild.data = '<?=gettext("Switch to"); ?> ' + unit + '/s';
195 6afa3a82 Scott Ullrich
  unit = (unit == 'bits') ? 'bytes' : 'bits';
196 5b237745 Scott Ullrich
}
197
198
function switch_scale(event)
199
{
200 8454080a Carlos Eduardo Ramos
  scale_type = (scale_type == 'up') ? '<?=gettext("follow"); ?>' : '<?=gettext("up"); ?>';
201 6afa3a82 Scott Ullrich
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
202 5b237745 Scott Ullrich
}
203
204 6afa3a82 Scott Ullrich
function fetch_data() {
205
  getURL('<?=$fetch_link?>', plot_data);
206 5b237745 Scott Ullrich
}
207
208 6afa3a82 Scott Ullrich
function plot_data(obj) {
209
  // Show datetimelegend
210
  var now = new Date();
211
  var datetime = (now.getMonth()+1) + "/" + now.getDate() + "/" + now.getFullYear() + ' ' + 
212
    LZ(now.getHours()) + ":" + LZ(now.getMinutes()) + ":" + LZ(now.getSeconds());
213
  SVGDoc.getElementById('datetime').firstChild.data = datetime;
214
215
  if (!obj.success)
216
    return handle_error();  // getURL failed to get data
217
218
  var t = obj.content.split("|");
219
  var ugmt = parseFloat(t[0]);  // ugmt is an unixtimestamp style
220
  var ifin = parseInt(t[1]);    // number of bytes received by the interface
221
  var ifout = parseInt(t[2]);   // number of bytes sent by the interface
222
  var scale;
223
224
  if (!isNumber(ifin) || !isNumber(ifout))
225
    return handle_error();
226
227
  var diff_ugmt  = ugmt - last_ugmt;
228 67c04e80 Seth Mos
  var diff_ifin  = ifin - last_ifin;
229
  var diff_ifout = ifout - last_ifout;
230
231 6afa3a82 Scott Ullrich
  if (diff_ugmt == 0)
232
    diff_ugmt = 1;  /* avoid division by zero */
233
234
  last_ugmt = ugmt;
235
  last_ifin = ifin;
236
  last_ifout = ifout;
237 9228de6c jim-p
  var graphTimerId = 0;
238 6afa3a82 Scott Ullrich
  switch (plot_in.length) {
239
  	case 0:
240
  		SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'visible');
241
		plot_in[0] = diff_ifin / diff_ugmt;
242
		plot_out[0] = diff_ifout / diff_ugmt;
243 9228de6c jim-p
		setTimeout('fetch_data()',<?=1000*($time_interval + $init_delay)?>);
244 6afa3a82 Scott Ullrich
		return;
245
	case 1:
246
    	SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'hidden');
247
    	break;
248
    case max_num_points:
249
		// shift plot to left if the maximum number of plot points has been reached
250
		var i = 0;
251
		while (i < max_num_points) {
252
		  plot_in[i] = plot_in[i+1];
253
		  plot_out[i] = plot_out[++i];
254 5b237745 Scott Ullrich
		}
255 6afa3a82 Scott Ullrich
		plot_in.length--;
256
		plot_out.length--;
257
  }
258
259
  plot_in[plot_in.length] = diff_ifin / diff_ugmt;
260
  plot_out[plot_out.length]= diff_ifout / diff_ugmt;
261
  var index_plot = plot_in.length - 1;
262
263
  SVGDoc.getElementById('graph_in_txt').firstChild.data = formatSpeed(plot_in[index_plot], unit);
264
  SVGDoc.getElementById('graph_out_txt').firstChild.data = formatSpeed(plot_out[index_plot], unit);
265
266
  /* determine peak for sensible scaling */
267
  if (scale_type == 'up') {
268
    if (plot_in[index_plot] > max)
269
      max = plot_in[index_plot];
270
    if (plot_out[index_plot] > max)
271
      max = plot_out[index_plot];
272
  }
273
  else if (scale_type == 'follow') {
274
    i = 0;
275
    max = 0;
276
    while (i < plot_in.length) {
277
      if (plot_in[i] > max)
278
        max = plot_in[i];
279
      if (plot_out[i] > max)
280
        max = plot_out[i];
281
      i++;
282
    }
283
  }
284
285
  var rmax;  // max, rounded up
286
287
  if (unit == 'bits') {
288
    /* round up max, such that
289
         100 kbps -> 200 kbps -> 400 kbps -> 800 kbps -> 1 Mbps -> 2 Mbps -> ... */
290
    rmax = 12500;
291
    i = 0;
292
    while (max > rmax) {
293
      i++;
294
      if (i && (i % 4 == 0))
295
        rmax *= 1.25;
296
      else
297
        rmax *= 2;
298
    }
299
  } else {
300
    /* round up max, such that
301
         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 ... */
302
    rmax = 10240;
303
    i = 0;
304
    while (max > rmax) {
305
      i++;
306
      if (i && (i % 4 == 0))
307
        rmax *= 1.25;
308
      else
309
        rmax *= 2;
310
      
311
      if (i == 8)
312
        rmax *= 1.024;
313
    }
314
  }
315
316
  scale = <?=$height?> / rmax;
317
318
  /* change labels accordingly */
319
  SVGDoc.getElementById('grid_txt1').firstChild.data = formatSpeed(3*rmax/4,unit);
320
  SVGDoc.getElementById('grid_txt2').firstChild.data = formatSpeed(2*rmax/4,unit);
321
  SVGDoc.getElementById('grid_txt3').firstChild.data = formatSpeed(rmax/4,unit);
322
323
  var path_in = "M 0 " + (<?=$height?> - (plot_in[0] * scale));
324
  var path_out = "M 0 " + (<?=$height?> - (plot_out[0] * scale));
325
  for (i = 1; i < plot_in.length; i++)
326
  {
327
    var x = step * i;
328
    var y_in = <?=$height?> - (plot_in[i] * scale);
329
    var y_out = <?=$height?> - (plot_out[i] * scale);
330
    path_in += " L" + x + " " + y_in;
331
    path_out += " L" + x + " " + y_out;
332
  }
333
334
  SVGDoc.getElementById('error').setAttributeNS(null, 'visibility', 'hidden');
335
  SVGDoc.getElementById('graph_in').setAttributeNS(null, 'd', path_in);
336
  SVGDoc.getElementById('graph_out').setAttributeNS(null, 'd', path_out);
337
338
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
339 5b237745 Scott Ullrich
}
340
341 6afa3a82 Scott Ullrich
function handle_error() {
342
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
343
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
344 5b237745 Scott Ullrich
}
345
346
function isNumber(a) {
347 6afa3a82 Scott Ullrich
  return typeof a == 'number' && isFinite(a);
348 5b237745 Scott Ullrich
}
349
350 6afa3a82 Scott Ullrich
function formatSpeed(speed, unit) {
351
  if (unit == 'bits')
352
    return formatSpeedBits(speed);
353
  if (unit == 'bytes')
354
    return formatSpeedBytes(speed);
355 5b237745 Scott Ullrich
}
356
357
function formatSpeedBits(speed) {
358 6afa3a82 Scott Ullrich
  // format speed in bits/sec, input: bytes/sec
359
  if (speed < 125000)
360 6c83f226 Vinicius Coque
    return Math.round(speed / 125) + " <?=gettext("Kbps"); ?>";
361 6afa3a82 Scott Ullrich
  if (speed < 125000000)
362 6c83f226 Vinicius Coque
    return Math.round(speed / 1250)/100 + " <?=gettext("Mbps"); ?>";
363 6afa3a82 Scott Ullrich
  // else
364 6c83f226 Vinicius Coque
  return Math.round(speed / 1250000)/100 + " <?=gettext("Gbps"); ?>";  /* wow! */
365 5b237745 Scott Ullrich
}
366 6afa3a82 Scott Ullrich
367 5b237745 Scott Ullrich
function formatSpeedBytes(speed) {
368 6afa3a82 Scott Ullrich
  // format speed in bytes/sec, input:  bytes/sec
369
  if (speed < 1048576)
370 6c83f226 Vinicius Coque
    return Math.round(speed / 10.24)/100 + " <?=gettext("KB/s"); ?>";
371 6afa3a82 Scott Ullrich
  if (speed < 1073741824)
372 6c83f226 Vinicius Coque
    return Math.round(speed / 10485.76)/100 + " <?=gettext("MB/s"); ?>";
373 6afa3a82 Scott Ullrich
  // else
374 6c83f226 Vinicius Coque
  return Math.round(speed / 10737418.24)/100 + " <?=gettext("GB/s"); ?>";  /* wow! */
375 5b237745 Scott Ullrich
}
376 6afa3a82 Scott Ullrich
377 5b237745 Scott Ullrich
function LZ(x) {
378 6afa3a82 Scott Ullrich
  return (x < 0 || x > 9 ? "" : "0") + x;
379 5b237745 Scott Ullrich
}
380 6afa3a82 Scott Ullrich
381
    ]]>
382
  </script>
383 985a897f Scott Ullrich
</svg>