More work on desktop multiplexor.
Ylian Saint-Hilaire committed
Apr 27, 2020 at 17:39 UTC
92105f352a3dd2b3cfb019d8a80868e0567819d0
1 file changed
+106
-276
meshdesktopmultiplex.js
+106
-276
@@ -57,8 +57,10 @@ MNG_ERROR = 65,
57
MNG_ENCAPSULATE_AGENT_COMMAND = 70
58
*/
59
60
-function CreateDesktopDecoder() {
60
+function CreateDesktopDecoder(parent, domain, id, func) {
61
var obj = {};
62
+ obj.id = id;
63
+ obj.parent = parent;
64
obj.agent = null; // Reference to the connection object that is the agent.
65
obj.viewers = []; // Array of references to all viewers.
66
obj.viewersSendingCount = 0; // Number of viewers currently activaly sending something.
@@ -82,6 +84,8 @@ function CreateDesktopDecoder() {
84
obj.imageFrameRate = 50; // Current framerate setting, this is the lowest values of all viewers.
85
obj.protocolOptions = null; // Set to the protocol options of the first viewer that connected.
86
obj.viewerConnected = false; // Set to true if one viewer attempted to connect to the agent.
87
+ obj.recordingFile = null; // Present if we are recording to file.
88
+ obj.recordingFileWriting = false; // Set to true is we are in the process if writing to the recording file.
89
90
// Add an agent or viewer
91
obj.addPeer = function (peer) {
@@ -152,11 +156,11 @@ function CreateDesktopDecoder() {
156
delete peer.sending;
157
delete peer.sendQueue;
158
155
- // Resume flow control if this was the peer
159
+ // Resume flow control if this was the peer that was limiting traffic (because it was the fastest one).
160
if (peer.sending == true) {
161
obj.viewersSendingCount--;
162
peer.sending = false;
159
- if ((obj.viewersSendingCount < obj.viewers.length) && obj.agent && (obj.agent.paused == true)) { obj.agent.paused = false; obj.agent.ws._socket.resume(); }
163
+ if ((obj.viewersSendingCount < obj.viewers.length) && (obj.recordingFileWriting == false) && obj.agent && (obj.agent.paused == true)) { obj.agent.paused = false; obj.agent.ws._socket.resume(); }
164
}
165
166
// If this is the last viewer, disconnect the agent
@@ -170,6 +174,17 @@ function CreateDesktopDecoder() {
174
delete obj.viewers;
175
delete obj.imagesCounters;
176
delete obj.images;
177
+
178
+ // Close the recording file if needed
179
+ if (obj.recordingFile != null) {
180
+ var rf = obj.recordingFile;
181
+ delete obj.recordingFile;
182
+ recordingEntry(rf.fd, 3, 0, 'MeshCentralMCREC', function (fd, filename) {
183
+ parent.parent.fs.close(fd);
184
+ // Now that the recording file is closed, check if we need to index this file.
185
+ if (domain.sessionrecording.index !== false) { parent.parent.certificateOperations.acceleratorPerformOperation('indexMcRec', filename); }
186
+ }, rf.filename);
187
+ }
188
}
189
190
// Send data to the agent or queue it up for sending
@@ -249,7 +264,7 @@ function CreateDesktopDecoder() {
264
if (viewer.sending == false) {
265
viewer.sending = true;
266
obj.viewersSendingCount++;
252
- if ((obj.viewersSendingCount >= obj.viewers.length) && obj.agent && (obj.agent.paused == false)) { obj.agent.paused = true; obj.agent.ws._socket.pause(); }
267
+ if (((obj.viewersSendingCount >= obj.viewers.length) || (obj.recordingFileWriting == true)) && obj.agent && (obj.agent.paused == false)) { obj.agent.paused = true; obj.agent.ws._socket.pause(); }
268
}
269
} else {
270
// Nothing to send
@@ -257,14 +272,23 @@ function CreateDesktopDecoder() {
272
273
// Flow control, resume agent if needed
274
obj.viewersSendingCount--;
260
- if ((obj.viewersSendingCount < obj.viewers.length) && obj.agent && (obj.agent.paused == true)) { obj.agent.paused = false; obj.agent.ws._socket.resume(); }
275
+ if ((obj.viewersSendingCount < obj.viewers.length) && (obj.recordingFileWriting == false) && obj.agent && (obj.agent.paused == true)) { obj.agent.paused = false; obj.agent.ws._socket.resume(); }
276
}
277
}
278
}
279
280
// Process data coming from the agent or any viewers
281
obj.processData = function (peer, data) {
267
- if (peer == obj.agent) { obj.processAgentData(data); } else { obj.processViewerData(peer, data); }
282
+ if (peer == obj.agent) {
283
+ obj.recordingFileWriting = true;
284
+ recordData(true, data, function () {
285
+ obj.recordingFileWriting = false;
286
+ if ((obj.viewersSendingCount < obj.viewers.length) && obj.agent && (obj.agent.paused == true)) { obj.agent.paused = false; obj.agent.ws._socket.resume(); }
287
+ obj.processAgentData(data);
288
+ });
289
+ } else {
290
+ obj.processViewerData(peer, data);
291
+ }
292
}
293
294
// Process incoming viewer data
@@ -503,6 +527,73 @@ function CreateDesktopDecoder() {
527
}
528
}
529
530
+ function recordingSetup(domain, func) {
531
+ // Setup session recording
532
+ if ((domain.sessionrecording == true || ((typeof domain.sessionrecording == 'object') && ((domain.sessionrecording.protocols == null) || (domain.sessionrecording.protocols.indexOf(2) >= 0))))) {
533
+ var now = new Date(Date.now());
534
+ var recFilename = 'desktopSession' + ((domain.id == '') ? '' : '-') + domain.id + '-' + now.getUTCFullYear() + '-' + parent.common.zeroPad(now.getUTCMonth(), 2) + '-' + parent.common.zeroPad(now.getUTCDate(), 2) + '-' + parent.common.zeroPad(now.getUTCHours(), 2) + '-' + parent.common.zeroPad(now.getUTCMinutes(), 2) + '-' + parent.common.zeroPad(now.getUTCSeconds(), 2) + '-' + obj.id + '.mcrec'
535
+ var recFullFilename = null;
536
+ if (domain.sessionrecording.filepath) {
537
+ try { parent.parent.fs.mkdirSync(domain.sessionrecording.filepath); } catch (e) { }
538
+ recFullFilename = parent.parent.path.join(domain.sessionrecording.filepath, recFilename);
539
+ } else {
540
+ try { parent.parent.fs.mkdirSync(parent.parent.recordpath); } catch (e) { }
541
+ recFullFilename = parent.parent.path.join(parent.parent.recordpath, recFilename);
542
+ }
543
+ parent.parent.fs.open(recFullFilename, 'w', function (err, fd) {
544
+ if (err != null) { func(false); return; }
545
+ // Write the recording file header
546
+ var metadata = { magic: 'MeshCentralRelaySession', ver: 1, sessionid: obj.id, time: new Date().toLocaleString(), protocol: 2 };
547
+ var firstBlock = JSON.stringify(metadata);
548
+ recordingEntry(fd, 1, 0, firstBlock, function () {
549
+ obj.recordingFile = { fd: fd, filename: recFullFilename };
550
+ obj.recordingFileWriting = false;
551
+ func(true);
552
+ });
553
+ });
554
+ } else {
555
+ func(false);
556
+ }
557
+ }
558
+
559
+ // Record data to the recording file
560
+ function recordData(isAgent, data, func) {
561
+ try {
562
+ if (obj.recordingFile != null) {
563
+ // Write data to recording file
564
+ recordingEntry(obj.recordingFile.fd, 2, (isAgent ? 0 : 2), data, function () { func(data); });
565
+ } else {
566
+ func(data);
567
+ }
568
+ } catch (ex) { console.log(ex); }
569
+ }
570
+
571
+ // Record a new entry in a recording log
572
+ function recordingEntry(fd, type, flags, data, func, tag) {
573
+ try {
574
+ if (typeof data == 'string') {
575
+ // String write
576
+ var blockData = Buffer.from(data), header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
577
+ header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
578
+ header.writeInt16BE(flags, 2); // Flags (1 = Binary, 2 = User)
579
+ header.writeInt32BE(blockData.length, 4); // Size
580
+ header.writeIntBE(new Date(), 10, 6); // Time
581
+ var block = Buffer.concat([header, blockData]);
582
+ parent.parent.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
583
+ } else {
584
+ // Binary write
585
+ var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
586
+ header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
587
+ header.writeInt16BE(flags | 1, 2); // Flags (1 = Binary, 2 = User)
588
+ header.writeInt32BE(data.length, 4); // Size
589
+ header.writeIntBE(new Date(), 10, 6); // Time
590
+ var block = Buffer.concat([header, data]);
591
+ parent.parent.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
592
+ }
593
+ } catch (ex) { console.log(ex); func(fd, tag); }
594
+ }
595
+
596
+ recordingSetup(domain, function () { func(obj); });
597
return obj;
598
}
599
@@ -654,186 +745,16 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
745
// Create if needed and add this peer to the desktop multiplexor
746
obj.deskDecoder = parent.desktoprelays[obj.id];
747
if (obj.deskDecoder == null) {
657
- obj.deskDecoder = CreateDesktopDecoder();
658
- parent.desktoprelays[obj.id] = obj.deskDecoder;
659
- }
660
- obj.deskDecoder.addPeer(obj);
661
- ws._socket.resume(); // Release the traffic
662
-
663
- /*
664
- // If this is a MeshMessenger session, the ID is the two userid's and authentication must match one of them.
665
- if (obj.id.startsWith('meshmessenger/')) {
666
- if ((obj.id.startsWith('meshmessenger/user/') == true) && (user == null)) { try { obj.close(); } catch (e) { } return null; } // If user-to-user, both sides need to be authenticated.
667
- var x = obj.id.split('/'), user1 = x[1] + '/' + x[2] + '/' + x[3], user2 = x[4] + '/' + x[5] + '/' + x[6];
668
- if ((x[1] != 'user') && (x[4] != 'user')) { try { obj.close(); } catch (e) { } return null; } // MeshMessenger session must have at least one authenticated user
669
- if ((x[1] == 'user') && (x[4] == 'user')) {
670
- // If this is a user-to-user session, you must be authenticated to join.
671
- if ((user._id != user1) && (user._id != user2)) { try { obj.close(); } catch (e) { } return null; }
672
- } else {
673
- // If only one side of the session is a user
674
- // !!!!! TODO: Need to make sure that one of the two sides is the correct user. !!!!!
675
- }
676
- }
677
-
678
- // Validate that the id is valid, we only need to do this on non-authenticated sessions.
679
- // TODO: Figure out when this needs to be done.
680
- if (!parent.args.notls) {
681
- // Check the identifier, if running without TLS, skip this.
682
- var ids = obj.id.split(':');
683
- if (ids.length != 3) { ws.close(); delete obj.id; return null; } // Invalid ID, drop this.
684
- if (parent.crypto.createHmac('SHA384', parent.relayRandom).update(ids[0] + ':' + ids[1]).digest('hex') != ids[2]) { ws.close(); delete obj.id; return null; } // Invalid HMAC, drop this.
685
- if ((Date.now() - parseInt(ids[1])) > 120000) { ws.close(); delete obj.id; return null; } // Expired time, drop this.
686
- obj.id = ids[0];
687
- }
688
-
689
- // Check the peer connection status
690
- {
691
- var relayinfo = parent.wsrelays[obj.id];
692
- if (relayinfo) {
693
- if (relayinfo.state == 1) {
694
- // Check that at least one connection is authenticated
695
- if ((obj.authenticated != true) && (relayinfo.peer1.authenticated != true)) {
696
- ws.close();
697
- parent.parent.debug('relay', 'Relay without-auth: ' + obj.id + ' (' + cleanRemoteAddr(obj.req.ip) + ')');
698
- delete obj.id;
699
- delete obj.ws;
700
- delete obj.peer;
701
- return null;
702
- }
703
-
704
- // Check that both connection are for the same user
705
- if (!obj.id.startsWith('meshmessenger/')) {
706
- var u1 = obj.user ? obj.user._id : obj.ruserid;
707
- var u2 = relayinfo.peer1.user ? relayinfo.peer1.user._id : relayinfo.peer1.ruserid;
708
- if (parent.args.user != null) { // If the server is setup with a default user, correct the userid now.
709
- if (u1 != null) { u1 = 'user/' + domain.id + '/' + parent.args.user.toLowerCase(); }
710
- if (u2 != null) { u2 = 'user/' + domain.id + '/' + parent.args.user.toLowerCase(); }
711
- }
712
- if (u1 != u2) {
713
- ws.close();
714
- parent.parent.debug('relay', 'Relay auth mismatch (' + u1 + ' != ' + u2 + '): ' + obj.id + ' (' + cleanRemoteAddr(obj.req.ip) + ')');
715
- delete obj.id;
716
- delete obj.ws;
717
- delete obj.peer;
718
- return null;
719
- }
720
- }
721
-
722
- // Connect to peer
723
- obj.peer = relayinfo.peer1;
724
- obj.peer.peer = obj;
725
- relayinfo.peer2 = obj;
726
- relayinfo.state = 2;
727
- relayinfo.peer1.ws._socket.resume(); // Release the traffic
728
- relayinfo.peer2.ws._socket.resume(); // Release the traffic
729
- ws.time = relayinfo.peer1.ws.time = Date.now();
730
-
731
- relayinfo.peer1.ws.peer = relayinfo.peer2.ws;
732
- relayinfo.peer2.ws.peer = relayinfo.peer1.ws;
733
-
734
- // Remove the timeout
735
- if (relayinfo.timeout) { clearTimeout(relayinfo.timeout); delete relayinfo.timeout; }
736
-
737
- // Setup the agent PING/PONG timers
738
- if ((typeof parent.parent.args.agentping == 'number') && (obj.pingtimer == null)) { obj.pingtimer = setInterval(sendPing, parent.parent.args.agentping * 1000); }
739
- else if ((typeof parent.parent.args.agentpong == 'number') && (obj.pongtimer == null)) { obj.pongtimer = setInterval(sendPong, parent.parent.args.agentpong * 1000); }
740
-
741
- // Setup the desktop decoder
742
- obj.deskDecoder = obj.peer.deskDecoder = CreateDesktopDecoder();
743
- obj.deskDecoder.addPeer(obj);
744
- obj.deskDecoder.addPeer(obj.peer);
745
-
746
- // Setup session recording
747
- var sessionUser = obj.user;
748
- if (sessionUser == null) { sessionUser = obj.peer.user; }
749
- if ((sessionUser != null) && (domain.sessionrecording == true || ((typeof domain.sessionrecording == 'object') && ((domain.sessionrecording.protocols == null) || (domain.sessionrecording.protocols.indexOf(parseInt(obj.req.query.p)) >= 0))))) {
750
- // Get the computer name
751
- parent.db.Get(obj.req.query.nodeid, function (err, nodes) {
752
- var xusername = '', xdevicename = '', xdevicename2 = null;
753
- if ((nodes != null) && (nodes.length == 1)) { xdevicename2 = nodes[0].name; xdevicename = '-' + parent.common.makeFilename(nodes[0].name); }
754
-
755
- // Get the username and make it acceptable as a filename
756
- if (sessionUser._id) { xusername = '-' + parent.common.makeFilename(sessionUser._id.split('/')[2]); }
757
-
758
- var now = new Date(Date.now());
759
- var recFilename = 'relaysession' + ((domain.id == '') ? '' : '-') + domain.id + '-' + now.getUTCFullYear() + '-' + parent.common.zeroPad(now.getUTCMonth(), 2) + '-' + parent.common.zeroPad(now.getUTCDate(), 2) + '-' + parent.common.zeroPad(now.getUTCHours(), 2) + '-' + parent.common.zeroPad(now.getUTCMinutes(), 2) + '-' + parent.common.zeroPad(now.getUTCSeconds(), 2) + xusername + xdevicename + '-' + obj.id + '.mcrec'
760
- var recFullFilename = null;
761
- if (domain.sessionrecording.filepath) {
762
- try { parent.parent.fs.mkdirSync(domain.sessionrecording.filepath); } catch (e) { }
763
- recFullFilename = parent.parent.path.join(domain.sessionrecording.filepath, recFilename);
764
- } else {
765
- try { parent.parent.fs.mkdirSync(parent.parent.recordpath); } catch (e) { }
766
- recFullFilename = parent.parent.path.join(parent.parent.recordpath, recFilename);
767
- }
768
- parent.parent.fs.open(recFullFilename, 'w', function (err, fd) {
769
- if (err != null) {
770
- // Unable to record
771
- try { ws.send('c'); } catch (ex) { } // Send connect to both peers
772
- try { relayinfo.peer1.ws.send('c'); } catch (ex) { }
773
- } else {
774
- // Write the recording file header
775
- var metadata = { magic: 'MeshCentralRelaySession', ver: 1, userid: sessionUser._id, username: sessionUser.name, sessionid: obj.id, ipaddr1: cleanRemoteAddr(obj.req.ip), ipaddr2: cleanRemoteAddr(obj.peer.req.ip), time: new Date().toLocaleString(), protocol: (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.p), nodeid: (((obj.req == null) || (obj.req.query == null)) ? null : obj.req.query.nodeid ) };
776
- if (xdevicename2 != null) { metadata.devicename = xdevicename2; }
777
- var firstBlock = JSON.stringify(metadata);
778
- recordingEntry(fd, 1, 0, firstBlock, function () {
779
- try { relayinfo.peer1.ws.logfile = ws.logfile = { fd: fd, lock: false, filename: recFullFilename }; } catch (ex) {
780
- try { ws.send('c'); } catch (ex) { } // Send connect to both peers, 'cr' indicates the session is being recorded.
781
- try { relayinfo.peer1.ws.send('c'); } catch (ex) { }
782
- return;
783
- }
784
- try { ws.send('cr'); } catch (ex) { } // Send connect to both peers, 'cr' indicates the session is being recorded.
785
- try { relayinfo.peer1.ws.send('cr'); } catch (ex) { }
786
- });
787
- }
788
- });
789
- });
790
- } else {
791
- // Send session start
792
- try { ws.send('c'); } catch (ex) { } // Send connect to both peers
793
- try { relayinfo.peer1.ws.send('c'); } catch (ex) { }
794
- }
795
-
796
- parent.parent.debug('relay', 'Relay connected: ' + obj.id + ' (' + cleanRemoteAddr(obj.req.ip) + ' --> ' + cleanRemoteAddr(obj.peer.req.ip) + ')');
797
-
798
- // Log the connection
799
- if (sessionUser != null) {
800
- var msg = 'Started relay session';
801
- if (obj.req.query.p == 1) { msg = 'Started terminal session'; }
802
- else if (obj.req.query.p == 2) { msg = 'Started desktop session'; }
803
- else if (obj.req.query.p == 5) { msg = 'Started file management session'; }
804
- var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: sessionUser._id, username: sessionUser.name, msg: msg + ' \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.req.ip) + ' to ' + cleanRemoteAddr(req.ip), protocol: req.query.p, nodeid: req.query.nodeid };
805
- parent.parent.DispatchEvent(['*', sessionUser._id], obj, event);
806
- }
807
- } else {
808
- // Connected already, drop (TODO: maybe we should re-connect?)
809
- ws.close();
810
- parent.parent.debug('relay', 'Relay duplicate: ' + obj.id + ' (' + cleanRemoteAddr(obj.req.ip) + ')');
811
- delete obj.id;
812
- delete obj.ws;
813
- delete obj.peer;
814
- return null;
815
- }
816
- } else {
817
- // Wait for other relay connection
818
- ws._socket.pause(); // Hold traffic until the other connection
819
- parent.wsrelays[obj.id] = { peer1: obj, state: 1, timeout: setTimeout(function () { closeBothSides(); }, 30000) };
820
- parent.parent.debug('relay', 'Relay holding: ' + obj.id + ' (' + cleanRemoteAddr(obj.req.ip) + ') ' + (obj.authenticated ? 'Authenticated' : ''));
821
-
822
- // Check if a peer server has this connection
823
- if (parent.parent.multiServer != null) {
824
- var rsession = parent.wsPeerRelays[obj.id];
825
- if ((rsession != null) && (rsession.serverId > parent.parent.serverId)) {
826
- // We must initiate the connection to the peer
827
- parent.parent.multiServer.createPeerRelay(ws, req, rsession.serverId, obj.req.session.userid);
828
- delete parent.wsrelays[obj.id];
829
- } else {
830
- // Send message to other peers that we have this connection
831
- parent.parent.multiServer.DispatchMessage(JSON.stringify({ action: 'relay', id: obj.id }));
832
- }
833
- }
834
- }
748
+ CreateDesktopDecoder(parent, domain, obj.id, function (deskDecoder) {
749
+ obj.deskDecoder = deskDecoder;
750
+ parent.desktoprelays[obj.id] = obj.deskDecoder;
751
+ obj.deskDecoder.addPeer(obj);
752
+ ws._socket.resume(); // Release the traffic
753
+ });
754
+ } else {
755
+ obj.deskDecoder.addPeer(obj);
756
+ ws._socket.resume(); // Release the traffic
757
}
836
- */
758
}
759
760
// When data is received from the mesh relay web socket
@@ -856,97 +777,6 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain, user, cookie
777
obj.close();
778
});
779
859
- /*
860
- // Close both our side and the peer side.
861
- function closeBothSides() {
862
- if (obj.id != null) {
863
- var relayinfo = parent.wsrelays[obj.id];
864
- if (relayinfo != null) {
865
- if (relayinfo.state == 2) {
866
- var peer = (relayinfo.peer1 == obj) ? relayinfo.peer2 : relayinfo.peer1;
867
-
868
- // Disconnect the peer
869
- try { if (peer.relaySessionCounted) { parent.relaySessionCount--; delete peer.relaySessionCounted; } } catch (ex) { console.log(ex); }
870
- parent.parent.debug('relay', 'Relay disconnect: ' + obj.id + ' (' + cleanRemoteAddr(obj.req.ip) + ' --> ' + cleanRemoteAddr(peer.req.ip) + ')');
871
- try { peer.ws.close(); } catch (e) { } // Soft disconnect
872
- try { peer.ws._socket._parent.end(); } catch (e) { } // Hard disconnect
873
-
874
- // Log the disconnection
875
- if (ws.time) {
876
- var msg = 'Ended relay session';
877
- if (obj.req.query.p == 1) { msg = 'Ended terminal session'; }
878
- else if (obj.req.query.p == 2) { msg = 'Ended desktop session'; }
879
- else if (obj.req.query.p == 5) { msg = 'Ended file management session'; }
880
- if (user) {
881
- var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: user._id, username: user.name, msg: msg + ' \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.req.ip) + ' to ' + cleanRemoteAddr(obj.req.ip) + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: obj.req.query.p, nodeid: obj.req.query.nodeid };
882
- parent.parent.DispatchEvent(['*', user._id], obj, event);
883
- } else if (peer.user) {
884
- var event = { etype: 'relay', action: 'relaylog', domain: domain.id, userid: peer.user._id, username: peer.user.name, msg: msg + ' \"' + obj.id + '\" from ' + cleanRemoteAddr(obj.peer.req.ip) + ' to ' + cleanRemoteAddr(obj.req.ip) + ', ' + Math.floor((Date.now() - ws.time) / 1000) + ' second(s)', protocol: obj.req.query.p, nodeid: obj.req.query.nodeid };
885
- parent.parent.DispatchEvent(['*', peer.user._id], obj, event);
886
- }
887
- }
888
-
889
- // Aggressive peer cleanup
890
- delete peer.id;
891
- delete peer.ws;
892
- delete peer.peer;
893
- if (peer.pingtimer != null) { clearInterval(peer.pingtimer); delete peer.pingtimer; }
894
- if (peer.pongtimer != null) { clearInterval(peer.pongtimer); delete peer.pongtimer; }
895
- } else {
896
- parent.parent.debug('relay', 'Relay disconnect: ' + obj.id + ' (' + cleanRemoteAddr(obj.req.ip) + ')');
897
- }
898
-
899
- // Close the recording file if needed
900
- if (ws.logfile != null) {
901
- var logfile = ws.logfile;
902
- delete ws.logfile;
903
- if (peer.ws) { delete peer.ws.logfile; }
904
- recordingEntry(logfile.fd, 3, 0, 'MeshCentralMCREC', function (fd, tag) {
905
- parent.parent.fs.close(fd);
906
- // Now that the recording file is closed, check if we need to index this file.
907
- if (domain.sessionrecording.index !== false) { parent.parent.certificateOperations.acceleratorPerformOperation('indexMcRec', tag.logfile.filename); }
908
- }, { ws: ws, pws: peer.ws, logfile: logfile });
909
- }
910
-
911
- try { ws.close(); } catch (ex) { }
912
- delete parent.wsrelays[obj.id];
913
- }
914
- }
915
-
916
- // Aggressive cleanup
917
- delete obj.id;
918
- delete obj.ws;
919
- delete obj.peer;
920
- if (obj.pingtimer != null) { clearInterval(obj.pingtimer); delete obj.pingtimer; }
921
- if (obj.pongtimer != null) { clearInterval(obj.pongtimer); delete obj.pongtimer; }
922
- }
923
-
924
- // Record a new entry in a recording log
925
- function recordingEntry(fd, type, flags, data, func, tag) {
926
- try {
927
- if (typeof data == 'string') {
928
- // String write
929
- var blockData = Buffer.from(data), header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
930
- header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
931
- header.writeInt16BE(flags, 2); // Flags (1 = Binary, 2 = User)
932
- header.writeInt32BE(blockData.length, 4); // Size
933
- header.writeIntBE(new Date(), 10, 6); // Time
934
- var block = Buffer.concat([header, blockData]);
935
- parent.parent.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
936
- } else {
937
- // Binary write
938
- var header = Buffer.alloc(16); // Header: Type (2) + Flags (2) + Size(4) + Time(8)
939
- header.writeInt16BE(type, 0); // Type (1 = Header, 2 = Network Data)
940
- header.writeInt16BE(flags | 1, 2); // Flags (1 = Binary, 2 = User)
941
- header.writeInt32BE(data.length, 4); // Size
942
- header.writeIntBE(new Date(), 10, 6); // Time
943
- var block = Buffer.concat([header, data]);
944
- parent.parent.fs.write(fd, block, 0, block.length, function () { func(fd, tag); });
945
- }
946
- } catch (ex) { console.log(ex); func(fd, tag); }
947
- }
948
- */
949
-
780
// Mark this relay session as authenticated if this is the user end.
781
obj.authenticated = (user != null);
782
if (obj.authenticated) {