Project

General

Profile

Download (14.3 KB) Statistics
| Branch: | Tag: | Revision:
1 5b237745 Scott Ullrich
<?php
2
/*
3
	graph.php
4 6afa3a82 Scott Ullrich
	part of m0n0wall (http://m0n0.ch/wall)
5
	
6 985a897f Scott Ullrich
	Copyright (C) 2004-2006 T. Lechat <dev@lechat.org>, Manuel Kasper <mk@neon1.net>
7 6afa3a82 Scott Ullrich
	and Jonathan Watt <jwatt@jwatt.org>.
8 5b237745 Scott Ullrich
	All rights reserved.
9 6afa3a82 Scott Ullrich
	
10 5b237745 Scott Ullrich
	Redistribution and use in source and binary forms, with or without
11
	modification, are permitted provided that the following conditions are met:
12 6afa3a82 Scott Ullrich
	
13 5b237745 Scott Ullrich
	1. Redistributions of source code must retain the above copyright notice,
14
	   this list of conditions and the following disclaimer.
15 6afa3a82 Scott Ullrich
	
16 5b237745 Scott Ullrich
	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 6afa3a82 Scott Ullrich
	
20 5b237745 Scott Ullrich
	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 6b07c15a Matthew Grooms
##|+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 12e437a2 Scott Ullrich
require("globals.inc");
40 8b379e47 Scott Ullrich
require("guiconfig.inc");
41 beb54c8f Scott Ullrich
42 45581172 Ermal Luçi
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 6afa3a82 Scott Ullrich
header("Content-type: image/svg+xml");
48 5b237745 Scott Ullrich
49
/********** HTTP GET Based Conf ***********/
50 6afa3a82 Scott Ullrich
$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 5b237745 Scott Ullrich
53
/********* Other conf *******/
54 6afa3a82 Scott Ullrich
$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 358cb12c Scott Dale
if ($_GET["timeint"])
57
	$time_interval = $_GET["timeint"];		//Refresh time Interval
58
else
59 920e60b5 Scott Ullrich
	$time_interval = 3;
60 0543e1e9 Scott Ullrich
61 6afa3a82 Scott Ullrich
//SVG attributes
62
$attribs['axis']='fill="black" stroke="black"';
63 a85f75c2 Scott Ullrich
$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 6afa3a82 Scott Ullrich
$attribs['legend']='fill="black" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="4"';
68 a85f75c2 Scott Ullrich
$attribs['graphname']='fill="#FF0000" font-family="Tahoma, Verdana, Arial, Helvetica, sans-serif" font-size="8"';
69 6afa3a82 Scott Ullrich
$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 a85f75c2 Scott Ullrich
$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 6afa3a82 Scott Ullrich
$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 5b237745 Scott Ullrich
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 6afa3a82 Scott Ullrich
$height=100;            //SVG internal height : do not modify
80
$width=200;             //SVG internal width : do not modify
81 5b237745 Scott Ullrich
82 72d1b575 Scott Ullrich
$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 5b237745 Scott Ullrich
/********* Graph DATA **************/
91 6afa3a82 Scott Ullrich
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 5b237745 Scott Ullrich
var max = 0;
168 6afa3a82 Scott Ullrich
var plot_in = new Array();
169
var plot_out = new Array();
170 5b237745 Scott Ullrich
171 6afa3a82 Scott Ullrich
var max_num_points = <?=$nb_plot?>;  // maximum number of plot data points
172
var step = <?=$width?> / max_num_points ;
173 5b237745 Scott Ullrich
var unit = 'bits';
174
var scale_type = '<?=$scale_type?>';
175
176
function init(evt) {
177 6afa3a82 Scott Ullrich
  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 5b237745 Scott Ullrich
181 6afa3a82 Scott Ullrich
  fetch_data();
182 5b237745 Scott Ullrich
}
183
184
function switch_unit(event)
185
{
186 6afa3a82 Scott Ullrich
  SVGDoc.getElementById('switch_unit').firstChild.data = 'Switch to ' + unit + '/s';
187
  unit = (unit == 'bits') ? 'bytes' : 'bits';
188 5b237745 Scott Ullrich
}
189
190
function switch_scale(event)
191
{
192 6afa3a82 Scott Ullrich
  scale_type = (scale_type == 'up') ? 'follow' : 'up';
193
  SVGDoc.getElementById('switch_scale').firstChild.data = 'AutoScale (' + scale_type + ')';
194 5b237745 Scott Ullrich
}
195
196 6afa3a82 Scott Ullrich
function fetch_data() {
197
  getURL('<?=$fetch_link?>', plot_data);
198 5b237745 Scott Ullrich
}
199
200 6afa3a82 Scott Ullrich
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 67c04e80 Seth Mos
  var diff_ifin  = ifin - last_ifin;
221
  var diff_ifout = ifout - last_ifout;
222
223 6afa3a82 Scott Ullrich
  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 5b237745 Scott Ullrich
		}
247 6afa3a82 Scott Ullrich
		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 5b237745 Scott Ullrich
}
332
333 6afa3a82 Scott Ullrich
function handle_error() {
334
  SVGDoc.getElementById("error").setAttributeNS(null, 'visibility', 'visible');
335
  setTimeout('fetch_data()',<?=1000*$time_interval?>);
336 5b237745 Scott Ullrich
}
337
338
function isNumber(a) {
339 6afa3a82 Scott Ullrich
  return typeof a == 'number' && isFinite(a);
340 5b237745 Scott Ullrich
}
341
342 6afa3a82 Scott Ullrich
function formatSpeed(speed, unit) {
343
  if (unit == 'bits')
344
    return formatSpeedBits(speed);
345
  if (unit == 'bytes')
346
    return formatSpeedBytes(speed);
347 5b237745 Scott Ullrich
}
348
349
function formatSpeedBits(speed) {
350 6afa3a82 Scott Ullrich
  // 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 5b237745 Scott Ullrich
}
358 6afa3a82 Scott Ullrich
359 5b237745 Scott Ullrich
function formatSpeedBytes(speed) {
360 6afa3a82 Scott Ullrich
  // 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 5b237745 Scott Ullrich
}
368 6afa3a82 Scott Ullrich
369 5b237745 Scott Ullrich
function LZ(x) {
370 6afa3a82 Scott Ullrich
  return (x < 0 || x > 9 ? "" : "0") + x;
371 5b237745 Scott Ullrich
}
372 6afa3a82 Scott Ullrich
373
    ]]>
374
  </script>
375 985a897f Scott Ullrich
</svg>