Completed server load-balancing support

Ylian Saint-Hilaire committed Sep 20, 2017 at 14:44 UTC 453383f851395f84daf9a24e045eba7aa5f7cd38
19 files changed +307 -58
agents/MeshService.exe
Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ
agents/MeshService64.exe
Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ
agents/meshagent_arm
Binary files a/agents/meshagent_arm and b/agents/meshagent_arm differ
agents/meshagent_pi
Binary files a/agents/meshagent_pi and b/agents/meshagent_pi differ
agents/meshagent_pogo
Binary files a/agents/meshagent_pogo and b/agents/meshagent_pogo differ
agents/meshagent_poky
Binary files a/agents/meshagent_poky and b/agents/meshagent_poky differ
agents/meshagent_poky64
Binary files a/agents/meshagent_poky64 and b/agents/meshagent_poky64 differ
agents/meshagent_x86
Binary files a/agents/meshagent_x86 and b/agents/meshagent_x86 differ
agents/meshagent_x86-64
Binary files a/agents/meshagent_x86-64 and b/agents/meshagent_x86-64 differ
agents/meshagent_x86-64_nokvm
Binary files a/agents/meshagent_x86-64_nokvm and b/agents/meshagent_x86-64_nokvm differ
agents/meshagent_x86_nokvm
Binary files a/agents/meshagent_x86_nokvm and b/agents/meshagent_x86_nokvm differ
agents/meshcore.js
+86 -38
@@ -26,7 +26,7 @@ function createMeshCore(agent) {
26 var lastNetworkInfo = null;
27 var lastPublicLocationInfo = null;
28 var selfInfoUpdateTimer = null;
29 - obj.useNativePipes = (process.platform == 'win32');
29 + obj.useNativePipes = true; //(process.platform == 'win32');
30
31 var http = require('http');
32 var fs = require('fs');
@@ -158,7 +158,7 @@ function createMeshCore(agent) {
158 };
159
160 // Replace a string with a number if the string is an exact number
161 - function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) == x)) { x = parseInt(x); } return x; }
161 + function toNumberIfNumber(x) { if ((typeof x == 'string') && (+parseInt(x) === x)) { x = parseInt(x); } return x; }
162
163 // Convert decimal to hex
164 function char2hex(i) { return (i + 0x100).toString(16).substr(-2).toUpperCase(); }
@@ -218,16 +218,48 @@ function createMeshCore(agent) {
218 return results;
219 }
220
221 - // Parge a URL string into an options object
222 - function parseUrl(url) {
223 - var x = url.split('/');
224 - if (x.length < 4) return null;
225 - var y = x[2].split(':');
226 - var options = {};
227 - var options = { protocol: x[0], hostname: y[0], path: '/' + x.splice(3).join('/') };
228 - if (y.length == 1) { options.port = ((x[0] == 'https:') || (x[0] == 'wss:')) ? 443 : 80; } else { options.port = parseInt(y[1]); }
229 - if (isNaN(options.port) == true) return null;
230 - return options;
221 + // Get server target url with a custom path
222 + function getServerTargetUrl(path) {
223 + var x = mesh.ServerUrl;
224 + //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
225 + if (x == null) { return null; }
226 + if (path == null) { path = ''; }
227 + x = http.parseUri(x);
228 + if (x == null) return null;
229 + return x.protocol + '//' + x.host + ':' + x.port + '/' + path;
230 + }
231 +
232 + // Get server url. If the url starts with "*/..." change it, it not use the url as is.
233 + function getServerTargetUrlEx(url) {
234 + if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
235 + return url;
236 + }
237 +
238 + // Send a wake-on-lan packet
239 + function sendWakeOnLan(hexMac) {
240 + var count = 0;
241 + try {
242 + var interfaces = require('os').networkInterfaces();
243 + var magic = 'FFFFFFFFFFFF';
244 + for (var x = 1; x <= 16; ++x) { magic += hexMac; }
245 + var magicbin = Buffer.from(magic, 'hex');
246 +
247 + for (var adapter in interfaces) {
248 + if (interfaces.hasOwnProperty(adapter)) {
249 + for (var i = 0; i < interfaces[adapter].length; ++i) {
250 + var addr = interfaces[adapter][i];
251 + if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) {
252 + var socket = require('dgram').createSocket({ type: "udp4" });
253 + socket.bind({ address: addr.address });
254 + socket.setBroadcast(true);
255 + socket.send(magicbin, 7, "255.255.255.255");
256 + count++;
257 + }
258 + }
259 + }
260 + }
261 + } catch (e) { }
262 + return count;
263 }
264
265 // Handle a mesh agent command
@@ -245,21 +277,26 @@ function createMeshCore(agent) {
277 else if (data.type == 'tunnel') { // Process a new tunnel connection request
278 if (data.value && data.sessionid) {
279 // Create a new tunnel object
248 - var tunnel = http.request(parseUrl(data.value));
249 - tunnel.upgrade = onTunnelUpgrade;
250 - tunnel.sessionid = data.sessionid;
251 - tunnel.rights = data.rights;
252 - tunnel.state = 0;
253 - tunnel.url = data.value;
254 - tunnel.protocol = 0;
255 -
256 - // Put the tunnel in the tunnels list
257 - var index = 1;
258 - while (tunnels[index]) { index++; }
259 - tunnel.index = index;
260 - tunnels[index] = tunnel;
261 -
262 - sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
280 + //sendConsoleText(data.value);
281 + var xurl = getServerTargetUrlEx(data.value);
282 + //sendConsoleText(xurl);
283 + if (xurl != null) {
284 + var tunnel = http.request(http.parseUri(xurl));
285 + tunnel.upgrade = onTunnelUpgrade;
286 + tunnel.sessionid = data.sessionid;
287 + tunnel.rights = data.rights;
288 + tunnel.state = 0;
289 + tunnel.url = xurl;
290 + tunnel.protocol = 0;
291 +
292 + // Put the tunnel in the tunnels list
293 + var index = 1;
294 + while (tunnels[index]) { index++; }
295 + tunnel.index = index;
296 + tunnels[index] = tunnel;
297 +
298 + sendConsoleText('New tunnel connection #' + index + ': ' + tunnel.url + ', rights: ' + tunnel.rights, data.sessionid);
299 + }
300 }
301 }
302 break;
@@ -267,7 +304,7 @@ function createMeshCore(agent) {
304 case 'wakeonlan': {
305 // Send wake-on-lan on all interfaces for all MAC addresses in data.macs array. The array is a list of HEX MAC addresses.
306 sendConsoleText('Server requesting wake-on-lan for: ' + data.macs.join(', '));
270 - // TODO!!!!
307 + for (var i in data.macs) { sendWakeOnLan(data.macs[i]); }
308 break;
309 }
310 case 'poweraction': {
@@ -554,7 +591,7 @@ function createMeshCore(agent) {
591 var response = null;
592 switch (cmd) {
593 case 'help': { // Displays available commands
557 - response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseurl, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power.';
594 + response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan.';
595 break;
596 }
597 case 'notify': { // Send a notification message to the mesh
@@ -569,7 +606,7 @@ function createMeshCore(agent) {
606 break;
607 }
608 case 'info': { // Return information about the agent and agent core module
572 - response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.';
609 + response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform Info: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nNative Pipes: ' + obj.useNativePipes + '.\r\nServer URL: ' + mesh.ServerUrl + '.';
610 break;
611 }
612 case 'selfinfo': { // Return self information block
@@ -628,10 +665,6 @@ function createMeshCore(agent) {
665 response = 'Database compacted: ' + r;
666 break;
667 }
631 - case 'parseurl': {
632 - response = objToString(parseUrl(args['_'][0]));
633 - break;
634 - }
668 case 'httpget': {
669 if (consoleHttpRequest != null) {
670 response = 'HTTP operation already in progress.';
@@ -639,7 +672,7 @@ function createMeshCore(agent) {
672 if (args['_'].length != 1) {
673 response = 'Proper usage: httpget (url)';
674 } else {
642 - var options = parseUrl(args['_'][0]);
675 + var options = http.parseUri(args['_'][0]);
676 options.method = 'GET';
677 if (options == null) {
678 response = 'Invalid url.';
@@ -648,7 +681,7 @@ function createMeshCore(agent) {
681 consoleHttpRequest.sessionid = sessionid;
682 if (consoleHttpRequest != null) {
683 consoleHttpRequest.end();
651 - response = 'HTTPGET ' + options.protocol + '//' + options.hostname + ':' + options.port + options.path;
684 + response = 'HTTPGET ' + options.protocol + '//' + options.host + ':' + options.port + options.path;
685 }
686 }
687 }
@@ -670,7 +703,7 @@ function createMeshCore(agent) {
703 } else {
704 var httprequest = null;
705 try {
673 - httprequest = http.request(parseUrl(args['_'][0]));
706 + httprequest = http.request(http.parseUri(args['_'][0]));
707 } catch (e) { response = 'Invalid HTTP websocket request'; }
708 if (httprequest != null) {
709 httprequest.upgrade = onWebSocketUpgrade;
@@ -756,7 +789,18 @@ function createMeshCore(agent) {
789 break;
790 }
791 case 'netinfo': { // Show network interface information
759 - response = objToString(mesh.NetInfo, 0, '.');
792 + //response = objToString(mesh.NetInfo, 0, '.');
793 + var interfaces = require('os').networkInterfaces();
794 + response = objToString(interfaces, 0, '.');
795 + break;
796 + }
797 + case 'wakeonlan': { // Send wake-on-lan
798 + if ((args['_'].length != 1) || (args['_'][0].length != 12)) {
799 + response = 'Proper usage: wakeonlan [mac], for example "wakeonlan 010203040506".';
800 + } else {
801 + var count = sendWakeOnLan(args['_'][0]);
802 + response = 'Sent wake-on-lan on ' + count + ' interface(s).';
803 + }
804 break;
805 }
806 case 'sendall': { // Send a message to all consoles on this mesh
@@ -782,6 +826,10 @@ function createMeshCore(agent) {
826 });
827 break;
828 }
829 + case 'parseuri': {
830 + response = JSON.stringify(http.parseUri(args['_'][0]));
831 + break;
832 + }
833 default: { // This is an unknown command, return an error message
834 response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.';
835 break;
meshagent.js
+6 -3
@@ -378,9 +378,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
378 delete command.sessionid; // Remove the sessionid, since we are sending to that sessionid, so it's implyed.
379 ws.send(JSON.stringify(command));
380 } else if (obj.parent.parent.multiServer != null) {
381 - // We need to send this message to other servers
382 - command.fromNodeid = obj.dbNodeKey;
383 - obj.parent.parent.multiServer.DispatchMessage(command);
381 + // See if we can send this to a peer server
382 + var serverid = obj.parent.wsPeerSessions2[command.sessionid];
383 + if (serverid != null) {
384 + command.fromNodeid = obj.dbNodeKey;
385 + obj.parent.parent.multiServer.DispatchMessageSingleServer(command, serverid);
386 + }
387 }
388 }
389 } else if (command.userid != null) { // If this command has a userid, that is the target.
mesherrors.txt
+57
@@ -2017,3 +2017,60 @@ Error: not opened
2017 at Receiver.opcodes.2.finish (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:633:12)
2018
2019
2020 +-------- 9/20/2017, 11:40:47 AM --------
2021 +
2022 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522
2023 + obj.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId
2024 + ^
2025 +
2026 +TypeError: Cannot set property 'AmtMachine7' of undefined
2027 + at Object.obj.ProcessPeerServerMessage (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522:51)
2028 + at processServerData (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:377:32)
2029 + at WebSocket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:262:49)
2030 + at emitTwo (events.js:106:13)
2031 + at WebSocket.emit (events.js:191:7)
2032 + at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10)
2033 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18
2034 + at Receiver.applyExtensions (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:371:5)
2035 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:508:14
2036 + at Receiver.flush (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:347:3)
2037 +
2038 +
2039 +-------- 9/20/2017, 11:40:51 AM --------
2040 +
2041 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522
2042 + obj.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId
2043 + ^
2044 +
2045 +TypeError: Cannot set property 'AmtMachine7' of undefined
2046 + at Object.obj.ProcessPeerServerMessage (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:522:51)
2047 + at processServerData (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:377:32)
2048 + at WebSocket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\multiserver.js:262:49)
2049 + at emitTwo (events.js:106:13)
2050 + at WebSocket.emit (events.js:191:7)
2051 + at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10)
2052 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18
2053 + at Receiver.applyExtensions (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:371:5)
2054 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:508:14
2055 + at Receiver.flush (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:347:3)
2056 +
2057 +
2058 +-------- 9/20/2017, 1:55:44 PM --------
2059 +
2060 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1155
2061 + for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } }
2062 + ^
2063 +
2064 +TypeError: Cannot read property 'domainid' of undefined
2065 + at WebSocket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\webserver.js:1155:89)
2066 + at emitTwo (events.js:106:13)
2067 + at WebSocket.emit (events.js:191:7)
2068 + at Receiver.ontext (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\WebSocket.js:841:10)
2069 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:536:18
2070 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\Receiver.js:368:7
2071 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\ws\lib\PerMessageDeflate.js:249:5
2072 + at afterWrite (_stream_writable.js:360:3)
2073 + at onwrite (_stream_writable.js:351:7)
2074 + at WritableState.onwrite (_stream_writable.js:89:5)
2075 +
2076 +
multiserver.js
+50 -1
@@ -472,17 +472,29 @@ module.exports.CreateMultiServer = function (parent, args) {
472 obj.SetupPeerServer = function (server, peerServerId) {
473 console.log('Connected to peer server ' + peerServerId + '.');
474 obj.peerServers[peerServerId] = server;
475 +
476 + // Send the list of connections to the peer
477 server.send(JSON.stringify({ action: 'connectivityTable', connectivityTable: obj.parent.peerConnectivityByNode[obj.parent.serverId] }));
478 +
479 + // Send a list of user sessions to the peer
480 + server.send(JSON.stringify({ action: 'sessionsTable', sessionsTable: Object.keys(obj.parent.webserver.wssessions2) }));
481 }
482
483 // We disconnected to a peer server, clean up everything
484 obj.ClearPeerServer = function (server, peerServerId) {
485 console.log('Disconnected from peer server ' + peerServerId + '.');
486 +
487 + // Clean up the connectivity state
488 delete obj.peerServers[peerServerId];
482 - //delete obj.parent.peerConnectivityByMesh[peerServerId]; // TODO: We will need to re-adjust all of the node power states.
489 var oldList = obj.parent.peerConnectivityByNode[peerServerId];
490 obj.parent.peerConnectivityByNode[peerServerId] = {};
491 obj.parent.UpdateConnectivityState(oldList);
492 +
493 + // Clean up the sessions list
494 + for (var i in obj.parent.webserver.wsPeerSessions[peerServerId]) { delete obj.parent.webserver.wsPeerSessions2[obj.parent.webserver.wsPeerSessions[peerServerId][i]]; }
495 + delete obj.parent.webserver.wsPeerSessions[peerServerId];
496 + delete obj.parent.webserver.wsPeerSessions3[peerServerId];
497 + obj.parent.webserver.recountSessions(); // Recount all sessions
498 }
499
500 // Process a message coming from a peer server
@@ -498,6 +510,43 @@ module.exports.CreateMultiServer = function (parent, args) {
510 obj.parent.UpdateConnectivityState(msg.connectivityTable);
511 break;
512 }
513 + case 'sessionsTable': {
514 + obj.parent.webserver.wsPeerSessions[peerServerId] = msg.sessionsTable;
515 + var userToSession = {};
516 + for (var i in msg.sessionsTable) {
517 + var sessionid = msg.sessionsTable[i];
518 + obj.parent.webserver.wsPeerSessions2[sessionid] = peerServerId;
519 + var userid = sessionid.split('/').slice(0, 3).join('/'); // Take the sessionid and keep only the userid partion
520 + if (userToSession[userid] == null) { userToSession[userid] = [sessionid]; } else { userToSession[userid].push(sessionid); } // UserId -> [ SessionId ]
521 + }
522 + obj.parent.webserver.wsPeerSessions3[peerServerId] = userToSession; // ServerId --> UserId --> SessionId
523 + obj.parent.webserver.recountSessions(); // Recount all sessions
524 + break;
525 + }
526 + case 'sessionStart': {
527 + obj.parent.webserver.wsPeerSessions[peerServerId].push(msg.sessionid);
528 + obj.parent.webserver.wsPeerSessions2[msg.sessionid] = peerServerId;
529 + var userid = msg.sessionid.split('/').slice(0, 3).join('/');
530 + if (obj.parent.webserver.wsPeerSessions3[peerServerId] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId] = {}; }
531 + if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] == null) { obj.parent.webserver.wsPeerSessions3[peerServerId][userid] = [ msg.sessionid ]; } else { obj.parent.webserver.wsPeerSessions3[peerServerId][userid].push(msg.sessionid); }
532 + obj.parent.webserver.recountSessions(msg.sessionid); // Recount a specific user
533 + break;
534 + }
535 + case 'sessionEnd': {
536 + var i = obj.parent.webserver.wsPeerSessions[peerServerId].indexOf(msg.sessionid);
537 + if (i >= 0) { obj.parent.webserver.wsPeerSessions[peerServerId].splice(i, 1); }
538 + delete obj.parent.webserver.wsPeerSessions2[msg.sessionid];
539 + var userid = msg.sessionid.split('/').slice(0, 3).join('/');
540 + if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid] != null) {
541 + i = obj.parent.webserver.wsPeerSessions3[peerServerId][userid].indexOf(msg.sessionid);
542 + if (i >= 0) {
543 + obj.parent.webserver.wsPeerSessions3[peerServerId][userid].splice(i, 1);
544 + if (obj.parent.webserver.wsPeerSessions3[peerServerId][userid].length == 0) { delete obj.parent.webserver.wsPeerSessions3[peerServerId][userid]; }
545 + }
546 + }
547 + obj.parent.webserver.recountSessions(msg.sessionid); // Recount a specific user
548 + break;
549 + }
550 case 'SetConnectivityState': {
551 obj.parent.SetConnectivityState(msg.meshid, msg.nodeid, msg.connectTime, msg.connectType, msg.powerState, peerServerId);
552 break;
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.0.7-y",
3 + "version": "0.0.8-b",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/scripts/agent-redir-ws-0.1.0.js
+3 -2
@@ -24,7 +24,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
24
25 obj.Start = function (nodeid) {
26 var url2, url = window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/meshrelay.ashx?id=" + obj.tunnelid;
27 - if (serverPublicNamePort) { url2 = window.location.protocol.replace("http", "ws") + "//" + serverPublicNamePort + "/meshrelay.ashx?id=" + obj.tunnelid; } else { url2 = url; }
27 + //if (serverPublicNamePort) { url2 = window.location.protocol.replace("http", "ws") + "//" + serverPublicNamePort + "/meshrelay.ashx?id=" + obj.tunnelid; } else { url2 = url; }
28 obj.nodeid = nodeid;
29 obj.connectstate = 0;
30 obj.socket = new WebSocket(url);
@@ -33,7 +33,8 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
33 obj.socket.onerror = function (e) { console.error(e); }
34 obj.socket.onclose = obj.xxOnSocketClosed;
35 obj.xxStateChange(1);
36 - obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 });
36 + //obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: url2 });
37 + obj.meshserver.Send({ action: 'msg', type: 'tunnel', nodeid: obj.nodeid, value: "*/meshrelay.ashx?id=" + obj.tunnelid });
38 //obj.debug("Agent Redir Start: " + url);
39 }
40
views/login.handlebars
+1 -1
@@ -150,7 +150,7 @@
150 if ('{{loginmode}}' != '') { go({{loginmode}}); } else { go(1); }
151 QV('newAccountDiv', '{{{newAccount}}}' != '0' );
152 if ((passhint != null) && (passhint.length > 0)) { QV("showPassHintLink", true); }
153 - QV("anewaccountpass", (newAccountPass == 1));
153 + QV("newAccountPass", (newAccountPass == 1));
154 }
155
156 function showPassHint() {
webserver.js
+103 -12
@@ -74,10 +74,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
74
75 // Main lists
76 obj.wsagents = {};
77 - obj.wssessions = {}; // UserId --> Array Of Sessions
78 - obj.wssessions2 = {}; // UserId + SessionId --> Session
79 - obj.wsrelays = {}; // Id -> Relay
80 - obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
77 + obj.wssessions = {}; // UserId --> Array Of Sessions
78 + obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
79 + obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
80 + obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
81 + obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
82 + obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount
83 + obj.wsrelays = {}; // Id -> Relay
84 + obj.wsPeerRelays = {}; // Id -> { ServerId, Time }
85
86 // Setup randoms
87 obj.crypto.randomBytes(32, function (err, buf) { obj.httpAuthRandom = buf; });
@@ -383,7 +387,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
387 res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.certificates.CommonName, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass });
388 } else {
389 // Send back the login application
386 - res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newAccounts, newAccountPass: ((domain.newAccountsPass == null)?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
390 + res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newAccounts, newAccountPass: (((domain.newAccountsPass == null) || (domain.newAccountsPass == ''))?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
391 }
392 }
393
@@ -941,8 +945,15 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
945 ws.sessionId = user._id + '/' + ('' + Math.random()).substring(2);
946 obj.wssessions2[ws.sessionId] = ws;
947 if (!obj.wssessions[user._id]) { obj.wssessions[user._id] = [ws]; } else { obj.wssessions[user._id].push(ws); }
944 - obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[user._id].length, nolog: 1, domain: domain.id })
945 -
948 + if (obj.parent.multiServer == null) {
949 + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[user._id].length, nolog: 1, domain: domain.id })
950 + } else {
951 + obj.recountSessions(ws.sessionId); // Recount sessions
952 + }
953 +
954 + // If we have peer servers, inform them of the new session
955 + if (obj.parent.multiServer != null) { obj.parent.multiServer.DispatchMessage({ action: 'sessionStart', sessionid: ws.sessionId }); }
956 +
957 // Handle events
958 ws.HandleEvent = function (source, event) {
959 if (!event.domain || event.domain == domain.id) {
@@ -1136,11 +1147,17 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1147 }
1148 case 'wssessioncount':
1149 {
1139 - // Request a list of all web socket session count
1140 - if ((user.siteadmin & 2) == 0) break;
1150 + // Request a list of all web socket user session count
1151 var wssessions = {};
1142 - for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } }
1143 - ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions }));
1152 + if ((user.siteadmin & 2) == 0) break;
1153 + if (obj.parent.multiServer == null) {
1154 + // No peering, use simple session counting
1155 + for (var i in obj.wssessions) { if (obj.wssessions[i][0].domainid == domain.id) { wssessions[i] = obj.wssessions[i].length; } }
1156 + } else {
1157 + // We have peer servers, use more complex session counting
1158 + for (var userid in obj.sessionsCount) { if (userid.split('/')[1] == domain.id) { wssessions[userid] = obj.sessionsCount[userid]; } }
1159 + }
1160 + ws.send(JSON.stringify({ action: 'wssessioncount', wssessions: wssessions })); // wssessions is: userid --> count
1161 break;
1162 }
1163 case 'deleteuser':
@@ -1664,10 +1681,19 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1681 if (i >= 0) {
1682 obj.wssessions[ws.userid].splice(i, 1);
1683 var user = obj.users[ws.userid];
1667 - if (user) { obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[ws.userid].length, nolog: 1, domain: domain.id }) }
1684 + if (user) {
1685 + if (obj.parent.multiServer == null) {
1686 + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: user.name, count: obj.wssessions[ws.userid].length, nolog: 1, domain: domain.id })
1687 + } else {
1688 + obj.recountSessions(ws.sessionId); // Recount sessions
1689 + }
1690 + }
1691 if (obj.wssessions[ws.userid].length == 0) { delete obj.wssessions[ws.userid]; }
1692 }
1693 }
1694 +
1695 + // If we have peer servers, inform them of the disconnected session
1696 + if (obj.parent.multiServer != null) { obj.parent.multiServer.DispatchMessage({ action: 'sessionEnd', sessionid: ws.sessionId }); }
1697 });
1698
1699 // Send user information to web socket, this is the first thing we send
@@ -2126,5 +2152,70 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
2152 // Start server on a free port
2153 CheckListenPort(obj.args.port, StartWebServer);
2154
2155 +/*
2156 + obj.wssessions = {}; // UserId --> Array Of Sessions
2157 + obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd)
2158 + obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd"
2159 + obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId
2160 + obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ]
2161 +*/
2162 +
2163 + // Count sessions and event any changes
2164 + obj.recountSessions = function (changedSessionId) {
2165 + if (changedSessionId == null) {
2166 + // Recount all sessions
2167 +
2168 + // Calculate the session count for all userid's
2169 + var newSessionsCount = {};
2170 + for (var userid in obj.wssessions) { newSessionsCount[userid] = obj.wssessions[userid].length; }
2171 + for (var serverid in obj.wsPeerSessions3) {
2172 + for (var userid in obj.wsPeerSessions3[serverid]) {
2173 + var c = obj.wsPeerSessions3[serverid][userid].length;
2174 + if (newSessionsCount[userid] == null) { newSessionsCount[userid] = c; } else { newSessionsCount[userid] += c; }
2175 + }
2176 + }
2177 +
2178 + // See what session counts have changed, event any changes
2179 + for (var userid in newSessionsCount) {
2180 + var newcount = newSessionsCount[userid];
2181 + var oldcount = obj.sessionsCount[userid];
2182 + if (oldcount == null) { oldcount = 0; } else { delete obj.sessionsCount[userid]; }
2183 + if (newcount != oldcount) {
2184 + var x = userid.split('/');
2185 + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 })
2186 + }
2187 + }
2188 +
2189 + // If there are any counts left in the old counts, event to zero
2190 + for (var userid in obj.sessionsCount) {
2191 + var oldcount = obj.sessionsCount[userid];
2192 + if ((oldcount != null) && (oldcount != 0)) {
2193 + var x = userid.split('/');
2194 + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: 0, domain: x[1], nolog: 1, nopeers: 1 })
2195 + }
2196 + }
2197 +
2198 + // Set the new session counts
2199 + obj.sessionsCount = newSessionsCount;
2200 + } else {
2201 + // Figure out the userid
2202 + var userid = changedSessionId.split('/').slice(0, 3).join('/');
2203 +
2204 + // Recount only changedSessionId
2205 + var newcount = 0;
2206 + if (obj.wssessions[userid] != null) { newcount = obj.wssessions[userid].length; }
2207 + for (var serverid in obj.wsPeerSessions3) { if (obj.wsPeerSessions3[serverid][userid] != null) { newcount += obj.wsPeerSessions3[serverid][userid].length; } }
2208 + var oldcount = obj.sessionsCount[userid];
2209 + if (oldcount == null) { oldcount = 0; }
2210 +
2211 + // If the count changed, update and event
2212 + if (newcount != oldcount) {
2213 + var x = userid.split('/');
2214 + obj.parent.DispatchEvent(['*'], obj, { action: 'wssessioncount', username: x[2], count: newcount, domain: x[1], nolog: 1, nopeers: 1 })
2215 + obj.sessionsCount[userid] = newcount;
2216 + }
2217 + }
2218 + }
2219 +
2220 return obj;
2221 }