Project

General

Profile

Download (14.3 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
require("globals.inc");
40
require("guiconfig.inc");
41

    
42
header("Last-Modified: " . gmdate( "D, j M Y H:i:s" ) . " GMT" );
43
header("Expires: " . gmdate( "D, j M Y H:i:s", time() ) . " GMT" );
44
header("Cache-Control: no-store, no-cache, must-revalidate" ); // HTTP/1.1
45
header("Cache-Control: post-check=0, pre-check=0", FALSE );
46
header("Pragma: no-cache"); // HTTP/1.0
47
header("Content-type: image/svg+xml");
48

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

    
53
/********* Other conf *******/
54
$scale_type="up";               //Autoscale default setup : "up" = only increase scale; "follow" = increase and decrease scale according to current graphed datas
55
$nb_plot=120;                   //NB plot in graph
56
if ($_GET["timeint"])
57
	$time_interval = $_GET["timeint"];		//Refresh time Interval
58
else
59
	$time_interval = 3;
60

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

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

    
79
$height=100;            //SVG internal height : do not modify
80
$width=200;             //SVG internal width : do not modify
81

    
82
$fetch_link = "ifstats.php?if={$ifnum}";
83

    
84
/* check for custom theme colors */
85
if(file_exists("/usr/local/www/themes/{$g['theme']}/graph.php")) {
86
	$themetxt = file_get_contents("/usr/local/www/themes/{$g['theme']}/graph.php");
87
	eval($themetxt);
88
} 
89

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

    
119
/**
120
 * getURL is a proprietary Adobe function, but it's simplicity has made it very
121
 * popular. If getURL is undefined we spin our own by wrapping XMLHttpRequest.
122
 */
123
if (typeof getURL == 'undefined') {
124
  getURL = function(url, callback) {
125
    if (!url)
126
      throw 'No URL for getURL';
127

    
128
    try {
129
      if (typeof callback.operationComplete == 'function')
130
        callback = callback.operationComplete;
131
    } catch (e) {}
132
    if (typeof callback != 'function')
133
      throw 'No callback function for getURL';
134

    
135
    var http_request = null;
136
    if (typeof XMLHttpRequest != 'undefined') {
137
      http_request = new XMLHttpRequest();
138
    }
139
    else if (typeof ActiveXObject != 'undefined') {
140
      try {
141
        http_request = new ActiveXObject('Msxml2.XMLHTTP');
142
      } catch (e) {
143
        try {
144
          http_request = new ActiveXObject('Microsoft.XMLHTTP');
145
        } catch (e) {}
146
      }
147
    }
148
    if (!http_request)
149
      throw 'Both getURL and XMLHttpRequest are undefined';
150

    
151
    http_request.onreadystatechange = function() {
152
      if (http_request.readyState == 4) {
153
        callback( { success : true,
154
                    content : http_request.responseText,
155
                    contentType : http_request.getResponseHeader("Content-Type") } );
156
      }
157
    }
158
    http_request.open('GET', url, true);
159
    http_request.send(null);
160
  }
161
}
162

    
163
var SVGDoc = null;
164
var last_ifin = 0;
165
var last_ifout = 0;
166
var last_ugmt = 0;
167
var max = 0;
168
var plot_in = new Array();
169
var plot_out = new Array();
170

    
171
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
172
var step = <?=$width?> / max_num_points ;
173
var unit = 'bits';
174
var scale_type = '<?=$scale_type?>';
175

    
176
function init(evt) {
177
  SVGDoc = evt.target.ownerDocument;
178
  SVGDoc.getElementById("switch_unit").addEventListener("mousedown", switch_unit, false);
179
  SVGDoc.getElementById("switch_scale").addEventListener("mousedown", switch_scale, false);
180

    
181
  fetch_data();
182
}
183

    
184
function switch_unit(event)
185
{
186
  SVGDoc.getElementById('switch_unit').firstChild.data = 'Switch to ' + unit + '/s';
187
  unit = (unit == 'bits') ? 'bytes' : 'bits';
188
}
189

    
190
function switch_scale(event)
191
{
192
  scale_type = (scale_type == 'up') ? 'follow' : 'up';
193
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
194
}
195

    
196
function fetch_data() {
197
  getURL('<?=$fetch_link?>', plot_data);
198
}
199

    
200
function plot_data(obj) {
201
  // Show datetimelegend
202
  var now = new Date();
203
  var datetime = (now.getMonth()+1) + "/" + now.getDate() + "/" + now.getFullYear() + ' ' + 
204
    LZ(now.getHours()) + ":" + LZ(now.getMinutes()) + ":" + LZ(now.getSeconds());
205
  SVGDoc.getElementById('datetime').firstChild.data = datetime;
206

    
207
  if (!obj.success)
208
    return handle_error();  // getURL failed to get data
209

    
210
  var t = obj.content.split("|");
211
  var ugmt = parseFloat(t[0]);  // ugmt is an unixtimestamp style
212
  var ifin = parseInt(t[1]);    // number of bytes received by the interface
213
  var ifout = parseInt(t[2]);   // number of bytes sent by the interface
214
  var scale;
215

    
216
  if (!isNumber(ifin) || !isNumber(ifout))
217
    return handle_error();
218

    
219
  var diff_ugmt  = ugmt - last_ugmt;
220
  var diff_ifin  = ifin - last_ifin;
221
  var diff_ifout = ifout - last_ifout;
222

    
223
  if (diff_ugmt == 0)
224
    diff_ugmt = 1;  /* avoid division by zero */
225

    
226
  last_ugmt = ugmt;
227
  last_ifin = ifin;
228
  last_ifout = ifout;
229
  
230
  switch (plot_in.length) {
231
  	case 0:
232
  		SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'visible');
233
		plot_in[0] = diff_ifin / diff_ugmt;
234
		plot_out[0] = diff_ifout / diff_ugmt;
235
		setTimeout('fetch_data()',<?=1000*$time_interval?>);
236
		return;
237
	case 1:
238
    	SVGDoc.getElementById("collect_initial").setAttributeNS(null, 'visibility', 'hidden');
239
    	break;
240
    case max_num_points:
241
		// shift plot to left if the maximum number of plot points has been reached
242
		var i = 0;
243
		while (i < max_num_points) {
244
		  plot_in[i] = plot_in[i+1];
245
		  plot_out[i] = plot_out[++i];
246
		}
247
		plot_in.length--;
248
		plot_out.length--;
249
  }
250

    
251
  plot_in[plot_in.length] = diff_ifin / diff_ugmt;
252
  plot_out[plot_out.length]= diff_ifout / diff_ugmt;
253
  var index_plot = plot_in.length - 1;
254

    
255
  SVGDoc.getElementById('graph_in_txt').firstChild.data = formatSpeed(plot_in[index_plot], unit);
256
  SVGDoc.getElementById('graph_out_txt').firstChild.data = formatSpeed(plot_out[index_plot], unit);
257

    
258
  /* determine peak for sensible scaling */
259
  if (scale_type == 'up') {
260
    if (plot_in[index_plot] > max)
261
      max = plot_in[index_plot];
262
    if (plot_out[index_plot] > max)
263
      max = plot_out[index_plot];
264
  }
265
  else if (scale_type == 'follow') {
266
    i = 0;
267
    max = 0;
268
    while (i < plot_in.length) {
269
      if (plot_in[i] > max)
270
        max = plot_in[i];
271
      if (plot_out[i] > max)
272
        max = plot_out[i];
273
      i++;
274
    }
275
  }
276

    
277
  var rmax;  // max, rounded up
278

    
279
  if (unit == 'bits') {
280
    /* round up max, such that
281
         100 kbps -> 200 kbps -> 400 kbps -> 800 kbps -> 1 Mbps -> 2 Mbps -> ... */
282
    rmax = 12500;
283
    i = 0;
284
    while (max > rmax) {
285
      i++;
286
      if (i && (i % 4 == 0))
287
        rmax *= 1.25;
288
      else
289
        rmax *= 2;
290
    }
291
  } else {
292
    /* round up max, such that
293
         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 ... */
294
    rmax = 10240;
295
    i = 0;
296
    while (max > rmax) {
297
      i++;
298
      if (i && (i % 4 == 0))
299
        rmax *= 1.25;
300
      else
301
        rmax *= 2;
302
      
303
      if (i == 8)
304
        rmax *= 1.024;
305
    }
306
  }
307

    
308
  scale = <?=$height?> / rmax;
309

    
310
  /* change labels accordingly */
311
  SVGDoc.getElementById('grid_txt1').firstChild.data = formatSpeed(3*rmax/4,unit);
312
  SVGDoc.getElementById('grid_txt2').firstChild.data = formatSpeed(2*rmax/4,unit);
313
  SVGDoc.getElementById('grid_txt3').firstChild.data = formatSpeed(rmax/4,unit);
314

    
315
  var path_in = "M 0 " + (<?=$height?> - (plot_in[0] * scale));
316
  var path_out = "M 0 " + (<?=$height?> - (plot_out[0] * scale));
317
  for (i = 1; i < plot_in.length; i++)
318
  {
319
    var x = step * i;
320
    var y_in = <?=$height?> - (plot_in[i] * scale);
321
    var y_out = <?=$height?> - (plot_out[i] * scale);
322
    path_in += " L" + x + " " + y_in;
323
    path_out += " L" + x + " " + y_out;
324
  }
325

    
326
  SVGDoc.getElementById('error').setAttributeNS(null, 'visibility', 'hidden');
327
  SVGDoc.getElementById('graph_in').setAttributeNS(null, 'd', path_in);
328
  SVGDoc.getElementById('graph_out').setAttributeNS(null, 'd', path_out);
329

    
330
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
331
}
332

    
333
function handle_error() {
334
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
335
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
336
}
337

    
338
function isNumber(a) {
339
  return typeof a == 'number' && isFinite(a);
340
}
341

    
342
function formatSpeed(speed, unit) {
343
  if (unit == 'bits')
344
    return formatSpeedBits(speed);
345
  if (unit == 'bytes')
346
    return formatSpeedBytes(speed);
347
}
348

    
349
function formatSpeedBits(speed) {
350
  // format speed in bits/sec, input: bytes/sec
351
  if (speed < 125000)
352
    return Math.round(speed / 125) + " Kbps";
353
  if (speed < 125000000)
354
    return Math.round(speed / 1250)/100 + " Mbps";
355
  // else
356
  return Math.round(speed / 1250000)/100 + " Gbps";  /* wow! */
357
}
358

    
359
function formatSpeedBytes(speed) {
360
  // format speed in bytes/sec, input:  bytes/sec
361
  if (speed < 1048576)
362
    return Math.round(speed / 10.24)/100 + " KB/s";
363
  if (speed < 1073741824)
364
    return Math.round(speed / 10485.76)/100 + " MB/s";
365
  // else
366
  return Math.round(speed / 10737418.24)/100 + " GB/s";  /* wow! */
367
}
368

    
369
function LZ(x) {
370
  return (x < 0 || x > 9 ? "" : "0") + x;
371
}
372

    
373
    ]]>
374
  </script>
375
</svg>
(62-62/203)