Improved WebRTC support

This commit is contained in:
Ylian Saint-Hilaire 2018-01-18 15:43:43 -08:00
parent 92aaf754fb
commit 4106b322d6
16 changed files with 2854 additions and 128 deletions

View File

@ -44,7 +44,6 @@
<Compile Include="swarmserver.js" />
<Compile Include="multiserver.js" />
<Compile Include="pass.js" />
<Compile Include="public\relay.js" />
<Compile Include="public\scripts\amt-0.2.0.js" />
<Compile Include="public\scripts\agent-desktop-0.0.2.js" />
<Compile Include="public\scripts\amt-desktop-0.0.2.js" />
@ -58,7 +57,6 @@
<Compile Include="public\scripts\amt-wsman-ws-0.2.0.js" />
<Compile Include="public\scripts\common-0.0.1.js" />
<Compile Include="public\scripts\filesaver.1.1.20151003.js" />
<Compile Include="public\scripts\inflate.js" />
<Compile Include="public\scripts\meshcentral.js" />
<Compile Include="redirserver.js" />
<Compile Include="webserver.js" />
@ -119,8 +117,6 @@
<Content Include="public\images\mapmarker.png" />
<Content Include="public\images\meshicon50.png" />
<Content Include="public\images\trash.png" />
<Content Include="public\index.html" />
<Content Include="public\relay.htm" />
<Content Include="public\scriptblocks.txt" />
<Content Include="public\sounds\chimes.mp3" />
<Content Include="public\styles\font-awesome\css\font-awesome.min.css" />

Binary file not shown.

Binary file not shown.

View File

@ -36,6 +36,7 @@ function createMeshCore(agent) {
var wifiScanner = null;
var networkMonitor = null;
var amtscanner = null;
var nextTunnelIndex = 1;
/*
var AMTScanner = require("AMTScanner");
@ -337,7 +338,7 @@ function createMeshCore(agent) {
if (xurl != null) {
var woptions = http.parseUri(xurl);
woptions.rejectUnauthorized = 0;
sendConsoleText(JSON.stringify(woptions));
//sendConsoleText(JSON.stringify(woptions));
var tunnel = http.request(woptions);
tunnel.upgrade = onTunnelUpgrade;
tunnel.onerror = function (e) { sendConsoleText('ERROR: ' + JSON.stringify(e)); }
@ -349,10 +350,8 @@ function createMeshCore(agent) {
tunnel.tcpaddr = data.tcpaddr;
tunnel.tcpport = data.tcpport;
tunnel.end();
sendConsoleText('tunnel.end() called');
// Put the tunnel in the tunnels list
var index = 1;
while (tunnels[index]) { index++; }
var index = nextTunnelIndex++;;
tunnel.index = index;
tunnels[index] = tunnel;
@ -443,6 +442,7 @@ function createMeshCore(agent) {
this.s = s;
s.httprequest = this;
s.end = onTunnelClosed;
s.tunnel = this;
if (this.tcpport != null) {
// This is a TCP relay connection, pause now and try to connect to the target.
@ -472,6 +472,7 @@ function createMeshCore(agent) {
}
function onTunnelClosed() {
if (tunnels[this.httprequest.index] == null) return; // Stop duplicate calls.
sendConsoleText("Tunnel #" + this.httprequest.index + " closed.", this.httprequest.sessionid);
delete tunnels[this.httprequest.index];
@ -487,6 +488,21 @@ function createMeshCore(agent) {
// If there is a upload or download active on this connection, close the file
if (this.httprequest.uploadFile) { fs.closeSync(this.httprequest.uploadFile); this.httprequest.uploadFile = undefined; }
if (this.httprequest.downloadFile) { fs.closeSync(this.httprequest.downloadFile); this.httprequest.downloadFile = undefined; }
// Clean up WebRTC
if (this.webrtc != null) {
if (this.webrtc.rtcchannel) { try { this.webrtc.rtcchannel.close(); } catch (e) { } this.webrtc.rtcchannel.removeAllListeners('data'); this.webrtc.rtcchannel.removeAllListeners('end'); delete this.webrtc.rtcchannel; }
if (this.webrtc.websocket) { delete this.webrtc.websocket; }
try { this.webrtc.close(); } catch (e) { }
this.webrtc.removeAllListeners('connected');
this.webrtc.removeAllListeners('disconnected');
this.webrtc.removeAllListeners('dataChannel');
delete this.webrtc;
}
// Clean up WebSocket
this.removeAllListeners('data');
delete this;
}
function onTunnelSendOk() { sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid); }
function onTunnelData(data) {
@ -661,34 +677,71 @@ function createMeshCore(agent) {
}
}
// Attempt to setup and switch the tunnel over to WebRTC
// Called when receiving control data on WebRTC
function onTunnelWebRTCControlData(data) {
if (typeof data != 'string') return;
var obj;
try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC'); return; }
if (obj.type == 'close') {
sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
try { this.close(); } catch (e) { }
try { this.xrtc.close(); } catch (e) { }
}
}
// Called when receiving control data on websocket
function onTunnelControlData(data) {
sendConsoleText('onTunnelControlData: ' + data);
var obj = JSON.parse(data);
if (obj.type == 'offer') {
if (typeof data != 'string') return;
//sendConsoleText('onTunnelControlData: ' + data);
//console.log('onTunnelControlData: ' + data);
var obj;
try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON'); return; }
if (obj.type == 'close') {
// We received the close on the websocket
sendConsoleText('Tunnel #' + this.tunnel.index + ' WebSocket control close');
try { this.close(); } catch (e) { }
} else if (obj.type == 'webrtc1') {
this.write("{\"type\":\"webrtc2\"}"); // Indicates we will no longer get any data on websocket, switching to WebRTC at this point.
if (this.httprequest.protocol == 1) { // Terminal
// Switch the user input from websocket to webrtc at this point.
this.unpipe(this.httprequest.process.stdin);
this.rtcchannel.pipe(this.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
this.resume(); // Resume the websocket to keep receiving control data
} else if (this.httprequest.protocol == 2) { // Desktop
// Switch the user input from websocket to webrtc at this point.
this.unpipe(this.httprequest.desktop.kvm);
this.webrtc.rtcchannel.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
this.resume(); // Resume the websocket to keep receiving control data
}
} else if (obj.type == 'webrtc2') {
// Other side received websocket end of data marker, start sending data on WebRTC channel
if (this.httprequest.protocol == 1) { // Terminal
this.httprequest.process.stdout.pipe(this.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
} else if (this.httprequest.protocol == 2) { // Desktop
this.httprequest.desktop.kvm.pipe(this.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
}
} else 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('connected', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected'); });
this.webrtc.on('disconnected', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected'); });
this.webrtc.on('dataChannel', function (rtcchannel) {
sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
//sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
rtcchannel.xrtc = this;
this.rtcchannel = rtcchannel;
this.rtcchannel.on('data', onTunnelWebRTCControlData);
this.rtcchannel.on('end', function () { sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed'); });
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.
// This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
this.websocket.httprequest.process.stdout.unpipe(this.websocket);
this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
} 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.
// This is a KVM data stream, unpipe the KVM now and indicate to the other side that KVM data will no longer be received over WebSocket
this.websocket.httprequest.desktop.kvm.unpipe(this.websocket);
this.websocket.write("{\"type\":\"webrtc1\"}"); // End of data marker
}
/*
else {

View File

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

View File

@ -1133,6 +1133,7 @@ var CreateAmtRedirect = function (module) {
obj.user = null;
obj.pass = null;
obj.authuri = "/RedirectionService";
obj.tlsv1only = 0;
obj.connectstate = 0;
obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER
@ -1152,7 +1153,7 @@ var CreateAmtRedirect = function (module) {
obj.user = user;
obj.pass = pass;
obj.connectstate = 0;
obj.socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/webrelay.ashx?p=2&host=" + host + "&port=" + port + "&tls=" + tls + ((user == '*') ? "&serverauth=1" : "") + ((typeof pass === "undefined") ? ("&serverauth=1&user=" + user) : "")); // The "p=2" indicates to the relay that this is a REDIRECTION session
obj.socket = new WebSocket(window.location.protocol.replace("http", "ws") + "//" + window.location.host + window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/')) + "/webrelay.ashx?p=2&host=" + host + "&port=" + port + "&tls=" + tls + ((user == '*') ? "&serverauth=1" : "") + ((typeof pass === "undefined") ? ("&serverauth=1&user=" + user) : "") + "&tls1only=" + obj.tlsv1only); // The "p=2" indicates to the relay that this is a REDIRECTION session
obj.socket.onopen = obj.xxOnSocketConnected;
obj.socket.onmessage = obj.xxOnMessage;
obj.socket.onclose = obj.xxOnSocketClosed;
@ -33060,7 +33061,7 @@ if (typeof module !== "undefined" && module.exports) {
});
}
var version = '0.5.7';
var version = '0.5.8';
var urlvars = null;
var amtstack;
var wsstack = null;

10
public/samples/relay.htm Normal file
View File

@ -0,0 +1,10 @@
<html>
<head>
<script type="text/javascript" src="relay.js"></script>
</head>
<body>
<script>
var relay = createMeshConnection('0D49FDEFFB778D40C062DD34A3E96113:1485387591408:b2970207326684b4de5375d097db23c85e64497eaa72013b56a8ecd8063fb9b3').connect();
</script>
</body>
</html>

48
public/samples/relay.js Normal file
View File

@ -0,0 +1,48 @@
/**
* @fileoverview Dynamic interface to MeshCentral2
* @author Ylian Saint-Hilaire
* @version v0.0.1
*/
var createMeshConnection = function (connectionId) {
var obj = {};
obj.connectionId = connectionId;
obj.state = 0;
obj.websocket = null;
obj.onStateChanged = null;
obj.onData = null;
obj.connect = function () {
if (obj.state == 0) {
obj.websocket = new WebSocket(window.location.protocol.replace('http', 'ws') + '//' + window.location.host + '/meshrelay.ashx?id=' + obj.connectionId);
obj.websocket.binaryType = "arraybuffer";
obj.websocket.onopen = function (e) { console.log('WebSocket Connected', e); };
obj.websocket.onmessage = function (e) {
console.log('WebSocket Message', e);
if ((obj.state = 1) && (e.data == 'c')) {
obj.state = 2;
if (obj.onStateChanged) { onStateChanged(obj, 2); }
console.log('WebSocket Peer Connection', e);
obj.send('bob');
} else {
if (obj.onData != null) { obj.onData(obj, e.data); }
}
};
obj.websocket.onclose = function (e) {
console.log('WebSocket Closed', e);
obj.state = 0;
if (obj.onStateChanged) { onStateChanged(obj, 0); }
};
obj.websocket.onerror = function (e) { console.log('WebSocket Error', e); };
obj.state = 1;
if (obj.onStateChanged) { onStateChanged(obj, 1); }
}
return obj;
};
obj.send = function (data) {
if ((obj.state == 2) && (obj.websocket != null)) { obj.websocket.send(data); }
};
return obj;
}

View File

@ -93,15 +93,18 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
obj.ProcessPictureMsg = function (str, X, Y) {
//if (obj.targetnode != null) obj.Debug("ProcessPictureMsg " + X + "," + Y + " - " + obj.targetnode.substring(0, 8));
var tile = new Image();
obj.tilesReceived++;
tile.xcount = obj.tilesReceived++;
//console.log('Tile #' + tile.xcount);
var r = obj.tilesReceived;
tile.src = "data:image/jpeg;base64," + btoa(str.substring(4, str.length));
tile.onload = function () {
//console.log('DecodeTile #' + this.xcount);
if (obj.Canvas != null && obj.KillDraw < r && obj.State != 0) {
obj.PendingOperations.push([r, 2, tile, X, Y]);
while (obj.DoPendingOperations()) { }
}
}
tile.error = function () { console.log('DecodeTileError'); }
}
obj.DoPendingOperations = function () {

View File

@ -50,17 +50,25 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) {
// Called to pass websocket control messages
obj.xxOnControlCommand = function (msg) {
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);
var controlMsg;
try { controlMsg = JSON.parse(msg); } catch (e) { return; }
if (obj.webrtc != null) {
if (controlMsg.type == 'answer') {
obj.webrtc.setRemoteDescription(new RTCSessionDescription(controlMsg), function () { /*console.log('WebRTC remote ok');*/ }, obj.xxCloseWebRTC);
} else if (controlMsg.type == 'webrtc1') {
obj.socket.send("{\"type\":\"webrtc2\"}"); // Confirm we got end of data marker, indicates data will no longer be received on websocket.
} else if (controlMsg.type == 'webrtc2') {
// TODO: Resume/Start sending data over WebRTC
}
}
}
// Close the WebRTC connection, should be called if a problem occurs during WebRTC setup.
obj.xxCloseWebRTC = function () {
if (obj.webchannel != null) { obj.webchannel.close(); obj.webchannel = null; }
if (obj.webrtc != null) { obj.webrtc.close(); obj.webrtc = null; }
try { obj.webchannel.send("{\"type\":\"close\"}"); } catch (e) { }
if (obj.webchannel != null) { try { obj.webchannel.close(); } catch (e) { } obj.webchannel = null; }
if (obj.webrtc != null) { try { obj.webrtc.close(); } catch (e) { } obj.webrtc = null; }
obj.webRtcActive = false;
}
obj.xxOnMessage = function (e) {
@ -78,23 +86,22 @@ 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.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.webchannel.onmessage = function (event) { obj.xxOnMessage({ data: event.data }); };
obj.webchannel.onopen = function () {
obj.webRtcActive = true;
obj.socket.send("{\"type\":\"webrtc1\"}"); // Indicate to the other side that data traffic will no longer be sent over websocket.
// TODO: Hold/Stop sending data over websocket
if (obj.onStateChanged != null) { obj.onStateChanged(obj, obj.State); }
};
obj.webchannel.onclose = function (event) { console.log('WebRTC close'); 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
} 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('WebRTC ICE', obj.webrtc.iceConnectionState);
if ((obj.webrtc.iceConnectionState == 'disconnected') || (obj.webrtc.iceConnectionState == 'failed')) { obj.xxCloseWebRTC(); }
}
}
obj.webrtc.oniceconnectionstatechange = function () { if (obj.webrtc != null) { if ((obj.webrtc.iceConnectionState == 'disconnected') || (obj.webrtc.iceConnectionState == 'failed')) { obj.xxCloseWebRTC(); } } }
obj.webrtc.createOffer(function (offer) {
// Got the offer
obj.webrtcoffer = offer;
@ -189,13 +196,14 @@ 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();
if (obj.socket != null) { obj.socket.close(); obj.socket = null; }
if (obj.socket != null) {
try { obj.socket.send("{\"type\":\"close\"}"); } catch (e) { }
try { obj.socket.close(); } catch (e) { }
obj.socket = null;
}
obj.xxStateChange(0);
}
return obj;

View File

@ -23,6 +23,8 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.useZRLE = true;
obj.showmouse = true;
obj.buttonmask = 0;
//obj.inbytes = 0;
//obj.outbytes = 0;
obj.spare = null;
obj.sparew = 0;
obj.spareh = 0;
@ -33,9 +35,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.onScreenSizeChange = null;
obj.frameRateDelay = 0;
// ###BEGIN###{DesktopRotation}
obj.noMouseRotate = false;
obj.rotation = 0;
// ###END###{DesktopRotation}
// ###BEGIN###{DesktopFocus}
obj.mx = 0; // Last mouse x position
obj.my = 0; // Last mouse y position
@ -43,10 +46,13 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.oy = -1; // Old mouse y position
obj.focusmode = 0;
// ###END###{DesktopFocus}
// ###BEGIN###{Inflate}
obj.inflate = ZLIB.inflateInit(-15);
// ###END###{Inflate}
// Private method
obj.Debug = function (msg) { console.log(msg); }
obj.xxStateChange = function (newstate) {
if (newstate == 0) {
obj.canvas.fillStyle = '#000000';
@ -58,10 +64,12 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (!obj.showmouse) { QS(obj.canvasid).cursor = 'none'; }
}
}
obj.ProcessData = function (data) {
if (!data) return;
// obj.Debug("KRecv(" + data.length + "): " + rstr2hex(data));
//obj.inbytes += data.length;
//obj.Debug("KRecv(" + obj.inbytes + ")");
obj.acc += data;
while (obj.acc.length > 0) {
//obj.Debug("KAcc(" + obj.acc.length + "): " + rstr2hex(obj.acc));
@ -90,12 +98,15 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
else if (obj.state == 3 && obj.acc.length >= 24) {
// Getting server init
// ###BEGIN###{DesktopRotation}
obj.rotation = 0; // We don't currently support screen init while rotated.
// ###END###{DesktopRotation}
var namelen = ReadInt(obj.acc, 20);
if (obj.acc.length < 24 + namelen) return;
cmdsize = 24 + namelen;
obj.canvas.canvas.width = obj.rwidth = obj.width = obj.ScreenWidth = ReadShort(obj.acc, 0);
obj.canvas.canvas.height = obj.rheight = obj.height = obj.ScreenHeight = ReadShort(obj.acc, 2);
// These are all values we don't really need, we are going to only run in RGB565 or RGB332 and not use the flexibility provided by these settings.
// Makes the javascript code smaller and maybe a bit faster.
/*
@ -126,22 +137,22 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var supportedEncodings = '';
if (obj.useZRLE) supportedEncodings += IntToStr(16);
supportedEncodings += IntToStr(0);
obj.Send(String.fromCharCode(2, 0) + ShortToStr((supportedEncodings.length / 4) + 1) + supportedEncodings + IntToStr(-223)); // Supported Encodings + Desktop Size
// Set the pixel encoding to something much smaller
// obj.Send(String.fromCharCode(0, 0, 0, 0, 16, 16, 0, 1) + ShortToStr(31) + ShortToStr(63) + ShortToStr(31) + String.fromCharCode(11, 5, 0, 0, 0, 0)); // Setup 16 bit color RGB565 (This is the default, so we don't need to set it)
if (obj.bpp == 1) obj.Send(String.fromCharCode(0, 0, 0, 0, 8, 8, 0, 1) + ShortToStr(7) + ShortToStr(7) + ShortToStr(3) + String.fromCharCode(5, 2, 0, 0, 0, 0)); // Setup 8 bit color RGB332
obj.state = 4;
obj.parent.xxStateChange(3);
_SendRefresh();
//obj.timer = setInterval(obj.xxOnTimer, 50);
// ###BEGIN###{DesktopFocus}
obj.ox = -1; // Old mouse x position
// ###END###{DesktopFocus}
if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); }
}
else if (obj.state == 4) {
@ -161,10 +172,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
height = ReadShort(obj.acc, 6),
s = width * height,
encoding = ReadInt(obj.acc, 8);
if (encoding < 17) {
if (width < 1 || width > 64 || height < 1 || height > 64) { console.log("Invalid tile size (" + width + "," + height + "), disconnecting."); return obj.Stop(); }
// Set the spare bitmap to the rigth size if it's not already. This allows us to recycle the spare most if not all the time.
if (obj.sparew != width || obj.spareh != height) {
obj.sparew = obj.sparew2 = width;
@ -178,7 +189,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
}
if (encoding == 0xFFFFFF21) {
// Desktop Size (0xFFFFFF21, -223)
obj.canvas.canvas.width = obj.rwidth = obj.width = width;
@ -193,7 +204,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var ptr = 12, cs = 12 + (s * obj.bpp);
if (obj.acc.length < cs) return; // Check we have all the data needed and we can only draw 64x64 tiles.
cmdsize = cs;
// CRITICAL LOOP, optimize this as much as possible
for (var i = 0; i < s; i++) { _setPixel(obj.acc.charCodeAt(ptr++) + ((obj.bpp == 2) ? (obj.acc.charCodeAt(ptr++) << 8) : 0), i); }
_putImage(obj.spare, x, y);
@ -205,23 +216,22 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.acc.length < (16 + datalen)) return;
//obj.Debug("RECT ZRLE (" + x + "," + y + "," + width + "," + height + ") LEN = " + datalen);
//obj.Debug("RECT ZRLE LEN: " + ReadShortX(obj.acc, 17) + ", DATA: " + rstr2hex(obj.acc.substring(16)));
// Process the ZLib header if this is the first block
var ptr = 16, delta = 5, dx = 0;
if (obj.ZRLEfirst == 1) { obj.ZRLEfirst = 0; ptr += 2; delta = 7; dx = 2; } // Skip the ZLib header
if (datalen > 5 && obj.acc.charCodeAt(ptr) == 0 && ReadShortX(obj.acc, ptr + 1) == (datalen - delta)) {
// This is an uncompressed ZLib data block
_decodeLRE(obj.acc, ptr + 5, x, y, width, height, s, datalen);
}
// ###BEGIN###{Inflate}
// ###BEGIN###{Inflate}
else {
// This is compressed ZLib data, decompress and process it.
var arr = inflate(obj.acc.substring(ptr, ptr + datalen - dx));
if (arr.length > 0) { _decodeLRE(String.fromCharCode.apply(null, new Uint8Array(arr)), 0, x, y, width, height, s, arr.length); } else { obj.Debug("Invalid deflate data"); }
var arr = obj.inflate.inflate(obj.acc.substring(ptr, ptr + datalen - dx));
if (arr.length > 0) { _decodeLRE(arr, 0, x, y, width, height, s, arr.length); } else { obj.Debug("Invalid deflate data"); }
}
// ###END###{Inflate}
cmdsize = 16 + datalen;
}
else {
@ -237,12 +247,12 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
}
}
if (cmdsize == 0) return;
obj.acc = obj.acc.substring(cmdsize);
}
}
function _decodeLRE(data, ptr, x, y, width, height, s, datalen) {
var subencoding = data.charCodeAt(ptr++), index, v, runlengthdecode, palette = {}, rlecount = 0, runlength = 0, i;
// obj.Debug("RECT RLE (" + (datalen - 5) + ", " + subencoding + "):" + rstr2hex(data.substring(21, 21 + (datalen - 5))));
@ -255,23 +265,23 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
// Solid color tile
v = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0);
obj.canvas.fillStyle = 'rgb(' + ((obj.bpp == 1) ? ((v & 224) + ',' + ((v & 28) << 3) + ',' + _fixColor((v & 3) << 6)) : (((v >> 8) & 248) + ',' + ((v >> 3) & 252) + ',' + ((v & 31) << 3))) + ')';
// ###BEGIN###{DesktopRotation}
var xx = _rotX(x, y);
y = _rotY(x, y);
x = xx;
// ###END###{DesktopRotation}
obj.canvas.fillRect(x, y, width, height);
}
else if (subencoding > 1 && subencoding < 17) { // Packed palette encoded tile
// Read the palette
var br = 4, bm = 15; // br is BitRead and bm is BitMask. By adjusting these two we can support all the variations in this encoding.
for (i = 0; i < subencoding; i++) { palette[i] = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0); }
// Compute bits to read & bit mark
if (subencoding == 2) { br = 1; bm = 1; } else if (subencoding <= 4) { br = 2; bm = 3; }
// Display all the bits
while (rlecount < s && ptr < data.length) { v = data.charCodeAt(ptr++); for (i = (8 - br) ; i >= 0; i -= br) { _setPixel(palette[(v >> i) & bm], rlecount++); } }
_putImage(obj.spare, x, y);
@ -280,10 +290,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
while (rlecount < s && ptr < data.length) {
// Get the run color
v = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0);
// Decode the run length. This is the fastest and most compact way I found to do this.
runlength = 1; do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255);
// Draw a run
while (--runlength >= 0) { _setPixel(v, rlecount++); }
}
@ -292,22 +302,22 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
else if (subencoding > 129) { // Palette RLE encoded tile
// Read the palette
for (i = 0; i < (subencoding - 128) ; i++) { palette[i] = data.charCodeAt(ptr++) + ((obj.bpp == 2) ? (data.charCodeAt(ptr++) << 8) : 0); }
// Decode RLE on palette
while (rlecount < s && ptr < data.length) {
// Setup the run, get the color index and get the color from the palette.
runlength = 1; index = data.charCodeAt(ptr++); v = palette[index % 128];
// If the index starts with high order bit 1, this is a run and decode the run length.
if (index > 127) { do { runlength += (runlengthdecode = data.charCodeAt(ptr++)); } while (runlengthdecode == 255); }
// Draw a run
while (--runlength >= 0) { _setPixel(v, rlecount++); }
}
_putImage(obj.spare, x, y);
}
}
function _putImage(i, x, y) {
// ###BEGIN###{DesktopRotation}
var xx = _arotX(x, y);
@ -316,10 +326,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
// ###END###{DesktopRotation}
obj.canvas.putImageData(i, x, y);
}
function _setPixel(v, p) {
var pp = p * 4;
// ###BEGIN###{DesktopRotation}
if (obj.rotation > 0) {
if (obj.rotation == 1) {
@ -337,7 +347,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
}
// ###END###{DesktopRotation}
if (obj.bpp == 1) {
// Set 8bit color RGB332
obj.spare.data[pp++] = v & 224;
@ -351,7 +361,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
obj.spare.data[pp] = 0xFF; // Set alpha channel to opaque.
}
// ###BEGIN###{DesktopRotation}
function _arotX(x, y) {
if (obj.rotation == 0) return x;
@ -360,7 +370,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return y;
return 0;
}
function _arotY(x, y) {
if (obj.rotation == 0) return y;
if (obj.rotation == 1) return x;
@ -368,7 +378,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return obj.canvas.canvas.height - obj.spareh - x;
return 0;
}
function _crotX(x, y) {
if (obj.rotation == 0) return x;
if (obj.rotation == 1) return y;
@ -376,7 +386,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return obj.canvas.canvas.height - y;
return 0;
}
function _crotY(x, y) {
if (obj.rotation == 0) return y;
if (obj.rotation == 1) return obj.canvas.canvas.width - x;
@ -384,7 +394,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return x;
return 0;
}
function _rotX(x, y) {
if (obj.rotation == 0) return x;
if (obj.rotation == 1) return x;
@ -392,7 +402,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return x - obj.canvas.canvas.height;
return 0;
}
function _rotY(x, y) {
if (obj.rotation == 0) return y;
if (obj.rotation == 1) return y - obj.canvas.canvas.width;
@ -400,7 +410,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 3) return y;
return 0;
}
obj.tcanvas = null;
obj.setRotation = function (x) {
while (x < 0) { x += 4; }
@ -409,7 +419,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var rw = obj.canvas.canvas.width;
var rh = obj.canvas.canvas.height;
if (obj.rotation == 1 || obj.rotation == 3) { rw = obj.canvas.canvas.height; rh = obj.canvas.canvas.width; }
// Copy the canvas, put it back in the correct direction
if (obj.tcanvas == null) obj.tcanvas = document.createElement('canvas');
var tcanvasctx = obj.tcanvas.getContext('2d');
@ -421,7 +431,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
if (obj.rotation == 1) tcanvasctx.drawImage(obj.canvas.canvas, -obj.canvas.canvas.width, 0);
if (obj.rotation == 2) tcanvasctx.drawImage(obj.canvas.canvas, -obj.canvas.canvas.width, -obj.canvas.canvas.height);
if (obj.rotation == 3) tcanvasctx.drawImage(obj.canvas.canvas, 0, -obj.canvas.canvas.height);
// Change the size and orientation and copy the canvas back into the rotation
if (obj.rotation == 0 || obj.rotation == 2) { obj.canvas.canvas.height = rw; obj.canvas.canvas.width = rh; }
if (obj.rotation == 1 || obj.rotation == 3) { obj.canvas.canvas.height = rh; obj.canvas.canvas.width = rw; }
@ -429,16 +439,16 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.canvas.rotate((newrotation * 90) * Math.PI / 180);
obj.rotation = newrotation;
obj.canvas.drawImage(obj.tcanvas, _rotX(0, 0), _rotY(0, 0));
obj.width = obj.canvas.canvas.width;
obj.height = obj.canvas.canvas.height;
if (obj.onScreenResize != null) obj.onScreenResize(obj, obj.width, obj.height, obj.CanvasId);
return true;
}
// ###END###{DesktopRotation}
function _fixColor(c) { return (c > 127) ? (c + 32) : c; }
function _SendRefresh() {
// ###BEGIN###{DesktopFocus}
if (obj.focusmode > 0) {
@ -447,34 +457,40 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.Send(String.fromCharCode(3, 1) + ShortToStr(Math.max(Math.min(obj.ox, obj.mx) - obj.focusmode, 0)) + ShortToStr(Math.max(Math.min(obj.oy, obj.my) - obj.focusmode, 0)) + ShortToStr(df + Math.abs(obj.ox - obj.mx)) + ShortToStr(df + Math.abs(obj.oy - obj.my))); // FramebufferUpdateRequest
obj.ox = obj.mx;
obj.oy = obj.my;
} else
// ###END###{DesktopFocus} {
} else {
// ###END###{DesktopFocus}
// Request the entire screen
obj.Send(String.fromCharCode(3, 1, 0, 0, 0, 0) + ShortToStr(obj.rwidth) + ShortToStr(obj.rheight)); // FramebufferUpdateRequest
// ###BEGIN###{DesktopFocus}
}
// ###END###{DesktopFocus}
}
obj.Start = function () {
//obj.Debug("KVM-Start");
obj.state = 0;
obj.acc = "";
obj.ZRLEfirst = 1;
//obj.inbytes = 0;
//obj.outbytes = 0;
// ###BEGIN###{Inflate}
inflate_start();
obj.inflate.inflateReset();
// ###END###{Inflate}
for (var i in obj.sparecache) { delete obj.sparecache[i]; }
}
obj.Stop = function () {
obj.UnGrabMouseInput();
obj.UnGrabKeyInput();
obj.parent.Stop();
}
obj.Send = function (x) {
//obj.Debug("KSend(" + x.length + "): " + rstr2hex(x));
//obj.outbytes += x.length;
obj.parent.Send(x);
}
/*
Intel AMT only recognizes a small subset of keysym characters defined in the keysymdef.h so you dont need to
implement all the languages (this is taken care by the USB Scancode Extension in RFB4.0 protocol).
@ -535,9 +551,9 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.sendkey(kk, d);
return obj.haltEvent(e);
}
obj.sendkey = function (k, d) { obj.Send(String.fromCharCode(4, d, 0, 0) + IntToStr(k)); }
obj.SendCtrlAltDelMsg = function () { obj.sendcad(); }
obj.sendcad = function () {
obj.sendkey(0xFFE3, 1); // Control
@ -547,10 +563,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
obj.sendkey(0xFFE9, 0); // Alt
obj.sendkey(0xFFE3, 0); // Control
}
var _MouseInputGrab = false;
var _KeyInputGrab = false;
obj.GrabMouseInput = function () {
if (_MouseInputGrab == true) return;
var c = obj.canvas.canvas;
@ -560,7 +576,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
//if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = obj.xxDOMMouseScroll; else c.onmousewheel = obj.xxMouseWheel;
_MouseInputGrab = true;
}
obj.UnGrabMouseInput = function () {
if (_MouseInputGrab == false) return;
var c = obj.canvas.canvas;
@ -570,7 +586,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
//if (navigator.userAgent.match(/mozilla/i)) c.DOMMouseScroll = null; else c.onmousewheel = null;
_MouseInputGrab = false;
}
obj.GrabKeyInput = function () {
if (_KeyInputGrab == true) return;
document.onkeyup = obj.handleKeyUp;
@ -578,7 +594,7 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
document.onkeypress = obj.handleKeys;
_KeyInputGrab = true;
}
obj.UnGrabKeyInput = function () {
if (_KeyInputGrab == false) return;
document.onkeyup = null;
@ -586,12 +602,12 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
document.onkeypress = null;
_KeyInputGrab = false;
}
obj.handleKeys = function (e) { return obj.haltEvent(e); }
obj.handleKeyUp = function (e) { return _keyevent(0, e); }
obj.handleKeyDown = function (e) { return _keyevent(1, e); }
obj.haltEvent = function (e) { if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); return false; }
// RFB "PointerEvent" and mouse handlers
obj.mousedown = function (e) { obj.buttonmask |= (1 << e.button); return obj.mousemove(e); }
obj.mouseup = function (e) { obj.buttonmask &= (0xFFFF - (1 << e.button)); return obj.mousemove(e); }
@ -600,15 +616,17 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
var pos = obj.getPositionOfControl(Q(obj.canvasid));
obj.mx = (e.pageX - pos[0]) * (obj.canvas.canvas.height / Q(obj.canvasid).offsetHeight);
obj.my = ((e.pageY - pos[1] + (scrolldiv ? scrolldiv.scrollTop : 0)) * (obj.canvas.canvas.width / Q(obj.canvasid).offsetWidth));
// ###BEGIN###{DesktopRotation}
obj.mx2 = _crotX(obj.mx, obj.my);
obj.my = _crotY(obj.mx, obj.my);
obj.mx = obj.mx2;
if (obj.noMouseRotate != true) {
obj.mx2 = _crotX(obj.mx, obj.my);
obj.my = _crotY(obj.mx, obj.my);
obj.mx = obj.mx2;
}
// ###END###{DesktopRotation}
obj.Send(String.fromCharCode(5, obj.buttonmask) + ShortToStr(obj.mx) + ShortToStr(obj.my));
// ###BEGIN###{DesktopFocus}
// Update focus area if we are in focus mode
QV('DeskFocus', obj.focusmode);
@ -627,11 +645,10 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
q.height = ((df * qx) - 6) + 'px';
}
// ###END###{DesktopFocus}
return obj.haltEvent(e);
}
obj.mousewheel = function (e) { }
obj.getPositionOfControl = function (Control) {
var Position = Array(2);
Position[0] = Position[1] = 0;
@ -642,6 +659,6 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) {
}
return Position;
}
return obj;
}

View File

@ -0,0 +1,279 @@
/* zlib-adler32.js -- JavaScript implementation for the zlib adler32.
Version: 0.2.0
LastModified: Apr 12 2012
Copyright (C) 2012 Masanao Izumo <iz@onicos.co.jp>
API documentation
==============================================================================
Usage: adler = ZLIB.adler32(adler, buf, offset, len);
Update a running Adler-32 checksum with the bytes buf[offset..offset+len-1] and
return the updated checksum. If buf is null, this function returns the
required initial value for the checksum.
An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
much faster.
Usage example:
var adler = ZLIB.adler32(0, null, 0, 0);
while (read_buffer(buffer, length) != EOF) {
adler = ZLIB.adler32(adler, buffer, 0, length);
}
if (adler != original_adler) error();
==============================================================================
Usage: adler = ZLIB.adler32_combine(adler1, adler2, len2);
Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note
that the z_off_t type (like off_t) is a signed integer. If len2 is
negative, the result has no meaning or utility.
*/
if( typeof ZLIB === 'undefined' ) {
alert('ZLIB is not defined. SRC zlib.js before zlib-adler32.js')
}
(function() {
/* adler32.c -- compute the Adler-32 checksum of a data stream
* Copyright (C) 1995-2011 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
var BASE = 65521; /* largest prime smaller than 65536 */
var NMAX = 5552;
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
/* ========================================================================= */
function adler32_string(adler, buf, offset, len)
{
var sum2;
var n;
/* split Adler-32 into component sums */
sum2 = (adler >>> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (len == 1) {
adler += buf.charCodeAt(offset) & 0xff;
if (adler >= BASE)
adler -= BASE;
sum2 += adler;
if (sum2 >= BASE)
sum2 -= BASE;
return adler | (sum2 << 16);
}
/* initial Adler-32 value (deferred check for len == 1 speed) */
if (buf === null)
return 1;
/* in case short lengths are provided, keep it somewhat fast */
if (len < 16) {
while (len--) {
adler += buf.charCodeAt(offset++) & 0xff;
sum2 += adler;
}
if (adler >= BASE)
adler -= BASE;
sum2 %= BASE; /* only added so many BASE's */
return adler | (sum2 << 16);
}
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
n = NMAX >> 4; /* NMAX is divisible by 16 */
do {
/* 16 sums unrolled */
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
} while (--n);
adler %= BASE;
sum2 %= BASE;
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if (len) { /* avoid modulos if none remaining */
while (len >= 16) {
len -= 16;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
}
while (len--) {
adler += buf.charCodeAt(offset++) & 0xff; sum2 += adler;
}
adler %= BASE;
sum2 %= BASE;
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
function adler32_array(adler, buf, offset, len)
{
var sum2;
var n;
/* split Adler-32 into component sums */
sum2 = (adler >>> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (len == 1) {
adler += buf[offset];
if (adler >= BASE)
adler -= BASE;
sum2 += adler;
if (sum2 >= BASE)
sum2 -= BASE;
return adler | (sum2 << 16);
}
/* initial Adler-32 value (deferred check for len == 1 speed) */
if (buf === null)
return 1;
/* in case short lengths are provided, keep it somewhat fast */
if (len < 16) {
while (len--) {
adler += buf[offset++];
sum2 += adler;
}
if (adler >= BASE)
adler -= BASE;
sum2 %= BASE; /* only added so many BASE's */
return adler | (sum2 << 16);
}
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
n = NMAX >> 4; /* NMAX is divisible by 16 */
do {
/* 16 sums unrolled */
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
} while (--n);
adler %= BASE;
sum2 %= BASE;
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if (len) { /* avoid modulos if none remaining */
while (len >= 16) {
len -= 16;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
adler += buf[offset++]; sum2 += adler;
}
while (len--) {
adler += buf[offset++]; sum2 += adler;
}
adler %= BASE;
sum2 %= BASE;
}
/* return recombined sums */
return adler | (sum2 << 16);
}
/* ========================================================================= */
ZLIB.adler32 = function(adler, buf, offset, len)
{
if(typeof buf === 'string') {
return adler32_string(adler, buf, offset, len);
} else {
return adler32_array(adler, buf, offset, len);
}
};
ZLIB.adler32_combine = function(adler1, adler2, len2)
{
var sum1;
var sum2;
var rem;
/* for negative len, return invalid adler32 as a clue for debugging */
if (len2 < 0)
return 0xffffffff;
/* the derivation of this formula is left as an exercise for the reader */
len2 %= BASE; /* assumes len2 >= 0 */
rem = len2;
sum1 = adler1 & 0xffff;
sum2 = rem * sum1;
sum2 %= BASE;
sum1 += (adler2 & 0xffff) + BASE - 1;
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE;
if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
}());

View File

@ -0,0 +1,246 @@
/* zlib-adler32.js -- JavaScript implementation for the zlib crc32.
Version: 0.2.0
LastModified: Apr 12 2012
Copyright (C) 2012 Masanao Izumo <iz@onicos.co.jp>
API documentation
==============================================================================
Usage: crc = ZLIB.crc32(crc, buf, offset, len);
Update a running CRC-32 with the bytes buf[offset..offset+len-1] and return the
updated CRC-32. If buf is null, this function returns the required
initial value for the for the crc. Pre- and post-conditioning (one's
complement) is performed within this function so it shouldn't be done by the
application.
Usage example:
var crc = ZLIB.crc32(0, null, 0, 0);
while (read_buffer(buffer, length) != EOF) {
crc = ZLIB.crc32(crc, buffer, 0, length);
}
if (crc != original_crc) error();
==============================================================================
Usage: crc = crc32_combine(crc1, crc2, len2);
Combine two CRC-32 check values into one. For two sequences of bytes,
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
len2.
*/
if( typeof ZLIB === 'undefined' ) {
alert('ZLIB is not defined. SRC zlib.js before zlib-crc32.js')
}
(function() {
/* crc32.c -- compute the CRC-32 of a data stream
* Copyright (C) 1995-2006, 2010, 2011 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*
* Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
* CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
* tables for updating the shift register in one step with three exclusive-ors
* instead of four steps with four exclusive-ors. This results in about a
* factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
*/
var crc_table = [
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0x2d02ef8d ];
/* ========================================================================= */
function crc32_string(crc, buf, offset, len)
{
if (buf == null) return 0;
crc = crc ^ 0xffffffff;
while (len >= 8) {
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
len -= 8;
}
if (len) do {
crc = crc_table[(crc ^ buf.charCodeAt(offset++)) & 0xff] ^ (crc >>> 8)
} while (--len);
return crc ^ 0xffffffff;
}
/* ========================================================================= */
function crc32_array(crc, buf, offset, len)
{
if (buf == null) return 0;
crc = crc ^ 0xffffffff;
while (len >= 8) {
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
len -= 8;
}
if (len) do {
crc = crc_table[(crc ^ buf[offset++]) & 0xff] ^ (crc >>> 8)
} while (--len);
return crc ^ 0xffffffff;
}
/* ========================================================================= */
ZLIB.crc32 = function(crc, buf, offset, len)
{
if(typeof buf === 'string') {
return crc32_string(crc, buf, offset, len);
} else {
return crc32_array(crc, buf, offset, len);
}
};
/* ========================================================================= */
var GF2_DIM = 32; /* dimension of GF(2) vectors (length of CRC) */
/* ========================================================================= */
function gf2_matrix_times(mat, vec)
{
var sum;
var mat_i = 0;
sum = 0;
while (vec) {
if (vec & 1)
sum ^= mat[mat_i];
vec >>= 1;
mat_i++;
}
return sum;
}
/* ========================================================================= */
function gf2_matrix_square(square, mat)
{
var n;
for (n = 0; n < GF2_DIM; n++)
square[n] = gf2_matrix_times(mat, mat[n]);
}
/* ========================================================================= */
ZLIB.crc32_combine = function(crc1, crc2, len2)
{
var n;
var row;
var even; /* even-power-of-two zeros operator */
var odd; /* odd-power-of-two zeros operator */
/* degenerate case (also disallow negative lengths) */
if (len2 <= 0)
return crc1;
even = new Array(GF2_DIM);
odd = new Array(GF2_DIM);
/* put operator for one zero bit in odd */
odd[0] = 0xedb88320; /* CRC-32 polynomial */
row = 1;
for (n = 1; n < GF2_DIM; n++) {
odd[n] = row;
row <<= 1;
}
/* put operator for two zero bits in even */
gf2_matrix_square(even, odd);
/* put operator for four zero bits in odd */
gf2_matrix_square(odd, even);
/* apply len2 zeros to crc1 (first square will put the operator for one
zero byte, eight zero bits, in even) */
do {
/* apply zeros operator for this bit of len2 */
gf2_matrix_square(even, odd);
if (len2 & 1)
crc1 = gf2_matrix_times(even, crc1);
len2 >>= 1;
/* if no more bits set, then done */
if (len2 == 0)
break;
/* another iteration of the loop with odd and even swapped */
gf2_matrix_square(odd, even);
if (len2 & 1)
crc1 = gf2_matrix_times(odd, crc1);
len2 >>= 1;
/* if no more bits set, then done */
} while (len2 != 0);
/* return combined crc */
crc1 ^= crc2;
return crc1;
};
}());

File diff suppressed because one or more lines are too long

111
public/scripts/zlib.js Normal file
View File

@ -0,0 +1,111 @@
/* zlib.js -- JavaScript implementation for the zlib.
Version: 0.2.0
LastModified: Apr 12 2012
Copyright (C) 2012 Masanao Izumo <iz@onicos.co.jp>
The original copyright notice (zlib 1.2.6):
Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
jloup@gzip.org madler@alumni.caltech.edu
The data format used by the zlib library is described by RFCs (Request for
Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
(zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
*/
var ZLIB = ( ZLIB || {} ); // ZLIB namespace initialization
// common definitions
if(typeof ZLIB.common_initialized === 'undefined') {
ZLIB.Z_NO_FLUSH = 0;
ZLIB.Z_PARTIAL_FLUSH = 1;
ZLIB.Z_SYNC_FLUSH = 2;
ZLIB.Z_FULL_FLUSH = 3;
ZLIB.Z_FINISH = 4;
ZLIB.Z_BLOCK = 5;
ZLIB.Z_TREES = 6;
/* Allowed flush values; see deflate() and inflate() below for details */
ZLIB.Z_OK = 0;
ZLIB.Z_STREAM_END = 1;
ZLIB.Z_NEED_DICT = 2;
ZLIB.Z_ERRNO = (-1);
ZLIB.Z_STREAM_ERROR = (-2);
ZLIB.Z_DATA_ERROR = (-3);
ZLIB.Z_MEM_ERROR = (-4);
ZLIB.Z_BUF_ERROR = (-5);
ZLIB.Z_VERSION_ERROR = (-6);
/* Return codes for the compression/decompression functions. Negative values
* are errors, positive values are used for special but normal events.
*/
ZLIB.Z_DEFLATED = 8; /* The deflate compression method (the only one supported in this version) */
/**
* z_stream constructor
* @constructor
*/
ZLIB.z_stream = function() {
this.next_in = 0; /* next input byte */
this.avail_in = 0; /* number of bytes available in input_data */
this.total_in = 0; /* total number of input bytes read so far */
this.next_out = 0; /* next output byte */
this.avail_out = 0; /* remaining free space at next_out */
this.total_out = 0; /* total number of bytes output so far */
this.msg = null; /* last error message, null if no error */
this.state = null; /* not visible by applications */
this.data_type = 0; /* best guess about the data type: binary or text */
this.adler = 0; /* TODO: adler32 value of the uncompressed data */
// zlib.js
this.input_data = ''; /* input data */
this.output_data = ''; /* output data */
this.error = 0; /* error code */
this.checksum_function = null; /* crc32(for gzip) or adler32(for zlib) */
};
/**
* TODO
* @constructor
*/
ZLIB.gz_header = function() {
this.text = 0; /* true if compressed data believed to be text */
this.time = 0; /* modification time */
this.xflags = 0; /* extra flags (not used when writing a gzip file) */
this.os = 0xff; /* operating system */
this.extra = null; /* extra field string or null if none */
this.extra_len = 0; /* this.extra.length (only when reading header) */
this.extra_max = 0; /* space at extra (only when reading header) */
this.name = null; /* file name string or null if none */
this.name_max = 0; /* space at name (only when reading header) */
this.comment = null; /* comment string or null if none */
this.comm_max = 0; /* space at comment (only when reading header) */
this.hcrc = 0; /* true if there was or will be a header crc */
this.done = 0; /* true when done reading gzip header (not used
when writing a gzip file) */
};
ZLIB.common_initialized = true;
} // common definitions

View File

@ -15,7 +15,10 @@
<script type="text/javascript" src="scripts/amt-wsman-0.2.0.js"></script>
<script type="text/javascript" src="scripts/amt-desktop-0.0.2.js"></script>
<script type="text/javascript" src="scripts/amt-terminal-0.0.2.js"></script>
<script type="text/javascript" src="scripts/inflate.js"></script>
<script type="text/javascript" src="scripts/zlib.js"></script>
<script type="text/javascript" src="scripts/zlib-inflate.js"></script>
<script type="text/javascript" src="scripts/zlib-adler32.js"></script>
<script type="text/javascript" src="scripts/zlib-crc32.js"></script>
<script type="text/javascript" src="scripts/amt-redir-ws-0.1.0.js"></script>
<script type="text/javascript" src="scripts/amt-wsman-ws-0.2.0.js"></script>
<script type="text/javascript" src="scripts/agent-redir-ws-0.1.0.js"></script>
@ -660,6 +663,7 @@
// Check if we are in debug mode
args = parseUriArgs();
debugmode = (args.debug == 1);
attemptWebRTC = (args.webrtc == 1);
QV('p13AutoConnect', debugmode); // Files
QV('autoconnectbutton2', debugmode); // Terminal
QV('autoconnectbutton1', debugmode); // Desktop