Project

General

Profile

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