Project

General

Profile

Download (13.9 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
require("guiconfig.inc");
33

    
34
header("Last-Modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" );
35
header("Expires: " . gmdate( "D, j M Y H:i:s", time() ) . " GMT" );
36
header("Cache-Control: no-store, no-cache, must-revalidate" ); // HTTP/1.1
37
header("Cache-Control: post-check=0, pre-check=0", FALSE );
38
header("Pragma: no-cache"); // HTTP/1.0
39
header("Content-type: image/svg+xml");
40

    
41
/********** HTTP GET Based Conf ***********/
42
$ifnum=@$_GET["ifnum"];  // BSD / SNMP interface name / number
43
$ifname=@$_GET["ifname"]?$_GET["ifname"]:"Interface $ifnum";  //Interface name that will be showed on top right of graph
44

    
45
/********* Other conf *******/
46
$scale_type="up";               //Autoscale default setup : "up" = only increase scale; "follow" = increase and decrease scale according to current graphed datas
47
$nb_plot=120;                   //NB plot in graph
48
if ($_GET["timeint"])
49
	$time_interval = $_GET["timeint"];		//Refresh time Interval
50
else
51
	$time_interval = 3;
52

    
53
$fetch_link = "ifstats.php?if={$ifnum}";
54

    
55
//SVG attributes
56
$attribs['axis']='fill="black" stroke="black"';
57
$attribs['in']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
58
$attribs['out']='fill="#000000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="7"';
59
$attribs['graph_in']='fill="none" stroke="#FF0000" stroke-opacity="0.8"';
60
$attribs['graph_out']='fill="none" stroke="#000000" stroke-opacity="0.8"';
61
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
62
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
63
$attribs['grid_txt']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="6"';
64
$attribs['grid']='stroke="gray" stroke-opacity="0.5"';
65
$attribs['switch_unit']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
66
$attribs['switch_scale']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4" text-decoration="underline"';
67
$attribs['error']='fill="blue" font-family="Arial" font-size="4"';
68
$attribs['collect_initial']='fill="gray" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
69

    
70
//Error text if we cannot fetch data : depends on which method is used
71
$error_text = "Cannot get data about interface $ifnum";
72

    
73
$height=100;            //SVG internal height : do not modify
74
$width=200;             //SVG internal width : do not modify
75

    
76
/********* Graph DATA **************/
77
print('<?xml version="1.0" encoding="iso-8859-1"?>' . "\n");?>
78
<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)">
79
  <g id="graph">
80
    <rect id="bg" x1="0" y1="0" width="100%" height="100%" fill="white"/>
81
    <line id="axis_x" x1="0" y1="0" x2="0" y2="100%" <?=$attribs['axis']?>/>
82
    <line id="axis_y" x1="0" y1="100%" x2="100%" y2="100%" <?=$attribs['axis']?>/>
83
    <path id="graph_out" d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_out']?>/>
84
    <path id="graph_in"  d="M0 <?=$height?> L 0 <?=$height?>" <?=$attribs['graph_in']?>/>
85
    <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']?>/>
86
    <text id="grid_txt1" x="<?=$width?>" y="<?=$height/4*1?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
87
    <text id="grid_txt2" x="<?=$width?>" y="<?=$height/4*2?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
88
    <text id="grid_txt3" x="<?=$width?>" y="<?=$height/4*3?>" <?=$attribs['grid_txt']?> text-anchor="end"> </text>
89
    <text id="graph_in_lbl" x="5" y="8" <?=$attribs['in']?>>In</text>
90
    <text id="graph_out_lbl" x="5" y="16" <?=$attribs['out']?>>Out</text>
91
    <text id="graph_in_txt" x="20" y="8" <?=$attribs['in']?>> </text>
92
    <text id="graph_out_txt" x="20" y="16" <?=$attribs['out']?>> </text>
93
    <text id="ifname" x="<?=$width?>" y="8" <?=$attribs['graphname']?> text-anchor="end"><?=$ifname?></text>
94
    <text id="switch_unit" x="<?=$width*0.55?>" y="5" <?=$attribs['switch_unit']?>>Switch to bytes/s</text>
95
    <text id="switch_scale" x="<?=$width*0.55?>" y="11" <?=$attribs['switch_scale']?>>AutoScale (<?=$scale_type?>)</text>
96
    <text id="datetime" x="<?=$width*0.33?>" y="5" <?=$attribs['legend']?>> </text>
97
    <text id="graphlast" x="<?=$width*0.55?>" y="17" <?=$attribs['legend']?>>Graph shows last <?=$time_interval*$nb_plot?> seconds</text>
98
    <polygon id="axis_arrow_x" <?=$attribs['axis']?> points="<?=($width) . "," . ($height)?> <?=($width-2) . "," . ($height-2)?> <?=($width-2) . "," . $height?>"/>
99
    <text id="error" x="<?=$width*0.5?>" y="<?=$height*0.5?>"  visibility="hidden" <?=$attribs['error']?> text-anchor="middle"><?=$error_text?></text>
100
    <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>
101
  </g>
102
  <script type="text/ecmascript">
103
    <![CDATA[
104

    
105
/**
106
 * getURL is a proprietary Adobe function, but it's simplicity has made it very
107
 * popular. If getURL is undefined we spin our own by wrapping XMLHttpRequest.
108
 */
109
if (typeof getURL == 'undefined') {
110
  getURL = function(url, callback) {
111
    if (!url)
112
      throw 'No URL for getURL';
113

    
114
    try {
115
      if (typeof callback.operationComplete == 'function')
116
        callback = callback.operationComplete;
117
    } catch (e) {}
118
    if (typeof callback != 'function')
119
      throw 'No callback function for getURL';
120

    
121
    var http_request = null;
122
    if (typeof XMLHttpRequest != 'undefined') {
123
      http_request = new XMLHttpRequest();
124
    }
125
    else if (typeof ActiveXObject != 'undefined') {
126
      try {
127
        http_request = new ActiveXObject('Msxml2.XMLHTTP');
128
      } catch (e) {
129
        try {
130
          http_request = new ActiveXObject('Microsoft.XMLHTTP');
131
        } catch (e) {}
132
      }
133
    }
134
    if (!http_request)
135
      throw 'Both getURL and XMLHttpRequest are undefined';
136

    
137
    http_request.onreadystatechange = function() {
138
      if (http_request.readyState == 4) {
139
        callback( { success : true,
140
                    content : http_request.responseText,
141
                    contentType : http_request.getResponseHeader("Content-Type") } );
142
      }
143
    }
144
    http_request.open('GET', url, true);
145
    http_request.send(null);
146
  }
147
}
148

    
149
var SVGDoc = null;
150
var last_ifin = 0;
151
var last_ifout = 0;
152
var last_ugmt = 0;
153
var max = 0;
154
var plot_in = new Array();
155
var plot_out = new Array();
156

    
157
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
158
var step = <?=$width?> / max_num_points ;
159
var unit = 'bits';
160
var scale_type = '<?=$scale_type?>';
161

    
162
function init(evt) {
163
  SVGDoc = evt.target.ownerDocument;
164
  SVGDoc.getElementById("switch_unit").addEventListener("mousedown", switch_unit, false);
165
  SVGDoc.getElementById("switch_scale").addEventListener("mousedown", switch_scale, false);
166

    
167
  fetch_data();
168
}
169

    
170
function switch_unit(event)
171
{
172
  SVGDoc.getElementById('switch_unit').firstChild.data = 'Switch to ' + unit + '/s';
173
  unit = (unit == 'bits') ? 'bytes' : 'bits';
174
}
175

    
176
function switch_scale(event)
177
{
178
  scale_type = (scale_type == 'up') ? 'follow' : 'up';
179
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
180
}
181

    
182
function fetch_data() {
183
  getURL('<?=$fetch_link?>', plot_data);
184
}
185

    
186
function plot_data(obj) {
187
  // Show datetimelegend
188
  var now = new Date();
189
  var datetime = (now.getMonth()+1) + "/" + now.getDate() + "/" + now.getFullYear() + ' ' + 
190
    LZ(now.getHours()) + ":" + LZ(now.getMinutes()) + ":" + LZ(now.getSeconds());
191
  SVGDoc.getElementById('datetime').firstChild.data = datetime;
192

    
193
  if (!obj.success)
194
    return handle_error();  // getURL failed to get data
195

    
196
  var t = obj.content.split("|");
197
  var ugmt = parseFloat(t[0]);  // ugmt is an unixtimestamp style
198
  var ifin = parseInt(t[1]);    // number of bytes received by the interface
199
  var ifout = parseInt(t[2]);   // number of bytes sent by the interface
200
  var scale;
201

    
202
  if (!isNumber(ifin) || !isNumber(ifout))
203
    return handle_error();
204

    
205
  var diff_ugmt  = ugmt - last_ugmt;
206
  var diff_ifin  = ifin - last_ifin;
207
  var diff_ifout = ifout - last_ifout;
208

    
209
  if (diff_ugmt == 0)
210
    diff_ugmt = 1;  /* avoid division by zero */
211

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

    
237
  plot_in[plot_in.length] = diff_ifin / diff_ugmt;
238
  plot_out[plot_out.length]= diff_ifout / diff_ugmt;
239
  var index_plot = plot_in.length - 1;
240

    
241
  SVGDoc.getElementById('graph_in_txt').firstChild.data = formatSpeed(plot_in[index_plot], unit);
242
  SVGDoc.getElementById('graph_out_txt').firstChild.data = formatSpeed(plot_out[index_plot], unit);
243

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

    
263
  var rmax;  // max, rounded up
264

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

    
294
  scale = <?=$height?> / rmax;
295

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

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

    
312
  SVGDoc.getElementById('error').setAttributeNS(null, 'visibility', 'hidden');
313
  SVGDoc.getElementById('graph_in').setAttributeNS(null, 'd', path_in);
314
  SVGDoc.getElementById('graph_out').setAttributeNS(null, 'd', path_out);
315

    
316
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
317
}
318

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

    
324
function isNumber(a) {
325
  return typeof a == 'number' && isFinite(a);
326
}
327

    
328
function formatSpeed(speed, unit) {
329
  if (unit == 'bits')
330
    return formatSpeedBits(speed);
331
  if (unit == 'bytes')
332
    return formatSpeedBytes(speed);
333
}
334

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

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

    
355
function LZ(x) {
356
  return (x < 0 || x > 9 ? "" : "0") + x;
357
}
358

    
359
    ]]>
360
  </script>
361
</svg>
362

    
(61-61/174)