Project

General

Profile

Download (15 KB) Statistics
| Branch: | Tag: | Revision:

univnautes / usr / local / www / graph.php @ a1b66bec

1
<?php
2
/*
3
	graph.php
4
	part of m0n0wall (http://m0n0.ch/wall)
5
	
6
	Copyright (C) 2004-2006 T. Lechat <dev@lechat.org>, Manuel Kasper <mk@neon1.net>
7
	and Jonathan Watt <jwatt@jwatt.org>.
8
	All rights reserved.
9
	
10
	Redistribution and use in source and binary forms, with or without
11
	modification, are permitted provided that the following conditions are met:
12
	
13
	1. Redistributions of source code must retain the above copyright notice,
14
	   this list of conditions and the following disclaimer.
15
	
16
	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
	
20
	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
/*
32
	pfSense_MODULE:	graph
33
*/
34

    
35
##|+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
require("globals.inc");
43
require("guiconfig.inc");
44

    
45
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
header("Content-type: image/svg+xml");
51

    
52
/********** HTTP GET Based Conf ***********/
53
$ifnum=@$_GET["ifnum"];  // BSD / SNMP interface name / number
54
$ifnum = get_real_interface($ifnum);
55
$ifname=@$_GET["ifname"]?$_GET["ifname"]:"Interface $ifnum";  //Interface name that will be showed on top right of graph
56

    
57
/********* Other conf *******/
58
if (isset($config["widgets"]["trafficgraphs"]["scale_type"]))
59
	$scale_type = $config["widgets"]["trafficgraphs"]["scale_type"];
60
else
61
	$scale_type = "up";
62

    
63
$nb_plot=120;                   //NB plot in graph
64
if ($_GET["timeint"])
65
	$time_interval = $_GET["timeint"];		//Refresh time Interval
66
else
67
	$time_interval = 3;
68

    
69
if ($_GET["initdelay"])
70
	$init_delay = $_GET["initdelay"];		//Initial Delay
71
else
72
	$init_delay = 3;
73

    
74
//SVG attributes
75
$attribs['axis']='fill="black" stroke="black"';
76
$attribs['in']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
77
$attribs['out']='fill="#000000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
78
$attribs['graph_in']='fill="none" stroke="#FF0000" stroke-opacity="0.8"';
79
$attribs['graph_out']='fill="none" stroke="#000000" stroke-opacity="0.8"';
80
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
81
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
82
$attribs['grid_txt']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="6"';
83
$attribs['grid']='stroke="gray" stroke-opacity="0.5"';
84
$attribs['switch_unit']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
85
$attribs['switch_scale']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
86
$attribs['error']='fill="blue" font-family="Arial" font-size="4"';
87
$attribs['collect_initial']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
88

    
89
//Error text if we cannot fetch data : depends on which method is used
90
$error_text = "Cannot get data about interface " . htmlspecialchars($ifnum);
91

    
92
$height=100;            //SVG internal height : do not modify
93
$width=200;             //SVG internal width : do not modify
94

    
95
$fetch_link = "ifstats.php?if=" . htmlspecialchars($ifnum);
96

    
97
/* check for custom theme colors */
98
if(file_exists("/usr/local/www/themes/{$g['theme']}/graph.php")) {
99
	$themetxt = file_get_contents("/usr/local/www/themes/{$g['theme']}/graph.php");
100
	eval($themetxt);
101
} 
102

    
103
/********* Graph DATA **************/
104
print('<?xml version="1.0" ?>' . "\n");?>
105
<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)">
106
  <g id="graph">
107
    <rect id="bg" x1="0" y1="0" width="100%" height="100%" fill="white"/>
108
    <line id="axis_x" x1="0" y1="0" x2="0" y2="100%" <?=$attribs['axis']?>/>
109
    <line id="axis_y" x1="0" y1="100%" x2="100%" y2="100%" <?=$attribs['axis']?>/>
110
    <path id="graph_out" d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_out']?>/>
111
    <path id="graph_in"  d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_in']?>/>
112
    <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']?>/>
113
    <text id="grid_txt1" x="<?=$width?>" y="<?=$height/4*1?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
114
    <text id="grid_txt2" x="<?=$width?>" y="<?=$height/4*2?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
115
    <text id="grid_txt3" x="<?=$width?>" y="<?=$height/4*3?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
116
    <text id="graph_in_lbl" x="5" y="8" <?=$attribs['in']?>><?=gettext("In"); ?></text>
117
    <text id="graph_out_lbl" x="5" y="16" <?=$attribs['out']?>><?=gettext("Out"); ?></text>
118
    <text id="graph_in_txt" x="20" y="8" <?=$attribs['in']?>> </text>
119
    <text id="graph_out_txt" x="20" y="16" <?=$attribs['out']?>> </text>
120
    <text id="ifname" x="<?=$width?>" y="8" <?=$attribs['graphname']?> text-anchor="end"><?=htmlspecialchars($ifname)?></text>
121
    <text id="switch_unit" x="<?=$width*0.55?>" y="5" <?=$attribs['switch_unit']?>><?=gettext("Switch to bytes/s"); ?></text>
122
    <text id="switch_scale" x="<?=$width*0.55?>" y="11" <?=$attribs['switch_scale']?>><?=gettext("AutoScale"); ?> (<?=$scale_type?>)</text>
123
    <text id="date" x="<?=$width*0.33?>" y="5" <?=$attribs['legend']?>> </text>
124
    <text id="time" x="<?=$width*0.33?>" y="11" <?=$attribs['legend']?>> </text>
125
    <text id="graphlast" x="<?=$width*0.55?>" y="17" <?=$attribs['legend']?>><?=gettext("Graph shows last"); ?> <?=$time_interval*$nb_plot?> <?=gettext("seconds"); ?></text>
126
    <polygon id="axis_arrow_x" <?=$attribs['axis']?> points="<?=($width) . "," . ($height)?> <?=($width-2) . "," . ($height-2)?> <?=($width-2) . "," . $height?>"/>
127
    <text id="error" x="<?=$width*0.5?>" y="<?=$height*0.5?>"  visibility="hidden" <?=$attribs['error']?> text-anchor="middle"><?=$error_text?></text>
128
    <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>
129
  </g>
130
  <script type="text/ecmascript">
131
    <![CDATA[
132

    
133
/**
134
 * getURL is a proprietary Adobe function, but it's simplicity has made it very
135
 * popular. If getURL is undefined we spin our own by wrapping XMLHttpRequest.
136
 */
137
if (typeof getURL == 'undefined') {
138
  getURL = function(url, callback) {
139
    if (!url)
140
      throw '<?=gettext("No URL for getURL"); ?>';
141

    
142
    try {
143
      if (typeof callback.operationComplete == 'function')
144
        callback = callback.operationComplete;
145
    } catch (e) {}
146
    if (typeof callback != 'function')
147
      throw '<?=gettext("No callback function for getURL"); ?>';
148

    
149
    var http_request = null;
150
    if (typeof XMLHttpRequest != 'undefined') {
151
      http_request = new XMLHttpRequest();
152
    }
153
    else if (typeof ActiveXObject != 'undefined') {
154
      try {
155
        http_request = new ActiveXObject('Msxml2.XMLHTTP');
156
      } catch (e) {
157
        try {
158
          http_request = new ActiveXObject('Microsoft.XMLHTTP');
159
        } catch (e) {}
160
      }
161
    }
162
    if (!http_request)
163
      throw '<?=gettext("Both getURL and XMLHttpRequest are undefined"); ?>';
164

    
165
    http_request.onreadystatechange = function() {
166
      if (http_request.readyState == 4) {
167
        callback( { success : true,
168
                    content : http_request.responseText,
169
                    contentType : http_request.getResponseHeader("Content-Type") } );
170
      }
171
    }
172
    http_request.open('GET', url, true);
173
    http_request.send(null);
174
  }
175
}
176

    
177
var SVGDoc = null;
178
var last_ifin = 0;
179
var last_ifout = 0;
180
var last_ugmt = 0;
181
var max = 0;
182
var plot_in = new Array();
183
var plot_out = new Array();
184

    
185
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
186
var step = <?=$width?> / max_num_points ;
187
var unit = 'bits';
188
var scale_type = '<?=$scale_type?>';
189

    
190
function init(evt) {
191
  SVGDoc = evt.target.ownerDocument;
192
  SVGDoc.getElementById("switch_unit").addEventListener("mousedown", switch_unit, false);
193
  SVGDoc.getElementById("switch_scale").addEventListener("mousedown", switch_scale, false);
194

    
195
  fetch_data();
196
}
197

    
198
function switch_unit(event)
199
{
200
  SVGDoc.getElementById('switch_unit').firstChild.data = '<?=gettext("Switch to"); ?> ' + unit + '/s';
201
  unit = (unit == 'bits') ? 'bytes' : 'bits';
202
}
203

    
204
function switch_scale(event)
205
{
206
  scale_type = (scale_type == 'up') ? '<?=gettext("follow"); ?>' : '<?=gettext("up"); ?>';
207
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
208
}
209

    
210
function fetch_data() {
211
  getURL('<?=$fetch_link?>', plot_data);
212
}
213

    
214
function plot_data(obj) {
215
  // Show datetimelegend
216
  var now = new Date();
217
  var time = LZ(now.getHours()) + ":" + LZ(now.getMinutes()) + ":" + LZ(now.getSeconds());
218
  SVGDoc.getElementById('time').firstChild.data = time;
219
  var date = (now.getMonth()+1) + "/" + now.getDate() + "/" + now.getFullYear();
220
  SVGDoc.getElementById('date').firstChild.data = date;
221

    
222
  if (!obj.success)
223
    return handle_error();  // getURL failed to get data
224

    
225
  var t = obj.content.split("|");
226
  var ugmt = parseFloat(t[0]);  // ugmt is an unixtimestamp style
227
  var ifin = parseInt(t[1], 10);    // number of bytes received by the interface
228
  var ifout = parseInt(t[2], 10);   // number of bytes sent by the interface
229
  var scale;
230

    
231
  if (!isNumber(ifin) || !isNumber(ifout))
232
    return handle_error();
233

    
234
  var diff_ugmt  = ugmt - last_ugmt;
235
  var diff_ifin  = ifin - last_ifin;
236
  var diff_ifout = ifout - last_ifout;
237

    
238
  if (diff_ugmt == 0)
239
    diff_ugmt = 1;  /* avoid division by zero */
240

    
241
  last_ugmt = ugmt;
242
  last_ifin = ifin;
243
  last_ifout = ifout;
244
  var graphTimerId = 0;
245
  switch (plot_in.length) {
246
  	case 0:
247
  		SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'visible');
248
		plot_in[0] = diff_ifin / diff_ugmt;
249
		plot_out[0] = diff_ifout / diff_ugmt;
250
		setTimeout('fetch_data()',<?=1000*($time_interval + $init_delay)?>);
251
		return;
252
	case 1:
253
    	SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'hidden');
254
    	break;
255
    case max_num_points:
256
		// shift plot to left if the maximum number of plot points has been reached
257
		var i = 0;
258
		while (i < max_num_points) {
259
		  plot_in[i] = plot_in[i+1];
260
		  plot_out[i] = plot_out[++i];
261
		}
262
		plot_in.length--;
263
		plot_out.length--;
264
  }
265

    
266
  plot_in[plot_in.length] = diff_ifin / diff_ugmt;
267
  plot_out[plot_out.length]= diff_ifout / diff_ugmt;
268
  var index_plot = plot_in.length - 1;
269

    
270
  SVGDoc.getElementById('graph_in_txt').firstChild.data = formatSpeed(plot_in[index_plot], unit);
271
  SVGDoc.getElementById('graph_out_txt').firstChild.data = formatSpeed(plot_out[index_plot], unit);
272

    
273
  /* determine peak for sensible scaling */
274
  if (scale_type == 'up') {
275
    if (plot_in[index_plot] > max)
276
      max = plot_in[index_plot];
277
    if (plot_out[index_plot] > max)
278
      max = plot_out[index_plot];
279
  }
280
  else if (scale_type == 'follow') {
281
    i = 0;
282
    max = 0;
283
    while (i < plot_in.length) {
284
      if (plot_in[i] > max)
285
        max = plot_in[i];
286
      if (plot_out[i] > max)
287
        max = plot_out[i];
288
      i++;
289
    }
290
  }
291

    
292
  var rmax;  // max, rounded up
293

    
294
  if (unit == 'bits') {
295
    /* round up max, such that
296
         100 kbps -> 200 kbps -> 400 kbps -> 800 kbps -> 1 Mbps -> 2 Mbps -> ... */
297
    rmax = 12500;
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
  } else {
307
    /* round up max, such that
308
         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 ... */
309
    rmax = 10240;
310
    i = 0;
311
    while (max > rmax) {
312
      i++;
313
      if (i && (i % 4 == 0))
314
        rmax *= 1.25;
315
      else
316
        rmax *= 2;
317
      
318
      if (i == 8)
319
        rmax *= 1.024;
320
    }
321
  }
322

    
323
  scale = <?=$height?> / rmax;
324

    
325
  /* change labels accordingly */
326
  SVGDoc.getElementById('grid_txt1').firstChild.data = formatSpeed(3*rmax/4,unit);
327
  SVGDoc.getElementById('grid_txt2').firstChild.data = formatSpeed(2*rmax/4,unit);
328
  SVGDoc.getElementById('grid_txt3').firstChild.data = formatSpeed(rmax/4,unit);
329

    
330
  var path_in = "M 0 " + (<?=$height?> - (plot_in[0] * scale));
331
  var path_out = "M 0 " + (<?=$height?> - (plot_out[0] * scale));
332
  for (i = 1; i < plot_in.length; i++)
333
  {
334
    var x = step * i;
335
    var y_in = <?=$height?> - (plot_in[i] * scale);
336
    var y_out = <?=$height?> - (plot_out[i] * scale);
337
    path_in += " L" + x + " " + y_in;
338
    path_out += " L" + x + " " + y_out;
339
  }
340

    
341
  SVGDoc.getElementById('error').setAttributeNS(null, 'visibility', 'hidden');
342
  SVGDoc.getElementById('graph_in').setAttributeNS(null, 'd', path_in);
343
  SVGDoc.getElementById('graph_out').setAttributeNS(null, 'd', path_out);
344

    
345
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
346
}
347

    
348
function handle_error() {
349
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
350
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
351
}
352

    
353
function isNumber(a) {
354
  return typeof a == 'number' && isFinite(a);
355
}
356

    
357
function formatSpeed(speed, unit) {
358
  if (unit == 'bits')
359
    return formatSpeedBits(speed);
360
  if (unit == 'bytes')
361
    return formatSpeedBytes(speed);
362
}
363

    
364
function formatSpeedBits(speed) {
365
  // format speed in bits/sec, input: bytes/sec
366
  if (speed < 125000)
367
    return Math.round(speed / 125) + " <?=gettext("Kbps"); ?>";
368
  if (speed < 125000000)
369
    return Math.round(speed / 1250)/100 + " <?=gettext("Mbps"); ?>";
370
  // else
371
  return Math.round(speed / 1250000)/100 + " <?=gettext("Gbps"); ?>";  /* wow! */
372
}
373

    
374
function formatSpeedBytes(speed) {
375
  // format speed in bytes/sec, input:  bytes/sec
376
  if (speed < 1048576)
377
    return Math.round(speed / 10.24)/100 + " <?=gettext("KB/s"); ?>";
378
  if (speed < 1073741824)
379
    return Math.round(speed / 10485.76)/100 + " <?=gettext("MB/s"); ?>";
380
  // else
381
  return Math.round(speed / 10737418.24)/100 + " <?=gettext("GB/s"); ?>";  /* wow! */
382
}
383

    
384
function LZ(x) {
385
  return (x < 0 || x > 9 ? "" : "0") + x;
386
}
387

    
388
    ]]>
389
  </script>
390
</svg>
(84-84/256)