First pass at adding WebRTC support.
Ylian Saint-Hilaire committed
Jan 16, 2018 at 17:30 UTC
92aaf754fb11d3313d223276c29c181f1cfed926
12 files changed
+163
-140
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/agent_debug/MeshService.exe
Binary files /dev/null and b/agents/agent_debug/MeshService.exe differ
agents/agent_debug/MeshService64.exe
Binary files /dev/null and b/agents/agent_debug/MeshService64.exe differ
agents/meshcore.js
+77
-75
@@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7
8
- http://www.apache.org/licenses/LICENSE-2.0
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,7 +20,6 @@ function createMeshCore(agent) {
20
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
21
obj.meshCoreInfo = "MeshCore v4";
22
obj.meshCoreCapabilities = 14; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
23
- obj.useNativePipes = true; //(process.platform == 'win32');
23
var meshServerConnectionState = 0;
24
var tunnels = {};
25
var lastSelfInfo = null;
@@ -54,6 +53,7 @@ function createMeshCore(agent) {
53
scan.scan("10.2.55.128/25", 2000);
54
*/
55
56
+ /*
57
// Try to load up the network monitor
58
try {
59
networkMonitor = require('NetworkMonitor');
@@ -61,6 +61,7 @@ function createMeshCore(agent) {
61
networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
62
networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
63
} catch (e) { networkMonitor = null; }
64
+ */
65
66
// Try to load up the Intel AMT scanner
67
try {
@@ -506,28 +507,7 @@ function createMeshCore(agent) {
507
if (len > 0) { this.write(buf.slice(0, len)); } else { fs.closeSync(this.httprequest.downloadFile); this.httprequest.downloadFile = undefined; this.end(); }
508
return;
509
}
509
-
510
- // Setup remote desktop & terminal without using native pipes
511
- if ((this.httprequest.desktop) && (obj.useNativePipes == false)) {
512
- if (data.length > 21 && data.toString().startsWith('**********%%%%%%###**')) {
513
- var controlMsg = JSON.parse(data.toString().substring(21));
514
- if (controlMsg.type == 'offer') {
515
- this.webrtc = rtc.createConnection();
516
- this.webrtc.on('connected', function () { sendConsoleText('OnWebRTC_Connected'); });
517
- this.webrtc.on('dataChannel', function () { sendConsoleText('OnWebRTC_DataChannel'); });
518
- var counterOffer = this.webrtc.setOffer(controlMsg.sdp);
519
- this.write('**********%%%%%%###**' + JSON.stringify({ type: 'answer', sdp: counterOffer }));
520
- sendConsoleText('counterOfferSent');
521
- } else {
522
- sendConsoleText(JSON.stringify(controlMsg));
523
- }
524
- } else {
525
- this.httprequest.desktop.kvm.write(data);
526
- }
527
- return;
528
- }
529
- if ((this.httprequest.terminal) && (obj.useNativePipes == false)) { this.httprequest.terminal.write(data); return; }
530
-
510
+
511
if (this.httprequest.state == 0) {
512
// Check if this is a relay connection
513
if (data == 'c') { this.httprequest.state = 1; sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid); }
@@ -538,59 +518,39 @@ function createMeshCore(agent) {
518
this.httprequest.protocol = parseInt(data);
519
if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
520
if (this.httprequest.protocol == 1) {
541
- if (obj.useNativePipes == false) {
542
- // Remote Terminal without using native pipes
543
- if (process.platform == "win32") {
544
- this.httprequest.terminal = childProcess.execFile("%windir%\\system32\\cmd.exe");
545
- } else {
546
- this.httprequest.terminal = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
547
- }
548
- this.httprequest.terminal.tunnel = this;
549
- this.httprequest.terminal.on('exit', function (ecode, sig) { this.tunnel.end(); });
550
- this.httprequest.terminal.stdout.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
551
- this.httprequest.terminal.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
521
+ // Remote terminal using native pipes
522
+ if (process.platform == "win32") {
523
+ this.httprequest.process = childProcess.execFile("%windir%\\system32\\cmd.exe");
524
} else {
553
- // Remote terminal using native pipes
554
- if (process.platform == "win32") {
555
- this.httprequest.process = childProcess.execFile("%windir%\\system32\\cmd.exe");
556
- } else {
557
- this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
558
- }
559
- this.httprequest.process.tunnel = this;
560
- this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
561
- this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
562
- this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
563
- this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
564
- this.prependListener('end', function () { this.httprequest.process.kill(); });
525
+ this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
526
}
527
+ this.httprequest.process.tunnel = this;
528
+ this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
529
+ this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
530
+ this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
531
+ this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
532
+ this.prependListener('end', function () { this.httprequest.process.kill(); });
533
+ this.removeAllListeners('data');
534
+ this.on('data', onTunnelControlData);
535
+ //this.write('MeshCore Terminal Hello!1');
536
}
537
if (this.httprequest.protocol == 2) {
568
- if (obj.useNativePipes == false) {
569
- // Remote Desktop without using native pipes
570
- this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
571
- this.httprequest.desktop.kvm.tunnel = this;
572
- this.httprequest.desktop.kvm.on('data', function (data) { this.tunnel.write(data); });
573
- this.desktop = this.httprequest.desktop;
574
- this.end = function () { if (--this.desktop.kvm.connectionCount == 0) { this.httprequest.desktop.kvm.end(); } };
575
- if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
576
- } else {
577
- // Remote desktop using native pipes
578
- this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
579
- this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
580
- this.desktop = this.httprequest.desktop;
581
- this.end = function () {
582
- --this.desktop.kvm.connectionCount;
583
- this.unpipe(this.httprequest.desktop.kvm);
584
- this.httprequest.desktop.kvm.unpipe(this);
585
- if (this.desktop.kvm.connectionCount == 0) { this.httprequest.desktop.kvm.end(); }
586
- };
587
- if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
588
- //this.write('Hello!');
589
- //sendConsoleText('KVM WriteHello');
590
- this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
591
- this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
592
- //this.on('data', function (data) { sendConsoleText('KVM: ' + data); });
593
- }
538
+ // Remote desktop using native pipes
539
+ this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
540
+ this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
541
+ this.desktop = this.httprequest.desktop;
542
+ this.end = function () {
543
+ --this.desktop.kvm.connectionCount;
544
+ this.unpipe(this.httprequest.desktop.kvm);
545
+ this.httprequest.desktop.kvm.unpipe(this);
546
+ if (this.desktop.kvm.connectionCount == 0) { this.httprequest.desktop.kvm.end(); }
547
+ };
548
+ if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
549
+ this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
550
+ this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
551
+ this.removeAllListeners('data');
552
+ this.on('data', onTunnelControlData);
553
+ //this.write('MeshCore KVM Hello!1');
554
}
555
else if (this.httprequest.protocol == 5) {
556
// Setup files
@@ -700,7 +660,49 @@ function createMeshCore(agent) {
660
//sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid);
661
}
662
}
703
-
663
+
664
+ // Attempt to setup and switch the tunnel over to WebRTC
665
+ function onTunnelControlData(data) {
666
+ sendConsoleText('onTunnelControlData: ' + data);
667
+ var obj = JSON.parse(data);
668
+ if (obj.type == 'offer') {
669
+ // This is a WebRTC offer.
670
+ this.webrtc = rtc.createConnection();
671
+ this.webrtc.websocket = this;
672
+ this.webrtc.on('connected', function () { sendConsoleText('WebRTC connected'); });
673
+ this.webrtc.on('dataChannel', function (rtcchannel) {
674
+ sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
675
+ this.rtcchannel = rtcchannel;
676
+ if (this.websocket.httprequest.protocol == 1) { // Terminal
677
+ // This is a terminal data stream, re-setup the pipes
678
+ // Un-pipe
679
+ this.websocket.unpipe(this.websocket.httprequest.process.stdin);
680
+ //this.websocket.httprequest.process.stdout.unpipe(this.websocket);
681
+ // Re-pipe
682
+ rtcchannel.pipe(this.websocket.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
683
+ //this.websocket.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
684
+ } else if (this.websocket.httprequest.protocol == 2) { // Desktop
685
+ // This is a KVM data stream, re-setup the pipes
686
+ // Un-pipe
687
+ this.websocket.unpipe(this.websocket.httprequest.desktop.kvm);
688
+ //this.websocket.httprequest.desktop.kvm.unpipe(this.websocket);
689
+ // Re-pipe
690
+ rtcchannel.pipe(this.websocket.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
691
+ //this.websocket.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
692
+ }
693
+ /*
694
+ else {
695
+ // Debug, just display on agent console
696
+ rtcchannel.on('data', function (buffer) { sendConsoleText("RTCReceived: " + buffer.length + " bytes"); });
697
+ rtcchannel.on('end', function () { sendConsoleText("RTCChannel: " + this.name + " was closed"); });
698
+ channel.write('WebRTC HELLO!');
699
+ }
700
+ */
701
+ });
702
+ this.write({ type: "answer", sdp: this.webrtc.setOffer(obj.sdp) });
703
+ }
704
+ }
705
+
706
// Console state
707
var consoleWebSockets = {};
708
var consoleHttpRequest = null;
@@ -740,7 +742,7 @@ function createMeshCore(agent) {
742
break;
743
}
744
case 'info': { // Return information about the agent and agent core module
743
- 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 + '.';
745
+ 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\nServer URL: ' + mesh.ServerUrl + '.';
746
if (amtLmsState >= 0) { response += '\r\nBuilt -in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amtLmsState] + '.'; }
747
response += '\r\nModules: ' + JSON.stringify(addedModules) + '';
748
response += '\r\nServerConnected: ' + mesh.isControlChannelConnected + '';
certoperations.js
+14
-12
@@ -203,17 +203,19 @@ module.exports.CertificateOperations = function () {
203
}
204
205
// If CA certificates are present, load them
206
- var caok, caindex = 1, calist = [];
207
- do {
208
- caok = false;
209
- if (obj.fileExists(directory + '/webserver-cert-chain' + caindex + '.crt')) {
210
- var caCertificate = obj.fs.readFileSync(directory + '/webserver-cert-chain' + caindex + '.crt', 'utf8');
211
- calist.push(caCertificate);
212
- caok = true;
213
- }
214
- caindex++;
215
- } while (caok == true);
216
- r.web.ca = calist;
206
+ if (r.web != null) {
207
+ var caok, caindex = 1, calist = [];
208
+ do {
209
+ caok = false;
210
+ if (obj.fileExists(directory + '/webserver-cert-chain' + caindex + '.crt')) {
211
+ var caCertificate = obj.fs.readFileSync(directory + '/webserver-cert-chain' + caindex + '.crt', 'utf8');
212
+ calist.push(caCertificate);
213
+ caok = true;
214
+ }
215
+ caindex++;
216
+ } while (caok == true);
217
+ r.web.ca = calist;
218
+ }
219
220
// Decode certificate arguments
221
var commonName = 'un-configured', country, organization, forceWebCertGen = 0;
@@ -374,7 +376,7 @@ module.exports.CertificateOperations = function () {
376
amtConsoleName = consoleCertAndKey.cert.subject.getField('CN').value;
377
}
378
377
- var r = { root: { cert: rootCertificate, key: rootPrivateKey }, web: { cert: webCertificate, key: webPrivateKey }, mps: { cert: mpsCertificate, key: mpsPrivateKey }, agent: { cert: agentCertificate, key: agentPrivateKey }, console: { cert: consoleCertificate, key: consolePrivateKey }, ca: calist, CommonName: commonName, RootName: rootName, AmtConsoleName: amtConsoleName, dns: {} };
379
+ var r = { root: { cert: rootCertificate, key: rootPrivateKey }, web: { cert: webCertificate, key: webPrivateKey, ca: [] }, mps: { cert: mpsCertificate, key: mpsPrivateKey }, agent: { cert: agentCertificate, key: agentPrivateKey }, console: { cert: consoleCertificate, key: consolePrivateKey }, ca: calist, CommonName: commonName, RootName: rootName, AmtConsoleName: amtConsoleName, dns: {} };
380
381
// Look for domains with DNS names that have no certificates and generated them.
382
for (var i in config.domains) {
interceptor.js
+21
-10
@@ -183,21 +183,32 @@ module.exports.CreateHttpInterceptor = function (args) {
183
obj.ws.count -= rl;
184
if (obj.ws.count == 0) { obj.ws.mode = 0; }
185
return r;
186
- } else if (obj.ws.mode == 2) { // Chunked Body Mode
186
+ } else if (obj.amt.mode == 2) { // Chunked Body Mode
187
// Send data one chunk at a time
188
- var headerend = obj.ws.acc.indexOf('\r\n');
188
+ var headerend = obj.amt.acc.indexOf('\r\n');
189
if (headerend < 0) return "";
190
- var chunksize = parseInt(obj.ws.acc.substring(0, headerend), 16);
191
- if (chunksize == 0 && obj.ws.acc.length >= headerend + 4) {
190
+ var chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
191
+ if (isNaN(chunksize)) { // TODO: Check this path
192
+ // Chunk is not in this batch, move one
193
+ var r = obj.amt.acc.substring(0, headerend + 2);
194
+ obj.amt.acc = obj.amt.acc.substring(headerend + 2);
195
+ // Peek if we next is the end of chunked transfer
196
+ headerend = obj.amt.acc.indexOf('\r\n');
197
+ if (headerend > 0) {
198
+ chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
199
+ if (chunksize == 0) { obj.amt.mode = 0; }
200
+ }
201
+ return r;
202
+ } else if (chunksize == 0 && obj.amt.acc.length >= headerend + 4) {
203
// Send the ending chunk (NOTE: We do not support trailing headers)
193
- var r = obj.ws.acc.substring(0, headerend + 4);
194
- obj.ws.acc = obj.ws.acc.substring(headerend + 4);
195
- obj.ws.mode = 0;
204
+ var r = obj.amt.acc.substring(0, headerend + 4);
205
+ obj.amt.acc = obj.amt.acc.substring(headerend + 4);
206
+ obj.amt.mode = 0;
207
return r;
197
- } else if (chunksize > 0 && obj.ws.acc.length >= headerend + 4) {
208
+ } else if (chunksize > 0 && obj.amt.acc.length >= headerend + 4) {
209
// Send a chunk
199
- var r = obj.ws.acc.substring(0, headerend + chunksize + 4);
200
- obj.ws.acc = obj.ws.acc.substring(headerend + chunksize + 4);
210
+ var r = obj.amt.acc.substring(0, headerend + chunksize + 4);
211
+ obj.amt.acc = obj.amt.acc.substring(headerend + chunksize + 4);
212
return r;
213
}
214
} else if (obj.ws.mode == 3) { // Until Close Mode
meshrelay.js
+6
-6
@@ -175,16 +175,16 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
175
}
176
}
177
}
178
-
179
- ws.flushSink = function () {
180
- try { ws.resume(); } catch (e) { }
181
- };
178
+
179
+ ws.flushSink = function () { try { ws.resume(); } catch (e) { } };
180
181
// When data is received from the mesh relay web socket
182
ws.on('message', function (data) {
183
//console.log(typeof data, data.length);
186
- //if (typeof data == 'string') console.log(data);
187
- if (this.peer != null) { try { this.pause(); this.peer.send(data, ws.flushSink); } catch (e) { } }
184
+ if (this.peer != null) {
185
+ //if (typeof data == 'string') { console.log('Relay: ' + data); }
186
+ try { this.pause(); this.peer.send(data, ws.flushSink); } catch (e) { }
187
+ }
188
});
189
190
// If error, do nothing
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.1.2-s",
3
+ "version": "0.1.2-t",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
public/scripts/agent-desktop-0.0.2.js
+1
-1
@@ -172,7 +172,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
172
obj.ProcessData = function (str) {
173
if (str.length < 4) return;
174
var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2);
175
- if (command >= 18) { console.error("Invalid KVM command " + command + " of size " + cmdsize); obj.parent.Stop(); return; }
175
+ if (command >= 18) { console.error("Invalid KVM command " + command + " of size " + cmdsize); console.log("Invalid KVM data", str.length, str, rstr2hex(str)); return; }
176
if (cmdsize > str.length) { console.error("KVM invalid command size", cmdsize, str.length); return; }
177
//meshOnDebug("KVM Command: " + command + " Len:" + cmdsize);
178
if (obj.debugmode == 1) { console.log("KVM Command: " + command + " Len:" + cmdsize); }
public/scripts/agent-redir-ws-0.1.0.js
+27
-27
@@ -17,6 +17,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
17
obj.tunnelid = Math.random().toString(36).substring(2); // Generate a random client tunnel id
18
obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER, 4 = Files, 5 = FileTransfer
19
obj.attemptWebRTC = false;
20
+ obj.webRtcActive = false;
21
obj.webrtc = null;
22
obj.webchannel = null;
23
obj.onStateChanged = null;
@@ -49,12 +50,10 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
50
51
// Called to pass websocket control messages
52
obj.xxOnControlCommand = function (msg) {
52
- //console.log(msg);
53
- //obj.socket.send('hellobob');
53
var controlMsg = JSON.parse(msg);
54
if ((controlMsg.type == 'answer') && (obj.webrtc != null)) {
56
- console.log('gotAnswer', JSON.stringify(controlMsg));
57
- obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { console.log('WebRTC remote ok'); }, obj.xxCloseWebRTC);
55
+ //console.log('gotAnswer', JSON.stringify(controlMsg));
56
+ obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { /*console.log('WebRTC remote ok');*/ }, obj.xxCloseWebRTC);
57
}
58
}
59
@@ -65,7 +64,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
64
}
65
66
obj.xxOnMessage = function (e) {
68
- if (obj.debugmode == 1) { console.log('Recv', e.data); }
67
+ //if (obj.debugmode == 1) { console.log('Recv', e.data); }
68
if (obj.State < 3) {
69
if (e.data == 'c') {
70
obj.socket.send(obj.protocol);
@@ -79,28 +78,27 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
78
79
if (obj.webrtc != null) {
80
obj.webchannel = obj.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
82
- obj.webchannel.onmessage = function (event) { console.log("DataChannel - onmessage", event.data); };
83
- obj.webchannel.onopen = function () { console.log("DataChannel - onopen"); };
84
- obj.webchannel.onclose = function (event) { console.log("DataChannel - onclose"); }
85
- obj.webrtc.ondatachannel = function (e) { console.log('ondatachannel'); } // TODO: Should not be needed
81
+ obj.webchannel.onmessage = function (event) { console.log("DataChannel - onmessage", event.data); obj.xxOnMessage(event.data); };
82
+ obj.webchannel.onopen = function () { obj.webRtcActive = true; if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.State); } /*obj.webchannel.send("Browser WebRTC Hello!!!");*/ };
83
+ obj.webchannel.onclose = function (event) { obj.Stop(); }
84
obj.webrtc.onicecandidate = function (e) {
85
if (e.candidate == null) {
88
- console.log('createOffer', JSON.stringify(obj.webrtcoffer));
89
- obj.socket.send('**********%%%%%%###**' + JSON.stringify(obj.webrtcoffer)); // End of candidates, send the offer
86
+ //console.log('createOffer', JSON.stringify(obj.webrtcoffer));
87
+ obj.socket.send(JSON.stringify(obj.webrtcoffer)); // End of candidates, send the offer
88
} else {
89
obj.webrtcoffer.sdp += ("a=" + e.candidate.candidate + "\r\n"); // New candidate, add it to the SDP
90
}
91
}
92
obj.webrtc.oniceconnectionstatechange = function () {
93
if (obj.webrtc != null) {
96
- console.log('oniceconnectionstatechange', obj.webrtc.iceConnectionState);
94
+ //console.log('WebRTC ICE', obj.webrtc.iceConnectionState);
95
if ((obj.webrtc.iceConnectionState == 'disconnected') || (obj.webrtc.iceConnectionState == 'failed')) { obj.xxCloseWebRTC(); }
96
}
97
}
98
obj.webrtc.createOffer(function (offer) {
99
// Got the offer
100
obj.webrtcoffer = offer;
103
- obj.webrtc.setLocalDescription(offer, function () { console.log('WebRTC local ok'); }, obj.xxCloseWebRTC);
101
+ obj.webrtc.setLocalDescription(offer, function () { /*console.log('WebRTC local ok');*/ }, obj.xxCloseWebRTC);
102
}, obj.xxCloseWebRTC, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
103
}
104
}
@@ -108,10 +106,14 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
106
return;
107
}
108
}
109
+
110
if (typeof e.data == 'string') {
111
// Control messages, most likely WebRTC setup
112
obj.xxOnControlCommand(e.data);
114
- } else if (typeof e.data == 'object') {
113
+ return;
114
+ }
115
+
116
+ if (typeof e.data == 'object') {
117
var f = new FileReader();
118
if (f.readAsBinaryString) {
119
// Chrome & Firefox (Draft)
@@ -138,7 +140,6 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
140
141
obj.xxOnSocketData = function (data) {
142
if (!data || obj.connectstate == -1) return;
141
-
143
if (typeof data === 'object') {
144
// This is an ArrayBuffer, convert it to a string array (used in IE)
145
var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
@@ -146,39 +147,35 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
147
data = binary;
148
}
149
else if (typeof data !== 'string') return;
149
-
150
- // TODO: Don't use a prefix anymore, use string encoding instead
151
- if (data.length > 21 && data.startsWith('**********%%%%%%###**')) { obj.xxOnControlCommand(data.substring(21)); return; }
152
-
150
//console.log("xxOnSocketData", rstr2hex(data));
154
-
151
return obj.m.ProcessData(data);
152
}
153
154
obj.Send = function (x) {
159
- //obj.debug("Agent Redir Send(" + x.length + "): " + rstr2hex(x));
155
+ //obj.debug("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + rstr2hex(x));
156
+ //console.log("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + rstr2hex(x));
157
if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
158
if (typeof x == 'string') {
159
if (obj.debugmode == 1) {
160
var b = new Uint8Array(x.length), c = [];
161
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); c.push(x.charCodeAt(i)); }
165
- obj.socket.send(b.buffer);
166
- console.log('Send', c);
162
+ if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
163
+ //console.log('Send', c);
164
} else {
165
var b = new Uint8Array(x.length);
166
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
170
- obj.socket.send(b.buffer);
167
+ if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
168
}
169
} else {
173
- if (obj.debugmode == 1) { console.log('Send', x); }
174
- obj.socket.send(x);
170
+ //if (obj.debugmode == 1) { console.log('Send', x); }
171
+ if (obj.webRtcActive == true) { obj.webchannel.send(x); } else { obj.socket.send(x); }
172
}
173
}
174
}
175
176
obj.xxOnSocketClosed = function () {
177
//obj.debug("Agent Redir Socket Closed");
181
- if (obj.debugmode == 1) { console.log('onSocketClosed'); }
178
+ //if (obj.debugmode == 1) { console.log('onSocketClosed'); }
179
obj.Stop(1);
180
}
181
@@ -192,6 +189,9 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
189
obj.Stop = function (x) {
190
if (obj.debugmode == 1) { console.log('stop', x); }
191
//obj.debug("Agent Redir Socket Stopped");
192
+ obj.webRtcActive = false;
193
+ obj.webrtc = null;
194
+ obj.webchannel = null;
195
obj.xxStateChange(0);
196
obj.connectstate = -1;
197
obj.xxCloseWebRTC();
views/default.handlebars
+16
-8
@@ -647,6 +647,7 @@
647
var amtScanResults = null;
648
var debugmode = false;
649
var clickOnce = detectClickOnce();
650
+ var attemptWebRTC = false;
651
652
function startup() {
653
if ((features & 32) == 0) {
@@ -2934,7 +2935,7 @@
2935
desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort);
2936
desktop.debugmode = debugmode;
2937
desktop.m.debugmode = debugmode;
2937
- //desktop.attemptWebRTC = debugmode;
2938
+ desktop.attemptWebRTC = attemptWebRTC;
2939
desktop.onStateChanged = onDesktopStateChange;
2940
desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
2941
desktop.m.ScalingLevel = desktopsettings.scaling;
@@ -2954,7 +2955,10 @@
2955
function onDesktopStateChange(xdesktop, state) {
2956
var xstate = state;
2957
if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
2957
- QH('deskstatus', StatusStrs[xstate]);
2958
+ var str = StatusStrs[xstate];
2959
+ if (desktop.webRtcActive == true) { str += ', WebRTC'; }
2960
+ //if (desktop.m.stopInput == true) { str += ', Loopback'; }
2961
+ QH('deskstatus', str);
2962
QE('deskSaveBtn', state == 3);
2963
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (state != 0) && (desktopsettings.showfocus));
2964
QE('DeskCAD', state == 3);
@@ -3143,7 +3147,9 @@
3147
function onTerminalStateChange(xterminal, state) {
3148
var xstate = state;
3149
if ((xstate == 3) && (xterminal.contype == 2)) { xstate++; }
3146
- QH('termstatus', StatusStrs[xstate]);
3150
+ var str = StatusStrs[xstate];
3151
+ if (terminal.webRtcActive == true) { str += ', WebRTC'; }
3152
+ QH('termstatus', str);
3153
switch (state) {
3154
case 0:
3155
// Disconnected, clear the terminal
@@ -3180,7 +3186,7 @@
3186
terminal = CreateAgentRedirect(meshserver, CreateAmtRemoteTerminal('Term'), serverPublicNamePort);
3187
terminal.debugmode = debugmode;
3188
terminal.m.debugmode = debugmode;
3183
- //terminal.attemptWebRTC = debugmode;
3189
+ terminal.attemptWebRTC = attemptWebRTC;
3190
terminal.onStateChanged = onTerminalStateChange;
3191
terminal.Start(terminalNode._id);
3192
terminal.contype = 1;
@@ -3251,7 +3257,9 @@
3257
3258
function onFilesStateChange(xfiles, state) {
3259
p13Connect.value = (state == 0) ? 'Connect' : 'Disconnect';
3254
- Q('p13Status').textContent = StatusStrs[state];
3260
+ var str = StatusStrs[state];
3261
+ if (files.webRtcActive == true) { str += ', WebRTC'; }
3262
+ Q('p13Status').textContent = str;
3263
switch (state) {
3264
case 0:
3265
// Disconnected, clear the files
@@ -3286,7 +3294,7 @@
3294
if (!files) {
3295
// Setup a mesh agent files
3296
files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort);
3289
- files.attemptWebRTC = debugmode;
3297
+ files.attemptWebRTC = false;
3298
files.onStateChanged = onFilesStateChange;
3299
files.Start(filesNode._id);
3300
} else {
@@ -3492,7 +3500,7 @@
3500
// Called by the html page to start a download, arguments are: path, file name and file size.
3501
function p13downloadfile(x, y, z) {
3502
downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort); // Create our file transport
3495
- downloadFile.attemptWebRTC = debugmode;
3503
+ downloadFile.attemptWebRTC = false;
3504
downloadFile.onStateChanged = onFileDownloadStateChange;
3505
downloadFile.xpath = decodeURIComponent(x);
3506
downloadFile.xfile = decodeURIComponent(y);
@@ -3571,7 +3579,7 @@
3579
// Connect again
3580
function p13uploadReconnect() {
3581
uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort);
3574
- uploadFile.ws.attemptWebRTC = debugmode;
3582
+ uploadFile.ws.attemptWebRTC = false;
3583
uploadFile.ws.onStateChanged = onFileUploadStateChange;
3584
uploadFile.ws.Start(filesNode._id);
3585
}