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
$time_interval=1;		//Refresh time Interval
42

    
43
$fetch_link = "ifstats.php?if={$ifnum}";
44

    
45
//SVG attributes
46
$attribs['axis']='fill="black" stroke="black"';
47
$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
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
52
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
53
$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
$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
$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

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

    
66
/********* Graph DATA **************/
67
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
var max = 0;
144
var plot_in = new Array();
145
var plot_out = new Array();
146

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

    
152
function init(evt) {
153
  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

    
157
  fetch_data();
158
}
159

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

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

    
172
function fetch_data() {
173
  getURL('<?=$fetch_link?>', plot_data);
174
}
175

    
176
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
		}
223
		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
}
308

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

    
314
function isNumber(a) {
315
  return typeof a == 'number' && isFinite(a);
316
}
317

    
318
function formatSpeed(speed, unit) {
319
  if (unit == 'bits')
320
    return formatSpeedBits(speed);
321
  if (unit == 'bytes')
322
    return formatSpeedBytes(speed);
323
}
324

    
325
function formatSpeedBits(speed) {
326
  // 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
}
334

    
335
function formatSpeedBytes(speed) {
336
  // 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
}
344

    
345
function LZ(x) {
346
  return (x < 0 || x > 9 ? "" : "0") + x;
347
}
348

    
349
    ]]>
350
  </script>
351
</svg>
(56-56/167)