Project

General

Profile

Download (13.8 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
  if (last_ifin > ifin) {
200
    var diff_ifin  = ifin - last_ifin;
201
  } else {
202
    real_last_ifin = (4294967296 - last_ifin)
203
    var diff_ifin  = ifin + real_last_ifin;
204
  }
205
  if (last_ifout > ifout) {
206
    var diff_ifout  = ifout - last_ifout;
207
  } else {
208
    real_last_ifout = (4294967296 - last_ifout)
209
    var diff_ifout  = ifout + real_last_ifout;
210
  }
211
  
212
  if (diff_ugmt == 0)
213
    diff_ugmt = 1;  /* avoid division by zero */
214

    
215
  last_ugmt = ugmt;
216
  last_ifin = ifin;
217
  last_ifout = ifout;
218
  
219
  switch (plot_in.length) {
220
  	case 0:
221
  		SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'visible');
222
		plot_in[0] = diff_ifin / diff_ugmt;
223
		plot_out[0] = diff_ifout / diff_ugmt;
224
		setTimeout('fetch_data()',<?=1000*$time_interval?>);
225
		return;
226
	case 1:
227
    	SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'hidden');
228
    	break;
229
    case max_num_points:
230
		// shift plot to left if the maximum number of plot points has been reached
231
		var i = 0;
232
		while (i < max_num_points) {
233
		  plot_in[i] = plot_in[i+1];
234
		  plot_out[i] = plot_out[++i];
235
		}
236
		plot_in.length--;
237
		plot_out.length--;
238
  }
239

    
240
  plot_in[plot_in.length] = diff_ifin / diff_ugmt;
241
  plot_out[plot_out.length]= diff_ifout / diff_ugmt;
242
  var index_plot = plot_in.length - 1;
243

    
244
  SVGDoc.getElementById('graph_in_txt').firstChild.data = formatSpeed(plot_in[index_plot], unit);
245
  SVGDoc.getElementById('graph_out_txt').firstChild.data = formatSpeed(plot_out[index_plot], unit);
246

    
247
  /* determine peak for sensible scaling */
248
  if (scale_type == 'up') {
249
    if (plot_in[index_plot] > max)
250
      max = plot_in[index_plot];
251
    if (plot_out[index_plot] > max)
252
      max = plot_out[index_plot];
253
  }
254
  else if (scale_type == 'follow') {
255
    i = 0;
256
    max = 0;
257
    while (i < plot_in.length) {
258
      if (plot_in[i] > max)
259
        max = plot_in[i];
260
      if (plot_out[i] > max)
261
        max = plot_out[i];
262
      i++;
263
    }
264
  }
265

    
266
  var rmax;  // max, rounded up
267

    
268
  if (unit == 'bits') {
269
    /* round up max, such that
270
         100 kbps -> 200 kbps -> 400 kbps -> 800 kbps -> 1 Mbps -> 2 Mbps -> ... */
271
    rmax = 12500;
272
    i = 0;
273
    while (max > rmax) {
274
      i++;
275
      if (i && (i % 4 == 0))
276
        rmax *= 1.25;
277
      else
278
        rmax *= 2;
279
    }
280
  } else {
281
    /* round up max, such that
282
         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 ... */
283
    rmax = 10240;
284
    i = 0;
285
    while (max > rmax) {
286
      i++;
287
      if (i && (i % 4 == 0))
288
        rmax *= 1.25;
289
      else
290
        rmax *= 2;
291
      
292
      if (i == 8)
293
        rmax *= 1.024;
294
    }
295
  }
296

    
297
  scale = <?=$height?> / rmax;
298

    
299
  /* change labels accordingly */
300
  SVGDoc.getElementById('grid_txt1').firstChild.data = formatSpeed(3*rmax/4,unit);
301
  SVGDoc.getElementById('grid_txt2').firstChild.data = formatSpeed(2*rmax/4,unit);
302
  SVGDoc.getElementById('grid_txt3').firstChild.data = formatSpeed(rmax/4,unit);
303

    
304
  var path_in = "M 0 " + (<?=$height?> - (plot_in[0] * scale));
305
  var path_out = "M 0 " + (<?=$height?> - (plot_out[0] * scale));
306
  for (i = 1; i < plot_in.length; i++)
307
  {
308
    var x = step * i;
309
    var y_in = <?=$height?> - (plot_in[i] * scale);
310
    var y_out = <?=$height?> - (plot_out[i] * scale);
311
    path_in += " L" + x + " " + y_in;
312
    path_out += " L" + x + " " + y_out;
313
  }
314

    
315
  SVGDoc.getElementById('error').setAttributeNS(null, 'visibility', 'hidden');
316
  SVGDoc.getElementById('graph_in').setAttributeNS(null, 'd', path_in);
317
  SVGDoc.getElementById('graph_out').setAttributeNS(null, 'd', path_out);
318

    
319
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
320
}
321

    
322
function handle_error() {
323
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
324
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
325
}
326

    
327
function isNumber(a) {
328
  return typeof a == 'number' && isFinite(a);
329
}
330

    
331
function formatSpeed(speed, unit) {
332
  if (unit == 'bits')
333
    return formatSpeedBits(speed);
334
  if (unit == 'bytes')
335
    return formatSpeedBytes(speed);
336
}
337

    
338
function formatSpeedBits(speed) {
339
  // format speed in bits/sec, input: bytes/sec
340
  if (speed < 125000)
341
    return Math.round(speed / 125) + " Kbps";
342
  if (speed < 125000000)
343
    return Math.round(speed / 1250)/100 + " Mbps";
344
  // else
345
  return Math.round(speed / 1250000)/100 + " Gbps";  /* wow! */
346
}
347

    
348
function formatSpeedBytes(speed) {
349
  // format speed in bytes/sec, input:  bytes/sec
350
  if (speed < 1048576)
351
    return Math.round(speed / 10.24)/100 + " KB/s";
352
  if (speed < 1073741824)
353
    return Math.round(speed / 10485.76)/100 + " MB/s";
354
  // else
355
  return Math.round(speed / 10737418.24)/100 + " GB/s";  /* wow! */
356
}
357

    
358
function LZ(x) {
359
  return (x < 0 || x > 9 ? "" : "0") + x;
360
}
361

    
362
    ]]>
363
  </script>
364
</svg>
(63-63/186)