Project

General

Profile

Download (14.8 KB) Statistics
| Branch: | Tag: | Revision:
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
$ifname=@$_GET["ifname"]?$_GET["ifname"]:"Interface $ifnum";  //Interface name that will be showed on top right of graph
55

    
56
/********* Other conf *******/
57
$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
if ($_GET["timeint"])
60
	$time_interval = $_GET["timeint"];		//Refresh time Interval
61
else
62
	$time_interval = 3;
63

    
64
if ($_GET["initdelay"])
65
	$init_delay = $_GET["initdelay"];		//Initial Delay
66
else
67
	$init_delay = 3;
68

    
69
//SVG attributes
70
$attribs['axis']='fill="black" stroke="black"';
71
$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
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
76
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
77
$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
$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
$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

    
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
$height=100;            //SVG internal height : do not modify
88
$width=200;             //SVG internal width : do not modify
89

    
90
$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
/********* Graph DATA **************/
99
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
    <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
    <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
    <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
    <text id="datetime" x="<?=$width*0.33?>" y="5" <?=$attribs['legend']?>> </text>
119
    <text id="graphlast" x="<?=$width*0.55?>" y="17" <?=$attribs['legend']?>><?=gettext("Graph shows last"); ?> <?=$time_interval*$nb_plot?> <?=gettext("seconds"); ?></text>
120
    <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
    <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
  </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
      throw '<?=gettext("No URL for getURL"); ?>';
135

    
136
    try {
137
      if (typeof callback.operationComplete == 'function')
138
        callback = callback.operationComplete;
139
    } catch (e) {}
140
    if (typeof callback != 'function')
141
      throw '<?=gettext("No callback function for getURL"); ?>';
142

    
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
      throw '<?=gettext("Both getURL and XMLHttpRequest are undefined"); ?>';
158

    
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
var max = 0;
176
var plot_in = new Array();
177
var plot_out = new Array();
178

    
179
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
180
var step = <?=$width?> / max_num_points ;
181
var unit = 'bits';
182
var scale_type = '<?=$scale_type?>';
183

    
184
function init(evt) {
185
  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

    
189
  fetch_data();
190
}
191

    
192
function switch_unit(event)
193
{
194
  SVGDoc.getElementById('switch_unit').firstChild.data = '<?=gettext("Switch to"); ?> ' + unit + '/s';
195
  unit = (unit == 'bits') ? 'bytes' : 'bits';
196
}
197

    
198
function switch_scale(event)
199
{
200
  scale_type = (scale_type == 'up') ? '<?=gettext("follow"); ?>' : '<?=gettext("up"); ?>';
201
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
202
}
203

    
204
function fetch_data() {
205
  getURL('<?=$fetch_link?>', plot_data);
206
}
207

    
208
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
  var diff_ifin  = ifin - last_ifin;
229
  var diff_ifout = ifout - last_ifout;
230

    
231
  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
  var graphTimerId = 0;
238
  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
		setTimeout('fetch_data()',<?=1000*($time_interval + $init_delay)?>);
244
		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
		}
255
		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
}
340

    
341
function handle_error() {
342
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
343
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
344
}
345

    
346
function isNumber(a) {
347
  return typeof a == 'number' && isFinite(a);
348
}
349

    
350
function formatSpeed(speed, unit) {
351
  if (unit == 'bits')
352
    return formatSpeedBits(speed);
353
  if (unit == 'bytes')
354
    return formatSpeedBytes(speed);
355
}
356

    
357
function formatSpeedBits(speed) {
358
  // format speed in bits/sec, input: bytes/sec
359
  if (speed < 125000)
360
    return Math.round(speed / 125) + " <?=gettext("Kbps"); ?>";
361
  if (speed < 125000000)
362
    return Math.round(speed / 1250)/100 + " <?=gettext("Mbps"); ?>";
363
  // else
364
  return Math.round(speed / 1250000)/100 + " <?=gettext("Gbps"); ?>";  /* wow! */
365
}
366

    
367
function formatSpeedBytes(speed) {
368
  // format speed in bytes/sec, input:  bytes/sec
369
  if (speed < 1048576)
370
    return Math.round(speed / 10.24)/100 + " <?=gettext("KB/s"); ?>";
371
  if (speed < 1073741824)
372
    return Math.round(speed / 10485.76)/100 + " <?=gettext("MB/s"); ?>";
373
  // else
374
  return Math.round(speed / 10737418.24)/100 + " <?=gettext("GB/s"); ?>";  /* wow! */
375
}
376

    
377
function LZ(x) {
378
  return (x < 0 || x > 9 ? "" : "0") + x;
379
}
380

    
381
    ]]>
382
  </script>
383
</svg>
(69-69/220)