More agent deflate compression support.

Ylian Saint-Hilaire committed Jul 17, 2020 at 19:55 UTC 8be7984a60a8feb8e3919e960ff353ba95a50d7c
5 files changed +42 -26
agents/meshcore.js
+28 -17
@@ -643,6 +643,7 @@ function createMeshCore(agent) {
643
644 // Send a wake-on-lan packet
645 function sendWakeOnLan(hexMac) {
646 + hexMac = hexMac.split(':').join('');
647 var count = 0;
648 try {
649 var interfaces = require('os').networkInterfaces();
@@ -650,17 +651,12 @@ function createMeshCore(agent) {
651 for (var x = 1; x <= 16; ++x) { magic += hexMac; }
652 var magicbin = Buffer.from(magic, 'hex');
653
653 - for (var adapter in interfaces)
654 - {
655 - if (interfaces.hasOwnProperty(adapter))
656 - {
657 - for (var i = 0; i < interfaces[adapter].length; ++i)
658 - {
654 + for (var adapter in interfaces) {
655 + if (interfaces.hasOwnProperty(adapter)) {
656 + for (var i = 0; i < interfaces[adapter].length; ++i) {
657 var addr = interfaces[adapter][i];
660 - if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00'))
661 - {
662 - try
663 - {
658 + if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) {
659 + try {
660 var socket = require('dgram').createSocket({ type: 'udp4' });
661 socket.bind({ address: addr.address });
662 socket.setBroadcast(true);
@@ -668,14 +664,12 @@ function createMeshCore(agent) {
664 socket.descriptorMetadata = 'WoL (' + addr.address + ' => ' + hexMac + ')';
665 count++;
666 }
671 - catch(ee)
672 - {
673 - }
667 + catch (ex) { }
668 }
669 }
670 }
671 }
678 - } catch (e) { }
672 + } catch (ex) { }
673 return count;
674 }
675
@@ -701,7 +695,8 @@ function createMeshCore(agent) {
695 if (xurl != null) {
696 xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters
697 var woptions = http.parseUri(xurl);
704 - woptions.perMessageDeflate = true;
698 + woptions.perMessageDeflate = false;
699 + if (typeof data.perMessageDeflate == 'boolean') { woptions.perMessageDeflate = data.perMessageDeflate; }
700 woptions.rejectUnauthorized = 0;
701 //sendConsoleText(JSON.stringify(woptions));
702 //sendConsoleText('TUNNEL: ' + JSON.stringify(data));
@@ -1188,9 +1183,25 @@ function createMeshCore(agent) {
1183 }
1184
1185 function onTunnelClosed() {
1191 - if (tunnels[this.httprequest.index] == null) return; // Stop duplicate calls.
1186 + var tunnel = tunnels[this.httprequest.index];
1187 + if (tunnel == null) return; // Stop duplicate calls.
1188 +
1189 + // Sent tunnel statistics to the server
1190 + mesh.SendCommand({
1191 + action: 'tunnelCloseStats',
1192 + url: tunnel.url,
1193 + userid: tunnel.userid,
1194 + protocol: tunnel.protocol,
1195 + sessionid: tunnel.sessionid,
1196 + sent: this.bytesSent_uncompressed + '',
1197 + sentActual: this.bytesSent_actual + '',
1198 + sentRatio: this.bytesSent_ratio,
1199 + received: this.bytesReceived_uncompressed + '',
1200 + receivedActual: this.bytesReceived_actual + '',
1201 + receivedRatio: this.bytesReceived_ratio
1202 + });
1203
1193 -// sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid);
1204 + //sendConsoleText("Tunnel #" + this.httprequest.index + " closed. Sent -> " + this.bytesSent_uncompressed + ' bytes (uncompressed), ' + this.bytesSent_actual + ' bytes (actual), ' + this.bytesSent_ratio + '% compression', this.httprequest.sessionid);
1205 delete tunnels[this.httprequest.index];
1206
1207 /*
meshagent.js
+6 -7
@@ -239,7 +239,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
239 if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; } // If agent disconnection, complete and exit now.
240 if (obj.nodeid != null) { parent.parent.debug('agent', "Agent update required, NodeID=0x" + obj.nodeid.substring(0, 16) + ', ' + obj.agentExeInfo.desc); }
241 parent.agentStats.agentBinaryUpdate++;
242 - if (obj.agentExeInfo.data == null) {
242 + if ((obj.agentExeInfo.data == null) && (((obj.agentInfo.capabilities & 0x80) == 0) || (obj.agentExeInfo.zdata == null))) {
243 // Read the agent from disk
244 parent.fs.open(obj.agentExeInfo.path, 'r', function (err, fd) {
245 if (obj.agentExeInfo == null) return; // Agent disconnected during this call.
@@ -292,7 +292,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
292 obj.agentUpdate.buf[2] = 0;
293 obj.agentUpdate.buf[3] = 1;
294
295 - /*
295 // If agent supports compression, send the compressed agent if possible.
296 if ((obj.agentInfo.capabilities & 0x80) && (obj.agentExeInfo.zdata != null)) {
297 // Send compressed data
@@ -305,11 +304,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
304 obj.agentUpdate.agentUpdateHash = obj.agentExeInfo.hash;
305 //console.log('Sending uncompressed update agent', obj.agentExeInfo.hashhex);
306 }
308 - */
309 -
310 - // Send uncompressed data
311 - obj.agentUpdate.agentUpdateData = obj.agentExeInfo.data;
312 - obj.agentUpdate.agentUpdateHash = obj.agentExeInfo.hash;
307
308 const len = Math.min(parent.parent.agentUpdateBlockSize, obj.agentUpdate.agentUpdateData.length - obj.agentUpdate.ptr);
309 if (len > 0) {
@@ -1418,6 +1412,11 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1412 }
1413 break;
1414 }
1415 + case 'tunnelCloseStats': {
1416 + // TODO: This this extra stats from the tunnel, you can merge this into the tunnel event in the database.
1417 + //console.log(command);
1418 + break;
1419 + }
1420 case 'plugin': {
1421 if ((parent.parent.pluginHandler == null) || (typeof command.plugin != 'string')) break;
1422 try {
meshcentral-config-schema.json
+2 -1
@@ -55,7 +55,8 @@
55 "agentPong": { "type": "integer", "minimum": 1, "description": "When specified, sends data to the agent at x seconds interval." },
56 "agentIdleTimeout": { "type": "integer", "minimum": 1 },
57 "compression": { "type": "boolean", "default": true, "description": "Enables GZIP compression for web requests." },
58 - "wscompression": { "type": "boolean", "default": false, "description": "Enables websocket per-message deflate compression." },
58 + "wscompression": { "type": "boolean", "default": false, "description": "Enables server-side, websocket per-message deflate compression." },
59 + "agentwscompression": { "type": "boolean", "default": true, "description": "Enables agent-side, websocket per-message deflate compression. wscompression must also be true for this to work." },
60 "meshErrorLogPath": { "type": "string" },
61 "npmPath": { "type": "string" },
62 "npmProxy": { "type": "string", "format": "uri" },
meshuser.js
+3
@@ -1218,6 +1218,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1218 if (typeof domain.notificationmessages.terminal == 'string') { command.soptions.notifyMsgTerminal = domain.notificationmessages.terminal; }
1219 if (typeof domain.notificationmessages.files == 'string') { command.soptions.notifyMsgFiles = domain.notificationmessages.files; }
1220 }
1221 +
1222 + // Add tunnel pre-message deflate
1223 + if (typeof parent.parent.config.settings.agentwscompression == 'boolean') { command.perMessageDeflate = parent.parent.config.settings.agentwscompression; }
1224 }
1225
1226 // If a response is needed, set a callback function
sample-config-advanced.json
+3 -1
@@ -37,7 +37,9 @@
37 "_allowFraming": true,
38 "_cookieIpCheck": false,
39 "_cookieEncoding": "hex",
40 - "_compression": false,
40 + "_compression": true,
41 + "_wscompression": false,
42 + "_agentwscompression": true,
43 "_webRTC": false,
44 "_nice404": false,
45 "_clickOnce": false,