summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsamhed <samuel@cendio.se>2016-06-02 16:00:33 +0200
committersamhed <samuel@cendio.se>2016-06-03 16:37:19 +0200
commit3df13262394515efe5877ce33fd0dbdf35e1b743 (patch)
tree582a6ded51f88e67f0a74a40acab5faa61f81f7f
parent37195e4b5e776d1ce19a65ba72009536de7dcd67 (diff)
downloadnovnc-3df13262394515efe5877ce33fd0dbdf35e1b743.tar.gz
Add support for fences
We don't actually use these, but servers may require this for other features.
-rw-r--r--include/rfb.js71
-rw-r--r--tests/test.rfb.js25
2 files changed, 95 insertions, 1 deletions
diff --git a/include/rfb.js b/include/rfb.js
index 14e0aa6..71672ff 100644
--- a/include/rfb.js
+++ b/include/rfb.js
@@ -56,7 +56,8 @@ var RFB;
['last_rect', -224 ],
['Cursor', -239 ],
['ExtendedDesktopSize', -308 ],
- ['xvp', -309 ]
+ ['xvp', -309 ],
+ ['Fence', -312 ]
];
this._encHandlers = {};
@@ -70,6 +71,8 @@ var RFB;
this._disconnTimer = null; // disconnection timer
this._msgTimer = null; // queued handle_msg timer
+ this._supportsFence = false;
+
// Frame buffer update state
this._FBU = {
rects: 0,
@@ -1041,6 +1044,42 @@ var RFB;
return true;
},
+ _handle_server_fence_msg: function() {
+ if (this._sock.rQwait("ServerFence header", 8, 1)) { return false; }
+ this._sock.rQskipBytes(3); // Padding
+ var flags = this._sock.rQshift32();
+ var length = this._sock.rQshift8();
+
+ if (this._sock.rQwait("ServerFence payload", length, 9)) { return false; }
+ var payload = this._sock.rQshiftStr(length); // FIXME: 64 bytes max
+
+ this._supportsFence = true;
+
+ /*
+ * Fence flags
+ *
+ * (1<<0) - BlockBefore
+ * (1<<1) - BlockAfter
+ * (1<<2) - SyncNext
+ * (1<<31) - Request
+ */
+
+ if (!(flags & (1<<31))) {
+ return this._fail("Unexpected fence response");
+ }
+
+ // Filter out unsupported flags
+ // FIXME: support syncNext
+ flags &= (1<<0) | (1<<1);
+
+ // BlockBefore and BlockAfter are automatically handled by
+ // the fact that we process each incoming message
+ // synchronuosly.
+ RFB.messages.clientFence(this._sock, flags, payload);
+
+ return true;
+ },
+
_handle_xvp_msg: function () {
if (this._sock.rQwait("XVP version and message", 3, 1)) { return false; }
this._sock.rQskip8(); // Padding
@@ -1092,6 +1131,9 @@ var RFB;
case 3: // ServerCutText
return this._handle_server_cut_text();
+ case 248: // ServerFence
+ return this._handle_server_fence_msg();
+
case 250: // XVP
return this._handle_xvp_msg();
@@ -1350,6 +1392,33 @@ var RFB;
sock.flush();
},
+ clientFence: function (sock, flags, payload) {
+ var buff = sock._sQ;
+ var offset = sock._sQlen;
+
+ buff[offset] = 248; // msg-type
+
+ buff[offset + 1] = 0; // padding
+ buff[offset + 2] = 0; // padding
+ buff[offset + 3] = 0; // padding
+
+ buff[offset + 4] = flags >> 24; // flags
+ buff[offset + 5] = flags >> 16;
+ buff[offset + 6] = flags >> 8;
+ buff[offset + 7] = flags;
+
+ var n = payload.length;
+
+ buff[offset + 8] = n; // length
+
+ for (var i = 0; i < n; i++) {
+ buff[offset + 9 + i] = payload.charCodeAt(i);
+ }
+
+ sock._sQlen += 9 + n;
+ sock.flush();
+ },
+
pixelFormat: function (sock, bpp, depth, true_color) {
var buff = sock._sQ;
var offset = sock._sQlen;
diff --git a/tests/test.rfb.js b/tests/test.rfb.js
index a0fdf8f..be6aa1b 100644
--- a/tests/test.rfb.js
+++ b/tests/test.rfb.js
@@ -1705,6 +1705,31 @@ describe('Remote Frame Buffer Protocol Client', function() {
expect(client.get_onBell()).to.have.been.calledOnce;
});
+ it('should respond correctly to ServerFence', function () {
+ var expected_msg = {_sQ: new Uint8Array(16), _sQlen: 0, flush: function() {}};
+ var incoming_msg = {_sQ: new Uint8Array(16), _sQlen: 0, flush: function() {}};
+
+ var payload = "foo\x00ab9";
+
+ // ClientFence and ServerFence are identical in structure
+ RFB.messages.clientFence(expected_msg, (1<<0) | (1<<1), payload);
+ RFB.messages.clientFence(incoming_msg, 0xffffffff, payload);
+
+ client._sock._websocket._receive_data(incoming_msg._sQ);
+
+ expect(client._sock).to.have.sent(expected_msg._sQ);
+
+ expected_msg._sQlen = 0;
+ incoming_msg._sQlen = 0;
+
+ RFB.messages.clientFence(expected_msg, (1<<0), payload);
+ RFB.messages.clientFence(incoming_msg, (1<<0) | (1<<31), payload);
+
+ client._sock._websocket._receive_data(incoming_msg._sQ);
+
+ expect(client._sock).to.have.sent(expected_msg._sQ);
+ });
+
it('should fail on an unknown message type', function () {
client._sock._websocket._receive_data(new Uint8Array([87]));
expect(client._rfb_state).to.equal('failed');