added aten-ikvm support
This commit is contained in:
parent
d2c58aec70
commit
24439f5bf2
|
|
@ -128,7 +128,7 @@ use a WebSockets to TCP socket proxy. There is a python proxy included
|
||||||
* UI and Icons : Chris Gordon
|
* UI and Icons : Chris Gordon
|
||||||
* Original Logo : Michael Sersen
|
* Original Logo : Michael Sersen
|
||||||
* tight encoding : Michael Tinglof (Mercuri.ca)
|
* tight encoding : Michael Tinglof (Mercuri.ca)
|
||||||
* pixel format conversion : [Alexander Clouter](http://www.digriz.org.uk/)
|
* pixel format conversion and ATEN iKVM support : [Alexander Clouter](http://www.digriz.org.uk/)
|
||||||
|
|
||||||
* Included libraries:
|
* Included libraries:
|
||||||
* web-socket-js : Hiroshi Ichikawa (github.com/gimite/web-socket-js)
|
* web-socket-js : Hiroshi Ichikawa (github.com/gimite/web-socket-js)
|
||||||
|
|
|
||||||
|
|
@ -376,3 +376,80 @@ XK_udiaeresis = 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIA
|
||||||
XK_yacute = 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */
|
XK_yacute = 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */
|
||||||
XK_thorn = 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */
|
XK_thorn = 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */
|
||||||
XK_ydiaeresis = 0x00ff; /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */
|
XK_ydiaeresis = 0x00ff; /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */
|
||||||
|
|
||||||
|
var XK2HID = {};
|
||||||
|
|
||||||
|
// F{1..12}
|
||||||
|
for (var i = XK_F1; i <= XK_F12; i++) {
|
||||||
|
XK2HID[i] = 0x3a + (i - XK_F1);
|
||||||
|
}
|
||||||
|
// A-Za-z
|
||||||
|
for (var i = XK_A; i <= XK_Z; i++) {
|
||||||
|
XK2HID[i] = 0x04 + (i - XK_A);
|
||||||
|
XK2HID[i + (XK_a - XK_A)] = 0x04 + (i - XK_A);
|
||||||
|
}
|
||||||
|
// 1-9
|
||||||
|
for (var i = XK_1; i <= XK_9; i++) {
|
||||||
|
XK2HID[i] = 0x1e + (i - XK_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XK2HID[XK_0] = 0x27;
|
||||||
|
XK2HID[XK_Return] = 0x28;
|
||||||
|
XK2HID[XK_Escape] = 0x29;
|
||||||
|
XK2HID[XK_BackSpace] = 0x2a;
|
||||||
|
XK2HID[XK_Tab] = 0x2b;
|
||||||
|
XK2HID[XK_space] = 0x2c;
|
||||||
|
XK2HID[XK_minus] = 0x2d;
|
||||||
|
XK2HID[XK_equal] = 0x2e;
|
||||||
|
XK2HID[XK_bracketleft] = 0x2f;
|
||||||
|
XK2HID[XK_bracketright] = 0x30;
|
||||||
|
XK2HID[XK_backslash] = 0x31;
|
||||||
|
XK2HID[XK_semicolon] = 0x33;
|
||||||
|
XK2HID[XK_apostrophe] = 0x34;
|
||||||
|
XK2HID[XK_grave] = 0x35;
|
||||||
|
XK2HID[XK_comma] = 0x36;
|
||||||
|
XK2HID[XK_period] = 0x37;
|
||||||
|
XK2HID[XK_slash] = 0x38;
|
||||||
|
|
||||||
|
XK2HID[XK_Print] = 0x46;
|
||||||
|
XK2HID[XK_Scroll_Lock] = 0x47;
|
||||||
|
XK2HID[XK_Pause] = 0x48;
|
||||||
|
XK2HID[XK_Insert] = 0x49;
|
||||||
|
XK2HID[XK_Home] = 0x4a;
|
||||||
|
XK2HID[XK_Page_Up] = 0x4b;
|
||||||
|
XK2HID[XK_Delete] = 0x4c;
|
||||||
|
XK2HID[XK_End] = 0x4d;
|
||||||
|
XK2HID[XK_Page_Down] = 0x4e;
|
||||||
|
XK2HID[XK_Right] = 0x4f;
|
||||||
|
XK2HID[XK_Left] = 0x50;
|
||||||
|
XK2HID[XK_Down] = 0x51;
|
||||||
|
XK2HID[XK_Up] = 0x52;
|
||||||
|
|
||||||
|
XK2HID[XK_Control_L] = 0xe0;
|
||||||
|
XK2HID[XK_Control_R] = XK2HID[XK_Control_L];
|
||||||
|
XK2HID[XK_Shift_L] = 0xe1;
|
||||||
|
XK2HID[XK_Shift_R] = XK2HID[XK_Shift_L];
|
||||||
|
XK2HID[XK_Alt_L] = 0xe2;
|
||||||
|
XK2HID[XK_Alt_R] = XK2HID[XK_Alt_L];
|
||||||
|
XK2HID[XK_Super_L] = 0xe3;
|
||||||
|
XK2HID[XK_Super_R] = XK2HID[XK_Super_L];
|
||||||
|
|
||||||
|
XK2HID[XK_Caps_Lock] = 0x39;
|
||||||
|
|
||||||
|
// locale hardcoded hack
|
||||||
|
XK2HID[XK_less] = XK2HID[XK_comma];
|
||||||
|
XK2HID[XK_greater] = XK2HID[XK_period];
|
||||||
|
XK2HID[XK_exclam] = XK2HID[XK_1];
|
||||||
|
XK2HID[XK_at] = XK2HID[XK_2];
|
||||||
|
XK2HID[XK_numbersign] = XK2HID[XK_3];
|
||||||
|
XK2HID[XK_dollar] = XK2HID[XK_4];
|
||||||
|
XK2HID[XK_percent] = XK2HID[XK_5];
|
||||||
|
XK2HID[XK_asciicircum] = XK2HID[XK_6];
|
||||||
|
XK2HID[XK_ampersand] = XK2HID[XK_7];
|
||||||
|
XK2HID[XK_asterisk] = XK2HID[XK_8];
|
||||||
|
XK2HID[XK_parenleft] = XK2HID[XK_9];
|
||||||
|
XK2HID[XK_parenright] = XK2HID[XK_0];
|
||||||
|
XK2HID[XK_underscore] = XK2HID[XK_minus];
|
||||||
|
XK2HID[XK_bar] = XK2HID[XK_backslash];
|
||||||
|
XK2HID[XK_quotedbl] = XK2HID[XK_apostrophe];
|
||||||
|
XK2HID[XK_asciitilde] = XK2HID[XK_grave];
|
||||||
|
|
|
||||||
259
include/rfb.js
259
include/rfb.js
|
|
@ -33,6 +33,7 @@ var RFB;
|
||||||
this._rfb_auth_scheme = '';
|
this._rfb_auth_scheme = '';
|
||||||
|
|
||||||
this._rfb_tightvnc = false;
|
this._rfb_tightvnc = false;
|
||||||
|
this._rfb_atenikvm = false;
|
||||||
this._rfb_xvp_ver = 0;
|
this._rfb_xvp_ver = 0;
|
||||||
|
|
||||||
// In preference order
|
// In preference order
|
||||||
|
|
@ -43,6 +44,7 @@ var RFB;
|
||||||
['HEXTILE', 0x05 ],
|
['HEXTILE', 0x05 ],
|
||||||
['RRE', 0x02 ],
|
['RRE', 0x02 ],
|
||||||
['RAW', 0x00 ],
|
['RAW', 0x00 ],
|
||||||
|
['ATEN', 0x59 ],
|
||||||
['DesktopSize', -223 ],
|
['DesktopSize', -223 ],
|
||||||
['Cursor', -239 ],
|
['Cursor', -239 ],
|
||||||
|
|
||||||
|
|
@ -74,6 +76,8 @@ var RFB;
|
||||||
subrects: 0, // RRE
|
subrects: 0, // RRE
|
||||||
lines: 0, // RAW
|
lines: 0, // RAW
|
||||||
tiles: 0, // HEXTILE
|
tiles: 0, // HEXTILE
|
||||||
|
aten_len: -1, // ATEN
|
||||||
|
aten_type: -1, // ATEN
|
||||||
bytes: 0,
|
bytes: 0,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
|
@ -120,6 +124,7 @@ var RFB;
|
||||||
'local_cursor': false, // Request locally rendered cursor
|
'local_cursor': false, // Request locally rendered cursor
|
||||||
'shared': true, // Request shared mode
|
'shared': true, // Request shared mode
|
||||||
'view_only': false, // Disable client mouse/keyboard
|
'view_only': false, // Disable client mouse/keyboard
|
||||||
|
'aten_password_sep': ':', // Separator for ATEN iKVM password fields
|
||||||
'xvp_password_sep': '@', // Separator for XVP password fields
|
'xvp_password_sep': '@', // Separator for XVP password fields
|
||||||
'disconnectTimeout': 3, // Time (s) to wait for disconnection
|
'disconnectTimeout': 3, // Time (s) to wait for disconnection
|
||||||
'wsProtocols': ['binary', 'base64'], // Protocols to use in the WebSocket connection
|
'wsProtocols': ['binary', 'base64'], // Protocols to use in the WebSocket connection
|
||||||
|
|
@ -329,9 +334,12 @@ var RFB;
|
||||||
this._FBU.lines = 0; // RAW
|
this._FBU.lines = 0; // RAW
|
||||||
this._FBU.tiles = 0; // HEXTILE
|
this._FBU.tiles = 0; // HEXTILE
|
||||||
this._FBU.zlibs = []; // TIGHT zlib encoders
|
this._FBU.zlibs = []; // TIGHT zlib encoders
|
||||||
|
this._FBU.aten_len = -1 // ATEN
|
||||||
|
this._FBU.aten_type = -1; // ATEN
|
||||||
this._mouse_buttonMask = 0;
|
this._mouse_buttonMask = 0;
|
||||||
this._mouse_arr = [];
|
this._mouse_arr = [];
|
||||||
this._rfb_tightvnc = false;
|
this._rfb_tightvnc = false;
|
||||||
|
this._rfb_atenikvm = false;
|
||||||
|
|
||||||
// Clear the per connection encoding stats
|
// Clear the per connection encoding stats
|
||||||
var i;
|
var i;
|
||||||
|
|
@ -683,6 +691,36 @@ var RFB;
|
||||||
},
|
},
|
||||||
|
|
||||||
// authentication
|
// authentication
|
||||||
|
_negotiate_aten_auth: function () {
|
||||||
|
var aten_sep = this._aten_password_sep;
|
||||||
|
var aten_auth = this._rfb_password.split(aten_sep);
|
||||||
|
if (aten_auth.length < 2) {
|
||||||
|
this._updateState('password', 'ATEN iKVM credentials required (user' + aten_sep +
|
||||||
|
'password) -- got only ' + this._rfb_password);
|
||||||
|
this._onPasswordRequired(this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._rfb_atenikvm = true;
|
||||||
|
|
||||||
|
if (this._rfb_tightvnc) {
|
||||||
|
this._rfb_tightvnc = false;
|
||||||
|
} else {
|
||||||
|
this._sock.rQskipBytes(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sock.rQskipBytes(16);
|
||||||
|
|
||||||
|
var username = aten_auth[0];
|
||||||
|
username += Array(24-username.length+1).join("\x00");
|
||||||
|
var password = aten_auth.slice(1).join(aten_sep);
|
||||||
|
password += Array(24-password.length+1).join("\x00");
|
||||||
|
|
||||||
|
this._sock.send_string(username+password);
|
||||||
|
this._updateState("SecurityResult");
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
_negotiate_xvp_auth: function () {
|
_negotiate_xvp_auth: function () {
|
||||||
var xvp_sep = this._xvp_password_sep;
|
var xvp_sep = this._xvp_password_sep;
|
||||||
var xvp_auth = this._rfb_password.split(xvp_sep);
|
var xvp_auth = this._rfb_password.split(xvp_sep);
|
||||||
|
|
@ -750,6 +788,7 @@ var RFB;
|
||||||
if (!this._rfb_tightvnc) { // first pass, do the tunnel negotiation
|
if (!this._rfb_tightvnc) { // first pass, do the tunnel negotiation
|
||||||
if (this._sock.rQwait("num tunnels", 4)) { return false; }
|
if (this._sock.rQwait("num tunnels", 4)) { return false; }
|
||||||
var numTunnels = this._sock.rQshift32();
|
var numTunnels = this._sock.rQshift32();
|
||||||
|
if (this._rfb_version === 3.8 && (numTunnels & 0xffff0ff0) >>> 0 === 0xaff90fb0) { return this._negotiate_aten_auth(); }
|
||||||
if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) { return false; }
|
if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) { return false; }
|
||||||
|
|
||||||
this._rfb_tightvnc = true;
|
this._rfb_tightvnc = true;
|
||||||
|
|
@ -765,6 +804,12 @@ var RFB;
|
||||||
var subAuthCount = this._sock.rQshift32();
|
var subAuthCount = this._sock.rQshift32();
|
||||||
if (this._sock.rQwait("sub auth capabilities", 16 * subAuthCount, 4)) { return false; }
|
if (this._sock.rQwait("sub auth capabilities", 16 * subAuthCount, 4)) { return false; }
|
||||||
|
|
||||||
|
// Newer X10 Supermicro motherboards get here
|
||||||
|
if (this._rfb_version === 3.8 && numTunnels === 0 && subAuthCount === 0) {
|
||||||
|
Util.Warn("Newer ATEN iKVM detected, you may get an 'unsupported encoding 87'");
|
||||||
|
return this._negotiate_aten_auth();
|
||||||
|
}
|
||||||
|
|
||||||
var clientSupportedTypes = {
|
var clientSupportedTypes = {
|
||||||
'STDVNOAUTH__': 1,
|
'STDVNOAUTH__': 1,
|
||||||
'STDVVNCAUTH_': 2
|
'STDVVNCAUTH_': 2
|
||||||
|
|
@ -851,6 +896,7 @@ var RFB;
|
||||||
|
|
||||||
_negotiate_server_init: function () {
|
_negotiate_server_init: function () {
|
||||||
if (this._sock.rQwait("server initialization", 24)) { return false; }
|
if (this._sock.rQwait("server initialization", 24)) { return false; }
|
||||||
|
if (this._rfb_atenikvm && this._sock.rQwait("ATEN server initialization", 36)) { return false; }
|
||||||
|
|
||||||
/* Screen size */
|
/* Screen size */
|
||||||
this._fb_width = this._sock.rQshift16();
|
this._fb_width = this._sock.rQshift16();
|
||||||
|
|
@ -878,6 +924,14 @@ var RFB;
|
||||||
if (this._sock.rQwait('server init name', name_length, 24)) { return false; }
|
if (this._sock.rQwait('server init name', name_length, 24)) { return false; }
|
||||||
this._fb_name = Util.decodeUTF8(this._sock.rQshiftStr(name_length));
|
this._fb_name = Util.decodeUTF8(this._sock.rQshiftStr(name_length));
|
||||||
|
|
||||||
|
if (this._rfb_atenikvm) {
|
||||||
|
this._sock.rQskipBytes(8); // unknown
|
||||||
|
this._sock.rQskip8(); // IKVMVideoEnable
|
||||||
|
this._sock.rQskip8(); // IKVMKMEnable
|
||||||
|
this._sock.rQskip8(); // IKVMKickEnable
|
||||||
|
this._sock.rQskip8(); // VUSBEnable
|
||||||
|
}
|
||||||
|
|
||||||
if (this._rfb_tightvnc) {
|
if (this._rfb_tightvnc) {
|
||||||
if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + name_length)) { return false; }
|
if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + name_length)) { return false; }
|
||||||
// In TightVNC mode, ServerInit message is extended
|
// In TightVNC mode, ServerInit message is extended
|
||||||
|
|
@ -924,6 +978,83 @@ var RFB;
|
||||||
this._convertColor = true;
|
this._convertColor = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ATEN 'wisdom' from chicken-aten-ikvm:lens/lens.rb
|
||||||
|
// tested against the following Supermicro motherboards
|
||||||
|
// (use 'dmidecode -s baseboard-product-name' for model):
|
||||||
|
// - X7SPA-F
|
||||||
|
// - X8DTL
|
||||||
|
// - X8SIE-F
|
||||||
|
// - X9SCL/X9SCM
|
||||||
|
// - X9SCM-F
|
||||||
|
// - X9DRD-iF
|
||||||
|
// - X9SRE/X9SRE-3F/X9SRi/X9SRi-3F
|
||||||
|
// - X9DRL-3F/X9DRL-6F
|
||||||
|
// - X10SLD
|
||||||
|
//
|
||||||
|
// Not supported (uses encoding 87):
|
||||||
|
// - X10SL7-F
|
||||||
|
// - X10SLD-F
|
||||||
|
// - X10SLM-F
|
||||||
|
// - X10SLE
|
||||||
|
//
|
||||||
|
// Simply does not work:
|
||||||
|
// Hermon (WPMC450) [hangs at login]:
|
||||||
|
// - X7SB3-F
|
||||||
|
// - X8DTU-F
|
||||||
|
// - X8STi-3F
|
||||||
|
// Peppercon (Raritan/Kira100) [connection refused]:
|
||||||
|
// - X7SBi
|
||||||
|
//
|
||||||
|
// Thanks to Brian Rak and Erik Smit for testing
|
||||||
|
if (this._rfb_atenikvm) {
|
||||||
|
// we do not know the resolution till the first fbupdate so go large
|
||||||
|
// although, not necessary, saves a pointless full screen refresh
|
||||||
|
this._fb_width = 10000;
|
||||||
|
this._fb_height = 10000;
|
||||||
|
|
||||||
|
// lies about what it supports
|
||||||
|
Util.Warn("ATEN iKVM lies and only does 15 bit depth with RGB555");
|
||||||
|
this._convertColor = true;
|
||||||
|
this._pixelFormat.bpp = 16;
|
||||||
|
this._pixelFormat.depth = 15;
|
||||||
|
this._pixelFormat.red_max = (1 << 5) - 1;
|
||||||
|
this._pixelFormat.green_max = (1 << 5) - 1;
|
||||||
|
this._pixelFormat.blue_max = (1 << 5) - 1;
|
||||||
|
this._pixelFormat.red_shift = 10;
|
||||||
|
this._pixelFormat.green_shift = 5;
|
||||||
|
this._pixelFormat.blue_shift = 0;
|
||||||
|
|
||||||
|
// changes to protocol format
|
||||||
|
RFB.messages.keyEvent = function (keysym, down) {
|
||||||
|
if (XK2HID[keysym] === undefined) {
|
||||||
|
Util.Warn("XK2HID["+keysym+"] returns undefined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var arr = [4];
|
||||||
|
arr.push8(0);
|
||||||
|
arr.push8(down);
|
||||||
|
arr.push16(0);
|
||||||
|
arr.push32(XK2HID[keysym]);
|
||||||
|
arr.push32(0);
|
||||||
|
arr.push32(0);
|
||||||
|
arr.push8(0);
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
RFB.messages.pointerEvent = function (x, y, mask) {
|
||||||
|
var arr = [5];
|
||||||
|
arr.push8(0);
|
||||||
|
arr.push8(mask);
|
||||||
|
arr.push16(x);
|
||||||
|
arr.push16(y);
|
||||||
|
arr.push32(0);
|
||||||
|
arr.push32(0);
|
||||||
|
arr.push16(0);
|
||||||
|
arr.push8(0);
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (this._convertColor)
|
if (this._convertColor)
|
||||||
this._display.set_true_color(this._pixelFormat.true_color);
|
this._display.set_true_color(this._pixelFormat.true_color);
|
||||||
this._onFBResize(this, this._fb_width, this._fb_height);
|
this._onFBResize(this, this._fb_width, this._fb_height);
|
||||||
|
|
@ -1093,6 +1224,42 @@ var RFB;
|
||||||
msg_type = this._sock.rQshift8();
|
msg_type = this._sock.rQshift8();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._rfb_atenikvm) {
|
||||||
|
switch (msg_type) {
|
||||||
|
case 4: // Front Ground Event
|
||||||
|
Util.Debug("ATEN iKVM Front Ground Event");
|
||||||
|
this._sock.rQskipBytes(20);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 22: // Keep Alive Event
|
||||||
|
Util.Debug("ATEN iKVM Keep Alive Event");
|
||||||
|
this._sock.rQskipBytes(1);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 51: // Video Get Info
|
||||||
|
Util.Debug("ATEN iKVM Video Get Info");
|
||||||
|
this._sock.rQskipBytes(4);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 55: // Mouse Get Info
|
||||||
|
Util.Debug("ATEN iKVM Mouse Get Info");
|
||||||
|
this._sock.rQskipBytes(2);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 57: // Session Message
|
||||||
|
Util.Debug("ATEN iKVM Session Message");
|
||||||
|
this._sock.rQskipBytes(4); // u32
|
||||||
|
this._sock.rQskipBytes(4); // u32
|
||||||
|
this._sock.rQskipBytes(256);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 60: // Get Viewer Lang
|
||||||
|
Util.Debug("ATEN iKVM Get Viewer Lang");
|
||||||
|
this._sock.rQskipBytes(8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (msg_type) {
|
switch (msg_type) {
|
||||||
case 0: // FramebufferUpdate
|
case 0: // FramebufferUpdate
|
||||||
var ret = this._framebufferUpdate();
|
var ret = this._framebufferUpdate();
|
||||||
|
|
@ -1166,6 +1333,11 @@ var RFB;
|
||||||
this._FBU.encoding);
|
this._FBU.encoding);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ATEN uses 0x00 even when it is meant to be 0x59
|
||||||
|
if (this._rfb_atenikvm && this._FBU.encoding === 0x00) {
|
||||||
|
this._FBU.encoding = 0x59;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._timing.last_fbu = (new Date()).getTime();
|
this._timing.last_fbu = (new Date()).getTime();
|
||||||
|
|
@ -1272,6 +1444,7 @@ var RFB;
|
||||||
['local_cursor', 'rw', 'bool'], // Request locally rendered cursor
|
['local_cursor', 'rw', 'bool'], // Request locally rendered cursor
|
||||||
['shared', 'rw', 'bool'], // Request shared mode
|
['shared', 'rw', 'bool'], // Request shared mode
|
||||||
['view_only', 'rw', 'bool'], // Disable client mouse/keyboard
|
['view_only', 'rw', 'bool'], // Disable client mouse/keyboard
|
||||||
|
['aten_password_sep', 'rw', 'str'], // Separator for ATEN iKVM password fields
|
||||||
['xvp_password_sep', 'rw', 'str'], // Separator for XVP password fields
|
['xvp_password_sep', 'rw', 'str'], // Separator for XVP password fields
|
||||||
['disconnectTimeout', 'rw', 'int'], // Time (s) to wait for disconnection
|
['disconnectTimeout', 'rw', 'int'], // Time (s) to wait for disconnection
|
||||||
['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection
|
['wsProtocols', 'rw', 'arr'], // Protocols to use in the WebSocket connection
|
||||||
|
|
@ -1967,6 +2140,92 @@ var RFB;
|
||||||
|
|
||||||
compress_lo: function () {
|
compress_lo: function () {
|
||||||
Util.Error("Server sent compress level pseudo-encoding");
|
Util.Error("Server sent compress level pseudo-encoding");
|
||||||
|
},
|
||||||
|
|
||||||
|
ATEN: function () {
|
||||||
|
if (this._FBU.aten_len === - 1) {
|
||||||
|
this._FBU.bytes = 8;
|
||||||
|
if (this._sock.rQwait("ATEN", this._FBU.bytes)) { return false; }
|
||||||
|
this._FBU.bytes = 0;
|
||||||
|
this._sock.rQskipBytes(4);
|
||||||
|
this._FBU.aten_len = this._sock.rQshift32();
|
||||||
|
|
||||||
|
if (this._FBU.width === 64896 && this._FBU.height === 65056) {
|
||||||
|
Util.Info("ATEN iKVM screen is probably off");
|
||||||
|
if (this._FBU.aten_len !== 10) {
|
||||||
|
Util.Debug(">> ATEN iKVM screen off (aten_len="+this._FBU.aten_len+")");
|
||||||
|
this._fail('expected aten_len to be 10 when screen is off');
|
||||||
|
}
|
||||||
|
this._FBU.aten_len -= 10;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this._fb_width !== this._FBU.width && this._fb_height !== this._FBU.height) {
|
||||||
|
Util.Debug(">> ATEN resize desktop");
|
||||||
|
this._fb_width = this._FBU.width;
|
||||||
|
this._fb_height = this._FBU.height;
|
||||||
|
this._onFBResize(this, this._fb_width, this._fb_height);
|
||||||
|
this._display.resize(this._fb_width, this._fb_height);
|
||||||
|
Util.Debug("<< ATEN resize desktop");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._FBU.aten_type === -1) {
|
||||||
|
this._FBU.bytes = 10;
|
||||||
|
if (this._sock.rQwait("ATEN", this._FBU.bytes)) { return false; }
|
||||||
|
this._FBU.bytes = 0;
|
||||||
|
this._FBU.aten_type = this._sock.rQshift8();
|
||||||
|
this._sock.rQskip8();
|
||||||
|
|
||||||
|
this._sock.rQshift32(); // number of subrects
|
||||||
|
if (this._FBU.aten_len !== this._sock.rQshift32()) {
|
||||||
|
return this._fail('ATEN RAW len mis-match');
|
||||||
|
}
|
||||||
|
this._FBU.aten_len -= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this._FBU.aten_len > 0) {
|
||||||
|
switch (this._FBU.aten_type) {
|
||||||
|
case 0: // Subrects
|
||||||
|
this._FBU.bytes = 6 + (16 * 16 * this._pixelFormat.Bpp); // at least a subrect
|
||||||
|
if (this._sock.rQwait("ATEN", this._FBU.bytes)) { return false; }
|
||||||
|
var a = this._sock.rQshift16();
|
||||||
|
var b = this._sock.rQshift16();
|
||||||
|
var y = this._sock.rQshift8();
|
||||||
|
var x = this._sock.rQshift8();
|
||||||
|
this._display.renderQ_push({
|
||||||
|
'type': 'blit',
|
||||||
|
'data': this._convert_color(this._sock.rQshiftBytes(this._FBU.bytes - 6)),
|
||||||
|
'x': x * 16,
|
||||||
|
'y': y * 16,
|
||||||
|
'width': 16,
|
||||||
|
'height': 16
|
||||||
|
});
|
||||||
|
this._FBU.aten_len -= this._FBU.bytes;
|
||||||
|
this._FBU.bytes = 0;
|
||||||
|
break;
|
||||||
|
case 1: // RAW
|
||||||
|
var olines = (this._FBU.lines === 0) ? this._FBU.height : this._FBU.lines;
|
||||||
|
this._encHandlers.RAW();
|
||||||
|
this._FBU.aten_len -= (olines - this._FBU.lines) * this._FBU.width * this._pixelFormat.Bpp;
|
||||||
|
if (this._FBU.bytes > 0) return false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return this._fail('unknown ATEN type: '+this._FBU.aten_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._FBU.aten_len < 0) {
|
||||||
|
this._fail('aten_len dropped below zero');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._FBU.aten_type === 0) {
|
||||||
|
this._FBU.rects--;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._FBU.aten_len = -1;
|
||||||
|
this._FBU.aten_type = -1;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -789,6 +789,51 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
expect(client._rfb_state).to.equal('failed');
|
expect(client._rfb_state).to.equal('failed');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ATEN iKVM Authentication Handler', function () {
|
||||||
|
var client;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
client = make_rfb();
|
||||||
|
client.connect('host', 8675);
|
||||||
|
client._sock._websocket._open();
|
||||||
|
client._rfb_state = 'Security';
|
||||||
|
client._rfb_version = 3.8;
|
||||||
|
send_security(16, client);
|
||||||
|
client._sock._websocket._get_sent_data(); // skip the security reply
|
||||||
|
client._rfb_password = 'test1:test2';
|
||||||
|
});
|
||||||
|
|
||||||
|
var auth = [
|
||||||
|
116, 101, 115, 116, 49, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
116, 101, 115, 116, 50, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
it('via old style method', function () {
|
||||||
|
client._sock._websocket._receive_data(new Uint8Array([
|
||||||
|
0xaf, 0xf9, 0x0f, 0xb0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0]));
|
||||||
|
expect(client._rfb_tightvnc).to.be.false;
|
||||||
|
expect(client._rfb_atenikvm).to.be.true;
|
||||||
|
expect(client._sock).to.have.sent(auth);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('via new style method', function () {
|
||||||
|
client._sock._websocket._receive_data(new Uint8Array([
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0]));
|
||||||
|
expect(client._rfb_tightvnc).to.be.false;
|
||||||
|
expect(client._rfb_atenikvm).to.be.true;
|
||||||
|
expect(client._sock).to.have.sent(auth);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('SecurityResult', function () {
|
describe('SecurityResult', function () {
|
||||||
|
|
@ -936,6 +981,23 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
expect(client._rfb_state).to.equal('normal');
|
expect(client._rfb_state).to.equal('normal');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle an ATEN iKVM server initialization', function () {
|
||||||
|
client._rfb_atenikvm = true;
|
||||||
|
send_server_init({ true_color: 1, bpp: 32 }, client);
|
||||||
|
client._sock._websocket._receive_data(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
|
||||||
|
expect(client._pixelFormat.bpp).to.equal(16);
|
||||||
|
expect(client._pixelFormat.depth).to.equal(15);
|
||||||
|
expect(client._pixelFormat.red_max).to.equal(31);
|
||||||
|
expect(client._pixelFormat.green_max).to.equal(31);
|
||||||
|
expect(client._pixelFormat.blue_max).to.equal(31);
|
||||||
|
expect(client._pixelFormat.red_shift).to.equal(10);
|
||||||
|
expect(client._pixelFormat.green_shift).to.equal(5);
|
||||||
|
expect(client._pixelFormat.blue_shift).to.equal(0);
|
||||||
|
expect(client._pixelFormat.Bpp).to.equal(2);
|
||||||
|
expect(client._pixelFormat.Bdepth).to.equal(2);
|
||||||
|
expect(client._rfb_state).to.equal('normal');
|
||||||
|
});
|
||||||
|
|
||||||
it('should call the resize callback and resize the display', function () {
|
it('should call the resize callback and resize the display', function () {
|
||||||
client.set_onFBResize(sinon.spy());
|
client.set_onFBResize(sinon.spy());
|
||||||
sinon.spy(client._display, 'resize');
|
sinon.spy(client._display, 'resize');
|
||||||
|
|
@ -1477,6 +1539,96 @@ describe('Remote Frame Buffer Protocol Client', function() {
|
||||||
// TODO(directxman12): test this
|
// TODO(directxman12): test this
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('the ATEN encoding handler', function () {
|
||||||
|
var client;
|
||||||
|
beforeEach(function () {
|
||||||
|
client = make_rfb();
|
||||||
|
client.connect('host', 8675);
|
||||||
|
client._sock._websocket._open();
|
||||||
|
client._rfb_state = 'normal';
|
||||||
|
client._fb_name = 'some device';
|
||||||
|
client._rfb_atenikvm = true;
|
||||||
|
// start large, then go small
|
||||||
|
client._fb_width = 10000;
|
||||||
|
client._fb_height = 10000;
|
||||||
|
client._display._fb_width = 10000;
|
||||||
|
client._display._fb_height = 10000;
|
||||||
|
client._display._viewportLoc.w = 10000;
|
||||||
|
client._display._viewportLoc.h = 10000;
|
||||||
|
client._convertColor = true;
|
||||||
|
client._pixelFormat.Bpp = 2;
|
||||||
|
client._pixelFormat.big_endian = false;
|
||||||
|
client._pixelFormat.red_shift = 10;
|
||||||
|
client._pixelFormat.red_max = 31;
|
||||||
|
client._pixelFormat.green_shift = 5;
|
||||||
|
client._pixelFormat.green_max = 31;
|
||||||
|
client._pixelFormat.blue_shift = 0;
|
||||||
|
client._pixelFormat.blue_max = 31;
|
||||||
|
});
|
||||||
|
|
||||||
|
var aten_target_data_arr = [0xa8, 0xe8, 0xf8, 0xff];
|
||||||
|
var aten_target_data;
|
||||||
|
|
||||||
|
before(function () {
|
||||||
|
for (var i = 0; i < 10; i++) {
|
||||||
|
aten_target_data_arr = aten_target_data_arr.concat(aten_target_data_arr);
|
||||||
|
}
|
||||||
|
aten_target_data = new Uint8Array(aten_target_data_arr);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle subtype subrect encoding', function () {
|
||||||
|
var info = [{ x: 0, y: 0, width: 32, height: 32, encoding: 0x59 }];
|
||||||
|
var rect = [];
|
||||||
|
|
||||||
|
rect.push32(0); // padding
|
||||||
|
rect.push32(2082); // 10 + 32x32x2Bpp + 6*(num of subrects)
|
||||||
|
|
||||||
|
rect.push8(0); // type
|
||||||
|
rect.push8(0); // padding
|
||||||
|
|
||||||
|
rect.push32(4); // num of subrects (32/16)*(32/16)
|
||||||
|
rect.push32(2082); // length (again)
|
||||||
|
|
||||||
|
for (var y = 0; y < 2; y++) {
|
||||||
|
for (var x = 0; x < 2; x++) {
|
||||||
|
rect.push16(0); // a
|
||||||
|
rect.push16(0); // b
|
||||||
|
rect.push8(y);
|
||||||
|
rect.push8(x);
|
||||||
|
|
||||||
|
for (var i = 0; i < 16*16; i++) {
|
||||||
|
rect.push16(0xbf57);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send_fbu_msg(info, [rect], client);
|
||||||
|
expect(client._display).to.have.displayed(aten_target_data);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle subtype RAW encoding', function () {
|
||||||
|
// do not use encoding=0x59 here, as rfb.js should override it
|
||||||
|
var info = [{ x: 0, y: 0, width: 32, height: 32, encoding: 0x00 }];
|
||||||
|
var rect = [];
|
||||||
|
|
||||||
|
rect.push32(0); // padding
|
||||||
|
rect.push32(2058); // 10 + 32x32x2Bpp
|
||||||
|
|
||||||
|
rect.push8(1); // type
|
||||||
|
rect.push8(0); // padding
|
||||||
|
|
||||||
|
rect.push32(0); // padding
|
||||||
|
rect.push32(2058); // length (again)
|
||||||
|
|
||||||
|
for (var i = 0; i < 32*32; i++) {
|
||||||
|
rect.push16(0xbf57);
|
||||||
|
}
|
||||||
|
|
||||||
|
send_fbu_msg(info, [rect], client);
|
||||||
|
expect(client._display).to.have.displayed(aten_target_data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle the DesktopSize pseduo-encoding', function () {
|
it('should handle the DesktopSize pseduo-encoding', function () {
|
||||||
client.set_onFBResize(sinon.spy());
|
client.set_onFBResize(sinon.spy());
|
||||||
sinon.spy(client._display, 'resize');
|
sinon.spy(client._display, 'resize');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue