Project

General

Profile

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