Project

General

Profile

Download (13.7 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
##|+PRIV
33
##|*IDENT=page-diagnostics-interfacetraffic
34
##|*NAME=Diagnostics: Interface Traffic page
35
##|*DESCR=Allow access to the 'Diagnostics: Interface Traffic' page.
36
##|*MATCH=graph.php*
37
##|-PRIV
38

    
39

    
40
header("Content-type: image/svg+xml");
41

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
168
  fetch_data();
169
}
170

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

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

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

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

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

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

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

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

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

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

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

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

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

    
264
  var rmax;  // max, rounded up
265

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

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

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

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

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

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

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

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

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

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

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

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

    
360
    ]]>
361
  </script>
362
</svg>
(62-62/211)