diff --git a/agents/MeshService.exe b/agents/MeshService.exe index dc5b99ae..257fa188 100644 Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ diff --git a/agents/MeshService64.exe b/agents/MeshService64.exe index 24c4032f..bfe22f32 100644 Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ diff --git a/agents/agent_debug/MeshService.exe b/agents/agent_debug/MeshService.exe new file mode 100644 index 00000000..257fa188 Binary files /dev/null and b/agents/agent_debug/MeshService.exe differ diff --git a/agents/agent_debug/MeshService64.exe b/agents/agent_debug/MeshService64.exe new file mode 100644 index 00000000..bfe22f32 Binary files /dev/null and b/agents/agent_debug/MeshService64.exe differ diff --git a/agents/meshcore.js b/agents/meshcore.js index 20f5b67c..14bac0d1 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -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 { @@ -506,28 +507,7 @@ function createMeshCore(agent) { if (len > 0) { this.write(buf.slice(0, len)); } else { fs.closeSync(this.httprequest.downloadFile); this.httprequest.downloadFile = undefined; this.end(); } 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 @@ -700,7 +660,49 @@ function createMeshCore(agent) { //sendConsoleText("Got tunnel #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid); } } - + + // 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 + ''; diff --git a/certoperations.js b/certoperations.js index 8ded6fc0..3500488a 100644 --- a/certoperations.js +++ b/certoperations.js @@ -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) { diff --git a/interceptor.js b/interceptor.js index d6330ae6..1c55262b 100644 --- a/interceptor.js +++ b/interceptor.js @@ -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 diff --git a/meshrelay.js b/meshrelay.js index fc72351e..019664fa 100644 --- a/meshrelay.js +++ b/meshrelay.js @@ -175,16 +175,16 @@ 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 diff --git a/package.json b/package.json index 9d12f037..a5ebf957 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.1.2-s", + "version": "0.1.2-t", "keywords": [ "Remote Management", "Intel AMT", diff --git a/public/scripts/agent-desktop-0.0.2.js b/public/scripts/agent-desktop-0.0.2.js index dc94d6e7..8ad4f92c 100644 --- a/public/scripts/agent-desktop-0.0.2.js +++ b/public/scripts/agent-desktop-0.0.2.js @@ -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); } diff --git a/public/scripts/agent-redir-ws-0.1.0.js b/public/scripts/agent-redir-ws-0.1.0.js index 94dd52f5..a815287d 100644 --- a/public/scripts/agent-redir-ws-0.1.0.js +++ b/public/scripts/agent-redir-ws-0.1.0.js @@ -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(); diff --git a/views/default.handlebars b/views/default.handlebars index 1629cdc7..c2b1cd66 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -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); }