summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2018-07-20 16:00:43 +0200
committerPierre Ossman <ossman@cendio.se>2018-08-22 15:12:10 +0200
commit11309f32434bdd56dcea380ed7abd98abe9e9fae (patch)
tree063e242c20d82edd8c423b1fb3d8f1eaca5e9b9c
parente17cae8f32722a24f994188d93748599d2e595ac (diff)
downloadnovnc-11309f32434bdd56dcea380ed7abd98abe9e9fae.tar.gz
Handle pseudo encodings directly
These have very special behaviour compared to normal data encodings, so separate out them and handle them separately.
-rw-r--r--core/rfb.js296
1 files changed, 150 insertions, 146 deletions
diff --git a/core/rfb.js b/core/rfb.js
index 334f334..1bfb282 100644
--- a/core/rfb.js
+++ b/core/rfb.js
@@ -2,6 +2,7 @@
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
* Copyright (C) 2018 Samuel Mannehed for Cendio AB
+ * Copyright (C) 2018 Pierre Ossman for Cendio AB
* Licensed under MPL 2.0 (see LICENSE.txt)
*
* See README.md for usage and integration instructions.
@@ -162,12 +163,6 @@ export default class RFB extends EventTargetMixin {
this._encHandlers[encodings.encodingTight] = RFB.encodingHandlers.TIGHT.bind(this, false);
this._encHandlers[encodings.encodingTightPNG] = RFB.encodingHandlers.TIGHT.bind(this, true);
- this._encHandlers[encodings.pseudoEncodingDesktopSize] = RFB.encodingHandlers.DesktopSize.bind(this);
- this._encHandlers[encodings.pseudoEncodingLastRect] = RFB.encodingHandlers.last_rect.bind(this);
- this._encHandlers[encodings.pseudoEncodingCursor] = RFB.encodingHandlers.Cursor.bind(this);
- this._encHandlers[encodings.pseudoEncodingQEMUExtendedKeyEvent] = RFB.encodingHandlers.QEMUExtendedKeyEvent.bind(this);
- this._encHandlers[encodings.pseudoEncodingExtendedDesktopSize] = RFB.encodingHandlers.ExtendedDesktopSize.bind(this);
-
// NB: nothing that needs explicit teardown should be done
// before this point, since this can throw an exception
try {
@@ -1477,17 +1472,13 @@ export default class RFB extends EventTargetMixin {
this._FBU.height = (hdr[6] << 8) + hdr[7];
this._FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) +
(hdr[10] << 8) + hdr[11], 10);
-
- if (!this._encHandlers[this._FBU.encoding]) {
- this._fail("Unsupported encoding (encoding: " +
- this._FBU.encoding + ")");
- return false;
- }
}
- const ret = this._encHandlers[this._FBU.encoding]();
+ if (!this._handleRect()) {
+ return false;
+ }
- if (!ret) { return ret; } // need more data
+ this._FBU.rects--;
}
this._display.flip();
@@ -1495,6 +1486,151 @@ export default class RFB extends EventTargetMixin {
return true; // We finished this FBU
}
+ _handleRect() {
+ switch (this._FBU.encoding) {
+ case encodings.pseudoEncodingLastRect:
+ this._FBU.rects = 1; // Will be decreased when we return
+ return true;
+
+ case encodings.pseudoEncodingCursor:
+ return this._handleCursor();
+
+ case encodings.pseudoEncodingQEMUExtendedKeyEvent:
+ // Old Safari doesn't support creating keyboard events
+ try {
+ const keyboardEvent = document.createEvent("keyboardEvent");
+ if (keyboardEvent.code !== undefined) {
+ this._qemuExtKeyEventSupported = true;
+ }
+ } catch (err) {
+ // Do nothing
+ }
+ return true;
+
+ case encodings.pseudoEncodingDesktopSize:
+ this._resize(this._FBU.width, this._FBU.height);
+ return true;
+
+ case encodings.pseudoEncodingExtendedDesktopSize:
+ return this._handleExtendedDesktopSize();
+
+ default:
+ return this._handleDataRect();
+ }
+ }
+
+ _handleCursor() {
+ const x = this._FBU.x; // hotspot-x
+ const y = this._FBU.y; // hotspot-y
+ const w = this._FBU.width;
+ const h = this._FBU.height;
+
+ const pixelslength = w * h * 4;
+ const masklength = Math.floor((w + 7) / 8) * h;
+
+ this._FBU.bytes = pixelslength + masklength;
+ if (this._sock.rQwait("cursor encoding", this._FBU.bytes)) {
+ return false;
+ }
+
+ this._cursor.change(this._sock.rQshiftBytes(pixelslength),
+ this._sock.rQshiftBytes(masklength),
+ x, y, w, h);
+
+ this._FBU.bytes = 0;
+
+ return true;
+ }
+
+ _handleExtendedDesktopSize() {
+ this._FBU.bytes = 4;
+ if (this._sock.rQwait("ExtendedDesktopSize", this._FBU.bytes)) {
+ return false;
+ }
+
+ const number_of_screens = this._sock.rQpeek8();
+
+ this._FBU.bytes += number_of_screens * 16;
+ if (this._sock.rQwait("ExtendedDesktopSize", this._FBU.bytes)) {
+ return false;
+ }
+
+ const firstUpdate = !this._supportsSetDesktopSize;
+ this._supportsSetDesktopSize = true;
+
+ // Normally we only apply the current resize mode after a
+ // window resize event. However there is no such trigger on the
+ // initial connect. And we don't know if the server supports
+ // resizing until we've gotten here.
+ if (firstUpdate) {
+ this._requestRemoteResize();
+ }
+
+ this._sock.rQskipBytes(1); // number-of-screens
+ this._sock.rQskipBytes(3); // padding
+
+ for (let i = 0; i < number_of_screens; i += 1) {
+ // Save the id and flags of the first screen
+ if (i === 0) {
+ this._screen_id = this._sock.rQshiftBytes(4); // id
+ this._sock.rQskipBytes(2); // x-position
+ this._sock.rQskipBytes(2); // y-position
+ this._sock.rQskipBytes(2); // width
+ this._sock.rQskipBytes(2); // height
+ this._screen_flags = this._sock.rQshiftBytes(4); // flags
+ } else {
+ this._sock.rQskipBytes(16);
+ }
+ }
+
+ /*
+ * The x-position indicates the reason for the change:
+ *
+ * 0 - server resized on its own
+ * 1 - this client requested the resize
+ * 2 - another client requested the resize
+ */
+
+ // We need to handle errors when we requested the resize.
+ if (this._FBU.x === 1 && this._FBU.y !== 0) {
+ let msg = "";
+ // The y-position indicates the status code from the server
+ switch (this._FBU.y) {
+ case 1:
+ msg = "Resize is administratively prohibited";
+ break;
+ case 2:
+ msg = "Out of resources";
+ break;
+ case 3:
+ msg = "Invalid screen layout";
+ break;
+ default:
+ msg = "Unknown reason";
+ break;
+ }
+ Log.Warn("Server did not accept the resize request: "
+ + msg);
+ } else {
+ this._resize(this._FBU.width, this._FBU.height);
+ }
+
+ this._FBU.bytes = 0;
+
+ return true;
+ }
+
+ _handleDataRect() {
+ let handler = this._encHandlers[this._FBU.encoding];
+ if (!handler) {
+ this._fail("Unsupported encoding (encoding: " +
+ this._FBU.encoding + ")");
+ return false;
+ }
+
+ return handler();
+ }
+
_updateContinuousUpdates() {
if (!this._enabledContinuousUpdates) { return; }
@@ -1883,7 +2019,6 @@ RFB.encodingHandlers = {
if (this._FBU.lines > 0) {
this._FBU.bytes = this._FBU.width * pixelSize; // At least another line
} else {
- this._FBU.rects--;
this._FBU.bytes = 0;
}
@@ -1897,7 +2032,6 @@ RFB.encodingHandlers = {
this._FBU.x, this._FBU.y, this._FBU.width,
this._FBU.height);
- this._FBU.rects--;
this._FBU.bytes = 0;
return true;
},
@@ -1926,7 +2060,6 @@ RFB.encodingHandlers = {
const chunk = Math.min(this._rre_chunk_sz, this._FBU.subrects);
this._FBU.bytes = (4 + 8) * chunk;
} else {
- this._FBU.rects--;
this._FBU.bytes = 0;
}
@@ -2044,10 +2177,6 @@ RFB.encodingHandlers = {
this._FBU.tiles--;
}
- if (this._FBU.tiles === 0) {
- this._FBU.rects--;
- }
-
return true;
},
@@ -2350,132 +2479,7 @@ RFB.encodingHandlers = {
this._FBU.bytes = 0;
- this._FBU.rects--;
return true;
},
-
- last_rect() {
- this._FBU.rects = 0;
- return true;
- },
-
- ExtendedDesktopSize() {
- this._FBU.bytes = 1;
- if (this._sock.rQwait("ExtendedDesktopSize", this._FBU.bytes)) { return false; }
-
- const firstUpdate = !this._supportsSetDesktopSize;
- this._supportsSetDesktopSize = true;
-
- // Normally we only apply the current resize mode after a
- // window resize event. However there is no such trigger on the
- // initial connect. And we don't know if the server supports
- // resizing until we've gotten here.
- if (firstUpdate) {
- this._requestRemoteResize();
- }
-
- const number_of_screens = this._sock.rQpeek8();
-
- this._FBU.bytes = 4 + (number_of_screens * 16);
- if (this._sock.rQwait("ExtendedDesktopSize", this._FBU.bytes)) { return false; }
-
- this._sock.rQskipBytes(1); // number-of-screens
- this._sock.rQskipBytes(3); // padding
-
- for (let i = 0; i < number_of_screens; i += 1) {
- // Save the id and flags of the first screen
- if (i === 0) {
- this._screen_id = this._sock.rQshiftBytes(4); // id
- this._sock.rQskipBytes(2); // x-position
- this._sock.rQskipBytes(2); // y-position
- this._sock.rQskipBytes(2); // width
- this._sock.rQskipBytes(2); // height
- this._screen_flags = this._sock.rQshiftBytes(4); // flags
- } else {
- this._sock.rQskipBytes(16);
- }
- }
-
- /*
- * The x-position indicates the reason for the change:
- *
- * 0 - server resized on its own
- * 1 - this client requested the resize
- * 2 - another client requested the resize
- */
-
- // We need to handle errors when we requested the resize.
- if (this._FBU.x === 1 && this._FBU.y !== 0) {
- let msg = "";
- // The y-position indicates the status code from the server
- switch (this._FBU.y) {
- case 1:
- msg = "Resize is administratively prohibited";
- break;
- case 2:
- msg = "Out of resources";
- break;
- case 3:
- msg = "Invalid screen layout";
- break;
- default:
- msg = "Unknown reason";
- break;
- }
- Log.Warn("Server did not accept the resize request: "
- + msg);
- } else {
- this._resize(this._FBU.width, this._FBU.height);
- }
-
- this._FBU.bytes = 0;
- this._FBU.rects -= 1;
- return true;
- },
-
- DesktopSize() {
- this._resize(this._FBU.width, this._FBU.height);
- this._FBU.bytes = 0;
- this._FBU.rects -= 1;
- return true;
- },
-
- Cursor() {
- Log.Debug(">> set_cursor");
- const x = this._FBU.x; // hotspot-x
- const y = this._FBU.y; // hotspot-y
- const w = this._FBU.width;
- const h = this._FBU.height;
-
- const pixelslength = w * h * 4;
- const masklength = Math.floor((w + 7) / 8) * h;
-
- this._FBU.bytes = pixelslength + masklength;
- if (this._sock.rQwait("cursor encoding", this._FBU.bytes)) { return false; }
-
- this._cursor.change(this._sock.rQshiftBytes(pixelslength),
- this._sock.rQshiftBytes(masklength),
- x, y, w, h);
-
- this._FBU.bytes = 0;
- this._FBU.rects--;
-
- Log.Debug("<< set_cursor");
- return true;
- },
-
- QEMUExtendedKeyEvent() {
- this._FBU.rects--;
-
- // Old Safari doesn't support creating keyboard events
- try {
- const keyboardEvent = document.createEvent("keyboardEvent");
- if (keyboardEvent.code !== undefined) {
- this._qemuExtKeyEventSupported = true;
- }
- } catch (err) {
- // Do nothing
- }
- }
}