Project

General

Profile

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

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

    
85
$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
/********* Graph DATA **************/
94
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
    <text id="graph_in_lbl" x="5" y="8" <?=$attribs['in']?>>In</text>
107
    <text id="graph_out_lbl" x="5" y="16" <?=$attribs['out']?>>Out</text>
108
    <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
    <text id="switch_unit" x="<?=$width*0.55?>" y="5" <?=$attribs['switch_unit']?>>Switch to bytes/s</text>
112
    <text id="switch_scale" x="<?=$width*0.55?>" y="11" <?=$attribs['switch_scale']?>>AutoScale (<?=$scale_type?>)</text>
113
    <text id="datetime" x="<?=$width*0.33?>" y="5" <?=$attribs['legend']?>> </text>
114
    <text id="graphlast" x="<?=$width*0.55?>" y="17" <?=$attribs['legend']?>>Graph shows last <?=$time_interval*$nb_plot?> seconds</text>
115
    <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
    <text id="collect_initial" x="<?=$width*0.5?>" y="<?=$height*0.5?>"  visibility="hidden" <?=$attribs['collect_initial']?> text-anchor="middle">Collecting initial data, please wait...</text>
118
  </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
      throw 'No URL for getURL';
130

    
131
    try {
132
      if (typeof callback.operationComplete == 'function')
133
        callback = callback.operationComplete;
134
    } catch (e) {}
135
    if (typeof callback != 'function')
136
      throw 'No callback function for getURL';
137

    
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
      throw 'Both getURL and XMLHttpRequest are undefined';
153

    
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
var max = 0;
171
var plot_in = new Array();
172
var plot_out = new Array();
173

    
174
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
175
var step = <?=$width?> / max_num_points ;
176
var unit = 'bits';
177
var scale_type = '<?=$scale_type?>';
178

    
179
function init(evt) {
180
  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

    
184
  fetch_data();
185
}
186

    
187
function switch_unit(event)
188
{
189
  SVGDoc.getElementById('switch_unit').firstChild.data = 'Switch to ' + unit + '/s';
190
  unit = (unit == 'bits') ? 'bytes' : 'bits';
191
}
192

    
193
function switch_scale(event)
194
{
195
  scale_type = (scale_type == 'up') ? 'follow' : 'up';
196
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
197
}
198

    
199
function fetch_data() {
200
  getURL('<?=$fetch_link?>', plot_data);
201
}
202

    
203
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
  var diff_ifin  = ifin - last_ifin;
224
  var diff_ifout = ifout - last_ifout;
225

    
226
  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
		}
250
		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
}
335

    
336
function handle_error() {
337
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
338
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
339
}
340

    
341
function isNumber(a) {
342
  return typeof a == 'number' && isFinite(a);
343
}
344

    
345
function formatSpeed(speed, unit) {
346
  if (unit == 'bits')
347
    return formatSpeedBits(speed);
348
  if (unit == 'bytes')
349
    return formatSpeedBytes(speed);
350
}
351

    
352
function formatSpeedBits(speed) {
353
  // format speed in bits/sec, input: bytes/sec
354
  if (speed < 125000)
355
    return Math.round(speed / 125) + " Kbps";
356
  if (speed < 125000000)
357
    return Math.round(speed / 1250)/100 + " Mbps";
358
  // else
359
  return Math.round(speed / 1250000)/100 + " Gbps";  /* wow! */
360
}
361

    
362
function formatSpeedBytes(speed) {
363
  // format speed in bytes/sec, input:  bytes/sec
364
  if (speed < 1048576)
365
    return Math.round(speed / 10.24)/100 + " KB/s";
366
  if (speed < 1073741824)
367
    return Math.round(speed / 10485.76)/100 + " MB/s";
368
  // else
369
  return Math.round(speed / 10737418.24)/100 + " GB/s";  /* wow! */
370
}
371

    
372
function LZ(x) {
373
  return (x < 0 || x > 9 ? "" : "0") + x;
374
}
375

    
376
    ]]>
377
  </script>
378
</svg>
(69-69/221)