diff options
Diffstat (limited to 'libvncserver/websockets.c')
-rw-r--r-- | libvncserver/websockets.c | 613 |
1 files changed, 72 insertions, 541 deletions
diff --git a/libvncserver/websockets.c b/libvncserver/websockets.c index f5dd120..4361bdd 100644 --- a/libvncserver/websockets.c +++ b/libvncserver/websockets.c @@ -30,10 +30,6 @@ /* errno */ #include <errno.h> -#ifndef _MSC_VER -#include <resolv.h> /* __b64_ntop */ -#endif - #ifdef LIBVNCSERVER_HAVE_ENDIAN_H #include <endian.h> #elif LIBVNCSERVER_HAVE_SYS_ENDIAN_H @@ -45,24 +41,14 @@ #endif #include <string.h> +#if LIBVNCSERVER_UNISTD_H #include <unistd.h> +#endif #include "rfb/rfbconfig.h" #include "rfbssl.h" #include "rfbcrypto.h" - -#define WS_NTOH64(n) htobe64(n) -#define WS_NTOH32(n) htobe32(n) -#define WS_NTOH16(n) htobe16(n) -#define WS_HTON64(n) htobe64(n) -#define WS_HTON16(n) htobe16(n) - -#define B64LEN(__x) (((__x + 2) / 3) * 12 / 3) -#define WSHLENMAX 14 /* 2 + sizeof(uint64_t) + sizeof(uint32_t) */ - -enum { - WEBSOCKETS_VERSION_HIXIE, - WEBSOCKETS_VERSION_HYBI -}; +#include "ws_decode.h" +#include "base64.h" #if 0 #include <sys/syscall.h> @@ -71,77 +57,12 @@ static int gettid() { } #endif -typedef int (*wsEncodeFunc)(rfbClientPtr cl, const char *src, int len, char **dst); -typedef int (*wsDecodeFunc)(rfbClientPtr cl, char *dst, int len); - -typedef struct ws_ctx_s { - char codeBufDecode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ - char codeBufEncode[B64LEN(UPDATE_BUF_SIZE) + WSHLENMAX]; /* base64 + maximum frame header length */ - char readbuf[8192]; - int readbufstart; - int readbuflen; - int dblen; - char carryBuf[3]; /* For base64 carry-over */ - int carrylen; - int version; - int base64; - wsEncodeFunc encode; - wsDecodeFunc decode; -} ws_ctx_t; - -typedef union ws_mask_s { - char c[4]; - uint32_t u; -} ws_mask_t; - -/* XXX: The union and the structs do not need to be named. - * We are working around a bug present in GCC < 4.6 which prevented - * it from recognizing anonymous structs and unions. - * See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=4784 - */ -typedef struct __attribute__ ((__packed__)) ws_header_s { - unsigned char b0; - unsigned char b1; - union { - struct __attribute__ ((__packed__)) { - uint16_t l16; - ws_mask_t m16; - } s16; - struct __attribute__ ((__packed__)) { - uint64_t l64; - ws_mask_t m64; - } s64; - ws_mask_t m; - } u; -} ws_header_t; - -enum -{ - WS_OPCODE_CONTINUATION = 0x0, - WS_OPCODE_TEXT_FRAME, - WS_OPCODE_BINARY_FRAME, - WS_OPCODE_CLOSE = 0x8, - WS_OPCODE_PING, - WS_OPCODE_PONG -}; - -#define FLASH_POLICY_RESPONSE "<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\n" -#define SZ_FLASH_POLICY_RESPONSE 93 - /* * draft-ietf-hybi-thewebsocketprotocol-10 * 5.2.2. Sending the Server's Opening Handshake */ #define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" -#define SERVER_HANDSHAKE_HIXIE "HTTP/1.1 101 Web Socket Protocol Handshake\r\n\ -Upgrade: WebSocket\r\n\ -Connection: Upgrade\r\n\ -%sWebSocket-Origin: %s\r\n\ -%sWebSocket-Location: %s://%s%s\r\n\ -%sWebSocket-Protocol: %s\r\n\ -\r\n%s" - #define SERVER_HANDSHAKE_HYBI "HTTP/1.1 101 Switching Protocols\r\n\ Upgrade: websocket\r\n\ Connection: Upgrade\r\n\ @@ -168,12 +89,11 @@ struct timeval #endif static rfbBool webSocketsHandshake(rfbClientPtr cl, char *scheme); -void webSocketsGenMd5(char * target, char *key1, char *key2, char *key3); static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst); -static int webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char **dst); -static int webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len); -static int webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len); + +static int ws_read(void *cl, char *buf, size_t len); + static int min (int a, int b) { @@ -190,8 +110,8 @@ static void webSocketsGenSha1Key(char *target, int size, char *key) iov[1].iov_base = GUID; iov[1].iov_len = sizeof(GUID) - 1; digestsha1(iov, 2, hash); - if (-1 == __b64_ntop(hash, sizeof(hash), target, size)) - rfbErr("b64_ntop failed\n"); + if (-1 == rfbBase64NtoP(hash, sizeof(hash), target, size)) + rfbErr("rfbBase64NtoP failed\n"); } /* @@ -214,13 +134,9 @@ webSocketsCheck (rfbClientPtr cl) return FALSE; } - if (strncmp(bbuf, "<", 1) == 0) { - rfbLog("Got Flash policy request, sending response\n"); - if (rfbWriteExact(cl, FLASH_POLICY_RESPONSE, - SZ_FLASH_POLICY_RESPONSE) < 0) { - rfbErr("webSocketsHandshake: failed sending Flash policy response"); - } - return FALSE; + if (strncmp(bbuf, "RFB ", 4) == 0) { + rfbLog("Normal socket connection\n"); + return TRUE; } else if (strncmp(bbuf, "\x16", 1) == 0 || strncmp(bbuf, "\x80", 1) == 0) { rfbLog("Got TLS/SSL WebSockets connection\n"); if (-1 == rfbssl_init(cl)) { @@ -278,10 +194,13 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) if ((n < 0) && (errno == ETIMEDOUT)) { break; } - if (n == 0) + if (n == 0) { rfbLog("webSocketsHandshake: client gone\n"); - else + } + else { rfbLogPerror("webSocketsHandshake: read"); + } + free(response); free(buf); return FALSE; @@ -336,24 +255,33 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) /* rfbLog("Got key2: %s\n", key2); */ /* HyBI */ - } else if ((strncasecmp("sec-websocket-protocol: ", line, min(llen,24))) == 0) { + } else if ((strncasecmp("sec-websocket-protocol: ", line, min(llen,24))) == 0) { protocol = line+24; buf[len-2] = '\0'; rfbLog("Got protocol: %s\n", protocol); } else if ((strncasecmp("sec-websocket-origin: ", line, min(llen,22))) == 0) { - sec_ws_origin = line+22; + sec_ws_origin = line+22; buf[len-2] = '\0'; } else if ((strncasecmp("sec-websocket-key: ", line, min(llen,19))) == 0) { - sec_ws_key = line+19; + sec_ws_key = line+19; buf[len-2] = '\0'; } else if ((strncasecmp("sec-websocket-version: ", line, min(llen,23))) == 0) { - sec_ws_version = strtol(line+23, NULL, 10); + sec_ws_version = strtol(line+23, NULL, 10); buf[len-2] = '\0'; - } + } linestart = len; } } + + /* older hixie handshake, this could be removed if + * a final standard is established -- removed now */ + if (!sec_ws_version) { + rfbErr("Hixie no longer supported\n"); + free(response); + free(buf); + return FALSE; + } if (!(path && host && (origin || sec_ws_origin))) { rfbErr("webSocketsHandshake: incomplete client handshake\n"); @@ -363,12 +291,6 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) } if ((protocol) && (strstr(protocol, "binary"))) { - if (! sec_ws_version) { - rfbErr("webSocketsHandshake: 'binary' protocol not supported with Hixie\n"); - free(response); - free(buf); - return FALSE; - } rfbLog(" - webSocketsHandshake: using binary/raw encoding\n"); base64 = FALSE; protocol = "binary"; @@ -386,32 +308,16 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) * Generate the WebSockets server response based on the the headers sent * by the client. */ + char accept[B64LEN(SHA1_HASH_SIZE) + 1]; + rfbLog(" - WebSockets client version hybi-%02d\n", sec_ws_version); + webSocketsGenSha1Key(accept, sizeof(accept), sec_ws_key); - if (sec_ws_version) { - char accept[B64LEN(SHA1_HASH_SIZE) + 1]; - rfbLog(" - WebSockets client version hybi-%02d\n", sec_ws_version); - webSocketsGenSha1Key(accept, sizeof(accept), sec_ws_key); - if(strlen(protocol) > 0) - len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, - SERVER_HANDSHAKE_HYBI, accept, protocol); - else - len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, - SERVER_HANDSHAKE_HYBI_NO_PROTOCOL, accept); + if(strlen(protocol) > 0) { + len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, + SERVER_HANDSHAKE_HYBI, accept, protocol); } else { - /* older hixie handshake, this could be removed if - * a final standard is established */ - if (!(key1 && key2 && key3)) { - rfbLog(" - WebSockets client version hixie-75\n"); - prefix[0] = '\0'; - trailer[0] = '\0'; - } else { - rfbLog(" - WebSockets client version hixie-76\n"); - snprintf(prefix, 5, "Sec-"); - webSocketsGenMd5(trailer, key1, key2, key3); - } - len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, - SERVER_HANDSHAKE_HIXIE, prefix, origin, prefix, scheme, - host, path, prefix, protocol, trailer); + len = snprintf(response, WEBSOCKETS_MAX_HANDSHAKE_LEN, + SERVER_HANDSHAKE_HYBI_NO_PROTOCOL, accept); } if (rfbWriteExact(cl, response, len) < 0) { @@ -424,357 +330,30 @@ webSocketsHandshake(rfbClientPtr cl, char *scheme) free(response); free(buf); - wsctx = calloc(1, sizeof(ws_ctx_t)); - if (sec_ws_version) { - wsctx->version = WEBSOCKETS_VERSION_HYBI; - wsctx->encode = webSocketsEncodeHybi; - wsctx->decode = webSocketsDecodeHybi; - } else { - wsctx->version = WEBSOCKETS_VERSION_HIXIE; - wsctx->encode = webSocketsEncodeHixie; - wsctx->decode = webSocketsDecodeHixie; - } + wsctx->encode = webSocketsEncodeHybi; + wsctx->decode = webSocketsDecodeHybi; + wsctx->ctxInfo.readFunc = ws_read; wsctx->base64 = base64; + hybiDecodeCleanupComplete(wsctx); cl->wsctx = (wsCtx *)wsctx; return TRUE; } - -void -webSocketsGenMd5(char * target, char *key1, char *key2, char *key3) -{ - unsigned int i, spaces1 = 0, spaces2 = 0; - unsigned long num1 = 0, num2 = 0; - unsigned char buf[17]; - struct iovec iov[1]; - - for (i=0; i < strlen(key1); i++) { - if (key1[i] == ' ') { - spaces1 += 1; - } - if ((key1[i] >= 48) && (key1[i] <= 57)) { - num1 = num1 * 10 + (key1[i] - 48); - } - } - num1 = num1 / spaces1; - - for (i=0; i < strlen(key2); i++) { - if (key2[i] == ' ') { - spaces2 += 1; - } - if ((key2[i] >= 48) && (key2[i] <= 57)) { - num2 = num2 * 10 + (key2[i] - 48); - } - } - num2 = num2 / spaces2; - - /* Pack it big-endian */ - buf[0] = (num1 & 0xff000000) >> 24; - buf[1] = (num1 & 0xff0000) >> 16; - buf[2] = (num1 & 0xff00) >> 8; - buf[3] = num1 & 0xff; - - buf[4] = (num2 & 0xff000000) >> 24; - buf[5] = (num2 & 0xff0000) >> 16; - buf[6] = (num2 & 0xff00) >> 8; - buf[7] = num2 & 0xff; - - strncpy((char *)buf+8, key3, 8); - buf[16] = '\0'; - - iov[0].iov_base = buf; - iov[0].iov_len = 16; - digestmd5(iov, 1, target); - target[16] = '\0'; - - return; -} static int -webSocketsEncodeHixie(rfbClientPtr cl, const char *src, int len, char **dst) -{ - int sz = 0; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - - wsctx->codeBufEncode[sz++] = '\x00'; - len = __b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode+sz, sizeof(wsctx->codeBufEncode) - (sz + 1)); - if (len < 0) { - return len; - } - sz += len; - - wsctx->codeBufEncode[sz++] = '\xff'; - *dst = wsctx->codeBufEncode; - return sz; -} - -static int -ws_read(rfbClientPtr cl, char *buf, int len) +ws_read(void *ctxPtr, char *buf, size_t len) { int n; + rfbClientPtr cl = ctxPtr; if (cl->sslctx) { - n = rfbssl_read(cl, buf, len); + n = rfbssl_read(cl, buf, len); } else { - n = read(cl->sock, buf, len); + n = read(cl->sock, buf, len); } return n; } static int -ws_peek(rfbClientPtr cl, char *buf, int len) -{ - int n; - if (cl->sslctx) { - n = rfbssl_peek(cl, buf, len); - } else { - while (-1 == (n = recv(cl->sock, buf, len, MSG_PEEK))) { - if (errno != EAGAIN) - break; - } - } - return n; -} - -static int -webSocketsDecodeHixie(rfbClientPtr cl, char *dst, int len) -{ - int retlen = 0, n, i, avail, modlen, needlen; - char *buf, *end = NULL; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - - buf = wsctx->codeBufDecode; - - n = ws_peek(cl, buf, len*2+2); - - if (n <= 0) { - /* save errno because rfbErr() will tamper it */ - int olderrno = errno; - rfbErr("%s: peek (%d) %m\n", __func__, errno); - errno = olderrno; - return n; - } - - - /* Base64 encoded WebSockets stream */ - - if (buf[0] == '\xff') { - i = ws_read(cl, buf, 1); /* Consume marker */ - buf++; - n--; - } - if (n == 0) { - errno = EAGAIN; - return -1; - } - if (buf[0] == '\x00') { - i = ws_read(cl, buf, 1); /* Consume marker */ - buf++; - n--; - } - if (n == 0) { - errno = EAGAIN; - return -1; - } - - /* end = memchr(buf, '\xff', len*2+2); */ - end = memchr(buf, '\xff', n); - if (!end) { - end = buf + n; - } - avail = end - buf; - - len -= wsctx->carrylen; - - /* Determine how much base64 data we need */ - modlen = len + (len+2)/3; - needlen = modlen; - if (needlen % 4) { - needlen += 4 - (needlen % 4); - } - - if (needlen > avail) { - /* rfbLog("Waiting for more base64 data\n"); */ - errno = EAGAIN; - return -1; - } - - /* Any carryover from previous decode */ - for (i=0; i < wsctx->carrylen; i++) { - /* rfbLog("Adding carryover %d\n", wsctx->carryBuf[i]); */ - dst[i] = wsctx->carryBuf[i]; - retlen += 1; - } - - /* Decode the rest of what we need */ - buf[needlen] = '\x00'; /* Replace end marker with end of string */ - /* rfbLog("buf: %s\n", buf); */ - n = __b64_pton(buf, (unsigned char *)dst+retlen, 2+len); - if (n < len) { - rfbErr("Base64 decode error\n"); - errno = EIO; - return -1; - } - retlen += n; - - /* Consume the data from socket */ - i = ws_read(cl, buf, needlen); - - wsctx->carrylen = n - len; - retlen -= wsctx->carrylen; - for (i=0; i < wsctx->carrylen; i++) { - /* rfbLog("Saving carryover %d\n", dst[retlen + i]); */ - wsctx->carryBuf[i] = dst[retlen + i]; - } - - /* rfbLog("<< webSocketsDecode, retlen: %d\n", retlen); */ - return retlen; -} - -static int -webSocketsDecodeHybi(rfbClientPtr cl, char *dst, int len) -{ - char *buf, *payload; - uint32_t *payload32; - int ret = -1, result = -1; - int total = 0; - ws_mask_t mask; - ws_header_t *header; - int i; - unsigned char opcode; - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - int flength, fhlen; - /* int fin; */ /* not used atm */ - - /* rfbLog(" <== %s[%d]: %d cl: %p, wsctx: %p-%p (%d)\n", __func__, gettid(), len, cl, wsctx, (char *)wsctx + sizeof(ws_ctx_t), sizeof(ws_ctx_t)); */ - - if (wsctx->readbuflen) { - /* simply return what we have */ - if (wsctx->readbuflen > len) { - memcpy(dst, wsctx->readbuf + wsctx->readbufstart, len); - result = len; - wsctx->readbuflen -= len; - wsctx->readbufstart += len; - } else { - memcpy(dst, wsctx->readbuf + wsctx->readbufstart, wsctx->readbuflen); - result = wsctx->readbuflen; - wsctx->readbuflen = 0; - wsctx->readbufstart = 0; - } - goto spor; - } - - buf = wsctx->codeBufDecode; - header = (ws_header_t *)wsctx->codeBufDecode; - - ret = ws_peek(cl, buf, B64LEN(len) + WSHLENMAX); - - if (ret < 2) { - /* save errno because rfbErr() will tamper it */ - if (-1 == ret) { - int olderrno = errno; - rfbErr("%s: peek; %m\n", __func__); - errno = olderrno; - } else if (0 == ret) { - result = 0; - } else { - errno = EAGAIN; - } - goto spor; - } - - opcode = header->b0 & 0x0f; - /* fin = (header->b0 & 0x80) >> 7; */ /* not used atm */ - flength = header->b1 & 0x7f; - - /* - * 4.3. Client-to-Server Masking - * - * The client MUST mask all frames sent to the server. A server MUST - * close the connection upon receiving a frame with the MASK bit set to 0. - **/ - if (!(header->b1 & 0x80)) { - rfbErr("%s: got frame without mask\n", __func__, ret); - errno = EIO; - goto spor; - } - - if (flength < 126) { - fhlen = 2; - mask = header->u.m; - } else if (flength == 126 && 4 <= ret) { - flength = WS_NTOH16(header->u.s16.l16); - fhlen = 4; - mask = header->u.s16.m16; - } else if (flength == 127 && 10 <= ret) { - flength = WS_NTOH64(header->u.s64.l64); - fhlen = 10; - mask = header->u.s64.m64; - } else { - /* Incomplete frame header */ - rfbErr("%s: incomplete frame header\n", __func__, ret); - errno = EIO; - goto spor; - } - - /* absolute length of frame */ - total = fhlen + flength + 4; - payload = buf + fhlen + 4; /* header length + mask */ - - if (-1 == (ret = ws_read(cl, buf, total))) { - int olderrno = errno; - rfbErr("%s: read; %m", __func__); - errno = olderrno; - return ret; - } else if (ret < total) { - /* GT TODO: hmm? */ - rfbLog("%s: read; got partial data\n", __func__); - } else { - buf[ret] = '\0'; - } - - /* process 1 frame (32 bit op) */ - payload32 = (uint32_t *)payload; - for (i = 0; i < flength / 4; i++) { - payload32[i] ^= mask.u; - } - /* process the remaining bytes (if any) */ - for (i*=4; i < flength; i++) { - payload[i] ^= mask.c[i % 4]; - } - - switch (opcode) { - case WS_OPCODE_CLOSE: - rfbLog("got closure, reason %d\n", WS_NTOH16(((uint16_t *)payload)[0])); - errno = ECONNRESET; - break; - case WS_OPCODE_TEXT_FRAME: - if (-1 == (flength = __b64_pton(payload, (unsigned char *)wsctx->codeBufDecode, sizeof(wsctx->codeBufDecode)))) { - rfbErr("%s: Base64 decode error; %m\n", __func__); - break; - } - payload = wsctx->codeBufDecode; - /* fall through */ - case WS_OPCODE_BINARY_FRAME: - if (flength > len) { - memcpy(wsctx->readbuf, payload + len, flength - len); - wsctx->readbufstart = 0; - wsctx->readbuflen = flength - len; - flength = len; - } - memcpy(dst, payload, flength); - result = flength; - break; - default: - rfbErr("%s: unhandled opcode %d, b0: %02x, b1: %02x\n", __func__, (int)opcode, header->b0, header->b1); - } - - /* single point of return, if someone has questions :-) */ -spor: - /* rfbLog("%s: ret: %d/%d\n", __func__, result, len); */ - return result; -} - -static int webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) { int blen, ret = -1, sz = 0; @@ -799,12 +378,12 @@ webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) header = (ws_header_t *)wsctx->codeBufEncode; if (wsctx->base64) { - opcode = WS_OPCODE_TEXT_FRAME; - /* calculate the resulting size */ - blen = B64LEN(len); + opcode = WS_OPCODE_TEXT_FRAME; + /* calculate the resulting size */ + blen = B64LEN(len); } else { - opcode = WS_OPCODE_BINARY_FRAME; - blen = len; + opcode = WS_OPCODE_BINARY_FRAME; + blen = len; } header->b0 = 0x80 | (opcode & 0x0f); @@ -822,16 +401,16 @@ webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) } if (wsctx->base64) { - if (-1 == (ret = __b64_ntop((unsigned char *)src, len, wsctx->codeBufEncode + sz, sizeof(wsctx->codeBufEncode) - sz))) { - rfbErr("%s: Base 64 encode failed\n", __func__); - } else { - if (ret != blen) - rfbErr("%s: Base 64 encode; something weird happened\n", __func__); - ret += sz; - } + if (-1 == (ret = rfbBase64NtoP((unsigned char *)src, len, wsctx->codeBufEncode + sz, sizeof(wsctx->codeBufEncode) - sz))) { + rfbErr("%s: Base 64 encode failed\n", __func__); + } else { + if (ret != blen) + rfbErr("%s: Base 64 encode; something weird happened\n", __func__); + ret += sz; + } } else { - memcpy(wsctx->codeBufEncode + sz, src, len); - ret = sz + len; + memcpy(wsctx->codeBufEncode + sz, src, len); + ret = sz + len; } *dst = wsctx->codeBufEncode; @@ -842,76 +421,28 @@ webSocketsEncodeHybi(rfbClientPtr cl, const char *src, int len, char **dst) int webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst) { - return ((ws_ctx_t *)cl->wsctx)->encode(cl, src, len, dst); + return webSocketsEncodeHybi(cl, src, len, dst); } int webSocketsDecode(rfbClientPtr cl, char *dst, int len) { - return ((ws_ctx_t *)cl->wsctx)->decode(cl, dst, len); + ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; + wsctx->ctxInfo.ctxPtr = cl; + return webSocketsDecodeHybi(wsctx, dst, len); } - -/* returns TRUE if client sent a close frame or a single 'end of frame' - * marker was received, FALSE otherwise - * - * Note: This is a Hixie-only hack! - **/ +/** + * This is a stub function that was once used for Hixie-encoding. + * We keep it for API compatibility. + */ rfbBool webSocketCheckDisconnect(rfbClientPtr cl) { - ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - /* With Base64 encoding we need at least 4 bytes */ - char peekbuf[4]; - int n; - - if (wsctx->version == WEBSOCKETS_VERSION_HYBI) - return FALSE; - - if (cl->sslctx) - n = rfbssl_peek(cl, peekbuf, 4); - else - n = recv(cl->sock, peekbuf, 4, MSG_PEEK); - - if (n <= 0) { - if (n != 0) - rfbErr("%s: peek; %m", __func__); - rfbCloseClient(cl); - return TRUE; - } - - if (peekbuf[0] == '\xff') { - int doclose = 0; - /* Make sure we don't miss a client disconnect on an end frame - * marker. Because we use a peek buffer in some cases it is not - * applicable to wait for more data per select(). */ - switch (n) { - case 3: - if (peekbuf[1] == '\xff' && peekbuf[2] == '\x00') - doclose = 1; - break; - case 2: - if (peekbuf[1] == '\x00') - doclose = 1; - break; - default: - return FALSE; - } - - if (cl->sslctx) - n = rfbssl_read(cl, peekbuf, n); - else - n = read(cl->sock, peekbuf, n); - - if (doclose) { - rfbErr("%s: websocket close frame received\n", __func__); - rfbCloseClient(cl); - } - return TRUE; - } return FALSE; } + /* returns TRUE if there is data waiting to be read in our internal buffer * or if is there any pending data in the buffer of the SSL implementation */ @@ -920,8 +451,8 @@ webSocketsHasDataInBuffer(rfbClientPtr cl) { ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx; - if (wsctx && wsctx->readbuflen) - return TRUE; + if (wsctx && wsctx->readlen) + return TRUE; return (cl->sslctx && rfbssl_pending(cl) > 0); } |