fix proto sort
[tomato/davidwu.git] / release / src / router / www / qos-detailed.asp
blob0c8ef8866bca767e83c1425a9703bae583087ebb
1 <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN'>
2 <!--
3 Tomato GUI
4 Copyright (C) 2006-2010 Jonathan Zarate
5 http://www.polarcloud.com/tomato/
7 Filtering/Extensions on this QoS/Connection Details page
8 Copyright (C) 2011 Augusto Bott
9 http://code.google.com/p/tomato-sdhc-vlan/
11 For use with Tomato Firmware only.
12 No part of this file may be used without permission.
13 -->
14 <html>
15 <head>
16 <meta http-equiv='content-type' content='text/html;charset=utf-8'>
17 <meta name='robots' content='noindex,nofollow'>
18 <title>[<% ident(); %>] QoS: View Details</title>
19 <link rel='stylesheet' type='text/css' href='tomato.css'>
20 <% css(); %>
21 <script type='text/javascript' src='tomato.js'></script>
23 <!-- / / / -->
25 <style type='text/css'>
26 #grid .co7 {
27 width: 20px;
29 #grid .co8 {
30 text-align: right;
32 #grid .co9 {
33 text-align: right;
35 </style>
37 <script type='text/javascript' src='debug.js'></script>
38 <script type='text/javascript' src='protocols.js'></script>
39 <script type='text/javascript' src='interfaces.js'></script>
41 <script type='text/javascript'>
43 // <% nvram('qos_classnames,lan_ipaddr,lan1_ipaddr,lan2_ipaddr,lan3_ipaddr,lan_netmask,lan1_netmask,lan2_netmask,lan3_netmask,t_hidelr'); %>
45 var Unclassified = ['Unclassified'];
46 var classNames = nvram.qos_classnames.split(' '); //Toastman Class Labels
47 var abc = Unclassified.concat(classNames);
49 var colors = ['F08080','E6E6FA','0066CC','8FBC8F','FAFAD2','ADD8E6','9ACD32','E0FFFF','90EE90','FF9933','FFF0F5'];
50 var filterip = [];
51 var filteripe = [];
53 if ((viewClass = '<% cgi_get("class"); %>') == '') {
54 viewClass = -1;
56 else if ((isNaN(viewClass *= 1)) || (viewClass < 0) || (viewClass > 10)) {
57 viewClass = 0;
60 var queue = [];
61 var xob = null;
62 var cache = [];
63 var lock = 0;
65 function resolve()
67 if ((queue.length == 0) || (xob)) return;
69 xob = new XmlHttp();
70 xob.onCompleted = function(text, xml) {
71 eval(text);
72 for (var i = 0; i < resolve_data.length; ++i) {
73 var r = resolve_data[i];
74 if (r[1] == '') r[1] = r[0];
75 cache[r[0]] = r[1];
76 if (lock == 0) grid.setName(r[0], r[1]);
78 if (queue.length == 0) {
79 if ((lock == 0) && (resolveCB) && (grid.sortColumn == 4)) grid.resort();
81 else setTimeout(resolve, 500);
82 xob = null;
84 xob.onError = function(ex) {
85 xob = null;
88 xob.post('resolve.cgi', 'ip=' + queue.splice(0, 20).join(','));
91 var resolveCB = 0;
92 var bcastCB = 0;
93 var mcastCB = 0;
95 function resolveChanged()
97 var b;
99 b = E('_f_autoresolve').checked ? 1 : 0;
100 if (b != resolveCB) {
101 resolveCB = b;
102 cookie.set('qos_resolve', b);
104 if (b) grid.resolveAll();
107 var grid = new TomatoGrid();
109 grid.dataToView = function(data) {
110 var s, v = [];
111 for (var col = 0; col < data.length; ++col) {
112 switch (col) {
113 case 5: // Class
114 s = abc[data[col]] || ('' + data[col]);
115 break;
116 case 6: // Rule #
117 s = (data[col] * 1 > 0) ? ('' + data[col]) : '';
118 break;
119 case 7: // Bytes out
120 case 8: // Bytes in
121 s = scaleSize(data[col] * 1);
122 break;
123 default:
124 s = '' + data[col];
125 break;
127 v.push(s);
129 return v;
132 grid.sortCompare = function(a, b) {
133 var obj = TGO(a);
134 var col = obj.sortColumn;
135 var da = a.getRowData();
136 var db = b.getRowData();
137 var r;
139 switch (col) {
140 case 2: // S port
141 case 4: // D port
142 case 6: // Rule #
143 case 7: // Bytes out
144 case 8: // Bytes in
145 r = cmpInt(da[col], db[col]);
146 break;
147 case 5: // Class
148 r = cmpInt(da[col] ? da[col] : 10000, db[col] ? db[col] : 10000);
149 break;
150 case 1:
151 case 3:
152 var a = fixIP(da[col]);
153 var b = fixIP(db[col]);
154 if ((a != null) && (b != null)) {
155 r = aton(a) - aton(b);
156 break;
158 default:
159 r = cmpText(da[col], db[col]);
160 break;
162 return obj.sortAscending ? r : -r;
165 grid.onClick = function(cell) {
166 var row = PR(cell);
167 var ip = row.getRowData()[3];
168 if (this.lastClicked != row) {
169 this.lastClicked = row;
170 if (ip.indexOf('<') == -1) {
171 queue.push(ip);
172 row.style.cursor = 'wait';
173 resolve();
176 else {
177 this.resolveAll();
181 grid.resolveAll = function()
183 var i, ip, row, q, cols, j;
185 q = [];
186 cols = [1, 3];
187 for (i = 1; i < this.tb.rows.length; ++i) {
188 row = this.tb.rows[i];
189 for (j = cols.length-1; j >= 0; j--) {
190 ip = row.getRowData()[cols[j]];
191 if (ip.indexOf('<') == -1) {
192 if (!q[ip]) {
193 q[ip] = 1;
194 queue.push(ip);
196 row.style.cursor = 'wait';
200 q = null;
201 resolve();
204 grid.setName = function(ip, name) {
205 var i, row, data, cols, j;
207 cols = [1, 3];
208 for (i = this.tb.rows.length - 1; i > 0; --i) {
209 row = this.tb.rows[i];
210 data = row.getRowData();
211 for (j = cols.length-1; j >= 0; j--) {
212 if (data[cols[j]] == ip) {
213 data[cols[j]] = name + ((ip.indexOf(':') != -1) ? '<br>' : ' ') + '<small>(' + ip + ')</small>';
214 row.setRowData(data);
215 if (E('_f_shortcuts').checked)
216 data[cols[j]] = data[cols[j]] + ' <small><a href="javascript:addExcludeList(\'' + ip + '\')" title="Exclude from List">[Hide]</a></small>';
217 row.cells[cols[j]].innerHTML = data[cols[j]];
218 row.style.cursor = 'default';
224 grid.setup = function() {
225 this.init('grid', 'sort');
226 this.headerSet(['Proto', 'Source', 'S Port', 'Destination', 'D Port', 'Class', 'Rule', 'Bytes Out', 'Bytes In']);
229 var ref = new TomatoRefresh('update.cgi', '', 0, 'qos_detailed');
231 var numconntotal = 0;
232 var numconnshown = 0;
234 ref.refresh = function(text) {
235 var i, b, d, cols, j;
237 ++lock;
239 numconntotal = 0;
240 numconnshown = 0;
242 try {
243 ctdump = [];
244 eval(text);
246 catch (ex) {
247 ctdump = [];
250 grid.lastClicked = null;
251 grid.removeAllData();
253 var c = [];
254 var q = [];
255 var cursor;
256 var ip;
258 var fskip;
260 cols = [2, 3];
262 for (i = 0; i < ctdump.length; ++i) {
263 fskip=0;
264 numconntotal++;
265 b = ctdump[i];
267 if (E('_f_excludegw').checked) {
268 if ((b[2] == nvram.lan_ipaddr) || (b[3] == nvram.lan_ipaddr) ||
269 (b[2] == nvram.lan1_ipaddr) || (b[3] == nvram.lan1_ipaddr) ||
270 (b[2] == nvram.lan2_ipaddr) || (b[3] == nvram.lan2_ipaddr) ||
271 (b[2] == nvram.lan3_ipaddr) || (b[3] == nvram.lan3_ipaddr) ||
272 (b[2] == '127.0.0.1') || (b[3] == '127.0.0.1')) {
273 continue;
277 if (E('_f_excludebcast').checked) {
278 if ((b[3] == getBroadcastAddress(getNetworkAddress(nvram.lan_ipaddr,nvram.lan_netmask),nvram.lan_netmask)) ||
279 (b[3] == getBroadcastAddress(getNetworkAddress(nvram.lan1_ipaddr,nvram.lan1_netmask),nvram.lan1_netmask)) ||
280 (b[3] == getBroadcastAddress(getNetworkAddress(nvram.lan2_ipaddr,nvram.lan2_netmask),nvram.lan2_netmask)) ||
281 (b[3] == getBroadcastAddress(getNetworkAddress(nvram.lan3_ipaddr,nvram.lan3_netmask),nvram.lan3_netmask)) ||
282 (b[3] == '255.255.255.255') || (b[3] == '0.0.0.0')) {
283 continue;
287 if (E('_f_excludemcast').checked) {
288 var mmin = 3758096384; // aton('224.0.0.0')
289 var mmax = 4026531839; // aton('239.255.255.255')
290 if (((aton(b[2]) >= mmin) && (aton(b[2]) <= mmax)) ||
291 ((aton(b[3]) >= mmin) && (aton(b[3]) <= mmax))) {
292 continue;
296 if (filteripe.length>0) {
297 fskip = 0;
298 for (x = 0; x < filteripe.length; ++x) {
299 if ((b[2] == filteripe[x]) || (b[3] == filteripe[x])) {
300 fskip=1;
301 break;
304 if (fskip == 1) continue;
307 if (filterip.length>0) {
308 fskip = 1;
309 for (x = 0; x < filterip.length; ++x) {
310 if ((b[2] == filterip[x]) || (b[3] == filterip[x])) {
311 fskip=0;
312 break;
315 if (fskip == 1) continue;
318 for (j = cols.length-1; j >= 0; j--) {
319 ip = b[cols[j]];
320 if (cache[ip] != null) {
321 c[ip] = cache[ip];
322 b[cols[j]] = cache[ip] + ((ip.indexOf(':') != -1) ? '<br>' : ' ') + '<small>(' + ip + ')</small>';
323 cursor = 'default';
325 else {
326 if (resolveCB) {
327 if (!q[ip]) {
328 q[ip] = 1;
329 queue.push(ip);
331 cursor = 'wait';
333 else cursor = null;
335 if (E('_f_shortcuts').checked) {
336 if (cache[ip] == null) {
337 b[cols[j]] = b[cols[j]] + ' <small><a href="javascript:addToResolveQueue(\'' + ip + '\')" title="Resolve the hostname of this address">[resolve]</a></small>';
339 b[cols[j]] = b[cols[j]] + ' <small><a href="javascript:addExcludeList(\'' + ip + '\')" title="Filter out this IP">[hide]</a></small>';
343 numconnshown++;
344 d = [protocols[b[0]] || b[0], b[2], b[4], b[3], b[5], b[8], b[9], b[6], b[7]];
345 var row = grid.insertData(-1, d);
346 if (cursor) row.style.cursor = cursor;
348 cache = c;
349 c = null;
350 q = null;
352 grid.resort();
353 setTimeout(function() { E('loading').style.visibility = 'hidden'; }, 100);
355 --lock;
357 if (resolveCB) resolve();
358 if (numconnshown != numconntotal)
359 E('numtotalconn').innerHTML='<small><i>(showing ' + numconnshown + ' out of ' + numconntotal + ' connections)</i></small>';
360 else
361 E('numtotalconn').innerHTML='<small><i>(' + numconntotal + ' connections)</i></small>';
364 function addExcludeList(address) {
365 if (E('_f_filter_ipe').value.length<6) {
366 E('_f_filter_ipe').value = address;
367 } else {
368 if (E('_f_filter_ipe').value.indexOf(address) < 0) {
369 E('_f_filter_ipe').value = E('_f_filter_ipe').value + ',' + address;
372 dofilter();
375 function addToResolveQueue(ip) {
376 queue.push(ip);
377 resolve();
380 function init() {
381 var c;
383 if ((c = cookie.get('qos_filterip')) != null) {
384 cookie.set('qos_filterip', '', 0);
385 if (c.length>6) {
386 E('_f_filter_ip').value = c;
387 filterip = c.split(',');
391 if (((c = cookie.get('qos_resolve')) != null) && (c == '1')) {
392 E('_f_autoresolve').checked = resolveCB = 1;
395 if (((c = cookie.get('qos_bcast')) != null) && (c == '1')) {
396 E('_f_excludebcast').checked = bcastCB = 1;
399 if (((c = cookie.get('qos_mcast')) != null) && (c == '1')) {
400 E('_f_excludemcast').checked = mcastCB = 1;
403 if (((c = cookie.get('qos_details_filters_vis')) != null) && (c == '1')) {
404 toggleVisibility("filters");
407 if (viewClass != -1) E('stitle').innerHTML = 'Details: ' + abc[viewClass] + ' <span id=\'numtotalconn\'></span>';
409 E('_f_shortcuts').checked = (((c = cookie.get('qos_detailed_shortcuts')) != null) && (c == '1'));
411 grid.setup();
412 ref.postData = 'exec=ctdump&arg0=' + viewClass;
413 ref.initPage(250);
415 if (!ref.running) ref.once = 1;
416 ref.start();
419 function dofilter() {
420 if (E('_f_filter_ip').value.length>6) {
421 filterip = E('_f_filter_ip').value.split(',');
422 } else {
423 filterip = [];
426 if (E('_f_filter_ipe').value.length>6) {
427 filteripe = E('_f_filter_ipe').value.split(',');
428 } else {
429 filteripe = [];
432 if (!ref.running) ref.once = 1;
433 ref.start();
436 function toggleVisibility(whichone) {
437 if(E('sesdiv' + whichone).style.display=='') {
438 E('sesdiv' + whichone).style.display='none';
439 E('sesdiv' + whichone + 'showhide').innerHTML='(Click here to show)';
440 cookie.set('qos_details_' + whichone + '_vis', 0);
441 } else {
442 E('sesdiv' + whichone).style.display='';
443 E('sesdiv' + whichone + 'showhide').innerHTML='(Click here to hide)';
444 cookie.set('qos_details_' + whichone + '_vis', 1);
448 function verifyFields(focused, quiet)
450 var b;
452 b = E('_f_excludebcast').checked ? 1 : 0;
453 if (b != bcastCB) {
454 bcastCB = b;
455 cookie.set('qos_bcast', b);
458 b = E('_f_excludemcast').checked ? 1 : 0;
459 if (b != mcastCB) {
460 mcastCB = b;
461 cookie.set('qos_mcast', b);
464 cookie.set('qos_detailed_shortcuts', (E('_f_shortcuts').checked ? '1' : '0'), 1);
466 dofilter();
467 resolveChanged();
468 return 1;
471 </script>
472 </head>
473 <body onload='init()'>
474 <form id='_fom' action='javascript:{}'>
475 <table id='container' cellspacing=0>
476 <tr><td colspan=2 id='header'>
477 <div class='title'>Tomato</div>
478 <div class='version'>Version <% version(); %></div>
479 </td></tr>
480 <tr id='body'><td id='navi'><script type='text/javascript'>navi()</script></td>
481 <td id='content'>
482 <div id='ident'><% ident(); %></div>
484 <!-- / / / -->
486 <div class='section-title' id='stitle' onclick='document.location="qos-graphs.asp"' style='cursor:pointer'>Details <span id='numtotalconn'></span></div>
487 <div class='section'>
488 <table id='grid' class='tomato-grid' style="float:left" cellspacing=1></table>
490 <div id='loading'><br><b>Loading...</b></div>
491 </div>
493 <!-- / / / -->
495 <div class='section-title'>Filters <small><i><a href='javascript:toggleVisibility("filters");'><span id='sesdivfiltersshowhide'>(Click here to show)</span></a></i></small></div>
496 <div class='section' id='sesdivfilters' style='display:none'>
497 <script type='text/javascript'>
498 var c;
499 c = [];
500 c.push({ title: 'Show only these IPs', name: 'f_filter_ip', size: 50, maxlen: 255, type: 'text', suffix: ' <small>(Comma separated list)</small>' });
501 c.push({ title: 'Exclude these IPs', name: 'f_filter_ipe', size: 50, maxlen: 255, type: 'text', suffix: ' <small>(Comma separated list)</small>' });
502 c.push({ title: 'Exclude gateway traffic', name: 'f_excludegw', type: 'checkbox', value: ((nvram.t_hidelr) == '1' ? 1 : 0) });
503 c.push({ title: 'Exclude IPv4 broadcast', name: 'f_excludebcast', type: 'checkbox' });
504 c.push({ title: 'Exclude IPv4 multicast', name: 'f_excludemcast', type: 'checkbox' });
505 c.push({ title: 'Auto resolve addresses', name: 'f_autoresolve', type: 'checkbox' });
506 c.push({ title: 'Show shortcuts', name: 'f_shortcuts', type: 'checkbox' });
507 createFieldTable('',c);
508 </script>
509 </div>
511 <!-- / / / -->
513 </td></tr>
514 <tr><td id='footer' colspan=2>
515 <script type='text/javascript'>genStdRefresh(1,1,'ref.toggle()');</script>
516 </td></tr>
517 </table>
518 </form>
519 </body>
520 </html>