Skip to content

Commit

Permalink
Added handshakeType to allow increase wait for ws/wss handshake.
Browse files Browse the repository at this point in the history
For long latency clients then may not be able to deliver the websocket
handshake before we fall back to regular the RFB protocol.

So to not introduce a multisecond delay for all conenction a handshakeType
setting is introduced to tell which type of handshake we expect.

The problem is that a RFB client will be quiet "forever" until the server
sends it's signature. On the other hand a websocket client will send it's
HTTP websocket handshake immediately.

Before the server for sure know the the type of client the connect procedure
cannot continue. There is no other option than to wait for some amount of time
when the client type is auto detected.
  • Loading branch information
sgh committed Apr 29, 2022
1 parent 1c51df2 commit fca39ff
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 7 deletions.
21 changes: 14 additions & 7 deletions libvncserver/websockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ Connection: Upgrade\r\n\
Sec-WebSocket-Accept: %s\r\n\
\r\n"

#define WEBSOCKETS_CLIENT_CONNECT_WAIT_MS 100
#define WEBSOCKETS_CLIENT_SEND_WAIT_MS 100
#define WEBSOCKETS_CLIENT_CONNECT_WAIT_MS 500
#define WEBSOCKETS_MAX_HANDSHAKE_LEN 4096

#if defined(__linux__) && defined(NEED_TIMEVAL)
Expand Down Expand Up @@ -119,8 +118,17 @@ webSocketsCheck (rfbClientPtr cl)
char bbuf[4], *scheme;
int ret;

ret = rfbPeekExactTimeout(cl, bbuf, 4,
WEBSOCKETS_CLIENT_CONNECT_WAIT_MS);
int timeout = WEBSOCKETS_CLIENT_CONNECT_WAIT_MS;
switch (cl->screen->handshake_type) {
case RFB_HANDSHAKE_AUTO:
timeout = cl->screen->maxClientWait ? cl->screen->maxClientWait : rfbMaxClientWait;
break;
case RFB_HANDSHAKE_WEBSOCKET:
timeout = WEBSOCKETS_CLIENT_CONNECT_WAIT_MS;
break;
}

ret = rfbPeekExactTimeout(cl, bbuf, 4, timeout);
if ((ret < 0) && (errno == ETIMEDOUT)) {
rfbLog("Normal socket connection\n");
return TRUE;
Expand All @@ -138,7 +146,7 @@ webSocketsCheck (rfbClientPtr cl)
rfbErr("webSocketsHandshake: rfbssl_init failed\n");
return FALSE;
}
ret = rfbPeekExactTimeout(cl, bbuf, 4, WEBSOCKETS_CLIENT_CONNECT_WAIT_MS);
ret = rfbPeekExactTimeout(cl, bbuf, 4, timeout);
scheme = "wss";
} else {
scheme = "ws";
Expand Down Expand Up @@ -183,8 +191,7 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme)
}

while (len < WEBSOCKETS_MAX_HANDSHAKE_LEN-1) {
if ((n = rfbReadExactTimeout(cl, buf+len, 1,
WEBSOCKETS_CLIENT_SEND_WAIT_MS)) <= 0) {
if ((n = rfbReadExact(cl, buf+len, 1)) <= 0) {
if ((n < 0) && (errno == ETIMEDOUT)) {
break;
}
Expand Down
15 changes: 15 additions & 0 deletions rfb/rfb.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ enum rfbSocketState {
RFB_SOCKET_SHUTDOWN
};

enum rfbHandshakeType {
RFB_HANDSHAKE_AUTO,
RFB_HANDSHAKE_WEBSOCKET,
};

typedef void (*rfbKbdAddEventProcPtr) (rfbBool down, rfbKeySym keySym, struct _rfbClientRec* cl);
typedef void (*rfbKbdReleaseAllKeysProcPtr) (struct _rfbClientRec* cl);
typedef void (*rfbPtrAddEventProcPtr) (int buttonMask, int x, int y, struct _rfbClientRec* cl);
Expand Down Expand Up @@ -372,6 +377,16 @@ typedef struct _rfbScreenInfo
#ifdef LIBVNCSERVER_HAVE_LIBZ
rfbSetXCutTextUTF8ProcPtr setXCutTextUTF8;
#endif
/** This setting specifies the handshake type to expect.
* WebSocket clients are detected by the presence of a special handshake.
* The handshake can only be detected by waiting some time for it. Normal
* RFB clients do not transmit an initial handshake.
*
* RFB_HANDSHAKE_AUTO - wait 100ms for WS handshake. Then fall back to normal RFB.
* RFB_HANDSHAKE_WEBSOCKET - wait 500ms for WS handshake.
*
*/
enum rfbHandshakeType handshake_type;
} rfbScreenInfo, *rfbScreenInfoPtr;


Expand Down

0 comments on commit fca39ff

Please sign in to comment.