Project

General

Profile

Download (13.5 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
header("Content-type: image/svg+xml");
33

    
34
/********** HTTP GET Based Conf ***********/
35
$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

    
38
/********* Other conf *******/
39
$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
if ($_GET["timeint"])
42
	$time_interval = $_GET["timeint"];		//Refresh time Interval
43
else
44
	$time_interval = 3;
45

    
46
$fetch_link = "ifstats.php?if={$ifnum}";
47

    
48
//SVG attributes
49
$attribs['axis']='fill="black" stroke="black"';
50
$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
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
55
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
56
$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
$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
$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

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

    
69
/********* Graph DATA **************/
70
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
var max = 0;
147
var plot_in = new Array();
148
var plot_out = new Array();
149

    
150
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
151
var step = <?=$width?> / max_num_points ;
152
var unit = 'bits';
153
var scale_type = '<?=$scale_type?>';
154

    
155
function init(evt) {
156
  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

    
160
  fetch_data();
161
}
162

    
163
function switch_unit(event)
164
{
165
  SVGDoc.getElementById('switch_unit').firstChild.data = 'Switch to ' + unit + '/s';
166
  unit = (unit == 'bits') ? 'bytes' : 'bits';
167
}
168

    
169
function switch_scale(event)
170
{
171
  scale_type = (scale_type == 'up') ? 'follow' : 'up';
172
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
173
}
174

    
175
function fetch_data() {
176
  getURL('<?=$fetch_link?>', plot_data);
177
}
178

    
179
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
		}
226
		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
}
311

    
312
function handle_error() {
313
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
314
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
315
}
316

    
317
function isNumber(a) {
318
  return typeof a == 'number' && isFinite(a);
319
}
320

    
321
function formatSpeed(speed, unit) {
322
  if (unit == 'bits')
323
    return formatSpeedBits(speed);
324
  if (unit == 'bytes')
325
    return formatSpeedBytes(speed);
326
}
327

    
328
function formatSpeedBits(speed) {
329
  // 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
}
337

    
338
function formatSpeedBytes(speed) {
339
  // 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
}
347

    
348
function LZ(x) {
349
  return (x < 0 || x > 9 ? "" : "0") + x;
350
}
351

    
352
    ]]>
353
  </script>
354
</svg>
(63-63/186)