29 #ifdef __STRICT_ANSI__ 37 #ifdef LIBVNCSERVER_HAVE_ENDIAN_H 39 #elif LIBVNCSERVER_HAVE_SYS_ENDIAN_H 40 #include <sys/endian.h> 43 #ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H 44 #include <sys/types.h> 48 #if LIBVNCSERVER_UNISTD_H 51 #include "rfb/rfbconfig.h" 58 #include <sys/syscall.h> 60 return (
int)syscall(SYS_gettid);
68 #define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 70 #define SERVER_HANDSHAKE_HYBI "HTTP/1.1 101 Switching Protocols\r\n\ 71 Upgrade: websocket\r\n\ 72 Connection: Upgrade\r\n\ 73 Sec-WebSocket-Accept: %s\r\n\ 74 Sec-WebSocket-Protocol: %s\r\n\ 77 #define SERVER_HANDSHAKE_HYBI_NO_PROTOCOL "HTTP/1.1 101 Switching Protocols\r\n\ 78 Upgrade: websocket\r\n\ 79 Connection: Upgrade\r\n\ 80 Sec-WebSocket-Accept: %s\r\n\ 83 #define WEBSOCKETS_CLIENT_CONNECT_WAIT_MS 100 84 #define WEBSOCKETS_CLIENT_SEND_WAIT_MS 100 85 #define WEBSOCKETS_MAX_HANDSHAKE_LEN 4096 87 #if defined(__linux__) && defined(NEED_TIMEVAL) 90 long int tv_sec,tv_usec;
95 static rfbBool webSocketsHandshake(rfbClientPtr cl,
char *scheme);
97 static int webSocketsEncodeHybi(rfbClientPtr cl,
const char *src,
int len,
char **dst);
99 static int ws_read(
void *cl,
char *buf,
size_t len);
104 return a < b ? a : b;
107 static void webSocketsGenSha1Key(
char *target,
int size,
char *key)
109 unsigned char hash[SHA1_HASH_SIZE];
110 char tmp[strlen(key) +
sizeof(
GUID) - 1];
111 memcpy(tmp, key, strlen(key));
112 memcpy(tmp + strlen(key),
GUID,
sizeof(
GUID) - 1);
113 hash_sha1(hash, tmp,
sizeof(tmp));
114 if (-1 == rfbBase64NtoP(hash,
sizeof(hash), target, size))
115 rfbErr(
"rfbBase64NtoP failed\n");
125 char bbuf[4], *scheme;
130 if ((ret < 0) && (errno == ETIMEDOUT)) {
131 rfbLog(
"Normal socket connection\n");
133 }
else if (ret <= 0) {
134 rfbErr(
"webSocketsHandshake: unknown connection error\n");
138 if (strncmp(bbuf,
"RFB ", 4) == 0) {
139 rfbLog(
"Normal socket connection\n");
141 }
else if (strncmp(bbuf,
"\x16", 1) == 0 || strncmp(bbuf,
"\x80", 1) == 0) {
142 rfbLog(
"Got TLS/SSL WebSockets connection\n");
144 rfbErr(
"webSocketsHandshake: rfbssl_init failed\n");
153 if (strncmp(bbuf,
"GET ", 4) != 0) {
154 rfbErr(
"webSocketsHandshake: invalid client header\n");
158 rfbLog(
"Got '%s' WebSockets handshake\n", scheme);
160 if (!webSocketsHandshake(cl, scheme)) {
168 webSocketsHandshake(rfbClientPtr cl,
char *scheme)
170 char *buf, *response, *line;
171 int n, linestart = 0, len = 0, llen, base64 =
FALSE;
172 char *path = NULL, *host = NULL, *origin = NULL, *protocol = NULL;
173 char *key1 = NULL, *key2 = NULL;
174 char *sec_ws_origin = NULL;
175 char *sec_ws_key = NULL;
176 char sec_ws_version = 0;
177 ws_ctx_t *wsctx = NULL;
194 if ((n < 0) && (errno == ETIMEDOUT)) {
198 rfbLog(
"webSocketsHandshake: client gone\n");
210 llen = len - linestart;
211 if (((llen >= 2)) && (buf[len-1] ==
'\n')) {
212 line = buf+linestart;
213 if ((llen == 2) && (strncmp(
"\r\n", line, 2) == 0)) {
216 if ((n < 0) && (errno == ETIMEDOUT)) {
220 rfbLog(
"webSocketsHandshake: client gone\n");
232 }
else if ((llen >= 16) && ((strncmp(
"GET ", line, min(llen,4))) == 0)) {
236 cl->wspath = strdup(path);
238 }
else if ((strncasecmp(
"host: ", line, min(llen,6))) == 0) {
242 }
else if ((strncasecmp(
"origin: ", line, min(llen,8))) == 0) {
246 }
else if ((strncasecmp(
"sec-websocket-key1: ", line, min(llen,20))) == 0) {
250 }
else if ((strncasecmp(
"sec-websocket-key2: ", line, min(llen,20))) == 0) {
256 }
else if ((strncasecmp(
"sec-websocket-protocol: ", line, min(llen,24))) == 0) {
259 rfbLog(
"Got protocol: %s\n", protocol);
260 }
else if ((strncasecmp(
"sec-websocket-origin: ", line, min(llen,22))) == 0) {
261 sec_ws_origin = line+22;
263 }
else if ((strncasecmp(
"sec-websocket-key: ", line, min(llen,19))) == 0) {
264 sec_ws_key = line+19;
266 }
else if ((strncasecmp(
"sec-websocket-version: ", line, min(llen,23))) == 0) {
267 sec_ws_version = strtol(line+23, NULL, 10);
277 if (!sec_ws_version) {
278 rfbErr(
"Hixie no longer supported\n");
284 if (!(path && host && (origin || sec_ws_origin))) {
285 rfbErr(
"webSocketsHandshake: incomplete client handshake\n");
291 if ((protocol) && (strstr(protocol,
"base64"))) {
292 rfbLog(
" - webSocketsHandshake: using base64 encoding\n");
296 rfbLog(
" - webSocketsHandshake: using binary/raw encoding\n");
297 if ((protocol) && (strstr(protocol,
"binary"))) {
308 char accept[
B64LEN(SHA1_HASH_SIZE) + 1];
309 rfbLog(
" - WebSockets client version hybi-%02d\n", sec_ws_version);
310 webSocketsGenSha1Key(accept,
sizeof(accept), sec_ws_key);
312 if(strlen(protocol) > 0) {
321 rfbErr(
"webSocketsHandshake: failed sending WebSockets response\n");
330 wsctx = calloc(1,
sizeof(ws_ctx_t));
332 rfbErr(
"webSocketsHandshake: could not allocate memory for context\n");
335 wsctx->encode = webSocketsEncodeHybi;
337 wsctx->ctxInfo.readFunc = ws_read;
338 wsctx->base64 = base64;
340 cl->wsctx = (
wsCtx *)wsctx;
345 ws_read(
void *ctxPtr,
char *buf,
size_t len)
348 rfbClientPtr cl = ctxPtr;
352 n = read(cl->sock, buf, len);
358 webSocketsEncodeHybi(rfbClientPtr cl,
const char *src,
int len,
char **dst)
360 int blen, ret = -1, sz = 0;
361 unsigned char opcode =
'\0';
363 ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
390 header->
b0 = 0x80 | (opcode & 0x0f);
392 header->
b1 = (uint8_t)blen;
394 }
else if (blen <= 65536) {
405 if (-1 == (ret = rfbBase64NtoP((
unsigned char *)src, len, wsctx->codeBufEncode + sz,
sizeof(wsctx->codeBufEncode) - sz))) {
406 rfbErr(
"%s: Base 64 encode failed\n", __func__);
409 rfbErr(
"%s: Base 64 encode; something weird happened\n", __func__);
413 memcpy(wsctx->codeBufEncode + sz, src, len);
417 *dst = wsctx->codeBufEncode;
425 return webSocketsEncodeHybi(cl, src, len, dst);
431 ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
432 wsctx->ctxInfo.ctxPtr = cl;
453 ws_ctx_t *wsctx = (ws_ctx_t *)cl->wsctx;
455 if (wsctx && wsctx->readlen)
int rfbReadExactTimeout(rfbClientPtr cl, char *buf, int len, int timeout)
#define SERVER_HANDSHAKE_HYBI_NO_PROTOCOL
rfbBool webSocketsCheck(rfbClientPtr cl)
int rfbssl_read(rfbClientPtr cl, char *buf, int bufsize)
int rfbPeekExactTimeout(rfbClientPtr cl, char *buf, int len, int timeout)
#define WEBSOCKETS_MAX_HANDSHAKE_LEN
rfbBool webSocketCheckDisconnect(rfbClientPtr cl)
This is a stub function that was once used for Hixie-encoding.
#define WEBSOCKETS_CLIENT_SEND_WAIT_MS
int webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst)
int rfbWriteExact(rfbClientPtr cl, const char *buf, int len)
int rfbReadExact(rfbClientPtr cl, char *buf, int len)
int rfbssl_init(rfbClientPtr cl)
int webSocketsDecode(rfbClientPtr cl, char *dst, int len)
void rfbLogPerror(const char *str)
void hybiDecodeCleanupComplete(ws_ctx_t *wsctx)
#define WEBSOCKETS_CLIENT_CONNECT_WAIT_MS
#define SERVER_HANDSHAKE_HYBI
rfbBool webSocketsHasDataInBuffer(rfbClientPtr cl)
int webSocketsDecodeHybi(ws_ctx_t *wsctx, char *dst, int len)
Read function for websocket-socket emulation.
int rfbssl_pending(rfbClientPtr cl)