First pass at adding WebRTC support.

This commit is contained in:
Ylian Saint-Hilaire 2018-01-16 17:30:34 -08:00
parent 65d6775303
commit 92aaf754fb
12 changed files with 164 additions and 141 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -5,7 +5,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
@ -20,7 +20,6 @@ function createMeshCore(agent) {
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
obj.meshCoreInfo = "MeshCore v4";
obj.meshCoreCapabilities = 14; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript
obj.useNativePipes = true; //(process.platform == 'win32');
var meshServerConnectionState = 0;
var tunnels = {};
var lastSelfInfo = null;
@ -54,6 +53,7 @@ function createMeshCore(agent) {
scan.scan("10.2.55.128/25", 2000);
*/
/*
// Try to load up the network monitor
try {
networkMonitor = require('NetworkMonitor');
@ -61,6 +61,7 @@ function createMeshCore(agent) {
networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
} catch (e) { networkMonitor = null; }
*/
// Try to load up the Intel AMT scanner
try {
@ -507,27 +508,6 @@ function createMeshCore(agent) {
return;
}
// Setup remote desktop & terminal without using native pipes
if ((this.httprequest.desktop) && (obj.useNativePipes == false)) {
if (data.length > 21 && data.toString().startsWith('**********%%%%%%###**')) {
var controlMsg = JSON.parse(data.toString().substring(21));
if (controlMsg.type == 'offer') {
this.webrtc = rtc.createConnection();
this.webrtc.on('connected', function () { sendConsoleText('OnWebRTC_Connected'); });
this.webrtc.on('dataChannel', function () { sendConsoleText('OnWebRTC_DataChannel'); });
var counterOffer = this.webrtc.setOffer(controlMsg.sdp);
this.write('**********%%%%%%###**' + JSON.stringify({ type: 'answer', sdp: counterOffer }));
sendConsoleText('counterOfferSent');
} else {
sendConsoleText(JSON.stringify(controlMsg));
}
} else {
this.httprequest.desktop.kvm.write(data);
}
return;
}
if ((this.httprequest.terminal) && (obj.useNativePipes == false)) { this.httprequest.terminal.write(data); return; }
if (this.httprequest.state == 0) {
// Check if this is a relay connection
if (data == 'c') { this.httprequest.state = 1; sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid); }
@ -538,59 +518,39 @@ function createMeshCore(agent) {
this.httprequest.protocol = parseInt(data);
if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
if (this.httprequest.protocol == 1) {
if (obj.useNativePipes == false) {
// Remote Terminal without using native pipes
if (process.platform == "win32") {
this.httprequest.terminal = childProcess.execFile("%windir%\\system32\\cmd.exe");
} else {
this.httprequest.terminal = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
}
this.httprequest.terminal.tunnel = this;
this.httprequest.terminal.on('exit', function (ecode, sig) { this.tunnel.end(); });
this.httprequest.terminal.stdout.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
this.httprequest.terminal.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
// Remote terminal using native pipes
if (process.platform == "win32") {
this.httprequest.process = childProcess.execFile("%windir%\\system32\\cmd.exe");
} else {
// Remote terminal using native pipes
if (process.platform == "win32") {
this.httprequest.process = childProcess.execFile("%windir%\\system32\\cmd.exe");
} else {
this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
}
this.httprequest.process.tunnel = this;
this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
this.prependListener('end', function () { this.httprequest.process.kill(); });
this.httprequest.process = childProcess.execFile("/bin/sh", ["sh"], { type: childProcess.SpawnTypes.TERM });
}
this.httprequest.process.tunnel = this;
this.httprequest.process.on('exit', function (ecode, sig) { this.tunnel.end(); });
this.httprequest.process.stderr.on('data', function (chunk) { this.parent.tunnel.write(chunk); });
this.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
this.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
this.prependListener('end', function () { this.httprequest.process.kill(); });
this.removeAllListeners('data');
this.on('data', onTunnelControlData);
//this.write('MeshCore Terminal Hello!1');
}
if (this.httprequest.protocol == 2) {
if (obj.useNativePipes == false) {
// Remote Desktop without using native pipes
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
this.httprequest.desktop.kvm.tunnel = this;
this.httprequest.desktop.kvm.on('data', function (data) { this.tunnel.write(data); });
this.desktop = this.httprequest.desktop;
this.end = function () { if (--this.desktop.kvm.connectionCount == 0) { this.httprequest.desktop.kvm.end(); } };
if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
} else {
// Remote desktop using native pipes
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
this.desktop = this.httprequest.desktop;
this.end = function () {
--this.desktop.kvm.connectionCount;
this.unpipe(this.httprequest.desktop.kvm);
this.httprequest.desktop.kvm.unpipe(this);
if (this.desktop.kvm.connectionCount == 0) { this.httprequest.desktop.kvm.end(); }
};
if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
//this.write('Hello!');
//sendConsoleText('KVM WriteHello');
this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
//this.on('data', function (data) { sendConsoleText('KVM: ' + data); });
}
// Remote desktop using native pipes
this.httprequest.desktop = { state: 0, kvm: mesh.getRemoteDesktopStream(), tunnel: this };
this.httprequest.desktop.kvm.parent = this.httprequest.desktop;
this.desktop = this.httprequest.desktop;
this.end = function () {
--this.desktop.kvm.connectionCount;
this.unpipe(this.httprequest.desktop.kvm);
this.httprequest.desktop.kvm.unpipe(this);
if (this.desktop.kvm.connectionCount == 0) { this.httprequest.desktop.kvm.end(); }
};
if (this.httprequest.desktop.kvm.hasOwnProperty("connectionCount")) { this.httprequest.desktop.kvm.connectionCount++; } else { this.httprequest.desktop.kvm.connectionCount = 1; }
this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
this.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
this.removeAllListeners('data');
this.on('data', onTunnelControlData);
//this.write('MeshCore KVM Hello!1');
}
else if (this.httprequest.protocol == 5) {
// Setup files
@ -701,6 +661,48 @@ function createMeshCore(agent) {
}
}
// Attempt to setup and switch the tunnel over to WebRTC
function onTunnelControlData(data) {
sendConsoleText('onTunnelControlData: ' + data);
var obj = JSON.parse(data);
if (obj.type == 'offer') {
// This is a WebRTC offer.
this.webrtc = rtc.createConnection();
this.webrtc.websocket = this;
this.webrtc.on('connected', function () { sendConsoleText('WebRTC connected'); });
this.webrtc.on('dataChannel', function (rtcchannel) {
sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
this.rtcchannel = rtcchannel;
if (this.websocket.httprequest.protocol == 1) { // Terminal
// This is a terminal data stream, re-setup the pipes
// Un-pipe
this.websocket.unpipe(this.websocket.httprequest.process.stdin);
//this.websocket.httprequest.process.stdout.unpipe(this.websocket);
// Re-pipe
rtcchannel.pipe(this.websocket.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
//this.websocket.httprequest.process.stdout.pipe(this, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
} else if (this.websocket.httprequest.protocol == 2) { // Desktop
// This is a KVM data stream, re-setup the pipes
// Un-pipe
this.websocket.unpipe(this.websocket.httprequest.desktop.kvm);
//this.websocket.httprequest.desktop.kvm.unpipe(this.websocket);
// Re-pipe
rtcchannel.pipe(this.websocket.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
//this.websocket.httprequest.desktop.kvm.pipe(this, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
}
/*
else {
// Debug, just display on agent console
rtcchannel.on('data', function (buffer) { sendConsoleText("RTCReceived: " + buffer.length + " bytes"); });
rtcchannel.on('end', function () { sendConsoleText("RTCChannel: " + this.name + " was closed"); });
channel.write('WebRTC HELLO!');
}
*/
});
this.write({ type: "answer", sdp: this.webrtc.setOffer(obj.sdp) });
}
}
// Console state
var consoleWebSockets = {};
var consoleHttpRequest = null;
@ -740,7 +742,7 @@ function createMeshCore(agent) {
break;
}
case 'info': { // Return information about the agent and agent core module
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 + '.';
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 + '.';
if (amtLmsState >= 0) { response += '\r\nBuilt -in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amtLmsState] + '.'; }
response += '\r\nModules: ' + JSON.stringify(addedModules) + '';
response += '\r\nServerConnected: ' + mesh.isControlChannelConnected + '';

View File

@ -203,17 +203,19 @@ module.exports.CertificateOperations = function () {
}
// If CA certificates are present, load them
var caok, caindex = 1, calist = [];
do {
caok = false;
if (obj.fileExists(directory + '/webserver-cert-chain' + caindex + '.crt')) {
var caCertificate = obj.fs.readFileSync(directory + '/webserver-cert-chain' + caindex + '.crt', 'utf8');
calist.push(caCertificate);
caok = true;
}
caindex++;
} while (caok == true);
r.web.ca = calist;
if (r.web != null) {
var caok, caindex = 1, calist = [];
do {
caok = false;
if (obj.fileExists(directory + '/webserver-cert-chain' + caindex + '.crt')) {
var caCertificate = obj.fs.readFileSync(directory + '/webserver-cert-chain' + caindex + '.crt', 'utf8');
calist.push(caCertificate);
caok = true;
}
caindex++;
} while (caok == true);
r.web.ca = calist;
}
// Decode certificate arguments
var commonName = 'un-configured', country, organization, forceWebCertGen = 0;
@ -374,7 +376,7 @@ module.exports.CertificateOperations = function () {
amtConsoleName = consoleCertAndKey.cert.subject.getField('CN').value;
}
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: {} };
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: {} };
// Look for domains with DNS names that have no certificates and generated them.
for (var i in config.domains) {

View File

@ -183,21 +183,32 @@ module.exports.CreateHttpInterceptor = function (args) {
obj.ws.count -= rl;
if (obj.ws.count == 0) { obj.ws.mode = 0; }
return r;
} else if (obj.ws.mode == 2) { // Chunked Body Mode
} else if (obj.amt.mode == 2) { // Chunked Body Mode
// Send data one chunk at a time
var headerend = obj.ws.acc.indexOf('\r\n');
var headerend = obj.amt.acc.indexOf('\r\n');
if (headerend < 0) return "";
var chunksize = parseInt(obj.ws.acc.substring(0, headerend), 16);
if (chunksize == 0 && obj.ws.acc.length >= headerend + 4) {
// Send the ending chunk (NOTE: We do not support trailing headers)
var r = obj.ws.acc.substring(0, headerend + 4);
obj.ws.acc = obj.ws.acc.substring(headerend + 4);
obj.ws.mode = 0;
var chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
if (isNaN(chunksize)) { // TODO: Check this path
// Chunk is not in this batch, move one
var r = obj.amt.acc.substring(0, headerend + 2);
obj.amt.acc = obj.amt.acc.substring(headerend + 2);
// Peek if we next is the end of chunked transfer
headerend = obj.amt.acc.indexOf('\r\n');
if (headerend > 0) {
chunksize = parseInt(obj.amt.acc.substring(0, headerend), 16);
if (chunksize == 0) { obj.amt.mode = 0; }
}
return r;
} else if (chunksize > 0 && obj.ws.acc.length >= headerend + 4) {
} else if (chunksize == 0 && obj.amt.acc.length >= headerend + 4) {
// Send the ending chunk (NOTE: We do not support trailing headers)
var r = obj.amt.acc.substring(0, headerend + 4);
obj.amt.acc = obj.amt.acc.substring(headerend + 4);
obj.amt.mode = 0;
return r;
} else if (chunksize > 0 && obj.amt.acc.length >= headerend + 4) {
// Send a chunk
var r = obj.ws.acc.substring(0, headerend + chunksize + 4);
obj.ws.acc = obj.ws.acc.substring(headerend + chunksize + 4);
var r = obj.amt.acc.substring(0, headerend + chunksize + 4);
obj.amt.acc = obj.amt.acc.substring(headerend + chunksize + 4);
return r;
}
} else if (obj.ws.mode == 3) { // Until Close Mode

View File

@ -176,15 +176,15 @@ module.exports.CreateMeshRelay = function (parent, ws, req, domain) {
}
}
ws.flushSink = function () {
try { ws.resume(); } catch (e) { }
};
ws.flushSink = function () { try { ws.resume(); } catch (e) { } };
// When data is received from the mesh relay web socket
ws.on('message', function (data) {
//console.log(typeof data, data.length);
//if (typeof data == 'string') console.log(data);
if (this.peer != null) { try { this.pause(); this.peer.send(data, ws.flushSink); } catch (e) { } }
if (this.peer != null) {
//if (typeof data == 'string') { console.log('Relay: ' + data); }
try { this.pause(); this.peer.send(data, ws.flushSink); } catch (e) { }
}
});
// If error, do nothing

View File

@ -1,6 +1,6 @@
{
"name": "meshcentral",
"version": "0.1.2-s",
"version": "0.1.2-t",
"keywords": [
"Remote Management",
"Intel AMT",

View File

@ -172,7 +172,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
obj.ProcessData = function (str) {
if (str.length < 4) return;
var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2);
if (command >= 18) { console.error("Invalid KVM command " + command + " of size " + cmdsize); obj.parent.Stop(); return; }
if (command >= 18) { console.error("Invalid KVM command " + command + " of size " + cmdsize); console.log("Invalid KVM data", str.length, str, rstr2hex(str)); return; }
if (cmdsize > str.length) { console.error("KVM invalid command size", cmdsize, str.length); return; }
//meshOnDebug("KVM Command: " + command + " Len:" + cmdsize);
if (obj.debugmode == 1) { console.log("KVM Command: " + command + " Len:" + cmdsize); }

View File

@ -17,6 +17,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
obj.tunnelid = Math.random().toString(36).substring(2); // Generate a random client tunnel id
obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER, 4 = Files, 5 = FileTransfer
obj.attemptWebRTC = false;
obj.webRtcActive = false;
obj.webrtc = null;
obj.webchannel = null;
obj.onStateChanged = null;
@ -49,12 +50,10 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
// Called to pass websocket control messages
obj.xxOnControlCommand = function (msg) {
//console.log(msg);
//obj.socket.send('hellobob');
var controlMsg = JSON.parse(msg);
if ((controlMsg.type == 'answer') && (obj.webrtc != null)) {
console.log('gotAnswer', JSON.stringify(controlMsg));
obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { console.log('WebRTC remote ok'); }, obj.xxCloseWebRTC);
//console.log('gotAnswer', JSON.stringify(controlMsg));
obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { /*console.log('WebRTC remote ok');*/ }, obj.xxCloseWebRTC);
}
}
@ -65,7 +64,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
}
obj.xxOnMessage = function (e) {
if (obj.debugmode == 1) { console.log('Recv', e.data); }
//if (obj.debugmode == 1) { console.log('Recv', e.data); }
if (obj.State < 3) {
if (e.data == 'c') {
obj.socket.send(obj.protocol);
@ -79,28 +78,27 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
if (obj.webrtc != null) {
obj.webchannel = obj.webrtc.createDataChannel("DataChannel", {}); // { ordered: false, maxRetransmits: 2 }
obj.webchannel.onmessage = function (event) { console.log("DataChannel - onmessage", event.data); };
obj.webchannel.onopen = function () { console.log("DataChannel - onopen"); };
obj.webchannel.onclose = function (event) { console.log("DataChannel - onclose"); }
obj.webrtc.ondatachannel = function (e) { console.log('ondatachannel'); } // TODO: Should not be needed
obj.webchannel.onmessage = function (event) { console.log("DataChannel - onmessage", event.data); obj.xxOnMessage(event.data); };
obj.webchannel.onopen = function () { obj.webRtcActive = true; if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.State); } /*obj.webchannel.send("Browser WebRTC Hello!!!");*/ };
obj.webchannel.onclose = function (event) { obj.Stop(); }
obj.webrtc.onicecandidate = function (e) {
if (e.candidate == null) {
console.log('createOffer', JSON.stringify(obj.webrtcoffer));
obj.socket.send('**********%%%%%%###**' + JSON.stringify(obj.webrtcoffer)); // End of candidates, send the offer
//console.log('createOffer', JSON.stringify(obj.webrtcoffer));
obj.socket.send(JSON.stringify(obj.webrtcoffer)); // End of candidates, send the offer
} else {
obj.webrtcoffer.sdp += ("a=" + e.candidate.candidate + "\r\n"); // New candidate, add it to the SDP
}
}
obj.webrtc.oniceconnectionstatechange = function () {
if (obj.webrtc != null) {
console.log('oniceconnectionstatechange', obj.webrtc.iceConnectionState);
//console.log('WebRTC ICE', obj.webrtc.iceConnectionState);
if ((obj.webrtc.iceConnectionState == 'disconnected') || (obj.webrtc.iceConnectionState == 'failed')) { obj.xxCloseWebRTC(); }
}
}
obj.webrtc.createOffer(function (offer) {
// Got the offer
obj.webrtcoffer = offer;
obj.webrtc.setLocalDescription(offer, function () { console.log('WebRTC local ok'); }, obj.xxCloseWebRTC);
obj.webrtc.setLocalDescription(offer, function () { /*console.log('WebRTC local ok');*/ }, obj.xxCloseWebRTC);
}, obj.xxCloseWebRTC, { mandatory: { OfferToReceiveAudio: false, OfferToReceiveVideo: false } });
}
}
@ -108,10 +106,14 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
return;
}
}
if (typeof e.data == 'string') {
// Control messages, most likely WebRTC setup
obj.xxOnControlCommand(e.data);
} else if (typeof e.data == 'object') {
return;
}
if (typeof e.data == 'object') {
var f = new FileReader();
if (f.readAsBinaryString) {
// Chrome & Firefox (Draft)
@ -138,7 +140,6 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
obj.xxOnSocketData = function (data) {
if (!data || obj.connectstate == -1) return;
if (typeof data === 'object') {
// This is an ArrayBuffer, convert it to a string array (used in IE)
var binary = "", bytes = new Uint8Array(data), length = bytes.byteLength;
@ -146,39 +147,35 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
data = binary;
}
else if (typeof data !== 'string') return;
// TODO: Don't use a prefix anymore, use string encoding instead
if (data.length > 21 && data.startsWith('**********%%%%%%###**')) { obj.xxOnControlCommand(data.substring(21)); return; }
//console.log("xxOnSocketData", rstr2hex(data));
return obj.m.ProcessData(data);
}
obj.Send = function (x) {
//obj.debug("Agent Redir Send(" + x.length + "): " + rstr2hex(x));
//obj.debug("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + rstr2hex(x));
//console.log("Agent Redir Send(" + obj.webRtcActive + ", " + x.length + "): " + rstr2hex(x));
if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) {
if (typeof x == 'string') {
if (obj.debugmode == 1) {
var b = new Uint8Array(x.length), c = [];
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); c.push(x.charCodeAt(i)); }
obj.socket.send(b.buffer);
console.log('Send', c);
if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
//console.log('Send', c);
} else {
var b = new Uint8Array(x.length);
for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); }
obj.socket.send(b.buffer);
if (obj.webRtcActive == true) { obj.webchannel.send(b.buffer); } else { obj.socket.send(b.buffer); }
}
} else {
if (obj.debugmode == 1) { console.log('Send', x); }
obj.socket.send(x);
//if (obj.debugmode == 1) { console.log('Send', x); }
if (obj.webRtcActive == true) { obj.webchannel.send(x); } else { obj.socket.send(x); }
}
}
}
obj.xxOnSocketClosed = function () {
//obj.debug("Agent Redir Socket Closed");
if (obj.debugmode == 1) { console.log('onSocketClosed'); }
//if (obj.debugmode == 1) { console.log('onSocketClosed'); }
obj.Stop(1);
}
@ -192,6 +189,9 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
obj.Stop = function (x) {
if (obj.debugmode == 1) { console.log('stop', x); }
//obj.debug("Agent Redir Socket Stopped");
obj.webRtcActive = false;
obj.webrtc = null;
obj.webchannel = null;
obj.xxStateChange(0);
obj.connectstate = -1;
obj.xxCloseWebRTC();

View File

@ -647,6 +647,7 @@
var amtScanResults = null;
var debugmode = false;
var clickOnce = detectClickOnce();
var attemptWebRTC = false;
function startup() {
if ((features & 32) == 0) {
@ -2934,7 +2935,7 @@
desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort);
desktop.debugmode = debugmode;
desktop.m.debugmode = debugmode;
//desktop.attemptWebRTC = debugmode;
desktop.attemptWebRTC = attemptWebRTC;
desktop.onStateChanged = onDesktopStateChange;
desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best.
desktop.m.ScalingLevel = desktopsettings.scaling;
@ -2954,7 +2955,10 @@
function onDesktopStateChange(xdesktop, state) {
var xstate = state;
if ((xstate == 3) && (xdesktop.contype == 2)) { xstate++; }
QH('deskstatus', StatusStrs[xstate]);
var str = StatusStrs[xstate];
if (desktop.webRtcActive == true) { str += ', WebRTC'; }
//if (desktop.m.stopInput == true) { str += ', Loopback'; }
QH('deskstatus', str);
QE('deskSaveBtn', state == 3);
QV('deskFocusBtn', (desktop != null) && (desktop.contype == 2) && (state != 0) && (desktopsettings.showfocus));
QE('DeskCAD', state == 3);
@ -3143,7 +3147,9 @@
function onTerminalStateChange(xterminal, state) {
var xstate = state;
if ((xstate == 3) && (xterminal.contype == 2)) { xstate++; }
QH('termstatus', StatusStrs[xstate]);
var str = StatusStrs[xstate];
if (terminal.webRtcActive == true) { str += ', WebRTC'; }
QH('termstatus', str);
switch (state) {
case 0:
// Disconnected, clear the terminal
@ -3180,7 +3186,7 @@
terminal = CreateAgentRedirect(meshserver, CreateAmtRemoteTerminal('Term'), serverPublicNamePort);
terminal.debugmode = debugmode;
terminal.m.debugmode = debugmode;
//terminal.attemptWebRTC = debugmode;
terminal.attemptWebRTC = attemptWebRTC;
terminal.onStateChanged = onTerminalStateChange;
terminal.Start(terminalNode._id);
terminal.contype = 1;
@ -3251,7 +3257,9 @@
function onFilesStateChange(xfiles, state) {
p13Connect.value = (state == 0) ? 'Connect' : 'Disconnect';
Q('p13Status').textContent = StatusStrs[state];
var str = StatusStrs[state];
if (files.webRtcActive == true) { str += ', WebRTC'; }
Q('p13Status').textContent = str;
switch (state) {
case 0:
// Disconnected, clear the files
@ -3286,7 +3294,7 @@
if (!files) {
// Setup a mesh agent files
files = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotFiles), serverPublicNamePort);
files.attemptWebRTC = debugmode;
files.attemptWebRTC = false;
files.onStateChanged = onFilesStateChange;
files.Start(filesNode._id);
} else {
@ -3492,7 +3500,7 @@
// Called by the html page to start a download, arguments are: path, file name and file size.
function p13downloadfile(x, y, z) {
downloadFile = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotDownloadData), serverPublicNamePort); // Create our file transport
downloadFile.attemptWebRTC = debugmode;
downloadFile.attemptWebRTC = false;
downloadFile.onStateChanged = onFileDownloadStateChange;
downloadFile.xpath = decodeURIComponent(x);
downloadFile.xfile = decodeURIComponent(y);
@ -3571,7 +3579,7 @@
// Connect again
function p13uploadReconnect() {
uploadFile.ws = CreateAgentRedirect(meshserver, CreateRemoteFiles(p13gotUploadData), serverPublicNamePort);
uploadFile.ws.attemptWebRTC = debugmode;
uploadFile.ws.attemptWebRTC = false;
uploadFile.ws.onStateChanged = onFileUploadStateChange;
uploadFile.ws.Start(filesNode._id);
}