Add Websock send queue helpers
Callers shouldn't be poking around directly in to the send queue, but should use accessor functions like for the read queue.
This commit is contained in:
parent
7356d4e60b
commit
f8b65f9fe1
12
core/ra2.js
12
core/ra2.js
|
@ -182,7 +182,8 @@ export default class RSAAESAuthenticationState extends EventTargetMixin {
|
||||||
clientPublicKey[3] = clientKeyLength & 0xff;
|
clientPublicKey[3] = clientKeyLength & 0xff;
|
||||||
clientPublicKey.set(clientN, 4);
|
clientPublicKey.set(clientN, 4);
|
||||||
clientPublicKey.set(clientE, 4 + clientKeyBytes);
|
clientPublicKey.set(clientE, 4 + clientKeyBytes);
|
||||||
this._sock.send(clientPublicKey);
|
this._sock.sQpushBytes(clientPublicKey);
|
||||||
|
this._sock.flush();
|
||||||
|
|
||||||
// 3: Send client random
|
// 3: Send client random
|
||||||
const clientRandom = new Uint8Array(16);
|
const clientRandom = new Uint8Array(16);
|
||||||
|
@ -193,7 +194,8 @@ export default class RSAAESAuthenticationState extends EventTargetMixin {
|
||||||
clientRandomMessage[0] = (serverKeyBytes & 0xff00) >>> 8;
|
clientRandomMessage[0] = (serverKeyBytes & 0xff00) >>> 8;
|
||||||
clientRandomMessage[1] = serverKeyBytes & 0xff;
|
clientRandomMessage[1] = serverKeyBytes & 0xff;
|
||||||
clientRandomMessage.set(clientEncryptedRandom, 2);
|
clientRandomMessage.set(clientEncryptedRandom, 2);
|
||||||
this._sock.send(clientRandomMessage);
|
this._sock.sQpushBytes(clientRandomMessage);
|
||||||
|
this._sock.flush();
|
||||||
|
|
||||||
// 4: Receive server random
|
// 4: Receive server random
|
||||||
await this._waitSockAsync(2);
|
await this._waitSockAsync(2);
|
||||||
|
@ -234,7 +236,8 @@ export default class RSAAESAuthenticationState extends EventTargetMixin {
|
||||||
clientHash = await window.crypto.subtle.digest("SHA-1", clientHash);
|
clientHash = await window.crypto.subtle.digest("SHA-1", clientHash);
|
||||||
serverHash = new Uint8Array(serverHash);
|
serverHash = new Uint8Array(serverHash);
|
||||||
clientHash = new Uint8Array(clientHash);
|
clientHash = new Uint8Array(clientHash);
|
||||||
this._sock.send(await clientCipher.makeMessage(clientHash));
|
this._sock.sQpushBytes(await clientCipher.makeMessage(clientHash));
|
||||||
|
this._sock.flush();
|
||||||
await this._waitSockAsync(2 + 20 + 16);
|
await this._waitSockAsync(2 + 20 + 16);
|
||||||
if (this._sock.rQshift16() !== 20) {
|
if (this._sock.rQshift16() !== 20) {
|
||||||
throw new Error("RA2: wrong server hash");
|
throw new Error("RA2: wrong server hash");
|
||||||
|
@ -295,7 +298,8 @@ export default class RSAAESAuthenticationState extends EventTargetMixin {
|
||||||
for (let i = 0; i < password.length; i++) {
|
for (let i = 0; i < password.length; i++) {
|
||||||
credentials[username.length + 2 + i] = password.charCodeAt(i);
|
credentials[username.length + 2 + i] = password.charCodeAt(i);
|
||||||
}
|
}
|
||||||
this._sock.send(await clientCipher.makeMessage(credentials));
|
this._sock.sQpushBytes(await clientCipher.makeMessage(credentials));
|
||||||
|
this._sock.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasStarted() {
|
get hasStarted() {
|
||||||
|
|
342
core/rfb.js
342
core/rfb.js
|
@ -1381,7 +1381,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
while (repeaterID.length < 250) {
|
while (repeaterID.length < 250) {
|
||||||
repeaterID += "\0";
|
repeaterID += "\0";
|
||||||
}
|
}
|
||||||
this._sock.sendString(repeaterID);
|
this._sock.sQpushString(repeaterID);
|
||||||
|
this._sock.flush();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1391,7 +1392,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
|
|
||||||
const cversion = "00" + parseInt(this._rfbVersion, 10) +
|
const cversion = "00" + parseInt(this._rfbVersion, 10) +
|
||||||
".00" + ((this._rfbVersion * 10) % 10);
|
".00" + ((this._rfbVersion * 10) % 10);
|
||||||
this._sock.sendString("RFB " + cversion + "\n");
|
this._sock.sQpushString("RFB " + cversion + "\n");
|
||||||
|
this._sock.flush();
|
||||||
Log.Debug('Sent ProtocolVersion: ' + cversion);
|
Log.Debug('Sent ProtocolVersion: ' + cversion);
|
||||||
|
|
||||||
this._rfbInitState = 'Security';
|
this._rfbInitState = 'Security';
|
||||||
|
@ -1443,7 +1445,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
return this._fail("Unsupported security types (types: " + types + ")");
|
return this._fail("Unsupported security types (types: " + types + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sock.send([this._rfbAuthScheme]);
|
this._sock.sQpush8(this._rfbAuthScheme);
|
||||||
|
this._sock.flush();
|
||||||
} else {
|
} else {
|
||||||
// Server decides
|
// Server decides
|
||||||
if (this._sock.rQwait("security scheme", 4)) { return false; }
|
if (this._sock.rQwait("security scheme", 4)) { return false; }
|
||||||
|
@ -1505,12 +1508,15 @@ export default class RFB extends EventTargetMixin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const xvpAuthStr = String.fromCharCode(this._rfbCredentials.username.length) +
|
this._sock.sQpush8(this._rfbCredentials.username.length);
|
||||||
String.fromCharCode(this._rfbCredentials.target.length) +
|
this._sock.sQpush8(this._rfbCredentials.target.length);
|
||||||
this._rfbCredentials.username +
|
this._sock.sQpushString(this._rfbCredentials.username);
|
||||||
this._rfbCredentials.target;
|
this._sock.sQpushString(this._rfbCredentials.target);
|
||||||
this._sock.sendString(xvpAuthStr);
|
|
||||||
|
this._sock.flush();
|
||||||
|
|
||||||
this._rfbAuthScheme = securityTypeVNCAuth;
|
this._rfbAuthScheme = securityTypeVNCAuth;
|
||||||
|
|
||||||
return this._negotiateAuthentication();
|
return this._negotiateAuthentication();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1528,7 +1534,9 @@ export default class RFB extends EventTargetMixin {
|
||||||
return this._fail("Unsupported VeNCrypt version " + major + "." + minor);
|
return this._fail("Unsupported VeNCrypt version " + major + "." + minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sock.send([0, 2]);
|
this._sock.sQpush8(0);
|
||||||
|
this._sock.sQpush8(2);
|
||||||
|
this._sock.flush();
|
||||||
this._rfbVeNCryptState = 1;
|
this._rfbVeNCryptState = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1587,10 +1595,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
return this._fail("Unsupported security types (types: " + subtypes + ")");
|
return this._fail("Unsupported security types (types: " + subtypes + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sock.send([this._rfbAuthScheme >> 24,
|
this._sock.sQpush32(this._rfbAuthScheme);
|
||||||
this._rfbAuthScheme >> 16,
|
this._sock.flush();
|
||||||
this._rfbAuthScheme >> 8,
|
|
||||||
this._rfbAuthScheme]);
|
|
||||||
|
|
||||||
this._rfbVeNCryptState = 4;
|
this._rfbVeNCryptState = 4;
|
||||||
return true;
|
return true;
|
||||||
|
@ -1609,20 +1615,11 @@ export default class RFB extends EventTargetMixin {
|
||||||
const user = encodeUTF8(this._rfbCredentials.username);
|
const user = encodeUTF8(this._rfbCredentials.username);
|
||||||
const pass = encodeUTF8(this._rfbCredentials.password);
|
const pass = encodeUTF8(this._rfbCredentials.password);
|
||||||
|
|
||||||
this._sock.send([
|
this._sock.sQpush32(user.length);
|
||||||
(user.length >> 24) & 0xFF,
|
this._sock.sQpush32(pass.length);
|
||||||
(user.length >> 16) & 0xFF,
|
this._sock.sQpushString(user);
|
||||||
(user.length >> 8) & 0xFF,
|
this._sock.sQpushString(pass);
|
||||||
user.length & 0xFF
|
this._sock.flush();
|
||||||
]);
|
|
||||||
this._sock.send([
|
|
||||||
(pass.length >> 24) & 0xFF,
|
|
||||||
(pass.length >> 16) & 0xFF,
|
|
||||||
(pass.length >> 8) & 0xFF,
|
|
||||||
pass.length & 0xFF
|
|
||||||
]);
|
|
||||||
this._sock.sendString(user);
|
|
||||||
this._sock.sendString(pass);
|
|
||||||
|
|
||||||
this._rfbInitState = "SecurityResult";
|
this._rfbInitState = "SecurityResult";
|
||||||
return true;
|
return true;
|
||||||
|
@ -1641,7 +1638,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
// TODO(directxman12): make genDES not require an Array
|
// TODO(directxman12): make genDES not require an Array
|
||||||
const challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16));
|
const challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16));
|
||||||
const response = RFB.genDES(this._rfbCredentials.password, challenge);
|
const response = RFB.genDES(this._rfbCredentials.password, challenge);
|
||||||
this._sock.send(response);
|
this._sock.sQpushBytes(response);
|
||||||
|
this._sock.flush();
|
||||||
this._rfbInitState = "SecurityResult";
|
this._rfbInitState = "SecurityResult";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1659,8 +1657,9 @@ export default class RFB extends EventTargetMixin {
|
||||||
if (this._rfbCredentials.ardPublicKey != undefined &&
|
if (this._rfbCredentials.ardPublicKey != undefined &&
|
||||||
this._rfbCredentials.ardCredentials != undefined) {
|
this._rfbCredentials.ardCredentials != undefined) {
|
||||||
// if the async web crypto is done return the results
|
// if the async web crypto is done return the results
|
||||||
this._sock.send(this._rfbCredentials.ardCredentials);
|
this._sock.sQpushBytes(this._rfbCredentials.ardCredentials);
|
||||||
this._sock.send(this._rfbCredentials.ardPublicKey);
|
this._sock.sQpushBytes(this._rfbCredentials.ardPublicKey);
|
||||||
|
this._sock.flush();
|
||||||
this._rfbCredentials.ardCredentials = null;
|
this._rfbCredentials.ardCredentials = null;
|
||||||
this._rfbCredentials.ardPublicKey = null;
|
this._rfbCredentials.ardPublicKey = null;
|
||||||
this._rfbInitState = "SecurityResult";
|
this._rfbInitState = "SecurityResult";
|
||||||
|
@ -1724,10 +1723,12 @@ export default class RFB extends EventTargetMixin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sock.send([0, 0, 0, this._rfbCredentials.username.length]);
|
this._sock.sQpush32(this._rfbCredentials.username.length);
|
||||||
this._sock.send([0, 0, 0, this._rfbCredentials.password.length]);
|
this._sock.sQpush32(this._rfbCredentials.password.length);
|
||||||
this._sock.sendString(this._rfbCredentials.username);
|
this._sock.sQpushString(this._rfbCredentials.username);
|
||||||
this._sock.sendString(this._rfbCredentials.password);
|
this._sock.sQpushString(this._rfbCredentials.password);
|
||||||
|
this._sock.flush();
|
||||||
|
|
||||||
this._rfbInitState = "SecurityResult";
|
this._rfbInitState = "SecurityResult";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1765,7 +1766,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
"vendor or signature");
|
"vendor or signature");
|
||||||
}
|
}
|
||||||
Log.Debug("Selected tunnel type: " + clientSupportedTunnelTypes[0]);
|
Log.Debug("Selected tunnel type: " + clientSupportedTunnelTypes[0]);
|
||||||
this._sock.send([0, 0, 0, 0]); // use NOTUNNEL
|
this._sock.sQpush32(0); // use NOTUNNEL
|
||||||
|
this._sock.flush();
|
||||||
return false; // wait until we receive the sub auth count to continue
|
return false; // wait until we receive the sub auth count to continue
|
||||||
} else {
|
} else {
|
||||||
return this._fail("Server wanted tunnels, but doesn't support " +
|
return this._fail("Server wanted tunnels, but doesn't support " +
|
||||||
|
@ -1815,7 +1817,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
|
|
||||||
for (let authType in clientSupportedTypes) {
|
for (let authType in clientSupportedTypes) {
|
||||||
if (serverSupportedTypes.indexOf(authType) != -1) {
|
if (serverSupportedTypes.indexOf(authType) != -1) {
|
||||||
this._sock.send([0, 0, 0, clientSupportedTypes[authType]]);
|
this._sock.sQpush32(clientSupportedTypes[authType]);
|
||||||
|
this._sock.flush();
|
||||||
Log.Debug("Selected authentication type: " + authType);
|
Log.Debug("Selected authentication type: " + authType);
|
||||||
|
|
||||||
switch (authType) {
|
switch (authType) {
|
||||||
|
@ -1911,9 +1914,10 @@ export default class RFB extends EventTargetMixin {
|
||||||
passwordBytes[password.length] = 0;
|
passwordBytes[password.length] = 0;
|
||||||
usernameBytes = legacyCrypto.encrypt({ name: "DES-CBC", iv: secret }, key, usernameBytes);
|
usernameBytes = legacyCrypto.encrypt({ name: "DES-CBC", iv: secret }, key, usernameBytes);
|
||||||
passwordBytes = legacyCrypto.encrypt({ name: "DES-CBC", iv: secret }, key, passwordBytes);
|
passwordBytes = legacyCrypto.encrypt({ name: "DES-CBC", iv: secret }, key, passwordBytes);
|
||||||
this._sock.send(B);
|
this._sock.sQpushBytes(B);
|
||||||
this._sock.send(usernameBytes);
|
this._sock.sQpushBytes(usernameBytes);
|
||||||
this._sock.send(passwordBytes);
|
this._sock.sQpushBytes(passwordBytes);
|
||||||
|
this._sock.flush();
|
||||||
this._rfbInitState = "SecurityResult";
|
this._rfbInitState = "SecurityResult";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2141,7 +2145,8 @@ export default class RFB extends EventTargetMixin {
|
||||||
return this._handleSecurityReason();
|
return this._handleSecurityReason();
|
||||||
|
|
||||||
case 'ClientInitialisation':
|
case 'ClientInitialisation':
|
||||||
this._sock.send([this._shared ? 1 : 0]); // ClientInitialisation
|
this._sock.sQpush8(this._shared ? 1 : 0); // ClientInitialisation
|
||||||
|
this._sock.flush();
|
||||||
this._rfbInitState = 'ServerInitialisation';
|
this._rfbInitState = 'ServerInitialisation';
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -2887,21 +2892,13 @@ export default class RFB extends EventTargetMixin {
|
||||||
// Class Methods
|
// Class Methods
|
||||||
RFB.messages = {
|
RFB.messages = {
|
||||||
keyEvent(sock, keysym, down) {
|
keyEvent(sock, keysym, down) {
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(4); // msg-type
|
||||||
const offset = sock._sQlen;
|
sock.sQpush8(down);
|
||||||
|
|
||||||
buff[offset] = 4; // msg-type
|
sock.sQpush16(0);
|
||||||
buff[offset + 1] = down;
|
|
||||||
|
|
||||||
buff[offset + 2] = 0;
|
sock.sQpush32(keysym);
|
||||||
buff[offset + 3] = 0;
|
|
||||||
|
|
||||||
buff[offset + 4] = (keysym >> 24);
|
|
||||||
buff[offset + 5] = (keysym >> 16);
|
|
||||||
buff[offset + 6] = (keysym >> 8);
|
|
||||||
buff[offset + 7] = keysym;
|
|
||||||
|
|
||||||
sock._sQlen += 8;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2915,46 +2912,28 @@ RFB.messages = {
|
||||||
return xtScanCode;
|
return xtScanCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(255); // msg-type
|
||||||
const offset = sock._sQlen;
|
sock.sQpush8(0); // sub msg-type
|
||||||
|
|
||||||
buff[offset] = 255; // msg-type
|
sock.sQpush16(down);
|
||||||
buff[offset + 1] = 0; // sub msg-type
|
|
||||||
|
|
||||||
buff[offset + 2] = (down >> 8);
|
sock.sQpush32(keysym);
|
||||||
buff[offset + 3] = down;
|
|
||||||
|
|
||||||
buff[offset + 4] = (keysym >> 24);
|
|
||||||
buff[offset + 5] = (keysym >> 16);
|
|
||||||
buff[offset + 6] = (keysym >> 8);
|
|
||||||
buff[offset + 7] = keysym;
|
|
||||||
|
|
||||||
const RFBkeycode = getRFBkeycode(keycode);
|
const RFBkeycode = getRFBkeycode(keycode);
|
||||||
|
|
||||||
buff[offset + 8] = (RFBkeycode >> 24);
|
sock.sQpush32(RFBkeycode);
|
||||||
buff[offset + 9] = (RFBkeycode >> 16);
|
|
||||||
buff[offset + 10] = (RFBkeycode >> 8);
|
|
||||||
buff[offset + 11] = RFBkeycode;
|
|
||||||
|
|
||||||
sock._sQlen += 12;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
pointerEvent(sock, x, y, mask) {
|
pointerEvent(sock, x, y, mask) {
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(5); // msg-type
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
buff[offset] = 5; // msg-type
|
sock.sQpush8(mask);
|
||||||
|
|
||||||
buff[offset + 1] = mask;
|
sock.sQpush16(x);
|
||||||
|
sock.sQpush16(y);
|
||||||
|
|
||||||
buff[offset + 2] = x >> 8;
|
|
||||||
buff[offset + 3] = x;
|
|
||||||
|
|
||||||
buff[offset + 4] = y >> 8;
|
|
||||||
buff[offset + 5] = y;
|
|
||||||
|
|
||||||
sock._sQlen += 6;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -3054,14 +3033,11 @@ RFB.messages = {
|
||||||
},
|
},
|
||||||
|
|
||||||
clientCutText(sock, data, extended = false) {
|
clientCutText(sock, data, extended = false) {
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(6); // msg-type
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
buff[offset] = 6; // msg-type
|
sock.sQpush8(0); // padding
|
||||||
|
sock.sQpush8(0); // padding
|
||||||
buff[offset + 1] = 0; // padding
|
sock.sQpush8(0); // padding
|
||||||
buff[offset + 2] = 0; // padding
|
|
||||||
buff[offset + 3] = 0; // padding
|
|
||||||
|
|
||||||
let length;
|
let length;
|
||||||
if (extended) {
|
if (extended) {
|
||||||
|
@ -3070,12 +3046,7 @@ RFB.messages = {
|
||||||
length = data.length;
|
length = data.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff[offset + 4] = length >> 24;
|
sock.sQpush32(length);
|
||||||
buff[offset + 5] = length >> 16;
|
|
||||||
buff[offset + 6] = length >> 8;
|
|
||||||
buff[offset + 7] = length;
|
|
||||||
|
|
||||||
sock._sQlen += 8;
|
|
||||||
|
|
||||||
// We have to keep track of from where in the data we begin creating the
|
// We have to keep track of from where in the data we begin creating the
|
||||||
// buffer for the flush in the next iteration.
|
// buffer for the flush in the next iteration.
|
||||||
|
@ -3085,11 +3056,8 @@ RFB.messages = {
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
|
|
||||||
let flushSize = Math.min(remaining, (sock._sQbufferSize - sock._sQlen));
|
let flushSize = Math.min(remaining, (sock._sQbufferSize - sock._sQlen));
|
||||||
for (let i = 0; i < flushSize; i++) {
|
|
||||||
buff[sock._sQlen + i] = data[dataOffset + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
sock._sQlen += flushSize;
|
sock.sQpushBytes(data.subarray(dataOffset, dataOffset + flushSize));
|
||||||
sock.flush();
|
sock.flush();
|
||||||
|
|
||||||
remaining -= flushSize;
|
remaining -= flushSize;
|
||||||
|
@ -3099,92 +3067,57 @@ RFB.messages = {
|
||||||
},
|
},
|
||||||
|
|
||||||
setDesktopSize(sock, width, height, id, flags) {
|
setDesktopSize(sock, width, height, id, flags) {
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(251); // msg-type
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
buff[offset] = 251; // msg-type
|
sock.sQpush8(0); // padding
|
||||||
buff[offset + 1] = 0; // padding
|
|
||||||
buff[offset + 2] = width >> 8; // width
|
|
||||||
buff[offset + 3] = width;
|
|
||||||
buff[offset + 4] = height >> 8; // height
|
|
||||||
buff[offset + 5] = height;
|
|
||||||
|
|
||||||
buff[offset + 6] = 1; // number-of-screens
|
sock.sQpush16(width);
|
||||||
buff[offset + 7] = 0; // padding
|
sock.sQpush16(height);
|
||||||
|
|
||||||
|
sock.sQpush8(1); // number-of-screens
|
||||||
|
|
||||||
|
sock.sQpush8(0); // padding
|
||||||
|
|
||||||
// screen array
|
// screen array
|
||||||
buff[offset + 8] = id >> 24; // id
|
sock.sQpush32(id);
|
||||||
buff[offset + 9] = id >> 16;
|
sock.sQpush16(0); // x-position
|
||||||
buff[offset + 10] = id >> 8;
|
sock.sQpush16(0); // y-position
|
||||||
buff[offset + 11] = id;
|
sock.sQpush16(width);
|
||||||
buff[offset + 12] = 0; // x-position
|
sock.sQpush16(height);
|
||||||
buff[offset + 13] = 0;
|
sock.sQpush32(flags);
|
||||||
buff[offset + 14] = 0; // y-position
|
|
||||||
buff[offset + 15] = 0;
|
|
||||||
buff[offset + 16] = width >> 8; // width
|
|
||||||
buff[offset + 17] = width;
|
|
||||||
buff[offset + 18] = height >> 8; // height
|
|
||||||
buff[offset + 19] = height;
|
|
||||||
buff[offset + 20] = flags >> 24; // flags
|
|
||||||
buff[offset + 21] = flags >> 16;
|
|
||||||
buff[offset + 22] = flags >> 8;
|
|
||||||
buff[offset + 23] = flags;
|
|
||||||
|
|
||||||
sock._sQlen += 24;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
clientFence(sock, flags, payload) {
|
clientFence(sock, flags, payload) {
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(248); // msg-type
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
buff[offset] = 248; // msg-type
|
sock.sQpush8(0); // padding
|
||||||
|
sock.sQpush8(0); // padding
|
||||||
|
sock.sQpush8(0); // padding
|
||||||
|
|
||||||
buff[offset + 1] = 0; // padding
|
sock.sQpush32(flags);
|
||||||
buff[offset + 2] = 0; // padding
|
|
||||||
buff[offset + 3] = 0; // padding
|
|
||||||
|
|
||||||
buff[offset + 4] = flags >> 24; // flags
|
sock.sQpush8(payload.length);
|
||||||
buff[offset + 5] = flags >> 16;
|
sock.sQpushString(payload);
|
||||||
buff[offset + 6] = flags >> 8;
|
|
||||||
buff[offset + 7] = flags;
|
|
||||||
|
|
||||||
const n = payload.length;
|
|
||||||
|
|
||||||
buff[offset + 8] = n; // length
|
|
||||||
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
buff[offset + 9 + i] = payload.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
sock._sQlen += 9 + n;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
enableContinuousUpdates(sock, enable, x, y, width, height) {
|
enableContinuousUpdates(sock, enable, x, y, width, height) {
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(150); // msg-type
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
buff[offset] = 150; // msg-type
|
sock.sQpush8(enable);
|
||||||
buff[offset + 1] = enable; // enable-flag
|
|
||||||
|
|
||||||
buff[offset + 2] = x >> 8; // x
|
sock.sQpush16(x);
|
||||||
buff[offset + 3] = x;
|
sock.sQpush16(y);
|
||||||
buff[offset + 4] = y >> 8; // y
|
sock.sQpush16(width);
|
||||||
buff[offset + 5] = y;
|
sock.sQpush16(height);
|
||||||
buff[offset + 6] = width >> 8; // width
|
|
||||||
buff[offset + 7] = width;
|
|
||||||
buff[offset + 8] = height >> 8; // height
|
|
||||||
buff[offset + 9] = height;
|
|
||||||
|
|
||||||
sock._sQlen += 10;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
pixelFormat(sock, depth, trueColor) {
|
pixelFormat(sock, depth, trueColor) {
|
||||||
const buff = sock._sQ;
|
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
let bpp;
|
let bpp;
|
||||||
|
|
||||||
if (depth > 16) {
|
if (depth > 16) {
|
||||||
|
@ -3197,100 +3130,69 @@ RFB.messages = {
|
||||||
|
|
||||||
const bits = Math.floor(depth/3);
|
const bits = Math.floor(depth/3);
|
||||||
|
|
||||||
buff[offset] = 0; // msg-type
|
sock.sQpush8(0); // msg-type
|
||||||
|
|
||||||
buff[offset + 1] = 0; // padding
|
sock.sQpush8(0); // padding
|
||||||
buff[offset + 2] = 0; // padding
|
sock.sQpush8(0); // padding
|
||||||
buff[offset + 3] = 0; // padding
|
sock.sQpush8(0); // padding
|
||||||
|
|
||||||
buff[offset + 4] = bpp; // bits-per-pixel
|
sock.sQpush8(bpp);
|
||||||
buff[offset + 5] = depth; // depth
|
sock.sQpush8(depth);
|
||||||
buff[offset + 6] = 0; // little-endian
|
sock.sQpush8(0); // little-endian
|
||||||
buff[offset + 7] = trueColor ? 1 : 0; // true-color
|
sock.sQpush8(trueColor ? 1 : 0);
|
||||||
|
|
||||||
buff[offset + 8] = 0; // red-max
|
sock.sQpush16((1 << bits) - 1); // red-max
|
||||||
buff[offset + 9] = (1 << bits) - 1; // red-max
|
sock.sQpush16((1 << bits) - 1); // green-max
|
||||||
|
sock.sQpush16((1 << bits) - 1); // blue-max
|
||||||
|
|
||||||
buff[offset + 10] = 0; // green-max
|
sock.sQpush8(bits * 0); // red-shift
|
||||||
buff[offset + 11] = (1 << bits) - 1; // green-max
|
sock.sQpush8(bits * 1); // green-shift
|
||||||
|
sock.sQpush8(bits * 2); // blue-shift
|
||||||
|
|
||||||
buff[offset + 12] = 0; // blue-max
|
sock.sQpush8(0); // padding
|
||||||
buff[offset + 13] = (1 << bits) - 1; // blue-max
|
sock.sQpush8(0); // padding
|
||||||
|
sock.sQpush8(0); // padding
|
||||||
|
|
||||||
buff[offset + 14] = bits * 0; // red-shift
|
|
||||||
buff[offset + 15] = bits * 1; // green-shift
|
|
||||||
buff[offset + 16] = bits * 2; // blue-shift
|
|
||||||
|
|
||||||
buff[offset + 17] = 0; // padding
|
|
||||||
buff[offset + 18] = 0; // padding
|
|
||||||
buff[offset + 19] = 0; // padding
|
|
||||||
|
|
||||||
sock._sQlen += 20;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
clientEncodings(sock, encodings) {
|
clientEncodings(sock, encodings) {
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(2); // msg-type
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
buff[offset] = 2; // msg-type
|
sock.sQpush8(0); // padding
|
||||||
buff[offset + 1] = 0; // padding
|
|
||||||
|
|
||||||
buff[offset + 2] = encodings.length >> 8;
|
sock.sQpush16(encodings.length);
|
||||||
buff[offset + 3] = encodings.length;
|
|
||||||
|
|
||||||
let j = offset + 4;
|
|
||||||
for (let i = 0; i < encodings.length; i++) {
|
for (let i = 0; i < encodings.length; i++) {
|
||||||
const enc = encodings[i];
|
sock.sQpush32(encodings[i]);
|
||||||
buff[j] = enc >> 24;
|
|
||||||
buff[j + 1] = enc >> 16;
|
|
||||||
buff[j + 2] = enc >> 8;
|
|
||||||
buff[j + 3] = enc;
|
|
||||||
|
|
||||||
j += 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sock._sQlen += j - offset;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
fbUpdateRequest(sock, incremental, x, y, w, h) {
|
fbUpdateRequest(sock, incremental, x, y, w, h) {
|
||||||
const buff = sock._sQ;
|
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
if (typeof(x) === "undefined") { x = 0; }
|
if (typeof(x) === "undefined") { x = 0; }
|
||||||
if (typeof(y) === "undefined") { y = 0; }
|
if (typeof(y) === "undefined") { y = 0; }
|
||||||
|
|
||||||
buff[offset] = 3; // msg-type
|
sock.sQpush8(3); // msg-type
|
||||||
buff[offset + 1] = incremental ? 1 : 0;
|
|
||||||
|
|
||||||
buff[offset + 2] = (x >> 8) & 0xFF;
|
sock.sQpush8(incremental ? 1 : 0);
|
||||||
buff[offset + 3] = x & 0xFF;
|
|
||||||
|
|
||||||
buff[offset + 4] = (y >> 8) & 0xFF;
|
sock.sQpush16(x);
|
||||||
buff[offset + 5] = y & 0xFF;
|
sock.sQpush16(y);
|
||||||
|
sock.sQpush16(w);
|
||||||
|
sock.sQpush16(h);
|
||||||
|
|
||||||
buff[offset + 6] = (w >> 8) & 0xFF;
|
|
||||||
buff[offset + 7] = w & 0xFF;
|
|
||||||
|
|
||||||
buff[offset + 8] = (h >> 8) & 0xFF;
|
|
||||||
buff[offset + 9] = h & 0xFF;
|
|
||||||
|
|
||||||
sock._sQlen += 10;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
},
|
},
|
||||||
|
|
||||||
xvpOp(sock, ver, op) {
|
xvpOp(sock, ver, op) {
|
||||||
const buff = sock._sQ;
|
sock.sQpush8(250); // msg-type
|
||||||
const offset = sock._sQlen;
|
|
||||||
|
|
||||||
buff[offset] = 250; // msg-type
|
sock.sQpush8(0); // padding
|
||||||
buff[offset + 1] = 0; // padding
|
|
||||||
|
|
||||||
buff[offset + 2] = ver;
|
sock.sQpush8(ver);
|
||||||
buff[offset + 3] = op;
|
sock.sQpush8(op);
|
||||||
|
|
||||||
sock._sQlen += 4;
|
|
||||||
sock.flush();
|
sock.flush();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -175,6 +175,32 @@ export default class Websock {
|
||||||
|
|
||||||
// Send Queue
|
// Send Queue
|
||||||
|
|
||||||
|
sQpush8(num) {
|
||||||
|
this._sQ[this._sQlen++] = num;
|
||||||
|
}
|
||||||
|
|
||||||
|
sQpush16(num) {
|
||||||
|
this._sQ[this._sQlen++] = (num >> 8) & 0xff;
|
||||||
|
this._sQ[this._sQlen++] = (num >> 0) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
sQpush32(num) {
|
||||||
|
this._sQ[this._sQlen++] = (num >> 24) & 0xff;
|
||||||
|
this._sQ[this._sQlen++] = (num >> 16) & 0xff;
|
||||||
|
this._sQ[this._sQlen++] = (num >> 8) & 0xff;
|
||||||
|
this._sQ[this._sQlen++] = (num >> 0) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
sQpushString(str) {
|
||||||
|
let bytes = str.split('').map(chr => chr.charCodeAt(0));
|
||||||
|
this.sQpushBytes(new Uint8Array(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
sQpushBytes(bytes) {
|
||||||
|
this._sQ.set(bytes, this._sQlen);
|
||||||
|
this._sQlen += bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
flush() {
|
flush() {
|
||||||
if (this._sQlen > 0 && this.readyState === 'open') {
|
if (this._sQlen > 0 && this.readyState === 'open') {
|
||||||
this._websocket.send(new Uint8Array(this._sQ.buffer, 0, this._sQlen));
|
this._websocket.send(new Uint8Array(this._sQ.buffer, 0, this._sQlen));
|
||||||
|
@ -182,16 +208,6 @@ export default class Websock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
send(arr) {
|
|
||||||
this._sQ.set(arr, this._sQlen);
|
|
||||||
this._sQlen += arr.length;
|
|
||||||
this.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
sendString(str) {
|
|
||||||
this.send(str.split('').map(chr => chr.charCodeAt(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event Handlers
|
// Event Handlers
|
||||||
off(evt) {
|
off(evt) {
|
||||||
this._eventHandlers[evt] = () => {};
|
this._eventHandlers[evt] = () => {};
|
||||||
|
|
|
@ -157,6 +157,66 @@ describe('Websock', function () {
|
||||||
sock.attach(websock);
|
sock.attach(websock);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('sQpush8()', function () {
|
||||||
|
it('should send a single byte', function () {
|
||||||
|
sock.sQpush8(42);
|
||||||
|
sock.flush();
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([42]));
|
||||||
|
});
|
||||||
|
it('should not send any data until flushing', function () {
|
||||||
|
sock.sQpush8(42);
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sQpush16()', function () {
|
||||||
|
it('should send a number as two bytes', function () {
|
||||||
|
sock.sQpush16(420);
|
||||||
|
sock.flush();
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([1, 164]));
|
||||||
|
});
|
||||||
|
it('should not send any data until flushing', function () {
|
||||||
|
sock.sQpush16(420);
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sQpush32()', function () {
|
||||||
|
it('should send a number as two bytes', function () {
|
||||||
|
sock.sQpush32(420420);
|
||||||
|
sock.flush();
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([0, 6, 106, 68]));
|
||||||
|
});
|
||||||
|
it('should not send any data until flushing', function () {
|
||||||
|
sock.sQpush32(420420);
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sQpushString()', function () {
|
||||||
|
it('should send a string buffer', function () {
|
||||||
|
sock.sQpushString('\x12\x34\x56\x78\x90');
|
||||||
|
sock.flush();
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x90]));
|
||||||
|
});
|
||||||
|
it('should not send any data until flushing', function () {
|
||||||
|
sock.sQpushString('\x12\x34\x56\x78\x90');
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sQpushBytes()', function () {
|
||||||
|
it('should send a byte buffer', function () {
|
||||||
|
sock.sQpushBytes(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x90]));
|
||||||
|
sock.flush();
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x90]));
|
||||||
|
});
|
||||||
|
it('should not send any data until flushing', function () {
|
||||||
|
sock.sQpushBytes(new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x90]));
|
||||||
|
expect(sock).to.have.sent(new Uint8Array([]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('flush', function () {
|
describe('flush', function () {
|
||||||
it('should actually send on the websocket', function () {
|
it('should actually send on the websocket', function () {
|
||||||
sock._sQ = new Uint8Array([1, 2, 3]);
|
sock._sQ = new Uint8Array([1, 2, 3]);
|
||||||
|
@ -174,20 +234,6 @@ describe('Websock', function () {
|
||||||
expect(sock).to.have.sent(new Uint8Array([]));
|
expect(sock).to.have.sent(new Uint8Array([]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('send', function () {
|
|
||||||
it('should send the given data immediately', function () {
|
|
||||||
sock.send([1, 2, 3]);
|
|
||||||
expect(sock).to.have.sent(new Uint8Array([1, 2, 3]));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('sendString', function () {
|
|
||||||
it('should send after converting the string to an array', function () {
|
|
||||||
sock.sendString("\x01\x02\x03");
|
|
||||||
expect(sock).to.have.sent(new Uint8Array([1, 2, 3]));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('lifecycle methods', function () {
|
describe('lifecycle methods', function () {
|
||||||
|
|
Loading…
Reference in New Issue