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
}