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