VNC-275 implement explicit keepalive (#172)
* VNC-275 implement explicit keepalive * VNC-275 graceful disconnect --------- Co-authored-by: Matt McClaskey <matt@kasmweb.com>
This commit is contained in:
parent
0baf17a263
commit
887662b0ad
|
|
@ -1579,7 +1579,7 @@ const UI = {
|
|||
}, 10000);
|
||||
} else {
|
||||
//send keep-alive
|
||||
UI.rfb.sendKey(1, null, false);
|
||||
UI.rfb.sendKeepAlive();
|
||||
}
|
||||
}
|
||||
}, 5000);
|
||||
|
|
@ -1856,7 +1856,11 @@ const UI = {
|
|||
},
|
||||
|
||||
disconnectedRx(event) {
|
||||
parent.postMessage({ action: 'disconnectrx', value: event.detail.reason}, '*' );
|
||||
const detail = event.detail || {};
|
||||
if (detail.serverNotice && detail.serverNotice.graceful) {
|
||||
return;
|
||||
}
|
||||
parent.postMessage({ action: 'disconnectrx', value: detail.reason}, '*' );
|
||||
},
|
||||
|
||||
toggleNav(){
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ export const encodings = {
|
|||
pseudoEncodingVideoOutTimeLevel1: -1986,
|
||||
pseudoEncodingVideoOutTimeLevel100: -1887,
|
||||
pseudoEncodingQOI: -1886,
|
||||
pseudoEncodingKasmDisconnectNotify: -1885,
|
||||
|
||||
pseudoEncodingVMwareCursor: 0x574d5664,
|
||||
pseudoEncodingVMwareCursorPosition: 0x574d5666,
|
||||
|
|
|
|||
98
core/rfb.js
98
core/rfb.js
|
|
@ -43,6 +43,8 @@ import { toSignedRelative16bit } from './util/int.js';
|
|||
// How many seconds to wait for a disconnect to finish
|
||||
const DISCONNECT_TIMEOUT = 3;
|
||||
const DEFAULT_BACKGROUND = 'rgb(40, 40, 40)';
|
||||
const CLIENT_MSG_TYPE_KEEPALIVE = 184;
|
||||
const SERVER_MSG_TYPE_DISCONNECT_NOTIFY = 185;
|
||||
|
||||
// Minimum wait (ms) between two mouse moves
|
||||
const MOUSE_MOVE_DELAY = 17;
|
||||
|
|
@ -105,6 +107,10 @@ export default class RFB extends EventTargetMixin {
|
|||
this._rfbInitState = '';
|
||||
this._rfbAuthScheme = -1;
|
||||
this._rfbCleanDisconnect = true;
|
||||
this._disconnectReason = null;
|
||||
this._disconnectCode = null;
|
||||
this._serverDisconnectNotice = null;
|
||||
this._lastServerDisconnectNotice = null;
|
||||
|
||||
// Server capabilities
|
||||
this._rfbVersion = 0;
|
||||
|
|
@ -996,6 +1002,16 @@ export default class RFB extends EventTargetMixin {
|
|||
}
|
||||
}
|
||||
|
||||
sendKeepAlive() {
|
||||
if (this._rfbConnectionState !== 'connected') { return; }
|
||||
|
||||
if (this._isPrimaryDisplay) {
|
||||
RFB.messages.keepAlive(this._sock);
|
||||
} else {
|
||||
this._proxyRFBMessage('keepAlive', []);
|
||||
}
|
||||
}
|
||||
|
||||
focus() {
|
||||
this._keyboard.focus();
|
||||
}
|
||||
|
|
@ -1178,7 +1194,26 @@ export default class RFB extends EventTargetMixin {
|
|||
}
|
||||
msg += ")";
|
||||
}
|
||||
switch (this._rfbConnectionState) {
|
||||
if (typeof e.code === 'number') {
|
||||
this._disconnectCode = e.code;
|
||||
}
|
||||
|
||||
if (e.reason) {
|
||||
this._disconnectReason = e.reason;
|
||||
}
|
||||
|
||||
if (this._serverDisconnectNotice) {
|
||||
const notice = this._serverDisconnectNotice;
|
||||
if (notice.reason && !this._disconnectReason) {
|
||||
this._disconnectReason = notice.reason;
|
||||
}
|
||||
this._rfbCleanDisconnect = !!notice.graceful;
|
||||
this._lastServerDisconnectNotice = notice;
|
||||
this._serverDisconnectNotice = null;
|
||||
} else if (e.wasClean === false || e.code === 1006) {
|
||||
this._rfbCleanDisconnect = false;
|
||||
}
|
||||
switch (this._rfbConnectionState) {
|
||||
case 'connecting':
|
||||
this._fail("Connection closed " + msg);
|
||||
break;
|
||||
|
|
@ -1723,6 +1758,14 @@ export default class RFB extends EventTargetMixin {
|
|||
|
||||
Log.Debug("New state '" + state + "', was '" + oldstate + "'.");
|
||||
|
||||
if (state === 'connecting') {
|
||||
this._disconnectReason = null;
|
||||
this._disconnectCode = null;
|
||||
this._serverDisconnectNotice = null;
|
||||
this._lastServerDisconnectNotice = null;
|
||||
this._rfbCleanDisconnect = true;
|
||||
}
|
||||
|
||||
if (this._disconnTimer && state !== 'disconnecting') {
|
||||
Log.Debug("Clearing disconnect timer");
|
||||
clearTimeout(this._disconnTimer);
|
||||
|
|
@ -1756,7 +1799,13 @@ export default class RFB extends EventTargetMixin {
|
|||
case 'disconnected':
|
||||
this.dispatchEvent(new CustomEvent(
|
||||
"disconnect", { detail:
|
||||
{ clean: this._rfbCleanDisconnect } }));
|
||||
{ clean: this._rfbCleanDisconnect,
|
||||
reason: this._disconnectReason,
|
||||
code: this._disconnectCode,
|
||||
serverNotice: this._lastServerDisconnectNotice } }));
|
||||
this._disconnectReason = null;
|
||||
this._disconnectCode = null;
|
||||
this._lastServerDisconnectNotice = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1781,6 +1830,9 @@ export default class RFB extends EventTargetMixin {
|
|||
Log.Error("RFB failure: " + details);
|
||||
break;
|
||||
}
|
||||
this._disconnectReason = details;
|
||||
this._disconnectCode = null;
|
||||
this._serverDisconnectNotice = null;
|
||||
this._rfbCleanDisconnect = false; //This is sent to the UI
|
||||
|
||||
// Transition to disconnected without waiting for socket to close
|
||||
|
|
@ -1890,6 +1942,9 @@ export default class RFB extends EventTargetMixin {
|
|||
RFB.messages.pointerEvent(this._sock, this._mousePos.x, this._mousePos.y, 0, event.data.args[2], event.data.args[3]);
|
||||
this._setLastActive();
|
||||
break;
|
||||
case 'keepAlive':
|
||||
RFB.messages.keepAlive(this._sock);
|
||||
break;
|
||||
case 'keyEvent':
|
||||
RFB.messages.keyEvent(this._sock, ...event.data.args);
|
||||
this._setLastActive();
|
||||
|
|
@ -3163,6 +3218,7 @@ export default class RFB extends EventTargetMixin {
|
|||
encs.push(encodings.pseudoEncodingContinuousUpdates);
|
||||
encs.push(encodings.pseudoEncodingDesktopName);
|
||||
encs.push(encodings.pseudoEncodingExtendedClipboard);
|
||||
encs.push(encodings.pseudoEncodingKasmDisconnectNotify);
|
||||
if (this._hasWebp())
|
||||
encs.push(encodings.pseudoEncodingWEBP);
|
||||
if (this._enableQOI)
|
||||
|
|
@ -3692,6 +3748,8 @@ export default class RFB extends EventTargetMixin {
|
|||
|
||||
case 183: // KASM unix relay data
|
||||
return this._handleUnixRelay();
|
||||
case SERVER_MSG_TYPE_DISCONNECT_NOTIFY: // KASM disconnect notice
|
||||
return this._handleDisconnectNotify();
|
||||
|
||||
case 248: // ServerFence
|
||||
return this._handleServerFenceMsg();
|
||||
|
|
@ -3857,6 +3915,32 @@ export default class RFB extends EventTargetMixin {
|
|||
processRelay && processRelay(payload);
|
||||
}
|
||||
|
||||
_handleDisconnectNotify() {
|
||||
if (this._sock.rQwait("DisconnectNotify header", 8, 1)) { return false; }
|
||||
const flags = this._sock.rQshift8();
|
||||
this._sock.rQskipBytes(3);
|
||||
const reasonLength = this._sock.rQshift32();
|
||||
if (reasonLength > 0 && this._sock.rQwait("DisconnectNotify reason", reasonLength, 8)) { return false; }
|
||||
|
||||
let reason = null;
|
||||
if (reasonLength > 0) {
|
||||
reason = this._sock.rQshiftStr(reasonLength);
|
||||
}
|
||||
|
||||
const graceful = (flags & 0x1) !== 0;
|
||||
this._serverDisconnectNotice = { flags, reason, graceful };
|
||||
|
||||
if (reason !== null) {
|
||||
this._disconnectReason = reason;
|
||||
}
|
||||
|
||||
if (graceful) {
|
||||
this._rfbCleanDisconnect = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_framebufferUpdate() {
|
||||
if (this._FBU.rects === 0) {
|
||||
if (this._sock.rQwait("FBU header", 3, 1)) { return false; }
|
||||
|
|
@ -4425,6 +4509,16 @@ RFB.messages = {
|
|||
sock.flush();
|
||||
},
|
||||
|
||||
keepAlive(sock) {
|
||||
const buff = sock._sQ;
|
||||
const offset = sock._sQlen;
|
||||
|
||||
buff[offset] = CLIENT_MSG_TYPE_KEEPALIVE;
|
||||
|
||||
sock._sQlen += 1;
|
||||
sock.flush();
|
||||
},
|
||||
|
||||
// Used to build Notify and Request data.
|
||||
_buildExtendedClipboardFlags(actions, formats) {
|
||||
let data = new Uint8Array(4);
|
||||
|
|
|
|||
Loading…
Reference in New Issue